diff --git a/src/agent/model.ts b/src/agent/model.ts index 472c908..b3788f0 100644 --- a/src/agent/model.ts +++ b/src/agent/model.ts @@ -68,3 +68,29 @@ export function getModelUpdateArgs( const modelInfo = getModelInfo(modelIdentifier); return modelInfo?.updateArgs; } + +/** + * Resolve a model ID from the llm_config.model value + * The llm_config.model is the model portion without the provider prefix + * (e.g., "z-ai/glm-4.6:exacto" for handle "openrouter/z-ai/glm-4.6:exacto") + * + * Note: This may not distinguish between variants like gpt-5.2-medium vs gpt-5.2-high + * since they share the same handle. For provider fallback, this is acceptable. + * + * @param llmConfigModel - The model value from agent.llm_config.model + * @returns The model ID if found, null otherwise + */ +export function resolveModelByLlmConfig(llmConfigModel: string): string | null { + // Try to find a model whose handle ends with the llm_config model value + const match = models.find((m) => m.handle.endsWith(`/${llmConfigModel}`)); + if (match) return match.id; + + // Also try exact match on the model portion (for simple cases like "gpt-5.2") + const exactMatch = models.find((m) => { + const parts = m.handle.split("/"); + return parts.slice(1).join("/") === llmConfigModel; + }); + if (exactMatch) return exactMatch.id; + + return null; +} diff --git a/src/agent/subagents/manager.ts b/src/agent/subagents/manager.ts index 3514d56..7108617 100644 --- a/src/agent/subagents/manager.ts +++ b/src/agent/subagents/manager.ts @@ -18,6 +18,9 @@ import { permissionMode } from "../../permissions/mode"; import { sessionPermissions } from "../../permissions/session"; import { settingsManager } from "../../settings-manager"; import { getErrorMessage } from "../../utils/error"; +import { getClient } from "../client"; +import { getCurrentAgentId } from "../context"; +import { resolveModelByLlmConfig } from "../model"; import { getAllSubagentConfigs, type SubagentConfig } from "."; // ============================================================================ @@ -50,6 +53,36 @@ interface ExecutionState { // Helper Functions // ============================================================================ +/** + * Get the primary agent's model ID + * Fetches from API and resolves to a known model ID + */ +async function getPrimaryAgentModel(): Promise { + try { + const agentId = getCurrentAgentId(); + const client = await getClient(); + const agent = await client.agents.retrieve(agentId); + const model = agent.llm_config?.model; + if (model) { + return resolveModelByLlmConfig(model); + } + return null; + } catch { + return null; + } +} + +/** + * Check if an error message indicates an unsupported provider + */ +function isProviderNotSupportedError(errorOutput: string): boolean { + return ( + errorOutput.includes("Provider") && + errorOutput.includes("is not supported") && + errorOutput.includes("supported providers:") + ); +} + /** * Record a tool call to the state store */ @@ -328,7 +361,11 @@ async function executeSubagent( userPrompt: string, baseURL: string, subagentId: string, + isRetry = false, ): Promise { + // Update the state with the model being used (may differ on retry/fallback) + updateSubagent(subagentId, { model }); + try { const cliArgs = buildSubagentArgs(type, config, model, userPrompt); @@ -376,6 +413,23 @@ async function executeSubagent( // Handle non-zero exit code if (exitCode !== 0) { + // Check if this is a provider-not-supported error and we haven't retried yet + if (!isRetry && isProviderNotSupportedError(stderr)) { + const primaryModel = await getPrimaryAgentModel(); + if (primaryModel) { + // Retry with the primary agent's model + return executeSubagent( + type, + config, + primaryModel, + userPrompt, + baseURL, + subagentId, + true, // Mark as retry to prevent infinite loops + ); + } + } + return { agentId: state.agentId || "", report: "", diff --git a/src/cli/components/SubagentGroupDisplay.tsx b/src/cli/components/SubagentGroupDisplay.tsx index be5f3a4..cd8598c 100644 --- a/src/cli/components/SubagentGroupDisplay.tsx +++ b/src/cli/components/SubagentGroupDisplay.tsx @@ -88,13 +88,14 @@ const AgentRow = memo(({ agent, isLast, expanded }: AgentRowProps) => { return ( - {/* Main row: tree char + description + type + stats */} + {/* Main row: tree char + description + type + model + stats */} {treeChar} {getDotElement()} {agent.description} · {agent.type.toLowerCase()} - · {stats} + {agent.model && · {agent.model}} + · {stats} {/* Subagent URL */} diff --git a/src/cli/components/SubagentGroupStatic.tsx b/src/cli/components/SubagentGroupStatic.tsx index 64abf3b..e14327a 100644 --- a/src/cli/components/SubagentGroupStatic.tsx +++ b/src/cli/components/SubagentGroupStatic.tsx @@ -31,6 +31,7 @@ export interface StaticSubagent { totalTokens: number; agentURL: string | null; error?: string; + model?: string; } interface SubagentGroupStaticProps { @@ -58,13 +59,14 @@ const AgentRow = memo(({ agent, isLast }: AgentRowProps) => { return ( - {/* Main row: tree char + description + type + stats */} + {/* Main row: tree char + description + type + model + stats */} {treeChar} {agent.description} · {agent.type.toLowerCase()} - · {stats} + {agent.model && · {agent.model}} + · {stats} {/* Subagent URL */} diff --git a/src/cli/components/colors.ts b/src/cli/components/colors.ts index 1dddc63..f7859be 100644 --- a/src/cli/components/colors.ts +++ b/src/cli/components/colors.ts @@ -120,7 +120,6 @@ export const colors = { completed: brandColors.statusSuccess, error: brandColors.statusError, treeChar: brandColors.textDisabled, - stats: brandColors.textSecondary, hint: brandColors.textDisabled, }, diff --git a/src/cli/helpers/subagentAggregation.ts b/src/cli/helpers/subagentAggregation.ts index 0210252..f122afd 100644 --- a/src/cli/helpers/subagentAggregation.ts +++ b/src/cli/helpers/subagentAggregation.ts @@ -108,6 +108,7 @@ export function createSubagentGroupItem( totalTokens: subagent.totalTokens, agentURL: subagent.agentURL, error: subagent.error, + model: subagent.model, }); } } diff --git a/src/cli/helpers/subagentState.ts b/src/cli/helpers/subagentState.ts index 3ac0cbc..bd3524b 100644 --- a/src/cli/helpers/subagentState.ts +++ b/src/cli/helpers/subagentState.ts @@ -26,6 +26,7 @@ export interface SubagentState { totalTokens: number; durationMs: number; error?: string; + model?: string; startTime: number; toolCallId?: string; // Links this subagent to its parent Task tool call }