test(providers): cover stream family plugin hooks

This commit is contained in:
Vincent Koc
2026-04-04 23:20:20 +09:00
parent fa34f3a9d5
commit a2e0a094c1
3 changed files with 172 additions and 0 deletions

View File

@@ -2,6 +2,8 @@ import type {
ProviderReplaySessionEntry,
ProviderSanitizeReplayHistoryContext,
} from "openclaw/plugin-sdk/plugin-entry";
import type { StreamFn } from "@mariozechner/pi-agent-core";
import type { Context, Model } from "@mariozechner/pi-ai";
import { describe, expect, it } from "vitest";
import {
registerProviderPlugin,
@@ -127,4 +129,55 @@ describe("google provider plugin hooks", () => {
} as never),
).toEqual([]);
});
it("wires google-thinking stream hooks for direct and Gemini CLI providers", async () => {
const { providers } = await registerProviderPlugin({
plugin: googlePlugin,
id: "google",
name: "Google Provider",
});
const googleProvider = requireRegisteredProvider(providers, "google");
const cliProvider = requireRegisteredProvider(providers, "google-gemini-cli");
let capturedPayload: Record<string, unknown> | undefined;
const baseStreamFn: StreamFn = (model, _context, options) => {
const payload = { config: { thinkingConfig: { thinkingBudget: -1 } } } as Record<
string,
unknown
>;
options?.onPayload?.(payload as never, model as never);
capturedPayload = payload;
return {} as never;
};
const runCase = (provider: typeof googleProvider, providerId: string) => {
const wrapped = provider.wrapStreamFn?.({
provider: providerId,
modelId: "gemini-3.1-pro-preview",
thinkingLevel: "high",
streamFn: baseStreamFn,
} as never);
void wrapped?.(
{
api: "google-generative-ai",
provider: providerId,
id: "gemini-3.1-pro-preview",
} as Model<"google-generative-ai">,
{ messages: [] } as Context,
{},
);
expect(capturedPayload).toMatchObject({
config: { thinkingConfig: { thinkingLevel: "HIGH" } },
});
const thinkingConfig = (
(capturedPayload as Record<string, unknown>).config as Record<string, unknown>
).thinkingConfig as Record<string, unknown>;
expect(thinkingConfig).not.toHaveProperty("thinkingBudget");
};
runCase(googleProvider, "google");
runCase(cliProvider, "google-gemini-cli");
});
});

View File

@@ -0,0 +1,81 @@
import type { StreamFn } from "@mariozechner/pi-agent-core";
import type { Context, Model } from "@mariozechner/pi-ai";
import { describe, expect, it } from "vitest";
import { registerSingleProviderPlugin } from "../../test/helpers/plugins/plugin-registration.js";
import plugin from "./index.js";
describe("kilocode provider plugin", () => {
it("owns passthrough-gemini replay policy for Gemini-backed models", async () => {
const provider = await registerSingleProviderPlugin(plugin);
expect(
provider.buildReplayPolicy?.({
provider: "kilocode",
modelApi: "openai-completions",
modelId: "gemini-2.5-pro",
} as never),
).toMatchObject({
applyAssistantFirstOrderingFix: false,
validateGeminiTurns: false,
validateAnthropicTurns: false,
sanitizeThoughtSignatures: {
allowBase64Only: true,
includeCamelCase: true,
},
});
});
it("wires kilocode-thinking stream hooks", async () => {
const provider = await registerSingleProviderPlugin(plugin);
let capturedPayload: Record<string, unknown> | undefined;
const baseStreamFn: StreamFn = (model, _context, options) => {
const payload = { config: { thinkingConfig: { thinkingBudget: -1 } } } as Record<
string,
unknown
>;
options?.onPayload?.(payload as never, model as never);
capturedPayload = payload;
return {} as never;
};
const wrappedReasoning = provider.wrapStreamFn?.({
provider: "kilocode",
modelId: "openai/gpt-5.4",
thinkingLevel: "high",
streamFn: baseStreamFn,
} as never);
void wrappedReasoning?.(
{
api: "openai-completions",
provider: "kilocode",
id: "openai/gpt-5.4",
} as Model<"openai-completions">,
{ messages: [] } as Context,
{},
);
expect(capturedPayload).toMatchObject({
reasoning: { effort: "high" },
});
const wrappedAuto = provider.wrapStreamFn?.({
provider: "kilocode",
modelId: "kilo/auto",
thinkingLevel: "high",
streamFn: baseStreamFn,
} as never);
void wrappedAuto?.(
{
api: "openai-completions",
provider: "kilocode",
id: "kilo/auto",
} as Model<"openai-completions">,
{ messages: [] } as Context,
{},
);
expect(capturedPayload).not.toHaveProperty("reasoning");
});
});

View File

@@ -1,3 +1,5 @@
import type { StreamFn } from "@mariozechner/pi-agent-core";
import type { Context, Model } from "@mariozechner/pi-ai";
import { describe, expect, it } from "vitest";
import { registerSingleProviderPlugin } from "../../test/helpers/plugins/plugin-registration.js";
import plugin from "./index.js";
@@ -20,4 +22,40 @@ describe("moonshot provider plugin", () => {
validateAnthropicTurns: true,
});
});
it("wires moonshot-thinking stream hooks", async () => {
const provider = await registerSingleProviderPlugin(plugin);
let capturedPayload: Record<string, unknown> | undefined;
const baseStreamFn: StreamFn = (model, _context, options) => {
const payload = { config: { thinkingConfig: { thinkingBudget: -1 } } } as Record<
string,
unknown
>;
options?.onPayload?.(payload as never, model as never);
capturedPayload = payload;
return {} as never;
};
const wrapped = provider.wrapStreamFn?.({
provider: "moonshot",
modelId: "kimi-k2.5",
thinkingLevel: "off",
streamFn: baseStreamFn,
} as never);
void wrapped?.(
{
api: "openai-completions",
provider: "moonshot",
id: "kimi-k2.5",
} as Model<"openai-completions">,
{ messages: [] } as Context,
{},
);
expect(capturedPayload).toMatchObject({
config: { thinkingConfig: { thinkingBudget: -1 } },
thinking: { type: "disabled" },
});
});
});