refactor(athena): remove council-orchestrator and council-prompt modules

Delete the orchestrator that launched council members via the custom athena_council tool. This logic is now replaced by standard task() calls from Athena's prompt.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
ismeth
2026-02-19 02:20:02 +01:00
committed by YeonGyu-Kim
parent f5b809ccea
commit 70f074f579
3 changed files with 0 additions and 346 deletions

View File

@@ -1,228 +0,0 @@
import { describe, expect, test } from "bun:test"
import { buildCouncilPrompt } from "./council-prompt"
import { executeCouncil } from "./council-orchestrator"
import type { CouncilConfig } from "./types"
interface MockLaunchInput {
description: string
prompt: string
agent: string
parentSessionID: string
parentMessageID: string
parentAgent?: string
model?: { providerID: string; modelID: string; variant?: string }
}
function createMockTask(id: string, launch: MockLaunchInput) {
return {
id,
status: "pending" as const,
parentSessionID: launch.parentSessionID,
parentMessageID: launch.parentMessageID,
description: launch.description,
prompt: launch.prompt,
agent: launch.agent,
}
}
describe("executeCouncil", () => {
//#given a council with 3 members and a question
//#when executeCouncil is called
//#then all members are launched with the same prompt and parsed model ids
test("launches all members with identical prompt and model params", async () => {
const launches: MockLaunchInput[] = []
const launcher = {
launch: async (input: MockLaunchInput) => {
launches.push(input)
return createMockTask(`task-${launches.length}`, input)
},
}
const council: CouncilConfig = {
members: [
{ model: "openai/gpt-5.3-codex", name: "openai" },
{ model: "anthropic/claude-sonnet-4-5", name: "anthropic" },
{ model: "google/gemini-3-pro", name: "google" },
],
}
const question = "How can we improve the retry strategy?"
const result = await executeCouncil({
question,
council,
launcher,
parentSessionID: "session-1",
parentMessageID: "message-1",
parentAgent: "sisyphus",
})
const expectedPrompt = buildCouncilPrompt(question)
expect(launches).toHaveLength(3)
expect(result.launched).toHaveLength(3)
expect(result.failures).toHaveLength(0)
expect(result.totalMembers).toBe(3)
for (const launch of launches) {
expect(launch.prompt).toBe(expectedPrompt)
expect(launch.agent).toBe("council-member")
}
expect(launches[0]?.model).toEqual({ providerID: "openai", modelID: "gpt-5.3-codex" })
expect(launches[1]?.model).toEqual({ providerID: "anthropic", modelID: "claude-sonnet-4-5" })
expect(launches[2]?.model).toEqual({ providerID: "google", modelID: "gemini-3-pro" })
})
//#given a council with 3 members where 1 launch throws
//#when executeCouncil is called
//#then launch failures are captured separately from successful launches
test("captures launch failures separately from successful launches", async () => {
const launcher = {
launch: async (input: MockLaunchInput) => {
if (input.model?.providerID === "anthropic") {
throw new Error("Provider unavailable")
}
return createMockTask(`task-${input.model?.providerID}`, input)
},
}
const result = await executeCouncil({
question: "Find race condition risks",
council: {
members: [
{ model: "openai/gpt-5.3-codex" },
{ model: "anthropic/claude-sonnet-4-5" },
{ model: "google/gemini-3-pro" },
],
},
launcher,
parentSessionID: "session-1",
parentMessageID: "message-1",
})
expect(result.launched).toHaveLength(2)
expect(result.failures).toHaveLength(1)
expect(result.totalMembers).toBe(3)
expect(result.failures[0]?.member.model).toBe("anthropic/claude-sonnet-4-5")
expect(result.failures[0]?.error).toContain("Launch failed")
})
//#given a council where all launches throw
//#when executeCouncil is called
//#then all members appear as failures with zero launched
test("returns all failures when every launch throws", async () => {
const launcher = {
launch: async () => {
throw new Error("Model unavailable")
},
}
const result = await executeCouncil({
question: "Analyze unknown module",
council: {
members: [
{ model: "openai/gpt-5.3-codex" },
{ model: "anthropic/claude-sonnet-4-5" },
],
},
launcher,
parentSessionID: "session-1",
parentMessageID: "message-1",
})
expect(result.launched).toHaveLength(0)
expect(result.failures).toHaveLength(2)
expect(result.totalMembers).toBe(2)
expect(result.failures.every((f) => f.error.includes("Launch failed"))).toBe(true)
})
//#given a council with one invalid model string
//#when executeCouncil is called
//#then invalid member becomes a failure while others still launch
test("handles invalid model strings without crashing council execution", async () => {
const launches: MockLaunchInput[] = []
const launcher = {
launch: async (input: MockLaunchInput) => {
launches.push(input)
return createMockTask(`task-${launches.length}`, input)
},
}
const result = await executeCouncil({
question: "Audit dependency graph",
council: {
members: [
{ model: "invalid-model" },
{ model: "openai/gpt-5.3-codex" },
],
},
launcher,
parentSessionID: "session-1",
parentMessageID: "message-1",
})
expect(launches).toHaveLength(1)
expect(result.launched).toHaveLength(1)
expect(result.failures).toHaveLength(1)
expect(result.failures.find((f) => f.member.model === "invalid-model")?.error).toContain("Launch failed")
})
//#given members with per-member variant
//#when executeCouncil is called
//#then launch receives variant in model for each corresponding member
test("passes member variant to launch input model", async () => {
const launches: MockLaunchInput[] = []
const launcher = {
launch: async (input: MockLaunchInput) => {
launches.push(input)
return createMockTask(`task-${launches.length}`, input)
},
}
await executeCouncil({
question: "Compare architecture options",
council: {
members: [
{ model: "openai/gpt-5.3-codex", variant: "high" },
{ model: "anthropic/claude-sonnet-4-5" },
],
},
launcher,
parentSessionID: "session-1",
parentMessageID: "message-1",
})
expect(launches).toHaveLength(2)
expect(launches[0]?.model?.variant).toBe("high")
expect(launches[1]?.model?.variant).toBeUndefined()
})
//#given launched members
//#when executeCouncil returns
//#then each launched member has a taskId for background_output retrieval
test("returns task IDs for background_output retrieval", async () => {
const launcher = {
launch: async (input: MockLaunchInput) =>
createMockTask(`bg_${input.model?.providerID}`, input),
}
const result = await executeCouncil({
question: "Review error handling",
council: {
members: [
{ model: "openai/gpt-5.3-codex", name: "OpenAI" },
{ model: "google/gemini-3-pro", name: "Gemini" },
],
},
launcher,
parentSessionID: "session-1",
parentMessageID: "message-1",
})
expect(result.launched).toHaveLength(2)
expect(result.launched[0]?.taskId).toBe("bg_openai")
expect(result.launched[0]?.member.name).toBe("OpenAI")
expect(result.launched[1]?.taskId).toBe("bg_google")
expect(result.launched[1]?.member.name).toBe("Gemini")
})
})

View File

@@ -1,94 +0,0 @@
import type { LaunchInput, BackgroundTask } from "../../features/background-agent/types"
import { log } from "../../shared/logger"
import { buildCouncilPrompt } from "./council-prompt"
import { parseModelString } from "./model-parser"
import type { CouncilConfig, CouncilLaunchFailure, CouncilLaunchedMember, CouncilLaunchResult, CouncilMemberConfig } from "./types"
export type CouncilLaunchInput = LaunchInput
export interface CouncilLauncher {
launch(input: CouncilLaunchInput): Promise<BackgroundTask>
}
export interface CouncilExecutionInput {
question: string
council: CouncilConfig
launcher: CouncilLauncher
parentSessionID: string
parentMessageID: string
parentAgent?: string
}
/**
* Launches all council members in parallel and returns launch outcomes.
* Does NOT wait for task completion — actual results are collected by the
* agent via background_output calls after this returns.
*/
export async function executeCouncil(input: CouncilExecutionInput): Promise<CouncilLaunchResult> {
const { question, council, launcher, parentSessionID, parentMessageID, parentAgent } = input
log("[athena-council] Executing council", { memberCount: council.members.length })
const prompt = buildCouncilPrompt(question)
const launchResults = await Promise.allSettled(
council.members.map((member) =>
launchMember(member, prompt, launcher, parentSessionID, parentMessageID, parentAgent)
)
)
const launched: CouncilLaunchedMember[] = []
const failures: CouncilLaunchFailure[] = []
launchResults.forEach((result, index) => {
const member = council.members[index]
if (result.status === "fulfilled") {
launched.push({ member, taskId: result.value.id })
return
}
failures.push({
member,
error: `Launch failed: ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`,
})
})
log("[athena-council] Council execution complete", { launched: launched.length, failures: failures.length })
return {
question,
launched,
failures,
totalMembers: council.members.length,
}
}
async function launchMember(
member: CouncilMemberConfig,
prompt: string,
launcher: CouncilLauncher,
parentSessionID: string,
parentMessageID: string,
parentAgent: string | undefined
): Promise<BackgroundTask> {
const parsedModel = parseModelString(member.model)
if (!parsedModel) {
throw new Error(`Invalid model string: "${member.model}"`)
}
const memberName = member.name ?? member.model
return launcher.launch({
description: `Council member: ${memberName}`,
prompt,
agent: "council-member",
parentSessionID,
parentMessageID,
parentAgent,
model: {
providerID: parsedModel.providerID,
modelID: parsedModel.modelID,
...(member.variant ? { variant: member.variant } : {}),
},
})
}

View File

@@ -1,24 +0,0 @@
export function buildCouncilPrompt(question: string): string {
return `You are a council member in a multi-model analysis council. Your role is to provide independent, thorough analysis of the question below.
## Your Role
- You are one of several AI models analyzing the same question independently
- Your analysis should be thorough and evidence-based
- You are read-only - you cannot modify any files, only analyze
- Focus on finding real issues, not hypothetical ones
## Instructions
1. Analyze the question carefully
2. Search the codebase thoroughly using available tools (Read, Grep, Glob, LSP)
3. Report your findings with evidence (file paths, line numbers, code snippets)
4. For each finding, state:
- What the issue/observation is
- Where it is (file path, line number)
- Why it matters (severity: critical/high/medium/low)
- Your confidence level (high/medium/low)
5. Be concise but thorough - quality over quantity
## Question
${question}`
}