3.9 Reactive Compression
When a Prompt-Too-Long (PTL) error occurs, reactive compression triggers as the last resort:
// src/query.ts — Second phase of PTL recovery
// reactiveCompact is a feature('REACTIVE_COMPACT')-gated require;
// its implementation lives in services/compact/reactiveCompact.ts (absent from this source snapshot)
if ((isWithheld413 || isWithheldMedia) && reactiveCompact) {
const compacted = await reactiveCompact.tryReactiveCompact({
hasAttempted: hasAttemptedReactiveCompact,
querySource,
aborted: toolUseContext.abortController.signal.aborted,
messages: messagesForQuery,
cacheSafeParams: {
systemPrompt, userContext, systemContext,
toolUseContext, forkContextMessages: messagesForQuery,
},
})
if (compacted) {
// Build post-compression messages, continue the loop
state.transition = { reason: 'reactive_compact_retry' }
}
}During normal operation, autocompact should proactively trigger when context utilization reaches the threshold (approximately 83%~90% of total window, depending on the model's reservedTokensForSummary), preventing PTL errors from occurring. Reactive compression is only needed in the following situations:
- Autocompact is disabled or skipped
- A single tool result is unusually large, jumping past the autocompact threshold in one step
- Context Collapse drainage didn't free enough tokens
Design Decision: How are compression thresholds determined?
The auto-compression trigger formula is
tokens >= effectiveContextWindow - AUTOCOMPACT_BUFFER_TOKENS, whereAUTOCOMPACT_BUFFER_TOKENS = 13,000(src/services/compact/autoCompact.ts).effectiveContextWindowitself =contextWindow - Math.min(getMaxOutputTokensForModel(model), 20_000), i.e., it deducts the output reservation for compression summaries (MAX_OUTPUT_TOKENS_FOR_SUMMARY = 20,000, based on p99.99 compression summary output of 17,387 tokens). For a 200K context window, the threshold is approximately 92.8% relative to effectiveWindow (167K/180K), and approximately 83.5%~89.5% relative to total window (depending on whetherreservedTokensForSummaryis 20K or 8K). The 13K buffer ensures there's still enough space to complete the current tool execution and generate the summary when compression triggers. Related to this isWARNING_THRESHOLD_BUFFER_TOKENS = 20,000— the warning threshold = autocompact threshold − 20,000, i.e. warnings start appearing to the user 20K tokens before auto-compression triggers (when autocompact is disabled, it's 20K beloweffectiveWindowinstead).
Design Decision: Why does max_output_tokens default to only 8K instead of 32K?
CAPPED_DEFAULT_MAX_TOKENS = 8,000(src/utils/context.ts). The source code comment explains the reason: "BQ p99 output = 4,911 tokens, so 32k/64k defaults over-reserve 8-16× slot capacity." The API server reserves computational resources (slots) based onmax_output_tokens; if every request declares 32K but actually only uses 5K, the server's resource utilization is extremely low. 8K as the default covers 99% of actual needs. When the model is actually truncated due tomax_tokens, the system automatically upgrades toESCALATED_MAX_TOKENS = 64,000and cleanly retries — this is the MOT (Max Output Tokens) recovery mechanism.