siyuan-note/siyuan · error

agent context cannot be compacted enough: recent messages ex

Error message

agent context cannot be compacted enough: recent messages exceed the input budget

What it means

After walking candidate entry counts to find the largest prefix of old entries that can be compacted while leaving enough room for the compaction summary, selectedCandidateIndex equals len(candidates) — no candidate fits. compactContext returns errContextCannotBeCompacted with "recent messages exceed the input budget": even the most aggressive compaction leaves a too-large remainder, so the summary request would exceed the model context.

Source

Thrown at kernel/agent/agent.go:808

			nativeResponsesCompaction := util.IsOpenAIResponsesProtocol(protocol) &&
				util.SupportsOpenAIResponsesCompaction(ctx)
			// 原生 compact 无法限制输出长度,覆盖所有已完成轮次,避免 opaque window 返回后仍超出预算。
			selectedCandidateIndex := len(candidates) - 1
			if !nativeResponsesCompaction {
				selectedCandidateIndex = sort.Search(len(candidates), func(i int) bool {
					candidate := candidates[i]
					candidateCheckpointMsgs := checkpointMessagesAfterCompaction(sessionEntries, candidate, tail)
					candidateMessages := checkpointMessagesToOpenAIWithSummary(
						candidateCheckpointMsgs, language, capabilities, nil)
					candidateMessages, _ = projectImageMessages(candidateMessages)
					baseTokens := estimateProtocolRequestTokens(model, protocol, candidateMessages,
						candidateCheckpointMsgs, nil, requestTools)
					return compactionSummaryMinTokens <= inputBudget-baseTokens-compactionSummaryOverhead
				})
			}
			if selectedCandidateIndex == len(candidates) {
				return false, fmt.Errorf("%w: recent messages exceed the input budget", errContextCannotBeCompacted)
			}
			selectedEntryCount := candidates[selectedCandidateIndex]
			selectedCheckpointMsgs := checkpointMessagesAfterCompaction(sessionEntries, selectedEntryCount, tail)
			selectedMessages := checkpointMessagesToOpenAIWithSummary(
				selectedCheckpointMsgs, language, capabilities, nil)
			estimatedSelectedMessages, _ := projectImageMessages(selectedMessages)
			baseTokens := estimateProtocolRequestTokens(model, protocol, estimatedSelectedMessages,
				selectedCheckpointMsgs, nil, requestTools)
			summaryMaxTokens := min(
				compactionSummaryMaxTokens, inputBudget-baseTokens-compactionSummaryOverhead)

			sourceMessages := entriesToAgentMessages(sessionEntries[coveredEntryCount:selectedEntryCount])

			sendEvent(ch, AgentEvent{Type: "thinking", Reasoning: "compacting context"})
			var nextCompaction *runtimeCompaction
			var compactionStateErr error
			if nativeResponsesCompaction {
				responseSource := entriesToAgentMessages(sessionEntries[coveredEntryCount:selectedEntryCount])

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Move large tool outputs out of the message history (summarize or truncate them before they enter the tail window)
  2. Use a model with a larger context window or reduce maxCompletionTokens to enlarge the input budget
  3. Start a fresh session; if the tail is genuinely that large, compaction cannot save it
  4. Reduce per-tool-call output limits configured for the agent's tools

Example fix

// before
tool := agent.RegisterTool(readFile, outputLimit: 100000) // results dominate the tail
// after
tool := agent.RegisterTool(readFile, outputLimit: 8000) // cap tool output so the tail fits
Defensive patterns

Strategy: fallback

Validate before calling

tailTokens := estimateProtocolRequestTokens(model, protocol, tailMessages, tailCheckpointMsgs, nil, requestTools)
reserve := compactionSummaryMinTokens + compactionSummaryOverhead
if tailTokens+reserve > contextInputBudget(contextLimit, maxCompletionTokens) {
    return fmt.Errorf("recent messages (~%d tokens) exceed the compactable budget; trim the tail first", tailTokens)
}

Try / catch

if err := agent.Send(ctx, msg); errors.Is(err, errContextCannotBeCompacted) &&
    strings.Contains(err.Error(), "recent messages exceed the input budget") {
    // start a new session or move to a larger-context model; retry is not useful as-is
}

Prevention

When it happens

Trigger: The tail messages that must be kept after compacting all candidates (current turn tail plus remaining checkpoint messages) still exceed inputBudget minus the minimum summary token reserve (compactionSummaryMinTokens + overhead). Happens when the kept recent messages alone are huge.

Common situations: Very large tool results in the recent (uncompactable) window; a small-context model combined with oversized recent turns; repeated huge attachments that keep re-appearing after each compaction.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/fc204b935cb41801. Report an issue: GitHub.