fix(agents): keep object keys clean by separating list display from runtime name
Discovered via post-implementation review (Oracle goal verification): the prior commit's prefix swap (ZWSP -> ASCII spaces) inherited a pre-existing architectural bug from the ZWSP era. `getAgentListDisplayName()` was an alias for `getAgentRuntimeName()`, which meant every callsite that used the "list display" name as an OBJECT KEY (config.agent keys, lookup keys, HTTP-header-bound paths) ended up carrying the sort prefix. This worked silently with ZWSP because zero-width characters are visually invisible. With ASCII space prefixes, the same bug becomes user-visible and violates the explicit RFC 7230 constraint documented in AGENTS.md: "ZWSP MUST NOT appear in object keys (used as HTTP header values)." Fix: separate the two concepts that were conflated. - `getAgentListDisplayName(key)` now returns the CLEAN display name (alias of `getAgentDisplayName`). Used for object keys, config keys, and any path where the name will be sent over HTTP. - `getAgentRuntimeName(key)` keeps its prefixed return value. Used ONLY for the `.name` field that OpenCode reads for `localeCompare` sort. `agent-key-remapper.ts` was already correct: it uses `getAgentRuntimeName` for the `.name` field. The bug was that `getAgentListDisplayName` (used as the object key) also returned the prefix. Test updates: - agent-display-names.test.ts splits the assertions: getAgentListDisplayName asserts clean names, new getAgentRuntimeName describe asserts prefixes - All other tests using getAgentListDisplayName as an expected object key continue to pass because they always wanted clean names Verification: - bun test: 5769 pass / 10 pre-existing failures (unchanged) - bun run typecheck: clean - Manual: agent-key-remapper output keys verified RFC 7230 safe (no leading whitespace, no ZWSP); name fields preserve descending-space prefix for canonical core agent ordering
This commit is contained in:
@@ -50,31 +50,20 @@ export function getAgentRuntimeName(configKey: string): string {
|
||||
return prefix ? `${prefix}${displayName}` : displayName
|
||||
}
|
||||
|
||||
/**
|
||||
* Get display name for an agent config key.
|
||||
* Uses case-insensitive lookup for backward compatibility.
|
||||
* Returns original key if not found.
|
||||
*/
|
||||
export function getAgentDisplayName(configKey: string): string {
|
||||
// Try exact match first
|
||||
const exactMatch = AGENT_DISPLAY_NAMES[configKey]
|
||||
if (exactMatch !== undefined) return exactMatch
|
||||
|
||||
// Fall back to case-insensitive search
|
||||
|
||||
const lowerKey = configKey.toLowerCase()
|
||||
for (const [k, v] of Object.entries(AGENT_DISPLAY_NAMES)) {
|
||||
if (k.toLowerCase() === lowerKey) return v
|
||||
}
|
||||
|
||||
// Unknown agent: return original key
|
||||
|
||||
return configKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Runtime-facing agent name used for OpenCode list ordering.
|
||||
*/
|
||||
export function getAgentListDisplayName(configKey: string): string {
|
||||
return getAgentRuntimeName(configKey)
|
||||
return getAgentDisplayName(configKey)
|
||||
}
|
||||
|
||||
const REVERSE_DISPLAY_NAMES: Record<string, string> = Object.fromEntries(
|
||||
|
||||
Reference in New Issue
Block a user