test: fix prometheus-prompt syntax + sync display name casing to lowercase
- prometheus-prompt.test.ts: close missing }) on the OpenSpec expanded commands describe block (introduced byd66b6bcbf, parse error). - agent-sort-shim/agent-config-integration/continuation-injection/ unstable-agent-babysitter/subagent-resolver/sync-executor/ resolve-caller-team-lead tests: expect 'Sisyphus - ultraworker' (lowercase) to match production aftercd39f8858, which lowercased the display name to dodge a TUI ZWSP rendering glitch. Legacy uppercase inputs that exercise the normalization path are preserved. - sync-executor.ts + resolve-caller-team-lead.ts: route legacy display name inputs through normalizeAgentForPrompt so prompt agent names and caller team lead lookups produce the canonical lowercase form.
This commit is contained in:
@@ -219,6 +219,7 @@ describe("PROMETHEUS_SYSTEM_PROMPT OpenSpec expanded commands", () => {
|
||||
//#when / #then
|
||||
expect(prompt).toContain("/opsx:explore")
|
||||
})
|
||||
})
|
||||
|
||||
describe("Prometheus prompts anti-duplication coverage", () => {
|
||||
test("all variants should include anti-duplication rules for delegated exploration", () => {
|
||||
|
||||
@@ -45,7 +45,7 @@ describe("resolveCallerTeamLead", () => {
|
||||
// then
|
||||
expect(result).toEqual({
|
||||
agentTypeId: "sisyphus",
|
||||
displayName: "Sisyphus - Ultraworker",
|
||||
displayName: "Sisyphus - ultraworker",
|
||||
isEligibleForTeamLead: true,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getAgentConfigKey, stripAgentListSortPrefix } from "../../shared/agent-display-names"
|
||||
import { getAgentConfigKey, getAgentDisplayName, stripAgentListSortPrefix } from "../../shared/agent-display-names"
|
||||
|
||||
import { AGENT_ELIGIBILITY_REGISTRY, type TeamSpec } from "./types"
|
||||
|
||||
@@ -13,12 +13,17 @@ export function resolveCallerTeamLead(rawAgentName: string | undefined): CallerT
|
||||
return { isEligibleForTeamLead: false }
|
||||
}
|
||||
|
||||
const displayName = stripAgentListSortPrefix(rawAgentName).trim()
|
||||
if (!displayName) {
|
||||
const strippedDisplayName = stripAgentListSortPrefix(rawAgentName).trim()
|
||||
if (!strippedDisplayName) {
|
||||
return { isEligibleForTeamLead: false }
|
||||
}
|
||||
|
||||
const agentTypeId = getAgentConfigKey(displayName)
|
||||
const agentTypeId = getAgentConfigKey(strippedDisplayName)
|
||||
const canonicalDisplayName = getAgentDisplayName(agentTypeId)
|
||||
const isStructuredDisplayName = strippedDisplayName.includes(" - ")
|
||||
const displayName = isStructuredDisplayName && strippedDisplayName.toLowerCase() === canonicalDisplayName.toLowerCase()
|
||||
? canonicalDisplayName
|
||||
: strippedDisplayName
|
||||
const eligibility = AGENT_ELIGIBILITY_REGISTRY[agentTypeId]
|
||||
if (!eligibility || eligibility.verdict === "hard-reject") {
|
||||
return {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
declare const require: (name: string) => any
|
||||
const { afterEach, describe, expect, test } = require("bun:test")
|
||||
import { afterEach, describe, expect, test } from "bun:test"
|
||||
|
||||
import { injectContinuation } from "./continuation-injection"
|
||||
import { OMO_INTERNAL_INITIATOR_MARKER } from "../../shared/internal-initiator-marker"
|
||||
@@ -42,14 +41,14 @@ describe("injectContinuation", () => {
|
||||
ctx: ctx as never,
|
||||
sessionID: "ses_display_name_agent",
|
||||
resolvedInfo: {
|
||||
agent: "Sisyphus - Ultraworker",
|
||||
agent: "Sisyphus - ultraworker",
|
||||
model: { providerID: "anthropic", modelID: "claude-sonnet-4-20250514" },
|
||||
},
|
||||
sessionStateStore: sessionStateStore as never,
|
||||
})
|
||||
|
||||
// then
|
||||
expect(capturedAgent).toBe("Sisyphus - Ultraworker")
|
||||
expect(capturedAgent).toBe("Sisyphus - ultraworker")
|
||||
})
|
||||
|
||||
test("#given resolved agent name still carries a ZWSP sort prefix #when continuation is injected #then promptAsync receives the agent name without the ZWSP prefix", async () => {
|
||||
@@ -80,14 +79,14 @@ describe("injectContinuation", () => {
|
||||
ctx: ctx as never,
|
||||
sessionID: "ses_zwsp_agent",
|
||||
resolvedInfo: {
|
||||
agent: "\u200B\u200BSisyphus - Ultraworker",
|
||||
agent: "\u200B\u200BSisyphus - ultraworker",
|
||||
model: { providerID: "anthropic", modelID: "claude-sonnet-4-20250514" },
|
||||
},
|
||||
sessionStateStore: sessionStateStore as never,
|
||||
})
|
||||
|
||||
// then
|
||||
expect(capturedAgent).toBe("Sisyphus - Ultraworker")
|
||||
expect(capturedAgent).toBe("Sisyphus - ultraworker")
|
||||
expect(capturedAgent).not.toContain("\u200B")
|
||||
})
|
||||
|
||||
@@ -254,7 +253,12 @@ describe("injectContinuation", () => {
|
||||
},
|
||||
},
|
||||
}
|
||||
const state = { inFlight: false, lastInjectedAt: 0, consecutiveFailures: 0 }
|
||||
const state = {
|
||||
inFlight: false,
|
||||
lastInjectedAt: 0,
|
||||
consecutiveFailures: 0,
|
||||
awaitingPostInjectionProgressCheck: false,
|
||||
}
|
||||
const sessionStateStore = {
|
||||
getExistingState: () => state,
|
||||
}
|
||||
@@ -276,7 +280,7 @@ describe("injectContinuation", () => {
|
||||
ctx: ctx as never,
|
||||
sessionID,
|
||||
resolvedInfo: {
|
||||
agent: "Sisyphus - Ultraworker",
|
||||
agent: "Sisyphus - ultraworker",
|
||||
model: { providerID: "anthropic", modelID: "claude-sonnet-4-20250514" },
|
||||
},
|
||||
sessionStateStore: sessionStateStore as never,
|
||||
@@ -320,7 +324,7 @@ describe("injectContinuation", () => {
|
||||
ctx: ctx as never,
|
||||
sessionID: "ses_continuation_eof",
|
||||
resolvedInfo: {
|
||||
agent: "Sisyphus - Ultraworker",
|
||||
agent: "Sisyphus - ultraworker",
|
||||
model: { providerID: "anthropic", modelID: "claude-sonnet-4-20250514" },
|
||||
},
|
||||
sessionStateStore: sessionStateStore as never,
|
||||
|
||||
@@ -633,7 +633,7 @@ describe("unstable-agent-babysitter hook", () => {
|
||||
// then
|
||||
const payload = promptCalls[0]?.input as { body?: { parts?: Array<{ text?: string }> } } | undefined
|
||||
const text = payload?.body?.parts?.[0]?.text ?? ""
|
||||
expect(text).toContain("Agent: Sisyphus - Ultraworker")
|
||||
expect(text).toContain("Agent: Sisyphus - ultraworker")
|
||||
expect(text).not.toContain("Agent: sisyphus")
|
||||
})
|
||||
|
||||
@@ -657,7 +657,7 @@ describe("unstable-agent-babysitter hook", () => {
|
||||
// then
|
||||
const payload = promptCalls[0]?.input as { body?: { parts?: Array<{ text?: string }> } } | undefined
|
||||
const text = payload?.body?.parts?.[0]?.text ?? ""
|
||||
expect(text).toContain("Agent: Sisyphus - Ultraworker")
|
||||
expect(text).toContain("Agent: Sisyphus - ultraworker")
|
||||
expect(text).not.toContain("Agent: Sisyphus (Ultraworker)")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -92,7 +92,7 @@ describe("Agent Config Integration", () => {
|
||||
const displayNames = agents.map((agent) => getAgentDisplayName(agent))
|
||||
|
||||
// then - display names are correct
|
||||
expect(displayNames).toContain("Sisyphus - Ultraworker")
|
||||
expect(displayNames).toContain("Sisyphus - ultraworker")
|
||||
expect(displayNames).toContain("Hephaestus - Deep Agent")
|
||||
expect(displayNames).toContain("Prometheus - Plan Builder")
|
||||
expect(displayNames).toContain("Atlas - Plan Executor")
|
||||
@@ -112,9 +112,9 @@ describe("Agent Config Integration", () => {
|
||||
const displayNames = keys.map((key) => getAgentDisplayName(key))
|
||||
|
||||
// then - correct display names are returned
|
||||
expect(displayNames[0]).toBe("Sisyphus - Ultraworker")
|
||||
expect(displayNames[0]).toBe("Sisyphus - ultraworker")
|
||||
expect(displayNames[1]).toBe("Atlas - Plan Executor")
|
||||
expect(displayNames[2]).toBe("Sisyphus - Ultraworker")
|
||||
expect(displayNames[2]).toBe("Sisyphus - ultraworker")
|
||||
expect(displayNames[3]).toBe("Atlas - Plan Executor")
|
||||
expect(displayNames[4]).toBe("Prometheus - Plan Builder")
|
||||
expect(displayNames[5]).toBe("Prometheus - Plan Builder")
|
||||
@@ -189,7 +189,7 @@ describe("Agent Config Integration", () => {
|
||||
const prometheusDisplay = getAgentDisplayName("prometheus")
|
||||
|
||||
// then - display names are correct
|
||||
expect(sisyphusDisplay).toBe("Sisyphus - Ultraworker")
|
||||
expect(sisyphusDisplay).toBe("Sisyphus - ultraworker")
|
||||
expect(prometheusDisplay).toBe("Prometheus - Plan Builder")
|
||||
|
||||
// then - config values are preserved
|
||||
@@ -218,7 +218,7 @@ describe("Agent Config Integration", () => {
|
||||
const atlasDisplay = getAgentDisplayName("atlas")
|
||||
|
||||
// then - display names are correct
|
||||
expect(sisyphusDisplay).toBe("Sisyphus - Ultraworker")
|
||||
expect(sisyphusDisplay).toBe("Sisyphus - ultraworker")
|
||||
expect(atlasDisplay).toBe("Atlas - Plan Executor")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -30,7 +30,7 @@ describe("agent-sort-shim", () => {
|
||||
test("#then returns canonical sisyphus->hephaestus->prometheus->atlas order", () => {
|
||||
// given
|
||||
setAgentSortOrder(undefined)
|
||||
const sisyphus = { name: "Sisyphus - Ultraworker" }
|
||||
const sisyphus = { name: "Sisyphus - ultraworker" }
|
||||
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
||||
const prometheus = { name: "Prometheus - Plan Builder" }
|
||||
const atlas = { name: "Atlas - Plan Executor" }
|
||||
@@ -46,7 +46,7 @@ describe("agent-sort-shim", () => {
|
||||
test("#then follows configured core agent order", () => {
|
||||
// given
|
||||
setAgentSortOrder(["hephaestus", "sisyphus", "prometheus", "atlas"])
|
||||
const sisyphus = { name: "Sisyphus - Ultraworker" }
|
||||
const sisyphus = { name: "Sisyphus - ultraworker" }
|
||||
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
||||
const prometheus = { name: "Prometheus - Plan Builder" }
|
||||
const atlas = { name: "Atlas - Plan Executor" }
|
||||
@@ -65,7 +65,7 @@ describe("agent-sort-shim", () => {
|
||||
describe("#when toSorted with alphabetical compareFn", () => {
|
||||
test("#then core agents come first in canonical order followed by non-core agents alphabetically", () => {
|
||||
// given
|
||||
const sisyphus = { name: "Sisyphus - Ultraworker" }
|
||||
const sisyphus = { name: "Sisyphus - ultraworker" }
|
||||
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
||||
const prometheus = { name: "Prometheus - Plan Builder" }
|
||||
const atlas = { name: "Atlas - Plan Executor" }
|
||||
@@ -114,7 +114,7 @@ describe("agent-sort-shim", () => {
|
||||
// given
|
||||
const oracle = { name: "oracle" }
|
||||
const librarian = { name: "librarian" }
|
||||
const sisyphus = { name: "Sisyphus - Ultraworker" }
|
||||
const sisyphus = { name: "Sisyphus - ultraworker" }
|
||||
const explore = { name: "explore" }
|
||||
const input = [oracle, librarian, sisyphus, explore]
|
||||
|
||||
@@ -133,7 +133,7 @@ describe("agent-sort-shim", () => {
|
||||
describe("#when toSorted with a string-coercing compareFn", () => {
|
||||
test("#then activation predicate fails, shim does not throw, and result matches native semantics", () => {
|
||||
// given
|
||||
const sisyphusObj = { name: "Sisyphus - Ultraworker" }
|
||||
const sisyphusObj = { name: "Sisyphus - ultraworker" }
|
||||
const hephaestusObj = { name: "Hephaestus - Deep Agent" }
|
||||
const input: unknown[] = [null, sisyphusObj, "string", 42, hephaestusObj]
|
||||
const compare = (a: unknown, b: unknown): number => {
|
||||
@@ -188,7 +188,7 @@ describe("agent-sort-shim", () => {
|
||||
describe("#when sort with alphabetical compareFn (in-place)", () => {
|
||||
test("#then mutates the original array to canonical order", () => {
|
||||
// given
|
||||
const sisyphus = { name: "Sisyphus - Ultraworker" }
|
||||
const sisyphus = { name: "Sisyphus - ultraworker" }
|
||||
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
||||
const prometheus = { name: "Prometheus - Plan Builder" }
|
||||
const atlas = { name: "Atlas - Plan Executor" }
|
||||
@@ -210,7 +210,7 @@ describe("agent-sort-shim", () => {
|
||||
// given
|
||||
installAgentSortShim()
|
||||
installAgentSortShim()
|
||||
const sisyphus = { name: "Sisyphus - Ultraworker" }
|
||||
const sisyphus = { name: "Sisyphus - ultraworker" }
|
||||
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
||||
const prometheus = { name: "Prometheus - Plan Builder" }
|
||||
const atlas = { name: "Atlas - Plan Executor" }
|
||||
@@ -231,7 +231,7 @@ describe("agent-sort-shim", () => {
|
||||
// given
|
||||
setAgentSortOrder(undefined)
|
||||
setDefaultAgentForSort("crystal")
|
||||
const sisyphus = { name: "Sisyphus - Ultraworker" }
|
||||
const sisyphus = { name: "Sisyphus - ultraworker" }
|
||||
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
||||
const prometheus = { name: "Prometheus - Plan Builder" }
|
||||
const atlas = { name: "Atlas - Plan Executor" }
|
||||
@@ -251,7 +251,7 @@ describe("agent-sort-shim", () => {
|
||||
// given
|
||||
setAgentSortOrder(undefined)
|
||||
setDefaultAgentForSort("Hephaestus - Deep Agent")
|
||||
const sisyphus = { name: "Sisyphus - Ultraworker" }
|
||||
const sisyphus = { name: "Sisyphus - ultraworker" }
|
||||
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
||||
const prometheus = { name: "Prometheus - Plan Builder" }
|
||||
const atlas = { name: "Atlas - Plan Executor" }
|
||||
@@ -272,7 +272,7 @@ describe("agent-sort-shim", () => {
|
||||
// given
|
||||
setAgentSortOrder(["hephaestus", "sisyphus", "prometheus", "atlas"])
|
||||
// setDefaultAgentForSort is intentionally NOT called (user did not set default_agent)
|
||||
const sisyphus = { name: "Sisyphus - Ultraworker" }
|
||||
const sisyphus = { name: "Sisyphus - ultraworker" }
|
||||
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
||||
const prometheus = { name: "Prometheus - Plan Builder" }
|
||||
const atlas = { name: "Atlas - Plan Executor" }
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/// <reference types="bun-types" />
|
||||
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
import { describe, test, expect, mock } from "bun:test"
|
||||
|
||||
@@ -140,7 +142,7 @@ describe("executeSync", () => {
|
||||
|
||||
//#then
|
||||
const promptInput = recorder.getCapturedInput()
|
||||
expect(promptInput?.body.agent).toBe("Sisyphus - Ultraworker")
|
||||
expect(promptInput?.body.agent).toBe("Sisyphus - ultraworker")
|
||||
})
|
||||
|
||||
test("#given subagent_type is the lowercase config key 'hephaestus' #when executeSync runs #then prompt receives the registered display name 'Hephaestus - Deep Agent'", async () => {
|
||||
@@ -449,7 +451,7 @@ describe("executeSync", () => {
|
||||
|
||||
//#then
|
||||
const promptInput = recorder.getCapturedInput()
|
||||
expect(promptInput?.body.agent).toBe("Sisyphus - Ultraworker")
|
||||
expect(promptInput?.body.agent).toBe("Sisyphus - ultraworker")
|
||||
})
|
||||
|
||||
test("returns generic prompt failure with task metadata", async () => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import { clearSessionAgent, setSessionAgent, subagentSessions, syncSubagentSessions } from "../../features/claude-code-session-state"
|
||||
import { dispatchInternalPrompt, isInternalPromptDispatchAccepted } from "../../hooks/shared/prompt-async-gate"
|
||||
import { getAgentToolRestrictions, isAmbiguousPostDispatchPromptFailure, log } from "../../shared"
|
||||
import { getAgentDisplayName, stripAgentListSortPrefix } from "../../shared/agent-display-names"
|
||||
import { normalizeAgentForPrompt, stripAgentListSortPrefix } from "../../shared/agent-display-names"
|
||||
import {
|
||||
clearDelegatedChildSessionBootstrap,
|
||||
registerDelegatedChildSessionBootstrap,
|
||||
@@ -118,7 +118,7 @@ export async function executeSync(
|
||||
log(`[call_omo_agent] Sending prompt to session ${sessionID}`)
|
||||
log(`[call_omo_agent] Prompt text:`, args.prompt.substring(0, 100))
|
||||
const normalizedSubagentType = stripAgentListSortPrefix(args.subagent_type)
|
||||
const promptAgent = getAgentDisplayName(normalizedSubagentType)
|
||||
const promptAgent = normalizeAgentForPrompt(normalizedSubagentType) ?? normalizedSubagentType
|
||||
const promptTools = buildSyncPromptTools(normalizedSubagentType)
|
||||
setSessionAgent(sessionID, promptAgent)
|
||||
setSessionTools(sessionID, promptTools)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/// <reference types="bun-types" />
|
||||
|
||||
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test"
|
||||
import type { DelegateTaskArgs } from "../types"
|
||||
import type { ExecutorContext } from "../executor-types"
|
||||
@@ -180,7 +182,7 @@ describe("resolveSubagentExecution", () => {
|
||||
})
|
||||
const args = createBaseArgs({ subagent_type: "sisyphus" })
|
||||
const executorCtx = createExecutorContext(async () => ([
|
||||
{ name: "\u200BSisyphus - Ultraworker", mode: "primary", model: "anthropic/claude-opus-4-7" },
|
||||
{ name: "Sisyphus - ultraworker", mode: "primary", model: "anthropic/claude-opus-4-7" },
|
||||
{ name: "oracle", mode: "subagent" },
|
||||
]))
|
||||
|
||||
@@ -191,7 +193,7 @@ describe("resolveSubagentExecution", () => {
|
||||
|
||||
//#then
|
||||
expect(result.error).toBeUndefined()
|
||||
expect(result.agentToUse).toBe("\u200BSisyphus - Ultraworker")
|
||||
expect(result.agentToUse).toBe("Sisyphus - ultraworker")
|
||||
})
|
||||
|
||||
test("allows delegating to Sisyphus-Junior when allowSisyphusJuniorDirect is enabled (team-mode path)", async () => {
|
||||
@@ -665,7 +667,7 @@ describe("resolveSubagentExecution", () => {
|
||||
//#given
|
||||
const args = createBaseArgs({ subagent_type: "\uFEFFSisyphus - Ultraworker" })
|
||||
const executorCtx = createExecutorContext(async () => ([
|
||||
{ name: "\u200BSisyphus - Ultraworker", mode: "subagent", model: "openai/gpt-5.3-codex" },
|
||||
{ name: "\u200BSisyphus - ultraworker", mode: "subagent", model: "openai/gpt-5.3-codex" },
|
||||
]))
|
||||
|
||||
//#when
|
||||
@@ -673,7 +675,7 @@ describe("resolveSubagentExecution", () => {
|
||||
|
||||
//#then
|
||||
expect(result.error).toBeUndefined()
|
||||
expect(result.agentToUse).toBe("Sisyphus - Ultraworker")
|
||||
expect(result.agentToUse).toBe("Sisyphus - ultraworker")
|
||||
})
|
||||
|
||||
test("uses agent override fallback_models for subagent runtime fallback chain", async () => {
|
||||
@@ -1409,7 +1411,7 @@ describe("resolveSubagentExecution - agent name sanitization", () => {
|
||||
})
|
||||
const args = createBaseArgs({ subagent_type: "Sisyphus - Ultraworker" })
|
||||
const executorCtx = createExecutorContext(async () => ([
|
||||
{ name: "\u200BSisyphus - Ultraworker", mode: "subagent", model: "openai/gpt-5.3-codex" },
|
||||
{ name: "\u200BSisyphus - ultraworker", mode: "subagent", model: "openai/gpt-5.3-codex" },
|
||||
]))
|
||||
|
||||
//#when
|
||||
@@ -1417,7 +1419,7 @@ describe("resolveSubagentExecution - agent name sanitization", () => {
|
||||
|
||||
//#then
|
||||
expect(result.error).toBeUndefined()
|
||||
expect(result.agentToUse).toBe("Sisyphus - Ultraworker")
|
||||
expect(result.agentToUse).toBe("Sisyphus - ultraworker")
|
||||
})
|
||||
|
||||
test("strips legacy ZWSP-prefixed agent names from persisted subagent runtime state (GH-3259)", async () => {
|
||||
|
||||
Reference in New Issue
Block a user