( agentModel: string | undefined, parentModel: string, toolSpecifiedModel?: ModelAlias, permissionMode?: PermissionMode, )
| 35 | * IAM permissions are scoped to specific cross-region inference profiles. |
| 36 | */ |
| 37 | export function getAgentModel( |
| 38 | agentModel: string | undefined, |
| 39 | parentModel: string, |
| 40 | toolSpecifiedModel?: ModelAlias, |
| 41 | permissionMode?: PermissionMode, |
| 42 | ): string { |
| 43 | if (process.env.CLAUDE_CODE_SUBAGENT_MODEL) { |
| 44 | return parseUserSpecifiedModel(process.env.CLAUDE_CODE_SUBAGENT_MODEL) |
| 45 | } |
| 46 | |
| 47 | // Extract Bedrock region prefix from parent model to inherit for subagents. |
| 48 | // This ensures subagents use the same cross-region inference profile (e.g., "eu.", "us.") |
| 49 | // as the parent, which is required when IAM permissions only allow specific regions. |
| 50 | const parentRegionPrefix = getBedrockRegionPrefix(parentModel) |
| 51 | |
| 52 | // Helper to apply parent region prefix for Bedrock models. |
| 53 | // `originalSpec` is the raw model string before resolution (alias or full ID). |
| 54 | // If the user explicitly specified a full model ID that already carries its own |
| 55 | // region prefix (e.g., "eu.anthropic.…"), we preserve it instead of overwriting |
| 56 | // with the parent's prefix. This prevents silent data-residency violations when |
| 57 | // an agent config intentionally pins to a different region than the parent. |
| 58 | const applyParentRegionPrefix = ( |
| 59 | resolvedModel: string, |
| 60 | originalSpec: string, |
| 61 | ): string => { |
| 62 | if (parentRegionPrefix && getAPIProvider() === 'bedrock') { |
| 63 | if (getBedrockRegionPrefix(originalSpec)) return resolvedModel |
| 64 | return applyBedrockRegionPrefix(resolvedModel, parentRegionPrefix) |
| 65 | } |
| 66 | return resolvedModel |
| 67 | } |
| 68 | |
| 69 | // Prioritize tool-specified model if provided |
| 70 | if (toolSpecifiedModel) { |
| 71 | if (aliasMatchesParentTier(toolSpecifiedModel, parentModel)) { |
| 72 | return parentModel |
| 73 | } |
| 74 | const model = parseUserSpecifiedModel(toolSpecifiedModel) |
| 75 | return applyParentRegionPrefix(model, toolSpecifiedModel) |
| 76 | } |
| 77 | |
| 78 | const agentModelWithExp = agentModel ?? getDefaultSubagentModel() |
| 79 | |
| 80 | if (agentModelWithExp === 'inherit') { |
| 81 | // Apply runtime model resolution for inherit to get the effective model |
| 82 | // This ensures agents using 'inherit' get opusplan→Opus resolution in plan mode |
| 83 | return getRuntimeMainLoopModel({ |
| 84 | permissionMode: permissionMode ?? 'default', |
| 85 | mainLoopModel: parentModel, |
| 86 | exceeds200kTokens: false, |
| 87 | }) |
| 88 | } |
| 89 | |
| 90 | if (aliasMatchesParentTier(agentModelWithExp, parentModel)) { |
| 91 | return parentModel |
| 92 | } |
| 93 | const model = parseUserSpecifiedModel(agentModelWithExp) |
| 94 | return applyParentRegionPrefix(model, agentModelWithExp) |
no test coverage detected