Skip to content

Commit f05b789

Browse files
authored
test: align Codex provider payload test (#74536)
1 parent 665b0ef commit f05b789

1 file changed

Lines changed: 69 additions & 10 deletions

File tree

extensions/openai/openai-provider.test.ts

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,61 @@
11
import type { StreamFn } from "@mariozechner/pi-agent-core";
22
import type { Context, Model, SimpleStreamOptions } from "@mariozechner/pi-ai";
3-
import { describe, expect, it, vi } from "vitest";
3+
import { beforeEach, describe, expect, it, vi } from "vitest";
44
import { buildOpenAICodexProviderPlugin } from "./openai-codex-provider.js";
55
import { buildOpenAIProvider } from "./openai-provider.js";
66

7-
const refreshOpenAICodexTokenMock = vi.hoisted(() => vi.fn());
7+
const mocks = vi.hoisted(() => ({
8+
refreshOpenAICodexToken: vi.fn(),
9+
openAIResponsesTransportStreamFn: vi.fn(),
10+
}));
811

912
vi.mock("./openai-codex-provider.runtime.js", () => ({
10-
refreshOpenAICodexToken: refreshOpenAICodexTokenMock,
13+
refreshOpenAICodexToken: mocks.refreshOpenAICodexToken,
1114
}));
1215

16+
vi.mock("openclaw/plugin-sdk/provider-stream-family", async (importOriginal) => {
17+
const actual =
18+
await importOriginal<typeof import("openclaw/plugin-sdk/provider-stream-family")>();
19+
const wrapStreamFn: NonNullable<typeof actual.OPENAI_RESPONSES_STREAM_HOOKS.wrapStreamFn> = (
20+
ctx,
21+
) => {
22+
let nextStreamFn = actual.createOpenAIAttributionHeadersWrapper(ctx.streamFn, {
23+
codexNativeTransportStreamFn: mocks.openAIResponsesTransportStreamFn,
24+
});
25+
26+
if (actual.resolveOpenAIFastMode(ctx.extraParams)) {
27+
nextStreamFn = actual.createOpenAIFastModeWrapper(nextStreamFn);
28+
}
29+
30+
const serviceTier = actual.resolveOpenAIServiceTier(ctx.extraParams);
31+
if (serviceTier) {
32+
nextStreamFn = actual.createOpenAIServiceTierWrapper(nextStreamFn, serviceTier);
33+
}
34+
35+
const textVerbosity = actual.resolveOpenAITextVerbosity(ctx.extraParams);
36+
if (textVerbosity) {
37+
nextStreamFn = actual.createOpenAITextVerbosityWrapper(nextStreamFn, textVerbosity);
38+
}
39+
40+
nextStreamFn = actual.createCodexNativeWebSearchWrapper(nextStreamFn, {
41+
config: ctx.config,
42+
agentDir: ctx.agentDir,
43+
});
44+
return actual.createOpenAIResponsesContextManagementWrapper(
45+
actual.createOpenAIReasoningCompatibilityWrapper(nextStreamFn),
46+
ctx.extraParams,
47+
);
48+
};
49+
50+
return {
51+
...actual,
52+
OPENAI_RESPONSES_STREAM_HOOKS: {
53+
...actual.OPENAI_RESPONSES_STREAM_HOOKS,
54+
wrapStreamFn,
55+
},
56+
};
57+
});
58+
1359
function runWrappedPayloadCase(params: {
1460
wrap: NonNullable<ReturnType<typeof buildOpenAIProvider>["wrapStreamFn"]>;
1561
provider: string;
@@ -49,6 +95,13 @@ function runWrappedPayloadCase(params: {
4995
}
5096

5197
describe("buildOpenAIProvider", () => {
98+
beforeEach(() => {
99+
mocks.openAIResponsesTransportStreamFn.mockReset();
100+
mocks.openAIResponsesTransportStreamFn.mockImplementation(() => {
101+
throw new Error("unexpected native OpenAI Responses transport call");
102+
});
103+
});
104+
52105
it("exposes grouped model/auth picker labels for API key setup", () => {
53106
const provider = buildOpenAIProvider();
54107
const apiKey = provider.auth.find((method) => method.id === "api-key");
@@ -683,6 +736,15 @@ describe("buildOpenAIProvider", () => {
683736
if (!wrap) {
684737
throw new Error("expected Codex wrapper");
685738
}
739+
const payload = {
740+
store: false,
741+
text: { verbosity: "medium" },
742+
tools: [{ type: "function", name: "read" }],
743+
};
744+
mocks.openAIResponsesTransportStreamFn.mockImplementation((model, _context, options) => {
745+
options?.onPayload?.(payload, model);
746+
return {} as ReturnType<StreamFn>;
747+
});
686748
const result = runWrappedPayloadCase({
687749
wrap,
688750
provider: "openai-codex",
@@ -720,13 +782,10 @@ describe("buildOpenAIProvider", () => {
720782
id: "gpt-5.4",
721783
baseUrl: "https://chatgpt.com/backend-api",
722784
} as Model<"openai-codex-responses">,
723-
payload: {
724-
store: false,
725-
text: { verbosity: "medium" },
726-
tools: [{ type: "function", name: "read" }],
727-
},
785+
payload,
728786
});
729787

788+
expect(mocks.openAIResponsesTransportStreamFn).toHaveBeenCalledTimes(1);
730789
expect(result.payload.store).toBe(false);
731790
expect(result.payload.service_tier).toBe("priority");
732791
expect(result.payload.text).toEqual({ verbosity: "high" });
@@ -749,8 +808,8 @@ describe("buildOpenAIProvider", () => {
749808
expires: Date.now() - 60_000,
750809
};
751810

752-
refreshOpenAICodexTokenMock.mockReset();
753-
refreshOpenAICodexTokenMock.mockRejectedValueOnce(
811+
mocks.refreshOpenAICodexToken.mockReset();
812+
mocks.refreshOpenAICodexToken.mockRejectedValueOnce(
754813
new Error("Failed to extract accountId from token"),
755814
);
756815

0 commit comments

Comments
 (0)