diff --git a/src/agents/athena/council-intent-addendums.ts b/src/agents/athena/council-intent-addendums.ts index 83e767a9c..01aef7b0c 100644 --- a/src/agents/athena/council-intent-addendums.ts +++ b/src/agents/athena/council-intent-addendums.ts @@ -1,4 +1,57 @@ export const COUNCIL_INTENT_ADDENDUMS: Record = { + DIAGNOSE: ` +## Analysis Intent: DIAGNOSE + +You are conducting a **diagnosis** — your goal is to trace an observed problem back to its root cause through systematic investigation. + +**Focus:** +- Start from the reported symptom — what is actually observed vs. what is expected? +- Form hypotheses about potential causes, ordered by likelihood +- For each hypothesis, gather concrete evidence that confirms or eliminates it +- Follow the causal chain backward: symptom ← immediate cause ← deeper cause ← root cause +- Distinguish the root cause from contributing factors and coincidental observations +- Propose a fix that addresses the root cause, not just the symptom +- You are NOT scanning broadly for issues — you are investigating a specific problem + +**Required output fields:** +- Symptom (observed vs. expected), Hypotheses investigated (with evidence for/against each) +- Root cause (with causal chain and confidence), Contributing factors +- Recommended fix (targeting root cause, with verification approach) + +**Structure your response as:** +\`\`\` + +## Symptom +[What is happening vs. what should be happening] + +## Investigation +### Hypothesis 1: [description] +- **Likelihood**: high/medium/low +- **Evidence for**: [what supports this hypothesis] +- **Evidence against**: [what contradicts it] +- **Verdict**: confirmed / eliminated / inconclusive + +### Hypothesis 2: [description] +... + +## Root Cause +- **What**: [the root cause, stated in one clear sentence] +- **Causal Chain**: [symptom] ← [immediate cause] ← [root cause] +- **Confidence**: high/medium/low +- **Key Evidence**: [the specific evidence that pinpoints this as the root cause] + +## Contributing Factors +- [Conditions that aren't the root cause but make the problem worse or more frequent] + +## Recommended Fix +- **Target**: [what specifically to change] +- **Verification**: [how to confirm the symptom is resolved] + +## Summary +[One-paragraph diagnosis with overall confidence level] + +\`\`\``, + AUDIT: ` ## Analysis Intent: AUDIT @@ -10,6 +63,7 @@ You are conducting an **audit** — your goal is to find discrete issues, risks, - Severity determines priority: critical (blocks/breaks), high (significant risk), medium (should fix), low (nice to fix) - For each finding, provide the specific location (reference, section, or component where it occurs) - State your confidence: high (clear evidence), medium (likely but needs verification), low (suspicion, investigate further) +- **This is a broad sweep, not a targeted trace.** If you are starting from a specific symptom and need to find its root cause, that is DIAGNOSE — not AUDIT. **Required output fields per finding:** - Title, Severity (critical/high/medium/low), Location, Confidence (high/medium/low) @@ -32,47 +86,6 @@ You are conducting an **audit** — your goal is to find discrete issues, risks, ## Summary [Total findings by severity. Overall risk assessment with confidence levels.] -\`\`\``, - - EVALUATE: ` -## Analysis Intent: EVALUATE - -You are conducting an **evaluation** — your goal is to compare options against criteria and surface tradeoffs. - -**Focus:** -- Identify the options available (explicit or implied by the question) -- Define evaluation criteria relevant to the context (cost, complexity, performance, maintainability, risk, etc.) -- Assess each option against each criterion with evidence, not assumptions -- Surface tradeoffs clearly — where one option wins, another likely loses -- If the question implies a recommendation is needed, provide one with conditions - -**Required output fields:** -- Options identified, Criteria used, Per-option assessment, Tradeoff summary -- Conditional recommendation (if decision is required), Confidence per assessment - -**Structure your response as:** -\`\`\` - -## Options Identified -1. [Option A] — [brief description] -2. [Option B] — [brief description] - -## Criteria & Assessment -| Criterion | Option A | Option B | -|-----------|----------|----------| -| [e.g. Complexity] | [assessment] | [assessment] | - -## Tradeoff Summary -- Option A excels at [X] but sacrifices [Y] -- Option B excels at [Y] but sacrifices [X] - -## Recommendation -[If applicable: "Choose A if [condition]; choose B if [condition]"] -- **Confidence**: [level and reasoning] - -## Risks & Unknowns -[Uncertainties that could change the recommendation] - \`\`\``, PLAN: ` @@ -118,6 +131,47 @@ You are conducting a **planning analysis** — your goal is to define current st ## Summary [Overall effort assessment, key risks, confidence in feasibility] +\`\`\``, + + EVALUATE: ` +## Analysis Intent: EVALUATE + +You are conducting an **evaluation** — your goal is to compare options against criteria and surface tradeoffs. + +**Focus:** +- Identify the options available (explicit or implied by the question) +- Define evaluation criteria relevant to the specific decision context (not generic checklists — choose criteria that actually differentiate the options) +- Assess each option against each criterion with evidence, not assumptions +- Surface tradeoffs clearly — where one option wins, another likely loses +- If the question implies a recommendation is needed, provide one with conditions + +**Required output fields:** +- Options identified, Criteria used, Per-option assessment, Tradeoff summary +- Conditional recommendation (if decision is required), Confidence per assessment + +**Structure your response as:** +\`\`\` + +## Options Identified +1. [Option A] — [brief description] +2. [Option B] — [brief description] + +## Criteria & Assessment +| Criterion | Option A | Option B | +|-----------|----------|----------| +| [e.g. Complexity] | [assessment] | [assessment] | + +## Tradeoff Summary +- Option A excels at [X] but sacrifices [Y] +- Option B excels at [Y] but sacrifices [X] + +## Recommendation +[If applicable: "Choose A if [condition]; choose B if [condition]"] +- **Confidence**: [level and reasoning] + +## Risks & Unknowns +[Uncertainties that could change the recommendation] + \`\`\``, EXPLAIN: ` @@ -131,7 +185,9 @@ You are conducting an **explanatory analysis** — your goal is to build underst - Provide evidence and references for each mechanism (not just assertions) - Map relationships, data flows, or causal chains between components - Acknowledge unknowns, gaps in evidence, and areas of uncertainty -- Works for any domain: architecture, external systems, abstract concepts, research topics + +**Use this intent for:** "how does X work", "explain Y", "what is Z", "why does this exist", "describe the architecture of..." questions. +**This is NOT a catch-all.** If the question doesn't fit this focus, it likely belongs in FREEFORM. **Required output fields:** - Thesis statement, Key mechanisms/components (with evidence) @@ -163,5 +219,87 @@ You are conducting an **explanatory analysis** — your goal is to build underst ## Summary [Synthesized explanation with overall confidence level] +\`\`\``, + + CREATE: ` +## Analysis Intent: CREATE + +You are here to **produce something** — not to analyze, evaluate, or plan it. + +**Focus:** +- Produce the actual deliverable directly — code, prose, design, spec, whatever was asked for +- Let the deliverable type dictate its own natural structure +- Write at a professional level, as if this will be used directly +- Be thorough and complete — a finished piece beats a polished fragment +- Make creative choices decisively; note significant ones briefly at the end + +**You are not an analyst right now. Stop analyzing. Start making.** + +Do not produce a findings report. Do not produce a severity matrix. Do not produce an options comparison. Produce the thing that was asked for. + +**Structure your response as:** +\`\`\` + +[Your complete deliverable. Structure it however is natural for what you're creating. There is no prescribed internal format.] + +--- +*Choices: [Optional — only if significant decisions aren't self-evident]* + +\`\`\``, + + PERSPECTIVES: ` +## Analysis Intent: PERSPECTIVES + +You are **surfacing genuine viewpoints and taking a stand** — your goal is to map the intellectual landscape, then declare where you land. + +**Focus:** +- Identify 2-4 perspectives that are genuinely held — real positions, not straw men +- Argue each perspective at its strongest — as if you believed it +- Identify the crux: what assumption must be true for each position to be right? +- After presenting perspectives, declare YOUR position and defend it +- Name what you're giving up by not choosing another perspective + +**Neutral summaries are failure.** If you find every perspective equally valid, you have not thought hard enough. Take a position. + +**Required output fields:** +- 2-4 named perspectives (each: position, evidence, crux) +- Core tensions between perspectives +- Your declared position with reasoning and confidence + +**Structure your response as:** +\`\`\` + +## Perspective 1: [Name/Label] +- **Position**: [what this perspective argues — be precise] +- **Strongest evidence**: [why a thoughtful person holds this view] +- **What it gets right**: [genuine strengths, honestly stated] +- **Crux**: [what assumption must be true for this to be right] + +## Perspective 2: [Name/Label] +... + +## Core Tensions +[Where these perspectives actually collide — incompatible assumptions or values] + +## My Position +[Which view you find most defensible. Be direct. Name the cost — what you're giving up or what remains uncertain even given your stance.] +- **Confidence**: high/medium/low +- **What would change my mind**: [specific conditions or evidence] + +\`\`\``, + + FREEFORM: ` +## Analysis Intent: FREEFORM + +Respond naturally to the question below. No analytical framework is imposed. + +Use whatever structure serves the answer best. Analyze if analysis helps. Answer directly if a direct answer is better. Be conversational if the question is conversational. + +You MUST still wrap your response in \`\` tags for extraction. + +\`\`\` + +[Your response — structured however is most appropriate for the question] + \`\`\``, } diff --git a/src/tools/prepare-council-prompt/tools.test.ts b/src/tools/prepare-council-prompt/tools.test.ts index 3e5f07ad2..40b6dfb0a 100644 --- a/src/tools/prepare-council-prompt/tools.test.ts +++ b/src/tools/prepare-council-prompt/tools.test.ts @@ -75,16 +75,65 @@ describe("createPrepareCouncilPromptTool", () => { }) }) + describe("#when called with intent DIAGNOSE", () => { + it("#then produces file containing DIAGNOSE addendum", async () => { + tmpDir = await mkdtemp(join(tmpdir(), "council-test-")) + const toolDef = createPrepareCouncilPromptTool(tmpDir) + const result = await toolDef.execute({ prompt: "Why is the API returning 500 errors?", intent: "DIAGNOSE" }, mockContext) + + const filePath = extractFilePath(result) + const content = await readFile(filePath, "utf-8") + expect(content).toContain("## Analysis Intent: DIAGNOSE") + }) + }) + + describe("#when called with intent CREATE", () => { + it("#then produces file containing CREATE addendum", async () => { + tmpDir = await mkdtemp(join(tmpdir(), "council-test-")) + const toolDef = createPrepareCouncilPromptTool(tmpDir) + const result = await toolDef.execute({ prompt: "Write a poem about TypeScript", intent: "CREATE" }, mockContext) + + const filePath = extractFilePath(result) + const content = await readFile(filePath, "utf-8") + expect(content).toContain("## Analysis Intent: CREATE") + }) + }) + + describe("#when called with intent PERSPECTIVES", () => { + it("#then produces file containing PERSPECTIVES addendum", async () => { + tmpDir = await mkdtemp(join(tmpdir(), "council-test-")) + const toolDef = createPrepareCouncilPromptTool(tmpDir) + const result = await toolDef.execute({ prompt: "What do you think about microservices?", intent: "PERSPECTIVES" }, mockContext) + + const filePath = extractFilePath(result) + const content = await readFile(filePath, "utf-8") + expect(content).toContain("## Analysis Intent: PERSPECTIVES") + }) + }) + + describe("#when called with intent FREEFORM", () => { + it("#then produces file containing FREEFORM addendum", async () => { + tmpDir = await mkdtemp(join(tmpdir(), "council-test-")) + const toolDef = createPrepareCouncilPromptTool(tmpDir) + const result = await toolDef.execute({ prompt: "Tell me something interesting", intent: "FREEFORM" }, mockContext) + + const filePath = extractFilePath(result) + const content = await readFile(filePath, "utf-8") + expect(content).toContain("## Analysis Intent: FREEFORM") + }) + }) + describe("#when called without intent", () => { - it("#then defaults to AUDIT addendum", async () => { + it("#then produces file without any intent addendum", async () => { tmpDir = await mkdtemp(join(tmpdir(), "council-test-")) const toolDef = createPrepareCouncilPromptTool(tmpDir) const result = await toolDef.execute({ prompt: "Review this module" }, mockContext) - expect(result).toContain("intent: AUDIT") + expect(result).toContain("intent: none") const filePath = extractFilePath(result) const content = await readFile(filePath, "utf-8") - expect(content).toContain("## Analysis Intent: AUDIT") + expect(content).not.toContain("## Analysis Intent:") + expect(content).toContain("## Analysis Question") }) }) diff --git a/src/tools/prepare-council-prompt/tools.ts b/src/tools/prepare-council-prompt/tools.ts index fd6ae0753..b0be30c18 100644 --- a/src/tools/prepare-council-prompt/tools.ts +++ b/src/tools/prepare-council-prompt/tools.ts @@ -45,10 +45,16 @@ The "mode" parameter controls whether council members can delegate exploration t - "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. +- "DIAGNOSE": Trace a specific problem to its root cause through systematic investigation. +- "AUDIT": Find issues, risks, violations with severity ratings (broad sweep). - "PLAN": Define current state, target state, phased path. +- "EVALUATE": Compare options against criteria, surface tradeoffs. - "EXPLAIN": Build understanding of mechanisms and relationships. +- "CREATE": Produce a deliverable directly (code, prose, design, spec). +- "PERSPECTIVES": Surface genuine viewpoints, argue each at its strongest, take a position. +- "FREEFORM": No analytical framework imposed — respond naturally. + +If no intent is specified, no analysis framework is injected. Returns the file path to reference in subsequent task() calls.` @@ -61,7 +67,7 @@ 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"'), + intent: tool.schema.string().optional().describe('Question intent: "DIAGNOSE", "AUDIT", "PLAN", "EVALUATE", "EXPLAIN", "CREATE", "PERSPECTIVES", "FREEFORM"'), }, async execute(args: { prompt: string; mode?: string; intent?: string }) { if (!args.prompt?.trim()) { @@ -72,12 +78,12 @@ 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"] + const validIntents = Object.keys(COUNCIL_INTENT_ADDENDUMS) if (args.intent !== undefined && !validIntents.includes(args.intent.toUpperCase())) { - return `Invalid intent: "${args.intent}". Valid intents: "AUDIT", "EVALUATE", "PLAN", "EXPLAIN".` + return `Invalid intent: "${args.intent}". Valid intents: ${validIntents.map((i) => `"${i}"`).join(", ")}.` } - const resolvedIntent = args.intent?.toUpperCase() ?? "AUDIT" + const resolvedIntent = args.intent?.toUpperCase() const mode = args.mode === "delegation" ? "delegation" : "solo" @@ -89,14 +95,10 @@ 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}` + const intentAddendum = resolvedIntent ? (COUNCIL_INTENT_ADDENDUMS[resolvedIntent] ?? "") : "" + const content = intentAddendum + ? `${modeAddendum}\n\n${intentAddendum}\n\n## Analysis Question\n\n${args.prompt}` + : `${modeAddendum}\n\n## Analysis Question\n\n${args.prompt}` await writeFile(filePath, content, "utf-8") @@ -108,7 +110,7 @@ ${args.prompt}` log("[prepare-council-prompt] Saved prompt", { filePath, length: args.prompt.length, mode }) - return `Council prompt saved to: ${filePath} (mode: ${mode}, intent: ${resolvedIntent}) + return `Council prompt saved to: ${filePath} (mode: ${mode}, intent: ${resolvedIntent ?? "none"}) Use this path in each council member's task() call: - prompt: "Read ${filePath} for your instructions."