Skip to content

Tool Result Offloading - #115

Merged
berges99 merged 3 commits into
mainfrom
feat/tool-result-offload
Aug 6, 2026
Merged

Tool Result Offloading#115
berges99 merged 3 commits into
mainfrom
feat/tool-result-offload

Conversation

@berges99

@berges99 berges99 commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

…ime — lossless spill + paged read-back

Large tool results dominate agent context. New tool_result_offload module reduces a
result once, the moment it is produced — before it enters memory, the dump, or any
provider request — so history stays append-only (prompt-cache friendly) and the
reduction persists into traces.

- ToolResultLimit(threshold, action): Spill (default — persist payload, keep preview +
  handle + JSON shape sketch inline) or Truncate (head/tail/head_tail clamp). Spill
  degrades to a bounded truncation when no store is reachable.
- Configure globally via Agent(tool_result_limit=...) or per tool via
  Tool(result_limit=...); int shorthand supported, None exempts. Pinned tools, error
  results, and read_tool_result's own output are always exempt.
- LocalOffloadStore: relative-key handles, 0700 root, traversal/symlink-safe reads,
  never-clobber writes, keep-forever with opt-in TTL pruning.
- read_tool_result asters when a store exists: line-numbered paging with hard
  caps (500 lines / 50k chars) and literal-substring filtering.

summarize() hardening (the loudest compaction complaints across harnesses): user
messages carried verbatim across incremental passes (never paraphrased), canonical
record of every summarized region written to the store and readable back, conservative
continuation note instead of "continue without asking", grounding rules in the
summarizer prompts, and a rehydrate= hook re-run on every pass.

compact_tool_results() treats offloaded placeholders as already compacted (opt out with
keep_offloaded=False); replacement templates gain {handle}.
@cursor

cursor Bot commented Aug 6, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes the agent tool-result path, trace serialization, and compaction semantics; mishandling could drop or mis-point handles, though behavior is heavily tested and store paths are sanitized.

Overview
Introduces production-time tool result offloading so oversized tool outputs are shrunk once when they are created (before memory, dumps, and LLM requests), keeping history append-only and prompt-cache friendly.

Agents gain tool_result_limit (int shorthand or ToolResultLimit with Spill / Truncate); tools can override via Tool(result_limit=...). Spill writes the full payload to LocalOffloadStore, leaves a preview + handle on ToolResultContent.offload_handle, records metadata on the span, and auto-registers read_tool_result for bounded paging. Errors, pinned results, and the read tool itself stay exempt; spill failures fall back to truncate.

Memory compaction is aligned with offloading: compact_tool_results defaults to keep_offloaded=True (and {handle} in replacement templates), and summarize now emits structured sections—verbatim user messages, offload-backed canonical transcripts, conservative continuation notes, and optional rehydrate—with incremental summarization fed only the LLM summary slice. The agent shares its offload store with summarize for canonical records and read_tool_result when needed.

Public exports, message deserialization for offload_handle, and extensive tests cover agent/command/approval paths, store safety, and compaction edge cases. CLAUDE.md documents the two-layer context bounding model.

Reviewed by Cursor Bugbot for commit 8b02e15. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ae1feb0. Configure here.

Comment thread python/timbal/core/memory_compaction.py Outdated
…ctured field

A compact_tool_results(replacement=...) rewrite can strip the read_tool_result
pointer from a spilled result's placeholder prose while the structured
offload_handle field survives. _format_message_for_transcript now emits the
handle from the field, so the summary's canonical record always resolves back
to the full payload regardless of placeholder mutations. Regression test pins
the broken-chain scenario.

Also fixes test_int_shorthand on Windows: Path.home() ignores $HOME there
(USERPROFILE wins), so patch the method instead of the env var.
….md; polish test portability

- CLAUDE.md: new section covering ToolResultLimit (Spill/Truncate, per-tool
  precedence, exemptions), the auto-registered read_tool_result tool, and the
  sectioned summarize() output (verbatim user messages, canonical record,
  rehydrate hook).
- read_tool_result: add schema description for the handle param so the model
  knows where handles come from.
- Symlink-escape test skips on platforms where symlink creation needs
  elevated privileges (unprivileged Windows) instead of erroring.
@berges99
berges99 merged commit 2473c74 into main Aug 6, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants