refactor(agents): replace broken ZWSP sort prefixes with leading ASCII spaces
The ZWSP-based core agent sort prefixes silently failed to produce the canonical sisyphus -> hephaestus -> prometheus -> atlas order. Empirical testing of OpenCode's Agent.list() sort behavior shows that Unicode collation treats zero-width characters as ignorable at the primary level, so ZWSP-prefixed names sorted alphabetically with non-core agents interleaved (e.g. Sisyphus, athena, Atlas, explore, Hephaestus, ...). This commit replaces the ZWSP prefixes with leading ASCII spaces in descending lengths (sisyphus=4, hephaestus=3, prometheus=2, atlas=1). ASCII spaces sort reliably before alphabetic characters in localeCompare under all locales and render correctly in every terminal. Changes: - AGENT_LIST_SORT_PREFIXES: ZWSP -> leading spaces (4-3-2-1 descending) - stripAgentListSortPrefix: now strips both legacy ZWSP and new leading whitespace, preserving backward compatibility with existing sessions - normalizeStoredAgentName / normalizeRegisteredAgentName: extract a shared stripSortPrefix helper that handles both prefix formats - agent-config-handler: resolve user-provided default_agent display names through getAgentConfigKey before applying the runtime prefix, so configs like default_agent="Hephaestus - Deep Agent" are normalized - agent-runtime-name-sort.test.ts: new regression test simulating OpenCode's exact sortBy logic (default_agent desc + name asc localeCompare) to verify canonical core agent order under randomised input permutations - AGENTS.md: document the empirical finding that ZWSP was broken, why ASCII spaces work, and the descending prefix-length contract Existing strip functions retain ZWSP support so legacy session state and configs continue to resolve correctly without migration.
This commit is contained in:
@@ -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 { AGENT_DISPLAY_NAMES, getAgentConfigKey, getAgentRuntimeName } from "../shared/agent-display-names";
|
||||
import { AGENT_NAME_MAP } from "../shared/migration";
|
||||
import { registerAgentName } from "../features/claude-code-session-state";
|
||||
import {
|
||||
@@ -189,8 +189,11 @@ export async function applyAgentConfig(params: {
|
||||
|
||||
if (isSisyphusEnabled && builtinAgents.sisyphus) {
|
||||
if (configuredDefaultAgent) {
|
||||
(params.config as { default_agent?: string }).default_agent =
|
||||
getAgentRuntimeName(configuredDefaultAgent);
|
||||
const configKey = getAgentConfigKey(configuredDefaultAgent);
|
||||
const isKnownBuiltin = configKey in AGENT_DISPLAY_NAMES;
|
||||
(params.config as { default_agent?: string }).default_agent = isKnownBuiltin
|
||||
? getAgentRuntimeName(configKey)
|
||||
: configuredDefaultAgent;
|
||||
} else {
|
||||
(params.config as { default_agent?: string }).default_agent =
|
||||
getAgentRuntimeName("sisyphus");
|
||||
|
||||
Reference in New Issue
Block a user