

























@@ -11,10 +11,12 @@ function makeProvider(
1111id: string,
1212order: number,
1313parse: (ctx: SpeechDirectiveTokenParseContext) => SpeechDirectiveTokenParseResult | undefined,
14+options?: { aliases?: string[] },
1415): SpeechProviderPlugin {
1516return {
1617 id,
1718label: id,
19+aliases: options?.aliases,
1820autoSelectOrder: order,
1921parseDirectiveToken: parse,
2022isConfigured: () => true,
@@ -123,24 +125,111 @@ describe("parseTtsDirectives provider-aware routing", () => {
123125expect(result.overrides.providerOverrides?.minimax).toBeUndefined();
124126});
125127126-it("falls through when the preferred provider does not handle the key", () => {
128+it("does not fall through when the explicit provider does not handle the key", () => {
127129const result = parseTtsDirectives("[[tts:provider=minimax style=0.4]]", fullPolicy, {
128130providers: [elevenlabs, minimax],
129131});
130132131133expect(result.overrides.provider).toBe("minimax");
132-expect(result.overrides.providerOverrides?.elevenlabs).toEqual({ style: 0.4 });
134+expect(result.overrides.providerOverrides?.elevenlabs).toBeUndefined();
133135expect(result.overrides.providerOverrides?.minimax).toBeUndefined();
136+expect(result.warnings).toContain('unsupported minimax directive key "style"');
134137});
135138136-it("routes mixed tokens independently in the same directive", () => {
139+it("keeps explicit-provider tokens scoped to the selected provider", () => {
137140const result = parseTtsDirectives("[[tts:provider=minimax style=0.4 speed=1.2]]", fullPolicy, {
138141providers: [elevenlabs, minimax],
139142});
140143141144expect(result.overrides.provider).toBe("minimax");
142145expect(result.overrides.providerOverrides?.minimax).toEqual({ speed: 1.2 });
143-expect(result.overrides.providerOverrides?.elevenlabs).toEqual({ style: 0.4 });
146+expect(result.overrides.providerOverrides?.elevenlabs).toBeUndefined();
147+expect(result.warnings).toContain('unsupported minimax directive key "style"');
148+});
149+150+it("does not route explicit provider tokens to another provider with overlapping keys", () => {
151+const openai = makeProvider("openai", 10, ({ key, value }) => {
152+if (key === "model") {
153+return { handled: true, overrides: { model: value } };
154+}
155+return undefined;
156+});
157+const elevenlabsModel = makeProvider("elevenlabs", 20, ({ key, value }) => {
158+if (key === "model") {
159+return { handled: true, overrides: { modelId: value } };
160+}
161+return undefined;
162+});
163+164+const result = parseTtsDirectives("[[tts:provider=elevenlabs model=eleven_v3]]", fullPolicy, {
165+providers: [openai, elevenlabsModel],
166+});
167+168+expect(result.overrides.provider).toBe("elevenlabs");
169+expect(result.overrides.providerOverrides?.elevenlabs).toEqual({ modelId: "eleven_v3" });
170+expect(result.overrides.providerOverrides?.openai).toBeUndefined();
171+expect(result.warnings).toEqual([]);
172+});
173+174+it("warns instead of routing prefixed tokens to another provider when provider is explicit", () => {
175+const result = parseTtsDirectives(
176+"[[tts:provider=elevenlabs openai_model=gpt-4o-mini-tts]]",
177+fullPolicy,
178+{ providers: [elevenlabs, minimax] },
179+);
180+181+expect(result.overrides.provider).toBe("elevenlabs");
182+expect(result.overrides.providerOverrides).toBeUndefined();
183+expect(result.warnings).toContain('unsupported elevenlabs directive key "openai_model"');
184+});
185+186+it("passes the selected provider id to the chosen provider parser", () => {
187+let selectedProvider: string | undefined;
188+const selected = makeProvider("selected", 10, (ctx) => {
189+selectedProvider = ctx.selectedProvider;
190+return { handled: true, overrides: { voice: ctx.value } };
191+});
192+193+const result = parseTtsDirectives("[[tts:provider=selected voice=test]]", fullPolicy, {
194+providers: [selected],
195+});
196+197+expect(result.overrides.providerOverrides?.selected).toEqual({ voice: "test" });
198+expect(selectedProvider).toBe("selected");
199+});
200+201+it("resolves explicit provider aliases without rewriting the requested provider value", () => {
202+const microsoft = makeProvider(
203+"microsoft",
204+10,
205+({ key, value }) =>
206+key === "voice" ? { handled: true, overrides: { voice: value } } : undefined,
207+{ aliases: ["edge"] },
208+);
209+210+const result = parseTtsDirectives(
211+"[[tts:provider=edge voice=en-US-MichelleNeural]]",
212+fullPolicy,
213+{
214+providers: [microsoft],
215+},
216+);
217+218+expect(result.overrides.provider).toBe("edge");
219+expect(result.overrides.providerOverrides?.microsoft).toEqual({
220+voice: "en-US-MichelleNeural",
221+});
222+expect(result.warnings).toEqual([]);
223+});
224+225+it("warns once and drops non-provider tokens when the explicit provider is unknown", () => {
226+const result = parseTtsDirectives("[[tts:provider=missing speed=1.2 style=0.4]]", fullPolicy, {
227+providers: [elevenlabs, minimax],
228+});
229+230+expect(result.overrides.provider).toBe("missing");
231+expect(result.overrides.providerOverrides).toBeUndefined();
232+expect(result.warnings).toEqual(['unknown provider "missing"']);
144233});
145234146235it("keeps last-wins provider semantics", () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。