mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-05 23:42:03 +00:00
4513 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4cd9f0cbe4
|
feat(core): add shared permission flow for tool execution unification (#3723)
* docs: scaffold branch for #3247 tool execution unification Placeholder commit to establish the branch for PR creation. Actual refactoring will be done in subsequent commits. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(core): add shared permission flow for tool execution unification This addresses #3247 by consolidating duplicated tool execution behavior across Interactive, Non-Interactive, and ACP modes behind shared execution utilities. - Add permissionFlow.ts: shared L3→L4 permission evaluation logic - Add permissionFlow.test.ts: comprehensive test coverage (17 tests) - Export from index.ts for use across all execution modes Why: Permission handling logic was duplicated in CoreToolScheduler and Session.runTool(). This shared module ensures consistent behavior across all modes and provides a single source of truth for future fixes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(e2e): add bundle step to E2E workflow and fix canUseTool test - Add 'npm run bundle' to E2E workflow so dist/cli.js exists for SDK tests - Fix 'should handle control responses when stdin closes before replies' test: - Use helper.getPath() for absolute file path - Make prompt explicitly invoke write_file tool - Remove inputStreamDonePromise timeout that caused false failures - Add q.endInput() to signal stdin done - Assert canUseTool was called and file content is updated * fix(core): wire evaluatePermissionFlow() and address PR review feedback Address review feedback on PR #3723: - Wire evaluatePermissionFlow() in coreToolScheduler.ts (both call sites) - Wire evaluatePermissionFlow() in Session.ts (ACP mode) - Delete TOOL_EXECUTION_UNIFICATION.md (had literal \n artifacts) - Add PermissionFlowPermission union type for stronger typing - Document the 'default' permission state in docstring - Use needsConfirmation/isPlanModeBlocked/isAutoEditApproved helpers --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
0b7a569ac7
|
fix(cli): honor proxy setting (#3753)
Some checks failed
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
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
* fix(cli): honor proxy setting * fix(cli): apply settings proxy to channel start * test(cli): cover channel start settings proxy --------- Co-authored-by: cyphercodes <cyphercodes@users.noreply.github.com> |
||
|
|
6efcf2b877
|
feat(core): add FileReadCache and short-circuit unchanged Reads (#3717)
* feat(core): add FileReadCache and short-circuit unchanged Reads
Track Read / Edit / WriteFile operations per session in a new
FileReadCache, keyed by (dev, ino) so symlinks, hardlinks, and
case-variant paths collapse to one entry. ReadFile consults the cache
on entry: when a full Read of a text file is repeated against an
unchanged inode (mtime+size match, no intervening recordWrite), it
returns a short placeholder instead of re-emitting the file content.
Range-scoped Reads, non-text payloads, and post-write reads always
fall through to the full pipeline.
The cache is a one-instance-per-Config field, which gives subagents an
empty cache automatically. Edit / WriteFile do not consume it yet — a
follow-up will wire prior-read enforcement onto the same cache.
* fix(core): refine FileReadCache contract per PR review feedback
Three changes addressing review feedback on PR #3717:
1. Truncated reads no longer arm the placeholder. A "full" Read whose
output got truncated (line cap or character cap) means the model
only saw the head of the file; returning `file_unchanged` next call
would falsely imply "you've already seen everything", so we keep
such entries non-cacheable and let the next call re-emit the
truncated window.
2. Add a Config-level escape hatch (`fileReadCacheDisabled`, default
false). When true, ReadFile bypasses both the fast-path lookup and
the post-read record so behaviour matches the pre-cache build
byte-for-byte. Intended for sessions that may undergo context
compaction or transcript transformation, where the placeholder's
"you saw the content earlier in this conversation" assumption
becomes unreliable.
3. The `unchangedResult` placeholder now explicitly warns about three
distinct retrieval failures: context compaction, subagent transcript
transformation, and external mutation (shell / MCP / other process).
The previous wording only covered the third.
Also adds a `READ_FILE_CACHE` debug logger that emits `hit` / `miss`
on every full-Read cache consultation, so cache-hit rate can be
observed locally without committing to a full telemetry pipeline.
* fix(core): clear FileReadCache on startNewSession
The file-read cache backs ReadFile's `file_unchanged` placeholder,
whose correctness depends on the model having seen the prior full
read earlier in the *current* conversation. `/clear` and session
resume both go through `startNewSession()`, which previously left
cache entries from the outgoing session in place.
Result: a follow-up full Read of an unchanged file in the new
session could return the placeholder despite the new conversation
never having received the file contents, leaving the model to
reason about content it cannot retrieve.
Calls `this.fileReadCache.clear()` from `startNewSession()` and
adds a regression test asserting the cache is empty after a session
restart.
Reported by `pomelo-nwu` on PR #3717.
* fix(core): tighten FileReadCache contract per 3rd review pass
Six issues raised by the 3rd review on PR #3717, all addressed:
1. Subagent cache isolation (was the most critical bug). Every
subagent / scoped-agent / fork path constructs its Config via
`Object.create(parent)`, which does not run instance field
initializers. The child therefore resolved `fileReadCache` through
the prototype chain to the parent's instance — so a subagent's
ReadFile would return the file_unchanged placeholder for files
the subagent's own transcript had never received. Fixed centrally
in `getFileReadCache()` with a lazy own-property check, so every
`Object.create(Config)` site (6 of them today) automatically gets
an isolated cache without each site needing to remember to
override the field. New regression tests assert (a) `Object.create`
children get a distinct cache and (b) repeated calls return the
same instance.
2. Edit / WriteFile now call `cache.recordWrite(absPath, postWriteStats)`
on the success path. Without this, low-resolution mtime filesystems
(FAT/exFAT, NFS attribute caches, same-millisecond rewrites on
POSIX) would leave the cache reporting `fresh` after an edit and
ReadFile would serve the pre-edit placeholder. Best-effort: a
stat failure here is non-fatal (the next Read will re-stat).
3. `tryCompressChat` (in `core/client.ts`) now clears the cache after
`startChat(newHistory)` succeeds. Compaction rewrites the prompt
history so prior full-Read tool results may no longer be in the
model's context, but the cache previously kept claiming "the
model has seen this file in this conversation."
4. ReadFile auto-memory paths skip the fast-path entirely. Auto-memory
files (AGENTS.md and the auto-memory root) get a per-read
`<system-reminder>` freshness note in the slow path; returning the
placeholder would silently drop that staleness signal. These files
are small; re-emitting them is cheap.
5. The cache's recorded fingerprint is now the post-read stat, not
the pre-read one. processSingleFileContent does its own internal
stat between the pre-read stat and the bytes that land in
`result.llmContent`; if the file mutated in that window, the old
code would record a fingerprint that did not correspond to the
bytes actually emitted. A subsequent Read whose stat happened to
match the recorded fingerprint would then serve a placeholder
pointing at content the model never saw.
6. The empty `catch` around the pre-read stat now logs `stat-failed`
with `err.code` so oncall can distinguish a transient stat failure
from a genuine cache miss in the debug stream. One-line change,
no behaviour difference.
Reported by `pomelo-nwu` on PR #3717.
* test(core): mock getFileReadCache in client.test.ts
CI flagged 5 tryCompressChat tests as TypeError after the cache.clear()
hook was added in
|
||
|
|
3f0b47172a
|
chore(release): v0.15.6 (#3766)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
6c71b6b09c
|
chore(core): drop tool token usage tracking (#3727)
The `tool_token_count` field was sourced from `toolUsePromptTokenCount` on the GenAI usage metadata, but none of the providers we adapt (OpenAI/DashScope, Anthropic) populate it, and Google's Gemini API only emits it for built-in server-side tools that qwen-code does not use. The metric was therefore always zero in practice, so the dedicated counter, telemetry field, UI row, and supporting plumbing are removed end-to-end (telemetry types, OTEL counter type, UI aggregation, model stats display, qwen-logger payload, VS Code session schema, and docs). |
||
|
|
23e76ff26d
|
fix(vscode-companion): fill slash commands into input on Enter instead of auto-submitting (#3618)
* fix(vscode-companion): fill slash commands into input on Enter instead of auto-submitting (#1990) Previously, selecting any slash command from the VSCode completion menu via Enter would immediately send it to the agent, giving users no chance to append arguments. This was especially problematic for skills and custom commands that accept parameters. Changes: - Commands that accept input (skills, commands with completion) now fill into the input box on Enter, letting users type arguments before submitting - No-arg built-in commands (/clear, /doctor, etc.) still auto-submit on Enter for convenience - Tab always fills without submitting (unchanged) - Client-side commands (/auth, /account, /model) still execute immediately (unchanged) The distinction is driven by the ACP `input` field: Session.ts now sets `input: { hint }` for commands that accept arguments (non-BUILT_IN kind or commands with completion functions), and `input: null` for the rest. Also fixes: - /auth + /login unified handling in useMessageSubmit.ts - authCancelled message now clears waiting state (prevents input lockup) - Stale /login comment updated to /auth in WebViewProvider.ts Resolves #1990 * fix(acp): derive input field from argumentHint and subCommands, not just kind+completion The previous logic only checked `kind !== BUILT_IN || completion != null` to decide whether a command accepts arguments. This caused built-in commands like /bug, /context, /export, /language, and /stats to be marked as no-input (auto-submit on Enter), even though they accept meaningful arguments or have subcommands. Now a command is considered to accept input when any of: - it is not a BUILT_IN command - it has a completion function - it declares an argumentHint - it has subCommands Also adds argumentHint to /bug since it accepts a description but has neither completion nor subCommands. * fix(vscode-companion): strip U+200B from completion insertion path The contentEditable input uses U+200B as a height placeholder. When selecting a completion item, the raw textContent was used directly for computing trigger position and building the new text, which could preserve the hidden character and produce text like "\u200B/commit" that downstream slash-command handling may not recognize. Now strip zero-width spaces from the text before computing cursor position and trigger offsets, and adjust the cursor for any removed characters so the final inserted text is placeholder-free. * fix(vscode-companion): add stripZeroWidthSpaces to @qwen-code/webui mock in App.test.tsx The test mock for @qwen-code/webui was missing the newly imported stripZeroWidthSpaces function, causing 4 test failures in CI. |
||
|
|
49e462c021
|
fix(lsp): 修复 LSP 文档、isPathSafe 限制,并提升 LSP 工具调用率 (#3615)
* fix(docs): correct outdated and inaccurate LSP documentation
- Remove reference to non-existent `packages/cli/LSP_DEBUGGING_GUIDE.md`
- Remove reference to unimplemented `/lsp status` slash command
- Replace incorrect `DEBUG=lsp*` env var with actual debug log location
(`~/.qwen/debug/` session files with `[LSP]` tag)
- Remove external Claude Code documentation links (`code.claude.com`)
- Document `isPathSafe` constraint: absolute paths outside workspace
are blocked, users must add server binary directory to PATH
- Add practical troubleshooting: `ps aux | grep <server>` to check
if the server process is actually running
- Add clangd-specific guidance: `--background-index`, `compile_commands.json`
location, and `--compile-commands-dir` usage
- Simplify trust documentation (remove vague "configure in settings")
* fix(lsp): allow absolute paths in LSP server command configuration
Previously, `isPathSafe` rejected any command containing a path
separator that resolved outside the workspace directory. This blocked
legitimate use cases where users specify absolute paths to language
server binaries (e.g. `/usr/bin/clangd`, `/opt/tools/jdtls/bin/jdtls`).
The fix allows:
- Bare command names resolved via PATH (unchanged)
- Absolute paths (explicit user intent, already gated by trust checks)
- Relative paths within the workspace (unchanged)
Only relative paths that traverse outside the workspace (e.g.
`../../malicious-binary`) are still blocked.
Closes: server silently fails to start when users configure absolute
paths in `.lsp.json`, with only a debug log warning visible.
* feat(lsp): inject LSP priority instruction into system prompt when enabled
The model was not using the LSP tool because the system prompt's
"Tool Usage" section never mentioned it. The tool description alone
("ALWAYS use LSP as the PRIMARY tool") was insufficient — models
follow system prompt instructions more reliably than tool descriptions.
Changes:
- getCoreSystemPrompt() accepts `options.lspEnabled` parameter
- When LSP is enabled, injects an instruction in the Tool Usage section
telling the model to ALWAYS use the LSP tool FIRST for code
intelligence queries (definitions, references, hover, symbols, etc.)
instead of falling back to grep/readfile
- Updated client.ts to pass config.isLspEnabled() to the prompt builder
- Updated test mocks and snapshots
* feat(lsp): add symbolName parameter for position-free LSP queries
The model avoided calling LSP for findReferences, hover, etc. because
these operations required filePath + line + character which the user
rarely provides. The model would read files directly instead.
Changes:
- Add `symbolName` optional parameter to LspTool
- When symbolName is provided without line/character, auto-resolve
the symbol's position via workspaceSymbol before executing the
actual operation (findReferences, hover, goToImplementation, etc.)
- Update tool description with examples showing symbolName usage
- Move LSP priority instruction to top of system prompt for visibility
- Add debug logging for LSP prompt injection
This enables natural queries like:
{operation: "findReferences", symbolName: "Calculator"}
{operation: "hover", symbolName: "addShape"}
without requiring the user to know exact file positions.
* feat(lsp): add LSP reminder to grep/readfile tool descriptions
When LSP is enabled, the model often chose grep or readfile instead
of LSP for code intelligence queries. Now the competing tools'
descriptions include a note reminding the model to use the LSP tool
for definitions, references, symbols, hover, diagnostics, etc.
This "push-pull" approach:
- System prompt pushes toward LSP (top-level priority instruction)
- Grep/ReadFile descriptions pull away from code intelligence usage
* fix(docs): align LSP doc with isPathSafe change — absolute paths now supported
The doc still said "absolute paths outside the workspace are not
supported" but the code was changed to allow them. Updated all
three places (Required Fields table, Troubleshooting, Debugging)
to reflect that absolute paths are now accepted.
* fix(lsp): improve symbol-based tool resolution
* fix(lsp): normalize display paths across platforms
* fix(lsp): narrow docs and path safety changes
* fix(lsp): add edge-case tests for isPathSafe and fix Chinese comment
- Add test for intermediate path traversal (./a/../../../etc/passwd)
- Add test for forward-slash relative paths (tools/clangd)
- Replace Chinese JSDoc with English on requestUserConsent
* fix(lsp): rename requestUserConsent to checkWorkspaceTrust
The method only checks workspace trust level and does not actually
prompt the user for consent. Rename the method and update the JSDoc
and call-site log message to accurately reflect the behavior.
|
||
|
|
f771acb353
|
fix(cli): persist directory add entries (#3752)
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
* fix(cli): persist directory add entries * fix(cli): persist accepted workspace directories * fix(cli): handle existing workspace directories --------- Co-authored-by: cyphercodes <cyphercodes@users.noreply.github.com> |
||
|
|
2f1b52d3d3
|
fix(core): preserve reasoning_content in rewind, compression, and merge paths (#3579) (#3737)
* fix(core): preserve reasoning_content in rewind, compression, and merge paths (#3579) * chore(core): remove dead stripThoughtsFromHistory methods (#3579) * revert(pr): remove redundant reasoning merge per review feedback (#3737) Per tanzhenxin's review: the compressed ack is plain text without tool_calls so the thought-part injection is unnecessary, and the converter reasoning merge is redundant given #3729's canonical ensureReasoningContentOnToolCalls in the deepseek provider. Both paths are now handled at the request boundary, not in history transformation. |
||
|
|
b2ab751087
|
fix(cli): correct model precedence — argv > settings > auth env vars (#3645)
* fix(cli): correct OPENAI_MODEL precedence without breaking /model selection Fixes model precedence regression from #3567 (reverted in #3633): - argv.model > settings.model.name > OPENAI_MODEL > QWEN_MODEL - settings.model.name wins over OPENAI_MODEL when it matches a provider - OPENAI_MODEL only used as fallback when no explicit model is configured - Added tests proving both paths: settings wins, and OPENAI_MODEL fallback works Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(cli): separate model selection from provider lookup to prevent env override The previous implementation iterated through candidates [argv.model, settings.model.name, OPENAI_MODEL, QWEN_MODEL] and picked the first matching provider. This caused settings.model.name to be overridden by OPENAI_MODEL when the former didn't match any provider. Fix by: 1. First resolve target model using strict precedence 2. Only look up provider for that specific model 3. Filter OPENAI_MODEL/QWEN_MODEL from env when model was resolved from settings or argv, preventing the core resolver from picking up these env vars Also fixes Edge Case 5 test (was testing buggy behavior) and adds integration test verifying settings.model.name wins over OPENAI_MODEL. * fix(types): remove unused type annotation from mock The mockImplementation used ModelConfigSourcesInput type which wasn't properly resolved. Remove the type annotation to fix TypeScript and ESLint errors. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * trigger CI * chore: trigger clean CI build * fix(test): make mock compatible with CI type checking The mockImplementation was causing TS2345 in CI because the return type didn't match ModelConfigResolutionResult. Fixed by using optional chaining and removing type annotations that caused CI build failures. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(test): make mock compatible with CI type checking The mock of resolveModelConfig returned sources as { model: string } instead of { model: ConfigSource }, causing a type error in CI only (where strictBuild is enabled). Use proper ConfigSource objects. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(test): update mock to match reviewer suggestion Use proper ConfigSource objects with path/envKey details as suggested in the review, matching what resolveModelConfig actually returns. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * test(cli): add regression tests for model precedence Adds [Regression] tests that guard against the original bug where OPENAI_MODEL incorrectly overrode settings.model.name. Tests cover: - settings.model.name precedence over OPENAI_MODEL - OPENAI_MODEL used when settings.model.name not set - argv.model overriding both settings and env - QWEN_MODEL as fallback when OPENAI_MODEL not set - Non-OpenAI auth ignoring OPENAI_MODEL Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(cli): address reviewer feedback on model precedence PR - Add missing assertion in Non-OpenAI auth test to verify OPENAI_MODEL is filtered from env passed to resolveModelConfig - Clean up modelProvider lookup comment to clarify the old bug is fixed Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(cli): address review feedback on model precedence PR - Sanitize OPENAI_MODEL/QWEN_MODEL in beforeEach to prevent flaky tests - Remove stray "// trigger rebuild" comment - Add AUTH_ENV_MODEL_VARS mapping for all auth types (not just OpenAI) - Fix filteredEnv logic to strip ALL model env vars when model not from env - Use sourceEnvVar tracking to only keep the env var that was actually used Fixes the blocking test failure when OPENAI_MODEL is set in shell env. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(cli): fix test assertion for filtered env, add source-based filtering comments --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: Mistral Vibe <vibe@mistral.ai> |
||
|
|
da2936336b
|
fix(core): replay DeepSeek reasoning_content on all assistant turns (#3747)
Extend the DeepSeek reasoning_content normalization (introduced in #3729) to assistant turns without tool_calls. The DeepSeek API rejects follow-up requests in thinking mode whenever any prior assistant turn omits reasoning_content, not just turns that carried tool_calls. |
||
|
|
9861114ff3
|
fix(cli): keep sticky todo panel compact (#3647)
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
* fix(cli): keep sticky todo panel compact * fix(cli): stabilize sticky todo redraws * fix(cli): address sticky todo review feedback * fix(cli): size sticky todo number column correctly * fix(cli): address sticky todo review feedback |
||
|
|
cae09279fa
|
fix(cli): bound SubAgent display by visual height to prevent flicker (#3721)
* fix(cli): bound SubAgent display by visual height to prevent flicker
The SubAgent runtime display used hard-coded MAX_TASK_PROMPT_LINES=5 and
MAX_TOOL_CALLS=5 plus character-length truncation (`length > 80`). On narrow
terminals the soft-wrapped content overflowed the available height as the
tool-call list grew, forcing Ink to clear and redraw on every update.
Pull AgentExecutionDisplay onto the same visual-height/visual-width slicing
pattern that ToolMessage and ConversationMessages already use:
- Add `sliceTextByVisualHeight` to textUtils — counts soft wraps as visual
rows, supports top/bottom overflow direction.
- AgentExecutionDisplay now derives maxTaskPromptLines / maxToolCalls from
the assigned `availableHeight` and uses `truncateToVisualWidth` (CJK +
emoji safe) instead of substring(0, 80). Compact mode is unchanged.
- Drop the 300 ms debounced `refreshStatic` AppContainer fired on every
terminalWidth change — that was a flicker source on resize and the
static area no longer needs the refresh.
Tests:
- textUtils.test.ts covers undefined maxHeight, top/bottom overflow, and
soft-wrap counting.
- AgentExecutionDisplay.test.tsx asserts the height-bounded render keeps
the prompt + tool list inside the assigned rows.
- AppContainer.test.tsx asserts width-only changes no longer clear the
terminal.
* test(tui): add SubAgent flicker regression script and ANSI counter
Two reusable tools for measuring TUI flicker:
- `scripts/measure-flicker.mjs` — standalone Node script that counts the
ANSI escape sequences which betray flicker (clearTerminalPair, clearScreen,
eraseLine, cursorUp) inside any recorded raw stream (`script` log,
`tmux pipe-pane` output, custom PTY capture). Supports baseline diff mode.
- `integration-tests/terminal-capture/subagent-flicker-regression.ts` —
end-to-end ratchet that boots a mock OpenAI server, drives a real qwen
process through an `agent` tool dispatch + 5 `read_file` SubAgent rounds,
then reads PTY bytes and asserts ANSI-redraw counts stay below configured
ceilings. Mirrors PR #43f128b20's resize-clear-regression pattern.
Reference numbers (60-col / 18-row terminal, fixed build):
clearTerminalPair=5, clearScreen=10, eraseLine=440, cursorUp=132
The ratchet defaults to 10/20 ceilings — roughly 2× steady state — so
regressions like reverting sliceTextByVisualHeight or restoring the
width-driven refreshStatic trip the build.
Implementation notes captured in the script's docstring:
- Strips HTTP_PROXY family env vars (NO_PROXY isn't honored by undici,
so corp proxy would otherwise hijack the loopback request).
- Drops `--bare` (bare mode hard-codes the registered tool set and
rejects the `agent` tool); HOME is sandboxed to a temp dir instead.
- Mock server speaks SSE because the CLI requests stream:true.
* fix(cli): address inline review on SubAgent flicker fix
Three issues from inline review on PR #3721:
1. **availableHeight as total budget (Critical).** The previous formula
only constrained prompt + tool-call height, not the surrounding
header / section labels / gaps / footer. Default and verbose mode
could still overrun the parent-provided budget. Subtract a fixed-row
overhead (10 rows running, 18 completed) before computing
`maxTaskPromptLines` / `maxToolCalls`. Add unit tests that assert the
rendered frame line-count stays within `availableHeight` for both
running and completed states.
2. **Ratchet that actually distinguishes fix from no-fix.** The previous
`clearTerminalPair` / `clearScreen` ceilings passed for both fixed
and unfixed builds. Add an `eraseLine` upper bound (default 460) —
that's the metric whose drop reflects the in-place-update efficiency
the visual-height fix delivers (no-fix observed 469, with-fix 434).
Refresh docstring with the current numbers and a coverage map that
honestly states what this ratchet does and does not exercise.
3. **Keypress scope.** `useKeypress` was active on every mounted
`AgentExecutionDisplay`, including completed/historical instances in
chat history — Ctrl+E / Ctrl+F would toggle them all in lock-step
and cause large scrollback reflows. Gate `isActive` on
`data.status === 'running'`. Test mock now also honors
`{ isActive }` so the new "completed displays ignore Ctrl+E"
regression is enforceable.
* fix(cli): address round-2 inline review on SubAgent flicker
Three follow-up issues from inline review on PR #3721:
1. **sliceTextByVisualHeight reservedRows early-return (Critical).**
The early return compared `visualLineCount <= targetMaxHeight` and
ignored `reservedRows`, so a caller asking us to keep one row free
for a footer could still receive the full input back with
`hiddenLinesCount: 0` even though only `targetMaxHeight - reservedRows`
content rows were actually available. Compare against
`visibleContentHeight` instead and add a regression test for the
`'a\nb\nc' / 3 / reservedRows: 1` case the reviewer flagged.
2. **Footer hint and rendered prompt now share one slicing result
(Suggestion).** Previously `hasMoreLines` looked at
`data.taskPrompt.split('\n').length` (hard newlines only), but the
prompt body was already truncated by `sliceTextByVisualHeight` (which
counts soft wraps). A long single-line prompt could be visually
truncated without the footer ever surfacing the "ctrl+f to show
more" hint. Lift the slice into the parent component and feed both
the rendered `TaskPromptSection` and the footer's `hasMoreLines`
from the same `hiddenLinesCount`.
3. **Running → completed transition test (Critical).** The previous
"completed displays ignore Ctrl+E" test rendered already-completed
data, so `useKeypress` was inactive from the start and Ctrl+E was a
no-op trivially. It missed the real path: a running subagent gets
expanded, then completes while preserving the expanded
`displayMode` — which is exactly when the completed-state budget
has to hold the layout. Replace the test with a `rerender`-based
one that runs the full transition, asserts the completed expanded
frame stays within `availableHeight`, and asserts the post-transition
Ctrl+E is a no-op. Bumped `COMPLETED_FIXED_OVERHEAD` from 18 to 22
to accommodate the ExecutionSummary + ToolUsage block accounting
that the new transition test exposed.
* fix(cli): gate SubAgent useKeypress on isFocused for parallel runs
Per @yiliang114's review on PR #3721 — `data.status === 'running'` alone
fixes the historical/scrollback case but two SubAgents running in parallel
both stay `running`, so a single Ctrl+E / Ctrl+F still toggles them in
lock-step and the dual reflow brings back the flicker the gating was meant
to prevent. The component already receives `isFocused` from ToolMessage
(via SubagentExecutionRenderer) for the inline confirmation prompt — reuse
it on the keypress hook:
isActive: data.status === 'running' && isFocused
Adds a regression test that renders a running SubAgent with
`isFocused={false}` and asserts Ctrl+E is a no-op (frame unchanged).
---------
Co-authored-by: wenshao <wenshao@U-K7F6PQY3-2157.local>
|
||
|
|
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> |
||
|
|
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
|
||
|
|
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> |
||
|
|
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> |
||
|
|
2ee014e347
|
fix(cli): refresh static header on model switch (#3667)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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 |
||
|
|
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 |
||
|
|
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. |
||
|
|
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. |
||
|
|
96116dc76f
|
chore(release): sdk-typescript v0.1.7 (#3688)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
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 (
|
||
|
|
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 |
||
|
|
d09c19c0c5
|
fix(core,cli): stop stripping reasoning on switch and resume paths (#3682) | ||
|
|
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> |
||
|
|
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. |
||
|
|
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. |
||
|
|
8a278767ed
|
fix(core): recover from }{ glued records on session JSONL load (#3606) (#3656)
|
||
|
|
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> |
||
|
|
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. |
||
|
|
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 |
||
|
|
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 |
||
|
|
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.
|
||
|
|
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> |
||
|
|
ccb9857a5c
|
refactor(config): dedupe QWEN_CODE_API_TIMEOUT_MS env override logic (#3653)
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
Extract duplicated timeout env override block into a shared helper applyTimeoutEnvOverride(), used by both resolveModelConfig() and resolveQwenOAuthConfig(). Preserves precedence: modelProvider > env > settings > default. Adds [Regression] and [Additional] tests guarding against the original OAuth-path bug and covering edge cases. |
||
|
|
534ca986eb
|
feat(cli): add argument-hint support for slash commands (#3593)
Adds argument-hint support across the slash command pipeline. Skill and command authors specify an argument-hint field in markdown frontmatter, which renders as inline ghost text when the user has typed the command name but not yet provided arguments. Pipeline: - Skill parsing: SkillConfig.argumentHint parsed from SKILL.md frontmatter - Command loaders: propagated through SkillCommandLoader, BundledSkillLoader, FileCommandLoader, command-factory - UI: useCommandCompletion shows hint as ghost text with showCursorBeforeText layout; InputPrompt separates display text from Tab-accept text - ACP: passed as input.hint per spec - Bundled skills (batch, loop, qc-helper, review) get hints Hint is excluded from completion menu labels to keep the dropdown clean and disappears as soon as the user starts typing arguments. |
||
|
|
3b0b6c052b
|
feat(cli): add API preconnect to reduce first-call latency (#3318)
Fire a fire-and-forget HEAD request early in startup to warm the TCP+TLS connection. Subsequent SDK calls share an undici dispatcher with preconnect, reusing the warmed connection to save 100-200ms on the first request. Skip conditions: - NODE_EXTRA_CA_CERTS set (enterprise TLS inspection) - Sandbox mode (process-restart context) - Non-default baseUrl (mTLS / private deployment) - Non-Node runtimes (Bun) Disable via QWEN_CODE_DISABLE_PRECONNECT=1. Closes #3223 |
||
|
|
70127b5cd8
|
fix(config): support QWEN_CODE_API_TIMEOUT_MS across OAuth and non-OAuth paths (#3629)
* feat(config): support API timeout env override Adds support for QWEN_CODE_API_TIMEOUT_MS as an environment override for model generation timeout. Qwen Code already supports timeout configuration via: settings.model.generationConfig.timeout This change introduces an env-based override for users running slow local/OpenAI-compatible backends where editing config is less convenient. Precedence: modelProvider > env var > settings > default (120000ms) Behavior: - Valid positive env values override configured timeout - Invalid values are ignored - Default behavior remains unchanged (applied in buildClient()) Note: The 5-minute timeout reported in #1045 originally came from undici's default bodyTimeout, which is now disabled (bodyTimeout:0). The modelConfigResolver default is 120000ms (2 minutes). Includes unit tests covering precedence and validation. Closes #1045 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * test(core): add edge-case tests for QWEN_CODE_API_TIMEOUT_MS Covers: large timeout values, whitespace-padded env values, negative env values, and reinforces provider > env > settings precedence. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(config): support QWEN_CODE_API_TIMEOUT_MS override Adds support for QWEN_CODE_API_TIMEOUT_MS as an environment override for model generation timeout. Closes #13 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
310eb88fba
|
fix(cli): guard gradient rendering without colors (#3640)
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
|
||
|
|
04afc610ea
|
fix(vscode-companion): slash command completion not triggering after message submit (#3609)
* fix(vscode-companion): slash command completion not triggering after message submit After submitting a message, the input field is cleared with a zero-width space (\u200B) to maintain contentEditable height. When the user then types "/", the DOM content becomes "\u200B/" and the trigger character lands at position 1 instead of 0. The word boundary check only recognized regular space and newline, so the zero-width space was rejected as an invalid boundary — preventing the completion popup from appearing. Add \u200B to the valid word boundary characters so "/" and "@" triggers work correctly after message submission without requiring an extra backspace. Closes #3592 * refactor(webui): extract zero-width space placeholder into shared constant Replace scattered `\u200B` magic strings with a shared `ZERO_WIDTH_SPACE` constant and `stripZeroWidthSpaces()` helper exported from @qwen-code/webui. This also improves the slash command completion fix: instead of adding \u200B to the word boundary check, strip it at the source in handleInput (consistent with InputForm's onInput handler) and clamp the cursor position to the stripped text length. Closes #3592 * test: add tests for zero-width space handling and shouldSendMessage - Add unit tests for ZERO_WIDTH_SPACE constant and stripZeroWidthSpaces helper (via @qwen-code/webui import) - Add shouldSendMessage tests covering empty, whitespace, zero-width space, and attachment scenarios - Add parseExportSlashCommand tests for zero-width space input * fix(test): use correct ImageAttachment type in shouldSendMessage tests Fix CI lint failure by providing all required ImageAttachment fields (id, name, type, size, data, timestamp) instead of non-existent mediaType property. |
||
|
|
b5c7abd28e
|
feat: Adds Catalan language support (#3643)
* Initial version * Some fixes * Fix sentences * More fixes * Fix * Latest fixes |
||
|
|
a6b0b7e579
|
Revert "fix(cli): respect OPENAI_MODEL precedence in CLI model resolution (#3567)" (#3633)
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
This reverts commit
|
||
|
|
29887ddfef
|
fix(core): match DeepSeek provider by model name for sglang/vllm (#3613) (#3620)
Some OpenAI-compatible servers (notably sglang's deepseek-v4 jinja template) crash on the array form of message content even when it carries a single text block, with `TypeError: sequence item 0: expected str instance, list found` at `encoding_dsv4.py:336`. The DeepSeekOpenAICompatibleProvider already flattens content arrays into joined strings in buildRequest, but isDeepSeekProvider only matched on the official api.deepseek.com baseUrl. DeepSeek models served behind sglang / vllm / ollama / etc. bypass the workaround and hit the bug. Extend the matcher to also detect by model name (case-insensitive substring 'deepseek'), so any OpenAI-compatible endpoint serving a DeepSeek model picks up the same content-format flattening. Fixes #3613 Co-authored-by: wenshao <wenshao@U-K7F6PQY3-2157.local> |
||
|
|
569cfe10fa
|
fix(telemetry): use safeJsonStringify in FileExporter to avoid circular reference crash (#3630)
When --telemetry-outfile is configured, FileSpanExporter.serialize called JSON.stringify directly on OTel ReadableSpan instances. The spans hold a back-reference to BatchSpanProcessor (._shutdownOnce -> BindOnceFuture._that -> BatchSpanProcessor), which forms a cycle and triggers "TypeError: Converting circular structure to JSON" on every export. Combined with DiagConsoleLogger, the error was repeatedly printed to stderr and polluted the Ink TUI. Switch FileExporter.serialize to the existing safeJsonStringify utility, matching the upstream gemini-cli fix so future merges stay clean. Add a focused regression test that mimics the BatchSpanProcessor cycle shape; broader cycle behavior is already covered by safeJsonStringify.test.ts. Co-authored-by: wenshao <wenshao@U-K7F6PQY3-2157.local> |
||
|
|
eea4e10eea
|
feat(cli): add sticky todo panel to app layouts (#3507)
* feat(cli): add sticky todo panel to app layouts * fix(cli): hide sticky todos during feedback dialog |
||
|
|
f7cfe53c6a
|
fix(core): preserve settings-sourced apiKey when registry model envKey is absent (#3495)
* fix(core): preserve settings-sourced apiKey when registry model envKey is absent (#3417) On restart, `applyResolvedModelDefaults` unconditionally cleared the apiKey resolved from `settings.security.auth.apiKey` (layer 4 fallback) and only read from `process.env[model.envKey]`. When the provider-specific env var was absent (e.g. key stored only in settings), the correctly resolved key was discarded, causing a 401 error. Now capture the previously-resolved apiKey before clearing and fall back to it when `process.env[model.envKey]` is empty, but only for safe source kinds (`settings` and general `env` without `via.modelProviders`). Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): also preserve CLI-sourced apiKey during syncAfterAuthRefresh Address review feedback: keys passed via CLI flags (e.g. --openaiApiKey) were dropped on restart because source kind 'cli' was not in the fallback allowlist. Add 'cli' to the condition and a regression test. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): move apiKey preservation from applyResolvedModelDefaults to syncAfterAuthRefresh The previous fallback logic inside applyResolvedModelDefaults could leak a settings/cli-sourced apiKey to a different provider when switching models within the same authType (e.g. dashscope → openai). This is a credential safety issue because the two providers may have different baseUrls. Move the save/restore logic to syncAfterAuthRefresh Step 1, guarded by an `isUnchanged` check (same authType AND same modelId). This ensures: - Restart scenario: apiKey preserved (same model, no change) - Cross-provider switch: apiKey cleared (different modelId) Also adds two cross-provider switch tests (settings-sourced and CLI-sourced) per review feedback. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): replace non-null assertion with truthiness guard and add cold-start test - Replace `savedApiKeySource!` with a truthiness guard for safer source restoration - Add test for cold-start scenario (previousAuthType undefined) to verify no key preservation occurs on first syncAfterAuthRefresh - Fix stale "short-circuit" comment in programmatic key test Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): detect provider config hot-reload in isUnchanged check When a model provider config is hot-reloaded (e.g. via Coding Plan update) changing envKey or baseUrl while keeping the same model id, the save/restore logic must not preserve the old apiKey. Extend the isUnchanged guard to compare apiKeyEnvKey and baseUrl against the resolved model, but only after applyResolvedModelDefaults has run at least once (apiKeyEnvKey !== undefined). On first startup call these fields are still unset, so the check is skipped to preserve the settings/cli-sourced key correctly. Adds two hot-reload tests (envKey change and baseUrl change). Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): use baseUrl source as hasBeenApplied signal for provider change detection Replace `apiKeyEnvKey !== undefined` guard with `baseUrl source === 'modelProviders'` to reliably detect whether applyResolvedModelDefaults has been called before. This fixes two edge cases: 1. No-envKey models: hot-reload changing baseUrl was undetected because apiKeyEnvKey remained undefined. Now baseUrl source is checked. 2. Startup with envKey but omitted baseUrl: undefined !== default URL could falsely trigger isProviderChanged. Now skipped at startup since baseUrl source is not yet 'modelProviders'. Updates hot-reload test fixtures to simulate post-apply state (baseUrl source as 'modelProviders') and adds no-envKey hot-reload test. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): shallow-clone savedApiKeySource to avoid mutation risk Copy the ConfigSource object before applyResolvedModelDefaults runs, so a future refactor that mutates source objects in place won't break the save/restore logic. 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> |