ai-agents 0.4.3 → 0.6.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/.rubocop.yml +7 -9
- data/CHANGELOG.md +27 -0
- data/CLAUDE.md +1 -3
- data/docs/concepts/callbacks.md +1 -1
- data/docs/guides/multi-agent-systems.md +13 -13
- data/docs/guides/rails-integration.md +56 -56
- data/docs/guides/request-headers.md +91 -0
- data/docs/guides/structured-output.md +2 -2
- data/docs/guides.md +1 -0
- data/docs/index.md +1 -1
- data/examples/isp-support/agents_factory.rb +33 -32
- data/examples/isp-support/interactive.rb +72 -32
- data/lib/agents/agent.rb +7 -4
- data/lib/agents/agent_runner.rb +3 -2
- data/lib/agents/handoff.rb +13 -5
- data/lib/agents/helpers/headers.rb +29 -0
- data/lib/agents/helpers/message_extractor.rb +88 -0
- data/lib/agents/helpers.rb +9 -0
- data/lib/agents/runner.rb +115 -45
- data/lib/agents/version.rb +1 -1
- data/lib/agents.rb +1 -2
- metadata +7 -5
- data/lib/agents/chat.rb +0 -161
- data/lib/agents/message_extractor.rb +0 -97
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f8fa7ec73784bc0fb1e9e6bd4852c6d0295160c4ca28d435c895cba28f5cd58
|
4
|
+
data.tar.gz: 3e489f11ae2a5c93b4232ec78e3c7385c83f303c28039ed35fa082669fedaf4b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba5050ba743466993826d888673d90696d27f422df3d3972027fa141de05d6436c45cd44dba0836dc6350ad83c0ff1628ba43bbce6d93e5e49e8efc450554e91
|
7
|
+
data.tar.gz: efed7a181a6f52c4c8feb8b84e1bbb2309b5216a85569dae69dd4038cde0cdad7a283e066181414e50657aee063e79935573799fdc24abc6253b02bcb8e5d09f
|
data/.rubocop.yml
CHANGED
@@ -10,20 +10,18 @@ Style/StringLiterals:
|
|
10
10
|
Style/StringLiteralsInInterpolation:
|
11
11
|
EnforcedStyle: double_quotes
|
12
12
|
|
13
|
+
Metrics/MethodLength:
|
14
|
+
Max: 20
|
15
|
+
Metrics/ClassLength:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
RSpec/MultipleDescribes:
|
19
|
+
Enabled: false
|
13
20
|
RSpec/MultipleExpectations:
|
14
21
|
Max: 10
|
15
|
-
|
16
22
|
RSpec/ExampleLength:
|
17
23
|
Max: 20
|
18
|
-
|
19
24
|
RSpec/MultipleMemoizedHelpers:
|
20
25
|
Max: 15
|
21
|
-
|
22
26
|
RSpec/SpecFilePathFormat:
|
23
27
|
Enabled: false
|
24
|
-
|
25
|
-
Metrics/MethodLength:
|
26
|
-
Max: 20
|
27
|
-
|
28
|
-
RSpec/MultipleDescribes:
|
29
|
-
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,33 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## [0.6.0] - 2025-10-16
|
9
|
+
|
10
|
+
### Added
|
11
|
+
- **Custom HTTP Headers Support**: Agents can now specify custom HTTP headers for LLM requests
|
12
|
+
- Added `headers` parameter to `Agent#initialize` for setting agent-level default headers
|
13
|
+
- Runtime headers can be passed via `headers` parameter in `AgentRunner#run` method
|
14
|
+
- Runtime headers take precedence over agent-level headers when keys overlap
|
15
|
+
- Headers are automatically normalized (symbolized keys) and validated
|
16
|
+
- Full support for headers across agent handoffs with proper merging logic
|
17
|
+
- New `Agents::Helpers::Headers` module for header normalization and merging
|
18
|
+
- Comprehensive test coverage for header functionality
|
19
|
+
|
20
|
+
### Changed
|
21
|
+
- **Code Organization**: Refactored internal helpers into dedicated module structure
|
22
|
+
- Moved `MessageExtractor` to `Agents::Helpers::MessageExtractor` module
|
23
|
+
- Converted `MessageExtractor` from class-based to module-function pattern
|
24
|
+
- Created `lib/agents/helpers/` directory for helper modules
|
25
|
+
- All helper modules now use consistent flat naming convention (`Agents::Helpers::ModuleName`)
|
26
|
+
|
27
|
+
## [0.5.0] - 2025-08-20
|
28
|
+
|
29
|
+
### Added
|
30
|
+
- Tool halting functionality for enhanced agent control
|
31
|
+
|
32
|
+
### Removed
|
33
|
+
- Removed chat.rb component that made the codebase brittle
|
34
|
+
|
8
35
|
## [0.4.3] - 2025-08-04
|
9
36
|
|
10
37
|
### Fixed
|
data/CLAUDE.md
CHANGED
@@ -63,7 +63,6 @@ This will start a command-line interface where you can interact with the multi-a
|
|
63
63
|
- **Agent**: An AI assistant with a specific role, instructions, and tools.
|
64
64
|
- **Tool**: A custom function that an agent can use to perform actions (e.g., look up customer data, send an email).
|
65
65
|
- **Handoff**: The process of transferring a conversation from one agent to another. This is a core feature of the SDK.
|
66
|
-
- **AgentRunner**: The thread-safe execution manager that coordinates multi-agent conversations and provides the main API.
|
67
66
|
- **Runner**: Internal component that manages individual conversation turns (used by AgentRunner).
|
68
67
|
- **Context**: A shared state object that stores conversation history and agent information, fully serializable for persistence.
|
69
68
|
- **Callbacks**: Event hooks for monitoring agent execution, including agent thinking, tool start/complete, and handoffs.
|
@@ -114,7 +113,6 @@ ruby examples/isp-support/interactive.rb
|
|
114
113
|
### Core Components
|
115
114
|
|
116
115
|
- **Agents::Agent**: Individual AI agents with specific roles, instructions, and tools
|
117
|
-
- **Agents::AgentRunner**: Thread-safe execution manager with callback support
|
118
116
|
- **Agents::Runner**: Orchestrates multi-agent conversations with automatic handoffs
|
119
117
|
- **Agents::Tool**: Base class for custom tools that agents can execute
|
120
118
|
- **Agents::Context**: Shared state management across agent interactions
|
@@ -174,7 +172,7 @@ support = Agent.new(name: "Support", instructions: "Technical support...")
|
|
174
172
|
triage.register_handoffs(billing, support)
|
175
173
|
|
176
174
|
# Create thread-safe runner (first agent is default entry point)
|
177
|
-
runner = Agents::
|
175
|
+
runner = Agents::Runner.with_agents(triage, billing, support)
|
178
176
|
|
179
177
|
# Add real-time callbacks for monitoring
|
180
178
|
runner.on_agent_thinking { |agent_name, input| puts "🧠 #{agent_name} is thinking..." }
|
data/docs/concepts/callbacks.md
CHANGED
@@ -26,7 +26,7 @@ The SDK provides four types of callbacks that give you visibility into different
|
|
26
26
|
Callbacks are registered on the AgentRunner using chainable methods:
|
27
27
|
|
28
28
|
```ruby
|
29
|
-
runner = Agents::
|
29
|
+
runner = Agents::Runner.with_agents(triage, support)
|
30
30
|
.on_agent_thinking { |agent, input| puts "#{agent} thinking..." }
|
31
31
|
.on_tool_start { |tool, args| puts "Using #{tool}" }
|
32
32
|
.on_tool_complete { |tool, result| puts "#{tool} completed" }
|
@@ -23,7 +23,7 @@ billing_agent = Agents::Agent.new(
|
|
23
23
|
)
|
24
24
|
|
25
25
|
support_agent = Agents::Agent.new(
|
26
|
-
name: "Support",
|
26
|
+
name: "Support",
|
27
27
|
instructions: "Provide technical troubleshooting and product support."
|
28
28
|
)
|
29
29
|
|
@@ -37,7 +37,7 @@ triage_agent = Agents::Agent.new(
|
|
37
37
|
triage_agent.register_handoffs(billing_agent, support_agent)
|
38
38
|
|
39
39
|
# Create runner with triage as entry point
|
40
|
-
runner = Agents::
|
40
|
+
runner = Agents::Runner.with_agents(triage_agent, billing_agent, support_agent)
|
41
41
|
```
|
42
42
|
|
43
43
|
### Dynamic Instructions
|
@@ -52,7 +52,7 @@ support_agent = Agents::Agent.new(
|
|
52
52
|
<<~INSTRUCTIONS
|
53
53
|
You are a technical support specialist for #{customer_tier} tier customers.
|
54
54
|
#{customer_tier == "premium" ? "Provide priority white-glove service." : ""}
|
55
|
-
|
55
|
+
|
56
56
|
Available tools: diagnostics, escalation
|
57
57
|
INSTRUCTIONS
|
58
58
|
}
|
@@ -73,7 +73,7 @@ sales_agent = Agents::Agent.new(
|
|
73
73
|
)
|
74
74
|
|
75
75
|
support_agent = Agents::Agent.new(
|
76
|
-
name: "Support",
|
76
|
+
name: "Support",
|
77
77
|
instructions: "Handle technical issues and product troubleshooting. Transfer sales questions to sales team."
|
78
78
|
)
|
79
79
|
```
|
@@ -108,7 +108,7 @@ The first agent in `AgentRunner.with_agents()` becomes the default entry point:
|
|
108
108
|
|
109
109
|
```ruby
|
110
110
|
# Triage agent handles all initial conversations
|
111
|
-
runner = Agents::
|
111
|
+
runner = Agents::Runner.with_agents(triage_agent, billing_agent, support_agent)
|
112
112
|
|
113
113
|
# Start conversation
|
114
114
|
result = runner.run("I need help with my account")
|
@@ -168,9 +168,9 @@ triage_agent = Agents::Agent.new(
|
|
168
168
|
name: "Triage",
|
169
169
|
instructions: ->(context) {
|
170
170
|
business_hours = context[:business_hours] || false
|
171
|
-
|
171
|
+
|
172
172
|
base_instructions = "Route users to appropriate departments."
|
173
|
-
|
173
|
+
|
174
174
|
if business_hours
|
175
175
|
base_instructions + " All departments are available."
|
176
176
|
else
|
@@ -189,8 +189,8 @@ Test each agent in isolation:
|
|
189
189
|
```ruby
|
190
190
|
RSpec.describe "BillingAgent" do
|
191
191
|
let(:agent) { create_billing_agent }
|
192
|
-
let(:runner) { Agents::
|
193
|
-
|
192
|
+
let(:runner) { Agents::Runner.with_agents(agent) }
|
193
|
+
|
194
194
|
it "handles payment inquiries" do
|
195
195
|
result = runner.run("What payment methods do you accept?")
|
196
196
|
expect(result.output).to include("credit card", "bank transfer")
|
@@ -205,13 +205,13 @@ Test complete workflows:
|
|
205
205
|
```ruby
|
206
206
|
RSpec.describe "Customer Support Workflow" do
|
207
207
|
let(:runner) { create_support_runner } # Creates triage + specialists
|
208
|
-
|
208
|
+
|
209
209
|
it "routes billing questions correctly" do
|
210
210
|
result = runner.run("I have a billing question")
|
211
|
-
|
211
|
+
|
212
212
|
# Verify handoff occurred
|
213
213
|
expect(result.context[:current_agent]).to eq("Billing")
|
214
|
-
|
214
|
+
|
215
215
|
# Test continued conversation
|
216
216
|
followup = runner.run("What are your payment terms?", context: result.context)
|
217
217
|
expect(followup.output).to include("payment terms")
|
@@ -258,4 +258,4 @@ threads = users.map do |user|
|
|
258
258
|
# Handle result...
|
259
259
|
end
|
260
260
|
end
|
261
|
-
```
|
261
|
+
```
|
@@ -49,7 +49,7 @@ class CreateConversations < ActiveRecord::Migration[7.0]
|
|
49
49
|
t.string :current_agent
|
50
50
|
t.timestamps
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
add_index :conversations, [:user_id, :created_at]
|
54
54
|
end
|
55
55
|
end
|
@@ -61,25 +61,25 @@ Define the Conversation model:
|
|
61
61
|
# app/models/conversation.rb
|
62
62
|
class Conversation < ApplicationRecord
|
63
63
|
belongs_to :user
|
64
|
-
|
64
|
+
|
65
65
|
# Serialize context as JSON
|
66
66
|
serialize :context, JSON
|
67
|
-
|
67
|
+
|
68
68
|
validates :context, presence: true
|
69
|
-
|
69
|
+
|
70
70
|
def self.for_user(user)
|
71
71
|
where(user: user).order(:created_at)
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
def self.latest_for_user(user)
|
75
75
|
for_user(user).last
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
# Convert to agent context hash
|
79
79
|
def to_agent_context
|
80
80
|
context.deep_symbolize_keys
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
# Create from agent result
|
84
84
|
def self.from_agent_result(user, result)
|
85
85
|
create!(
|
@@ -102,26 +102,26 @@ class AgentConversationService
|
|
102
102
|
@user = user
|
103
103
|
@runner = create_agent_runner
|
104
104
|
end
|
105
|
-
|
105
|
+
|
106
106
|
def send_message(message)
|
107
107
|
# Get existing conversation context
|
108
108
|
context = load_conversation_context
|
109
|
-
|
109
|
+
|
110
110
|
# Run agent with message
|
111
111
|
result = @runner.run(message, context: context)
|
112
|
-
|
112
|
+
|
113
113
|
# Persist updated conversation
|
114
114
|
save_conversation(result)
|
115
|
-
|
115
|
+
|
116
116
|
result
|
117
117
|
end
|
118
|
-
|
118
|
+
|
119
119
|
def reset_conversation
|
120
120
|
Conversation.where(user: @user).destroy_all
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
private
|
124
|
-
|
124
|
+
|
125
125
|
def create_agent_runner
|
126
126
|
# Create your agents here
|
127
127
|
triage_agent = Agents::Agent.new(
|
@@ -129,52 +129,52 @@ class AgentConversationService
|
|
129
129
|
instructions: build_triage_instructions,
|
130
130
|
tools: [CustomerLookupTool.new]
|
131
131
|
)
|
132
|
-
|
132
|
+
|
133
133
|
billing_agent = Agents::Agent.new(
|
134
134
|
name: "Billing",
|
135
135
|
instructions: "Handle billing and payment inquiries.",
|
136
136
|
tools: [BillingTool.new, PaymentTool.new]
|
137
137
|
)
|
138
|
-
|
138
|
+
|
139
139
|
support_agent = Agents::Agent.new(
|
140
140
|
name: "Support",
|
141
141
|
instructions: "Provide technical support and troubleshooting.",
|
142
142
|
tools: [TechnicalTool.new]
|
143
143
|
)
|
144
|
-
|
144
|
+
|
145
145
|
triage_agent.register_handoffs(billing_agent, support_agent)
|
146
|
-
|
147
|
-
Agents::
|
146
|
+
|
147
|
+
Agents::Runner.with_agents(triage_agent, billing_agent, support_agent)
|
148
148
|
end
|
149
|
-
|
149
|
+
|
150
150
|
def build_triage_instructions
|
151
151
|
->(context) {
|
152
152
|
user_info = context[:user_info] || {}
|
153
|
-
|
153
|
+
|
154
154
|
<<~INSTRUCTIONS
|
155
155
|
You are a customer service triage agent for #{@user.name}.
|
156
|
-
|
156
|
+
|
157
157
|
Customer Details:
|
158
158
|
- Name: #{@user.name}
|
159
159
|
- Email: #{@user.email}
|
160
160
|
- Account Type: #{user_info[:account_type] || 'standard'}
|
161
|
-
|
161
|
+
|
162
162
|
Route customers to the appropriate department:
|
163
163
|
- Billing: Payment issues, account billing, refunds
|
164
164
|
- Support: Technical problems, product questions
|
165
|
-
|
165
|
+
|
166
166
|
Always be professional and helpful.
|
167
167
|
INSTRUCTIONS
|
168
168
|
}
|
169
169
|
end
|
170
|
-
|
170
|
+
|
171
171
|
def load_conversation_context
|
172
172
|
latest_conversation = Conversation.latest_for_user(@user)
|
173
173
|
return initial_context unless latest_conversation
|
174
|
-
|
174
|
+
|
175
175
|
latest_conversation.to_agent_context
|
176
176
|
end
|
177
|
-
|
177
|
+
|
178
178
|
def initial_context
|
179
179
|
{
|
180
180
|
user_id: @user.id,
|
@@ -185,7 +185,7 @@ class AgentConversationService
|
|
185
185
|
}
|
186
186
|
}
|
187
187
|
end
|
188
|
-
|
188
|
+
|
189
189
|
def save_conversation(result)
|
190
190
|
Conversation.from_agent_result(@user, result)
|
191
191
|
end
|
@@ -200,13 +200,13 @@ Create a controller for handling agent conversations:
|
|
200
200
|
# app/controllers/agent_conversations_controller.rb
|
201
201
|
class AgentConversationsController < ApplicationController
|
202
202
|
before_action :authenticate_user!
|
203
|
-
|
203
|
+
|
204
204
|
def create
|
205
205
|
service = AgentConversationService.new(current_user)
|
206
|
-
|
206
|
+
|
207
207
|
begin
|
208
208
|
result = service.send_message(params[:message])
|
209
|
-
|
209
|
+
|
210
210
|
render json: {
|
211
211
|
response: result.output,
|
212
212
|
agent: result.context[:current_agent],
|
@@ -217,19 +217,19 @@ class AgentConversationsController < ApplicationController
|
|
217
217
|
render json: { error: "Unable to process your request" }, status: 500
|
218
218
|
end
|
219
219
|
end
|
220
|
-
|
220
|
+
|
221
221
|
def reset
|
222
222
|
service = AgentConversationService.new(current_user)
|
223
223
|
service.reset_conversation
|
224
|
-
|
224
|
+
|
225
225
|
render json: { message: "Conversation reset successfully" }
|
226
226
|
end
|
227
|
-
|
227
|
+
|
228
228
|
def history
|
229
229
|
conversations = Conversation.for_user(current_user)
|
230
230
|
.includes(:user)
|
231
231
|
.limit(50)
|
232
|
-
|
232
|
+
|
233
233
|
render json: conversations.map do |conv|
|
234
234
|
{
|
235
235
|
id: conv.id,
|
@@ -252,13 +252,13 @@ class CustomerLookupTool < Agents::Tool
|
|
252
252
|
name "lookup_customer"
|
253
253
|
description "Look up customer information by email or ID"
|
254
254
|
param :identifier, type: "string", desc: "Email address or customer ID"
|
255
|
-
|
255
|
+
|
256
256
|
def perform(tool_context, identifier:)
|
257
257
|
# Access Rails models safely
|
258
258
|
customer = User.find_by(email: identifier) || User.find_by(id: identifier)
|
259
|
-
|
259
|
+
|
260
260
|
return "Customer not found" unless customer
|
261
|
-
|
261
|
+
|
262
262
|
{
|
263
263
|
name: customer.name,
|
264
264
|
email: customer.email,
|
@@ -274,13 +274,13 @@ class BillingTool < Agents::Tool
|
|
274
274
|
name "get_billing_info"
|
275
275
|
description "Retrieve billing information for a customer"
|
276
276
|
param :user_id, type: "integer", desc: "Customer user ID"
|
277
|
-
|
277
|
+
|
278
278
|
def perform(tool_context, user_id:)
|
279
279
|
user = User.find(user_id)
|
280
280
|
billing_info = user.billing_profile
|
281
|
-
|
281
|
+
|
282
282
|
return "No billing information found" unless billing_info
|
283
|
-
|
283
|
+
|
284
284
|
{
|
285
285
|
plan: billing_info.plan_name,
|
286
286
|
status: billing_info.status,
|
@@ -301,13 +301,13 @@ For longer conversations, use background jobs:
|
|
301
301
|
# app/jobs/agent_conversation_job.rb
|
302
302
|
class AgentConversationJob < ApplicationJob
|
303
303
|
queue_as :default
|
304
|
-
|
304
|
+
|
305
305
|
def perform(user_id, message, conversation_id = nil)
|
306
306
|
user = User.find(user_id)
|
307
307
|
service = AgentConversationService.new(user)
|
308
|
-
|
308
|
+
|
309
309
|
result = service.send_message(message)
|
310
|
-
|
310
|
+
|
311
311
|
# Broadcast result via ActionCable
|
312
312
|
ActionCable.server.broadcast(
|
313
313
|
"agent_conversation_#{user_id}",
|
@@ -327,7 +327,7 @@ def create_async
|
|
327
327
|
params[:message],
|
328
328
|
params[:conversation_id]
|
329
329
|
)
|
330
|
-
|
330
|
+
|
331
331
|
render json: { job_id: job_id }
|
332
332
|
end
|
333
333
|
```
|
@@ -341,12 +341,12 @@ Implement comprehensive error handling:
|
|
341
341
|
class AgentConversationService
|
342
342
|
class AgentError < StandardError; end
|
343
343
|
class ContextError < StandardError; end
|
344
|
-
|
344
|
+
|
345
345
|
def send_message(message)
|
346
346
|
validate_message(message)
|
347
|
-
|
347
|
+
|
348
348
|
context = load_conversation_context
|
349
|
-
|
349
|
+
|
350
350
|
begin
|
351
351
|
result = @runner.run(message, context: context)
|
352
352
|
save_conversation(result)
|
@@ -359,9 +359,9 @@ class AgentConversationService
|
|
359
359
|
raise ContextError, "Conversation context corrupted"
|
360
360
|
end
|
361
361
|
end
|
362
|
-
|
362
|
+
|
363
363
|
private
|
364
|
-
|
364
|
+
|
365
365
|
def validate_message(message)
|
366
366
|
raise ArgumentError, "Message cannot be blank" if message.blank?
|
367
367
|
raise ArgumentError, "Message too long" if message.length > 5000
|
@@ -378,26 +378,26 @@ Test Rails integration with RSpec:
|
|
378
378
|
RSpec.describe AgentConversationService do
|
379
379
|
let(:user) { create(:user) }
|
380
380
|
let(:service) { described_class.new(user) }
|
381
|
-
|
381
|
+
|
382
382
|
describe '#send_message' do
|
383
383
|
it 'creates a conversation record' do
|
384
384
|
expect {
|
385
385
|
service.send_message("Hello")
|
386
386
|
}.to change(Conversation, :count).by(1)
|
387
387
|
end
|
388
|
-
|
388
|
+
|
389
389
|
it 'persists context correctly' do
|
390
390
|
result = service.send_message("Hello")
|
391
391
|
conversation = Conversation.last
|
392
|
-
|
392
|
+
|
393
393
|
expect(conversation.user).to eq(user)
|
394
394
|
expect(conversation.context).to include('user_id' => user.id)
|
395
395
|
end
|
396
396
|
end
|
397
|
-
|
397
|
+
|
398
398
|
describe '#reset_conversation' do
|
399
399
|
before { service.send_message("Hello") }
|
400
|
-
|
400
|
+
|
401
401
|
it 'destroys all conversations for user' do
|
402
402
|
expect {
|
403
403
|
service.reset_conversation
|
@@ -437,4 +437,4 @@ add_index :conversations, :created_at
|
|
437
437
|
every 1.day, at: '2:00 am' do
|
438
438
|
runner "Conversation.where('created_at < ?', 30.days.ago).destroy_all"
|
439
439
|
end
|
440
|
-
```
|
440
|
+
```
|
@@ -0,0 +1,91 @@
|
|
1
|
+
---
|
2
|
+
layout: default
|
3
|
+
title: Custom Request Headers
|
4
|
+
parent: Guides
|
5
|
+
nav_order: 6
|
6
|
+
---
|
7
|
+
|
8
|
+
# Custom Request Headers
|
9
|
+
|
10
|
+
Custom HTTP headers allow you to pass additional metadata with your LLM API requests. This is useful for authentication, request tracking, A/B testing, and provider-specific features.
|
11
|
+
|
12
|
+
## Basic Usage
|
13
|
+
|
14
|
+
### Agent-Level Headers
|
15
|
+
|
16
|
+
Set default headers when creating an agent that will be applied to all requests:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
agent = Agents::Agent.new(
|
20
|
+
name: "Assistant",
|
21
|
+
instructions: "You are a helpful assistant",
|
22
|
+
headers: {
|
23
|
+
"X-Custom-ID" => "agent-123",
|
24
|
+
"X-Environment" => "production"
|
25
|
+
}
|
26
|
+
)
|
27
|
+
|
28
|
+
runner = Agents::Runner.with_agents(agent)
|
29
|
+
result = runner.run("Hello!")
|
30
|
+
# All requests will include the custom headers
|
31
|
+
```
|
32
|
+
|
33
|
+
### Runtime Headers
|
34
|
+
|
35
|
+
Override or add headers for specific requests:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
agent = Agents::Agent.new(
|
39
|
+
name: "Assistant",
|
40
|
+
instructions: "You are a helpful assistant"
|
41
|
+
)
|
42
|
+
|
43
|
+
runner = Agents::Runner.with_agents(agent)
|
44
|
+
|
45
|
+
# Pass headers at runtime
|
46
|
+
result = runner.run(
|
47
|
+
"What's the weather?",
|
48
|
+
headers: {
|
49
|
+
"X-Request-ID" => "req-456",
|
50
|
+
"X-User-ID" => "user-789"
|
51
|
+
}
|
52
|
+
)
|
53
|
+
```
|
54
|
+
|
55
|
+
### Header precedence
|
56
|
+
|
57
|
+
When both agent-level and runtime headers are provided, **runtime headers take precedence**:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
agent = Agents::Agent.new(
|
61
|
+
name: "Assistant",
|
62
|
+
instructions: "You are a helpful assistant",
|
63
|
+
headers: {
|
64
|
+
"X-Environment" => "staging",
|
65
|
+
"X-Agent-ID" => "agent-001"
|
66
|
+
}
|
67
|
+
)
|
68
|
+
|
69
|
+
runner = Agents::Runner.with_agents(agent)
|
70
|
+
|
71
|
+
result = runner.run(
|
72
|
+
"Hello!",
|
73
|
+
headers: {
|
74
|
+
"X-Environment" => "production", # Overrides agent's staging value
|
75
|
+
"X-Request-ID" => "req-123" # Additional header
|
76
|
+
}
|
77
|
+
)
|
78
|
+
|
79
|
+
# Final headers sent to LLM API:
|
80
|
+
# {
|
81
|
+
# "X-Environment" => "production", # Runtime value wins
|
82
|
+
# "X-Agent-ID" => "agent-001", # From agent
|
83
|
+
# "X-Request-ID" => "req-123" # From runtime
|
84
|
+
# }
|
85
|
+
```
|
86
|
+
|
87
|
+
## See Also
|
88
|
+
|
89
|
+
- [Multi-Agent Systems](multi-agent-systems.html) - Using headers across agent handoffs
|
90
|
+
- [Rails Integration](rails-integration.html) - Request tracking in Rails applications
|
91
|
+
- [State Persistence](state-persistence.html) - Combining headers with conversation state
|
@@ -30,7 +30,7 @@ extraction_agent = Agents::Agent.new(
|
|
30
30
|
}
|
31
31
|
)
|
32
32
|
|
33
|
-
runner = Agents::
|
33
|
+
runner = Agents::Runner.with_agents(extraction_agent)
|
34
34
|
result = runner.run("I love the new product features, especially the API and dashboard!")
|
35
35
|
|
36
36
|
# Response will be valid JSON matching the schema:
|
@@ -62,7 +62,7 @@ contact_agent = Agents::Agent.new(
|
|
62
62
|
response_schema: ContactSchema
|
63
63
|
)
|
64
64
|
|
65
|
-
runner = Agents::
|
65
|
+
runner = Agents::Runner.with_agents(contact_agent)
|
66
66
|
result = runner.run("Hi, I'm Sarah Johnson from TechCorp. You can reach me at sarah@techcorp.com or 555-0123. I'm interested in AI and automation solutions.")
|
67
67
|
|
68
68
|
# Returns structured contact data:
|
data/docs/guides.md
CHANGED
@@ -17,3 +17,4 @@ Practical guides for building real-world applications with the AI Agents library
|
|
17
17
|
- **[Rails Integration](guides/rails-integration.html)** - Integrating agents with Ruby on Rails applications and ActiveRecord persistence
|
18
18
|
- **[State Persistence](guides/state-persistence.html)** - Managing conversation state and context across sessions and processes
|
19
19
|
- **[Structured Output](guides/structured-output.html)** - Enforcing JSON schema validation for reliable agent responses
|
20
|
+
- **[Custom Request Headers](guides/request-headers.html)** - Adding custom HTTP headers for authentication, tracking, and provider-specific features
|
data/docs/index.md
CHANGED
@@ -81,7 +81,7 @@ support = Agents::Agent.new(
|
|
81
81
|
triage.register_handoffs(support)
|
82
82
|
|
83
83
|
# Create runner and start conversation
|
84
|
-
runner = Agents::
|
84
|
+
runner = Agents::Runner.with_agents(triage, support)
|
85
85
|
result = runner.run("I need help with a technical issue")
|
86
86
|
|
87
87
|
puts result.output
|