refactor(athena): strip audit bias from council member prompt + add intent addendums + write boundary hook + relax restrictions
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
export const COUNCIL_INTENT_ADDENDUMS: Record<string, string> = {
|
||||
AUDIT: `
|
||||
## Analysis Intent: AUDIT
|
||||
|
||||
You are conducting an **audit** — your goal is to find discrete issues, risks, or violations.
|
||||
|
||||
**Focus:**
|
||||
- Search for problems, anti-patterns, security risks, correctness issues, or violations of stated requirements
|
||||
- Each finding must be a distinct, actionable item with concrete evidence
|
||||
- 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)
|
||||
|
||||
**Required output fields per finding:**
|
||||
- Title, Severity (critical/high/medium/low), Location, Confidence (high/medium/low)
|
||||
- Issue description, Supporting evidence, Suggested fix
|
||||
|
||||
**Structure your response as:**
|
||||
\`\`\`
|
||||
<COUNCIL_MEMBER_RESPONSE>
|
||||
## Finding 1: [Title]
|
||||
- **Severity**: high
|
||||
- **Location**: [specific reference — e.g. component, section, endpoint, rule]
|
||||
- **Confidence**: high
|
||||
- **Issue**: [what is wrong and why it matters]
|
||||
- **Evidence**: [concrete reference, snippet, or observation that proves the issue]
|
||||
- **Suggested Fix**: [actionable recommendation]
|
||||
|
||||
## Finding 2: [Title]
|
||||
...
|
||||
|
||||
## Summary
|
||||
[Total findings by severity. Overall risk assessment with confidence levels.]
|
||||
</COUNCIL_MEMBER_RESPONSE>
|
||||
\`\`\``,
|
||||
|
||||
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:**
|
||||
\`\`\`
|
||||
<COUNCIL_MEMBER_RESPONSE>
|
||||
## 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]
|
||||
</COUNCIL_MEMBER_RESPONSE>
|
||||
\`\`\``,
|
||||
|
||||
PLAN: `
|
||||
## Analysis Intent: PLAN
|
||||
|
||||
You are conducting a **planning analysis** — your goal is to define current state, target state, and a phased path between them.
|
||||
|
||||
**Focus:**
|
||||
- Assess where things stand now (current state, constraints, existing assets)
|
||||
- Define the target state clearly (what "done" looks like)
|
||||
- Break the path into phases with sequencing, dependencies, and exit criteria
|
||||
- Identify risks per phase and mitigation strategies
|
||||
- Estimate effort where possible (relative sizing is fine: small/medium/large)
|
||||
|
||||
**Required output fields:**
|
||||
- Current state assessment, Target state definition
|
||||
- Phases (each with: goal, tasks, exit criteria, dependencies, risks, effort estimate)
|
||||
- Critical path, Key risks and mitigations
|
||||
|
||||
**Structure your response as:**
|
||||
\`\`\`
|
||||
<COUNCIL_MEMBER_RESPONSE>
|
||||
## Current State
|
||||
[What exists today, constraints, and starting conditions]
|
||||
|
||||
## Target State
|
||||
[What "done" looks like — measurable where possible]
|
||||
|
||||
## Phase 1: [Name]
|
||||
- **Goal**: [what this phase achieves]
|
||||
- **Tasks**: [concrete work items]
|
||||
- **Exit Criteria**: [how you know this phase is complete]
|
||||
- **Dependencies**: [what must be true before starting]
|
||||
- **Risks**: [what could go wrong, with mitigation]
|
||||
- **Effort**: [small/medium/large or time estimate]
|
||||
|
||||
## Phase 2: [Name]
|
||||
...
|
||||
|
||||
## Critical Path & Dependencies
|
||||
[Which phases block others, what the minimum viable sequence is]
|
||||
|
||||
## Summary
|
||||
[Overall effort assessment, key risks, confidence in feasibility]
|
||||
</COUNCIL_MEMBER_RESPONSE>
|
||||
\`\`\``,
|
||||
|
||||
EXPLAIN: `
|
||||
## Analysis Intent: EXPLAIN
|
||||
|
||||
You are conducting an **explanatory analysis** — your goal is to build understanding of how something works, why it exists, or what it means.
|
||||
|
||||
**Focus:**
|
||||
- Lead with a clear thesis statement — your one-sentence answer to the question
|
||||
- Identify the key mechanisms, components, or concepts that drive the answer
|
||||
- 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
|
||||
|
||||
**Required output fields:**
|
||||
- Thesis statement, Key mechanisms/components (with evidence)
|
||||
- Relationships and interactions, Evidence references
|
||||
- Unknowns and knowledge gaps, Overall confidence
|
||||
|
||||
**Structure your response as:**
|
||||
\`\`\`
|
||||
<COUNCIL_MEMBER_RESPONSE>
|
||||
## Thesis
|
||||
[One clear sentence answering the core question]
|
||||
|
||||
## Key Mechanisms
|
||||
### 1. [Mechanism/Component Name]
|
||||
- **What**: [description]
|
||||
- **Evidence**: [reference, observation, or reasoning]
|
||||
- **Role**: [how this contributes to the overall answer]
|
||||
|
||||
### 2. [Mechanism/Component Name]
|
||||
...
|
||||
|
||||
## Relationships & Interactions
|
||||
[How the mechanisms connect — data flows, dependencies, causal chains]
|
||||
|
||||
## Unknowns & Gaps
|
||||
- [What you could not determine or verify]
|
||||
- [Areas where confidence is lower and why]
|
||||
|
||||
## Summary
|
||||
[Synthesized explanation with overall confidence level]
|
||||
</COUNCIL_MEMBER_RESPONSE>
|
||||
\`\`\``,
|
||||
}
|
||||
@@ -4,33 +4,26 @@ import { createAgentToolAllowlist } from "../../shared"
|
||||
|
||||
const MODE: AgentMode = "subagent"
|
||||
|
||||
export const COUNCIL_MEMBER_PROMPT = `You are an independent code analyst in a multi-model analysis council. Your role is to provide thorough, evidence-based analysis.
|
||||
export const COUNCIL_MEMBER_PROMPT = `You are an independent analyst in a multi-model analysis council. Your role is to provide thorough, evidence-based analysis.
|
||||
|
||||
## Your Role
|
||||
- You are one of several AI models analyzing the same question independently
|
||||
- Your analysis should be thorough and evidence-based
|
||||
- You are read-only — you cannot modify any files, only analyze
|
||||
- Focus on finding real issues, not hypothetical ones
|
||||
|
||||
## Instructions
|
||||
1. Analyze the question carefully
|
||||
2. Search the codebase thoroughly using available tools (Read, Grep, Glob, LSP)
|
||||
3. Report your findings with evidence (file paths, line numbers, code snippets)
|
||||
4. For each finding, state:
|
||||
- What the issue/observation is
|
||||
- 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
|
||||
2. Use available tools to gather evidence relevant to the question
|
||||
3. For each point, state what you observed, where (if applicable), and your confidence level
|
||||
4. Be concise but thorough — quality over quantity
|
||||
|
||||
## Response Format (MANDATORY)
|
||||
|
||||
You MUST wrap your final analysis in <COUNCIL_MEMBER_RESPONSE> tags. This is how the system extracts your findings.
|
||||
|
||||
**Include inside tags:**
|
||||
- Key findings with evidence (file paths, line numbers, code snippets)
|
||||
- Key findings with supporting evidence
|
||||
- Confidence levels for each finding (high/medium/low)
|
||||
- Severity assessments (critical/high/medium/low)
|
||||
- Concerns and caveats
|
||||
|
||||
**Exclude from tags (keep outside):**
|
||||
@@ -41,14 +34,12 @@ You MUST wrap your final analysis in <COUNCIL_MEMBER_RESPONSE> tags. This is how
|
||||
**Example structure:**
|
||||
\`\`\`
|
||||
<COUNCIL_MEMBER_RESPONSE>
|
||||
## Finding 1: [Title]
|
||||
- **Location**: src/path/to/file.ts:42-56
|
||||
- **Severity**: high
|
||||
## Point 1: [Title]
|
||||
- **Observation**: [what you found]
|
||||
- **Confidence**: high
|
||||
- **Issue**: [description]
|
||||
- **Evidence**: [code snippet or reference]
|
||||
- **Details**: [supporting evidence or reasoning]
|
||||
|
||||
## Finding 2: [Title]
|
||||
## Point 2: [Title]
|
||||
...
|
||||
|
||||
## Summary
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { ATHENA_AGENT } from "./constants"
|
||||
|
||||
export function isAthenaAgent(agentName: string | undefined): boolean {
|
||||
return agentName?.toLowerCase().includes(ATHENA_AGENT) ?? false
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export const HOOK_NAME = "athena-sisyphus-only"
|
||||
|
||||
export const ATHENA_AGENT = "athena"
|
||||
|
||||
export const BLOCKED_TOOLS = ["Write", "Edit", "write", "edit"]
|
||||
@@ -0,0 +1,49 @@
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import { HOOK_NAME, BLOCKED_TOOLS } from "./constants"
|
||||
import { log } from "../../shared/logger"
|
||||
import { getAgentFromSession } from "../prometheus-md-only/agent-resolution"
|
||||
import { isAthenaAgent } from "./agent-matcher"
|
||||
import { isAllowedPath } from "./path-policy"
|
||||
|
||||
export function createAthenaSisyphusOnlyHook(ctx: PluginInput) {
|
||||
return {
|
||||
"tool.execute.before": async (
|
||||
input: { tool: string; sessionID: string; callID: string },
|
||||
output: { args: Record<string, unknown>; message?: string }
|
||||
): Promise<void> => {
|
||||
if (!BLOCKED_TOOLS.includes(input.tool)) {
|
||||
return
|
||||
}
|
||||
|
||||
const agentName = await getAgentFromSession(input.sessionID, ctx.directory, ctx.client)
|
||||
|
||||
if (!isAthenaAgent(agentName)) {
|
||||
return
|
||||
}
|
||||
|
||||
const filePath = (output.args.filePath ?? output.args.path ?? output.args.file) as string | undefined
|
||||
if (!filePath) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isAllowedPath(filePath, ctx.directory)) {
|
||||
log(`[${HOOK_NAME}] Blocked: Athena attempted write outside .sisyphus/`, {
|
||||
sessionID: input.sessionID,
|
||||
tool: input.tool,
|
||||
filePath,
|
||||
agent: agentName,
|
||||
})
|
||||
throw new Error(
|
||||
`[${HOOK_NAME}] Athena can only write/edit files inside .sisyphus/ directory. Attempted to modify: ${filePath}`
|
||||
)
|
||||
}
|
||||
|
||||
log(`[${HOOK_NAME}] Allowed: .sisyphus/ write permitted`, {
|
||||
sessionID: input.sessionID,
|
||||
tool: input.tool,
|
||||
filePath,
|
||||
agent: agentName,
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./constants"
|
||||
export { createAthenaSisyphusOnlyHook } from "./hook"
|
||||
@@ -0,0 +1,30 @@
|
||||
import { relative, resolve, isAbsolute } from "node:path"
|
||||
|
||||
/**
|
||||
* Cross-platform path validator for Athena file writes.
|
||||
* Uses path.resolve/relative instead of string matching to handle:
|
||||
* - Windows backslashes (e.g., .sisyphus\\notepads\\x.yaml)
|
||||
* - Mixed separators (e.g., .sisyphus\\plans/x.md)
|
||||
* - Case-insensitive directory matching
|
||||
* - Workspace confinement (blocks paths outside root or via traversal)
|
||||
* - No extension restriction: any file type is allowed inside .sisyphus/
|
||||
*/
|
||||
export function isAllowedPath(filePath: string, workspaceRoot: string): boolean {
|
||||
// 1. Resolve to absolute path
|
||||
const resolved = resolve(workspaceRoot, filePath)
|
||||
|
||||
// 2. Get relative path from workspace root
|
||||
const rel = relative(workspaceRoot, resolved)
|
||||
|
||||
// 3. Reject if escapes root (starts with ".." or is absolute)
|
||||
if (rel.startsWith("..") || isAbsolute(rel)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 4. Check if .sisyphus/ or .sisyphus\ exists anywhere in the path (case-insensitive)
|
||||
if (!/\.sisyphus[/\\]/i.test(rel)) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -48,8 +48,6 @@ const AGENT_RESTRICTIONS: Record<string, Record<string, boolean>> = {
|
||||
},
|
||||
|
||||
athena: {
|
||||
write: false,
|
||||
edit: false,
|
||||
call_omo_agent: false,
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user