Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/fixes/12921-bedrock-vendor-context-limits.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **fix(bedrock):** model import now resolves context limits for every vendor prefix instead of only `anthropic.*`, so `global.openai.gpt-5.6-*` no longer imports with a null `inputTokenLimit` and gets rejected pre-flight at the 200k default ([#12921](https://github.com/diegosouzapw/OmniRoute/pull/12921)).
20 changes: 13 additions & 7 deletions open-sse/config/bedrock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,19 @@ export function getBedrockKnownModelLimits(modelId: string): {
if (!trimmed) return null;

const unqualified = trimmed.includes("/") ? trimmed.slice(trimmed.indexOf("/") + 1) : trimmed;
const withoutProfilePrefix = unqualified.replace(/^(?:eu|us|global)\./i, "");
const withoutProviderPrefix = withoutProfilePrefix.replace(/^anthropic\./i, "");
const spec =
getModelSpec(trimmed) ||
getModelSpec(unqualified) ||
getModelSpec(withoutProfilePrefix) ||
getModelSpec(withoutProviderPrefix);
// A Bedrock id is "<vendor>.<model>" optionally behind a cross-region profile
// prefix: "global.openai.gpt-5.6-sol", "us.anthropic.claude-...". The model
// name itself contains dots ("gpt-5.6-sol"), so peel at most those two leading
// qualifiers and keep the first candidate a spec knows. Peeling only
// "anthropic." left every other vendor (openai, meta, amazon, ...) without a
// context window, and the caller then fell back to a 200k default (#12915).
const segments = unqualified.split(".");
const spec = [trimmed, unqualified, segments.slice(1).join("."), segments.slice(2).join(".")]
.filter((candidate) => candidate.length > 0)
.reduce<ReturnType<typeof getModelSpec>>(
(found, candidate) => found || getModelSpec(candidate),
undefined
);

if (!spec?.contextWindow && !spec?.maxOutputTokens) return null;
return {
Expand Down
57 changes: 57 additions & 0 deletions tests/unit/bedrock-vendor-context-limits-12915.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { discoverBedrockNativeModels } from "../../open-sse/services/bedrock.ts";

// ─── #12915 — every Bedrock vendor prefix must resolve a context window ──────
// Bedrock ids are "<vendor>.<model>", optionally behind a cross-region profile
// prefix ("global.openai.gpt-5.6-sol"). The known-limits lookup used to peel
// only "anthropic.", so imported openai.* models carried no inputTokenLimit and
// the pre-flight context check fell back to a 200k default — rejecting 1M-context
// models locally, before the request ever reached AWS.

function bedrockFetcher(): (url: string, init: RequestInit) => Promise<Response> {
return async (url: string) => {
const body = url.includes("/inference-profiles")
? { inferenceProfileSummaries: [] }
: {
modelSummaries: [
{
modelId: "global.openai.gpt-5.6-sol",
modelName: "GPT-5.6 Sol",
providerName: "OpenAI",
responseStreamingSupported: true,
},
{
modelId: "global.anthropic.claude-opus-4-6-v1",
modelName: "Claude Opus 4.6",
providerName: "Anthropic",
responseStreamingSupported: true,
},
],
};
return new Response(JSON.stringify(body), {
status: 200,
headers: { "Content-Type": "application/json" },
});
};
}

describe("Bedrock model discovery (#12915)", () => {
it("carries a context window for openai.* models, not just anthropic.*", async () => {
const { models } = await discoverBedrockNativeModels({
apiKey: "test-key",
providerSpecificData: { region: "eu-west-1" },
fetcher: bedrockFetcher(),
});

const openai = models.find((m) => m.id === "global.openai.gpt-5.6-sol");
const anthropic = models.find((m) => m.id === "global.anthropic.claude-opus-4-6-v1");

// 1_050_000 and 1_000_000 differ, so a lookup that silently answered with the
// anthropic model's limit would not pass either assertion.
assert.equal(openai?.inputTokenLimit, 1_050_000);
assert.equal(openai?.outputTokenLimit, 128_000);
// The anthropic path must keep working unchanged.
assert.equal(anthropic?.inputTokenLimit, 1_000_000);
});
});
Loading