Examples: Nested Agents (Agent-as-Tool)
Table of Contents
- 01_basic_delegation - Agent-as-tool with AgentIDs field
- 02_specialist_agents - Multiple specialists with orchestrator
- 03_multi_level_hierarchy - 3-level PM -> Lead -> Worker
01_basic_delegation
Basic agent-as-tool: research specialist delegated from orchestrator via AgentIDs.
package main
import (
"context"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/youssefsiam38/agentpg"
"github.com/youssefsiam38/agentpg/driver/pgxv5"
)
func main() {
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer cancel()
pool, _ := pgxpool.New(ctx, os.Getenv("DATABASE_URL"))
defer pool.Close()
drv := pgxv5.New(pool)
client, _ := agentpg.NewClient(drv, &agentpg.ClientConfig{APIKey: os.Getenv("ANTHROPIC_API_KEY")})
client.Start(ctx)
defer client.Stop(context.Background())
maxTokens := 10000
// Create child agent FIRST (research specialist)
researchSpecialist, err := client.CreateAgent(ctx, &agentpg.AgentDefinition{
Name: "research-specialist",
Description: "A research specialist for detailed analysis",
Model: "claude-sonnet-4-5-20250929",
SystemPrompt: `You are a research specialist. Your role is to:
1. Analyze topics thoroughly
2. Provide detailed explanations with examples
3. Break down complex concepts into understandable parts`,
MaxTokens: &maxTokens,
})
if err != nil {
log.Fatal(err)
}
// Create parent orchestrator with delegation via AgentIDs
orchestrator, err := client.CreateAgent(ctx, &agentpg.AgentDefinition{
Name: "orchestrator",
Description: "Main assistant that can delegate to specialists",
Model: "claude-sonnet-4-5-20250929",
SystemPrompt: `You are a helpful assistant that can delegate research tasks to a specialist.
When users ask for detailed information, use the research agent tool.
For simple questions, answer directly without delegation.`,
AgentIDs: []uuid.UUID{researchSpecialist.ID}, // research-specialist becomes a callable tool
MaxTokens: &maxTokens,
})
if err != nil {
log.Fatal(err)
}
sessionID, _ := client.NewSession(ctx, nil, nil)
// Simple question - no delegation
resp1, _ := client.RunSync(ctx, sessionID, orchestrator.ID, "What is 2 + 2?", nil)
for _, block := range resp1.Message.Content {
if block.Type == agentpg.ContentTypeText {
fmt.Println(block.Text)
}
}
// Research question - triggers delegation to research-specialist
resp2, _ := client.RunSync(ctx, sessionID, orchestrator.ID,
"Can you research and explain how neural networks learn?", nil)
for _, block := range resp2.Message.Content {
if block.Type == agentpg.ContentTypeText {
fmt.Println(block.Text)
}
}
}
02_specialist_agents
Multiple specialists (code, data, research) with own tools, coordinated by orchestrator.
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"os/signal"
"strings"
"syscall"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/youssefsiam38/agentpg"
"github.com/youssefsiam38/agentpg/driver/pgxv5"
"github.com/youssefsiam38/agentpg/tool"
)
type CodeAnalysisTool struct{}
func (c *CodeAnalysisTool) Name() string { return "analyze_code" }
func (c *CodeAnalysisTool) Description() string { return "Analyze code for patterns and issues" }
func (c *CodeAnalysisTool) InputSchema() tool.ToolSchema {
return tool.ToolSchema{
Type: "object",
Properties: map[string]tool.PropertyDef{
"code": {Type: "string", Description: "The code to analyze"},
"language": {Type: "string", Enum: []string{"go", "python", "javascript", "typescript"}},
},
Required: []string{"code", "language"},
}
}
func (c *CodeAnalysisTool) Execute(ctx context.Context, input json.RawMessage) (string, error) {
var params struct {
Code string `json:"code"`
Language string `json:"language"`
}
json.Unmarshal(input, ¶ms)
lines := strings.Count(params.Code, "\n") + 1
return fmt.Sprintf("Code Analysis (%s):\n- Lines: %d\n- Language: %s", params.Language, lines, params.Language), nil
}
type DataQueryTool struct{}
func (d *DataQueryTool) Name() string { return "query_data" }
func (d *DataQueryTool) Description() string {
return "Query and analyze datasets (simulated)"
}
func (d *DataQueryTool) InputSchema() tool.ToolSchema {
return tool.ToolSchema{
Type: "object",
Properties: map[string]tool.PropertyDef{
"dataset": {Type: "string", Enum: []string{"sales", "users", "products", "logs"}},
"operation": {Type: "string", Enum: []string{"count", "average", "sum", "list"}},
},
Required: []string{"dataset", "operation"},
}
}
func (d *DataQueryTool) Execute(ctx context.Context, input json.RawMessage) (string, error) {
var params struct {
Dataset string `json:"dataset"`
Operation string `json:"operation"`
}
json.Unmarshal(input, ¶ms)
data := map[string]map[string]string{
"sales": {"count": "Total records: 15,432", "sum": "Total revenue: $1,967,100"},
"users": {"count": "Total users: 5,892", "average": "Average age: 34.2 years"},
}
if result, ok := data[params.Dataset][params.Operation]; ok {
return result, nil
}
return "No data found", nil
}
type SearchTool struct{}
func (s *SearchTool) Name() string { return "search_knowledge" }
func (s *SearchTool) Description() string { return "Search knowledge base for information" }
func (s *SearchTool) InputSchema() tool.ToolSchema {
return tool.ToolSchema{
Type: "object",
Properties: map[string]tool.PropertyDef{
"query": {Type: "string", Description: "Search query"},
"domain": {Type: "string", Enum: []string{"technology", "science", "business", "general"}},
},
Required: []string{"query"},
}
}
func (s *SearchTool) Execute(ctx context.Context, input json.RawMessage) (string, error) {
var params struct {
Query string `json:"query"`
Domain string `json:"domain"`
}
json.Unmarshal(input, ¶ms)
return fmt.Sprintf("Search results for '%s' in %s domain:\n1. Relevant article\n2. Documentation\n3. Tutorial",
params.Query, params.Domain), nil
}
func main() {
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer cancel()
pool, _ := pgxpool.New(ctx, os.Getenv("DATABASE_URL"))
defer pool.Close()
drv := pgxv5.New(pool)
client, _ := agentpg.NewClient(drv, &agentpg.ClientConfig{APIKey: os.Getenv("ANTHROPIC_API_KEY")})
// Register all tools
client.RegisterTool(&CodeAnalysisTool{})
client.RegisterTool(&DataQueryTool{})
client.RegisterTool(&SearchTool{})
client.Start(ctx)
defer client.Stop(context.Background())
maxTokens := 2048
// Specialist agents with their own tools
codeSpecialist, _ := client.CreateAgent(ctx, &agentpg.AgentDefinition{
Name: "code-specialist", Description: "Code analysis specialist",
Model: "claude-sonnet-4-5-20250929",
SystemPrompt: "You are a code analysis specialist. Use analyze_code to get metrics.",
Tools: []string{"analyze_code"}, MaxTokens: &maxTokens,
})
dataSpecialist, _ := client.CreateAgent(ctx, &agentpg.AgentDefinition{
Name: "data-specialist", Description: "Data analysis specialist",
Model: "claude-sonnet-4-5-20250929",
SystemPrompt: "You are a data analysis specialist. Query data before providing insights.",
Tools: []string{"query_data"}, MaxTokens: &maxTokens,
})
researchSpecialist, _ := client.CreateAgent(ctx, &agentpg.AgentDefinition{
Name: "research-specialist", Description: "Research and knowledge specialist",
Model: "claude-sonnet-4-5-20250929",
SystemPrompt: "You are a research specialist. Use search_knowledge to find information.",
Tools: []string{"search_knowledge"}, MaxTokens: &maxTokens,
})
// Orchestrator delegates to specialists (no direct tools)
orchestrator, _ := client.CreateAgent(ctx, &agentpg.AgentDefinition{
Name: "orchestrator", Description: "Orchestrator that coordinates specialists",
Model: "claude-sonnet-4-5-20250929",
SystemPrompt: `You are an orchestrator. Delegate tasks to specialists:
- Code Agent: code analysis and reviews
- Data Agent: data analysis and queries
- Research Agent: general research`,
AgentIDs: []uuid.UUID{codeSpecialist.ID, dataSpecialist.ID, researchSpecialist.ID},
MaxTokens: &maxTokens,
})
sessionID, _ := client.NewSession(ctx, nil, nil)
// Code question -> delegates to code-specialist
resp, _ := client.RunSync(ctx, sessionID, orchestrator.ID,
"Analyze this Go code:\nfunc fibonacci(n int) int {\n if n <= 1 { return n }\n return fibonacci(n-1) + fibonacci(n-2)\n}", nil)
for _, block := range resp.Message.Content {
if block.Type == agentpg.ContentTypeText {
fmt.Println(block.Text)
}
}
// Data question -> delegates to data-specialist
resp, _ = client.RunSync(ctx, sessionID, orchestrator.ID,
"What are our total sales and how many users do we have?", nil)
for _, block := range resp.Message.Content {
if block.Type == agentpg.ContentTypeText {
fmt.Println(block.Text)
}
}
}
03_multi_level_hierarchy
3-level hierarchy: Project Manager -> Team Leads -> Workers with specialized tools.
Architecture:
Level 1 (Project Manager)
|-- Engineering Lead (Level 2)
| |-- Frontend Developer (Level 3) [lint_frontend]
| |-- Backend Developer (Level 3) [run_tests]
| +-- Database Specialist (Level 3) [run_migration]
+-- Design Lead (Level 2)
+-- UX Designer (Level 3) [review_design]
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/youssefsiam38/agentpg"
"github.com/youssefsiam38/agentpg/driver/pgxv5"
"github.com/youssefsiam38/agentpg/tool"
)
// Level 3 tools
type FrontendLintTool struct{}
func (f *FrontendLintTool) Name() string { return "lint_frontend" }
func (f *FrontendLintTool) Description() string { return "Lint frontend code for issues" }
func (f *FrontendLintTool) InputSchema() tool.ToolSchema {
return tool.ToolSchema{
Type: "object",
Properties: map[string]tool.PropertyDef{"code": {Type: "string"}},
Required: []string{"code"},
}
}
func (f *FrontendLintTool) Execute(ctx context.Context, input json.RawMessage) (string, error) {
return "Frontend lint passed: No ESLint warnings. React best practices followed.", nil
}
type BackendTestTool struct{}
func (b *BackendTestTool) Name() string { return "run_tests" }
func (b *BackendTestTool) Description() string { return "Run backend tests" }
func (b *BackendTestTool) InputSchema() tool.ToolSchema {
return tool.ToolSchema{
Type: "object",
Properties: map[string]tool.PropertyDef{"package": {Type: "string"}},
Required: []string{"package"},
}
}
func (b *BackendTestTool) Execute(ctx context.Context, input json.RawMessage) (string, error) {
return "Tests passed: 45/45 tests passed. Coverage: 87%.", nil
}
type DatabaseMigrationTool struct{}
func (d *DatabaseMigrationTool) Name() string { return "run_migration" }
func (d *DatabaseMigrationTool) Description() string { return "Run database migration" }
func (d *DatabaseMigrationTool) InputSchema() tool.ToolSchema {
return tool.ToolSchema{
Type: "object",
Properties: map[string]tool.PropertyDef{"migration": {Type: "string"}},
Required: []string{"migration"},
}
}
func (d *DatabaseMigrationTool) Execute(ctx context.Context, input json.RawMessage) (string, error) {
return "Migration completed: Applied 3 pending migrations. Schema up to date.", nil
}
type DesignReviewTool struct{}
func (d *DesignReviewTool) Name() string { return "review_design" }
func (d *DesignReviewTool) Description() string { return "Review UI/UX design" }
func (d *DesignReviewTool) InputSchema() tool.ToolSchema {
return tool.ToolSchema{
Type: "object",
Properties: map[string]tool.PropertyDef{"component": {Type: "string"}},
Required: []string{"component"},
}
}
func (d *DesignReviewTool) Execute(ctx context.Context, input json.RawMessage) (string, error) {
return "Design review: Accessibility score 94/100. Color contrast meets WCAG 2.1 AA.", nil
}
func main() {
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer cancel()
pool, _ := pgxpool.New(ctx, os.Getenv("DATABASE_URL"))
defer pool.Close()
drv := pgxv5.New(pool)
client, _ := agentpg.NewClient(drv, &agentpg.ClientConfig{
APIKey: os.Getenv("ANTHROPIC_API_KEY"), Name: "hierarchy-demo",
})
// Register all tools BEFORE Start
client.RegisterTool(&FrontendLintTool{})
client.RegisterTool(&BackendTestTool{})
client.RegisterTool(&DatabaseMigrationTool{})
client.RegisterTool(&DesignReviewTool{})
client.Start(ctx)
defer client.Stop(context.Background())
maxW, maxL, maxM := 1024, 1536, 2048
// Level 3: Workers with specialized tools
frontendDev, _ := client.CreateAgent(ctx, &agentpg.AgentDefinition{
Name: "frontend-developer", Description: "Frontend developer specialist for React/TypeScript",
Model: "claude-sonnet-4-5-20250929",
SystemPrompt: "You are a frontend developer. Use lint_frontend to check code quality.",
Tools: []string{"lint_frontend"}, MaxTokens: &maxW,
})
backendDev, _ := client.CreateAgent(ctx, &agentpg.AgentDefinition{
Name: "backend-developer", Description: "Backend developer specialist for Go/APIs",
Model: "claude-sonnet-4-5-20250929",
SystemPrompt: "You are a backend developer. Use run_tests to verify code.",
Tools: []string{"run_tests"}, MaxTokens: &maxW,
})
dbSpecialist, _ := client.CreateAgent(ctx, &agentpg.AgentDefinition{
Name: "database-specialist", Description: "Database specialist for schemas and migrations",
Model: "claude-sonnet-4-5-20250929",
SystemPrompt: "You are a database specialist. Use run_migration for schema changes.",
Tools: []string{"run_migration"}, MaxTokens: &maxW,
})
uxDesigner, _ := client.CreateAgent(ctx, &agentpg.AgentDefinition{
Name: "ux-designer", Description: "UX designer for accessibility and design",
Model: "claude-sonnet-4-5-20250929",
SystemPrompt: "You are a UX designer. Use review_design for accessibility checks.",
Tools: []string{"review_design"}, MaxTokens: &maxW,
})
// Level 2: Team leads delegate to workers
engineeringLead, _ := client.CreateAgent(ctx, &agentpg.AgentDefinition{
Name: "engineering-lead", Description: "Engineering team lead coordinating technical work",
Model: "claude-sonnet-4-5-20250929",
SystemPrompt: "You are the Engineering Team Lead. Coordinate frontend, backend, and database work.",
AgentIDs: []uuid.UUID{frontendDev.ID, backendDev.ID, dbSpecialist.ID}, MaxTokens: &maxL,
})
designLead, _ := client.CreateAgent(ctx, &agentpg.AgentDefinition{
Name: "design-lead", Description: "Design team lead coordinating UX work",
Model: "claude-sonnet-4-5-20250929",
SystemPrompt: "You are the Design Team Lead. Coordinate design and UX work.",
AgentIDs: []uuid.UUID{uxDesigner.ID}, MaxTokens: &maxL,
})
// Level 1: Project Manager delegates to leads
pm, _ := client.CreateAgent(ctx, &agentpg.AgentDefinition{
Name: "project-manager", Description: "Project manager coordinating all teams",
Model: "claude-sonnet-4-5-20250929",
SystemPrompt: `You are the Project Manager. Your direct reports:
- Engineering Lead: Manages frontend, backend, and database teams
- Design Lead: Manages UX and design team
Break tasks down and delegate appropriately.`,
AgentIDs: []uuid.UUID{engineeringLead.ID, designLead.ID}, MaxTokens: &maxM,
})
sessionID, _ := client.NewSession(ctx, nil, nil)
// Full project status - cascades through all 3 levels
resp, _ := client.RunFastSync(ctx, sessionID, pm.ID,
"Get a complete status update on the user auth feature. Check engineering on code quality and tests, and design on login page accessibility.", nil)
if resp.Message != nil {
for _, block := range resp.Message.Content {
if block.Type == agentpg.ContentTypeText {
fmt.Println(block.Text)
}
}
}
}