Skip to content
Kward Search API index

Class: Kward::Transport::PluginChatGateway

Inherits:
Object
  • Object
show all
Defined in:
lib/kward/transport/plugin_chat_gateway.rb

Overview

Adapts the shared plugin-chat runtime to the transport host contract.

Constant Summary collapse

POLL_INTERVAL =
0.05
TERMINAL_STATUSES =
%w[completed canceled failed].freeze
IMAGE_MIME_TYPES =
%w[image/png image/jpeg image/gif image/webp].freeze

Instance Method Summary collapse

Constructor Details

#initialize(runtime:, transport_id:, poll_interval: POLL_INTERVAL) ⇒ PluginChatGateway

Returns a new instance of PluginChatGateway.



13
14
15
16
17
18
19
# File 'lib/kward/transport/plugin_chat_gateway.rb', line 13

def initialize(runtime:, transport_id:, poll_interval: POLL_INTERVAL)
  @runtime = runtime
  @transport_id = transport_id.to_s
  @poll_interval = poll_interval
  @subscriptions = []
  @mutex = Mutex.new
end

Instance Method Details

#cancel_transport_plugin_chat_turn(turn_id:) ⇒ Object



78
79
80
81
# File 'lib/kward/transport/plugin_chat_gateway.rb', line 78

def cancel_transport_plugin_chat_turn(turn_id:)
  @runtime.cancel_turn(turn_id: turn_id)
  nil
end

#resolve_transport_chat(transport_id:, type_id:, conversation:, actor:, scope_key:, descriptor: {}, workspace_root: nil) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/kward/transport/plugin_chat_gateway.rb', line 21

def resolve_transport_chat(transport_id:, type_id:, conversation:, actor:, scope_key:, descriptor: {}, workspace_root: nil)
  validate_transport_id!(transport_id)
  validate_conversation!(conversation)
  validate_actor!(actor)
  chat = @runtime.open(
    type_id: type_id,
    surface: :transport,
    scope_key: scope_key,
    descriptor: transport_descriptor(conversation, actor, descriptor),
    workspace_root: workspace_root || Dir.pwd
  )
  Host::PluginChatHandle.new(
    id: chat.id,
    type_id: chat.type.id,
    scope_key: chat.scope_key,
    name: chat.type.title
  )
end

#shutdownObject



104
105
106
107
108
109
110
111
112
113
# File 'lib/kward/transport/plugin_chat_gateway.rb', line 104

def shutdown
  subscriptions = @mutex.synchronize do
    current = @subscriptions
    @subscriptions = []
    current
  end
  subscriptions.each(&:kill)
  subscriptions.each(&:join)
  nil
end

#start_transport_plugin_chat_turn(chat_id:, actor:, input:, attachments: [], streaming_behavior: nil, execution_profile: nil) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/kward/transport/plugin_chat_gateway.rb', line 40

def start_transport_plugin_chat_turn(chat_id:, actor:, input:, attachments: [], streaming_behavior: nil, execution_profile: nil)
  if execution_profile && !execution_profile.attachments && !Array(attachments).empty?
    raise ArgumentError, "transport execution profile does not allow attachments"
  end
  unless streaming_behavior.nil? || %i[aggregate none].include?(streaming_behavior.to_sym)
    raise ArgumentError, "plugin chat turns do not support #{streaming_behavior} streaming"
  end

  turn = @runtime.start_turn(
    chat_id: chat_id,
    input: @runtime.input_with_attachments(input, normalize_attachments(attachments)),
    display_input: input.to_s,
    context: { actor: actor }
  )
  Host::PluginChatTurnHandle.new(id: turn.id, chat_id: turn.chat_id)
end

#subscribe_transport_plugin_chat_turn(turn_id:, after: nil) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/kward/transport/plugin_chat_gateway.rb', line 83

def subscribe_transport_plugin_chat_turn(turn_id:, after: nil)
  cursor = after.to_i
  thread = Thread.new do
    loop do
      events = transport_plugin_chat_turn_events(turn_id: turn_id, after: cursor)
      events.each do |event|
        cursor = event.sequence
        yield event
      end
      status = transport_plugin_chat_turn_status(turn_id: turn_id)
      break if TERMINAL_STATUSES.include?(status[:status].to_s)

      sleep @poll_interval
    end
  rescue StandardError
    nil
  end
  @mutex.synchronize { @subscriptions << thread }
  thread
end

#transport_plugin_chat_transcript(chat_id:) ⇒ Object



57
58
59
60
# File 'lib/kward/transport/plugin_chat_gateway.rb', line 57

def transport_plugin_chat_transcript(chat_id:)
  chat = fetch_chat(chat_id)
  { messages: chat.driver.messages }
end

#transport_plugin_chat_turn_events(turn_id:, after: nil) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/kward/transport/plugin_chat_gateway.rb', line 62

def transport_plugin_chat_turn_events(turn_id:, after: nil)
  @runtime.turn_events(turn_id: turn_id, after_sequence: after.to_i).map do |event|
    Transport.turn_event(
      type: event.fetch(:type),
      session_id: event.fetch(:chatId),
      turn_id: event.fetch(:turnId),
      sequence: event.fetch(:sequence),
      payload: event.fetch(:payload, {})
    )
  end
end

#transport_plugin_chat_turn_status(turn_id:) ⇒ Object



74
75
76
# File 'lib/kward/transport/plugin_chat_gateway.rb', line 74

def transport_plugin_chat_turn_status(turn_id:)
  turn_payload(@runtime.turn_status(turn_id: turn_id))
end