diff --git a/src/extension-host/runtime-backend-catalog.test.ts b/src/extension-host/runtime-backend-catalog.test.ts index eae0e2aa04f..8c3f565e8c3 100644 --- a/src/extension-host/runtime-backend-catalog.test.ts +++ b/src/extension-host/runtime-backend-catalog.test.ts @@ -102,6 +102,11 @@ describe("runtime-backend-catalog", () => { expect(entries.find((entry) => entry.backendId === "edge")?.capabilities).toEqual([ "tts.synthesis", ]); + expect(catalog.listExtensionHostTtsRuntimeBackendIds()).toEqual([ + "openai", + "elevenlabs", + "edge", + ]); }); it("aggregates runtime-backend catalog entries across subsystem families", async () => { diff --git a/src/extension-host/runtime-backend-catalog.ts b/src/extension-host/runtime-backend-catalog.ts index c46188d12a9..e821a375fca 100644 --- a/src/extension-host/runtime-backend-catalog.ts +++ b/src/extension-host/runtime-backend-catalog.ts @@ -1,3 +1,4 @@ +import type { TtsProvider } from "../config/types.tts.js"; import type { MediaUnderstandingCapability } from "../media-understanding/types.js"; import { EXTENSION_HOST_REMOTE_EMBEDDING_PROVIDER_IDS } from "./embedding-runtime-registry.js"; import type { EmbeddingProviderId } from "./embedding-runtime-types.js"; @@ -121,6 +122,12 @@ export function listExtensionHostTtsRuntimeBackendCatalogEntries(): readonly Ext })); } +export function listExtensionHostTtsRuntimeBackendIds(): readonly TtsProvider[] { + return listExtensionHostTtsRuntimeBackendCatalogEntries().map( + (entry) => entry.backendId as TtsProvider, + ); +} + export function listExtensionHostRuntimeBackendCatalogEntries(): readonly ExtensionHostRuntimeBackendCatalogEntry[] { return [ ...listExtensionHostEmbeddingRuntimeBackendCatalogEntries(), diff --git a/src/extension-host/tts-runtime-setup.test.ts b/src/extension-host/tts-runtime-setup.test.ts index 02755343c21..ba31375b2a7 100644 --- a/src/extension-host/tts-runtime-setup.test.ts +++ b/src/extension-host/tts-runtime-setup.test.ts @@ -1,7 +1,7 @@ import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; import os from "node:os"; import path from "node:path"; -import { afterEach, describe, expect, it } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import { withEnv } from "../test-utils/env.js"; import type { ResolvedTtsConfig } from "./tts-config.js"; import { @@ -9,6 +9,10 @@ import { resolveExtensionHostTtsRequestSetup, } from "./tts-runtime-setup.js"; +vi.mock("./runtime-backend-catalog.js", () => ({ + listExtensionHostTtsRuntimeBackendIds: vi.fn(() => ["openai", "elevenlabs", "edge"]), +})); + const tempDirs: string[] = []; function createPrefsPath(contents: object): string { diff --git a/src/extension-host/tts-runtime-setup.ts b/src/extension-host/tts-runtime-setup.ts index 06e062ff3d7..6e15cf7e195 100644 --- a/src/extension-host/tts-runtime-setup.ts +++ b/src/extension-host/tts-runtime-setup.ts @@ -1,10 +1,8 @@ import { existsSync, readFileSync } from "node:fs"; import type { TtsProvider } from "../config/types.tts.js"; +import { listExtensionHostTtsRuntimeBackendIds } from "./runtime-backend-catalog.js"; import type { ResolvedTtsConfig } from "./tts-config.js"; -import { - resolveExtensionHostTtsApiKey, - resolveExtensionHostTtsProviderOrder, -} from "./tts-runtime-registry.js"; +import { resolveExtensionHostTtsApiKey } from "./tts-runtime-registry.js"; type TtsUserPrefs = { tts?: { @@ -67,8 +65,9 @@ export function resolveExtensionHostTtsRequestSetup(params: { const provider = params.providerOverride ?? resolveExtensionHostTtsProvider(params.config, params.prefsPath); + const providerOrder = listExtensionHostTtsRuntimeBackendIds(); return { config: params.config, - providers: resolveExtensionHostTtsProviderOrder(provider), + providers: [provider, ...providerOrder.filter((candidate) => candidate !== provider)], }; } diff --git a/src/extension-host/tts-status.test.ts b/src/extension-host/tts-status.test.ts index 6f5f90426e9..5a4e34beaf6 100644 --- a/src/extension-host/tts-status.test.ts +++ b/src/extension-host/tts-status.test.ts @@ -1,10 +1,14 @@ -import { describe, expect, it } from "vitest"; +import { describe, expect, it, vi } from "vitest"; import { formatExtensionHostTtsStatusText, resolveExtensionHostTtsStatusSnapshot, setExtensionHostLastTtsAttempt, } from "./tts-status.js"; +vi.mock("./runtime-backend-catalog.js", () => ({ + listExtensionHostTtsRuntimeBackendIds: vi.fn(() => ["openai", "elevenlabs", "edge"]), +})); + describe("tts-status", () => { it("builds a status snapshot from host-owned preferences and runtime state", () => { const config = { diff --git a/src/extension-host/tts-status.ts b/src/extension-host/tts-status.ts index ec2d9c2ea38..41af9ad886f 100644 --- a/src/extension-host/tts-status.ts +++ b/src/extension-host/tts-status.ts @@ -1,4 +1,5 @@ import type { TtsProvider } from "../config/types.tts.js"; +import { listExtensionHostTtsRuntimeBackendIds } from "./runtime-backend-catalog.js"; import type { ResolvedTtsConfig } from "./tts-config.js"; import { getExtensionHostTtsMaxLength, @@ -9,7 +10,6 @@ import { import { isExtensionHostTtsProviderConfigured, resolveExtensionHostTtsApiKey, - resolveExtensionHostTtsProviderOrder, } from "./tts-runtime-registry.js"; import { resolveExtensionHostTtsProvider } from "./tts-runtime-setup.js"; @@ -57,8 +57,8 @@ export function resolveExtensionHostTtsStatusSnapshot(params: { }): ExtensionHostTtsStatusSnapshot { const { config, prefsPath } = params; const provider = resolveExtensionHostTtsProvider(config, prefsPath); - const fallbackProviders = resolveExtensionHostTtsProviderOrder(provider) - .slice(1) + const fallbackProviders = listExtensionHostTtsRuntimeBackendIds() + .filter((candidate) => candidate !== provider) .filter((candidate) => isExtensionHostTtsProviderConfigured(config, candidate)); return { enabled: isExtensionHostTtsEnabled(config, prefsPath),