ai-agents 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.claude/commands/bump-version.md +44 -0
- data/CHANGELOG.md +35 -0
- data/CLAUDE.md +59 -15
- data/README.md +29 -106
- data/docs/Gemfile +14 -0
- data/docs/Gemfile.lock +183 -0
- data/docs/_config.yml +53 -0
- data/docs/_sass/color_schemes/ruby.scss +72 -0
- data/docs/_sass/custom/custom.scss +93 -0
- data/docs/architecture.md +353 -0
- data/docs/assets/fonts/InterVariable.woff2 +0 -0
- data/docs/concepts/agent-tool.md +166 -0
- data/docs/concepts/agents.md +43 -0
- data/docs/concepts/callbacks.md +42 -0
- data/docs/concepts/context.md +110 -0
- data/docs/concepts/handoffs.md +81 -0
- data/docs/concepts/runner.md +87 -0
- data/docs/concepts/tools.md +62 -0
- data/docs/concepts.md +22 -0
- data/docs/guides/agent-as-tool-pattern.md +242 -0
- data/docs/guides/multi-agent-systems.md +261 -0
- data/docs/guides/rails-integration.md +440 -0
- data/docs/guides/state-persistence.md +451 -0
- data/docs/guides.md +18 -0
- data/docs/index.md +97 -0
- data/examples/collaborative-copilot/README.md +169 -0
- data/examples/collaborative-copilot/agents/analysis_agent.rb +48 -0
- data/examples/collaborative-copilot/agents/answer_suggestion_agent.rb +50 -0
- data/examples/collaborative-copilot/agents/copilot_orchestrator.rb +85 -0
- data/examples/collaborative-copilot/agents/integrations_agent.rb +58 -0
- data/examples/collaborative-copilot/agents/research_agent.rb +52 -0
- data/examples/collaborative-copilot/data/contacts.json +47 -0
- data/examples/collaborative-copilot/data/conversations.json +170 -0
- data/examples/collaborative-copilot/data/knowledge_base.json +58 -0
- data/examples/collaborative-copilot/data/linear_issues.json +83 -0
- data/examples/collaborative-copilot/data/stripe_billing.json +71 -0
- data/examples/collaborative-copilot/interactive.rb +90 -0
- data/examples/collaborative-copilot/tools/create_linear_ticket_tool.rb +58 -0
- data/examples/collaborative-copilot/tools/get_article_tool.rb +41 -0
- data/examples/collaborative-copilot/tools/get_contact_tool.rb +51 -0
- data/examples/collaborative-copilot/tools/get_conversation_tool.rb +53 -0
- data/examples/collaborative-copilot/tools/get_stripe_billing_tool.rb +44 -0
- data/examples/collaborative-copilot/tools/search_contacts_tool.rb +57 -0
- data/examples/collaborative-copilot/tools/search_conversations_tool.rb +54 -0
- data/examples/collaborative-copilot/tools/search_knowledge_base_tool.rb +55 -0
- data/examples/collaborative-copilot/tools/search_linear_issues_tool.rb +60 -0
- data/examples/isp-support/interactive.rb +43 -4
- data/lib/agents/agent.rb +34 -0
- data/lib/agents/agent_runner.rb +66 -1
- data/lib/agents/agent_tool.rb +113 -0
- data/lib/agents/callback_manager.rb +54 -0
- data/lib/agents/handoff.rb +8 -34
- data/lib/agents/message_extractor.rb +82 -0
- data/lib/agents/run_context.rb +5 -2
- data/lib/agents/runner.rb +16 -27
- data/lib/agents/tool_wrapper.rb +11 -1
- data/lib/agents/version.rb +1 -1
- data/lib/agents.rb +3 -0
- metadata +48 -1
@@ -0,0 +1,242 @@
|
|
1
|
+
---
|
2
|
+
layout: default
|
3
|
+
title: Agent-as-Tool Pattern
|
4
|
+
parent: Guides
|
5
|
+
nav_order: 4
|
6
|
+
---
|
7
|
+
|
8
|
+
# Agent-as-Tool Pattern Guide
|
9
|
+
|
10
|
+
The Agent-as-Tool pattern enables **multi-agent collaboration** where specialized agents work behind the scenes to help each other, without the user knowing multiple agents are involved.
|
11
|
+
|
12
|
+
## When to Use This Pattern
|
13
|
+
|
14
|
+
Use Agent-as-Tool when you need:
|
15
|
+
|
16
|
+
- **Specialized Processing**: Different agents excel at different tasks
|
17
|
+
- **Behind-the-Scenes Coordination**: Agents collaborate invisibly to the user
|
18
|
+
- **Multi-step Workflows**: Complex processes requiring different expertise
|
19
|
+
- **Modular Architecture**: Clean separation of concerns between agents
|
20
|
+
|
21
|
+
## Core Concept
|
22
|
+
|
23
|
+
### Handoffs vs Agent-as-Tool
|
24
|
+
|
25
|
+
**Handoffs**: "Let me transfer you to billing"
|
26
|
+
- User-visible conversation transfer
|
27
|
+
- Full context shared
|
28
|
+
- Agent takes over conversation
|
29
|
+
|
30
|
+
**Agent-as-Tool**: "Let me check that for you" (uses billing agent internally)
|
31
|
+
- Invisible to user
|
32
|
+
- Limited context (state only)
|
33
|
+
- Returns control to caller
|
34
|
+
|
35
|
+
## Basic Implementation
|
36
|
+
|
37
|
+
### Step 1: Create Specialized Agents
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
# Research agent - finds customer information
|
41
|
+
research_agent = Agents::Agent.new(
|
42
|
+
name: "ResearchAgent",
|
43
|
+
instructions: <<~PROMPT
|
44
|
+
You research customer information and history.
|
45
|
+
Return contact details including email addresses.
|
46
|
+
PROMPT,
|
47
|
+
tools: [customer_lookup_tool, conversation_search_tool]
|
48
|
+
)
|
49
|
+
|
50
|
+
# Billing agent - handles payment operations
|
51
|
+
billing_agent = Agents::Agent.new(
|
52
|
+
name: "BillingAgent",
|
53
|
+
instructions: <<~PROMPT
|
54
|
+
You handle billing operations using Stripe.
|
55
|
+
CRITICAL: You need customer email addresses for billing lookups.
|
56
|
+
Contact IDs will NOT work.
|
57
|
+
PROMPT,
|
58
|
+
tools: [stripe_billing_tool]
|
59
|
+
)
|
60
|
+
```
|
61
|
+
|
62
|
+
### Step 2: Create Orchestrator with Agent Tools
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
# Main agent coordinates specialists
|
66
|
+
orchestrator = Agents::Agent.new(
|
67
|
+
name: "SupportCopilot",
|
68
|
+
instructions: <<~PROMPT
|
69
|
+
You help support agents by coordinating specialist agents.
|
70
|
+
|
71
|
+
**CRITICAL: Multi-Step Workflow Approach**
|
72
|
+
|
73
|
+
For complex queries, break them into steps and use tools sequentially:
|
74
|
+
1. Plan your approach: What information do you need?
|
75
|
+
2. Execute sequentially: Use EXACT results from previous tools
|
76
|
+
3. Build context progressively: Each tool builds on previous findings
|
77
|
+
|
78
|
+
**Tool Requirements:**
|
79
|
+
- research_customer: Returns contact details including emails
|
80
|
+
- check_billing: Requires customer email (not contact ID)
|
81
|
+
|
82
|
+
Always think: "What did I learn and how do I use it next?"
|
83
|
+
PROMPT,
|
84
|
+
tools: [
|
85
|
+
research_agent.as_tool(
|
86
|
+
name: "research_customer",
|
87
|
+
description: "Research customer details. Returns contact info including email."
|
88
|
+
),
|
89
|
+
billing_agent.as_tool(
|
90
|
+
name: "check_billing",
|
91
|
+
description: "Check billing status. Requires customer email address."
|
92
|
+
)
|
93
|
+
]
|
94
|
+
)
|
95
|
+
```
|
96
|
+
|
97
|
+
### Step 3: Use with Context Persistence
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
# Set up runner with context persistence
|
101
|
+
runner = Agents::Runner.with_agents(orchestrator)
|
102
|
+
context = {}
|
103
|
+
|
104
|
+
# Interactive loop maintains context
|
105
|
+
loop do
|
106
|
+
user_input = gets.chomp
|
107
|
+
break if user_input == "exit"
|
108
|
+
|
109
|
+
# Pass and update context each turn
|
110
|
+
result = runner.run(user_input, context: context)
|
111
|
+
context = result.context if result.context
|
112
|
+
|
113
|
+
puts result.output
|
114
|
+
end
|
115
|
+
```
|
116
|
+
|
117
|
+
## Advanced Features
|
118
|
+
|
119
|
+
### Custom Output Extraction
|
120
|
+
|
121
|
+
Extract specific information for other tools:
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
research_agent.as_tool(
|
125
|
+
name: "get_customer_email",
|
126
|
+
description: "Get customer email address",
|
127
|
+
output_extractor: ->(result) {
|
128
|
+
# Extract just the email instead of full response
|
129
|
+
email_match = result.output.match(/Email:\s*([^\s]+)/i)
|
130
|
+
email_match&.captures&.first || "Email not found"
|
131
|
+
}
|
132
|
+
)
|
133
|
+
```
|
134
|
+
|
135
|
+
## Best Practices
|
136
|
+
|
137
|
+
### 1. Clear Tool Descriptions with Requirements
|
138
|
+
|
139
|
+
Specify what each tool needs and provides:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
# Good: Clear requirements
|
143
|
+
billing_agent.as_tool(
|
144
|
+
name: "check_stripe_billing",
|
145
|
+
description: "Check Stripe billing info. Requires customer email (not contact ID)."
|
146
|
+
)
|
147
|
+
|
148
|
+
research_agent.as_tool(
|
149
|
+
name: "research_customer",
|
150
|
+
description: "Research customer details. Returns email address and contact info."
|
151
|
+
)
|
152
|
+
|
153
|
+
# Avoid: Vague descriptions
|
154
|
+
agent.as_tool(name: "process", description: "Do stuff")
|
155
|
+
```
|
156
|
+
|
157
|
+
### 2. Multi-Step Workflow Instructions
|
158
|
+
|
159
|
+
Guide orchestrators to chain tool calls properly:
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
orchestrator = Agent.new(
|
163
|
+
instructions: <<~PROMPT
|
164
|
+
**For complex queries requiring multiple pieces of information:**
|
165
|
+
|
166
|
+
1. Plan what information you need to gather
|
167
|
+
2. Use tools sequentially, building on previous results
|
168
|
+
3. Extract specific values from tool outputs for subsequent calls
|
169
|
+
4. Don't pass original parameters - use discovered values
|
170
|
+
|
171
|
+
**Example:** To check billing for CONTACT-123:
|
172
|
+
Step 1: research_customer("Get details for CONTACT-123") → finds email
|
173
|
+
Step 2: check_billing("Check billing for [discovered email]") → not original ID
|
174
|
+
PROMPT
|
175
|
+
)
|
176
|
+
```
|
177
|
+
|
178
|
+
### 3. Explicit Parameter Requirements in Agent Instructions
|
179
|
+
|
180
|
+
Make tool parameter needs crystal clear:
|
181
|
+
|
182
|
+
```ruby
|
183
|
+
billing_agent = Agent.new(
|
184
|
+
instructions: <<~PROMPT
|
185
|
+
**CRITICAL: Billing Requirements**
|
186
|
+
- Stripe billing lookups REQUIRE customer email addresses
|
187
|
+
- Contact IDs, names, phone numbers will NOT work
|
188
|
+
- If you don't have email, clearly state you need it
|
189
|
+
PROMPT
|
190
|
+
)
|
191
|
+
```
|
192
|
+
|
193
|
+
### 4. Handle Errors with Guidance
|
194
|
+
|
195
|
+
Provide helpful error messages that guide next steps:
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
# In orchestrator instructions
|
199
|
+
instructions = <<~PROMPT
|
200
|
+
**Error Handling:**
|
201
|
+
- If billing fails due to missing email: Use research_customer first
|
202
|
+
- If contact not found: Ask for more identifying information
|
203
|
+
- Always provide helpful responses even if tools fail
|
204
|
+
PROMPT
|
205
|
+
```
|
206
|
+
|
207
|
+
### 5. Context Persistence for Multi-Turn Conversations
|
208
|
+
|
209
|
+
Maintain state across conversation turns:
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
# Maintain context between interactions
|
213
|
+
runner = Agents::Runner.with_agents(orchestrator)
|
214
|
+
context = {}
|
215
|
+
|
216
|
+
# Each turn builds on previous context
|
217
|
+
result = runner.run(user_input, context: context)
|
218
|
+
context = result.context if result.context
|
219
|
+
```
|
220
|
+
|
221
|
+
### 6. Design Focused Agents
|
222
|
+
|
223
|
+
Keep agent responsibilities clear and narrow:
|
224
|
+
|
225
|
+
```ruby
|
226
|
+
# Good: Focused responsibility
|
227
|
+
customer_agent = Agent.new(
|
228
|
+
name: "CustomerAgent",
|
229
|
+
instructions: "Handle customer data lookups and history research"
|
230
|
+
)
|
231
|
+
|
232
|
+
# Avoid: Too broad
|
233
|
+
everything_agent = Agent.new(
|
234
|
+
name: "EverythingAgent",
|
235
|
+
instructions: "Handle all customer operations, billing, support, and analysis"
|
236
|
+
)
|
237
|
+
```
|
238
|
+
|
239
|
+
## See Also
|
240
|
+
|
241
|
+
- [AgentTool Concept](../concepts/agent-tool.html)
|
242
|
+
- [Multi-Agent Systems Guide](multi-agent-systems.html)
|
@@ -0,0 +1,261 @@
|
|
1
|
+
---
|
2
|
+
layout: default
|
3
|
+
title: Building Multi-Agent Systems
|
4
|
+
parent: Guides
|
5
|
+
nav_order: 1
|
6
|
+
---
|
7
|
+
|
8
|
+
# Building Multi-Agent Systems
|
9
|
+
|
10
|
+
Multi-agent systems allow you to decompose complex problems into specialized agents that collaborate to provide comprehensive solutions. This guide covers patterns and best practices for designing effective multi-agent workflows.
|
11
|
+
|
12
|
+
## Core Patterns
|
13
|
+
|
14
|
+
### Hub-and-Spoke Architecture
|
15
|
+
|
16
|
+
The most common and stable pattern is hub-and-spoke, where a central triage agent routes conversations to specialized agents:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
# Specialized agents
|
20
|
+
billing_agent = Agents::Agent.new(
|
21
|
+
name: "Billing",
|
22
|
+
instructions: "Handle billing inquiries, payment processing, and account issues."
|
23
|
+
)
|
24
|
+
|
25
|
+
support_agent = Agents::Agent.new(
|
26
|
+
name: "Support",
|
27
|
+
instructions: "Provide technical troubleshooting and product support."
|
28
|
+
)
|
29
|
+
|
30
|
+
# Central hub agent
|
31
|
+
triage_agent = Agents::Agent.new(
|
32
|
+
name: "Triage",
|
33
|
+
instructions: "Route users to the appropriate specialist. Only hand off, don't solve problems yourself."
|
34
|
+
)
|
35
|
+
|
36
|
+
# Register handoffs (one-way: triage -> specialists)
|
37
|
+
triage_agent.register_handoffs(billing_agent, support_agent)
|
38
|
+
|
39
|
+
# Create runner with triage as entry point
|
40
|
+
runner = Agents::AgentRunner.with_agents(triage_agent, billing_agent, support_agent)
|
41
|
+
```
|
42
|
+
|
43
|
+
### Dynamic Instructions
|
44
|
+
|
45
|
+
Use Proc-based instructions to create context-aware agents:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
support_agent = Agents::Agent.new(
|
49
|
+
name: "Support",
|
50
|
+
instructions: ->(context) {
|
51
|
+
customer_tier = context[:customer_tier] || "standard"
|
52
|
+
<<~INSTRUCTIONS
|
53
|
+
You are a technical support specialist for #{customer_tier} tier customers.
|
54
|
+
#{customer_tier == "premium" ? "Provide priority white-glove service." : ""}
|
55
|
+
|
56
|
+
Available tools: diagnostics, escalation
|
57
|
+
INSTRUCTIONS
|
58
|
+
}
|
59
|
+
)
|
60
|
+
```
|
61
|
+
|
62
|
+
## Agent Design Principles
|
63
|
+
|
64
|
+
### Clear Boundaries
|
65
|
+
|
66
|
+
Each agent should have a distinct, non-overlapping responsibility:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
# GOOD: Clear specialization
|
70
|
+
sales_agent = Agents::Agent.new(
|
71
|
+
name: "Sales",
|
72
|
+
instructions: "Handle product inquiries, pricing, and purchase decisions. Transfer technical questions to support."
|
73
|
+
)
|
74
|
+
|
75
|
+
support_agent = Agents::Agent.new(
|
76
|
+
name: "Support",
|
77
|
+
instructions: "Handle technical issues and product troubleshooting. Transfer sales questions to sales team."
|
78
|
+
)
|
79
|
+
```
|
80
|
+
|
81
|
+
### Avoiding Handoff Loops
|
82
|
+
|
83
|
+
Design instructions to prevent infinite handoffs:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
# BAD: Conflicting handoff criteria
|
87
|
+
agent_a = Agents::Agent.new(
|
88
|
+
instructions: "Handle X. If you need Y info, hand off to Agent B."
|
89
|
+
)
|
90
|
+
agent_b = Agents::Agent.new(
|
91
|
+
instructions: "Handle Y. If you need X context, hand off to Agent A."
|
92
|
+
)
|
93
|
+
|
94
|
+
# GOOD: Clear escalation hierarchy
|
95
|
+
specialist = Agents::Agent.new(
|
96
|
+
instructions: "Handle specialized requests. Ask users for needed info directly."
|
97
|
+
)
|
98
|
+
triage = Agents::Agent.new(
|
99
|
+
instructions: "Route users to specialists. Don't solve problems yourself."
|
100
|
+
)
|
101
|
+
```
|
102
|
+
|
103
|
+
## Conversation Flow Management
|
104
|
+
|
105
|
+
### Entry Points
|
106
|
+
|
107
|
+
The first agent in `AgentRunner.with_agents()` becomes the default entry point:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
# Triage agent handles all initial conversations
|
111
|
+
runner = Agents::AgentRunner.with_agents(triage_agent, billing_agent, support_agent)
|
112
|
+
|
113
|
+
# Start conversation
|
114
|
+
result = runner.run("I need help with my account")
|
115
|
+
# -> Automatically starts with triage_agent
|
116
|
+
```
|
117
|
+
|
118
|
+
### Context Preservation
|
119
|
+
|
120
|
+
The AgentRunner automatically maintains conversation history across handoffs:
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
# First interaction
|
124
|
+
result1 = runner.run("My name is John and I have a billing question")
|
125
|
+
# -> Triage agent hands off to billing agent
|
126
|
+
|
127
|
+
# Continue conversation
|
128
|
+
result2 = runner.run("What payment methods do you accept?", context: result1.context)
|
129
|
+
# -> Billing agent remembers John's name and previous context
|
130
|
+
```
|
131
|
+
|
132
|
+
### Handoff Detection
|
133
|
+
|
134
|
+
The system automatically determines the current agent from conversation history:
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
# No need to manually specify which agent to use
|
138
|
+
result = runner.run("Follow up question", context: previous_result.context)
|
139
|
+
# -> AgentRunner automatically selects correct agent based on conversation state
|
140
|
+
```
|
141
|
+
|
142
|
+
## Advanced Patterns
|
143
|
+
|
144
|
+
### Tool-Specific Agents
|
145
|
+
|
146
|
+
Create agents specialized for particular tool categories:
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
data_agent = Agents::Agent.new(
|
150
|
+
name: "DataAnalyst",
|
151
|
+
instructions: "Analyze data and generate reports using available analytics tools.",
|
152
|
+
tools: [DatabaseTool.new, ChartGeneratorTool.new, ReportTool.new]
|
153
|
+
)
|
154
|
+
|
155
|
+
communication_agent = Agents::Agent.new(
|
156
|
+
name: "Communications",
|
157
|
+
instructions: "Handle notifications and external communications.",
|
158
|
+
tools: [EmailTool.new, SlackTool.new, SMSTool.new]
|
159
|
+
)
|
160
|
+
```
|
161
|
+
|
162
|
+
### Conditional Handoffs
|
163
|
+
|
164
|
+
Use dynamic instructions to control handoff behavior:
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
triage_agent = Agents::Agent.new(
|
168
|
+
name: "Triage",
|
169
|
+
instructions: ->(context) {
|
170
|
+
business_hours = context[:business_hours] || false
|
171
|
+
|
172
|
+
base_instructions = "Route users to appropriate departments."
|
173
|
+
|
174
|
+
if business_hours
|
175
|
+
base_instructions + " All departments are available."
|
176
|
+
else
|
177
|
+
base_instructions + " Only hand off urgent technical issues to support. Others should wait for business hours."
|
178
|
+
end
|
179
|
+
}
|
180
|
+
)
|
181
|
+
```
|
182
|
+
|
183
|
+
## Testing Multi-Agent Systems
|
184
|
+
|
185
|
+
### Unit Testing Individual Agents
|
186
|
+
|
187
|
+
Test each agent in isolation:
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
RSpec.describe "BillingAgent" do
|
191
|
+
let(:agent) { create_billing_agent }
|
192
|
+
let(:runner) { Agents::AgentRunner.with_agents(agent) }
|
193
|
+
|
194
|
+
it "handles payment inquiries" do
|
195
|
+
result = runner.run("What payment methods do you accept?")
|
196
|
+
expect(result.output).to include("credit card", "bank transfer")
|
197
|
+
end
|
198
|
+
end
|
199
|
+
```
|
200
|
+
|
201
|
+
### Integration Testing Handoffs
|
202
|
+
|
203
|
+
Test complete workflows:
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
RSpec.describe "Customer Support Workflow" do
|
207
|
+
let(:runner) { create_support_runner } # Creates triage + specialists
|
208
|
+
|
209
|
+
it "routes billing questions correctly" do
|
210
|
+
result = runner.run("I have a billing question")
|
211
|
+
|
212
|
+
# Verify handoff occurred
|
213
|
+
expect(result.context.current_agent_name).to eq("Billing")
|
214
|
+
|
215
|
+
# Test continued conversation
|
216
|
+
followup = runner.run("What are your payment terms?", context: result.context)
|
217
|
+
expect(followup.output).to include("payment terms")
|
218
|
+
end
|
219
|
+
end
|
220
|
+
```
|
221
|
+
|
222
|
+
## Common Pitfalls
|
223
|
+
|
224
|
+
### Over-Specialization
|
225
|
+
Don't create too many narrow agents - it increases handoff complexity and latency.
|
226
|
+
|
227
|
+
### Under-Specified Instructions
|
228
|
+
Vague instructions lead to inappropriate handoffs. Be explicit about what each agent should and shouldn't handle.
|
229
|
+
|
230
|
+
### Circular Dependencies
|
231
|
+
Avoid mutual handoffs between agents. Use hub-and-spoke or clear hierarchical patterns instead.
|
232
|
+
|
233
|
+
### Context Leakage
|
234
|
+
Don't rely on shared mutable state. Use the context hash for inter-agent communication.
|
235
|
+
|
236
|
+
## Performance Considerations
|
237
|
+
|
238
|
+
### Handoff Overhead
|
239
|
+
Each handoff adds latency. Design agents to minimize unnecessary transfers.
|
240
|
+
|
241
|
+
### Context Size
|
242
|
+
Large contexts increase token usage. Clean up irrelevant data periodically:
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
# Remove old conversation history
|
246
|
+
cleaned_context = result.context.dup
|
247
|
+
cleaned_context[:conversation_history] = cleaned_context[:conversation_history].last(10)
|
248
|
+
```
|
249
|
+
|
250
|
+
### Concurrent Execution
|
251
|
+
AgentRunner is thread-safe, allowing multiple conversations simultaneously:
|
252
|
+
|
253
|
+
```ruby
|
254
|
+
# Safe to use same runner across threads
|
255
|
+
threads = users.map do |user|
|
256
|
+
Thread.new do
|
257
|
+
user_result = runner.run(user.message, context: user.context)
|
258
|
+
# Handle result...
|
259
|
+
end
|
260
|
+
end
|
261
|
+
```
|