Skip to content

0003 Event-subscriber bridge instead of driving the tool manually

Status

Accepted

Context

AnswerService must inject the citation contract and sources block into the agent's system prompt, and must capture the tool's results — but the agent loop, not the module, owns tool execution (ADR 0001).

Decision

A single-slot AgentRunContext service holds the current run's agent ID, base prompt, sources block, and a tool-results callback. Two subscribers bridge into the agent loop:

  • AnswerSystemPromptSubscriber on BuildSystemPromptEvent, priority 10, appends the citation contract, guidance, and sources block to the agent's own prompt. It never replaces the prompt. Priority 10 is chosen because ai_context's own subscriber runs at priority 0 and must layer on top of this module's additions, not be clobbered by them.
  • AnswerToolResultSubscriber on AgentToolFinishedExecutionEvent filters for the ai_search:rag_search plugin and reads its structured tool output back into the run context.

Hard rule: subscribers append to the system prompt, they never replace it.

Consequences

  • Lesson learned in live testing: the run context must stay alive across lazy stream consumption. Clearing it immediately after solve() returned silently dropped the sources block for round 2, because round 2 only runs while the caller iterates the stream — this is why the stream is consumed inside the same try/finally block that owns AgentRunContext.