cyberine
UsageRun recipes

History compaction spills oversized tool results instead of truncating to 80 chars

For a worker with historyCompression: true on its WorkerProfile (see src/core/workerProfiles.ts), once accumulated message history exceeds historyCompressionBudget (default 8000 tokens, CYBERINE_HISTORY_COMPRESSION_BUDGET), TruncationHistoryCompressor (src/core/historyCompression.ts) now tries a cheaper fix FIRST, before dropping any turn of the conversation: any tool-result message estimated at 200+ tokens is spilled to disk (the same store TOOL-RESULT-SPILL / spill_retrieve uses) and replaced in place with a short locator note. The whole history is re-measured afterward — a worker whose bulk is tool-output bytes often fits again without losing a single round, just the raw bytes of what a tool printed; you will see [history compaction: N tool result(s) spilled to disk, no messages dropped] in the worker's output stream when this alone was enough.

Only when spilling still is not enough does the existing drop-and-digest path run: the oldest rounds are dropped and replaced by one === COMPRESSED HISTORY === system message ([history compressed: N messages summarized, M tool result(s) spilled to disk]). Two correctness fixes ship alongside the spill behavior: a dropped tool result now shows its spill:// locator in the digest instead of a blind 80-char slice (which used to risk cutting a retrieval path off mid-string), and an assistant's tool-call turn is never dropped separately from its own tool-result turn(s) — they are always kept or dropped together, since a request with one but not the other is invalid for most providers.

Known Limitations and Deferred Work (src/core/historyCompression.ts). This is purely mechanical — no LLM summarization call is made (a separate, costed decision, deliberately out of scope here). The digest text itself is still a plain heuristic summary, not derived from what was actually spilled; a spilled tool result that later gets dropped shows only its locator, not any content preview. There is no cross-round de-duplication — the same underlying file read twice by a worker produces two independent spill files if both are ever compacted. src/tui/contextView.ts mirrors this file's approxTokens/messageTokens heuristic for its own /context report; those two functions are untouched by this change specifically so that mirror stays accurate.