Skip to main content
ChatCLI implements a comprehensive tool result management system that ensures integrity, controls context size, and progressively compacts old results. This is essential for long agent sessions where dozens of tool calls can saturate the context window.

Tool Result Pairing

Every tool_use (a tool call made by the model) must have a corresponding tool_result in the conversation history. When this pairing breaks — due to interruption, timeout, or silent error — the API rejects the history. The EnsureToolResultPairing system automatically validates and repairs:
ProblemRepair Action
tool_use without tool_result (orphan)Injects synthetic error result
tool_result without tool_use (orphan)Removes from history
Duplicate tool_use IDsKeeps only the first occurrence

Synthetic Results

When a tool_use has no corresponding result, ChatCLI injects:
[Tool result missing -- the tool execution was interrupted or failed silently.
Do NOT retry this tool call. Analyze what went wrong and try a different approach.]
The message instructs the model to not repeat the failed tool call, preventing infinite retry loops.

3-Phase Validation

1

ID Collection

Traverses the entire history collecting tool_use IDs (from assistant messages) and tool_result IDs (from tool messages).
2

Misalignment Detection

Compares the two sets of IDs. Tool uses without a result are ā€œmissingā€. Tool results without a use are ā€œorphansā€. Duplicate IDs are flagged for deduplication.
3

History Reconstruction

Rebuilds the history: removes orphans, deduplicates tool_use IDs, and injects synthetic results after assistant messages with unmatched tool_uses.

Result Budget Enforcement

Tool results such as large file reads or command output can quickly consume the context window. The budget system limits the aggregate size at three levels:
LevelLimitVariable / OverrideDefault
Per-tool (new)Cap applied inside the dispatch before aggregationTruncationAware.MaxResultChars() capability per plugin30,000 chars (global)
Per resultMaximum size of a single resultCHATCLI_TOOL_RESULT_MAX_CHARS20,000 chars
Per turnAggregate size of all results in the turnCHATCLI_TOOL_RESULT_BUDGET_CHARS200,000 chars

Per-tool truncation (capability)

Plugins that implement plugins.TruncationAware declare their own cap — useful when the tool has non-default context needs:
PluginCapRationale
@read80,000Large files (~1500 lines) are the primary code-learning surface; a low cap blinds the model
@search60,000Breadth-oriented structured output (file:line:match) — the model needs reach
@tree50,000Monorepo listings easily exceed 30k
Other plugins30,000Global default
Truncation preserves the historical head/tail shape (5000-char preview + 1000-char suffix + [TRUNCATED N chars omitted, M kept] marker).

How Enforcement Works

The budget is applied in two passes:
Each individual result is checked against DefaultPerResultMaxChars (20KB). If it exceeds the limit, the full content is saved to disk and replaced with a preview:
[first 4,000 chars of the result]

... [85,432 chars omitted -- full output saved to /tmp/chatcli-tool-results/budget_tc_1_0.txt]

[last 1,000 chars of the result]

Disk Persistence

Truncated results are saved as temporary files inside the Session Workspace, instead of the legacy global /tmp/chatcli-tool-results/:
$TMPDIR/chatcli-agent-<random>/tool-results/
  budget_tc_1_0_1.txt    # Full result from tool call 1
  budget_tc_2_3_2.txt    # Full result from tool call 2
  result_read_3.txt      # Secondary storage (workers package)
Moving to a per-session directory has two important effects:
  1. Isolation between sessions. Multiple chatcli instances running in parallel on the same host no longer share the overflow pool.
  2. On-demand reads by the agent. The scratch dir is on the agent’s read allowlist, so when the model encounters the [full output saved to ...] marker in the preview, it can open the file with read_file:
<tool_call name="@coder" args='{"cmd":"read","args":{"file":"/tmp/chatcli-agent-Xy7K3a/tool-results/budget_tc_3_1.txt","start":1200,"end":1500}}' />
Before this release, the path was a dead end — the read tool blocked it because it was outside the workspace boundary. The budget ā€œsaved the outputā€ but the agent had no way to access it.
Files are automatically cleaned up when the session ends (ChatCLI.cleanup), respecting CHATCLI_AGENT_KEEP_TMPDIR=true for debugging. A periodic global cleanup is no longer required.

Preview: Head + Tail

The preview retains the beginning and end of the result to maximize usefulness:
ComponentSize
Head (beginning)4,000 chars (cuts at the last line break)
ReferenceFile path on disk
Tail (end)1,000 chars (cuts at the first line break)

Progressive Microcompaction

Microcompaction progressively reduces the size of old tool results as the conversation advances, without losing critical information:
Result AgeActionDetails
Current and previous turnNo changeResults preserved in full
2+ turns agoTruncatedHead (2,000 chars) + tail (500 chars)
4+ turns agoSummarizedOne-line description: [Old tool result cleared -- 450 lines, 28K chars, Go source]

Content Type Detection

The summary automatically identifies the content type for context:
ContentDetected Type
Starts with { or [JSON
Contains package Go source
Contains def Python source
Contains function JavaScript source
Starts with diff or ---diff
Starts with commit git log
Othertext

Microcompaction Configuration

VariableDescriptionDefault
CHATCLI_MICROCOMPACT_TRUNCATE_TURNSTurns before truncating2
CHATCLI_MICROCOMPACT_SUMMARIZE_TURNSTurns before summarizing4
Only results larger than 3,000 chars are compacted. Small results are always preserved. Results from write and execution tools are preserved as they contain critical error information.

Complete Flow

Tool result management is applied in this order during the agent loop:
1. Tool executes and returns result
2. EnsureToolResultPairing -> fixes misalignments
3. EnforceToolResultBudget -> truncates large results
4. ApplyMicrocompact -> compacts old results
5. Clean history sent to the API

Complete Configuration

Environment VariableDescriptionDefault
CHATCLI_TOOL_RESULT_BUDGET_CHARSAggregate budget per turn200,000
CHATCLI_TOOL_RESULT_MAX_CHARSMaximum size per result20,000
CHATCLI_MICROCOMPACT_TRUNCATE_TURNSTurns before truncation starts2
CHATCLI_MICROCOMPACT_SUMMARIZE_TURNSTurns before summarization starts4

Next Steps

Session Workspace

Where overflow files live and how the agent reads them.

Subagent Delegation

Complementary strategy to avoid saturating context with raw data.

Context Recovery

What happens when even with budgeting the context overflows.

Cost Tracking

Monitor token consumption including tool results.