Class: PiAgent::ExtensionUI

Inherits:
Object
  • Object
show all
Defined in:
lib/pi_agent/extension_ui.rb

Overview

Handles the bidirectional Extension UI sub-protocol.

pi extensions can request user interaction (ctx.ui.select, ctx.ui.confirm, ...). In RPC mode these arrive as extension_ui_request messages. Dialog methods block the agent until the client sends a matching extension_ui_response; fire-and-forget methods expect no response.

Each request is handled on its own thread so a slow or blocking handler never stalls the transport reader thread (and therefore the agent event stream).

The handler is a callable taking a Request and returning:

- select / input / editor : a String value, or nil to cancel
- confirm                 : true / false, or nil to cancel
- fire-and-forget methods : return value ignored

With no handler, dialogs are auto-cancelled so the agent never hangs.

Defined Under Namespace

Classes: Request

Constant Summary collapse

DIALOG_METHODS =
%i[select confirm input editor].freeze

Instance Method Summary collapse

Constructor Details

#initialize(writer:, handler: nil) ⇒ ExtensionUI

Returns a new instance of ExtensionUI.



53
54
55
56
57
58
# File 'lib/pi_agent/extension_ui.rb', line 53

def initialize(writer:, handler: nil)
  @writer = writer
  @handler = handler
  @threads = []
  @mutex = Mutex.new
end

Instance Method Details

#dispatch(msg) ⇒ Object

Route an extension_ui_request message. Non-blocking: spawns a thread to run the handler and (for dialogs) send the response.



62
63
64
65
66
67
68
# File 'lib/pi_agent/extension_ui.rb', line 62

def dispatch(msg)
  request = Request.new(msg)
  @mutex.synchronize do
    @threads.select!(&:alive?)
    @threads << Thread.new { handle(request) }
  end
end

#shutdown(timeout: 5) ⇒ Object

Wait for in-flight handler threads to finish (each up to timeouts).



71
72
73
# File 'lib/pi_agent/extension_ui.rb', line 71

def shutdown(timeout: 5)
  @mutex.synchronize { @threads.dup }.each { |t| t.join(timeout) }
end