Skip to content

feat(handoff): scale transcript budget to the destination context window - #686

Open
playtix-brain wants to merge 1 commit into
Porabuild:masterfrom
playtix-brain:feat/handoff-context-budget
Open

feat(handoff): scale transcript budget to the destination context window#686
playtix-brain wants to merge 1 commit into
Porabuild:masterfrom
playtix-brain:feat/handoff-context-budget

Conversation

@playtix-brain

Copy link
Copy Markdown
Contributor

Handoff transcripts are truncated from the front, so the budget decides which end of the conversation the receiving agent loses. At 50k characters (~12k tokens) it loses the beginning — the goal, the constraints, the decisions — and starts mid-sentence:

Context captured from the Claude Code chat transcript because provider resume and terminal scrollback were unavailable.

Assistant:
s são quase todos trabalho do servidor — o `/health` do RAG faz uma busca de verdade.

That is a real handoff from a 1M-context model handing off to another 1M-context model: 12k tokens kept, everything before it dropped, first word cut in half.

Change

The budget now scales with the destination model's context window and claims a share of it (35%), instead of a fixed constant that predates today's windows:

Destination Before After
200k context 50k chars (~12k tokens) 400k chars (~100k tokens)
1M context 50k chars (~12k tokens) 1.4M chars (~350k tokens)
unknown 50k chars 400k chars

handoffTranscriptBudget(contextSize) parses the provider's own context id ("1m", "200k", plain token counts) and never returns below the 400k default, so an unparsable or tiny value cannot make the handoff worse than it is today. The remaining 65% of the window stays free for the work the receiving agent was handed.

Selection behaviour is unchanged — first user message pinned, conversation before tool activity, gap markers — only the ceiling moved, and selectRows now takes it as a parameter instead of reading a module constant.

Tests: 11 passing. The three budget-filling tests now pass an explicit test budget so they assert selection behaviour rather than tracking whatever the default happens to be; three new cases cover scaling, the fallback, and the floor.

🤖 Generated with Claude Code

Handoff transcripts are truncated from the front, so a 50k-char budget
(~12k tokens) drops the start of the conversation — goal, constraints,
decisions — and hands the next agent a transcript that begins mid-word.

Size the budget from the destination model's context id instead, claiming
35% of it and never going below the previous-generation default of 400k
chars. A 1M-context handoff now carries ~350k tokens instead of ~12k.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@SDSLeon SDSLeon left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Deep review (findings-only, PR tests verified 11/11 locally). Direction looks right — scaling the ceiling to the destination window instead of a fixed 50k is the correct fix for front-truncation eating the goal/constraints. Details inline.

Scope question to confirm: since gui→gui handoffs now take the thread-transcript route (own thread on switch, thread mention on fork — nothing copied), this PR only affects context-file handoffs: anything involving a terminal, mirrored threads, read_thread disabled, and the mobile path. Is that the intended readership? Related: 35% of the destination window rides the new session's first message for the rest of its run — deliberate trade vs. a smaller share?

* of its session, so it is filled by priority rather than recency alone.
*/
export const MAX_TRANSCRIPT_CONTEXT_CHARS = 50_000;
export /**

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The /** Whole-file budget, roughly 12-15k tokens… */ block above (lines 5–9) documented the deleted MAX_TRANSCRIPT_CONTEXT_CHARS and now contradicts the new comment below it (“Small next to any current context window”). It was orphaned when the constant was removed — suggest deleting lines 5–9.

* of its session, so it is filled by priority rather than recency alone.
*/
export const MAX_TRANSCRIPT_CONTEXT_CHARS = 50_000;
export /**

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit: the leading export on this line now exports HANDOFF_CONTEXT_SHARE — leftover from replacing export const MAX_TRANSCRIPT_CONTEXT_CHARS. Only handoffTranscriptBudget needs to be public; suggest dropping this export.

const DEFAULT_MAX_TRANSCRIPT_CONTEXT_CHARS = 400_000;

/** `"1m"` / `"200k"` / `"272000"` -> token count, or undefined when unparsable. */
function tokensFromContextSize(contextSize: string | undefined): number | undefined {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit: this reimplements parseContextWindowInput() (src/shared/agents/codexContextWindows.ts) for the same contextSize id format, minus its comma handling and 1k–10M clamps — e.g. "20m" is rejected there but yields a ~28M-char budget here. Suggest reusing the shared parser and keeping the 400k floor on top.

export function buildTranscriptContext(
thread: Thread,
sourceLabel: string,
maxChars: number = DEFAULT_MAX_TRANSCRIPT_CONTEXT_CHARS,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Coupling note: raising this default 50k → 400k silently 8×'s the other caller, src/mobile/useRemoteDesktop.ts:1184, which passes no budget — and mobile inlines the transcript into the prompt with no attachment-file fallback (the buildHandoffLaunchInput inline path), so it is the path most exposed to prompt-size limits. input.targetConfig.contextSize is in scope there; suggest threading handoffTranscriptBudget(...) through it too, or calling out mobile as intentionally default-only.

});
});

describe("handoffTranscriptBudget", () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggestion: nothing tests the PR's core claim — that the dialog forwards the destination's contextSize — and there are no cases for realistic ids ("1M", "272k", "default", "1.05M"). A wiring test plus parametrized ids would lock this (and the parser-parity point on tokensFromContextSize) in.

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