mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-07-09 17:19:02 +00:00
479 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
fbdaa52c52
|
Gate browser automation MCP on external adapter (#6472)
* feat(cli): gate browser automation adapter * fix(cli): close browser automation review gaps * test(cli): cover browser automation gates * fix(cli): close browser automation review gaps * fix(cli): close browser automation review gaps |
||
|
|
0a54652e07
|
fix(core): configurable vision bridge timeout + retry with fresh budget (#6541)
* fix(core): configurable vision bridge timeout + retry with fresh budget The vision bridge capped image transcription at a hardcoded 30s. On a slow or proxied vision endpoint one latency spike permanently lost the image: the retry inside the side query shared the same abort signal, so a second attempt inherited whatever seconds were left of the first attempt's budget. Add a visionBridgeTimeoutMs setting (per attempt; unset keeps 30s, non-positive values are ignored) and retry a timed-out attempt once at the bridge level with a freshly created timeout signal. Non-timeout failures still fail immediately, and user cancellation is still reported as skipped. Fixes #6524 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(core): harden visionBridgeTimeoutMs against invalid timer values Maintainer E2E review found that fractional or out-of-range values such as 30000.5 and 4294967296 could pass the old number-typed config path and Config's Number.isFinite && > 0 guard. Node rejects fractional AbortSignal.timeout values with RangeError and can degrade oversized timer values to a 1ms timeout, which made image turns fail before any model request. Tighten the Config guard to positive integers within the supported 32-bit timer ceiling, make visionBridgeTimeoutMs a bounded integer setting so /config and the generated JSON schema reject bad values up front, and move AbortSignal.timeout/any creation inside the bridge try block so any future bad value becomes a safe failure result instead of an escaped rejection. Also mark the setting requiresRestart because it is read once in the Config constructor. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
6dafb330f2
|
docs: fix model-provider config shape and refresh feature/setting drift (#6552)
Audit findings against the current codebase:
- model-providers.md, auth.md: the documented modelProviders shape used
the reverted `{ protocol, models }` wrapper. The canonical shape is a
bare `ModelConfig[]` array per provider id (a wrapped entry in a
migrated settings file is silently skipped). Update all examples and
prose, document the separate top-level `providerProtocol` map for
custom provider ids, and correct the unknown-key behavior.
- settings.md: correct the default for
`model.chatCompression.screenshotTriggerThreshold` (20, not 50).
- commands.md: add the missing `/reload-plugins` command and note that
`/dream` and `/forget` are registered only when managed auto-memory
is available.
- Add a Computer Use feature page (on-by-default desktop automation via
the cua-driver native driver) and wire it into the features nav and
the qc-helper doc index.
Co-authored-by: Claude <noreply@anthropic.com>
|
||
|
|
87cad6f1ae
|
feat(memory): make background memory agent timeouts configurable (#6459)
* feat(memory): make background memory agent timeouts configurable Adds a memory.agentTimeoutMinutes setting that overrides the hardcoded max runtime of the four background memory agents (extraction, dream, remember, skill review). Unset keeps each agent's built-in default (2-5 minutes); 0 disables the time limit entirely. Local LLM setups load large extraction prompts far slower than hosted models, so the fixed 2-minute extractor budget times out before the context even finishes loading — and each retry carries a longer conversation, making the next timeout more likely. Fixes #6308 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(memory): address review — wire agentTimeoutMinutes to skill review, clamp negatives, add tests The auto-skill scheduling path always passed an explicit timeoutMs, so the new setting never reached the skill review agent; drop the redundant pass-through so the planner's config fallback applies. Clamp negative settings values at the Config constructor (schema validation only runs on interactive edit paths). Add positive override tests for the dream, remember, and skill review planners, and reduce the settings.md diff to the single new table row. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(memory): cover negative-clamp and remember default-timeout paths Review follow-up: assert the Config constructor treats a negative memory.agentTimeoutMinutes as unset, and that the remember planner keeps its built-in 5-minute default when nothing is configured. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> |
||
|
|
082b3bb3d9
|
fix(memory): give each linked git worktree its own auto-memory root (#6462)
getAutoMemoryRoot() resolved linked worktrees back to the canonical repository root, so every worktree of a repo shared one project memory. Focused worktree sessions polluted the shared MEMORY.md index with unrelated entries, and chats/, workflows/, and team memory were already per-worktree — project memory was the only shared exception. Anchor project memory at the nearest git root (same resolution team memory already uses) so each worktree gets its own memory directory. The main checkout resolves to the same path as before, so existing memory is unaffected. Fixes #6449 Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
1f92787aa0
|
feat(channels): add dmPolicy config to disable private/DM messages (#6521)
* feat(channels): add dmPolicy config to disable private/DM messages Add DmGate class mirroring GroupGate to gate DM/private messages in channel adapters. Operators can now set dmPolicy: 'disabled' in their channel config to silently drop all DM messages while keeping group messages active. Closes #6392 * fix(channels): address review feedback for dmPolicy - Add dmPolicy: 'open' to all test config factories (8 files) to maintain type correctness with required ChannelConfig field - Add integration tests in ChannelBase.test.ts: - preflightInbound: DM dropped + group passes when dmPolicy=disabled - isStoredLoopTargetAuthorized: DM loop job disabled + group passes - Add dmPolicy assertions in config-utils.test.ts (default + explicit) - Keep dmPolicy as required field (not optional) for strict parity with groupPolicy |
||
|
|
1420566620
|
feat(serve): Bound replay snapshot history (#6482)
* feat(serve): Bound replay snapshot history Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6482) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review suggestions (#6482) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(acp-bridge): fix replay truncation assertion access Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(serve): keep replay cap validation out of fast path runtime Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(acp-bridge): reset replay window on bulk seed Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6482) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: fix CI failure on PR #6482 Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(sdk): expose bounded replay status types Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
14f02c132a
|
fix(core): Match hook display-name matchers to tool ids (#6373)
* fix(core): match hook tool display names * fix(core): tighten hook matcher aliases * fix(core): align hook matcher aliases |
||
|
|
27f8f2c95d
|
feat(cli): Add serve env isolation and total admission (#6416)
* feat(cli): add serve env isolation and total admission Add runtime-local serve env snapshots, explicit env injection for low-cost workspace-scoped consumers, and sourceEnv support for ACP child spawn. Add a daemon-wide maxTotalSessions admission reservation hook for fresh session creation while keeping multi-workspace sessions gated. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6416) Reject fractional maxTotalSessions values so the daemon-wide session cap remains an integer count and matches the documented limit semantics. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): address PR review feedback (#6416) Always pass the runtime env to A2UI stdio transports, keep daemon runtime env metadata coherent after env reload fallback, and tighten total-admission coverage. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): address total admission review feedback (#6416) Add retryable ACP error data for total session limits, log total-admission REST rejections, and keep session-limit response scopes explicit. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): address env review feedback (#6416) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): restore scheduled task serve deps (#6416) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): isolate runtime env reload base (#6416) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6416) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6416) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6416) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6416) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: fix CI failure on PR #6416 Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): address daemon admission review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): address runtime env review feedback Scrub daemon bearer tokens from A2UI stdio MCP environments and prune reload-owned keys from the daemon runtime base before rebuilding runtime env snapshots. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): preserve daemon env base on reload Keep runtime env rebuilds anchored to the boot-time daemon base snapshot, preventing reload-owned key pruning from dropping valid shell-exported values. Also carry env file read failure details into runtime metadata and daemon logs. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): satisfy env metadata lint rules Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
394c1a289e
|
docs(channels): add WeCom to channels overview (#6490)
The WeCom intelligent robot channel (added in #6436) has its own guide and _meta.ts entry, but the channels overview was never updated. Add WeCom to the platform list, quick-start guide links, the `type` option and `token` exclusion note, new `botId`/`secret` option rows, the media-support note, and the slash-command channel enumeration. Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
e3d7d10d1d
|
[codex] add natural channel memory intents (#6376)
* feat(channels): add natural channel memory intents * fix(channels): add explicit guard and exhaustiveness check for clear_confirm intent The clear_confirm path was handled as implicit fall-through at the bottom of handleChannelMemoryIntent. If a new intent kind were added to the ChannelMemoryIntent union, it would silently execute clearChannelMemory without user confirmation — a data-loss risk. Add explicit if (intent.kind === 'clear_confirm') guard and a const _exhaustive: never assertion so TypeScript flags any unhandled kinds at compile time. * fix(channels): close session leak in classifier and fix regex separator - BridgeChannelMemoryIntentClassifier now wraps prompt() in try/finally to always call cancelSession(), preventing daemon session leaks on every classifier invocation. Cleanup errors are caught so they cannot mask a successful classification result. - Add missing optional punctuation separator to the 以后记住 regex pattern for consistency with other Chinese remember patterns. * fix(channels): enforce pending clear state for channel memory confirmation The clear_confirm intent executed clearChannelMemory directly without verifying a prior clear_request was issued for the same chat. Any authorized user could clear any chat's memory by sending the confirmation phrase standalone, bypassing the two-step flow. Add a per-target pending clear map (chatId + threadId, 60s TTL) that is set during clear_request and verified+consumed during clear_confirm. Standalone confirmation phrases now get rejected with a prompt to issue the clear request first. * fix(channels): include senderId in pendingClears key to prevent cross-user confirmation User A could initiate clear_request in a group chat and User B could confirm it, since the pending key only included chatId+threadId. Add senderId to the key so only the user who initiated the clear can confirm it. * fix(channels): harden memory intent review fixes * fix(channels): cover memory clear sender guard * fix(channels): block group memory mutations * fix(channels): avoid ambiguous memory saves * test(channels): cover memory classifier cleanup * test(channels): cover memory clear expiry * fix(channels): restore channel memory slash aliases * test(channels): cover memory intent edge cases |
||
|
|
467b292b50
|
feat(channels): add WeCom intelligent robot channel (#6436)
* feat(channels): add WeCom smart bot channel * fix(channels): harden wecom review suggestions * fix(channels): address wecom critical review * fix(channels): include wecom mixed voice text * fix(channels): tighten wecom outbound media * fix(channels): harden wecom outbound sends * fix(channels): address wecom review blockers * fix(channels): address wecom review followups * fix(channels): harden wecom inbound handling * fix(channels): address wecom auth and media review * fix(channels): tighten wecom inbound cleanup * fix(channels): harden wecom media safety * fix(channels): address wecom review typecheck * fix(channels): harden wecom media review gaps * fix(channels): address wecom review blockers * fix(channels): tighten wecom media edge cases * fix(channels): address wecom review blockers * fix(channels): address wecom media review blockers * fix(channels): address wecom review follow-ups * fix(channels): address wecom review blockers * fix(channels): close wecom review blockers * fix(channels): close wecom preflight dedup race * fix(channels): close wecom review gaps * fix(channels): harden wecom kick reconnect * fix(channels): defer wecom session resolution * fix(channels): clean wecom session attachments * fix(channels): harden wecom reconnect and media cleanup * fix(channels): address wecom review diagnostics * fix(channels): improve wecom diagnostics * fix(channels): reset wecom kick retries * fix(channels): improve wecom diagnostics * fix(channels): preserve sync cancel preflight * fix(channels): close wecom connection and ssrf gaps * fix(channels): clean coalesced wecom attachments * fix(channels): bound wecom sdk connect wait * fix(channels): scope wecom untracked attachment cleanup * fix(channels): block wecom nat64 local-use ssrf * fix(channels): harden wecom media handling * fix(channels): harden wecom group gates * fix(channels): bound wecom kick reconnect cycles * fix(channels): drain loop collect prompts directly * fix(channels): align wecom buffer hooks * fix(channels): harden wecom delivery failures * fix(channels): recover from wecom attachment write failures * fix(channels): surface wecom media send failures * fix(channels): harden wecom replay and reconnect * fix(channels): clarify wecom partial delivery cleanup * fix(channels): close wecom rejected downloads * fix(channels): retain wecom dedup after processing starts * fix(channels): harden wecom reconnect and media errors * fix(channels): add wecom media error context * fix(channels): improve wecom dns diagnostics * fix(channels): keep wecom kick retry alive * fix(channels): allow wecom quoted bot replies * fix(channels): preserve wecom code fences across chunks * fix(channels): harden wecom reconnect lifecycle * fix(channels): report wecom media dir setup failures * fix(channels): harden wecom reconnect recovery * fix(channels): align wecom review fixes * fix(channels): harden wecom marker parsing * fix(channels): keep wecom reconnect timers alive * fix(channels): handle wecom tilde fences * fix(channels): preserve wecom fence state * fix(channels): clean up wecom attachment races * fix(channels): bind wecom media reads to file handles * fix(channels): prevent wecom symlink media opens * fix(channels): address wecom review blockers * fix(wecom): remove media URL from error messages to prevent credential leakage The guardedHttpsDownload error messages included rawUrl (truncated to 120 chars), which leaks private WeCom media download URLs into stderr and log aggregation systems. Remove the URL from redirect and HTTP error messages. * fix(wecom): address review feedback — tests, security, correctness - Remove stale URL assertions from media download error tests (the error messages no longer include raw URLs after the credential-leak fix) - Redact sensitive fields (secret, aeskey, token, password, authorization) in formatSdkError's JSON.stringify fallback to prevent credential leakage in logs - Add indented code block detection to findCodeRanges so [IMAGE: path] inside 4-space/tab-indented code is not stripped as a media marker - Add disconnectGeneration guard before mkdirSync in downloadAttachments to prevent orphaned temp directories when disconnect() races with in-flight attachment downloads * fix(wecom): wrap client.disconnect() in catch block to preserve connection error In the connect() catch block, client.disconnect() could throw (e.g. if the WebSocket was already destroyed), masking the original connection error. Wrap in try/catch so cleanup failures never shadow the root cause. * fix(channels): address wecom reconnect review blockers * fix(channels): harden wecom reconnect review fixes * fix(channels): harden wecom review blockers * fix(channels): address wecom review blockers * fix(channels): preserve unsupported wecom media markers * fix(channels): address wecom reliability suggestions * fix(channels): allow wecom retry after early drops --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
80340fb73f
|
fix(review): remove qwen-code-specific core-infra gate from bundled /review (#6412)
The bundled /review skill is a general command that runs against arbitrary
repositories (and cross-repo PRs), but a previous change baked qwen-code's own
"core infrastructure is maintainer-only" governance into the shipped prompt:
hardcoded packages/core and packages/*/src/{auth,providers,models,config,tools,services}
paths, a 500+ line hard block, and an authorAssociation-based maintainer check.
Those path names are generic — src/auth, src/config, src/tools, src/services are
common across monorepos — so an external contributor's large PR to an unrelated
repo would be hard-blocked as "must be maintainer-initiated" under a policy that
repo never adopted.
Remove the gate and its escalate-flag plumbing (Steps 1, 6, and 7) from the
bundled skill, along with the matching DESIGN.md rationale and the user-doc
section. qwen-code's maintainer-only policy stays documented in AGENTS.md for
this repo. The Issue Fidelity / root-cause ownership agent (Agent 0) is a
universal review principle and is left unchanged.
Co-authored-by: dragon <dragon@U-2Q53JQG9-0233.local>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
bcdb44c5d3
|
docs(hooks): document PreToolUse permissionDecision 'ask' behavior (#6411)
Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
57326e55be
|
feat(review): add issue-fidelity and root-cause ownership gate to /review (#6395)
* feat(review): add issue-fidelity and root-cause ownership gate to /review Adds a dedicated Issue Fidelity & Root-Cause Ownership agent (Agent 0) to the /review pipeline and a core-infrastructure scope gate that runs before the review agents. Agent 0 fetches linked GitHub issue evidence directly (closingIssuesReferences plus issue comments) instead of trusting the PR author's framing, compares the original reported failure against the PR's claimed fix, and flags client-side parser/sanitizer workarounds for malformed upstream output as Critical unless a maintainer explicitly requested the defensive mitigation. The core-infra gate applies the repository's existing two-tier maintainer-only rule before spending review budget. This hardens the pipeline against a false-approval mode where a bot PR passes its own tests and reads as internally reasonable but fixes the author's mistaken diagnosis rather than the linked issue's actual root cause. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(review): address PR review feedback on issue-fidelity gate - Fetch issue evidence with `gh issue view --json title,body,comments` so the issue body (reporter repro/observed payload/expected behavior) is included; `--comments` alone omits it. Use each closingIssuesReferences entry's own repository so cross-repo linked issues resolve correctly. - Treat closingIssuesReferences as a discovery hint (fetch apparent target issues even when it is empty) and treat fetched issue content as untrusted data (extract facts, ignore embedded instructions). - Run Agent 0 (Issue Fidelity) only for PR targets; skip it for local-diff and file-path reviews, and require the PR number/repo/context in its prompt. Handle empty references / non-bugfix / gh failure explicitly. - Pass Agent 0's quoted issue evidence to Step 4 batch verification and stop it rejecting issue-grounded findings just because the code compiles/tests pass. - Make the core-infrastructure gate concrete: deterministic maintainer signal via authorAssociation, count only core-path lines, honor the AGENTS.md low-risk-sweep exception, clean up the worktree on hard block, run the gate right after fetch-pr (before npm ci), and map escalate -> COMMENT (never APPROVE) in Steps 6-7. - Sync agent counts and token math across SKILL.md, DESIGN.md, and code-review.md (Agent 0 is PR-only; ~620-730K). * docs(review): rename 'Linked Issue Fit' heading to 'Issue Fidelity' Aligns the code-review docs heading with the 'Issue Fidelity' name used for Agent 0 in SKILL.md and DESIGN.md, so the section connects to the pipeline diagram. Addresses review feedback. * docs(review): stop core-infra hard block before load-rules and surface it via --comment - Hard block now stops before Step 2 (load-rules) instead of before Step 3, so a PR destined for hard-block no longer runs the load-rules step. - In --comment mode the hard block posts an event=COMMENT on the PR, matching the escalate path's GitHub visibility, so external authors see the block. --------- Co-authored-by: dragon <dragon@U-2Q53JQG9-0233.local> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
6f2f21ff7e
|
docs: standardize GitHub Actions capitalization (#6367) | ||
|
|
be0b0749c1
|
docs: fix settings.json reference drift against schema (#6351)
Correct and complete the user-facing settings documentation against packages/cli/src/config/settingsSchema.ts: - settings.md: fix general.defaultFileEncoding type (enum, not string); document the general.voice.* dictation settings, top-level modelFallbacks and modelPricing, tools.computerUse.idleTimeoutMs, mcp.toolIdleTimeoutMs, and the skills.disabled denylist. - model-providers.md: correct the resolution-layers table — only --openai-api-key/--openai-base-url exist; there are no provider-specific credential CLI flags. Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
fa81e0a604
|
docs: fix skill invocation syntax and include Feishu in channel lists (#6320)
* docs: fix skill invocation syntax and include Feishu in channel lists * docs: add Feishu column to channel media-handling table Address review feedback on PR #6320: after adding Feishu to the prose channel lists, the 'Platform differences' media-handling table still omitted it. Add a Feishu column (images/files via the authenticated Open API resources endpoint, 50MB limit; rich-text 'post' captions), verified against packages/channels/feishu/src/media.ts and FeishuAdapter.ts. Add a note that QQ Bot ignores incoming media (per QQChannel.ts) so it has no row. * docs: clarify Feishu post messages drop embedded images The Platform differences table claimed Feishu rich-text (post) messages carry 'mixed text + images', but FeishuAdapter's post parser only extracts text/a/at nodes and silently drops img nodes (both the live handler and the history-backfill path). Correct the Captions cell to say text is extracted and embedded images are ignored. * docs: mark clientId/clientSecret as required for Feishu too Feishu declares requiredConfigFields: ['clientId', 'clientSecret'] (packages/channels/feishu/src/index.ts), same as DingTalk, but the channel options table listed both fields as DingTalk-only. Update the Required column and descriptions to cover Feishu (App ID / App Secret). * docs: note token is not needed for Feishu in channel config table * docs: note 50MB limit on Feishu image downloads Feishu images and files both flow through the same downloadMedia() in packages/channels/feishu/src/media.ts, which enforces a single MAX_DOWNLOAD_BYTES = 50MB cap. Add the (50MB limit) note to the Images cell for consistency with the Files cell. * docs: clarify /skills panel-vs-run behavior per review feedback - skills.md: add a migration Note that /skills <name> now opens the Skills panel and ignores trailing args; use /<skill-name> to run. - commands.md: list the /skills Usage cell as /skills, /<skill-name> for consistency with the rest of the table. --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: 易良 <1204183885@qq.com> |
||
|
|
e1f5d21008
|
fix(core): treat request timeout of 0 as disabled instead of aborting immediately (#6288)
* fix(core): treat request timeout of 0 as disabled instead of aborting immediately A provider `generationConfig.timeout` of `0` (and `QWEN_CODE_API_TIMEOUT_MS=0`) now disables the request timeout, matching the existing `QWEN_STREAM_IDLE_TIMEOUT_MS=0` convention, instead of being coerced to the 120s default (Anthropic `||`) or passed to the OpenAI SDK as `timeout: 0` (which the SDK treats as an immediate abort). - add `resolveRequestTimeout()` + `DISABLED_REQUEST_TIMEOUT_MS`, mapping a disabled timeout to the JS timer ceiling (2^31-1 ms), reusing the same ceiling already used for `MAX_STREAM_IDLE_TIMEOUT_MS` - use it in the OpenAI default/dashscope providers and the Anthropic provider - accept `0` in the `QWEN_CODE_API_TIMEOUT_MS` env override without weakening the shared `parsePositiveIntegerEnv` (relied on by ~15 other callers to reject 0) - document the timeout unit and 0-disables semantics in settings.md Fixes #6049 * Update packages/core/src/core/openaiContentGenerator/provider/dashscope.test.ts Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com> * test(core): fix broken constants mock merge in dashscope.test Commit 0f5aa0c interleaved two vi.mock('../constants.js') blocks, leaving orphaned fragments that produced TS syntax errors and stopped the dashscope suite from loading. Replace with a single importOriginal-based mock that overrides only DASHSCOPE_PROXY_BASE_URL and delegates every other constant (timeouts, DISABLED_REQUEST_TIMEOUT_MS, resolveRequestTimeout) to the real module, so the mock cannot drift from the implementation. --------- Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com> |
||
|
|
cdf83d8bd0
|
fix(core): give Stop-hook continuations a fresh per-turn tool-call budget; make the cap configurable (#6238)
* fix(core): give Stop-hook continuations a fresh per-turn tool-call budget; make the cap configurable A blocking Stop-hook continuation (e.g. a /goal iteration) feeds a fresh user-role prompt to the model — a new logical turn — but the loop detector never reset, so an entire goal chain billed one per-turn tool-call budget and healthy long-running goals halted with turn_tool_call_cap. The ACP daemon path already used per-continuation budgets; core now matches. - Reset loop detection at each blocking Stop-hook continuation - Add model.maxToolCallsPerTurn setting (default 100; <= 0 disables), resolved once in Config (<= 0 maps to Infinity) - Honor the in-session 'Disable loop detection for this session' choice in the per-turn cap, as the dialog always claimed - Point the headless halt message at the setting; update dialog/docs * test(cli): add DEFAULT_MAX_TOOL_CALLS_PER_TURN to core module mocks --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
fe3dd93e8f
|
Add sessionless workspace memory forget and dream (#6227)
* feat(serve): add sessionless memory forget and dream * fix(serve): thread abort through memory forget * fix(serve): address workspace memory review feedback * fix(serve): address memory review follow-up * fix(memory): harden forget review paths * fix(serve): classify memory availability failures * fix(serve): document memory task capacity tiers * fix(memory): address review edge cases * chore: remove mobile-mcp formatting noise |
||
|
|
9658dccfbb
|
feat(daemon): add session artifact APIs (#5895)
* docs: add session artifacts daemon API design * docs: tighten session artifacts design scope * docs: frame artifacts API as complete v1 capability * docs: address artifacts review follow-ups * docs: clarify artifacts reset boundary * docs: clarify batch hook artifact flow * docs: address latest artifact design audit * docs: tighten artifact event and store semantics * docs: simplify artifact v1 merge policy * docs: resolve artifact v1 review blockers * docs: tighten artifact trust and retention semantics * docs: close artifact v1 boundary gaps * feat(daemon): add session artifact APIs * fix(daemon): harden session artifact semantics * fix(sdk): update daemon browser bundle budget * fix(daemon): tighten artifact ingestion boundaries * fix(daemon): cache artifact workspace realpath * fix(daemon): sanitize artifact add dispatch input * docs(daemon): align artifact change wire shape * fix(daemon): harden artifact status validation * test(daemon): cover artifact acp dispatch * test(daemon): update artifact capability baseline * fix(daemon): clear workspace locator on published artifacts * fix(core): forward post-tool batch artifacts * fix(daemon): harden artifact status refresh * fix(daemon): guard artifact event ingestion * test(daemon): cover non-strict artifact drops * fix(core): align artifact display validation * fix(daemon): serialize artifact store operations * chore(daemon): clarify artifact publisher tool name * fix(daemon): coordinate artifact route mutations * fix(daemon): harden artifact refresh comparison * fix(daemon): harden artifact ingress edge cases * fix(daemon): guard artifact rpc mutations during archive * fix(daemon): gate session metadata mutation auth * fix(daemon): harden artifact route boundaries * fix(channels): compact drained group history * fix(daemon): address artifact review findings * fix(daemon): address artifact review follow-ups * fix(daemon): preserve hook artifact success output * fix(daemon): handle artifact review edge cases * fix(daemon): address artifact review hardening * test(daemon): cover artifact review edge cases * fix(daemon): validate hook artifact aggregation * fix(daemon): improve artifact ingestion diagnostics * fix(daemon): address artifact review feedback * fix(daemon): address artifact review feedback * fix(daemon): harden session artifact ingress * fix(daemon): harden artifact edge cases * fix(daemon): tighten artifact path validation * fix(daemon): address artifact review races * fix(daemon): surface artifact path inspection errors * fix(daemon): forward batch hook artifacts in ACP * fix(daemon): clean artifact bridge metadata * test(daemon): cover artifact store edge cases * fix(daemon): resolve artifact file url symlinks * fix(daemon): harden artifact ingestion paths * fix(daemon): harden artifact review paths * test(daemon): cover artifact tool name sync * fix(daemon): harden artifact republish validation * chore(daemon): remove unrelated artifact PR churn * fix(daemon): address artifact review gaps * test(daemon): cover artifact url rejection * chore(daemon): drop unrelated formatting churn * chore(daemon): update settings schema * fix(daemon): harden artifact validation * fix(daemon): tighten artifact event validation * docs(core): clarify artifact env flag comment * test(cli): align soft failure artifact expectation * fix(daemon): address artifact review edge cases * fix(daemon): enable artifact metadata recording * fix(daemon): harden artifact store review paths --------- Co-authored-by: 秦奇 <gary.gq@alibaba-inc.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
0633b8a985
|
feat(scheduler): make recurring cron/loop job expiration configurable (#6173)
* feat(scheduler): make recurring cron/loop job expiration configurable Recurring cron/loop jobs previously auto-expired after a hardcoded 7 days with no way to extend or disable the limit, forcing long-running daemon deployments to recreate jobs weekly. Add an experimental.cronRecurringMaxAgeDays setting (default 7) and a QWEN_CODE_CRON_MAX_AGE_DAYS environment-variable override (takes precedence, for cloud/container deployments). A value of 0 disables expiry so jobs run until deleted; negative or unparseable values fall back to the 7-day default. The configured limit also applies to durable tasks restored from disk, and the CronCreate tool description now reflects the effective limit instead of a hardcoded '7 days'. Closes #6167 * refactor(scheduler): drop unused DEFAULT_RECURRING_MAX_AGE_MS export Review feedback on #6173 — the ms constant is only used inside the module as the constructor default; keep only the days constant public. * fix(scheduler): align zero max-age semantics and warn on cron expiry misconfiguration Review feedback on #6173: - CronScheduler constructor now maps 0 to Infinity (never expire), matching the config layer instead of silently substituting the 7-day default for direct callers. - Invalid QWEN_CODE_CRON_MAX_AGE_DAYS / cronRecurringMaxAgeDays values now log a warning before falling back to the default, leaving a breadcrumb for misconfigured deployments. - Durable tasks found past the recurring max age at load now log a warning before their final fire + delete, since a lowered max age retroactively expires long-lived tasks and deletion is unrecoverable. - New durable-restore tests: a custom max age applies to tasks reloaded from disk, and a disabled max age (Infinity) restores a 30-day-old task as live instead of aging it out. * fix(scheduler): surface cron expiry warnings on the console Review feedback on #6173: - The invalid-config and retroactive-expiry warnings moved from debugLogger (file-only, off unless QWEN_DEBUG_LOG_FILE is set) to console.warn so they reach container/daemon logs where this knob matters; the config warning is latched to fire once per Config instance. - CronCreateTool's constructor now resolves the max age once instead of three times, so an invalid env var can't emit duplicate warnings during tool registration. * fix(scheduler): reject non-finite timestamps in durable task validation Review feedback on #6173: JSON like -1e999 parses to -Infinity, which passes the typeof-number check and then poisons date math — with a finite lastFiredAt the entry reads as an overdue aged task and the retroactive-expiry warning's toISOString() throws RangeError mid-load, so one malformed persisted entry blocks durable cron startup/takeover. Validation now requires finite createdAt (and lastFiredAt when non-null), routing such entries through the existing fix-or-delete contract for corrupt files. Verified the new end-to-end test reproduces the RangeError without the fix. * refactor(scheduler): single-source the max-age contract and freeze it at Config construction Review follow-ups on #6173: - Extract normalizeRecurringMaxAge as the single owner of the 0/Infinity no-expiry contract, used by both the Config layer and the CronScheduler constructor, so the constructor's 0 handling can no longer be removed as apparent dead code. - Resolve QWEN_CODE_CRON_MAX_AGE_DAYS once at Config construction into a readonly field, honoring the setting's requiresRestart contract; mid-session env changes can no longer make the tool description, tool output, and scheduler report different expiries. The warn once-latch is now unnecessary (construction warns at most once). |
||
|
|
8de93b876b
|
feat(core): allow sub-agents to spawn nested sub-agents up to a configurable depth (#6189)
* feat(core): allow bounded nested sub-agent spawning via maxSubagentDepth Sub-agents may now spawn sub-agents up to a configurable maximum nesting depth (default 5; 1 reproduces the previous no-nesting behavior). Enforced in two layers sharing one predicate: prepareTools() hides the agent tool from leaf-depth sub-agents, and AgentTool.execute() rejects over-depth spawns as an authoritative backstop. Teammates, forks, and the workflow tool remain excluded from nesting. Launch depth is persisted in the agent meta sidecar and restored on resume (including deferred-approval continuations and in-process AgentInteractive frames) so a resumed nested agent cannot regain spawn capacity. See knowledge/qwen-code/design/nested-subagents.md. * fix(core): address review findings on nested sub-agent spawning - Deny the agent tool to workflow-spawned subagents: depth gating would otherwise re-admit it, letting a workflow leaf spawn outside the orchestrator's concurrency cap, agent accounting, and token budget. - Reject non-finite maxSubagentDepth values (JSON 1e309 parses to Infinity and would unbound the recursion cap; NaN would silently block all nesting) and cap the knob at 100 to catch typos. - Add a --max-subagent-depth CLI flag mirroring sibling budget flags, with loud validation for flag typos, and document the setting. - Log guard rejections (depth, fork containment) and silent fork-to-subagent downgrades through the agent debug logger. - Refresh stale comments (depthOverride resume pinning, depth-gated AgentTool exclusion) and drop references to a design doc that lives outside the repository. - Fill review-noted test gaps: nesting predicate primitives, fork-context prepareTools, persisted-depth restoration on background resume, nested AgentInteractive depth pinning, nested fork fallback, and the blocked-spawn returnDisplay shape. * fix(cli): add maxSubagentDepth to the CliArgs test literal The exhaustive CliArgs mock in gemini.test.tsx missed the new field, failing CI's clean tsc build (the local incremental build skipped the test file). * fix(core): add a teammate backstop to the agent spawn guards execute() backstopped depth and fork containment but not the teammate exclusion, so its guards covered less than prepareTools() gates. A teammate spawn call that slipped past schema-hiding would have nested. Block it symmetrically with the fork guard, log the rejection, and pin the behavior in a test. * fix(core): normalize persisted maxSubagentDepth on resume The resume path trusted the raw sidecar value, bypassing the Config clamp — a tampered or malformed sidecar (1e309 parses to Infinity; JSON.stringify turns Infinity into null) would remove the nesting cap for resumed agents. Extract the clamp into a shared normalizeMaxSubagentDepth used by both the Config constructor and the flag-restore path, and refresh the stale settings schema description (clamp range, non-finite fallback, workflow-agent wording). * test(core): pin null-to-default normalization of resumed maxSubagentDepth JSON.stringify(Infinity) === 'null', so a sidecar can legitimately carry null; widen the persisted flag type to admit it and parameterize the resume test over both the clamp (5000 -> 100) and the null fallback (null -> 5). * fix(core): harden nesting depth edges from final review pass - Normalize persisted meta.depth on resume: the sidecar is untrusted JSON, and a tampered negative depth (or -1e309 → -Infinity) would pin the resumed frame below zero and pass canSpawnNestedAgent for every cap. Invalid values fail closed to the depth ceiling — the agent keeps running but cannot spawn. - Register monitor notification routing for in-process interactive agents: framing runLoop() made their monitors agent-owned, and owned dispatch has no session fallback, so notifications were silently dropped. InProcessBackend now routes them into the agent's message queue and tears the routing down on release. - Downgrade background spawn requests from nested launchers to awaited foreground runs: a nested launcher cannot honor the background completion contract (send_message/task_stop excluded, notifications session-scoped), which orphaned the child's results. - Extract spawnBlockReason() as the single spawn-exclusion policy shared by prepareTools() and execute(), replacing two hand-kept copies of the depth/teammate/fork rules. - Share DEFAULT_MAX_SUBAGENT_DEPTH / MAX_SUBAGENT_DEPTH_LIMIT across the core normalizer, the CLI flag validator, and the settings schema. - Log dropped teammate names from nested spawns; revert the impossible |null persisted-flag widening to an honest tampered-sidecar framing; document the constructor-time depth capture invariant. * test(cli): add DEFAULT_MAX_SUBAGENT_DEPTH to core package mocks settingsSchema.ts now imports the shared constant, so CLI tests that mock @qwen-code/qwen-code-core with an explicit export list need the new export. * feat(cli): display nested sub-agents as a tree in the TUI (#6191) * feat(core): allow bounded nested sub-agent spawning via maxSubagentDepth Sub-agents may now spawn sub-agents up to a configurable maximum nesting depth (default 5; 1 reproduces the previous no-nesting behavior). Enforced in two layers sharing one predicate: prepareTools() hides the agent tool from leaf-depth sub-agents, and AgentTool.execute() rejects over-depth spawns as an authoritative backstop. Teammates, forks, and the workflow tool remain excluded from nesting. Launch depth is persisted in the agent meta sidecar and restored on resume (including deferred-approval continuations and in-process AgentInteractive frames) so a resumed nested agent cannot regain spawn capacity. See knowledge/qwen-code/design/nested-subagents.md. * feat(cli): display nested sub-agents as a tree in the TUI Render nested agents depth-first with indent + dim '↳' in the live agent panel and background tasks view; promote orphaned children to root with a '· from <parent>' annotation. Detail view gains a level badge, Parent breadcrumb, and Sub-agents section. The [blocking] tag and two-step cancel confirm now apply only to provably user-blocking foreground chains. Parent completion summaries carry a '· N sub-agents' tail (guard-rejected spawns now record as failed tool calls so the count stays honest). Also fixes the live-panel Enter-for-detail order mismatch by sharing one display order between the panel render and the composer keyboard mapping. * fix(core): address round-1 review on nested sub-agent spawning - Derive launch metadata (hooks, spans, task rows, meta sidecar) from the resolved subagent config instead of the raw requested type, so a fork request that falls back to the awaitable path no longer reports "fork". - Pin the blocked-spawn failure contract in tests: error is set and returnDisplay.status is 'failed' for both the depth and fork guards; also document the failure-path routing at buildSpawnBlockedResult. - Drop source-comment references to private knowledge/ design docs that do not exist in this repository. * test: address round-2 review on sub-agent counting and fork fallback - Exercise the legacy 'task' alias in the scrollback sub-agent count so the migration-aware name set is covered, not just the canonical name. - Pin the nested-fork downgrade: a sub-agent requesting a fork falls back to the awaitable general-purpose subagent even in interactive mode. - Drop a duplicated 'nesting depth guard' describe block left behind by the automated base-branch merge (kept the copy with the failure-shape assertions). * fix(core): keep actionable guidance in blocked-spawn error messages The scheduler's failure path sends only error.message to the model and the scrollback, discarding llmContent. With the terse terminateReason as the message, a blocked spawn lost its "do the task yourself instead" instruction, inviting retry loops. Carry the full guidance text in error.message and keep terminateReason for the display card. * test(cli): pin the tree indent clamp at depth beyond TREE_INDENT_MAX_LEVELS Maintainer mutation-testing on the PR found that removing the clamp in treeRowPrefix survived the suite. Assert a depth-4 row indents 3 levels (12 spaces), plus the base marker/indent behavior. --------- 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-bot@users.noreply.github.com> |
||
|
|
dc8e155927
|
docs: correct stale CLI flags/keybinding and document model.reasoningEffort (#6219)
- Remove nonexistent --all-files/-a and --show-memory-usage flags from the CLI arguments and headless option tables (no longer defined in the yargs parser in packages/cli/src/config/config.ts). - Add the commonly-needed --model/-m flag to the headless options table and fix the --approval-mode example to use the valid choice auto-edit (the parser rejects the underscore form auto_edit). - Drop the stale Meta+Enter alias from the external-editor shortcut; that chord is bound to NEWLINE, while OPEN_EXTERNAL_EDITOR binds only Ctrl+X. - Document the model.reasoningEffort setting (set via /effort), which is exposed in the settings dialog but was missing from the settings reference. Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
55e425c1d2
|
docs: document the /config slash command (#6145)
Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
2c95d9383f
|
feat(core,cli): unified reasoning effort with /effort command (#6072)
* feat(core,cli): unified reasoning effort with /effort command
Expose a provider-agnostic reasoning-effort ladder (low/medium/high/xhigh/max) through a new /effort slash command and a global model.reasoningEffort setting. Bare /effort opens an interactive tier picker (and lists tiers in non-interactive/ACP mode); /effort <tier> sets one directly. A single canonical reasoning.effort config is translated and clamped per provider so one control works everywhere:
- OpenAI: reasoning_effort (max clamps to xhigh)
- DeepSeek: flat reasoning_effort (low/medium→high, xhigh→max)
- GLM / z.ai: new adapter flattens nested reasoning.effort to a verbatim reasoning_effort
- Anthropic: output_config.effort, gated per model — Opus 4.7/4.8 and 5.x families pass xhigh/max through; Opus 4.6/Sonnet 4.6 take max only; older clamp to high
- Gemini: thinking_level (adds medium; xhigh/max cap at HIGH)
- Qwen / DashScope: a set effort turns on enable_thinking (no per-tier field yet — the single column to extend when qwen ships one)
Config.setReasoningEffort updates the live config so the change takes effect on the next turn without an auth refresh, and is re-applied across model switches and auth refreshes (including the initial one at startup) so the effort survives /model switches and CLI restarts — even for provider-backed models, whose preset sync would otherwise overwrite reasoning and drop the persisted effort. The model-with-reasoning status line now tracks the effort and updates immediately when /effort changes it.
A new core/reasoning-effort.ts holds the canonical tier list, rank-based clamp, and input normalizer shared across providers and the command.
* fix(core): reject date suffix as Anthropic minor version for effort gating
The version regex parsed the 8-digit date suffix of dated model ids
(e.g. claude-opus-4-20250514 = Opus 4.0) as the minor version, so
atLeast(4, 6)/atLeast(4, 7) returned true and Opus 4.0 was wrongly
granted the xhigh/max effort tiers it does not support, producing an
HTTP 400 on /effort max with no clamp warning.
Cap the minor-version group at one or two digits with a trailing (?!\d)
so a date suffix is not mis-parsed (a bare {1,2} cap is insufficient: it
would still greedily capture '20' from '20250514'). Dated ids that do
carry a minor, like claude-opus-4-7-20251101, still resolve to minor 7.
Adds a regression test asserting effort 'max' clamps to 'high' on
claude-opus-4-20250514.
* fix(i18n): translate /effort command description for all locales
The mustTranslateKeys strict-parity test failed because the new /effort
command description fell back to English in zh and zh-TW. Add the
description string to every locale file so the command is translated like
its siblings and strict-parity locales no longer fall back.
* fix(core): correct DeepSeek effort mapping and adaptive-thinking model parse
Address two review findings on the reasoning-effort path in
anthropicContentGenerator:
- DeepSeek anthropic-compatible output_config.effort accepts only high/max,
but resolveEffectiveEffort passed low/medium through verbatim (only
remapping xhigh -> max), which the endpoint would 400 on. Mirror the
DeepSeek OpenAI adapter (deepseek.ts): low/medium lift to high, xhigh/max
group to max.
- modelSupportsAdaptiveThinking used /claude-(?:opus|sonnet|haiku)-(\d+)-(\d+)/,
so a dated id like claude-opus-4-20250514 (Opus 4.0) parsed the 8-digit date
suffix as the minor version (>= 6), wrongly selecting adaptive thinking and
tripping a server 400. Apply the same date-suffix-guarded regex the sibling
anthropicSupportedEffortTiers already uses, also covering the fable/mythos
families and a bare major (claude-opus-5).
Add regression tests for both.
* fix(core,cli): address /effort review feedback
- anthropic: family-guard the `max` tier on the 4.x branch so haiku 4.x no
longer gains `max` (a server 400); 5.x families still get it via major>=5.
- effort command: when `setReasoningEffort` no-ops because thinking is disabled
(reasoning: false), report that the tier won't take effect yet instead of a
misleading success message (the tier is still persisted for future sessions).
- dashscope: drop the pipeline-injected nested `reasoning` object when
`enable_thinking` is set, so qwen never receives two competing thinking knobs
(mirrors deepseek.ts / zai.ts).
Adds regression tests for each.
* fix(core): collapse empty reasoning to undefined and drop redundant effort re-apply
setReasoningEffort(undefined) now resets reasoning to undefined instead of
leaving a truthy empty object, which the pipeline would emit as wire noise
and which would make 'if (cfg.reasoning)' a false positive.
handleModelChange no longer re-applies the reasoning effort after the
full-refresh path: refreshAuth already captures and restores it, so the
second call was redundant. The qwen-oauth hot-update path keeps its own
re-apply because it never routes through refreshAuth.
* fix(core): log once when Gemini clamps xhigh/max effort to HIGH
Gemini has no tier above HIGH, so /effort xhigh|max silently ran at HIGH
with no trace. Mirror the Anthropic generator's one-time clamp warning via
a per-generator latch so the downgrade is discoverable in debug logs.
* fix(core): warn when GLM model on non-Z.ai host skips reasoning_effort flatten
isZaiProvider routes any glm-* model through this provider, but the
reasoning_effort reshape stays hostname-gated. A self-hosted GLM on a
non-Z.ai hostname therefore kept its nested reasoning.effort unflattened
silently. Keep the reshape hostname-gated (so we never push GLM's flat
field at an arbitrary OpenAI-compatible backend) but log the skip once so
the gap is discoverable.
* docs(core,cli): correct false OpenAI 'max'->'xhigh' clamp claim
The reasoning-effort docs claimed OpenAI adapters clamp 'max' to 'xhigh',
but the default OpenAI-compatible pipeline forwards the tier verbatim and
no such clamp exists. Reword the doc comment and the reasoningEffort
setting description (and the regenerated VS Code schema) to match.
* fix(cli): clarify effort confirmation and improve the effort dialog UX
- The /effort confirmation now states the tier is the requested one and the
effective tier depends on the active provider/model, instead of implying
the shown tier is what reaches the wire (providers clamp per model).
- EffortDialog no longer pre-selects 'high' when no effort is configured;
the cursor starts at the top and a footer notes the provider default is
in effect, so the highlight is not mistaken for the current setting.
- The dialog path now mirrors the slash-command read-back: when thinking is
disabled (setReasoningEffort is a no-op), it surfaces an info message that
the tier is persisted but won't take effect until thinking is re-enabled.
* refactor(core): extract shared parseClaudeModelVersion for Claude effort gating
anthropicSupportedEffortTiers and modelSupportsAdaptiveThinking each parsed
Claude model ids with their own near-identical regex (family list +
date-suffix guard), kept in sync only by a comment. Extract a single
parseClaudeModelVersion helper both consume so adding a new family is a
one-line change with no drift risk between effort tiers and the thinking
shape.
* fix(anthropic): drop manual budget_tokens on models that reject it
Opus 4.7+ and every 5.x family (Sonnet 5, Fable 5, Mythos 5) dropped
manual extended thinking: a request with
thinking:{type:'enabled', budget_tokens:N} returns a 400 on those models,
which require adaptive thinking with output_config.effort instead
(https://platform.claude.com/docs/en/build-with-claude/effort).
buildThinkingConfig honored an explicit reasoning.budget_tokens on every
model, so a preset carrying budget_tokens (with or without /effort) shipped
the manual shape to an adaptive-only model and 400'd. Gate the escape hatch
behind a new modelRejectsManualThinking() predicate so the budget is only
emitted for models that still accept it (Opus 4.5/4.6, Sonnet 4.6, older
4.x, and unknown/unversioned ids); adaptive-only models fall through to
{type:'adaptive'} and let output_config.effort govern thinking depth.
* fix(cli,core): warn on invalid model.reasoningEffort; guard hot-update field set
- modelConfigUtils: surface a startup warning when settings.model.reasoningEffort
holds an unrecognized value (normalizes to undefined and was silently skipped),
so a typo in settings.json doesn't leave /effort with no visible effect.
- config: document that the qwen-oauth hot-update field set deliberately excludes
`reasoning`, which is captured and re-applied via setReasoningEffort() — adding
it to the copied set would mask the effort restore across model switches.
* fix(core,cli): address /effort review feedback
- config: re-apply reasoning effort on the full-refresh model-switch path.
switchModel() wipes modelsConfig.reasoning via applyResolvedModelDefaults
before handleModelChange fires, so refreshAuth's own capture reads undefined;
restore the tier from the live config. Add a regression test.
- gemini: make buildThinkingConfig's effort switch exhaustive (explicit
'undefined' case + never-guarded default) so a new tier is a compile error
rather than a silent map to UNSPECIFIED.
- anthropic: emit a one-time warning when budget_tokens is dropped on models
that reject manual thinking (Opus 4.7+/5.x); reword the version-regex comment
to correctly credit the (?!\\d) lookahead. Add reseller-prefixed and 5.x
effort-gating tests.
- cli/effort: confirm the requested tier in-chat on dialog success (mirror the
slash-command message); add hook tests.
- tests: add dashscope vision-branch effort test and determineProvider z.ai
routing tests.
* fix(core): harden reasoning-effort normalize and correct stale clamp comment
- normalizeReasoningEffort: reject non-string input (e.g. a hand-edited
settings.json with a boolean/number reasoningEffort) instead of calling
.trim() on it and crashing at startup; add regression tests.
- contentGenerator: update the reasoning-effort ladder comment to reflect
the per-model Anthropic tier gating (Opus 4.7+/5.x accept xhigh/max,
Opus/Sonnet 4.6 accept max, older models cap at high) instead of the
outdated blanket 'xhigh/max -> high' description.
Addresses PR review feedback.
* fix: remove stray OpenClaw-Query-Submit gitlink
This branch carries a submodule gitlink (mode 160000, commit be66572)
with no .gitmodules entry. It entered via a merge from an older main
state; current main no longer contains it, so this branch would
re-introduce it on merge, breaking clone --recursive and any submodule
init. Remove it from the index.
* test(cli): add EffortDialog render tests
Adds render/behavior tests for EffortDialog mirroring
ApprovalModeDialog.test.tsx: renders the title and all five tiers,
shows/hides the 'no effort configured' hint based on currentEffort,
and verifies the active Escape handler cancels with undefined while
non-Escape keys do not.
* refactor(anthropic): single-source Claude family list; warn on DeepSeek effort remap
Derive the ClaudeModelFamily union and the model-id regex from one
CLAUDE_MODEL_FAMILIES const so the type and the parser can't drift apart
behind the 'as ClaudeModelFamily' cast.
Emit a one-time debugLogger.warn when the DeepSeek anthropic-compatible
branch remaps a requested effort tier (low/medium -> high, xhigh -> max),
mirroring the real-Anthropic clamp path so a silently upgraded effort is
visible in debug logs.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: DragonnZhang <dragonzhang1024@gmail.com>
|
||
|
|
bb7b4d8d57
|
feat(serve): support HTTPS/TLS via --tls-cert and --tls-key flags (#6032)
* feat(serve): support HTTPS/TLS via --tls-cert and --tls-key Serve `qwen serve` over HTTPS when both `--tls-cert` and `--tls-key` point at PEM files, instead of plain HTTP. The motivation is mobile / cross-device access: a LAN IP (`192.168.x.x`) is not a browser secure context over `http://`, so `getUserMedia` (voice input), WebRTC, and other secure-context-only APIs are blocked on phones/tablets. Bringing your own cert (e.g. via mkcert) unlocks them. Implementation wraps the existing Express app in `https.createServer` when TLS is configured; `https.Server extends http.Server`, so the connection cap, address lookup, ACP attach, and graceful-close paths are unchanged. The plain-HTTP path stays bit-for-bit identical when no certs are given. The startup banner and loopback same-origin set now reflect the active scheme. Scope is TLS termination only — no auto-generation, no ACME. TLS is orthogonal to the bearer-token gate: non-loopback binds still require a token. Boot fails loudly if only one of the two flags is given, or if a cert/key file can't be read, rather than silently downgrading to HTTP. Closes #6001 Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(serve): add HTTPS loopback origins to self-origin and ACP checks * fix(serve): accept port-less Origin header on default ports 80/443 Per RFC 7230 §5.4, browsers omit the port in the Origin header when it matches the scheme default (http→80, https→443). The origin checks in self-origin.ts and acp-http/index.ts always included the port suffix, so a browser on port 443 sending 'Origin: https://localhost' (no :443) would fail the loopback origin match. Add port-less origin entries when the server listens on port 80 or 443, mirroring the pattern already used in auth.ts hostAllowlist. * fix(serve): add port-less origins to installSameOriginOriginStrip for RFC 7230 compliance * fix(serve): validate TLS cert expiry and parse errors at boot https.createServer starts cleanly with an expired certificate, then every client handshake is rejected (NET::ERR_CERT_DATE_INVALID) while /health stays green — a silent outage that's hard to diagnose. Parse the cert with X509Certificate at boot and fail loud with an actionable message when it's expired or unparseable. Also wrap createServer so a cert/key mismatch surfaces a framed error instead of a raw OpenSSL string. Add tests for the expired-cert guard and the previously-uncovered --tls-key read error path. Co-Authored-By: Qwen-Coder <noreply@qwen.ai> * fix(serve): close TLS validation gaps from review - Reject not-yet-valid certs (notBefore > now) at boot, symmetric to the existing expiry guard — same silent NET::ERR_CERT_DATE_INVALID outage. - Add port-less host entries (default 80/443) to the WS upgrade Host allowlist, mirroring the REST allowlist (auth.ts) and the Origin checks; without it every WS upgrade is 403'd when TLS runs on port 443. - Cover the previously-untested X509 parse-error and cert/key-mismatch boot branches. - Docs: include localhost/127.0.0.1 in the mkcert TLS example so the URL --open rewrites to (127.0.0.1) isn't rejected with CN mismatch. Co-Authored-By: Qwen-Coder <noreply@qwen.ai> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: Qwen-Coder <noreply@qwen.ai> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> |
||
|
|
427b5ade33
|
docs: document model/auth settings, /model --vision, and --safe-mode (#6028)
* docs: document model/auth settings, /model --vision, and --safe-mode Refresh user docs to match the current codebase: - commands.md: add the /model --vision override (vision-bridge model) - settings.md: add model.baseUrl, model.sessionTokenLimit, visionModel, and voiceModel; document the deprecated security.auth.apiKey and security.auth.baseUrl keys with a pointer to modelProviders - troubleshooting.md: document the --safe-mode flag for isolating customization issues * docs: address review feedback on sessionTokenLimit, safe-mode, deprecation notes - model.sessionTokenLimit: correct default to -1 (runtime fallback in core/config.ts) and clarify breach behavior (current send dropped, not session abort) per client.ts SessionTokenLimitExceeded handling. - --safe-mode: expand the disabled-customizations list to also cover permission rules, approval mode overrides, memory features, and sandbox settings, matching cli/config.ts. - security.auth.apiKey/baseUrl: align deprecation wording with the existing tools.* entries (**Deprecated.**) and drop the unsubstantiated '(slated for removal)' qualifier. * docs: note QWEN_CODE_SAFE_MODE env var as a safe-mode alternative Document the QWEN_CODE_SAFE_MODE=true environment variable as an alternative activation path for safe mode, for cases where the CLI cannot accept flags (verified against isSafeModeEnv in packages/core/src/utils/safe-mode.ts). * docs: clarify model.baseUrl, sessionTokenLimit=0, and safe-mode subagents - model.baseUrl: describe it as a picker-managed disambiguator, not a hand-editable override (stale values can misroute to a same-id provider). - model.sessionTokenLimit: note that 0 is treated as unlimited (same as -1), unlike model.maxToolCalls where 0 disallows all calls. - --safe-mode: include custom subagents in the list of disabled customizations (only built-in subagents load in safe mode). * docs: clarify sessionTokenLimit semantics and add --safe-mode to headless flags - settings.md: reword model.sessionTokenLimit to reflect that the gate compares the last recorded prompt token count before the next send (not a per-send preflight cap), and that the next send is dropped. - headless.md: add a --safe-mode row to the CLI flags table so the diagnostic flag is discoverable there, cross-referencing Troubleshooting. * docs: align safe-mode sandbox wording to 'sandbox settings' Safe mode passes an empty Settings object to loadSandboxConfig (packages/cli/src/config/config.ts:1793), so it strips settings-sourced sandbox config while the --sandbox flag and QWEN_SANDBOX env still apply. Match headless.md to troubleshooting.md's accurate 'sandbox settings'. * docs: correct safe-mode approval-mode wording and align both lists Safe mode only strips settings-sourced approval mode; the --yolo and --approval-mode CLI flags are evaluated before the safeMode guard (packages/cli/src/config/config.ts:1521-1528) and still take effect. Reword to 'settings-sourced approval mode overrides' and note the CLI flags in troubleshooting.md and headless.md, and make the enumerated safe-mode disable list identical (same items and order) across both. --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
6a5ad453c8
|
[codex] Add explicit channel memory for messaging channels (#6051)
* chore: ignore local worktrees * feat(core): add channel memory store * fix(core): preserve dots in channel memory paths * fix(core): guard dot channel memory paths * feat(channels): add channel memory commands * fix(channels): defer channel memory session invalidation * feat(channels): inject channel memory into sessions * fix(channels): serialize channel memory context injection * fix(channels): harden channel memory context races * fix(channels): let queued turn retry memory context * feat(cli): wire channel memory into channel startup * docs(channels): document channel memory * fix(channels): harden channel memory handling * fix(channels): gate channel memory injection * fix(channels): serialize channel memory clears * fix(channels): tolerate channel memory read failures * fix(channels): harden channel memory review gaps * fix(channels): harden channel memory review gaps * fix(channels): protect shared channel memory * test(channels): allow group memory view test * fix(channels): block group memory writes * fix(channels): include memory in loop prompts * fix(channels): preserve session context order after merge * fix(channels): retry loop memory context after read failure --------- Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> |
||
|
|
1a46df5d92
|
fix(cli): load browser MCP tools by default (#6006)
* fix(cli): load browser MCP tools by default * fix(cli): cover browser MCP env flags * fix: address browser MCP review follow-ups * fix(cli): add browser MCP diagnostics * fix(cli): tighten browser MCP auto-wiring * fix(cli): address browser MCP diagnostics * revert(cli): drop browser MCP diagnostic churn * revert(cli): drop optional CDP startup diagnostic * refactor(cli): load browser MCP dynamically * fix(cli): lazily attach CDP tunnel * test(cli): use repo deps for CDP tunnel acceptance * fix(cli): scope browser MCP defaults to extension origins * fix(cli): recover from lazy CDP attach failures * fix(chrome-extension): bind CDP replies to source socket * ci: allow slower actionlint runs * fix(cli): harden chrome devtools runtime MCP registration * test(cli): satisfy lint in CDP registration race test * test(cli): cover chrome devtools MCP retry loop * test(cli): cover chrome devtools skip paths * ci: restore actionlint timeout |
||
|
|
891c59fbaa
|
feat(channels): add group history backfill (#6074)
* feat(channels): add group history backfill * fix(channels): harden group history backfill * fix(channels): address group history review gaps * fix(channels): apply wildcard group history limit |
||
|
|
17fbaa25cd
|
refactor(review): drop deterministic-analysis and autofix steps (#6092)
* refactor(review): drop deterministic-analysis and autofix steps
Slim the bundled /review skill from 11 to 9 steps by removing Step 3
(deterministic analysis — auto-run of tsc/eslint/ruff/clippy/go vet
plus CI-lint discovery) and Step 8 (autofix — PR-worktree auto-fix,
commit and push).
Renumber the remaining steps (4→3 … 11→9) and update every
cross-reference. Agent 7 (Build & Test) stays in the parallel review
step and now always runs build+test instead of skipping when Step 3
had already compiled. The [linter]/[typecheck] source tags are dropped;
[build]/[test]/[review] remain. DESIGN.md is updated to match (step
numbers, removed Autofix/deterministic rationale, LLM-budget table).
* refactor(review): address review feedback on the /review slimming
Follow-up to the 11->9 step change, addressing PR review comments:
- Restore base-branch CI-config protection in Agent 7. The removed Step 3 carried the instruction to read CI config from the base branch; without it Agent 7 would discover build/test commands from the untrusted PR branch. Re-added to Agent 7's CI-config discovery clause.
- Drop the stale "linters" token from the worktree rule (no standalone linter step runs anymore).
- Narrow the exclusion criteria: substantive lint/type issues (unused vars, unreachable code, type errors) are no longer auto-excluded now that no deterministic tool catches them; only pure formatting stays excluded.
- Update user docs to match: docs/users/features/code-review.md (11->9 steps, remove the Deterministic Analysis and Autofix sections, drop the two comparison-table rows, renumber the Token-efficiency table) and docs/users/features/commands.md (agent count).
- Fix stale step-number references in CLI comments: cleanup.ts (Step 11->9) and presubmit.ts (Step 9->7, comment + yargs describe).
* refactor(review): remove orphaned deterministic subcommand, polish docs
Second round of PR feedback:
- Remove the now-orphaned `qwen review deterministic` subcommand. review.ts describes these subcommands as "internal helpers used by the /review skill"; with Step 3 gone the skill no longer invokes it, so the ~740-line module plus its import / registration / describe / subcommand-list entries were dead code. Deleted deterministic.ts and its wiring in review.ts.
- Decouple the exclusion criterion from pipeline state (SKILL.md): substantive lint/type issues (unused vars, unreachable code, type errors) are now "in scope — LLM agents should report them" rather than "no longer have a deterministic tool catching them", so the rule stays correct if a linter step is ever re-added.
- Drop the stale "linting" justification from the worktree dependency-install note (SKILL.md); only build/test remain.
- DESIGN.md: rename the subcommands section to "presubmit and cleanup", drop "lint" from the review-tools rejected alternative, and fix the "we already have those" cell to "We retain build/test (Agent 7)".
* refactor(review): resolve exclusion-criteria contradiction, polish wording
Third round of PR feedback:
- Merge the exclusion criteria to remove the contradiction between the unconditional "matches codebase conventions" exclude and the "substantive lint/type issues are in scope" include. Now a single bullet: cosmetic style/formatting/naming is excluded, but substantive issues a linter or type checker would flag (unused variables, unreachable code, type errors) are in scope even where the surrounding code tolerates them. Kept decoupled from pipeline state (no "deterministic tool" wording). Applied in both SKILL.md and docs/users/features/code-review.md.
- SKILL.md lightweight-mode skip: "(no local reports or cache)" to match Step 8's title ("Save review report and cache").
- DESIGN.md: rename the CI-config section to "auto-discover build/test commands" to match the body, which was narrowed to build/test only.
* test(review): guard qwen review subcommand surface, fix stale docs linting ref
- Add packages/cli/src/commands/review.test.ts verifying the `qwen review` builder registers exactly [fetch-pr, pr-context, load-rules, presubmit, cleanup], no longer registers the removed `deterministic` subcommand, and that `describe` no longer mentions deterministic analysis. Guards against silently re-adding the subcommand or dropping a helper (review.ts previously had no test).
- docs/users/features/code-review.md: drop the orphaned "linting" from the Worktree Isolation dependency-install note; only build/test remain now that Step 3 is gone.
|
||
|
|
855a2b3d69
|
feat(auto-mode): add classifyAllShell setting to route all shell commands through classifier (#6040)
* feat(auto-mode): add classifyAllShell setting to route all shell commands through classifier When autoMode.classifyAllShell is true, every shell command (including read-only ones that would normally be auto-approved) is routed through the auto-mode LLM classifier for safety review. Default false preserves existing behavior. Closes #6039 * fix(core): add classifyAllShell check to autoApproveCompatiblePendingTools The third forceAutoReviewForAllow computation site in autoApproveCompatiblePendingTools was missing the shouldClassifyAllShellForAutoMode OR-branch, allowing shell commands to bypass the classifier when classifyAllShell is enabled. Addresses qwen-code-ci-bot critical review on PR #6040. * fix(core): use optional chaining in shouldClassifyAllShellForAutoMode Prevents TypeError when config.getAutoModeSettings() returns undefined in tests or edge cases where AutoModeSettings is not initialized. * docs(auto-mode): document classifyAllShell setting Add new section explaining the classifyAllShell option, a tip in the 'How it works' overview, and a commented-out example in the approval-mode configuration reference. * fix(test): add missing getAutoModeSettings mock in AUTO denial counter reset test |
||
|
|
e324104ce8
|
docs: refresh settings, MCP glob, auth alias, and autonomous loop docs (#6090)
Audit docs/ against the current codebase and correct user-facing drift: - Document glob-pattern support (* and ?) for mcp.allowed / mcp.excluded in settings.md and the MCP feature page (feat #6012). - Add missing user-facing settings rows: general.terminalBell, general.preventSystemSleep, general.chatRecording; ui.showStatusInTitle, ui.disableWorkflowKeywordTrigger, ui.enableUserFeedback, ui.compactInline, ui.useTerminalBuffer, ui.hideBuiltinWorktreeIndicator; memory.enableTeamMemory, memory.enableTeamMemorySync; tools.toolSearch.enabled. - Note the QWEN_MODEL alias for OPENAI_MODEL in the auth protocol table. - Document the autonomous (bare /loop) mode in scheduled-tasks (feat #5991). Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
cf6323bfb5
|
feat(cli): Add daemon-managed channel worker for serve --channel (#6031)
* feat(cli): add daemon-managed channel worker * codex: address PR review feedback (#5978) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6031) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6031) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6031) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): harden serve channel worker lifecycle Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): cover channel worker edge cases Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): address channel worker review followups Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): clear channel pidfile after worker exit Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): address serve channel review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): harden serve channel worker review issues Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): preserve channel worker exit errors Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): harden daemon channel worker startup Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): address channel worker review cleanup Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): track channel worker exit explicitly Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6031) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address daemon worker startup review (#6031) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6031) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address daemon worker disconnect review (#6031) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): address serve channel review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): address channel worker review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
e92fcbab46
|
fix(cli): switch TUI prefix ✦→◆ to fix glyph overflow on some terminals (#5974)
* fix(cli): replace ✦ (U+2726) with ◆ (U+25C6) and add ∵/∴ thinking icons - Replace ✦ with ◆ across all TUI components to fix East Asian Ambiguous width misalignment (string-width reports 1 but terminals render 2 columns). - Use ∵ (because) during thinking streaming, ∴ (therefore) when thinking is complete — matches the mathematical reasoning pair. Co-Authored-By: Qwen Code <noreply@alibaba-inc.com> * fix(cli): reduce STATUS_INDICATOR_WIDTH from 3 to 2 after ◆ replacement ◆ (U+25C6) is a consistent width-1 character across all terminals, so the tool status indicator no longer needs the extra column that was reserved for the ambiguous-width ✦ (U+2726). Co-Authored-By: Qwen Code <noreply@alibaba-inc.com> * fix(cli): catch missed ✦→◆ references in tests, docs, and scenarios * fix(cli): shorten tmux spinner frames from 3 to 2 chars to match STATUS_INDICATOR_WIDTH=2 TMUX_SPINNER_FRAMES changed from ['. ', '.. ', '...'] to ['· ', '··'] to prevent 1-column overflow in tmux when STATUS_INDICATOR_WIDTH was reduced from 3 to 2 after the ◆ replacement. * revert(cli): keep narrow '.' tmux spinner frames instead of ambiguous '·' '.' (U+002E) is Narrow (always 1 col), giving a guaranteed fixed-width tmux spinner. '·' (U+00B7) is East Asian Ambiguous, so on ambiguous-width=2 terminals the frames become 3/4 cols and the spinner jitters — the opposite of the "fixed-width frames" the surrounding comment promises. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen Code <noreply@alibaba-inc.com> Co-authored-by: pomelo.lcw <pomelo.lcw@alibaba-inc.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
7b9e31885b
|
feat(web-shell): add mobile sidebar drawer with session list (#6003)
* feat(web-shell): add mobile sidebar drawer with session list Replace the display:none behavior at viewport <=760px with an overlay drawer pattern. A hamburger menu button appears on mobile, tapping it slides the existing WebShellSidebar in as a fixed overlay with a semi-transparent backdrop. Selecting or creating a session auto-closes the drawer. Desktop layout (>=761px) is unaffected. Closes #6000 * fix(web-shell): address review feedback for mobile sidebar drawer - Use display:contents for desktop wrapper transparency (Critical: sidebar was hidden) - Fix z-index stacking so sidebar renders above backdrop in drawer - Force sidebar expand when mobile drawer is open (collapsed state) - Hide resizeHandle on mobile to prevent touch scroll conflicts - Reset drawer state on viewport resize via matchMedia listener - Add role=dialog, aria-modal, Escape key dismissal, body scroll lock - Add aria-expanded to hamburger button - Close drawer when opening Settings or resuming sessions * fix(web-shell): address second round of review feedback - Remove dead :global(.sidebar) selector (CSS Modules hash class names) - Fix Escape key capture-phase handler to not intercept sidebar inputs - Conditionally apply role=dialog/aria-modal only when drawer is open - Stop toggling collapsed prop on drawer open/close to preserve sidebar state - Add closeMobileDrawer() for bare /resume command path - Fix hamburger button vertical centering in empty chat state on mobile * fix(web-shell): fix stacking context and escape handler in mobile drawer * fix(web-shell): prevent iOS Safari background scroll when drawer is open * chore: remove accidentally committed .qwen-session and gitignore it The .qwen-session file is a developer-local session UUID generated by qwen serve. It was accidentally committed to the repo and should never be tracked. * fix(web-shell): address review feedback for mobile drawer - Don't preventDefault touchmove inside the drawer so the session list can scroll natively; only block scrolling on the page behind it. - Defer Escape to a pending tool/permission approval (reject) instead of closing the drawer when a prompt is visible. - Reuse isEditableTarget from utils/dom and only bail out for editable targets outside the drawer, so the drawer search input still closes on the first Escape. - Close the drawer before awaiting loadSession so it doesn't linger over the old transcript, matching the other session-switch paths. - Keep the drawer panel visible until the backdrop finishes fading out to avoid a one-frame flicker on close. Co-Authored-By: Qwen-Coder <noreply@qwen.ai> * fix(web-shell): mobile drawer ignores collapsed rail + block backdrop scroll - collapsed: a user who collapsed the desktop sidebar got a mobile drawer that still rendered as the icon rail (no session list — the whole point of the drawer). Force the expanded layout while the drawer is open. - touchmove: the allowlist matched the outer [data-mobile-drawer] wrapper, which also contains the full-screen backdrop, so a touchmove starting on the dim backdrop skipped preventDefault and let iOS Safari scroll the page behind. Exclude the backdrop so only the panel keeps native scroll. Co-Authored-By: Qwen-Coder <noreply@qwen.ai> * fix(web-shell): harden mobile drawer collapse, error path, and width cap - Hide the sidebar collapse button while the mobile drawer is open so its no-op toggle can no longer silently persist desktop collapsed state. - Close the drawer before awaiting createSession() so a failed create no longer leaves the drawer stuck open with page scroll locked. - Drop redundant width/min-width/position from .sidebar.mobileOpen and cap it with max-width:100vw so a wide persisted width can't overflow phones. Co-Authored-By: Qwen-Coder <noreply@qwen.ai> --------- Co-authored-by: pomelo-nwu <czynwu@gmail.com> Co-authored-by: Qwen-Coder <noreply@qwen.ai> |
||
|
|
a756676b21
|
fix(cli): replace all emoji with Unicode text symbols in TUI rendering (#5999)
* fix(cli): replace all emoji status icons with Unicode text symbols Comprehensive cleanup of emoji in TUI rendering paths (follow-up to #5787 / #5788). Replaces width-2 emoji with width-1 Unicode text symbols from the project's existing glyph vocabulary. ## Source changes (25 source files) Status indicators: - McpStatus: 🟢→● 🔄→◐ 🔴→● (colors preserved via Text color prop) - ideCommand: 🟢→● 🟡→◐ 🔴→● (both getIdeStatusMessage functions) - Footer: 🔒 removed (sandbox text label is self-explanatory) - Footer: ⚙→▷ (workflow active indicator) - ToolMessage: ⏳→◌ (progress + queued approval) - McpStatus: ⏳→◌ (server startup message) - LiveAgentPanel: ⏸→‖ (pause glyph) Text prefixes and labels: - StatusMessages: 🔎→◎ (vision bridge gutter prefix) - Session: 🚫→✗ (blocked notifications) - useGeminiStream: 🔎→◎ 🚫→✗ 💡→★ (prefixes and headers) - useContextualTips: 💡→★ (tip prefix) - WelcomeBackDialog: 👋🎯📋 removed (text labels are self-explanatory) - CreationSummary: ✅→✓ ❌→✗ - summaryCommand: ❌→✗ - AppContainer: ❌→✗ - AgentEditStep: ❌→✗ - useAutoAcceptIndicator: ℹ️→i - McpStatus Tips: 💡→★ Core package: - agent-statistics: 📋→▸ 🔧→● ⏱️→(stripped) 🔁→● 🔢→● ✅→✓ 🚀→● 💡→★ - shell: 🤖 removed from PR attribution footer - artifact-tool: 📄 removed from publish display - coreToolScheduler: ⚠️→⚠ (strip VS16) Standardized ⚠️ (U+26A0+VS16, width-2) → ⚠ (U+26A0, width-1): - CommandFormatMigrationNudge, command-migration-tool, useGeminiStream i18n: all 9 locale files updated for changed keys. ## Test changes (5 test files) - ideCommand.test.ts: 5 emoji assertions updated - McpStatus.test.tsx: 13 snapshots updated - HistoryItemDisplay.test.tsx: 🔎→◎ assertions - useGeminiStream.test.tsx: VS16 + 🔄 assertions - agent-statistics.test.ts: all emoji assertions updated * fix(cli): address review feedback — fix docs, tests, and glyph issues - Fix McpStatus test snapshots to actually exercise connecting/disconnected states via serverStatus prop instead of ineffective vi.spyOn mock - Update user docs (status-line.md, ide-integration.md) to match new symbols - Change Footer workflow indicator from ⚙ to ▷ for consistency - Fix Duration line leading space in agent-statistics formatCompact/formatDetailed - Revert ‖ (U+2016, EAW=Ambiguous) back to ⏸ (EAW=Narrow) for CJK terminals - Restore 🤖 in PR attribution (GitHub web UI, not TUI) - Add old emoji to lspCommand.test.ts negative assertion - Tighten Footer test to assert full ▷ glyph text * fix(cli): sync JSDoc with code for shell attribution and regenerate McpStatus snapshot * fix(cli): distinct IDE status glyphs + mark LLM-facing retry directives - ideCommand: Connected and Disconnected both rendered an identical bullet differing only by color, indistinguishable under deuteranopia/protanopia, in NO_COLOR terminals, or when copy-pasted. Use the PR's established ✓/✗ vocabulary (✓ Connected, ✗ Disconnected); Connecting keeps ◐. - coreToolScheduler: note that the ⚠ in the two RETRY_LOOP directives is an LLM-facing prompt string, not a TUI glyph, so it isn't 'fixed' for width later. Co-Authored-By: Qwen-Coder <noreply@qwen.ai> --------- Co-authored-by: pomelo.lcw <pomelo.lcw@alibaba-inc.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: Qwen-Coder <noreply@qwen.ai> |
||
|
|
f3694dde67
|
feat(ui): add ui.history.collapsePreviewCount to show last N turns when resuming collapsed sessions (#5848)
* feat: add ui.history.collapsePreviewCount to show last N turns on resume * chore: regenerate settings schema for collapsePreviewCount --------- Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
35a8851a38
|
feat(core): add --insecure flag to skip TLS verification for self-signed endpoints (#3535) (#5962)
* feat(core): add --insecure flag to skip TLS verification for self-signed endpoints (#3535) Enable skipping TLS certificate verification for outbound model API connections via a new --insecure CLI flag, QWEN_TLS_INSECURE, or NODE_TLS_REJECT_UNAUTHORIZED=0. The setting is applied to the undici dispatcher Qwen Code installs: a direct connection uses connect TLS options, while a proxied connection disables verification for the upstream origin (requestTls) and a self-signed HTTPS proxy (proxyTls). Off by default; behavior is unchanged when not enabled. Fixes #3535 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(core): address review on --insecure (security + simplification) (#3535) - Block project .env from enabling QWEN_TLS_INSECURE by adding it to PROJECT_ENV_HARDCODED_EXCLUSIONS, so an untrusted repo cannot silently disable TLS verification for all API connections. - Remove the unverifiable Bun fetch `tls` special-casing; Bun users can still opt out via NODE_TLS_REJECT_UNAUTHORIZED=0, which Bun honors natively. - Do not suggest `--insecure` in the TLS error hint when verification is already disabled; show a network/protocol-oriented message instead. - Add tests: env-flag regex/falsy branches, loadCliConfig env side-effect, fetch hint variants, and a security guard for the project .env exclusion. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(core): harden --insecure per review (#3535) - Block NODE_TLS_REJECT_UNAUTHORIZED from project .env too (initial load only consults PROJECT_ENV_HARDCODED_EXCLUSIONS), since isTlsVerificationDisabled() honors it. - When opting out, set NODE_TLS_REJECT_UNAUTHORIZED=0 process-wide in loadCliConfig and emit a stderr MITM warning. This makes the opt-out effective on the Bun runtime and the proxy-creation fallback path (which the undici dispatcher does not cover), and gives a user-visible signal. - Avoid evaluating isTlsVerificationDisabled() twice on the proxy path via a default parameter on getOrCreateSharedDispatcher. - Update tests accordingly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(cli): broaden --insecure warning and log it; add env-path tests (#3535) - Broaden the TLS-disabled warning to state the process-wide blast radius (API, OAuth, MCP servers, child processes), since NODE_TLS_REJECT_UNAUTHORIZED=0 is set process-wide. - Also emit the warning via debugLogger so the state is discoverable in ~/.qwen/debug/ after terminal scrollback is gone. - Add tests for the env-var-only path (pre-set QWEN_TLS_INSECURE) and the already-disabled guard (no duplicate assignment/warning). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
c90e6e7ba4
|
feat(channels): Add channel agent bridge abstraction (#5978)
* feat(channels): add channel agent bridge abstraction Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(channels): handle bridge session lifecycle cleanup Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(channels): close bridge lifecycle review gaps Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5978) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5978) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix: address channel bridge review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5978) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5978) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
8daeb5b1f9
|
feat(core): add configurable auto-compact threshold and Stop hook context usage (#4025) (#5868)
* feat(core): add configurable auto-compact threshold and Stop hook context usage (#4025) Add two features requested in issue #4025: 1. Configurable auto-compact threshold via settings.json - Add context.autoCompactThreshold setting (0-1, default 0.7) - Extend computeThresholds(window, pct?) to accept optional pct parameter - Wire all 4 call sites (chatCompressionService, geminiChat, contextCommand, useContextualTips) - Large windows (>110K) dominated by absolute branch, custom threshold mainly affects small windows 2. Stop hook stdin payload includes context usage data - Add ContextUsageData interface and buildContextUsage helper - Extend StopInput with context_usage, context_limit, input_tokens fields - Wire 3 callers (Session.ts, client.ts, config.ts) - Enables hook scripts to observe context usage and suggest compact strategies * fix(test): add getAutoCompactThreshold mock to geminiChat.test.ts, add NaN guard to buildContextUsage * fix(review): address round 4 findings — schema constraints, Partial<ContextUsageData>, buildContextUsage validation * docs: add context.autoCompactThreshold and Stop hook context usage fields documentation * fix(review): add contextWindowSize fallback, pct clamp, doc accuracy, threshold propagation test * fix: correct warn value in contextCommand test comment * test(chatCompressionService): fix misleading pct=1 test name and assertion * fix(chatCompressionService): prevent negative warn threshold for low pct values * docs(chatCompressionService): update JSDoc warn formula to include max(0, ...) floor * test(chatCompressionService): add pct clamping tests and fix NaN handling Add tests for out-of-range pct values (-0.5, 1.5, NaN) to verify computeThresholds clamping behavior. Fix implementation to use Number.isFinite() check so NaN falls back to DEFAULT_PCT instead of propagating through Math.max(0, NaN) which yields NaN. * test(config): add MCP Stop dispatch validation tests Add tests for buildContextUsage runtime validation in MCP Stop dispatch path: - Valid numeric inputs produce correct ContextUsageData - Missing/undefined fields return undefined - String values rejected by Number.isFinite validation - Negative values return undefined Also add Number.isFinite check for contextWindowSize in buildContextUsage to properly validate MCP input types at runtime. * fix(chatCompressionService): fix TypeScript type narrowing for pct parameter Use explicit undefined check before Number.isFinite to properly narrow the number | undefined type in the ternary expression. --------- Co-authored-by: 俊良 <zzj542558@alibaba-inc.com> |
||
|
|
673454839e
|
feat(memory): add a git-shared team memory tier (#5886)
* feat(memory): add a git-shared team memory tier
Add an opt-in third auto-memory tier — TEAM — stored in the repository at
`.qwen/team-memory/` and shared with collaborators through git. The private
USER and PROJECT tiers are unchanged.
- Enabled via the `memory.enableTeamMemory` setting (default off) or the
`QWEN_CODE_MEMORY_TEAM` env override; inactive otherwise.
- The model is taught a three-tier prompt and when to route saves to the
shared tier (project-wide conventions, team-wide references).
- Writes to the team directory are scanned for secrets (a curated
gitleaks-style ruleset) and hard-blocked, since the directory is committed
to the repo and visible to everyone with repo access.
- Team writes default to 'ask' permission — not auto-allowed like the private
tiers — so they are proposed for confirmation in the default approval mode
and surface in the git diff for review.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(vscode): update settings schema for team memory
* fix(memory): harden team memory review gaps
* fix(memory): address team-memory PR review feedback
- secret-scanner: AWS key suffix is base62 ([A-Z0-9]), not base32
([A-Z2-7]) — old class missed IDs with digits 0/1/8/9; add a
positive test for such a key.
- paths: document that isAnyAutoMemPath deliberately excludes team
memory (security-load-bearing — team writes must stay 'ask').
- extractionAgentPlanner: name the team-memory dir in the scoped deny
message so a denied team write is debuggable.
- prompt: spell the tier count via a number-word lookup so a future
4th tier never silently reads "two".
- team-memory-secret-guard: debug-log matched rule IDs only (never the
secret content) when a write is blocked.
- edit: when a blocked team write's secret already exists in the
on-disk file, tell the user to delete the committed secret.
- docs: caveat that a directory-form gitignore (.qwen/) makes the
!-reinclude a no-op; use the file-glob form.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(memory): harden team-memory secret guard on blocked writes and notebooks
- write-file: blocked team-memory secret write now returns an `error`
field (INVALID_TOOL_PARAMS) so the framework treats it as a failure
instead of a silent success, mirroring edit.ts.
- notebook-edit: scan the serialized .ipynb that hits disk through the
team-memory secret guard before writing, blocking with the same
`error` field; behavior unchanged for non-team-memory paths.
- store: log non-ENOENT errors in readTeamAutoMemoryIndex before
re-throwing, so EACCES/EIO/ELOOP no longer vanish via config.ts's
best-effort `.catch(() => null)`.
- config: emit a debug diagnostic when team memory is enabled but
suppressed by the untrusted-workspace trust gate.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* feat(memory): auto-generate the team memory index
Generate the team `MEMORY.md` index by scanning the saved memory files
instead of having the model hand-maintain it. The index is derived and
ordered by path, so the committed file is deterministic across machines.
This removes the git merge-conflict surface a hand-edited shared index would
have, keeps the index consistent with the files, and frees the model from the
two-step save for the team tier.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* feat(memory): opt-in git sync for team memory
Add an opt-in, best-effort git sync of team memory at session start so a
daemon can share team memory through the remote without manual git. Off by
default; enabled with `QWEN_CODE_MEMORY_TEAM_SYNC=1`.
It commits the team directory (only that path), pulls fast-forward-only, then
pushes. `--ff-only` is deliberate: it never creates a merge commit or a
conflict — a diverged branch is skipped rather than touching the working tree.
All git is best-effort and never throws, so a failure cannot break a session.
Commits can be attributed to the acting user via an optional author, for
cooperative per-user attribution on a shared daemon.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(core): close team-memory secret-guard regex + test gaps
- secret-scanner: add `_` to the two T3BlbkFJ-marker char classes so legacy
base64url OpenAI keys with underscores in the body no longer bypass the
scanner; extend the OpenAI positive samples with an underscore key body.
- edit: cover the pre-existing-secret branch — seed the on-disk file with a
full detectable token, assert the distinct "already exists" message and that
the blocked edit leaves the file untouched.
- team-paths: cover the first-ever write before .qwen/team-memory exists,
exercising realpathNearestExisting walking up to an existing ancestor.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* feat(core): add Google OAuth client secret and SendGrid secret-scanner rules
Extend the team-memory secret scanner with two more high-confidence,
distinctive-prefix credential patterns (both gitleaks rules):
- gcp-oauth-client-secret: GOCSPX- prefix + 24 base64url chars,
placed next to the existing GCP AIza API-key rule.
- sendgrid-api-token: SG. + 22-char id + . + 43-char secret.
Both have a near-zero false-positive bar, matching the curated set's
existing criteria. Add a load-bearing positive sample per rule.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(memory): warn when team memory is enabled but not git-shareable
When the team tier is active, emit a one-time startup warning if its
directory is git-ignored (e.g. a directory-form `.qwen/` ignore that a
`!`-reinclude cannot escape) or there is no git root — so the tier never
silently shares nothing. Gated on the active (trusted + enabled) tier;
probes a representative file path with `git check-ignore`, and is
latched so refreshHierarchicalMemory re-runs do not re-emit it.
Closes the last open review thread (wenshao + qwen-code-ci-bot both
flagged the silent-inert case); the docs caveat already shipped.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* feat(memory): dedup team index by description; fix empty-frontmatter parse
The team index now collapses entries that share a (normalized) description
into one line — listing the other files via "(also: …)" — so two people
saving the same shared fact don't surface as duplicates. Nothing is dropped;
every file path is preserved and the grouping is deterministic (input is
path-sorted).
Also fix a pre-existing frontmatter bug: parseFrontmatterValue used `\s*`,
which crosses newlines, so an empty value (`description:`) captured the next
frontmatter line. Bound it to horizontal whitespace.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* feat(memory): add memory.enableTeamMemorySync setting
Team-memory git sync was env-only (QWEN_CODE_MEMORY_TEAM_SYNC). Add a
first-class `memory.enableTeamMemorySync` setting mirroring the
enableTeamMemory plumbing (settingsSchema, cli/core config, acpAgent
type/schema/default/keys/normalizer, desktop mirror), with the env var kept
as a 0/1 override. Off by default. Docs updated.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(memory): audit hardening — resilient scan, deterministic team index
From a multi-round adversarial audit of the team-memory tier:
- scan: a single unreadable memory file (EACCES, or a TOCTOU delete during
`git pull`) no longer rejects the whole scan and wipe every memory from the
index — per-file failures are caught and skipped (debug-logged).
- indexer: order the team index by code unit, not `localeCompare()`, so the
committed MEMORY.md is byte-identical across machines/locales and the
ff-only sync can't wedge on index churn.
- scan: escape the frontmatter key before building its RegExp (latent hardening).
- config: surface a skipped/failed team-memory sync at debug level instead of
silently swallowing it.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(memory): deterministic team index cap + surface diverged sync
Round-2 audit follow-ups:
- scan: the >200-file cap selected its subset by mtime + locale basename, which
differs per machine/locale — so a large team's committed index churned and
wedged the ff-only sync. Team scans now cap by code-unit path (deterministic);
private tiers keep mtime-recency (never shared, so it's fine).
- sync: a diverged branch made `pull --ff-only` (and the push) fail with no
`skippedReason` — a silent no-op for a user who opted into sync. Now reported
as `pull-failed` / `push-failed` and logged. Docs note pull/push are
whole-branch, not path-scoped.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(memory): regenerate settings schema for enableTeamMemorySync
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(memory): harden team-memory git sync (reconcile-first, scoped push, safe failure)
The opt-in team-memory git sync could publish unrelated local commits, wedge a
two-writer branch, leave team files staged on commit failure, and hang session
start on a credential prompt. Harden all four maintainer-flagged criticals:
- Reconcile first: run `git pull --ff-only` BEFORE committing so the local team
commit lands on top of upstream instead of diverging; a diverged branch is
skipped cleanly as `pull-failed` rather than committing then wedging `--ff-only`.
- Scoped push: push only when THIS sync created the commit and the branch was
not already ahead of `@{u}` (pre-sync), via an explicit single-branch refspec
(`HEAD:<merge-ref>`) — never an unqualified `git push`. New `local-ahead` skip.
- Safe failure: unstage the team path when the commit fails (hook/GPG/identity)
so a user's next manual `git commit` cannot sweep team files in.
- Non-interactive git: force `GIT_TERMINAL_PROMPT=0` + batch-mode SSH, SIGKILL on
timeout, and a shorter timeout so sync cannot block session start on a prompt.
config refresh: rebuild the team index BEFORE syncing (so a fresh MEMORY.md is
committed/pushed, with a re-build after a pull that brought new files) and key
the shareability latch by projectRoot so a newly entered repo is re-checked.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(memory): harden team-memory index/scan/path security
Address the security/correctness criticals from PR #5886 review. Team
memory is committed to the repo and loaded into every collaborator's
system prompt, so its write/scan/classification paths are trust
boundaries.
- indexer: pass noFollow on the team MEMORY.md write and reject a
symlinked team root, so a committed `.qwen/team-memory` (or index)
symlink can't redirect the generated index outside the repo.
- indexer: sanitize attacker-controlled frontmatter title/description
(strip control/zero-width/bidi chars, collapse newlines, defang
code/link markdown, cap length) before embedding into MEMORY.md, to
prevent prompt injection into the shared context.
- indexer: skip the rewrite when the generated index is byte-identical,
avoiding mtime churn and no-op commit cycles.
- scan: normalize CRLF before parsing so a Windows checkout's team files
don't silently drop out of the shared index.
- paths: resolve a dangling final-component symlink via lstat/readlink in
realpathNearestExisting, so a `decoy -> team-memory/leak.md` (missing
target) is classified as team and the secret scanner can't be bypassed.
- secret-scanner: bound both quantifiers in the openai-api-key T3BlbkFJ
rule ({20,512}) to remove O(n^2) ReDoS backtracking; real keys still
match.
- team-memory-git-status: also probe a representative topic path so a
repo that re-includes the index but ignores topic files is flagged as
non-shareable.
- notebook-edit: run the team-memory secret scan in validateToolParamValues
too, for parity with edit/write-file.
Adds load-bearing tests for each fix.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(memory): sanitize team index paths and verify whole-path containment
Refines the earlier team-memory security hardening with two fixes the
first pass left open:
- sanitizeIndexPath now defangs the attacker-controlled relativePath
rendered into the committed MEMORY.md — at BOTH the `](path)` link
target and the "(also: ...)" dedup suffix. A git filename may legally
contain newlines and markdown delimiters, so a raw path could inject a
second physical line (e.g. "- SYSTEM:") and reopen the prompt-injection
structure the patch was closing for title/description.
- rebuildTeamAutoMemoryIndex now realpath-resolves the whole team root
and requires it to equal repoRoot/.qwen/team-memory. The prior lstat
only inspected the leaf, so a symlinked PARENT component (e.g.
`.qwen -> /tmp/out`) let scan/write escape the repo undetected while
the guard believed it had rejected symlinks.
Also adds a regression test pinning the security-load-bearing invariant
that isAnyAutoMemPath excludes team paths (so team writes stay ask-gated).
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(memory): keep team index link targets addressable, not just safe
The earlier injection fix rewrote legal filename chars (`(` `)` `[` `]` and
backticks) to `_` and used that destroyed value as the ACTUAL MEMORY.md link
target. A real file `feedback/a(b).md` was emitted as `](feedback/a_b_.md)`,
which does not exist (or, worse, collides with a different real file) — the
link was injection-safe but no longer addressable.
Replace `sanitizeIndexPath` with `encodeIndexPathTarget`, a reversible
percent-encoder: every char outside an addressable allowlist (alphanumerics
and `/ . - _ ~`) is percent-encoded, so breakout chars become inert ASCII
(newline->%0A, `(`->%28, `)`->%29, space->%20, backtick->%60, ...). The target
is a single line with no `](`/`)` breakout, yet `decodeURIComponent` recovers
the exact original path so the link resolves to the real file. `/` is kept
literal so the path still works as a relative reference. Applied at both index
sites (the main `](path)` link and the `(also: ...)` suffix). The display label
(title) stays non-reversibly sanitized as before — it is not addressable.
Update the path tests to assert the emitted target percent-decodes back to the
real relative path, and add a `feedback/a(b).md` case. The newline+`]`/`)`
injection assertions remain (mutation-verified: they fail if the encoding is
dropped).
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(memory): gate team-memory sync on the index safety check
rebuildTeamAutoMemoryIndex throws when the team root is a symlink that
could redirect the committed index outside the repo, but the surrounding
.catch swallowed the error and syncTeamMemory ran independently — so a
refused symlink/escape still got git add/commit/push'd on the out-of-repo
dir, defeating the indexer's refusal. Capture whether the rebuild
succeeded and only sync when it did, so a failed safety check skips sync
entirely.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(memory): harden team-memory git sync and cover execute-time secret scan
Several robustness fixes to the team-memory git sync, plus a missing test:
- Respect a user's GIT_SSH_COMMAND: append our non-interactive batch guards
(-oBatchMode=yes -oConnectTimeout=5) onto it instead of clobbering it, so a
custom identity (-i), proxy jump (-J), or non-standard port is preserved.
- Skip cleanly on a detached HEAD (new `detached-head` skippedReason) instead
of creating an orphaned commit that can never be pushed. A branch with no
upstream still commits locally as before.
- Use SIGTERM (not SIGKILL) as the git kill signal so a timeout mid-commit/-pull
lets git release index.lock and clean up; the non-interactive ssh guards
already bound the network-hang case.
- docs(memory): correct the sync description to match the implementation
(rebuild index, ff-pull BEFORE commit, push only the scoped sync commit,
skip on divergence/no-upstream).
- test(notebook-edit): cover the execute-time team-memory secret scan (the
full-notebook backstop), distinct from the existing validate-time test.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(memory): split security vs operational team-sync failures; per-op git kill signal
Refine the recent team-memory sync changes per review:
- indexer: throw a typed TeamMemoryRootSecurityError for the symlink/escape
rejection so the sync gate can tell a SECURITY refusal apart from an
OPERATIONAL IO failure. config now blocks sync ONLY on the security class;
an operational rebuild failure (EACCES/ENOSPC/EPERM) is logged but
self-corrects on the next rebuild and no longer permanently gates legitimate
team sync. The security invariant (never add/commit/push an escaping root)
is unchanged.
- team-memory-sync: pass a per-op kill signal to tryGit — SIGKILL for the
hang-prone network/ref ops (pull/push/rev-parse/symbolic-ref; no index.lock
to corrupt), SIGTERM for mutating ops (add/commit) so git can release locks
and clean up. Node's execFile timeout does not escalate to SIGKILL on its
own, so a child trapping SIGTERM could hang past the timeout.
- team-memory-sync: thread the resolved branch into resolvePushTarget so it no
longer re-spawns `git symbolic-ref` after the detached-HEAD check.
- docs: fix a broken sentence in the team-memory git-sync section.
- tests: cover both rebuild failure classes (security -> sync skipped;
operational -> sync still runs) and a positive gate (rebuild ok + sync
enabled -> sync runs); assert the typed error on the indexer symlink tests.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen-Coder <noreply@qwen.ai>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
|
||
|
|
f33dd61f8a
|
fix(core): stop repeated truncated write_file/edit retries from looping (#5934)
* fix(core): stop repeated truncated edit retries * fix(core): default output tokens to the model limit instead of the 8K cap The 8K CAPPED_DEFAULT_MAX_TOKENS made normal large responses (esp. file writes) truncate, forcing a truncate->escalate round-trip and, worst case, a retry loop. Default to the model's declared output limit instead; the existing escalation + multi-turn recovery stay as the truncation backstop. The 8K cap was a slot-reservation optimization. Claude Code keeps the same cap but gates it behind a feature flag that defaults OFF for third-party providers; qwen-code's providers are all third-party / OpenAI-compatible / self-hosted, so matching that default-off behavior is the safe choice. The capacity tradeoff stays opt-in via QWEN_CODE_MAX_OUTPUT_TOKENS. Refs #5756 * fix(core): use a truncation-specific stop directive for repeated truncated writes * docs: update max tokens configuration wording |
||
|
|
24edd459ea
|
feat(serve): query a single session's status by id (#5857)
* feat(serve): query a single session's status by id
Add a daemon HTTP endpoint, GET /session/:id/status, that returns the
live status summary for one session by its id — the same per-item shape
that the workspace session list produces (sessionId, workspaceCwd,
createdAt, displayName, clientCount, hasActivePrompt). It answers 200
with the summary when the daemon holds a live session with that id, and
404 when the id is unknown.
Previously the only way to read a session's live state was the full
paginated workspace session list, forcing a caller that already holds a
session id to fetch every page and filter client-side just to answer
"is this session still running?". A by-id lookup is the natural
primitive for polling a single known session's hasActivePrompt /
clientCount — for example, a client UI that disables controls or shows a
"task in progress" hint while a specific session is running.
The data already exists on the bridge, so this adds one accessor
(getSessionSummary) sharing the same summary builder as the list path,
one route, unit tests, and a docs note.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(serve): clarify /session/:id/status returns the live bridge view
The session-status docs said the response is "the same item shape that
GET /workspace/:id/sessions lists". That parity only holds at the bridge
layer; the HTTP list endpoint enriches each item with persisted
session-store data, so for the same live session the two routes diverge
on createdAt (persisted first-prompt time vs live spawn time), updatedAt
(present only on the list), and displayName (derived from the stored
title/prompt vs the live session's own, usually unset). Reword to
describe /status as the raw live-session view, spell out those
differences, and fix the 404 note to match the actual { error, sessionId }
body (no code field).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(serve): advertise GET /session/:id/status via session_status capability
The new single-session status route had no entry in the capability
registry, so clients couldn't feature-detect it the way they pre-flight
the sibling read-only session routes (session_context, session_tasks,
session_stats, session_lsp, …). Add an always-on `session_status` tag,
mirror it in the registered-features test, and document it in the
protocol feature list, the capability→route map, and the capability
versioning reference.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(serve): pin that /session/:id/status omits displayName when unset
The docs state the route returns displayName only when the live session
has one, but no test asserted the key is absent from the HTTP body in
that case — it relied implicitly on res.json() dropping the
undefined-valued key. Add a sibling 200 test with a summary that has no
displayName and assert the key is not present, so a future change to the
shared summary builder can't silently break the documented shape.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(serve): add session_status to the integration capabilities baseline
The capabilities-envelope integration test pins the full caps.features
list returned by a live daemon, so adding the session_status capability
tag to the registry made the live list diverge from the test's hardcoded
baseline (CI: expected 65, received 66). Add session_status to that
baseline in the same position the registry emits it (after session_lsp),
and to the session-lifecycle capability-tag reference for completeness.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: 云胧 <yungsen.hys@alibaba-inc.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
07beac1ddb
|
feat(telemetry): Make sensitive span attribute limit configurable (#5804)
* feat(telemetry): Make sensitive span attribute limit configurable Default sensitive native OTel span attribute payload truncation to 1 MiB and allow users to override the limit via settings or environment. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: fix CI failure on PR #5804 Add the new sensitive span attribute default export to telemetry/core mocks used by the full Windows test suite. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5804) Include invalid telemetry max-length values in errors, make the telemetry parser stricter, include the configured truncation limit in markers, and cover the exact truncation boundary. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5804) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5804) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5804) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(cli): fix ACP worktree mock for telemetry limit Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): honor telemetry limit for model output spans Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(core): cover telemetry span limit edge cases Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5804) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5804) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5804) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5804) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5804) Keep sensitive span truncation results within the configured max length, make response-text extraction require an explicit cap, and cover whitespace-only sensitive span max length env values. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5804) Keep model-output span attribute writes best-effort and share visible response text extraction between log and sensitive span paths. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): address telemetry review feedback Bound prefixed tool span payloads, share sensitive max-length validation, and cover multi-part sensitive model output. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): update workspace facade core mock Add telemetry sensitive span length constants to the qwen-code-core mock used by the workspace service facade test so settings schema imports can load. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5804) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5804) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5804) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: 易良 <1204183885@qq.com> |
||
|
|
4efe2c77bc
|
docs: add vertex-ai auth, missing commands, and qc-helper index entries (#5727)
* docs: add CLI subcommands section with qwen sessions list
- Add section 5 to commands.md for CLI-level subcommands
- Document qwen sessions list with --json and --limit flags
- Include output format, examples, and usage patterns
The sessions list command was added in commit
|
||
|
|
44b80da0db
|
feat(memory): confirm auto-generated skills before persisting (#5616)
* feat(memory): add memory.autoSkillConfirm setting schema * feat(memory): add Config.getAutoSkillConfirmEnabled() * feat(memory): wire memory.autoSkillConfirm through cli/acp/desktop settings * feat(memory): add pending-skills staging helpers * feat(memory): stage auto-skills for confirmation in runSkillReview * feat(memory): pass autoSkillConfirm flag from client to skill review * feat(memory): skill-review subscriptions + accept/reject pending APIs * feat(cli): add skill-review dialog state to UI context * feat(cli): add SkillReviewDialog component * feat(cli): render SkillReviewDialog from DialogManager * feat(cli): wire skill-review subscription and idle dialog routing * feat(cli): show pending auto-skill review hint in footer * feat(cli): add autoSkillConfirm toggle to /memory dialog * docs(memory): document memory.autoSkillConfirm setting * fix(cli): focus and Ctrl+C-close the skill-review dialog * fix(memory): address review on auto-skill confirmation - stage only newly-created skills, never agent-edited pre-existing ones, so Discard can't delete a skill the user already confirmed - re-read pendingSkills after the await in resolvePendingSkill so concurrent Keep-all/Discard-all removes every entry, not just the last - surface accept/reject fs failures (try/catch + log + .catch) instead of silently swallowing them - remount SkillReviewDialog per task via key so its snapshot never goes stale across consecutive skill-review batches - skip redundant skillReviewPending updates with a signature compare - remove the unreachable openSkillReviewDialog action - add debug logging to the pending-skills module - ignore .qwen/pending-skills/ explicitly in .gitignore * fix(memory): address round 2 review on auto-skill confirmation - acceptPendingSkill: when the staged dir is gone, no-op only if the skill is already in the skills root; otherwise throw so resolvePendingSkill keeps it pending and logs, preventing silent data loss - fall back to the agent's systemMessage for progress text when staging yields zero pending (a pre-existing-skill edit is still a durable change) - log the no-task / no-target early returns in resolvePendingSkill - replace internal tracker references in an AppContainer comment * fix(memory): harden auto-skill confirmation for multi-batch and edge cases - parseDescription: keep an empty description empty instead of spilling onto the next YAML line - namespace staged dirs under the task id so a later same-named batch can't clobber a still-deferred earlier one - track Esc-dismissed batches in a Set (not a single value) and only mark a batch dismissed on Esc, so a partially-failed Keep-all can reopen for the unresolved skills - document the in-place updateRecord invariant the accept/reject race fix relies on - add the missing license header to pending-skills.test.ts * fix(memory): strip quoted descriptions; Ctrl+C defers skill-review dialog - parseDescription: strip a matching pair of surrounding quotes so a `description: "..."` frontmatter value isn't rendered with literal quotes - useDialogClose: Ctrl+C on the skill-review dialog now calls dismissSkillReviewDialog (records the batch as dismissed) instead of plain close, matching Esc — otherwise the idle effect immediately reopened it --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
87ce3f47a3
|
feat(cli): Add skill usage stats (#5826)
* feat(cli): Add skill usage stats Track live session skill invocations in daemon stats and expose /stats skills across interactive and non-interactive flows. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#5826) Add non-interactive skill stats tests for action rejection and prompt hook errors. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |