Download src/utils/model/agent.ts from chenbhao/codev: direct link, hf CLI and curl.
- Browser
- Download file 6.56 kB
-
https://huggingface.co/chenbhao/codev/resolve/main/src/utils/model/agent.ts
- Command line
-
hf download hf://chenbhao/codev/src/utils/model/agent.ts
-
curl -L -o agent.ts https://huggingface.co/chenbhao/codev/resolve/main/src/utils/model/agent.ts
6.56 kB
| 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' | |
| import { getOpenCodeApiKey } from '../auth.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) | |
| const provider = getAPIProvider() | |
| // OpenCode free-mode sessions are known to be more reliable when subagents | |
| // stay on the parent's already-working model instead of switching to alias- | |
| // derived variants like haiku -> gpt-5-nano. If the user has configured an | |
| // OpenCode API key, keep honoring explicit alias-based model selection. | |
| const shouldInheritParentForKeylessOpenCode = | |
| provider === 'opencode' && !getOpenCodeApiKey() | |
| // 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 && provider === 'bedrock') { | |
| if (getBedrockRegionPrefix(originalSpec)) return resolvedModel | |
| return applyBedrockRegionPrefix(resolvedModel, parentRegionPrefix) | |
| } | |
| return resolvedModel | |
| } | |
| const shouldStickToParentModel = (spec: string): boolean => { | |
| if (!shouldInheritParentForKeylessOpenCode) { | |
| return false | |
| } | |
| const normalized = spec.toLowerCase() | |
| return ( | |
| normalized === 'haiku' || | |
| normalized === 'sonnet' || | |
| normalized === 'opus' || | |
| normalized === 'best' | |
| ) | |
| } | |
| // Prioritize tool-specified model if provided | |
| if (toolSpecifiedModel) { | |
| if (shouldStickToParentModel(toolSpecifiedModel)) { | |
| return parentModel | |
| } | |
| 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 (shouldStickToParentModel(agentModelWithExp)) { | |
| return parentModel | |
| } | |
| 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', | |
| }, | |
| ] | |
| } | |