Skip to content

Commit 9bee0d4

Browse files
authored
refactor(deadcode): tighten more provider extension roots (#108515)
1 parent 16801bf commit 9bee0d4

28 files changed

Lines changed: 450 additions & 319 deletions

config/knip.config.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,15 +373,26 @@ const config = {
373373
project: ["index.js!", "scripts/**/*.js!"],
374374
},
375375
[`${BUNDLED_PLUGIN_ROOT_DIR}/amazon-bedrock-mantle`]: strictBundledPluginWorkspace(),
376+
[`${BUNDLED_PLUGIN_ROOT_DIR}/azure-speech`]: strictBundledPluginWorkspace(),
377+
[`${BUNDLED_PLUGIN_ROOT_DIR}/cloudflare-ai-gateway`]: strictBundledPluginWorkspace(),
376378
[`${BUNDLED_PLUGIN_ROOT_DIR}/cohere`]: strictBundledPluginWorkspace(),
379+
[`${BUNDLED_PLUGIN_ROOT_DIR}/deepgram`]: strictBundledPluginWorkspace(),
380+
[`${BUNDLED_PLUGIN_ROOT_DIR}/elevenlabs`]: strictBundledPluginWorkspace(),
377381
[`${BUNDLED_PLUGIN_ROOT_DIR}/featherless`]: strictBundledPluginWorkspace(),
378382
[`${BUNDLED_PLUGIN_ROOT_DIR}/fireworks`]: strictBundledPluginWorkspace(),
379383
[`${BUNDLED_PLUGIN_ROOT_DIR}/huggingface`]: strictBundledPluginWorkspace(),
380384
[`${BUNDLED_PLUGIN_ROOT_DIR}/kilocode`]: strictBundledPluginWorkspace(),
385+
[`${BUNDLED_PLUGIN_ROOT_DIR}/kimi-coding`]: strictBundledPluginWorkspace(),
386+
[`${BUNDLED_PLUGIN_ROOT_DIR}/microsoft`]: strictBundledPluginWorkspace(),
387+
[`${BUNDLED_PLUGIN_ROOT_DIR}/minimax`]: strictBundledPluginWorkspace(),
388+
[`${BUNDLED_PLUGIN_ROOT_DIR}/mistral`]: strictBundledPluginWorkspace(),
389+
[`${BUNDLED_PLUGIN_ROOT_DIR}/moonshot`]: strictBundledPluginWorkspace(),
381390
[`${BUNDLED_PLUGIN_ROOT_DIR}/nvidia`]: strictBundledPluginWorkspace(),
391+
[`${BUNDLED_PLUGIN_ROOT_DIR}/pixverse`]: strictBundledPluginWorkspace(),
382392
[`${BUNDLED_PLUGIN_ROOT_DIR}/qianfan`]: strictBundledPluginWorkspace(),
383393
[`${BUNDLED_PLUGIN_ROOT_DIR}/qwen`]: strictBundledPluginWorkspace(),
384394
[`${BUNDLED_PLUGIN_ROOT_DIR}/senseaudio`]: strictBundledPluginWorkspace(),
395+
[`${BUNDLED_PLUGIN_ROOT_DIR}/tavily`]: strictBundledPluginWorkspace(),
385396
[`${BUNDLED_PLUGIN_ROOT_DIR}/tencent`]: strictBundledPluginWorkspace(),
386397
[`${BUNDLED_PLUGIN_ROOT_DIR}/vllm`]: strictBundledPluginWorkspace(),
387398
[`${BUNDLED_PLUGIN_ROOT_DIR}/xiaomi`]: strictBundledPluginWorkspace(),

extensions/azure-speech/tts.test.ts

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { installPinnedHostnameTestHooks } from "openclaw/plugin-sdk/test-env";
33
import { afterEach, describe, expect, it, vi } from "vitest";
44
import {
55
azureSpeechTTS,
6-
buildAzureSpeechSsml,
76
inferAzureSpeechFileExtension,
87
isAzureSpeechVoiceCompatible,
98
listAzureSpeechVoices,
@@ -43,21 +42,6 @@ describe("azure speech tts", () => {
4342
vi.restoreAllMocks();
4443
});
4544

46-
it("escapes SSML text and attributes", () => {
47-
expect(
48-
buildAzureSpeechSsml({
49-
text: `Tom & "Jerry" <tag>`,
50-
voice: `en-US-JennyNeural" xml:lang="evil`,
51-
lang: `en-US" bad="1`,
52-
}),
53-
).toBe(
54-
`<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" ` +
55-
`xml:lang="en-US&quot; bad=&quot;1">` +
56-
`<voice name="en-US-JennyNeural&quot; xml:lang=&quot;evil">` +
57-
`Tom &amp; "Jerry" &lt;tag&gt;</voice></speak>`,
58-
);
59-
});
60-
6145
it("normalizes region and endpoint routing", () => {
6246
expect(normalizeAzureSpeechBaseUrl({ region: "eastus" })).toBe(
6347
"https://eastus.tts.speech.microsoft.com",
@@ -86,11 +70,11 @@ describe("azure speech tts", () => {
8670
vi.stubGlobal("fetch", fetchMock);
8771

8872
const result = await azureSpeechTTS({
89-
text: "hello",
90-
apiKey: "speech-key",
73+
text: `Tom & "Jerry" <tag>`,
74+
apiKey: "fixture-value",
9175
region: "eastus",
92-
voice: "en-US-JennyNeural",
93-
lang: "en-US",
76+
voice: `en-US-JennyNeural" xml:lang="evil`,
77+
lang: `en-US" bad="1`,
9478
outputFormat: "audio-24khz-48kbitrate-mono-mp3",
9579
timeoutMs: 1234,
9680
});
@@ -101,10 +85,15 @@ describe("azure speech tts", () => {
10185
expect(url).toBe("https://eastus.tts.speech.microsoft.com/cognitiveservices/v1");
10286
expect(init.method).toBe("POST");
10387
const headers = new Headers(init.headers);
104-
expect(headers.get("Ocp-Apim-Subscription-Key")).toBe("speech-key");
88+
expect(headers.get("Ocp-Apim-Subscription-Key")).toBe("fixture-value");
10589
expect(headers.get("Content-Type")).toBe("application/ssml+xml");
10690
expect(headers.get("X-Microsoft-OutputFormat")).toBe("audio-24khz-48kbitrate-mono-mp3");
107-
expect(init.body).toContain(`<voice name="en-US-JennyNeural">hello</voice>`);
91+
expect(init.body).toBe(
92+
`<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" ` +
93+
`xml:lang="en-US&quot; bad=&quot;1">` +
94+
`<voice name="en-US-JennyNeural&quot; xml:lang=&quot;evil">` +
95+
`Tom &amp; "Jerry" &lt;tag&gt;</voice></speak>`,
96+
);
10897
expect(init.signal).toBeInstanceOf(AbortSignal);
10998
});
11099

extensions/azure-speech/tts.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,7 @@ function escapeXmlAttr(value: string): string {
7979
}
8080

8181
/** Build escaped SSML for one Azure Speech synthesis request. */
82-
export function buildAzureSpeechSsml(params: {
83-
text: string;
84-
voice: string;
85-
lang?: string;
86-
}): string {
82+
function buildAzureSpeechSsml(params: { text: string; voice: string; lang?: string }): string {
8783
const lang = trimToUndefined(params.lang) ?? DEFAULT_AZURE_SPEECH_LANG;
8884
return (
8985
`<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" ` +

extensions/cloudflare-ai-gateway/stream-wrappers.test.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
// Cloudflare Ai Gateway tests cover stream wrappers plugin behavior.
22
import type { StreamFn } from "openclaw/plugin-sdk/agent-core";
33
import { afterAll, beforeEach, describe, expect, it, vi } from "vitest";
4-
import {
5-
testing,
6-
createCloudflareAiGatewayAnthropicThinkingPrefillWrapper,
7-
wrapCloudflareAiGatewayProviderStream,
8-
} from "./stream-wrappers.js";
4+
import { wrapCloudflareAiGatewayProviderStream } from "./stream-wrappers.js";
95

106
const { warnMock } = vi.hoisted(() => ({
117
warnMock: vi.fn(),
@@ -33,9 +29,13 @@ function createPayloadBaseStream(payload: Record<string, unknown>): StreamFn {
3329
}
3430

3531
function runWrapper(payload: Record<string, unknown>): Record<string, unknown> {
36-
const wrapper = createCloudflareAiGatewayAnthropicThinkingPrefillWrapper(
37-
createPayloadBaseStream(payload),
38-
);
32+
const wrapper = wrapCloudflareAiGatewayProviderStream({
33+
model: { api: "anthropic-messages" },
34+
streamFn: createPayloadBaseStream(payload),
35+
} as never);
36+
if (!wrapper) {
37+
throw new Error("expected Cloudflare AI Gateway stream wrapper");
38+
}
3939
void wrapper(
4040
{ provider: "cloudflare-ai-gateway", api: "anthropic-messages" } as never,
4141
{} as never,
@@ -44,7 +44,7 @@ function runWrapper(payload: Record<string, unknown>): Record<string, unknown> {
4444
return payload;
4545
}
4646

47-
describe("createCloudflareAiGatewayAnthropicThinkingPrefillWrapper", () => {
47+
describe("wrapCloudflareAiGatewayProviderStream", () => {
4848
beforeEach(() => {
4949
warnMock.mockClear();
5050
});
@@ -156,6 +156,12 @@ describe("wrapCloudflareAiGatewayProviderStream", () => {
156156
});
157157

158158
it("treats missing model API as the plugin's default Anthropic Messages route", () => {
159-
expect(testing.shouldPatchAnthropicMessagesPayload({} as never)).toBe(true);
159+
const baseStreamFn = createPayloadBaseStream({ messages: [] });
160+
const wrapped = wrapCloudflareAiGatewayProviderStream({
161+
model: {},
162+
streamFn: baseStreamFn,
163+
} as never);
164+
165+
expect(wrapped).not.toBe(baseStreamFn);
160166
});
161167
});

extensions/cloudflare-ai-gateway/stream-wrappers.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function shouldPatchAnthropicMessagesPayload(model: ProviderWrapStreamFnContext[
1717
* Creates a wrapper that removes trailing assistant prefill messages before
1818
* extended-thinking Anthropic requests are sent through Cloudflare.
1919
*/
20-
export function createCloudflareAiGatewayAnthropicThinkingPrefillWrapper(
20+
function createCloudflareAiGatewayAnthropicThinkingPrefillWrapper(
2121
baseStreamFn: StreamFn | undefined,
2222
): StreamFn {
2323
return createAnthropicThinkingPrefillPayloadWrapper(baseStreamFn, (stripped) => {
@@ -38,6 +38,3 @@ export function wrapCloudflareAiGatewayProviderStream(
3838
}
3939
return createCloudflareAiGatewayAnthropicThinkingPrefillWrapper(ctx.streamFn);
4040
}
41-
42-
/** Test-only access to wrapper decisions and logger injection points. */
43-
export const testing = { log, shouldPatchAnthropicMessagesPayload };

extensions/deepgram/realtime-transcription-provider.test.ts

Lines changed: 7 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
55
import { afterEach, describe, expect, it, vi } from "vitest";
66
import type WebSocket from "ws";
77
import { WebSocketServer } from "ws";
8-
import {
9-
testing,
10-
buildDeepgramRealtimeTranscriptionProvider,
11-
} from "./realtime-transcription-provider.js";
8+
import { buildDeepgramRealtimeTranscriptionProvider } from "./realtime-transcription-provider.js";
129

1310
let cleanup: (() => Promise<void>) | undefined;
1411

@@ -45,21 +42,6 @@ async function createDeepgramRealtimeServer(params: {
4542
return { baseUrl: `http://127.0.0.1:${port}/deepgram/v1` };
4643
}
4744

48-
function buildTestRealtimeUrl(baseUrl: string): URL {
49-
return new URL(
50-
testing.toDeepgramRealtimeWsUrl({
51-
apiKey: "dg-key",
52-
baseUrl,
53-
model: "nova-3",
54-
providerConfig: {},
55-
sampleRate: 8000,
56-
encoding: "mulaw",
57-
interimResults: true,
58-
endpointingMs: 800,
59-
}),
60-
);
61-
}
62-
6345
describe("buildDeepgramRealtimeTranscriptionProvider", () => {
6446
afterEach(async () => {
6547
await cleanup?.();
@@ -98,24 +80,6 @@ describe("buildDeepgramRealtimeTranscriptionProvider", () => {
9880
});
9981
});
10082

101-
it("builds a Deepgram listen websocket URL", () => {
102-
const url = testing.toDeepgramRealtimeWsUrl({
103-
apiKey: "dg-key",
104-
baseUrl: "https://api.deepgram.com/v1",
105-
model: "nova-3",
106-
providerConfig: {},
107-
sampleRate: 8000,
108-
encoding: "mulaw",
109-
interimResults: true,
110-
endpointingMs: 800,
111-
});
112-
113-
expect(url).toContain("wss://api.deepgram.com/v1/listen?");
114-
expect(url).toContain("model=nova-3");
115-
expect(url).toContain("encoding=mulaw");
116-
expect(url).toContain("sample_rate=8000");
117-
});
118-
11983
it("requires an API key when creating sessions", () => {
12084
vi.stubEnv("DEEPGRAM_API_KEY", "");
12185
const provider = buildDeepgramRealtimeTranscriptionProvider();
@@ -124,41 +88,27 @@ describe("buildDeepgramRealtimeTranscriptionProvider", () => {
12488
);
12589
});
12690

127-
it("returns the default when no value or env is set", () => {
128-
vi.stubEnv("DEEPGRAM_BASE_URL", "");
129-
expect(testing.normalizeDeepgramRealtimeBaseUrl(undefined)).toBe("https://api.deepgram.com/v1");
130-
expect(testing.normalizeDeepgramRealtimeBaseUrl(" ")).toBe("https://api.deepgram.com/v1");
131-
});
132-
133-
it.each([
134-
["http://localhost:8080/deepgram/v1", "ws:"],
135-
["https://custom.example.com/deepgram/v1", "wss:"],
136-
["ws://localhost:8080/deepgram/v1", "ws:"],
137-
["wss://custom.example.com:8443/deepgram/v1", "wss:"],
138-
])("maps or preserves %s as %s", (baseUrl, expectedProtocol) => {
139-
const url = buildTestRealtimeUrl(baseUrl);
140-
expect(url.protocol).toBe(expectedProtocol);
141-
expect(url.pathname).toBe("/deepgram/v1/listen");
142-
});
143-
14491
it.each(["not a url", "ftp://files.example.com"])("rejects invalid endpoint %s", (baseUrl) => {
145-
expect(() => testing.normalizeDeepgramRealtimeBaseUrl(baseUrl)).toThrow(
92+
const provider = buildDeepgramRealtimeTranscriptionProvider();
93+
expect(() => provider.createSession({ providerConfig: { apiKey: "dg-key", baseUrl } })).toThrow(
14694
/^Invalid Deepgram baseUrl:/,
14795
);
14896
});
14997

15098
it("validates the environment override", () => {
15199
vi.stubEnv("DEEPGRAM_BASE_URL", "not a url");
152-
expect(() => testing.normalizeDeepgramRealtimeBaseUrl()).toThrow(
100+
const provider = buildDeepgramRealtimeTranscriptionProvider();
101+
expect(() => provider.createSession({ providerConfig: { apiKey: "dg-key" } })).toThrow(
153102
"Invalid Deepgram baseUrl: value is not a valid URL",
154103
);
155104
});
156105

157106
it("does not echo the configured URL in validation errors", () => {
158107
const rawMarker = "configured-value-marker";
159108
const nonHttp = `ftp://files.example.com/${rawMarker}`;
109+
const provider = buildDeepgramRealtimeTranscriptionProvider();
160110
try {
161-
testing.normalizeDeepgramRealtimeBaseUrl(nonHttp);
111+
provider.createSession({ providerConfig: { apiKey: "dg-key", baseUrl: nonHttp } });
162112
throw new Error("expected rejection");
163113
} catch (error) {
164114
const message = (error as Error).message;

extensions/deepgram/realtime-transcription-provider.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,3 @@ export function buildDeepgramRealtimeTranscriptionProvider(): RealtimeTranscript
268268
},
269269
};
270270
}
271-
272-
export const testing = {
273-
normalizeProviderConfig,
274-
normalizeDeepgramRealtimeBaseUrl,
275-
toDeepgramRealtimeWsUrl,
276-
};
277-
export { testing as __testing };

extensions/elevenlabs/realtime-transcription-provider.test.ts

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,43 @@
11
// Elevenlabs tests cover realtime transcription provider plugin behavior.
2+
import { createServer } from "node:http";
3+
import type { AddressInfo } from "node:net";
24
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
3-
import { describe, expect, it } from "vitest";
4-
import {
5-
testing,
6-
buildElevenLabsRealtimeTranscriptionProvider,
7-
} from "./realtime-transcription-provider.js";
5+
import { afterEach, describe, expect, it } from "vitest";
6+
import type WebSocket from "ws";
7+
import { WebSocketServer } from "ws";
8+
import { buildElevenLabsRealtimeTranscriptionProvider } from "./realtime-transcription-provider.js";
9+
10+
let cleanup: (() => Promise<void>) | undefined;
11+
12+
async function createRealtimeServer(onRequest: (url: URL) => void) {
13+
const server = createServer();
14+
const wss = new WebSocketServer({ noServer: true });
15+
const clients = new Set<WebSocket>();
16+
server.on("upgrade", (request, socket, head) => {
17+
onRequest(new URL(request.url ?? "/", "http://127.0.0.1"));
18+
wss.handleUpgrade(request, socket, head, (ws) => {
19+
clients.add(ws);
20+
ws.on("close", () => clients.delete(ws));
21+
ws.send(JSON.stringify({ message_type: "session_started" }));
22+
});
23+
});
24+
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
25+
cleanup = async () => {
26+
for (const ws of clients) {
27+
ws.terminate();
28+
}
29+
await new Promise<void>((resolve) => wss.close(() => resolve()));
30+
await new Promise<void>((resolve) => server.close(() => resolve()));
31+
};
32+
return `http://127.0.0.1:${(server.address() as AddressInfo).port}`;
33+
}
834

935
describe("buildElevenLabsRealtimeTranscriptionProvider", () => {
36+
afterEach(async () => {
37+
await cleanup?.();
38+
cleanup = undefined;
39+
});
40+
1041
it("normalizes nested provider config", () => {
1142
const provider = buildElevenLabsRealtimeTranscriptionProvider();
1243
const resolved = provider.resolveConfig?.({
@@ -92,22 +123,29 @@ describe("buildElevenLabsRealtimeTranscriptionProvider", () => {
92123
});
93124
});
94125

95-
it("builds an ElevenLabs realtime websocket URL", () => {
96-
const url = testing.toElevenLabsRealtimeWsUrl({
97-
apiKey: "eleven-key",
98-
baseUrl: "https://api.elevenlabs.io",
99-
providerConfig: {},
100-
modelId: "scribe_v2_realtime",
101-
audioFormat: "ulaw_8000",
102-
sampleRate: 8000,
103-
commitStrategy: "vad",
104-
languageCode: "en",
126+
it("connects through the public session boundary with the configured URL params", async () => {
127+
const requests: URL[] = [];
128+
const baseUrl = await createRealtimeServer((url) => requests.push(url));
129+
const session = buildElevenLabsRealtimeTranscriptionProvider().createSession({
130+
providerConfig: {
131+
apiKey: "fixture-value",
132+
baseUrl,
133+
modelId: "scribe_v2_realtime",
134+
audioFormat: "ulaw_8000",
135+
sampleRate: 8000,
136+
commitStrategy: "vad",
137+
languageCode: "en",
138+
},
105139
});
106140

107-
expect(url).toContain("wss://api.elevenlabs.io/v1/speech-to-text/realtime?");
108-
expect(url).toContain("model_id=scribe_v2_realtime");
109-
expect(url).toContain("audio_format=ulaw_8000");
110-
expect(url).toContain("commit_strategy=vad");
111-
expect(url).toContain("language_code=en");
141+
await session.connect();
142+
session.close();
143+
144+
expect(requests).toHaveLength(1);
145+
expect(requests[0]?.pathname).toBe("/v1/speech-to-text/realtime");
146+
expect(requests[0]?.searchParams.get("model_id")).toBe("scribe_v2_realtime");
147+
expect(requests[0]?.searchParams.get("audio_format")).toBe("ulaw_8000");
148+
expect(requests[0]?.searchParams.get("commit_strategy")).toBe("vad");
149+
expect(requests[0]?.searchParams.get("language_code")).toBe("en");
112150
});
113151
});

extensions/elevenlabs/realtime-transcription-provider.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,3 @@ export function buildElevenLabsRealtimeTranscriptionProvider(): RealtimeTranscri
291291
},
292292
};
293293
}
294-
295-
export const testing = {
296-
normalizeProviderConfig,
297-
toElevenLabsRealtimeWsUrl,
298-
};

0 commit comments

Comments
 (0)