Merge remote-tracking branch 'origin/main' into model-registry

This commit is contained in:
Mario Zechner
2026-06-10 18:49:18 +02:00
99 changed files with 3278 additions and 796 deletions
@@ -3,8 +3,11 @@ import { getModels, getProviders } from "../src/models.ts";
import type { Api, Model } from "../src/types.ts";
const EXPECTED_CURRENT_ADAPTIVE_THINKING_MODELS = [
"anthropic/claude-fable-5",
"anthropic/claude-opus-4-8",
"opencode/claude-fable-5",
"opencode/claude-opus-4-8",
"vercel-ai-gateway/anthropic/claude-fable-5",
"vercel-ai-gateway/anthropic/claude-opus-4.8",
];
@@ -22,7 +25,7 @@ describe("Anthropic adaptive thinking model metadata", () => {
expect(flaggedModels).toEqual(expect.arrayContaining([...EXPECTED_CURRENT_ADAPTIVE_THINKING_MODELS].sort()));
expect(flaggedModels).toEqual(
flaggedModels.filter((modelId) => /(opus[-.]4[-.][678]|sonnet[-.]4[-.]6)/.test(modelId)),
flaggedModels.filter((modelId) => /(opus[-.]4[-.][678]|sonnet[-.]4[-.]6|fable[-.]5)/.test(modelId)),
);
});
});
@@ -83,6 +83,13 @@ describe("Anthropic forceAdaptiveThinking compat override", () => {
expect(payload.output_config).toEqual({ effort: "medium" });
});
it("uses adaptive thinking with native xhigh effort for Claude Fable 5", async () => {
const payload = await capturePayload(getModel("anthropic", "claude-fable-5"), { reasoning: "xhigh" });
expect(payload.thinking).toEqual({ type: "adaptive", display: "summarized" });
expect(payload.output_config).toEqual({ effort: "xhigh" });
});
it("allows built-in adaptive models to opt out with compat.forceAdaptiveThinking false", async () => {
const model: Model<"anthropic-messages"> = {
...getModel("anthropic", "claude-opus-4-8"),
@@ -132,6 +132,13 @@ describe("Anthropic thinking disable payload", () => {
expect(payload.output_config).toBeUndefined();
});
it("omits thinking.type=disabled for Claude Fable 5 when thinking is off", async () => {
const payload = await capturePayload(getModel("anthropic", "claude-fable-5"));
expect(payload.thinking).toBeUndefined();
expect(payload.output_config).toBeUndefined();
});
it("uses adaptive thinking for Claude Opus 4.8 when reasoning is enabled", async () => {
const payload = await capturePayload(getModel("anthropic", "claude-opus-4-8"), { reasoning: "high" });
@@ -13,6 +13,7 @@ interface CapturedAzureClientOptions {
interface CapturedAzureResponsesPayload {
prompt_cache_key?: string;
store?: boolean;
}
const azureMock = vi.hoisted(() => ({
@@ -144,6 +145,16 @@ describe("azure-openai-responses base URL normalization", () => {
expect(azureMock.lastParams?.prompt_cache_key).toBe("x".repeat(64));
});
it("disables server-side response storage", async () => {
const model = getModel("azure-openai-responses", "gpt-4o-mini");
await streamAzureOpenAIResponses(model, context, {
apiKey: "test-api-key",
azureBaseUrl: "https://my-resource.openai.azure.com",
}).result();
expect(azureMock.lastParams?.store).toBe(false);
});
it("builds correct default URL from AZURE_OPENAI_RESOURCE_NAME", async () => {
process.env.AZURE_OPENAI_RESOURCE_NAME = "my-resource";
const model = getModel("azure-openai-responses", "gpt-4o-mini");
@@ -128,4 +128,30 @@ describe("bedrock endpoint resolution", () => {
expect(config.endpoint).toBe("https://bedrock-vpc.example.com");
expect(config.region).toBe("us-west-2");
});
it("extracts region from inference profile ARN regardless of AWS_REGION", async () => {
process.env.AWS_REGION = "us-east-1";
const baseModel = getModel("amazon-bedrock", "us.anthropic.claude-opus-4-8");
const model: Model<"bedrock-converse-stream"> = {
...baseModel,
id: "arn:aws:bedrock:us-west-2:123456789012:application-inference-profile/abc123",
};
const config = await captureClientConfig(model);
expect(config.region).toBe("us-west-2");
});
it("extracts region from GovCloud inference profile ARN", async () => {
process.env.AWS_REGION = "us-east-1";
const baseModel = getModel("amazon-bedrock", "us.anthropic.claude-opus-4-8");
const model: Model<"bedrock-converse-stream"> = {
...baseModel,
id: "arn:aws-us-gov:bedrock:us-gov-west-1:123456789012:application-inference-profile/abc123",
};
const config = await captureClientConfig(model);
expect(config.region).toBe("us-gov-west-1");
});
});
@@ -83,6 +83,25 @@ describe("Bedrock thinking payload", () => {
expect(payload.additionalModelRequestFields?.anthropic_beta).toBeUndefined();
});
it("uses adaptive thinking for Claude Fable 5 when reasoning is enabled", async () => {
const model = getModel("amazon-bedrock", "global.anthropic.claude-fable-5");
const payload = await capturePayload(model);
expect(payload.additionalModelRequestFields?.thinking).toEqual({ type: "adaptive", display: "summarized" });
expect(payload.additionalModelRequestFields?.output_config).toEqual({ effort: "high" });
expect(payload.additionalModelRequestFields?.anthropic_beta).toBeUndefined();
});
it("maps xhigh reasoning to effort=xhigh for Claude Fable 5", async () => {
const model = getModel("amazon-bedrock", "global.anthropic.claude-fable-5");
const payload = await capturePayload(model, { reasoning: "xhigh" });
expect(payload.additionalModelRequestFields?.thinking).toEqual({ type: "adaptive", display: "summarized" });
expect(payload.additionalModelRequestFields?.output_config).toEqual({ effort: "xhigh" });
});
it("omits display for GovCloud model ids on non-adaptive Claude thinking", async () => {
const baseModel = getModel("amazon-bedrock", "us.anthropic.claude-sonnet-4-5-20250929-v1:0");
const model: Model<"bedrock-converse-stream"> = {
@@ -1120,6 +1120,33 @@ describe("openai-completions tool_choice", () => {
expect(params.reasoning_effort).toBeUndefined();
});
it("sends max_tokens for OpenCode completions models", async () => {
const cases = [getModel("opencode-go", "kimi-k2.6")!, getModel("opencode", "grok-build-0.1")!] as const;
for (const model of cases) {
let payload: unknown;
expect(model.compat?.maxTokensField).toBe("max_tokens");
await streamSimple(
model,
{
messages: [{ role: "user", content: "Hi", timestamp: Date.now() }],
},
{
apiKey: "test",
maxTokens: 123,
onPayload: (params: unknown) => {
payload = params;
},
},
).result();
const params = (payload ?? mockState.lastParams) as { max_tokens?: number; max_completion_tokens?: number };
expect(params.max_tokens).toBe(123);
expect(params.max_completion_tokens).toBeUndefined();
}
});
it("omits reasoning effort for OpenCode Grok Build", async () => {
const model = getModel("opencode", "grok-build-0.1")!;
let payload: unknown;
+15 -1
View File
@@ -20,7 +20,14 @@ describe("getSupportedThinkingLevels", () => {
expect(getSupportedThinkingLevels(model!)).toContain("xhigh");
});
it("does not include xhigh for non-Opus Anthropic models", () => {
it("includes xhigh but not off for Anthropic Claude Fable 5 on anthropic-messages API", () => {
const model = getModel("anthropic", "claude-fable-5");
expect(model).toBeDefined();
expect(getSupportedThinkingLevels(model!)).toContain("xhigh");
expect(getSupportedThinkingLevels(model!)).not.toContain("off");
});
it("does not include xhigh for Claude Sonnet 4.5", () => {
const model = getModel("anthropic", "claude-sonnet-4-5");
expect(model).toBeDefined();
expect(getSupportedThinkingLevels(model!)).not.toContain("xhigh");
@@ -79,4 +86,11 @@ describe("getSupportedThinkingLevels", () => {
expect(model).toBeDefined();
expect(getSupportedThinkingLevels(model!)).toContain("xhigh");
});
it("includes xhigh but not off for Bedrock Claude Fable 5", () => {
const model = getModel("amazon-bedrock", "global.anthropic.claude-fable-5");
expect(model).toBeDefined();
expect(getSupportedThinkingLevels(model!)).toContain("xhigh");
expect(getSupportedThinkingLevels(model!)).not.toContain("off");
});
});