Problem
Compaction/reset paths can break session invariants in two related ways:
- hook contexts can lose or mis-normalize
messageProvider
- successful compaction can leave stale token/cost accounting behind
In practice this causes downstream consumers to see one real conversation as multiple logical sessions, and can also trap a session in repeated compaction safeguard loops after the transcript has already been cleared.
Concrete affected paths
Today this cluster shows up across several connected paths:
- auto compaction hook dispatch via
handleAutoCompactionStart/End
- engine-owned compaction hook dispatch in
compact.queued.ts
- command reset hooks via
emitResetCommandHooks
- gateway
sessions.reset via emitGatewayBeforeResetPluginHook
- post-compaction session accounting when
tokensAfter === 0
Reproduction A: provider invariants
- Use a channel-scoped session key like
agent:main:feishu:default:direct:ou_xxx
- Register a plugin that uses
ctx.sessionKey + ctx.messageProvider to build stable session identity
- Trigger auto compaction,
/new, /reset, or sessions.reset
- Observe
ctx.messageProvider missing, mixed-case, or inferred from a non-channel key shape
- Plugin falls back to
unknown or treats Telegram / telegram as different providers
- One real conversation is split into multiple logical sessions
Reproduction B: token accounting invariants
- Start a long-running session that reaches compaction
- Let compaction collapse the remaining transcript to an effectively empty/zero-token state
- Observe the transcript is cleared but cached accounting still reports old totals
- Next turn hits the compaction safeguard again because
totalTokens / cost state was not reset consistently
Expected
Compaction/reset code paths should preserve the same session invariants everywhere:
- hook contexts should expose a normalized deliverable
messageProvider when one is actually known
- non-channel session keys should not manufacture fake providers
- post-compaction token/cost accounting should be refreshed from the compaction result, including zero-token outcomes
Actual
Different paths currently preserve different subsets of those invariants, so downstream systems must guess or degrade.
Scope
This is broader than the original single-field hook bug. It covers the coordinated compaction/reset invariant cluster now reported separately in:
Problem
Compaction/reset paths can break session invariants in two related ways:
messageProviderIn practice this causes downstream consumers to see one real conversation as multiple logical sessions, and can also trap a session in repeated compaction safeguard loops after the transcript has already been cleared.
Concrete affected paths
Today this cluster shows up across several connected paths:
handleAutoCompactionStart/Endcompact.queued.tsemitResetCommandHookssessions.resetviaemitGatewayBeforeResetPluginHooktokensAfter === 0Reproduction A: provider invariants
agent:main:feishu:default:direct:ou_xxxctx.sessionKey+ctx.messageProviderto build stable session identity/new,/reset, orsessions.resetctx.messageProvidermissing, mixed-case, or inferred from a non-channel key shapeunknownor treatsTelegram/telegramas different providersReproduction B: token accounting invariants
totalTokens/ cost state was not reset consistentlyExpected
Compaction/reset code paths should preserve the same session invariants everywhere:
messageProviderwhen one is actually knownActual
Different paths currently preserve different subsets of those invariants, so downstream systems must guess or degrade.
Scope
This is broader than the original single-field hook bug. It covers the coordinated compaction/reset invariant cluster now reported separately in: