fix(athena): prevent recursive council explosion — deny tool for bg tasks + dedup guard
Council members launched as agent='athena' got Athena's system prompt saying 'ALWAYS call athena_council first', plus the tool wasn't denied for bg athena tasks. Each council member spawned 4 more → exponential explosion (47+ tasks). Three fixes: 1. Deny athena_council in ATHENA_RESTRICTIONS (agent-tool-restrictions.ts) - Only affects background athena tasks (task-starter.ts) - Primary Athena (user-selected) still has access via permission field 2. Session-level dedup guard prevents re-calling while council is running - If Athena retries during long wait, returns 'already running' 3. Increase wait timeout from 2min to 10min (council members need time for real code analysis with Read/Grep/LSP)
This commit is contained in:
@@ -14,7 +14,7 @@ const EXPLORATION_AGENT_DENYLIST: Record<string, boolean> = {
|
||||
}
|
||||
|
||||
const ATHENA_RESTRICTIONS = permissionToToolBooleans(
|
||||
createAgentToolRestrictions(["write", "edit"]).permission
|
||||
createAgentToolRestrictions(["write", "edit", "athena_council"]).permission
|
||||
)
|
||||
|
||||
const AGENT_RESTRICTIONS: Record<string, Record<string, boolean>> = {
|
||||
|
||||
@@ -6,10 +6,13 @@ import { ATHENA_COUNCIL_TOOL_DESCRIPTION } from "./constants"
|
||||
import { createCouncilLauncher } from "./council-launcher"
|
||||
import type { AthenaCouncilToolArgs } from "./types"
|
||||
|
||||
const WAIT_INTERVAL_MS = 200
|
||||
const WAIT_TIMEOUT_MS = 120000
|
||||
const WAIT_INTERVAL_MS = 500
|
||||
const WAIT_TIMEOUT_MS = 600000
|
||||
const TERMINAL_STATUSES: Set<BackgroundTaskStatus> = new Set(["completed", "error", "cancelled", "interrupt"])
|
||||
|
||||
/** Tracks active council executions per session to prevent duplicate launches. */
|
||||
const activeCouncilSessions = new Set<string>()
|
||||
|
||||
function isCouncilConfigured(councilConfig: CouncilConfig | undefined): councilConfig is CouncilConfig {
|
||||
return Boolean(councilConfig && councilConfig.members.length > 0)
|
||||
}
|
||||
@@ -114,25 +117,34 @@ export function createAthenaCouncilTool(args: {
|
||||
return "Athena council not configured. Add agents.athena.council.members to your config."
|
||||
}
|
||||
|
||||
const execution = await executeCouncil({
|
||||
question: toolArgs.question,
|
||||
council: councilConfig,
|
||||
launcher: createCouncilLauncher(backgroundManager),
|
||||
parentSessionID: toolContext.sessionID,
|
||||
parentMessageID: toolContext.messageID,
|
||||
parentAgent: toolContext.agent,
|
||||
})
|
||||
if (activeCouncilSessions.has(toolContext.sessionID)) {
|
||||
return "Council is already running for this session. Wait for the current council execution to complete."
|
||||
}
|
||||
|
||||
const taskIds = execution.responses
|
||||
.map((response) => response.taskId)
|
||||
.filter((taskId) => taskId.length > 0)
|
||||
activeCouncilSessions.add(toolContext.sessionID)
|
||||
try {
|
||||
const execution = await executeCouncil({
|
||||
question: toolArgs.question,
|
||||
council: councilConfig,
|
||||
launcher: createCouncilLauncher(backgroundManager),
|
||||
parentSessionID: toolContext.sessionID,
|
||||
parentMessageID: toolContext.messageID,
|
||||
parentAgent: toolContext.agent,
|
||||
})
|
||||
|
||||
const latestTasks = await waitForTasksToSettle(taskIds, backgroundManager, toolContext.abort)
|
||||
const refreshedResponses = execution.responses.map((response) =>
|
||||
response.taskId ? refreshResponse(response, latestTasks.get(response.taskId)) : response
|
||||
)
|
||||
const taskIds = execution.responses
|
||||
.map((response) => response.taskId)
|
||||
.filter((taskId) => taskId.length > 0)
|
||||
|
||||
return formatCouncilOutput(refreshedResponses, execution.totalMembers)
|
||||
const latestTasks = await waitForTasksToSettle(taskIds, backgroundManager, toolContext.abort)
|
||||
const refreshedResponses = execution.responses.map((response) =>
|
||||
response.taskId ? refreshResponse(response, latestTasks.get(response.taskId)) : response
|
||||
)
|
||||
|
||||
return formatCouncilOutput(refreshedResponses, execution.totalMembers)
|
||||
} finally {
|
||||
activeCouncilSessions.delete(toolContext.sessionID)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user