From 134994895760c2ca93b71e4599bcd1893482f1bb Mon Sep 17 00:00:00 2001 From: ismeth Date: Thu, 19 Feb 2026 02:20:18 +0100 Subject: [PATCH] refactor(athena): delete athena_council tool directory Remove the entire custom tool implementation (constants, launcher, session-waiter, tool-helpers, tools, types, and all tests). Council members are now launched via the standard task tool. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- src/tools/athena-council/constants.ts | 10 - .../athena-council/council-launcher.test.ts | 51 ----- src/tools/athena-council/council-launcher.ts | 18 -- src/tools/athena-council/index.ts | 1 - .../athena-council/session-waiter.test.ts | 108 --------- src/tools/athena-council/session-waiter.ts | 67 ------ src/tools/athena-council/tool-helpers.ts | 95 -------- src/tools/athena-council/tools.test.ts | 205 ------------------ src/tools/athena-council/tools.ts | 118 ---------- src/tools/athena-council/types.ts | 13 -- 10 files changed, 686 deletions(-) delete mode 100644 src/tools/athena-council/constants.ts delete mode 100644 src/tools/athena-council/council-launcher.test.ts delete mode 100644 src/tools/athena-council/council-launcher.ts delete mode 100644 src/tools/athena-council/index.ts delete mode 100644 src/tools/athena-council/session-waiter.test.ts delete mode 100644 src/tools/athena-council/session-waiter.ts delete mode 100644 src/tools/athena-council/tool-helpers.ts delete mode 100644 src/tools/athena-council/tools.test.ts delete mode 100644 src/tools/athena-council/tools.ts delete mode 100644 src/tools/athena-council/types.ts diff --git a/src/tools/athena-council/constants.ts b/src/tools/athena-council/constants.ts deleted file mode 100644 index 3a61a753b..000000000 --- a/src/tools/athena-council/constants.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const ATHENA_COUNCIL_TOOL_DESCRIPTION_TEMPLATE = `Execute Athena's multi-model council for exactly ONE member per call. - -Pass members as a single-item array containing one member name or model ID. Athena should call this tool once per selected member. - -This tool launches the selected member as a background task and returns task/session metadata immediately. -After launching ALL members, use background_wait(task_ids=[...all IDs...]) to wait for results. It blocks until the next member finishes and returns progress. Repeat with remaining IDs until all complete. - -{members} - -IMPORTANT: This tool is designed for Athena agent use only. It requires council configuration to be present.` diff --git a/src/tools/athena-council/council-launcher.test.ts b/src/tools/athena-council/council-launcher.test.ts deleted file mode 100644 index 3877308c1..000000000 --- a/src/tools/athena-council/council-launcher.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { describe, expect, test } from "bun:test" -import type { BackgroundManager } from "../../features/background-agent" -import type { BackgroundTask, LaunchInput } from "../../features/background-agent/types" -import { createCouncilLauncher } from "./council-launcher" - -function createMockTask(id: string): BackgroundTask { - return { - id, - parentSessionID: "session-1", - parentMessageID: "message-1", - description: "test", - prompt: "test", - agent: "athena", - status: "running", - } -} - -describe("createCouncilLauncher", () => { - //#given a council launch input with all fields - //#when launch is called - //#then all fields are forwarded to the background manager - test("forwards all launch input fields to background manager", async () => { - const capturedInputs: LaunchInput[] = [] - const mockManager = { - launch: async (input: LaunchInput) => { - capturedInputs.push(input) - return createMockTask("bg-1") - }, - getTask: () => undefined, - } as unknown as BackgroundManager - - const launcher = createCouncilLauncher(mockManager) - - await launcher.launch({ - description: "Council member: test", - prompt: "Analyze this", - agent: "athena", - parentSessionID: "session-1", - parentMessageID: "message-1", - model: { providerID: "openai", modelID: "gpt-5.3-codex" }, - }) - - expect(capturedInputs).toHaveLength(1) - expect(capturedInputs[0]?.description).toBe("Council member: test") - expect(capturedInputs[0]?.prompt).toBe("Analyze this") - expect(capturedInputs[0]?.agent).toBe("athena") - expect(capturedInputs[0]?.parentSessionID).toBe("session-1") - expect(capturedInputs[0]?.parentMessageID).toBe("message-1") - expect(capturedInputs[0]?.model).toEqual({ providerID: "openai", modelID: "gpt-5.3-codex" }) - }) -}) diff --git a/src/tools/athena-council/council-launcher.ts b/src/tools/athena-council/council-launcher.ts deleted file mode 100644 index 0f83ba5c5..000000000 --- a/src/tools/athena-council/council-launcher.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { CouncilLauncher, CouncilLaunchInput } from "../../agents/athena/council-orchestrator" -import type { BackgroundManager } from "../../features/background-agent" - -export function createCouncilLauncher(manager: BackgroundManager): CouncilLauncher { - return { - launch(input: CouncilLaunchInput) { - return manager.launch({ - description: input.description, - prompt: input.prompt, - agent: input.agent, - parentSessionID: input.parentSessionID, - parentMessageID: input.parentMessageID, - parentAgent: input.parentAgent, - model: input.model, - }) - }, - } -} diff --git a/src/tools/athena-council/index.ts b/src/tools/athena-council/index.ts deleted file mode 100644 index ef1a860ed..000000000 --- a/src/tools/athena-council/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { createAthenaCouncilTool } from "./tools" diff --git a/src/tools/athena-council/session-waiter.test.ts b/src/tools/athena-council/session-waiter.test.ts deleted file mode 100644 index 8c3918b7e..000000000 --- a/src/tools/athena-council/session-waiter.test.ts +++ /dev/null @@ -1,108 +0,0 @@ -/// - -import { describe, expect, test } from "bun:test" -import type { BackgroundManager } from "../../features/background-agent" -import { waitForCouncilSessions } from "./session-waiter" - -describe("waitForCouncilSessions", () => { - test("resolves all sessions when tasks have sessionIDs immediately", async () => { - //#given - const launched = [ - { member: { model: "openai/gpt-5.3-codex", name: "GPT" }, taskId: "task-1" }, - { member: { model: "anthropic/claude-opus-4-6" }, taskId: "task-2" }, - ] - const manager = { - getTask: (id: string) => ({ sessionID: `ses-${id}` }), - } as unknown as BackgroundManager - - //#when - const result = await waitForCouncilSessions(launched, manager) - - //#then - expect(result.sessions).toHaveLength(2) - expect(result.timedOut).toBe(false) - expect(result.aborted).toBe(false) - expect(result.sessions[0].taskId).toBe("task-1") - expect(result.sessions[0].memberName).toBe("GPT") - expect(result.sessions[1].taskId).toBe("task-2") - expect(result.sessions[1].memberName).toBe("anthropic/claude-opus-4-6") - }) - - test("returns empty sessions for empty launched list", async () => { - //#given - const manager = { getTask: () => undefined } as unknown as BackgroundManager - - //#when - const result = await waitForCouncilSessions([], manager) - - //#then - expect(result.sessions).toHaveLength(0) - expect(result.timedOut).toBe(false) - expect(result.aborted).toBe(false) - }) - - test("sets aborted flag when abort signal fires", async () => { - //#given - const launched = [ - { member: { model: "openai/gpt-5.3-codex" }, taskId: "task-1" }, - ] - const manager = { getTask: () => undefined } as unknown as BackgroundManager - const controller = new AbortController() - // Abort immediately - controller.abort() - - //#when - const result = await waitForCouncilSessions(launched, manager, controller.signal) - - //#then - expect(result.sessions).toHaveLength(0) - expect(result.aborted).toBe(true) - expect(result.timedOut).toBe(false) - }) - - test("resolves partial sessions when some tasks get sessionIDs", async () => { - //#given - const launched = [ - { member: { model: "openai/gpt-5.3-codex", name: "GPT" }, taskId: "task-1" }, - { member: { model: "anthropic/claude-opus-4-6" }, taskId: "task-2" }, - ] - const controller = new AbortController() - let callCount = 0 - const manager = { - getTask: (id: string) => { - callCount++ - // Only task-1 gets a session, task-2 never does - if (id === "task-1") return { sessionID: "ses-task-1" } - return undefined - }, - } as unknown as BackgroundManager - - // Abort after a short delay to avoid waiting full 30s - setTimeout(() => controller.abort(), 200) - - //#when - const result = await waitForCouncilSessions(launched, manager, controller.signal) - - //#then - expect(result.sessions).toHaveLength(1) - expect(result.sessions[0].taskId).toBe("task-1") - expect(result.aborted).toBe(true) - }) - - test("uses member model as memberName when name is not provided", async () => { - //#given - const launched = [ - { member: { model: "google/gemini-3-pro" }, taskId: "task-1" }, - ] - const manager = { - getTask: () => ({ sessionID: "ses-1" }), - } as unknown as BackgroundManager - - //#when - const result = await waitForCouncilSessions(launched, manager) - - //#then - expect(result.sessions[0].memberName).toBe("google/gemini-3-pro") - expect(result.sessions[0].model).toBe("google/gemini-3-pro") - }) -}) diff --git a/src/tools/athena-council/session-waiter.ts b/src/tools/athena-council/session-waiter.ts deleted file mode 100644 index bc7f39478..000000000 --- a/src/tools/athena-council/session-waiter.ts +++ /dev/null @@ -1,67 +0,0 @@ -import type { BackgroundManager } from "../../features/background-agent" -import type { CouncilLaunchedMember } from "../../agents/athena/types" - -const WAIT_INTERVAL_MS = 100 -const WAIT_TIMEOUT_MS = 30_000 - -interface CouncilSessionInfo { - taskId: string - memberName: string - model: string - sessionId: string -} - -export interface CouncilSessionWaitResult { - sessions: CouncilSessionInfo[] - timedOut: boolean - aborted: boolean -} - -/** - * Waits for background sessions to be created for launched council members. - * Returns session info for each member whose session became available within the timeout. - */ -export async function waitForCouncilSessions( - launched: CouncilLaunchedMember[], - manager: BackgroundManager, - abort?: AbortSignal -): Promise { - const results: CouncilSessionInfo[] = [] - const pending = new Map( - launched.map((entry) => [entry.taskId, entry]) - ) - - const deadline = Date.now() + WAIT_TIMEOUT_MS - let timedOut = false - let aborted = false - - while (pending.size > 0 && Date.now() < deadline) { - if (abort?.aborted) { - aborted = true - break - } - - for (const [taskId, entry] of pending) { - const task = manager.getTask(taskId) - if (task?.sessionID) { - results.push({ - taskId, - memberName: entry.member.name ?? entry.member.model, - model: entry.member.model, - sessionId: task.sessionID, - }) - pending.delete(taskId) - } - } - - if (pending.size > 0) { - await new Promise((resolve) => setTimeout(resolve, WAIT_INTERVAL_MS)) - } - } - - if (pending.size > 0 && !aborted) { - timedOut = true - } - - return { sessions: results, timedOut, aborted } -} diff --git a/src/tools/athena-council/tool-helpers.ts b/src/tools/athena-council/tool-helpers.ts deleted file mode 100644 index 7be7ce122..000000000 --- a/src/tools/athena-council/tool-helpers.ts +++ /dev/null @@ -1,95 +0,0 @@ -import type { CouncilConfig, CouncilMemberConfig } from "../../agents/athena/types" -import { ATHENA_COUNCIL_TOOL_DESCRIPTION_TEMPLATE } from "./constants" - -function isCouncilConfigured(councilConfig: CouncilConfig | undefined): councilConfig is CouncilConfig { - return Boolean(councilConfig && councilConfig.members.length > 0) -} - -interface FilterCouncilMembersResult { - members: CouncilMemberConfig[] - error?: string -} - -function buildSingleMemberSelectionError(members: CouncilMemberConfig[]): string { - const availableNames = members.map((member) => member.name ?? member.model).join(", ") - return `athena_council runs one member per call. Pass exactly one member in members (single-item array). Available members: ${availableNames}.` -} - -function filterCouncilMembers( - members: CouncilMemberConfig[], - selectedNames: string[] | undefined -): FilterCouncilMembersResult { - if (!selectedNames || selectedNames.length === 0) { - return { - members: [], - error: buildSingleMemberSelectionError(members), - } - } - - const memberLookup = new Map() - members.forEach((member) => { - memberLookup.set(member.model.toLowerCase(), member) - if (member.name) { - memberLookup.set(member.name.toLowerCase(), member) - } - }) - - const unresolved: string[] = [] - const filteredMembers: CouncilMemberConfig[] = [] - const includedMembers = new Set() - - selectedNames.forEach((selectedName) => { - const selectedKey = selectedName.toLowerCase() - const matchedMember = memberLookup.get(selectedKey) - if (!matchedMember) { - unresolved.push(selectedName) - return - } - - if (includedMembers.has(matchedMember)) { - return - } - - includedMembers.add(matchedMember) - filteredMembers.push(matchedMember) - }) - - if (unresolved.length > 0) { - const availableDescriptions = members - .map((member) => { - if (member.name) { - return `${member.name} (${member.model})` - } - return member.model - }) - .join(", ") - return { - members: [], - error: `Unknown council members: ${unresolved.join(", ")}. Available: ${availableDescriptions}.`, - } - } - - return { members: filteredMembers } -} - -function buildToolDescription(councilConfig: CouncilConfig | undefined): string { - const memberList = councilConfig?.members.length - ? councilConfig.members.map((m) => `- ${m.name ?? m.model}`).join("\n") - : "No members configured." - - return ATHENA_COUNCIL_TOOL_DESCRIPTION_TEMPLATE.replace("{members}", `Available council members:\n${memberList}`) -} - -function formatCouncilLaunchFailure( - failures: Array<{ member: { name?: string; model: string }; error: string }> -): string { - const failureLines = failures - .map((failure) => `- **${failure.member.name ?? failure.member.model}**: ${failure.error}`) - .join("\n") - - return failureLines - ? `Failed to launch council member.\n\n### Launch Failures\n\n${failureLines}` - : "Failed to launch council member." -} - -export { isCouncilConfigured, filterCouncilMembers, buildSingleMemberSelectionError, buildToolDescription, formatCouncilLaunchFailure } diff --git a/src/tools/athena-council/tools.test.ts b/src/tools/athena-council/tools.test.ts deleted file mode 100644 index 03da86526..000000000 --- a/src/tools/athena-council/tools.test.ts +++ /dev/null @@ -1,205 +0,0 @@ -/// - -import { describe, expect, test } from "bun:test" -import type { BackgroundManager } from "../../features/background-agent" -import type { BackgroundTask } from "../../features/background-agent/types" -import { createAthenaCouncilTool } from "./tools" -import { filterCouncilMembers } from "./tool-helpers" - -const mockManager = { - getTask: () => undefined, - launch: async () => { - throw new Error("launch should not be called in config validation tests") - }, -} as unknown as BackgroundManager - -const mockToolContext = { - sessionID: "session-1", - messageID: "message-1", - agent: "athena", - abort: new AbortController().signal, -} - -const configuredMembers = [ - { name: "Claude", model: "anthropic/claude-sonnet-4-5" }, - { name: "GPT", model: "openai/gpt-5.3-codex" }, - { model: "google/gemini-3-pro" }, -] - -function createRunningTask(id: string, sessionID = `ses-${id}`): BackgroundTask { - return { - id, - parentSessionID: "session-1", - parentMessageID: "message-1", - description: `Council member task ${id}`, - prompt: "prompt", - agent: "council-member", - status: "running", - sessionID, - } -} - -describe("filterCouncilMembers", () => { - test("returns selection error when selection is undefined", () => { - const result = filterCouncilMembers(configuredMembers, undefined) - expect(result.members).toEqual([]) - expect(result.error).toBe( - "athena_council runs one member per call. Pass exactly one member in members (single-item array). Available members: Claude, GPT, google/gemini-3-pro." - ) - }) - - test("returns selection error when selection is empty", () => { - const result = filterCouncilMembers(configuredMembers, []) - expect(result.members).toEqual([]) - expect(result.error).toBe( - "athena_council runs one member per call. Pass exactly one member in members (single-item array). Available members: Claude, GPT, google/gemini-3-pro." - ) - }) - - test("filters members using case-insensitive name and model matching", () => { - const result = filterCouncilMembers(configuredMembers, ["gpt", "GOOGLE/GEMINI-3-PRO"]) - expect(result.members).toEqual([configuredMembers[1], configuredMembers[2]]) - expect(result.error).toBeUndefined() - }) - - test("returns helpful error when selected members are not configured", () => { - const result = filterCouncilMembers(configuredMembers, ["mistral", "xai/grok-3"]) - expect(result.members).toEqual([]) - expect(result.error).toBe( - "Unknown council members: mistral, xai/grok-3. Available: Claude (anthropic/claude-sonnet-4-5), GPT (openai/gpt-5.3-codex), google/gemini-3-pro." - ) - }) - - test("deduplicates when same member is selected by both name and model", () => { - const result = filterCouncilMembers(configuredMembers, ["Claude", "anthropic/claude-sonnet-4-5"]) - expect(result.members).toEqual([configuredMembers[0]]) - expect(result.error).toBeUndefined() - }) -}) - -describe("createAthenaCouncilTool", () => { - test("returns error when councilConfig is undefined", async () => { - const athenaCouncilTool = createAthenaCouncilTool({ - backgroundManager: mockManager, - councilConfig: undefined, - }) - - const result = await athenaCouncilTool.execute({ question: "How should we proceed?" }, mockToolContext) - - expect(result).toBe("Athena council is not configured. Add council members to agents.athena.council.members in .opencode/oh-my-opencode.jsonc.") - }) - - test("returns error when councilConfig has empty members", async () => { - const athenaCouncilTool = createAthenaCouncilTool({ - backgroundManager: mockManager, - councilConfig: { members: [] }, - }) - - const result = await athenaCouncilTool.execute({ question: "Any concerns?" }, mockToolContext) - - expect(result).toBe("Athena council is not configured. Add council members to agents.athena.council.members in .opencode/oh-my-opencode.jsonc.") - }) - - test("returns helpful error when members contains invalid names", async () => { - const athenaCouncilTool = createAthenaCouncilTool({ - backgroundManager: mockManager, - councilConfig: { members: configuredMembers }, - }) - - const result = await athenaCouncilTool.execute( - { question: "Who should investigate this?", members: ["unknown-model"] }, - mockToolContext - ) - - expect(result).toBe("Unknown council members: unknown-model. Available: Claude (anthropic/claude-sonnet-4-5), GPT (openai/gpt-5.3-codex), google/gemini-3-pro.") - }) - - test("returns selection error when members are omitted", async () => { - const athenaCouncilTool = createAthenaCouncilTool({ - backgroundManager: mockManager, - councilConfig: { members: configuredMembers }, - }) - - const result = await athenaCouncilTool.execute({ question: "How should we proceed?" }, mockToolContext) - - expect(result).toBe( - "athena_council runs one member per call. Pass exactly one member in members (single-item array). Available members: Claude, GPT, google/gemini-3-pro." - ) - }) - - test("returns selection error when multiple members are provided", async () => { - const athenaCouncilTool = createAthenaCouncilTool({ - backgroundManager: mockManager, - councilConfig: { members: configuredMembers }, - }) - - const result = await athenaCouncilTool.execute( - { question: "How should we proceed?", members: ["Claude", "GPT"] }, - mockToolContext - ) - - expect(result).toBe( - "athena_council runs one member per call. Pass exactly one member in members (single-item array). Available members: Claude, GPT, google/gemini-3-pro." - ) - }) - - test("launches selected member and returns background task metadata", async () => { - let launchCount = 0 - const taskStore = new Map() - const launchManager = { - launch: async () => { - launchCount += 1 - const task = createRunningTask(`bg-${launchCount}`) - taskStore.set(task.id, task) - return task - }, - getTask: (id: string) => taskStore.get(id), - } as unknown as BackgroundManager - - const athenaCouncilTool = createAthenaCouncilTool({ - backgroundManager: launchManager, - councilConfig: { members: configuredMembers }, - }) - - const result = await athenaCouncilTool.execute( - { question: "Who should investigate this?", members: ["GPT"] }, - mockToolContext - ) - - expect(launchCount).toBe(1) - expect(result).toContain("Council member launched in background.") - expect(result).toContain("Task ID: bg-1") - expect(result).toContain("Session ID: ses-bg-1") - expect(result).toContain("Member: GPT") - expect(result).toContain("Model: openai/gpt-5.3-codex") - expect(result).toContain("Status: running") - expect(result).toContain("background_output") - expect(result).toContain("task_id=\"bg-1\"") - expect(result).toContain("") - expect(result).toContain("session_id: ses-bg-1") - }) - - test("returns launch failure details when selected member fails", async () => { - const launchManager = { - launch: async () => { - throw new Error("provider outage") - }, - getTask: () => undefined, - } as unknown as BackgroundManager - - const athenaCouncilTool = createAthenaCouncilTool({ - backgroundManager: launchManager, - councilConfig: { members: configuredMembers }, - }) - - const result = await athenaCouncilTool.execute( - { question: "Any concerns?", members: ["GPT"] }, - mockToolContext - ) - - expect(result).toContain("Failed to launch council member.") - expect(result).toContain("### Launch Failures") - expect(result).toContain("**GPT**") - expect(result).toContain("provider outage") - }) -}) diff --git a/src/tools/athena-council/tools.ts b/src/tools/athena-council/tools.ts deleted file mode 100644 index 86aff7593..000000000 --- a/src/tools/athena-council/tools.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { tool, type ToolDefinition } from "@opencode-ai/plugin" -import { executeCouncil } from "../../agents/athena/council-orchestrator" -import type { CouncilConfig } from "../../agents/athena/types" -import type { BackgroundManager } from "../../features/background-agent" -import { createCouncilLauncher } from "./council-launcher" -import { waitForCouncilSessions } from "./session-waiter" -import type { AthenaCouncilToolArgs, AthenaCouncilToolContext } from "./types" -import { storeToolMetadata } from "../../features/tool-metadata-store" -import { log } from "../../shared/logger" -import { - isCouncilConfigured, - filterCouncilMembers, - buildSingleMemberSelectionError, - buildToolDescription, - formatCouncilLaunchFailure, -} from "./tool-helpers" - -export function createAthenaCouncilTool(args: { - backgroundManager: BackgroundManager - councilConfig: CouncilConfig | undefined -}): ToolDefinition { - const { backgroundManager, councilConfig } = args - const description = buildToolDescription(councilConfig) - - return tool({ - description, - args: { - question: tool.schema.string().describe("The question to send to all council members"), - members: tool.schema - .array(tool.schema.string()) - .optional() - .describe("Single-item list containing exactly one council member name or model ID."), - }, - async execute(toolArgs: AthenaCouncilToolArgs, toolContext: AthenaCouncilToolContext) { - if (!isCouncilConfigured(councilConfig)) { - return "Athena council is not configured. Add council members to agents.athena.council.members in .opencode/oh-my-opencode.jsonc." - } - - const filteredMembers = filterCouncilMembers(councilConfig.members, toolArgs.members) - if (filteredMembers.error) { - return filteredMembers.error - } - if (filteredMembers.members.length !== 1) { - return buildSingleMemberSelectionError(councilConfig.members) - } - - const execution = await executeCouncil({ - question: toolArgs.question, - council: { members: filteredMembers.members }, - launcher: createCouncilLauncher(backgroundManager), - parentSessionID: toolContext.sessionID, - parentMessageID: toolContext.messageID, - parentAgent: toolContext.agent, - }) - - if (execution.launched.length === 0) { - return formatCouncilLaunchFailure(execution.failures) - } - - const launched = execution.launched[0] - const launchedMemberName = launched?.member.name ?? launched?.member.model - const launchedMemberModel = launched?.member.model ?? "unknown" - const launchedTaskId = launched?.taskId ?? "unknown" - - log("[athena-council] Launching council member", { member: launchedMemberName, model: launchedMemberModel, taskId: launchedTaskId }) - - const waitResult = await waitForCouncilSessions(execution.launched, backgroundManager, toolContext.abort) - const launchedSession = waitResult.sessions.find((session) => session.taskId === launchedTaskId) - const sessionId = launchedSession?.sessionId ?? "pending" - - let statusNote = "" - if (waitResult.timedOut) { - statusNote = "\nNote: Session creation timed out. The task is still running — use background_output to check status." - } else if (waitResult.aborted) { - statusNote = "\nNote: Session wait was aborted. The task may still be running." - } - - log("[athena-council] Session resolved", { taskId: launchedTaskId, sessionId }) - - if (toolContext.metadata) { - const memberMetadata = { - title: `Council: ${launchedMemberName}`, - metadata: { - sessionId, - agent: "council-member", - model: launchedMemberModel, - description: `Council member: ${launchedMemberName}`, - }, - } - try { - await toolContext.metadata(memberMetadata) - - if (toolContext.callID) { - storeToolMetadata(toolContext.sessionID, toolContext.callID, memberMetadata) - } - } catch (error) { - log("[athena-council] Metadata storage failed (best-effort)", { error: error instanceof Error ? error.message : String(error) }) - } - } - - return `Council member launched in background. - -Task ID: ${launchedTaskId} -Session ID: ${sessionId} -Member: ${launchedMemberName} -Model: ${launchedMemberModel} -Status: running${statusNote} - -Use \`background_output\` with task_id="${launchedTaskId}" to collect this member's result. -- block=true: Wait for completion and return the result -- full_session=true: Include full session messages when needed - - -session_id: ${sessionId} -` - }, - }) -} diff --git a/src/tools/athena-council/types.ts b/src/tools/athena-council/types.ts deleted file mode 100644 index 934fcc716..000000000 --- a/src/tools/athena-council/types.ts +++ /dev/null @@ -1,13 +0,0 @@ -export interface AthenaCouncilToolArgs { - question: string - members?: string[] -} - -export interface AthenaCouncilToolContext { - sessionID: string - messageID: string - agent: string - abort: AbortSignal - metadata?: (input: { title?: string; metadata?: Record }) => void | Promise - callID?: string -}