fix(ai): stop stripping images from multimodal qwen3.8-max on dashscope

The DashScope compatible-mode text-only override from #1859 matched all
qwen*-max ids, so it vetoed image content for qwen3.8-max even though that
model is multimodal in the bundled catalog (image input, #8019). inspect_image
routed to qwen3.8-max therefore received the [image omitted] placeholder and
reported no image.

Narrow isDashscopeCompatibleModeTextOnlyQwen so the -max branch only flags
pre-3.8 SKUs as text-only; coder families stay text-only. 3.8+ -max ids now
send image_url content.

Fixes #8305
This commit is contained in:
roboomp
2026-08-12 03:23:19 +00:00
parent 06aecdd51f
commit a556ad61f8
3 changed files with 20 additions and 5 deletions
+4
View File
@@ -2,6 +2,10 @@
## [Unreleased]
### Fixed
- Fixed the DashScope compatible-mode text-only Qwen override (issue #1859) stripping images from `qwen3.8-max`, which became multimodal in the bundled catalog (image input, #8019). The `-max` guard now only vetoes image content for pre-3.8 SKUs, so `qwen3.8-max`/`qwen3.8-max-preview` and later flagships send `image_url` content — restoring `inspect_image` on those models configured against `dashscope.aliyuncs.com/compatible-mode/v1` ([#8305](https://github.com/can1357/oh-my-pi/issues/8305)).
## [17.2.15] - 2026-08-12
### Fixed
+13 -3
View File
@@ -39,7 +39,11 @@ export function joinTextWithImagePlaceholder(text: string, omittedImages: boolea
* multimodal content arrays for. The compatible-mode endpoint also serves
* multimodal Qwen SKUs without `vl` in the id (e.g. `qwen3.7-plus`), so this
* guard only covers families verified to be text-only for issue #1859:
* `qwen*-max` and `qwen*-coder*`.
* `qwen*-coder*` and `qwen*-max` up to and including `qwen3.7-max`.
*
* Qwen-Max became multimodal at `qwen3.8-max` (image input, issue #8019), so
* `-max` SKUs at version 3.8 or newer are excluded — otherwise the override
* would strip images from a genuinely vision-capable flagship (issue #8305).
*
* Used as a defensive override in `convertMessages` so a misconfigured custom
* provider (issue #1859) can't drive the request into an unrecoverable 400.
@@ -48,7 +52,13 @@ export function isDashscopeCompatibleModeTextOnlyQwen(model: Model<"openai-compl
if (!isDashscopeCompatibleModeUrl(model.baseUrl)) {
return false;
}
const id = model.id.toLowerCase();
if (!isQwenModelId(model.id)) return false;
return /\bqwen(?:[\d.]+)?-max\b/.test(id) || /\bqwen(?:[\d.]+)?-coder\b/.test(id);
const id = model.id.toLowerCase();
if (/\bqwen(?:[\d.]+)?-coder\b/.test(id)) return true;
const maxMatch = id.match(/\bqwen(\d+(?:\.\d+)?)?-max\b/);
if (!maxMatch) return false;
// Bare `qwen-max` (undefined version) is the text-only 2.5-era flagship;
// treat missing/pre-3.8 versions as text-only, 3.8+ as multimodal.
const version = maxMatch[1] ? Number.parseFloat(maxMatch[1]) : 0;
return version < 3.8;
}
@@ -394,8 +394,9 @@ describe("openai-completions convertMessages", () => {
it("preserves image_url for DashScope compatible-mode multimodal Qwen models", () => {
// Counter-cases for the issue #1859 guard: DashScope also exposes
// genuinely multimodal Qwen ids without `vl` in the name (`qwen3.7-plus`),
// so the text-only override must be limited to known text-only families.
for (const id of ["qwen3.7-plus", "qwen-vl-max"]) {
// and Qwen-Max is multimodal from `qwen3.8-max` onward (issue #8305), so
// the text-only override must be limited to known text-only families.
for (const id of ["qwen3.7-plus", "qwen-vl-max", "qwen3.8-max", "qwen3.8-max-preview"]) {
const baseModel = getBundledModel("openai", "gpt-4o-mini") as Model<"openai-completions">;
const model: Model<"openai-completions"> = {
...baseModel,