fix(api): disable summarization below a viable context budget

A tiny user-set maxContextTokens re-triggers summarization on every graph
step (the summary allocation rounds to nothing and history still
overflows), burning dozens of LLM calls until the recursion limit aborts
the run with an opaque LangGraph error. Fall back to plain pruning under a
1024-token floor so the run either fits or fails fast with the actionable
empty_messages breakdown.
This commit is contained in:
Marco Beretta 2026-08-06 19:36:41 +02:00
parent 7ae15aa572
commit 6fdf2c8c63
No known key found for this signature in database
GPG key ID: D918033D8E74CC11
2 changed files with 56 additions and 1 deletions

View file

@ -543,6 +543,35 @@ describe('summarizationEnabled resolution', () => {
expect(config.provider).toBe('openAI');
expect(config.model).toBe('gpt-4o');
});
it('false when the effective context budget is below the viable minimum', async () => {
/**
* A tiny user-set maxContextTokens re-triggers summarization on every
* graph step until the recursion limit aborts the run; the guard falls
* back to plain pruning instead.
*/
const agents = await callAndCapture({
agents: [makeAgent({ maxContextTokens: 10 })],
summarizationConfig: {
enabled: true,
provider: 'anthropic',
model: 'claude-3-haiku',
},
});
expect(agents[0].summarizationEnabled).toBe(false);
});
it('true at exactly the 1024-token viable minimum', async () => {
const agents = await callAndCapture({
agents: [makeAgent({ maxContextTokens: 1024 })],
summarizationConfig: {
enabled: true,
provider: 'anthropic',
model: 'claude-3-haiku',
},
});
expect(agents[0].summarizationEnabled).toBe(true);
});
});
// ---------------------------------------------------------------------------

View file

@ -775,6 +775,18 @@ function shapeSummarizationConfig(
};
}
/**
* Below this context budget a summarization cycle cannot make progress: the
* summary allocation rounds down to a handful of tokens, the rewritten history
* still overflows, and the graph re-triggers summarization on every step until
* the recursion limit aborts the run dozens of wasted LLM calls surfaced to
* the user as an opaque LangGraph error. Falling back to plain pruning instead
* either fits the request or fails fast with the actionable `empty_messages`
* token-budget breakdown. Matches the floor `initializeAgent` applies when the
* user supplies no override.
*/
const MIN_SUMMARIZATION_CONTEXT_TOKENS = 1024;
/**
* Applies `reserveRatio` against the pre-ratio base context budget, falling
* back to the pre-computed `maxContextTokens` from initializeAgent.
@ -1629,6 +1641,20 @@ export async function createRun({
agent.maxContextTokens,
);
const summarizationViable =
effectiveMaxContextTokens == null ||
effectiveMaxContextTokens >= MIN_SUMMARIZATION_CONTEXT_TOKENS;
if (summarization.enabled && !summarizationViable) {
logger.warn(
'[createRun] Summarization disabled for this run: context budget below viable minimum',
{
agentId: agent.id,
effectiveMaxContextTokens,
minimum: MIN_SUMMARIZATION_CONTEXT_TOKENS,
},
);
}
const reasoningKey = getReasoningKey(provider, llmConfig, agent.endpoint, agent.reasoningKey);
const agentInput: AgentInputs = {
provider,
@ -1645,7 +1671,7 @@ export async function createRun({
useLegacyContent: agent.useLegacyContent ?? false,
discoveredTools:
!isSubagent && discoveredTools.size > 0 ? Array.from(discoveredTools) : undefined,
summarizationEnabled: summarization.enabled,
summarizationEnabled: summarization.enabled && summarizationViable,
summarizationConfig: summarization.config,
initialSummary: isSubagent ? undefined : initialSummary,
contextPruningConfig: summarization.contextPruning,