Merge remote-tracking branch 'origin/main' into model-registry
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user