// Anthropic tests cover provider policy api plugin behavior. import type { ModelDefinitionConfig } from "openclaw/plugin-sdk/provider-model-types"; import { describe, expect, it } from "vitest"; import { applyConfigDefaults, normalizeConfig, resolveThinkingProfile, } from "./provider-policy-api.js"; function createModel(id: string, name: string): ModelDefinitionConfig { return { id, name, reasoning: false, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, }, contextWindow: 128_000, maxTokens: 8_192, }; } function collectLegacyExtendedLevelIds(levels: readonly { id: string }[] | undefined): string[] { const ids: string[] = []; for (const level of levels ?? []) { if (level.id === "xhigh" || level.id === "max") { ids.push(level.id); } } return ids; } function levelIds(levels: readonly { id: string }[] | undefined): string[] { return (levels ?? []).map((level) => level.id); } describe("anthropic provider policy public artifact", () => { it("normalizes Anthropic provider config", () => { const normalized = normalizeConfig({ provider: "anthropic", providerConfig: { baseUrl: "https://api.anthropic.com", models: [createModel("claude-sonnet-4-6", "Claude Sonnet 4.6")], }, }); expect(normalized.api).toBe("anthropic-messages"); expect(normalized.baseUrl).toBe("https://api.anthropic.com"); }); it("normalizes Claude CLI provider config", () => { const normalized = normalizeConfig({ provider: "claude-cli", providerConfig: { baseUrl: "https://api.anthropic.com", models: [createModel("claude-sonnet-4-6", "Claude Sonnet 4.6")], }, }); expect(normalized.api).toBe("anthropic-messages"); }); it("does not normalize non-Anthropic provider config", () => { const providerConfig = { baseUrl: "https://chatgpt.com/backend-api/codex", models: [createModel("gpt-5.4", "GPT-5.4")], }; expect( normalizeConfig({ provider: "openai", providerConfig, }), ).toBe(providerConfig); }); it("applies Anthropic API-key defaults without loading the full provider plugin", () => { const nextConfig = applyConfigDefaults({ config: { auth: { profiles: { "anthropic:default": { provider: "anthropic", mode: "api_key", }, }, order: { anthropic: ["anthropic:default"] }, }, agents: { defaults: {}, }, }, env: {}, }); expect(nextConfig.agents?.defaults?.contextPruning?.mode).toBe("cache-ttl"); expect(nextConfig.agents?.defaults?.contextPruning?.ttl).toBe("1h"); }); it("adds cacheRetention defaults for dated Anthropic primary model refs", () => { const nextConfig = applyConfigDefaults({ config: { auth: { profiles: { "anthropic:default": { provider: "anthropic", mode: "api_key", }, }, }, agents: { defaults: { model: { primary: "anthropic/claude-sonnet-4-20250514" }, }, }, }, env: {}, }); expect( nextConfig.agents?.defaults?.models?.["anthropic/claude-sonnet-4-6"]?.params?.cacheRetention, ).toBe("short"); }); it("exposes Claude Opus 4.8 thinking levels without loading the full provider plugin", () => { const profile = resolveThinkingProfile({ provider: "anthropic", modelId: "claude-opus-4-8", }); const ids = levelIds(profile?.levels); expect(ids).toContain("xhigh"); expect(ids).toContain("adaptive"); expect(ids).toContain("max"); expect(profile?.defaultLevel).toBe("off"); }); it("exposes the always-adaptive Claude Fable 5 thinking profile", () => { const profile = resolveThinkingProfile({ provider: "anthropic", modelId: "claude-fable-5", }); expect(profile).toEqual({ levels: [ { id: "off" }, { id: "minimal" }, { id: "low" }, { id: "medium" }, { id: "high" }, { id: "xhigh" }, { id: "adaptive" }, { id: "max" }, ], defaultLevel: "high", preserveWhenCatalogReasoningFalse: true, }); expect( resolveThinkingProfile({ provider: "claude-cli", modelId: "claude-fable-5", }), ).toEqual({ levels: [{ id: "off" }], defaultLevel: "off", }); }); it("does not return fable-5 off-thinking profile for claude-fable-50 (prefix boundary check)", () => { const profile = resolveThinkingProfile({ provider: "claude-cli", modelId: "claude-fable-50", }); expect(profile).not.toBeNull(); expect(profile?.defaultLevel).not.toBe("off"); }); it("exposes native max without xhigh for direct Claude 4.6 routes", () => { for (const provider of ["anthropic", "claude-cli"]) { const profile = resolveThinkingProfile({ provider, modelId: "claude-opus-4-6", }); if (!profile) { throw new Error(`Expected ${provider} policy profile`); } expect(levelIds(profile.levels)).toContain("adaptive"); expect(levelIds(profile.levels)).toContain("max"); expect(profile.defaultLevel).toBe("adaptive"); expect(collectLegacyExtendedLevelIds(profile.levels)).toStrictEqual(["max"]); } }); it("does not expose Anthropic thinking profiles for unrelated providers", () => { expect( resolveThinkingProfile({ provider: "openai", modelId: "claude-opus-4-7", }), ).toBeNull(); }); });