Why Self-Correction is Essential for Agency§

When human developers encounter a compiler error or an API response error, they do not give up immediately. They read the error traceback, adjust function arguments, fix missing syntax, and re-execute.

Conversely, naive LLM tool-calling implementations crash as soon as a tool invocation throws an exception. To build resilient autonomous agents, developers must construct Self-Correction Loops that treat runtime errors as feedback signals rather than fatal crashes.

---

Architecture of a Self-Correction Execution Engine§

[ Agent Prompt ] ➔ [ LLM Tool Call Generation ] 
                 ➔ [ Execute Tool ]
                        │
             ┌──────────┴──────────┐
             ▼                     ▼
       ( Success )            ( Exception )
             │                     │
             ▼                     ▼
     [ Return Result ]   [ Format Error Stack Trace ]
                                   │
                                   ▼
                         [ Re-Prompt LLM (Attempt N+1) ]

TypeScript Self-Correction Middleware Example§

export async function executeToolWithSelfCorrection(
  llmClient: any,
  toolMap: Record<string, Function>,
  initialMessages: any[],
  maxRetries = 3
) {
  let messages = [...initialMessages];

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    const response = await llmClient.chat.completions.create({
      model: "gpt-4o",
      messages,
      tools: Object.values(toolMap).map(t => t.schema),
    });

    const choice = response.choices[0].message;
    if (!choice.tool_calls || choice.tool_calls.length === 0) {
      return choice.content;
    }

    messages.push(choice);
    for (const call of choice.tool_calls) {
      const tool = toolMap[call.function.name];
      try {
        const args = JSON.parse(call.function.arguments);
        const result = await tool.execute(args);
        messages.push({
          role: "tool",
          tool_call_id: call.id,
          content: JSON.stringify(result),
        });
      } catch (err: any) {
        console.warn(`Tool ${call.function.name} failed: ${err.message}`);
        messages.push({
          role: "tool",
          tool_call_id: call.id,
          content: JSON.stringify({
            error: true,
            message: err.message,
            hint: "Review parameter schema and correct argument values.",
          }),
        });
      }
    }
  }

  throw new Error(`Agent failed to self-correct after ${maxRetries} attempts.`);
}