Skip to content

fix: compression summaries always role:assistant (Bug 39)#80

Closed
ranxianglei wants to merge 2 commits into
masterfrom
2026-07-09_summary-role-assistant
Closed

fix: compression summaries always role:assistant (Bug 39)#80
ranxianglei wants to merge 2 commits into
masterfrom
2026-07-09_summary-role-assistant

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

Summary

Fixes the issue where compression summaries were sometimes injected as role: "user", causing models to misattribute their own prior compression recaps as user instructions.

Root Cause

filterCompressedRanges() in lib/messages/prune.ts had two injection paths:

  1. Merge path (Bug 36): If the next surviving message was role: "user", the summary was merged INTO that user message — giving it role: "user".
  2. Standalone path (Bug 37): Otherwise, a standalone role: "assistant" synthetic message was created.

Bug 36 originally rejected the standalone path because AssistantMessage required fields. Bug 37 solved this. The merge path was no longer necessary but remained as a source of role confusion.

Changes

  • lib/messages/prune.ts: Remove merge path, always use standalone assistant
  • lib/messages/prune.ts: Remove dead findNextSurvivingMessage function
  • tests/prune.test.ts: 3 tests updated for standalone assertions
  • tests/e2e-message-transform.test.ts: 3 tests updated for standalone assertions

Verification

  • typecheck: ✅ PASS
  • build: ✅ PASS (354.25 KB)
  • tests: 587 pass, 1 fail (pre-existing Bun quirk in prompts.test.ts)

issue #13

Previously, compression summaries were merged into the following user
message when one existed (Bug 36 merge path), giving them role:'user'.
This caused models to misattribute their own prior compression recaps
as user instructions.

Bug 37 already solved the original reason for the merge path
(AssistantMessage field fabrication). This commit removes the merge
path entirely — all summaries are now standalone role:'assistant'.

Changes:
- prune.ts: Remove dual-path logic, always use standalone assistant
- prune.ts: Remove dead findNextSurvivingMessage function
- tests: Update 6 tests across prune.test.ts + e2e-message-transform.test.ts

issue #13
The breakdown and tool-output reminder only showed 5 candidates, causing
the model to compress too narrowly (1 message per batch). Increasing to
15 gives the model more compression candidates at once.

Changed:
- utils.ts: largestRanges 10→15, largestToolRanges 5→15
- inject.ts: toolOutputReminder topRanges 5→15

issue #13
@ranxianglei

Copy link
Copy Markdown
Owner Author

Superseded by v1.11.0 (PR #95).

This PR's approach (force all summaries to role: assistant) would fix #78 (drift) but worsen #20 (echo) — making the echo happen 100% of the time instead of conditionally.

v1.11.0 takes a different approach: summaries are injected as synthetic tool-call + tool-result pairs (acp_context_recap). The model sees role: tool — a neutral third role that is neither user instruction nor own prior voice. This fixes both #78 and #20 simultaneously.

Recommend closing this PR.

@ranxianglei

Copy link
Copy Markdown
Owner Author

Closing as superseded by v1.11.0 (PR #95).

This PR's approach (force all summaries to role:assistant) would fix #78 (drift) but worsen #20 (echo). v1.11.0 uses tool-result injection instead — a fundamentally better solution that fixes both issues simultaneously.

See: #95

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.

1 participant