diff --git a/src/agents/pi-embedded-runner.openai-tool-id-preservation.test.ts b/src/agents/pi-embedded-runner.openai-tool-id-preservation.test.ts index 04445c26590..18532b3bbe5 100644 --- a/src/agents/pi-embedded-runner.openai-tool-id-preservation.test.ts +++ b/src/agents/pi-embedded-runner.openai-tool-id-preservation.test.ts @@ -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"]; diff --git a/src/agents/pi-embedded-runner.sanitize-session-history.policy.test.ts b/src/agents/pi-embedded-runner.sanitize-session-history.policy.test.ts index 3ff4d59801f..58649597dee 100644 --- a/src/agents/pi-embedded-runner.sanitize-session-history.policy.test.ts +++ b/src/agents/pi-embedded-runner.sanitize-session-history.policy.test.ts @@ -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"]; diff --git a/src/agents/pi-embedded-runner.sanitize-session-history.test-harness.ts b/src/agents/pi-embedded-runner.sanitize-session-history.test-harness.ts index faed4127eac..2e73db49ad9 100644 --- a/src/agents/pi-embedded-runner.sanitize-session-history.test-harness.ts +++ b/src/agents/pi-embedded-runner.sanitize-session-history.test-harness.ts @@ -83,6 +83,22 @@ export async function createSanitizeSessionHistoryProviderRuntimeMock( }; } +export function createSanitizeSessionHistoryProviderHookRuntimeMock( + extra: Record = {}, +) { + 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 { vi.resetModules(); vi.resetAllMocks(); diff --git a/src/agents/pi-embedded-runner.sanitize-session-history.test.ts b/src/agents/pi-embedded-runner.sanitize-session-history.test.ts index 7d73d809e12..86ddf7f0278 100644 --- a/src/agents/pi-embedded-runner.sanitize-session-history.test.ts +++ b/src/agents/pi-embedded-runner.sanitize-session-history.test.ts @@ -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( "../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, diff --git a/src/agents/transcript-policy.policy.test.ts b/src/agents/transcript-policy.policy.test.ts index 208281834ef..d5b2968a17a 100644 --- a/src/agents/transcript-policy.policy.test.ts +++ b/src/agents/transcript-policy.policy.test.ts @@ -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" ? { diff --git a/src/agents/transcript-policy.test.ts b/src/agents/transcript-policy.test.ts index ea99bbbf590..d7ca0123e5b 100644 --- a/src/agents/transcript-policy.test.ts +++ b/src/agents/transcript-policy.test.ts @@ -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( - "../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(), }; });