fix(athena): implement 10 prompt audit fixes from council review

- Fix 1: Clarify 'restart at Step 3' → 'restart the council workflow from Step 3 (intent classification)'
- Fix 2: Replace {council-session-name} with static references to council_finalize archive_dir
- Fix 3: Add documenting comment for call_omo_agent in solo mode allowlist
- Fix 4: Add delegation agent rationale comment to RUNTIME_GUIDANCE_BY_INTENT
- Fix 5: Type-safe COUNCIL_INTENT_ADDENDUMS with Record<CouncilIntent, string>
- Fix 6: Clarify FREEFORM wording re COUNCIL_MEMBER_RESPONSE tag requirement
- Fix 7: Remove dead Step 15 fallback from agent.ts
- Fix 8: Add compound question intent precedence guidance
- Fix 9: Fix AUDIT double-period typo
- Fix 10: Add edge case test for extractCouncilResponse with literal tag text
This commit is contained in:
ismeth
2026-03-01 02:52:42 +01:00
committed by YeonGyu-Kim
parent c265200f5f
commit 227a59a796
6 changed files with 56 additions and 26 deletions
@@ -44,7 +44,6 @@ describe("Athena prompt config injection placeholders", () => {
expect(athenaConfig.prompt).toContain("Step 12: Synthesize")
expect(athenaConfig.prompt).toContain("Step 13: Determine follow-up path from council_finalize runtime guidance")
expect(athenaConfig.prompt).toContain("Step 14: Execute the runtime guidance action flow")
expect(athenaConfig.prompt).toContain("Step 15: Fallback behavior if runtime guidance is missing")
})
it("#then omits legacy mixed step labels", () => {
@@ -1,4 +1,6 @@
export const COUNCIL_INTENT_ADDENDUMS: Record<string, string> = {
import type { CouncilIntent } from "./council-runtime-guidance"
export const COUNCIL_INTENT_ADDENDUMS: Record<CouncilIntent, string> = {
DIAGNOSE: `
## Analysis Intent: DIAGNOSE
@@ -63,7 +65,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.**.
- **This is a broad sweep, not a targeted trace.**
**Required output fields per finding:**
- Title, Severity (critical/high/medium/low), Location, Confidence (high/medium/low)
@@ -291,7 +293,7 @@ You are **surfacing genuine viewpoints and taking a stand** — your goal is to
FREEFORM: `
## Analysis Intent: FREEFORM
Respond naturally to the question below. No analytical framework is imposed.
Respond naturally to the question below. No analytical framework is imposed (apart from the required COUNCIL_MEMBER_RESPONSE tags for extraction).
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.
@@ -86,6 +86,10 @@ export function createCouncilMemberAgent(model: string): AgentConfig {
"lsp_symbols",
"lsp_diagnostics",
"ast_grep_search",
// call_omo_agent is included in both solo and delegation modes.
// Solo mode restricts its use via prompt instruction (COUNCIL_SOLO_ADDENDUM)
// rather than tool-level restriction. This is intentional — tool-level
// restriction would require separate agent configs per mode.
"call_omo_agent",
"background_output",
"background_wait",
+23 -18
View File
@@ -12,6 +12,11 @@ const VALID_INTENTS = [
export type CouncilIntent = (typeof VALID_INTENTS)[number]
const RUNTIME_GUIDANCE_BY_INTENT: Record<CouncilIntent, string> = {
// Delegation agent design rationale:
// - DIAGNOSE = single targeted fix → Hephaestus (direct implementation) / Sisyphus (orchestrated implementation)
// - AUDIT = multi-finding remediation → Atlas (todo-list orchestration) / Prometheus (phased planning)
// Other intents (PLAN, EVALUATE, EXPLAIN, CREATE, PERSPECTIVES, FREEFORM) are INFORMATIONAL
// and offer context-appropriate delegation options in their action paths.
DIAGNOSE: `
<runtime_synthesis_rules>
Use DIAGNOSE synthesis.
@@ -234,7 +239,7 @@ Question({
options: [
{ label: "Execute full plan (Prometheus)", description: "Hand off all phases to Prometheus for execution" },
{ label: "Execute selected phase (Prometheus)", description: "Choose one phase and execute only that phase first" },
{ label: "Write to document", description: "Write the plan under .sisyphus/athena/notes/{council-session-name}" },
{ label: "Write to document", description: "Save to .sisyphus/athena/notes/ (named after this council session)" },
{ label: "Ask follow-up", description: "Ask another planning question" },
{ label: "Done", description: "No further action needed" }
],
@@ -258,8 +263,8 @@ Question({
3) Execute selected action:
- Execute full plan (Prometheus) -> switch_agent(agent="prometheus") with full synthesized plan.
- Execute selected phase (Prometheus) -> switch_agent(agent="prometheus") with only the selected phase plus dependencies.
- Write to document -> write the document directly to ".sisyphus/athena/notes/{council-session-name}" and then report the exact path to the user.
- Ask follow-up -> ask user then restart at Step 3.
- Write to document -> write the document to the ".sisyphus/athena/notes/" directory using the council session name from the council_finalize archive_dir, then report the exact path to the user.
- Ask follow-up -> ask user then restart the council workflow from Step 3 (intent classification).
- Done -> acknowledge and end.
</runtime_action_paths>`,
@@ -282,7 +287,7 @@ Question({
options: [
{ label: "Adopt option -> create plan (Prometheus)", description: "Turn a selected option into an execution plan" },
{ label: "Adopt option -> implement now", description: "Implement a selected option immediately" },
{ label: "Write to document", description: "Write under .sisyphus/athena/notes/{council-session-name}" },
{ label: "Write to document", description: "Save to .sisyphus/athena/notes/ (named after this council session)" },
{ label: "Ask follow-up", description: "Ask another comparison question" },
{ label: "Done", description: "No further action needed" }
],
@@ -321,8 +326,8 @@ Question({
- Adopt option -> implement now + Hephaestus -> switch_agent(agent="hephaestus") with selected option.
- Adopt option -> implement now + Sisyphus -> switch_agent(agent="sisyphus") with selected option.
- Adopt option -> implement now + Sisyphus ultrawork -> switch_agent(agent="sisyphus") and prefix handoff context with "ultrawork ".
- Write to document -> write directly to ".sisyphus/athena/notes/{council-session-name}" and then report the exact path.
- Ask follow-up -> ask user then restart at Step 3.
- Write to document -> write the document to the ".sisyphus/athena/notes/" directory using the council session name from the council_finalize archive_dir, then report the exact path.
- Ask follow-up -> ask user then restart the council workflow from Step 3 (intent classification).
- Done -> acknowledge and end.
</runtime_action_paths>`,
@@ -345,7 +350,7 @@ Question({
header: "Explanation Next Step",
options: [
{ label: "Convert to action plan (Prometheus)", description: "Turn insights into a phased plan" },
{ label: "Write to document", description: "Write under .sisyphus/athena/notes/{council-session-name}" },
{ label: "Write to document", description: "Save to .sisyphus/athena/notes/ (named after this council session)" },
{ label: "Ask follow-up", description: "Ask another explanatory question" },
{ label: "Done", description: "No further action needed" }
],
@@ -355,8 +360,8 @@ Question({
2) Execute selected action:
- Convert to action plan (Prometheus) -> switch_agent(agent="prometheus") with synthesized explanation and target outcome.
- Write to document -> write directly to ".sisyphus/athena/notes/{council-session-name}" and then report the exact path.
- Ask follow-up -> ask user then restart at Step 3.
- Write to document -> write the document to the ".sisyphus/athena/notes/" directory using the council session name from the council_finalize archive_dir, then report the exact path.
- Ask follow-up -> ask user then restart the council workflow from Step 3 (intent classification).
- Done -> acknowledge and end.
</runtime_action_paths>`,
@@ -405,7 +410,7 @@ Question({
{ label: "Implement selected creation (Hephaestus)", description: "Direct implementation with Hephaestus" },
{ label: "Implement selected creation (Sisyphus)", description: "Implementation with Sisyphus" },
{ label: "Implement selected creation (Sisyphus ultrawork)", description: "Implementation with Sisyphus using ultrawork mode" },
{ label: "Write selected creation to document", description: "Write under .sisyphus/athena/notes/{council-session-name}" },
{ label: "Write selected creation to document", description: "Save to .sisyphus/athena/notes/ (named after this council session)" },
{ label: "Ask follow-up", description: "Ask another creation-focused question" },
{ label: "Done", description: "No further action needed" }
],
@@ -417,8 +422,8 @@ Question({
- Implement selected creation (Hephaestus) -> switch_agent(agent="hephaestus") with only selected creation(s).
- Implement selected creation (Sisyphus) -> switch_agent(agent="sisyphus") with only selected creation(s).
- Implement selected creation (Sisyphus ultrawork) -> switch_agent(agent="sisyphus") and prefix handoff context with "ultrawork ", including only selected creation(s).
- Write selected creation to document -> write directly to ".sisyphus/athena/notes/{council-session-name}" and then report the exact path.
- Ask follow-up -> ask user then restart at Step 3.
- Write selected creation to document -> write the document to the ".sisyphus/athena/notes/" directory using the council session name from the council_finalize archive_dir, then report the exact path.
- Ask follow-up -> ask user then restart the council workflow from Step 3 (intent classification).
- Done -> acknowledge and end.
</runtime_action_paths>`,
@@ -443,7 +448,7 @@ Question({
options: [
{ label: "Commit to stance -> create plan (Prometheus)", description: "Turn a chosen stance into a phased plan" },
{ label: "Commit to stance -> implement now", description: "Implement based on a chosen stance immediately" },
{ label: "Write to document", description: "Write under .sisyphus/athena/notes/{council-session-name}" },
{ label: "Write to document", description: "Save to .sisyphus/athena/notes/ (named after this council session)" },
{ label: "Ask follow-up", description: "Ask another perspective question" },
{ label: "Done", description: "No further action needed" }
],
@@ -482,8 +487,8 @@ Question({
- Commit to stance -> implement now + Hephaestus -> switch_agent(agent="hephaestus") with selected stance.
- Commit to stance -> implement now + Sisyphus -> switch_agent(agent="sisyphus") with selected stance.
- Commit to stance -> implement now + Sisyphus ultrawork -> switch_agent(agent="sisyphus") and prefix handoff context with "ultrawork ".
- Write to document -> write directly to ".sisyphus/athena/notes/{council-session-name}" and then report the exact path.
- Ask follow-up -> ask user then restart at Step 3.
- Write to document -> write the document to the ".sisyphus/athena/notes/" directory using the council session name from the council_finalize archive_dir, then report the exact path.
- Ask follow-up -> ask user then restart the council workflow from Step 3 (intent classification).
- Done -> acknowledge and end.
</runtime_action_paths>`,
@@ -506,7 +511,7 @@ Question({
options: [
{ label: "Create plan (Prometheus)", description: "Turn the result into a phased execution plan" },
{ label: "Implement now", description: "Implement directly from this result" },
{ label: "Write to document", description: "Write under .sisyphus/athena/notes/{council-session-name}" },
{ label: "Write to document", description: "Save to .sisyphus/athena/notes/ (named after this council session)" },
{ label: "Ask follow-up", description: "Ask another question" },
{ label: "Done", description: "No further action needed" }
],
@@ -533,8 +538,8 @@ Question({
- Implement now + Hephaestus -> switch_agent(agent="hephaestus") with synthesized result.
- Implement now + Sisyphus -> switch_agent(agent="sisyphus") with synthesized result.
- Implement now + Sisyphus ultrawork -> switch_agent(agent="sisyphus") and prefix handoff context with "ultrawork ".
- Write to document -> write directly to ".sisyphus/athena/notes/{council-session-name}" and then report the exact path.
- Ask follow-up -> ask user then restart at Step 3.
- Write to document -> write the document to the ".sisyphus/athena/notes/" directory using the council session name from the council_finalize archive_dir, then report the exact path.
- Ask follow-up -> ask user then restart the council workflow from Step 3 (intent classification).
- Done -> acknowledge and end.
</runtime_action_paths>`,
}
@@ -64,6 +64,26 @@ describe("extractCouncilResponse", () => {
})
})
describe("#given response body contains literal COUNCIL_MEMBER_RESPONSE tag text", () => {
it("#then extracts the actual tagged response, not the discussed tag", () => {
const text = [
"Here is my exploration log where I discuss the tag format.",
"The system uses <COUNCIL_MEMBER_RESPONSE> tags for extraction.",
"Now here is my actual response:",
"<COUNCIL_MEMBER_RESPONSE>",
"## Finding 1: Tag discussion in body",
"The extractor uses lastIndexOf to find the opening tag.",
"</COUNCIL_MEMBER_RESPONSE>",
].join("\n")
const result = extractCouncilResponse(text)
expect(result).toEqual({
has_response: true,
response_complete: true,
result: "## Finding 1: Tag discussion in body\nThe extractor uses lastIndexOf to find the opening tag.",
})
})
})
describe("#given an empty string", () => {
it("#then returns has_response false and null result", () => {
const result = extractCouncilResponse("")
+4 -4
View File
@@ -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, COUNCIL_INTENT_ADDENDUMS } from "../../agents/athena"
import { COUNCIL_SOLO_ADDENDUM, COUNCIL_DELEGATION_ADDENDUM, COUNCIL_INTENT_ADDENDUMS, getValidCouncilIntents, type CouncilIntent } from "../../agents/athena"
const CLEANUP_DELAY_MS = 30 * 60 * 1000
const COUNCIL_TMP_DIR = ".sisyphus/tmp"
@@ -78,8 +78,8 @@ Returns the file path to reference in subsequent task() calls.`
return `Invalid mode: "${args.mode}". Valid modes: "solo", "delegation".`
}
const validIntents = Object.keys(COUNCIL_INTENT_ADDENDUMS)
if (args.intent !== undefined && !validIntents.includes(args.intent.toUpperCase())) {
const validIntents = getValidCouncilIntents()
if (args.intent !== undefined && !(validIntents as readonly string[]).includes(args.intent.toUpperCase())) {
return `Invalid intent: "${args.intent}". Valid intents: ${validIntents.map((i) => `"${i}"`).join(", ")}.`
}
@@ -95,7 +95,7 @@ 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 = resolvedIntent ? (COUNCIL_INTENT_ADDENDUMS[resolvedIntent] ?? "") : ""
const intentAddendum = resolvedIntent ? (COUNCIL_INTENT_ADDENDUMS[resolvedIntent as CouncilIntent] ?? "") : ""
const content = intentAddendum
? `${modeAddendum}\n\n${intentAddendum}\n\n## Analysis Question\n\n${args.prompt}`
: `${modeAddendum}\n\n## Analysis Question\n\n${args.prompt}`