diff --git a/src/agents/pi-embedded-runner/run/attempt.test.ts b/src/agents/pi-embedded-runner/run/attempt.test.ts index 1953099cf7b..ec85037aefb 100644 --- a/src/agents/pi-embedded-runner/run/attempt.test.ts +++ b/src/agents/pi-embedded-runner/run/attempt.test.ts @@ -17,6 +17,11 @@ import { wrapStreamFnTrimToolCallNames, } from "./attempt.js"; +type FakeWrappedStream = { + result: () => Promise; + [Symbol.asyncIterator]: () => AsyncIterator; +}; + function createOllamaProviderConfig(injectNumCtxForOpenAICompat: boolean): OpenClawConfig { return { models: { @@ -32,6 +37,34 @@ function createOllamaProviderConfig(injectNumCtxForOpenAICompat: boolean): OpenC }; } +function createFakeStream(params: { + events: unknown[]; + resultMessage: unknown; +}): FakeWrappedStream { + return { + async result() { + return params.resultMessage; + }, + [Symbol.asyncIterator]() { + return (async function* () { + for (const event of params.events) { + yield event; + } + })(); + }, + }; +} + +async function invokeWrappedTestStream( + wrap: ( + baseFn: (...args: never[]) => unknown, + ) => (...args: never[]) => FakeWrappedStream | Promise, + baseFn: (...args: never[]) => unknown, +): Promise { + const wrappedFn = wrap(baseFn); + return await Promise.resolve(wrappedFn({} as never, {} as never, {} as never)); +} + describe("resolvePromptBuildHookResult", () => { function createLegacyOnlyHookRunner() { return { @@ -190,30 +223,14 @@ describe("resolveAttemptFsWorkspaceOnly", () => { }); }); describe("wrapStreamFnTrimToolCallNames", () => { - function createFakeStream(params: { events: unknown[]; resultMessage: unknown }): { - result: () => Promise; - [Symbol.asyncIterator]: () => AsyncIterator; - } { - return { - async result() { - return params.resultMessage; - }, - [Symbol.asyncIterator]() { - return (async function* () { - for (const event of params.events) { - yield event; - } - })(); - }, - }; - } - async function invokeWrappedStream( baseFn: (...args: never[]) => unknown, allowedToolNames?: Set, ) { - const wrappedFn = wrapStreamFnTrimToolCallNames(baseFn as never, allowedToolNames); - return await wrappedFn({} as never, {} as never, {} as never); + return await invokeWrappedTestStream( + (innerBaseFn) => wrapStreamFnTrimToolCallNames(innerBaseFn as never, allowedToolNames), + baseFn, + ); } function createEventStream(params: { @@ -725,27 +742,11 @@ describe("wrapStreamFnTrimToolCallNames", () => { }); describe("wrapStreamFnRepairMalformedToolCallArguments", () => { - function createFakeStream(params: { events: unknown[]; resultMessage: unknown }): { - result: () => Promise; - [Symbol.asyncIterator]: () => AsyncIterator; - } { - return { - async result() { - return params.resultMessage; - }, - [Symbol.asyncIterator]() { - return (async function* () { - for (const event of params.events) { - yield event; - } - })(); - }, - }; - } - async function invokeWrappedStream(baseFn: (...args: never[]) => unknown) { - const wrappedFn = wrapStreamFnRepairMalformedToolCallArguments(baseFn as never); - return await wrappedFn({} as never, {} as never, {} as never); + return await invokeWrappedTestStream( + (innerBaseFn) => wrapStreamFnRepairMalformedToolCallArguments(innerBaseFn as never), + baseFn, + ); } it("repairs anthropic-compatible tool arguments when trailing junk follows valid JSON", async () => {