fix(compact): preserve replay ownership (PR2 round 2)

This commit is contained in:
Hypatia May
2026-07-15 15:13:57 +08:00
parent f038780ff6
commit 99dccf559a
10 changed files with 154 additions and 29 deletions

View File

@@ -81,7 +81,7 @@ forever:
agent/request (config only) -> log request/header -> llm/stream (frozen)
'assistant/chunk'
agent/step-result
'assistant/message'
'assistant/message' (transformed content, or an empty successful-call anchor if step-result rejects)
each tool call:
'tool/call'
tools/pre-execute -> monotonic guards -> tools/execute -> tools/post-execute -> tools/result

View File

@@ -30,7 +30,7 @@ This is not a coupling smell — it is the contract's domain. The "only cordis"
An earlier draft put the full algorithm (the retention walk, token-summing, text extraction) as concrete methods on the interface. That recouples the contract to one strategy: a backend that wants a different retention policy or event sequence would have to fight inherited concrete code. Making both core methods abstract puts every *how* decision in the backend and keeps the interface a statement of *what*. Token measurement is not a compaction hook at all; the standalone service lets multiple consumers share one model/session replay fold.
`compactIfNeeded(agent, fullSystemPrompt, sessionPrefix, signal)` takes required pressure inputs and cancellation. The session comes from the agent. `compactRegion(session, start, end, agent, signal?)` keeps an optional signal for manual callers. The pre-step integration resolves a provisional model from the latest logged request header, then `AgentOptions.model`; a model-less router-only first step skips pressure because `agent/request` can route later. The default summarizer resolves its model from explicit config, the latest logged routed model, then agent options.
`compactIfNeeded(agent, fullSystemPrompt, sessionPrefix, signal)` takes required pressure inputs and cancellation. The session comes from the agent. `compactRegion(session, start, end, agent, signal?)` keeps an optional signal for manual callers and requires `session === agent.session`; implementations reject mismatch before model resolution, lock acquisition, summarization, or log mutation. The pre-step integration resolves a provisional model from the latest logged request header, then `AgentOptions.model`; a model-less router-only first step skips pressure because `agent/request` can route later. The default summarizer resolves its model from explicit config, the latest logged routed model, then agent options.
### Auto-compaction runs on `agent/pre-step`, a dedicated surface-mutation seam