Commit graph

5654 commits

Author SHA1 Message Date
copilot-swe-agent[bot]
bbaa8ffc75
chore: no changes - code review requested
Agent-Logs-Url: https://github.com/QwenLM/qwen-code/sessions/38467aec-15b9-4b76-9139-0b2cfe40477a
2026-05-05 13:14:35 +00:00
yiliang114
668c006941 test(installer): isolate standalone dist fixture 2026-05-05 19:49:42 +08:00
yiliang114
b078ade587 fix(installer): avoid prerelease installer asset links 2026-05-05 19:34:46 +08:00
yiliang114
ccf83e9da7 fix(installer): address release asset review feedback 2026-05-05 18:39:04 +08:00
yiliang114
ec654dd87c feat(installer): publish release installer assets 2026-05-04 21:34:33 +08:00
yiliang114
fee51d1d91 fix(installer): harden standalone review fixes 2026-05-04 17:38:07 +08:00
yiliang114
e7e3f9077d fix(installer): simplify Windows option validation 2026-05-04 16:56:02 +08:00
yiliang114
0eb58a81a2 fix(installer): avoid Windows validation parse errors 2026-05-04 16:27:47 +08:00
yiliang114
1ca86fe8e7 fix(installer): address standalone review hardening 2026-05-04 16:03:34 +08:00
yiliang114
66dec5f5b4 ci: narrow installer debug matrix 2026-05-03 01:14:48 +08:00
yiliang114
faa9087f2d fix(installer): use robust Windows checksum hashing 2026-05-03 01:14:19 +08:00
yiliang114
69e22f9418 test(installer): preserve Windows cmd quotes 2026-05-03 00:50:18 +08:00
yiliang114
fee13e4ddf test(installer): fix Windows batch smoke quoting 2026-05-03 00:27:50 +08:00
yiliang114
a4a15e1ded test(installer): add Windows batch install smoke 2026-05-02 23:56:09 +08:00
yiliang114
2b40bad5df chore(installer): simplify standalone release review fixes 2026-05-02 23:27:25 +08:00
yiliang114
47fdfbc64d chore(installer): remove internal planning docs 2026-05-02 23:08:29 +08:00
yiliang114
472e51eb19 fix(installer): stabilize standalone script checks 2026-05-02 22:52:44 +08:00
yiliang114
571959532b chore(installer): clarify review followups 2026-05-02 21:11:50 +08:00
yiliang114
d7277a6976 fix(installer): address standalone review findings 2026-05-02 21:07:14 +08:00
yiliang114
d2e5b1bd07 fix(installer): harden standalone archive installs 2026-05-02 20:20:56 +08:00
yiliang114
eb2a9a8bef feat(installer): add standalone archive installation 2026-04-30 22:04:01 +08:00
顾盼
65a1503e13
fix(memory): use project transcript path for dream (#3722)
Some checks are pending
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
* fix(memory): use project transcript path for dream

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

* fix(memory): quote dream transcript grep path

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

* test(memory): make dream prompt quoting test portable

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-29 17:56:53 +08:00
tanzhenxin
762f603e9b
fix(core): inject reasoning_content on DeepSeek tool-call replays (#3729)
DeepSeek's thinking-mode API requires every prior assistant turn that
carried tool_calls to replay reasoning_content in subsequent requests,
or it returns HTTP 400 ("The reasoning_content in the thinking mode
must be passed back to the API"). The model can legitimately return a
tool round without any reasoning text — qwen-code then stored no
thought parts and rebuilt the next request with reasoning_content
absent, tripping the API's check.

The DeepSeek provider now normalizes outgoing assistant messages so
any turn carrying tool_calls always has reasoning_content set (empty
string when none was emitted). Other providers are unaffected.

Refs #3695
2026-04-29 16:28:29 +08:00
Shaojin Wen
7b3d36e1f3
feat(cli): wire background shells into combined Background tasks dialog (#3720)
* feat(cli): wire background shells into combined Background tasks dialog

Phase B follow-up #2: surface managed background shells in the same
overlay that already shows local subagents, so users get one unified
view instead of having to remember /tasks for shells.

- BackgroundShellRegistry: add setRegisterCallback/setStatusChangeCallback
  and requestCancel(id), mirroring BackgroundTaskRegistry's contract.
  register() also fires statusChange so subscribers see the lifecycle
  start, not just transitions.
- useBackgroundTaskView: subscribe to both registries, merge entries by
  startTime, attach a `kind` discriminator (DialogEntry union) so
  renderers can dispatch on agent vs shell.
- BackgroundTasksPill: group running counts by kind ("2 shells, 1 local
  agent"); when all entries are terminal, collapse to "N task(s) done".
- BackgroundTasksDialog: replace per-kind section header with a single
  "Background tasks" header; ListBody renders shell rows as
  "[shell] <command>"; DetailBody dispatches to AgentDetailBody (the
  original) or a new ShellDetailBody (cwd / output file / pid / exit).
- Context cancelSelected switches by kind: agents go through cancel(),
  shells through requestCancel() — only aborts, lets the spawn settle
  path record the real terminal state (mirrors task_stop in #3687).

Tests: 8 pill cases (singular/plural per kind, mixed, terminal-only),
4 dialog cases (auto-fallback on running→terminal, cancel flow,
already-terminal stays in detail, selectedIndex clamp); shell registry
gains 5 callback tests + 3 requestCancel tests.

* fix(cli): refresh detail-body agent fields between status changes

useBackgroundTaskView shallow-copies agent entries into DialogEntry so
each entry can carry a `kind` discriminator. The copy detaches
`recentActivities` from the registry: BackgroundTaskRegistry.appendActivity
mutates `entry.recentActivities = next` on the registry object and emits
`activityChange`, but the dialog's activity callback only bumps a local
counter — so the snapshot's `recentActivities` reference goes stale and
the Progress block keeps rendering the old array until the next
status-driven refresh.

Resolve `selectedEntry` against the registry on each render when the
selected entry is an agent, with `activityTick` as a useMemo dep so it
recomputes on every activity callback. Snapshot remains the source of
truth for the list (no churn on the pill / AppContainer); only the
detail body re-reads live.

Also rename the non-empty list section header from "Local agents" to
"Background tasks" to match the empty-state branch and the unified
multi-kind contents.

---------

Co-authored-by: wenshao <wenshao@U-K7F6PQY3-2157.local>
2026-04-29 16:06:36 +08:00
pomelo
3ea81a1a6f
feat(skills): add tmux-real-user-testing skill for readable TUI test logs (#3577)
Some checks are pending
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
* feat(skills): add tmux-real-user-testing skill for readable TUI test logs

Add a generic skill that uses tmux as a

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>"real user recording harness":
drive the TUI with keyboard actions and capture-pane at each step to
produce a readable, reviewable interaction timeline log.

- General-purpose design: no scenario-specific hardcoding
- Helper script with session-collision detection and eval-friendly output
- wait-for polling instead of blind sleeps, timeout dumps current pane
- Manual workflow guide with scene-design methodology

* Update .qwen/skills/tmux-real-user-testing/SKILL.md

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>

* Update .qwen/skills/tmux-real-user-testing/scripts/tmux-real-user-log.sh

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>

* fix(skills): harden tmux helper key forwarding

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

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-29 11:19:00 +08:00
Shaojin Wen
1b9e8ec45d
feat(core): wire background shells into the task_stop tool (#3687)
* feat(core): wire background shells into the task_stop tool

Phase B follow-up #1 from #3634, unblocked by #3471 (control plane) merging
in. The model can now cancel a managed background shell with the same
`task_stop` tool it uses for subagents — no more falling back to
`kill <pid>` via BashTool.

Lookup order: subagent registry first (existing behavior), then the
background shell registry as a fallback. Agent IDs follow
`<subagentName>-<suffix>` and shell IDs follow `bg_<8 hex chars>`, so the
two namespaces cannot collide in practice; the order is fixed for
determinism (a defensive test pins agent-wins-over-shell).

The shell cancel path resolves through the entry's own AbortController
(which `BackgroundShellRegistry.cancel` triggers); the child process
exit handler then settles the registry to `cancelled` and the on-disk
output file is preserved for inspection via `/tasks` or a direct `Read`.
This matches Phase B's "registry's own AbortController is the
cancellation source of truth" design without needing the in-flight
notification framework that subagents use.

Tests: 7 task-stop tests (was 4) — added cancel-shell happy path,
NOT_RUNNING for already-exited shell, and a defensive
agent-takes-precedence-on-id-collision case.

* fix(core): defer shell terminal transition until spawn handler settles

@doudouOUC noticed that the previous task_stop path called
`BackgroundShellRegistry.cancel(id, Date.now())`, which marked the entry
`cancelled` immediately. The spawn handler's settle path only records
real exit info via cancel/complete/fail when the entry is still
`running`, so the cancel-vs-exit race could permanently hide a real
completed/failed result and `/tasks` would show a terminal endTime
while the process was still draining.

Add a `requestCancel(id)` method to `BackgroundShellRegistry` that
triggers the entry's AbortController only; status stays `running` until
the settle path observes the abort and records the real terminal state.
The immediate-mark `cancel(id, endTime)` is reserved for `abortAll()` /
shutdown, where the CLI process is tearing down anyway and there is no
settle handler to wait for.

Tests updated:
- `task-stop.test.ts` cancel-shell happy path now asserts the entry
  stays `running` with `endTime` undefined post-stop, and the abort
  signal fires (the settle path's contract, not task_stop's, is the
  one that flips status).
- 3 new `requestCancel` tests in `backgroundShellRegistry.test.ts`:
  running → abort+still-running, terminal entry no-op, unknown id no-op.

---------

Co-authored-by: wenshao <wenshao@U-K7F6PQY3-2157.local>
2026-04-29 10:10:41 +08:00
pomelo
2ee014e347
fix(cli): refresh static header on model switch (#3667)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-29 07:16:26 +08:00
Ird
8896f93fe9
mcp config as cli (#1279)
* mcp config as cli

* fix: failed test cases

* updated tests to match the new api

* fix: update mcp-config tests for new API and fix type import

* mcp config type declared handler.ts

---------

Co-authored-by: Ird <irdali.durrani@fixstars.com>
Co-authored-by: mingholy.lmh <mingholy.lmh@alibaba-inc.com>
2026-04-29 07:00:33 +08:00
易良
8de1bcb279
chore(release): bump version to 0.15.3 (#3708)
Some checks failed
Qwen Code CI / CodeQL (push) Waiting to run
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
SDK Python / SDK Python (3.10) (push) Has been cancelled
SDK Python / SDK Python (3.11) (push) Has been cancelled
SDK Python / SDK Python (3.12) (push) Has been cancelled
Update all package versions from 0.15.2 to 0.15.3 across the monorepo
including root package.json, package-lock.json, and all sub-packages
(channels, cli, core, vscode-ide-companion, web-templates, webui).

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-28 21:04:52 +08:00
jinye
ba8d452ce5
fix(ci): preserve preview version overrides (#3705)
* fix(ci): preserve preview version overrides

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-28 20:26:42 +08:00
tanzhenxin
8807c02676
fix(core): set DeepSeek V4 context to 1M and output to 384K (#3693)
Some checks are pending
Qwen Code CI / CodeQL (push) Waiting to run
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
DeepSeek V4 (flash, pro) ships with a 1M context window and 384K
max output, but the generic deepseek pattern was capping it at 128K
input / 8K-64K output. Add a dedicated v4 pattern that takes
precedence over the generic deepseek fallback.

Fixes #3679
2026-04-28 16:44:20 +08:00
tanzhenxin
784b3cef66
fix(core): treat ask_user_question multiSelect as optional (#3699)
The schema advertised `default: false` but also listed the field as required,
and the validator hard-rejected calls where the model omitted it. Models read
the default annotation and reasonably skipped the field, then got the error
`Question 1: "multiSelect" must be a boolean.` and could not recover.

Make multiSelect optional in the schema and the input types, and only error
when the field is present with a non-boolean value. Existing UI consumers
already coalesce a missing value to false.

Fixes #3218
2026-04-28 16:40:26 +08:00
tanzhenxin
6763124a05
fix(cli): preserve description in subject-bearing thought chunks (#3691)
When a streamed reasoning chunk arrived with both a parsed subject (from
**Title**) and a description (the body text after \n\n in the same chunk),
the Thought event handler routed only to setThought and discarded the
description. As a result, the first body word that happened to share a
chunk with the closing ** was dropped from the persistent reasoning
display.

Treat subject-only chunks as discrete loading-indicator updates and route
all chunks carrying streamed text through the throttled buffer. The
existing flush merger preserves the subject across batched events.
2026-04-28 16:32:59 +08:00
tanzhenxin
e973dabf37
test(cli): remove flaky TUI input tests surfaced by CI history mining (#3694)
These eight tests share the same shape — stdin.write(...) followed by a
fixed setTimeout while waiting for React state to settle — and have
failed across multiple unrelated commits on slow CI runners (Windows and
Ubuntu 24.x). Mining the last 60 failed CI runs showed each one failing
on 2-10 distinct SHAs, with low fails-per-SHA — the classic signature
of a timing flake rather than a real bug.

Removed:
- AuthDialog > should trigger OpenRouter OAuth from API key options
- AuthDialog Custom API Key Wizard > navigates to protocol selection
  when Custom API Key is selected
- AuthDialog Custom API Key Wizard > navigates to base URL input after
  selecting a protocol
- AuthDialog Custom API Key Wizard > calls handleCustomApiKeySubmit on
  Enter in review view
- AuthDialog Custom API Key Wizard > shows advanced config screen after
  entering model IDs
- AuthDialog Custom API Key Wizard > passes generationConfig when
  advanced options are toggled
- InputPrompt > prompt suggestions > accepts and submits the prompt
  suggestion on Enter when the buffer is empty
- SessionPicker > Preview Mode > opens preview on Space and closes on Esc

The behaviors are still covered by adjacent tests in the same suites.
2026-04-28 16:32:48 +08:00
qwen-code-ci-bot
96116dc76f
chore(release): sdk-typescript v0.1.7 (#3688)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-04-28 14:59:13 +08:00
tanzhenxin
fd6727973b
fix(ci): use squash merge for SDK release auto-merge (#3690)
The repo disallows merge commits, so `gh pr merge --merge --auto` always
exits 1 — every release run goes red even when publish, tag, and PR
creation all succeed (e.g. v0.1.7 in run 25036315088). Switch to
`--squash` to match the repo's allowed merge methods.
2026-04-28 14:58:50 +08:00
Shaojin Wen
aac2e96ec3
feat(core): managed background shell pool with /tasks command (#3642)
Some checks are pending
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
Qwen Code CI / Lint (push) Waiting to run
* feat(core): managed background shell pool with /bashes command

Replace shell.ts's `&` fork-and-detach background path with a managed
process registry. Background shells now have observable lifecycle, captured
output, and explicit cancellation — matching the pattern used by background
subagents (#3076).

Phase B from #3634 (background task management roadmap).

What changes
- New `BackgroundShellRegistry` (services/backgroundShellRegistry.ts):
  per-process entry with status (running / completed / failed / cancelled),
  AbortController, output file path. State transitions are one-shot
  (terminal status sticks; late callbacks no-op). Mirrors the lifecycle
  shape of #3471's BackgroundTaskRegistry so the two can be unified later.
- `shell.ts` is_background path rewritten as `executeBackground`:
  - Spawns the unwrapped command (no '&', no pgrep envelope)
  - Streams stdout to `<projectDir>/tasks/<sessionId>/shell-<id>.output`
    (path layout aligns with the direction sketched in #3471 review)
  - Bridges the external abort signal into the entry's AbortController so
    a single source of truth governs cancellation
  - Returns immediately with id + output path; agent's turn isn't blocked
  - Settles the registry entry asynchronously when ShellExecutionService
    resolves: complete (clean exit) / fail (error) / cancel (aborted)
- Removes ~120 lines of dead bg-specific code from shell.ts:
  pgrep wrapping, '&' appending, Windows ampersand cleanup, Windows
  early-return path, bg PID parsing, tempFile cleanup
- New `/bashes` slash command: lists registered shells with id, status,
  runtime, command, output path. Empty state prints a friendly message.

What this PR doesn't do
- Footer pill / dialog integration — gated on #3488 landing
- task_stop / send_message integration — gated on #3471 landing
- Auto-backgrounding heuristics for long foreground bash — Phase D

Test plan
- 11 registry unit tests (state machine + idempotent terminal transitions)
- 4 background-path tests in shell.test.ts (spawn no-wrap + complete /
  fail / cancel settle paths)
- 2 /bashes command tests (empty + populated)
- Full core suite: 247 files / 6075 passed (existing tests unaffected)

* fix(core): address PR #3642 review feedback

Three [Critical] from the auto review + naming alignment with Claude Code:

- shell.ts settle: non-zero exit code or termination signal now bucket into
  `failed` instead of `completed`. The previous `if (result.error) fail else
  complete()` would misreport `false` / failed `npm test` as success because
  ShellExecutionService surfaces ordinary command failures as a non-zero
  exitCode with `error: null`. Failure reason carries the exit code or signal
  so `/tasks` shows the real cause.

- ShellExecutionService.childProcessFallback: add `streamStdout` mode that
  emits each decoded chunk through the existing onOutputEvent path. The
  default (foreground) path continues to buffer + emit the cleaned final
  blob, so existing in-line shell calls are unaffected. executeBackground
  opts in via `{ streamStdout: true }`, which is what makes the captured
  output file actually useful for long-running processes (dev servers,
  watchers) — without it the file stayed empty until the process exited.

- shell.ts test fixture: cancel-settle test was using `signal: 'SIGTERM'`
  but `ShellExecutionResult.signal` is `number | null`. TS2322 broke the
  build; switched to `signal: null`. Added a test that explicitly covers
  the new "non-zero exit → failed" path so the bucketing change has
  regression coverage.

- shell.ts comment: explicitly document why background shells force
  `shouldUseNodePty=false` (no terminal, no human; node-pty would be dead
  weight for fire-and-forget commands).

- /bashes → /tasks (alias bashes), description "List and manage background
  tasks" — matches Claude Code's command name. Currently lists shells only;
  will surface other task kinds (subagents, monitor) as those registries
  land via #3471 / #3488.

* fix(core): address PR #3642 second-round review feedback

- shellExecutionService streaming: drop stdout/stderr buffer + outputChunks
  accumulation in streaming mode. Each decoded chunk goes straight to
  onOutputEvent and is GC-eligible immediately. Long-running background
  commands (dev servers, watchers) no longer accumulate unbounded memory
  proportional to total output. Buffered (foreground) mode is unchanged.

- shell.ts executeBackground: stripAnsi each chunk before writing to the
  output file. Dev servers / build tools spam color codes and cursor-move
  sequences that would render as garbage in the file the agent reads.

- bashesCommand: command description "List and manage" → "List background
  tasks" — current implementation only supports listing, cancellation
  follows when the unified task_stop tool from #3471 is wired in. Replace
  the hand-rolled formatRuntime helper with the shared formatDuration
  utility (uses hideTrailingZeros for parity with the previous output).

- backgroundShellRegistry: add a comment documenting the lack of an
  eviction policy as a known limitation. LRU / age-based / capped-size
  eviction (and on-disk output rotation) is left as a follow-up alongside
  the broader output-file lifecycle story.

* fix(core): address PR #3642 third-round review feedback

- shell.ts executeBackground: add 'error' listener on the output write
  stream. fs.createWriteStream surfaces write failures (disk full,
  permission, fs going away) as 'error' events; without a listener Node
  treats it as an uncaught exception and kills the entire CLI session.
  Log + drop is the sane default — the registry still settles via
  resultPromise so /tasks shows the right terminal status.

- shell.ts executeBackground: store the abort handler reference and
  removeEventListener in the settle callback. Background shells outlive
  the turn signal; the dangling listener was keeping `entryAc` (and
  transitively `outputStream`) reachable until the turn signal itself was
  GC'd, which for long sessions would never happen.

- shell.test.ts: extend the createWriteStream mock with an `on` stub so
  the new error-listener wiring doesn't crash the test suite.

* refactor(cli): drop /bashes alias and rename file to tasksCommand

Per follow-up review: the slash command should be exclusively /tasks.
Removes the `bashes` altName, renames `bashesCommand{,.test}.ts` →
`tasksCommand{,.test}.ts`, renames the exported binding `bashesCommand`
→ `tasksCommand`, and cleans up the remaining `/bashes` references in
backgroundShellRegistry.ts comments. No behavior change beyond the
alias removal.

* refactor(cli): finish tasksCommand rename — apply content changes

The previous commit (03c8503c8) only captured the file rename via
`git mv`; the export name change (`bashesCommand` → `tasksCommand`),
the removal of `altNames: ['bashes']`, the import update in
BuiltinCommandLoader, and the `/bashes` → `/tasks` comments in
backgroundShellRegistry.ts were unstaged when that commit landed.
Squash candidate before merge.

* fix(core): address PR #3642 fourth-round review feedback

Four reviewer concerns from @wenshao + @doudouOUC:

- [Critical] Config.shutdown() now also calls
  `backgroundShellRegistry.abortAll()`. Previously only the subagent
  registry was aborted, so a managed background shell could outlive the
  CLI process and orphan its child. Symmetric with how
  `BackgroundTaskRegistry.abortAll()` is wired in.

- [P1] shell.ts executeBackground strips a trailing `&` from the command
  before spawn. The managed path is itself the backgrounding mechanism;
  forwarding `node server.js &` verbatim made bash exit immediately while
  the real child outlived the wrapper, causing the registry to settle as
  `completed` while the shell was still running and chunked output to
  land on a closed stream. Strip + warn.

- [P2] Output file moves under `storage.getProjectTempDir()` (specifically
  `<projectTempDir>/background-shells/<sessionId>/shell-<id>.output`).
  `ReadFileTool` already auto-allows the project temp dir, so the LLM
  can `Read` the captured output without bouncing off a permission
  prompt — important because background-agent contexts can't surface
  interactive prompts.

- [P2] Background shells are no longer killed when the current turn's
  AbortSignal fires. Forwarding the turn signal into the entry's
  AbortController meant a Ctrl+C on the turn would also terminate
  intentionally backgrounded dev servers / watchers, contradicting the
  independent-lifecycle promise. Cancellation now flows only through
  `entryAc` (driven by future `task_stop` integration via #3471).

Tests:
- New `abortAll` registry tests cover running / mixed / empty cases.
- `runs background commands as managed pool entries` test stops asserting
  the wrapper-vs-entry signal identity since they're now structurally
  separate (no turn-to-entry forwarding).
- New `does not forward the turn signal into the background shell` test
  pins the new behavior.
- New `strips trailing & from the spawned command` test pins the strip.
- Removed the cancel-via-outer-signal settle test — that path no longer
  exists; cancellation is exercised end-to-end via the registry's own
  `cancel` and `abortAll` tests in `backgroundShellRegistry.test.ts`.

* fix(core): tighten trailing & strip — narrow regex + ReDoS-safe

Two reviewer concerns on the same line of #3642 round 4:

- [Critical CodeQL] `\s*&+\s*$` is a polynomial-time regex on
  uncontrolled input (long all-`&` strings backtrack quadratically).
- [P2 doudouOUC] `&+` is too greedy: it also rewrites `npm run dev &&`
  into `npm run dev` (breaks logical AND syntax) and `echo foo \&` into
  `echo foo \` (eats the escaped literal). Only the bare bash background
  operator should be stripped.

Replace the regex with a small linear-time helper
`stripTrailingBackgroundAmp` that explicitly checks for the three
"don't touch" cases (`&&`, `\&`, no trailing `&`). Plain `endsWith` /
`slice` — no regex backtracking, and the intent reads off the page.

Tests:
- Existing strip-trailing-`&` test still passes.
- New `does not strip a trailing &&` test pins the logical-AND case.
- New `does not strip an escaped trailing \\&` test pins the escape case.

* fix(core): keep binary-detection sniff in streaming mode

@doudouOUC noted that `streamStdout` shortcut returned before the
binary-sniff path, so a background command emitting binary bytes
(`cat /bin/ls`, image dump, etc.) would be text-decoded and appended
to the task output file unbounded.

Restructure handleOutput so the sniff-and-cutover logic runs in both
modes:

- Both modes accumulate up to MAX_SNIFF_SIZE for the binary check.
  The accumulator is bounded; once the threshold is reached, it stops
  growing in streaming mode (dropped on binary detection / left
  inert on text confirmation) and continues to accumulate in buffered
  mode (existing foreground behavior).
- Streaming mode emits 'binary_detected' as soon as `isBinary` trips
  so the consumer can stop writing the output file. Up to ~4KB of
  bytes may have been emitted as text chunks before detection — this
  is bounded and acceptable; the unbounded write is the pathology
  reviewers flagged.
- Streaming text mode still emits each decoded chunk immediately and
  does not accumulate stdout/stderr strings, so long-running text
  streams remain GC-friendly.
- Buffered (foreground) behavior is unchanged — the sniff accumulator
  is the same path the existing tests cover.

Tests: 50 shellExecutionService + 11 backgroundShellRegistry + 57
shell.test.ts all pass; no regressions.

* fix(core): tighten streaming sniff bound + Windows rmSync flake

Two unrelated reds on the latest CI run:

1. [P1 doudouOUC] Streaming sniff buffer leaks on small chunks.
   The previous fix recomputed `sniffedBytes` from
   `Buffer.concat(outputChunks.slice(0, 20)).length` on every chunk —
   pinned to the first 20 chunks. If those total under MAX_SNIFF_SIZE
   (line-sized stdout, e.g. dev-server logs) the byte count never grew,
   the sniff branch stayed open forever, and `outputChunks` accumulated
   every later chunk — exactly the leak `streamStdout` was meant to
   prevent.

   Track sniffed bytes by running sum (`sniffedBytes += data.length`)
   so the bound is genuine. When sniff confirms text in streaming mode,
   drop the accumulator immediately so subsequent chunks fall through
   the streaming emit path without ever touching it.

2. file-exporters.test.ts afterEach `fs.rmSync` flaked on Windows
   (ENOTEMPTY: directory not empty). The exporter's underlying write
   stream hasn't always released its handle by the time `rmSync` runs.
   Pass `maxRetries: 5, retryDelay: 50` so the cleanup retries through
   the brief Windows handle-release window instead of failing the test
   on a CI quirk.

---------

Co-authored-by: wenshao <wenshao@U-K7F6PQY3-2157.local>
2026-04-28 11:06:50 +08:00
tanzhenxin
03c88b7308
feat(cli): background-agent UI — pill, combined dialog, detail view (#3488)
* feat(cli): background-task UI — pill, combined dialog, detail view

Adds the user-facing surface for background tasks on top of the
model-facing agent control primitives merged in #3471. A dedicated
pill in the footer summarises running tasks, ↓ focuses it, and Enter
opens a combined dialog listing every task with a detail view that
shows the original prompt, live stats, and a rolling progress feed
of recent tool invocations.

Also renames BackgroundAgent* to BackgroundTask* for consistency with
the user-facing terminology and the task_* tool family.

* chore: trigger CI
2026-04-28 10:57:59 +08:00
Fu Yuchen
d09c19c0c5
fix(core,cli): stop stripping reasoning on switch and resume paths (#3682) 2026-04-28 09:22:17 +08:00
jinye
4ac9ec07c3
fix(cli): recognize OpenAI-compatible providers in qwen auth status (#3623)
* fix(cli): recognize OpenAI-compatible providers in `qwen auth status`

Previously `qwen auth status` treated all `selectedType=openai` setups
as Coding Plan, checking only `BAILIAN_CODING_PLAN_API_KEY`. Users who
configured generic OpenAI-compatible providers (e.g. Xunfei, DeepSeek,
Ollama) via `modelProviders.openai` saw a misleading "Alibaba Cloud
Coding Plan (Incomplete)" even though their provider worked correctly.

Split the USE_OPENAI branch into two paths:
- Coding Plan: detected by `codingPlan.region` or `CODING_PLAN_ENV_KEY`
- Generic OpenAI-compatible: checks API key from modelProviders envKey,
  OPENAI_API_KEY, or settings.security.auth.apiKey; displays provider
  info including model name and base URL.

Closes #3612

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

* fix(cli): improve Coding Plan detection and align API key check semantics

Address review feedback:

1. Detect Coding Plan via isCodingPlanConfig(baseUrl, envKey) on the
   active modelProviders entry instead of checking BAILIAN_CODING_PLAN_API_KEY
   env var presence. A stale env key from a previous setup no longer
   misclassifies a generic OpenAI-compatible provider as Coding Plan.

2. When modelProviders entry has an explicit envKey, only check that key
   without falling back to OPENAI_API_KEY or settings.security.auth.apiKey.
   This mirrors hasApiKeyForAuth() semantics in auth.ts, preventing
   status from reporting "configured" when the actual provider key is
   missing.

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

* fix(cli): fix TS2367 type error in displayRegion comparison

`detectedCodingPlanRegion` is `CodingPlanRegion | false`, so
`!== true` comparison is invalid. Simplify to truthiness check.

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

* fix(cli): refine model fallback and Coding Plan key detection

- Only fall back to models[0] when model.name is unset; when set but
  not matching any provider entry, treat as unmanaged to avoid binding
  status to an unrelated provider's envKey/baseUrl.
- Simplify hasCodingPlanKey to only check CODING_PLAN_ENV_KEY, not
  activeModelConfig.envKey, preventing a generic provider key from
  being mistaken as Coding Plan credentials when codingPlan.region
  is stale.

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

* fix(cli): prioritize active model config over stale codingPlan.region

When activeModelConfig exists, trust isCodingPlanConfig() result over
potentially stale codingPlan.region from a previous setup. This prevents
a user who switched from Coding Plan to a generic provider from still
seeing "Alibaba Cloud Coding Plan" in auth status.

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

* fix(cli): avoid stale Coding Plan fallback in auth status

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

---------

Co-authored-by: jinye.djy <jinye.djy@alibaba-inc.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-28 09:06:09 +08:00
JerryLee
1befabe586
fix(core): handle shell line continuations in command splitting (#3600)
Some checks are pending
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
Fixes #3158.

`splitCommands()` previously handled backslash escapes before newline/operator splitting, so a chained command like `cd project && \\<LF>git add ...` produced segments starting with a backslash-newline pair, leaving the extracted command root empty and bypassing per-command permission checks for the chained sub-command.

Treat `\\` followed by LF as a removed line continuation, while keeping `\\` followed by CRLF as a normal command separator (bash escapes only \r; the trailing \n still ends the command). This preserves the contract that every chained sub-command is visible to permission parsing and prevents an attacker from hiding a command behind a pseudo-continuation like `echo SAFE \\<CR><LF>rm -rf /`.

Adds regression coverage for both the LF-continuation positive case and the escaped-CRLF safety case.
2026-04-27 23:31:37 +08:00
Bramha.dev
414b3304cd
fix(core): split tool-result media into follow-up user message for strict OpenAI compat (#3617)
Fixes #3616.

Adds opt-in `splitToolMedia` flag (default false). When enabled, media parts (image / audio / video / file) returned by MCP tool calls are split into a follow-up `role: "user"` message instead of being embedded in the `role: "tool"` message. Required for strict OpenAI-compatible servers (e.g., LM Studio) that reject non-text content on tool messages with HTTP 400 "Invalid 'messages' in payload".

Media from parallel tool responses is accumulated and emitted as a single follow-up user message after all tool messages, preserving OpenAI's contiguity requirement for tool responses.

Default behavior is unchanged for permissive providers.
2026-04-27 23:01:02 +08:00
qqqys
8a278767ed
fix(core): recover from }{ glued records on session JSONL load (#3606) (#3656) 2026-04-27 22:50:17 +08:00
jinye
f0e8601982
fix(cli): add API Key option to qwen auth interactive menu (#3624)
* fix(cli): add "API Key" option to `qwen auth` interactive menu

The `qwen auth` CLI command only showed 2 options (Coding Plan, Qwen OAuth),
while the interactive `/auth` dialog showed 3 (Coding Plan, API Key, Qwen OAuth).
Users following the README instructions to configure OpenRouter/Fireworks via
`qwen auth` had no API Key entry point.

- Add "API Key" option to the `runInteractiveAuth` menu with two sub-paths:
  "Alibaba Cloud ModelStudio Standard API Key" (guided flow) and
  "Custom API Key" (prints docs link)
- Add `qwen auth api-key` yargs subcommand for direct access
- Extract `createMinimalArgv` / `loadAuthConfig` helpers to eliminate duplicated
  CliArgs boilerplate
- Extract `promptForInput` to share raw-mode stdin logic between `promptForKey`
  and `promptForModelIds`
- Improve `showAuthStatus` to distinguish Coding Plan, Standard API Key, and
  generic OpenAI-compatible configurations
- Align menu labels and descriptions with the interactive `/auth` dialog

Closes #3413

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

* docs: add `qwen auth api-key` to auth subcommand tables

Update documentation to reflect the new `qwen auth api-key` subcommand:
- auth.md: add to subcommands table, examples, and interactive menu display
- commands.md: add to CLI Auth Subcommands table
- quickstart.md: add to quick-reference command table

* fix(cli): restore incomplete Coding Plan warning in showAuthStatus

When selectedType is USE_OPENAI and Coding Plan metadata exists but
the API key is missing, show the incomplete warning instead of falling
through to the generic "OpenAI-compatible" status.

* refactor(cli): use endpoint constants in region selector and fix status formatting

- Use ALIBABA_STANDARD_API_KEY_ENDPOINTS constants for region
  descriptions instead of hardcoded URLs
- Restore trailing newline in showAuthStatus "no auth" command list
  for consistent spacing

* fix(cli): determine active auth method from model config in showAuthStatus

Previously showAuthStatus checked which env keys exist to determine
the auth method, causing false reports when users switch providers
(e.g., Coding Plan key still present after switching to Standard API Key).

Now it inspects the active model's provider config (baseUrl/envKey) to
determine the actual method, and validates the corresponding key exists:
- Coding Plan: check via isCodingPlanConfig + CODING_PLAN_ENV_KEY
- Standard API Key: check via DASHSCOPE_STANDARD_API_KEY_ENV_KEY + endpoints
- Generic OpenAI-compatible: check if the model's envKey is set

Also clear stale Coding Plan metadata (codingPlan.region/version and
process.env) when switching to Standard API Key.

* fix(cli): add legacy fallback in showAuthStatus and clear persisted Coding Plan env

- When no active model config is found (legacy setups without
  modelProviders), fall back to env key / metadata checks for
  Coding Plan status detection. Fixes CI test failures.
- When activeConfig exists but has no envKey, report incomplete
  status instead of false positive "Configured".
- Clear persisted env.BAILIAN_CODING_PLAN_API_KEY from settings
  when switching to Standard API Key, not just process.env.

* fix(cli): also remove Coding Plan model entries when switching to Standard API Key

When switching to Standard API Key, filter out existing Coding Plan
model entries from modelProviders.openai in addition to old Standard
entries. Previously these were preserved but their credential source
(BAILIAN_CODING_PLAN_API_KEY) was cleared, leaving broken model
entries visible in /model.

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-27 22:01:47 +08:00
tanzhenxin
581c74d76e
feat(core): model-facing agent control (task_stop, send_message, per-agent transcript) (#3471)
* feat(core): task_stop, send_message, and live transcripts for background agents

Add two new tools (task_stop, send_message) and a plain-text transcript
writer so the parent model can control and observe long-running background
subagents. The agent lifecycle is also tightened so every background launch
is paired with exactly one terminal task_notification — including under
cancellation races and pathological tools that swallow AbortSignal.

* feat(core): switch background-agent transcript to ChatRecord JSONL

Replaces the plain-text per-agent transcript writer with one that emits
the same ChatRecord schema as the main session log. Each background
subagent now writes to <projectDir>/subagents/<sessionId>/agent-<id>.jsonl
with a .meta.json sidecar; records carry agentId/agentName/agentColor
and isSidechain so a single parser can reconstruct the parent session
and its subagents as one tree.

A new EXTERNAL_MESSAGE event is emitted when send_message injections are
drained inside agent-core, so each follow-up message is persisted as a
user-role record and the transcript remains a complete view of the run.

read_file's auto-allow set is extended to <projectDir>/subagents/ so the
model can keep polling the transcript path advertised in the launch
response and the completion notification XML.

* feat(core): emit full background agent result in task-notification

Drop the 2000-char truncation on <result> in emitNotification. The agent
output is already a model-generated summary; truncating it strips content
the parent agent specifically asked for. The <output-file> path is still
included for anyone who wants the structured transcript.

* test(cli): add hasUnfinalizedAgents/abortAll to registry mock

The nonInteractiveCli test stub was missing two methods that the
runtime now calls when draining background agents on shutdown,
causing every runNonInteractive test to fail with TypeError.

* test(core): use path.join in agent-transcript path helper assertions

Hard-coded forward slashes in expected paths failed on Windows where
path.join produces backslashes.

* fix(core): thread nested agent identity into sidecar metadata

* feat(agent): improve background agent launch tool result

- Add internal-ID qualifier, anti-duplication clause, and large-file reading strategy to the launch tool-result template, ported from claw-code.
- Rename transcript_file to output_file for consistency.
- Reference read_file and run_shell_command via ToolNames constants instead of raw strings.

* fix(core): rename send_message target field

* fix(core): exclude task_stop and send_message from subagents

These are parent-side control-plane tools for managing background
subagents. Subagents themselves cannot launch background agents
(AGENT is already excluded), so they have no agent IDs to manage
natively, and exposing the tools only widens the surface for
cross-agent interference if an ID leaks via prompt or transcript.

* refactor(core): generalize task_stop and send_message framing to "task"

Today every BackgroundTaskRegistry entry is a subagent, but the
control-plane tools were named and described as agent-only. Generalize
so future task kinds (e.g. backgrounded shells, monitors) can share
the same registry without a model-facing rename.

- task_stop / send_message: descriptions, error messages, and ToolError
  enum values drop the "agent" framing in favor of "task".
- send_message: parameter to -> task_id, matching task_stop for a
  uniform control-plane contract.
- BackgroundTaskRegistry.hasUnfinalizedAgents -> hasUnfinalizedTasks.
- agent-transcript: add a TODO at getSubagentSessionDir flagging that
  <projectDir>/subagents/ is part of the model-facing contract via
  <output-file>; future kinds should migrate to <projectDir>/tasks/.
- Add a test for complete()-after-finalizeCancelled no-op to pin the
  one-notification-per-task SDK contract through the post-notified
  re-entry path.
2026-04-27 20:36:38 +08:00
dreamWB
596b5a3fd7
feat(vscode): add tab dot indicator and notification system (#3106) (#3661)
* feat(vscode): add tab dot indicator and notification system (#3106)

Add a three-layer notification system for the VSCode extension:

- Tab dot indicator: orange (task completed) / blue (needs user input,
  higher priority). Appears when the tab is not the active editor.
- VS Code notification bubble with a "Show" button that focuses the
  Qwen Code panel when clicked.
- Platform notification sound (macOS: Glass.aiff via afplay,
  Windows: SystemSounds.Asterisk, Linux: canberra-gtk-play / paplay).

Notification rules (aligned with CLI useAttentionNotifications):
- Task completed: notify when user is not watching the panel AND task
  took >= 20 seconds. idleNotificationSent guard prevents duplicates
  across multi-turn endTurn events.
- Permission / askUserQuestion: notify immediately when user is not
  watching (no duration threshold). attentionNotified guard prevents
  duplicates per request.
- "Watching" = VS Code window focused AND panel visible.

New settings: qwen-code.dotIndicator (boolean) and
qwen-code.notifications (boolean), both default to true.

Also refactors three duplicate onDidReceiveMessage handlers into a
shared handleCommonWebviewMessage method.

* fix(vscode): address PR review — improve JSDoc, add sidebar no-op comment, add paplay error logging
2026-04-27 20:28:16 +08:00
dreamWB
00ba2ef600
feat(cli): add OSC notification support for iTerm2, Kitty, and Ghostty (#3562)
* feat(cli): add OSC notification support for iTerm2, Kitty, and Ghostty

Replace the basic terminal bell with protocol-specific OSC notifications
that display rich system notifications with title and message content.

- Add terminal detection (TERM → TERM_PROGRAM → KITTY_WINDOW_ID fallback)
- Add OSC 9 (iTerm2), OSC 99 (Kitty 3-step), OSC 777 (Ghostty/cmux)
- Add tmux/screen DCS passthrough with ESC byte doubling
- Add notification routing service with auto terminal detection
- Add dynamic tool name in approval notifications
- Refactor useTerminalProgress to use shared osc.ts module
- 42 unit tests covering all detection paths and protocols

Closes #2528

* fix(cli): address PR review feedback for OSC notification system

- Reorder terminal detection: TERM_PROGRAM first, TERM fallback, KITTY_WINDOW_ID last
- Add TTY guard in sendNotification to skip OSC when stdout is piped
- Add sanitizeOscPayload to prevent control character injection in OSC payloads
- Replace hand-rolled PendingToolCall with imported TrackedToolCall type
- Extract awaiting tool name via useMemo to avoid useEffect re-fires
- Unify brand name to "Qwen Code" in all notification messages
- Remove unused TerminalWriteContext/Provider/Hook exports
- Fix docstring: OSC_PREFIX 9;4 → OSC 9;4

* fix(cli): base64-encode Kitty OSC 99 payloads and fix screen ST conflict

- Add encodeKittyPayload() to base64-encode UTF-8 text for Kitty OSC 99
- oscKittyNotify() now uses e=1 flag with base64-encoded title/body
- osc() falls back to BEL terminator for Kitty inside GNU screen to
  avoid ST conflicting with the DCS passthrough wrapper's own ST
2026-04-27 20:28:07 +08:00
Shaojin Wen
f420742831
feat(cli,core): LLM-generated summary labels for tool-call batches (#3538)
Some checks are pending
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
* feat(cli,core): generate tool-use summaries for compact mode

After each tool batch completes, fire a parallel fast-model call to
generate a short git-commit-subject-style label summarizing what the
batch accomplished (e.g. "Read txt files", "Searched in auth/"). In
compact mode the label replaces the generic "Tool × N" header so N
parallel tool calls collapse to a single semantic row.

The fast-model call (~1s) runs fire-and-forget, overlapped with the
next turn's API stream, so there is no perceived latency. Missing
fast model, aborted turns, and model failures all degrade silently to
the existing rendering.

The summary is also emitted as a `tool_use_summary` history entry
with `precedingToolUseIds`, keeping the shape compatible with SDK
clients that want to render collapsed tool views on their own.

Gated by `experimental.emitToolUseSummaries` (default on). Can be
overridden per-session with `QWEN_CODE_EMIT_TOOL_USE_SUMMARIES=0|1`.

The system prompt and truncation rules (300 chars per tool field,
200 chars of trailing assistant text as intent prefix) match the
existing behavior seen in other tools that emit the same message
type, so SDK consumers see a consistent shape across clients.

* fix(core): bound cleanSummary quote-strip regex to avoid ReDoS

CodeQL js/polynomial-redos flagged the /^["'`]+|["'`]+$/g pattern in
cleanSummary because its input comes from an LLM (treated as
uncontrolled). The original regex is anchored and linear in practice,
but tightening the quantifier to {1,10} both satisfies the static
check and caps engine work on pathological model output with a long
run of quotes. Ten opening/closing quotes is well past anything a real
label would produce.

* fix(cli): render tool_use_summary inline so full mode also shows the label

The summary was only visible in compact mode because the full-mode
ToolGroupMessage ignored the compactLabel prop. Compact mode got away
with this because mergeCompactToolGroups triggers refreshStatic(),
which re-renders the merged tool_group with its newly-looked-up
label. Full mode has no such refresh path, so when the fast-model
call resolves *after* the tool_group has been committed to the
append-only <Static>, there is no way to retroactively decorate it.

Switch to rendering `tool_use_summary` as its own inline history item
(a single dim `● <label>` line). New items append cleanly to <Static>,
so the summary flows in naturally once the fast-model call resolves.
Compact mode still replaces the merged tool_group header with the
label and hides the standalone summary line via the `compactMode`
guard.

With this, the feature works under the default `ui.compactMode: false`
— not just the opt-in compact view.

* docs: tool-use-summaries feature guide, settings entry, and design doc

Three new docs matching the existing fast-model feature docs layout:

- docs/users/features/tool-use-summaries.md — user-facing guide
  covering full + compact rendering, configuration (settings + env),
  failure modes, cost, and cross-links to followup-suggestions.

- docs/users/configuration/settings.md — register the new
  experimental.emitToolUseSummaries setting next to the other
  fast-model-driven UI settings.

- docs/design/tool-use-summary/tool-use-summary-design.md — deep dive
  matching the compact-mode-design.md competitive-analysis style.
  Documents the Claude Code port (prompt, truncation, timing, gate),
  the deviations (settings layer, default on, cleanSummary, dual
  render paths), and the Ink <Static> append-only rationale that
  drove the inline full-mode render vs header-replacement split.

* docs: add Recommended pairing section to tool-use-summaries

Full-mode rendering of the summary works, but for small same-type
batches (Read × 3 and similar) the label visibly restates what the
tool lines already show. Pairing with ui.compactMode: true folds
the whole batch into a single labeled row, which is the cleanest
transcript shape once the label is available.

Adds a dedicated section showing the paired settings.json snippet
and explicitly calling out when each mode wins (and when to turn
the feature off instead).

* fix: address review feedback on tool-use summary generation

Addresses multiple issues from @chiga0's review:

Blocking — compact-mode label invisible for single-batch turns.
mergeCompactToolGroups's adjacency-only gating left a trailing
tool_use_summary in the merged result whenever there was no second
batch to merge across. That pushed mergedHistory.length lock-step
with history.length and MainContent's refreshStatic heuristic
(currMLen <= prevMLen) never fired, so Ink's append-only <Static>
never repainted the tool_group with its newly-looked-up label.
Drop tool_use_summary items unconditionally now; gemini_thought
still survives to avoid unnecessary repaints. New tests cover
the single-batch case and the summary-before-user-message case.

Blocking — stale summary appears after Ctrl+C on the next turn.
summarySignal captured the CURRENT turn's AbortController, but the
summary resolves during the NEXT turn's streaming window. The next
turn's submitQuery allocates a fresh controller, so the captured
signal was never aborted — Ctrl+C during the new turn used to let
the previous turn's summary land in the transcript seconds later.
Fix: dedicated per-batch AbortController tracked in a ref set,
aborted eagerly from cancelOngoingRequest; resolve-time check reads
the live abort state and turnCancelledRef.

High — summarizer input pollution.
geminiTools contained error/cancelled tools; retry-loop warnings
and "Cancelled by user" strings were feeding the fast model.
cleanSummary can only reject error-shaped output, not prevent the
model from hallucinating a plausible label from bad input (the PR's
own tmux screenshot showed "Read txt files · 5 tools" where 4 of
the 5 were prior-retry failures). Filter to status === 'success'
before building the prompt; skip the call entirely if nothing's
left.

High — unstable label on merged groups.
getCompactLabel iterated all callIds and returned the first hit,
so asynchronous resolution order made the header visibly flip
from SB to SA when batch A resolved after batch B. Lock onto
item.tools[0].callId to keep stable "leading batch governs"
semantics.

High — force-expanded groups in compact mode had no label at all.
Compact mode routes non-force-expand groups through
CompactToolGroupDisplay (consumes compactLabel) and force-expand
groups through the full ToolGroupMessage (ignores compactLabel);
the standalone ● line was gated on !compactMode, creating a dead
zone — exactly the diagnostically valuable case. MainContent now
computes absorbedCallIds (which groups actually consume the
header replacement) and passes summaryAbsorbed to
HistoryItemDisplay; force-expand groups in compact mode get the
standalone line as the label's only path to the screen.

Medium — cleanSummary robustness.
Extend quote-strip to Unicode curly + CJK corner brackets; strip
markdown emphasis (**bold**, _italic_); broaden refusal-prefix
rejection to curly-apostrophe "I can't", Chinese "我无法 / 我不能 /
抱歉 / 无法", and "Failed to / Sorry, / Request failed". 7 new
cleanSummary tests cover the added cases.

Low — concurrent-rendering safety.
Move historyRef.current = history from render phase into
useLayoutEffect so bailed renders can't leave a dropped value.

Low — CompactToolGroupDisplay readability.
Extract renderSummaryHeader / renderDefaultHeader helpers and
document the toolCalls.length > 1 count-suffix guard so a future
"fix" to >= 1 doesn't reintroduce "Read config.json · 1 tools".

Docs — add Scope & Lifecycle section to tool-use-summaries.md
covering (1) one generation per batch shared by both modes,
(2) no backfill on toggle / session resume, (3) main-agent batches
only with the Task-tool clarification.

* fix: address second-round review feedback on tool-use summaries

Critical — force-expand groups lost their summary entirely.
Previous round's "drop tool_use_summary unconditionally" merge fix
also stripped summaries for force-expanded groups, defeating the
exact case (errors, confirmations, focused shell) where the
standalone ● label is the label's only path to the screen. The
merge function now takes an absorbedCallIds set: summaries whose
preceding callIds are all absorbed by a compact tool_group header
are dropped (so refreshStatic still fires), but force-expanded
summaries pass through to be rendered standalone by
HistoryItemDisplay. MainContent computes absorbedCallIds from raw
history and passes it in. New tests cover both the absorbed-drop
and the force-expand-preserve cases plus the empty-set default
for callers that don't compute absorption.

Suggestion — late-arriving summaries could land out of order.
A slow fast-model call could resolve after the next turn's
content was committed, planting the ● label between later items
in full mode. The resolve callback now captures the first batch
callId, locates the corresponding tool_group at resolve time,
and drops the summary if a newer tool_group has already appeared
in history. New test exercises this with a manually-resolved
fast-model promise.

Suggestion — truncateJson allocated full JSON for large strings.
A 10MB ReadFile result was being JSON.stringify'd in full only to
be sliced down to 300 chars. Added preTruncate that walks the
value (depth-bounded to 4) and slices string leaves to maxLength
before serialization. Tests verify the input never reaches its
full pre-cap form.

Suggestion — settings description over-claimed SDK emission.
The description said summaries are emitted to SDK clients as a
tool_use_summary message; the SDK plumbing isn't actually wired
in this PR (the factory is exported for follow-up). Updated
settings.json description and regenerated the vscode schema to
state CLI-only scope explicitly.

Suggestion — fastModel data-boundary not documented.
When fastModel uses a different provider than the main session
model, tool inputs/outputs cross a new auth boundary that users
may not expect. Added "Data flow & privacy" section to the user
feature doc spelling out: same-provider fast model = no scope
change; different-provider = strictly larger sharing scope; two
escape hatches (same-provider fast model OR feature off).
Code-level mitigation (metadata-only mode) deferred.
2026-04-27 16:54:10 +08:00
pomelo
7fe853a782
Feat/openrouter auth (#3576)
* feat(cli): add OpenRouter auth flow

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

* feat(cli): add OpenRouter model management UI

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

* fix(cli): align OpenRouter OAuth fallback session

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

* refactor(cli): unify OpenRouter model setup flow

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

* feat(auth): update OAuth description with provider examples and i18n support

- Updated OAuth option description to include provider examples (OpenRouter, ModelScope)
- Added internationalization support for new description text
- Updated all language files (en, zh, de, fr, ja, pt, ru) with translations

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

* docs: simplify OpenRouter design docs

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

* test(auth): fix OpenRouter OAuth mock typing

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

* test(auth): sync AuthDialog tests with new three-option main menu layout

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

Update assertions that referenced removed 'Qwen OAuth' and 'OpenRouter' options in the main/API-key views to match the refactored OAUTH / CODING_PLAN / API_KEY structure.

* fix(i18n): add missing zh-TW translation for browser-based auth key

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

zh-TW.js was generated from main's en.js which had already removed this key, but the PR re-adds it in en.js. Sync zh-TW with the new translation.

* feat(cli): Improve custom auth wizard with step indicators and cleaner advanced config (#3607)

* feat(cli): Add custom API key auth wizard with 6-step setup flow

Replace the documentation-only

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>"Custom API Key" screen with an
in-terminal wizard: Protocol select → Base URL input → API Key input →
Model ID input → JSON review → Save.

- Add 5 new ViewLevels and render functions in AuthDialog
- Implement utility functions: generateCustomApiKeyEnvKey (normalization),
  normalizeCustomModelIds (split/trim/dedupe), maskApiKey (display)
- Implement handleCustomApiKeySubmit in useAuth with backup, env key
  generation, modelProviders merge, auth refresh, and user feedback
- Wire handler through UIActionsContext and AppContainer
- Add 18 unit tests for utilities, 4 wizard flow integration tests

* feat(cli): Improve custom auth wizard with step indicators and cleaner advanced config

- Add step indicators (Step 1/6 · Protocol) to each wizard screen
- Remove redundant Protocol/Endpoint context from each step for focus
- Redesign advanced config: add descriptions to thinking/modality toggles
- Remove max tokens option; keep only thinking and modality settings
- Add ↑↓ arrow navigation with Space toggle and Enter to continue
- Generation config flows through review JSON and final submit

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

* test: Fix Windows CI failures in fileUtils and AuthDialog tests

- fileUtils.test.ts: Mock node:child_process execFile to prevent
  pdftotext spawn that times out on Windows (ENOENT, 5s timeout)
- AuthDialog.test.tsx: Add char-by-char typeText() helper to work
  around Node 24.x + ink TextInput compatibility issue on Windows

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

* fix(cli): Reset advanced wizard state and use JSON.stringify for settings preview

- Reset advancedThinkingEnabled, advancedModalityEnabled, and
  focusedConfigIndex when re-entering custom wizard to prevent
  state leakage between configurations
- Replace hand-rolled JSON string concatenation with
  JSON.stringify for settings.json preview to properly escape
  special characters in model IDs and base URLs

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

---------

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

* fix(cli): harden OpenRouter OAuth callback handling

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

* test(cli): stabilize OpenRouter state mismatch test

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

* test(cli): stabilize custom auth wizard navigation

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-27 14:47:44 +08:00
jinye
96bc874197
chore(gitignore): add .codex directory to gitignore (#3665)
🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)

Co-authored-by: jinye.djy <jinye.djy@alibaba-inc.com>
2026-04-27 14:38:56 +08:00