Skip to content

Merge upstream QwenLM/qwen-code v0.14.4#8

Open
lukemarsden wants to merge 2838 commits intomainfrom
feature/001804-we-havent-updated-qwen
Open

Merge upstream QwenLM/qwen-code v0.14.4#8
lukemarsden wants to merge 2838 commits intomainfrom
feature/001804-we-havent-updated-qwen

Conversation

@lukemarsden
Copy link
Copy Markdown

Summary

Merges upstream QwenLM/qwen-code main (v0.14.4) into our fork, which was pinned at v0.4.1. This is a ~10 major version jump bringing in ~2800 upstream commits with significant improvements to ACP protocol support (now using @agentclientprotocol/sdk v0.14.1), new features (fork subagents, startup profiler, hooks), and bug fixes.

Changes

  • Resolved 11 merge conflicts — took upstream for 6 files, deleted 2 files upstream removed (schema.ts, smart-edit.ts), manually merged 3 files
  • Cleaned up fork debug logging (console.error statements) from 4 files that the linter flagged
  • Preserved fork-specific changes: bind-mount path normalization, QWEN_DATA_DIR env var, shell prompt customizations (is_background, XML tool call suppression), session history callId queue fix
  • Dropped fork changes superseded by upstream: custom ACP Zod schema types, ACP v0.10.0 alignment, debug logging (6 commits), [object Object] error fix, shell security disabling

What was kept from our fork

  • normalizeProjectPath() in paths.ts — handles bind-mount path equivalence for containerized environments
  • normalizeProjectPath usage in chatRecordingService.ts — ensures session hashing works across bind-mount paths
  • QWEN_DATA_DIR in storage.ts — persistent storage location override (consider migrating to upstream's QWEN_RUNTIME_DIR)
  • Prompt customizations in prompts.tsis_background parameter instruction and XML tool call suppression
  • getErrorMessage import retained in ls.ts where still used

What was dropped

  • schema.ts — custom Zod-based ACP type definitions, superseded by @agentclientprotocol/sdk types
  • smart-edit.ts — tool removed by upstream entirely
  • Shell security disabling — upstream now has a mature AST-based shell checker; can be re-applied as config if needed
  • All debug console.error logging — 6 commits worth of temporary debugging statements

Notes for review

  • QWEN_DATA_DIR env var may want to be migrated to upstream's QWEN_RUNTIME_DIR pattern in a follow-up
  • Shell security checks are now re-enabled (upstream approach) — verify this works in our sandbox environment
  • Build and all 188 tests pass

🔗 Open in Helix

📋 Spec:

🚀 Built with Helix

wenshao and others added 30 commits April 6, 2026 17:50
Save approved plans to ~/.qwen/plans/{sessionId}.md so they can be
referenced later in the session or reviewed outside the CLI.

Changes:
- Storage: add getPlansDir() and getPlanFilePath()
- Config: add savePlan(), loadPlan(), getPlanFilePath() methods
- ExitPlanModeTool: persist plan to disk when user approves
- Tests: 4 new Config tests, 2 new ExitPlanModeTool assertions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Covers configuration, JSON stdin fields, examples (model+tokens,
git branch, script file), behavior details, and troubleshooting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add jq prerequisite section
- Clarify that settings changes take effect without restart
- Provide complete JSON in troubleshooting test command
- Move script filename out of code block to avoid shebang confusion

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add size > 0 check before computing context percentage to prevent
division by zero when context_window_size is unavailable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The settings parser uses stripJsonComments + JSON.parse, which does
not support trailing commas. Changed the config example from jsonc
to json and removed trailing commas so users can copy-paste safely.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix "three distinct permission modes" → "four" (Plan was always listed)
- Update refactor example to use /plan command instead of /approval-mode
- Fix grammar in example description

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use echo "$input" instead of echo $input for proper shell variable
quoting, consistent with the script file example.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PS1 \n should be removed or replaced with a space since the status
line only displays the first line of stdout. Also added a guideline
that commands must produce exactly one line of output.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Footer comment now accurately states only the "? for shortcuts"
  hint is suppressed, not all left-section items
- Docs now note that Windows uses cmd.exe by default and suggest
  wrapping commands with bash -c or using a bash script

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Inline shell snippets need sh -c to execute via pipe, matching how
child_process.exec() runs the configured command.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
"Use the Agent tool with subagent_type" is more direct than
"Create an Agent", reducing ambiguity for the model.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…, autofix, and security hardening

Comprehensive improvements to the /review skill based on competitive analysis
of Copilot Code Review, Claude Code /ultrareview, and Gemini CLI async-pr-review.

Key changes (all prompt-only, no TypeScript code changes):

- P0: Integrate linter/typecheck (Step 1.5) — run project tools before LLM agents,
  with error/warning severity distinction
- P1: Add Agent 5 for build & test verification with env/code failure distinction
- P1: Cross-file impact analysis for Agents 1-4 with 10-symbol prioritization limit
- P1: Project custom review rules (.qwen/review-rules.md, copilot-instructions.md,
  AGENTS.md, QWEN.md) with base-branch reading for PR security
- P2: Autofix with user confirmation, PR branch commit, and verdict split
  (terminal vs PR submission)
- P2: Pattern aggregation for same-type findings across locations
- P2: Confidence levels (high/low) with "Needs Human Review" section
- P2: Skip "Nice to have" from PR inline comments to reduce noise
- P3: Incremental review via .qwen/review-cache/ with rebase fallback
- P3: Report persistence to .qwen/reviews/ with timestamp filenames

Security hardening:
- PR description prompt injection defense (untrusted DATA marker)
- Base-branch rule loading prevents review-bypass injection
- Concurrency-safe temp file paths with {target} suffix
- Safe git stash handling (conditional pop)
- Argument disambiguation (integer vs URL vs file path)

Audited through 14 rounds of undirected review with 40 issues found and fixed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add tsc --incremental flag to speed up repeated type checks
- Increase type checker timeout to 120s (linters remain 60s)
- Improve cross-file grep patterns to cover .functionName, import { functionName }
- Don't truncate Critical pattern groups — list all locations
- Clarify pre-commit hook as a commit failure scenario in autofix

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…atus

Per maintainer review (tanzhenxin): default verboseMode reverted to true
to preserve existing behavior — compact mode is opt-in via Ctrl+O.

Also addresses wenshao's security concern: in compact mode, tool groups
now force-expand on Error status (in addition to existing Confirming
handling), and ToolMessage force-shows result for both Confirming and
Error statuses so users always see diffs before approval and error
details for debugging.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix filter-then-truncate ordering: capture full linter output first,
  filter to changed files, then truncate (not head before filter)
- Record informational notes for skipped checks instead of silent skip
- Agent 5: capture full build/test output, keep first 50 + last 100
  lines instead of tail-only (preserves error context)
- Fix [Needs Review] vs severity tag contradiction: use both
  [Needs Review][Suggestion] format

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix Step 1.5 intro: clarify whole-project vs per-file tool handling
  and filter-then-report approach
- Fix dedup + deterministic finding ambiguity: merged findings with any
  deterministic source are pre-confirmed and skip verification
- Fix autofix stash orphan: stop and let user handle commit failure
  instead of silently stashing (which Step 5 wouldn't pop)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The autofix step (Step 3.5) needs targeted text replacement to apply
fixes safely. Without the edit tool, only full-file rewrites via
write_file would be available, which is risky for partial fixes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix golangci-lint: use ./... (package pattern) instead of file paths
- Unify PR comment prefix format: define canonical prefixes for normal,
  auto-fixed, and low-confidence findings in the template
- Stop workflow entirely on autofix commit failure (dirty tree would
  block Step 5 branch restore)
- Accept broader .gitignore patterns like .qwen/* for cache/reviews dirs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Source field to Step 2 output schema (Agents 1-4: [review],
  Agent 5: [build]/[test]) so Step 2.5 dedup can detect pre-confirmed
- Require Agent 5 to emit [build]/[test] tags explicitly
- Use grep -F (fixed-string) instead of -E regex for cross-file search
  to avoid metacharacter issues with JS symbols like $

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After presenting findings for a PR review, append a tip:
"Tip: run /review <number> --comment to post these as PR inline comments."

This leverages the existing follow-up suggestion system — it will
read the tip in context and likely suggest the command as ghost text,
letting users discover the feature via Tab without blocking prompts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix Source vs Issue field inconsistency: deterministic findings now
  use Source field ([linter]/[typecheck]) consistently with the schema
- Add base branch ref resolution with origin/<base> fallback and
  git fetch for fresh/non-standard checkouts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When PR checkout fails or incremental review finds no new changes,
restore the environment (checkout original branch, pop stash) before
stopping. Previously these early exits left the stash orphaned.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When deduplication merges findings with different severities (e.g.,
a Critical typecheck error with a Suggestion from LLM review), the
merged finding now uses the highest severity. Deterministic severity
is treated as authoritative and cannot be downgraded.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Step 1.5 said "the diff output" (singular) but local reviews produce
two diffs (git diff + git diff --staged). Changed files list now
explicitly takes the union of both.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add {{model}} template variable support in BundledSkillLoader. When a
skill body contains {{model}}, it is replaced with the runtime model ID
from config.getModel(). Only skills that use the variable are affected.

The /review skill now appends a model attribution footer to PR review
summaries: "Reviewed by {model} via Qwen Code /review"

This enables cross-model review workflows (e.g., develop with model A,
review with model B) with accurate attribution in PR comments.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Copilot-instructions.md precedence: prefer .github/ path, do not
  load both when both exist
- Simplify getModel() call: remove unnecessary typeof guard since
  Config already defines getModel()
- Fix TS2352 type error in test: use proper mock cast pattern
- Add getModel to base mockConfig for test consistency

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rename "should use unknown when model is not available" to
"when getModel returns undefined" — the mock config does define
getModel, it just returns undefined.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
pomelo-nwu and others added 27 commits April 13, 2026 16:54
…ment (QwenLM#3207)

Add news item about:
- Daily quota reduced from 1,000 to 100 requests/day
- Free tier discontinuation on 2026-04-15
- Migration path to Alibaba Cloud Coding Plan

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
…chable (QwenLM#3181)

* fix(cli): recover from stuck bracketed-paste mode and keep Ctrl+C reachable

If bracketed-paste-start (`ESC[200~`) arrives but paste-end (`ESC[201~`)
is lost — for example on Ghostty + Sogou pinyin on macOS, which a user
reported in a working directory with only three files — `isPaste` stays
`true` forever. The order of checks inside `handleKeypress`:

  1. `key.name === 'paste-start'`  → set isPaste = true, return
  2. `key.name === 'paste-end'`    → reset + flush + return
  3. `if (isPaste) { pasteBuffer.append; return }`
  4. backslash / return handling
  5. arrow keys
  6. Ctrl+C

means that every subsequent key — **including Ctrl+C** — is appended to
the paste buffer and silently returned. The user has no keyboard escape
hatch; they must kill the process / restart the terminal.

Two layered fixes:

1. **Ctrl+C escape hatch.** Move the Ctrl+C check above the `isPaste`
   branch and clear paste state when it fires. Ctrl+C now always reaches
   the broadcast regardless of any stuck paste state.

2. **Idle timeout auto-recovery.** Add `PASTE_IDLE_TIMEOUT_MS = 1000`.
   Start the timer on paste-start, reset it on each paste content byte,
   clear it on paste-end. If the timer fires, force-flush the paste
   buffer as a regular paste event and reset `isPaste`. A
   `pasteAlreadyFlushed` flag guards against a stale paste-end event
   arriving later and broadcasting a spurious empty/image paste.

Two regression tests cover both paths:
- `Ctrl+C escapes a paste mode that never received its paste-end marker`
- `auto-recovers from a stuck paste mode via idle timeout`

Both fail on main and pass with this change. Full cli test suite:
3968 pass / 7 skipped, no regressions.

* test(cli): derive paste idle-timeout wait from PASTE_IDLE_TIMEOUT_MS

Address review feedback: the auto-recovery regression test hard-coded a
1500ms sleep instead of referencing the production constant. Import
PASTE_IDLE_TIMEOUT_MS and derive the wait as `constant + 200ms buffer`
so the test stays in sync if the production timeout is ever tuned.

* docs(cli): clarify paste state-machine comments from review feedback

Address review bot nits:
- forceFlushStuckPaste: explain why the empty-guard is asymmetric
  (isPaste/buffer can be out of sync after a Ctrl+C vs idle-timeout race)
- paste-end handler: note that pasteAlreadyFlushed=false is the reset
  for the next paste cycle
- auto-recovers test: frame it as the "automatic recovery safety net"
  counterpart to the manual Ctrl+C escape test above

Comments only, no behavioural change.
…enLM#3199)

Remove directories and files that are no longer needed for Qwen Code:

- .gcp/: Google Cloud Platform build configs (legacy from Gemini CLI)
- .aoneci/: Alibaba AoneCI workflow (replaced by GitHub Actions)
- hello/: Example extension template (not needed in repo root)
- .allstar/: Google Allstar security policy config (Google legacy artifact)

These artifacts are either obsolete or superseded by
GitHub Actions workflows and the current Dockerfile.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* refactor: merge test-utils package into core

Consolidate the standalone @qwen-code/qwen-code-test-utils package
into packages/core/src/test-utils/, eliminating the need for a
separate package that only provided createTmpDir, cleanupTmpDir,
and FileSystemStructure type.

Changes:
- Move file-system-test-helpers.ts into core/src/test-utils/
- Re-export from core's test-utils index
- Update 3 core test files to use relative imports
- Update cli useAtCompletion test to import from @qwen-code/qwen-code-core
- Remove test-utils devDependency from core and cli package.json
- Delete packages/test-utils/ directory

All affected tests pass (fileSearch, crawler, ignore, useAtCompletion).

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix: remove deleted test-utils from build order

The test-utils package was merged into core but the build script still
tried to build it separately, causing CI failures.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
)

- Change default model from qwen3.6-plus to qwen3.5-plus for both China and Global regions
- qwen3.6-plus requires Pro subscription, Lite users cannot use it
- Add description to qwen3.6-plus indicating Pro subscription requirement
- Update MAINLINE_CODER_MODEL to qwen3.5-plus for OpenAI-compatible API default

Fixes QwenLM#3037

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* ci(release): parallelize release validation

* ci(release): allow publish when tests are skipped

* ci(release): drop planning artifact from workflow PR

* ci(release): address workflow review findings

* ci(release): fix quality job bootstrap

* ci(release): fix docker test and dry-run notify flow
…QwenLM#2904)

* feat: add contextual tips system with post-response context awareness

Add a context-aware tips system that proactively shows helpful tips based
on session state. Post-response tips warn when context usage exceeds 80%
or 95%, suggesting /compress. Startup tips rotate across sessions via LRU
scheduling with cross-session persistence (~/.qwen/tip_history.json).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use value import for runtime values in useContextualTips

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address PR review feedback

- Use lastSessionTimestamp instead of totalShown for cross-session LRU
- Move getTipHistory singleton from Tips.tsx to services/tips/index.ts
- Defer TipHistory.load() when hideTips is true (no side effects)
- Use os.tmpdir() in tests for cross-platform portability
- Add proper translations for de/ja/pt/ru locale files
- Accept TipHistory | null in useContextualTips

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address Copilot review feedback

- Validate tips field type in TipHistory.load() to handle corrupted JSON
- Split approval-mode tip into platform-specific variants using ctx.platform
- Add afterEach cleanup for temp files in all test suites
- Guard useContextualTips against null tipHistory

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: import shared DEFAULT_TOKEN_LIMIT, harden tipHistory, set file permissions

- Import DEFAULT_TOKEN_LIMIT from @qwen-code/qwen-code-core instead of
  hardcoding 1_048_576 in tipRegistry.ts and useContextualTips.ts
- Add normalizeEntry() to defensively handle corrupted tip history entries
- Write tip_history.json with mode 0o600 for privacy on multi-user systems

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove unused compressionThreshold from TipContext

compressionThreshold was defined in TipContext but never used by any tip's
isRelevant check. Remove it to avoid misleading consumers into thinking
tips respect the user's compression settings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: sanitize sessionCount and getLastShown against corrupted tip history

- Validate sessionCount is finite and non-negative in TipHistory.load()
- Use normalizeEntry() in getLastShown() for corrupted lastSessionTimestamp

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add contextual tips user documentation

Add docs/users/features/tips.md covering startup tips, post-response
context warnings, tip history persistence, and the hideTips setting.
Update settings.md description and register the new page in _meta.ts.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(subagents): propagate approval mode to sub-agents

Replace hardcoded PermissionMode.Default with resolution logic:
- Permissive parent modes (yolo, auto-edit) always win
- Plan-mode parents keep sub-agents in plan mode
- Agent definitions can declare approvalMode in frontmatter
- Default fallback is auto-edit in trusted folders
- Untrusted folders block privileged mode escalation

Also maps Claude permission aliases (acceptEdits, bypassPermissions,
dontAsk) to qwen-code approval modes in the converter.

* fix(subagents): correct dontAsk mapping and add approval mode resolution tests

Map Claude's `dontAsk` to `default` instead of `auto-edit` — `dontAsk`
denies prompts (restrictive) so `default` is a closer semantic match.

Add 9 unit tests covering the full `resolveSubagentApprovalMode` decision
matrix: permissive parent override, agent-declared modes, trusted/untrusted
folder blocking, and plan-mode fallback.

* test: remove flaky InputPrompt tab-suggestion test on Windows
…wenLM#3197)

pathReader.ts hardcoded respectGitIgnore: true when filtering files for
@{path} injection (used by slash commands), ignoring the user's
context.fileFiltering.respectGitIgnore setting. This meant gitignored
files were silently dropped even when the user explicitly set the
setting to false.

Now reads the filtering options from config instead of hardcoding.

Fixes QwenLM#3142
…M#2949)

* feat(skills): add model override support via skill frontmatter

Allow skills to specify a `model` field in YAML frontmatter to override
which model is used for subsequent turns within the same agentic loop.
The override flows through ToolResult → ToolCallResponseInfo →
SendMessageOptions and naturally expires when the loop ends.

Resolves QwenLM#2052

* fix(core): only include modelOverride in response when defined

Fixes strict equality test failures in nonInteractiveToolExecutor.test.ts
where the extra undefined modelOverride field caused object mismatch.

* fix(skills): fix model override pipeline issues

- Wire up modelOverride in interactive CLI path (useGeminiStream)
- Fix inherit/no-model unable to clear a prior override by using
  'in' operator instead of truthiness checks in scheduler and CLI
- Reject empty/whitespace model strings in parseModelField()
- Extract shared parseModelField() to deduplicate skill-load and
  skill-manager parsing logic
- Propagate modelOverride through stop-hook continuation in client

* fix(skills): persist model override across turns in interactive and cron paths

The interactive path stored the skill model override in a local variable,
causing it to be lost when subsequent non-skill tool turns ran. Use a ref
to persist the override for the duration of the agentic loop, resetting on
new user messages. Also propagate modelOverride in the cron execution loop
for consistency with the main non-interactive path.

* fix(skills): preserve model override on retry and add unit tests

Retry in interactive mode was clearing modelOverrideRef, causing the
skill-selected model to silently fall back to session default. Guard
the reset so retries preserve the active override.

Add unit tests for parseModelField (edge cases, type validation) and
modelOverride propagation through the skill tool result path.
…M#3192)

* fix(core): show clear error when MCP server cwd does not exist

Validate that the configured cwd directory exists before spawning the
MCP server process. Previously, a non-existent cwd caused Node.js to
emit "spawn <cmd> ENOENT" — indistinguishable from the command binary
being missing. Now throws a descriptive error naming the server and
the missing path.

Fixes QwenLM#3163

* test(core): add test for MCP stdio transport without cwd
…wenLM#3187)

validateAuthMethod's pre-flight check only inspected OPENAI_API_KEY (and
settings.security.auth.apiKey), so credentials supplied via --openai-api-key
were rejected even though refreshAuth would have accepted them. macOS users
were unaffected because OPENAI_API_KEY is commonly exported in their shell
profile; on Linux without that env var, the CLI failed to start.

hasApiKeyForAuth now prefers the API key already resolved into
generationConfig.apiKey when a Config is provided. The unified resolver
folds CLI flags, env vars, settings, and modelProvider envKey lookups into
this single value, so validation matches runtime behavior.

Fixes QwenLM#3171
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
When ESC (or Ctrl+C) cancelled an in-progress model response, the
input buffer was being repopulated with the just-submitted prompt.
The handler unconditionally read userMessages.at(-1) and called
buffer.setText with it, surprising users who expected ESC to leave
the input clean. The previous prompt is still recoverable via Up
arrow / Ctrl+P history navigation.

Queued follow-up messages still get moved into the buffer for
editing on cancel, but now via the atomic popAllMessages helper,
and any in-progress draft the user typed is preserved by prepending
the queued text instead of clobbering it (matching the existing
popQueueIntoInput convention in InputPrompt).

Fixes QwenLM#3204
Typing `exit`, `quit`, `:q`, `:q!`, `:wq`, or `:wq!` at the prompt now
exits the CLI — same as `/quit`. This matches Claude Code behavior and
helps users on mobile (e.g. Termux) where Ctrl+C is harder to type.

Closes QwenLM#3169
…LM#3064)

* feat(subagents): add disallowedTools field to agent definitions

Add a `disallowedTools` blocklist to agent frontmatter, letting agents
specify tools they should not have access to. Supports exact tool names,
MCP server-level patterns (e.g., `mcp__slack`), and display name aliases.

Applied as a post-filter in AgentCore.prepareTools() after the existing
`tools` allowlist. Persisted through serialize/parse roundtrips.

* docs: document disallowedTools and MCP tool behavior for subagents

Add Tool Configuration section to sub-agents docs explaining:
- tools allowlist and disallowedTools blocklist
- How MCP tools follow the same allowlist/blocklist rules
- MCP server-level patterns in disallowedTools

* fix(subagents): validate disallowedTools in SubagentValidator

Reuse the existing validateTools() method to validate disallowedTools
entries at config validation time, catching non-string and empty entries
before they reach runtime.

* test: remove flaky BaseSelectionList scroll test on Windows
The agent name validation regex only permitted ASCII letters, numbers,
hyphens, and underscores, silently rejecting agents with non-ASCII names
(e.g., Chinese "项目管理"). Replace the regex with Unicode property
escapes (\p{L}\p{N}) to allow letters and numbers from any script.

Also guard the lowercase naming convention warning so it only fires when
the name contains ASCII letters, since case is meaningless for CJK
scripts.

Fixes QwenLM#3149
* feat(core): add microcompaction for idle context cleanup

Clear old tool result content from chat history when the user returns
after an idle period (default 60 min). Replaces functionResponse output
with a sentinel string for compactable tools (read_file, shell, grep,
glob, web_fetch, web_search, edit, write_file), keeping the N most
recent results intact (default 5). Runs before full compression so it
can shed tokens cheaply without an API call.

- Time-based trigger reuses lastApiCompletionTimestamp from thinking cleanup
- Per-part counting so keepRecent applies to individual tool results
  even when batched in parallel
- Preserves tool error responses (only clears successful outputs)
- Configurable via settings.json (context.microcompaction) with env var
  overrides for E2E testing
- Enabled by default

* refactor(config): unify idle cleanup settings under clearContextOnIdle

Consolidate thinking block cleanup and tool results microcompaction
config into a single `context.clearContextOnIdle` settings group:

  {
    "context": {
      "clearContextOnIdle": {
        "thinkingThresholdMinutes": 5,
        "toolResultsThresholdMinutes": 60,
        "toolResultsNumToKeep": 5
      }
    }
  }

- Use -1 on either threshold to disable that cleanup (no enabled bool)
- Remove separate `microcompaction` and `gapThresholdMinutes` settings
- Thinking cleanup: 5 min default (unchanged)
- Tool results cleanup: 60 min default
- Preserve tool error responses (only clear successful outputs)

* feat(vscode-ide-companion): add clearContextOnIdle settings configuration

- Add gapThresholdMinutes settings for thinking blocks, tool results, and retention count
- Remove deprecated gapThresholdMinutes from root settings level

This reorganizes the context clearing settings into a dedicated clearContextOnIdle object with configurable thresholds for thinking blocks and tool results.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(core): restrict microcompaction to user-initiated messages only

Move microcompactHistory() inside the UserQuery/Cron guard so model
latency during tool-call loops doesn't count as user idle time.

* docs: update settings docs for clearContextOnIdle config rename

Replace stale `context.gapThresholdMinutes` entry with the new
`context.clearContextOnIdle.*` settings group introduced in the
microcompaction feature.

* fix(core): address review comments on microcompaction PR

- Guard against NaN in toolResultsNumToKeep with Number.isFinite()
- Report effective keepRecent (after Math.max) in meta, not raw config
- Fix comment to mention cron messages alongside user messages

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
…wenLM#3217)

* docs: update quota exceeded alternatives to OpenRouter and Fireworks

- Update README.md news section to recommend OpenRouter and Fireworks
  as primary alternatives, with ModelStudio as third option
- Update retry.ts quota error message to include OpenRouter and
  Fireworks URLs for users whose OAuth quota has been exhausted

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(test): update retry test assertions to match new quota error message

* docs: update free tier quota to 100 req/day with sunset notice and alternatives

Update all references to reflect the Qwen OAuth free tier policy change:
- 1,000 → 100 requests/day across code, i18n, and docs
- Add 2026-04-15 sunset date everywhere
- Guide users to OpenRouter, Fireworks AI, or ModelStudio in docs
- Remove CHANGELOG.md

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: tanzhenxin <tanzhenxing1987@gmail.com>
… SDK API (QwenLM#2916)

* feat(cli): implement non-interactive /context output and diagnostic

- Extract collectContextData() from contextCommand.ts for shared usage.
- Register /context in ALLOWED_BUILTIN_COMMANDS_NON_INTERACTIVE.
- Extend SDK control protocol with GET_CONTEXT_USAGE request.
- Implement handleGetContextUsage in SystemController for programmatic token queries.
- Expose getContextUsage() method in the TypeScript SDK Query interface.

* fix: address review feedback and fix critical bugs in context usage feature

- Add missing `get_context_usage` route in ControlDispatcher (SDK calls would throw)
- Fix `executionMode` defaulting: use `?? 'interactive'` to match other commands
- Validate dynamic import of `collectContextData` before invoking
- Preserve original error message in handleGetContextUsage catch block
- Add ControlDispatcher test for get_context_usage routing
- Add JSDoc comment for context command in non-interactive allowlist

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: re-check abort signal after async operations in handleGetContextUsage

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add getContextUsage() to SDK TypeScript documentation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: clarify getContextUsage showDetails is a display hint, not a data filter

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: make showDetails affect response shape, add getContextUsage test

- When showDetails is false, return empty detail arrays instead of full
  data so /context and /context detail produce different payloads
- Add unit test for Query.getContextUsage() covering request payload
  and response handling

* fix: strip UI type from SDK response, sync Java SDK protocol

- Remove leaked `type: 'context_usage'` from control response payload
- Add GET_CONTEXT_USAGE to Java SDK protocol mirror (enum, interface,
  union type)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
 feat(cli): add startup performance profiler (QwenLM#3219)

  Add a lightweight startup profiler activated via QWEN_CODE_PROFILE_STARTUP=1.
  When enabled, collects performance.now() timestamps at 7 key phases in main()
  and writes a JSON report to ~/.qwen/startup-perf/. Also records
  process.uptime() at T0 to capture module loading time not covered by
  checkpoint-based measurement.

  Key design decisions:
  - Only profiles inside sandbox child process to avoid duplicate reports
  - initStartupProfiler() is idempotent (resets state on each call)
  - Filename uses report.sessionId for consistency with JSON content
  - Zero overhead when disabled (single env var check)

  Initial measurement: module loading ~1342ms (94%), main() ~85ms (6%),
  confirming barrel exports and eager dependency loading as primary
  optimization targets for QwenLM#3011.

  Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* feat(core): implement fork subagent for context sharing

- Make subagent_type optional in AgentTool
- Add forkSubagent.ts to build identical tool result prefixes
- Run fork processes in the background to preserve UX

* fix(core): fix test failures related to root execution and optional subagent_type

- Skip pathReader and edit tool permission tests when running as root
- Fix agent.test.ts to correctly mock execute call with extraHistory
- Remove unused imports in forkSubagent.ts

* fix(core): fix fork subagent bugs and add CacheSafeParams integration

Bug fixes:
- Fix AgentParams.subagent_type type: string -> string? (match schema)
- Fix undefined agentType passed to hook system (fallback to subagentConfig.name)
- Fix hook continuation missing extraHistory parameter
- Fix functionResponse missing id field (match coreToolScheduler pattern)
- Fix consecutive user messages in Gemini API (ensure history ends with model)
- Fix duplicate task_prompt when directive already in extraHistory
- Fix FORK_AGENT.systemPrompt empty string causing createChat to throw
- Fix redundant dynamic import of forkSubagent.js (merge into single import)
- Fix non-fork agent returning empty string on execution failure
- Fix misleading fork child rule referencing non-existent system prompt config
- Fix functionResponse.response key from {result:} to {output:} for consistency

CacheSafeParams integration:
- Retrieve parent's generationConfig via getCacheSafeParams() for cache sharing
- Add generationConfigOverride to CreateChatOptions and AgentHeadless.execute()
- Add toolsOverride to AgentHeadless.execute() for parent tool declarations
- Fork API requests now share byte-identical prefix with parent (DashScope cache hits)
- Graceful degradation when CacheSafeParams unavailable (first turn)

Docs:
- Add Fork Subagent section to sub-agents.md user manual
- Add fork-subagent-design.md design document

* fix(core): apply subagent tool exclusion to forked agents

Fork children were inheriting parent's cached tool declarations directly,
bypassing prepareTools() filtering and gaining access to AgentTool and
cron tools. Extract EXCLUDED_TOOLS_FOR_SUBAGENTS as a shared constant
and apply it to forkToolsOverride.

* fix(core): skip env history whenever extraHistory is provided

Previously gated on generationConfigOverride, which meant the no-cache
fallback path (CacheSafeParams unavailable) still ran getInitialChatHistory
and duplicated env bootstrap messages already present in the parent's
history. Gate on extraHistory instead so both fork paths skip env init.

* fix(core): use explicit skipEnvHistory flag for fork env handling

The previous fix gated env-init skipping on the presence of extraHistory,
but agent-interactive (arena) also passes extraHistory — its chatHistory is
env-stripped by stripStartupContext() and DOES need fresh env init for the
child's working directory. Skipping env there broke the interactive path.

Replace the implicit gate with an explicit skipEnvHistory option that only
fork sets (when extraHistory is present, since fork's history comes from
getHistory(true) and already contains env).

* fix(core): defend skipEnvHistory gate against empty extraHistory

Edge case: when the parent's rawHistory ends with a user message and has
length 1, extraHistory becomes []. The previous gate (extraHistory !==
undefined) would set skipEnvHistory: true, leaving the fork with neither
env bootstrap nor parent history. Check length > 0 so empty arrays fall
through to the normal env-init path.

* fix(core): apply skipEnvHistory to stop-hook retry execute

The second subagent.execute() call in the SubagentStop retry loop was
missing skipEnvHistory, so on retry the fork's env context would be
duplicated — same bug as the initial tanzhenxin report, just on a less
common code path.
…2984)

* feat(vscode-ide-companion): add /account for account display

* fix(account): intercept typed /account command and read session-level config

1. Handle literal /account in useMessageSubmit.ts so typing it triggers
   the account dialog instead of sending it as a chat message.
2. Pass sessionId through extMethod params and read from session config
   instead of agent-level config, so /account reflects model changes
   made via /model within the current session.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
…3246)

DashScope throttling (`Throttling.AllocationQuota`) surfaces as an
SSE `event:error` frame mid-stream with `:HTTP_STATUS/429` as a
comment and a non-numeric `code` in the payload. The existing
detection paths missed it, so subagents failed immediately with
`Failed to run subagent: id:1 event:error ...` instead of retrying.

- `getErrorStatus`: add a final fallback that parses `HTTP_STATUS/NNN`
  out of `error.message`, bounded by `\b` and the 100-599 range, so
  streamed errors where the SDK never sees a real HTTP status can
  still be classified.
- `getErrorCode`: fix three `|| null` early-returns that swallowed
  later fall-through paths when the provider code was non-numeric
  (`isApiError` top-level, `isApiError` JSON-in-message, and
  `isStructuredError`). The branches now fall through on non-numeric
  values so `.status` or the new `HTTP_STATUS/NNN` fallback can
  recover the real code.
…ow (QwenLM#3249)

* fix(vscode): limit session tab title length to prevent tab bar overflow

- Extract truncatePanelTitle() into panelTitleUtils.ts; operates on
  Unicode code points to avoid splitting surrogate pairs (e.g. emoji);
  truncates to first 50 code points + '…'
- Apply truncation uniformly in WebViewProvider for all updatePanelTitle
  messages, covering both createOrShowPanel and restorePanel paths
- Remove redundant 50-char truncation in SessionMessageHandler; panel
  title truncation is now the sole responsibility of WebViewProvider
- Align getSessionTitle() to use the same limit (50 code points + '…')
  for visual consistency between session list and tab title
- Add unit tests for truncatePanelTitle covering empty string, boundary,
  long title, and emoji surrogate-pair edge cases

Fixes QwenLM#2873

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(vscode): reuse truncatePanelTitle in getSessionTitle and fix fallback title logic

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Merges upstream main (v0.14.4) into our fork (previously at v0.4.1).
~10 major version jump with ~2800 new upstream commits.

Conflict resolution (11 files):
- Took upstream: acpAgent.ts, cli/errors.ts, edit.ts, glob.ts,
  shell-utils.ts, tools.ts
- Deleted (upstream removed): schema.ts, smart-edit.ts
- Manual merge: chatRecordingService.ts, ls.ts, paths.ts

Cleaned up fork debug logging in: HistoryReplayer.ts, Session.ts,
config.ts, sessionService.ts

Fork changes kept: bind-mount path normalization, QWEN_DATA_DIR,
is_background instruction, XML tool call suppression, callId queue fix

Fork changes dropped: schema.ts, smart-edit.ts, ACP v0.10.0 alignment,
debug logging, error display fix, shell security disabling
{iconUrl && (
<div className="relative">
<img
src={iconUrl}
this.sendToWebView({
type: 'sessionTitleUpdated',
data: {
sessionId: this.currentConversationId,
// macOS/Linux: All VSCode-like IDEs (VSCode, Cursor, Windsurf, etc.)
// are Electron-based, so we always need ELECTRON_RUN_AS_NODE=1
// to run Node.js scripts using the IDE's bundled runtime.
const quotePosix = (s: string) => `"${s.replace(/"/g, '\\"')}"`;
// On Windows, we rely on the race logic below to handle background tasks.
// We just ensure the command string is clean.
if (isWindows && shouldRunInBackground) {
finalCommand = finalCommand.trim().replace(/&+$/, '').trim();
Comment on lines +55 to +59
return str.replace(regex, (match, key) =>
context[key as keyof VariableContext] == null
? match
: (context[key as keyof VariableContext] as string),
);
Comment on lines +11 to +12
return text
.replace(/```[\s\S]*?\n([\s\S]*?)```/g, '$1')
});
} catch {
// Fallback to plain text for the failed chunk only
await this.bot.api.sendMessage(chatId, chunk.replace(/<[^>]*>/g, ''));
Comment on lines +790 to +793
proxyProcess = spawn(proxyShell, proxyShellArgs, {
stdio: ['ignore', 'pipe', 'pipe'],
detached: true,
});
buildArgs += `-f ${path.resolve(projectSandboxDockerfile)} -i ${image}`;
}
execSync(
`cd ${gcRoot} && node scripts/build_sandbox.js -s ${buildArgs}`,
// Fallback to 'bash' and let the system handle it
cachedBashPath = 'bash';
return 'bash';
}
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 15, 2026

Code Coverage Summary

Package Lines Statements Functions Branches
CLI N/A% N/A% N/A% N/A%
Core N/A% N/A% N/A% N/A%
CLI Package - Full Text Report
CLI full-text-summary.txt not found at: coverage_artifact/cli/coverage/full-text-summary.txt
Core Package - Full Text Report
Core full-text-summary.txt not found at: coverage_artifact/core/coverage/full-text-summary.txt

For detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run.

- QwenLogger.getInstance() now unconditionally returns undefined,
  preventing any events from being collected or sent to Alibaba's
  RUM endpoint (gb4w8c3ygj-default-sea.rum.aliyuncs.com)
- Change usageStatisticsEnabled default from true to false in both
  settingsSchema.ts and config.ts
- Gut updateCheck.ts to always return null, preventing npm registry
  queries for version checks (our fork is not published to npm)
- OpenTelemetry OTLP left intact (defaults to localhost:4317, requires
  explicit opt-in, useful for our own observability)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.