YeonGyu-Kim a691a3ac0a refactor: migrate delegate_task to task tool with metadata fixes
- Rename delegate_task tool to task across codebase (100 files)
- Update model references: claude-opus-4-6 → 4-5, gpt-5.3-codex → 5.2-codex
- Add tool-metadata-store to restore metadata overwritten by fromPlugin()
- Add session ID polling for BackgroundManager task sessions
- Await async ctx.metadata() calls in tool executors
- Add ses_ prefix guard to getMessageDir for performance
- Harden BackgroundManager with idle deferral and error handling
- Fix duplicate task key in sisyphus-junior test object literals
- Fix unawaited showOutputToUser in ast_grep_replace
- Fix background=true → run_in_background=true in ultrawork prompt
- Fix duplicate task/task references in docs and comments
2026-02-06 21:35:30 +09:00

137 lines
3.8 KiB
TypeScript

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: "load_skills",
errorType: "missing_load_skills",
fixHint: "Add load_skills=[] parameter (empty array if no skills needed). Note: Calling Skill tool does NOT populate this.",
},
{
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 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("[ERROR]") && !output.includes("Invalid arguments")) 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 `[task ERROR] Fix the error and retry with correct parameters.`
}
let guidance = `
[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 task NOW with corrected parameters.
Example of CORRECT call:
\`\`\`
task(
description="Task description",
prompt="Detailed prompt...",
category="unspecified-low", // OR subagent_type="explore"
run_in_background=false,
load_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() !== "task") return
const errorInfo = detectDelegateTaskError(output.output)
if (errorInfo) {
const guidance = buildRetryGuidance(errorInfo)
output.output += `\n${guidance}`
}
},
}
}