Skip to content

Commit d72115c

Browse files
committed
refactor: genericize speech provider config surface
1 parent 83ca6fb commit d72115c

26 files changed

Lines changed: 607 additions & 665 deletions

docs/.generated/plugin-sdk-api-baseline.json

Lines changed: 107 additions & 89 deletions
Large diffs are not rendered by default.

docs/.generated/plugin-sdk-api-baseline.jsonl

Lines changed: 91 additions & 89 deletions
Large diffs are not rendered by default.

docs/reference/secretref-credential-surface.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ Scope intent:
2929
- `agents.list[].memorySearch.remote.apiKey`
3030
- `talk.apiKey`
3131
- `talk.providers.*.apiKey`
32-
- `messages.tts.elevenlabs.apiKey`
33-
- `messages.tts.openai.apiKey`
32+
- `messages.tts.providers.*.apiKey`
3433
- `tools.web.fetch.firecrawl.apiKey`
3534
- `plugins.entries.brave.config.webSearch.apiKey`
3635
- `plugins.entries.google.config.webSearch.apiKey`
@@ -63,12 +62,10 @@ Scope intent:
6362
- `channels.slack.accounts.*.signingSecret`
6463
- `channels.discord.token`
6564
- `channels.discord.pluralkit.token`
66-
- `channels.discord.voice.tts.elevenlabs.apiKey`
67-
- `channels.discord.voice.tts.openai.apiKey`
65+
- `channels.discord.voice.tts.providers.*.apiKey`
6866
- `channels.discord.accounts.*.token`
6967
- `channels.discord.accounts.*.pluralkit.token`
70-
- `channels.discord.accounts.*.voice.tts.elevenlabs.apiKey`
71-
- `channels.discord.accounts.*.voice.tts.openai.apiKey`
68+
- `channels.discord.accounts.*.voice.tts.providers.*.apiKey`
7269
- `channels.irc.password`
7370
- `channels.irc.nickserv.password`
7471
- `channels.irc.accounts.*.password`

docs/reference/secretref-user-supplied-credentials-matrix.json

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,9 @@
8080
"optIn": true
8181
},
8282
{
83-
"id": "channels.discord.accounts.*.voice.tts.elevenlabs.apiKey",
83+
"id": "channels.discord.accounts.*.voice.tts.providers.*.apiKey",
8484
"configFile": "openclaw.json",
85-
"path": "channels.discord.accounts.*.voice.tts.elevenlabs.apiKey",
86-
"secretShape": "secret_input",
87-
"optIn": true
88-
},
89-
{
90-
"id": "channels.discord.accounts.*.voice.tts.openai.apiKey",
91-
"configFile": "openclaw.json",
92-
"path": "channels.discord.accounts.*.voice.tts.openai.apiKey",
85+
"path": "channels.discord.accounts.*.voice.tts.providers.*.apiKey",
9386
"secretShape": "secret_input",
9487
"optIn": true
9588
},
@@ -108,16 +101,9 @@
108101
"optIn": true
109102
},
110103
{
111-
"id": "channels.discord.voice.tts.elevenlabs.apiKey",
104+
"id": "channels.discord.voice.tts.providers.*.apiKey",
112105
"configFile": "openclaw.json",
113-
"path": "channels.discord.voice.tts.elevenlabs.apiKey",
114-
"secretShape": "secret_input",
115-
"optIn": true
116-
},
117-
{
118-
"id": "channels.discord.voice.tts.openai.apiKey",
119-
"configFile": "openclaw.json",
120-
"path": "channels.discord.voice.tts.openai.apiKey",
106+
"path": "channels.discord.voice.tts.providers.*.apiKey",
121107
"secretShape": "secret_input",
122108
"optIn": true
123109
},
@@ -420,16 +406,9 @@
420406
"optIn": true
421407
},
422408
{
423-
"id": "messages.tts.elevenlabs.apiKey",
424-
"configFile": "openclaw.json",
425-
"path": "messages.tts.elevenlabs.apiKey",
426-
"secretShape": "secret_input",
427-
"optIn": true
428-
},
429-
{
430-
"id": "messages.tts.openai.apiKey",
409+
"id": "messages.tts.providers.*.apiKey",
431410
"configFile": "openclaw.json",
432-
"path": "messages.tts.openai.apiKey",
411+
"path": "messages.tts.providers.*.apiKey",
433412
"secretShape": "secret_input",
434413
"optIn": true
435414
},

extensions/browser/src/browser-runtime.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export {
2424
browserTabAction,
2525
browserTabs,
2626
} from "./browser/client.js";
27+
export { runBrowserProxyCommand } from "./node-host/invoke-browser.js";
2728
export type {
2829
BrowserCreateProfileResult,
2930
BrowserDeleteProfileResult,

extensions/discord/src/voice/manager.ts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -72,29 +72,31 @@ function mergeTtsConfig(base: TtsConfig, override?: TtsConfig): TtsConfig {
7272
if (!override) {
7373
return base;
7474
}
75+
const baseProviders = base.providers ?? {};
76+
const overrideProviders = override.providers ?? {};
77+
const mergedProviders = Object.fromEntries(
78+
[...new Set([...Object.keys(baseProviders), ...Object.keys(overrideProviders)])].map(
79+
(providerId) => {
80+
const baseProvider = baseProviders[providerId] ?? {};
81+
const overrideProvider = overrideProviders[providerId] ?? {};
82+
return [
83+
providerId,
84+
{
85+
...baseProvider,
86+
...overrideProvider,
87+
},
88+
];
89+
},
90+
),
91+
);
7592
return {
7693
...base,
7794
...override,
7895
modelOverrides: {
7996
...base.modelOverrides,
8097
...override.modelOverrides,
8198
},
82-
elevenlabs: {
83-
...base.elevenlabs,
84-
...override.elevenlabs,
85-
voiceSettings: {
86-
...base.elevenlabs?.voiceSettings,
87-
...override.elevenlabs?.voiceSettings,
88-
},
89-
},
90-
openai: {
91-
...base.openai,
92-
...override.openai,
93-
},
94-
edge: {
95-
...base.edge,
96-
...override.edge,
97-
},
99+
...(Object.keys(mergedProviders).length === 0 ? {} : { providers: mergedProviders }),
98100
};
99101
}
100102

extensions/elevenlabs/speech-provider.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,13 @@ function normalizeElevenLabsBaseUrl(baseUrl: string | undefined): string {
9494
function normalizeElevenLabsProviderConfig(
9595
rawConfig: Record<string, unknown>,
9696
): ElevenLabsProviderConfig {
97-
const raw = asObject(rawConfig.elevenlabs);
97+
const providers = asObject(rawConfig.providers);
98+
const raw = asObject(providers?.elevenlabs) ?? asObject(rawConfig.elevenlabs);
9899
const rawVoiceSettings = asObject(raw?.voiceSettings);
99100
return {
100101
apiKey: normalizeResolvedSecretInputString({
101102
value: raw?.apiKey,
102-
path: "messages.tts.elevenlabs.apiKey",
103+
path: "messages.tts.providers.elevenlabs.apiKey",
103104
}),
104105
baseUrl: normalizeElevenLabsBaseUrl(trimToUndefined(raw?.baseUrl)),
105106
voiceId: trimToUndefined(raw?.voiceId) ?? DEFAULT_ELEVENLABS_VOICE_ID,

extensions/microsoft/speech-provider.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,11 @@ function asObject(value: unknown): Record<string, unknown> | undefined {
6464
function normalizeMicrosoftProviderConfig(
6565
rawConfig: Record<string, unknown>,
6666
): MicrosoftProviderConfig {
67+
const providers = asObject(rawConfig.providers);
6768
const rawEdge = asObject(rawConfig.edge);
6869
const rawMicrosoft = asObject(rawConfig.microsoft);
69-
const raw = { ...(rawEdge ?? {}), ...(rawMicrosoft ?? {}) };
70+
const rawProvider = asObject(providers?.microsoft);
71+
const raw = { ...(rawEdge ?? {}), ...(rawMicrosoft ?? {}), ...(rawProvider ?? {}) };
7072
const outputFormat = trimToUndefined(raw.outputFormat);
7173
return {
7274
enabled: asBoolean(raw.enabled) ?? true,

extensions/openai/speech-provider.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,12 @@ function asObject(value: unknown): Record<string, unknown> | undefined {
4747
function normalizeOpenAIProviderConfig(
4848
rawConfig: Record<string, unknown>,
4949
): OpenAITtsProviderConfig {
50-
const raw = asObject(rawConfig.openai);
50+
const providers = asObject(rawConfig.providers);
51+
const raw = asObject(providers?.openai) ?? asObject(rawConfig.openai);
5152
return {
5253
apiKey: normalizeResolvedSecretInputString({
5354
value: raw?.apiKey,
54-
path: "messages.tts.openai.apiKey",
55+
path: "messages.tts.providers.openai.apiKey",
5556
}),
5657
baseUrl: normalizeOpenAITtsBaseUrl(
5758
trimToUndefined(raw?.baseUrl) ??

extensions/voice-call/src/config.test.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ function createBaseConfig(provider: "telnyx" | "twilio" | "plivo" | "mock"): Voi
1313

1414
function requireElevenLabsTtsConfig(config: Pick<VoiceCallConfig, "tts">) {
1515
const tts = config.tts;
16-
if (!tts?.elevenlabs) {
16+
const elevenlabs = tts?.providers?.elevenlabs;
17+
if (!elevenlabs || typeof elevenlabs !== "object") {
1718
throw new Error("voice-call config did not preserve nested elevenlabs TTS config");
1819
}
19-
return { tts, elevenlabs: tts.elevenlabs };
20+
return { tts, elevenlabs };
2021
}
2122

2223
describe("validateProviderConfig", () => {
@@ -202,14 +203,16 @@ describe("normalizeVoiceCallConfig", () => {
202203
const normalized = normalizeVoiceCallConfig({
203204
tts: {
204205
provider: "elevenlabs",
205-
elevenlabs: {
206-
apiKey: {
207-
source: "env",
208-
provider: "elevenlabs",
209-
id: "ELEVENLABS_API_KEY",
210-
},
211-
voiceSettings: {
212-
speed: 1.1,
206+
providers: {
207+
elevenlabs: {
208+
apiKey: {
209+
source: "env",
210+
provider: "elevenlabs",
211+
id: "ELEVENLABS_API_KEY",
212+
},
213+
voiceSettings: {
214+
speed: 1.1,
215+
},
213216
},
214217
},
215218
},

0 commit comments

Comments
 (0)