Skip to content

09. Response Items And Runtime Spine ​

This chapter explains how the agent loop moves from frontend teaching steps to real model-visible history. AgentResponseItem becomes the core data structure of the runtime spine.

After reading this chapter, you should understand:

  • why response items are more fundamental than UI steps
  • how the runtime spine organizes model -> tool -> model cycles
  • why the scheduler is a separate module
  • how assistant runtime roles distinguish working text from final output

Background ​

The early agent had steps and logs, but it still lacked a precise model-visible history.

A real tool loop needs the model to see:

text
assistant requested tool
tool returned output
assistant continues from that output

UI steps are not enough for that. The runtime needs history items.

AgentResponseItem ​

The key file is:

text
lib/agent-response-items.ts

The core union is:

ts
type AgentResponseItem =
  | { type: 'message'; role: 'system' | 'user' | 'assistant'; content: string }
  | { type: 'function_call'; callId: string; name: string; argumentsJson: string }
  | { type: 'function_call_output'; callId: string; toolName: string; output: string; isError: boolean };

This is the teaching-simplified version: the real message branch also carries optional providerPhase and runtimeRole fields, introduced in later chapters. The full shape lives in lib/agent-response-items.ts.

This is the model-visible history, independent of frontend display.

Runtime Spine ​

The fixed teaching flow was replaced by:

text
initialize history
call model with history and tools
commit assistant message / function calls
execute tool batch
append function_call_output
repeat until no tool calls

The main file is:

text
lib/agent.ts

Scheduler ​

The scheduler lives in:

text
lib/agent-tool-scheduler.ts

It chooses:

text
all tools parallel-capable -> Promise.all
otherwise                 -> sequential

It does not infer data dependencies. If the model needs tool B to depend on tool A, it should request B in a later sampling round after A's output is in history.

Assistant Runtime Roles ​

Assistant messages can become:

text
working_message
final_response

This is an agent-level classification. It is not the same as provider phase metadata.

Git Evidence ​

Relevant commit:

text
e6ff55e Add agent runtime spine

Why This Was A Turning Point ​

This phase made the system feel like an agent runtime rather than a service with a tool call. The source of truth moved from display steps to model-visible history.

Common Misunderstandings ​

Misunderstanding 1: UI Steps Can Be Model History ​

UI steps are presentation objects. Model history is protocol state. They have different jobs and should not be mixed.

Misunderstanding 2: The Runtime Spine Is The Entire Agent Run ​

The runtime spine is the loop skeleton. A full run also includes input parsing, events, sessions, cancellation, debug, and final response assembly.

Misunderstanding 3: Assistant Text Does Not Need Roles ​

The same assistant text can be a working message before tools or a final response when no tools are requested. Runtime roles let UI and debug surfaces express that difference.

Chapter Summary ​

This chapter moves the agent from step-driven to history-driven: model-visible response items become the source of truth, the scheduler controls tool batches, and the runtime spine connects model calls with tool execution.

Chapter Checkpoint ​

Verify that the shape of model-visible history is locked down by deterministic tests (no key, fake gateway):

bash
npx tsx --test --test-name-pattern "records" tests/agent-sampling-loop.test.ts

Measured output:

text
✔ records working message, function call, tool output, and final response
✔ records built-in read tool output through the sampling loop
ℹ pass 2

The first case asserts the full runtime-spine cycle item by item: assistant working message, function_call, function_call_output, and final response each land in history in order. The second proves that the real built-in read tool's output also lands in function_call_output. Open tests/agent-sampling-loop.test.ts next to those assertions — they are the executable version of this chapter's history contract.