Skip to main content

Lifecycle

Lifecycle executes one request through a single-pass phase sequence:

resolve → prepare → generate → finalize

Phase contracts

  • resolve: pick model and policy
  • prepare: build base agent input, tools, session context, and policy state
  • generate: run model + tool loop; effects (format, lint) apply per-tool-result via callback; the model may emit a lifecycle signal (done, no_op, blocked) alongside its final text
  • finalize: accept lifecycle signal, emit final response and summary events; a blocked signal maps to ChatResponseState = "awaiting-input"

Single-pass execution

One generation pass runs, effects apply inline during tool execution, and the lifecycle completes. There is no regeneration loop, no feedback injection, and no retry logic at the lifecycle level.

Effects

  • effects are lifecycle-owned side effects applied per-tool-result via the onToolResult callback on the session
  • the lifecycle configures the callback during context creation; tool execution calls it after each successful tool
  • format runs silently; lint errors are appended to the tool result so the model can see and act on them
  • current effects are driven by detected workspace commands (format, lint)

Step budget

  • checkStepBudget() is inlined into tool execution and enforces per-cycle and total tool-call limits
  • when the budget is exhausted, the tool call is blocked with a budgetExhausted error code
  • this is the only pre-tool policy check; there is no guard abstraction

Run control

  • RunControl is a first-class abstraction that owns yield and cancellation behavior for a lifecycle run
  • created at the transport layer (e.g. RPC) where queue and abort state are known, and threaded into the lifecycle as a single object
  • shouldYield() is checked after generation completes and before accepting the result; yielding skips result acceptance and memory commit
  • isCancelled() is checked at event emission boundaries and in error handlers
  • both methods are polled (not event-driven) — the answer can change over time as external state evolves

Memory integration point

  • memory injection happens during request setup before generation
  • memory commit is scheduled as best-effort background work at finalize
  • commit failures are logged via lifecycle debug events and do not fail the user response

Key files