diff --git a/src/agents/athena/index.ts b/src/agents/athena/index.ts index dd75da507..6d812c3b5 100644 --- a/src/agents/athena/index.ts +++ b/src/agents/athena/index.ts @@ -1,2 +1,3 @@ export { createAthenaAgent, ATHENA_PROMPT_METADATA } from "./agent" export { createCouncilMemberAgent, COUNCIL_MEMBER_PROMPT, COUNCIL_SOLO_ADDENDUM, COUNCIL_DELEGATION_ADDENDUM } from "./council-member-agent" +export { COUNCIL_INTENT_ADDENDUMS } from "./council-intent-addendums" diff --git a/src/config/schema/hooks.ts b/src/config/schema/hooks.ts index 4121493a3..16f4e3c15 100644 --- a/src/config/schema/hooks.ts +++ b/src/config/schema/hooks.ts @@ -37,6 +37,7 @@ export const HookNameSchema = z.enum([ "json-error-recovery", "delegate-task-retry", "prometheus-md-only", + "athena-sisyphus-only", "sisyphus-junior-notepad", "no-sisyphus-gpt", "no-hephaestus-non-gpt", diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 1b3f39c9e..7b692c3b9 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -35,6 +35,7 @@ export { createAutoSlashCommandHook } from "./auto-slash-command"; export { createEditErrorRecoveryHook } from "./edit-error-recovery"; export { createPrometheusMdOnlyHook } from "./prometheus-md-only"; +export { createAthenaSisyphusOnlyHook } from "./athena-sisyphus-only"; export { createSisyphusJuniorNotepadHook } from "./sisyphus-junior-notepad"; export { createTaskResumeInfoHook } from "./task-resume-info"; export { createStartWorkHook } from "./start-work"; diff --git a/src/plugin/hooks/create-session-hooks.ts b/src/plugin/hooks/create-session-hooks.ts index af87bd366..a5343e0ac 100644 --- a/src/plugin/hooks/create-session-hooks.ts +++ b/src/plugin/hooks/create-session-hooks.ts @@ -19,6 +19,7 @@ import { createTaskResumeInfoHook, createStartWorkHook, createPrometheusMdOnlyHook, + createAthenaSisyphusOnlyHook, createSisyphusJuniorNotepadHook, createNoSisyphusGptHook, createNoHephaestusNonGptHook, @@ -55,6 +56,7 @@ export type SessionHooks = { delegateTaskRetry: ReturnType | null startWork: ReturnType | null prometheusMdOnly: ReturnType | null + athenaSisyphusOnly: ReturnType | null sisyphusJuniorNotepad: ReturnType | null noSisyphusGpt: ReturnType | null noHephaestusNonGpt: ReturnType | null @@ -227,6 +229,9 @@ export function createSessionHooks(args: { ? safeHook("prometheus-md-only", () => createPrometheusMdOnlyHook(ctx)) : null + const athenaSisyphusOnly = isHookEnabled("athena-sisyphus-only") + ? safeHook("athena-sisyphus-only", () => createAthenaSisyphusOnlyHook(ctx)) + : null const sisyphusJuniorNotepad = isHookEnabled("sisyphus-junior-notepad") ? safeHook("sisyphus-junior-notepad", () => createSisyphusJuniorNotepadHook(ctx)) : null @@ -287,6 +292,7 @@ export function createSessionHooks(args: { delegateTaskRetry, startWork, prometheusMdOnly, + athenaSisyphusOnly, sisyphusJuniorNotepad, noSisyphusGpt, noHephaestusNonGpt, diff --git a/src/plugin/tool-execute-before.ts b/src/plugin/tool-execute-before.ts index 1c36ae167..1ccc0906c 100644 --- a/src/plugin/tool-execute-before.ts +++ b/src/plugin/tool-execute-before.ts @@ -104,6 +104,7 @@ export function createToolExecuteBeforeHandler(args: { await hooks.tasksTodowriteDisabler?.["tool.execute.before"]?.(input, output) await hooks.webfetchRedirectGuard?.["tool.execute.before"]?.(input, output) await hooks.prometheusMdOnly?.["tool.execute.before"]?.(input, output) + await hooks.athenaSisyphusOnly?.["tool.execute.before"]?.(input, output) await hooks.sisyphusJuniorNotepad?.["tool.execute.before"]?.(input, output) await hooks.atlasHook?.["tool.execute.before"]?.(input, output) diff --git a/src/tools/prepare-council-prompt/tools.ts b/src/tools/prepare-council-prompt/tools.ts index 4347cd190..fd6ae0753 100644 --- a/src/tools/prepare-council-prompt/tools.ts +++ b/src/tools/prepare-council-prompt/tools.ts @@ -3,7 +3,7 @@ import { randomUUID } from "node:crypto" import { writeFile, unlink, mkdir, readdir, stat } from "node:fs/promises" import { join } from "node:path" import { log } from "../../shared/logger" -import { COUNCIL_SOLO_ADDENDUM, COUNCIL_DELEGATION_ADDENDUM } from "../../agents/athena" +import { COUNCIL_SOLO_ADDENDUM, COUNCIL_DELEGATION_ADDENDUM, COUNCIL_INTENT_ADDENDUMS } from "../../agents/athena" const CLEANUP_DELAY_MS = 30 * 60 * 1000 const COUNCIL_TMP_DIR = ".sisyphus/tmp" @@ -44,6 +44,12 @@ The "mode" parameter controls whether council members can delegate exploration t - "solo" (default): Members do all exploration themselves. More thorough but uses more tokens. - "delegation": Members can delegate to explore/librarian agents. Faster, lighter context. +The "intent" parameter controls the analysis framework injected into the prompt: +- "AUDIT" (default): Find issues, risks, violations with severity ratings. +- "EVALUATE": Compare options against criteria, surface tradeoffs. +- "PLAN": Define current state, target state, phased path. +- "EXPLAIN": Build understanding of mechanisms and relationships. + Returns the file path to reference in subsequent task() calls.` cleanupStaleTempFiles(directory).catch((err) => { @@ -55,8 +61,9 @@ Returns the file path to reference in subsequent task() calls.` args: { prompt: tool.schema.string().describe("The full analysis prompt/question for council members"), mode: tool.schema.string().optional().describe('Analysis mode: "solo" (default) or "delegation"'), + intent: tool.schema.string().optional().describe('Question intent: "AUDIT", "EVALUATE", "PLAN", "EXPLAIN"'), }, - async execute(args: { prompt: string; mode?: string }) { + async execute(args: { prompt: string; mode?: string; intent?: string }) { if (!args.prompt?.trim()) { return "Prompt cannot be empty." } @@ -65,6 +72,13 @@ Returns the file path to reference in subsequent task() calls.` return `Invalid mode: "${args.mode}". Valid modes: "solo", "delegation".` } + const validIntents = ["AUDIT", "EVALUATE", "PLAN", "EXPLAIN"] + if (args.intent !== undefined && !validIntents.includes(args.intent.toUpperCase())) { + return `Invalid intent: "${args.intent}". Valid intents: "AUDIT", "EVALUATE", "PLAN", "EXPLAIN".` + } + + const resolvedIntent = args.intent?.toUpperCase() ?? "AUDIT" + const mode = args.mode === "delegation" ? "delegation" : "solo" try { @@ -75,8 +89,11 @@ Returns the file path to reference in subsequent task() calls.` const filePath = join(tmpDir, filename) const modeAddendum = mode === "delegation" ? COUNCIL_DELEGATION_ADDENDUM : COUNCIL_SOLO_ADDENDUM + const intentAddendum = COUNCIL_INTENT_ADDENDUMS[resolvedIntent] ?? COUNCIL_INTENT_ADDENDUMS["AUDIT"] const content = `${modeAddendum} +${intentAddendum} + ## Analysis Question ${args.prompt}` @@ -91,7 +108,7 @@ ${args.prompt}` log("[prepare-council-prompt] Saved prompt", { filePath, length: args.prompt.length, mode }) - return `Council prompt saved to: ${filePath} (mode: ${mode}) + return `Council prompt saved to: ${filePath} (mode: ${mode}, intent: ${resolvedIntent}) Use this path in each council member's task() call: - prompt: "Read ${filePath} for your instructions."