mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-11-13 10:13:47 +00:00
432 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7bda51a070
|
feat(core): add model.loopProtection and remind instead of stopping loops by default (#15016)
* feat(core): add model.loopProtection and remind before loop stops Add the model.loopProtection setting (stop, warn, off). Under the default stop, every stop point stays where it is; the always-on guards (identical calls, shell inspection, daemon invalid tool parameters, stuck repetition past the adaptive cap) first send the model one reminder with the next tool results. warn only reminds, except for content and thought repetition; off neither reminds nor stops. Budgets stop in every mode. A new loop_protection telemetry event records each reminded, stopped and observed decision. Loop stop hints and the TUI dialog note name the setting. Refs #14828 * feat(core): default model.loopProtection to warn A firing loop guard now reminds the model once and lets the turn continue by default. Budgets still stop every mode, and content and thought repetition still stops. Set model.loopProtection to "stop" to keep the previous stop points. Refs #14828 * fix(core): keep side queries out of the running turn's loop decisions A concurrent /btw side query shares the client's loop detector. Its retry dropped the turn's pending reminders, its stateful tool results could queue a global-duplicate reminder into the turn, and under `off` it marked patterns observed under the turn's prompt id. Route recordToolResult through the same ownership gate, drop pending reminders once on the owner's Retry only, and skip observed decisions for side queries. Warn once when model.loopProtection is not a valid mode instead of silently using the default, and update the consecutive-identical comment that still described an unconditional halt. * fix(core): keep reminders across side queries and guard unknown modes A concurrent /btw side query starts as a UserQuery, so its reset cleared the running turn's queued reminders and reminded/observed decisions. Under `warn` the stuck turn then got no reminder at all. Keep that state on a side query's reset, and log each reminder under the prompt id that queued it. Validate model.loopProtection in core Config as well, since SDK and serve embedders bypass the CLI check and an unknown mode acted as `off`. For a stateful read tool with no recorded results, `warn` now records an observed decision at the stop point instead of a reminder claiming the result will not change; `stop` still fails safe and stops. * fix(core): let late stateful results earn the warn reminder Under `warn`, a stateful read that reached the stop point before its results were recorded was observed under the 'identical' key, which then blocked the reminder for the rest of the streak even after the results came back unchanged. Record that case under its own key so the reminder can still be sent once the evidence is in. In daemon sessions, leave queued loop reminders untaken when the repeated tool failure guard stops the batch, so they are not logged as `reminded` without being sent. Update the telemetry docs for `observed` under `warn`, note in model.skipLoopDetection that model.loopProtection decides whether the always-on guards remind or stop, and drop the stale DashScope #5019 rationale. |
||
|
|
b51ce2c305
|
feat(workflow): add per-turn human-origin workflow hints (#14876)
* feat(workflow): add per-turn human-origin workflow hints * fix(workflow): preserve intent across recall and cached submissions --------- Co-authored-by: qqqys <266654365+qqqys@users.noreply.github.com> |
||
|
|
f1645116b0
|
feat(serve): add persisted workspace artifact library (#14867)
* feat(serve): add persisted workspace artifact library * fix(serve): align artifact library capability contract * fix(serve): preserve artifact library ownership and replay --------- Co-authored-by: 丁炳智 <dingbingzhi.dbz@alibaba-inc.com> |
||
|
|
a4937a3533
|
feat(web-shell): refresh model catalogs from the model selector (#14685)
* feat(web-shell): refresh model catalogs from the model selector
* fix(web-shell): stabilize model refresh state and capability tests
* fix(web-shell): preserve refreshed model catalogs and runtime scope
* fix(ci): sync upstream build heap budget
Sync the 6144 MB build heap ceiling from upstream PR #14822 (
|
||
|
|
bf118a1220
|
feat(core): report why loop protection stopped a turn (#14858)
Two loop types cover two causes each: turn_tool_call_cap is an explicit model.maxToolCallsPerTurn, the adaptive backstop or a stuck halt past the soft cap, and global_tool_call_duplicate is the heuristic duplicate detector or the duplicate provider tool-call id breaker. Each of these stops now carries an additive loopReason, and cap stops carry the call count and the limit that applied, on the LoopDetected event, the loop_detected telemetry and the daemon turn_error. The SDK keeps the detail on transcript blocks instead of dropping the loop type. The headless CLI, the TUI loop dialog, OpenTUI and Web Shell (en and zh-CN) explain each cause and what to change. No detector fires or stops at a different point. The export renderer budget rises to 2,050,000 for the new i18n keys (+5,139 bytes measured). Part of #14828. |
||
|
|
dc8b523d39
|
feat(web-shell): show background shell task runtime details (#14831)
* feat(web-shell): show background shell task runtime details * fix(build): budget shared shell task runtime labels * test(serve): sync shell runtime telemetry route counts --------- Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com> |
||
|
|
5ded4b8c2a
|
docs(telemetry): clarify OTLP HTTP uses JSON encoding (#14664)
Co-authored-by: 易良 <1204183885@qq.com> |
||
|
|
6ec1b83044
|
feat(web-shell): delete selected message groups from session history (#14297)
* feat(web-shell): add grouped message deletion with durable history updates * fix(web-shell): repair message deletion CI contracts * docs(serve): index message deletion protocol routes * fix(web-shell): harden grouped deletion recovery and export build * fix(web-shell): allow selecting all message groups for deletion * test(cli): observe hook cancellation rejection before waiting --------- Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> |
||
|
|
798e5c9b66
|
fix(web-shell): preserve slash highlighting in user messages (#14171)
* fix(web-shell): preserve slash highlighting in user messages Fixes #14161 * perf(web-shell): trim slash highlighting bundle overhead Render highlighted text through a plain helper, keep captured line breaks, and only mount the URL renderer for text that can contain an explicit URL. Reuse the existing scoped data attribute for styling. This reduces the transcript JavaScript guard count from 1,332,162 to 1,331,354 UTF-16 units. Preserve host fragment merging and add mixed-case URL and scheduled-task highlighting coverage. * test(web-shell): pin slash-highlight replay path and styling contract * test(web-shell): compare full declaration sets for composer slash parity Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: 铃蓝 <guolinliang.gll@alibaba-inc.com> 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-Coder <qwen-coder@alibabacloud.com> |
||
|
|
06efd789b1
|
feat(telemetry): Record reasoning effort on LLM spans (#14718) | ||
|
|
7abcc60348
|
fix(sdk): size session create from the daemon session budget (#14588)
* fix(sdk): size session create from the daemon session budget POST /session answers only after the daemon spawned the session's ACP child and finished its initialize handshake, but the client charged that wait to the generic 30s request deadline. The daemon bounds the handshake with --initialize-timeout-ms (10s by default, 60s on the shared E2E runners), so a slow spawn was abandoned while the daemon still completed it and channel users saw "Could not create task". Restore already sizes its deadline from the advertised limits.sessionRestoreTimeoutMs plus headroom. Apply the same derived deadline to session create and worktree reset, which spawn children for the same kind of work, and keep an explicitly configured client timeout winning. The channel-workers E2E test now also outlives the initialize budget it gives the daemon. Fixes #14584 * fix(web-shell): widen the create watchdog past the daemon handshake budget Session create now waits on the daemon's ACP handshake budget (70s by default) instead of the generic 30s request deadline, so a workspace create action costs one capability preflight plus that larger create request. The watchdog that bounds the whole action still assumed 2 x 30s and would abandon a create the SDK now deliberately allows. Raise CREATE_WATCHDOG_TIMEOUT_MS to cover preflight + create + headroom, and update the deadline tests: the create and preflight budgets are no longer equal by design, a hung create is bounded at 115s, and the SDK request timeout case needs a session delay above the new create budget. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-conflict/jmvdyvii4fo * fix(web-shell): size the create watchdog from the advertised session budget The SDK now sizes a session create from the daemon's advertised session budget rather than the generic 30s request deadline, so a workspace create can span a 30s capability preflight plus a 70s create request. The create watchdog was still a fixed 75s derived from the old "2 x 30s" shape, so the browser reported a create timeout on a spawn the daemon was still finishing -- the bug class the SDK change fixes, one layer up. It also reddened the required Test lane: actions.test.ts guards that the watchdog covers preflight + create + headroom, a floor that is now 115s. Derive the watchdog from the same advertised budget the restore path already reads, so the two clients stop diverging whenever a budget moves, and drop the "keep in sync with DEFAULT_FETCH_TIMEOUT_MS" comment that no longer describes where the number comes from. The guard that asserted a preflight and a create share one budget now asserts what the test is named for: the create budget is sized from the session budget, and the watchdog covers the sum plus headroom. The two neighbouring watchdog tests derive their expected deadline from the same helper instead of hardcoding 75000ms, so the next budget move does not silently re-break them. The restore and load watchdogs are untouched -- they were already derived and still sit at 75s for an old daemon. * fix(sdk): stop a short restore budget from shortening a session create `limits.sessionRestoreTimeoutMs` is the operator's restore knob, and the server returns an explicit `--session-restore-timeout-ms` verbatim with no floor -- only the `--initialize-timeout-ms` branch clamps to the default. Sizing create and worktree reset from it alone meant a legal config like `--initialize-timeout-ms 60000 --session-restore-timeout-ms 5000` gave both routes a 15s client deadline, under the 30s generic request deadline they used before this change, so a create that always worked was now abandoned. Give the two spawn routes their own resolver that floors the derived budget at the generic request deadline. Restore keeps the unfloored budget: pinning it low is deliberate, and flooring the shared helper would have raised it. The Web Shell create watchdog gets the same floor on its create half, so a short restore pin yields a 75s watchdog (30s preflight + 30s create + 15s headroom) rather than 60s, which would have re-opened the gap this PR closes. * docs(sdk): narrow the timeout claims this change falsifies Three statements described create as a short-lived 30s route and the Web Shell creation limit as a fixed 75s, which stops being true once create is sized from the advertised session budget and the watchdog is derived from it. Correct the fetchTimeoutMs option doc, the session-operation resolver's own contract (the advertised field is the restore knob, so for a spawn it hints at the handshake cost rather than bounding it, and a client that creates before reading capabilities still falls back to the 70s default), and the daemon configuration page's Web Shell deadline section -- including scoping the "--initialize-timeout-ms does not raise the create request" claim to the capability preflight, which is the only leg it still holds for. * test(e2e): defer the channel-worker deadline to main #14587 already widened this file's budgets on main (300s ceiling), so this branch's per-test comment would only have lowered it back to 120s. The client fix this PR carries is covered by the SDK and Web Shell unit tests. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmve7t0jzg8 * docs(daemon): correct the create-deadline claims and pin the new budgets R2-1: the Web Shell README section this page links to still documented the replaced 75s fixed action limit, so a host integrator sizing a create against it would tear down a spawn the daemon still completes. R1-6: qualify the initialize-timeout claim with the explicit restore pin, the 60000 floor and the un-read capabilities fallback. R2-3: pin the deliberately unfloored restore route. R2-2: pin the advertised budget reaching the create watchdog through the real call chain. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmvegdno2gr --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
0e2886a844
|
feat(daemon): support session-targeted Skill and Extension refresh (#14050)
* feat(daemon): support session-targeted Skill and Extension refresh * test(daemon): include session refresh in capability baseline * docs(daemon): align session refresh references with contracts * fix(serve): handle selected refresh lifecycle and lookup edge cases --------- Co-authored-by: Ethan Ye <ethanye@U-463KXYWL-1938.local> |
||
|
|
b4614845f0
|
fix(web-shell): delete attachments from an empty composer (#13947)
* fix(web-shell): delete attachments from an empty composer * fix: address review feedback for #13947 * fix: follow up review findings for #13947 * fix(web-shell): preserve draft boundaries during keyboard deletion --------- Co-authored-by: Zhangchenhao-111 <285911435+Zhangchenhao-111@users.noreply.github.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
808722d9d7
|
feat(web-shell): add side task archive controls (#14300)
Some checks are pending
Qwen Code CI / Classify PR (push) Waiting to run
Qwen Code CI / Test (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Lint & Static (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / web-shell E2E Smoke (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Test (macos-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Test (windows-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Integration Tests (no-AK, No Sandbox) (push) Blocked by required conditions
Qwen Code CI / Integration Tests (CLI, No Sandbox) (push) Blocked by required conditions
E2E Tests / Build for E2E (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/1 (push) Blocked by required conditions
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/1 (push) Blocked by required conditions
E2E Tests / E2E Test - macOS - shard 1/2 (push) Blocked by required conditions
E2E Tests / E2E Test - macOS - shard 2/2 (push) Blocked by required conditions
E2E Tests / E2E Interactive - OpenTUI renderer (bun) (push) Blocked by required conditions
E2E Tests / channel-plugin E2E (nightly) (push) Blocked by required conditions
E2E Tests / cron-interactive E2E (nightly) (push) Blocked by required conditions
E2E Tests / web-shell Browser Regression (push) Waiting to run
* feat(web-shell): add side task archive controls Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(serve): harden side task archive controls Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(integration): pin session_archive_idle_guard in the serve capability baseline capabilities.ts registers session_archive_idle_guard and server.test.ts already lists it, but the second baseline list in the no-AK integration gate was not updated, so the deep-equal diff failed on exactly that one capability. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-conflict/jmv9k9mxh7h * fix(web-shell): archive and restore side tasks in their owning workspace The side-task archive/restore callbacks called the unscoped client, whose routes resolve ids against the legacy-primary catalog. A task owned by a secondary workspace answered notFound without any state migration, and because both callbacks counted notFound as a successful removal the UI cleared state anyway. Group each request by the task's workspaceCwd and call through the workspace-qualified route (standalone tasks keep the legacy path); notFound now surfaces as a per-session error and the task stays in the catalog. Regression pins: qualified routing for archive and restore with a secondary-workspace task and a standalone task in one call, and a notFound answer that keeps the tab and reports the session id; the three pre-existing archive tests move to workspace-scoped spies. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(web-shell): address review follow-ups - separator, removal-set reset, overview batch archive * docs(design): sync side-task archive design with workspace-qualified routing Review pointed out that the design pair still described the pre-fix contract: it listed not-found among the outcomes that leave the active list, and never stated that archive and restore must be workspace-qualified. That missing sentence is the same omission that allowed the secondary-Workspace bug, so the docs now carry it. Both languages state that each callback groups ids by the task's own workspaceCwd and calls the workspace-qualified route, that ids with no recorded workspace keep the legacy unscoped call, and that a notFound answer now keeps the task listed and reports a per-session error instead of clearing UI state for an operation the daemon never performed. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
a84dbff23e
|
feat(providers): add QwenCloud as the first /auth entry (#14073)
* feat(providers): add 千问AI平台 / QwenCloud as the first /auth entry Adds QwenCloud as a new top-level provider group ahead of Alibaba ModelStudio, following the product ruling in #14025: the two entries coexist rather than one replacing the other, so saved ModelStudio credentials, endpoints and model selections keep resolving to their existing presets and no migration is needed. Two new presets share the ModelStudio wizard shape (Access Method -> Platform -> API Key -> models): - qwencloud-standard (pay-as-you-go, `sk-` / `sk-ws-` keys) - qwencloud-token-plan (Credit subscription, `sk-sp-` keys) Each offers China (千问AI平台) and International (QwenCloud) as an explicit platform choice, so the UI language never decides the endpoint. Coding Plan is not offered here — it is a ModelStudio product. Endpoints were taken from the platform's own documentation and probed before landing (all four return the DashScope `invalid_api_key` error envelope): - https://maas.qianwenaiapi.com/compatible-mode/v1 - https://token-plan.maas.qianwenaiapi.com/compatible-mode/v1 - https://maas.qwencloudapi.com/compatible-mode/v1 - https://token-plan.maas.qwencloudapi.com/compatible-mode/v1 The new hosts are added to the DashScope provider detection and the web-search endpoint allowlist so the built-in `web_search` backend keeps working; both new env keys are added to the no-AK CI gate's cleared-env list. Group wiring is mirrored across the ink and OpenTUI dialogs, the VS Code provider picker, and the serve catalog consumed by Web Shell. Closes #14025 Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): add QwenCloud auth strings to en and zh-TW locales The new auth entries introduced in the previous commit were only added to zh.js. Since en.js is the source of translation keys and both zh and zh-TW enforce strict key parity, the i18n check failed with "Extra key in zh.js" for all eight strings. Add the same keys to en.js as identity mappings and to zh-TW.js with Traditional Chinese values, so all three locale files have an identical key set. * test(cli): follow the QwenCloud row in the OpenTUI auth menu tests The new first /auth entry shifts the main menu by one row, but the tests addressed the sub-menus by position, so most flows landed a row early and the region-height assertions still named the old first row. * feat(providers): localize the QwenCloud /auth entry label per locale The top-level /auth entry was the only mixed CJK/Latin label in the menu ("千问AI平台 / QwenCloud"), and because en/zh mapped that key to itself it was effectively hardcoded mixed in every locale. Route it through i18n instead: en and other locales show "QwenCloud", zh shows "千问AI平台", zh-TW shows "千問AI平台". Locale-neutral surfaces (serve catalog, VS Code provider picker) carry the single Latin brand; the Chinese brand stays visible in the explicit platform step ("China — 千问AI平台") and the docs. The step-title flowTitle now goes through t() so the localized brand also appears in "… · Step 1/3 · …". Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(providers): register QwenCloud hosts in telemetry and reasoning classifiers The QwenCloud MaaS hosts and env keys were registered in the two host gates this PR edits, but two further independent classifiers of the same hosts did not learn about them, and both misclassify the entry this PR makes the first-position default: - telemetry/gen-ai-provider.ts had no providerFromHostname match for maas.qianwenaiapi.com / maas.qwencloudapi.com and no PROVIDER_BY_ENV_KEY entry for QWENCLOUD_API_KEY / QWENCLOUD_TOKEN_PLAN_API_KEY, so resolveGenAiProviderName fell through to its `default: return 'openai'` arm. Every span and log record for a QwenCloud install was attributed to OpenAI, while the identical ModelStudio path resolved to 'dashscope'. - core/reasoning-overrides.ts keeps its own inline hostname regex without the new hosts, so a user-authored partial reasoning override on a qwen* model behind a QwenCloud baseUrl selected 'qwen-chat-template' -> toggleOnly -> invalidReasoning, which captureLatestReasoning catches and warns. The override was silently discarded; the same declaration on dashscope.aliyuncs.com resolves to 'dashscope-effort'. Also widen the SDK-side mirror DaemonAuthProviderCatalog.groups[].id to include 'qwencloud', which packages/cli/src/serve/types.ts and auth-provider-helpers.ts already emit as the first group, and derive web-shell's AuthGroupId from that union instead of re-declaring it, so the SDK type is the single source of truth. A second literal union in web-shell is why nothing reddened in-repo while the daemon emitted a group id its own published wire type declared impossible. The new suffixes go inside the existing anchored (^|\.)...$ group, so a forged maas.qianwenaiapi.com.evil.com cannot match while the legitimate token-plan. subscription subdomains still do. Both env keys map to the existing 'dashscope' provider value rather than a new one. The hosts stay literals in gen-ai-provider.ts rather than importing QWENCLOUD_MAAS_HOSTS: that module is a zero-import telemetry leaf, and dashscope.ts already imports core/reasoning-overrides at runtime, so importing back would cycle. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmv8fwg2z5f * test(providers): pin QwenCloud host classification and registry membership Cover behaviour this PR added that no test observed: - dashscope.test.ts: the QwenCloud MaaS pay-as-you-go and token-plan hosts are DashScope origins, plus dot-boundary lookalike negatives. - web-search.test.ts: the same four hosts pass the web-search gate. - qwencloud-standard/token-plan.test.ts: both presets are registered in ALL_PROVIDERS and QWENCLOUD_PROVIDERS, and the qwencloud access-method group excludes Coding Plan (replaces a constant-true id/label check). Each new assertion is mutation-verified: dropping isQwenCloudOrigin from the dashscope return, weakening its host match, dropping the QWENCLOUD_MAAS_HOSTS spread, removing the two registry entries, or flipping codingPlanProvider uiGroup each turns exactly the intended test red. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmv8mbxgn5t * test(providers,cli): pin QwenCloud preset separation and the auth catalog group Coverage for lines this PR itself added (review round 1: R1-21, R1-26, R1-15): - qwencloudStandardProvider.ownsModel is cross-checked against its QwenCloud Token Plan sibling and against a foreign envKey on its own endpoint. The two presets share uiGroup, catalog and protocol bucket, so that envKey gate is the only discriminator; dropping it kept the suite green while applyModelProvidersPatch would claim a Token Plan install. - buildAuthProviderCatalog gets its first test: the QwenCloud group is first and carries both access methods. A misspelled group filter stayed green. - The zero-row main-menu paint test now names row 0, which this PR re-pointed from Alibaba ModelStudio to QwenCloud while only rows 1 and 2 stayed pinned. Each assertion was confirmed load-bearing by one mutation that the pre-existing tests did not catch. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmv8oh38g5y * docs(users): sweep the /auth menu enumeration in overview and quickstart This PR re-numbered the /auth menu to four options in auth.md and model-providers.md, but overview.md and quickstart.md still described three entries with Alibaba ModelStudio as the recommended one (review round 1: R1-4). The doc set contradicted itself, and a quickstart reader holding a QwenCloud key was routed to the ModelStudio entry, whose endpoints reject it. Both pages now list QwenCloud first and reserve the "recommended setup" claim for it, matching auth.md. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmv8oh38g5y * fix(providers): validate daemon credentials and close QwenCloud follow-ups (#14302) * fix(serve): validate API key format before persisting in daemon install path The CLI, ACP and VS Code surfaces each call provider.validateApiKey before persisting credentials. The daemon route (POST /workspace/auth/provider) did not, because validateApiKey is a function on ProviderConfig and cannot be serialized to the wire — so no client of this route can apply the check either. Without this guard a key the provider's own entry rejects (e.g. a Token Plan sk-sp- key aimed at the Standard API Key entry) gets persisted silently, and the user only discovers the mismatch at the first authenticated call. Fix: call validateApiKey in the route after protocol validation and before invoking installAuthProvider. Return 400 with code 'invalid_api_key' on failure, matching the other three surfaces. Closes #14257 (item S3 / R2-13). * fix(providers): address #14257 deferred Suggestions (D1/D2, T1/T3-T9, I1, P5, S6/S7) Batch fix for actionable items from #14257: Docs: - D1: Add settings.json example to QwenCloud headless setup section - D2: Add QwenCloud rows to web-search.md auto-activation table Tests: - T1: Pin flowTitle locale resolution in both dialog suites - T3/T4: Assert QwenCloud sub-menu contents (Token Plan + Standard, no Coding Plan) - T5: Add missing token-plan.maas.qwencloudapi.com endpoint to dashscope.test.ts - T6: Add QwenCloud host tests to reasoning-overrides.test.ts - T7: Assert providerState in qwencloud-standard preset test - T8: Test ownsModel baseUrl conjunct independently of envKey - T9: Test providerMatchesCredentials URL gate independently of envKey - S7: Assert QwenCloud group in VS Code AuthMessageHandler picker i18n: - I1: Add validateApiKey messages to all 9 locale files Product: - P5: Fix qwen3.7-plus modalities to include video (matches alibaba-token-plan) Code: - S6: Update docstring enumerations in dashscope.ts and web-search.ts Remaining items need human decisions: P1-P4 (wording/labels), S1-S5 (API surface), T2 (ink suite gating is a pre-existing harness pattern). * fix(auth): translate provider titles at render time Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(providers): handle optional preset models Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(providers): pin Token Plan providerState and ownsModel baseUrl leg Addresses four review Suggestions on this PR: - R1-10 (#14257 T7): the providerState stamp was asserted for the Standard preset only. Token Plan has two baseUrl options and a baseUrl-dependent modelNamePrefix, so stamp both routes. - R1-11 (#14257 T8): the deciding baseUrl negative for ownsModel was added to the Standard suite only. The Token Plan negatives added here differ in envKey, so the baseUrl conjunct was never the deciding factor. - R1-1: the web-search host note contradicted the two QwenCloud rows this PR adds to the table on the same page. Name the Model Studio and QwenCloud MaaS families the code actually accepts. - R1-4: the daemon route comment claimed parity with the CLI/ACP/VS Code copies. Those resolve the endpoint first and validate the resolved URL; this route validates the client-supplied baseUrl. Comment only. Both new Token Plan rows were mutation-checked one mutant at a time: dropping baseUrl from resolveProviderState, stamping the provider default endpoint instead of the requested one, and relaxing ownsModel to envKey-only each turn exactly the intended row red. An additional cross-route "versions must differ" row stayed green under all of them (model configs already embed baseUrl), so it was dropped rather than shipped inert. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmv9zmmcj86 * test: make the QwenCloud witnesses discriminating; trim daemon key once R1-9: the two Token Plan cases and the four lookalike cases never reached the dashscope host regex - both blocks short-circuited in validateReasoningDeclaration/validateReasoningCapabilities before route.baseUrl was parsed, and the block comment misstated the Token Plan endpoints as unregistered. Fold the Token Plan hosts into the QwenCloud host table with a declaration that omits `thinking`/`profile`, so all four registered endpoints now pin the anchored suffixes. R1-5/R1-6: the Ink VIEW_TITLES fix had no CI-executed guard (every keystroke case is skipped under CI=true) and its T1 case asserted only the already-lazy flowTitle path. Add one ungated, keystroke-free render assertion and assert the sub-menu heading between the two keystrokes. R1-3: validate and forward the same trimmed key rather than validating the trimmed value while forwarding the raw one. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmva623ox8i * fix(auth): guard zh locale test cleanup, note hand-written provider caveat R1-7: wrap the QwenCloud zh flow-title test body in try/finally so unmount() and the locale reset still run when an assertion rejects, matching the shape of the opentui twin added in the same change. R1-2: note in the settings.json alternative that a hand-written provider entry carries no capabilities stamp, so /effort offers the generic tiers rather than the QwenCloud curated set. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmvaacf8g8p * fix(providers): address #14073 round-3 deferred Suggestions - docs/design/auth/motivation.md: QwenCloud-first /auth enumeration (S1) - docs/users/quickstart.md: name QwenCloud credentials in Before you begin (S3) - docs/users/configuration/auth.md: scope the Token Plan prefix rule to ModelStudio vs QwenCloud so Option 1 and Option 4 no longer read as contradictory (S4) - qwencloud-standard.test.ts: correct the ownsModel comment — envKey and baseUrl conjuncts each exclude the sibling independently (S5) - auth-provider-helpers.test.ts + alibaba-standard.test.ts: pin every catalog group's providerIds and the alibaba uiGroup (S6) - web-search.test.ts: forged-suffix boundary cases for the QwenCloud host gate (S7) S2 (6-latin-locale backfill) and S8 (web-shell group dict) verified as no-ops: the sibling ModelStudio strings rely on the identical raw-key fallback in the same locales/dictionary. * fix(auth): localize provider API key errors * fix(providers): seed Token Plan only with models its endpoint serves A live GET /models on the China Token Plan route (real subscription key, 2026-10-16) serves neither kimi-k3 nor deepseek-v4-pro-0813 — the endpoint offers kimi-k2.x and deepseek-v4-pro instead, matching the platform doc's personal-edition table. The shared QWENCLOUD_MODELS seed list therefore pre-filled two ids the wizard would install as dead entries whenever discovery succeeded, and offered them in the offline fallback. Filter the shared catalog down to the five confirmed-served models for the Token Plan preset instead of duplicating stamps; the Standard (pay-as-you-go) catalog keeps the full list, which no live data has falsified. Pinned by a new preset test asserting the exact seed ids. --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(auth): preserve explicit models during provider discovery --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
87de74860b
|
docs(tools): add looot to the web search MCP services (#13999)
Co-authored-by: 易良 <1204183885@qq.com> |
||
|
|
87dcc4a708
|
feat(web-shell): add file-tree deletion with confirmation (#14158)
* feat(web-shell): add confirmed file deletion from file tree * test(serve): include file deletion in capability baseline * fix(web-shell): address file deletion review suggestions * test(cli): synchronize child cancellation tests * test(web-shell): refresh transcript budget after file actions --------- Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
17d5f774ea
|
feat(web-shell): add file creation and confirmed folder deletion (#14169)
* feat(web-shell): add file creation and confirmed folder deletion * fix(web-shell): address file tree review and transcript regression --------- Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: 易良 <1204183885@qq.com> |
||
|
|
74033d0bd2
|
fix(sdk): release reconnect transports created after disposal (#13864)
* fix(sdk): release reconnect transports created after disposal * fix(sdk): preserve closure errors during reconnect cleanup * test(sdk): satisfy lint in reconnect disposal coverage * test(sdk): model reconnect subscription failures during iteration |
||
|
|
1ce7d71633
|
fix(core): preserve fuzzy edit line boundaries (#13484)
* fix(core): preserve blank lines after fuzzy edits * test(core): cover repeated fuzzy edit matches * fix(core): keep fuzzy edits within whole-line matches |
||
|
|
3319e819b9
|
fix(sdk-python): resolve Windows command shims on the effective PATH (#13862)
* fix(sdk-python): resolve Windows command shims on the effective PATH * style(sdk-python): format Windows shim regression assertion * fix(sdk-python): secure Windows command lookup and cleanup * style(sdk-python): align test import grouping with CI --------- Co-authored-by: 易良 <1204183885@qq.com> |
||
|
|
7326ac6e0b
|
Add SerpApi to web search MCP services list (#13104)
* Add SerpApi to web search MCP services list * Updated best for, added a information that is sent to SerpApi. * Moved the information sent to SerpApi part in the description to align with the format followed by other listings. |
||
|
|
c3c38cf583
|
feat(web-shell): bridge trajectory history and live lifecycle state (#13952)
* feat(web-shell): bridge trajectory history and live lifecycle state * fix(web-shell): preserve trajectory recovery and bound transcript bundle * fix(acp-bridge): preserve request lifecycle frames across compaction * fix(web-shell): address trajectory recovery review findings --------- Co-authored-by: qqqys <266654365+qqqys@users.noreply.github.com> |
||
|
|
008c0de746
|
docs(sdk): clarify empty core-tool allowlists across SDKs (#13949)
Co-authored-by: Zhangchenhao-111 <285911435+Zhangchenhao-111@users.noreply.github.com> |
||
|
|
f8c99414b2
|
fix(core): report monitor startup failures as tool errors (#13460)
* fix(core): report monitor startup failures as tool errors * fix(core): classify monitor startup failures consistently |
||
|
|
23274922f5
|
feat(web-shell): add Send now for queued mid-turn messages (#13681)
* feat(web-shell): add Send now for queued mid-turn messages
A message typed while a turn runs waits for the model response that is
streaming and for its tool batch, so a correction typed into a long answer
reached the model seconds later, and Stop was the only faster path.
Typing keeps that behavior: the message stays queued, editable and
deletable until the next tool boundary. A new Send now action on a queued
row asks the daemon to deliver the queued messages at once.
POST /session/:id/mid-turn-messages/send-now, advertised by
session_mid_turn_send_now, sends the agent craft/midTurnSendNow. While a
foreground turn streams a response that has not started a tool call, the
agent drains the user's messages, cuts the response short, keeps the part
already streamed, and answers in the same turn. Running tools are never
interrupted, a response that started a tool call is never cut, queue-only
steering is not taken early, and a request is scoped to the turn that
received it. Input taken by a turn that is then stopped or fails is kept
in that turn's conversation.
The TypeScript SDK gains sendMidTurnMessagesNow on both clients.
* fix(web-shell): address review findings on Send now
- Restart the Stop-hook state when a continuation answers input that
cut its response short, so the next Stop check is not hook-forced and
the consecutive-block count and reasons start over.
- Give input a finished turn keeps unsent a 2 s resolution deadline of
its own; the deadline also cancels media bridges.
- Requeue a failed send-now drain in its original order, and log a
send-now request the agent rejects.
- In Web Shell, reconcile a row whose message already left the queue
and ignore a repeated click while a request is out.
- State the tool-call carve-out wherever Send now is described, and
document goal turns, the narrow no-answer window and token accounting.
- Add tests for the review's gaps, drive the drain deadline with fake
timers, and add the route to the multi-workspace failure tables.
* fix(web-shell): keep send-now input a stopped tool boundary leaves unbuilt
When a turn is stopped while a tool-boundary drain resolves a message,
the drain now hands back the messages it has not built that an early
send-now drain took, so the end-of-turn keep records them. Input the
boundary drain took for itself is still dropped there, as before.
- Tests: the stopped boundary keeps that input once and carries nothing
into the next turn; a Goal continuation is cut; a background
notification turn is not; a failed send-now drain does not requeue a
message that left the queue meanwhile.
- Bridge and SDK contracts: the cut applies to a foreground turn's
streaming response, and `requested: true` does not mean a cut.
- Protocol and design docs: the timed-out send-now drain, resending a
settled id, the 10-message drain limit, and the tool-boundary drop.
* test(web-shell): pin send-now behavior questioned in review
- Assert that cron and background-notification turns never open their
response to interruption and that a send-now request arms nothing
while they stream.
- A response cut short by queued input still answers that input when it
ends with an error, while an error from a response its drain did not
cut remains the turn's error. Explain in `watch` and the design doc why
the cut response's error is absorbed: the cut does not always arrive as
an AbortError, and the response was given up.
- A message whose deletion missed while a failing drain held it is still
delivered, which matches the `{ removed: false }` answer the client
got. Document this in the protocol reference.
- Rename a requeue test to say it covers a queue-only entry.
* docs(web-shell): scope the abort invariant and drain-held removals
- The main prompt loop's catch states that other AbortErrors surface.
Note that a response cut short by queued input reaches that catch only
when the turn itself is stopped meanwhile, because `watch` absorbs
whatever a cut response throws.
- In the force-drain paragraph, add the drain-held case of
`{ removed: false }`. Such an id must not be re-posted, and its listing
in `settledMessageIds` is not final, because a failed drain returns it
to the queue without an event.
|
||
|
|
e31d5500f1
|
feat(managed-agent): H6a schedule and automation run record contract (#13536)
* feat(managed-agent): H6a schedule and automation run record contract The H6a slice of #12827, ahead of any producer: both bodies register and replay in TypeScript and Java while both domains stay disabled for submission. - managed-schedule v1 (chain scheduleId): owner scope, bounded goal, a five-field cron with an IANA timezone, append-only definition revisions (each successor exactly +1) with their digest, the prompt resource reference, the persistent/per_run target mode with the target frozen exactly for persistent, the skip/queue_one/allow overlap and none/latest/bounded catch-up vocabularies (the limit set exactly for bounded), an enabled flag, and a purely logical run block that freezes the definition for good once terminal. - managed-automation_run v1 (chain automationRunId): the pinned definition revision, the closed occurrenceKey union — schedule:<slot> as a canonical UTC instant to the second (open question 1 answered), manual:<commandId>, webhook:<eventId> registered and refused — the frozen sessionMode/target, and the H0b run block: a durable dispatchId from the first revision, no executionCallId or definition pin, the delivery line past planned only once the run ended so a delivery never re-runs the model. - The shared managed-automation-record/1 fixtures pin keys, fixed keys, vocabularies, 56 body cases and 22 successor transitions, replayed by the TypeScript gate and the Java contract test; the seven timezones anchor in each host tz database. - The projection registry and its v1 fixtures grow the two bodies under additionalRecordBodies, as do the Java RECORD_BODIES; the domains stay out of MANAGED_SESSION_ENABLED_DOMAINS and commitExtensionRecord still refuses them — enablement is the H6b producer slice's explicit step. Design: docs/design/2026-10-04-managed-automation.md (bilingual update). * fix(managed-agent): close the H6a review round's contract findings Round-1 review of the H6a record contract (#13536): one Critical, the rest Suggestions, each verified against this head. - R1-1 (Critical): Java boundedText charged one byte per unpaired surrogate (the default encoder folds it to '?') while Node's Buffer.byteLength charges the three of U+FFFD, so the two validators disagreed on identical wire bytes for a 1366-surrogate goal. Java now charges the same three bytes per unpaired surrogate. Shared boundary cases pin both sides (1365 accepted, 1366 high and low refused). - R1-6/R1-7: the cron validator now checks per-field atoms semantically — digit/list/range/step atoms only, values inside each field's bounds, steps within 1–max, ranges never wrapping — with one honest refusal message per rule instead of one message for all. Fixtures pin */0, */60, - - - - -, 99 99 99 99 99, 0 24 and 17-9. - R1-8: the timezone refusal no longer claims IANA validation; the contract is shape-only on purpose (hosts disagree which names resolve), named in the body comment and the design document. - R1-9: the seven anchored timezones now replay through the validator as body cases, so the host tz anchors witness implementation behaviour, not only host-DB membership. - R1-11: Java runs the catchUpLimit value check before the bounded pairing rule, the same order as TypeScript. - R1-12: pinned that an automation_run task row reads definitionRevision null (the run block holds no definition pin); the authoritative revision lives on the record — asserted in both contract suites and named in the design document. - R1-3: design documents synced to the shipped contract in both languages (occurrence identity, automationRunId chain identity, terminal freeze, count_limit framing, delivery target, per_run target, provenance marker, DST canonicalization tables reassigned to H6b). Not changed, with replies on the threads: promptRef store verification stays out of the record contract (cross-scope reference, resolved at H6b definition admission), and timezone names stay shape-checked (host tz databases disagree; semantic resolution pinned to H6b admission). |
||
|
|
8505479d87
|
docs(serve): fix stale permission-route note and document pending-prompt events (#13281)
docs/users/qwen-serve.md still described session-scoped permission routing as Stage 1.5 future work and pointed integrators at the legacy process-global vote route. Rewrite the note: the session-scoped route ships (Wave 4 / F3) and is the recommended form for new multi-workspace integrations; the legacy route remains for pre-F3 single-workspace clients with its 404 semantics spelled out (the same body as a lost vote for a session owned by another runtime). Add event-reference entries for pending_prompt_added / pending_prompt_started / pending_prompt_completed to docs/developers/daemon/09-event-schema.md: payload fields, the state union, the idle-session no-event caveat, and the "queue-view bookkeeping, not a turn terminal" guidance (correlate turn_complete / turn_error by promptId for completion). Derived from the field notes and triage in #13279. |
||
|
|
4970bfa172
|
feat(managed-agent): adopt the next Hosted Harness generation (G3) (#13174)
* feat(managed-agent): adopt the next Hosted Harness generation (G3) A Hosted Session no longer dies with the Harness process generation that first served it (#12952 G3, Steps 1+2). On a generation signal the control plane renegotiates once through the connector instead of failing every bound Session until its own restart; pending Turns re-attach through the takeover load as their retries come due. Takeover refusals split into a typed terminal decline (deterministic in the journal) and the existing retriable code; the takeover load is idempotent against a lost reply and gets its own timeout; negotiation requires the journal-contract feature token so a rolled-back Harness is refused once; a marked-but-never-admitted Turn withdraws its submission mark, backstopped by journal commandId idempotency. The failover runner gains a Harness-only restart arm on all three scenarios (harness_boot_id moves with no Java restart) and a SIGSTOP/SIGCONT frozen former-owner fencing arm, wired into hosted-harness-mysql together with the previously local-only basic mode. Design docs included in English and Chinese. * fix(managed-agent): tolerate the bootstrap 404 of a restarting Hosted Harness The serve delegating app answers every routed path with a bare pre-contract 404 while its runtime is still starting. The Harness-restart arms raced that window: a prompt submitted milliseconds after the new process bound the port could meet the bare 404, which the client read as a generation contract violation and ended the Turn as hosted_harness_protocol_error without any retry. A missing boot header on 404 now maps to a transient transport error so the coordinator retries through the window, and the failover runner waits on deep health (?deep=1) before driving turns into a restarted Harness. Terminal turn failures now also log their underlying exception. * fix(managed-agent): freeze only the Harness writer in the former-owner fencing arm SIGSTOPping both original owners left the original Spring's workspace binding unreclaimable: the reclaim proves death from /proc liveness, and a stopped JVM still reads as alive there, so the replacement's reconcile timed out (runtime_broker_reconcile_timeout) and the Turn never completed. The arm now stops only the original Harness (reclaiming its workspace binding requires the Spring to die anyway — the continuation mode's crashProcess), completes the Turn with a full replacement, then wakes the frozen writer and asserts the journal, transcript, and session binding are untouched. Design D7 updated in both languages with the discovered boundary: resource-level takeover of a surviving owner is structurally out of reach today, which is exactly what this issue's sequential-generation scope excludes. * ci: retrigger sdk-java workflow after event delivery stall * fix(managed-agent): pin the fencing proof on writer identity, not head revision The first merge-base run of the freeze arm failed its own gate: after waking the frozen Harness the journal head moved (rev 30 -> 45) while the writer generation, boot binding, transcript, and terminal count all held. The moved revisions were the replacement's own legal churn, not old-writer mutation, so the head-equality assertion conflated the two. The exit-check claim is identity: no transaction out of the old writer generation after it wakes. Count that straight off qwen_managed_session_journal_tx (which carries writer_generation), keep the binding/transcript/terminal assertions, and align design D7 in both languages. The error string now also reports the old-writer tx count. * fix(managed-agent): qualify the journal tx schema in the freeze-arm gate The identity-based old-writer count queried qwen_managed_session_journal_tx unqualified; the runner's MySQL connection has no default schema, so the arm died with ERROR 1046 instead of evaluating the fence. Qualify it as qwen_managed_agent.qwen_managed_session_journal_tx like every other query in this runner. No behavior change to the assertions themselves. * fix(managed-agent): harden takeover correctness from the R1 review - settle turn_settled checkpoints through the load route's own tail instead of a terminal decline, and keep transient store verdicts (missing_state/missing_checkpoint) retriable on both authorization reads - exempt only takeover-shaped 409s from the pre-admission retry budget; every other failure kind meets it - scope the 120s load-timeout to recovery loads so plain attaches under the CHM bin locks stay on 30s - adoptGeneration: move map churn out of the connector monitor (lock-order inversion), evict only stale-boot entries on equal-boot mismatches - answer a duplicate submit of an already-settled prompt with a 202 replay anchored at its input.accepted sequence - withdrawSubmissionAttempted: guard on the same status window as its peer CAS methods; complete capability mismatch terminally in both remaining coordinator layers - runner: freeze-arm pre-freeze liveness assertion, /health-proven wake non-vacuity, teardown SIGCONT, exact-string dispatch-generation bounds - CI: job ceiling 95 with corrected ceiling math; pin all seven failover arms in hosted-process-ci.test.js - sync both design-doc languages with the shipped behavior * fix(managed-agent): close the R2 review round on the replaceable-host-harness slice - withdraw + cancel interference (R2-1, Critical): a CANCELLING Turn whose never-admitted mark was withdrawn is fast-cancelled instead of being re-dispatched into a second live execution at the adopted generation - the generation-mismatch catch escapes the pre-admission budget only on a bound Session, like every sibling arm (R2-3) - bound the remote-supplied decline reason to the error_message column so the terminal write itself never throws (R2-5) - the last fail(...) in the catch ladder is failTerminally with the exception logged, like its siblings (R2-6); the withdrawal itself is logged too (R2-7) - freeze arm: the replacement Spring inherits the original port so the woken writer meets a live fencing control plane, not a dead socket (R2-2); the wake block asserts the head actually advanced past the frozen owner's writer generation, drops the wrong heartbeat claim (R1-8 follow-up), separates the two disk-audit meanings, and asserts the retained Harness home (R2-8) - the hosted /capabilities feature list derives from the registry instead of a hand-maintained literal (R2-9) - docs: D7 scoped to the journal half of the Q2 exit check, the binding half and the pre-contract-404 classification recorded in Boundaries (R2-4, R2-10) * docs(sdk-java): correct the load-timeout coverage comment in the client test * fix(managed-agent): reference the frozen Harness through the children registry in teardown The R1-4 teardown SIGCONT referenced the try-block-scoped `harness` binding from the finally block, so every freeze-arm run died with ReferenceError after all fencing assertions had already passed (CI run 37009843147). Reach the child through the children registry by its start() name instead. * docs(managed-agent): scope the adoption sentence to this slice's takeover reach * fix(managed-agent): close the R3 review round at its five shared roots - retract the turn_settled settle tail to a typed decline: the tail answered 200 with no recovery watermark (Java then failed the bind, orphaned a completed journal turn), fabricated state:'completed' on phase alone, ran mutating work under a passive load, and retained no snapshot for the lost-reply retry. D10 already owns rebind-and-keep-reading as the Step 3 row (R1-25-re, R3-2 .. R3-5) - the load route's restore guard applies the same durable-vs-transient verdict read, because the bundle collapses both into one blocked bit and the durable decline was unreachable from production (R1-26-re) - the pre-admission exemption keys on lease-shaped 409 codes only: configuration-shaped 409s (e.g. hosted_tool_profile_conflict) meet the budget, and the same 409 exempts nothing on an unbound Session (R1-1-re, R1-30-re, R3-13) - equal-boot adoption keeps pendingRecovery: the markers were minted by the same live client (R1-29-re) - lifecycle capability mismatch: revert completing-as-unconfirmed — that skipped the drain, flipped the session, and recorded a clean row with no FAILED vocabulary to tell it apart; the reason-loud retry is the honest end of the line until an operator realigns versions, and the README sentence says so. Action-response outbox keeps its honest FAILED-with-code terminal (R1-45-re, R3-5, R3-15) - test hardening: concurrency close-once now surfaces worker assertion failures via Future.get and pins that no real client build happened (R3-12); loadTimeout-vs-requestTimeout discriminated at the call site (R3-9); single-walk acceptedInputSequence (R3-18) - runner: 5-column execution queries pin runtime_session_id unchanged under --harness-only (R3-14); frozen-arm teardown looks the child up by a shared label constant and fails the run on a drift (R3-17) - CI: ceiling 105 covers the nine summed step ceilings (92) plus the uncapped setup steps (R3-6); the seven-arm pin also asserts each script's flags and the install step's existence (R3-16) - docs: both languages re-synced (D5 retraction, D9a code allow-list, D7 teardown, D8 runtime identity, honest validation digests, the four missing changes-table rows, README retry clause) * fix(managed-agent): replay takeover snapshots only to a same-shape request A passive load only asks broker.status(), so its snapshot keeps phase='await_runtime'; replaying it to a drive load handed the coordinator a checkpoint that isContinuationReady() can never accept, terminally failing an otherwise continuable Turn. Record the request shape with the snapshot and replay only on a mode match; the clear conditions stay promptId-only. Also make the adoption race test deterministic: a package-private createClient() seam lets the test inject the replacement instead of a real /capabilities call (proven flaky on CI), worker assertion failures now surface through Future.get, and the pendingRecovery fixture seeds its marker through the recovery path. * fix(managed-agent): close the self-audit round on the replaceable-harness slice Three rounds of undirected plus adversarial audit over the whole PR diff (31 files), with three parallel deep-dive passes over the Java, TypeScript and runner/docs surfaces. Every finding was re-verified against the tree before acting; five reported defects were rejected on evidence. Correctness: - the load route read the blocked-restore verdict AFTER managed.close(); sealing the journal makes every later store read fail as "writer is not active", which the authority erases into missing_state, so the durable branch this PR added could never fire and a corrupt checkpoint stayed in the retry-forever class. Read the verdict first, and pin the order with a witness that goes red when the read moves back (the local authority's seal does not disable reads, so only the ordering assertion catches it). - drop hosted_session_already_attached from the lease-bounded 409 set: the daemon removes an attachment only on an explicit detach or delete and this control plane never detaches, so a Spring restart against a surviving Harness retried a permanent refusal forever instead of ending the Turn. - adoptGeneration evicts by boot identity in both branches instead of clearing, so a marker minted by a concurrent rebuild can no longer be erased between two adjacent clears (which left a live attachment with a null recovery report), and markers follow their attachment. - the post-withdrawal fast-cancel reads the row again: a cancel landing after the claim is invisible in the claimed snapshot, and acting on it submitted a live execution only to cancel it below. - a durable verdict re-read after settling now declines as checkpoint_blocked, matching the identical pre-settle classification. - an unrecognized blocked reason throws instead of declining, so a reason core adds later cannot silently become a terminal Turn failure. - the operator-settable load-timeout is validated at connector construction; a bad value previously threw on every client() call and surfaced as an endless transient retry naming only the exception class. Tests: already_attached and lost-withdrawal-CAS witnesses; the fast-cancel witness now pins the re-read (cancel after claim); the concurrent-adoption test surfaces worker assertions through Future.get and injects the replacement through a package-private createClient() seam instead of standing up a live /capabilities call; the CI pin gains each arm's mode flag and a ceiling-sum invariant. Docs (both languages): D1 now describes the boot-identity eviction and lists what this slice really added to HostedHarnessClient; D3 no longer claims the bind-refusal path stops being reached (it is D4's trigger); D6 records the same-shape replay clause; D7's fence rationale no longer blames heartbeats (lease renewal touches writer_lease_until only); D9a names the two exempt codes and why already_attached is not one; the validation digest states which claims are pinned and which are not; the CI arithmetic reads 12 + 8x10 = 92; the stale workflow nit is dropped. * chore(ide): regenerate NOTICES for the merged dependency set (email channel) * fix(ide): replace the workspace-polluted NOTICES with the pristine regeneration The file committed in |
||
|
|
f2e069061a
|
feat(web-shell): add adaptive navigation rail and unified Live settings (#12943)
* feat(web-shell): add adaptive navigation rail and unified Live settings
* style(web-shell): add space below the Home action section
* Revert "style(web-shell): add space below the Home action section"
This reverts commit a2e1c7622336cceb174faf1814b057a727f6a589.
* fix(web-shell): Preserve navigation and Live drafts across refreshes
* fix(web-shell): keep rail navigation state, drag widths, and Live settings drafts consistent
Address the Critical findings from the latest review rounds:
- Build the standalone shell sidebar config from the sidebar's exported
defaults so the Agents entry can no longer silently drop out.
- Gate rail navigation's persisted uncollapse behind restoresColumn so
opening a full page (Settings, Plugins, ...) no longer rewrites the
user's collapse preference; only Home/Channels/Live restore the column.
- Reset the sidebar section when a panel closes and stop leaking 'split'
as a sidebar page, so a wide split keeps the home column and a working
collapse control.
- Clamp drag widths to the container-aware cap the CSS already renders,
floor the visual drag at the layout minimum, and restore the persisted
width from state instead of a mid-animation/container-capped rect.
- Cap the compact drawer's min-width at the container width.
- Keep the Live voice trigger reachable from the Live page header when
the sidebar's slot is hidden.
- Settle Live settings draft fields (and their conflict baselines) that a
refresh converges onto, so a later edit is not blocked by a stale
baseline.
* fix(web-shell): keep rail panel sections, status dots, and Live drafts consistent
Address review findings on the navigation-rail change: retain the
Channels/Live sidebar section when its panel closes (an explicit Home
choice sticks on the first click), load secondary-workspace attention
status whenever the Home column is hidden (idling the poll when nothing
runs), ignore zero-displacement presses on the resize handle, settle
padded Live settings drafts on trimmed refresh convergence, disable the
shortcut capture until status loads, key the empty-chat welcome chrome
off the shell container signal, and document /live in the pre-auth path
lists.
* fix(web-shell): close rail-era gaps in shortcut, dock, and status handling
Address the round-5 review findings on the navigation-rail change. The
Cmd/Ctrl+B handler resolved its target with e.target, which shadow-DOM
retargeting replaces with the portal host, so the editable-target
exemption never fired for portaled dialogs; it now reads
composedPath()[0] like its siblings. The same handler toggled the raw
sidebarCollapsed state, silently inverting the persisted preference in
the split-view fold band where the sidebar renders folded regardless;
the shortcut, the sidebar prop, and the environment-panel dock budget
now share one effective-collapsed expression. The rail's 56px is
excluded from the dock budget so the environment panel keeps docking at
1440px windows instead of being force-closed on load, with the e2e step
re-pinned at 1440 and the consequence recorded in the sidebar docs. The
secondary-workspace status queries now stay active while the Live
section column is open (the rail Home button is the only status surface
there), and the rail branch resets the project search when Live unmounts
its autoFocus field so a Home round-trip cannot steal focus. The Live
Voice card gates key removal and the required marker on the saved key
state, so a model edit leaving a route can no longer offer removal of a
key that was never stored.
* fix(web-shell): stop silent collapse-preference and drag-width rewrites
Address the round-5 review findings on the navigation-rail change, plus
the residual direction of the round-4 fold-band fix:
- The Cmd/Ctrl+B toggle computed from the effective folded state is a
constant expansion in the split-view fold band; it now rewrites the
unchanged preference there instead of flipping a stored `true` to
`false` on a keypress that changes nothing on screen.
- The rail's column restore fires `onCollapsedChange(false)` only when
the sidebar is actually collapsed, so a drawer tap on Channels/Live no
longer silently clears the desktop preference from the forced-open
drawer.
- The Channels rail entry restores the column only when the Channels
column exists (`channelNavigationEnabled`), matching openNavigation's
rule for full-page entries.
- The App's rail-Home callback drops its redundant preference write; the
sidebar's openNavigation already owns column restoration.
- A drag released at or past the container cap while the cap already
bound the start width no longer persists the capped width over a wider
stored preference, and releasing at the drag start restores the
pre-drag state width as well.
- The Live settings settle effect now runs only on a genuine status
change, so typing a value that briefly trims onto the saved one no
longer loses the just-typed characters.
Each behaviour is pinned by a unit case that goes red without its fix.
* fix(web-shell): settle Live drafts only on genuinely changed values
Follow-up to the round-5 settle fix: the daemon SDK returns a fresh
status object per fetch, so keying the settle effect on object identity
still let a 1s install poll or focus refresh with unchanged data
converge a padded draft the user was typing. Compare the settle-relevant
saved values against the previous status instead: only a refresh that
actually moved a saved value settles, while draft-only re-renders and
unchanged polls leave the in-progress text alone. Pinned by `does not
settle a padded draft when a poll returns unchanged values`, red against
the identity comparison and green with value comparison; the convergence
cases stay green.
* fix(web-shell): keep capped drags window-scoped and drop detached rail hints
Address the two round-6 Critical findings:
- The container-cap guard added last round only covered a release past the
cap. While the cap binds, the rendered edge cannot follow the pointer, so
the rect-based delta is container-scoped in both directions: a 2px
leftward jitter stored 298 over a 420 preference, and a later host
widening rendered the narrow value. Map the pointer delta onto the state
width whenever the cap bound at drag start, so persistence stays
window-scoped (418), while the past-cap branch keeps priority and an
uncapped drag still persists what the user saw.
- navigationHint held a live rail button and was only cleared by DOM
handlers on the nav. Removed elements fire neither pointerout nor blur,
so an unmounted rail - or just an unmounted hinted button, when its
feature gate flips - left the tooltip Popover open against a detached
node, painting the previous icon label near the viewport origin when the
rail returned. Clear the hint when the rail is gone or its anchor is
detached; the check runs every render because a dependency list cannot
observe a child unmounting while both deps stay unchanged.
Both are pinned by cases that go red without their fix: a leftward jitter
stores 418 (298 without the mapping, with the two neighbouring width cases
still green), and a rail tooltip does not survive a rail -> single -> rail
round trip.
* fix(web-shell): re-baseline hidden-surface and failed-save trackers
Address the two round-7 Critical findings:
- The secondary-workspace completion tracker only re-baselined while the
status surface was hidden, leaving a frozen running snapshot across a
visible Home period. Comparing the next refetch against it repainted a
completion the user watched happen as an unread one. The visible path now
nulls the per-source baseline, so the first hidden cycle after a visible
period is baseline-only: only completions actually observed while hidden
produce a dot. The always-hidden sibling path (and its existing test in
WebShellSidebar.collapse-persist.test.tsx) is untouched.
- A save rejected after the daemon persisted some of its writes (its
settings writes land before setEnabled, which rolls back only `enabled`)
was reported as settings.liveSetup.conflict: the stale apiKey baseline
compared against the refreshed keyConfigured/storedKey flipped by the
card's own request. The rejected save now queues a re-baseline of the
request keys and refreshes, and conflict with those keys is suspended
until the refreshed status lands and re-anchors them (state, not a ref,
so the re-baseline provokes the render that clears it).
Both pinned by cases that go red without the fix: no completed badge after
a plugins -> home -> plugins round trip while the sibling always-hidden
case stays green, and no conflict plus a retryable Save after a partially
landed save.
* fix(web-shell): stop certifying unfreshed secondary workspace status
Address the round-8 Critical (body-level, independently confirmed by
qqqys): the secondary catalog page is loaded and polled only while the
Home column is hidden, but the rail Home button folded its retained
snapshots into the indicator unconditionally. An approval resolved
elsewhere kept painting the amber dot and the "Waiting for approval"
accessible name until the user hid the Home column again — two render
sites for one stale certification, and a regression over the pre-PR
surface, which could only render the dot from a live, fetchable path.
build the rail indicator from the primary page plus only those secondary
sessions whose queries are currently armed. While the Home column is
visible the secondary contribution is dropped entirely; hiding the Home
column re-arms the queries and the still-waiting state comes back. On
live-state daemons the secondary catalog path is unloaded regardless, so
nothing live is hidden by this gate. Pinned by a plugins -> home ->
plugins round trip asserting both the dot attribute and the accessible
name, red without the gate while the always-hidden attention case stays
green.
* fix(web-shell): gate the completion tracker baseline on page freshness
Address round-9 Critical R9-1: nulling the secondary baseline on the
visible path closes only half the leak. On re-entering the hidden
surface the tracker installed the store's retained, never-refetched
catalog page as the new baseline (the guard rejected only loading and
error, never a stale page), so the poll arriving seconds later was
diffed against a snapshot taken before the visible window and a
completion the user watched was repainted as unread — exactly what the
visible-path null was supposed to prevent.
Stamp the moment the surface becomes hidden and refuse to install or
compare any secondary snapshot that is not provably fresh
(`(snapshot.updatedAt ?? 0) < hiddenSince`, an unstamped page counting
as not-fresh). The first after-hidden poll then installs the baseline
from truly fresh data. The strengthened round-trip case drives retained
running -> stale re-entry -> fresh idle; it is red without the gate
(the completion badge and the Finished accessible name both appear) and
green with it, while the always-hidden completion case stays green.
* fix(web-shell): clamp every collapse entrance and clear More on rail teardown
Address round-9 Criticals R9-2 and R9-3 (body-level):
- The split-view fold-band clamp lived only at the Cmd+B entrance; the
rail's Collapse/Expand button reached handleSidebarCollapsedChange
unclamped, so a click that visibly does nothing still overwrote the
stored preference and a stored `true` could never be re-written inside
the band. The clamp now lives once in the shared writer: in the fold
band it re-stores the current raw preference regardless of which value
was requested. (`sidebarCollapsed` and `splitFoldedSidebar` reach the
stable []-callback through refs — the former would close over the
mount-time value and the latter is declared later, TDZ.) The Cmd+B
site shrinks back to passing the toggle intent. Pinned by a third arm
in the fold-band App test that clicks the collapse toggle at 1100px
and finds the stored `true` untouched — red with the clamp removed.
- The More reset effect did not watch layout, so a rail -> single ->
rail round trip left moreOpen=true against an unmounted owner and the
rail returned with a phantom open menu (content in the document,
focus inside, never reopened). `layout` joins the dependency list and
a round-trip case in WebShellSidebar.collapse-persist.test.tsx goes
red without it.
* fix(web-shell): let exit-split navigation restore the column under the fold clamp
Address maintainer P2 inline: after the shared-writer clamp landed, a
Home click from the split-view fold band was still intercepted — the
rail's restoresColumn `onCollapsedChange(false)` wrote the folded raw
value back (correct for taps that stay in split view), and `onOpenHome`
then closed split view with the raw preference unchanged, leaving the
Home column folded until a second click.
Split the intent at the shared writer: `exitFoldBand` marks entrances
that reorganize the layout away from split view, bypassing preservation,
and the rail Home handler uses it when the fold band was the overriding
state at click time. Taps that stay in the fold (Cmd/Ctrl+B, the rail
Collapse/Expand button) keep their preference protection untouched, and
the write still never happens inside the mobile drawer, where
splitFoldedSidebar is forced false by construction — so the drawer case
is unaffected (drawer protection is preserved).
Pinned by a fourth arm in `does not invert the stored collapse
preference in the split-view fold band`: stored `true` at 1100px split
view, click `[data-testid="open-home"]` once, and the column is expanded
with the stored key `false`; dropping the bypass inverts that arm while
the three protected arms stay green.
* fix(web-shell): cover Channels and Live in the exit-split fold exception
Address maintainer P2 follow-up: the exitFoldBand carve-out applied only
to Home, so Channels and Live — whose `openPanel` call exits split view
through the web-shell page set (`setMainView('chat')`) the same way —
still had their restoresColumn write clamped when the fold band owned
the sidebar, leaving the section column folded until a second rail tap.
Extent the same bypass to those two entrances, with each entry's own
column-existing gate: Channels applies it only when channelSidebarEnabled
would actually produce a column (mirroring the rail's
channelNavigationEnabled rule, which still leaves the full-page channels
variant folded), and the Live handler inherits the liveSidebarEnabled
guard it's already defined under.
Pinned by two parallel cases beside the fold-band keyboard/click arms:
stored `true` at 1100px split view → one rail tap on `[data-testid=
"open-channels"]` (with `session_source_metadata`) and one on
`[data-testid="open-live"]` (with showLive) — each expands the column and
writes `false`; dropping both bypasses turns both cases red while the
protected Home arm stays green.
---------
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Shaojin Wen <szujobs@gmail.com>
|
||
|
|
fde56a8203
|
fix(serve): let Web Shell trust a workspace without a terminal (#13146)
* fix(serve): let Web Shell trust a workspace without a terminal Folder trust fails closed: with `security.folderTrust.enabled`, a folder that no rule decides is untrusted, and the only way to record a decision is the terminal prompt or `/permissions`. When `trustedFolders.json` is missing or unreadable, every registered workspace resolves untrusted at once and a Web Shell or Desktop client has no way back in. The existing `POST /workspace/trust/request` only publishes a request for a local operator, which those clients cannot satisfy. Add an operator-authority route that records the decision itself: POST /workspace/trust/grant POST /workspaces/:workspace/trust/grant _qwen/workspace/trust/grant It reuses the strict mutation gate and the existing trusted-folder writer, always targets the workspace the request already resolved to, and returns the status the workspace reports after the write. Refusals mirror the request route: folder trust disabled, managed scratch, live conversation, inactive runtime, unreadable trust file. Grant only; there is no revoke counterpart. The route is registered unconditionally and advertised through a new `workspace_trust_grant` capability that reuses the trust hot-reload toggle, so the Web Shell offers the action only where the decision reaches the running runtime without a restart, and an older daemon shows no affordance at all. Fixes #13130 * test(serve): add workspace_trust_grant to the integration capability baseline The route registration added workspace_trust_grant to EXPECTED_REGISTERED_FEATURES in serve/server.test.ts but not to the second baseline list in integration-tests/cli/qwen-serve-routes.test.ts, which deep-equals the live server's list and therefore failed deterministically. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(serve): document workspace_trust_grant in the protocol table and route envelope The new conditional tag was added to CONDITIONAL_SERVE_FEATURES but not to docs/developers/qwen-serve-protocol.md nor to the advertised-feature list in integration-tests/cli/qwen-serve-routes.test.ts, so capabilities-docs-contract and the capabilities envelope assertion both failed. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-conflict/jmupfte0zk0 * fix(serve): admit SSH trust/grant passthrough and pin grant guards - Add trust/grant to the REST SSH boundary POST passthrough so the workspace-qualified grant route matches its ACP SSH_METHODS twin; without it the Web Shell Trust button on an SSH workspace could only ever answer 501 (R1-2). - Reword the workspace_trust_grant capability row: the tag means the running runtime hot-applies the decision, not that the grant routes exist — they are registered unconditionally (R1-1). - Pin both grant routes' 503 workspace_runtime_unavailable guards with a transitioning primary and a draining secondary (R1-10). - Make the ACP grant dispatch test's pre-write status untrusted so the asserted reply can only be the post-write grant result (R1-9). Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmupzgp080a * docs(serve): narrow three workspace-trust claims to shipped behavior Review round 4 of #13146, doc-accuracy only. Three sentences this PR introduced stated something the code does not do: - qwen-serve-protocol.md: the workspace_qualified_rest_core rule said a capability may only define a narrower *read-only* policy, but this PR adds a grant mutation accepted for a registered untrusted workspace. Name workspace_trust_grant as the exception. - web-shell-workspace-trust-grant design doc (EN + zh-CN): the Refusals row promised 500 trusted_folders_invalid for a malformed, unreadable or non-regular trust file. A dangling symlink reads as no file and is replaced with a 200, corruption the write itself discovers answers internal_error, and the load verdict is cached with no production reset. Note all three; the writer is unchanged here. - trusted-folders.md: a missing file leaves every folder untrusted, but a malformed or unreadable one is a fatal configuration error and the trust routes answer 500. Split the two cases and scope the Web Shell recovery sentence to the no-rule case. No code changes. Code-side repairs for the divergences above are tracked separately. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmuq3r0k30o * docs(serve): correct three workspace-trust claims to measured behavior Design doc (en + zh-CN twin): - The "Already trusted" refusal row now names its precondition. A successful grant starts a rebuild that moves the entry to `transitioning`, and while it is there both grant routes answer 503 `workspace_runtime_unavailable` with `Retry-After: 1` even though the trust record is already written, so the row's unconditional idempotent 200 did not hold for that window. - The write-discovered corruption sentence was inverted. A symlinked or otherwise non-regular trust file, a document whose root is not a JSON object, and a rule carrying an invalid trust level all raise `FatalConfigError` from the writer, which `sendTrustError` maps to 500 `trusted_folders_invalid`. Only a syntactically invalid document that was still valid when the daemon first cached it reaches the write as a plain parse failure and answers 500 `internal_error`. Protocol doc: - The plural grant mutation's acceptance is not conditional on the `workspace_trust_grant` tag. Both grant routes are registered unconditionally and neither handler reads the capability, and the tag row already states the routes are served regardless. The tag reports hot-reload wiring only. Docs only: no production code, route, or capability surface changes. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmuqkwas11i * docs(serve): scope the trust-grant guarantees to shipped behavior - qwen-serve-protocol.md: the workspace_trust_grant row no longer states live application unconditionally — a higher-precedence source (IDE trust for the daemon's own cwd, a settings/trust-file load error) still wins, and the response's effective.source names the winner; the tag-absent case now says no writer applies live without hot-reload wiring (the terminal prompt included) instead of pointing at it as a remedy (R2-3). - trusted-folders.md: the malformed-file remedy gains the daemon-restart step (a running daemon caches the failed load and keeps refusing the Trust action), the fail-closed claim is scoped to folders no higher-priority signal decides, and the 500 claim is narrowed to the v1 routes with the v2 status route's 200 + configured.state:"error" shape named (R1-15). Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(serve): fail a trust grant that does not take effect grantWorkspaceTrust answered 200 on the write alone, never checking that the decision it recorded is the one the trust evaluator reaches. With an equal-depth DO_NOT_TRUST rule under an alias spelling of the same directory, a settings error, or an IDE distrust of the daemon's own cwd, the new TRUST_FOLDER entry loses and the workspace stays untrusted — the panel spins to its 30s deadline and silently reverts. After the write, re-evaluate with the same evaluator the reconciler drives (reading the post-write in-memory rule set, so no disk round-trip), and answer 409 trust_grant_ineffective when the grant did not take. Refusals tables updated in both design-doc languages. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs(serve): scope the trust-grant ACP and 503 claims to shipped behavior - Endpoints: state the Qualified row's ACP precondition. An untrusted non-primary workspace is refused 403 untrusted_workspace at the mount resolver before any dispatcher exists, so for the locked-out secondary this design exists to recover, the ACP column is undispatchable and recovery is REST-only. - Advertising: the consistency claim covers the capability tag and the REST surface, not the ACP counterpart. - Refusals: the 503 during a rebuild is retryable-until-applied, but the reference panel reports every rejection identically (#13186). And re-keying a path only replaces an equal-depth rule under that spelling, so an alias-spelled DO_NOT_TRUST survives the write and the grant answers 409 trust_grant_ineffective. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmuqvm3p20y * test(serve): pin SSH admission of workspace/trust/grant The SSH capabilities test swept the already-filtered advertised list and asserted only arrayContaining membership plus the absence of an ssh_workspace_operation_unsupported frame, so every assertion stayed true when the list shrank. Dropping 'workspace/trust/grant' from SSH_METHODS left the suite green while SSH-backed workspaces lost the only in-app trust recovery the design doc promises. Assert membership of '_qwen/workspace/trust/grant' in the advertised array. The sweep loop is unchanged: it still drives each method through Promise.allSettled against a dispatcher with no workspace service. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmuqvm3p20y * fix(serve): reply to a trust grant whose own write retired the generation The ACP `_qwen/workspace/trust/grant` case re-asserted the captured generation guard after the grant. A successful grant notifies the trust monitor, whose reconcile calls `registry.beginReplacement` and closes that very guard, so an operation that had already written and applied the decision was answered with `-32603` / `workspace_runtime_unavailable` / 503 while the REST twin answered 200. Keep the pre-write assert: for this method the generation closing is the success signal. The dispatch test now closes a real guard inside the spied grant, so re-adding the post-write assert turns it red. Also bring two documents back to the implemented contract: the `workspace_trust_grant` protocol row and the Web Shell bullet in trusted-folders.md. A refused grant answers 409 with only `error` and `code: "trust_grant_ineffective"` and carries no `effective` member, three causes can defeat a grant rather than two, the Trust action keys on the advertised capability rather than on route presence, and on a daemon without hot reload the v1 trust status does report the recorded decision while the runtime gates wait for a restart. Drop the never-read `state`/`source` fields from `WorkspaceTrustGrantIneffectiveError`. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmurpmcje1k * test(serve): forward the request context in the trust-grant dispatch spy The new `_qwen/workspace/trust/grant` dispatch test bound `fakeWorkspace.grantWorkspaceTrust` and re-invoked it with no arguments. `fakeWorkspace` is closed with `as unknown as DaemonWorkspaceService`, so the bound reference carries the interface arity `grantWorkspaceTrust(ctx: WorkspaceRequestContext)`, and `tsc --build` failed with TS2554. That runs inside the `prepare` hook of `pnpm install`, so the single type error took down every job at its Install dependencies step. Forward the context the dispatcher already supplies so the mock keeps calling the real fake with the same argument. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-conflict/jmurtjt4g1q * fix(serve): give the ACP trust-grant refusal a branchable 409 frame `WorkspaceTrustGrantIneffectiveError` had no arm in `toRpcError`, so the name-keyed switch fell through to the default arm and ACP clients received `{code: -32603, message: 'Internal error', data: {errorKind: 'internal'}}` for a refusal the REST twin answers as `409 { code: 'trust_grant_ineffective' }`. SDK transport negotiation prefers acp-ws/acp-http over REST, so that opaque frame was the default client path: a client could not tell a durably recorded but outruled grant from a daemon fault, and could not stop retrying. Map it beside the other typed refusals, following the shape the file already uses for a 4xx-classified conflict (`data.httpStatus` carries the 409, the JSON-RPC code agrees with the REST classification). The message is the same client-safe string REST already ships, so nothing new is disclosed. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmus0c5f620 * fix(daemon): Verify trust grants against persisted policy * fix(serve): preserve effective workspace trust grants --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: yiliang114 <yiliang114@users.noreply.github.com> |
||
|
|
5374641323
|
feat(memory): Opt-in selector skip for a unique new recall hit (#13158)
* feat(memory): opt-in extraction cooldown and selector skip experiments Moved out of #13020, where they had been bundled with unrelated deferred-tool work. Content is the #13020 head ( |
||
|
|
576689d073
|
fix(channels): clean up owned workers after config loss (#11071)
Some checks failed
SDK Python / Classify PR (push) Has been cancelled
SDK Python / SDK Python (3.12) (push) Has been cancelled
SDK Python / SDK Python (3.10) (push) Has been cancelled
SDK Python / SDK Python (3.11) (push) Has been cancelled
Qwen Code CI / Desktop Shell (windows-2022) (push) Blocked by required conditions
E2E Tests / Build for E2E (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/1 (push) Blocked by required conditions
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/1 (push) Blocked by required conditions
E2E Tests / E2E Test - macOS - shard 1/2 (push) Blocked by required conditions
E2E Tests / E2E Test - macOS - shard 2/2 (push) Blocked by required conditions
E2E Tests / E2E Interactive - OpenTUI renderer (bun) (push) Blocked by required conditions
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 / Flyway migration version uniqueness (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (push) Blocked by required conditions
E2E Tests / cron-interactive E2E (nightly) (push) Blocked by required conditions
E2E Tests / web-shell Browser Regression (push) Waiting to run
Android Mobile Shell / Build, unit tests, and lint (push) Waiting to run
Android Mobile Shell / Keystore and profiles (API 26) (push) Waiting to run
Android Mobile Shell / Keystore and profiles (API 36) (push) Waiting to run
SDK Java / ubuntu-latest / Java 11 (push) Waiting to run
SDK Java / Runtime Broker and Managed Agent MariaDB / Java 21 (push) Waiting to run
Verify Landlock helper / Native Windows settings and streams (push) Waiting to run
SDK Java / Hosted process fault gates / MySQL 8.4 / Java 21 (push) Waiting to run
SDK Java / Real daemon E2E / Java 11 (push) Waiting to run
Verify Landlock helper / Native Linux CLI boundary (push) Waiting to run
Verify Landlock helper / arm64 (push) Waiting to run
Verify Landlock helper / x64 (push) Waiting to run
* fix(channels): clean up owned workers after config loss Addresses #11063 for a single missing-config owner. Preserve revision and runtime ownership checks and make absent settings removal idempotent. * fix(channels): clarify missing-config ownership diagnostics Address PR #11071 review with named ownership checks, distinct rejection diagnostics, and explicit passive-read assertions. Preserve the current deletion contract. * fix(channels): gate missing-config delete convergence on persisted startup state * fix(channels): harden missing-config delete convergence - Re-read the merged channel config view after the worker stop window and fail closed with channel_settings_conflict when a configuration reappears at another scope mid-delete: the optimistic-concurrency token covers only the workspace's own scope files. - Reject the convergence while the worker manager is mid-transition: a starting or reconciling manager reports the candidate selection as no workers and nothing committed, which reads as the silent shape without being it. - Gate the "another scope" refusal on a record-valued merged entry so a legacy scalar entry in the workspace's own file converges instead of being misattributed to user or system settings. - Pass pre-loaded settings with skipLoadEnvironment to the injected loadChannelsConfig so the gate read no longer writes the target workspace's .env into the daemon's process-global environment. - Deduplicate the ownership invariant on the missing-config path: assertConvergeableRuntimeOwner now returns the confirmed owned-worker outcome instead of remove re-deriving it through a provably dead gate. - Correct both doc pages: the channel_instance_not_found promise only holds when the selected workspace's resolved scope does not own the configuration, and a home-directory workspace resolves that scope to the shared user file. * fix(channels): reject configured channel delete while runtime is mid-transition The mid-transition guard lived only on the missing-config branch, so a DELETE of a configured channel landing during the first-start window — when committedChannelNames() still reports nothing — skipped both the ownership check and the worker stop, deleted the configuration, and answered 200 with runtime stopped while a worker for that name was coming up. Hoist the settled check above the branch split so both branches inherit it, and pin the configured shape with a test. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): narrow mid-transition channel delete guard to at-risk channels (#11071) --------- Co-authored-by: 西岐 <fengqi.mfq@alibaba-inc.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: qwen-code-autofix <qwen-code-autofix[bot]@users.noreply.github.com> Co-authored-by: qwen-code[bot] <qwen-code[bot]@users.noreply.github.com> |
||
|
|
612a552959
|
feat(channels): add IMAP and SMTP email channel (#12939)
* feat(channels): add IMAP and SMTP email channel * test(channels): include email in managed channel catalog expectations --------- Co-authored-by: destire-mio <248462155+destire-mio@users.noreply.github.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
45ee202cb1
|
feat(agents): add isolated remote Qwen runtime hosts (#12582)
* feat(serve): join a coordinator as a runtime with one link `qwen serve --join <link>` takes the single link the coordinator shows under Agent → Runtime → Add runtime (<coordinator>/join/<workspace>/<token>) instead of --agent-host-server, --agent-host-workspace-id and the QWEN_AGENT_HOST_ENROLLMENT_TOKEN variable typed separately. The token is single-use and short-lived; the host saves its own credential after enrolling, as before. A host now advertises every program it can run (Qwen Code always, Codex when its CLI is on PATH or was asked for) so one machine appears as one runtime offering several programs. * feat(web-shell): Agent page tabs and a one-line Add runtime dialog The Agent page now always shows its three tabs (Agents, Conversations, Runtimes); they were hidden whenever the page was opened from the sidebar, which instead carried three sub-links. The sidebar keeps a single Agent entry. Add runtime is a dialog: it issues a single-use join token, shows `qwen serve ... --join '<link>'` (and an npx variant) with copy buttons, warns when the address is localhost or plain HTTP, and waits — the live stream flips it to "<name> is connected", listing the programs that machine offers, with a shortcut to create an agent on it. The old inline enrollment and remote-connect forms are gone; connecting an existing serve by address and token is the dialog's second tab. The client no longer builds the long enrollment command itself. Removes web code the PR audit confirmed dead: ThreadConversations.tsx, summariseWorkspaceWork, ThreadGroup.label, the unreachable create-method chooser in AgentCreatePage, the initialCreateTask/api/runtime/loading props, unused CSS module classes and a duplicated prop spread. * refactor(agents): remove dead workspace-agent code confirmed by audit Drops the scripts/audit harness (not wired into CI), request capture, the Codex turn-result adapter, the notification pipeline nothing could trigger, unused store/dispatcher/lease/A2A exports and legacy background-agent plumbing. Recover only reports work when a parent report is actually pending. * fix(web-shell): hide agentCollaboration from the settings message The experimental flag has no alias in the settings dialog map, which the alias-drift test rejects. * feat(agents): bind agents to a runtime program and share them over A2A An agent on a runtime can pick the program to run (Qwen Code or Codex) when that runtime offers both; the host runs each assignment with the program its agent is bound to and falls back to its default otherwise. Agents can be shared with callers outside the workspace: each share is its own A2A grant with a 7-day expiry, the token is shown once with a ready-to-run SendMessage curl, and any share can be revoked. A failed run's retry row now hides while that agent has a live run and once the conversation is closed. * fix(agents): push runtime liveness changes, not every heartbeat Heartbeats rewrite hosts.json every five seconds, and each write made every open tab refetch the whole roster and thread list. A runtime that died wrote nothing, so it never showed as offline without a reload. The event stream now compares what a person can see (runtimes, their programs, online or offline) on each hosts.json write and on a five-second timer, and only announces a change. Add runtime also recognises a machine that rejoins under its saved identity. * feat(web-shell): polish Agent page, New agent and the @ picker - New agent needs only a name; it can start from a .qwen/agents role, preselects the runtime it was opened for, and shows both programs with the reason one is unavailable. - Agent rows read "Program · Runtime", offer "@ Mention" and fold configure/share/pause/retire into a menu; moving an agent to another runtime keeps its program. - The @ picker shows each agent's program and runtime and ends with "New agent…"; at-items can now be actions via onSelect. - The collaboration composer says who a reply reaches and that other members are not interrupted; skip reasons and leftover strings are localised. * feat(agents): show a running agent's tool calls as steps A running member now lists its latest tool calls under its status line, one per line with running, done or failed, like a CI job's steps. The turn stream reports updates as an object so steps travel with stage and text; remote runtimes still report stage and text only. Also: subtasks in the team panel name their assignee, join links last 15 minutes as the spec says, and a share created from a localhost page warns that its address only works on this computer. * fix(agents): skip a liveness check when the store is busy A failed hosts.json read looked like every runtime leaving, which announced two spurious changes. * feat(agents): let a person's post pass the token budget The tree-wide token cap now binds only agent-authored posts, like the turn budget: agents on an exhausted tree stop waking each other, while a reply from a person still books work. Every automated path posts as an agent or the system, and A2A intake always starts a new root thread, so nothing unattended gains a bypass. * refactor(agents): move cross-runtime and A2A to a follow-up PR This PR now carries local collaboration only: agents on this computer, shared threads, streaming, waiting states, the @ picker and the Agent page with Agents and Conversations tabs. Moved out, to return in a stacked PR: agent hosts (join links, the --join and --agent-host-* flags, enrollment, heartbeat, lease and pickup routes, the host client and Codex host sessions), per-agent runtime and program binding, the Runtimes tab and Add runtime dialog, the A2A server, grants, external intake and agent sharing, and the @a2a-js/sdk dependency. Records written by builds that had them keep loading; the extra fields are ignored. * feat(agents): run agents on other computers and share them over A2A Brings back everything #11206 moved out, stacked on it: agent hosts (join links, the --join and --agent-host-* flags, enrollment, heartbeat, lease and pickup routes, the host client and Codex host sessions), per-agent runtime and program binding, runtime liveness events, the Runtimes tab and Add runtime dialog, the A2A server, grants, external intake, agent sharing and the @a2a-js/sdk dependency. This reverts commit |
||
|
|
b906f937ec
|
fix(serve): upload session attachments in 512 KiB chunks (#12923)
Some checks are pending
Qwen Code CI / Classify PR (push) Waiting to run
Qwen Code CI / Test (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Lint & Static (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / web-shell E2E Smoke (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Test (macos-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Test (windows-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Integration Tests (no-AK, No Sandbox) (push) Blocked by required conditions
Qwen Code CI / Integration Tests (CLI, No Sandbox) (push) Blocked by required conditions
Qwen Code CI / Desktop Shell (ubuntu-22.04) (push) Blocked by required conditions
Qwen Code CI / Desktop Shell (windows-2022) (push) Blocked by required conditions
E2E Tests / Build for E2E (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/1 (push) Blocked by required conditions
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/1 (push) Blocked by required conditions
E2E Tests / E2E Test - macOS - shard 1/2 (push) Blocked by required conditions
E2E Tests / E2E Test - macOS - shard 2/2 (push) Blocked by required conditions
E2E Tests / E2E Interactive - OpenTUI renderer (bun) (push) Blocked by required conditions
E2E Tests / channel-plugin E2E (nightly) (push) Blocked by required conditions
E2E Tests / cron-interactive E2E (nightly) (push) Blocked by required conditions
E2E Tests / web-shell Browser Regression (push) Waiting to run
pnpm Worktree Smoke / Install (macos-latest) (push) Waiting to run
pnpm Worktree Smoke / Install (ubuntu-latest) (push) Waiting to run
pnpm Worktree Smoke / Install (windows-latest) (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 / Runtime Broker and Managed Agent MariaDB / Java 21 (push) Waiting to run
SDK Java / Hosted process fault gates / MySQL 8.4 / Java 21 (push) Waiting to run
SDK Java / Real daemon E2E / Java 11 (push) Waiting to run
* fix(serve): upload session attachments in chunks * codex: address PR review feedback (#12923) * codex: address PR review feedback (#12923) * codex: address PR review feedback (#12923) --------- Co-authored-by: jinye.djy <3007091+doudouOUC@users.noreply.github.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
8c914ebe03
|
feat(agents): add local workspace-agent collaboration (#11206)
* test(agents): kill a writer mid-transaction, and say what that does not prove A daemon can die holding the workspace lock. Two things must be true afterwards and now are, from a real SIGKILL rather than an argument: the store stays readable with nothing written before the crash lost, and writes come back without anyone clearing the lock — a lock held by a dead process that nothing reclaims is a workspace wedged forever. How long recovery takes is reported rather than asserted, and that is a correction. An early probe measured a 10.5-second outage and I wrote that into both the script and a code comment as a measured fact. Four repeat runs recover in about 25ms and the outlier never reproduced, so the assertion that a write in the gap is refused was dropped: it depends on where in the staleness cycle the crash lands, and stating it as an invariant was wrong. Both comments now say what I can actually support. The route maps that refusal to 503 with a Retry-After instead of a 500 quoting a lock file at whoever clicked. It is a wait, not a fault, whether it lasts 25ms or ten seconds. The script also records what it does not cover, because I checked: replacing atomicWriteJSON with a plain truncating write leaves this and the concurrency script green. The file lock means two writers never touch one file at once, so atomicity only matters for a crash *during* a write, which killing an idle holder never reaches. store.test.ts covers that with fault injection. A script that passes under a mutation which should break it does not cover that property, and saying so is the difference between coverage and the appearance of it. * test(agents): fuzz the store against its invariants The other scripts check scenarios someone thought of. This one draws operations at random — create, post as a person or an agent, claim, finish, toggle, retire — and after every step asserts what must hold regardless of order: every thread readable, message sequences unique and increasing with the watermark ahead, run ids unique, queueSequence unique across the workspace, parent and root ids resolving, terminal runs carrying an end time, no agent running more than its maxConcurrentRuns, and no run booked for an agent after it retired. The status resolver is called on every thread, since it has to answer for any shape the store can reach. A refusal is a legal outcome and is recorded as one — the store simply has to stay consistent through it. The seed is printed and accepted back, so a failure is reproducible instead of a story about a run nobody can repeat. Clean over seven seeds, up to 800 steps. What makes that worth anything is what it does when the invariants are broken. Removing the concurrency check from claimRun is caught by step 42 on one seed and step 20 on another, named as "ag_1: 2 running over a limit of 1". Removing the retirement guard from decideDispatch — the exact bug fixed in |
||
|
|
a765229c0a
|
fix(daemon): persist session approval mode across cold restore (#12918)
* fix(daemon): persist session approval mode across cold restore * fix(core): Skip approval notifications for derived configs Prevent child-local approval mode changes from invoking the root-only listener on derived Config overlays. Clarify when explicit mode changes create a transcript and how recorder failures are retried. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
e39567eb56
|
fix(cli): honor --bare and --safe-mode in the cross-session messaging gate (#9845)
* feat(core): accept cross-session messages behind an inbound gate Step two of QwenLM/qwen-code#8724, rebuilt on current main now that the registry from step one has landed. A session can be reached by another session on the same machine, and every message that arrives is gated before the model can act on it. Off by default behind `agents.crossSessionMessaging`. Transport is one UNIX domain socket per session, NDJSON over the wire, one frame per line. The socket directory is 0700 and the socket 0600, and that is the whole access-control story: Node cannot read SO_PEERCRED without a native addon, so a frame's claimed `from` is not authenticated. Everything downstream assumes that. The gate is why the transport and the policy land together. With an explicit `agents.crossSessionInbound` the user decides; unset, the policy follows approval-mode parity — a message auto-delivers only when acting on it cannot do more than the sender could already have done itself. Anything unreadable holds. Held messages are settled rather than stranded: the buffer is bounded, shutdown expires the rest, and every terminal outcome goes back to the sender as a control frame. Content reaches the model inside a <cross_session_message> envelope with the delimiter defanged in the body, so a peer cannot close the envelope early and forge one attributed to the user. The envelope carries a fixed notice that a peer holds none of the user's authority, and the auto-mode classifier gains the matching rule. `/peers` lists and releases held messages; without it, holding would be indistinguishable from dropping. Landed only after four independent reviews, whose non-obvious findings are worth naming because they were all live defects: - A receiver in AUTO_EDIT auto-accepted peer messages and nothing reviewed what they caused. The old rationale — "every consequential action still faces its own gate" — is true of AUTO but false of AUTO_EDIT, where edit confirmations are approved outright and the classifier does not run. A peer could get a file written with no prompt, no classifier and no user. Receiver policy now turns on whether the mode reviews actions at all, not on whether it is YOLO. - `server.unref()` does not cover accepted connections, so any peer that connected and lingered pinned the session open forever. - `fs.mkdir(recursive)` and `fs.chmod` both follow a symlink, so another user could pre-create the world-writable `/tmp` fallback directory and redirect our 0700 chmod onto a directory of ours. - A full listen backlog surfaces as EAGAIN on Linux, not EBUSY; the busy case was being read as dead on the primary platform. - The envelope was escapable without markup: `escapeAttribute` handled `&<>"` but not newlines, so a crafted `fromName` could emit free-standing lines inside the opening tag. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(i18n): translate the /peers description in strict-parity locales `Test (ubuntu-latest, Node 22.x)` has failed every run on this branch with FAIL src/i18n/mustTranslateKeys.test.ts > does not fall back to English for any built-in command description in strict-parity locale { code: 'zh-TW' | 'zh' } AssertionError: expected [ 'peers' ] to deeply equal [] `peersCommand` set `description` to a literal English string rather than routing it through `t()`, so both strict-parity Chinese locales fell back to English and the parity test — which exists to catch exactly this — reported the `peers` path. Four merges of current main were attempted against this check. None could fix it: the untranslated description is introduced by this branch, so no state of main contains the missing keys. Use the `get description() { return t(...) }` form every other built-in command uses, and add the key to `en.js`, `zh.js` and `zh-TW.js`. All three locale files remain in sync at 1817 keys. Verified both directions in a clean worktree install: with the change, `mustTranslateKeys.test.ts` is 20/20; stashing it reproduces the CI failure exactly, `expected [ 'peers' ] to deeply equal []`, twice. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VgTjRF91xANQh6SY9YGyCf * fix(ipc): close Critical review findings in the cross-session inbox - Dedup held msgIds case-insensitively, matching /peers resolution - Print unique dash-stripped handles and resolve them in /peers - Bound outbound sends: in-flight cap plus an absolute deadline (socket.setTimeout is an idle timer a dribbling peer resets) - Defang whitespace-split and quote-glued envelope delimiter tokens - Seed onHeldChange subscribers with the current held snapshot - Skip POSIX-only socket-path tests on win32 like the sibling suites * fix(cli): gate held-message announcements on the held set growing Once the hold buffer is full, every further peer frame evicts the oldest entry while arriving under a fresh id; announcing each of those appends a history item and re-renders per frame — reintroducing one layer up the unbounded growth the hold buffer's ceiling exists to prevent. * fix(ipc): close round-6 Critical findings in the cross-session inbox * fix(ipc): close round-7 Critical findings in the cross-session inbox - defang envelope delimiters split by render-invisible separators the \s class misses, sharing flattenPeerLabel's strip class so the two cannot drift (R5-1) - restore admission-failed queue submissions deferred until idle, the same recovery the /btw path uses, so a restored peer envelope cannot leak raw into the racing turn's mid-turn steer drain (R7-1) - cap the accepted-message backlog symmetric to the held cap: the pre-wiring buffer and the post-wiring queue refuse once full, with an honest 'expired' receipt instead of unbounded socket-speed growth (R7-11) * fix(ipc): close round-8 Critical findings in the cross-session inbox - Refuse any msgId canonicalizing to `all` at the wire boundary and fold the /peers bulk keyword case, so a peer-chosen id can never alias the bulk action or trap a per-message decision (R8-1, R1-11, R1-27). - Re-hold approved messages whose delivery fails instead of silently dropping them: decide() returns 'failed' and parks the entry back at its position, reevaluate() re-holds failed releases, and /peers reports the failure honestly (R8-2, R1-18). - Drain accepted peer envelopes on a preprocessing-free path: the queue marks them peer, the drain submits them with the Teammate send type (which returns before slash/shell/@ handling), renders the one-line projection, and restores failed admissions as peer entries (R8-3). - Close the envelope-defang class structurally: escape every `<` in peer content so no forged delimiter survives regardless of wedged invisibles or homoglyph spellings; the open-enumeration regex is deleted (R5-1). Every guard is witnessed by new focused tests and verified with mutation probes (each probe fails its witnesses when removed, passes restored). * fix(ipc): close peer messaging lifecycle races * feat(core): address local peer sessions from agent tools * fix(core): make peer addresses unambiguous * fix(core): reserve peer routing namespace * fix(ipc): complete peer delivery feedback * fix(ipc): harden peer session routing * fix(cli): honor effective peer messaging gate * fix(cli): report effective peer messaging state * test(cli): teach the cross-session test doubles the new gate accessor The interactive UI gates the peer inbox on `config.isCrossSessionMessagingEnabled()` instead of the merged `agents.crossSessionMessaging` setting, so every config double that exercises `startInteractiveUI` must expose that accessor. The shared `sessionRegistryConfigStub` in `llm.test.tsx` builds most of those doubles, and the four `startInteractiveUI.test.tsx` cases that assert the inbox binds need the enabled config rather than the default. Fixes the 37 failing cli tests (`Tests 37 failed | 28548 passed`) in the `Test (ubuntu-latest, Node 22.x)` lane; both files now pass 101/101. * refactor(core): drop peer-receipts, superseded by peer-send on main The send-side receipt correlation this module implemented shipped on main as packages/core/src/ipc/peer-send.ts (#10158, step 3 of #8724), in a strictly richer form: it canonicalizes message ids, models seven delivery statuses with explicit legal-transition sets, bounds tracked sends at MAX_TRACKED_SENDS, and reports the settled receipt with its age. This copy had no production import site -- only its own test imported it -- so keeping it could only let it drift from the shipped version. Removing both files leaves the branch as just the cross-session messaging gate change it now describes. No behavior change. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): gate every peer-inbox reader on --bare and --safe-mode The only reader was isCrossSessionMessagingEnabled(settings.merged), which cannot see the two session-level suppressions. A session started with --bare or --safe-mode bound a UDS inbox and published its ipcPath into the live-session registry, advertising itself as addressable from the modes that exist to close cross-process surfaces. On the daemon path it was worse than visible. sendToPeer reports `disabled` only when the caller's own record lacks an ipcPath, so publishing one is also what let a suppressed hosted session send -- while inbound was already refused. An interactive TUI under the same flags bound nothing and sent nothing; a hosted session did both. Answer the question once, in the file whose doc comment already claims to be the one place it is answered: crossSessionMessagingSuppression(config) reads the two accessors Config already carries, and isCrossSessionMessagingActive(settings, config) narrows the setting with it. All four readers now ask that -- the interactive bind, the interactive failure banner, /peers, and registerHostedSession. /peers also stops hardcoding "--bare or --safe-mode" and names the cause that actually fired, with the environment channel that reaches each, so a session suppressed only by QWEN_CODE_SAFE_MODE recognises why. Drops the ConfigParameters field and accessor an earlier shape of this branch added. Config already stores both flags and loadCliConfig already passes them in, so the parameter duplicated two booleans that were on the object handed to every read site. Its fail-closed default was also what made the hosted reader look unsafe to wire, which is why that reader was deferred rather than fixed; reading the accessors removes both the parameter and the reason. Each new case was mutation-verified and each mutation reverted: ignoring config at the ACP gate, at the interactive bind, or at the banner branch turns the corresponding cases red; deleting the /peers message arm turns both of its cases red; dropping the getBareMode clause turns the bare-mode cases red in three suites. Refs #8724 Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: record that --bare and --safe-mode suppress cross-session messaging Five places stated the settings-only rule as a contract and would be wrong after the gate change: the agents.crossSessionMessaging row, the two --safe-mode inventories, the hosted-session registration paragraph, and the SDK's inbox note. The row now carries the same "Ignored in --bare and --safe-mode" clause its sibling general.outputStyle already has, and both inventories list cross-session messaging alongside the other surfaces safe mode closes. The dated design record docs/design/2026-09-02-peer-inbox-reachability.md is left as written -- it describes the state at its own date, and rewriting it would falsify the record rather than update it. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): name both causes when a flag and the setting both turn messaging off `/peers` answered with the startup suppression whenever one was in force, so a session whose own `agents.crossSessionMessaging` was also off was told the setting cannot matter, and was sent to a restart that leaves messaging off with the surviving cause still unnamed. The scope remedy now leads and the flag follows as a second cause when both fire; the single-cause text is byte-identical to before. Also qualify the SDK's universal reachability claim for the two flags in the three copies that carry it (package README, the `endpoint.ts` file JSDoc and the hand-maintained `docs/developers/sdk-typescript.md` mirror, whose inbox bullet was still the pre-PR twin of the one this branch amended), and record at the gate that an *inherited* `QWEN_CODE_SAFE_MODE` — unlike `QWEN_CODE_SIMPLE`, which `spawnChannel.ts` scrubs from spawned `qwen --acp` children — suppresses every session a daemon or editor hosts. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmujyzhfka1 --------- Co-authored-by: qqqys <qys177@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.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: yiliang114 <effortyliang@gmail.com> |
||
|
|
7f06a1e082
|
docs(developers): document CI and release repository variables (#11129)
* docs(developers): document CI and release repository variables * docs(developers): scope the worker-cap claim and note the retry tradeoff Review feedback: state which Vitest invocations actually consume QWEN_CI_VITEST_MAX_WORKERS, soften the retry-masking absolute, and point at the workflow files as the source of truth for the defaults. * docs(developers): attribute each CI pin to the test that actually holds it Review feedback: release-workflow.test.js does not pin the release worker-cap expressions; package-scripts.test.js asserts the QWEN_CI_VITEST_MAX_WORKERS / ecs-qwen- expression, while release-workflow.test.js pins the release retry and timeout expressions. Name both files with their respective attributions. * test(ci): keep documented variable defaults aligned with workflows * test(ci): derive documented variables bidirectionally and fix web-shell scope note * docs(ci): clarify variable scope and guard documented defaults * fix(ci): format variable guard and clarify worker scope |
||
|
|
5deddb722b
|
docs(tools): sync shell.md with the shipped run_shell_command contract (#12841)
* docs(tools): sync shell.md with the shipped run_shell_command contract Four statements in this file contradict the tool as shipped. is_background was documented as required -- twice in the arguments list and the Usage note, plus a "Required Background Parameter" section whose rationale was backwards. The schema is required: [command] (shell.ts:5762) and the parameter description says "Optional: ... If not specified, defaults to false (foreground execution)" (shell.ts:5743), so foreground is the fallback, not what the parameter exists to avoid. The foreground bullet list recommended cat and grep as one-time foreground commands, which the same tool description forbids in favour of the dedicated tools. #12532 replaced that list in the shipped description with one line; this mirrors it and states why the file tools are not candidates, so the list does not come back. "or by explicitly adding & to commands" offered & as a second control for backgrounding. On the managed background path a bare trailing & is stripped as redundant (stripTrailingBackgroundAmp, shell.ts:143, called at :4125). The sentence is now scoped to that path instead of claiming & never works: the example further down uses it with is_background=false, which is the unmanaged path, and is left alone deliberately. Verified against origin/main at |
||
|
|
81c260bb04
|
fix(mcp): Support larger Apps, scoped tool calls and isolated origins (#12258)
* fix(mcp): Make App resource limits configurable per server * docs(mcp): Explain App resource limits in pool fingerprints * fix(mcp): Degrade oversized App HTML per historical page document (#12258) Address review on the App resource limits change: - WebShell historical-page admission now drops each MCP App display's html whole (never truncated) when a page exceeds its byte budget, so two ceiling-size documents degrade to fallbackText instead of failing the whole page as non-retryable unavailable; the design doc ceiling rationale now names all five budgets a retained document crosses. - Pool fingerprint hashes App resource limits at their enforced (clamped/floored/defaulted) values via a shared module, so configs with byte-identical enforced policy share one pool entry. - Limit warnings name the setting in the source that declares the server (extension manifest or .mcp.json) instead of always pointing at settings.json, whose same-named entry would shadow rather than merge. - Timeout warnings credit the key that produced the deadline (timeout when no explicit App timeout is configured). - A non-finite configured limit now logs a debug warning naming the server, key, rejected value, and fallback instead of being silently discarded. - Add a reconnect-replay test pinning that App resource limits survive rediscovery, and sync the daemon transport-pool doc with the fingerprint contract. * fix(mcp): Preserve live sessions when App HTML exceeds queue budgets * fix(mcp): Preserve App limits across SDK and settings configuration * docs(mcp): Use verified Amplitude resource timeout * fix(mcp): Degrade App HTML in the replay envelope and window (#12258) - Restore the live byte cap's first-item rule for degraded App frames so a caught-up subscriber is admitted, not evicted, when even the reduced frame overflows an empty queue - Refuse to degrade an App frame whose fallbackText is empty; the byte cap eviction keeps the original resumable from the replay ring - Blank replayed App html oldest-first when a restore page exceeds the 32 MiB replay envelope so the session loads with fallback text instead of failing closed with transcript_page_too_large - Degrade retained App html oldest-first in the compacted replay window before evicting segments, so an oversized App turn is neither kept above the window budget nor evicted by the next turn * fix(cli): Show a notice for omitted HTML-only replay apps * fix(mcp): Render third-party Apps with isolated origins and scoped tools * fix(mcp): Align App route telemetry and regression fixtures * fix(mcp): Preserve historical App fallback and document origin isolation * fix(mcp): Harden App sandbox and preserve in-flight rendering * fix(mcp): Preserve vendor origins over remote connections * fix(web-shell): preserve MCP App tools in historical pages * fix(mcp): repair App call recovery and approval capacity * fix(mcp): repair pooled App connections in the calling session * fix(mcp): keep App approvals responsive and repair guarded connections * test(cli): update MCP App telemetry route audit * fix(web-shell): drop the duplicate session id on the pane transcript The main merge left sourceSessionId twice on TranscriptViewport, which fails the web-shell typecheck and stops every job at install. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(mcp): revoke failed apps and clarify resource timeout guidance --------- Co-authored-by: yungsen.hys <yungsen.hys@alibaba-inc.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
663d98eac5
|
feat(acp-bridge): deliver workspace changes to every paired engine (#12807)
On a paired Legacy/Managed Bridge, permission rules, the settings reload, the Session Workflow gate, model providers and Skills now reach every live engine. After workspace control handles the command, each live channel of another engine gets a versioned qwen/control/workspace/change notification and must acknowledge that exact revision; an engine that exits during delivery counts as settled. An engine that does not acknowledge is quarantined with the new reason workspace_change_unacknowledged, through the paired quarantine: no fresh sessions or new work, settled sessions close, and the channel retires by the drain deadline. After a change that tightens permissions its running turns are cancelled at once, its permission requests are refused, and Goal turns the child reports later are cancelled. A late exact acknowledgement of every missing change ends the quarantine early. Every quarantine now also refuses shell commands and continuations, and checks a prompt again after its attachments resolve. The command fails as partially applied; the workspace service still publishes saved permission rules and returns the Legacy reload result. Propagation is skipped while a workspace stop is in progress, and single-factory Bridges are unchanged. Part of #12737 (slice B2b, part two). |
||
|
|
a480bc7815
|
feat(acp-bridge): give each paired channel its own workspace runtime identity (#12776)
Each channel now keeps the epoch allocated when its handshake completed, so workspace status stamps, the lifecycle epoch, idle candidates and stop snapshots describe their own channel. Starting a Managed channel no longer restamps the Legacy runtime, and a Legacy exit makes its MCP and Skills preparation stale even while Managed stays live. A paired Bridge also reports the lifecycle of the Legacy channel that serves workspace control. The workspace runtime coordinator and the workspace service in all four daemon constructors use it instead of aggregate liveness, so a live Managed channel cannot make a failed Legacy preheat look ready. Single-channel Bridges report the same lifecycle as before. A workspace runtime stop now covers every live channel. The preview and receipt list each channel with its own epoch, the top-level epoch is the newest one so a later channel start stales the confirmation, and the stop waits for every registry release. Channels that an incomplete stop left running return to the idle policy. Part of #12737 (slice B2b, part one). |
||
|
|
1060b9e269
|
fix(serve): stop validating load-only restore fields on resume (#12768)
POST /session/:id/resume parsed and rejected liveReplayMode and compactedReplayMode even though resume never uses them and the published OpenAPI resume schema does not declare them, so a resume carrying an invalid load-only value failed with 400 against its own contract. The accepted body fields for load and resume now live in one runtime-owned list that the restore handler follows (load-only fields are parsed for load only) and the REST documentation contract test verifies the OpenAPI schemas against, replacing the second hardcoded array. The TypeScript SDK splits ResumeSessionRequest out of RestoreSessionRequest so resumeSession no longer exposes the load-only replay fields at the type level; the wire builder keeps dropping them for untyped callers. Closes #12146 |
||
|
|
5df67177df
|
feat(web-shell): prepare updates and restart from sidebar (#12734)
* feat(web-shell): prepare updates and restart from sidebar * test(serve): include daemon update in capability contracts * test: complete update contracts and isolate shell output fixtures * fix(web-shell): preserve task URLs and check update launchers * fix(serve): support older Node declarations in update checks |
||
|
|
879c311092
|
feat(serve): Enable private Hosted Harness no-tool text turns (#12713)
* feat(serve): Add private no-tool Hosted Harness turns * fix(serve): repair hosted turn initialization and history * codex: address PR review feedback (#12713) * codex: address PR review feedback (#12713) * codex: address PR review feedback (#12713) --------- Co-authored-by: jinye.djy <jinye.djy@U-Y37CF7G3-1943.local> Co-authored-by: Shaojin Wen <szujobs@gmail.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
be1a0a1fb0
|
feat(serve): support model and reasoning selection at session creation (#12308)
* feat(serve): support model and reasoning selection at session creation
* fix(serve): allow model-only session startup configuration
* test(serve): include startup capability in registry expectations
* fix(serve): roll back rejected standalone startup
* fix(serve): make definite startup rejections retryable and honest
- Map the ACP internalError wire shape ({code: -32603, data.details})
produced when switchModel refuses an unregistered model to
startup_config_rejected on the startup-config call path, so the
ordinary route answers 422 instead of 500 and the standalone path
takes its definite rollback branch.
- Roll back the persisted recording of a caller-supplied sessionId on
POST /session after a definite startup rejection, so a retry of the
same id is no longer answered with 409 session_id_conflict; uncertain
failures keep the recording.
- Publish auto in the OpenAPI approvalMode enum and pin it against
APPROVAL_MODES; narrow the 422/protocol/design cleanup wording to
match the implemented best-effort semantics; restore the sessionId in
the new rollback warning.
* fix(serve): keep uncertain startup faults uncertain and roll back ACP recordings (#12308)
- session-startup-config: drop the -32603 arm so child-side internal
errors (auth, credential, timeout, transport) stay uncertain instead
of a false definite startup_config_rejected; the ACP child now maps
only its two caller-caused switchModel refusals (unknown model for the
auth type, media-only primary) to invalid params, so definite
rejections ride -32602 alone.
- dispatch: roll back the persisted recording of a caller-supplied
sessionId on the ACP session/new transports after a definite startup
rejection, mirroring the REST route; uncertain outcomes keep it.
- routes/session: warn once when the recording rollback is refused or
fails instead of silently discarding the boolean outcome.
- standalone-session-service: extract the shared rollback sequence into
one helper used by both the startup-config and model_selection_failed
branches.
- openapi: qualify the 422 close/rollback as best-effort and replace the
unconfirmable status-view pointer with the self-certifying retry check.
* fix(serve): name the rejected session in startup rollback and align ACP error codes (#12308)
- SessionStartupConfigError carries an optional sessionId so both
rollback gates (REST route, ACP dispatcher) roll back the rejected
session's recording even when the caller never supplied an id or the
child did not honor it; a daemon-generated id no longer leaves a
listed, resumable phantom after a definite 422.
- A refused ACP recording rollback now logs the same inconclusive
warning the REST route emits instead of dropping the cleanup result.
- startup_config_rejected maps to JSON-RPC -32602 (caller input), with
data.httpStatus keeping the REST-equivalent 422; SDK transports key
on httpStatus, so client behavior is unchanged.
- SDK throws DaemonStartupConfigError (TypeError with code
'invalid_startup_config') for pre-transport startup rejections.
- Docs: modelApplied is documented as spawn-scoped again (an attach
omits it or reports the spawn owner's outcome).
- Tests: daemon-generated-id rollback pins on both transports, a
refused-rollback log pin, a service-boundary invalid-config guard
pin, full reasoning-selection acceptance coverage, whitespace trim
pins, and a real-ModelsConfig classifier coupling test.
* test(sdk): keep the message assertion beside the stable code on startup rejections (#12308)
* fix(serve): fail closed on control-character startup model ids (#12308)
A modelServiceId carrying a newline slipped past parseSessionStartupConfig
and produced a core refusal message the single-line classifier regexes
could not match, so a definite caller-caused rejection degraded to an
internal error and skipped the recording rollback. Reject control
characters at the parse boundary and make isCallerCausedModelRefusal
newline-tolerant; align the SDK and integration-guide modelApplied
presence rule with the spawn-scoped wording the bridge and OpenAPI
already publish.
* docs(sdk): name both transport error-code locations in DaemonStartupConfigError JSDoc (#12308)
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-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
|
||
|
|
73aa65a4b4
|
chore(desktop): rename packages/desktop-shell to packages/desktop (#12653)
* chore(desktop): rename packages/desktop-shell to packages/desktop The Electron-era packages/desktop was removed in #9085 and the OpenWork downstream has forked, so the short name is free and the shell suffix is the only thing left of the transition. Rename the package directory and every load-bearing reference: workspace negations (npm + pnpm), the ci.yml crate filter, desktop-release.yml, the isolation guard, lint/ignore configs, scripts tests, CLI workspace-fixture tests, and living docs. User-facing identity is untouched: the crate stays qwen-code-desktop, productName stays "Qwen Code Desktop", the bundle identifier, updater feed, release tag scheme, and the legacy electron-bridge asset names are all unchanged. check-desktop-isolation now guards both path names so the old one cannot re-enter a workspace set. Dated design docs under docs/design/ keep their historical paths deliberately. Refs #8596 * docs(design): follow the rename in the undated notification design notes The web-shell-browser-notification-details pair is a living doc without a date prefix, so it falls under the PR's update rule rather than the historical-record exception. * docs(desktop): stop citing paths the rename invalidated Three prose sites and one CI comment still described the pre-rename world, or contradicted themselves once `packages/desktop` named both the removed Electron app and the living Tauri shell. - ci.yml `desktop_shell`: the comment this branch added credited the Cargo.toml guard with keeping "branches from either side of the rename" green. It does not. A pre-rename head's files sit under `packages/desktop-shell`, which the changed-files filter no longer matches, so the job skips before the guard ever runs. Say that, and say what the guard does cover (a head the filter matched because ci.yml itself changed, with no crate at the new path). - docs/design/web-shell-user-message-links.md: "desktop-shell routing" / "desktop-shell clicks" -> "desktop-host", the wording this branch already chose in LinkifiedText.tsx for the same rule. - docs/design/telemetry-runtime-client-attribution-design.md: repoint the `runtime.rs` citation. It backs the live `QWEN_CODE_DESKTOP=1` claim, and the other document of record for that invariant -- the comment in acp-channel-fallback.ts -- was already repointed by this branch, so the two disagreed. Only the path token changes; the doc's dated findings are untouched. - brand-create.mjs / SKILL.md / src-tauri/src/main.rs: name the historical referent as historical (the Electron `packages/desktop` removed in PR 9085) instead of letting it read as a self-reference. In main.rs the citation `packages/desktop/packages/shared/src/config/storage.ts` now looked like a subpath of the file's own package. Rewritten, not deleted: the `QWEN_DEFAULT_WORKSPACE_DIR` clause next to it is the only in-code documentation of that override and still resolves. Deliberately not swept: `scripts/check-desktop-isolation.js`'s `packages/desktop-shell` tripwire, ci.yml's #8132 history comment, `docs/design/9152-architecture-invariant-classification.md` (names both spellings and is accurate), and the date-prefixed `docs/design/2026-07-31-desktop-web-shell-release.md`. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmug1iw422v * test(scripts): pin the desktop crate path and the isolation guard's coverage Both invariants fail green today, and this rename is the second time the crate directory has moved. `scripts/check-desktop-isolation.js` gained `'packages/desktop'` in `nativePrefixes` -- the only production-logic line in this branch -- and nothing read it. Deleting that line leaves the guard's output and exit code byte-identical, because `isNativeLocation('packages/desktop')` then matches no remaining prefix; a later PR that drops `!packages/desktop` from the root workspace list would re-admit the package with CI green. The `desktop_shell` job names the crate directory in five places (the changed-files filter, the Cargo.toml guard and its `::notice::` text, the rust-cache `workspaces:`, and two `working-directory:` values). Nothing asserted they agree with each other or with a directory that exists, so the next drift reports a skipped job as a passed one. The new suite parses both instead of re-running them, and is superset-shaped on purpose: `nativePrefixes` carries a fourth entry (the `packages/desktop-shell` tripwire) that nothing negates, and an exact-match assertion would invite deleting it. The npm/pnpm mirror of the negation list is already pinned by package-scripts.test.js, so this reads package.json only. Verified by mutation, each applied alone and then restored: reverting the filter alternative or either `working-directory` to `packages/desktop-shell`, dropping `'packages/desktop'` from `nativePrefixes`, and dropping `!packages/desktop` from package.json all turn this suite red. Today no other test does. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmug1iw422v * test(scripts): pin what the desktop-isolation tests actually claim Four review findings on scripts/tests/desktop-isolation.test.js, each verified by mutating the thing it claims to pin, before and after. - The comment above the local `isNativeLocation` copy claimed a change to the script's rule "has to be made here too". Nothing reads the rule back from the producer -- `nativePrefixesFromSource` parses the array literal only -- and narrowing the script's rule to prefix equality leaves the suite green. Describe the copy instead of claiming coupling that does not exist. - `still carries the Cargo.toml existence guard` matched only the guard's condition text. Flip the body's `changed=false` to `changed=true`, or move it after `fi`, and the suite stayed green at 5/5 while the job runs every gated step against a crate that is not there. Assert the assignment sits inside the guard's own `if ... fi` body. - Both on-disk checks keyed on the bare directory, so git-ignored residue under `packages/desktop-shell` (`node_modules`, which survives a branch switch with an empty `git status`) reddened two tests on a tree with no defect and blamed the root workspace set. Key on `package.json`, which is what `packages/*` requires to make a directory a workspace member; a real re-entry still reddens both. - The `startsWith(filterAlternative)` assertion compared a path built from `crateDir` -- `filterAlternative` with one trailing slash stripped -- back against `filterAlternative`, so it could not fail for any input. Dropping the trailing slash from the changed-files filter in ci.yml left it green. Replace it with the property that makes the alternative a path prefix rather than a bare string prefix. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmugedurp3j --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
f1361498ad
|
docs(tools): add Firecrawl to the web search MCP services (#12646)
Some checks are pending
Qwen Code CI / Classify PR (push) Waiting to run
Qwen Code CI / Test (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Lint & Static (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / web-shell E2E Smoke (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Test (macos-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Test (windows-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Integration Tests (no-AK, No Sandbox) (push) Blocked by required conditions
Qwen Code CI / Integration Tests (CLI, No Sandbox) (push) Blocked by required conditions
Qwen Code CI / Desktop Shell (ubuntu-22.04) (push) Blocked by required conditions
Qwen Code CI / Desktop Shell (windows-2022) (push) Blocked by required conditions
E2E Tests / Build for E2E (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/1 (push) Blocked by required conditions
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/1 (push) Blocked by required conditions
E2E Tests / E2E Test - macOS - shard 1/2 (push) Blocked by required conditions
E2E Tests / E2E Test - macOS - shard 2/2 (push) Blocked by required conditions
E2E Tests / E2E Interactive - OpenTUI renderer (bun) (push) Blocked by required conditions
E2E Tests / channel-plugin E2E (nightly) (push) Blocked by required conditions
E2E Tests / cron-interactive E2E (nightly) (push) Blocked by required conditions
E2E Tests / web-shell Browser Regression (push) Waiting to run
pnpm Worktree Smoke / Install (macos-latest) (push) Waiting to run
pnpm Worktree Smoke / Install (ubuntu-latest) (push) Waiting to run
pnpm Worktree Smoke / Install (windows-latest) (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 / Runtime Broker MariaDB / Java 21 (push) Waiting to run
SDK Java / Real daemon E2E / Java 11 (push) Waiting to run
Co-authored-by: Juampi <JuampiHernandez@users.noreply.github.com> |