fix(providers): preserved bedrock profile thinking suffixes
Handled Bedrock inference profile ARNs through the normal thinking selector parser so suffixes such as :off do not become part of the ARN. Fixes #3004
This commit is contained in:
@@ -200,15 +200,19 @@ const AMAZON_BEDROCK_PROVIDER = "amazon-bedrock";
|
||||
const BEDROCK_INFERENCE_PROFILE_ARN =
|
||||
/^arn:aws(?:-[a-z]+)*:bedrock:[a-z0-9-]+:[0-9]*:(?:application-inference-profile|inference-profile)\/[a-z0-9][a-z0-9._:-]*$/i;
|
||||
|
||||
function resolveBedrockInferenceProfileReference(
|
||||
provider: string,
|
||||
function hasBedrockInferenceProfileThinkingSuffix(modelId: string): boolean {
|
||||
const { base, level } = splitThinkingSuffix(modelId);
|
||||
return level !== undefined && BEDROCK_INFERENCE_PROFILE_ARN.test(base.trim());
|
||||
}
|
||||
|
||||
function resolveBedrockInferenceProfileModelId(
|
||||
modelId: string,
|
||||
availableModels: readonly Model<Api>[],
|
||||
): Model<Api> | undefined {
|
||||
if (provider.toLowerCase() !== AMAZON_BEDROCK_PROVIDER) return undefined;
|
||||
|
||||
const requestedId = modelId.trim();
|
||||
if (!BEDROCK_INFERENCE_PROFILE_ARN.test(requestedId)) return undefined;
|
||||
if (hasBedrockInferenceProfileThinkingSuffix(requestedId) || !BEDROCK_INFERENCE_PROFILE_ARN.test(requestedId)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const providerModels = availableModels.filter(model => model.provider.toLowerCase() === AMAZON_BEDROCK_PROVIDER);
|
||||
const defaultModelId = DEFAULT_MODEL_PER_PROVIDER[AMAZON_BEDROCK_PROVIDER];
|
||||
@@ -223,6 +227,15 @@ function resolveBedrockInferenceProfileReference(
|
||||
};
|
||||
}
|
||||
|
||||
function resolveBedrockInferenceProfileReference(
|
||||
provider: string,
|
||||
modelId: string,
|
||||
availableModels: readonly Model<Api>[],
|
||||
): Model<Api> | undefined {
|
||||
if (provider.toLowerCase() !== AMAZON_BEDROCK_PROVIDER) return undefined;
|
||||
return resolveBedrockInferenceProfileModelId(modelId, availableModels);
|
||||
}
|
||||
|
||||
const UPSTREAM_ROUTING_SLUG = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i;
|
||||
|
||||
/**
|
||||
@@ -502,6 +515,7 @@ function findExactCanonicalModelMatch(
|
||||
* The single model-matching engine. Tries, in order:
|
||||
* 1. exact `provider/id` reference (variant-alias and OpenRouter routed/date
|
||||
* fallbacks included),
|
||||
|
||||
* 2. exact canonical id (coalesces provider variants),
|
||||
* 3. exact bare id (preference-ranked),
|
||||
* 4. retired effort-tier variant alias (collapsed catalog entries),
|
||||
@@ -534,6 +548,11 @@ function matchModel(
|
||||
return pickPreferredModel(exactMatches, context);
|
||||
}
|
||||
|
||||
const bedrockInferenceProfile = resolveBedrockInferenceProfileModelId(modelPattern, availableModels);
|
||||
if (bedrockInferenceProfile) {
|
||||
return bedrockInferenceProfile;
|
||||
}
|
||||
|
||||
// Retired effort-tier variant ids (bare, no provider prefix) resolve to
|
||||
// their collapsed logical model; models from the providers whose table
|
||||
// declared the alias win ties. Auto-derived `X-thinking` pairs resolve
|
||||
|
||||
@@ -883,7 +883,7 @@ describe("resolveCliModel", () => {
|
||||
expect(result.model?.id).toBe("z-ai/glm-4.7-20251222:nitro");
|
||||
});
|
||||
|
||||
test("accepts Bedrock inference profile ARNs as explicit provider model ids", () => {
|
||||
test("accepts Bedrock inference profile ARNs and preserves thinking suffixes", () => {
|
||||
const defaultBedrockModel = buildModel({
|
||||
id: "us.anthropic.claude-opus-4-8",
|
||||
name: "Claude Opus 4.8 (US)",
|
||||
@@ -898,19 +898,30 @@ describe("resolveCliModel", () => {
|
||||
});
|
||||
const profileArn = "arn:aws:bedrock:us-east-2:1234567890:application-inference-profile/company-opus-48";
|
||||
|
||||
const result = resolveCliModel({
|
||||
const baseResult = resolveCliModel({
|
||||
cliProvider: "amazon-bedrock",
|
||||
cliModel: profileArn,
|
||||
modelRegistry: {
|
||||
getAll: () => [defaultBedrockModel],
|
||||
},
|
||||
});
|
||||
const offResult = resolveCliModel({
|
||||
cliProvider: "amazon-bedrock",
|
||||
cliModel: `${profileArn}:off`,
|
||||
modelRegistry: {
|
||||
getAll: () => [defaultBedrockModel],
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.error).toBeUndefined();
|
||||
expect(result.model?.provider).toBe("amazon-bedrock");
|
||||
expect(result.model?.api).toBe("bedrock-converse-stream");
|
||||
expect(result.model?.id).toBe(profileArn);
|
||||
expect(result.model?.name).toBe("Bedrock inference profile");
|
||||
expect(baseResult.error).toBeUndefined();
|
||||
expect(baseResult.model?.provider).toBe("amazon-bedrock");
|
||||
expect(baseResult.model?.api).toBe("bedrock-converse-stream");
|
||||
expect(baseResult.model?.id).toBe(profileArn);
|
||||
expect(baseResult.model?.name).toBe("Bedrock inference profile");
|
||||
expect(baseResult.thinkingLevel).toBeUndefined();
|
||||
expect(offResult.error).toBeUndefined();
|
||||
expect(offResult.model?.id).toBe(profileArn);
|
||||
expect(offResult.thinkingLevel).toBe("off");
|
||||
});
|
||||
|
||||
test("returns a clear error when there are no models", () => {
|
||||
|
||||
Reference in New Issue
Block a user