Repository navigation
docs(qwen): record compaction attribution limits - #609
Merged
Merged
Conversation
stamp-build
Bot
force-pushed
the
agent/otter/qwen-compaction-attribution
branch
from
November 2, 2026 20:53
e6572ed to
b5b1eb8
Compare
Merged
stamp-build Bot
added a commit
that referenced
this pull request
Nov 2, 2026
<!-- stamp:review:v1 --> <sup><img src="https://api.raft.build/api/avatars/pixel/bXVn.svg" width="16" height="16" align="absmiddle" alt=""> <b>Cindy</b> from open-agent-runtime opened this pull request through Stamp</sup><br><sup><a href="https://stamp.build/review?receipt=prc_757a5037d345493462e53a75c6fc292d"><picture><source media="(prefers-color-scheme: dark)" srcset="https://stamp.build/assets/brand/stamp-glyph-dark.d907ffcadb44.svg"><img src="https://stamp.build/assets/brand/stamp-glyph-light.58a2c10ed108.svg" width="13" height="12" align="absmiddle" alt=""></picture> View in Stamp →</a></sup> --- <!-- /stamp:review:v1 --> Minor release: a host can now ask a runtime to compact its context and wait until the runtime confirms it. This completes the 0.85.0 resume change: a prompt supplied on resume that only takes effect at the next native compaction (Claude's `systemPrompt` and `appendSystemPrompt`, Codex's `appendSystemPrompt`) can now be applied right away in the same session by resuming with the new prompt and then calling `compact()`. Codex's replacement `systemPrompt` already applies immediately. Stream-json turn ends also carry the native input identities. ## New: manual compaction (#610) - Optional `Runtime.manualCompaction` says before opening whether a runtime supports it: `{ kind: "supported", activeTurn }` or `{ kind: "unsupported", reason }`. An absent declaration means untested, not unsupported. Supported now: Claude, Codex and Pi (in-process and subprocess). Declared unsupported with reasons: Kimi, Qwen, Antigravity, CodeBuddy. Not yet declared: Grok, Qoder, Cursor, OpenCode, Pi Durable and the community Morph runtime. - Optional `Session.compact({ timeoutMs?, signal? })` returns a `CompactionOutcome` (new exported types `ManualCompaction`, `CompactionOptions`, `CompactionOutcome`): - `completed`: the runtime confirmed this compaction (Claude's `compact_boundary`, Codex's compaction item, Pi's manual compaction end); `frame` points at that record. - `rejected`: the compaction was not admitted, with a typed `code` and `reason`. Usually nothing reached the runtime, but Codex and Pi can also refuse after the native call (`runtime_refused`, `runtime_exited`), and Claude's command check talks to Claude first. Codes include `busy` (a turn, queued or not yet started input, another compaction, or an active Codex goal), `aborted` (the caller's `signal` was already aborted, so nothing was sent), `unsupported` (for example a project or user command shadows Claude's `/compact`), and the usual unreachable and error codes. - `failed`: the runtime reported failure, or the command did not actually compact (Claude reported failure, or its commands changed in between). - `aborted`: the runtime itself reported the compaction cancelled. - `unconfirmed`: OAR stopped observing without a confirmed result: `timeout`, `signal`, `disposed`, `runtime_exited`, `session_released` or `observation_failed`. - `compact()` throws `RangeError` when `timeoutMs` is negative or not finite. - **All current implementations require an idle session.** Codex and Pi would abort a running turn to compact; OAR never does that as a side effect. - **Waiting limits only stop waiting.** After the request is admitted, `timeoutMs` or `signal` return `unconfirmed`; the native compaction continues and the session stays `compacting` until the runtime settles, and later records still arrive. During that time new prompts, steer and a second `compact()` are refused as `busy`; input queued during the compaction is held by Claude and Pi until it ends, while Codex refuses it as `busy`. `timeoutMs: 0` sends the request without waiting. - `abort()` during compaction uses the runtime's own cancel once there is something to cancel; before that it is refused as `busy`. A queued Claude `/compact` cancelled before it starts ends `aborted`. A Claude compaction already running and then interrupted is reported by Claude as a failure, so `compact()` returns `failed` with that native record, independent of the turn's own aborted ending. Codex refuses `abort()` as `busy` until its compaction item names the turn. - Claude: before every `compact()` call, OAR sends Claude an `initialize` request in the same session and sends `/compact` only if Claude reports it as its built-in command. On Claude 2.1.316 (Linux) repeated `initialize` requests did not re-run the SessionStart hook or the HTTP MCP server and left the permission mode, settings, system prompt and tool list unchanged; this is not a claim about every version or every hook implementation. - Codex evidence covers local compaction; compaction under a ChatGPT login was checked in source only. Pi subprocess compaction is exempt from the usual 30 second RPC request deadline. - Record stream: new request kind `compact`, new `ControlAction` value `"compact"` (check exhaustive switches over `ControlAction`), and new `RejectionCode` `aborted`. ## Status checkpoint for incremental consumers - `StatusState` and `statusValue` are exported from the package root and `@botiverse/oar/observe`; `reduceStatus` and `initialStatus` now take and return `StatusState`. Hosts that fold status incrementally must persist the complete `StatusState` together with their cursor and pass it back unchanged. The displayed `AgentStatus` (`statusValue`, `Session.status()`) alone cannot continue a fold through a manual compaction. - The same applies to the observe helpers: `TaskState.status` is now a `StatusState`, and `SessionView` gains `statusState?`. Persist these whole as well. - While a manual compaction is in progress, `AgentStatus` is `running` with phase `compacting` and `compaction: { requestId, started? }`. ## Turn input identities - `turn_ended.inputId?` and `turn_ended.inputIds?` copy the stream-json result's `user_message_uuid` and ordered `user_message_uuids` when the runtime reports them, including on ordinary turns. Neither is derived from the other. When Claude merges several queued inputs into one turn, its `inputId` names the latter input and there is no first or last rule to rely on, so use `inputIds` to settle all of them. OAR's own interrupt fallback is separate and still uses `mergedInputIds` and `carries`. Claude reports these fields; Qwen 0.26.5 and Qoder 1.1.81 currently do not. - Stored OAR records do not change. Only re-projecting raw Claude native output with this version adds these two fields. ## Docs and experiments - Qwen compaction attribution (#609): in Qwen's stream-json output, the manual compaction status goes through the same assistant text frames as model output, so OAR cannot tell them apart; automatic compression emits no frame at all; and a user `compress.toml` can replace `/compress`. OAR emits no Qwen compaction events and does not guess from text. - DeepSeek Harness plugin bridge probe (#607): an external plugin shipped outside DSH can drive DSH's native controls and events without ACP, on DSH 0.2.1-rc.5 and 0.2.2-alpha.2. Experiment only; no DSH runtime yet. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Cindy <open-agent-runtime+cindy@agents.stamp.build>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Qwen 0.26.5 emits manual compression status as assistant text and exposes no automatic compression frame in stream-json. A user
compress.tomlcan replace/compresswith a model prompt, so neither the output text nor the submitted command safely identifies compaction.Document this limit in the Qwen runtime page and record-stream contract without changing the adapter. Keep a reproducible native probe, portable selected evidence and an unsubmitted upstream issue draft requesting structured manual/automatic compaction observations and resolved command origin.
Validation: native manual, automatic and overridden-command controls pass on Linux x64. Both compaction controls verify the unique summary reaches the next main provider request; an ordinary model response reproduces the native status verbatim. Full check passes (2,991 tests and 18 mock behaviors). The selector reproduces the committed evidence byte for byte. Other platforms are not claimed.
Tracks task #156. The issue draft is for Cindy to decide whether to submit. This PR does not change product behavior or the release version.