Major improvements to agent task completion detection: - No more guessing when tasks are done based on heuristics - Agents must explicitly call 'task_completed' tool - Added 'need_more_information' tool for clarification requests Advanced patterns from OpenAI SDK: - Tool approval mechanism with interactive prompts - Lifecycle hooks for observability (agent_start, tool_start, etc.) - Metrics collection for performance monitoring - Proper state management and event-driven architecture Fixes: - Fixed shell command deadlock by using async pipe reading - Fixed premature task completion after 3 iterations - Only show timeout info for non-default values in CLI Documentation: - Comprehensive guide in docs/agent-patterns.md - Migration guide for existing agents - Best practices and examples 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
4.9 KiB
4.9 KiB
Agent Patterns Documentation
This document describes the advanced agent patterns implemented in Peekaboo, inspired by the OpenAI SDK.
Table of Contents
Explicit Task Completion
Problem
Previously, the agent would guess when a task was complete based on:
- Iteration count and content length
- Magic phrases like "task is done"
- Detecting "finishing" tools like
say
This led to premature completion when agents were explaining their plans.
Solution
Agents now must explicitly signal completion using dedicated tools:
task_completed Tool
// Agent must call this when done
{
"name": "task_completed",
"arguments": {
"summary": "Converted ODS file to Markdown and sent email with poem",
"success": true,
"next_steps": "Consider installing pandoc for faster conversions"
}
}
need_more_information Tool
// Agent calls this when blocked
{
"name": "need_more_information",
"arguments": {
"question": "Which email account should I use to send the message?",
"context": "Multiple email accounts are configured"
}
}
Implementation
- Tools defined in
CompletionTools.swift - System prompt updated to require these tools
- AgentRunner checks for
task_completedtool call - CLI displays completion summary prominently
Tool Approval Mechanism
Configuration
let config = ToolApprovalConfig(
requiresApproval: ["shell", "delete_file"],
alwaysApproved: ["screenshot", "list_apps"],
alwaysRejected: ["rm -rf /"],
approvalHandler: InteractiveApprovalHandler()
)
Interactive Approval
When a tool requires approval:
⚠️ Tool Approval Required
Tool: shell
Arguments: {"command": "rm important-file.txt"}
Context: User requested file deletion
Approve? [y/n/always/never]:
Approval Results
approved: Allow this executionrejected: Block this executionapprovedAlways: Allow all future calls to this toolrejectedAlways: Block all future calls to this tool
Lifecycle Hooks
Events
public enum AgentLifecycleEvent {
case agentStarted(agent: String, context: String?)
case agentEnded(agent: String, output: String?)
case toolStarted(name: String, arguments: String)
case toolEnded(name: String, result: String, success: Bool)
case iterationStarted(number: Int)
case iterationCompleted(number: Int)
case errorOccurred(error: Error, context: String?)
}
Handlers
Console Logger
let consoleHandler = ConsoleLifecycleHandler(
verbose: true,
includeTimestamps: true
)
Output:
[14:23:45.123] 🚀 Agent 'Peekaboo Assistant' started
[14:23:45.234] 🔧 Tool 'screenshot' started
[14:23:45.567] 🔧 Tool 'screenshot' ✓
[14:23:46.789] ✅ Agent 'Peekaboo Assistant' completed
Metrics Collector
let metricsHandler = MetricsLifecycleHandler()
// After execution
let metrics = await metricsHandler.getMetrics()
print("Total tool calls: \(metrics.totalToolCalls)")
print("Average execution time: \(metrics.executionTimes.average)")
Custom Handlers
actor CustomHandler: AgentLifecycleHandler {
func handle(event: AgentLifecycleEvent) async {
switch event {
case .toolStarted(let name, _) where name == "shell":
// Log shell commands to audit trail
await AuditLog.record("Shell command executed")
default:
break
}
}
}
Best Practices
1. Always Use Completion Tools
- Don't rely on heuristics
- Agents must explicitly call
task_completed - Handle
need_more_informationgracefully
2. Configure Tool Approvals
- Require approval for destructive operations
- Auto-approve read-only operations
- Let users set permanent preferences
3. Add Lifecycle Handlers
- Use console handler for debugging
- Add metrics handler for performance monitoring
- Create custom handlers for audit trails
4. Error Handling
- Lifecycle events include error cases
- Tool errors don't stop execution
- Approval rejections are handled gracefully
Migration Guide
Updating Existing Agents
- Add completion tools to your tool list
- Update system prompt to mention completion requirement
- Test that agents call
task_completed
Adding Approvals
- Create
ToolApprovalConfig - Pass to agent during creation
- Implement custom approval handler if needed
Adding Lifecycle Tracking
- Create handlers for your needs
- Add to
LifecycleManager - Events will automatically flow
Future Enhancements
- Agent Handoffs: Transfer control between specialized agents
- Guardrails: Input/output validation with tripwires
- Structured Output: Type-safe outputs with schemas
- Persistence: Save and restore approval preferences
- Web UI: Visual approval interface