fix(agents): keep prometheus and atlas in canonical core order
This commit is contained in:
@@ -172,6 +172,24 @@ export async function applyAgentConfig(params: {
|
|||||||
agentConfig["hephaestus"] = builtinAgents.hephaestus;
|
agentConfig["hephaestus"] = builtinAgents.hephaestus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (plannerEnabled) {
|
||||||
|
const prometheusOverride = params.pluginConfig.agents?.["prometheus"] as
|
||||||
|
| (Record<string, unknown> & { prompt_append?: string })
|
||||||
|
| undefined;
|
||||||
|
|
||||||
|
agentConfig["prometheus"] = await buildPrometheusAgentConfig({
|
||||||
|
configAgentPlan: configAgent?.plan,
|
||||||
|
pluginPrometheusOverride: prometheusOverride,
|
||||||
|
userCategories: params.pluginConfig.categories,
|
||||||
|
currentModel,
|
||||||
|
disabledTools: params.pluginConfig.disabled_tools,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (builtinAgents.atlas) {
|
||||||
|
agentConfig["atlas"] = builtinAgents.atlas;
|
||||||
|
}
|
||||||
|
|
||||||
agentConfig["sisyphus-junior"] = createSisyphusJuniorAgentWithOverrides(
|
agentConfig["sisyphus-junior"] = createSisyphusJuniorAgentWithOverrides(
|
||||||
params.pluginConfig.agents?.["sisyphus-junior"],
|
params.pluginConfig.agents?.["sisyphus-junior"],
|
||||||
(builtinAgents.atlas as { model?: string } | undefined)?.model,
|
(builtinAgents.atlas as { model?: string } | undefined)?.model,
|
||||||
@@ -192,20 +210,6 @@ export async function applyAgentConfig(params: {
|
|||||||
agentConfig["OpenCode-Builder"] = override ? { ...base, ...override } : base;
|
agentConfig["OpenCode-Builder"] = override ? { ...base, ...override } : base;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plannerEnabled) {
|
|
||||||
const prometheusOverride = params.pluginConfig.agents?.["prometheus"] as
|
|
||||||
| (Record<string, unknown> & { prompt_append?: string })
|
|
||||||
| undefined;
|
|
||||||
|
|
||||||
agentConfig["prometheus"] = await buildPrometheusAgentConfig({
|
|
||||||
configAgentPlan: configAgent?.plan,
|
|
||||||
pluginPrometheusOverride: prometheusOverride,
|
|
||||||
userCategories: params.pluginConfig.categories,
|
|
||||||
currentModel,
|
|
||||||
disabledTools: params.pluginConfig.disabled_tools,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const filteredConfigAgents = configAgent
|
const filteredConfigAgents = configAgent
|
||||||
? Object.fromEntries(
|
? Object.fromEntries(
|
||||||
Object.entries(configAgent)
|
Object.entries(configAgent)
|
||||||
@@ -253,7 +257,9 @@ export async function applyAgentConfig(params: {
|
|||||||
params.config.agent = {
|
params.config.agent = {
|
||||||
...agentConfig,
|
...agentConfig,
|
||||||
...Object.fromEntries(
|
...Object.fromEntries(
|
||||||
Object.entries(builtinAgents).filter(([key]) => key !== "sisyphus" && key !== "hephaestus"),
|
Object.entries(builtinAgents).filter(
|
||||||
|
([key]) => key !== "sisyphus" && key !== "hephaestus" && key !== "atlas",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
...filterDisabledAgents(filteredUserAgents),
|
...filterDisabledAgents(filteredUserAgents),
|
||||||
...filterDisabledAgents(filteredProjectAgents),
|
...filterDisabledAgents(filteredProjectAgents),
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import { describe, expect, test } from "bun:test"
|
||||||
|
|
||||||
|
import { reorderAgentsByPriority } from "./agent-priority-order"
|
||||||
|
import { getAgentListDisplayName } from "../shared/agent-display-names"
|
||||||
|
|
||||||
|
describe("reorderAgentsByPriority", () => {
|
||||||
|
test("moves core agents to canonical order and injects runtime order fields", () => {
|
||||||
|
// given
|
||||||
|
const sisyphus = getAgentListDisplayName("sisyphus")
|
||||||
|
const hephaestus = getAgentListDisplayName("hephaestus")
|
||||||
|
const prometheus = getAgentListDisplayName("prometheus")
|
||||||
|
const atlas = getAgentListDisplayName("atlas")
|
||||||
|
const oracle = getAgentListDisplayName("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 = getAgentListDisplayName("sisyphus")
|
||||||
|
const atlas = getAgentListDisplayName("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")
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -19,6 +19,7 @@ import * as shared from "../shared"
|
|||||||
import * as configDir from "../shared/opencode-config-dir"
|
import * as configDir from "../shared/opencode-config-dir"
|
||||||
import * as permissionCompat from "../shared/permission-compat"
|
import * as permissionCompat from "../shared/permission-compat"
|
||||||
import * as modelResolver from "../shared/model-resolver"
|
import * as modelResolver from "../shared/model-resolver"
|
||||||
|
import * as agentPriorityOrder from "./agent-priority-order"
|
||||||
|
|
||||||
function createPluginConfig(overrides: Partial<OhMyOpenCodeConfig> = {}): OhMyOpenCodeConfig {
|
function createPluginConfig(overrides: Partial<OhMyOpenCodeConfig> = {}): OhMyOpenCodeConfig {
|
||||||
return {
|
return {
|
||||||
@@ -115,6 +116,7 @@ afterEach(() => {
|
|||||||
;(configDir.getOpenCodeConfigPaths as any)?.mockRestore?.()
|
;(configDir.getOpenCodeConfigPaths as any)?.mockRestore?.()
|
||||||
;(permissionCompat.migrateAgentConfig as any)?.mockRestore?.()
|
;(permissionCompat.migrateAgentConfig as any)?.mockRestore?.()
|
||||||
;(modelResolver.resolveModelWithFallback as any)?.mockRestore?.()
|
;(modelResolver.resolveModelWithFallback as any)?.mockRestore?.()
|
||||||
|
;(agentPriorityOrder.reorderAgentsByPriority as any)?.mockRestore?.()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("Sisyphus-Junior model inheritance", () => {
|
describe("Sisyphus-Junior model inheritance", () => {
|
||||||
@@ -212,6 +214,7 @@ describe("Plan agent demote behavior", () => {
|
|||||||
// #given
|
// #given
|
||||||
const createBuiltinAgentsMock = agents.createBuiltinAgents as unknown as {
|
const createBuiltinAgentsMock = agents.createBuiltinAgents as unknown as {
|
||||||
mockResolvedValue: (value: Record<string, unknown>) => void
|
mockResolvedValue: (value: Record<string, unknown>) => void
|
||||||
|
mock: { calls: unknown[][] }
|
||||||
}
|
}
|
||||||
createBuiltinAgentsMock.mockResolvedValue({
|
createBuiltinAgentsMock.mockResolvedValue({
|
||||||
sisyphus: { name: "sisyphus", prompt: "test", mode: "primary" },
|
sisyphus: { name: "sisyphus", prompt: "test", mode: "primary" },
|
||||||
@@ -252,6 +255,52 @@ describe("Plan agent demote behavior", () => {
|
|||||||
expect(ordered).toEqual(coreAgents)
|
expect(ordered).toEqual(coreAgents)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("assembles core agents first before priority reorder runs", async () => {
|
||||||
|
// #given
|
||||||
|
const createBuiltinAgentsMock = agents.createBuiltinAgents as unknown as {
|
||||||
|
mockResolvedValue: (value: Record<string, unknown>) => void
|
||||||
|
mock: { calls: unknown[][] }
|
||||||
|
}
|
||||||
|
createBuiltinAgentsMock.mockResolvedValue({
|
||||||
|
sisyphus: { name: "sisyphus", prompt: "test", mode: "primary" },
|
||||||
|
hephaestus: { name: "hephaestus", prompt: "test", mode: "primary" },
|
||||||
|
oracle: { name: "oracle", prompt: "test", mode: "subagent" },
|
||||||
|
atlas: { name: "atlas", prompt: "test", mode: "primary" },
|
||||||
|
})
|
||||||
|
const reorderSpy = spyOn(agentPriorityOrder, "reorderAgentsByPriority") as any
|
||||||
|
const pluginConfig = createPluginConfig({
|
||||||
|
sisyphus_agent: {
|
||||||
|
planner_enabled: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const config: Record<string, unknown> = {
|
||||||
|
model: "anthropic/claude-opus-4-6",
|
||||||
|
agent: {},
|
||||||
|
}
|
||||||
|
const handler = createConfigHandler({
|
||||||
|
ctx: { directory: "/tmp" },
|
||||||
|
pluginConfig,
|
||||||
|
modelCacheState: {
|
||||||
|
anthropicContext1MEnabled: false,
|
||||||
|
modelContextLimitsCache: new Map(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// #when
|
||||||
|
await handler(config)
|
||||||
|
|
||||||
|
// #then
|
||||||
|
const assembledAgentKeys = Object.keys(
|
||||||
|
reorderSpy.mock.calls.at(0)?.[0] as Record<string, unknown>
|
||||||
|
)
|
||||||
|
expect(assembledAgentKeys.slice(0, 4)).toEqual([
|
||||||
|
getAgentListDisplayName("sisyphus"),
|
||||||
|
getAgentListDisplayName("hephaestus"),
|
||||||
|
getAgentListDisplayName("prometheus"),
|
||||||
|
getAgentListDisplayName("atlas"),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
test("plan agent should be demoted to subagent without inheriting prometheus prompt", async () => {
|
test("plan agent should be demoted to subagent without inheriting prometheus prompt", async () => {
|
||||||
// #given
|
// #given
|
||||||
const pluginConfig = createPluginConfig({
|
const pluginConfig = createPluginConfig({
|
||||||
@@ -1255,6 +1304,7 @@ describe("per-agent todowrite/todoread deny when task_system enabled", () => {
|
|||||||
//#given
|
//#given
|
||||||
const createBuiltinAgentsMock = agents.createBuiltinAgents as unknown as {
|
const createBuiltinAgentsMock = agents.createBuiltinAgents as unknown as {
|
||||||
mockResolvedValue: (value: Record<string, unknown>) => void
|
mockResolvedValue: (value: Record<string, unknown>) => void
|
||||||
|
mock: { calls: unknown[][] }
|
||||||
}
|
}
|
||||||
createBuiltinAgentsMock.mockResolvedValue({
|
createBuiltinAgentsMock.mockResolvedValue({
|
||||||
sisyphus: { name: "sisyphus", prompt: "test", mode: "primary" },
|
sisyphus: { name: "sisyphus", prompt: "test", mode: "primary" },
|
||||||
@@ -1296,6 +1346,7 @@ describe("per-agent todowrite/todoread deny when task_system enabled", () => {
|
|||||||
//#given
|
//#given
|
||||||
const createBuiltinAgentsMock = agents.createBuiltinAgents as unknown as {
|
const createBuiltinAgentsMock = agents.createBuiltinAgents as unknown as {
|
||||||
mockResolvedValue: (value: Record<string, unknown>) => void
|
mockResolvedValue: (value: Record<string, unknown>) => void
|
||||||
|
mock: { calls: unknown[][] }
|
||||||
}
|
}
|
||||||
createBuiltinAgentsMock.mockResolvedValue({
|
createBuiltinAgentsMock.mockResolvedValue({
|
||||||
sisyphus: { name: "sisyphus", prompt: "test", mode: "primary" },
|
sisyphus: { name: "sisyphus", prompt: "test", mode: "primary" },
|
||||||
|
|||||||
Reference in New Issue
Block a user