Normalize agent name comparisons to handle display name keys

Hooks and tools now use getAgentConfigKey() to resolve agent names (which may
be display names like 'Atlas (Plan Executor)') to lowercase config keys
before comparison.

- session-utils: orchestrator check uses getAgentConfigKey
- atlas event-handler: boulder agent matching uses config keys
- category-skill-reminder: target agent check uses config keys
- todo-continuation-enforcer: skipAgents comparison normalized
- subagent-resolver: resolves 'metis' -> 'Metis (Plan Consultant)' for lookup
This commit is contained in:
YeonGyu-Kim
2026-02-16 20:43:09 +09:00
parent dde858794a
commit 49b6c108e2
6 changed files with 28 additions and 17 deletions
+5 -3
View File
@@ -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) {
+5 -4
View File
@@ -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")
)
}
@@ -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
}
@@ -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) {