Skip to content

fix(cli): accept the qwen-audio Token Plan ASR family in voice transport resolution - #10981

Open
now-ing wants to merge 1 commit into
QwenLM:mainfrom
now-ing:fix/asr-transport-allowlist-10932
Open

fix(cli): accept the qwen-audio Token Plan ASR family in voice transport resolution#10981
now-ing wants to merge 1 commit into
QwenLM:mainfrom
now-ing:fix/asr-transport-allowlist-10932

Conversation

@now-ing

@now-ing now-ing commented Sep 4, 2026

Copy link
Copy Markdown

What this PR does

Teaches the voice pipeline about the new qwen-audio-* Token Plan ASR model family, so resolveVoiceTransport() no longer rejects it as unsupported:

  • packages/cli/src/services/voice-model.ts — adds two family rules in resolveVoiceTransport():
    • qwen-audio-<version>-asr-flash (bare / dated snapshots) → qwen-asr-chat (same shape as the legacy qwen3-asr-flash)
    • qwen-audio-<version>-asr-flash-streaming / -realtime / qwen-audio-<version>-realtime[-plus]qwen-asr-realtime
    • *-filetrans / *-tts-plus / unrelated models still resolve to unsupported; the version segment is [\d.]+ so future 4.x IDs keep working
  • packages/web-shell/client/voice/voiceModels.ts — mirrors the same two patterns in the web-shell's hand-maintained isVoiceModelId() allowlist (the second gate the triage pointed out)
  • packages/cli/src/config/settingsSchema.ts + docs/users/configuration/settings.md — extends the keytermsFile description to mention the qwen-audio-* ASR family (keyterms biasing hangs off the qwen-asr-realtime transport, so new-family realtime variants inherit it)

deriveWebSocketBase() already strips the /compatible-mode/v1 suffix, so the Token Plan realtime endpoint works without URL plumbing — qwen-audio-3.0-realtime-plus is immediately usable for Token Plan dictation today (verified by the community probes in the issue).

Why it's needed

Fixes #10932. Model Studio's Token Plan serves speech recognition under the new family ID qwen-audio-3.0-asr-flash, but the client hardcodes only the legacy IDs, so voice transcription cannot select any Token Plan ASR model even where the server side accepts it. The gate is purely the client-side allowlist.

Note: community probing in the issue shows the bare qwen-audio-3.0-asr-flash is currently rejected by the Token Plan gateway on all three transports (server-side routing gap), and *-streaming variants are not provisioned yet. This PR fixes the client side so those work the moment the server provisions them; it does not (and cannot) fix server-side routing.

Reviewer Test Plan

How to verify

  1. npx vitest run packages/cli/src/ui/voice/voice-model.test.ts packages/web-shell/client/voice/voiceModels.test.ts — new resolveVoiceTransport cases cover: bare qwen-audio-3.0-asr-flashqwen-asr-chat; qwen-audio-3.0-asr-flash-streaming and qwen-audio-3.0-realtime-plusqwen-asr-realtime; unrelated / -filetrans / -tts-plus IDs → unsupported.
  2. Regression sweep (all green locally): voice-service, voice-command, modelCommand, use-voice-input (24), ModelDialog (60), resolve-voice-config — 221 tests passing.
  3. tsc --noEmit for packages/cli and packages/web-shell, plus eslint and prettier, all exit 0.

Evidence (Before & After)

Before: selecting a Token Plan ASR model rejects dictation with "unsupported model" from resolveVoiceTransport().
After: the model resolves to the proper chat/realtime transport (see tests above). N/A for screenshots — no visual surface changed.

Tested on

OS Status
🍏 macOS
🪟 Windows ⚠️
🐧 Linux ⚠️

…ort resolution

Model Studio Token Plan serves speech recognition under qwen-audio-<version>
ids (e.g. qwen-audio-3.0-asr-flash), but resolveVoiceTransport only matched
the legacy qwen3-asr ids, so voice dictation rejected the family at the
selection gate before any request was made.

Route the family like its qwen3-asr counterpart: bare and date-suffixed
asr-flash ids to the batch chat transport, *-realtime and
*-asr-flash-streaming ids to the OpenAI realtime WebSocket transport
(qwen-audio-3.0-realtime-plus is verified working there against the Token
Plan endpoint). filetrans and tts ids stay unsupported. Mirror the patterns
in the Web Shell's hand-maintained isVoiceModelId() picker gate and note
the family in the keyterms docs, whose biasing rides the realtime
transport.

Fixes QwenLM#10932

Signed-off-by: mac <bishopapril850965@yahoo.com>
@qwen-code-ci-bot

qwen-code-ci-bot commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Qwen Triage finishedview run. See the stage comments in this thread for the result.

Qwen Triage 已完成 —— 查看运行。结果见本线程中的各阶段评论。

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@now-ing thanks for picking up #10932 — before this can go to code review, the PR body needs the sections it's missing from the PR template:

  • ## Risk & Scope — the three bullets (main risk or tradeoff / not validated or out of scope / breaking changes). This is the one that matters most here: the thread on #10932 established that the bare qwen-audio-3.0-asr-flash answered 400 {} on the batch chat/completions shape, and that -streaming isn't provisioned on Token Plan yet. So the transport mapping for those two ids is a forward-looking choice rather than a verified one, and "Not validated / out of scope" is exactly where that belongs.
  • ## Linked IssuesFixes #10932 currently sits inline under Why it's needed. GitHub does resolve it there, but the template asks for its own section.
  • The <details><summary>中文说明</summary> block — a full Chinese translation of the body, paragraph by paragraph.

What this PR does, Why it's needed, How to verify, Evidence (Before & After) and Tested on are all filled in, so it's only the three above. Re-running triage after the edit picks the PR up from the top.

中文说明

@now-ing 感谢接手 #10932。在进入代码审查之前,PR 描述还需要补齐 PR 模板 中缺失的部分:

  • ## Risk & Scope —— 三个条目(主要风险或取舍 / 未验证或超出范围 / 破坏性变更)。这一条在此处最重要:#10932 的讨论已经确认,裸 ID qwen-audio-3.0-asr-flash 在批处理 chat/completions 形状下返回 400 {},且 -streaming 变体在 Token Plan 上尚未开通。因此这两个 id 的 transport 映射属于前瞻性选择而非已验证结论,「未验证 / 超出范围」正是应该写清楚这一点的地方。
  • ## Linked Issues —— Fixes #10932 目前写在 Why it's needed 里。GitHub 确实能识别,但模板要求单独成节。
  • <details><summary>中文说明</summary> 区块 —— 需要逐段对应地完整翻译上面的英文正文。

What this PR doesWhy it's neededHow to verifyEvidence (Before & After)Tested on 都已填写,只缺上面三项。补齐后重新触发 triage,会从头开始审查这个 PR。

Qwen Code · qwen3.8-max-2026-09-02

@wenshao

wenshao commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Maintainer verification — built a real runtime environment for this PR

I stood up a local stand-in for the Model Studio Token Plan gateway and drove the real CLI, the real qwen serve daemon and the real web-shell voice module against it, A/B against the merge-base (60161cb64a). The fix is correct and works end to end on all three surfaces. One blocking item: a generated file was not regenerated, so the Check settings schema is up-to-date CI step will fail.

Verified at ef99e5662, base 60161cb64a (PR is 2 commits behind main; no conflicting changes to any touched file).

Harness

No Token Plan credentials are needed. A local gateway speaks all three wire dialects the voice pipeline knows about, logging every request/frame as JSONL:

Endpoint Dialect Used by
POST /compatible-mode/v1/chat/completions with an input_audio part batch ASR qwen-asr-chat
WS /api-ws/v1/realtime?model=… OpenAI realtime qwen-asr-realtime
WS /api-ws/v1/inference DashScope run-task dashscope-task-realtime

Microphone capture is supplied by a stand-in sox on PATH that emits a real 16 kHz/mono/s16le WAV, so the TUI takes the genuine recorder path. Both arms run from the same source tree with only the PR's two production files toggled.


1. It fixes the reported bug — real TUI, real dictation

main reproduces #10932 on both surfaces the triage predicted: the picker rejects the model with formatUnsupportedVoiceModelMessage(), and a hand-set voiceModel fails at record time with the other string.

main — /model --voice rejects qwen-audio-3.0-asr-flash:

main picker rejects

main — hand-set voiceModel, press Space to dictate:

main record-time error

PR — the model is selectable, and a full dictation round trip completes:

PR dictation works

The request that reached the gateway is the real transcribeViaQwenAsr shape:

{"kind":"http.asr","path":"/compatible-mode/v1/chat/completions","model":"qwen-audio-3.0-asr-flash",
 "asr_options":{"enable_itn":true,"language":"en"},
 "messages":[{"role":"system","content":[{"type":"text","text":"Qwen MCP grep regex localhost codebase …"}]},
             {"role":"user","content":[{"type":"input_audio","format":"wav","dataBytes":51282}]}]}

Note the leading system message: keyterms biasing does reach the new family on the batch path, and on the realtime path as session.update.input_audio_transcription.corpus_text. That makes the keytermsFile doc/schema wording change in this PR factually correct, which was open loop #4 in the triage.

2. Real qwen serve daemon — both routes

Probe main PR
GET /workspace/voiceavailableVoiceModels [qwen3-asr-flash] [qwen-audio-3.0-asr-flash (qwen-asr-chat), qwen-audio-3.0-realtime-plus (qwen-asr-realtime), qwen3-asr-flash]
POST /workspace/voice/transcribe (real WAV body) 400 unsupported_voice_model 200 {"text":"…","model":"qwen-audio-3.0-asr-flash","transport":"qwen-asr-chat"}
WS /voice/stream with qwen-audio-3.0-realtime-plus, real PCM ready{streaming:false}error ready{streaming:true} → 2× interimfinal

The WS /voice/stream row is the Web Shell's own dictation path end to end, and it also shows the second-order effect of the fix: on main the realtime model silently degrades to streaming:false (isStreamingVoiceModel() is false for unsupported) before failing.

deriveWebSocketBase() needs no change, as the PR says — the socket landed on /api-ws/v1/realtime?model=qwen-audio-3.0-realtime-plus from a …/compatible-mode/v1 baseUrl with no URL plumbing.

3. Both allowlists agree — the "two gates" risk is closed

I ran 25 ids (real catalog ids, version-shape stress, suffix stress) through the CLI's resolveVoiceTransport() and the web-shell's isVoiceModelId() in the same process. The two hand-maintained gates agree on every one of the 25. A grep over the repo confirms there is no third allowlist — the other qwen3-asr-* hits are fixed default model ids in qwen-live/serve/live and error-message copy.

id                                             cli transport            web-shell allow
qwen-audio-3.0-asr-flash                       qwen-asr-chat            true
qwen-audio-3.0-asr-flash-streaming             qwen-asr-realtime        true
qwen-audio-3.0-realtime-plus                   qwen-asr-realtime        true
qwen-audio-4.1-asr-flash                       qwen-asr-chat            true    (forward-compatible ✓)
Qwen-Audio-3.0-ASR-Flash                       qwen-asr-chat            true    (case-insensitive ✓)
qwen-audio-3.0-asr-flash-filetrans             unsupported              false
qwen-audio-3.0-tts-plus                        unsupported              false
qwen-audio-3.0-tts-realtime                    unsupported              false
qwen-audio-3.0-omni-realtime                   unsupported              false
qwen3-asr-flash / -realtime / paraformer…      unchanged                unchanged

Regex cost is linear — a 200 kB pathological id resolves in 0.85 ms, no backtracking blowup.

4. The PR's own tests are load-bearing

Reverting only the two production files and keeping the new tests fails them, so they would catch a regression:

  • packages/cli/src/ui/voice/voice-model.test.ts — 8 pass on PR, 2 fail on merge-base source
  • packages/web-shell/client/voice/voiceModels.test.ts — 5 pass on PR, 2 fail on merge-base source

Regression sweep: 344 tests pass across voice-service, voice-command, modelCommand, use-voice-input, ModelDialog, resolve-voice-config, voice-transcriber, qwen-asr-realtime-session, workspace-voice. eslint, prettier --check and npm run check-i18n are clean on the changed files. (src/ui/opentui/dialog-data.test.ts cannot load here for lack of @opentui/* — it fails identically on main, so it is my environment, not the PR.)


Findings

🔴 Blocking — the generated VS Code settings schema was not regenerated

packages/cli/src/config/settingsSchema.ts is the source for packages/vscode-ide-companion/schemas/settings.schema.json, and ci.yml regenerates it and fails if the tree becomes dirty. I ran the repo's own trusted classifier for this PR — classify-pr-profile.sh QwenLM/qwen-code 10981full — so that step will run:

CI schema gate fails

The same command on main leaves the tree clean, so this is the PR's diff. Fix:

npm run generate:settings-schema && git add packages/vscode-ide-companion/schemas/settings.schema.json

🟡 The qwen-audio-3.0-realtime-plus claim is stronger than the evidence supports

The PR description says this id is "immediately usable for Token Plan dictation today (verified by the community probes in the issue)". What the probe in the issue actually established is that the id accepts the dialect (session.created/session.updated, commit accepted) — not that it emits conversation.item.input_audio_transcription.*. That distinction matters, because -realtime-plus reads like a conversational (speech-to-speech) realtime model, and those report the user's speech under response.audio_transcript.* instead.

I measured what happens in that case by pointing the real openQwenAsrRealtimeStream() at a gateway that accepts the dialect but answers a commit with response.* events only:

{"transcript": "", "thrown": null, "interims": [], "errors": [], "elapsedMs": 14}

An empty transcript, no error, no interim — dictation looks like it worked and inserts nothing. This is pre-existing client behaviour, not something the PR introduces, and the transport mapping is still the best inference from the evidence. But I'd soften the claim to "resolves to the realtime transport; end-to-end transcript delivery on Token Plan still to be confirmed", so nobody treats it as validated.

🟢 Minor — degenerate version segments are accepted

[\d.]+ matches dot-only strings, so qwen-audio-..-asr-flash and qwen-audio-3...0-asr-flash resolve to qwen-asr-chat. Both gates agree, so there is no CLI/web-shell skew — the only consequence is that a nonexistent id reaches the server instead of being rejected locally. Cosmetic; [\d]+(?:\.[\d]+)* would tighten it if you care.

🟢 Minor — the new doc comment is slightly imprecise about filetrans

The comment says "Other ids in the family (filetrans, tts) are not dictation transports and stay unsupported". True for the bare -asr-flash-filetrans, but qwen-audio-3.0-asr-flash-realtime-filetrans and -streaming-filetrans resolve to qwen-asr-realtime, because the realtime rule matches at the (?:-|$) boundary before the suffix. No such ids exist in the catalog — only the comment overstates.

ℹ️ For the record

Verdict

Fix is correct, minimal, lands on both gates, and is proven end to end on the TUI, the daemon REST route and the daemon voice WebSocket. Regenerate settings.schema.json and this is good to merge; the -realtime-plus wording is worth softening in the same push.

中文版

维护者验证 —— 为本 PR 搭建了真实运行环境

我在本地搭了一个 Model Studio Token Plan 网关的替身,让真实的 CLI、真实的 qwen serve 守护进程和真实的 web-shell 语音模块跑在它上面,并与 merge-base(60161cb64a)做 A/B 对照。修复本身是正确的,在三个界面上都端到端跑通了。有一个阻塞项:生成物没有重新生成,Check settings schema is up-to-date 这一步 CI 会失败。

验证提交 ef99e5662,base 60161cb64a(PR 落后 main 两个提交,所有改动文件均无冲突改动)。

验证环境

不需要 Token Plan 凭据。本地网关同时讲语音链路认识的三种协议,并把每个请求/帧以 JSONL 记录下来:

端点 协议 对应 transport
POST /compatible-mode/v1/chat/completions(带 input_audio 批处理 ASR qwen-asr-chat
WS /api-ws/v1/realtime?model=… OpenAI realtime qwen-asr-realtime
WS /api-ws/v1/inference DashScope run-task dashscope-task-realtime

麦克风采集由 PATH 上的替身 sox 提供,它输出真实的 16 kHz/单声道/s16le WAV,因此 TUI 走的是真正的录音器路径。两个对照臂跑同一份源码树,只切换 PR 的两个生产文件。


1. 确实修复了所报问题 —— 真实 TUI、真实语音输入

main 上按 triage 预测的两个界面都复现了 #10932:选择器用 formatUnsupportedVoiceModelMessage() 拒绝该模型;手动写入 voiceModel 后按空格,则在录音阶段抛出另一句报错。

main —— /model --voice 拒绝 qwen-audio-3.0-asr-flash

main picker rejects

main —— 手动设置 voiceModel,按空格听写:

main record-time error

PR —— 模型可选,并完成一次完整的语音输入闭环:

PR dictation works

到达网关的请求正是真实的 transcribeViaQwenAsr 形状:

{"kind":"http.asr","path":"/compatible-mode/v1/chat/completions","model":"qwen-audio-3.0-asr-flash",
 "asr_options":{"enable_itn":true,"language":"en"},
 "messages":[{"role":"system","content":[{"type":"text","text":"Qwen MCP grep regex localhost codebase …"}]},
             {"role":"user","content":[{"type":"input_audio","format":"wav","dataBytes":51282}]}]}

注意开头那条 system 消息:keyterms 偏置确实作用到了新系列——批处理路径走 system 消息,realtime 路径走 session.update.input_audio_transcription.corpus_text。这说明本 PR 对 keytermsFile 文档/schema 措辞的修改在事实上是准确的,也就是 triage 中第 4 个待办项。

2. 真实 qwen serve 守护进程 —— 两条路由

探测 main PR
GET /workspace/voiceavailableVoiceModels [qwen3-asr-flash] [qwen-audio-3.0-asr-flash (qwen-asr-chat), qwen-audio-3.0-realtime-plus (qwen-asr-realtime), qwen3-asr-flash]
POST /workspace/voice/transcribe(真实 WAV body) 400 unsupported_voice_model 200 {"text":"…","model":"qwen-audio-3.0-asr-flash","transport":"qwen-asr-chat"}
WS /voice/stream 使用 qwen-audio-3.0-realtime-plus、真实 PCM ready{streaming:false}error ready{streaming:true} → 2 次 interimfinal

WS /voice/stream 这一行就是 Web Shell 自己的语音输入链路的端到端验证,同时也展示了修复的二阶效果:在 main 上,realtime 模型会静默降级为 streaming:false(因为 unsupportedisStreamingVoiceModel() 返回 false),然后失败。

正如 PR 所说,deriveWebSocketBase() 无需改动——从 …/compatible-mode/v1 的 baseUrl 出发,socket 正确落在 /api-ws/v1/realtime?model=qwen-audio-3.0-realtime-plus,没有任何额外 URL 处理。

3. 两处白名单完全一致 —— triage 指出的"两道门"风险已闭合

我在同一个进程里,用 25 个 id(真实目录 id、版本形状压力、后缀压力)同时跑 CLI 的 resolveVoiceTransport() 与 web-shell 的 isVoiceModelId()两处手工维护的门在 25 个 id 上判定完全一致。 全仓 grep 确认不存在第三处白名单——其余 qwen3-asr-* 命中都是 qwen-live/serve/live 里的固定默认模型 id 和报错文案。

id                                             cli transport            web-shell allow
qwen-audio-3.0-asr-flash                       qwen-asr-chat            true
qwen-audio-3.0-asr-flash-streaming             qwen-asr-realtime        true
qwen-audio-3.0-realtime-plus                   qwen-asr-realtime        true
qwen-audio-4.1-asr-flash                       qwen-asr-chat            true    (向前兼容 ✓)
Qwen-Audio-3.0-ASR-Flash                       qwen-asr-chat            true    (大小写不敏感 ✓)
qwen-audio-3.0-asr-flash-filetrans             unsupported              false
qwen-audio-3.0-tts-plus                        unsupported              false
qwen-audio-3.0-tts-realtime                    unsupported              false
qwen-audio-3.0-omni-realtime                   unsupported              false
qwen3-asr-flash / -realtime / paraformer…      不变                     不变

正则代价是线性的——200 kB 的病态 id 解析耗时 0.85 ms,没有回溯爆炸。

4. PR 自带的测试是有效的

只回滚两个生产文件、保留新增测试后,它们会失败,说明确实能拦住回归:

  • packages/cli/src/ui/voice/voice-model.test.ts —— PR 上 8 通过,merge-base 源码上 2 失败
  • packages/web-shell/client/voice/voiceModels.test.ts —— PR 上 5 通过,merge-base 源码上 2 失败

回归扫描:voice-servicevoice-commandmodelCommanduse-voice-inputModelDialogresolve-voice-configvoice-transcriberqwen-asr-realtime-sessionworkspace-voice 共 344 个测试通过。改动文件上 eslintprettier --checknpm run check-i18n 均干净。(src/ui/opentui/dialog-data.test.ts 因本机缺少 @opentui/* 无法加载——它在 main 上同样失败,属于我的环境问题,与 PR 无关。)


结论清单

🔴 阻塞 —— 生成的 VS Code settings schema 未重新生成

packages/cli/src/config/settingsSchema.tspackages/vscode-ide-companion/schemas/settings.schema.json 的来源,ci.yml 会重新生成它并在工作区变脏时失败。我用仓库自带的可信分类器跑了本 PR —— classify-pr-profile.sh QwenLM/qwen-code 10981full,因此这一步会执行:

CI schema gate fails

同样的命令在 main 上不会产生任何改动,所以这确实是本 PR 的问题。修复:

npm run generate:settings-schema && git add packages/vscode-ide-companion/schemas/settings.schema.json

🟡 关于 qwen-audio-3.0-realtime-plus 的结论强于证据

PR 描述称该 id "immediately usable for Token Plan dictation today(已由 issue 中的社区探测验证)"。issue 里的探测实际确认的是该 id 接受这套协议session.created/session.updated、commit 被接受),而没有确认它会发出 conversation.item.input_audio_transcription.* 事件。这个区别很关键:-realtime-plus 看起来像是对话式(语音到语音)realtime 模型,而这类模型会把用户语音的转写放在 response.audio_transcript.* 里。

我把真实的 openQwenAsrRealtimeStream() 指向一个"接受协议但 commit 后只回 response.*"的网关,量化了这种情况:

{"transcript": "", "thrown": null, "interims": [], "errors": [], "elapsedMs": 14}

空转写、无报错、无中间结果——听写看起来成功了,却什么也没插入。这是客户端既有行为,并非本 PR 引入,而且从现有证据看这个 transport 映射仍是最合理的推断。但我建议把措辞放软为"解析到 realtime transport;Token Plan 上端到端的转写投递仍待确认",以免被当成已验证结论。

🟢 次要 —— 接受了退化的版本段

[\d.]+ 能匹配纯点字符串,因此 qwen-audio-..-asr-flashqwen-audio-3...0-asr-flash 都会解析为 qwen-asr-chat。两处门判定一致,所以不存在 CLI/web-shell 偏差——唯一后果是一个不存在的 id 会被发到服务端,而不是在本地被拒。属于观感问题;若在意可改为 [\d]+(?:\.[\d]+)*

🟢 次要 —— 新增注释对 filetrans 的描述略有出入

注释写道 "Other ids in the family (filetrans, tts) are not dictation transports and stay unsupported"。对裸的 -asr-flash-filetrans 成立,但 qwen-audio-3.0-asr-flash-realtime-filetrans-streaming-filetrans 会解析为 qwen-asr-realtime,因为 realtime 规则在 (?:-|$) 边界处就匹配上了。目录中并不存在这类 id——只是注释说法过满。

ℹ️ 备录

结论

修复正确、改动最小、两处门都覆盖到了,并已在 TUI、守护进程 REST 路由和守护进程语音 WebSocket 上端到端验证。重新生成 settings.schema.json 后即可合并;建议在同一次推送里把 -realtime-plus 的措辞放软。

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test Plan (not a blocker): 221 tests passing — this review observed 5832, 504 passed.

— qwen3.8-max via Qwen Code /review (v0.23.0)

default: '',
description:
'Path to a custom keyterms file (one term per line, "#" for comments) that biases voice transcription toward domain-specific terms. Relative paths resolve from the workspace root; defaults to ".qwen/voice-keyterms.txt" when present. The file contents are sent to the ASR provider and it is read only in trusted workspaces. Only applies to Qwen ASR models (qwen3-asr-*).',
'Path to a custom keyterms file (one term per line, "#" for comments) that biases voice transcription toward domain-specific terms. Relative paths resolve from the workspace root; defaults to ".qwen/voice-keyterms.txt" when present. The file contents are sent to the ASR provider and it is read only in trusted workspaces. Only applies to Qwen ASR models (qwen3-asr-* and the qwen-audio-* ASR family).',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Critical] R1-1: [fails-closed] [regression] The keytermsFile description was updated here, but the generated packages/vscode-ide-companion/schemas/settings.schema.json was not regenerated — its line 105 still reads Only applies to Qwen ASR models (qwen3-asr-*).. This PR touches packages/cli and packages/web-shell, so CI classifies it into the full profile; the lint_and_static job then runs npm run generate:settings-schema followed by the "Check settings schema is up-to-date" step (.github/workflows/ci.yml:1171-1185), which exits 1 when the schema file is dirty — and regenerating rewrites exactly this description. The PR therefore fails that CI gate as committed, and until the artifact is regenerated, VS Code settings IntelliSense keeps showing the stale family list, contradicting the docs this same PR updates.

Witness:

$ npm run generate:settings-schema      (scratch tree at ef99e56625)
exit 0
$ git status --porcelain packages/vscode-ide-companion/schemas/settings.schema.json
 M packages/vscode-ide-companion/schemas/settings.schema.json
- "description": "...Only applies to Qwen ASR models (qwen3-asr-*).",
+ "description": "...Only applies to Qwen ASR models (qwen3-asr-* and the qwen-audio-* ASR family).",

Regenerate and commit the artifact — do not hand-edit the JSON:

npm run generate:settings-schema

Note that scripts/generate-settings-schema.ts copies setting.description verbatim from SETTINGS_SCHEMA and rewrites the whole file (and scripts/build.js re-runs the generator after CLI builds), so the fix must be a regeneration, not a hand-edit of the description line. Acceptance criterion: the CI freshness gate itself — after npm run generate:settings-schema, git status --porcelain packages/vscode-ide-companion/schemas/settings.schema.json must be empty; without the regenerated artifact committed, the "Check settings schema is up-to-date" step exits 1.

— qwen3.8-max via Qwen Code /review (v0.23.0)

) {
return 'qwen-asr-realtime';
}
if (/^qwen-audio-[\d.]+-asr-flash(?:-\d{4}-\d{2}-\d{2})?$/.test(id)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R1-2: This diff makes the qwen-audio-*-asr-flash batch family selectable, but two recovery messages newly reachable for it still recommend only legacy ids: packages/cli/src/services/voice-transcriber.ts:843 ("Use qwen3-asr-flash for batch or choose a realtime voice model such as qwen3-asr-flash-realtime / fun-asr-realtime / paraformer-realtime-v2") and packages/cli/src/ui/hooks/use-voice-input.ts:335 ("switch voiceModel to qwen3-asr-flash for batch transcription"). A Token Plan user — the population issue 10932 enables — configures qwen-audio-3.0-asr-flash, which now passes the selection guard; if the endpoint then rejects it as model_not_supported, or a streaming qwen-audio model is selected without the native audio-capture module, the guidance sends them to qwen3-asr-flash — but the issue's own live probes show qwen3-asr-flash answering 404 model_not_found on the Token Plan gateway, so the user is pointed at a model their plan does not serve instead of their own family's batch variant, a second dead end.

Witness:

probe driving the real transcribeVoiceAudio() with a stubbed 400 model_not_supported response:
OBSERVED[qwen-audio-3.0-asr-flash]: This voice model cannot be used for batch
transcription. Use qwen3-asr-flash for batch or choose a realtime voice model such as
qwen3-asr-flash-realtime / fun-asr-realtime / paraformer-realtime-v2.

Extend both messages to also name the qwen-audio-*-asr-flash batch family — e.g. "Use qwen3-asr-flash or qwen-audio--asr-flash for batch ..." — or phrase the guidance generically ("a batch-capable ASR model").

— qwen3.8-max via Qwen Code /review (v0.23.0)

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

🖼️ web-shell visual preview

Rendered against a mock daemon (no real backend): the PR base vs this PR head ef99e56. Only screenshots that changed are shown (flows below, if any, are head-only) — refreshes on every push.

Screenshots · before / after

⚠️ One or more scenarios failed to render on this head, so this preview may be missing views — see the workflow run. The composites below are the scenarios that did render.

workflow-page-running-dark before/after

workflow-page-running-light before/after

workflow-page-saved-dark before/after

workflow-page-saved-detail-dark before/after

workflow-page-saved-detail-light before/after

workflow-page-saved-light before/after

Full-resolution recordings (.webm) are attached to the workflow run.

Qwen Code · web-shell visuals

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Voice dictation cannot use Token Plan ASR: resolveVoiceTransport rejects qwen-audio-3.0-asr-flash as unsupported

3 participants