import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from
"vitest" ;
import type { OpenClawConfig } from
"../config/types.js" ;
import { withAudioFixture, withVideoFixture } from
"./runner.test-utils.js" ;
import type { AudioTranscriptionRequest, VideoDescriptionRequest } from
"./types.js" ;
vi.mock(
"../agents/model-auth.js" , async () => {
const { createAvailableModelAuthMockModule } = await
import (
"./runner.test-mocks.js" );
return createAvailableModelAuthMockModule();
});
vi.mock(
"../plugins/capability-provider-runtime.js" , async () => {
const { createEmptyCapabilityProviderMockModule } = await
import (
"./runner.test-mocks.js" );
return createEmptyCapabilityProviderMockModule();
});
const proxyFetchMocks = vi.hoisted(() => {
const proxyFetch = vi.fn() as unknown as
typeof fetch;
const resolveProxyFetchFromEnv = vi.fn((env: NodeJS.ProcessEnv = process.env) => {
const hasProxy =
Boolean (
env.https_proxy?.trim() ||
env.HTTPS_PROXY?.trim() ||
env.http_proxy?.trim() ||
env.HTTP_PROXY?.trim(),
);
return hasProxy ? proxyFetch : undefined;
});
return { proxyFetch, resolveProxyFetchFromEnv };
});
vi.mock(
"../infra/net/proxy-fetch.js" , () => ({
resolveProxyFetchFromEnv: proxyFetchMocks.resolveProxyFetchFromEnv,
}));
let buildProviderRegistry:
typeof import (
"./runner.js" ).buildProviderRegistry;
let clearMediaUnderstandingBinaryCacheForTests:
typeof import (
"./runner.js" ).clearM
ediaUnderstandingBinaryCacheForTests;
let runCapability: typeof import ("./runner.js" ).runCapability;
function createOpenAiAudioCfg(providerOverrides: Record<string, unknown> = {}): OpenClawConfig {
return {
models: {
providers: {
openai: {
apiKey: "test-key" , // pragma: allowlist secret
...providerOverrides,
models: [],
},
},
},
tools: {
media: {
audio: {
enabled: true ,
models: [{ provider: "openai" , model: "whisper-1" }],
},
},
},
} as unknown as OpenClawConfig;
}
async function runAudioCapabilityWithFetchCapture(params: {
fixturePrefix: string;
outputText: string;
}): Promise<typeof fetch | undefined> {
let seenFetchFn: typeof fetch | undefined;
await withAudioFixture(params.fixturePrefix, async ({ ctx, media, cache }) => {
const providerRegistry = buildProviderRegistry({
openai: {
id: "openai" ,
capabilities: ["audio" ],
transcribeAudio: async (req: AudioTranscriptionRequest) => {
seenFetchFn = req.fetchFn;
return { text: params.outputText, model: req.model };
},
},
});
const result = await runCapability({
capability: "audio" ,
cfg: createOpenAiAudioCfg(),
ctx,
attachments: cache,
media,
providerRegistry,
});
expect(result.outputs[0 ]?.text).toBe(params.outputText);
});
return seenFetchFn;
}
describe("runCapability proxy fetch passthrough" , () => {
beforeAll(async () => {
({ buildProviderRegistry, clearMediaUnderstandingBinaryCacheForTests, runCapability } =
await import ("./runner.js" ));
});
beforeEach(() => {
vi.useRealTimers();
vi.clearAllMocks();
clearMediaUnderstandingBinaryCacheForTests();
});
afterEach(() => vi.unstubAllEnvs());
it("passes fetchFn to audio provider when HTTPS_PROXY is set" , async () => {
vi.stubEnv("HTTPS_PROXY" , "http://proxy.test:8080 ");
const seenFetchFn = await runAudioCapabilityWithFetchCapture({
fixturePrefix: "openclaw-audio-proxy" ,
outputText: "transcribed" ,
});
expect(seenFetchFn).toBe(proxyFetchMocks.proxyFetch);
});
it("passes fetchFn to video provider when HTTPS_PROXY is set" , async () => {
vi.stubEnv("HTTPS_PROXY" , "http://proxy.test:8080 ");
await withVideoFixture("openclaw-video-proxy" , async ({ ctx, media, cache }) => {
let seenFetchFn: typeof fetch | undefined;
const result = await runCapability({
capability: "video" ,
cfg: {
models: {
providers: {
moonshot: {
apiKey: "test-key" , // pragma: allowlist secret
models: [],
},
},
},
tools: {
media: {
video: {
enabled: true ,
models: [{ provider: "moonshot" , model: "kimi-k2.5" }],
},
},
},
} as unknown as OpenClawConfig,
ctx,
attachments: cache,
media,
providerRegistry: new Map([
[
"moonshot" ,
{
id: "moonshot" ,
capabilities: ["video" ],
describeVideo: async (req: VideoDescriptionRequest) => {
seenFetchFn = req.fetchFn;
return { text: "video ok" , model: req.model };
},
},
],
]),
});
expect(result.outputs[0 ]?.text).toBe("video ok" );
expect(seenFetchFn).toBe(proxyFetchMocks.proxyFetch);
});
});
it("does not pass fetchFn when no proxy env vars are set" , async () => {
vi.stubEnv("HTTPS_PROXY" , "" );
vi.stubEnv("HTTP_PROXY" , "" );
vi.stubEnv("https_proxy" , "" );
vi.stubEnv("http_proxy" , "" );
const seenFetchFn = await runAudioCapabilityWithFetchCapture({
fixturePrefix: "openclaw-audio-no-proxy" ,
outputText: "ok" ,
});
expect(seenFetchFn).toBeUndefined();
});
it("passes allowPrivateNetwork to audio provider when set in providerConfig.request" , async () => {
let seenRequest: AudioTranscriptionRequest["request" ];
await withAudioFixture("openclaw-audio-allowprivatenetwork" , async ({ ctx, media, cache }) => {
const providerRegistry = buildProviderRegistry({
openai: {
id: "openai" ,
capabilities: ["audio" ],
transcribeAudio: async (req: AudioTranscriptionRequest) => {
seenRequest = req.request;
return { text: "ok" , model: req.model };
},
},
});
const result = await runCapability({
capability: "audio" ,
cfg: createOpenAiAudioCfg({
request: {
allowPrivateNetwork: true ,
},
}),
ctx,
attachments: cache,
media,
providerRegistry,
});
expect(result.outputs[0 ]?.text).toBe("ok" );
});
expect(seenRequest?.allowPrivateNetwork).toBe(true );
});
});
Messung V0.5 in Prozent C=99 H=100 G=99
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-08)
¤
*© Formatika GbR, Deutschland