fix(agent-runtime): retry compaction summary before retained-tail fallback - #554
ZxlDragonDoctor wants to merge 2 commits into
Conversation
…lback Issue vastsa#543. Transient summary failures retry up to 3 times with backoff; budget-exceeded attempts shrink the payload and still call the model. Only after retries are exhausted does retained-tail recovery write a failure checkpoint (wording updated to say summary generation failed).
|
谢谢,方向是对的:先重试、再缩减、最后回退。这个 PR 与当前
另外根因还多一层:预检守卫对原始消息求和,而 pi 序列化时每条 tool result 已截到 2 000 字符,所以它高估了好几倍——这是「不调模型就失败」的主要来源。 #563 保留了你的三段式方向,用 Thanks — the direction (retry, then reduce, then fall back) is right and is kept in #563. What blocked landing this as-is: the outer loop retries deterministic failures too; shrinking by dropping the oldest messages leaves the checkpoint claiming a range the summary never saw; the test file mirrors the constants instead of importing the runtime; the ADR 0049 preflight decision changes without an ADR; and the branch conflicts with |
…e falling back Issue vastsa#543: on real long sessions most automatic compactions ended as the ~112-token retained-tail recovery notice, and the transcript row labelled each one "summary ≈112 tokens". Three things made the ADR 0049 fallback the common outcome instead of the exception: - compact() was called without a RetryPolicy, so pi-ai returned the first failed response as-is. The main turn retries transient failures through the streamFn wrapper, but the summary goes through Models.completeSimple and never reaches it; one dropped stream or 503 discarded the summary. - The preflight guard summed estimateTokens over the raw messages, while pi-agent-core serializes the conversation to text and caps every tool result at 2 000 characters. Tool-heavy sessions looked several times larger than the prompt that would be sent and skipped the model for summaries that would have fit. - ContextCompactionMark could not tell a fallback from a summary, so the row rendered the recovery notice as a successful summary of N tokens. The summary request now carries a bounded pi-ai RetryPolicy (3 retries, 2s/4s/8s, abort-aware; pi-ai's classifier decides what is transient, so quota and auth failures still return at once). The guard sizes the prompt pi actually serializes, and when that still exceeds the window it tries exactly one reduced input (tool results cut to a 500-char prefix, thinking dropped, no message removed) before the fallback runs. The mark gains an additive `fallback?: "retained_tail"` derived from persisted details, and the row labels such checkpoints as a failed summary in all locales. Supersedes PR vastsa#554, which retried every recoverable failure including deterministic ones and shrank the input by dropping the oldest messages while the checkpoint still claimed to cover them. Records ADR 0282 / D445 and updates E2E-084, the runtime spec, and the IPC mark shape.
Problem
Automatic context compaction often fails to produce a real summary. On failure the runtime immediately writes a
retained_tailfallback checkpoint (~112 tokens of recovery prose) and drops older messages from the next model request. There is no retry-until-a-real-summary-exists loop (#543).Two concrete gaps in
packages/agent-runtime/src/runtime.ts:buildCheckpointcallsgenerateCompactiononce; transient provider failures go straight torecoverCompactionFailure.compactionSummaryWouldExceedBudgetreturnsrecoverable: truewithout calling the model, so oversized history never attempts a reduced payload.Solution
performCompaction: up toCOMPACTION_SUMMARY_MAX_ATTEMPTS = 3with backoff (2s → 4s → 8s). Only after retries are exhausted does retained-tail recovery run.shrinkPreparationForSummary: when the budget guard trips, drop oldest summarize-eligible messages until the input fits, then still call the model. Keep at least one message.Classification, provider-retry backoff, abort/cancel paths, and the fresh_window rollover strategy are unchanged.
Testing
packages/agent-runtime/src/compaction-retry.test.ts:vitest/ desktop suite not run in this environment (fork behind upstreammain; rebasing after review).Issue alignment
Addresses #543. Claimed on the issue before implementation. Distinct from #224 / PR #249 (fallback recoverability on a later compaction) — this PR retries the failing attempt.
Non-goals
Core value: Long sessions keep a real model summary when the provider flaps, instead of silently dropping history behind a 112-token stub.