diff --git a/src/hooks/atlas/event-handler.ts b/src/hooks/atlas/event-handler.ts index 68c89e485..76a3a5004 100644 --- a/src/hooks/atlas/event-handler.ts +++ b/src/hooks/atlas/event-handler.ts @@ -2,6 +2,7 @@ import type { PluginInput } from "@opencode-ai/plugin" import { getPlanProgress, readBoulderState } from "../../features/boulder-state" import { subagentSessions } from "../../features/claude-code-session-state" import { log } from "../../shared/logger" +import { getAgentConfigKey } from "../../shared/agent-display-names" import { HOOK_NAME } from "./hook-name" import { isAbortError } from "./is-abort-error" import { injectBoulderContinuation } from "./boulder-continuation-injector" @@ -88,11 +89,12 @@ export function createAtlasEventHandler(input: { } const lastAgent = await getLastAgentFromSession(sessionID, ctx.client) - const requiredAgent = (boulderState.agent ?? "atlas").toLowerCase() - const lastAgentMatchesRequired = lastAgent === requiredAgent + const lastAgentKey = getAgentConfigKey(lastAgent ?? "") + const requiredAgent = getAgentConfigKey(boulderState.agent ?? "atlas") + const lastAgentMatchesRequired = lastAgentKey === requiredAgent const boulderAgentWasNotExplicitlySet = boulderState.agent === undefined const boulderAgentDefaultsToAtlas = requiredAgent === "atlas" - const lastAgentIsSisyphus = lastAgent === "sisyphus" + const lastAgentIsSisyphus = lastAgentKey === "sisyphus" const allowSisyphusWhenDefaultAtlas = boulderAgentWasNotExplicitlySet && boulderAgentDefaultsToAtlas && lastAgentIsSisyphus const agentMatches = lastAgentMatchesRequired || allowSisyphusWhenDefaultAtlas if (!agentMatches) { diff --git a/src/hooks/category-skill-reminder/hook.ts b/src/hooks/category-skill-reminder/hook.ts index b15715cda..a89d182b0 100644 --- a/src/hooks/category-skill-reminder/hook.ts +++ b/src/hooks/category-skill-reminder/hook.ts @@ -2,6 +2,7 @@ import type { PluginInput } from "@opencode-ai/plugin" import type { AvailableSkill } from "../../agents/dynamic-agent-prompt-builder" import { getSessionAgent } from "../../features/claude-code-session-state" import { log } from "../../shared" +import { getAgentConfigKey } from "../../shared/agent-display-names" import { buildReminderMessage } from "./formatter" /** @@ -75,11 +76,11 @@ export function createCategorySkillReminderHook( function isTargetAgent(sessionID: string, inputAgent?: string): boolean { const agent = getSessionAgent(sessionID) ?? inputAgent if (!agent) return false - const agentLower = agent.toLowerCase() + const agentKey = getAgentConfigKey(agent) return ( - TARGET_AGENTS.has(agentLower) || - agentLower.includes("sisyphus") || - agentLower.includes("atlas") + TARGET_AGENTS.has(agentKey) || + agentKey.includes("sisyphus") || + agentKey.includes("atlas") ) } diff --git a/src/hooks/todo-continuation-enforcer/continuation-injection.ts b/src/hooks/todo-continuation-enforcer/continuation-injection.ts index e9c36b470..a8e8586e6 100644 --- a/src/hooks/todo-continuation-enforcer/continuation-injection.ts +++ b/src/hooks/todo-continuation-enforcer/continuation-injection.ts @@ -9,6 +9,7 @@ import { } from "../../features/hook-message-injector" import { log } from "../../shared/logger" import { isSqliteBackend } from "../../shared/opencode-storage-detection" +import { getAgentConfigKey } from "../../shared/agent-display-names" import { CONTINUATION_PROMPT, @@ -103,7 +104,7 @@ export async function injectContinuation(args: { tools = tools ?? previousMessage?.tools } - if (agentName && skipAgents.includes(agentName)) { + if (agentName && skipAgents.some(s => getAgentConfigKey(s) === getAgentConfigKey(agentName))) { log(`[${HOOK_NAME}] Skipped: agent in skipAgents list`, { sessionID, agent: agentName }) return } diff --git a/src/hooks/todo-continuation-enforcer/idle-event.ts b/src/hooks/todo-continuation-enforcer/idle-event.ts index d97a9b6bf..689672c01 100644 --- a/src/hooks/todo-continuation-enforcer/idle-event.ts +++ b/src/hooks/todo-continuation-enforcer/idle-event.ts @@ -4,6 +4,7 @@ import type { BackgroundManager } from "../../features/background-agent" import type { ToolPermission } from "../../features/hook-message-injector" import { normalizeSDKResponse } from "../../shared" import { log } from "../../shared/logger" +import { getAgentConfigKey } from "../../shared/agent-display-names" import { ABORT_WINDOW_MS, @@ -162,8 +163,9 @@ export async function handleSessionIdle(args: { log(`[${HOOK_NAME}] Agent check`, { sessionID, agentName: resolvedInfo?.agent, skipAgents, hasCompactionMessage }) - if (resolvedInfo?.agent && skipAgents.includes(resolvedInfo.agent)) { - log(`[${HOOK_NAME}] Skipped: agent in skipAgents list`, { sessionID, agent: resolvedInfo.agent }) + const resolvedAgentName = resolvedInfo?.agent + if (resolvedAgentName && skipAgents.some(s => getAgentConfigKey(s) === getAgentConfigKey(resolvedAgentName))) { + log(`[${HOOK_NAME}] Skipped: agent in skipAgents list`, { sessionID, agent: resolvedAgentName }) return } if (hasCompactionMessage && !resolvedInfo?.agent) { diff --git a/src/shared/session-utils.ts b/src/shared/session-utils.ts index 5a9d33065..5884da784 100644 --- a/src/shared/session-utils.ts +++ b/src/shared/session-utils.ts @@ -2,6 +2,7 @@ import { findNearestMessageWithFields, findNearestMessageWithFieldsFromSDK } fro import { getMessageDir } from "./opencode-message-dir" import { isSqliteBackend } from "./opencode-storage-detection" import { log } from "./logger" +import { getAgentConfigKey } from "./agent-display-names" import type { PluginInput } from "@opencode-ai/plugin" export async function isCallerOrchestrator(sessionID?: string, client?: PluginInput["client"]): Promise { @@ -10,7 +11,7 @@ export async function isCallerOrchestrator(sessionID?: string, client?: PluginIn if (isSqliteBackend() && client) { try { const nearest = await findNearestMessageWithFieldsFromSDK(client, sessionID) - return nearest?.agent?.toLowerCase() === "atlas" + return getAgentConfigKey(nearest?.agent ?? "") === "atlas" } catch (error) { log("[session-utils] SDK orchestrator check failed", { sessionID, error: String(error) }) return false @@ -20,5 +21,5 @@ export async function isCallerOrchestrator(sessionID?: string, client?: PluginIn const messageDir = getMessageDir(sessionID) if (!messageDir) return false const nearest = findNearestMessageWithFields(messageDir) - return nearest?.agent?.toLowerCase() === "atlas" + return getAgentConfigKey(nearest?.agent ?? "") === "atlas" } diff --git a/src/tools/delegate-task/subagent-resolver.ts b/src/tools/delegate-task/subagent-resolver.ts index 79226a002..5651fba29 100644 --- a/src/tools/delegate-task/subagent-resolver.ts +++ b/src/tools/delegate-task/subagent-resolver.ts @@ -4,6 +4,7 @@ import { isPlanFamily } from "./constants" import { SISYPHUS_JUNIOR_AGENT } from "./sisyphus-junior-agent" import { parseModelString } from "./model-string-parser" import { AGENT_MODEL_REQUIREMENTS } from "../../shared/model-requirements" +import { getAgentDisplayName, getAgentConfigKey } from "../../shared/agent-display-names" import { normalizeSDKResponse } from "../../shared" import { getAvailableModelsForDelegateTask } from "./available-models" import { resolveModelForDelegateTask } from "./model-selection" @@ -54,13 +55,16 @@ Create the work plan directly - that's your job as the planning agent.`, const callableAgents = agents.filter((a) => a.mode !== "primary") + const resolvedDisplayName = getAgentDisplayName(agentToUse) const matchedAgent = callableAgents.find( (agent) => agent.name.toLowerCase() === agentToUse.toLowerCase() + || agent.name.toLowerCase() === resolvedDisplayName.toLowerCase() ) if (!matchedAgent) { const isPrimaryAgent = agents .filter((a) => a.mode === "primary") - .find((agent) => agent.name.toLowerCase() === agentToUse.toLowerCase()) + .find((agent) => agent.name.toLowerCase() === agentToUse.toLowerCase() + || agent.name.toLowerCase() === resolvedDisplayName.toLowerCase()) if (isPrimaryAgent) { return { @@ -83,10 +87,10 @@ Create the work plan directly - that's your job as the planning agent.`, agentToUse = matchedAgent.name - const agentNameLower = agentToUse.toLowerCase() - const agentOverride = agentOverrides?.[agentNameLower as keyof typeof agentOverrides] - ?? (agentOverrides ? Object.entries(agentOverrides).find(([key]) => key.toLowerCase() === agentNameLower)?.[1] : undefined) - const agentRequirement = AGENT_MODEL_REQUIREMENTS[agentNameLower] + const agentConfigKey = getAgentConfigKey(agentToUse) + const agentOverride = agentOverrides?.[agentConfigKey as keyof typeof agentOverrides] + ?? (agentOverrides ? Object.entries(agentOverrides).find(([key]) => key.toLowerCase() === agentConfigKey)?.[1] : undefined) + const agentRequirement = AGENT_MODEL_REQUIREMENTS[agentConfigKey] if (agentOverride?.model || agentRequirement || matchedAgent.model) { const availableModels = await getAvailableModelsForDelegateTask(client)