Class: Pikuri::Agent::Configurator
- Inherits:
-
Object
- Object
- Pikuri::Agent::Configurator
- Defined in:
- lib/pikuri/agent/configurator.rb
Overview
Build-time collector yielded into the Pikuri::Agent.new block. Hosts and Extension implementations call its methods to declare additional tools, listeners, system-prompt snippets, on_close handlers, and extension instances; #initialize drains the collected state into the agent’s final wiring before returning.
Why this exists
Splits “configure the agent” from “the agent’s runtime state”. Hosts can write a block that reads cleanly:
Pikuri::Agent.new(transport: ..., system_prompt: ...) do |c|
c.add_listener Pikuri::Agent::Listener::Terminal.new
c.add_tool Pikuri::Tool::CALCULATOR
c.add_extension Pikuri::Skill::Extension.new(catalog: catalog)
end
Extensions implement their configure© hook against the same type, so the call sites for “block users add stuff” and “extensions add stuff” share one API.
Lifecycle
One Configurator per Agent.new invocation. The Configurator is constructed inside #initialize, yielded to the block (if any), then its collected state is drained by the Agent body. The Configurator instance is discarded once Agent.new returns — it carries no runtime state.
Defined Under Namespace
Classes: SubAgentRequest
Instance Attribute Summary collapse
-
#cancellable ⇒ Control::Cancellable?
readonly
Cancellation control passed to the Agent ctor, or
nil. -
#extensions ⇒ Array<#configure>
readonly
Extension instances added via #add_extension, in declaration order.
-
#interloper ⇒ Control::Interloper?
readonly
Mid-loop user-input queue passed to the Agent ctor, or
nil. -
#listeners ⇒ Array<Listener::Base>
readonly
Listeners added via #add_listener, in declaration order.
-
#name ⇒ String
readonly
This agent’s identifier; empty for the main agent, hierarchical (+“sub_agent 0_1”+) for sub-agents.
-
#on_close_handlers ⇒ Array<Proc>
readonly
on_closehandlers added via #on_close, in declaration order. -
#step_limit ⇒ Control::StepLimit?
readonly
Step-budget control passed to the Agent ctor, or
nil. -
#streaming ⇒ Boolean
readonly
truewhen the agent opted into chunk-level streaming. -
#sub_agent_request ⇒ SubAgentRequest?
readonly
Set when the block called #allow_sub_agent;
nilotherwise. -
#system_prompt_additions ⇒ Array<String>
readonly
System-prompt snippets added via #append_system_prompt, in declaration order.
-
#system_prompt_base ⇒ String
readonly
The
system_prompt:kwarg passed to #initialize, untouched. -
#tools ⇒ Array<Tool>
readonly
Tools added via #add_tool, in declaration order.
-
#transport ⇒ Agent::ChatTransport
readonly
Same transport the Agent will use.
Instance Method Summary collapse
-
#add_extension(extension) ⇒ void
Register an extension.
-
#add_listener(listener) ⇒ void
Append a listener to the agent’s listener list.
-
#add_listeners(listeners) ⇒ void
Append several listeners at once.
-
#add_tool(tool) ⇒ void
Append a tool to the agent’s static tool list.
-
#add_tools(tools) ⇒ void
Append several tools at once.
-
#allow_sub_agent(max_steps: 10) ⇒ void
Enable the
sub_agenttool on this agent. -
#append_system_prompt(snippet) ⇒ void
Append a snippet to the system prompt.
-
#inherit_extensions(extensions) ⇒ void
Retain a list of already-configured extensions for the bind sweep without re-running
configure. -
#initialize(transport:, system_prompt_base:, name:, streaming:, step_limit:, cancellable:, interloper:) ⇒ Configurator
constructor
A new instance of Configurator.
-
#on_close { ... } ⇒ void
Register a handler called by #close.
Constructor Details
#initialize(transport:, system_prompt_base:, name:, streaming:, step_limit:, cancellable:, interloper:) ⇒ Configurator
Returns a new instance of Configurator.
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/pikuri/agent/configurator.rb', line 117 def initialize(transport:, system_prompt_base:, name:, streaming:, step_limit:, cancellable:, interloper:) @transport = transport @system_prompt_base = system_prompt_base @name = name @streaming = streaming @step_limit = step_limit @cancellable = cancellable @interloper = interloper @tools = [] @listeners = [] @system_prompt_additions = [] @on_close_handlers = [] @extensions = [] end |
Instance Attribute Details
#cancellable ⇒ Control::Cancellable? (readonly)
Returns cancellation control passed to the Agent ctor, or nil. Extensions that run sub-LLM calls during configure (e.g. an MCP description synthesizer) share this so a user cancel during boot propagates correctly.
64 65 66 |
# File 'lib/pikuri/agent/configurator.rb', line 64 def cancellable @cancellable end |
#extensions ⇒ Array<#configure> (readonly)
Returns extension instances added via #add_extension, in declaration order. The Agent ctor walks this list and calls bind(self) on each after wiring is complete.
94 95 96 |
# File 'lib/pikuri/agent/configurator.rb', line 94 def extensions @extensions end |
#interloper ⇒ Control::Interloper? (readonly)
Returns mid-loop user-input queue passed to the Agent ctor, or nil.
68 69 70 |
# File 'lib/pikuri/agent/configurator.rb', line 68 def interloper @interloper end |
#listeners ⇒ Array<Listener::Base> (readonly)
Returns listeners added via #add_listener, in declaration order. Drained by Pikuri::Agent#initialize.
77 78 79 |
# File 'lib/pikuri/agent/configurator.rb', line 77 def listeners @listeners end |
#name ⇒ String (readonly)
Returns this agent’s identifier; empty for the main agent, hierarchical (+“sub_agent 0_1”+) for sub-agents.
49 50 51 |
# File 'lib/pikuri/agent/configurator.rb', line 49 def name @name end |
#on_close_handlers ⇒ Array<Proc> (readonly)
Returns on_close handlers added via #on_close, in declaration order. Fired by Pikuri::Agent#close in LIFO order with per-handler rescue.
88 89 90 |
# File 'lib/pikuri/agent/configurator.rb', line 88 def on_close_handlers @on_close_handlers end |
#step_limit ⇒ Control::StepLimit? (readonly)
Returns step-budget control passed to the Agent ctor, or nil.
57 58 59 |
# File 'lib/pikuri/agent/configurator.rb', line 57 def step_limit @step_limit end |
#streaming ⇒ Boolean (readonly)
Returns true when the agent opted into chunk-level streaming.
53 54 55 |
# File 'lib/pikuri/agent/configurator.rb', line 53 def streaming @streaming end |
#sub_agent_request ⇒ SubAgentRequest? (readonly)
Returns set when the block called #allow_sub_agent; nil otherwise. The Agent ctor uses this to decide whether to create a Tool::SubAgent instance after the chat is wired (so the SubAgent tool’s parent.tools snapshot doesn’t include itself —recursion guard).
102 103 104 |
# File 'lib/pikuri/agent/configurator.rb', line 102 def sub_agent_request @sub_agent_request end |
#system_prompt_additions ⇒ Array<String> (readonly)
Returns system-prompt snippets added via #append_system_prompt, in declaration order. Joined with double-newline separators between the base prompt and each snippet by Pikuri::Agent#initialize.
83 84 85 |
# File 'lib/pikuri/agent/configurator.rb', line 83 def system_prompt_additions @system_prompt_additions end |
#system_prompt_base ⇒ String (readonly)
Returns the system_prompt: kwarg passed to Pikuri::Agent#initialize, untouched. Extensions append to the prompt via #append_system_prompt rather than mutating this; the attribute exists so a peek at the base is available for diagnostics.
45 46 47 |
# File 'lib/pikuri/agent/configurator.rb', line 45 def system_prompt_base @system_prompt_base end |
#tools ⇒ Array<Tool> (readonly)
Returns tools added via #add_tool, in declaration order. Drained by Pikuri::Agent#initialize.
72 73 74 |
# File 'lib/pikuri/agent/configurator.rb', line 72 def tools @tools end |
#transport ⇒ Agent::ChatTransport (readonly)
Returns same transport the Agent will use. Extensions read this to wire helpers consistently (e.g. an MCP description-synthesizer that calls the same model the agent itself uses).
38 39 40 |
# File 'lib/pikuri/agent/configurator.rb', line 38 def transport @transport end |
Instance Method Details
#add_extension(extension) ⇒ void
This method returns an undefined value.
Register an extension. The extension’s configure(self) is called immediately so source-order matches execution-order. The instance is also retained for the bind(agent) sweep that runs at the end of Pikuri::Agent#initialize.
Extensions must implement both configure and bind. The easy way is to include Pikuri::Agent::Extension — that mixes in empty defaults for both, so an extension overrides only what it cares about and leaves the other as a no-op.
204 205 206 207 208 |
# File 'lib/pikuri/agent/configurator.rb', line 204 def add_extension(extension) @extensions << extension extension.configure(self) nil end |
#add_listener(listener) ⇒ void
This method returns an undefined value.
Append a listener to the agent’s listener list.
159 160 161 162 |
# File 'lib/pikuri/agent/configurator.rb', line 159 def add_listener(listener) @listeners << listener nil end |
#add_listeners(listeners) ⇒ void
This method returns an undefined value.
Append several listeners at once. Accepts any enumerable (Array, ListenerList, …); declaration order is preserved. Sole intended caller today is Tool::SubAgent, which seeds a sub-agent’s Configurator from the parent’s listener list (run through ListenerList#for_sub_agent).
172 173 174 175 |
# File 'lib/pikuri/agent/configurator.rb', line 172 def add_listeners(listeners) listeners.each { |l| @listeners << l } nil end |
#add_tool(tool) ⇒ void
This method returns an undefined value.
Append a tool to the agent’s static tool list.
138 139 140 141 |
# File 'lib/pikuri/agent/configurator.rb', line 138 def add_tool(tool) @tools << tool nil end |
#add_tools(tools) ⇒ void
This method returns an undefined value.
Append several tools at once. Equivalent to calling #add_tool for each element of tools; declaration order is preserved. Sole intended caller today is Tool::SubAgent, which seeds a sub-agent’s Configurator from the parent’s tool snapshot.
150 151 152 153 |
# File 'lib/pikuri/agent/configurator.rb', line 150 def add_tools(tools) tools.each { |t| @tools << t } nil end |
#allow_sub_agent(max_steps: 10) ⇒ void
This method returns an undefined value.
Enable the sub_agent tool on this agent. Records the max_steps budget for sub-agent runs; the Agent ctor reads #sub_agent_request after the block returns and constructs the actual Tool::SubAgent so its snapshot of the parent’s tool list doesn’t include itself (recursion guard).
Sub-agents inherit the parent’s tool list (minus sub_agent itself), augmented system prompt, listeners (via for_sub_agent per listener), controls (per the per-control rule), and the parent’s extension list. Each inherited extension’s bind(sub_agent) fires during the sub-agent’s construction — that’s how MCP’s per-agent connect tool ends up keyed to the sub-agent rather than the parent.
262 263 264 265 266 267 |
# File 'lib/pikuri/agent/configurator.rb', line 262 def allow_sub_agent(max_steps: 10) raise 'allow_sub_agent may only be called once per agent' if @sub_agent_request @sub_agent_request = SubAgentRequest.new(max_steps: max_steps) nil end |
#append_system_prompt(snippet) ⇒ void
This method returns an undefined value.
Append a snippet to the system prompt. Snippets are joined to the base prompt with double-newline separators.
Used by extensions to register <available_skills>, <available_mcps>, and similar advertisement blocks. Block users typically pass the full system prompt via the ctor’s system_prompt: kwarg instead.
187 188 189 190 |
# File 'lib/pikuri/agent/configurator.rb', line 187 def append_system_prompt(snippet) @system_prompt_additions << snippet nil end |
#inherit_extensions(extensions) ⇒ void
This method returns an undefined value.
Retain a list of already-configured extensions for the bind sweep without re-running configure. Sole intended caller is Tool::SubAgent, which seeds a sub-agent’s Configurator from the parent’s extension list — the parent already drove configure and its system-prompt snippets / static tools are inherited by the sub-agent verbatim through #add_tools + #add_listeners + the augmented system_prompt; re-running configure on the sub-agent would double up those contributions. The bind(sub_agent) sweep in Pikuri::Agent#initialize still fires on each inherited extension so per-agent state (MCP’s per-agent connect tool, for example) gets installed fresh on the sub-agent.
225 226 227 228 |
# File 'lib/pikuri/agent/configurator.rb', line 225 def inherit_extensions(extensions) extensions.each { |ext| @extensions << ext } nil end |
#on_close { ... } ⇒ void
This method returns an undefined value.
Register a handler called by Pikuri::Agent#close. Handlers fire in LIFO order, each inside its own rescue — same semantics as ensure-block cleanup discipline.
236 237 238 239 240 241 |
# File 'lib/pikuri/agent/configurator.rb', line 236 def on_close(&blk) raise ArgumentError, 'on_close requires a block' unless block_given? @on_close_handlers << blk nil end |