feat(athena): add prepare_council_prompt tool for faster council launches
Athena saves the analysis prompt to a temp file once, then launches each council member with a short "Read <path> for your instructions" prompt. This eliminates repeated prompt text across N task calls while preserving individual clickable task panes in the TUI.
This commit is contained in:
parent
f9bb441644
commit
3fecc7baae
@ -35,7 +35,7 @@ Agent factories following `createXXXAgent(model) → AgentConfig` pattern. Each
|
|||||||
| Atlas | task, call_omo_agent |
|
| Atlas | task, call_omo_agent |
|
||||||
| Momus | write, edit, task |
|
| Momus | write, edit, task |
|
||||||
| Athena | write, edit, call_omo_agent |
|
| Athena | write, edit, call_omo_agent |
|
||||||
| Council-Member | write, edit, task, call_omo_agent, switch_agent, background_wait |
|
| Council-Member | write, edit, task, call_omo_agent, switch_agent, background_wait, prepare_council_prompt |
|
||||||
|
|
||||||
## STRUCTURE
|
## STRUCTURE
|
||||||
|
|
||||||
|
|||||||
@ -73,14 +73,17 @@ Step 2: Resolve the selected member list:
|
|||||||
- If user selected "All Members", resolve to every member from your available council members listed below.
|
- If user selected "All Members", resolve to every member from your available council members listed below.
|
||||||
- Otherwise resolve to the explicitly selected member labels.
|
- Otherwise resolve to the explicitly selected member labels.
|
||||||
|
|
||||||
Step 3: Launch each selected member via the task tool with run_in_background=true:
|
Step 3: Save the prompt, then launch members with short references:
|
||||||
- For each selected member, call the task tool with:
|
|
||||||
|
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 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")
|
- subagent_type: the exact member name from your available council members listed below (e.g., "Council: Claude Opus 4.6")
|
||||||
- run_in_background: true
|
- run_in_background: true
|
||||||
- prompt: the user's original question
|
- prompt: "Read <path> for your instructions." (where <path> is the file path from Step 3a)
|
||||||
- load_skills: []
|
- load_skills: []
|
||||||
- description: the member name (e.g., "Council: Claude Opus 4.6")
|
- description: the member name (e.g., "Council: Claude Opus 4.6")
|
||||||
- Launch ALL selected members FIRST (one task call per member, all in parallel) before collecting any results.
|
- Launch ALL selected members before collecting any results.
|
||||||
- Track every returned task_id and member mapping.
|
- Track every returned task_id and member mapping.
|
||||||
- IMPORTANT: Use EXACTLY the subagent_type names listed in your available council members below — they must match precisely.
|
- IMPORTANT: Use EXACTLY the subagent_type names listed in your available council members below — they must match precisely.
|
||||||
|
|
||||||
|
|||||||
@ -32,6 +32,7 @@ export function createCouncilMemberAgent(model: string): AgentConfig {
|
|||||||
"call_omo_agent",
|
"call_omo_agent",
|
||||||
"switch_agent",
|
"switch_agent",
|
||||||
"background_wait",
|
"background_wait",
|
||||||
|
"prepare_council_prompt",
|
||||||
])
|
])
|
||||||
|
|
||||||
const base = {
|
const base = {
|
||||||
|
|||||||
@ -26,6 +26,7 @@ export function applyToolConfig(params: {
|
|||||||
LspCodeActionResolve: false,
|
LspCodeActionResolve: false,
|
||||||
"task_*": false,
|
"task_*": false,
|
||||||
teammate: false,
|
teammate: false,
|
||||||
|
prepare_council_prompt: false,
|
||||||
...(params.pluginConfig.experimental?.task_system
|
...(params.pluginConfig.experimental?.task_system
|
||||||
? { todowrite: false, todoread: false }
|
? { todowrite: false, todoread: false }
|
||||||
: {}),
|
: {}),
|
||||||
@ -106,6 +107,7 @@ export function applyToolConfig(params: {
|
|||||||
athena.permission = {
|
athena.permission = {
|
||||||
...athena.permission,
|
...athena.permission,
|
||||||
task: "allow",
|
task: "allow",
|
||||||
|
prepare_council_prompt: "allow",
|
||||||
question: questionPermission,
|
question: questionPermission,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import {
|
|||||||
createTaskList,
|
createTaskList,
|
||||||
createTaskUpdateTool,
|
createTaskUpdateTool,
|
||||||
createHashlineEditTool,
|
createHashlineEditTool,
|
||||||
|
createPrepareCouncilPromptTool,
|
||||||
} from "../tools"
|
} from "../tools"
|
||||||
import { getMainSessionID } from "../features/claude-code-session-state"
|
import { getMainSessionID } from "../features/claude-code-session-state"
|
||||||
import { filterDisabledTools } from "../shared/disabled-tools"
|
import { filterDisabledTools } from "../shared/disabled-tools"
|
||||||
@ -138,6 +139,7 @@ export function createToolRegistry(args: {
|
|||||||
interactive_bash,
|
interactive_bash,
|
||||||
...taskToolsRecord,
|
...taskToolsRecord,
|
||||||
...hashlineToolsRecord,
|
...hashlineToolsRecord,
|
||||||
|
prepare_council_prompt: createPrepareCouncilPromptTool(),
|
||||||
}
|
}
|
||||||
|
|
||||||
const filteredTools = filterDisabledTools(allTools, pluginConfig.disabled_tools)
|
const filteredTools = filterDisabledTools(allTools, pluginConfig.disabled_tools)
|
||||||
|
|||||||
@ -63,6 +63,7 @@ const AGENT_RESTRICTIONS: Record<string, Record<string, boolean>> = {
|
|||||||
call_omo_agent: false,
|
call_omo_agent: false,
|
||||||
switch_agent: false,
|
switch_agent: false,
|
||||||
background_wait: false,
|
background_wait: false,
|
||||||
|
prepare_council_prompt: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -46,6 +46,7 @@ export {
|
|||||||
createTaskUpdateTool,
|
createTaskUpdateTool,
|
||||||
} from "./task"
|
} from "./task"
|
||||||
export { createHashlineEditTool } from "./hashline-edit"
|
export { createHashlineEditTool } from "./hashline-edit"
|
||||||
|
export { createPrepareCouncilPromptTool } from "./prepare-council-prompt"
|
||||||
|
|
||||||
export function createBackgroundTools(manager: BackgroundManager, client: OpencodeClient): Record<string, ToolDefinition> {
|
export function createBackgroundTools(manager: BackgroundManager, client: OpencodeClient): Record<string, ToolDefinition> {
|
||||||
const outputManager: BackgroundOutputManager = manager
|
const outputManager: BackgroundOutputManager = manager
|
||||||
|
|||||||
1
src/tools/prepare-council-prompt/index.ts
Normal file
1
src/tools/prepare-council-prompt/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { createPrepareCouncilPromptTool } from "./tools"
|
||||||
47
src/tools/prepare-council-prompt/tools.ts
Normal file
47
src/tools/prepare-council-prompt/tools.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { tool, type ToolDefinition } from "@opencode-ai/plugin"
|
||||||
|
import { writeFile, unlink } from "node:fs/promises"
|
||||||
|
import { join } from "node:path"
|
||||||
|
import { tmpdir } from "node:os"
|
||||||
|
import { log } from "../../shared/logger"
|
||||||
|
|
||||||
|
const CLEANUP_DELAY_MS = 30 * 60 * 1000
|
||||||
|
|
||||||
|
export function createPrepareCouncilPromptTool(): ToolDefinition {
|
||||||
|
const description = `Save a council analysis prompt to a temp file so council members can read it.
|
||||||
|
|
||||||
|
Athena-only tool. Saves the prompt once, then each council member task() call uses a short
|
||||||
|
"Read <path>" instruction instead of repeating the full question. This keeps task() calls
|
||||||
|
fast and small.
|
||||||
|
|
||||||
|
Returns the file path to reference in subsequent task() calls.`
|
||||||
|
|
||||||
|
return tool({
|
||||||
|
description,
|
||||||
|
args: {
|
||||||
|
prompt: tool.schema.string().describe("The full analysis prompt/question for council members"),
|
||||||
|
},
|
||||||
|
async execute(args: { prompt: string }) {
|
||||||
|
if (!args.prompt?.trim()) {
|
||||||
|
return "Prompt cannot be empty."
|
||||||
|
}
|
||||||
|
|
||||||
|
const filename = `athena-council-${crypto.randomUUID().slice(0, 8)}.md`
|
||||||
|
const filePath = join(tmpdir(), filename)
|
||||||
|
|
||||||
|
await writeFile(filePath, args.prompt, "utf-8")
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
unlink(filePath).catch(() => {})
|
||||||
|
}, CLEANUP_DELAY_MS)
|
||||||
|
|
||||||
|
log("[prepare-council-prompt] Saved prompt", { filePath, length: args.prompt.length })
|
||||||
|
|
||||||
|
return `Council prompt saved to: ${filePath}
|
||||||
|
|
||||||
|
Use this path in each council member's task() call:
|
||||||
|
- prompt: "Read ${filePath} for your instructions."
|
||||||
|
|
||||||
|
The file auto-deletes after 30 minutes.`
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user