Class: BoltRb::Handlers::AssistantHandler

Inherits:
Base
  • Object
show all
Defined in:
lib/bolt_rb/handlers/assistant_handler.rb

Overview

Handler for Slack AI assistant threads.

One subclass receives the three events that make up an assistant conversation: assistant_thread_started, assistant_thread_context_changed, and threaded direct messages from the user.

Examples:

class MyAssistant < BoltRb::AssistantHandler
  def thread_started
    set_suggested_prompts(['Summarize this channel'])
  end

  def user_message
    set_status('is thinking...')
    say("You said: #{text}")
  end
end

Constant Summary collapse

THREAD_STARTED =
'assistant_thread_started'
CONTEXT_CHANGED =
'assistant_thread_context_changed'
MESSAGE =
'message'

Instance Attribute Summary

Attributes inherited from Base

#context

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#ack, #call, #client, inherited, #initialize, middleware_stack, #payload, #respond, use

Constructor Details

This class inherits a constructor from BoltRb::Handlers::Base

Class Method Details

.matches?(payload) ⇒ Boolean

Match the assistant events and threaded user DMs

Parameters:

  • payload (Hash)

    The incoming Slack event payload

Returns:

  • (Boolean)


33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 33

def matches?(payload)
  # The abstract class is auto-registered but must never run
  return false if self == AssistantHandler

  event = payload['event']
  return false unless event

  case event['type']
  when THREAD_STARTED, CONTEXT_CHANGED then true
  when MESSAGE then user_thread_message?(event)
  else false
  end
end

Instance Method Details

#assistant_threadHash?

Return the assistant_thread object for thread events

Returns:

  • (Hash, nil)


110
111
112
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 110

def assistant_thread
  event['assistant_thread']
end

#channelString?

Return the DM channel ID of the assistant thread

Returns:

  • (String, nil)


117
118
119
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 117

def channel
  assistant_thread&.dig('channel_id') || event['channel']
end

#context_changedvoid

This method returns an undefined value.

Hook for a change of the user's active channel

The new context is saved before this runs. The default does nothing.



91
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 91

def context_changed; end

#eventHash

Return the event portion of the payload

Returns:

  • (Hash)

    The event data



103
104
105
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 103

def event
  payload['event']
end

#handlevoid

This method returns an undefined value.

Route the event to the matching hook method



66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 66

def handle
  case event['type']
  when THREAD_STARTED
    save_thread_context(assistant_thread['context'])
    thread_started
  when CONTEXT_CHANGED
    save_thread_context(assistant_thread['context'])
    context_changed
  when MESSAGE
    user_message
  end
end

#save_thread_context(context) ⇒ void

This method returns an undefined value.

Save a context for the current thread

Parameters:

  • context (Hash)

    The context to save



158
159
160
161
162
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 158

def save_thread_context(context)
  return if context.nil?

  thread_context_store.save(channel_id: channel, thread_ts: thread_ts, context: context)
end

#say(message) ⇒ Hash

Post a message into the assistant thread

Parameters:

  • message (String, Hash)

    Text or chat.postMessage options

Returns:

  • (Hash)

    The Slack API response



168
169
170
171
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 168

def say(message)
  options = message.is_a?(Hash) ? message : { text: message }
  client.chat_postMessage(options.merge(channel: channel, thread_ts: thread_ts))
end

#set_status(status) ⇒ Hash

Set the status line shown while the assistant works

Parameters:

  • status (String)

    Status text, for example 'is thinking...'

Returns:

  • (Hash)

    The Slack API response



177
178
179
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 177

def set_status(status)
  client.assistant_threads_setStatus(thread_target.merge(status: status))
end

#set_suggested_prompts(prompts, title: nil) ⇒ Hash

Set the suggested prompts shown to the user

Plain strings become prompts with the same title and message.

Parameters:

  • prompts (Array<String, Hash>)

    Up to four prompts

  • title (String, nil) (defaults to: nil)

    Optional heading above the prompts

Returns:

  • (Hash)

    The Slack API response



196
197
198
199
200
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 196

def set_suggested_prompts(prompts, title: nil)
  options = thread_target.merge(prompts: normalize_prompts(prompts))
  options[:title] = title if title
  client.assistant_threads_setSuggestedPrompts(options)
end

#set_title(title) ⇒ Hash

Set the title of the assistant thread

Parameters:

  • title (String)

    The thread title

Returns:

  • (Hash)

    The Slack API response



185
186
187
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 185

def set_title(title)
  client.assistant_threads_setTitle(thread_target.merge(title: title))
end

#textString?

Return the message text for user messages

Returns:

  • (String, nil)


138
139
140
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 138

def text
  event['text']
end

#thread_contextHash?

Return the context of the assistant thread

Thread events carry the context in the payload. User messages read it from the configured thread context store.

Returns:

  • (Hash, nil)

    Keys such as channel_id, team_id, enterprise_id



148
149
150
151
152
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 148

def thread_context
  return assistant_thread['context'] if assistant_thread

  thread_context_store.get(channel_id: channel, thread_ts: thread_ts)
end

#thread_startedObject

Hook for a new assistant thread

Raises:

  • (NotImplementedError)

    Subclasses must define this method



82
83
84
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 82

def thread_started
  raise NotImplementedError, "#{self.class} must implement #thread_started"
end

#thread_tsString?

Return the thread timestamp of the assistant thread

Returns:

  • (String, nil)


124
125
126
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 124

def thread_ts
  assistant_thread&.dig('thread_ts') || event['thread_ts']
end

#userString?

Return the user ID that owns the assistant thread

Returns:

  • (String, nil)


131
132
133
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 131

def user
  assistant_thread&.dig('user_id') || event['user']
end

#user_messageObject

Hook for a user message inside the assistant thread

Raises:

  • (NotImplementedError)

    Subclasses must define this method



96
97
98
# File 'lib/bolt_rb/handlers/assistant_handler.rb', line 96

def user_message
  raise NotImplementedError, "#{self.class} must implement #user_message"
end