Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Result Summarization

Large tool outputs are stored on disk as recallable artifacts and replaced in the context window with a short stub. When summarization is enabled, the stub’s body is produced by a cheap “summary” model instead of blunt truncation.

Implementation: crates/core/src/tools/summarize.rs (classification, prompts, request formatting, stubs, fallback truncation) integrated through harness.rs (handle_command_result) and handlers.rs (handle_summarization_response).

Threshold

A tool output is summarized when its length exceeds summarize_threshold, configurable via the summarize_threshold KDL key and defaulting to DEFAULT_SUMMARIZE_THRESHOLD = 12000 characters. Input sent to the summary model is capped at MAX_SUMMARIZABLE_LENGTH = 50000 characters. Summarization can be disabled with summarize_enabled = false.

Summary models

The summary model’s provider is taken from the summary_model config (or a summary_provider override) and resolved through the shared key chain. Default model per provider:

ProviderDefault model
Anthropicclaude-sonnet-4-20250514
OpenAIgpt-4.1
OpenRouteropenai/gpt-4.1
Ollamamistral:7b

Requests use temperature: 0.3 and max_tokens: 2048 (or the provider-appropriate completion-tokens parameter for OpenAI-compatible APIs).

Output classification

The tool name determines an output type, which selects a type-specific prompt and fallback head/tail ratio (ToolOutputType::from_tool_name):

TypeTool namesHead ratio
FileContentread, cat, __HASHLINE_READ__0.7
SearchResultsgrep, rg, search, ast-grep0.5
DirectoryListingls, find, fd, glob0.3
CommandOutputbash, sh (and any unknown tool)0.6
StructuredDatanix-search, gh0.5
WebContentweb-search, web-fetch0.5

Each type has its own prompt: command output preserves errors and exit codes verbatim, search results are grouped by file with line numbers, directory listings are grouped by kind, structured data extracts names and versions, and web content extracts main facts and quotes.

Code-file handling

For FileContent, SummarizationRequest::code_file splits the file into three parts: a before-section and after-section (summarized) around a relevant range that is reproduced exactly with hashlines. When no range is supplied the relevant range defaults to the middle third of the file. The prompt instructs the model to keep the surrounding summaries to one or two sentences and preserve the hashline section verbatim.

Pipeline

  1. A tool result arrives in handle_command_result. The full output is logged to the session’s messages.jsonl exactly once, regardless of what enters context.
  2. If the output exceeds the threshold and the session is ready, it is stored as a disk artifact and kept in memory for UI expansion.
  3. If summarization is enabled, a PendingSummary is queued, the request is dispatched to the summary model, and set_summarizing(true) gates user input until the response returns.
  4. In handle_summarization_response, the lock is cleared, the provider-specific response is parsed, and the summary is wrapped in an artifact stub. On a parse failure or non-200 status, fallback_truncate is used instead.

If summarization is disabled, step 3 is skipped and the artifact stub is built directly from fallback_truncate.

Artifact stubs and recall

format_artifact_stub wraps the summary with a header and a footer noting that the full output is stored:

[Artifact <call_id> | <tool> | <bytes> bytes, <lines> lines]
<summary>
[Full output stored — use recall_artifact("<call_id>") to search or read more]

The agent retrieves the full output on demand through the recall_artifact builtin tool (wire name __RECALL_ARTIFACT__), which reads or searches the stored artifact by call_id.

Fallback truncation

fallback_truncate splits at line boundaries using the type’s head/tail ratio, operates on character counts to stay UTF-8 safe, and inserts a [...N chars omitted...] marker between the kept head and tail. It is used whenever the summary model is disabled, unreachable, or returns an unparseable response.