

























1+import { describe, expect, it } from "vitest";
2+import type { SpeechProviderPlugin } from "../plugins/types.js";
3+import { parseTtsDirectives } from "./directives.js";
4+import type {
5+SpeechDirectiveTokenParseContext,
6+SpeechDirectiveTokenParseResult,
7+SpeechModelOverridePolicy,
8+} from "./provider-types.js";
9+10+function makeProvider(
11+id: string,
12+order: number,
13+parse: (ctx: SpeechDirectiveTokenParseContext) => SpeechDirectiveTokenParseResult | undefined,
14+): SpeechProviderPlugin {
15+return {
16+ id,
17+label: id,
18+autoSelectOrder: order,
19+parseDirectiveToken: parse,
20+isConfigured: () => true,
21+synthesize: async () => ({
22+audioBuffer: Buffer.alloc(0),
23+outputFormat: "mp3",
24+fileExtension: ".mp3",
25+voiceCompatible: false,
26+}),
27+} as SpeechProviderPlugin;
28+}
29+30+const elevenlabs = makeProvider("elevenlabs", 10, ({ key, value }) => {
31+if (key === "speed") {
32+return { handled: true, overrides: { speed: Number(value) } };
33+}
34+if (key === "style") {
35+return { handled: true, overrides: { style: Number(value) } };
36+}
37+return undefined;
38+});
39+40+const minimax = makeProvider("minimax", 20, ({ key, value }) => {
41+if (key === "speed") {
42+return { handled: true, overrides: { speed: Number(value) } };
43+}
44+return undefined;
45+});
46+47+const fullPolicy: SpeechModelOverridePolicy = {
48+enabled: true,
49+allowText: true,
50+allowProvider: true,
51+allowVoice: true,
52+allowModelId: true,
53+allowVoiceSettings: true,
54+allowNormalization: true,
55+allowSeed: true,
56+};
57+58+describe("parseTtsDirectives provider-aware routing", () => {
59+it("routes generic speed to the explicitly declared provider", () => {
60+const result = parseTtsDirectives(
61+"hello [[tts:provider=minimax speed=1.2]] world",
62+fullPolicy,
63+{
64+providers: [elevenlabs, minimax],
65+},
66+);
67+68+expect(result.overrides.provider).toBe("minimax");
69+expect(result.overrides.providerOverrides?.minimax).toEqual({ speed: 1.2 });
70+expect(result.overrides.providerOverrides?.elevenlabs).toBeUndefined();
71+});
72+73+it("routes correctly when provider appears after the generic token", () => {
74+const result = parseTtsDirectives("[[tts:speed=1.2 provider=minimax]] hi", fullPolicy, {
75+providers: [elevenlabs, minimax],
76+});
77+78+expect(result.overrides.provider).toBe("minimax");
79+expect(result.overrides.providerOverrides?.minimax).toEqual({ speed: 1.2 });
80+expect(result.overrides.providerOverrides?.elevenlabs).toBeUndefined();
81+});
82+83+it("routes to the preferred provider when no provider token is declared", () => {
84+const result = parseTtsDirectives("[[tts:speed=1.5]]", fullPolicy, {
85+providers: [elevenlabs, minimax],
86+preferredProviderId: "minimax",
87+});
88+89+expect(result.overrides.provider).toBeUndefined();
90+expect(result.overrides.providerOverrides?.minimax).toEqual({ speed: 1.5 });
91+expect(result.overrides.providerOverrides?.elevenlabs).toBeUndefined();
92+});
93+94+it("falls back to autoSelectOrder when no provider hint is available", () => {
95+const result = parseTtsDirectives("[[tts:speed=1.5]]", fullPolicy, {
96+providers: [elevenlabs, minimax],
97+});
98+99+expect(result.overrides.provider).toBeUndefined();
100+expect(result.overrides.providerOverrides?.elevenlabs).toEqual({ speed: 1.5 });
101+expect(result.overrides.providerOverrides?.minimax).toBeUndefined();
102+});
103+104+it("falls through when the preferred provider does not handle the key", () => {
105+const result = parseTtsDirectives("[[tts:provider=minimax style=0.4]]", fullPolicy, {
106+providers: [elevenlabs, minimax],
107+});
108+109+expect(result.overrides.provider).toBe("minimax");
110+expect(result.overrides.providerOverrides?.elevenlabs).toEqual({ style: 0.4 });
111+expect(result.overrides.providerOverrides?.minimax).toBeUndefined();
112+});
113+114+it("routes mixed tokens independently in the same directive", () => {
115+const result = parseTtsDirectives("[[tts:provider=minimax style=0.4 speed=1.2]]", fullPolicy, {
116+providers: [elevenlabs, minimax],
117+});
118+119+expect(result.overrides.provider).toBe("minimax");
120+expect(result.overrides.providerOverrides?.minimax).toEqual({ speed: 1.2 });
121+expect(result.overrides.providerOverrides?.elevenlabs).toEqual({ style: 0.4 });
122+});
123+124+it("keeps last-wins provider semantics", () => {
125+const result = parseTtsDirectives(
126+"[[tts:provider=elevenlabs provider=minimax speed=1.1]]",
127+fullPolicy,
128+{ providers: [elevenlabs, minimax] },
129+);
130+131+expect(result.overrides.provider).toBe("minimax");
132+expect(result.overrides.providerOverrides?.minimax).toEqual({ speed: 1.1 });
133+expect(result.overrides.providerOverrides?.elevenlabs).toBeUndefined();
134+});
135+136+it("ignores provider tokens when provider overrides are disabled", () => {
137+const policy: SpeechModelOverridePolicy = { ...fullPolicy, allowProvider: false };
138+const result = parseTtsDirectives("[[tts:provider=elevenlabs speed=1.2]]", policy, {
139+providers: [elevenlabs, minimax],
140+preferredProviderId: "minimax",
141+});
142+143+expect(result.overrides.provider).toBeUndefined();
144+expect(result.overrides.providerOverrides?.minimax).toEqual({ speed: 1.2 });
145+expect(result.overrides.providerOverrides?.elevenlabs).toBeUndefined();
146+});
147+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。