Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions packages/commands/src/commands/config/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export const UI_MODEL_DEFAULTS: Record<string, string> = {
default_reference_to_video_model: "wan3.0-video",
default_speech_model: "cosyvoice-v3-flash",
default_speech_recognition_model: "fun-asr",
default_omni_model: "qwen3.5-omni-plus",
default_omni_model: "qwen3.8-omni-flash",
};

/** One selectable model plus a short note on where the CLI uses it. */
Expand Down Expand Up @@ -131,7 +131,8 @@ export const UI_MODEL_CATALOG: Record<string, ModelOption[]> = {
{ id: "qwen-audio-3.0-asr-flash", role: "Token Plan speech/recognize (ASR)" },
],
default_omni_model: [
{ id: "qwen3.5-omni-plus", role: "omni/chat default" },
{ id: "qwen3.8-omni-flash", role: "omni/chat default · --text-only" },
{ id: "qwen3.5-omni-plus", role: "omni/chat · audio output path (without --text-only)" },
{ id: "qwen3-vl-plus", role: "vision/describe · multimodal input" },
],
};
Expand Down
24 changes: 20 additions & 4 deletions packages/commands/src/commands/omni/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,10 @@ export default defineCommand({
type: "string",
valueHint: "<model>",
description: {
"en-US": "Model ID (default: qwen3.5-omni-plus)",
"zh-CN": "模型 ID(默认:qwen3.5-omni-plus)",
"en-US":
"Model ID (default: qwen3.8-omni-flash; when --model is omitted and --text-only is absent, auto-switches to qwen3.5-omni-plus for audio output)",
"zh-CN":
"模型 ID(默认:qwen3.8-omni-flash;省略 --model 且未带 --text-only 时,自动切换为支持音频输出的 qwen3.5-omni-plus)",
},
},
system: {
Expand Down Expand Up @@ -275,12 +277,26 @@ export default defineCommand({
// --- Parse messages ---
const userMessages = flags.message ?? [];

const model = flags.model || settings.defaultOmniModel || "qwen3.5-omni-plus";
// Default to flash; switch to plus when --model is omitted and --text-only is absent (flash has no audio out).
const textOnly = flags.textOnly === true;
let model = flags.model || settings.defaultOmniModel || "qwen3.8-omni-flash";
if (!flags.model && !textOnly && model === "qwen3.8-omni-flash") {
model = "qwen3.5-omni-plus";
}
const voice = flags.voice || "Tina";
const audioFormat = flags.audioFormat || "wav";
const textOnly = flags.textOnly === true;
const format = settings.output;

// Explicit flash + audio path will be rejected by the server; warn locally without overriding --model.
if (flags.model === "qwen3.8-omni-flash" && !textOnly) {
ctx.output.warning({
"en-US":
"qwen3.8-omni-flash does not support audio output. Add --text-only, or omit --model to auto-switch to qwen3.5-omni-plus.",
"zh-CN":
"qwen3.8-omni-flash 不支持音频输出。请添加 --text-only,或省略 --model 以自动切换为 qwen3.5-omni-plus。",
});
}

// --- Build messages array ---
const allMessages: ChatMessage[] = [];
if (flags.system) {
Expand Down
41 changes: 36 additions & 5 deletions packages/commands/tests/e2e/omni.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
parseStdoutJson,
runCommandHelp,
runCommandE2e,
runCommandInProcess,
} from "./helpers.ts";
import { OMNI_ROUTES } from "./topic-routes.ts";

Expand All @@ -17,6 +18,36 @@ describe("e2e: omni", () => {
expect(exitCode, stderr).toBe(0);
expect(stderr).toMatch(/omni|--message|--audio|text-only/i);
});

test("omni --dry-run 无 --model/--text-only 时自动切换为 qwen3.5-omni-plus 并带 audio modalities", async () => {
const { stdout, stderr, exitCode } = await runCommandInProcess(
OMNI_ROUTES,
["omni", "--dry-run", "--message", "hi", "--output", "json"],
{ DASHSCOPE_API_KEY: "" },
);
expect(exitCode, stderr).toBe(0);
const data = parseStdoutJson<{
request?: { model?: string; modalities?: string[]; audio?: unknown };
}>(stdout);
expect(data.request?.model).toBe("qwen3.5-omni-plus");
expect(data.request?.modalities).toEqual(["text", "audio"]);
expect(data.request?.audio).toBeTruthy();
});

test("omni --dry-run 无 --model 且带 --text-only 时使用 qwen3.8-omni-flash 且无 modalities", async () => {
const { stdout, stderr, exitCode } = await runCommandInProcess(
OMNI_ROUTES,
["omni", "--dry-run", "--text-only", "--message", "hi", "--output", "json"],
{ DASHSCOPE_API_KEY: "" },
);
expect(exitCode, stderr).toBe(0);
const data = parseStdoutJson<{
request?: { model?: string; modalities?: string[]; audio?: unknown };
}>(stdout);
expect(data.request?.model).toBe("qwen3.8-omni-flash");
expect(data.request?.modalities).toBeUndefined();
expect(data.request?.audio).toBeUndefined();
});
});

describe.skipIf(!isBailianE2EMediaEnabled() || !isDashScopeE2EReady())(
Expand All @@ -38,7 +69,7 @@ describe.skipIf(!isBailianE2EMediaEnabled() || !isDashScopeE2EReady())(
const { stderr, exitCode } = await runCommandE2e(OMNI_ROUTES, [
"omni",
"--model",
"qwen3.5-omni-flash",
"qwen3.8-omni-flash",
]);
expect(exitCode).toBe(2);
expect(stderr).toMatch(/--message|Usage:/i);
Expand All @@ -48,7 +79,7 @@ describe.skipIf(!isBailianE2EMediaEnabled() || !isDashScopeE2EReady())(
const { stderr, exitCode } = await runCommandE2e(OMNI_ROUTES, [
"omni",
"--model",
"qwen3.5-omni-flash",
"qwen3.8-omni-flash",
"--audio",
"https://example.com/sample.flac",
"--text-only",
Expand All @@ -64,7 +95,7 @@ describe.skipIf(!isBailianE2EMediaEnabled() || !isDashScopeE2EReady())(
"omni",
"--dry-run",
"--model",
"qwen3.5-omni-flash",
"qwen3.8-omni-flash",
"--audio",
"https://example.com/sample.wav",
"--text-only",
Expand Down Expand Up @@ -95,7 +126,7 @@ describe.skipIf(!isBailianE2EMediaEnabled() || !isDashScopeE2EReady())(
expect(audioPart?.input_audio?.format).toBe("wav");
});

test("【qwen3.5-omni-flash】本地音频理解", async () => {
test("【qwen3.8-omni-flash】本地音频理解", async () => {
const outDir = makeE2eOutputDir(e2eLabelFromMetaUrl(import.meta.url));
const clipText = "端到端Omni音频测试";
const clipWav = join(outDir, "e2e-omni-input.wav");
Expand All @@ -121,7 +152,7 @@ describe.skipIf(!isBailianE2EMediaEnabled() || !isDashScopeE2EReady())(
const omni = await runCommandE2e(OMNI_ROUTES, [
"omni",
"--model",
"qwen3.5-omni-flash",
"qwen3.8-omni-flash",
"--audio",
clipWav,
"--text-only",
Expand Down
22 changes: 11 additions & 11 deletions skills/bailian-gen/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@ BAILIAN_CALLER_TYPE=agent BAILIAN_CALLER_NAME=codex BAILIAN_SKILL_NAME=bailian-g

## When to use which command

| User intent | Command | Default model |
| ---------------------------------------- | ----------------------------------------- | --------------------------------------------------- |
| Text-to-image | `bl image generate` | `qwen-image-3.0` |
| Image edit / multi-image merge | `bl image edit` (repeat `--image`) | `qwen-image-3.0` |
| Text-to-video / image-to-video | `bl video generate` | `wan3.0-video` |
| Video edit / style transfer | `bl video edit` | `happyhorse-1.0-video-edit` |
| Reference-to-video + voice | `bl video ref` | `wan3.0-video` |
| Speech synthesis (TTS / voiceover) | `bl speech synthesize` | `cosyvoice-v3-flash` |
| Speech recognition (ASR / transcription) | `bl speech recognize` | `fun-asr` |
| Image describe | `bl vision describe` | `qwen3-vl-plus`;宿主能做且未点名 → host-first |
| Video / A-V understand | `bl vision describe --video` 或 `bl omni` | 视频理解默认走百炼;`omni` 默认 `qwen3.5-omni-plus` |
| User intent | Command | Default model |
| ---------------------------------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Text-to-image | `bl image generate` | `qwen-image-3.0` |
| Image edit / multi-image merge | `bl image edit` (repeat `--image`) | `qwen-image-3.0` |
| Text-to-video / image-to-video | `bl video generate` | `wan3.0-video` |
| Video edit / style transfer | `bl video edit` | `happyhorse-1.0-video-edit` |
| Reference-to-video + voice | `bl video ref` | `wan3.0-video` |
| Speech synthesis (TTS / voiceover) | `bl speech synthesize` | `cosyvoice-v3-flash` |
| Speech recognition (ASR / transcription) | `bl speech recognize` | `fun-asr` |
| Image describe | `bl vision describe` | `qwen3-vl-plus`;宿主能做且未点名 → host-first |
| Video / A-V understand | `bl vision describe --video` 或 `bl omni` | 视频理解默认走百炼;`omni` 默认 `qwen3.8-omni-flash`,省略 `--model` 且无 `--text-only` 时自动切换 `qwen3.5-omni-plus` |

Unless the user explicitly specifies a model, omit `--model` and let the CLI use the active Profile’s default.

Expand Down
34 changes: 17 additions & 17 deletions skills/bailian-gen/reference/omni.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,23 @@ Index: [index.md](index.md)

#### Flags

| Flag | Type | Required | Description |
| ---------------------- | ------ | -------- | --------------------------------------------------------------------- |
| `--message <text>` | array | no | Message text (repeatable, prefix role: to set role) |
| `--model <model>` | string | no | Model ID (default: qwen3.5-omni-plus) |
| `--system <text>` | string | no | System prompt |
| `--image <url>` | array | no | Image URL or local file (repeatable) |
| `--audio <url>` | array | no | Audio URL or local file (.wav/.mp3/.amr/.aac/.m4a/.ogg/.3gp/.3gpp) |
| `--video <url>` | array | no | Video file URL / local path, or comma-separated frame URLs |
| `--voice <voice>` | string | no | Output voice ID (default: Tina). Use --list-voices to see all options |
| `--list-voices` | switch | no | List available output voices and exit |
| `--audio-format <fmt>` | string | no | Audio output format (default: wav) |
| `--audio-out <path>` | string | no | Save audio to file (default: auto-generate) |
| `--text-only` | switch | no | Output text only, no audio generation |
| `--max-tokens <n>` | number | no | Maximum tokens to generate |
| `--temperature <n>` | number | no | Sampling temperature (0.0, 2.0] |
| `--api-key <key>` | string | no | API key |
| `--base-url <url>` | string | no | API base URL |
| Flag | Type | Required | Description |
| ---------------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `--message <text>` | array | no | Message text (repeatable, prefix role: to set role) |
| `--model <model>` | string | no | Model ID (default: qwen3.8-omni-flash; when --model is omitted and --text-only is absent, auto-switches to qwen3.5-omni-plus for audio output) |
| `--system <text>` | string | no | System prompt |
| `--image <url>` | array | no | Image URL or local file (repeatable) |
| `--audio <url>` | array | no | Audio URL or local file (.wav/.mp3/.amr/.aac/.m4a/.ogg/.3gp/.3gpp) |
| `--video <url>` | array | no | Video file URL / local path, or comma-separated frame URLs |
| `--voice <voice>` | string | no | Output voice ID (default: Tina). Use --list-voices to see all options |
| `--list-voices` | switch | no | List available output voices and exit |
| `--audio-format <fmt>` | string | no | Audio output format (default: wav) |
| `--audio-out <path>` | string | no | Save audio to file (default: auto-generate) |
| `--text-only` | switch | no | Output text only, no audio generation |
| `--max-tokens <n>` | number | no | Maximum tokens to generate |
| `--temperature <n>` | number | no | Sampling temperature (0.0, 2.0] |
| `--api-key <key>` | string | no | API key |
| `--base-url <url>` | string | no | API base URL |

#### Examples

Expand Down
Loading