Skip to content

Improve 60k limit upon reading - #46

Open
yudistryan wants to merge 5 commits into
mainfrom
improve-60k-limit
Open

yudistryan wants to merge 5 commits into
mainfrom
improve-60k-limit

Conversation

@yudistryan

@yudistryan yudistryan commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Replace hard mid-string truncation at ~60k chars with eager multi-content chunks so agents can reconstruct valid JSON without a continue loop (e.g. Confluence pages).
  • Package execute_tools per results[] item: small siblings stay inline in content[0]; oversized items become stubs (continuationId, resultIndex, partsIncluded) plus following continuation envelopes.
  • Cap stored chunks via MAX_OVERFLOW_PARTS (default 5) and cap eager oversized items per batch via MAX_OVERFLOW_ITEMS (default 2); deferred stubs use continue_tool_result (omit part).
  • Keep continue_tool_result as optional re-fetch (user-bound, 10‑minute TTL, in-memory).

Diff highlights

Area Change
result-overflow.ts Eager packaging, per-item batch stubs, store/reaper, MAX_OVERFLOW_ITEMS
server.ts Multi-content wire + execute_tools batch path
meta-tools.ts Updated execute_tools / continue_tool_result contracts
config / .env.example / docs MAX_OVERFLOW_PARTS, MAX_OVERFLOW_ITEMS
tests Eager parts, ownership, TTL, part/item caps, MCP wiring

Agent contract

  1. On overflow, tools/call returns multiple content[] text blocks (envelopes with chunk).
  2. For execute_tools: read stubs in content[0].results[i]. If partsIncluded: true, concatenate that continuationId's chunks from following blocks in ascending part order, then JSON.parse. If partsIncluded: false, call continue_tool_result (omit part).
  3. Do not concatenate chunks across different items / continuationIds.
  4. continue_tool_result is only for deferred items, discarded parts, or clients that only read content[0].

Test plan

  • npm run test --workspace=@a-workbench/server -- tests/mcp-result-cap.test.ts
  • Manual: execute_tools with one small + one large Confluence page → header stub + eager parts; second large page with MAX_OVERFLOW_ITEMS=1 → deferred stub + continue_tool_result
  • Confirm complete: false when payload exceeds MAX_OVERFLOW_PARTS

Added functionality to handle oversized tool results by splitting them into manageable chunks. Introduced the `MAX_OVERFLOW_PARTS` environment variable to control the maximum number of chunks that can be fetched. Updated the MCP meta-tool to allow fetching subsequent parts using `continue_tool_result`. Documentation and tests have been added to cover the new behavior.
@yudistryan yudistryan self-assigned this Aug 7, 2026
@yudistryan
yudistryan marked this pull request as ready for review August 7, 2026 08:40
@yudistryan
yudistryan requested a review from barockok August 7, 2026 08:40
@barock-amartha

barock-amartha commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

@yudistryan I think the execute_tool need context (in its description) about this tool so it chains and doesn't need skill to chain.
how the execute_tools (prural) will works with this?

@yudistryan

Copy link
Copy Markdown
Collaborator Author
  1. you mean by adding more context so it will check all the read size first and automatically trigger the overflow mas @barockok?
  2. After some thoughts, i think we can use execute_tools to do overflow in parallel. let me figure it out

@burungbangkai

Copy link
Copy Markdown
Collaborator

cool.. another alternative in my mind: mimics how claude code handles it: write it as a file under /tmp, then tell the agent to use tool read_file to read it incrementally. @barockok, wydt should solve it by chunking like the PR or write to file? my alternative has another cons: how to cleans the /tmp directory so that the container did not run out of diskspace.

Return all stored overflow parts in one tools/call so agents can concat without a continue loop; package execute_tools per results[] item with stubs/resultIndex; cap eager oversized items via MAX_OVERFLOW_ITEMS (default 2) and keep continue_tool_result for deferred/re-fetch.
@yudistryan yudistryan changed the title Improve 60k limit upon reading Improve 60k limit upon reading Aug 11, 2026
@yudistryan

Copy link
Copy Markdown
Collaborator Author

guys @barockok @burungbangkai i just updated the PR to add context in execute_tools and now rather than serialize the context, it will do in parallel using execute_tools. Each continuation will be applied per item so it won't mixed up. Let me know if this approach is not really suited

Yudistryan Izhar Kamil added 2 commits August 18, 2026 14:00
MAX_OVERFLOW_PARTS silently scaled the real storage budget with the
per-block wire size, so changing MAX_RESULT_CHARS would shrink or blow up
how much of an oversized payload is retained. Replace it with
MAX_OVERFLOW_TOKENS (default 300000) and promote MAX_RESULT_CHARS to an
env var (default 60000); part count is now the quotient, so operators
retune only one knob.
@barockok

Copy link
Copy Markdown
Collaborator

Two architectural concerns worth revisiting:

1. Statefulness across pods

The continuation store is in-memory (Map per process). If continue_tool_result hits a different pod than the one that stored the parts, the lookup fails silently. Any horizontal scaling (2+ replicas) breaks the deferred-fetch path. The eager multi-content approach sidesteps this for partsIncluded:true cases, but partsIncluded:false stubs still depend on pod affinity.

2. Pagination doesn't escape context growth

The deeper issue with chunking is that paginating through continuation parts eventually loads the entire payload into the agent's context anyway — just spread across turns, with envelope overhead on top. It doesn't reduce context load; it defers it.

Alternative worth considering: overflow URL instead of chunked parts

When a result exceeds the char cap, persist the raw JSON to shared storage (GCS/S3 presigned URL, or a signed workbench endpoint backed by a shared PVC), return a small stub:

{ "_overflow": true, "url": "...", "size_bytes": 4200000, "ttl_seconds": 600 }

The agent curls the URL and filters locally (jq, grep). Only the extracted subset enters context — the full payload never does. The server stays stateless: no reaper, no continuation IDs, no pod affinity requirement. The tradeoff is that the agent must have an HTTP fetch capability, but that's a reasonable assumption for Claude Code and similar clients, and a fetch_url meta-tool could cover the rest.

@yudistryan

Copy link
Copy Markdown
Collaborator Author

Let me answer from second concern first mas @barockok. This capability is basically to let the agent reading all of the documents. Our objective is to ensure no missing context upon reading any documentation. Hence, we wanna allow the agent to read it all. This is QA specific task. To ensure other than QA agent not doing the same, we propose to add some limit as config such as MAX_OVERFLOW_TOKEN and MAX_RESULT_CHARS. So we still have the control of the overflow. That's why there will be some occasions where the agent might need to continue fetching the document after limit is reached.

As the first concern, is it possible to be stored somewhere mas @barockok? Since it won't be good to put it into in-memory but unable to store it into PVC.

@barockok

barockok commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

@yudistryan I don do completely aware on the goal. I think the PVC is fine.

@yudistryan

Copy link
Copy Markdown
Collaborator Author

@barockok basically, we just wanna read a whole document without any truncation mas. Let me update it so it'll store it into the PVC

@barockok

barockok commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

sorry was type @yudistryan

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.

4 participants