init claude-code
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
import type { PermissionMode } from '../permissions/PermissionMode.js'
|
||||
import { capitalize } from '../stringUtils.js'
|
||||
import { MODEL_ALIASES, type ModelAlias } from './aliases.js'
|
||||
import { applyBedrockRegionPrefix, getBedrockRegionPrefix } from './bedrock.js'
|
||||
import {
|
||||
getCanonicalName,
|
||||
getRuntimeMainLoopModel,
|
||||
parseUserSpecifiedModel,
|
||||
} from './model.js'
|
||||
import { getAPIProvider } from './providers.js'
|
||||
|
||||
export const AGENT_MODEL_OPTIONS = [...MODEL_ALIASES, 'inherit'] as const
|
||||
export type AgentModelAlias = (typeof AGENT_MODEL_OPTIONS)[number]
|
||||
|
||||
export type AgentModelOption = {
|
||||
value: AgentModelAlias
|
||||
label: string
|
||||
description: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default subagent model. Returns 'inherit' so subagents inherit
|
||||
* the model from the parent thread.
|
||||
*/
|
||||
export function getDefaultSubagentModel(): string {
|
||||
return 'inherit'
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the effective model string for an agent.
|
||||
*
|
||||
* For Bedrock, if the parent model uses a cross-region inference prefix (e.g., "eu.", "us."),
|
||||
* that prefix is inherited by subagents using alias models (e.g., "sonnet", "haiku", "opus").
|
||||
* This ensures subagents use the same region as the parent, which is necessary when
|
||||
* IAM permissions are scoped to specific cross-region inference profiles.
|
||||
*/
|
||||
export function getAgentModel(
|
||||
agentModel: string | undefined,
|
||||
parentModel: string,
|
||||
toolSpecifiedModel?: ModelAlias,
|
||||
permissionMode?: PermissionMode,
|
||||
): string {
|
||||
if (process.env.CLAUDE_CODE_SUBAGENT_MODEL) {
|
||||
return parseUserSpecifiedModel(process.env.CLAUDE_CODE_SUBAGENT_MODEL)
|
||||
}
|
||||
|
||||
// Extract Bedrock region prefix from parent model to inherit for subagents.
|
||||
// This ensures subagents use the same cross-region inference profile (e.g., "eu.", "us.")
|
||||
// as the parent, which is required when IAM permissions only allow specific regions.
|
||||
const parentRegionPrefix = getBedrockRegionPrefix(parentModel)
|
||||
|
||||
// Helper to apply parent region prefix for Bedrock models.
|
||||
// `originalSpec` is the raw model string before resolution (alias or full ID).
|
||||
// If the user explicitly specified a full model ID that already carries its own
|
||||
// region prefix (e.g., "eu.anthropic.…"), we preserve it instead of overwriting
|
||||
// with the parent's prefix. This prevents silent data-residency violations when
|
||||
// an agent config intentionally pins to a different region than the parent.
|
||||
const applyParentRegionPrefix = (
|
||||
resolvedModel: string,
|
||||
originalSpec: string,
|
||||
): string => {
|
||||
if (parentRegionPrefix && getAPIProvider() === 'bedrock') {
|
||||
if (getBedrockRegionPrefix(originalSpec)) return resolvedModel
|
||||
return applyBedrockRegionPrefix(resolvedModel, parentRegionPrefix)
|
||||
}
|
||||
return resolvedModel
|
||||
}
|
||||
|
||||
// Prioritize tool-specified model if provided
|
||||
if (toolSpecifiedModel) {
|
||||
if (aliasMatchesParentTier(toolSpecifiedModel, parentModel)) {
|
||||
return parentModel
|
||||
}
|
||||
const model = parseUserSpecifiedModel(toolSpecifiedModel)
|
||||
return applyParentRegionPrefix(model, toolSpecifiedModel)
|
||||
}
|
||||
|
||||
const agentModelWithExp = agentModel ?? getDefaultSubagentModel()
|
||||
|
||||
if (agentModelWithExp === 'inherit') {
|
||||
// Apply runtime model resolution for inherit to get the effective model
|
||||
// This ensures agents using 'inherit' get opusplan→Opus resolution in plan mode
|
||||
return getRuntimeMainLoopModel({
|
||||
permissionMode: permissionMode ?? 'default',
|
||||
mainLoopModel: parentModel,
|
||||
exceeds200kTokens: false,
|
||||
})
|
||||
}
|
||||
|
||||
if (aliasMatchesParentTier(agentModelWithExp, parentModel)) {
|
||||
return parentModel
|
||||
}
|
||||
const model = parseUserSpecifiedModel(agentModelWithExp)
|
||||
return applyParentRegionPrefix(model, agentModelWithExp)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a bare family alias (opus/sonnet/haiku) matches the parent model's
|
||||
* tier. When it does, the subagent inherits the parent's exact model string
|
||||
* instead of resolving the alias to a provider default.
|
||||
*
|
||||
* Prevents surprising downgrades: a Vertex user on Opus 4.6 (via /model) who
|
||||
* spawns a subagent with `model: opus` should get Opus 4.6, not whatever
|
||||
* getDefaultOpusModel() returns for 3P.
|
||||
* See https://github.com/anthropics/claude-code/issues/30815.
|
||||
*
|
||||
* Only bare family aliases match. `opus[1m]`, `best`, `opusplan` fall through
|
||||
* since they carry semantics beyond "same tier as parent".
|
||||
*/
|
||||
function aliasMatchesParentTier(alias: string, parentModel: string): boolean {
|
||||
const canonical = getCanonicalName(parentModel)
|
||||
switch (alias.toLowerCase()) {
|
||||
case 'opus':
|
||||
return canonical.includes('opus')
|
||||
case 'sonnet':
|
||||
return canonical.includes('sonnet')
|
||||
case 'haiku':
|
||||
return canonical.includes('haiku')
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function getAgentModelDisplay(model: string | undefined): string {
|
||||
// When model is omitted, getDefaultSubagentModel() returns 'inherit' at runtime
|
||||
if (!model) return 'Inherit from parent (default)'
|
||||
if (model === 'inherit') return 'Inherit from parent'
|
||||
return capitalize(model)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available model options for agents
|
||||
*/
|
||||
export function getAgentModelOptions(): AgentModelOption[] {
|
||||
return [
|
||||
{
|
||||
value: 'sonnet',
|
||||
label: 'Sonnet',
|
||||
description: 'Balanced performance - best for most agents',
|
||||
},
|
||||
{
|
||||
value: 'opus',
|
||||
label: 'Opus',
|
||||
description: 'Most capable for complex reasoning tasks',
|
||||
},
|
||||
{
|
||||
value: 'haiku',
|
||||
label: 'Haiku',
|
||||
description: 'Fast and efficient for simple tasks',
|
||||
},
|
||||
{
|
||||
value: 'inherit',
|
||||
label: 'Inherit from parent',
|
||||
description: 'Use the same model as the main conversation',
|
||||
},
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user