From bbde7ed20ba868d07f8c8973dcd8f42a3b0776d1 Mon Sep 17 00:00:00 2001 From: Cristina Poncela Cubeiro <140309543+cristinaponcela@users.noreply.github.com> Date: Wed, 28 Oct 2026 15:49:28 +0100 Subject: [PATCH] fix(ai): add Mantle strict mode and Daybreak models missing from models.dev --- .../ai/catalog/providers/amazon-bedrock.ts | 46 ++++++++++++++++--- packages/ai/test/bedrock-mantle.test.ts | 10 ++++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/packages/ai/catalog/providers/amazon-bedrock.ts b/packages/ai/catalog/providers/amazon-bedrock.ts index 7166ebb54..71fa4c2ed 100644 --- a/packages/ai/catalog/providers/amazon-bedrock.ts +++ b/packages/ai/catalog/providers/amazon-bedrock.ts @@ -1,5 +1,5 @@ import type { Model } from "../../src/types.ts"; -import { type ChatModel, defineProvider, modelsDevModels, withInputLimits } from "../define.ts"; +import { addMissing, type ChatModel, defineProvider, modelsDevModels, withInputLimits } from "../define.ts"; import type { ModelsDevModel } from "../sources/models-dev.ts"; // Opus 5 is only callable through cross-region inference profiles. @@ -24,15 +24,47 @@ function mantleModel(model: ChatModel, source: ModelsDevModel): Model<"openai-re api: "openai-responses", // models.dev writes the region as a `${AWS_REGION}` template. baseUrl: responses.baseUrl.replace(/\$\{AWS_REGION\}/, "{region}"), - // Mantle does not document OpenAI's extended prompt cache retention. - compat: { supportsLongCacheRetention: false }, + compat: { + // Mantle does not document OpenAI's extended prompt cache retention. + supportsLongCacheRetention: false, + ...(source.structuredOutput ? { supportsStrictMode: true } : {}), + }, }; } +/** + * Mantle-only models on AWS's model cards that models.dev does not list yet. + * Prices and limits come from the model cards: + * https://docs.aws.amazon.com/bedrock/latest/userguide/model-cards.html + */ +const MANTLE_MODELS_MISSING_UPSTREAM: Model<"openai-responses">[] = [ + { + id: "openai.gpt-5.6-cyber", + name: "Daybreak Red: GPT-5.6 Cyber", + cost: { input: 13.75, output: 82.5, cacheRead: 1.375, cacheWrite: 17.1875 }, + contextWindow: 272_000, + }, + { + id: "openai.gpt-daybreak-blue-5.6-sol", + name: "Daybreak Blue: GPT-5.6 Sol", + cost: { input: 5.5, output: 33, cacheRead: 0.55, cacheWrite: 6.875 }, + contextWindow: 1_000_000, + }, +].map((model) => ({ + ...model, + api: "openai-responses", + provider: "amazon-bedrock", + baseUrl: "https://bedrock-mantle.{region}.api.aws/openai/v1", + reasoning: true, + input: ["text", "image"], + maxTokens: 128_000, + compat: { supportsLongCacheRetention: false, supportsStrictMode: true }, +})); + export default defineProvider({ id: "amazon-bedrock", - models: (ctx) => - modelsDevModels(ctx, "amazon-bedrock", { + models: (ctx) => { + const models = modelsDevModels(ctx, "amazon-bedrock", { api: "bedrock-converse-stream", baseUrl: "", include: (source) => @@ -50,6 +82,8 @@ export default defineProvider({ ...(source.structuredOutput ? { compat: { supportsStrictMode: true } } : {}), }; }, - }), + }); + return addMissing(models, MANTLE_MODELS_MISSING_UPSTREAM); + }, finalize: (model) => withInputLimits(model, { images: { maxPerMessage: 20 } }), }); diff --git a/packages/ai/test/bedrock-mantle.test.ts b/packages/ai/test/bedrock-mantle.test.ts index 1004633a2..f97c18124 100644 --- a/packages/ai/test/bedrock-mantle.test.ts +++ b/packages/ai/test/bedrock-mantle.test.ts @@ -32,6 +32,16 @@ describe("Bedrock Mantle", () => { expect(converse.some((model) => model.id.includes("anthropic.claude"))).toBe(true); }); + it("lists Mantle models from AWS's model cards that models.dev does not", () => { + const ids = mantleModels().map((model) => model.id); + expect(ids).toEqual(expect.arrayContaining(["openai.gpt-5.6-cyber", "openai.gpt-daybreak-blue-5.6-sol"])); + }); + + it("uses strict tool schemas on Mantle models that support structured output", () => { + const model = mantleModels().find((candidate) => candidate.id === "openai.gpt-5.6-sol"); + expect(model?.compat).toMatchObject({ supportsStrictMode: true, supportsLongCacheRetention: false }); + }); + it("sends Responses requests to the regional Mantle host with the Bedrock API key", async () => { const model = mantleModels()[0]; const requests: { url: string; authorization: string | null }[] = [];