Module: Pikuri::Agent::Extension

Defined in:
lib/pikuri/agent/extension.rb

Overview

The Extension protocol — how hosts bolt extra capabilities (system-prompt snippets, tools, lifecycle hooks) onto an Pikuri::Agent. Extensions are added via Configurator#add_extension inside the Agent.new block; the Agent then drives three hooks on each — #configure during the block, #bind once the agent is fully constructed, and #on_user_message on every user turn thereafter.

Each phase receives that phase’s context object: configure gets the build-time Configurator; bind and on_user_message get the runtime ExtensionContext — the capability facade for everything that acts on the live agent (domain-event emission, raw tool registration, sub-agent listener derivation), with the agent itself readable via Pikuri::Agent::ExtensionContext#agent.

Mix this module into an extension class to inherit empty default implementations of all three hooks; override the ones you need. Extensions that don’t include this module still work *if they define all three methods themselves* — the Agent and Configurator call them by name with no respond_to? guard, so a missing one raises. The module exists to make the protocol explicit and to give “I want to implement just configure” extensions free no-op bind / on_user_message defaults (and any other combination).

Example

class MyExtension
  include Pikuri::Agent::Extension

  def configure(c)
    c.append_system_prompt("Always be polite.")
  end

  # bind not overridden — inherits the empty default
end

See Pikuri::Mcp::Extension and Pikuri::Skill::Extension (once those land in Steps 2-3 of the gem-split refactor — see IDEAS.md §“Extension protocol design”) for the canonical worked implementations.

Instance Method Summary collapse

Instance Method Details

#bind(ctx) ⇒ void

This method returns an undefined value.

Called by Pikuri::Agent#initialize after the block returns and the chat is fully wired, with the agent’s Pikuri::Agent::ExtensionContext as the argument. Fires once per agent the extension was registered to via Configurator#add_extension — in the typical setup that’s the parent agent only, since sub-agents do not inherit extensions. The default is a no-op; override when you need to install state keyed to the live agent. Things you typically do here:

Parameters:



93
# File 'lib/pikuri/agent/extension.rb', line 93

def bind(ctx); end

#configure(c) ⇒ void

This method returns an undefined value.

Called immediately by Configurator#add_extension during the Agent.new block, with the parent agent’s Configurator. Runs exactly once per extension instance, on the parent agent only — sub-agents do not re-run configure. The default is a no-op; override when you need to install agent-agnostic state. Things you typically do here:

Parameters:



67
# File 'lib/pikuri/agent/extension.rb', line 67

def configure(c); end

#on_user_message(ctx, content) ⇒ String?

Optional per-turn hook fired by the Pikuri::Agent after a user-message is added to the chat. The default is a no-op returning nil; override and return String to emit a ‘:system` message with that text.

Append-only, never mutate

The Agent only ever appends the returned block at the tail; it never rewrites or removes an earlier one. Mutating mid-log would bust the provider prefix cache for every message after the edit. Stale blocks ride the existing context-window machinery, not a per-turn rewrite.

Not inherited by sub-agents

Like the rest of the extension surface, this fires on the parent agent only — sub-agents do not inherit extensions, so a persona’s turns are never prefetched or recorded by the parent’s memory.

Parameters:

  • ctx (ExtensionContext)

    capability facade for the live agent whose turn this is — same instance bind received

  • content (String)

    the user message (initial or interloper) about to be sent to the model

Returns:

  • (String, nil)

    an optional block of text to be injected verbatim as a system-role message (after the user message), or nil to inject nothing



119
# File 'lib/pikuri/agent/extension.rb', line 119

def on_user_message(ctx, content); end