Repository navigation
[Bug] Compaction loop: summary system messages are never compacted and can keep the session above the threshold #383
Description
Summary
After the image-payload fix in #381, compaction can enter a self-sustaining loop: each successful compaction appends a new summary system message, but existing summaries are skipped by the next compaction because startIndex is the first non-system message. The main request keeps including all summaries, so activeTokens can remain above autoCompactWindow, and the agent loop compacts again on the next iteration.
This is distinct from the original HTTP 400 in #378 / #382. #381 fixes that failure; this issue tracks the loop it can expose.
Observed behavior
@vegamo/deepcode-cli0.4.3 with the fix(core): omit inline image data from compaction prompt #381 change applied locally.- The affected session reached 139 summary system messages, 1,246,916 characters total.
- A new summary was generated roughly every 30–60 seconds.
- Later summaries were degenerate ("transcript truncated", "no user turns"), consistent with compacting only a tiny tail plus prior summaries.
- The session stayed above the threshold at roughly 277K active tokens, so compaction re-triggered. There was no
contextWindoworautoCompactWindowoverride in the user settings; the CLI resolved a window below that value for this session.
Why it loops
Relevant code in packages/core/src/session.ts:
const sessionMessages = this.listSessionMessages(sessionId).filter((message) => !message.compacted);
const startIndex = sessionMessages.findIndex((message) => message.role !== "system");
// ...
const compactPrompt = getCompactPrompt(sessionMessages.slice(startIndex, endIndex));
// ...
sessionMessages.splice(endIndex, 0, summaryMessage);- Accumulated summaries are
role: "system"withmeta.isSummary. startIndexskips every system message, so a summary inserted before the first remaining non-system message is never included in a later summary prompt and never markedcompacted.- The main request still sends all of those summaries.
- If their combined size plus the tail stays above the window, the next agent-loop iteration calls
compactSession()again. - Each call appends another summary, so the summary total can grow faster than the tail shrinks. Once the summaries alone exceed the threshold, the loop is self-sustaining.
The trigger is at session.ts:1774:
if (session.activeTokens > compactPromptTokenThreshold) {
// ...
await this.compactSession(sessionId, sessionController.signal);
}Minimal reproduction
- Create a session with a small non-system tail and enough
meta.isSummarysystem messages that the active prompt is aboveautoCompactWindow. - Set
activeTokensabove the threshold, or let a real request set it. - Run the agent loop or call
compactSession()repeatedly. - Observe a new summary appended each time and
activeTokensremaining above the threshold.
A real-world trigger is a session that previously failed compaction because of inline images (#378 / #382). After #381, the first compaction succeeds; if the prompt is still above the window, the loop starts.
Suggested guards
- After a compaction, do not compact again in the same turn unless the main request's
activeTokensactually dropped; or cap compaction attempts per turn. - Treat summary system messages as compactable: include them in the compaction slice or merge them into the new summary instead of leaving them permanently at the front.
- Collapse existing summaries into one before appending a new one.
- Skip compaction when the slice contains no new non-system messages (only summaries and/or a tiny tail).
- Optionally cap the number or total size of summary messages.
Workaround
A local data repair can collapse the summaries and reset activeTokens, but that is not a product fix and most users will not know to do it.
Related
- fix(core): omit inline image data from compaction prompt #381 — omit inline image data from the compaction prompt
- [Bug] 自动压缩请求把图片 base64 当纯文本序列化,压缩自身超 1M token 后会话永久卡死(v0.4.3) #378, [Bug] Conversation compacting is crashing in v0.4.3 due to faulty image data summarization during compacting #382 — original HTTP 400 caused by base64 image payloads in the compaction prompt
Activity