Files
oh-my-opencode/src/plugin-handlers/agent-priority-order.test.ts
T
YeonGyu-Kim 47283f9238 fix(agents): remove ZWSP prefixes from config.agent keys (#3238)
Agent names in the config.agent object (which becomes the /agent API
response) contained invisible Zero-Width Space (U+200B) characters
baked in by getAgentListDisplayName(). These ZWSP prefixes were used
for TUI sort ordering, but they leaked into the public API surface.

Impact: any prompt_async consumer that discovered agent names via the
/agent endpoint and passed them back to prompt_async without manual
ZWSP stripping got silent message drops — the agent name didn't match.
hy-pony's feishu-bridge integration went dark after upgrading to 3.16.0
with no error, no warning, and no indication that invisible Unicode
characters in agent names were the cause.

Fix: switch all four callsites from getAgentListDisplayName() (which
prepends \u200B×N) to getAgentDisplayName() (clean names):

- agent-key-remapper.ts: config keys → display names (was the primary
  injection point)
- agent-priority-order.ts: CORE_AGENT_ORDER lookup (must agree with
  the keys emitted by the remapper)
- command-config-handler.ts: command agent field normalization
- tool-config-handler.ts: agent config lookup (simplified fallback
  chain since the primary lookup is now clean)

Sort ordering is preserved by:
1. JS object insertion order from reorderAgentsByPriority()
2. The injected `order` field (1-4) added by injectOrderField()

getAgentListDisplayName() is marked @deprecated with a link to #3238.
AGENT_LIST_SORT_PREFIXES and stripAgentListSortPrefix() are kept for
any internal callers that strip prefixes from legacy data.

Closes #3238
2026-04-08 22:51:59 +09:00

81 lines
2.3 KiB
TypeScript

import { describe, expect, test } from "bun:test"
import { reorderAgentsByPriority } from "./agent-priority-order"
import { getAgentDisplayName } from "../shared/agent-display-names"
describe("reorderAgentsByPriority", () => {
test("moves core agents to canonical order and injects runtime order fields", () => {
// given
const sisyphus = getAgentDisplayName("sisyphus")
const hephaestus = getAgentDisplayName("hephaestus")
const prometheus = getAgentDisplayName("prometheus")
const atlas = getAgentDisplayName("atlas")
const oracle = getAgentDisplayName("oracle")
const agents: Record<string, unknown> = {
[oracle]: { name: "oracle", mode: "subagent" },
[atlas]: { name: "atlas", mode: "primary" },
[prometheus]: { name: "prometheus", mode: "all" },
[hephaestus]: { name: "hephaestus", mode: "primary" },
[sisyphus]: { name: "sisyphus", mode: "primary" },
}
// when
const result = reorderAgentsByPriority(agents)
// then
expect(Object.keys(result)).toEqual([
sisyphus,
hephaestus,
prometheus,
atlas,
oracle,
])
expect(result[sisyphus]).toEqual({
name: "sisyphus",
mode: "primary",
order: 1,
})
expect(result[hephaestus]).toEqual({
name: "hephaestus",
mode: "primary",
order: 2,
})
expect(result[prometheus]).toEqual({
name: "prometheus",
mode: "all",
order: 3,
})
expect(result[atlas]).toEqual({
name: "atlas",
mode: "primary",
order: 4,
})
expect(result[oracle]).toEqual({
name: "oracle",
mode: "subagent",
})
})
test("leaves non-object agent configs untouched while still reordering keys", () => {
// given
const sisyphus = getAgentDisplayName("sisyphus")
const atlas = getAgentDisplayName("atlas")
const agents: Record<string, unknown> = {
[atlas]: "atlas-config",
custom: "custom-config",
[sisyphus]: "sisyphus-config",
}
// when
const result = reorderAgentsByPriority(agents)
// then
expect(Object.keys(result)).toEqual([sisyphus, atlas, "custom"])
expect(result[sisyphus]).toBe("sisyphus-config")
expect(result[atlas]).toBe("atlas-config")
expect(result.custom).toBe("custom-config")
})
})