bc0da0fad3
- prometheus-prompt.test.ts: close missing }) on the OpenSpec expanded commands describe block (introduced byd66b6bcbf, parse error). - agent-sort-shim/agent-config-integration/continuation-injection/ unstable-agent-babysitter/subagent-resolver/sync-executor/ resolve-caller-team-lead tests: expect 'Sisyphus - ultraworker' (lowercase) to match production aftercd39f8858, which lowercased the display name to dodge a TUI ZWSP rendering glitch. Legacy uppercase inputs that exercise the normalization path are preserved. - sync-executor.ts + resolve-caller-team-lead.ts: route legacy display name inputs through normalizeAgentForPrompt so prompt agent names and caller team lead lookups produce the canonical lowercase form.
290 lines
11 KiB
TypeScript
290 lines
11 KiB
TypeScript
/// <reference types="bun-types" />
|
|
|
|
import { afterEach, beforeAll, describe, expect, test } from "bun:test"
|
|
|
|
import { installAgentSortShim, setAgentSortOrder, setDefaultAgentForSort } from "./agent-sort-shim"
|
|
import { AGENT_DISPLAY_NAMES } from "./agent-display-names"
|
|
|
|
type AgentListItem = {
|
|
name: string
|
|
default_agent?: boolean
|
|
}
|
|
|
|
declare global {
|
|
interface Array<T> {
|
|
toSorted(compareFn?: (a: T, b: T) => number): T[]
|
|
}
|
|
}
|
|
|
|
describe("agent-sort-shim", () => {
|
|
beforeAll(() => {
|
|
installAgentSortShim()
|
|
})
|
|
|
|
afterEach(() => {
|
|
setAgentSortOrder(undefined)
|
|
})
|
|
|
|
describe("#given an array of all 4 core agent objects in random order", () => {
|
|
describe("#when toSorted with alphabetical compareFn", () => {
|
|
test("#then returns canonical sisyphus->hephaestus->prometheus->atlas order", () => {
|
|
// given
|
|
setAgentSortOrder(undefined)
|
|
const sisyphus = { name: "Sisyphus - ultraworker" }
|
|
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
|
const prometheus = { name: "Prometheus - Plan Builder" }
|
|
const atlas = { name: "Atlas - Plan Executor" }
|
|
const input = [atlas, prometheus, hephaestus, sisyphus]
|
|
|
|
// when
|
|
const result = input.toSorted((a, b) => a.name.localeCompare(b.name))
|
|
|
|
// then
|
|
expect(result).toEqual([sisyphus, hephaestus, prometheus, atlas])
|
|
})
|
|
|
|
test("#then follows configured core agent order", () => {
|
|
// given
|
|
setAgentSortOrder(["hephaestus", "sisyphus", "prometheus", "atlas"])
|
|
const sisyphus = { name: "Sisyphus - ultraworker" }
|
|
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
|
const prometheus = { name: "Prometheus - Plan Builder" }
|
|
const atlas = { name: "Atlas - Plan Executor" }
|
|
const input = [atlas, prometheus, hephaestus, sisyphus]
|
|
|
|
// when
|
|
const result = input.toSorted((a, b) => a.name.localeCompare(b.name))
|
|
|
|
// then
|
|
expect(result).toEqual([hephaestus, sisyphus, prometheus, atlas])
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("#given 4 core agents mixed with 2 non-core agent objects", () => {
|
|
describe("#when toSorted with alphabetical compareFn", () => {
|
|
test("#then core agents come first in canonical order followed by non-core agents alphabetically", () => {
|
|
// given
|
|
const sisyphus = { name: "Sisyphus - ultraworker" }
|
|
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
|
const prometheus = { name: "Prometheus - Plan Builder" }
|
|
const atlas = { name: "Atlas - Plan Executor" }
|
|
const build = { name: "build" }
|
|
const plan = { name: "plan" }
|
|
const input = [atlas, build, prometheus, plan, hephaestus, sisyphus]
|
|
|
|
// when
|
|
const result = input.toSorted((a, b) => a.name.localeCompare(b.name))
|
|
|
|
// then
|
|
expect(result).toEqual([sisyphus, hephaestus, prometheus, atlas, build, plan])
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("#given OpenCode Agent.list style sort with default agent priority", () => {
|
|
describe("#when toSorted compares default_agent first and then name", () => {
|
|
test("#then core agents stay in canonical order before non-core agents", () => {
|
|
// given
|
|
const sisyphus = { name: AGENT_DISPLAY_NAMES.sisyphus, default_agent: true }
|
|
const hephaestus = { name: AGENT_DISPLAY_NAMES.hephaestus }
|
|
const prometheus = { name: AGENT_DISPLAY_NAMES.prometheus }
|
|
const atlas = { name: AGENT_DISPLAY_NAMES.atlas }
|
|
const oracle = { name: AGENT_DISPLAY_NAMES.oracle }
|
|
const explore = { name: AGENT_DISPLAY_NAMES.explore }
|
|
const input: AgentListItem[] = [oracle, atlas, explore, prometheus, hephaestus, sisyphus]
|
|
|
|
// when
|
|
const result = input.toSorted((left, right) => {
|
|
const leftDefault = left.default_agent ? 1 : 0
|
|
const rightDefault = right.default_agent ? 1 : 0
|
|
if (leftDefault !== rightDefault) return rightDefault - leftDefault
|
|
return left.name.localeCompare(right.name)
|
|
})
|
|
|
|
// then
|
|
expect(result).toEqual([sisyphus, hephaestus, prometheus, atlas, explore, oracle])
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("#given an array with only one core agent and several non-core agent-like objects", () => {
|
|
describe("#when toSorted with case-sensitive string-comparison compareFn", () => {
|
|
test("#then activation predicate fails and result is ASCII-sensitive order with capital S before lowercase letters", () => {
|
|
// given
|
|
const oracle = { name: "oracle" }
|
|
const librarian = { name: "librarian" }
|
|
const sisyphus = { name: "Sisyphus - ultraworker" }
|
|
const explore = { name: "explore" }
|
|
const input = [oracle, librarian, sisyphus, explore]
|
|
|
|
// when
|
|
const result = input.toSorted((a, b) =>
|
|
a.name < b.name ? -1 : a.name > b.name ? 1 : 0,
|
|
)
|
|
|
|
// then
|
|
expect(result).toEqual([sisyphus, explore, librarian, oracle])
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("#given a mixed-type array containing null, objects, a string, and a number", () => {
|
|
describe("#when toSorted with a string-coercing compareFn", () => {
|
|
test("#then activation predicate fails, shim does not throw, and result matches native semantics", () => {
|
|
// given
|
|
const sisyphusObj = { name: "Sisyphus - ultraworker" }
|
|
const hephaestusObj = { name: "Hephaestus - Deep Agent" }
|
|
const input: unknown[] = [null, sisyphusObj, "string", 42, hephaestusObj]
|
|
const compare = (a: unknown, b: unknown): number => {
|
|
const sa = String(a)
|
|
const sb = String(b)
|
|
if (sa < sb) return -1
|
|
if (sa > sb) return 1
|
|
return 0
|
|
}
|
|
|
|
// when
|
|
const result = input.toSorted(compare)
|
|
|
|
// then
|
|
expect(result).toEqual([42, sisyphusObj, hephaestusObj, null, "string"])
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("#given a plain string array", () => {
|
|
describe("#when toSorted with no compareFn", () => {
|
|
test("#then returns native alphabetical ordering untouched", () => {
|
|
// given
|
|
const input = ["zebra", "apple", "mango"]
|
|
|
|
// when
|
|
const result = input.toSorted()
|
|
|
|
// then
|
|
expect(result).toEqual(["apple", "mango", "zebra"])
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("#given a number array", () => {
|
|
describe("#when sort with numeric compareFn (in-place)", () => {
|
|
test("#then mutates the array and returns the same reference in ascending order", () => {
|
|
// given
|
|
const input = [3, 1, 4, 1, 5, 9, 2, 6]
|
|
|
|
// when
|
|
const result = input.sort((a, b) => a - b)
|
|
|
|
// then
|
|
expect(result).toBe(input)
|
|
expect(input).toEqual([1, 1, 2, 3, 4, 5, 6, 9])
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("#given agent objects with all 4 core display names in random order", () => {
|
|
describe("#when sort with alphabetical compareFn (in-place)", () => {
|
|
test("#then mutates the original array to canonical order", () => {
|
|
// given
|
|
const sisyphus = { name: "Sisyphus - ultraworker" }
|
|
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
|
const prometheus = { name: "Prometheus - Plan Builder" }
|
|
const atlas = { name: "Atlas - Plan Executor" }
|
|
const input = [atlas, prometheus, hephaestus, sisyphus]
|
|
|
|
// when
|
|
const result = input.sort((a, b) => a.name.localeCompare(b.name))
|
|
|
|
// then
|
|
expect(result).toBe(input)
|
|
expect(input).toEqual([sisyphus, hephaestus, prometheus, atlas])
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("#given installAgentSortShim has been invoked multiple times", () => {
|
|
describe("#when toSorted is called on core agents after duplicate installs", () => {
|
|
test("#then result is canonical order with no double-wrapping side effects", () => {
|
|
// given
|
|
installAgentSortShim()
|
|
installAgentSortShim()
|
|
const sisyphus = { name: "Sisyphus - ultraworker" }
|
|
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
|
const prometheus = { name: "Prometheus - Plan Builder" }
|
|
const atlas = { name: "Atlas - Plan Executor" }
|
|
const input = [atlas, prometheus, hephaestus, sisyphus]
|
|
|
|
// when
|
|
const result = input.toSorted((a, b) => a.name.localeCompare(b.name))
|
|
|
|
// then
|
|
expect(result).toEqual([sisyphus, hephaestus, prometheus, atlas])
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("#given a custom default_agent configured via setDefaultAgentForSort", () => {
|
|
describe("#when toSorted is called on core agents mixed with the custom default agent", () => {
|
|
test("#then the custom default agent sorts first, followed by core agents in canonical order", () => {
|
|
// given
|
|
setAgentSortOrder(undefined)
|
|
setDefaultAgentForSort("crystal")
|
|
const sisyphus = { name: "Sisyphus - ultraworker" }
|
|
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
|
const prometheus = { name: "Prometheus - Plan Builder" }
|
|
const atlas = { name: "Atlas - Plan Executor" }
|
|
const crystal = { name: "crystal" }
|
|
const input = [atlas, crystal, prometheus, hephaestus, sisyphus]
|
|
|
|
// when
|
|
const result = input.toSorted((a, b) => a.name.localeCompare(b.name))
|
|
|
|
// then
|
|
expect(result).toEqual([crystal, sisyphus, hephaestus, prometheus, atlas])
|
|
})
|
|
})
|
|
|
|
describe("#when setDefaultAgentForSort is called with a core agent name", () => {
|
|
test("#then that core agent sorts first, others follow in remaining canonical order", () => {
|
|
// given
|
|
setAgentSortOrder(undefined)
|
|
setDefaultAgentForSort("Hephaestus - Deep Agent")
|
|
const sisyphus = { name: "Sisyphus - ultraworker" }
|
|
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
|
const prometheus = { name: "Prometheus - Plan Builder" }
|
|
const atlas = { name: "Atlas - Plan Executor" }
|
|
const input = [atlas, prometheus, hephaestus, sisyphus]
|
|
|
|
// when
|
|
const result = input.toSorted((a, b) => a.name.localeCompare(b.name))
|
|
|
|
// then
|
|
expect(result).toEqual([hephaestus, sisyphus, prometheus, atlas])
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("#given agent_order configured without default_agent", () => {
|
|
describe("#when setAgentSortOrder sets a non-canonical order and setDefaultAgentForSort is NOT called", () => {
|
|
test("#then the custom agent_order is preserved without implicit override", () => {
|
|
// given
|
|
setAgentSortOrder(["hephaestus", "sisyphus", "prometheus", "atlas"])
|
|
// setDefaultAgentForSort is intentionally NOT called (user did not set default_agent)
|
|
const sisyphus = { name: "Sisyphus - ultraworker" }
|
|
const hephaestus = { name: "Hephaestus - Deep Agent" }
|
|
const prometheus = { name: "Prometheus - Plan Builder" }
|
|
const atlas = { name: "Atlas - Plan Executor" }
|
|
const input = [atlas, sisyphus, prometheus, hephaestus]
|
|
|
|
// when
|
|
const result = input.toSorted((a, b) => a.name.localeCompare(b.name))
|
|
|
|
// then — Hephaestus must remain first per the user's agent_order
|
|
expect(result).toEqual([hephaestus, sisyphus, prometheus, atlas])
|
|
})
|
|
})
|
|
})
|
|
})
|