qwen-code/.github/workflows
易良 2583b5c7dd
feat(cli): add /model --vision for a fallback vision model (#5778)
* feat(cli): add /model --vision for a fallback vision model

Add `/model --vision <id>` and an interactive vision-model picker to
configure an image-capable model the vision bridge borrows when a
text-only main model receives an image, mirroring the `/model --fast`
pattern (flat `visionModel` setting + runtime `setVisionModel`). An
explicit vision model takes precedence over same-provider auto-select and
may cross providers; an unreachable pin falls back to auto-select rather
than firing the bridge at a model it can't reach.

Also fixes two vision-bridge issues surfaced while verifying #5126:

- The gate read stale modalities after a runtime model switch, so an
  @image sent right after switching to a multimodal model could still
  trigger the bridge. Refresh model-derived modalities on the qwen-oauth
  hot-update paths (setModel default-model + handleModelChange) so the
  gate reflects the current model.
- The transcription was appended after a now-empty "Content from <file>:"
  header, leading the primary model to re-read the image file and ignore
  the transcript. Stand the transcription in the image's slot and tell the
  model the image cannot be read by a tool.

Closes #5597

* fix(cli): add vision model description translations

* feat(cli): warn on non-image-capable /model --vision pin; cover modality refresh

Self-review follow-ups on the /model --vision work:

- Warn (but still honor) when /model --vision or the picker pins a model that
  isn't image-capable, reusing the vision bridge's isImageCapable so the
  explicit and auto-select paths agree on what counts as vision-capable.
  isImageCapable is now exported for the CLI to share.
- Exclude fastOnly models from --vision validation so it matches the
  completion filter.
- Add a Config-level test asserting handleModelChange refreshes modalities on
  the qwen-oauth hot path (the vision-bridge gate fix that lacked direct
  coverage).

* fix(cli): translate the non-image-capable vision model warning

Add zh/zh-TW/en entries for the /model --vision picker warning shown when a pinned model isn't image-capable, matching the existing vision-string translations.

* fix(vision-bridge): stop showing the image transcription twice

The vision bridge printed the full transcription in its notice AND fed it to
the primary model, which then re-stated it — so the user read the same image
description twice (once in the notice box, once in the answer).

- The notice now shows only the egress-disclosure header; the transcription is
  fed to the primary model and surfaced in its answer, so it is no longer
  duplicated. Removes the now-unused transcript truncation / control-char
  stripping helpers.
- The bridge model is instructed to transcribe/describe, not answer the user
  request (the user's intent is carried as a focus hint, not a question), so its
  output is context for the primary model rather than a second competing answer.

* fix(cli): register vision model i18n strings and cover /model --vision

- Register 'Vision Model' / 'Select Vision Model' in en/zh/zh-TW so the
  vision picker and confirmation aren't English-only for non-English users
  (mirrors the existing Voice Model entries).
- formatNonVisionModelWarning reuses the dialog's already-registered t()
  key instead of a plain English literal, keeping both paths i18n-consistent.
- Add the missing bare '/model --vision' tests (interactive dialog +
  non-interactive current-model report), mirroring the --voice coverage.

* refactor(vision-bridge): remove dead VisionBridgeResult.transcript field

The inline transcript display was dropped in 14de33333 (it duplicated the
description already fed to the primary model), leaving `transcript` set on
the result but never read in any production path. Remove the field and its
now-redundant test — the untrusted-wrapper assertion it carried is already
covered by 'converts images to an untrusted text block on success'.

* test(cli): cover vision-model branches; dedupe fast/vision helpers

Refactor (behavior-neutral):
- modelCommand.ts: fold identical formatUnavailableFast/VisionModelMessage
  bodies into formatUnavailableAuxModelMessage(label, hint).
- ModelDialog.tsx: extract the fast/vision selection-key parsing into
  encodeAuxModelSelector(); voice keeps using the model id directly.

Tests:
- config: malformed pin (catch branch) falls back instead of throwing;
  authType-qualified visionModel binds to the matching provider only;
  setVisionModel('')/undefined clears back to auto-select.
- modelCommand: authType-scoped vision rejection message.
- ModelDialog: non-image-capable pin emits the warning in history.

* test(cli): vision-mode coverage + register --vision completion i18n key

- i18n: register the `--vision` completion description key in en/zh/zh-TW
  (was wrapped in t() with no entry, so non-English showed English).
- useModelCommand: test vision mode opens + suppresses fast, resets on close.
- modelCommand: test --vision rejects fastOnly/voiceOnly models.

Also corrects the stale "30-minute" wait-timer comment in
qwen-code-pr-review.yml (actual env timer is 10m; point to repo settings).

* fix(core): exclude primary model from explicit vision bridge selection

resolveVisionModelSelection lacked the m.id !== primary guard that the
auto-select path (selectVisionBridgeModel) already has, so pinning the
text-only primary via /model --vision would fire the bridge at a model
that cannot read images. Mirror the auto-select guard.

* chore(core): log vision bridge transcription for traceability

The transcription is no longer surfaced to the user or carried on the
result; log it at debug so a wrong primary-model answer can be traced to
a misread image vs a downstream hallucination.

* test: cover vision model helpers and vision-model dialog dispatch

Add direct unit tests for encodeAuxModelSelector (3 key shapes) and
isImageCapable (isVision/modalities/name-fallback), and a dispatch test
for the /model --vision dialog case mirroring voice-model.

* fix(cli): render vision bridge notice as a dim tip, drop doubled marker

The success/cancelled vision-bridge notice was added as MessageType.INFO
(primary-color `●` gutter) while its text also led with `🔎`, producing a
doubled `● 🔎` marker. Route success/cancelled notices to a new dim
`vision_notice` variant (secondary color, single `🔎` gutter glyph) and
strip the baked-in glyphs from the notice text so the renderer owns the
prefix. Failures keep the prominent red `✕` ERROR variant (also
de-duplicated).

* test(cli): assert VISION_NOTICE type for mid-turn vision bridge notice

* test(cli): cover vision_notice classification and rendering

* fix(vision): harden vision-bridge model selection + UX

Address review feedback on #5778:
- config: provider-aware isCurrentPrimaryModel() so a cross-provider namesake
  (e.g. anthropic:shared-model vs an openai shared-model primary) stays an
  eligible vision pin; resolveVisionModelSelection now also filters fast/voice-
  only models (a settings.json pin bypasses the slash command) and warns on
  every silent-drop path so a stale pin is debuggable.
- modelCommand/ModelDialog: reject pinning the current primary as the vision
  model at set time (ignored at runtime) instead of persisting a dead pin.
- useModelCommand: vision mode suppresses voice so the dialog can't end up in
  two specialized modes at once.
- HistoryItemDisplay: vision_notice gets 0 top margin like its notice peers.
- vision-bridge-service: log transcription metadata only (model + length),
  never the raw text — screenshots carry tokens/PII and debug logs can be
  shared in support bundles.

PR #5778.

* fix(vision): fail-closed bridge routing, ambiguity guards, i18n, settings, tests

Address the remaining #5778 review feedback:
- baseLlmClient/sideQuery/vision-bridge: add an opt-in `failClosed` to the
  per-model resolve path; the vision bridge sets it so a missing cross-provider
  credential fails the conversion instead of silently routing image payloads at
  the text-only main generator (which BaseLlmClient otherwise falls back to).
- ModelDialog: reject a vision pin that maps to multiple same-provider endpoints
  (the persisted authType:modelId can't disambiguate base URLs), mirroring the
  voice-mode duplicate guard.
- modelCommand: wrap the non-interactive vision status message in t() with
  en/zh/zh-TW locale entries.
- SettingsDialog: wire the Vision Model row into the sub-dialog dispatch so Enter
  / Right-Arrow open the picker (like fastModel).
- image-part-utils: document the multi-image drop / "don't read_file" contract.
- tests: fail-closed resolve paths, primary-guard fallback, vision initialIndex,
  authType-qualified + malformed vision selectors, failure-path image removal.

PR #5778.

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: yiliang114 <effortyiliang@gmail.com>
2026-06-27 12:51:11 +00:00
..
audio-capture-prebuilds.yml ci(audio-capture): cross-compile darwin-x64 prebuild on arm64 runner (#5643) 2026-06-22 13:33:26 +00:00
build-and-publish-image.yml ci(deps): bump docker/* actions to Node 24 majors (#4131) 2026-05-14 10:54:01 +08:00
cd-cua-driver.yml feat(cua-driver): vendor qwen-cua-driver with opt-in 0–1000 relative coordinates (#5896) 2026-06-26 13:06:43 +00:00
check-issue-completeness.yml Upgrade GitHub Actions for Node 24 compatibility (#1876) 2026-05-12 15:02:33 +08:00
ci.yml ci: take CodeQL and E2E off the per-merge push path (#5859) 2026-06-25 10:50:12 +00:00
codeql.yml ci: take CodeQL and E2E off the per-merge push path (#5859) 2026-06-25 10:50:12 +00:00
desktop-release.yml ci(release): make release flow merge-queue-safe and keep release PRs out of notes (#5832) 2026-06-25 06:12:35 +00:00
docs-page-action.yml Upgrade GitHub Actions for Node 24 compatibility (#1876) 2026-05-12 15:02:33 +08:00
e2e.yml ci: take CodeQL and E2E off the per-merge push path (#5859) 2026-06-25 10:50:12 +00:00
gemini-scheduled-pr-triage.yml Upgrade GitHub Actions for Node 24 compatibility (#1876) 2026-05-12 15:02:33 +08:00
qwen-autofix.yml ci(release): queue release failures for autofix (#5551) 2026-06-22 12:49:12 +00:00
qwen-automated-issue-triage.yml Upgrade GitHub Actions for Node 24 compatibility (#1876) 2026-05-12 15:02:33 +08:00
qwen-code-pr-review.yml feat(cli): add /model --vision for a fallback vision model (#5778) 2026-06-27 12:51:11 +00:00
qwen-issue-followup-bot.yml fix(ci): fix triage prompt variable expansion, bot identity, and model secret (#4778) 2026-06-05 00:00:15 +08:00
qwen-scheduled-issue-triage.yml Sync upstream Gemini-CLI v0.8.2 (#838) 2025-10-23 09:27:04 +08:00
qwen-triage.yml ci: isolate per-run agent state for triage and PR review (#5885) 2026-06-26 07:09:27 +00:00
release-sdk-python.yml ci(release): make release flow merge-queue-safe and keep release PRs out of notes (#5832) 2026-06-25 06:12:35 +00:00
release-sdk.yml ci(release): make release flow merge-queue-safe and keep release PRs out of notes (#5832) 2026-06-25 06:12:35 +00:00
release-vscode-companion.yml ci(release): auto-publish VSCode companion after releases (#5572) 2026-06-22 02:08:44 +08:00
release.yml fix(packaging): bundle audio capture for mirror installs (#5747) 2026-06-25 08:13:45 +00:00
sdk-python.yml Upgrade GitHub Actions for Node 24 compatibility (#1876) 2026-05-12 15:02:33 +08:00
stale.yml Upgrade GitHub Actions for Node 24 compatibility (#1876) 2026-05-12 15:02:33 +08:00
sync-cua-driver-to-oss.yml feat(core): migrate Computer Use to cua-driver (cross-platform) (#5051) 2026-06-14 09:26:09 +08:00
sync-release-to-oss.yml ci: split Aliyun OSS sync into a separate post-release workflow (#4492) 2026-05-25 19:34:21 +08:00
terminal-bench.yml Upgrade GitHub Actions for Node 24 compatibility (#1876) 2026-05-12 15:02:33 +08:00