openclaw/src/agents/pi-embedded-runner/model.test-harness.ts

113 lines
3.2 KiB
TypeScript
Raw Normal View History

import { vi } from "vitest";
2026-02-17 14:31:40 +09:00
import type { ModelDefinitionConfig } from "../../config/types.js";
import { discoverModels } from "../pi-model-discovery.js";
2026-02-17 14:31:40 +09:00
export const makeModel = (id: string): ModelDefinitionConfig => ({
id,
name: id,
reasoning: false,
2026-02-17 14:31:40 +09:00
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 1,
maxTokens: 1,
});
export const OPENAI_CODEX_TEMPLATE_MODEL = {
id: "gpt-5.2-codex",
name: "GPT-5.2 Codex",
provider: "openai-codex",
api: "openai-codex-responses",
baseUrl: "https://chatgpt.com/backend-api",
reasoning: true,
input: ["text", "image"] as const,
cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 },
contextWindow: 272000,
maxTokens: 128000,
};
export function mockOpenAICodexTemplateModel(): void {
mockDiscoveredModel({
provider: "openai-codex",
modelId: "gpt-5.2-codex",
templateModel: OPENAI_CODEX_TEMPLATE_MODEL,
});
}
export function buildOpenAICodexForwardCompatExpectation(
id: string = "gpt-5.3-codex",
): Partial<typeof OPENAI_CODEX_TEMPLATE_MODEL> & { provider: string; id: string } {
const isGpt54 = id === "gpt-5.4";
return {
provider: "openai-codex",
id,
api: "openai-codex-responses",
baseUrl: "https://chatgpt.com/backend-api",
reasoning: true,
contextWindow: isGpt54 ? 1_050_000 : 272000,
maxTokens: 128000,
};
}
fix(agents): add forward-compat fallback for google-gemini-cli gemini-3.1-pro/flash-preview (#26570) * fix(agents): add "google" provider to isReasoningTagProvider to prevent reasoning leak The gemini-api-key auth flow creates a profile with provider "google" (e.g. google/gemini-3-pro-preview), but isReasoningTagProvider only matched "google-gemini-cli" (OAuth) and "google-generative-ai". As a result: - reasoningTagHint was false → system prompt omitted <think>/<final> formatting instructions - enforceFinalTag was false → <final> tag filtering was skipped Raw <think> reasoning output was delivered to the end user. Fix: add the bare "google" provider string to the match list and cover it with two new test cases (exact match + case-insensitive). Fixes #26551 * fix(agents): add forward-compat fallback for google-gemini-cli gemini-3.1-pro/flash-preview gemini-3.1-pro-preview and gemini-3.1-flash-preview are not yet present in pi-ai's built-in google-gemini-cli model catalog (only gemini-3-pro-preview and gemini-3-flash-preview are registered). When users configure these models they get "Unknown model" errors even though Gemini CLI OAuth supports them. The codebase already has isGemini31Model() in extra-params.ts, which proves intent to support these models. Add a resolveGoogleGeminiCli31ForwardCompatModel entry to resolveForwardCompatModel following the same clone-template pattern used for zai/glm-5 and anthropic 4.6 models. - gemini-3.1-pro-* clones gemini-3-pro-preview (with reasoning: true) - gemini-3.1-flash-* clones gemini-3-flash-preview (with reasoning: true) Also add test helpers and three test cases to model.forward-compat.test.ts. Fixes #26524 * Changelog: credit Google Gemini provider fallback fixes --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-02-27 08:39:13 +09:00
export const GOOGLE_GEMINI_CLI_PRO_TEMPLATE_MODEL = {
id: "gemini-3-pro-preview",
name: "Gemini 3 Pro Preview (Cloud Code Assist)",
provider: "google-gemini-cli",
api: "google-gemini-cli",
baseUrl: "https://cloudcode-pa.googleapis.com",
reasoning: true,
input: ["text", "image"] as const,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 200000,
maxTokens: 64000,
};
export const GOOGLE_GEMINI_CLI_FLASH_TEMPLATE_MODEL = {
id: "gemini-3-flash-preview",
name: "Gemini 3 Flash Preview (Cloud Code Assist)",
provider: "google-gemini-cli",
api: "google-gemini-cli",
baseUrl: "https://cloudcode-pa.googleapis.com",
reasoning: false,
input: ["text", "image"] as const,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 200000,
maxTokens: 64000,
};
export function mockGoogleGeminiCliProTemplateModel(): void {
mockDiscoveredModel({
provider: "google-gemini-cli",
modelId: "gemini-3-pro-preview",
templateModel: GOOGLE_GEMINI_CLI_PRO_TEMPLATE_MODEL,
});
}
export function mockGoogleGeminiCliFlashTemplateModel(): void {
mockDiscoveredModel({
provider: "google-gemini-cli",
modelId: "gemini-3-flash-preview",
templateModel: GOOGLE_GEMINI_CLI_FLASH_TEMPLATE_MODEL,
});
}
export function resetMockDiscoverModels(): void {
vi.mocked(discoverModels).mockReturnValue({
find: vi.fn(() => null),
} as unknown as ReturnType<typeof discoverModels>);
}
export function mockDiscoveredModel(params: {
provider: string;
modelId: string;
templateModel: unknown;
}): void {
vi.mocked(discoverModels).mockReturnValue({
find: vi.fn((provider: string, modelId: string) => {
if (provider === params.provider && modelId === params.modelId) {
return params.templateModel;
}
return null;
}),
} as unknown as ReturnType<typeof discoverModels>);
}