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 ‘timeout`s).



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