test(agents): mock provider hook runtime in replay suites

This commit is contained in:
Vincent Koc
2026-04-14 20:29:58 +01:00
parent 34f9211e5c
commit bd288e7683
6 changed files with 81 additions and 36 deletions

View File

@@ -2,6 +2,7 @@ import type { AgentMessage } from "@mariozechner/pi-agent-core";
import { beforeEach, describe, expect, it, vi } from "vitest";
import {
createSanitizeSessionHistoryHelpersMock,
createSanitizeSessionHistoryProviderHookRuntimeMock,
createSanitizeSessionHistoryProviderRuntimeMock,
loadSanitizeSessionHistoryWithCleanMocks,
makeInMemorySessionManager,
@@ -16,6 +17,24 @@ vi.mock(
"../plugins/provider-runtime.js",
async () => await createSanitizeSessionHistoryProviderRuntimeMock(),
);
vi.mock("../plugins/provider-hook-runtime.js", () =>
createSanitizeSessionHistoryProviderHookRuntimeMock({
resolveProviderRuntimePlugin: vi.fn(({ provider }: { provider?: string }) =>
provider === "openai"
? {
buildReplayPolicy: (context?: { modelApi?: string }) => ({
sanitizeMode: "images-only",
sanitizeToolCallIds: context?.modelApi === "openai-completions",
...(context?.modelApi === "openai-completions" ? { toolCallIdMode: "strict" } : {}),
applyAssistantFirstOrderingFix: false,
validateGeminiTurns: false,
validateAnthropicTurns: false,
}),
}
: undefined,
),
}),
);
describe("sanitizeSessionHistory openai tool id preservation", () => {
let sanitizeSessionHistory: SanitizeSessionHistoryHarness["sanitizeSessionHistory"];

View File

@@ -1,6 +1,7 @@
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import {
createSanitizeSessionHistoryHelpersMock,
createSanitizeSessionHistoryProviderHookRuntimeMock,
createSanitizeSessionHistoryProviderRuntimeMock,
loadSanitizeSessionHistoryWithCleanMocks,
makeMockSessionManager,
@@ -19,6 +20,9 @@ vi.mock(
"../plugins/provider-runtime.js",
async () => await createSanitizeSessionHistoryProviderRuntimeMock(),
);
vi.mock("../plugins/provider-hook-runtime.js", () =>
createSanitizeSessionHistoryProviderHookRuntimeMock(),
);
let sanitizeSessionHistory: SanitizeSessionHistoryHarness["sanitizeSessionHistory"];
let mockedHelpers: SanitizeSessionHistoryHarness["mockedHelpers"];

View File

@@ -83,6 +83,22 @@ export async function createSanitizeSessionHistoryProviderRuntimeMock(
};
}
export function createSanitizeSessionHistoryProviderHookRuntimeMock(
extra: Record<string, unknown> = {},
) {
return {
resolveProviderRuntimePlugin: vi.fn(() => undefined),
resolveProviderHookPlugin: vi.fn(() => undefined),
resolveProviderPluginsForHooks: vi.fn(() => []),
prepareProviderExtraParams: vi.fn(() => undefined),
wrapProviderStreamFn: vi.fn(() => undefined),
clearProviderRuntimeHookCache: vi.fn(),
resetProviderRuntimeHookCacheForTest: vi.fn(),
__testing: {},
...extra,
};
}
export async function loadSanitizeSessionHistoryWithCleanMocks(): Promise<SanitizeSessionHistoryHarness> {
vi.resetModules();
vi.resetAllMocks();

View File

@@ -27,41 +27,52 @@ vi.mock("./pi-embedded-helpers.js", async () => ({
sanitizeSessionMessagesImages: vi.fn(async (msgs) => msgs),
}));
vi.mock("../plugins/provider-hook-runtime.js", async () => ({
__testing: {},
clearProviderRuntimeHookCache: vi.fn(),
prepareProviderExtraParams: vi.fn(() => undefined),
resetProviderRuntimeHookCacheForTest: vi.fn(),
resolveProviderHookPlugin: vi.fn(() => undefined),
resolveProviderPluginsForHooks: vi.fn(() => []),
resolveProviderRuntimePlugin: vi.fn(({ provider }: { provider?: string }) =>
provider === "openrouter" || provider === "github-copilot"
? {
buildReplayPolicy: (context?: { modelId?: string | null }) => {
const modelId = (context?.modelId ?? "").toLowerCase();
if (provider === "openrouter") {
return {
applyAssistantFirstOrderingFix: false,
validateGeminiTurns: false,
validateAnthropicTurns: false,
...(modelId.includes("gemini")
? {
sanitizeThoughtSignatures: {
allowBase64Only: true,
includeCamelCase: true,
},
}
: {}),
};
}
if (provider === "github-copilot" && modelId.includes("claude")) {
return {
dropThinkingBlocks: true,
};
}
return undefined;
},
}
: undefined,
),
wrapProviderStreamFn: vi.fn(() => undefined),
}));
vi.mock("../plugins/provider-runtime.js", async () => {
const actual = await vi.importActual<typeof import("../plugins/provider-runtime.js")>(
"../plugins/provider-runtime.js",
);
return {
...actual,
resolveProviderRuntimePlugin: ({ provider }: { provider?: string }) =>
provider === "openrouter" || provider === "github-copilot"
? {
buildReplayPolicy: (context?: { modelId?: string | null }) => {
const modelId = (context?.modelId ?? "").toLowerCase();
if (provider === "openrouter") {
return {
applyAssistantFirstOrderingFix: false,
validateGeminiTurns: false,
validateAnthropicTurns: false,
...(modelId.includes("gemini")
? {
sanitizeThoughtSignatures: {
allowBase64Only: true,
includeCamelCase: true,
},
}
: {}),
};
}
if (provider === "github-copilot" && modelId.includes("claude")) {
return {
dropThinkingBlocks: true,
};
}
return undefined;
},
}
: undefined,
sanitizeProviderReplayHistoryWithPlugin: vi.fn(
async ({
provider,

View File

@@ -1,7 +1,7 @@
import { beforeAll, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
vi.mock("../plugins/provider-runtime.js", () => ({
vi.mock("../plugins/provider-hook-runtime.js", () => ({
resolveProviderRuntimePlugin: vi.fn(({ provider }: { provider?: string }) =>
provider === "mistral"
? {

View File

@@ -1,14 +1,10 @@
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
vi.mock("../plugins/provider-runtime.js", async () => {
const actual = await vi.importActual<typeof import("../plugins/provider-runtime.js")>(
"../plugins/provider-runtime.js",
);
vi.mock("../plugins/provider-hook-runtime.js", async () => {
const replayHelpers = await vi.importActual<
typeof import("../plugins/provider-replay-helpers.js")
>("../plugins/provider-replay-helpers.js");
return {
...actual,
resolveProviderRuntimePlugin: vi.fn(({ provider }: { provider?: string }) => {
if (
!provider ||
@@ -189,7 +185,6 @@ vi.mock("../plugins/provider-runtime.js", async () => {
},
};
}),
resetProviderRuntimeHookCacheForTest: vi.fn(),
};
});