Merge pull request #3033 from kimnamu/feat/bedrock-model-selection

fix(claude-local): respect model selection for Bedrock users
This commit is contained in:
Dotta
2026-04-07 21:48:29 -05:00
committed by GitHub
5 changed files with 48 additions and 7 deletions
@@ -32,6 +32,7 @@ import {
isClaudeUnknownSessionError,
} from "./parse.js";
import { resolveClaudeDesiredSkillNames } from "./skills.js";
import { isBedrockModelId } from "./models.js";
const __moduleDir = path.dirname(fileURLToPath(import.meta.url));
@@ -439,9 +440,12 @@ export async function execute(ctx: AdapterExecutionContext): Promise<AdapterExec
if (resumeSessionId) args.push("--resume", resumeSessionId);
if (dangerouslySkipPermissions) args.push("--dangerously-skip-permissions");
if (chrome) args.push("--chrome");
// Skip --model for Bedrock: Anthropic-style model IDs (e.g. "claude-opus-4-6") are not
// valid Bedrock model identifiers. Let the CLI use its own configured model instead.
if (model && !isBedrockAuth(effectiveEnv)) args.push("--model", model);
// For Bedrock: only pass --model when the ID is a Bedrock-native identifier
// (e.g. "us.anthropic.*" or ARN). Anthropic-style IDs like "claude-opus-4-6" are invalid
// on Bedrock, so skip them and let the CLI use its own configured model.
if (model && (!isBedrockAuth(effectiveEnv) || isBedrockModelId(model))) {
args.push("--model", model);
}
if (effort) args.push("--effort", effort);
if (maxTurns > 0) args.push("--max-turns", String(maxTurns));
if (effectiveInstructionsFilePath) {
@@ -1,5 +1,6 @@
export { execute, runClaudeLogin } from "./execute.js";
export { listClaudeSkills, syncClaudeSkills } from "./skills.js";
export { listClaudeModels } from "./models.js";
export { testEnvironment } from "./test.js";
export {
parseClaudeStreamJson,
@@ -0,0 +1,33 @@
import type { AdapterModel } from "@paperclipai/adapter-utils";
import { models as DIRECT_MODELS } from "../index.js";
/** AWS Bedrock model IDs — region-qualified identifiers required by the Bedrock API. */
const BEDROCK_MODELS: AdapterModel[] = [
{ id: "us.anthropic.claude-opus-4-6-v1", label: "Bedrock Opus 4.6" },
{ id: "us.anthropic.claude-sonnet-4-5-20250929-v2:0", label: "Bedrock Sonnet 4.5" },
{ id: "us.anthropic.claude-haiku-4-5-20251001-v1:0", label: "Bedrock Haiku 4.5" },
];
function isBedrockEnv(): boolean {
return (
process.env.CLAUDE_CODE_USE_BEDROCK === "1" ||
process.env.CLAUDE_CODE_USE_BEDROCK === "true" ||
(typeof process.env.ANTHROPIC_BEDROCK_BASE_URL === "string" &&
process.env.ANTHROPIC_BEDROCK_BASE_URL.trim().length > 0)
);
}
/**
* Return the model list appropriate for the current auth mode.
* When Bedrock env vars are detected, returns Bedrock-native model IDs;
* otherwise returns standard Anthropic API model IDs.
*/
export async function listClaudeModels(): Promise<AdapterModel[]> {
return isBedrockEnv() ? BEDROCK_MODELS : DIRECT_MODELS;
}
/** Check whether a model ID is a Bedrock-native identifier (not an Anthropic API short name). */
/** Bedrock model IDs use region-qualified prefixes (e.g. us.anthropic.*, eu.anthropic.*) or ARNs. */
export function isBedrockModelId(model: string): boolean {
return /^\w+\.anthropic\./.test(model) || model.startsWith("arn:aws:bedrock:");
}
@@ -16,6 +16,7 @@ import {
} from "@paperclipai/adapter-utils/server-utils";
import path from "node:path";
import { detectClaudeLoginRequired, parseClaudeStreamJson } from "./parse.js";
import { isBedrockModelId } from "./models.js";
function summarizeStatus(checks: AdapterEnvironmentCheck[]): AdapterEnvironmentTestResult["status"] {
if (checks.some((check) => check.level === "error")) return "fail";
@@ -163,10 +164,10 @@ export async function testEnvironment(
const args = ["--print", "-", "--output-format", "stream-json", "--verbose"];
if (dangerouslySkipPermissions) args.push("--dangerously-skip-permissions");
if (chrome) args.push("--chrome");
// Skip --model for Bedrock: Anthropic-style model IDs (e.g. "claude-opus-4-6") are not
// valid Bedrock model identifiers. Let the CLI use whatever model is configured in its
// own settings when Bedrock auth is active.
if (model && !hasBedrock) args.push("--model", model);
// For Bedrock: only pass --model when the ID is a Bedrock-native identifier.
if (model && (!hasBedrock || isBedrockModelId(model))) {
args.push("--model", model);
}
if (effort) args.push("--effort", effort);
if (maxTurns > 0) args.push("--max-turns", String(maxTurns));
if (extraArgs.length > 0) args.push(...extraArgs);
+2
View File
@@ -4,6 +4,7 @@ import {
execute as claudeExecute,
listClaudeSkills,
syncClaudeSkills,
listClaudeModels,
testEnvironment as claudeTestEnvironment,
sessionCodec as claudeSessionCodec,
getQuotaWindows as claudeGetQuotaWindows,
@@ -94,6 +95,7 @@ const claudeLocalAdapter: ServerAdapterModule = {
sessionCodec: claudeSessionCodec,
sessionManagement: getAdapterSessionManagement("claude_local") ?? undefined,
models: claudeModels,
listModels: listClaudeModels,
supportsLocalAgentJwt: true,
agentConfigurationDoc: claudeAgentConfigurationDoc,
getQuotaWindows: claudeGetQuotaWindows,