diff --git a/src/cli/run/message-part-delta.test.ts b/src/cli/run/message-part-delta.test.ts index 179366a24..6d7fefa6e 100644 --- a/src/cli/run/message-part-delta.test.ts +++ b/src/cli/run/message-part-delta.test.ts @@ -89,7 +89,7 @@ describe("message.part.delta handling", () => { //#given const ctx = createMockContext("ses_main") const state = createEventState() - state.agentColorsByName["Sisyphus (Ultraworker)"] = "#00CED1" + state.agentColorsByName["Sisyphus - Ultraworker"] = "#00CED1" const stdoutSpy = spyOn(process.stdout, "write").mockImplementation(() => true) const payload: EventPayload = { type: "message.updated", @@ -97,7 +97,7 @@ describe("message.part.delta handling", () => { info: { sessionID: "ses_main", role: "assistant", - agent: "Sisyphus (Ultraworker)", + agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6", variant: "max", }, @@ -115,7 +115,7 @@ describe("message.part.delta handling", () => { expect(rendered).toContain("\u001b[38;2;0;206;209m") expect(rendered).toContain("claude-opus-4-6 (max)") expect(rendered).toContain("└─") - expect(rendered).toContain("Sisyphus (Ultraworker)") + expect(rendered).toContain("Sisyphus - Ultraworker") stdoutSpy.mockRestore() }) @@ -128,7 +128,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus (Ultraworker)", modelID: "claude-opus-4-6" }, + info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, }, }, { @@ -187,7 +187,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus (Ultraworker)", modelID: "claude-opus-4-6" }, + info: { sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, }, }, { @@ -242,7 +242,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus (Ultraworker)", modelID: "claude-opus-4-6" }, + info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, }, }, { @@ -309,7 +309,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus (Ultraworker)", modelID: "claude-opus-4-6" }, + info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, }, }, { @@ -353,7 +353,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus (Ultraworker)", modelID: "claude-opus-4-6", variant: "max" }, + info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6", variant: "max" }, }, }, { @@ -388,7 +388,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_user", sessionID: "ses_main", role: "user", agent: "Sisyphus (Ultraworker)", modelID: "claude-opus-4-6" }, + info: { id: "msg_user", sessionID: "ses_main", role: "user", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, }, }, { @@ -410,7 +410,7 @@ describe("message.part.delta handling", () => { { type: "message.updated", properties: { - info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus (Ultraworker)", modelID: "claude-opus-4-6" }, + info: { id: "msg_assistant", sessionID: "ses_main", role: "assistant", agent: "Sisyphus - Ultraworker", modelID: "claude-opus-4-6" }, }, }, { diff --git a/src/cli/run/runner.test.ts b/src/cli/run/runner.test.ts index 19b7079a3..e0eb7ec3d 100644 --- a/src/cli/run/runner.test.ts +++ b/src/cli/run/runner.test.ts @@ -31,7 +31,7 @@ describe("resolveRunAgent", () => { ) // then - expect(agent).toBe("Hephaestus (Deep Agent)") + expect(agent).toBe("Hephaestus - Deep Agent") }) it("uses env agent over config", () => { @@ -43,7 +43,7 @@ describe("resolveRunAgent", () => { const agent = resolveRunAgent({ message: "test" }, config, env) // then - expect(agent).toBe("Atlas (Plan Executor)") + expect(agent).toBe("Atlas - Plan Executor") }) it("uses config agent over default", () => { @@ -54,7 +54,7 @@ describe("resolveRunAgent", () => { const agent = resolveRunAgent({ message: "test" }, config, {}) // then - expect(agent).toBe("Prometheus (Plan Builder)") + expect(agent).toBe("Prometheus - Plan Builder") }) it("falls back to sisyphus when none set", () => { @@ -65,7 +65,7 @@ describe("resolveRunAgent", () => { const agent = resolveRunAgent({ message: "test" }, config, {}) // then - expect(agent).toBe("Sisyphus (Ultraworker)") + expect(agent).toBe("Sisyphus - Ultraworker") }) it("skips disabled sisyphus for next available core agent", () => { @@ -76,18 +76,18 @@ describe("resolveRunAgent", () => { const agent = resolveRunAgent({ message: "test" }, config, {}) // then - expect(agent).toBe("Hephaestus (Deep Agent)") + expect(agent).toBe("Hephaestus - Deep Agent") }) it("maps display-name style default_run_agent values to canonical display names", () => { // given - const config = createConfig({ default_run_agent: "Sisyphus (Ultraworker)" }) + const config = createConfig({ default_run_agent: "Sisyphus - Ultraworker" }) // when const agent = resolveRunAgent({ message: "test" }, config, {}) // then - expect(agent).toBe("Sisyphus (Ultraworker)") + expect(agent).toBe("Sisyphus - Ultraworker") }) }) diff --git a/src/features/claude-code-session-state/state.test.ts b/src/features/claude-code-session-state/state.test.ts index 3f860b060..89a755bdb 100644 --- a/src/features/claude-code-session-state/state.test.ts +++ b/src/features/claude-code-session-state/state.test.ts @@ -40,13 +40,13 @@ describe("claude-code-session-state", () => { test("should strip zero-width ordering prefixes before storing agent for session", () => { // given const sessionID = "test-session-prefixed" - const agent = "\u200B\u200B\u200BPrometheus (Plan Builder)" + const agent = "\u200B\u200B\u200BPrometheus - Plan Builder" // when setSessionAgent(sessionID, agent) // then - expect(getSessionAgent(sessionID)).toBe("Prometheus (Plan Builder)") + expect(getSessionAgent(sessionID)).toBe("Prometheus - Plan Builder") }) test("should NOT overwrite existing agent (first-write wins)", () => { @@ -88,10 +88,10 @@ describe("claude-code-session-state", () => { setSessionAgent(sessionID, "sisyphus") // when - updateSessionAgent(sessionID, "\u200B\u200BHephaestus (Deep Agent)") + updateSessionAgent(sessionID, "\u200B\u200BHephaestus - Deep Agent") // then - expect(getSessionAgent(sessionID)).toBe("Hephaestus (Deep Agent)") + expect(getSessionAgent(sessionID)).toBe("Hephaestus - Deep Agent") }) }) @@ -133,21 +133,21 @@ describe("claude-code-session-state", () => { describe("agent registration", () => { test("should register config-key lookup when given a display name", () => { // given - registerAgentName("Atlas (Plan Executor)") + registerAgentName("Atlas - Plan Executor") // when / then expect(isAgentRegistered("atlas")).toBe(true) - expect(isAgentRegistered("Atlas (Plan Executor)")).toBe(true) + expect(isAgentRegistered("Atlas - Plan Executor")).toBe(true) }) describe("#given atlas display name with zero-width prefix", () => { describe("#when checking registration without the zero-width prefix", () => { test("#then it treats the display name as registered", () => { // given - registerAgentName("\u200BAtlas (Plan Executor)") + registerAgentName("\u200BAtlas - Plan Executor") // when - const isRegistered = isAgentRegistered("Atlas (Plan Executor)") + const isRegistered = isAgentRegistered("Atlas - Plan Executor") // then expect(isRegistered).toBe(true) diff --git a/src/hooks/atlas/index.test.ts b/src/hooks/atlas/index.test.ts index f2f2fd68f..0f9e7d605 100644 --- a/src/hooks/atlas/index.test.ts +++ b/src/hooks/atlas/index.test.ts @@ -1817,10 +1817,10 @@ session_id: ses_untrusted_999 started_at: "2026-01-02T10:00:00Z", session_ids: [MAIN_SESSION_ID], plan_name: "test-plan", - agent: "Atlas (Plan Executor)", + agent: "Atlas - Plan Executor", } writeBoulderState(TEST_DIR, state) - registerAgentName("Atlas (Plan Executor)") + registerAgentName("Atlas - Plan Executor") const mockInput = createMockPluginInput() const hook = createAtlasHook(mockInput) @@ -1836,7 +1836,7 @@ session_id: ses_untrusted_999 // then expect(mockInput._promptMock).toHaveBeenCalled() const callArgs = mockInput._promptMock.mock.calls[0][0] - expect(callArgs.body.agent).toBe("Atlas (Plan Executor)") + expect(callArgs.body.agent).toBe("Atlas - Plan Executor") expect(callArgs.body.agent).not.toBe("atlas") }) diff --git a/src/hooks/model-fallback/hook.test.ts b/src/hooks/model-fallback/hook.test.ts index 8c59db5f5..c16cbdbb5 100644 --- a/src/hooks/model-fallback/hook.test.ts +++ b/src/hooks/model-fallback/hook.test.ts @@ -94,7 +94,7 @@ describe("model fallback hook", () => { const set = setPendingModelFallback( "ses_model_fallback_main", - "Sisyphus (Ultraworker)", + "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-6-thinking", ) @@ -132,7 +132,7 @@ describe("model fallback hook", () => { const sessionID = "ses_model_fallback_main" expect( - setPendingModelFallback(sessionID, "Sisyphus (Ultraworker)", "anthropic", "claude-opus-4-6-thinking"), + setPendingModelFallback(sessionID, "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-6-thinking"), ).toBe(true) const firstOutput = { @@ -154,7 +154,7 @@ describe("model fallback hook", () => { //#when - second error re-arms fallback and should advance to next entry expect( - setPendingModelFallback(sessionID, "Sisyphus (Ultraworker)", "anthropic", "claude-opus-4-6"), + setPendingModelFallback(sessionID, "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-6"), ).toBe(true) const secondOutput = { @@ -181,13 +181,13 @@ describe("model fallback hook", () => { //#when const firstSet = setPendingModelFallback( sessionID, - "Sisyphus (Ultraworker)", + "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-6-thinking", ) const secondSet = setPendingModelFallback( sessionID, - "Sisyphus (Ultraworker)", + "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-6-thinking", ) @@ -218,7 +218,7 @@ describe("model fallback hook", () => { expect( setPendingModelFallback( sessionID, - "Sisyphus (Ultraworker)", + "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-6", ), @@ -262,7 +262,7 @@ describe("model fallback hook", () => { expect( setPendingModelFallback( sessionID, - "Sisyphus (Ultraworker)", + "Sisyphus - Ultraworker", "quotio", "claude-opus-4-6", ), @@ -308,7 +308,7 @@ describe("model fallback hook", () => { expect( setPendingModelFallback( sessionID, - "Sisyphus (Ultraworker)", + "Sisyphus - Ultraworker", "provider-x", "current-model", ), @@ -348,7 +348,7 @@ describe("model fallback hook", () => { const set = setPendingModelFallback( "ses_model_fallback_toast", - "Sisyphus (Ultraworker)", + "Sisyphus - Ultraworker", "anthropic", "claude-opus-4-6-thinking", ) @@ -389,7 +389,7 @@ describe("model fallback hook", () => { const set = setPendingModelFallback( sessionID, - "Atlas (Plan Executor)", + "Atlas - Plan Executor", "github-copilot", "claude-sonnet-4-5", ) diff --git a/src/hooks/no-hephaestus-non-gpt/hook.ts b/src/hooks/no-hephaestus-non-gpt/hook.ts index e621c6d01..afce7ba9c 100644 --- a/src/hooks/no-hephaestus-non-gpt/hook.ts +++ b/src/hooks/no-hephaestus-non-gpt/hook.ts @@ -54,11 +54,11 @@ export function createNoHephaestusNonGptHook( if (allowNonGptModel) { return } - input.agent = SISYPHUS_DISPLAY + input.agent = "sisyphus" if (output?.message) { - output.message.agent = SISYPHUS_DISPLAY + output.message.agent = "sisyphus" } - updateSessionAgent(input.sessionID, SISYPHUS_DISPLAY) + updateSessionAgent(input.sessionID, "sisyphus") } }, } diff --git a/src/hooks/no-hephaestus-non-gpt/index.test.ts b/src/hooks/no-hephaestus-non-gpt/index.test.ts index 3440cccc8..7686bdbf1 100644 --- a/src/hooks/no-hephaestus-non-gpt/index.test.ts +++ b/src/hooks/no-hephaestus-non-gpt/index.test.ts @@ -40,8 +40,8 @@ describe("no-hephaestus-non-gpt hook", () => { // then - toast is shown and agent is switched to sisyphus expect(showToast).toHaveBeenCalledTimes(2) - expect(output1.message.agent).toBe(SISYPHUS_DISPLAY) - expect(output2.message.agent).toBe(SISYPHUS_DISPLAY) + expect(output1.message.agent).toBe("sisyphus") + expect(output2.message.agent).toBe("sisyphus") expect(showToast.mock.calls[0]?.[0]).toMatchObject({ body: { title: "NEVER Use Hephaestus with Non-GPT", @@ -141,6 +141,6 @@ describe("no-hephaestus-non-gpt hook", () => { // then - toast shown via session-agent fallback, switched to sisyphus expect(showToast).toHaveBeenCalledTimes(1) - expect(output.message.agent).toBe(SISYPHUS_DISPLAY) + expect(output.message.agent).toBe("sisyphus") }) }) diff --git a/src/hooks/no-sisyphus-gpt/hook.ts b/src/hooks/no-sisyphus-gpt/hook.ts index a4e6c77da..65ab8d113 100644 --- a/src/hooks/no-sisyphus-gpt/hook.ts +++ b/src/hooks/no-sisyphus-gpt/hook.ts @@ -43,11 +43,11 @@ export function createNoSisyphusGptHook(ctx: PluginInput) { if (agentKey === "sisyphus" && modelID && isGptModel(modelID) && !isGpt5_4Model(modelID)) { showToast(ctx, input.sessionID) - input.agent = HEPHAESTUS_DISPLAY + input.agent = "hephaestus" if (output?.message) { - output.message.agent = HEPHAESTUS_DISPLAY + output.message.agent = "hephaestus" } - updateSessionAgent(input.sessionID, HEPHAESTUS_DISPLAY) + updateSessionAgent(input.sessionID, "hephaestus") } }, } diff --git a/src/hooks/no-sisyphus-gpt/index.test.ts b/src/hooks/no-sisyphus-gpt/index.test.ts index c5fef658d..908a01351 100644 --- a/src/hooks/no-sisyphus-gpt/index.test.ts +++ b/src/hooks/no-sisyphus-gpt/index.test.ts @@ -38,8 +38,8 @@ describe("no-sisyphus-gpt hook", () => { // then - toast is shown for every message expect(showToast).toHaveBeenCalledTimes(2) - expect(output1.message.agent).toBe(HEPHAESTUS_DISPLAY) - expect(output2.message.agent).toBe(HEPHAESTUS_DISPLAY) + expect(output1.message.agent).toBe("hephaestus") + expect(output2.message.agent).toBe("hephaestus") expect(showToast.mock.calls[0]?.[0]).toMatchObject({ body: { title: "NEVER Use Sisyphus with GPT", @@ -131,6 +131,6 @@ describe("no-sisyphus-gpt hook", () => { // then - toast shown via session-agent fallback expect(showToast).toHaveBeenCalledTimes(1) - expect(output.message.agent).toBe(HEPHAESTUS_DISPLAY) + expect(output.message.agent).toBe("hephaestus") }) }) diff --git a/src/hooks/prometheus-md-only/index.test.ts b/src/hooks/prometheus-md-only/index.test.ts index 5ff8d0ece..f51ac88e7 100644 --- a/src/hooks/prometheus-md-only/index.test.ts +++ b/src/hooks/prometheus-md-only/index.test.ts @@ -94,7 +94,7 @@ describe("prometheus-md-only", () => { test("should enforce md-only restriction for Prometheus display name Plan Builder", async () => { //#given - setupMessageStorage(TEST_SESSION_ID, "Prometheus (Plan Builder)") + setupMessageStorage(TEST_SESSION_ID, "Prometheus - Plan Builder") const hook = createPrometheusMdOnlyHook(createMockPluginInput()) const input = { tool: "Write", diff --git a/src/hooks/runtime-fallback/auto-retry.ts b/src/hooks/runtime-fallback/auto-retry.ts index fa8d1154a..de946af5b 100644 --- a/src/hooks/runtime-fallback/auto-retry.ts +++ b/src/hooks/runtime-fallback/auto-retry.ts @@ -133,14 +133,14 @@ export function createAutoRetryHelpers(deps: HookDeps) { }) const retryAgent = resolvedAgent ?? getSessionAgent(sessionID) - const retryAgentDisplayName = retryAgent ? getAgentDisplayName(retryAgent) : undefined sessionAwaitingFallbackResult.add(sessionID) scheduleSessionFallbackTimeout(sessionID, retryAgent) await ctx.client.session.promptAsync({ path: { id: sessionID }, body: { - ...(retryAgentDisplayName ? { agent: retryAgentDisplayName } : {}), + // Use config key to avoid HTTP header validation issues with display names + ...(retryAgent ? { agent: retryAgent } : {}), ...retryModelPayload, parts: retryParts, }, diff --git a/src/hooks/runtime-fallback/index.test.ts b/src/hooks/runtime-fallback/index.test.ts index fce27febe..a1b52c96e 100644 --- a/src/hooks/runtime-fallback/index.test.ts +++ b/src/hooks/runtime-fallback/index.test.ts @@ -2458,7 +2458,7 @@ describe("runtime-fallback", () => { expect(promptCalls.length).toBe(1) const callBody = promptCalls[0]?.body as Record - expect(callBody?.agent).toBe("Prometheus (Plan Builder)") + expect(callBody?.agent).toBe("prometheus") expect(callBody?.model).toEqual({ providerID: "github-copilot", modelID: "claude-opus-4.6" }) }) }) diff --git a/src/hooks/start-work/index.test.ts b/src/hooks/start-work/index.test.ts index 874c7910f..9957b9608 100644 --- a/src/hooks/start-work/index.test.ts +++ b/src/hooks/start-work/index.test.ts @@ -453,7 +453,7 @@ You are starting a Sisyphus work session. ) // then - expect(output.message.agent).toBe(getAgentListDisplayName("atlas")) + expect(output.message.agent).toBe("atlas") }) test("should switch to Atlas even when current session is Sisyphus (regression: #3155)", async () => { @@ -473,7 +473,7 @@ You are starting a Sisyphus work session. ) // atlas is registered in beforeEach, so it must be selected - expect(output.message.agent).toBe(getAgentListDisplayName("atlas")) + expect(output.message.agent).toBe("atlas") expect(sessionState.getSessionAgent("ses-sisyphus-to-atlas")).toBe("atlas") }) @@ -496,7 +496,7 @@ You are starting a Sisyphus work session. ) // then - expect(output.message.agent).toBe("Sisyphus (Ultraworker)") + expect(output.message.agent).toBe("sisyphus") expect(sessionState.getSessionAgent("ses-prometheus-to-sisyphus")).toBe("sisyphus") }) @@ -524,7 +524,7 @@ You are starting a Sisyphus work session. ) // then - expect(output.message.agent).toBe("Sisyphus (Ultraworker)") + expect(output.message.agent).toBe("sisyphus") expect(sessionState.getSessionAgent("ses-prometheus-to-worker")).toBe("sisyphus") expect(readBoulderState(testDir)?.agent).toBe("sisyphus") }) @@ -559,7 +559,7 @@ You are starting a Sisyphus work session. ) // then - expect(output.message.agent).toBe("Sisyphus (Ultraworker)") + expect(output.message.agent).toBe("sisyphus") expect(readBoulderState(testDir)?.agent).toBe("sisyphus") }) @@ -594,7 +594,7 @@ You are starting a Sisyphus work session. await atlasHook.handler({ event: { type: "session.idle", properties: { sessionID: "session-123" } } }) // then - expect(output.message.agent).toBe(getAgentListDisplayName("atlas")) + expect(output.message.agent).toBe("atlas") expect(readBoulderState(testDir)?.session_ids).toContain("session-123") expect(readBoulderState(testDir)?.agent).toBe("atlas") expect(promptAsyncMock).toHaveBeenCalledTimes(1) @@ -684,7 +684,7 @@ You are starting a Sisyphus work session. await firePendingTimers() // then - expect(output.message.agent).toBe(getAgentListDisplayName("atlas")) + expect(output.message.agent).toBe("atlas") expect(readBoulderState(testDir)?.session_ids).toContain("session-123") expect(readBoulderState(testDir)?.agent).toBe("atlas") expect(promptAsyncMock).toHaveBeenCalledTimes(1) diff --git a/src/hooks/start-work/start-work-hook.ts b/src/hooks/start-work/start-work-hook.ts index f916c2eae..357f9552a 100644 --- a/src/hooks/start-work/start-work-hook.ts +++ b/src/hooks/start-work/start-work-hook.ts @@ -85,12 +85,12 @@ export function createStartWorkHook(ctx: PluginInput) { const activeAgent = isAgentRegistered("atlas") ? "atlas" : "sisyphus" - const activeAgentDisplayName = activeAgent === "atlas" - ? getAgentListDisplayName(activeAgent) - : getAgentDisplayName(activeAgent) + const activeAgentDisplayName = getAgentDisplayName(activeAgent) updateSessionAgent(input.sessionID, activeAgent) if (output.message) { - output.message["agent"] = activeAgentDisplayName + // Use config key for agent field to avoid HTTP header validation issues + // Display names like "Atlas (Plan Executor)" contain parens that are invalid in headers + output.message["agent"] = activeAgent } const existingState = readBoulderState(ctx.directory) diff --git a/src/hooks/todo-continuation-enforcer/continuation-injection.test.ts b/src/hooks/todo-continuation-enforcer/continuation-injection.test.ts index 8feac9863..b7015b517 100644 --- a/src/hooks/todo-continuation-enforcer/continuation-injection.test.ts +++ b/src/hooks/todo-continuation-enforcer/continuation-injection.test.ts @@ -33,7 +33,7 @@ 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, diff --git a/src/plugin-handlers/agent-override-protection.ts b/src/plugin-handlers/agent-override-protection.ts index 476937b8c..1394698a9 100644 --- a/src/plugin-handlers/agent-override-protection.ts +++ b/src/plugin-handlers/agent-override-protection.ts @@ -1,4 +1,5 @@ const PARENTHETICAL_SUFFIX_PATTERN = /\s*(\([^)]*\)\s*)+$/u +const DASH_SUFFIX_PATTERN = /\s+-\s+.+$/u const ZERO_WIDTH_CHARACTERS_PATTERN = /[\u200B\u200C\u200D\uFEFF]/g export function normalizeProtectedAgentName(agentName: string): string { @@ -7,6 +8,7 @@ export function normalizeProtectedAgentName(agentName: string): string { .trim() .toLowerCase() .replace(PARENTHETICAL_SUFFIX_PATTERN, "") + .replace(DASH_SUFFIX_PATTERN, "") .replace(/[-_]/g, "") .trim() } diff --git a/src/plugin-interface.test.ts b/src/plugin-interface.test.ts index a3699668c..4dac3f7be 100644 --- a/src/plugin-interface.test.ts +++ b/src/plugin-interface.test.ts @@ -165,7 +165,7 @@ describe("createPluginInterface - command.execute.before", () => { ) // then - expect(output.message.agent).toBe(getAgentListDisplayName("atlas")) + expect(output.message.agent).toBe("atlas") expect(getSessionAgent("ses-command-atlas")).toBe("atlas") expect(readBoulderState(testDir)?.agent).toBe("atlas") }) diff --git a/src/plugin/chat-message.test.ts b/src/plugin/chat-message.test.ts index 11b4b6a48..e7128140b 100644 --- a/src/plugin/chat-message.test.ts +++ b/src/plugin/chat-message.test.ts @@ -87,7 +87,7 @@ describe("createChatMessageHandler - /start-work integration", () => { await handler(input, output) // then - expect(output.message["agent"]).toBe("Sisyphus (Ultraworker)") + expect(output.message["agent"]).toBe("sisyphus") expect(output.parts[0].text).toContain("") expect(output.parts[0].text).toContain("Auto-Selected Plan") expect(output.parts[0].text).toContain("boulder.json has been created") @@ -397,7 +397,7 @@ describe("createChatMessageHandler - TUI variant passthrough", () => { //#then expect(output.message["model"]).toBeUndefined() expect(getSessionModel("test-session")).toEqual({ providerID: "openai", modelID: "gpt-5.4" }) - expect(getSessionAgent("test-session")).toBe("Prometheus (Plan Builder)") + expect(getSessionAgent("test-session")).toBe("Prometheus - Plan Builder") }) test("respects a mid-conversation model switch instead of reusing the previous stored model", async () => { diff --git a/src/plugin/event.model-fallback.test.ts b/src/plugin/event.model-fallback.test.ts index 02c012070..481c5c419 100644 --- a/src/plugin/event.model-fallback.test.ts +++ b/src/plugin/event.model-fallback.test.ts @@ -92,8 +92,8 @@ describe("createEventHandler - model fallback", () => { parentID: "msg_user_1", modelID: "claude-opus-4-6-thinking", providerID: "anthropic", - mode: "Sisyphus (Ultraworker)", - agent: "Sisyphus (Ultraworker)", + mode: "Sisyphus - Ultraworker", + agent: "Sisyphus - Ultraworker", path: { cwd: "/tmp", root: "/tmp" }, cost: 0, tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, @@ -184,7 +184,7 @@ describe("createEventHandler - model fallback", () => { content: [], modelID: "claude-opus-4-6-thinking", providerID: "anthropic", - agent: "Sisyphus (Ultraworker)", + agent: "Sisyphus - Ultraworker", path: { cwd: "/tmp", root: "/tmp" }, }, }, @@ -246,7 +246,7 @@ describe("createEventHandler - model fallback", () => { role: "user", modelID: "claude-opus-4-6-thinking", providerID: "anthropic", - agent: "Sisyphus (Ultraworker)", + agent: "Sisyphus - Ultraworker", }, }, }, @@ -314,7 +314,7 @@ describe("createEventHandler - model fallback", () => { role: "user", modelID: "claude-opus-4-6", providerID: "quotio", - agent: "Sisyphus (Ultraworker)", + agent: "Sisyphus - Ultraworker", }, }, }, @@ -395,7 +395,7 @@ describe("createEventHandler - model fallback", () => { content: [], modelID: "claude-opus-4-6", providerID: "quotio", - agent: "Sisyphus (Ultraworker)", + agent: "Sisyphus - Ultraworker", path: { cwd: "/tmp", root: "/tmp" }, }, }, @@ -597,7 +597,7 @@ describe("createEventHandler - model fallback", () => { parentID: "msg_user_disabled_1", modelID: "claude-opus-4-6-thinking", providerID: "anthropic", - agent: "Sisyphus (Ultraworker)", + agent: "Sisyphus - Ultraworker", path: { cwd: "/tmp", root: "/tmp" }, cost: 0, tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, diff --git a/src/plugin/event.test.ts b/src/plugin/event.test.ts index 28e2d7fb2..2fc453dc2 100644 --- a/src/plugin/event.test.ts +++ b/src/plugin/event.test.ts @@ -771,7 +771,7 @@ describe("createEventHandler - retry dedupe lifecycle", () => { role: "user", modelID: "claude-opus-4-6-thinking", providerID: "anthropic", - agent: "Sisyphus (Ultraworker)", + agent: "Sisyphus - Ultraworker", }, }, }, diff --git a/src/plugin/fallback.cliproxyapi-matrix.test.ts b/src/plugin/fallback.cliproxyapi-matrix.test.ts index 8d8e3c6f4..30535a880 100644 --- a/src/plugin/fallback.cliproxyapi-matrix.test.ts +++ b/src/plugin/fallback.cliproxyapi-matrix.test.ts @@ -255,7 +255,7 @@ async function primeMainSession( content: [], modelID: PRIMARY_MODEL.modelID, providerID: PRIMARY_MODEL.providerID, - agent: "Sisyphus (Ultraworker)", + agent: "Sisyphus - Ultraworker", path: { cwd: "/tmp", root: "/tmp" }, }, }, @@ -337,7 +337,7 @@ async function triggerAssistantMessageError( model: PRIMARY_MODEL_STRING, modelID: PRIMARY_MODEL.modelID, providerID: PRIMARY_MODEL.providerID, - agent: "Sisyphus (Ultraworker)", + agent: "Sisyphus - Ultraworker", path: { cwd: "/tmp", root: "/tmp" }, error: { statusCode: 529, diff --git a/src/plugin/ultrawork-model-override.test.ts b/src/plugin/ultrawork-model-override.test.ts index 9ceb42aae..0204f0cae 100644 --- a/src/plugin/ultrawork-model-override.test.ts +++ b/src/plugin/ultrawork-model-override.test.ts @@ -174,7 +174,7 @@ describe("resolveUltraworkOverride", () => { const output = createOutput("ulw do something") //#when - const result = resolveUltraworkOverride(config, "Sisyphus (Ultraworker)", output) + const result = resolveUltraworkOverride(config, "Sisyphus - Ultraworker", output) //#then expect(result).toEqual({ providerID: "anthropic", modelID: "claude-opus-4-6", variant: "max" }) @@ -408,7 +408,7 @@ describe("applyUltraworkModelOverrideOnMessage", () => { const tui = createMockTui() //#when - applyUltraworkModelOverrideOnMessage(config, "Sisyphus (Ultraworker)", output, tui) + applyUltraworkModelOverrideOnMessage(config, "Sisyphus - Ultraworker", output, tui) //#then expect(dbOverrideSpy).toHaveBeenCalledWith( diff --git a/src/shared/agent-config-integration.test.ts b/src/shared/agent-config-integration.test.ts index 25cd14a26..1afc2f033 100644 --- a/src/shared/agent-config-integration.test.ts +++ b/src/shared/agent-config-integration.test.ts @@ -92,12 +92,12 @@ describe("Agent Config Integration", () => { const displayNames = agents.map((agent) => getAgentDisplayName(agent)) // then - display names are correct - expect(displayNames).toContain("Sisyphus (Ultraworker)") - expect(displayNames).toContain("Hephaestus (Deep Agent)") - expect(displayNames).toContain("Prometheus (Plan Builder)") - expect(displayNames).toContain("Atlas (Plan Executor)") - expect(displayNames).toContain("Metis (Plan Consultant)") - expect(displayNames).toContain("Momus (Plan Critic)") + expect(displayNames).toContain("Sisyphus - Ultraworker") + expect(displayNames).toContain("Hephaestus - Deep Agent") + expect(displayNames).toContain("Prometheus - Plan Builder") + expect(displayNames).toContain("Atlas - Plan Executor") + expect(displayNames).toContain("Metis - Plan Consultant") + expect(displayNames).toContain("Momus - Plan Critic") expect(displayNames).toContain("oracle") expect(displayNames).toContain("librarian") expect(displayNames).toContain("explore") @@ -112,12 +112,12 @@ 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[1]).toBe("Atlas (Plan Executor)") - 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)") + expect(displayNames[0]).toBe("Sisyphus - Ultraworker") + expect(displayNames[1]).toBe("Atlas - Plan Executor") + 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") }) test("returns original key for unknown agents", () => { @@ -189,8 +189,8 @@ describe("Agent Config Integration", () => { const prometheusDisplay = getAgentDisplayName("prometheus") // then - display names are correct - expect(sisyphusDisplay).toBe("Sisyphus (Ultraworker)") - expect(prometheusDisplay).toBe("Prometheus (Plan Builder)") + expect(sisyphusDisplay).toBe("Sisyphus - Ultraworker") + expect(prometheusDisplay).toBe("Prometheus - Plan Builder") // then - config values are preserved expect(result.migrated.sisyphus).toEqual({ model: "anthropic/claude-opus-4-6", temperature: 0.1 }) @@ -218,8 +218,8 @@ describe("Agent Config Integration", () => { const atlasDisplay = getAgentDisplayName("atlas") // then - display names are correct - expect(sisyphusDisplay).toBe("Sisyphus (Ultraworker)") - expect(atlasDisplay).toBe("Atlas (Plan Executor)") + expect(sisyphusDisplay).toBe("Sisyphus - Ultraworker") + expect(atlasDisplay).toBe("Atlas - Plan Executor") }) }) }) diff --git a/src/shared/agent-display-names.test.ts b/src/shared/agent-display-names.test.ts index 538c16174..050e4cfde 100644 --- a/src/shared/agent-display-names.test.ts +++ b/src/shared/agent-display-names.test.ts @@ -9,8 +9,8 @@ describe("getAgentDisplayName", () => { // when getAgentDisplayName called const result = getAgentDisplayName(configKey) - // then returns "Sisyphus (Ultraworker)" - expect(result).toBe("Sisyphus (Ultraworker)") + // then returns "Sisyphus - Ultraworker" + expect(result).toBe("Sisyphus - Ultraworker") }) it("returns display name for uppercase config key (old format - case-insensitive)", () => { @@ -20,8 +20,8 @@ describe("getAgentDisplayName", () => { // when getAgentDisplayName called const result = getAgentDisplayName(configKey) - // then returns "Sisyphus (Ultraworker)" (case-insensitive lookup) - expect(result).toBe("Sisyphus (Ultraworker)") + // then returns "Sisyphus - Ultraworker" (case-insensitive lookup) + expect(result).toBe("Sisyphus - Ultraworker") }) it("returns original key for unknown agents (fallback)", () => { @@ -42,8 +42,8 @@ describe("getAgentDisplayName", () => { // when getAgentDisplayName called const result = getAgentDisplayName(configKey) - // then returns "Atlas (Plan Executor)" - expect(result).toBe("Atlas (Plan Executor)") + // then returns "Atlas - Plan Executor" + expect(result).toBe("Atlas - Plan Executor") }) it("returns display name for prometheus", () => { @@ -53,8 +53,8 @@ describe("getAgentDisplayName", () => { // when getAgentDisplayName called const result = getAgentDisplayName(configKey) - // then returns "Prometheus (Plan Builder)" - expect(result).toBe("Prometheus (Plan Builder)") + // then returns "Prometheus - Plan Builder" + expect(result).toBe("Prometheus - Plan Builder") }) it("returns display name for sisyphus-junior", () => { @@ -75,8 +75,8 @@ describe("getAgentDisplayName", () => { // when getAgentDisplayName called const result = getAgentDisplayName(configKey) - // then returns "Metis (Plan Consultant)" - expect(result).toBe("Metis (Plan Consultant)") + // then returns "Metis - Plan Consultant" + expect(result).toBe("Metis - Plan Consultant") }) it("returns display name for momus", () => { @@ -86,8 +86,8 @@ describe("getAgentDisplayName", () => { // when getAgentDisplayName called const result = getAgentDisplayName(configKey) - // then returns "Momus (Plan Critic)" - expect(result).toBe("Momus (Plan Critic)") + // then returns "Momus - Plan Critic" + expect(result).toBe("Momus - Plan Critic") }) it("returns display name for oracle", () => { @@ -137,17 +137,17 @@ describe("getAgentDisplayName", () => { describe("getAgentConfigKey", () => { it("resolves display name to config key", () => { - // given display name "Sisyphus (Ultraworker)" + // given display name "Sisyphus - Ultraworker" // when getAgentConfigKey called // then returns "sisyphus" - expect(getAgentConfigKey("Sisyphus (Ultraworker)")).toBe("sisyphus") + expect(getAgentConfigKey("Sisyphus - Ultraworker")).toBe("sisyphus") }) it("resolves display name case-insensitively", () => { // given display name in different case // when getAgentConfigKey called // then returns "atlas" - expect(getAgentConfigKey("atlas (plan executor)")).toBe("atlas") + expect(getAgentConfigKey("atlas - plan executor")).toBe("atlas") }) it("passes through lowercase config keys unchanged", () => { @@ -167,11 +167,11 @@ describe("getAgentConfigKey", () => { it("resolves all core agent display names", () => { // given all core display names // when/then each resolves to its config key - expect(getAgentConfigKey("Hephaestus (Deep Agent)")).toBe("hephaestus") - expect(getAgentConfigKey("Prometheus (Plan Builder)")).toBe("prometheus") - expect(getAgentConfigKey("Atlas (Plan Executor)")).toBe("atlas") - expect(getAgentConfigKey("Metis (Plan Consultant)")).toBe("metis") - expect(getAgentConfigKey("Momus (Plan Critic)")).toBe("momus") + expect(getAgentConfigKey("Hephaestus - Deep Agent")).toBe("hephaestus") + expect(getAgentConfigKey("Prometheus - Plan Builder")).toBe("prometheus") + expect(getAgentConfigKey("Atlas - Plan Executor")).toBe("atlas") + expect(getAgentConfigKey("Metis - Plan Consultant")).toBe("metis") + expect(getAgentConfigKey("Momus - Plan Critic")).toBe("momus") expect(getAgentConfigKey("Sisyphus-Junior")).toBe("sisyphus-junior") }) @@ -182,10 +182,10 @@ describe("getAgentConfigKey", () => { describe("getAgentListDisplayName", () => { it("applies invisible stable-sort prefixes to the core agent list", () => { - expect(getAgentListDisplayName("sisyphus")).toBe("\u200BSisyphus (Ultraworker)") - expect(getAgentListDisplayName("hephaestus")).toBe("\u200B\u200BHephaestus (Deep Agent)") - expect(getAgentListDisplayName("prometheus")).toBe("\u200B\u200B\u200BPrometheus (Plan Builder)") - expect(getAgentListDisplayName("atlas")).toBe("\u200B\u200B\u200B\u200BAtlas (Plan Executor)") + expect(getAgentListDisplayName("sisyphus")).toBe("\u200BSisyphus - Ultraworker") + expect(getAgentListDisplayName("hephaestus")).toBe("\u200B\u200BHephaestus - Deep Agent") + expect(getAgentListDisplayName("prometheus")).toBe("\u200B\u200B\u200BPrometheus - Plan Builder") + expect(getAgentListDisplayName("atlas")).toBe("\u200B\u200B\u200B\u200BAtlas - Plan Executor") }) it("keeps non-core agents unprefixed for list display", () => { @@ -195,16 +195,16 @@ describe("getAgentListDisplayName", () => { describe("normalizeAgentForPrompt", () => { it("strips core UI ordering prefixes back to canonical display names", () => { - expect(normalizeAgentForPrompt(getAgentListDisplayName("sisyphus"))).toBe("Sisyphus (Ultraworker)") - expect(normalizeAgentForPrompt(getAgentListDisplayName("hephaestus"))).toBe("Hephaestus (Deep Agent)") - expect(normalizeAgentForPrompt(getAgentListDisplayName("prometheus"))).toBe("Prometheus (Plan Builder)") - expect(normalizeAgentForPrompt(getAgentListDisplayName("atlas"))).toBe("Atlas (Plan Executor)") + expect(normalizeAgentForPrompt(getAgentListDisplayName("sisyphus"))).toBe("Sisyphus - Ultraworker") + expect(normalizeAgentForPrompt(getAgentListDisplayName("hephaestus"))).toBe("Hephaestus - Deep Agent") + expect(normalizeAgentForPrompt(getAgentListDisplayName("prometheus"))).toBe("Prometheus - Plan Builder") + expect(normalizeAgentForPrompt(getAgentListDisplayName("atlas"))).toBe("Atlas - Plan Executor") }) }) describe("normalizeAgentForPromptKey", () => { it("converts built-in display names to config keys", () => { - expect(normalizeAgentForPromptKey("Sisyphus (Ultraworker)")).toBe("sisyphus") + expect(normalizeAgentForPromptKey("Sisyphus - Ultraworker")).toBe("sisyphus") }) it("preserves custom agents", () => { @@ -216,15 +216,15 @@ describe("AGENT_DISPLAY_NAMES", () => { it("contains all expected agent mappings", () => { // given expected mappings const expectedMappings = { - sisyphus: "Sisyphus (Ultraworker)", - hephaestus: "Hephaestus (Deep Agent)", - prometheus: "Prometheus (Plan Builder)", - atlas: "Atlas (Plan Executor)", + sisyphus: "Sisyphus - Ultraworker", + hephaestus: "Hephaestus - Deep Agent", + prometheus: "Prometheus - Plan Builder", + atlas: "Atlas - Plan Executor", "sisyphus-junior": "Sisyphus-Junior", - metis: "Metis (Plan Consultant)", - momus: "Momus (Plan Critic)", - athena: "Athena (Council)", - "athena-junior": "Athena-Junior (Council)", + metis: "Metis - Plan Consultant", + momus: "Momus - Plan Critic", + athena: "Athena - Council", + "athena-junior": "Athena-Junior - Council", oracle: "oracle", librarian: "librarian", explore: "explore", diff --git a/src/shared/agent-display-names.ts b/src/shared/agent-display-names.ts index 532155ccc..d42493fc6 100644 --- a/src/shared/agent-display-names.ts +++ b/src/shared/agent-display-names.ts @@ -4,15 +4,15 @@ * Display names include suffixes for UI/logs (e.g., "Sisyphus (Ultraworker)"). */ export const AGENT_DISPLAY_NAMES: Record = { - sisyphus: "Sisyphus (Ultraworker)", - hephaestus: "Hephaestus (Deep Agent)", - prometheus: "Prometheus (Plan Builder)", - atlas: "Atlas (Plan Executor)", + sisyphus: "Sisyphus - Ultraworker", + hephaestus: "Hephaestus - Deep Agent", + prometheus: "Prometheus - Plan Builder", + atlas: "Atlas - Plan Executor", "sisyphus-junior": "Sisyphus-Junior", - metis: "Metis (Plan Consultant)", - momus: "Momus (Plan Critic)", - athena: "Athena (Council)", - "athena-junior": "Athena-Junior (Council)", + metis: "Metis - Plan Consultant", + momus: "Momus - Plan Critic", + athena: "Athena - Council", + "athena-junior": "Athena-Junior - Council", oracle: "oracle", librarian: "librarian", explore: "explore", diff --git a/src/tools/delegate-task/zauc-mocks-subagent-resolver/subagent-resolver.test.ts b/src/tools/delegate-task/zauc-mocks-subagent-resolver/subagent-resolver.test.ts index e21b104fb..2a38af4d7 100644 --- a/src/tools/delegate-task/zauc-mocks-subagent-resolver/subagent-resolver.test.ts +++ b/src/tools/delegate-task/zauc-mocks-subagent-resolver/subagent-resolver.test.ts @@ -675,7 +675,7 @@ describe("resolveSubagentExecution - agent name sanitization", () => { }) const args = createBaseArgs({ subagent_type: "\\hephaestus\\" }) const executorCtx = createExecutorContext(async () => ([ - { name: "Hephaestus (Deep Agent)", mode: "subagent", model: "openai/gpt-5.3-codex" }, + { name: "Hephaestus - Deep Agent", mode: "subagent", model: "openai/gpt-5.3-codex" }, ])) //#when @@ -683,7 +683,7 @@ describe("resolveSubagentExecution - agent name sanitization", () => { //#then expect(result.error).toBeUndefined() - expect(result.agentToUse).toBe("Hephaestus (Deep Agent)") + expect(result.agentToUse).toBe("Hephaestus - Deep Agent") cacheSpy.mockRestore() })