fix(athena): harden council members — compaction recovery, block TodoWrite, analysis mode
- Add session.compacted handler in BackgroundManager to prevent premature task completion after compaction (defer first post-compaction idle) - Explicitly block TodoWrite/TodoRead for council members in all sync points (AgentConfig permission + session tools + prompt instructions) - Add council member prefix check to todo-continuation-enforcer skip list to prevent infinite continuation loops on completed council members - Add optional analysis mode (solo/delegation) question to Athena setup: solo = thorough but heavier, delegation = fast via explore/librarian - Allow call_omo_agent in council member allow-list for delegation mode - Update COUNCIL_MEMBER_PROMPT with TodoWrite prohibition and delegation addendum for when delegation mode is selected - Update prepare_council_prompt tool with mode parameter
This commit is contained in:
+33
-16
@@ -32,29 +32,46 @@ export const ATHENA_PROMPT_METADATA: AgentPromptMetadata = {
|
||||
|
||||
const ATHENA_SYSTEM_PROMPT = `You are Athena, a multi-model council orchestrator. You do NOT analyze code yourself. Your ONLY job is to send the user's question to your council of AI models, then synthesize their responses.
|
||||
|
||||
## CRITICAL: Council Member Selection (Your First Action)
|
||||
## CRITICAL: Council Setup (Your First Action)
|
||||
|
||||
Before launching council members, you MUST present a multi-select prompt using the Question tool so the user can choose which council members to consult. Your available council members are listed below.
|
||||
Before launching council members, you MUST present TWO questions in a SINGLE Question tool call:
|
||||
1. Which council members to consult
|
||||
2. How council members should analyze (solo vs. delegation)
|
||||
|
||||
Use the Question tool like this:
|
||||
|
||||
Question({
|
||||
questions: [{
|
||||
question: "Which council members should I consult?",
|
||||
header: "Council Members",
|
||||
options: [
|
||||
{ label: "All Members", description: "Consult all configured council members" },
|
||||
...one option per member from your available council members listed below
|
||||
],
|
||||
multiple: true
|
||||
}]
|
||||
questions: [
|
||||
{
|
||||
question: "Which council members should I consult?",
|
||||
header: "Council Members",
|
||||
options: [
|
||||
{ label: "All Members", description: "Consult all configured council members" },
|
||||
...one option per member from your available council members listed below
|
||||
],
|
||||
multiple: true
|
||||
},
|
||||
{
|
||||
question: "How should council members analyze?",
|
||||
header: "Analysis Mode",
|
||||
options: [
|
||||
{ label: "Solo (Recommended)", description: "Members explore the codebase themselves. More thorough and in-depth, but slower and uses more tokens." },
|
||||
{ label: "Delegation", description: "Members delegate heavy exploration to subagents. Faster and lighter on context, but may miss nuance." }
|
||||
],
|
||||
multiple: false
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
**Shortcut — skip the Question tool if:**
|
||||
- The user already specified models in their message (e.g., "ask GPT and Claude about X") → launch the specified members directly.
|
||||
- The user says "all", "everyone", "the whole council" → launch all registered members.
|
||||
Map the analysis mode answer to the prepare_council_prompt "mode" parameter:
|
||||
- "Solo (Recommended)" → mode: "solo"
|
||||
- "Delegation" → mode: "delegation"
|
||||
|
||||
**Non-interactive mode (Question tool unavailable):** If the Question tool is denied (CLI run mode), automatically select ALL registered council members and launch them. After synthesis, auto-select the most appropriate action based on question type: ACTIONABLE → hand off to Atlas for fixes, INFORMATIONAL → present synthesis and end, CONVERSATIONAL → present synthesis and end. Do NOT attempt to call the Question tool — it will be denied.
|
||||
**Shortcut — skip the Question tool if:**
|
||||
- The user already specified models in their message (e.g., "ask GPT and Claude about X") → launch the specified members directly. Still ask the analysis mode question unless specified.
|
||||
- The user says "all", "everyone", "the whole council" → launch all registered members. Still ask the analysis mode question unless specified.
|
||||
|
||||
**Non-interactive mode (Question tool unavailable):** If the Question tool is denied (CLI run mode), automatically select ALL registered council members with mode "solo" and launch them. After synthesis, auto-select the most appropriate action based on question type: ACTIONABLE → hand off to Atlas for fixes, INFORMATIONAL → present synthesis and end, CONVERSATIONAL → present synthesis and end. Do NOT attempt to call the Question tool — it will be denied.
|
||||
|
||||
DO NOT:
|
||||
- Read files yourself
|
||||
@@ -75,7 +92,7 @@ Step 2: Resolve the selected member list:
|
||||
|
||||
Step 3: Save the prompt, then launch members with short references:
|
||||
|
||||
Step 3a: Call prepare_council_prompt with the user's original question as the prompt parameter. This saves it to a temp file and returns the file path.
|
||||
Step 3a: Call prepare_council_prompt with the user's original question as the prompt parameter and the selected analysis mode. This saves it to a temp file and returns the file path. Example: prepare_council_prompt({ prompt: "...", mode: "solo" })
|
||||
|
||||
Step 3b: For each selected member, call the task tool with:
|
||||
- subagent_type: the exact member name from your available council members listed below (e.g., "Council: Claude Opus 4.6")
|
||||
|
||||
@@ -22,10 +22,26 @@ export const COUNCIL_MEMBER_PROMPT = `You are an independent code analyst in a m
|
||||
- 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`
|
||||
5. Be concise but thorough — quality over quantity
|
||||
|
||||
## CRITICAL: Do NOT use TodoWrite
|
||||
- Do NOT create todos or task lists
|
||||
- Do NOT use the TodoWrite tool under any circumstances
|
||||
- Simply report your findings directly in your response`
|
||||
|
||||
export const COUNCIL_DELEGATION_ADDENDUM = `
|
||||
## Delegation Mode
|
||||
You can delegate heavy exploration to specialized agents using call_omo_agent:
|
||||
- Use \`call_omo_agent(subagent_type="explore", ...)\` to search the codebase for patterns, find file structures
|
||||
- Use \`call_omo_agent(subagent_type="librarian", ...)\` for documentation lookups and external references
|
||||
- Always set \`run_in_background=true\` and collect results with \`background_output\`
|
||||
- Delegate broad searches, keep targeted reads for yourself
|
||||
- This saves your context window for analysis rather than exploration`
|
||||
|
||||
export function createCouncilMemberAgent(model: string): AgentConfig {
|
||||
// Allow-list: only read-only analysis tools. Everything else is denied via `*: deny`.
|
||||
// Allow-list: only read-only analysis tools + optional delegation.
|
||||
// Everything else is denied via `*: deny`.
|
||||
// TodoWrite/TodoRead explicitly denied to prevent uncompletable todo loops.
|
||||
const restrictions = createAgentToolAllowlist([
|
||||
"read",
|
||||
"grep",
|
||||
@@ -35,8 +51,14 @@ export function createCouncilMemberAgent(model: string): AgentConfig {
|
||||
"lsp_symbols",
|
||||
"lsp_diagnostics",
|
||||
"ast_grep_search",
|
||||
"call_omo_agent",
|
||||
])
|
||||
|
||||
// Explicitly deny TodoWrite/TodoRead even though `*: deny` should catch them.
|
||||
// Built-in OpenCode tools may bypass the wildcard deny.
|
||||
restrictions.permission.todowrite = "deny"
|
||||
restrictions.permission.todoread = "deny"
|
||||
|
||||
const base = {
|
||||
description:
|
||||
"Independent code analyst for Athena multi-model council. Read-only, evidence-based analysis. (Council Member - OhMyOpenCode)",
|
||||
|
||||
Reference in New Issue
Block a user