Skip to content

fix(agent-runtime): never wipe chat history on compaction - #1167

Closed
nordicnode wants to merge 9050 commits into
CodebuffAI:mainfrom
nordicnode:oss/compaction-wipe-1166
Closed

fix(agent-runtime): never wipe chat history on compaction#1167
nordicnode wants to merge 9050 commits into
CodebuffAI:mainfrom
nordicnode:oss/compaction-wipe-1166

Conversation

@nordicnode

@nordicnode nordicnode commented Aug 31, 2026

Copy link
Copy Markdown

Summary

Two verified paths could replace the model's entire context with nothing (issue #1166, from the "Model losing all chat history instead of compacting" reports):

  • /compact with an empty model response — the replacement summary was built from fullResponse without an emptiness check, and a silent empty stop yields no recovery chunk, so the whole history was replaced by a single message carrying nothing. Now the replacement only happens when the model actually produced a summary; otherwise the history is kept (the forced next step retries) and a warning is logged.
  • Summary identity by content — a user message quoting the summary markers matched isConversationSummary, so findLast picked the quote over the real summary and the real summary was neither re-parsed nor kept: every earlier turn vanished at the next compaction. Summaries are now stamped with a CONVERSATION_SUMMARY tag and recognized by provenance; a legacy fallback requires the full envelope (open+close tag, header, <historical_memory>) so pre-tag summaries still fold in. The context-pruner's inlined copy — which matched the bare tag alone, wiping memory on any message that merely mentioned the tag — gets the same treatment, closing the parity test's second deliberate divergence.

Regression tests for both mechanisms, including the exact steal shape (tag + header quote with no memory block) and the legacy-envelope case. The parity test now asserts BOTH implementations keep a tag-mentioning user message.

Validation

  • bun test packages/agent-runtime/src/__tests__/compact-history.test.ts packages/agent-runtime/src/__tests__/context-pruner-parity.test.ts packages/agent-runtime/src/__tests__/main-prompt.test.ts (55 pass, 7 new/updated)
  • Verified the new /compact test fails without the guard by stashing run-agent-step.ts
  • bun test packages/agent-runtime (only the 2 pre-existing prompts-schema-handling failures and 2 pre-existing agents-graveyard module-not-found errors remain — same on main)
  • bunx tsc --noEmit -p agents/tsconfig.json clean

Fixes #1166

Source: CodebuffAI/freebuff-private@9b8fb92689a45c3d52b65f6d4177bb8b0e4a29db
Source: CodebuffAI/freebuff-private@e20dcb5811c89bc349a283c8fb8b474f03857eaa
Source: CodebuffAI/freebuff-private@1a9bb08ef45331c94cfa616a7e5f91dbc3375e7b
Source: CodebuffAI/freebuff-private@2204d7f013215d4a9746f87ccadb88422bdbf0ce
Source: CodebuffAI/freebuff-private@d85f7624f6df913150afd97028ce8034caf9401c
Source: CodebuffAI/freebuff-private@496a274da0db56d0465478154dbd368ead06dc33
Source: CodebuffAI/freebuff-private@2479764c0c4dc98e75a5c5778d29d10938b5997e
Source: CodebuffAI/freebuff-private@72cb80a710ca0b69c0ea1c92caa09449ae14ae23
Source: CodebuffAI/freebuff-private@00c76d2a5513197c7f5963463a1511ce8a4086d6
Source: CodebuffAI/freebuff-private@ae3b428c053013f6c40d893c785f6f383a1eefb7
Source: CodebuffAI/freebuff-private@1f928dbc1d0b1c4ae199f3b12111897300092931
Source: CodebuffAI/freebuff-private@23d94d0a7272b2c1460bb5576c0359cf0fe2765a
Source: CodebuffAI/freebuff-private@56076c9423fb9d6b185fb66d4ec7d7818c544aa4
Source: CodebuffAI/freebuff-private@7ac0799f05337a0df3eafe682e030544ce191d2f
Source: CodebuffAI/freebuff-private@2464fed8ca7d9730dfa2226e1c4267353c2b1e85
Source: CodebuffAI/freebuff-private@d6c79c09d66c9187499f37445a7f82a93ae674a1
Source: CodebuffAI/freebuff-private@db635212c3c95b5545a46afd2fffa3e0d345dd48
Source: CodebuffAI/freebuff-private@8602eeac5f86c63dcdf7051675bda726cc8e0b71
Source: CodebuffAI/freebuff-private@03bff2f48d6c40320acc1cb41ca389d222ac2baa
Source: CodebuffAI/freebuff-private@54215700121b04bef2a7857489eb2017d24a113f
Source: CodebuffAI/freebuff-private@4f4f9a6cd4e9c7aa793a32fcdc8438ced2a0f5a2
Source: CodebuffAI/freebuff-private@5f1f82c2fb2bcf95a01ffb6fc28ccfc25619a83e
Source: CodebuffAI/freebuff-private@9d8b240c6862ab9c5c720af7a1facbf85a48a877
Source: CodebuffAI/freebuff-private@1b960fe83deb21c87e4cb615d7789123361ac407
Source: CodebuffAI/freebuff-private@e8b8ef0c39f6e5fd0f1da7fe1d2704027dcbfb16
Source: CodebuffAI/freebuff-private@407268a57ca56f64b87013573c29bc72058fff28
Source: CodebuffAI/freebuff-private@a138234f7d9310b8d2a89a7f9e478badc2f1b3f3
Source: CodebuffAI/freebuff-private@f0d724e3249e82a81fe934e51aa36f8d20d211e2
Source: CodebuffAI/freebuff-private@344142df6218b6602860cfc57dad3cca639ab8fd
Source: CodebuffAI/freebuff-private@ff3695d0b8ae4522891b5384a877cef203c89c34
github-actions Bot and others added 26 commits August 31, 2026 02:24
Source: CodebuffAI/freebuff-private@2d04668b529a04c2a90806272993d5f67a1afa1f
Source: CodebuffAI/freebuff-private@2f358ebf68b79b05acb81f18ee42ef4295edee17
Source: CodebuffAI/freebuff-private@e411009a76fbd9f689550bd51bc3b938209ec6f8
Source: CodebuffAI/freebuff-private@70a710b1d0941b7bd3a742dbc8e18f276b602850
Source: CodebuffAI/freebuff-private@3535770948dfde40d9b53936ad8487a3dbb90893
Source: CodebuffAI/freebuff-private@bba508a9f359d5e49230c932ef03fdb733c18bff
Source: CodebuffAI/freebuff-private@741dcfc4f0fc1e7c33d4544fc5ce7259e851c920
Source: CodebuffAI/freebuff-private@d9a3b75bd429ea44aca483addec9b5a3e3bcc79e
Source: CodebuffAI/freebuff-private@b76209dd2ec3f278ef28660c239c4e484572d7b4
Source: CodebuffAI/freebuff-private@ff62cf3506968799272123e6f637cdee6935e48f
Source: CodebuffAI/freebuff-private@d6591b0c4986740a517395811b4fe9d6e5db47b2
Source: CodebuffAI/freebuff-private@87a991308dfe74c4e68cf07c4206d0fc63db1c8a
Source: CodebuffAI/freebuff-private@5c9444e7ef7993a29e064220ef46c3a58af12b7d
Source: CodebuffAI/freebuff-private@e40b501c923f0bd2f33749cf6f081d9e74b42282
Source: CodebuffAI/freebuff-private@a82256a7abc33584a5bb1be29fbbd9c67c2dd8d7
Source: CodebuffAI/freebuff-private@42d9d1db9a7b2895732d49ab7d6ce84162fc81d4
Source: CodebuffAI/freebuff-private@61c0ffffb152a9b77e2ecfcd3d8adb0e4e4cfb87
Source: CodebuffAI/freebuff-private@a40168234a220d145b5ff7cf702b6364184d7296
Source: CodebuffAI/freebuff-private@91527d25716d4282b0e454e92ecf8b2fc8c1c9f1
Source: CodebuffAI/freebuff-private@09f98d52aaf28097b9509b34acdcd987ade63586
Source: CodebuffAI/freebuff-private@041104880304c80b39253ac43d4b6ffda95d0d65
Source: CodebuffAI/freebuff-private@59224af313776f1447bb0cd9908143c7c8c42014
Source: CodebuffAI/freebuff-private@e9ae9c9973b2a4201c679519104edbac24e18084
Source: CodebuffAI/freebuff-private@add9a3e8c175b5346ef9c0e1a210da2ce04c4847
Source: CodebuffAI/freebuff-private@e9f60dcb9e6bac2176579997d52ba34f51fec8dd
Two verified paths replaced the model's entire context with nothing:

1. /compact built its replacement summary from fullResponse without
   checking it was non-empty. A silent empty stop (finish part with a
   real reason, no content) yields no recovery chunk, so the whole
   history was replaced by a single message whose summary carried
   nothing — every earlier turn gone. Guard the replacement on
   fullResponse.trim() and keep the history (the forced next step
   retries the summary) when the model returned nothing.

2. Compaction identified its own summary by content: a user message
   containing <conversation_summary> and the header sentence. A user
   message quoting those markers (asking about this very mechanism,
   pasting a summary back) matched, findLast picked it over the real
   summary, and the real summary was then neither re-parsed nor kept —
   every earlier turn vanished at the next compaction. The inlined
   copy in the context-pruner matched the bare tag alone, so a message
   merely mentioning the tag wiped memory there too.

   Stamp summaries with a CONVERSATION_SUMMARY tag and recognize them
   by provenance; keep a legacy fallback requiring the full envelope
   (open+close tag, header, <historical_memory>) so pre-tag summaries
   still fold in. The pruner's tag-alone match — the parity test's
   deliberate divergence — closes: a bare tag mention no longer
   qualifies in either implementation.

Refs CodebuffAI#1166
@victorxheng

Copy link
Copy Markdown

Apologies — this PR was auto-closed by GitHub when we force-pushed a history rewrite of this repository (repository maintenance; every commit SHA changed). That was not a judgment on this PR, and GitHub does not allow us to reopen it because the commits it was based on no longer exist in the new history.

If you'd like to continue with this change: rebase your branch onto the new main (or recreate it from a fresh clone) and open a new PR — feel free to link back to this one for context, and we'll pick up the review there.

Sorry for the churn, and thanks for contributing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Compaction paths can wipe the entire chat history instead of compacting it

2 participants