mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-16 04:05:15 +00:00
24 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
abfd443698
|
docs(design): Define selective session restore (#8743)
* docs(design): plan selective session restore Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs(design): harden selective session restore plan Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs(design): Refine selective session restore plan Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs(design): Finalize selective restore lifecycle Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs(design): Tighten selective restore lifecycle Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs(design): finalize selective restore contracts Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs(design): align selective restore prerequisites Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs(design): narrow selective restore lifecycle Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs(design): refine selective restore execution Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs(plan): verify resumed channel updates Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs(design): update selective restore prerequisites Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs(design): allow stacked selective restore development Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: update selective restore prerequisites Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: tighten selective restore review gates Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: close selective restore evidence gaps Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: preserve goal evidence failure semantics Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: mark restore shape prerequisite merged Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
d3164572f3
|
feat(channels): add Feishu ask-user question cards (#8578)
* feat(channels): add Feishu ask-user question cards * fix(channels): harden Feishu question-card handoff and feedback paths * fix(channels): anchor Feishu card-creation timeout at creation start (#8578) * fix(channels): skip settled question-card delivery, retry input-request finalization - present() returns early when the request settled before listener registration (stop/cancel landing in the pre-presentation await): the card is no longer delivered just to be patched terminal, which left a spurious actionable-looking card when the patch failed. - endOutputCardBeforeInputRequest now retries the final patch with stripTables before deleting the card and re-sending plain text, mirroring onResponseComplete and the throttled update path. - truncateCardText budgets the 4-char fence prepend so rebalanced content stays within MAX_CARD_CHARS, matching onResponseComplete. * test(channels): cover Feishu question-card review findings - stop real network leaks: mock addReaction/removeReaction in the two handoff tests that drove onPromptStart with the real implementation (each run hit Feishu's tenant-token endpoint). - assert the OnIt reaction add/remove lifecycle positively. - pin settled-before-registration presentation to zero card delivery. - regression tests: input-request table-stripped retry, finalizing race (throttled timer cleared before the final patch), late card deletion when the input request lands mid-creation, abandoned creation-timer guard. - routing coverage for toast-only handled callbacks (no execute). - parse rejections: empty/malformed multi-select values; cancel-side name<->operation_id mismatch; visible submit/cancel button labels; cancelRun terminal label; submitted answers in patch-failure fallback; truncation tail-keeping and fence-rebalance cap. - harden subset toMatchObject assertions to strict toEqual. * fix(channels): type Feishu card-delivery errors; cover controller wiring seam sendInteractiveCard now throws FeishuCardDeliveryError (with the HTTP status when available) so createStreamingCard classifies delivery failures by error type instead of string-matching three message literals that could drift under rewording. Add an adapter test that keeps the real FeishuQuestionCardController with fetch mocked, asserting the POSTed body carries the question-card JSON (form name, question text, request id) — the constructor wiring seam every routing test previously mocked away. * fix(channels): cap Feishu input-request card retry; harden question-card tests * fix(channels): drain in-flight Feishu card PATCHes before final patch (#8578) Also carry a concurrently-written terminal status into the released card entry, report card-delivery failures from a typed error detail instead of slicing the message, and document the silent empty-completed-turn tradeoff. Adds round-5 review test pins: wiring seams (sendFallback, patchCard, timeoutMs), spy hygiene, claim-time card content, fallback suppression, expiry-timer survival, and non-vacuous release-time timestamp anchoring. * fix(channels): coordinate Feishu card stop races and throttle bursts (#8578) - endOutputCardBeforeInputRequest now defers to Stop (entry guard plus post-await re-checks mirroring onResponseComplete) and releaseOutputCard carries settled stop state, so a stopped run is never labelled 已完成 nor followed by a contradictory terminal message - coalesce throttled card updates queued behind a stalled PATCH into one trailing run instead of a burst - log every FeishuCardDeliveryError from createStreamingCard - consolidate onResponseComplete truncation through truncateCardText - question controller: a not-accepted in-flight response no longer flips a projected 已取消 card to 已过期, and a cancel claim no longer re-patches the terminal card already delivered in the callback response - test hygiene: hermetic fetch mocks for token-failure tests, restored fetch spies, required lifecycle fixture fields, bracket index access * test(web-shell): wait for history search focus before Escape in smoke (#8578) * fix(channels): resolve Feishu card finalization races from review (#8578) * fix(channels): recover Feishu cancel callbacks missing button value (#8578) --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> |
||
|
|
028747aa41
|
feat(feishu): enrich observed contact labels (#8569)
* docs: design feishu observed contact enrichment * docs: add Chinese Feishu enrichment design * feat(feishu): enrich observed contact labels * fix(feishu): preserve enriched contact labels * fix(feishu): harden observed-contact label enrichment lifecycle * fix(feishu): bound label caches, honor observation recency, silence enrichment token failures (#8569) - hydrate runtime label caches from the newest observation per contact so stale group membership labels cannot overwrite more recent ones - cap the user/chat label, in-flight lookup, and write-dedup maps at 500 entries (matching the persisted registry) and evict oldest entries - route best-effort label lookups through a silent token refresh path so enrichment failures no longer write to stderr - add tests for silent token refresh, newest-label hydration, cache cap, and the persisted-observation reject path in hook ordering * fix(feishu): address observed-contact label review feedback (#8569) * Track core (non-silent) waiters on the shared tenant-token refresh so a silent-initiated refresh still logs token errors for joined delivery callers. * Short-circuit label lookups on the resolved names cache so evicted lookup entries do not trigger redundant API requests. * Re-hydrate label caches from the persisted registry after an in-lifetime cache eviction so the next initial write cannot clobber a persisted label with the raw ID. * Add mutation-proof regression tests for the channel-isolation filter, the list-failure swallow, the silent HTTP-error branch, and the 'unknown' label guard. --------- Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com> |
||
|
|
20b3087aca
|
feat(browser-ext): add alpha readiness diagnostics (#6739)
* feat(browser-ext): add alpha readiness diagnostics * test(browser-ext): automate readiness verification * fix(browser-ext): support current devtools adapter * test(browser-ext): verify restored page after reconnect * fix(browser-ext): harden release and acceptance checks * test(browser-ext): cover onboarding transitions * fix(browser-ext): harden alpha diagnostics * test(cli): sync serve capabilities baseline * feat(browser-ext): add alpha readiness diagnostics * test(browser-ext): automate readiness verification * fix(browser-ext): support current devtools adapter * test(browser-ext): verify restored page after reconnect * fix(browser-ext): harden release and acceptance checks * test(browser-ext): cover onboarding transitions * fix(browser-ext): finalize Chrome Web Store package * fix(browser-ext): harden CDP diagnostics per review feedback (#6739) * fix(browser-ext): harden CDP diagnostics per review feedback (#6739) Distinguish the ACP child's idle placeholder (initialized: false, discoveryState: 'not_started') from a genuinely empty server list so the panel no longer shows a false "adapter is not connected" warning before the first session or after the child is reaped. Compare the tunnel endpoint's host+port against the daemon baseUrl to detect cross-daemon shadowing (a chrome-devtools entry pointing at a different daemon's /cdp was previously reported as connected). Guard package-extension and symlink tests with skipIf(process.platform === 'win32') so the Windows merge-queue gate does not fail on missing zip.exe or privilege-dependent symlinkSync. Also: destructure QwenCapabilityStatus lazily inside probeState so a missing capability-status.js no longer throws before the welcome screen renders; add the missing license header to manifest-version.js; replace the leftover #welcome height:100vh with flex sizing; add cross-reference comments for the shared /cdp path pattern. Note: probeJson intentionally drops the .catch(() => ({})) fallback so a 200 with a non-JSON body reads as unreachable; this also makes /health stricter than before. * fix(browser-ext): resolve CDP diagnostics review findings (#6739) * fix(browser-ext): mirror nightly build number in manifest test oracle (#6739) * fix(browser-ext): address alpha diagnostics review feedback (#6739) - declare the semver dependency used by manifest-version.js so an isolated workspace install no longer relies on root hoisting - make artifact-scan skip the root CLI bundle metafile with a warning when it is absent (it only exists after `cross-env DEV=true npm run bundle`), keeping the extension metafile required, so package-level test:release no longer fails - throttle the side panel /workspace/mcp probe to every 5th tick and reuse the cached snapshot in between, avoiding a cross-process RPC on every 2s poll - document the per-session CDP event fan-out and pin single-path event counts; note that Target.getDevToolsTarget is deliberately unsupported - guard the nightly build-number git lookup and the zip end handler - disclose the daemon-to-model-provider page-content flow in PRIVACY.md - drop brittle source-substring panel tests and add coverage for a chrome-devtools server with no config args * fix(browser-ext): improve acceptance diagnostics and honest phase naming (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(cli): stabilize flaky orphan-session transport tests (#6739) Replace hardcoded setTimeout(40ms) + assertion with vi.waitFor() in the session/new and session/load orphan tests. The 40ms budget is too tight under CI parallelism, causing intermittent removeSession-not-called failures. vi.waitFor polls until the assertion holds (default 1s timeout), matching the pattern already used elsewhere in this file. * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(cli): restore PAGE_SESSION_ID forwarding for lazy-attach path (#6739) The autoAttachActive gate on PAGE_SESSION_ID command forwarding broke the cdp-ws lazy-attach path, which sends commands with PAGE_SESSION_ID without a Target.setAutoAttach handshake. Revert the forwarding gate to unconditional PAGE_SESSION_ID acceptance while keeping the gated Target.attachedToTarget emission (the Critical fix). * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): make survivor tests load-bearing with log assertions (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): resolve review findings on diagnostics tests (#6739) - reject preview-range QWEN_CHROME_EXTENSION_BUILD_NUMBER values at the env var boundary with a message naming the variable, value, and range - assert the package-extension symlink test observably ran main() instead of passing on equality alone when both runs fail identically - add CLI-level tests proving explicit positional roots are scanned and a clean scan exits 0, covering paths the symlink-only tests skip on Windows Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com> Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
4338120100
|
feat(serve): resolve and report the daemon memory budget (#8245)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
SDK Java / ubuntu-latest / Java 11 (push) Waiting to run
SDK Java / ubuntu-latest / Java 17 (push) Waiting to run
SDK Java / macos-latest / Java 21 (push) Waiting to run
SDK Java / ubuntu-latest / Java 21 (push) Waiting to run
SDK Java / windows-latest / Java 21 (push) Waiting to run
SDK Java / Real daemon E2E / Java 11 (push) Waiting to run
* feat(serve): resolve and report the daemon memory budget The daemon has no notion of how much memory it has. It samples its own RSS and heap every five seconds, and polls the primary ACP child's RSS, but there is no limit anywhere to divide those by: no cgroup read, no heap-size limit, no ratio, no `limits.*` memory field. Every number it reports is an absolute byte count with nothing to compare against, so "how close to exhaustion is this daemon" cannot be answered from `/daemon/status` at all. Resolve one set of figures at boot and report them. Configured and effective budgets are separate: the effective value is capped at resolved cgroup or host memory, so an operator passing a budget larger than the machine gets a denominator the machine can actually back, with the discrepancy visible rather than silently resolved. A derived budget below the documented minimum is reported as `insufficientMemory` rather than clamped upward, which would have invented capacity that does not exist — a 768 MB host would otherwise report a 1 GB budget and poison every ratio computed from it. `limits.memory` carries the static figures, including `legacyCeilingMb`: the ceiling an ACP child receives today with no budget involved, so the gap between current behavior and any future policy is measurable before that policy exists. `runtime.memory` carries live counts and the advisory per-child share at both the registered and the live child count. Nothing here sizes a child. Dividing the pool by a workspace count is not a sound policy on its own, and the advisory shares exist to show why: on a 32 GB host with 25 registered workspaces and only the preheated primary live, a registered-count divisor would cut that child from 16384 MB to 614 MB for memory no dormant workspace is holding, while the per-child floor still lets 25 children authorise more than the pool. Registration is not allocation; a real policy needs admission at spawn time keyed on concurrently live children, and it needs this data to be designed against. Applying such a share is also a compatibility change even with no refusals, since it alters child GC and OOM behavior — so it is not something this change should slip in under the heading of reporting. Refs #8182 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(serve): report honest memory counts and guard the registered share (#8245) * fix(serve): reuse workspace snapshots when counting active children Counting active ACP children from `listManaged()` is right — `list()` only returns entries in `active` state, so a workspace mid-drain, mid-replacement, or blocked still holds a live child that `list()` drops. But taking the count by calling `getDaemonStatusSnapshot()` again per managed runtime undoes the existing reuse of the primary bridge's snapshot, and `getDaemonStatusSnapshot` rebuilds the whole session array on every call. The second pass also reads the tree at a different instant than the rest of the response, so `activeAcpChildren` could disagree with the session and channel figures beside it. Reuse the snapshots already taken instead, keyed by bridge, and fall back to a fresh call only for a managed runtime the first pass missed — which is exactly the non-`active` entry the `listManaged()` change exists to catch. The reuse this restores was already guarded by a test asserting one snapshot call per bridge, but that test resolves no memory budget, and the second pass ran only on the budget path — so it stayed green while every production `/daemon/status` call did the work twice. Added a case that resolves a budget and asserts the same property; it fails against the previous commit with "expected 1 times, but got 2 times". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(serve): address review feedback on daemon memory budget (#8245) * fix(serve): import isValidMemoryBudgetMb in serve command (#8245) * fix(serve): address review feedback on daemon memory budget (#8245) * fix(serve): stub isChannelLive on serve test fake bridges (#8245) * fix(serve): address review feedback on daemon memory budget (#8245) - Make the stderr-gate test host-independent by pinning os.totalmem through a vi.mock toggle instead of reading the runner's cgroup - Add a spawn-path constant parity test enforcing that getAcpMemoryArgs and legacyChildCeilingMb agree on the fraction and cap, converting the comment-only invariant into a test - Narrow the mirror comment to name only the two constants that actually have spawn-path counterparts - Accept availableMemorySource through the resolveDaemonMemoryBudget seam so the constrained path is testable end-to-end - Report maxChildHeapMb alongside minChildHeapMb on the wire so clients can distinguish the 16 GB cap from a large host - Move the listManaged/list comment to the computation it describes - Add a cross-reference at the opts literal for the late-assigned daemonMemoryBudget field * fix(serve): address review feedback on daemon memory budget (#8245) * fix(serve): address review — split fraction constant, sharpen parity test, deduplicate error, populate bootstrap memory (#8245) * fix(serve): address review — document maxChildHeapMb, make parity test order-independent (#8245) * fix(serve): address review — split parity test into two files to avoid cold re-import timeout (#8245) * fix(serve): address review — correct session count, compatibility scope, bootstrap memory docs (#8245) * fix(serve): address review — align help text framing, document default cap, fix stale comment (#8245) * fix(serve): address review — add positive memory-budget validation test, correct activeAcpChildren docs (#8245) * fix(serve): address review — document childRssBytes stale tail after watcher detach (#8245) --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> Co-authored-by: Qwen Autofix <qwen-autofix@users.noreply.github.com> Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
bd85599139
|
feat: visualize ordinary-session plan execution (#7580)
* feat: visualize ordinary session plan execution * fix(web-shell): complete plan workflow rendering * fix: preserve authoritative plan state * fix(core): isolate teammate todo state * fix: reject ambiguous empty plan snapshots * test(web-shell): cover workflow dialog wiring * feat(web-shell): preview workflow before execution * feat(web-shell): inspect workflow step details * feat(web-shell): preserve session workflow history * test: align failing CI tests with plan-isolation behavior SubAgentTracker: the emitter now guards subagent TodoWrite results (tool-call-emitter emitResult early-returns on subagentMeta), so a subagent todo no longer promotes into a session-level plan. Flip the stale assertion to expect no plan emission, mirroring the dedicated guard test in tool-call-emitter.test.ts. HistoricalPlanExecution: the pagination fixture's onLoadOlderHistory returned Promise<void>, but PlanExecutionHistoryProvider requires Promise<boolean> and throws 'Unable to load earlier session history' on a falsy resolution. Production wires loadOlderHistory (resolves true after layout); return true in the fixture to model a successful load. * refactor: simplify session plan execution workflow * fix(web-shell): preserve split plan approval workflow --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
d61b0ea475
|
perf(web-shell): paint the composer git chip before git status completes (#7680)
* perf(web-shell): paint the composer git chip before git status completes New sessions gated the chip on a full `git status --porcelain` subprocess behind GET /workspaces/:ws/git, so the branch chip appeared hundreds of milliseconds (worst case seconds) after the composer was ready. The daemon now keeps a per-workspace last-known summary with in-flight dedup and a 2s background-refresh throttle: the default GET returns the cached status (branch-only on a cold start) immediately and recomputes in the background, publishing git_status_changed over SSE only on a delta, while ?wait=1 keeps the previous blocking semantics. The composer fetches both paths concurrently — the fresh GET also covers the no-session state, which has no per-session SSE stream — so the branch paints in ~3ms and the counters land when the computation finishes. The sidebar keeps wait:true since it has no SSE fill-in path. * fix(web-shell): add exhaustiveness guard and worktree git-status test (#7680) * fix(web-shell): add exhaustiveness guard and worktree git-status test (#7680) * fix(web-shell): add exhaustiveness guard and worktree git-status test (#7680) * fix(cli): use writeStderrLineSafe in git-status refresh error path (#7680) * fix(web-shell): add debug trail to fresh-path catch and test branch-watcher dispose guard (#7680) * fix(cli): assert writeStderrLineSafe in git-status refresh failure test (#7680) --------- Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> |
||
|
|
bfe8ab4fea
|
feat(daemon): add explicit channel delivery (#7388)
* docs(channels): define immediate delivery v1
* feat(channels): add proactive delivery boundary
* feat(daemon): route channel delivery to workers
* feat(scheduler): persist channel delivery targets
* feat(daemon): accept reverse channel deliveries
* feat(daemon): deliver prompt and scheduled finals
* feat(daemon): add synchronous channel notify
* fix(channels): classify Feishu delivery network errors
* fix(daemon): harden channel delivery failures
* fix(channels): wrap DingTalk proactive token fetch in typed delivery error
A proactive token fetch failure escaped sendProactiveChunk as a plain Error, bypassing ChannelProactiveDeliveryError classification. Wrap it as a transient typed error (preserving the cause) so downstream classification dispatches on it consistently. Also cover the scheduled-source branch of the bridge channel-delivery ext-method, which previously had no test coverage.
* refactor(cli): rename shutdown drain constant to reflect dual scope (#7388)
* fix(cli): support delivery updates in scheduled-task PATCH (#7388)
* fix(cli): address review feedback on channel delivery (#7388)
- Guard empty text before scheduling channel delivery in both prompt
and cron paths, avoiding unnecessary IPC round-trips when the model
emits only tool calls
- Import MAX_CHANNEL_DELIVERY_NAME_LENGTH and
MAX_CHANNEL_DELIVERY_TARGET_ID_LENGTH from core instead of
redeclaring them, preventing potential drift between the persistence
and API validation layers
- Remove dead thought parameter from #collectChannelDeliveryText —
all call sites pass a single argument
* fix(cli): add cross-reference and invariant comments for channel delivery (#7388)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(cli): revert doc corruption and harden delivery event publish (#7388)
* fix(docs): revert prettier-mangled GitHub Action doc and add prettierignore guard (#7388)
* fix(cli): address review feedback on channel delivery (#7388)
- Make deliverChannelMessage error workspace-aware when routing fails
- Discriminate DaemonChannelDeliveryResultData union on status field
- Add old-target rejection assertion to PATCH delivery test
- Add IPC send failure path tests for channel delivery
- Add rehydration → authorization store integration test
* docs(cli): clarify delivery text scope, consume tradeoff, and 503 expectation (#7388)
* fix(cli): address review feedback on channel delivery (#7388)
- Document single-turn invariant on channelDeliveryCollector field
- Note adapter disposition drop in design doc for V1 scope
- Add text length bound to IPC request validator (defense-in-depth)
* docs(daemon): define final-only channel delivery
* fix(daemon): deliver only final response blocks
* test(daemon): cover cancelled scheduled delivery
* fix(daemon): skip delivery for unbound tasks, consolidate error codes (#7388)
* fix(feishu): validate message response codes
* Revert "fix(feishu): validate message response codes"
This reverts commit 85fc0943d69d2f5e7535477f2d46bfcd8c5c3c1e.
* refactor(channels): defer DingTalk error classification
* fix: apply CR suggestions from AI review
* test(channels): cover delivery failure paths
* fix(cli): add required ink FrameCell/ReadonlyFrame properties to selection tests
The branch was behind main where
|
||
|
|
5c5c1017fc
|
fix(core): Enforce final tool response budgets (#7323)
* fix(core): enforce final tool response budgets Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#7323) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#7323) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#7323) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#7323) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#7323) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
582fb49603
|
feat(web-shell): git status chip, visual working-tree diff, and sidebar git status (#7054)
* feat(web-shell): git status chip, visual working-tree diff, and sidebar git status
Bring working-tree Git awareness to the Web Shell (browser daemon session UI):
- Toolbar branch chip becomes a live status indicator: dirty (staged/unstaged/
untracked), ahead/behind upstream, stash count, detached HEAD, in-progress
operation (merge/rebase/cherry-pick/revert/bisect), and conflict count, each
with a non-color cue.
- Read-only "Changes" dialog: working-tree-vs-HEAD file list with per-file,
line-level, per-side syntax-highlighted diffs; opens via /diff or a dirty
chip; untracked files expand as fully-added and deleted files still diff.
- Per-workspace git status in the sidebar: a compact icon-only chip per trusted
workspace (status dot + hover tooltip); click opens that workspace's dialog.
All git access goes through the daemon REST API with per-workspace trust
gating; new SDK status fields are optional and additive (v2).
* fix(web-shell): themed tooltips and git-chip review follow-ups
Tooltips now render on the themed popover surface (bg-popover /
text-popover-foreground / border + fill-popover arrow) instead of the
inverted bg-foreground default, so they read dark-on-dark rather than a
bright box on the dark theme. Fixing the shared primitive corrects the
git branch tooltip in the composer toolbar and sidebar, plus every other
tooltip, at once.
Also addressing review feedback on the git integration:
- Replace the hand-drawn detached/conflict/stash SVG icons with
lucide-react (CircleDot / TriangleAlert / Layers) per the web-shell
icon convention.
- Gate the tooltip "Working tree clean" message on an enriched status
(computedAt) so a branch-only status no longer asserts clean.
- Include the file path in the diff dialog row aria-label so screen
readers can distinguish files.
- Reset the toolbar git chip on workspace switch so it never shows the
previous repo's branch/counts while the new fetch resolves.
- Log a sidebar git poll failure only on the success->failure transition
to avoid spamming a long-lived tab.
- Correct the SDK doc for DaemonWorkspaceGitDiffFile.added/removed
(0, not undefined, for binary files).
* fix(web-shell): address git-integration review suggestions
Follow-ups from the /review pass on the git integration:
- GitBranchIndicator: include the short SHA in the detached-HEAD tooltip
title, and add the "Working tree clean" status to the aria-label (gated
on an enriched status, matching the tooltip) so the two never drift.
- WorkspaceSection: keep the last known git status on a transient poll
failure instead of blanking the chip for a whole interval.
- App: surface a toast for `/diff` when no workspace is available instead
of silently consuming the composer input.
- Tests: cover the diff dialog's list-load and per-file load error paths,
and detectGitOperation's revert/bisect branches.
- Design doc: align the getGitWorkingTreeStatus spec text with the
decision (transient states return status with `operation`; null is
reserved for non-repo / git failure).
* fix(web-shell): focus-visible ring for git chip button; align doc poll interval
- Add a :focus-visible outline to .gitBranchChipButton so keyboard users
get a visible focus indicator (the chip resets UA button chrome).
- Design doc: align the active-workspace poll-interval references at 30s
to match the implementation.
* fix(web-shell): surface capped diffs, catch row-build failures, cover degradation paths
Address the remaining review findings on the git integration:
- Truncation is no longer silent: fetchGitDiffHunksForFile now returns
{ hunks, truncated } — the parser records files that actually lost
lines to MAX_LINES_PER_FILE (tracked path), and the untracked
synthesis reports its byte/line caps. The route forwards an additive
`truncated` flag on the hunks response (absent when not truncated, so
older clients and daemons are unaffected), and the Changes dialog
renders a "Diff truncated" note under the visible window.
- DiffHunks catches an unexpected buildRows rejection (e.g. malformed
hunk lines) and shows the per-file error instead of leaving an
unhandled rejection and a silently empty diff area.
- New tests: untracked and tracked truncation at the core caps, the
route's truncated passthrough (and its absence when clean), the
branch-only degradation when the working-tree summary throws, the
malformed-hunks error path, and the Shiki success path (a fake
tokenizer proving add rows pull new-side tokens and del rows pull
old-side tokens, not the plain-text fallback).
* fix(web-shell): drop dialog backdrop-blur that froze the page on open
The dialog and alert-dialog overlays applied `backdrop-blur-xs`, which
forces the browser to rasterize and blur the entire content behind the
overlay when a dialog opens. With a long transcript behind it, that
main-thread paint+blur froze the whole page — e.g. clicking the git
branch chip to open the Changes dialog. Keep the bg-black/10 scrim for
separation and drop the blur.
* fix(core): guard synthesizeUntrackedHunk against non-regular files
synthesizeUntrackedHunk opened an untracked path before checking its
type, so an untracked FIFO (listed by `ls-files --others`) would block
on open() forever waiting on a writer — hanging the daemon's event loop
and leaving the Web Shell Changes dialog stuck on a permanent loading
state. lstat-gate on regular files before opening, matching the existing
guard in countUntrackedLines. Adds a FIFO regression test.
* fix(web-shell,core): rename expansion, no-newline marker, chip measurement
Round-5 review Criticals:
- core: key renamed diff entries by the real (post-rename) path and carry
the old path for display, so renamed rows can be expanded — the synthetic
`old => new` key was sent to git as a nonexistent literal path. The diff
dialog renders the rename as `old → new`.
- core: preserve Git's `\ No newline at end of file` marker through the hunk
parser so a trailing-newline-only edit isn't shown as identical
removed/added lines (the viewer already renders it as a meta row).
- web-shell: the toolbar's hidden git-chip measurement replica now renders
the full chip content via the extracted GitBranchChipContent, so the
expanded width includes the status indicators and the compact/expanded
toggle no longer oscillates near the responsive threshold.
* fix(build): generate git-commit info even when prepare build is skipped
The review tooling runs `npm ci` with QWEN_SKIP_PREPARE=1 (to skip the
heavy prepare build) and then builds only the changed workspaces. Because
`prepare` exited before generating the gitignored git-commit.ts, a
per-workspace build of packages/cli failed at the unchanged systemInfo.ts
on the missing `../generated/git-commit.js` module. Generate the git-commit
info in the skip path too — it is cheap and never fails hard — so a later
per-workspace build or typecheck finds the module. The non-skip path still
generates it via `npm run build`.
* fix(web-shell,cli): address round-6 review suggestions
- cli: carry the pre-rename path (oldPath) through DiffRenderRow and show
renamed files as `old → new` in both the Ink and plain-text renderers.
The rename-keying fix updated the daemon and web-shell dialog but not the
CLI `/diff` renderer, which silently dropped the old path.
- web-shell: key DiffFileRow by workspace + path so switching workspace
remounts the row instead of reusing another workspace's hunks/open state
for a path both workspaces share.
- web-shell: show a loading placeholder in DiffHunks while rows are (re)built
(e.g. after a theme switch) instead of an empty, jumpily-resized box.
- web-shell: cover the /diff local intercept in App.test.tsx (opens the
Changes dialog and is not forwarded to the agent).
* fix(web-shell,cli,core): address round-7 review suggestions
- cli: sanitize the rendered filename (and pre-rename oldPath) in the Ink
DiffStatsDisplay via sanitizeFilenameForDisplay, matching the plain-text
renderer so a crafted path can't inject into the interactive view.
- cli: apply the read headers before awaiting the per-file diff fetch (as
handleDiffList does) so error responses also carry no-store/nosniff.
- cli + web-shell: strip Unicode bidi embedding/isolate controls
(U+202A-202E, U+2066-2069) in the filename/control-char sanitizers so a
crafted filename can't visually spoof its extension.
- core: guard countStashEntries with an lstat type check before readFile, so
a symlink-to-FIFO at logs/refs/stash can't block the event loop (the same
hazard already guarded in the untracked-file readers).
- core: cover fetchGitDiffHunksForFile's transient-state guard with a test
(the sibling helpers already had one).
* fix(web-shell,cli,core): address round-8 review suggestions
- core: pass --no-optional-locks to the ls-files call in
fetchGitDiffHunksForFile, matching the other runGit calls so it doesn't
contend for an optional index-refresh lock alongside concurrent git
add/commit.
- cli: add a route test asserting a rename's oldPath survives serialization
end-to-end (keyed by the new path, old path carried alongside).
- web-shell: add a GitDiffDialog test for the hiddenCount>0 "N more files
not shown" note (every payload previously used hiddenCount: 0).
- web-shell: drop the nonexistent primaryLabel prop from the WorkspaceSection
test (it is not a WorkspaceSectionProps member).
- docs: correct the plan doc — large-diff virtual scrolling was explicitly
descoped (core caps + per-file lazy loading), not implemented in Phase 2.
* fix(cli,web-shell): address round-9 review findings
- cli: propagate the pre-rename oldPath through DiffDialog's
perFileToUnified and render renamed files as `old → new` in the
interactive diff viewer (the rename-keying fix had updated the daemon,
the web-shell dialog, and the /diff stats, but not this viewer).
- cli: cover DiffStatsDisplay's rename (`old → new`) rendering and the
sanitizeFilenameForDisplay path for hostile filenames carrying control
characters.
- web-shell: guard the GitBranchIndicator test afterEach against
double-unmounting an already-unmounted root (the localization tests
assert on getTranslator without calling render()).
* fix(core,cli,web-shell): rename-aware single-file diff (old→new)
fetchGitDiffHunksForFile pathspec-limited the diff to the new path, which
defeats git's rename detection — a renamed file was reported as fully
added (every line +) instead of its actual edit. Thread an optional
pre-rename path through the single-file endpoint (core → route → SDK →
dialog) and diff old→new with -M when it is present, so expanding a
renamed file shows its real content change.
* fix(cli): address round-10 review suggestions
- DiffDialog: split the path-width budget between old and new paths for a
rename (reserving the " → " separator) so the combined width stays within
maxPathChars instead of overflowing the row layout.
- textUtils: extend MULTILINE_CONTROL_CHARS_REGEX with the Unicode bidi
ranges (matching FILENAME_CONTROL_CHARS_REGEX) and add a test that
sanitizeFilenameForDisplay strips bidi embedding/isolate controls.
- workspace-git-diff route: add a test that ?oldPath= is parsed and
forwarded to fetchGitDiffHunksForFile.
* test(sdk),docs: cover diff client methods; align design doc
- sdk: add DaemonClient unit tests for workspaceGitDiff() and
workspaceGitDiffFile(path, oldPath?) — URL construction (incl. urlEncode
on path/oldPath, with and without oldPath, plus the workspace-qualified
route) and response deserialization, mirroring the existing workspaceGit()
test.
- docs: add the oldPath? param to the workspaceGitDiffFile API spec; record
that the diff client methods now have unit tests (correcting the claim
that workspaceGit() had none); attribute the bundle-limit bump to
packages/sdk-typescript/scripts/build.js; clarify ahead/behind are relative
to upstream (0, and ↑N/↓N not shown, without one).
* fix(web-shell,core): address round-11 review suggestions
- GitBranchIndicator: count conflicted entries as dirty — a merge where every
changed file is conflicted (staged=unstaged=untracked=0) is still
uncommitted, so the expanded chip's dirty dot / data-dirty now reflect it.
- core: split the status branch line at the last "..." (the branch/upstream
separator) so a dotted branch name isn't truncated at the first "...".
- GitDiffDialog: guard DiffFileRow's in-flight fetch against unmount via a
cancelled ref, matching DiffHunks / GitDiffDialog.
- tests: forward oldPath when expanding a renamed file in the web-shell
dialog; bidi-strip coverage for the web-shell sanitizeControlChars;
untrusted-guard coverage on the single-file diff route; conflicted-only
dirty; branch-line "..." split.
* fix(web-shell,cli): address round-12 review suggestions
- DiffDialog: only render the rename "old → new" when there's room for both
sides (≥19 cols, so each gets ≥8); otherwise fall back to the new path
alone, so a narrow terminal no longer overflows the row (the Math.max(8,…)
floor could exceed maxPathChars).
- GitBranchIndicator test: guard afterEach container.remove() for non-render
tests run in isolation, and make the compact-mode ↑-suppression assertion
non-vacuous by giving the fixture an ahead count.
- App: compute the active workspace once (useMemo) and share it between the
git-status effect and the Changes-dialog entry point, so the chip and the
dialog can't drift onto different repos.
* fix(core,docs): address round-13 review suggestions
- core: add a rebase-apply detection test (git am / an interrupted
`rebase --apply` creates rebase-apply, which detectGitOperation also maps
to 'rebase'); previously only rebase-merge was exercised.
- docs: correct section 5 to describe the actual diff-dialog mechanism
(diffWorkspaceCwd state, not the stale activePanel design).
* test(core): cover stray no-newline marker before any hunk header
parseGitDiff's pre-hunk guard already skips a "\ No newline at end of
file" marker that appears before any @@ header, so a malformed/truncated
diff can't throw on a null currentHunk and lose subsequent files' hunks;
add a regression test pinning that behavior.
* fix(web-shell): unstick per-file diff loading and skip non-path git poll
- DiffFileRow: reset the cancelled-fetch flag on mount so StrictMode's
mount/unmount/mount replay no longer leaves it latched at true, which
dropped the fetched hunks and froze the row on "Loading changes…" despite
a 200 response.
- WorkspaceSection: skip the git status poll when the workspace cwd is not an
absolute path. A synthetic fallback workspace carries a display name there,
which the cwd-qualified route rejects with a 400.
* fix(web-shell,cli): address review suggestions on the git diff surface
- GitDiffDialog: highlight each diff side independently so a small side
keeps syntax highlighting even when the other side exceeds the size cap
(the old guard dropped both as soon as either was too large).
- ChatEditor: complete the .gitBranchChipButton reset (font/color/padding/
margin) so the clickable dirty-tree chip matches the read-only output chip
instead of picking up UA button styling.
- DiffDialog: cover the interactive rename display (old to new on a wide
terminal), mirroring the rename tests DiffStatsDisplay and GitDiffDialog
already have.
* test(web-shell,cli): cover git chip clean/reload/traversal paths, fix doc
- GitDiffDialog: add the missing expect(header).not.toBeNull() guard to the
three expand-file tests that lacked it, matching the others in the block.
- GitBranchIndicator: cover the known-clean aria-label branch (computedAt set
and every change counter zero).
- WorkspaceSection: verify a reloadToken change re-fetches git status instead
of waiting for the next 60s poll.
- workspace-git-diff route: verify a traversal oldPath is forwarded to core
and surfaced as available:false rather than escaping the workspace.
- Design doc: /diff is handled via setDiffWorkspaceCwd, not setActivePanel.
* fix(core): allow literal `..foo` paths in diff normalization
- toRepoRelativePath: reject only a real climb-out (`..` or `../…`), not a
literal `..foo` filename at the repo root, which the bare startsWith('..')
over-rejected, leaving the diff viewer unable to render such a file.
- parseGitDiff: cover the truncatedPaths output set directly (it was only
exercised indirectly through fetchGitDiffHunksForFile).
---------
Co-authored-by: wenshao <wenshao@example.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
|
||
|
|
a9a6ca4ac6
|
feat(channels): observe group names from inbound messages (#7155)
* feat(channels): expose observed workspace contacts * fix(channels): address observed contacts review feedback * docs(channels): design observed group names * docs(channels): plan observed group names * feat(channels): observe inbound group names --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> |
||
|
|
d4db5fcfab
|
feat(core): improve subagent delegation defaults and guardrails (#7048)
* docs(design): define default background subagents * feat(core): improve subagent delegation defaults * docs(core): cross-reference the three background-classification sites Add pointer comments linking the core dispatch source of truth (AgentTool.execute) and its two UI mirrors (web-shell isBackgroundSubAgentToolCall, desktop detectBackgroundEvents) so the replicated top-level-agent background heuristic is not changed in isolation. Addresses PR review feedback. * fix(core): align background classification for fork and named-teammate launches Address review feedback on the background-classification rule so core dispatch and the two UI classifiers stay consistent: - core: exclude a name-without-active-team launch from the default-background path so it stays foreground, matching both UI classifiers (which exclude name). Previously such a launch was backgrounded by core but tracked as foreground by the UIs. - web-shell and desktop classifiers: exclude subagent_type "fork" from the default-background heuristic, mirroring core's !isForkRequested guard. A top-level fork request with an omitted flag runs foreground in core but was classified as background by the UIs. - add a core dispatch test asserting a working_dir launch with an omitted run_in_background flag stays in the foreground. * test: cover fork/background classification and precedence per review feedback Address unresolved review threads on PR #7048: - Add web-shell and desktop UI classifier tests asserting an omitted-flag `subagent_type: "fork"` launch stays in the foreground, verifying the documented `!isForkRequested` parity with core dispatch. - Add a core AgentTool test asserting an explicit `run_in_background: false` overrides a subagent config with `background: true`, locking in the `run_in_background ?? config` precedence against a `||` regression. - Harden the Explore read-only prompt: pipelines must not send data to a network endpoint (no curl/wget/nc), closing the `cat file | curl` exfiltration gap. * fix(core): restore general no-unnecessary-files guard in general-purpose prompt Address review feedback: the rewritten general-purpose prompt dropped the broad guard against creating unrequested files, keeping only the documentation-specific line. Restore a general 'do not create files unless necessary' guard so speculative utility/config files are not created. * test(desktop): cover named-teammate foreground guard in detectBackgroundEvents Add a desktop tool-matching test asserting a top-level Agent with a `name` set (named teammate) stays foreground and emits no task_backgrounded event, mirroring the web-shell classifier's named-teammate coverage and the existing fork-exclusion test. * test(core): cover named-teammate foreground dispatch when flag omitted Add a core-dispatch test asserting a top-level Agent launch with `name` set and `run_in_background` omitted stays foreground when no team is active, guarding the `this.params.name === undefined` exclusion in backgroundRequested directly (previously only covered by the UI classifiers). --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
02cb3a6380
|
feat(channels): expose workspace-scoped observed contacts (#7109)
* feat(channels): expose observed workspace contacts * fix(channels): address observed contacts review feedback --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
4b802ca5f9
|
feat(channels): support DingTalk webhook delivery to direct messages (#6891)
* docs(channels): design DingTalk webhook DM delivery * docs(channels): translate DingTalk webhook DM design * feat(channels): support DingTalk webhook direct messages * fix(channels): isolate DingTalk webhook DM targets * fix(channels): handle DingTalk direct delivery failures * fix(channels): reject malformed DingTalk responses |
||
|
|
fea3ab3854
|
feat(serve): add extension management v2 (#6825)
* feat(cli): workspace-qualified extensions REST (daemon multi-workspace) Mirror the daemon extension-management REST surface to per-workspace routes, reusing the Phase 3 runtime resolver and trust gate. Extract a per-workspace extensions controller so the primary workspace shares one install queue, operation history, and status cache across the legacy and workspace-qualified routes. Reads resolve the target runtime only; mutations require a trusted workspace. Advertise a new baseline capability so clients can discover the surface, and add matching SDK client methods. Refs #6378. * qwen: address PR review feedback (#6638) Align the new extensions controller file's copyright year with the other new files added in this change. * qwen: address PR review feedback (#6638) Redact credentials from the extension source on the two success-path fan-outs (session refresh and refresh-failure broadcast), matching the operation record and failure broadcast. Document the non-cancellation semantics of the extension timeout wrapper. * qwen: address PR review feedback (#6638) Share the queue-full sentinel message via an exported constant so the throw site (controller) and the 429 match site (routes) cannot drift after the module split. Include the bound workspace in the extension operation log prefixes so concurrent per-workspace controllers are distinguishable in stderr. * feat(cli): add concurrent extension preparation Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): remove redundant extension context build Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): address extension review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): address final review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): address latest review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): reject links in npm extension archives Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): limit npm extension archive downloads Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): address review follow-ups Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): address latest review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): release rejected operation slots Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): address operation review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): align archive handling contracts Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): preserve watcher generation state Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs(extensions): align management contracts Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(sdk): bound extension operation polls Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(core): cover forged prepared commits Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(core): assert activation generation increment Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): close archive and polling gaps Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): retry suppressed extension generations Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(cli): cover archive URL extension updates Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(sdk): preserve unbounded operation waits Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): share npm redirect download deadline Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): preserve extension reload diagnostics Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): preserve installed Claude plugin paths Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): return committed activation state Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): preserve extension preparation errors Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): validate extension setting env vars Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): target extension reconciliation Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(cli): cover resultless legacy commit warnings Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): retain suppressed extension generations Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): record legacy runtime reconciliation Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): validate extension clients by runtime Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): record workspace activation refresh Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(cli): stop extension reconcilers after cases Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): resolve global runtimes at reconciliation Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): reconcile newly registered runtimes Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): prevent overlapping runtime reconciliation Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): dispose late runtime apps during shutdown Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): keep projection repair best effort Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): preserve committed store results Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): quarantine corrupt store journals Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): harden npm download redirects Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): address review edge cases Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): honor cancellation between preparation stages Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): retry prepared cleanup failures Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(extensions): cover committed artifact recovery boundary Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(serve): release extension refresh queue on timeout Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix: address extension review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6638) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): reconcile extension store compatibility state Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): bound npm redirects and isolate extension tests Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): make extension uninstall store-authoritative Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): defer prepared extension secret mutations Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): validate staged extensions before commit Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): enforce public extension network policy Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): handle extension response failures Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): surface committed refresh warnings Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): guard timer unref calls Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): release commit lane after durable writes Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(serve): update mutation callback assertions Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(serve): refresh live extension instructions Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): address latest review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): address follow-up review findings Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): address remaining activation feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(serve): preserve preparation queue status Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): enforce network request deadlines Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs(serve): clarify single-workspace capabilities Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): guard deferred settings commit Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): cancel archive extraction Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): harden refresh recovery Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(serve): serialize extension reconciliation Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(extensions): address post-commit review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6825) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6825) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6825) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: fix CI failure on PR #6825 Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: fix CI failure on PR #6825 Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6825) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix: address critical PR review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): bound legacy extension update checks Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(acp): deduplicate extension refresh requests Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6825) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6825) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6825) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6825) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(sdk): update browser bundle budget after main merge Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> |
||
|
|
263dbba741
|
fix(core): preserve managed memory during microcompaction (#6714)
* fix(core): preserve managed memory during microcompaction Refs #6487 * test(core): cover managed memory read errors --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
230db17650
|
feat(cli): group daemon channel workers by workspace (phase 4b) (#6635)
* feat(cli): group daemon channel workers by workspace (phase 4b) Multi-workspace `qwen serve --channel` now runs one channel worker per owning workspace instead of a single primary-bound worker. Each worker binds to its workspace's directory, daemon-workspace env marker, and effective env overlay. Channels are grouped implicitly by their configured working directory: a channel belongs to the registered workspace its resolved cwd matches, mirroring the worker's own workspace validation. Unknown, ambiguous, or untrusted targets fail fast at startup. The pidfile and daemon status grow an additive per-workspace worker list while keeping the existing single-worker fields for older readers; single-workspace daemons stay byte-identical to before. `--channel all` stays primary-only. Refs #6378 * fix(cli): harden multi-workspace channel workers Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): close listener after channel worker startup failure Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): restore grouped channel webhooks Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): mount runtime before channel workers start Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6635) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(cli): strengthen channel worker edge coverage Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * chore(cli): address channel review suggestions Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
ff514476de
|
feat(cli): workspace-qualified ACP transport (daemon multi-workspace phase 4) (#6621)
* docs(design): add daemon multi-workspace phase 4 (workspace-qualified ACP) design * feat(cli): add workspace-qualified ACP transport (issue #6378 phase 4) Per-runtime ACP dispatcher at /workspaces/:workspace/acp (HTTP + WS) dispatched by URL path from the single upgrade listener; per-runtime device-flow + reverse client-MCP; owner-index via bridge lifecycle; untrusted/unknown rejected; legacy /acp unchanged; advertise workspace_qualified_acp for multi-workspace. * fix(cli): keep per-runtime device-flow registry out of serve fast-path bundle Phase 4 secondary-runtime device-flow statically imported createDeviceFlowRegistry into run-qwen-serve, pulling glob/@iarna/toml into the serve fast-path bundle and failing the closure check. Import it dynamically at the creation site; the check now passes and behavior is unchanged. * refactor(cli): drop per-runtime device-flow for secondary workspaces Follow-up to the fast-path fix: instead of dynamically importing createDeviceFlowRegistry for secondary runtimes, drop the per-runtime device-flow wiring entirely. Secondary ACP device-flow falls back to the dispatcher default, keeping the serve fast-path bundle closure clean without the dynamic-import indirection. WorkspaceRuntime.deviceFlowRegistry stays optional for a future per-runtime hook. * fix(cli): share daemon-global device-flow across ACP mounts; harden WS path parsing Secondary ACP mounts share the daemon-global device-flow registry (single instance per daemon) instead of a per-runtime one; the event sink fans out to every trusted runtime bridge so secondary ACP clients receive their own flow events, fixing the reviewer #6621 Critical and the CI test failure. Drops WorkspaceRuntime.deviceFlowRegistry. WS upgrade path is parsed from the raw request-target instead of new URL().pathname, rejecting %2e%2e / backslash / dot-segment traversal. * refactor(cli): gate CDP claim on primary mount; return plural ACP POST promise Add a primary flag to RuntimeAcpMount so a secondary workspace's ACP connection cannot claim the CDP tunnel -- the claim is gated on activeMount.primary, matching the primary-only chrome-devtools MCP wiring. The plural /workspaces/:workspace/acp POST handler returns the dispatch promise instead of voiding it. * refactor(cli): centralize ACP-HTTP enablement in resolveAcpHttpEnabled Add resolveAcpHttpEnabled() as the single interpretation of the QWEN_SERVE_ACP_HTTP opt-out, replacing four independent env checks across mount, voice-WS advertisement, and CDP-MCP gating. Advertise workspace_qualified_acp only when the ACP HTTP surface is enabled AND multi-workspace sessions are active, so it is not announced when ACP HTTP is disabled. * feat(cli): ACP dispose 503 gate + aggregate connection snapshot across mounts After dispose() the shared ACP HTTP handlers (legacy /acp + workspace-qualified) return 503 server_disposed instead of racing torn-down registries during the shutdown drain. Add AcpHttpHandle.getSnapshot() aggregating connection and wsStream counts across the primary mount and every trusted secondary runtime, and switch the metrics sampler to it so daemon metrics report all workspaces' ACP connections rather than only the primary's. * test(cli): cover ACP dispose 503, aggregate snapshot, and raw dot-segment WS reject * docs(design): record Phase 4 ACP systematic rework (8-axis hardening) Correct the Summary (the device-flow registry stays daemon-global and shared, not per-runtime) and add a section documenting the final architecture: runtime mount factory, routing/trust isolation, raw request-target WS parsing, daemon-global device-flow with event-sink fan-out, primary-only CDP, disposed 503 gate, aggregate getSnapshot, and resolveAcpHttpEnabled-gated capability advertisement. * fix(cli): align /daemon/status ACP counts with the aggregate mount snapshot Code review found a drift: the metrics sampler switched to the aggregate AcpHttpHandle.getSnapshot() (all mounts) while /daemon/status still read the primary-only registry snapshot, so the two observability surfaces diverged under multi-workspace. Extend AcpHttpSnapshot to aggregate all transport counters (connection/session/sse/ws streams + pending client requests) and feed the /daemon/status transport summary from it; per-connection diagnostics and the connection cap stay primary-scoped. Also refresh the device-flow-registry doc comment to the daemon-global shared model. * test(cli): regression-test device-flow on a trusted secondary workspace Locks in the reviewer Critical fix: a trusted secondary workspace's ACP now shares the daemon-global device-flow registry, so device_flow/start reaches provider resolution (an unsupported-provider error here) instead of erroring 'Device flow not configured'. Wires a shared DeviceFlowRegistry into the test harness and drives initialize + device_flow/start over the secondary WebSocket. * docs(design): mark the superseded per-runtime device-flow section Address PR #6621 review: the pre-rework 'Per-runtime device-flow registry' section contradicted Systematic rework axis 4 (daemon-global shared registry + fan-out). Flag it as superseded design-history so readers don't build the wrong mental model. * refactor(cli): mount ACP only for trusted secondary workspaces Address PR #6621 review suggestions: (1) skip creating a dispatcher/registry/remember-lane for untrusted non-primary workspaces (they are 403-rejected before any mount lookup), so they no longer appear as always-zero entries in the aggregate getSnapshot(); (2) test that a secondary workspace cannot claim the process-wide CDP tunnel (primary-only guard); (3) test that a WS upgrade to an unknown selector is rejected 400. * test(cli): cover device-flow event fan-out across bridges Address PR #6621 review: the resolveEventBridges fan-out (the reviewer Critical fix's core delivery path) had zero test coverage. Add unit tests that a device-flow event reaches every resolved bridge, that one bridge throwing does not block the others (best-effort), and that it falls back to the single bridge when no resolver is provided. * fix(cli): report ACP connection pressure across all mounts Address PR #6621 review: the connection_capacity_high warning read the primary mount's snapshot only, so a saturated secondary workspace was invisible. Compute the busiest mount from the aggregate snapshot (per-mount cap is uniform, opts.maxConnections) so any mount nearing capacity triggers the warning. * test(cli): allow acp-http-enabled.ts in the serve process.env guard Fix CI failure on PR #6621: the serve process.env guard flagged the new acp-http-enabled.ts as a direct process.env reader. It is the QWEN_SERVE_ACP_HTTP interpreter extracted from index.ts and serve-features.ts (both already allow-listed); QWEN_SERVE_ACP_HTTP is a daemon-level process-global toggle, so the file inherits their allow-list entry. * docs: harden workspace-qualified ACP design Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: plan workspace-qualified ACP hardening Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): align workspace-qualified ACP routing Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): harden qualified ACP request errors Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(cli): cover unmarked URIError fallback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): make ACP disposal terminal Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): aggregate ACP connection diagnostics Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * chore: remove review process artifact Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): address workspace ACP review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): finish ACP review follow-ups Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
067cfbba62
|
docs: consolidate design docs and plans under docs/ (#6417)
Design docs and implementation plans were scattered across .qwen/design, .qwen/plans, and docs/superpowers. The .qwen/ locations are git-ignored, so docs written there never got tracked, while docs/design already held the richer, version-controlled set. Consolidate everything under docs/design and docs/plans, relocate two stray root docs into docs/design, and repoint the references left dangling by the move (moved-doc cross-links and a few source comments). Also update AGENTS.md and the feat-dev skill so the documented workflow writes new design docs and plans to the tracked docs/ locations. Co-authored-by: DragonnZhang <dragonzhang1024@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
6a726f6c63
|
refactor(core): centralize extension runtime refresh (#6152)
* refactor(core): centralize extension runtime refresh * test(core): add regression tests for allSettled and try/catch resilience in refreshExtensionRuntime * test(core): add restartMcpServers reject test and restore design rationale comments Address @wenshao's review feedback: - Add test for restartMcpServers rejection (the only fatal error path) - Restore key 'why' comments about allSettled and try/catch design decisions - Logger tag change to EXTENSION_RUNTIME_REFRESH is intentional (standalone module) * docs(core): add error-handling tier contract to refreshExtensionRuntime Add block comment documenting the three-tier error-handling contract (fatal/swallow/swallow) so future maintainers know which tier applies when adding new refresh steps. Addresses review feedback on #6152. --------- Co-authored-by: 俊良 <zzj542558@alibaba-inc.com> Co-authored-by: 易良 <1204183885@qq.com> |
||
|
|
a8a6ad2d06
|
feat(core)!: redesign auto-compaction thresholds with three-tier ladder (#4345)
* feat(core)!: redesign auto-compaction thresholds with three-tier ladder
Replaces the single 70% proportional threshold with a three-tier ladder
(warn/auto/hard) that combines proportional fallback with absolute
reservation. Large-window models (>=128K) now reserve ~33K instead of
30% of the window, freeing tens of thousands of context tokens that the
old formula wasted.
Other improvements bundled in the same redesign:
- Compression sideQuery now disables thinking and caps maxOutputTokens
at 20K, matching claude-code so the buffer math is predictable across
providers (Anthropic/OpenAI/Gemini handle thinking budgets
inconsistently)
- Failure handling upgraded from one-shot permanent lock to a 3-strike
circuit breaker; reactive overflow still latches immediately
- New estimatePromptTokens helper closes the lag-by-one-turn and
first-send-is-0 gaps in lastPromptTokenCount
- Hard-tier rescue pulls reactive overflow recovery forward to before
the API call, saving an oversized round-trip
- /context command displays the three-tier ladder + current tier
- tipRegistry's context-* tips track the new thresholds instead of
fixed 50/80/95 percentages
BREAKING CHANGE: chatCompression.contextPercentageThreshold setting is
removed. Settings files containing the field log a one-line deprecation
warning at startup and the value is ignored; behaviour is now controlled
by built-in thresholds via the new computeThresholds() function.
Design: docs/design/auto-compaction-threshold-redesign.md
Plan: docs/plans/2026-05-14-auto-compaction-threshold-redesign.md
* test(core): fix leftover hasFailedCompressionAttempt option in compress test
A pre-existing test case at chatCompressionService.test.ts:678 still
passed `hasFailedCompressionAttempt: false` in the CompressOptions
shape; rebasing onto current main surfaced this as a typecheck error
because the field was renamed to `consecutiveFailures` (Task 7 of the
three-tier ladder migration). Update to `consecutiveFailures: 0` —
semantically equivalent, the test asserts the side-query is called
when `force: true`, no other behaviour change.
* fix(core): drop compaction summary when output hits maxOutputTokens cap
Adds a defensive guard in ChatCompressionService.compress() that detects
when the side-query summary hit COMPACT_MAX_OUTPUT_TOKENS (20K). In that
case the summary is likely truncated mid-content, so we drop it and
return NOOP rather than persist a half-summary. The next send re-tries;
reactive overflow still catches the catastrophic case where the API
rejects the next request as too large.
Documented in the design doc as risk #2; the bot reviewer on PR #4168
correctly pushed for it to land alongside the threshold redesign rather
than as a follow-up since the new 20K cap is what makes truncation
likely in the first place.
* fix(cli): render three-tier thresholds in /context TUI view
The Task 11 redesign updated the non-interactive text formatter
(formatContextUsageText) but left ContextUsage.tsx — the interactive
React component that real /context users see — unchanged. As a result
the TUI still showed the old single "Autocompact buffer" line and none
of the new warn/auto/hard ladder.
Adds a "Compaction thresholds" section after the per-category breakdown:
- Effective window
- Warn / Auto / Hard threshold rows with a ▶ marker on the row the
current usage has crossed
- Current tier label coloured by severity (safe→green, warn/auto→
yellow, hard→red)
The existing progress bar legend (Used / Free / Autocompact buffer)
is preserved because it's tied to the three-segment progress bar
visualisation; the new section adds the absolute numbers + tier badge
on top of that.
Caught by the tmux e2e test (PR #4168 ci-monitor follow-up). Pre-fix
the assertion 'Compaction thresholds' missed completely from the TUI;
post-fix the new section renders correctly for fresh and live sessions
on 1M / 200K / 128K windows.
* fix(core,cli): address PR #4168 review batch 4
Behavior fixes:
- MAX_TOKENS truncation guard now returns COMPRESSION_FAILED_EMPTY_SUMMARY
instead of NOOP so the consecutive-failure breaker actually trips after
repeated max-length summaries (R1.1).
- Reactive overflow failure increments consecutiveFailures by 1 instead
of latching to MAX in one shot, so a transient network blip doesn't
permanently disable auto-compaction. The hard-tier rescue resets the
counter, which remains the designated recovery path (R1.2).
- /context current-tier classification uses rawOverhead (system + tools +
memory + skills) as the tier input when API data is not yet available,
rather than 0 — large inherited contexts no longer silently show 'safe'
(R2.2).
Performance:
- sendMessageStream computes effectiveTokens ONCE and passes it through
TryCompressOptions.precomputedEffectiveTokens, so the cheap-gate inside
service.compress doesn't redo the estimation. Also fixes the
imageTokenEstimate inconsistency between the rescue and cheap-gate
paths (R1.3 + R1.4).
- Steady-state path (lastPromptTokenCount > 0) skips the costly
getHistory(true) clone — estimatePromptTokens only needs the user
message in that branch.
Code hygiene:
- BYTES_PER_TOKEN → CHARS_PER_TOKEN (inputs are char counts, not byte
counts; CJK text would mislead under the old name) (R3.1).
- Drop dead getContextUsagePercent helper + index re-export — no callers
in source after the threshold rewire (R1.5).
- Add a comment on estimatePromptTokens' first-send fallback documenting
the ~15-20K under-estimate (system prompt + tools + skills) and that
reactive overflow is the safety net (R3.3).
Tests:
- New CLI ContextUsage.test.tsx exercises the React renderer for the
three-tier section: section presence, ▶ marker placement per tier,
current-tier label coloring (R1.6).
- New chatCompressionService.test.ts case pins that a stale
contextPercentageThreshold: 0 value in user settings no longer
short-circuits compaction (R2.1).
- New tokenEstimation.test.ts case covers functionResponse (distinct
nested-parts branch from functionCall) (R3.5).
- New geminiChat.test.ts integration test exercises the real
ChatCompressionService — not a mock — for the first-send-after-
inherited-history scenario where lastPromptTokenCount=0 and only the
full-history estimate can cross the auto threshold (R3.4).
Declined: R3.2 (change `>=` to `>` on the MAX_TOKENS guard). The current
operator catches the at-cap case as suspicious, which is intentional —
landing exactly at the output cap is far more likely truncation than
clean stop given p99.99 ≈ 17K. With R1.1 in place, persistent truncations
trip the breaker after MAX_CONSECUTIVE_FAILURES so the worst case is
bounded.
* fix(core,cli): address PR #4168 review batch 5
- R5.1: tighten /context tier comment + TODO. The rawOverhead-based fix
doesn't cover `--continue` restores with many history messages (since
rawOverhead excludes messagesTokens). UI may still show 'safe' for one
render until the first send. Documented inline and added a TODO to plumb
chat history into collectContextData for same-source-of-truth as the
cheap-gate.
- R5.2a: add TODO(finish_reason) at the truncation guard. The `>= cap`
heuristic false-positives on legitimate at-cap summaries; the proper
signal is finish_reason which runSideQuery doesn't surface today.
- R5.2b: split telemetry — new CompressionStatus.COMPRESSION_FAILED_OUTPUT_TRUNCATED
enum value. Distinct from EMPTY_SUMMARY so logs/telemetry can tell
prompt-quality failures (tune prompt / splitter) from capacity failures
(raise cap / shrink splitter input). isCompressionFailureStatus()
treats both as failures so the breaker behavior is unchanged.
- R5.3: expand consecutiveFailures JSDoc to clarify it tracks
"non-force, non-hard-rescue consecutive failures" — hard-rescue resets
the counter and force=true skips increments, so the counter is the
"regular path" health signal only; reactive overflow is the real
safety net for the force-only paths.
- R5.4: document the CompressOptions field rename
(hasFailedCompressionAttempt: boolean → consecutiveFailures: number)
as an SDK breaking change in the design doc with migration guide.
* fix(core): disambiguate hard-rescue from manual /compress orphan-strip
Self-review (dual reviewer / pr-triage round 1) caught a correctness
regression in the hard-rescue path:
`sendMessageStream` calls `tryCompress(force=true)` from inside the
pre-push window when `effectiveTokens >= hard`. The service's
orphan-strip predicate at `chatCompressionService.ts:426-429` gated on
`force` alone, which conflated two distinct call shapes:
- manual `/compress` (force=true, trigger='manual'): user-initiated
between turns; trailing model funcCall IS orphaned because no
funcResponse is coming
- hard-rescue (force=true, trigger='auto'): automatic mid-turn;
trailing model funcCall is ACTIVE because its matching funcResponse
is sitting in the pending `userContent` waiting to be pushed
The strip fired for both, so a hard-rescue triggered mid tool-use loop
would drop the active funcCall. After compression returned and
`userContent` (the funcResponse) was pushed, the next API request
carried tool_result with no matching tool_use → provider validation
error.
The in-code comment at L422-424 already documented this exact
constraint for the auto-compress case (`force=false`), but reusing
`force=true` for hard-rescue silently violated the same constraint.
Fix:
- Gate `hasOrphanedFuncCall` on `compactTrigger === 'manual'` instead
of `force`. The trigger field already disambiguates intent.
- `sendMessageStream` hard-rescue now passes `trigger: 'auto'`
explicitly (without it, `force=true` defaults to `trigger='manual'`
via the `?? (force ? 'manual' : 'auto')` resolver).
Sibling audit for "force=true non-manual callsites":
- `GeminiClient.tryCompressChat` (manual /compress): correct — manual
- `sendMessageStream` hard-rescue: fixed in this commit
- `sendMessageStream` reactive overflow catch: already passes
trigger='auto'; runs AFTER API call (userContent in history), so if
it observes a trailing funcCall it IS orphaned but findCompressSplitPoint
handles the case without needing the strip
RED-first regression test added:
`preserves trailing model+funcCall under hard-rescue (force=true + trigger=auto)`
in `chatCompressionService.test.ts`. Failed against pre-fix code (the
strip dropped the funcCall); passes against the fix.
Adjacent fixes from the same triage round:
- `docs/users/configuration/settings.md`: the
`chatCompression.contextPercentageThreshold` row still said "use 0
to disable compression entirely" — code has ignored the value since
the removal commit. Marked the row REMOVED with migration guidance
pointing at the design doc.
- `packages/core/src/config/config.ts`: the deprecation warning now
tells users how to silence it (remove the key) and where to read
current behavior, instead of just announcing the removal.
- `docs/design/auto-compaction-threshold-redesign.md`: closed Open
Question 2 (small-window hard/auto collapse) — decision is to NOT
annotate `/context`, with rationale on file.
Tests: 2395 core tests passing, typecheck clean.
* docs(core): fix tier-collapse direction in auto-compaction design doc
Self-review on the
|
||
|
|
a3037889a6
|
fix(core): replace structuredClone with shallow copy to prevent OOM in long sessions (#4286)
* docs: add OOM investigation reports and auto-compaction redesign proposal
- Runtime memory investigation plan
- Non-interactive memory benchmark report
- OOM reproduction report with 2GiB/4GiB synthetic tests
- Runtime diagnostics benchmark report
- Auto-compaction threshold redesign proposal
* fix(core): replace structuredClone with shallow copy to prevent OOM
Replace `structuredClone(this.history)` (called up to 4x per turn on the
send path) with a lightweight shallow copy via `copyContentContainer()`.
This eliminates the OOM root cause in long tool-heavy sessions where the
full deep clone exceeded remaining V8 heap headroom.
Key changes:
- Add `copyContentContainer()` helper ({...content, parts: [...parts]})
- Add `getRequestHistory()` private method for the send path
- Add `getHistoryShallow()`, `getHistoryTailShallow()`,
`peekLastHistoryEntry()`, `getLastModelMessageText()`,
`getHistoryLength()` for read-only callers
- Remove HEAP_PRESSURE_COMPRESSION_RATIO safety net (no longer needed
now that the underlying OOM cause is fixed)
- Update chatCompressionService to use getHistoryShallow(true)
- Update nextSpeakerChecker to send only lastMessage (not full history)
- Update memoryDiagnostics with process-tree RSS measurement
* feat(core): add runtimeDiagnostics utility for heap/memory instrumentation
Required by content generators (anthropic, openai, logging) which import
runtimeDiagnostics for optional heap-pressure telemetry during streaming.
Gated by QWEN_CODE_PROFILE_RUNTIME=1 environment variable.
* fix(cli): update doctorCommand test mocks for new MemoryDiagnostics interface
Add missing maxRSSRaw, maxRSSUnit, and processTree fields to test fixtures
to match the updated MemoryResourceUsage and MemoryDiagnostics interfaces.
* fix(vscode-ide-companion): use public core imports
* fix: address review comments — type guards, dead fallbacks, and doc accuracy
Code:
- Fix unsound type guard: `'text' in part` → `typeof part.text === 'string'`
in geminiChat.ts and client.ts (Copilot + wenshao feedback)
- Remove unnecessary optional chaining and dead fallback chains in client.ts
(getHistoryShallow, peekLastHistoryEntry, getHistoryLength, etc. now call
GeminiChat methods directly)
- Add 5s timeout to `execFileAsync('ps', ...)` in memoryDiagnostics.ts
Docs:
- Fix GiB conversion accuracy and add single-run caveat to summary
- Add Node.js version to test environment table
- Fix auto-compaction attempt count (5→4) in OOM report
- Soften root-cause attribution certainty
- Add MCP child process context to investigation plan
- Clarify "Codex" reference (→ OpenAI Codex)
- Fix truncated MCP server name (chrome → chrome-devtools)
- Remove duplicate verification commands in benchmark table
- Clarify thread exhaustion vs V8 heap OOM distinction
- Add workload confound caveat to before/after comparison
- Fix SUMMARY_RESERVE "hard relationship" vs thinking budget contradiction
* fix(core): restore fallback chains in client.ts for mock compatibility
The previous commit removed optional chaining from client.ts wrapper
methods, but client.test.ts mocks getChat() with partial objects that
lack the new shallow methods. Restore ?. fallback chains so both
production (GeminiChat) and test (mock) paths work correctly.
* docs: clarify memory review follow-ups
* docs: fix runtime benchmark unit conversion
* docs: add default-heap OOM stress report
* fix: update copyright year to 2026 in new files [skip ci]
New files added in this PR had 2025 copyright headers. Updated to 2026
to reflect the current year.
|
||
|
|
eef06ce376
|
feat(cli): add structured memory diagnostics JSON (#3785)
* feat(cli): add memory diagnostics doctor command * fix(core): platform-aware maxRSS conversion and accurate risk message - Extract platform detection before building diagnostics so the correct unit conversion can be applied: multiply by 1024 on Linux (where process.resourceUsage().maxRSS is in KB) but leave the value unchanged on macOS/Windows (where it is already in bytes). - Correct the native-memory-pressure risk message to accurately state that the threshold is 2× heap used, not just "larger than heapUsed". - Add a dedicated test to assert that maxRSS is not multiplied on a non-Linux platform (darwin). All 3 core and 9 CLI tests pass; typecheck clean. Agent-Logs-Url: https://github.com/QwenLM/qwen-code/sessions/9b413337-68ed-4d5c-af99-0d42378900c3 * test(core): cover active request memory risk * fix(cli): address memory diagnostics review feedback * fix(cli): harden memory diagnostics review fixes * fix(memory-diagnostics): tighten risk thresholds and expand readable output - Add 64MB absolute floor on native-memory-pressure so cold processes don't trip the 2x ratio check; raise active-handles threshold from 100 to 256 - Show detachedContexts, nativeContexts, maxRSS, CPU times, smapsRollup availability, and v8HeapSpaces summary in the readable /doctor memory output - Validate unknown memory subcommand args with a usage hint instead of silently dropping them - Wrap human-readable strings in t(...) for i18n parity with the rest of doctor - Advertise the memory subcommand via /doctor argumentHint while keeping acceptsInput false so the parent still auto-submits - Document _getActiveHandles/_getActiveRequests as undocumented Node internals - Update tests for new thresholds, expanded output, unknown-arg path, and abort-during-json * fix(cli): harden memory doctor diagnostics * fix(core): correct maxRSS byte handling and heapRatio consistency - Remove incorrect * 1024 multiplier for maxRSS on Linux (Node.js >=14.10 returns bytes on all platforms) - Use v8HeapStats.usedHeapSize for heapRatio to avoid cross-API inconsistency - Update test expectations and rename "does not multiply" test * fix(cli): resolve rebase conflicts in memory diagnostics - Rename local formatMemoryDiagnostics to formatCoreDiagnostics to avoid naming conflict with the imported utility from memoryDiagnostics.js - Update Session.test.ts to use objectContaining for _meta field added in recent main commits - Align doctorCommand.test.ts assertions with current parent command state (argumentHint includes --sample/--snapshot from main) * fix(core): use null instead of undefined for optional probes, deduplicate active count helpers - optionalProbe/optionalSyncProbe now return null on failure so JSON.stringify preserves the keys instead of silently omitting them. - Merge getActiveHandlesCount/getActiveRequestsCount into a single parameterized getProcessInternalCount helper. - Update MemoryDiagnostics interface: v8HeapSpaces, openFileDescriptors, smapsRollup are now T | null instead of T | undefined. * fix(cli): finish memory diagnostics review fixes * fix(cli): address memory diagnostics review feedback --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> |
||
|
|
cd1be1c524
|
feat(vscode-ide-companion): add agent execution tool display (#2590)
Preserve structured agent rawOutput through the VSCode session pipeline. Render dedicated agent execution cards from shared webui components. |