fix(bedrock): check model.name for prompt caching and adaptive thinking (#3527)

supportsPromptCaching, supportsAdaptiveThinking, supportsThinkingSignature,
and the Claude detection in streamSimpleBedrock/buildAdditionalModelRequestFields
all check model.id for Claude model name patterns. Application inference profile
ARNs are opaque and do not contain the model name, so these checks silently fail.

Fix by also checking model.name (user-controlled via models.json or
registerProvider) as a fallback in all affected functions. Added a shared
isAnthropicClaudeModel helper for the common Claude detection pattern.

Fixes #2925

Co-authored-by: Your Name <you@example.com>
This commit is contained in:
anirudhmarc
2026-04-26 01:58:17 +08:00
committed by GitHub
parent c19e64a444
commit 5a07d946ef
2 changed files with 119 additions and 25 deletions

View File

@@ -105,3 +105,67 @@ describe("Bedrock thinking payload", () => {
expect(payload.additionalModelRequestFields?.anthropic_beta).toBeUndefined();
});
});
describe("Application inference profile support", () => {
it("uses adaptive thinking when model.name contains the model name but ARN does not", async () => {
const baseModel = getModel("amazon-bedrock", "global.anthropic.claude-opus-4-6-v1");
const model: Model<"bedrock-converse-stream"> = {
...baseModel,
id: "arn:aws:bedrock:us-east-1:123456789012:application-inference-profile/my-profile",
name: "Claude Opus 4.6",
};
const payload = await capturePayload(model);
expect(payload.additionalModelRequestFields?.thinking).toEqual({ type: "adaptive", display: "summarized" });
expect(payload.additionalModelRequestFields?.output_config).toEqual({ effort: "high" });
});
it("injects cache points when model.name identifies a supported Claude model", async () => {
const baseModel = getModel("amazon-bedrock", "global.anthropic.claude-opus-4-6-v1");
const model: Model<"bedrock-converse-stream"> = {
...baseModel,
id: "arn:aws:bedrock:us-east-1:123456789012:application-inference-profile/my-profile",
name: "Claude Sonnet 4.6",
};
let capturedPayload: any;
const s = streamBedrock(model, {
systemPrompt: "You are helpful.",
messages: [{ role: "user", content: "Hello", timestamp: Date.now() }],
}, {
signal: AbortSignal.abort(),
onPayload: (payload) => {
capturedPayload = payload;
return payload;
},
});
for await (const event of s) {
if (event.type === "error") break;
}
// System prompt should have a cache point
expect(capturedPayload.system).toHaveLength(2);
expect(capturedPayload.system[1]).toHaveProperty("cachePoint");
// Last user message should have a cache point
const lastMsg = capturedPayload.messages[capturedPayload.messages.length - 1];
const lastContent = lastMsg.content[lastMsg.content.length - 1];
expect(lastContent).toHaveProperty("cachePoint");
});
it("falls back to fixed-budget thinking for non-adaptive Claude via model.name", async () => {
const baseModel = getModel("amazon-bedrock", "us.anthropic.claude-sonnet-4-5-20250929-v1:0");
const model: Model<"bedrock-converse-stream"> = {
...baseModel,
id: "arn:aws:bedrock:us-east-1:123456789012:application-inference-profile/my-profile",
name: "Claude Sonnet 4.5",
};
const payload = await capturePayload(model);
expect(payload.additionalModelRequestFields?.thinking).toMatchObject({ type: "enabled", budget_tokens: expect.any(Number) });
expect(payload.additionalModelRequestFields?.anthropic_beta).toEqual(["interleaved-thinking-2025-05-14"]);
});
});