Class: Legion::Gaia::Channels::TeamsAdapter

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

Constant Summary collapse

CAPABILITIES =
%i[rich_text adaptive_cards proactive_messaging mobile desktop mentions].freeze
MOBILE_CAPABILITIES =
%i[rich_text adaptive_cards mobile mentions].freeze
DESKTOP_CAPABILITIES =
%i[rich_text adaptive_cards desktop 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(app_id: nil) ⇒ TeamsAdapter

Returns a new instance of TeamsAdapter.



17
18
19
20
21
# File 'lib/legion/gaia/channels/teams_adapter.rb', line 17

def initialize(app_id: nil)
  super(channel_id: :teams, capabilities: CAPABILITIES)
  @app_id = app_id
  @conversation_store = Teams::ConversationStore.new
end

Instance Attribute Details

#app_idObject (readonly)

Returns the value of attribute app_id.



15
16
17
# File 'lib/legion/gaia/channels/teams_adapter.rb', line 15

def app_id
  @app_id
end

#conversation_storeObject (readonly)

Returns the value of attribute conversation_store.



15
16
17
# File 'lib/legion/gaia/channels/teams_adapter.rb', line 15

def conversation_store
  @conversation_store
end

Instance Method Details

#create_proactive_conversation(user_id:, tenant_id: nil) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/legion/gaia/channels/teams_adapter.rb', line 77

def create_proactive_conversation(user_id:, tenant_id: nil)
  profile = conversation_store.(user_id)
  service_url = profile&.service_url
  resolved_tenant = tenant_id || profile&.tenant_id
  return { error: :no_service_url } unless service_url
  return { error: :bot_runner_not_available } unless bot_runner_available?

  bot = Legion::Extensions::MicrosoftTeams::Client.new
  result = bot.create_conversation(
    service_url: service_url,
    bot_id: app_id,
    user_id: user_id,
    tenant_id: resolved_tenant
  )
  return result if result.is_a?(Hash) && result[:error]

  conversation_id = result[:conversation_id] || result['id']
  conversation_store.store(
    conversation_id: conversation_id,
    service_url: service_url,
    tenant_id: resolved_tenant
  )
  conversation_id
rescue StandardError => e
  if defined?(Legion::Logging)
    Legion::Logging.warn("TeamsAdapter create_proactive_conversation failed: #{e.message}")
  end
  { error: :create_conversation_failed, message: e.message }
end

#deliver(rendered_content, conversation_id: nil) ⇒ Object



59
60
61
62
63
64
# File 'lib/legion/gaia/channels/teams_adapter.rb', line 59

def deliver(rendered_content, conversation_id: nil)
  ref = conversation_id && conversation_store.lookup(conversation_id)
  return { error: :no_conversation_reference } unless ref

  deliver_via_bot(rendered_content, ref)
end

#deliver_proactive(output_frame) ⇒ Object



66
67
68
69
70
71
72
73
74
75
# File 'lib/legion/gaia/channels/teams_adapter.rb', line 66

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

  conversation_id = resolve_proactive_conversation(user_id)
  return conversation_id if conversation_id.is_a?(Hash) && conversation_id[:error]

  rendered = translate_outbound(output_frame)
  deliver(rendered, conversation_id: conversation_id)
end

#translate_inbound(activity) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/legion/gaia/channels/teams_adapter.rb', line 23

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

  identity = Teams::BotFrameworkAuth.extract_identity(activity)
  conversation = activity['conversation'] || activity[:conversation] || {}
  text = activity['text'] || activity[:text] || ''
  text = strip_mention(text, activity)

  conversation_store.store_from_activity(activity)

  InputFrame.new(
    content: text.strip,
    channel_id: :teams,
    content_type: detect_content_type(activity),
    channel_capabilities: capabilities_for_device(activity),
    device_context: build_device_context(activity),
    auth_context: build_auth_context(identity, activity),
    metadata: {
      source_type: :human_direct,
      salience: 0.9,
      conversation_id: conversation['id'] || conversation[:id],
      activity_id: activity['id'] || activity[:id],
      activity_type: activity['type'] || activity[:type]
    }
  )
end

#translate_outbound(output_frame) ⇒ Object



50
51
52
53
54
55
56
57
# File 'lib/legion/gaia/channels/teams_adapter.rb', line 50

def translate_outbound(output_frame)
  content = output_frame.content.to_s
  if output_frame.content_type == :adaptive_card
    { type: 'adaptive_card', card: output_frame.content }
  else
    { type: 'text', text: content }
  end
end

#validate_inbound(token, allow_emulator: false) ⇒ Object



107
108
109
110
111
# File 'lib/legion/gaia/channels/teams_adapter.rb', line 107

def validate_inbound(token, allow_emulator: false)
  return { valid: false, error: :no_app_id } unless app_id

  Teams::BotFrameworkAuth.validate_token(token, app_id: app_id, allow_emulator: allow_emulator)
end