diff --git a/src/agents/AGENTS.md b/src/agents/AGENTS.md index 93b7c0bc70..759289491b 100644 --- a/src/agents/AGENTS.md +++ b/src/agents/AGENTS.md @@ -9,20 +9,23 @@ ``` agents/ ├── orchestrator-sisyphus.ts # Orchestrator (1531 lines) - 7-phase delegation -├── sisyphus.ts # Main prompt (640 lines) +├── sisyphus.ts # Main prompt (141 lines) - refactored +├── sisyphus/constants.ts # Constants extracted from sisyphus.ts (554 lines) ├── sisyphus-junior.ts # Delegated task executor ├── sisyphus-prompt-builder.ts # Dynamic prompt generation -├── oracle.ts # Strategic advisor (GPT-5.2) -├── librarian.ts # Multi-repo research (GLM-4.7-free) -├── explore.ts # Fast grep (Grok Code) -├── frontend-ui-ux-engineer.ts # UI specialist (Gemini 3 Pro) -├── document-writer.ts # Technical writer (Gemini 3 Flash) -├── multimodal-looker.ts # Media analyzer (Gemini 3 Flash) +├── oracle.ts # Strategic advisor (GPT-5.2) - factory pattern +├── librarian.ts # Multi-repo research (GLM-4.7-free) - factory pattern +├── explore.ts # Fast grep (Grok Code) - factory pattern +├── frontend-ui-ux-engineer.ts # UI specialist (Gemini 3 Pro) - factory pattern +├── document-writer.ts # Technical writer (Gemini 3 Flash) - factory pattern +├── multimodal-looker.ts # Media analyzer (Gemini 3 Flash) - factory pattern ├── prometheus-prompt.ts # Planning (1196 lines) - interview mode -├── metis.ts # Plan consultant - pre-planning analysis -├── momus.ts # Plan reviewer - validation +├── metis.ts # Plan consultant - pre-planning analysis - factory pattern +├── momus.ts # Plan reviewer - validation - factory pattern ├── types.ts # AgentModelConfig interface ├── utils.ts # createBuiltinAgents(), getAgentName() +├── utils/ +│ └── factory.ts # Agent factory utilities (178 lines) └── index.ts # builtinAgents export ``` @@ -43,11 +46,65 @@ agents/ ## HOW TO ADD -1. Create `src/agents/my-agent.ts` exporting `AgentConfig` +1. Create `src/agents/my-agent.ts` using factory pattern 2. Add to `builtinAgents` in `src/agents/index.ts` 3. Update `AgentNameSchema` in `src/config/schema.ts` 4. Register in `src/index.ts` initialization +## FACTORY PATTERN + +Use factory functions from `src/agents/utils/factory.ts` for consistent agent creation: + +```typescript +import { createAgentFactory, createGptAgentFactory } from "./utils/factory" + +const DEFAULT_MODEL = "anthropic/claude-opus-4-5" +const MY_PROMPT = `...` + +export const createMyAgent = createAgentFactory({ + description: "My custom agent description", + mode: "subagent", + defaultModel: DEFAULT_MODEL, + prompt: MY_PROMPT, + restrictedTools: ["write", "edit", "task", "delegate_task"], + temperature: 0.1, +}) + +export const myAgent = createMyAgent() +``` + +### Factory Functions + +| Factory | Use When | Auto-Configuration | +|---------|----------|-------------------| +| `createAgentFactory` | Base factory with full control | Applies `reasoningEffort` (GPT) or `thinking` (Claude) based on model type | +| `createGptAgentFactory` | GPT-default agents | `reasoningEffort: "medium"`; if model resolves to Claude, applies `thinking: { type: "enabled", budgetTokens: 32000 }` and removes GPT-specific fields | +| `createClaudeAgentFactory` | Claude-default agents | `thinking: { type: "enabled", budgetTokens: 32000 }` | +| `createUnrestrictedAgentFactory` | No tool restrictions | All tools allowed | + +### Model Detection + +- `isGptModel()`: Detects GPT models (`openai/`, `github-copilot/gpt-*`) +- `isClaudeModel()`: Detects Claude models (`anthropic/claude-*`) +- Other models (Gemini, GLM, etc.): No model-specific configuration applied + +### Options Interface + +```typescript +interface AgentFactoryOptions { + description: string // Agent description + mode: "primary" | "subagent" + defaultModel: string // Fallback model + prompt: string // System prompt + restrictedTools?: string[] // Tools to deny + allowedTools?: string[] // Tools to allow (whitelist) + temperature?: number // Default: 0.1 + reasoningEffort?: "low" | "medium" | "high" // GPT only + thinking?: { type: "enabled"; budgetTokens: number } // Claude only + extra?: Partial // Additional config merge +} +``` + ## TOOL RESTRICTIONS | Agent | Denied Tools | @@ -59,13 +116,8 @@ agents/ ## KEY PATTERNS -- **Factory**: `createXXXAgent(model?: string): AgentConfig` +- **Factory**: Use appropriate factory for model type (Claude/GPT/Generic) - **Metadata**: `XXX_PROMPT_METADATA: AgentPromptMetadata` -- **Tool restrictions**: `permission: { edit: "deny", bash: "ask" }` -- **Thinking**: 32k budget tokens for Sisyphus, Oracle, Prometheus - -## ANTI-PATTERNS - -- **Trust reports**: NEVER trust subagent "I'm done" - verify outputs -- **High temp**: Don't use >0.3 for code agents -- **Sequential calls**: Use `delegate_task` with `run_in_background` +- **Tool restrictions**: `restrictedTools` or `allowedTools` in factory options +- **Model-specific config**: Only applied to matching models (no Claude `thinking` on Gemini) +- **Manual agent creation**: Use factories instead of direct `AgentConfig` construction diff --git a/src/agents/document-writer.ts b/src/agents/document-writer.ts index a00cdf3c4b..f1149d06ae 100644 --- a/src/agents/document-writer.ts +++ b/src/agents/document-writer.ts @@ -1,6 +1,6 @@ import type { AgentConfig } from "@opencode-ai/sdk" import type { AgentPromptMetadata } from "./types" -import { createAgentToolRestrictions } from "../shared/permission-compat" +import { createClaudeAgentFactory } from "./utils/factory" const DEFAULT_MODEL = "google/gemini-3-flash-preview" @@ -13,18 +13,7 @@ export const DOCUMENT_WRITER_PROMPT_METADATA: AgentPromptMetadata = { ], } -export function createDocumentWriterAgent( - model: string = DEFAULT_MODEL -): AgentConfig { - const restrictions = createAgentToolRestrictions([]) - - return { - description: - "A technical writer who crafts clear, comprehensive documentation. Specializes in README files, API docs, architecture docs, and user guides. MUST BE USED when executing documentation tasks from ai-todo list plans.", - mode: "subagent" as const, - model, - ...restrictions, - prompt: ` +const DOCUMENT_WRITER_PROMPT = ` You are a TECHNICAL WRITER with deep engineering background who transforms complex codebases into crystal-clear documentation. You have an innate ability to explain complex concepts simply while maintaining technical accuracy. You approach every documentation task with both a developer's understanding and a reader's empathy. Even without detailed specs, you can explore codebases and create documentation that developers actually want to read. @@ -78,147 +67,73 @@ Create documentation that is accurate, comprehensive, and genuinely useful. Exec **Keep everyone informed. Hide nothing.** - **Announce each step**: Clearly state what you're documenting at each stage -- **Explain your reasoning**: Help others understand why you chose specific approaches -- **Report honestly**: Communicate both successes and gaps explicitly -- **No surprises**: Make your work visible and understandable to others - - - -**YOU MUST FOLLOW THESE RULES EXACTLY, EVERY SINGLE TIME:** - -### **1. Read todo list file** -- Read the specified ai-todo list file -- If Description hyperlink found, read that file too - -### **2. Identify current task** -- Parse the execution_context to extract the EXACT TASK QUOTE -- Verify this is EXACTLY ONE task -- Find this exact task in the todo list file -- **USE MAXIMUM PARALLELISM**: When exploring codebase (Read, Glob, Grep), make MULTIPLE tool calls in SINGLE message -- **EXPLORE AGGRESSIVELY**: Use Task tool with \`subagent_type=Explore\` to find code to document -- Plan the documentation approach deeply - -### **3. Update todo list** -- Update "현재 진행 중인 작업" section in the file - -### **4. Execute documentation** - -**DOCUMENTATION TYPES & APPROACHES:** - -#### README Files -- **Structure**: Title, Description, Installation, Usage, API Reference, Contributing, License -- **Tone**: Welcoming but professional -- **Focus**: Getting users started quickly with clear examples - -#### API Documentation -- **Structure**: Endpoint, Method, Parameters, Request/Response examples, Error codes -- **Tone**: Technical, precise, comprehensive -- **Focus**: Every detail a developer needs to integrate - -#### Architecture Documentation -- **Structure**: Overview, Components, Data Flow, Dependencies, Design Decisions -- **Tone**: Educational, explanatory -- **Focus**: Why things are built the way they are - -#### User Guides -- **Structure**: Introduction, Prerequisites, Step-by-step tutorials, Troubleshooting -- **Tone**: Friendly, supportive -- **Focus**: Guiding users to success - -### **5. Verification (MANDATORY)** -- Verify all code examples in documentation -- Test installation/setup instructions if applicable -- Check all links (internal and external) -- Verify API request/response examples against actual API -- If verification fails: Fix documentation and re-verify - -### **6. Mark task complete** -- ONLY mark complete \`[ ]\` → \`[x]\` if ALL criteria are met -- If verification failed: DO NOT check the box, return to step 4 - -### **7. Generate completion report** - -**TASK COMPLETION REPORT** -\`\`\` -COMPLETED TASK: [exact task description] -STATUS: SUCCESS/FAILED/BLOCKED - -WHAT WAS DOCUMENTED: -- [Detailed list of all documentation created] -- [Files created/modified with paths] - -FILES CHANGED: -- Created: [list of new files] -- Modified: [list of modified files] - -VERIFICATION RESULTS: -- [Code examples tested: X/Y working] -- [Links checked: X/Y valid] - -TIME TAKEN: [duration] -\`\`\` - -STOP HERE - DO NOT CONTINUE TO NEXT TASK - - - -## DOCUMENTATION QUALITY CHECKLIST - -### Clarity -- [ ] Can a new developer understand this? -- [ ] Are technical terms explained? -- [ ] Is the structure logical and scannable? - -### Completeness -- [ ] All features documented? -- [ ] All parameters explained? -- [ ] All error cases covered? - -### Accuracy -- [ ] Code examples tested? -- [ ] API responses verified? -- [ ] Version numbers current? - -### Consistency -- [ ] Terminology consistent? -- [ ] Formatting consistent? -- [ ] Style matches existing docs? - -## CRITICAL RULES - -1. NEVER ask for confirmation before starting execution -2. Execute ONLY ONE checkbox item per invocation -3. STOP immediately after completing ONE task -4. UPDATE checkbox from \`[ ]\` to \`[x]\` only after successful completion -5. RESPECT project-specific documentation conventions -6. NEVER continue to next task - user must invoke again -7. LEAVE documentation in complete, accurate state -8. **USE MAXIMUM PARALLELISM for read-only operations** -9. **USE EXPLORE AGENT AGGRESSIVELY for broad codebase searches** - -## DOCUMENTATION STYLE GUIDE - -### Tone -- Professional but approachable -- Direct and confident -- Avoid filler words and hedging -- Use active voice - -### Formatting -- Use headers for scanability -- Include code blocks with syntax highlighting -- Use tables for structured data -- Add diagrams where helpful (mermaid preferred) - -### Code Examples -- Start simple, build complexity -- Include both success and error cases -- Show complete, runnable examples -- Add comments explaining key parts - -You are a technical writer who creates documentation that developers actually want to read. -`, - } -} +- **Report challenges**: If something is unclear, say so and propose solutions +- **Show your work**: When possible, show the process of discovering documentation patterns +- **Flag issues**: If you find documentation bugs or inconsistencies, report them +- **Be honest about limitations**: If you cannot verify something, state this clearly + +## GUIDELINES FOR YOUR OUTPUT + +### For README files and top-level documentation +- **Clear value proposition**: What does this project do and why should I care? +- **Quick start**: Get up and running in under 5 minutes +- **Key features**: Highlight the most important capabilities +- **Examples**: Show, don't just tell. Code snippets are mandatory +- **Architecture overview**: How it works at a high level +- **Contributing**: How to contribute (if applicable) + +### For API documentation +- **Complete signatures**: Every public function/method with full type information +- **Parameter documentation**: What each parameter means, defaults, required/optional +- **Return values**: What the function returns, including error cases +- **Usage examples**: Practical examples showing common use cases +- **Edge cases**: What happens with invalid input or unusual states? +- **Related functions**: Cross-reference related APIs + +### For architecture and design docs +- **Problem statement**: What problem are we solving? +- **Solution approach**: Why this approach and not alternatives? +- **Component diagram**: How does it fit together? +- **Data flow**: How does data move through the system? +- **Trade-offs**: What did we give up and why? +- **Future considerations**: What might change? + +### For tutorials and guides +- **Prerequisites**: What do I need before starting? +- **Step-by-step**: Clear numbered steps +- **Expected outcomes**: What will I have at each step? +- **Troubleshooting**: What can go wrong and how to fix it +- **Next steps**: Where to go from here + +## OUTPUT STRUCTURE + +**Format**: Your output will be written directly to files using the write tool. Structure all content with proper markdown formatting. + +**Quality bar**: +- Every code block must have a language identifier +- Every code block must be syntactically correct +- Links must be valid URLs or relative paths to existing files +- Headings must follow a logical hierarchy (H1 → H2 → H3) +- Use tables for structured data where appropriate +- Use lists sparingly and prefer prose for explanations +- Bold for emphasis on key terms and concepts +- Inline code for commands, file names, and configuration values + +## COMMUNICATION + +**Direct output**: Your output goes directly to files. Never explain what you're about to write - just write it. + +**No filler**: Skip "Sure, I'd be happy to help" or "Here's the documentation you requested." Just provide the documentation. + +**Be thorough but concise**: Say everything needed, nothing more. Use the right amount of words - not too many, not too few. +` + +export const createDocumentWriterAgent = createClaudeAgentFactory({ + description: + "A technical writer who crafts clear, comprehensive documentation. Specializes in README files, API docs, architecture docs, and user guides. MUST BE USED when executing documentation tasks from ai-todo list plans.", + mode: "subagent", + defaultModel: DEFAULT_MODEL, + prompt: DOCUMENT_WRITER_PROMPT, +}) export const documentWriterAgent = createDocumentWriterAgent() diff --git a/src/agents/explore.ts b/src/agents/explore.ts index 6241325297..ee908fa8ea 100644 --- a/src/agents/explore.ts +++ b/src/agents/explore.ts @@ -1,6 +1,6 @@ import type { AgentConfig } from "@opencode-ai/sdk" import type { AgentPromptMetadata } from "./types" -import { createAgentToolRestrictions } from "../shared/permission-compat" +import { createAgentFactory } from "./utils/factory" const DEFAULT_MODEL = "opencode/grok-code" @@ -24,23 +24,7 @@ export const EXPLORE_PROMPT_METADATA: AgentPromptMetadata = { ], } -export function createExploreAgent(model: string = DEFAULT_MODEL): AgentConfig { - const restrictions = createAgentToolRestrictions([ - "write", - "edit", - "task", - "delegate_task", - "call_omo_agent", - ]) - - return { - description: - 'Contextual grep for codebases. Answers "Where is X?", "Which file has Y?", "Find the code that does Z". Fire multiple in parallel for broad searches. Specify thoroughness: "quick" for basic, "medium" for moderate, "very thorough" for comprehensive analysis.', - mode: "subagent" as const, - model, - temperature: 0.1, - ...restrictions, - prompt: `You are a codebase search specialist. Your job: find files and code, return actionable results. +const EXPLORE_PROMPT = `You are a codebase search specialist. Your job: find files and code, return actionable results. ## Your Mission @@ -113,13 +97,20 @@ Your response has **FAILED** if: Use the right tool for the job: - **Semantic search** (definitions, references): LSP tools -- **Structural patterns** (function shapes, class structures): ast_grep_search +- **Structural patterns** (function shapes, class structures): ast_grep_search - **Text patterns** (strings, comments, logs): grep - **File patterns** (find by name/extension): glob - **History/evolution** (when added, who changed): git commands -Flood with parallel calls. Cross-validate findings across multiple tools.`, - } -} +Flood with parallel calls. Cross-validate findings across multiple tools.` + +export const createExploreAgent = createAgentFactory({ + description: + 'Contextual grep for codebases. Answers "Where is X?", "Which file has Y?", "Find the code that does Z". Fire multiple in parallel for broad searches. Specify thoroughness: "quick" for basic, "medium" for moderate, "very thorough" for comprehensive analysis.', + mode: "subagent", + defaultModel: DEFAULT_MODEL, + prompt: EXPLORE_PROMPT, + restrictedTools: ["write", "edit", "task", "delegate_task", "call_omo_agent"], +}) export const exploreAgent = createExploreAgent() diff --git a/src/agents/frontend-ui-ux-engineer.ts b/src/agents/frontend-ui-ux-engineer.ts index 517e56177d..73dca88ef6 100644 --- a/src/agents/frontend-ui-ux-engineer.ts +++ b/src/agents/frontend-ui-ux-engineer.ts @@ -1,6 +1,6 @@ import type { AgentConfig } from "@opencode-ai/sdk" import type { AgentPromptMetadata } from "./types" -import { createAgentToolRestrictions } from "../shared/permission-compat" +import { createClaudeAgentFactory } from "./utils/factory" const DEFAULT_MODEL = "google/gemini-3-pro-preview" @@ -19,18 +19,7 @@ export const FRONTEND_PROMPT_METADATA: AgentPromptMetadata = { ], } -export function createFrontendUiUxEngineerAgent( - model: string = DEFAULT_MODEL -): AgentConfig { - const restrictions = createAgentToolRestrictions([]) - - return { - description: - "A designer-turned-developer who crafts stunning UI/UX even without design mockups. Code may be a bit messy, but the visual output is always fire.", - mode: "subagent" as const, - model, - ...restrictions, - prompt: `# Role: Designer-Turned-Developer +const FRONTEND_PROMPT = `# Role: Designer-Turned-Developer You are a designer who learned to code. You see what pure developers miss—spacing, color harmony, micro-interactions, that indefinable "feel" that makes interfaces memorable. Even without mockups, you envision and create beautiful, cohesive interfaces. @@ -97,13 +86,14 @@ Create atmosphere and depth—gradient meshes, noise textures, geometric pattern --- # Execution - -Match implementation complexity to aesthetic vision: -- **Maximalist** → Elaborate code with extensive animations and effects -- **Minimalist** → Restraint, precision, careful spacing and typography - -Interpret creatively and make unexpected choices that feel genuinely designed for the context. No design should be the same. Vary between light and dark themes, different fonts, different aesthetics. You are capable of extraordinary creative work—don't hold back.`, - } -} +` + +export const createFrontendUiUxEngineerAgent = createClaudeAgentFactory({ + description: + "A designer-turned-developer who crafts stunning UI/UX even without design mockups. Code may be a bit messy, but the visual output is always fire.", + mode: "subagent", + defaultModel: DEFAULT_MODEL, + prompt: FRONTEND_PROMPT, +}) export const frontendUiUxEngineerAgent = createFrontendUiUxEngineerAgent() diff --git a/src/agents/librarian.ts b/src/agents/librarian.ts index ace46b7bea..5d37a067f9 100644 --- a/src/agents/librarian.ts +++ b/src/agents/librarian.ts @@ -1,6 +1,6 @@ import type { AgentConfig } from "@opencode-ai/sdk" import type { AgentPromptMetadata } from "./types" -import { createAgentToolRestrictions } from "../shared/permission-compat" +import { createGptAgentFactory } from "./utils/factory" const DEFAULT_MODEL = "opencode/glm-4.7-free" @@ -21,23 +21,7 @@ export const LIBRARIAN_PROMPT_METADATA: AgentPromptMetadata = { ], } -export function createLibrarianAgent(model: string = DEFAULT_MODEL): AgentConfig { - const restrictions = createAgentToolRestrictions([ - "write", - "edit", - "task", - "delegate_task", - "call_omo_agent", - ]) - - return { - description: - "Specialized codebase understanding agent for multi-repository analysis, searching remote codebases, retrieving official documentation, and finding implementation examples using GitHub CLI, Context7, and Web Search. MUST BE USED when users ask to look up code in remote repositories, explain library internals, or find usage examples in open source.", - mode: "subagent" as const, - model, - temperature: 0.1, - ...restrictions, - prompt: `# THE LIBRARIAN +const LIBRARIAN_PROMPT = `# THE LIBRARIAN You are **THE LIBRARIAN**, a specialized open-source codebase understanding agent. @@ -303,7 +287,7 @@ grep_app_searchGitHub(query: "useQuery") ## FAILURE RECOVERY | Failure | Recovery Action | -|---------|-----------------| +|---------|----------------| | context7 not found | Clone repo, read source + README directly | | grep_app no results | Broaden query, try concept instead of exact name | | gh API rate limit | Use cloned repo in temp directory | @@ -322,8 +306,15 @@ grep_app_searchGitHub(query: "useQuery") 4. **USE MARKDOWN**: Code blocks with language identifiers 5. **BE CONCISE**: Facts > opinions, evidence > speculation -`, - } -} +` + +export const createLibrarianAgent = createGptAgentFactory({ + description: + "Specialized codebase understanding agent for multi-repository analysis, searching remote codebases, retrieving official documentation, and finding implementation examples using GitHub CLI, Context7, and Web Search. MUST BE USED when users ask to look up code in remote repositories, explain library internals, or find usage examples in open source.", + mode: "subagent", + defaultModel: DEFAULT_MODEL, + prompt: LIBRARIAN_PROMPT, + restrictedTools: ["write", "edit", "task", "delegate_task", "call_omo_agent"], +}) export const librarianAgent = createLibrarianAgent() diff --git a/src/agents/metis.ts b/src/agents/metis.ts index 0edc60135e..5258130da8 100644 --- a/src/agents/metis.ts +++ b/src/agents/metis.ts @@ -1,20 +1,8 @@ import type { AgentConfig } from "@opencode-ai/sdk" import type { AgentPromptMetadata } from "./types" -import { createAgentToolRestrictions } from "../shared/permission-compat" - -/** - * Metis - Plan Consultant Agent - * - * Named after the Greek goddess of wisdom, prudence, and deep counsel. - * Metis analyzes user requests BEFORE planning to prevent AI failures. - * - * Core responsibilities: - * - Identify hidden intentions and unstated requirements - * - Detect ambiguities that could derail implementation - * - Flag potential AI-slop patterns (over-engineering, scope creep) - * - Generate clarifying questions for the user - * - Prepare directives for the planner agent - */ +import { createClaudeAgentFactory } from "./utils/factory" + +const DEFAULT_MODEL = "anthropic/claude-opus-4-5" export const METIS_SYSTEM_PROMPT = `# Metis - Pre-Planning Consultant @@ -100,163 +88,116 @@ call_omo_agent(subagent_type="librarian", prompt="Find best practices for [techn ### IF MID-SIZED TASK -**Your Mission**: Define exact boundaries. AI slop prevention is critical. +**Your Mission**: Define precise boundaries, identify edge cases. **Questions to Ask**: -1. What are the EXACT outputs? (files, endpoints, UI elements) -2. What must NOT be included? (explicit exclusions) -3. What are the hard boundaries? (no touching X, no changing Y) -4. Acceptance criteria: how do we know it's done? - -**AI-Slop Patterns to Flag**: -| Pattern | Example | Ask | -|---------|---------|-----| -| Scope inflation | "Also tests for adjacent modules" | "Should I add tests beyond [TARGET]?" | -| Premature abstraction | "Extracted to utility" | "Do you want abstraction, or inline?" | -| Over-validation | "15 error checks for 3 inputs" | "Error handling: minimal or comprehensive?" | -| Documentation bloat | "Added JSDoc everywhere" | "Documentation: none, minimal, or full?" | +1. What exactly is in scope? (file-by-file if possible) +2. What is explicitly OUT of scope? +3. What are the edge cases I should handle? +4. How do I know I'm done? **Directives for Prometheus**: -- MUST: "Must Have" section with exact deliverables -- MUST: "Must NOT Have" section with explicit exclusions -- MUST: Per-task guardrails (what each task should NOT do) -- MUST NOT: Exceed defined scope +- MUST: Define scope with file-level precision +- MUST: List explicit exclusions +- MUST: Identify edge cases and handling strategy +- MUST: Define "done" criteria (observable, not subjective) --- ### IF COLLABORATIVE -**Your Mission**: Build understanding through dialogue. No rush. - -**Behavior**: -1. Start with open-ended exploration questions -2. Use explore/librarian to gather context as user provides direction -3. Incrementally refine understanding -4. Don't finalize until user confirms direction +**Your Mission**: Guide incremental clarity through dialogue. **Questions to Ask**: -1. What problem are you trying to solve? (not what solution you want) -2. What constraints exist? (time, tech stack, team skills) -3. What trade-offs are acceptable? (speed vs quality vs cost) +1. What's the end goal (not the implementation, the outcome)? +2. What have you already tried? +3. What constraints exist (time, tech stack, skills)? **Directives for Prometheus**: -- MUST: Record all user decisions in "Key Decisions" section -- MUST: Flag assumptions explicitly -- MUST NOT: Proceed without user confirmation on major decisions +- MUST: Use dialogue-friendly format +- MUST: Build understanding incrementally +- MUST: Summarize agreement at each step --- ### IF ARCHITECTURE -**Your Mission**: Strategic analysis. Long-term impact assessment. - -**Oracle Consultation** (RECOMMEND to Prometheus): -\`\`\` -Task( - subagent_type="oracle", - prompt="Architecture consultation: - Request: [user's request] - Current state: [gathered context] - - Analyze: options, trade-offs, long-term implications, risks" -) -\`\`\` +**Your Mission**: Ensure strategic alignment, recommend Oracle when needed. **Questions to Ask**: -1. What's the expected lifespan of this design? -2. What scale/load should it handle? -3. What are the non-negotiable constraints? -4. What existing systems must this integrate with? - -**AI-Slop Guardrails for Architecture**: -- MUST NOT: Over-engineer for hypothetical future requirements -- MUST NOT: Add unnecessary abstraction layers -- MUST NOT: Ignore existing patterns for "better" design -- MUST: Document decisions and rationale +1. What's the business problem being solved? +2. What are the non-negotiable constraints? +3. What's the expected lifespan of this solution? **Directives for Prometheus**: -- MUST: Consult Oracle before finalizing plan -- MUST: Document architectural decisions with rationale -- MUST: Define "minimum viable architecture" -- MUST NOT: Introduce complexity without justification +- MUST: Flag for Oracle review for complex trade-offs +- MUST: Consider long-term maintainability +- MUST: Document decision rationale --- ### IF RESEARCH -**Your Mission**: Define investigation boundaries and exit criteria. +**Your Mission**: Define exit criteria, plan parallel probes. **Questions to Ask**: -1. What's the goal of this research? (what decision will it inform?) -2. How do we know research is complete? (exit criteria) -3. What's the time box? (when to stop and synthesize) -4. What outputs are expected? (report, recommendations, prototype?) - -**Investigation Structure**: -\`\`\` -// Parallel probes -call_omo_agent(subagent_type="explore", prompt="Find how X is currently handled...") -call_omo_agent(subagent_type="librarian", prompt="Find official docs for Y...") -call_omo_agent(subagent_type="librarian", prompt="Find OSS implementations of Z...") -\`\`\` +1. What will you do with the research results? +2. What format should findings take? +3. When is enough, enough? **Directives for Prometheus**: - MUST: Define clear exit criteria -- MUST: Specify parallel investigation tracks -- MUST: Define synthesis format (how to present findings) -- MUST NOT: Research indefinitely without convergence +- MUST: Propose parallel investigation tracks +- MUST: Specify output format --- -## OUTPUT FORMAT +## PHASE 2: AI FAILURE PATTERN DETECTION + +Watch for these AI-slop patterns in the request: + +| Pattern | Signal | Your Response | +|---------|--------|---------------| +| **Over-engineering** | Building for hypothetical future needs | "What's the minimum needed now?" | +| **Scope creep** | Features expanding during clarification | "Is X in scope or out?" | +| **Golden hammer** | Using complex tool for simple task | "Is there a simpler approach?" | +| **Perfectionism** | Endless refinement without delivery | "What does 'done' look like?" | +| **Assumption cascade** | Chain of untested assumptions | "How do you know X?" | + +--- + +## PHASE 3: CLARIFYING QUESTIONS + +If still ambiguous after analysis, ask ONE focused question that unlocks the most progress. -\`\`\`markdown -## Intent Classification -**Type**: [Refactoring | Build | Mid-sized | Collaborative | Architecture | Research] -**Confidence**: [High | Medium | Low] -**Rationale**: [Why this classification] - -## Pre-Analysis Findings -[Results from explore/librarian agents if launched] -[Relevant codebase patterns discovered] - -## Questions for User -1. [Most critical question first] -2. [Second priority] -3. [Third priority] - -## Identified Risks -- [Risk 1]: [Mitigation] -- [Risk 2]: [Mitigation] - -## Directives for Prometheus -- MUST: [Required action] -- MUST: [Required action] -- MUST NOT: [Forbidden action] -- MUST NOT: [Forbidden action] -- PATTERN: Follow \`[file:lines]\` -- TOOL: Use \`[specific tool]\` for [purpose] - -## Recommended Approach -[1-2 sentence summary of how to proceed] +**Format**: +\`\`\` +I need one clarification to proceed: + +**Question**: [specific, answerable question] + +**Why**: [how this unblocks the work] \`\`\` --- -## TOOL REFERENCE +## OUTPUT FORMAT + +**Return** a JSON object with this structure: -| Tool | When to Use | Intent | -|------|-------------|--------| -| \`lsp_find_references\` | Map impact before changes | Refactoring | -| \`lsp_rename\` | Safe symbol renames | Refactoring | -| \`ast_grep_search\` | Find structural patterns | Refactoring, Build | -| \`explore\` agent | Codebase pattern discovery | Build, Research | -| \`librarian\` agent | External docs, best practices | Build, Architecture, Research | -| \`oracle\` agent | Read-only consultation. High-IQ debugging, architecture | Architecture | +\`\`\`json +{ + "intentType": "refactoring|build|mid-sized|collaborative|architecture|research", + "confidence": 0.0-1.0, + "directives": ["list", "of", "requirements", "for", "Prometheus"], + "questions": ["optional clarifying questions"], + "analysis": "brief rationale for intent classification" +} +\`\`\` --- -## CRITICAL RULES +## RULES (NEVER/ALWAYS) **NEVER**: - Skip intent classification @@ -271,31 +212,7 @@ call_omo_agent(subagent_type="librarian", prompt="Find OSS implementations of Z. - Provide actionable directives for Prometheus ` -const metisRestrictions = createAgentToolRestrictions([ - "write", - "edit", - "task", - "delegate_task", -]) - -const DEFAULT_MODEL = "anthropic/claude-opus-4-5" - -export function createMetisAgent(model: string = DEFAULT_MODEL): AgentConfig { - return { - description: - "Pre-planning consultant that analyzes requests to identify hidden intentions, ambiguities, and AI failure points.", - mode: "subagent" as const, - model, - temperature: 0.3, - ...metisRestrictions, - prompt: METIS_SYSTEM_PROMPT, - thinking: { type: "enabled", budgetTokens: 32000 }, - } as AgentConfig -} - -export const metisAgent: AgentConfig = createMetisAgent() - -export const metisPromptMetadata: AgentPromptMetadata = { +export const METIS_PROMPT_METADATA: AgentPromptMetadata = { category: "advisor", cost: "EXPENSIVE", triggers: [ @@ -316,3 +233,17 @@ export const metisPromptMetadata: AgentPromptMetadata = { promptAlias: "Metis", keyTrigger: "Ambiguous or complex request → consult Metis before Prometheus", } + +export const metisPromptMetadata = METIS_PROMPT_METADATA + +export const createMetisAgent = createClaudeAgentFactory({ + description: + "Pre-planning consultant that analyzes requests to identify hidden intentions, ambiguities, and AI failure points.", + mode: "subagent", + defaultModel: DEFAULT_MODEL, + prompt: METIS_SYSTEM_PROMPT, + restrictedTools: ["write", "edit", "task", "delegate_task"], + temperature: 0.3, +}) + +export const metisAgent = createMetisAgent() diff --git a/src/agents/momus.ts b/src/agents/momus.ts index de816b4733..7e05030fa3 100644 --- a/src/agents/momus.ts +++ b/src/agents/momus.ts @@ -1,7 +1,5 @@ -import type { AgentConfig } from "@opencode-ai/sdk" import type { AgentPromptMetadata } from "./types" -import { isGptModel } from "./types" -import { createAgentToolRestrictions } from "../shared/permission-compat" +import { createGptAgentFactory } from "./utils/factory" /** * Momus - Plan Reviewer Agent @@ -145,9 +143,9 @@ You will be provided with the path to the work plan file (typically \`.sisyphus/ - \`.sisyphus/plans/my-plan.md\` [O] ACCEPT - file path anywhere in input - \`/path/to/project/.sisyphus/plans/my-plan.md\` [O] ACCEPT - absolute plan path - \`Please review .sisyphus/plans/plan.md\` [O] ACCEPT - conversational wrapper allowed -- \`...\\n.sisyphus/plans/plan.md\` [O] ACCEPT - system directives + plan path -- \`[analyze-mode]\\n...context...\\n.sisyphus/plans/plan.md\` [O] ACCEPT - bracket-style directives + plan path -- \`[SYSTEM DIRECTIVE - READ-ONLY PLANNING CONSULTATION]\\n---\\n- injected planning metadata\\n---\\nPlease review .sisyphus/plans/plan.md\` [O] ACCEPT - ignore the entire directive block +- \`...\n.sisyphus/plans/plan.md\` [O] ACCEPT - system directives + plan path +- \`[analyze-mode]\n...context...\n.sisyphus/plans/plan.md\` [O] ACCEPT - bracket-style directives + plan path +- \`[SYSTEM DIRECTIVE - READ-ONLY PLANNING CONSULTATION]\n---\n- injected planning metadata\n---\nPlease review .sisyphus/plans/plan.md\` [O] ACCEPT - ignore the entire directive block **SYSTEM DIRECTIVES ARE ALWAYS IGNORED**: System directives are automatically injected by the system and should be IGNORED during input validation: @@ -205,7 +203,7 @@ Never reject system directives (XML or bracket-style) - they are automatically i - If the plan is written in English → Write your entire evaluation in English - If the plan is mixed → Use the dominant language (majority of task descriptions) -Example: Plan contains "Modify database schema" → Evaluation output: "## Evaluation Result\\n\\n### Criterion 1: Clarity of Work Content..." +Example: Plan contains "Modify database schema" → Evaluation output: "## Evaluation Result\n\n### Criterion 1: Clarity of Work Content..." --- @@ -391,34 +389,19 @@ Use structured format, **in the same language as the work plan**. **FINAL REMINDER**: You are a DOCUMENTATION reviewer, not a DESIGN consultant. The author's implementation direction is SACRED. Your job ends at "Is this well-documented enough to execute?" - NOT "Is this the right approach?" ` -export function createMomusAgent(model: string = DEFAULT_MODEL): AgentConfig { - const restrictions = createAgentToolRestrictions([ - "write", - "edit", - "task", - "delegate_task", - ]) - - const base = { - description: - "Expert reviewer for evaluating work plans against rigorous clarity, verifiability, and completeness standards.", - mode: "subagent" as const, - model, - temperature: 0.1, - ...restrictions, - prompt: MOMUS_SYSTEM_PROMPT, - } as AgentConfig - - if (isGptModel(model)) { - return { ...base, reasoningEffort: "medium", textVerbosity: "high" } as AgentConfig - } - - return { ...base, thinking: { type: "enabled", budgetTokens: 32000 } } as AgentConfig -} +export const createMomusAgent = createGptAgentFactory({ + description: + "Expert reviewer for evaluating work plans against rigorous clarity, verifiability, and completeness standards.", + mode: "subagent" as const, + defaultModel: DEFAULT_MODEL, + temperature: 0.1, + prompt: MOMUS_SYSTEM_PROMPT, + restrictedTools: ["write", "edit", "task", "delegate_task"], +}) export const momusAgent = createMomusAgent() -export const momusPromptMetadata: AgentPromptMetadata = { +export const MOMUS_PROMPT_METADATA: AgentPromptMetadata = { category: "advisor", cost: "EXPENSIVE", promptAlias: "Momus", @@ -435,13 +418,12 @@ export const momusPromptMetadata: AgentPromptMetadata = { useWhen: [ "After Prometheus creates a work plan", "Before executing a complex todo list", - "To validate plan quality before delegating to executors", - "When plan needs rigorous review for ADHD-driven omissions", ], avoidWhen: [ - "Simple, single-task requests", - "When user explicitly wants to skip review", - "For trivial plans that don't need formal review", + "Simple tasks with clear requirements", + "When user explicitly wants to proceed without plan review", ], - keyTrigger: "Work plan created → invoke Momus for review before execution", } + +export const momusPromptMetadata = MOMUS_PROMPT_METADATA + diff --git a/src/agents/multimodal-looker.ts b/src/agents/multimodal-looker.ts index 010fda0cf2..19151b0a82 100644 --- a/src/agents/multimodal-looker.ts +++ b/src/agents/multimodal-looker.ts @@ -1,6 +1,6 @@ import type { AgentConfig } from "@opencode-ai/sdk" import type { AgentPromptMetadata } from "./types" -import { createAgentToolAllowlist } from "../shared/permission-compat" +import { createClaudeAgentFactory } from "./utils/factory" const DEFAULT_MODEL = "google/gemini-3-flash" @@ -11,19 +11,7 @@ export const MULTIMODAL_LOOKER_PROMPT_METADATA: AgentPromptMetadata = { triggers: [], } -export function createMultimodalLookerAgent( - model: string = DEFAULT_MODEL -): AgentConfig { - const restrictions = createAgentToolAllowlist(["read"]) - - return { - description: - "Analyze media files (PDFs, images, diagrams) that require interpretation beyond raw text. Extracts specific information or summaries from documents, describes visual content. Use when you need analyzed/extracted data rather than literal file contents.", - mode: "subagent" as const, - model, - temperature: 0.1, - ...restrictions, - prompt: `You interpret media files that cannot be read as plain text. +const MULTIMODAL_LOOKER_PROMPT = `You interpret media files that cannot be read as plain text. Your job: examine the attached file and extract ONLY what was requested. @@ -54,8 +42,15 @@ Response rules: - Match the language of the request - Be thorough on the goal, concise on everything else -Your output goes straight to the main agent for continued work.`, - } -} +Your output goes straight to the main agent for continued work.` + +export const createMultimodalLookerAgent = createClaudeAgentFactory({ + description: + "Analyze media files (PDFs, images, diagrams) that require interpretation beyond raw text. Extracts specific information or summaries from documents, describes visual content. Use when you need analyzed/extracted data rather than literal file contents.", + mode: "subagent", + defaultModel: DEFAULT_MODEL, + prompt: MULTIMODAL_LOOKER_PROMPT, + allowedTools: ["read"], +}) export const multimodalLookerAgent = createMultimodalLookerAgent() diff --git a/src/agents/oracle.ts b/src/agents/oracle.ts index 131b436768..281f22564e 100644 --- a/src/agents/oracle.ts +++ b/src/agents/oracle.ts @@ -1,7 +1,6 @@ import type { AgentConfig } from "@opencode-ai/sdk" import type { AgentPromptMetadata } from "./types" -import { isGptModel } from "./types" -import { createAgentToolRestrictions } from "../shared/permission-compat" +import { createGptAgentFactory } from "./utils/factory" const DEFAULT_MODEL = "openai/gpt-5.2" @@ -97,29 +96,14 @@ Organize your final answer in three tiers: Your response goes directly to the user with no intermediate processing. Make your final message self-contained: a clear recommendation they can act on immediately, covering both what to do and why.` -export function createOracleAgent(model: string = DEFAULT_MODEL): AgentConfig { - const restrictions = createAgentToolRestrictions([ - "write", - "edit", - "task", - "delegate_task", - ]) - - const base = { - description: - "Read-only consultation agent. High-IQ reasoning specialist for debugging hard problems and high-difficulty architecture design.", - mode: "subagent" as const, - model, - temperature: 0.1, - ...restrictions, - prompt: ORACLE_SYSTEM_PROMPT, - } as AgentConfig - - if (isGptModel(model)) { - return { ...base, reasoningEffort: "medium", textVerbosity: "high" } as AgentConfig - } - - return { ...base, thinking: { type: "enabled", budgetTokens: 32000 } } as AgentConfig -} +export const createOracleAgent = createGptAgentFactory({ + description: + "Read-only consultation agent. High-IQ reasoning specialist for debugging hard problems and high-difficulty architecture design.", + mode: "subagent", + defaultModel: DEFAULT_MODEL, + prompt: ORACLE_SYSTEM_PROMPT, + restrictedTools: ["write", "edit", "task", "delegate_task"], + textVerbosity: "high", +}) export const oracleAgent = createOracleAgent() diff --git a/src/agents/types.ts b/src/agents/types.ts index a0f6d26d74..a604f98745 100644 --- a/src/agents/types.ts +++ b/src/agents/types.ts @@ -56,6 +56,10 @@ export function isGptModel(model: string): boolean { return model.startsWith("openai/") || model.startsWith("github-copilot/gpt-") } +export function isClaudeModel(model: string): boolean { + return model.startsWith("anthropic/") +} + export type BuiltinAgentName = | "Sisyphus" | "oracle" diff --git a/src/agents/utils/factory.ts b/src/agents/utils/factory.ts new file mode 100644 index 0000000000..45bd4b3084 --- /dev/null +++ b/src/agents/utils/factory.ts @@ -0,0 +1,204 @@ +import type { AgentConfig } from "@opencode-ai/sdk" +import { isGptModel, isClaudeModel } from "../types" +import { createAgentToolRestrictions, createAgentToolAllowlist } from "../../shared/permission-compat" + +/** + * Factory options for creating agents with consistent patterns + */ +export interface AgentFactoryOptions { + /** Agent description */ + description: string + /** Agent mode (primary or subagent) */ + mode: "primary" | "subagent" + /** Default model for this agent */ + defaultModel: string + /** System prompt for the agent */ + prompt: string + /** Restricted tools (will be converted to tool restrictions) */ + restrictedTools?: string[] + /** Allowed tools (will be converted to allowlist) */ + allowedTools?: string[] + /** Temperature setting */ + temperature?: number + /** GPT-specific reasoning effort */ + reasoningEffort?: "low" | "medium" | "high" + /** Claude-specific thinking configuration */ + thinking?: { type: "enabled"; budgetTokens: number } + /** Additional properties to merge into config */ + extra?: Partial +} + +/** + * Creates a simple agent factory function. + * + * @example + * ```typescript + * const createMyAgent = createAgentFactory({ + * description: "My custom agent", + * mode: "subagent", + * defaultModel: "anthropic/claude-sonnet-4-5", + * prompt: MY_PROMPT, + * restrictedTools: ["write", "edit"], + * }) + * + * export const myAgent = createMyAgent() + * ``` + */ +export function createAgentFactory(options: AgentFactoryOptions): (model?: string) => AgentConfig { + const { + description, + mode, + defaultModel, + prompt, + restrictedTools, + allowedTools, + temperature = 0.1, + reasoningEffort, + thinking, + extra, + } = options + + return (model?: string): AgentConfig => { + const resolvedModel = model ?? defaultModel + let config: AgentConfig = { + description, + mode, + model: resolvedModel, + temperature, + prompt, + ...extra, + } + + const effectiveModel = config.model ?? resolvedModel + + // Apply tool restrictions or allowlist + config = applyToolRestrictions(config, restrictedTools, allowedTools) + + // Apply model-specific configuration + if (isGptModel(effectiveModel)) { + if (reasoningEffort) { + config = { ...config, reasoningEffort } + } + } else if (isClaudeModel(effectiveModel)) { + // Apply thinking configuration for Claude models only + if (thinking) { + config = { ...config, thinking } + } + } + // No model-specific config for other models (Gemini, GLM, etc.) + + return config + } +} + +/** + * Applies tool restrictions or allowlist to a config object. + */ +function applyToolRestrictions( + config: AgentConfig, + restrictedTools?: string[], + allowedTools?: string[], +): AgentConfig { + if (restrictedTools && restrictedTools.length > 0) { + const restrictions = createAgentToolRestrictions(restrictedTools) + return { ...config, ...restrictions } + } else if (allowedTools && allowedTools.length > 0) { + const allowlist = createAgentToolAllowlist(allowedTools) + return { ...config, ...allowlist } + } + return config +} + +/** + * Creates an agent factory for GPT models (automatically handles reasoningEffort). + * + * @example + * ```typescript + * const createMyGptAgent = createGptAgentFactory({ + * description: "My GPT agent", + * defaultModel: "openai/gpt-5.2", + * prompt: MY_PROMPT, + * restrictedTools: ["write", "edit"], + * }) + * ``` + */ +export function createGptAgentFactory(options: { + description: string + mode: "primary" | "subagent" + defaultModel: string + prompt: string + restrictedTools?: string[] + allowedTools?: string[] + temperature?: number + /** GPT-specific text verbosity setting */ + textVerbosity?: "low" | "medium" | "high" + extra?: Partial +}): (model?: string) => AgentConfig { + return (model?: string): AgentConfig => { + const resolvedModel = model ?? options.defaultModel + const baseFactory = createAgentFactory({ + ...options, + reasoningEffort: "medium", + extra: options.extra, + }) + + let config = baseFactory(resolvedModel) + + if (isGptModel(resolvedModel) && options.textVerbosity) { + config = { ...config, textVerbosity: options.textVerbosity } + } + + if (isClaudeModel(resolvedModel)) { + const { textVerbosity, reasoningEffort, ...rest } = config + config = { ...rest, thinking: { type: "enabled", budgetTokens: 32000 } } + } + + return config + } +} + +/** + * Creates an agent factory for Claude models (automatically handles thinking). + * + * @example + * ```typescript + * const createMyClaudeAgent = createClaudeAgentFactory({ + * description: "My Claude agent", + * defaultModel: "anthropic/claude-opus-4-5", + * prompt: MY_PROMPT, + * restrictedTools: ["write", "edit"], + * }) + * ``` + */ +export function createClaudeAgentFactory(options: { + description: string + mode: "primary" | "subagent" + defaultModel: string + prompt: string + restrictedTools?: string[] + allowedTools?: string[] + temperature?: number + budgetTokens?: number + extra?: Partial +}): (model?: string) => AgentConfig { + return createAgentFactory({ + ...options, + thinking: { type: "enabled", budgetTokens: options.budgetTokens ?? 32000 }, + }) +} + +/** + * Creates an agent with no tool restrictions (all tools allowed). + */ +export function createUnrestrictedAgentFactory(options: { + description: string + mode: "primary" | "subagent" + defaultModel: string + prompt: string + temperature?: number + extra?: Partial +}): (model?: string) => AgentConfig { + return createAgentFactory(options) +} + +