diff --git a/src/plugin-handlers/AGENTS.md b/src/plugin-handlers/AGENTS.md index f0d9949a70..56bd369fc0 100644 --- a/src/plugin-handlers/AGENTS.md +++ b/src/plugin-handlers/AGENTS.md @@ -8,16 +8,22 @@ The canonical agent order is **sisyphus → hephaestus → prometheus → atlas* This order is enforced via two mechanisms working together: 1. `CANONICAL_CORE_AGENT_ORDER` in `agent-priority-order.ts` controls object key insertion order -2. `agent-key-remapper.ts` injects ZWSP-prefixed runtime names into the `name` field for OpenCode's `localeCompare` sort +2. `agent-priority-order.ts` injects an explicit `order` field (1-4) into each core agent config -### Why Two Mechanisms +### How Ordering Works -OpenCode's `Agent.list()` sorts agents by `name` field via `localeCompare`. Object key order alone is not enough. The `name` field carries ZWSP prefixes (1-4 chars) so core agents sort before alphabetically-named agents. +`reorderAgentsByPriority` iterates over `CANONICAL_CORE_AGENT_ORDER`, matches each core agent by +display name, and inserts it first into the result object. JavaScript preserves string-key insertion +order (ES2015+), so core agents always appear before custom agents regardless of alphabetical order. -ZWSP is intentionally used in the `name` field only. It MUST NOT appear in: +The `order` field (integers 1-4) is stored as metadata this repo can provide — **this repo only +stores it**; whether OpenCode consumes it for rendering is outside this codebase's control. + +ZWSP (U+200B) MUST NOT appear anywhere in the agent config — not in: - Object keys (used as HTTP header values, causes RFC 7230 violations) - Display names returned by `getAgentDisplayName()` - Config keys +- The `name` field (OpenCode passes `name` as the `mode_type` HTTP header — ZWSP causes TypeError) ### History @@ -25,11 +31,12 @@ Agent ordering has caused 15+ commits, 8+ PRs, and multiple reverts due to: 1. Early ZWSP attempts that leaked into HTTP headers via object keys 2. Object.entries() iteration order depending on merge sequence 3. Multiple code paths assembling agents differently +4. ZWSP in the `name` field leaking into the `mode_type` HTTP header ### Forbidden Patterns DO NOT introduce: -- ZWSP in object keys or display names (only allowed in `name` field via `getAgentRuntimeName()`) +- ZWSP anywhere in agent configs (keys, display names, or `name` field) - Runtime sort shims or comparators - Alternative ordering constants - Object.entries() order dependencies diff --git a/src/plugin-handlers/agent-config-handler.test.ts b/src/plugin-handlers/agent-config-handler.test.ts index 8e06d7fcae..ac7551782c 100644 --- a/src/plugin-handlers/agent-config-handler.test.ts +++ b/src/plugin-handlers/agent-config-handler.test.ts @@ -9,13 +9,13 @@ import type { OhMyOpenCodeConfig } from "../config" import * as agentLoader from "../features/claude-code-agent-loader" import * as skillLoader from "../features/opencode-skill-loader" import type { LoadedSkill } from "../features/opencode-skill-loader" -import { getAgentListDisplayName, getAgentRuntimeName } from "../shared/agent-display-names" +import { getAgentDisplayName } from "../shared/agent-display-names" import { applyAgentConfig } from "./agent-config-handler" import type { PluginComponents } from "./plugin-components-loader" -const BUILTIN_SISYPHUS_DISPLAY_NAME = getAgentListDisplayName("sisyphus") -const BUILTIN_SISYPHUS_JUNIOR_DISPLAY_NAME = getAgentListDisplayName("sisyphus-junior") -const BUILTIN_MULTIMODAL_LOOKER_DISPLAY_NAME = getAgentListDisplayName("multimodal-looker") +const BUILTIN_SISYPHUS_DISPLAY_NAME = getAgentDisplayName("sisyphus") +const BUILTIN_SISYPHUS_JUNIOR_DISPLAY_NAME = getAgentDisplayName("sisyphus-junior") +const BUILTIN_MULTIMODAL_LOOKER_DISPLAY_NAME = getAgentDisplayName("multimodal-looker") function createPluginComponents(): PluginComponents { return { @@ -203,7 +203,7 @@ describe("applyAgentConfig builtin override protection", () => { // then expect(result[BUILTIN_SISYPHUS_DISPLAY_NAME]).toEqual({ ...builtinSisyphusConfig, - name: getAgentRuntimeName("sisyphus"), + name: getAgentDisplayName("sisyphus"), }) }) @@ -228,7 +228,7 @@ describe("applyAgentConfig builtin override protection", () => { // then expect(result[BUILTIN_SISYPHUS_DISPLAY_NAME]).toEqual({ ...builtinSisyphusConfig, - name: getAgentRuntimeName("sisyphus"), + name: getAgentDisplayName("sisyphus"), }) expect(result.SiSyPhUs).toBeUndefined() }) @@ -255,7 +255,7 @@ describe("applyAgentConfig builtin override protection", () => { // then expect(result[BUILTIN_SISYPHUS_DISPLAY_NAME]).toEqual({ ...builtinSisyphusConfig, - name: getAgentRuntimeName("sisyphus"), + name: getAgentDisplayName("sisyphus"), }) }) diff --git a/src/plugin-handlers/agent-config-handler.ts b/src/plugin-handlers/agent-config-handler.ts index b8c7a9ee60..e8c0388504 100644 --- a/src/plugin-handlers/agent-config-handler.ts +++ b/src/plugin-handlers/agent-config-handler.ts @@ -2,7 +2,7 @@ import { createBuiltinAgents } from "../agents"; import { createSisyphusJuniorAgentWithOverrides } from "../agents/sisyphus-junior"; import type { OhMyOpenCodeConfig } from "../config"; import { isTaskSystemEnabled, log, migrateAgentConfig } from "../shared"; -import { getAgentRuntimeName } from "../shared/agent-display-names"; +import { getAgentDisplayName, getAgentRuntimeName } from "../shared/agent-display-names"; import { AGENT_NAME_MAP } from "../shared/migration"; import { registerAgentName } from "../features/claude-code-session-state"; import { @@ -159,10 +159,10 @@ export async function applyAgentConfig(params: { if (isSisyphusEnabled && builtinAgents.sisyphus) { if (configuredDefaultAgent) { (params.config as { default_agent?: string }).default_agent = - getAgentRuntimeName(configuredDefaultAgent); + getAgentDisplayName(configuredDefaultAgent); } else { (params.config as { default_agent?: string }).default_agent = - getAgentRuntimeName("sisyphus"); + getAgentDisplayName("sisyphus"); } // Assembly order: Sisyphus -> Hephaestus -> Prometheus -> Atlas diff --git a/src/plugin-handlers/agent-key-remapper.test.ts b/src/plugin-handlers/agent-key-remapper.test.ts index 7640fbbf80..afc4ee04bf 100644 --- a/src/plugin-handlers/agent-key-remapper.test.ts +++ b/src/plugin-handlers/agent-key-remapper.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect } from "bun:test" import { remapAgentKeysToDisplayNames } from "./agent-key-remapper" -import { getAgentDisplayName, getAgentListDisplayName, getAgentRuntimeName } from "../shared/agent-display-names" +import { getAgentDisplayName } from "../shared/agent-display-names" describe("remapAgentKeysToDisplayNames", () => { it("remaps known agent keys to display names", () => { @@ -13,8 +13,8 @@ describe("remapAgentKeysToDisplayNames", () => { // when remapping const result = remapAgentKeysToDisplayNames(agents) - // then known agents get display name keys only - expect(result[getAgentListDisplayName("sisyphus")]).toBeDefined() + // then known agents get display name keys only (no ZWSP in key) + expect(result[getAgentDisplayName("sisyphus")]).toBeDefined() expect(result["oracle"]).toBeDefined() expect(result["sisyphus"]).toBeUndefined() }) @@ -48,14 +48,14 @@ describe("remapAgentKeysToDisplayNames", () => { // when remapping const result = remapAgentKeysToDisplayNames(agents) - // then all get display name keys - expect(result[getAgentListDisplayName("sisyphus")]).toBeDefined() + // then all get display name keys (no ZWSP in key) + expect(result[getAgentDisplayName("sisyphus")]).toBeDefined() expect(result["sisyphus"]).toBeUndefined() - expect(result[getAgentListDisplayName("hephaestus")]).toBeDefined() + expect(result[getAgentDisplayName("hephaestus")]).toBeDefined() expect(result["hephaestus"]).toBeUndefined() - expect(result[getAgentListDisplayName("prometheus")]).toBeDefined() + expect(result[getAgentDisplayName("prometheus")]).toBeDefined() expect(result["prometheus"]).toBeUndefined() - expect(result[getAgentListDisplayName("atlas")]).toBeDefined() + expect(result[getAgentDisplayName("atlas")]).toBeDefined() expect(result["atlas"]).toBeUndefined() expect(result[getAgentDisplayName("athena")]).toBeDefined() expect(result["athena"]).toBeUndefined() @@ -76,13 +76,13 @@ describe("remapAgentKeysToDisplayNames", () => { // when remapping const result = remapAgentKeysToDisplayNames(agents) - // then only display key is emitted - expect(Object.keys(result)).toEqual([getAgentListDisplayName("sisyphus")]) - expect(result[getAgentListDisplayName("sisyphus")]).toBeDefined() + // then only display key is emitted (no ZWSP in key) + expect(Object.keys(result)).toEqual([getAgentDisplayName("sisyphus")]) + expect(result[getAgentDisplayName("sisyphus")]).toBeDefined() expect(result["sisyphus"]).toBeUndefined() }) - it("returns runtime core agent list names in canonical order", () => { + it("returns clean core agent display names without ZWSP prefixes in keys", () => { // given const result = remapAgentKeysToDisplayNames({ atlas: {}, @@ -94,16 +94,19 @@ describe("remapAgentKeysToDisplayNames", () => { // when const remappedNames = Object.keys(result) - // then + // then keys have no ZWSP expect(remappedNames).toEqual([ - getAgentListDisplayName("atlas"), - getAgentListDisplayName("prometheus"), - getAgentListDisplayName("hephaestus"), - getAgentListDisplayName("sisyphus"), + getAgentDisplayName("atlas"), + getAgentDisplayName("prometheus"), + getAgentDisplayName("hephaestus"), + getAgentDisplayName("sisyphus"), ]) + for (const name of remappedNames) { + expect(name).not.toContain("\u200B") + } }) - it("keeps remapped core agent name fields aligned with OpenCode list ordering", () => { + it("preserves clean keys and rewrites core agent name fields to display names (no ZWSP)", () => { // given agents with raw config-key names const agents = { sisyphus: { name: "sisyphus", prompt: "test", mode: "primary" }, @@ -116,37 +119,37 @@ describe("remapAgentKeysToDisplayNames", () => { // when remapping const result = remapAgentKeysToDisplayNames(agents) - // then keys and names both use the same runtime-facing list names + // then both keys and name fields are HTTP-header-safe (no ZWSP) expect(Object.keys(result).slice(0, 4)).toEqual([ - getAgentListDisplayName("sisyphus"), - getAgentListDisplayName("hephaestus"), - getAgentListDisplayName("prometheus"), - getAgentListDisplayName("atlas"), + getAgentDisplayName("sisyphus"), + getAgentDisplayName("hephaestus"), + getAgentDisplayName("prometheus"), + getAgentDisplayName("atlas"), ]) - expect(result[getAgentListDisplayName("sisyphus")]).toEqual({ - name: getAgentRuntimeName("sisyphus"), + expect(result[getAgentDisplayName("sisyphus")]).toEqual({ + name: getAgentDisplayName("sisyphus"), prompt: "test", mode: "primary", }) - expect(result[getAgentListDisplayName("hephaestus")]).toEqual({ - name: getAgentRuntimeName("hephaestus"), + expect(result[getAgentDisplayName("hephaestus")]).toEqual({ + name: getAgentDisplayName("hephaestus"), prompt: "test", mode: "primary", }) - expect(result[getAgentListDisplayName("prometheus")]).toEqual({ - name: getAgentRuntimeName("prometheus"), + expect(result[getAgentDisplayName("prometheus")]).toEqual({ + name: getAgentDisplayName("prometheus"), prompt: "test", mode: "all", }) - expect(result[getAgentListDisplayName("atlas")]).toEqual({ - name: getAgentRuntimeName("atlas"), + expect(result[getAgentDisplayName("atlas")]).toEqual({ + name: getAgentDisplayName("atlas"), prompt: "test", mode: "primary", }) expect(result.oracle).toEqual({ name: "oracle", prompt: "test", mode: "subagent" }) }) - it("backfills runtime names for core agents when builtin configs omit name", () => { + it("backfills display names for core agents when builtin configs omit name", () => { // given builtin-style configs without name fields const agents = { sisyphus: { prompt: "test", mode: "primary" }, @@ -158,24 +161,24 @@ describe("remapAgentKeysToDisplayNames", () => { // when remapping const result = remapAgentKeysToDisplayNames(agents) - // then runtime-facing names stay aligned even when builtin configs omit name - expect(result[getAgentListDisplayName("sisyphus")]).toEqual({ - name: getAgentRuntimeName("sisyphus"), + // then name fields are clean display names (no ZWSP); ordering is via `order` field + expect(result[getAgentDisplayName("sisyphus")]).toEqual({ + name: getAgentDisplayName("sisyphus"), prompt: "test", mode: "primary", }) - expect(result[getAgentListDisplayName("hephaestus")]).toEqual({ - name: getAgentRuntimeName("hephaestus"), + expect(result[getAgentDisplayName("hephaestus")]).toEqual({ + name: getAgentDisplayName("hephaestus"), prompt: "test", mode: "primary", }) - expect(result[getAgentListDisplayName("prometheus")]).toEqual({ - name: getAgentRuntimeName("prometheus"), + expect(result[getAgentDisplayName("prometheus")]).toEqual({ + name: getAgentDisplayName("prometheus"), prompt: "test", mode: "all", }) - expect(result[getAgentListDisplayName("atlas")]).toEqual({ - name: getAgentRuntimeName("atlas"), + expect(result[getAgentDisplayName("atlas")]).toEqual({ + name: getAgentDisplayName("atlas"), prompt: "test", mode: "primary", }) diff --git a/src/plugin-handlers/agent-key-remapper.ts b/src/plugin-handlers/agent-key-remapper.ts index 56aea9ae92..c15241301b 100644 --- a/src/plugin-handlers/agent-key-remapper.ts +++ b/src/plugin-handlers/agent-key-remapper.ts @@ -1,4 +1,4 @@ -import { getAgentListDisplayName, getAgentRuntimeName } from "../shared/agent-display-names" +import { getAgentDisplayName } from "../shared/agent-display-names" function rewriteAgentNameForListDisplay( key: string, @@ -11,7 +11,7 @@ function rewriteAgentNameForListDisplay( const agent = value as Record return { ...agent, - name: getAgentRuntimeName(key), + name: getAgentDisplayName(key), } } @@ -21,7 +21,7 @@ export function remapAgentKeysToDisplayNames( const result: Record = {} for (const [key, value] of Object.entries(agents)) { - const displayName = getAgentListDisplayName(key) + const displayName = getAgentDisplayName(key) if (displayName && displayName !== key) { result[displayName] = rewriteAgentNameForListDisplay(key, value) // Regression guard: do not also assign result[key]. diff --git a/src/plugin-handlers/agent-priority-order.test.ts b/src/plugin-handlers/agent-priority-order.test.ts index 10890c3b0d..f9e64fa8f9 100644 --- a/src/plugin-handlers/agent-priority-order.test.ts +++ b/src/plugin-handlers/agent-priority-order.test.ts @@ -6,7 +6,7 @@ import { reorderAgentsByPriority, CANONICAL_CORE_AGENT_ORDER, } from "./agent-priority-order" -import { getAgentDisplayName, getAgentListDisplayName } from "../shared/agent-display-names" +import { getAgentDisplayName } from "../shared/agent-display-names" describe("agent-priority-order", () => { describe("CANONICAL_CORE_AGENT_ORDER", () => { @@ -36,10 +36,10 @@ describe("agent-priority-order", () => { describe("reorderAgentsByPriority", () => { // given: display names for all core agents - const sisyphus = getAgentListDisplayName("sisyphus") - const hephaestus = getAgentListDisplayName("hephaestus") - const prometheus = getAgentListDisplayName("prometheus") - const atlas = getAgentListDisplayName("atlas") + const sisyphus = getAgentDisplayName("sisyphus") + const hephaestus = getAgentDisplayName("hephaestus") + const prometheus = getAgentDisplayName("prometheus") + const atlas = getAgentDisplayName("atlas") const oracle = getAgentDisplayName("oracle") const librarian = getAgentDisplayName("librarian") const explore = getAgentDisplayName("explore") diff --git a/src/plugin-handlers/agent-priority-order.ts b/src/plugin-handlers/agent-priority-order.ts index 711f6a58c4..003679e255 100644 --- a/src/plugin-handlers/agent-priority-order.ts +++ b/src/plugin-handlers/agent-priority-order.ts @@ -1,4 +1,4 @@ -import { getAgentListDisplayName } from "../shared/agent-display-names" +import { getAgentDisplayName } from "../shared/agent-display-names" /** * CRITICAL: This is the ONLY source of truth for core agent ordering. @@ -25,7 +25,7 @@ const CORE_AGENT_ORDER: ReadonlyArray<{ order: number }> = CANONICAL_CORE_AGENT_ORDER.map((configKey, index) => ({ configKey, - displayName: getAgentListDisplayName(configKey), + displayName: getAgentDisplayName(configKey), order: index + 1, })) diff --git a/src/plugin-handlers/command-config-handler.test.ts b/src/plugin-handlers/command-config-handler.test.ts index fa39cea1b3..f4cccc36b1 100644 --- a/src/plugin-handlers/command-config-handler.test.ts +++ b/src/plugin-handlers/command-config-handler.test.ts @@ -9,7 +9,6 @@ import type { PluginComponents } from "./plugin-components-loader"; import { applyCommandConfig } from "./command-config-handler"; import { getAgentDisplayName, - getAgentListDisplayName, } from "../shared/agent-display-names"; function createPluginComponents(): PluginComponents { @@ -130,7 +129,7 @@ describe("applyCommandConfig", () => { // then const commandConfig = config.command as Record; - expect(commandConfig["start-work"]?.agent).toBe(getAgentListDisplayName("atlas")); + expect(commandConfig["start-work"]?.agent).toBe(getAgentDisplayName("atlas")); }); test("normalizes legacy display-name command agents to the runtime list name", async () => { @@ -155,6 +154,6 @@ describe("applyCommandConfig", () => { // then const commandConfig = config.command as Record; - expect(commandConfig["start-work"]?.agent).toBe(getAgentListDisplayName("atlas")); + expect(commandConfig["start-work"]?.agent).toBe(getAgentDisplayName("atlas")); }); }); diff --git a/src/plugin-handlers/command-config-handler.ts b/src/plugin-handlers/command-config-handler.ts index 471e4df522..86fdcfe26b 100644 --- a/src/plugin-handlers/command-config-handler.ts +++ b/src/plugin-handlers/command-config-handler.ts @@ -1,7 +1,7 @@ import type { OhMyOpenCodeConfig } from "../config"; import { getAgentConfigKey, - getAgentListDisplayName, + getAgentDisplayName, } from "../shared/agent-display-names"; import { loadUserCommands, @@ -99,7 +99,7 @@ export async function applyCommandConfig(params: { function remapCommandAgentFields(commands: Record>): void { for (const cmd of Object.values(commands)) { if (cmd?.agent && typeof cmd.agent === "string") { - cmd.agent = getAgentListDisplayName(getAgentConfigKey(cmd.agent)); + cmd.agent = getAgentDisplayName(getAgentConfigKey(cmd.agent)); } } } diff --git a/src/plugin-handlers/config-handler.test.ts b/src/plugin-handlers/config-handler.test.ts index e6ac62c9e6..59a44d2e83 100644 --- a/src/plugin-handlers/config-handler.test.ts +++ b/src/plugin-handlers/config-handler.test.ts @@ -3,7 +3,7 @@ import { describe, test, expect, spyOn, beforeEach, afterEach, mock } from "bun:test" import type { CategoryConfig } from "../config/schema" import type { OhMyOpenCodeConfig } from "../config" -import { getAgentDisplayName, getAgentListDisplayName, getAgentRuntimeName } from "../shared/agent-display-names" +import { getAgentDisplayName, getAgentRuntimeName } from "../shared/agent-display-names" import { resolveCategoryConfig } from "./category-config-resolver" import * as agents from "../agents" @@ -260,10 +260,10 @@ describe("Plan agent demote behavior", () => { // #then const keys = Object.keys(config.agent as Record) const coreAgents = [ - getAgentListDisplayName("sisyphus"), - getAgentListDisplayName("hephaestus"), - getAgentListDisplayName("prometheus"), - getAgentListDisplayName("atlas"), + getAgentDisplayName("sisyphus"), + getAgentDisplayName("hephaestus"), + getAgentDisplayName("prometheus"), + getAgentDisplayName("atlas"), ] const ordered = keys.filter((key) => coreAgents.includes(key)) expect(ordered).toEqual(coreAgents) @@ -308,10 +308,10 @@ describe("Plan agent demote behavior", () => { reorderSpy.mock.calls.at(0)?.[0] as Record ) expect(assembledAgentKeys.slice(0, 4)).toEqual([ - getAgentListDisplayName("sisyphus"), - getAgentListDisplayName("hephaestus"), - getAgentListDisplayName("prometheus"), - getAgentListDisplayName("atlas"), + getAgentDisplayName("sisyphus"), + getAgentDisplayName("hephaestus"), + getAgentDisplayName("prometheus"), + getAgentDisplayName("atlas"), ]) }) @@ -354,19 +354,19 @@ describe("Plan agent demote behavior", () => { expect(emittedCoreEntries).toEqual([ [ - getAgentListDisplayName("sisyphus"), + getAgentDisplayName("sisyphus"), expect.objectContaining({ name: getAgentRuntimeName("sisyphus") }), ], [ - getAgentListDisplayName("hephaestus"), + getAgentDisplayName("hephaestus"), expect.objectContaining({ name: getAgentRuntimeName("hephaestus") }), ], [ - getAgentListDisplayName("prometheus"), + getAgentDisplayName("prometheus"), expect.objectContaining({ name: getAgentRuntimeName("prometheus") }), ], [ - getAgentListDisplayName("atlas"), + getAgentDisplayName("atlas"), expect.objectContaining({ name: getAgentRuntimeName("atlas") }), ], ]) @@ -407,7 +407,7 @@ describe("Plan agent demote behavior", () => { expect(agents.plan).toBeDefined() expect(agents.plan.mode).toBe("subagent") expect(agents.plan.prompt).toBeUndefined() - expect(agents[getAgentListDisplayName("prometheus")]?.prompt).toBeDefined() + expect(agents[getAgentDisplayName("prometheus")]?.prompt).toBeDefined() }) test("plan agent remains unchanged when planner is disabled", async () => { @@ -441,7 +441,7 @@ describe("Plan agent demote behavior", () => { // #then - plan is not touched, prometheus is not created const agents = config.agent as Record - expect(agents[getAgentListDisplayName("prometheus")]).toBeUndefined() + expect(agents[getAgentDisplayName("prometheus")]).toBeUndefined() expect(agents.plan).toBeDefined() expect(agents.plan.mode).toBe("primary") expect(agents.plan.prompt).toBe("original plan prompt") @@ -472,7 +472,7 @@ describe("Plan agent demote behavior", () => { // then const agents = config.agent as Record - const prometheusKey = getAgentListDisplayName("prometheus") + const prometheusKey = getAgentDisplayName("prometheus") expect(agents[prometheusKey]).toBeDefined() expect(agents[prometheusKey].mode).toBe("all") }) @@ -508,7 +508,7 @@ describe("Agent permission defaults", () => { // #then const agentConfig = config.agent as Record }> - const hephaestusKey = getAgentListDisplayName("hephaestus") + const hephaestusKey = getAgentDisplayName("hephaestus") expect(agentConfig[hephaestusKey]).toBeDefined() expect(agentConfig[hephaestusKey].permission?.task).toBe("allow") }) @@ -536,7 +536,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { await handler(config) // then - expect(config.default_agent).toBe(getAgentRuntimeName("hephaestus")) + expect(config.default_agent).toBe(getAgentDisplayName("hephaestus")) }) test("canonicalizes configured default_agent when key uses mixed case", async () => { @@ -560,7 +560,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { await handler(config) // then - expect(config.default_agent).toBe(getAgentRuntimeName("hephaestus")) + expect(config.default_agent).toBe(getAgentDisplayName("hephaestus")) }) test("canonicalizes configured default_agent key to display name", async () => { @@ -584,13 +584,13 @@ describe("default_agent behavior with Sisyphus orchestration", () => { await handler(config) // #then - expect(config.default_agent).toBe(getAgentRuntimeName("hephaestus")) + expect(config.default_agent).toBe(getAgentDisplayName("hephaestus")) }) test("preserves existing display-name default_agent", async () => { // #given const pluginConfig = createPluginConfig({}) - const displayName = getAgentListDisplayName("hephaestus") + const displayName = getAgentDisplayName("hephaestus") const config: Record = { model: "anthropic/claude-opus-4-6", default_agent: displayName, @@ -609,7 +609,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { await handler(config) // #then - expect(config.default_agent).toBe(getAgentRuntimeName("hephaestus")) + expect(config.default_agent).toBe(getAgentDisplayName("hephaestus")) }) test("sets default_agent to sisyphus when missing", async () => { @@ -632,7 +632,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { await handler(config) // #then - expect(config.default_agent).toBe(getAgentRuntimeName("sisyphus")) + expect(config.default_agent).toBe(getAgentDisplayName("sisyphus")) }) test("uses canonical default_agent display name so OpenCode lookups match emitted agent keys", async () => { @@ -656,7 +656,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { await handler(config) // then - expect(config.default_agent).toBe(getAgentRuntimeName("hephaestus")) + expect(config.default_agent).toBe(getAgentDisplayName("hephaestus")) }) test("sets default_agent to sisyphus when configured default_agent is empty after trim", async () => { @@ -680,7 +680,7 @@ describe("default_agent behavior with Sisyphus orchestration", () => { await handler(config) // then - expect(config.default_agent).toBe(getAgentRuntimeName("sisyphus")) + expect(config.default_agent).toBe(getAgentDisplayName("sisyphus")) }) test("preserves custom default_agent names while trimming whitespace", async () => { @@ -874,7 +874,7 @@ describe("Prometheus direct override priority over category", () => { // then - direct override's reasoningEffort wins const agents = config.agent as Record - const pKey = getAgentListDisplayName("prometheus") + const pKey = getAgentDisplayName("prometheus") expect(agents[pKey]).toBeDefined() expect(agents[pKey].reasoningEffort).toBe("low") }) @@ -915,7 +915,7 @@ describe("Prometheus direct override priority over category", () => { // then - category's reasoningEffort is applied const agents = config.agent as Record - const pKey = getAgentListDisplayName("prometheus") + const pKey = getAgentDisplayName("prometheus") expect(agents[pKey]).toBeDefined() expect(agents[pKey].reasoningEffort).toBe("high") }) @@ -957,7 +957,7 @@ describe("Prometheus direct override priority over category", () => { // then - direct temperature wins over category const agents = config.agent as Record - const pKey = getAgentListDisplayName("prometheus") + const pKey = getAgentDisplayName("prometheus") expect(agents[pKey]).toBeDefined() expect(agents[pKey].temperature).toBe(0.1) }) @@ -993,7 +993,7 @@ describe("Prometheus direct override priority over category", () => { // #then - prompt_append is appended to base prompt, not overwriting it const agents = config.agent as Record - const pKey = getAgentListDisplayName("prometheus") + const pKey = getAgentDisplayName("prometheus") expect(agents[pKey]).toBeDefined() expect(agents[pKey].prompt).toContain("Prometheus") expect(agents[pKey].prompt).toContain(customInstructions) @@ -1218,7 +1218,7 @@ describe("Deadlock prevention - fetchAvailableModels must not receive client", ( // then - regression guard: handler completes and still assembles planner config const agentConfig = config.agent as Record - expect(agentConfig[getAgentListDisplayName("prometheus")]).toBeDefined() + expect(agentConfig[getAgentDisplayName("prometheus")]).toBeDefined() }) }) @@ -1384,17 +1384,17 @@ describe("command agent routing coherence", () => { //#then const agentConfig = config.agent as Record const commandConfig = config.command as Record - expect(Object.keys(agentConfig)).toContain(getAgentListDisplayName("atlas")) - expect(commandConfig["start-work"]?.agent).toBe(getAgentListDisplayName("atlas")) + expect(Object.keys(agentConfig)).toContain(getAgentDisplayName("atlas")) + expect(commandConfig["start-work"]?.agent).toBe(getAgentDisplayName("atlas")) }) }) describe("per-agent todowrite/todoread deny when task_system enabled", () => { const AGENTS_WITH_TODO_DENY = new Set([ - getAgentListDisplayName("sisyphus"), - getAgentListDisplayName("hephaestus"), - getAgentListDisplayName("prometheus"), - getAgentListDisplayName("atlas"), + getAgentDisplayName("sisyphus"), + getAgentDisplayName("hephaestus"), + getAgentDisplayName("prometheus"), + getAgentDisplayName("atlas"), getAgentDisplayName("sisyphus-junior"), ]) @@ -1475,10 +1475,10 @@ describe("per-agent todowrite/todoread deny when task_system enabled", () => { expect(lastCall?.[11]).toBe(false) const agentResult = config.agent as Record }> - expect(agentResult[getAgentListDisplayName("sisyphus")]?.permission?.todowrite).toBeUndefined() - expect(agentResult[getAgentListDisplayName("sisyphus")]?.permission?.todoread).toBeUndefined() - expect(agentResult[getAgentListDisplayName("hephaestus")]?.permission?.todowrite).toBeUndefined() - expect(agentResult[getAgentListDisplayName("hephaestus")]?.permission?.todoread).toBeUndefined() + expect(agentResult[getAgentDisplayName("sisyphus")]?.permission?.todowrite).toBeUndefined() + expect(agentResult[getAgentDisplayName("sisyphus")]?.permission?.todoread).toBeUndefined() + expect(agentResult[getAgentDisplayName("hephaestus")]?.permission?.todowrite).toBeUndefined() + expect(agentResult[getAgentDisplayName("hephaestus")]?.permission?.todoread).toBeUndefined() }) test("does not deny todowrite/todoread when task_system is undefined", async () => { @@ -1514,8 +1514,8 @@ describe("per-agent todowrite/todoread deny when task_system enabled", () => { expect(lastCall?.[11]).toBe(false) const agentResult = config.agent as Record }> - expect(agentResult[getAgentListDisplayName("sisyphus")]?.permission?.todowrite).toBeUndefined() - expect(agentResult[getAgentListDisplayName("sisyphus")]?.permission?.todoread).toBeUndefined() + expect(agentResult[getAgentDisplayName("sisyphus")]?.permission?.todowrite).toBeUndefined() + expect(agentResult[getAgentDisplayName("sisyphus")]?.permission?.todoread).toBeUndefined() }) })