import type { PluginInput } from "@opencode-ai/plugin" export interface DelegateTaskErrorPattern { pattern: string errorType: string fixHint: string } export const DELEGATE_TASK_ERROR_PATTERNS: DelegateTaskErrorPattern[] = [ { pattern: "run_in_background", errorType: "missing_run_in_background", fixHint: "Add run_in_background=false (for delegation) or run_in_background=true (for parallel exploration)", }, { pattern: "skills", errorType: "missing_skills", fixHint: "Add skills=[] parameter (empty array if no skills needed)", }, { pattern: "category OR subagent_type", errorType: "mutual_exclusion", fixHint: "Provide ONLY one of: category (e.g., 'general', 'quick') OR subagent_type (e.g., 'oracle', 'explore')", }, { pattern: "Must provide either category or subagent_type", errorType: "missing_category_or_agent", fixHint: "Add either category='general' OR subagent_type='explore'", }, { pattern: "Unknown category", errorType: "unknown_category", fixHint: "Use a valid category from the Available list in the error message", }, { pattern: "Agent name cannot be empty", errorType: "empty_agent", fixHint: "Provide a non-empty subagent_type value", }, { pattern: "Unknown agent", errorType: "unknown_agent", fixHint: "Use a valid agent from the Available agents list in the error message", }, { pattern: "Cannot call primary agent", errorType: "primary_agent", fixHint: "Primary agents cannot be called via delegate_task. Use a subagent like 'explore', 'oracle', or 'librarian'", }, { pattern: "Skills not found", errorType: "unknown_skills", fixHint: "Use valid skill names from the Available list in the error message", }, ] export interface DetectedError { errorType: string originalOutput: string } export function detectDelegateTaskError(output: string): DetectedError | null { if (!output.includes("❌")) return null for (const errorPattern of DELEGATE_TASK_ERROR_PATTERNS) { if (output.includes(errorPattern.pattern)) { return { errorType: errorPattern.errorType, originalOutput: output, } } } return null } function extractAvailableList(output: string): string | null { const availableMatch = output.match(/Available[^:]*:\s*(.+)$/m) return availableMatch ? availableMatch[1].trim() : null } export function buildRetryGuidance(errorInfo: DetectedError): string { const pattern = DELEGATE_TASK_ERROR_PATTERNS.find( (p) => p.errorType === errorInfo.errorType ) if (!pattern) { return `[delegate_task ERROR] Fix the error and retry with correct parameters.` } let guidance = ` [delegate_task CALL FAILED - IMMEDIATE RETRY REQUIRED] **Error Type**: ${errorInfo.errorType} **Fix**: ${pattern.fixHint} ` const availableList = extractAvailableList(errorInfo.originalOutput) if (availableList) { guidance += `\n**Available Options**: ${availableList}\n` } guidance += ` **Action**: Retry delegate_task NOW with corrected parameters. Example of CORRECT call: \`\`\` delegate_task( description="Task description", prompt="Detailed prompt...", category="unspecified-low", // OR subagent_type="explore" run_in_background=false, skills=[] ) \`\`\` ` return guidance } export function createDelegateTaskRetryHook(_ctx: PluginInput) { return { "tool.execute.after": async ( input: { tool: string; sessionID: string; callID: string }, output: { title: string; output: string; metadata: unknown } ) => { if (input.tool.toLowerCase() !== "delegate_task") return const errorInfo = detectDelegateTaskError(output.output) if (errorInfo) { const guidance = buildRetryGuidance(errorInfo) output.output += `\n${guidance}` } }, } }