fix(todo-continuation): normalize agent name to config key before promptAsync (#3149)

The todo-continuation-enforcer was passing raw agent names (which could be
display names like 'Sisyphus (Ultraworker)') to promptAsync. These names
contain spaces/parentheses that violate HTTP header specs, causing the
x-opencode-agent-name header validation to fail with 'unknown error' toast.

Added normalizeAgentForPromptKey() that converts display names to config keys
(e.g., 'Sisyphus (Ultraworker)' -> 'sisyphus') before API calls.

TDD: Added regression test that verifies config key is sent to promptAsync.
This commit is contained in:
YeonGyu-Kim
2026-04-06 11:44:11 +09:00
parent 98e6659af5
commit de6c74bfb4
4 changed files with 81 additions and 6 deletions
@@ -14,7 +14,10 @@ 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 {
getAgentConfigKey,
normalizeAgentForPromptKey,
} from "../../shared/agent-display-names"
import {
CONTINUATION_PROMPT,
@@ -122,12 +125,14 @@ export async function injectContinuation(args: {
tools = tools ?? previousMessage?.tools
}
if (agentName && skipAgents.some(s => getAgentConfigKey(s) === getAgentConfigKey(agentName))) {
const promptAgent = normalizeAgentForPromptKey(agentName)
if (promptAgent && skipAgents.some(s => getAgentConfigKey(s) === getAgentConfigKey(promptAgent))) {
log(`[${HOOK_NAME}] Skipped: agent in skipAgents list`, { sessionID, agent: agentName })
return
}
if (!agentName) {
if (!promptAgent) {
const compactionState = sessionStateStore.getExistingState(sessionID)
if (compactionState && isCompactionGuardActive(compactionState, Date.now())) {
log(`[${HOOK_NAME}] Skipped: agent unknown after compaction`, { sessionID })
@@ -162,7 +167,7 @@ ${todoList}`
try {
log(`[${HOOK_NAME}] Injecting continuation`, {
sessionID,
agent: agentName,
agent: promptAgent,
model,
incompleteCount: freshIncompleteCount,
})
@@ -172,7 +177,7 @@ ${todoList}`
await ctx.client.session.promptAsync({
path: { id: sessionID },
body: {
agent: agentName,
agent: promptAgent,
...(model !== undefined ? { model } : {}),
...(inheritedTools ? { tools: inheritedTools } : {}),
parts: [createInternalAgentTextPart(prompt)],