Class: Legion::Gaia::Channels::SlackAdapter

Inherits:
Legion::Gaia::ChannelAdapter show all
Defined in:
lib/legion/gaia/channels/slack_adapter.rb

Constant Summary collapse

CAPABILITIES =
%i[rich_text threads reactions mentions file_attachment].freeze

Instance Attribute Summary collapse

Attributes inherited from Legion::Gaia::ChannelAdapter

#capabilities, #channel_id

Instance Method Summary collapse

Methods inherited from Legion::Gaia::ChannelAdapter

#start, #started?, #stop, #supports?

Constructor Details

#initialize(signing_secret: nil, bot_token: nil, default_webhook: nil) ⇒ SlackAdapter

Returns a new instance of SlackAdapter.



13
14
15
16
17
18
# File 'lib/legion/gaia/channels/slack_adapter.rb', line 13

def initialize(signing_secret: nil, bot_token: nil, default_webhook: nil)
  super(channel_id: :slack, capabilities: CAPABILITIES)
  @signing_secret = signing_secret
  @bot_token = bot_token
  @default_webhook = default_webhook
end

Instance Attribute Details

#bot_tokenObject (readonly)

Returns the value of attribute bot_token.



11
12
13
# File 'lib/legion/gaia/channels/slack_adapter.rb', line 11

def bot_token
  @bot_token
end

#signing_secretObject (readonly)

Returns the value of attribute signing_secret.



11
12
13
# File 'lib/legion/gaia/channels/slack_adapter.rb', line 11

def signing_secret
  @signing_secret
end

Instance Method Details

#deliver(rendered_content, webhook: nil) ⇒ Object



46
47
48
49
50
51
# File 'lib/legion/gaia/channels/slack_adapter.rb', line 46

def deliver(rendered_content, webhook: nil)
  target_webhook = webhook || @default_webhook
  return deliver_via_api(rendered_content) if @bot_token && !target_webhook

  deliver_via_webhook(rendered_content, target_webhook)
end

#deliver_proactive(output_frame) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
# File 'lib/legion/gaia/channels/slack_adapter.rb', line 53

def deliver_proactive(output_frame)
  user_id = output_frame.[:target_user]
  return { error: :no_target_user } unless user_id

  dm_result = open_dm(user_id: user_id)
  return dm_result if dm_result.is_a?(Hash) && dm_result[:error]

  channel = dm_result[:channel_id]
  rendered = translate_outbound(output_frame).merge(channel: channel)
  deliver_via_api_to_channel(rendered)
end

#open_dm(user_id:) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/legion/gaia/channels/slack_adapter.rb', line 65

def open_dm(user_id:)
  return { error: :no_bot_token } unless @bot_token
  return { error: :slack_runner_not_available } unless slack_runner_available?

  result = Legion::Extensions::Slack::Runners::Chat.open_dm(
    user_id: user_id,
    token: @bot_token
  )
  return result if result.is_a?(Hash) && result[:error]

  { channel_id: result[:channel_id] || result['channel']&.dig('id') || result['channel'] }
rescue StandardError => e
  Legion::Logging.warn("SlackAdapter open_dm failed: #{e.message}") if defined?(Legion::Logging)
  { error: :open_dm_failed, message: e.message }
end

#translate_inbound(event) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/legion/gaia/channels/slack_adapter.rb', line 20

def translate_inbound(event)
  return nil unless event.is_a?(Hash)

  user = event['user'] || event[:user]
  InputFrame.new(
    content: strip_bot_mention(event['text'] || event[:text] || ''),
    channel_id: :slack,
    content_type: :text,
    channel_capabilities: CAPABILITIES,
    device_context: { platform: :desktop, input_method: :keyboard },
    auth_context: { user_id: user, team_id: event['team'] || event[:team], identity: user },
    metadata: (event)
  )
end

#translate_outbound(output_frame) ⇒ Object



35
36
37
38
39
40
41
42
43
44
# File 'lib/legion/gaia/channels/slack_adapter.rb', line 35

def translate_outbound(output_frame)
  content = output_frame.content.to_s
  thread_ts = output_frame.[:slack_thread_ts]
  channel = output_frame.[:slack_channel]

  result = { text: content }
  result[:thread_ts] = thread_ts if thread_ts
  result[:channel] = channel if channel
  result
end

#verify_request(signing_secret: nil, timestamp: nil, body: nil, signature: nil) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
# File 'lib/legion/gaia/channels/slack_adapter.rb', line 81

def verify_request(signing_secret: nil, timestamp: nil, body: nil, signature: nil)
  secret = signing_secret || @signing_secret
  return { valid: false, error: :no_signing_secret } unless secret

  Slack::SigningVerifier.verify(
    signing_secret: secret,
    timestamp: timestamp,
    body: body,
    signature: signature
  )
end