Problem
HistoryCompactSummaryInput carries an inputBudget so a compactor can avoid dispatching a request that is already estimated to exceed the selected model's capacity. The provider-native Codex compactor consumes that budget, but buildLlmHistorySummarizer() currently ignores it and materializes every newly folded RuntimeEvent into the generateText() request unchanged.
A large historical Tool Result can therefore make the text-summarization request itself exceed the context window before the model has a chance to summarize it. The resulting provider failure safely fails open, but it spends a request on a projection Runtime already estimated cannot fit and reports a generic provider failure instead of the precise local cause.
This text-summarizer behavior predates #2993. PR #2993 exposes the common input-budget contract while adding Codex provider-native compaction, but changing the existing text path is not part of that PR and should not block it.
Desired behavior
Make the text history summarizer honor HistoryCompactSummaryInput.inputBudget before provider dispatch.
The solution should:
- keep the RuntimeEvent ledger unchanged;
- preserve complete Tool Call / Tool Result pairing in the summarizer projection;
- preferentially bound or omit older Tool Result payloads while retaining later grounded conversation context;
- preserve rolling-summary behavior (
previousCheckpoint plus newly folded events);
- throw the typed
input_too_large summarizer failure before dispatch when the remaining non-tool projection still cannot fit;
- continue using the existing fail-open and diagnostic paths.
The implementation may share deterministic request-fitting logic with provider-native compaction if that reduces total complexity, but this issue does not require a new provider registry or compactor framework.
Non-goals
- Changing which compactor is selected for Codex subscription connections.
- Adding native-to-text fallback behavior.
- Making checkpoint formats interchangeable.
- Claiming tokenizer-exact capacity measurement; the existing context-budget estimate remains the policy input.
Acceptance criteria
- An oversized text-summarizer Tool Result is bounded before
generateText() without producing an orphan call or result.
- A projection that still exceeds
inputBudget after eligible Tool Result omission fails locally with input_too_large and does not dispatch.
- Ordinary and rolling text compaction remain behaviorally unchanged when the projection already fits.
- Tests verify the deterministic outgoing projection and failure boundary rather than treating a mocked provider response as proof that the request fits.
Problem
HistoryCompactSummaryInputcarries aninputBudgetso a compactor can avoid dispatching a request that is already estimated to exceed the selected model's capacity. The provider-native Codex compactor consumes that budget, butbuildLlmHistorySummarizer()currently ignores it and materializes every newly folded RuntimeEvent into thegenerateText()request unchanged.A large historical Tool Result can therefore make the text-summarization request itself exceed the context window before the model has a chance to summarize it. The resulting provider failure safely fails open, but it spends a request on a projection Runtime already estimated cannot fit and reports a generic provider failure instead of the precise local cause.
This text-summarizer behavior predates #2993. PR #2993 exposes the common input-budget contract while adding Codex provider-native compaction, but changing the existing text path is not part of that PR and should not block it.
Desired behavior
Make the text history summarizer honor
HistoryCompactSummaryInput.inputBudgetbefore provider dispatch.The solution should:
previousCheckpointplus newly folded events);input_too_largesummarizer failure before dispatch when the remaining non-tool projection still cannot fit;The implementation may share deterministic request-fitting logic with provider-native compaction if that reduces total complexity, but this issue does not require a new provider registry or compactor framework.
Non-goals
Acceptance criteria
generateText()without producing an orphan call or result.inputBudgetafter eligible Tool Result omission fails locally withinput_too_largeand does not dispatch.