a2a-ruby 1.0.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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +137 -0
- data/.simplecov +46 -0
- data/.yardopts +10 -0
- data/CHANGELOG.md +33 -0
- data/CODE_OF_CONDUCT.md +128 -0
- data/CONTRIBUTING.md +165 -0
- data/Gemfile +43 -0
- data/Guardfile +34 -0
- data/LICENSE.txt +21 -0
- data/PUBLISHING_CHECKLIST.md +214 -0
- data/README.md +171 -0
- data/Rakefile +165 -0
- data/docs/agent_execution.md +309 -0
- data/docs/api_reference.md +792 -0
- data/docs/configuration.md +780 -0
- data/docs/events.md +475 -0
- data/docs/getting_started.md +668 -0
- data/docs/integration.md +262 -0
- data/docs/server_apps.md +621 -0
- data/docs/troubleshooting.md +765 -0
- data/lib/a2a/client/api_methods.rb +263 -0
- data/lib/a2a/client/auth/api_key.rb +161 -0
- data/lib/a2a/client/auth/interceptor.rb +288 -0
- data/lib/a2a/client/auth/jwt.rb +189 -0
- data/lib/a2a/client/auth/oauth2.rb +146 -0
- data/lib/a2a/client/auth.rb +137 -0
- data/lib/a2a/client/base.rb +316 -0
- data/lib/a2a/client/config.rb +210 -0
- data/lib/a2a/client/connection_pool.rb +233 -0
- data/lib/a2a/client/http_client.rb +524 -0
- data/lib/a2a/client/json_rpc_handler.rb +136 -0
- data/lib/a2a/client/middleware/circuit_breaker_interceptor.rb +245 -0
- data/lib/a2a/client/middleware/logging_interceptor.rb +371 -0
- data/lib/a2a/client/middleware/rate_limit_interceptor.rb +142 -0
- data/lib/a2a/client/middleware/retry_interceptor.rb +161 -0
- data/lib/a2a/client/middleware.rb +116 -0
- data/lib/a2a/client/performance_tracker.rb +60 -0
- data/lib/a2a/configuration/defaults.rb +34 -0
- data/lib/a2a/configuration/environment_loader.rb +76 -0
- data/lib/a2a/configuration/file_loader.rb +115 -0
- data/lib/a2a/configuration/inheritance.rb +101 -0
- data/lib/a2a/configuration/validator.rb +180 -0
- data/lib/a2a/configuration.rb +201 -0
- data/lib/a2a/errors.rb +291 -0
- data/lib/a2a/modules.rb +50 -0
- data/lib/a2a/monitoring/alerting.rb +490 -0
- data/lib/a2a/monitoring/distributed_tracing.rb +398 -0
- data/lib/a2a/monitoring/health_endpoints.rb +204 -0
- data/lib/a2a/monitoring/metrics_collector.rb +438 -0
- data/lib/a2a/monitoring.rb +463 -0
- data/lib/a2a/plugin.rb +358 -0
- data/lib/a2a/plugin_manager.rb +159 -0
- data/lib/a2a/plugins/example_auth.rb +81 -0
- data/lib/a2a/plugins/example_middleware.rb +118 -0
- data/lib/a2a/plugins/example_transport.rb +76 -0
- data/lib/a2a/protocol/agent_card.rb +8 -0
- data/lib/a2a/protocol/agent_card_server.rb +584 -0
- data/lib/a2a/protocol/capability.rb +496 -0
- data/lib/a2a/protocol/json_rpc.rb +254 -0
- data/lib/a2a/protocol/message.rb +8 -0
- data/lib/a2a/protocol/task.rb +8 -0
- data/lib/a2a/rails/a2a_controller.rb +258 -0
- data/lib/a2a/rails/controller_helpers.rb +499 -0
- data/lib/a2a/rails/engine.rb +167 -0
- data/lib/a2a/rails/generators/agent_generator.rb +311 -0
- data/lib/a2a/rails/generators/install_generator.rb +209 -0
- data/lib/a2a/rails/generators/migration_generator.rb +232 -0
- data/lib/a2a/rails/generators/templates/add_a2a_indexes.rb +57 -0
- data/lib/a2a/rails/generators/templates/agent_controller.rb +122 -0
- data/lib/a2a/rails/generators/templates/agent_controller_spec.rb +160 -0
- data/lib/a2a/rails/generators/templates/agent_readme.md +200 -0
- data/lib/a2a/rails/generators/templates/create_a2a_push_notification_configs.rb +68 -0
- data/lib/a2a/rails/generators/templates/create_a2a_tasks.rb +83 -0
- data/lib/a2a/rails/generators/templates/example_agent_controller.rb +228 -0
- data/lib/a2a/rails/generators/templates/initializer.rb +108 -0
- data/lib/a2a/rails/generators/templates/push_notification_config_model.rb +228 -0
- data/lib/a2a/rails/generators/templates/task_model.rb +200 -0
- data/lib/a2a/rails/tasks/a2a.rake +228 -0
- data/lib/a2a/server/a2a_methods.rb +520 -0
- data/lib/a2a/server/agent.rb +537 -0
- data/lib/a2a/server/agent_execution/agent_executor.rb +279 -0
- data/lib/a2a/server/agent_execution/request_context.rb +219 -0
- data/lib/a2a/server/apps/rack_app.rb +311 -0
- data/lib/a2a/server/apps/sinatra_app.rb +261 -0
- data/lib/a2a/server/default_request_handler.rb +350 -0
- data/lib/a2a/server/events/event_consumer.rb +116 -0
- data/lib/a2a/server/events/event_queue.rb +226 -0
- data/lib/a2a/server/example_agent.rb +248 -0
- data/lib/a2a/server/handler.rb +281 -0
- data/lib/a2a/server/middleware/authentication_middleware.rb +212 -0
- data/lib/a2a/server/middleware/cors_middleware.rb +171 -0
- data/lib/a2a/server/middleware/logging_middleware.rb +362 -0
- data/lib/a2a/server/middleware/rate_limit_middleware.rb +382 -0
- data/lib/a2a/server/middleware.rb +213 -0
- data/lib/a2a/server/push_notification_manager.rb +327 -0
- data/lib/a2a/server/request_handler.rb +136 -0
- data/lib/a2a/server/storage/base.rb +141 -0
- data/lib/a2a/server/storage/database.rb +266 -0
- data/lib/a2a/server/storage/memory.rb +274 -0
- data/lib/a2a/server/storage/redis.rb +320 -0
- data/lib/a2a/server/storage.rb +38 -0
- data/lib/a2a/server/task_manager.rb +534 -0
- data/lib/a2a/transport/grpc.rb +481 -0
- data/lib/a2a/transport/http.rb +415 -0
- data/lib/a2a/transport/sse.rb +499 -0
- data/lib/a2a/types/agent_card.rb +540 -0
- data/lib/a2a/types/artifact.rb +99 -0
- data/lib/a2a/types/base_model.rb +223 -0
- data/lib/a2a/types/events.rb +117 -0
- data/lib/a2a/types/message.rb +106 -0
- data/lib/a2a/types/part.rb +288 -0
- data/lib/a2a/types/push_notification.rb +139 -0
- data/lib/a2a/types/security.rb +167 -0
- data/lib/a2a/types/task.rb +154 -0
- data/lib/a2a/types.rb +88 -0
- data/lib/a2a/utils/helpers.rb +245 -0
- data/lib/a2a/utils/message_buffer.rb +278 -0
- data/lib/a2a/utils/performance.rb +247 -0
- data/lib/a2a/utils/rails_detection.rb +97 -0
- data/lib/a2a/utils/structured_logger.rb +306 -0
- data/lib/a2a/utils/time_helpers.rb +167 -0
- data/lib/a2a/utils/validation.rb +8 -0
- data/lib/a2a/version.rb +6 -0
- data/lib/a2a-rails.rb +58 -0
- data/lib/a2a.rb +198 -0
- metadata +437 -0
@@ -0,0 +1,792 @@
|
|
1
|
+
# API Reference
|
2
|
+
|
3
|
+
This document provides a comprehensive reference for the A2A Ruby SDK API.
|
4
|
+
|
5
|
+
## Table of Contents
|
6
|
+
|
7
|
+
- [Client API](#client-api)
|
8
|
+
- [Server API](#server-api)
|
9
|
+
- [Types API](#types-api)
|
10
|
+
- [Configuration API](#configuration-api)
|
11
|
+
- [Transport API](#transport-api)
|
12
|
+
- [Authentication API](#authentication-api)
|
13
|
+
- [Error Handling](#error-handling)
|
14
|
+
|
15
|
+
## Client API
|
16
|
+
|
17
|
+
### A2A::Client::HttpClient
|
18
|
+
|
19
|
+
The primary client for communicating with A2A agents over HTTP.
|
20
|
+
|
21
|
+
#### Constructor
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
client = A2A::Client::HttpClient.new(endpoint_url, **options)
|
25
|
+
```
|
26
|
+
|
27
|
+
**Parameters:**
|
28
|
+
- `endpoint_url` (String) - The A2A agent endpoint URL
|
29
|
+
- `options` (Hash) - Optional configuration
|
30
|
+
- `:auth` (A2A::Client::Auth::Base) - Authentication strategy
|
31
|
+
- `:config` (A2A::Client::Config) - Client configuration
|
32
|
+
- `:middleware` (Array) - Middleware stack
|
33
|
+
- `:consumers` (Array) - Event consumers
|
34
|
+
|
35
|
+
**Example:**
|
36
|
+
```ruby
|
37
|
+
auth = A2A::Client::Auth::OAuth2.new(
|
38
|
+
client_id: "your-id",
|
39
|
+
client_secret: "your-secret",
|
40
|
+
token_url: "https://auth.example.com/token"
|
41
|
+
)
|
42
|
+
|
43
|
+
config = A2A::Client::Config.new
|
44
|
+
config.timeout = 60
|
45
|
+
config.streaming = true
|
46
|
+
|
47
|
+
client = A2A::Client::HttpClient.new(
|
48
|
+
"https://agent.example.com/a2a",
|
49
|
+
auth: auth,
|
50
|
+
config: config
|
51
|
+
)
|
52
|
+
```
|
53
|
+
|
54
|
+
#### Methods
|
55
|
+
|
56
|
+
##### send_message(message, context: nil, &block)
|
57
|
+
|
58
|
+
Sends a message to the agent and handles responses.
|
59
|
+
|
60
|
+
**Parameters:**
|
61
|
+
- `message` (A2A::Types::Message) - The message to send
|
62
|
+
- `context` (Hash, optional) - Request context
|
63
|
+
- `&block` - Block to handle streaming responses
|
64
|
+
|
65
|
+
**Returns:**
|
66
|
+
- Single response (if not streaming)
|
67
|
+
- Enumerator (if streaming without block)
|
68
|
+
- Yields responses to block (if streaming with block)
|
69
|
+
|
70
|
+
**Example:**
|
71
|
+
```ruby
|
72
|
+
message = A2A::Types::Message.new(
|
73
|
+
message_id: SecureRandom.uuid,
|
74
|
+
role: "user",
|
75
|
+
parts: [A2A::Types::TextPart.new(text: "Hello!")]
|
76
|
+
)
|
77
|
+
|
78
|
+
# Blocking call
|
79
|
+
response = client.send_message(message, streaming: false)
|
80
|
+
|
81
|
+
# Streaming with block
|
82
|
+
client.send_message(message) do |response|
|
83
|
+
case response
|
84
|
+
when A2A::Types::Message
|
85
|
+
puts "Agent: #{response.parts.first.text}"
|
86
|
+
when A2A::Types::TaskStatusUpdateEvent
|
87
|
+
puts "Status: #{response.status.state}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Streaming with enumerator
|
92
|
+
responses = client.send_message(message)
|
93
|
+
responses.each { |response| process(response) }
|
94
|
+
```
|
95
|
+
|
96
|
+
##### get_task(task_id, context: nil, history_length: nil)
|
97
|
+
|
98
|
+
Retrieves a task by ID.
|
99
|
+
|
100
|
+
**Parameters:**
|
101
|
+
- `task_id` (String) - The task ID
|
102
|
+
- `context` (Hash, optional) - Request context
|
103
|
+
- `history_length` (Integer, optional) - Limit message history
|
104
|
+
|
105
|
+
**Returns:**
|
106
|
+
- `A2A::Types::Task` - The task object
|
107
|
+
|
108
|
+
**Example:**
|
109
|
+
```ruby
|
110
|
+
task = client.get_task("task-123", history_length: 10)
|
111
|
+
puts "Task state: #{task.status.state}"
|
112
|
+
puts "Progress: #{task.status.progress}%" if task.status.progress
|
113
|
+
```
|
114
|
+
|
115
|
+
##### cancel_task(task_id, context: nil)
|
116
|
+
|
117
|
+
Cancels a task.
|
118
|
+
|
119
|
+
**Parameters:**
|
120
|
+
- `task_id` (String) - The task ID
|
121
|
+
- `context` (Hash, optional) - Request context
|
122
|
+
|
123
|
+
**Returns:**
|
124
|
+
- `A2A::Types::Task` - The updated task
|
125
|
+
|
126
|
+
**Example:**
|
127
|
+
```ruby
|
128
|
+
begin
|
129
|
+
task = client.cancel_task("task-123")
|
130
|
+
puts "Task canceled: #{task.status.state}"
|
131
|
+
rescue A2A::Errors::TaskNotCancelable => e
|
132
|
+
puts "Cannot cancel task: #{e.message}"
|
133
|
+
end
|
134
|
+
```
|
135
|
+
|
136
|
+
##### resubscribe(task_id, context: nil, &block)
|
137
|
+
|
138
|
+
Resubscribes to task updates for streaming.
|
139
|
+
|
140
|
+
**Parameters:**
|
141
|
+
- `task_id` (String) - The task ID
|
142
|
+
- `context` (Hash, optional) - Request context
|
143
|
+
- `&block` - Block to handle events
|
144
|
+
|
145
|
+
**Example:**
|
146
|
+
```ruby
|
147
|
+
client.resubscribe("task-123") do |event|
|
148
|
+
case event
|
149
|
+
when A2A::Types::TaskStatusUpdateEvent
|
150
|
+
puts "Status update: #{event.status.state}"
|
151
|
+
when A2A::Types::TaskArtifactUpdateEvent
|
152
|
+
puts "New artifact: #{event.artifact.name}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
##### get_card(context: nil)
|
158
|
+
|
159
|
+
Retrieves the agent card.
|
160
|
+
|
161
|
+
**Parameters:**
|
162
|
+
- `context` (Hash, optional) - Request context
|
163
|
+
|
164
|
+
**Returns:**
|
165
|
+
- `A2A::Types::AgentCard` - The agent card
|
166
|
+
|
167
|
+
**Example:**
|
168
|
+
```ruby
|
169
|
+
card = client.get_card
|
170
|
+
puts "Agent: #{card.name} v#{card.version}"
|
171
|
+
puts "Skills: #{card.skills.map(&:name).join(', ')}"
|
172
|
+
```
|
173
|
+
|
174
|
+
##### set_task_callback(task_id, push_config, context: nil)
|
175
|
+
|
176
|
+
Sets up push notifications for a task.
|
177
|
+
|
178
|
+
**Parameters:**
|
179
|
+
- `task_id` (String) - The task ID
|
180
|
+
- `push_config` (A2A::Types::PushNotificationConfig) - Push notification configuration
|
181
|
+
- `context` (Hash, optional) - Request context
|
182
|
+
|
183
|
+
**Example:**
|
184
|
+
```ruby
|
185
|
+
push_config = A2A::Types::PushNotificationConfig.new(
|
186
|
+
url: "https://your-app.com/webhooks/a2a",
|
187
|
+
authentication: {
|
188
|
+
type: "bearer",
|
189
|
+
token: "webhook-secret"
|
190
|
+
}
|
191
|
+
)
|
192
|
+
|
193
|
+
client.set_task_callback("task-123", push_config)
|
194
|
+
```
|
195
|
+
|
196
|
+
### A2A::Client::Config
|
197
|
+
|
198
|
+
Client configuration object.
|
199
|
+
|
200
|
+
#### Properties
|
201
|
+
|
202
|
+
```ruby
|
203
|
+
config = A2A::Client::Config.new
|
204
|
+
|
205
|
+
# Streaming configuration
|
206
|
+
config.streaming = true # Enable streaming responses
|
207
|
+
config.polling = false # Enable polling fallback
|
208
|
+
|
209
|
+
# Transport configuration
|
210
|
+
config.supported_transports = ['JSONRPC'] # Supported transport protocols
|
211
|
+
config.use_client_preference = true # Use client transport preference
|
212
|
+
|
213
|
+
# Timeout configuration
|
214
|
+
config.timeout = 30 # Request timeout in seconds
|
215
|
+
config.connect_timeout = 10 # Connection timeout in seconds
|
216
|
+
|
217
|
+
# Output configuration
|
218
|
+
config.accepted_output_modes = ['text', 'structured'] # Accepted output modes
|
219
|
+
|
220
|
+
# Push notification configuration
|
221
|
+
config.push_notification_configs = [] # Default push notification configs
|
222
|
+
```
|
223
|
+
|
224
|
+
## Server API
|
225
|
+
|
226
|
+
### A2A::Server::Agent
|
227
|
+
|
228
|
+
Mixin for creating A2A agents.
|
229
|
+
|
230
|
+
#### Usage
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
class MyAgent
|
234
|
+
include A2A::Server::Agent
|
235
|
+
|
236
|
+
# Agent configuration
|
237
|
+
a2a_config(
|
238
|
+
name: "My Agent",
|
239
|
+
description: "A sample A2A agent",
|
240
|
+
version: "1.0.0"
|
241
|
+
)
|
242
|
+
|
243
|
+
# Define skills
|
244
|
+
a2a_skill "greeting" do |skill|
|
245
|
+
skill.description = "Greet users"
|
246
|
+
skill.tags = ["greeting", "conversation"]
|
247
|
+
skill.examples = ["Hello", "Say hi"]
|
248
|
+
skill.input_modes = ["text"]
|
249
|
+
skill.output_modes = ["text"]
|
250
|
+
end
|
251
|
+
|
252
|
+
# Define methods
|
253
|
+
a2a_method "greet" do |params|
|
254
|
+
name = params[:name] || "there"
|
255
|
+
{ message: "Hello, #{name}!" }
|
256
|
+
end
|
257
|
+
end
|
258
|
+
```
|
259
|
+
|
260
|
+
#### Class Methods
|
261
|
+
|
262
|
+
##### a2a_config(**options)
|
263
|
+
|
264
|
+
Configures the agent metadata.
|
265
|
+
|
266
|
+
**Parameters:**
|
267
|
+
- `name` (String) - Agent name
|
268
|
+
- `description` (String) - Agent description
|
269
|
+
- `version` (String) - Agent version
|
270
|
+
- `url` (String, optional) - Agent URL
|
271
|
+
- `provider` (Hash, optional) - Provider information
|
272
|
+
|
273
|
+
##### a2a_skill(name, &block)
|
274
|
+
|
275
|
+
Defines an agent skill.
|
276
|
+
|
277
|
+
**Parameters:**
|
278
|
+
- `name` (String) - Skill name
|
279
|
+
- `&block` - Configuration block
|
280
|
+
|
281
|
+
**Block methods:**
|
282
|
+
- `description` (String) - Skill description
|
283
|
+
- `tags` (Array<String>) - Skill tags
|
284
|
+
- `examples` (Array<String>) - Usage examples
|
285
|
+
- `input_modes` (Array<String>) - Supported input modes
|
286
|
+
- `output_modes` (Array<String>) - Supported output modes
|
287
|
+
- `security` (Hash, optional) - Security requirements
|
288
|
+
|
289
|
+
##### a2a_method(name, **options, &block)
|
290
|
+
|
291
|
+
Defines an A2A method.
|
292
|
+
|
293
|
+
**Parameters:**
|
294
|
+
- `name` (String) - Method name
|
295
|
+
- `options` (Hash) - Method options
|
296
|
+
- `:streaming` (Boolean) - Whether method supports streaming
|
297
|
+
- `:auth_required` (Boolean) - Whether authentication is required
|
298
|
+
- `&block` - Method implementation
|
299
|
+
|
300
|
+
**Example:**
|
301
|
+
```ruby
|
302
|
+
# Simple method
|
303
|
+
a2a_method "get_weather" do |params|
|
304
|
+
location = params[:location]
|
305
|
+
WeatherService.current(location)
|
306
|
+
end
|
307
|
+
|
308
|
+
# Streaming method
|
309
|
+
a2a_method "weather_forecast", streaming: true do |params|
|
310
|
+
Enumerator.new do |yielder|
|
311
|
+
# Yield status updates
|
312
|
+
yielder << task_status_update("working")
|
313
|
+
|
314
|
+
# Yield data
|
315
|
+
forecast_data.each do |day|
|
316
|
+
message = A2A::Types::Message.new(
|
317
|
+
message_id: SecureRandom.uuid,
|
318
|
+
role: "agent",
|
319
|
+
parts: [A2A::Types::TextPart.new(text: day.to_json)]
|
320
|
+
)
|
321
|
+
yielder << message
|
322
|
+
end
|
323
|
+
|
324
|
+
# Final status
|
325
|
+
yielder << task_status_update("completed")
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
# Method with authentication
|
330
|
+
a2a_method "secure_operation", auth_required: true do |params|
|
331
|
+
# Access current user via @current_user (set by auth middleware)
|
332
|
+
return { error: "Unauthorized" } unless @current_user
|
333
|
+
|
334
|
+
perform_secure_operation(params, @current_user)
|
335
|
+
end
|
336
|
+
```
|
337
|
+
|
338
|
+
#### Instance Methods
|
339
|
+
|
340
|
+
##### handle_a2a_request(request)
|
341
|
+
|
342
|
+
Handles an A2A JSON-RPC request.
|
343
|
+
|
344
|
+
**Parameters:**
|
345
|
+
- `request` (A2A::Protocol::JsonRpc::Request) - The JSON-RPC request
|
346
|
+
|
347
|
+
**Returns:**
|
348
|
+
- Hash - JSON-RPC response
|
349
|
+
|
350
|
+
##### generate_agent_card(**overrides)
|
351
|
+
|
352
|
+
Generates an agent card from the agent definition.
|
353
|
+
|
354
|
+
**Parameters:**
|
355
|
+
- `overrides` (Hash) - Override default values
|
356
|
+
|
357
|
+
**Returns:**
|
358
|
+
- `A2A::Types::AgentCard` - The agent card
|
359
|
+
|
360
|
+
### A2A::Server::TaskManager
|
361
|
+
|
362
|
+
Manages task lifecycle and persistence.
|
363
|
+
|
364
|
+
#### Constructor
|
365
|
+
|
366
|
+
```ruby
|
367
|
+
task_manager = A2A::Server::TaskManager.new(storage: storage_backend)
|
368
|
+
```
|
369
|
+
|
370
|
+
#### Methods
|
371
|
+
|
372
|
+
##### create_task(type:, params: {}, **options)
|
373
|
+
|
374
|
+
Creates a new task.
|
375
|
+
|
376
|
+
**Parameters:**
|
377
|
+
- `type` (String) - Task type
|
378
|
+
- `params` (Hash) - Task parameters
|
379
|
+
- `options` (Hash) - Additional options
|
380
|
+
|
381
|
+
**Returns:**
|
382
|
+
- `A2A::Types::Task` - The created task
|
383
|
+
|
384
|
+
##### update_task_status(task_id, status)
|
385
|
+
|
386
|
+
Updates task status.
|
387
|
+
|
388
|
+
**Parameters:**
|
389
|
+
- `task_id` (String) - Task ID
|
390
|
+
- `status` (A2A::Types::TaskStatus) - New status
|
391
|
+
|
392
|
+
**Returns:**
|
393
|
+
- `A2A::Types::Task` - Updated task
|
394
|
+
|
395
|
+
##### get_task(task_id)
|
396
|
+
|
397
|
+
Retrieves a task.
|
398
|
+
|
399
|
+
**Parameters:**
|
400
|
+
- `task_id` (String) - Task ID
|
401
|
+
|
402
|
+
**Returns:**
|
403
|
+
- `A2A::Types::Task` - The task
|
404
|
+
|
405
|
+
**Raises:**
|
406
|
+
- `A2A::Errors::TaskNotFound` - If task doesn't exist
|
407
|
+
|
408
|
+
## Types API
|
409
|
+
|
410
|
+
### A2A::Types::Message
|
411
|
+
|
412
|
+
Represents an A2A message.
|
413
|
+
|
414
|
+
#### Constructor
|
415
|
+
|
416
|
+
```ruby
|
417
|
+
message = A2A::Types::Message.new(
|
418
|
+
message_id: SecureRandom.uuid,
|
419
|
+
role: "user", # "user" or "agent"
|
420
|
+
parts: [part1, part2], # Array of Part objects
|
421
|
+
context_id: "context-123", # Optional
|
422
|
+
task_id: "task-123", # Optional
|
423
|
+
metadata: { key: "value" }, # Optional
|
424
|
+
extensions: [], # Optional
|
425
|
+
reference_task_ids: [] # Optional
|
426
|
+
)
|
427
|
+
```
|
428
|
+
|
429
|
+
#### Properties
|
430
|
+
|
431
|
+
- `message_id` (String) - Unique message identifier
|
432
|
+
- `role` (String) - Message role ("user" or "agent")
|
433
|
+
- `parts` (Array<A2A::Types::Part>) - Message parts
|
434
|
+
- `context_id` (String, optional) - Context identifier
|
435
|
+
- `task_id` (String, optional) - Associated task ID
|
436
|
+
- `kind` (String) - Always "message"
|
437
|
+
- `metadata` (Hash, optional) - Additional metadata
|
438
|
+
- `extensions` (Array, optional) - Protocol extensions
|
439
|
+
- `reference_task_ids` (Array<String>, optional) - Referenced task IDs
|
440
|
+
|
441
|
+
### A2A::Types::Part
|
442
|
+
|
443
|
+
Base class for message parts. Use specific subclasses:
|
444
|
+
|
445
|
+
#### A2A::Types::TextPart
|
446
|
+
|
447
|
+
```ruby
|
448
|
+
text_part = A2A::Types::TextPart.new(
|
449
|
+
text: "Hello, world!",
|
450
|
+
metadata: { language: "en" } # Optional
|
451
|
+
)
|
452
|
+
```
|
453
|
+
|
454
|
+
#### A2A::Types::FilePart
|
455
|
+
|
456
|
+
```ruby
|
457
|
+
# File with bytes (base64 encoded)
|
458
|
+
file_part = A2A::Types::FilePart.new(
|
459
|
+
file: A2A::Types::FileWithBytes.new(
|
460
|
+
name: "document.pdf",
|
461
|
+
mime_type: "application/pdf",
|
462
|
+
bytes: Base64.encode64(file_content)
|
463
|
+
)
|
464
|
+
)
|
465
|
+
|
466
|
+
# File with URI reference
|
467
|
+
file_part = A2A::Types::FilePart.new(
|
468
|
+
file: A2A::Types::FileWithUri.new(
|
469
|
+
name: "document.pdf",
|
470
|
+
mime_type: "application/pdf",
|
471
|
+
uri: "https://storage.example.com/document.pdf"
|
472
|
+
)
|
473
|
+
)
|
474
|
+
```
|
475
|
+
|
476
|
+
#### A2A::Types::DataPart
|
477
|
+
|
478
|
+
```ruby
|
479
|
+
data_part = A2A::Types::DataPart.new(
|
480
|
+
data: { key: "value", numbers: [1, 2, 3] },
|
481
|
+
metadata: { format: "json" }
|
482
|
+
)
|
483
|
+
```
|
484
|
+
|
485
|
+
### A2A::Types::Task
|
486
|
+
|
487
|
+
Represents a task with lifecycle management.
|
488
|
+
|
489
|
+
#### Constructor
|
490
|
+
|
491
|
+
```ruby
|
492
|
+
task = A2A::Types::Task.new(
|
493
|
+
id: SecureRandom.uuid,
|
494
|
+
context_id: SecureRandom.uuid,
|
495
|
+
status: A2A::Types::TaskStatus.new(state: "submitted"),
|
496
|
+
artifacts: [], # Optional
|
497
|
+
history: [], # Optional
|
498
|
+
metadata: {} # Optional
|
499
|
+
)
|
500
|
+
```
|
501
|
+
|
502
|
+
#### Properties
|
503
|
+
|
504
|
+
- `id` (String) - Unique task identifier
|
505
|
+
- `context_id` (String) - Context identifier
|
506
|
+
- `status` (A2A::Types::TaskStatus) - Current task status
|
507
|
+
- `kind` (String) - Always "task"
|
508
|
+
- `artifacts` (Array<A2A::Types::Artifact>, optional) - Task artifacts
|
509
|
+
- `history` (Array<A2A::Types::Message>, optional) - Message history
|
510
|
+
- `metadata` (Hash, optional) - Additional metadata
|
511
|
+
|
512
|
+
### A2A::Types::TaskStatus
|
513
|
+
|
514
|
+
Represents task status and progress.
|
515
|
+
|
516
|
+
#### Constructor
|
517
|
+
|
518
|
+
```ruby
|
519
|
+
status = A2A::Types::TaskStatus.new(
|
520
|
+
state: "working", # Required
|
521
|
+
message: "Processing data...", # Optional
|
522
|
+
progress: 75, # Optional (0-100)
|
523
|
+
result: { processed: 1000 }, # Optional
|
524
|
+
error: { message: "Error occurred" }, # Optional
|
525
|
+
updated_at: Time.current.iso8601 # Optional
|
526
|
+
)
|
527
|
+
```
|
528
|
+
|
529
|
+
#### Valid States
|
530
|
+
|
531
|
+
- `submitted` - Task created, waiting to start
|
532
|
+
- `working` - Task in progress
|
533
|
+
- `input-required` - Task needs user input
|
534
|
+
- `completed` - Task finished successfully
|
535
|
+
- `canceled` - Task was canceled
|
536
|
+
- `failed` - Task failed with error
|
537
|
+
- `rejected` - Task rejected (invalid params, etc.)
|
538
|
+
- `auth-required` - Task needs authentication
|
539
|
+
- `unknown` - Unknown state
|
540
|
+
|
541
|
+
### A2A::Types::AgentCard
|
542
|
+
|
543
|
+
Represents agent capabilities and metadata.
|
544
|
+
|
545
|
+
#### Constructor
|
546
|
+
|
547
|
+
```ruby
|
548
|
+
card = A2A::Types::AgentCard.new(
|
549
|
+
name: "Weather Agent",
|
550
|
+
description: "Provides weather information",
|
551
|
+
version: "1.0.0",
|
552
|
+
url: "https://agent.example.com/a2a",
|
553
|
+
preferred_transport: "JSONRPC",
|
554
|
+
skills: [skill1, skill2],
|
555
|
+
capabilities: capabilities,
|
556
|
+
default_input_modes: ["text"],
|
557
|
+
default_output_modes: ["text", "structured"],
|
558
|
+
additional_interfaces: [interface1], # Optional
|
559
|
+
security: security_config, # Optional
|
560
|
+
security_schemes: [scheme1], # Optional
|
561
|
+
provider: provider_info, # Optional
|
562
|
+
protocol_version: "0.3.0", # Optional
|
563
|
+
supports_authenticated_extended_card: true, # Optional
|
564
|
+
signatures: [signature1], # Optional
|
565
|
+
documentation_url: "https://docs.example.com", # Optional
|
566
|
+
icon_url: "https://example.com/icon.png" # Optional
|
567
|
+
)
|
568
|
+
```
|
569
|
+
|
570
|
+
## Configuration API
|
571
|
+
|
572
|
+
### A2A.configure
|
573
|
+
|
574
|
+
Global configuration method.
|
575
|
+
|
576
|
+
```ruby
|
577
|
+
A2A.configure do |config|
|
578
|
+
# Protocol configuration
|
579
|
+
config.protocol_version = "0.3.0"
|
580
|
+
config.default_transport = "JSONRPC"
|
581
|
+
|
582
|
+
# Feature flags
|
583
|
+
config.streaming_enabled = true
|
584
|
+
config.push_notifications_enabled = true
|
585
|
+
|
586
|
+
# Timeouts
|
587
|
+
config.default_timeout = 30
|
588
|
+
config.connect_timeout = 10
|
589
|
+
|
590
|
+
# Logging
|
591
|
+
config.log_level = :info
|
592
|
+
config.log_requests = false
|
593
|
+
config.log_responses = false
|
594
|
+
|
595
|
+
# Storage
|
596
|
+
config.storage_backend = :database # :memory, :redis, :database
|
597
|
+
config.database_url = ENV['DATABASE_URL']
|
598
|
+
config.redis_url = ENV['REDIS_URL']
|
599
|
+
|
600
|
+
# Security
|
601
|
+
config.force_ssl = true
|
602
|
+
config.ssl_verify = true
|
603
|
+
|
604
|
+
# Performance
|
605
|
+
config.enable_metrics = true
|
606
|
+
config.metrics_backend = :prometheus # :prometheus, :statsd
|
607
|
+
|
608
|
+
# Rate limiting
|
609
|
+
config.rate_limit_enabled = true
|
610
|
+
config.rate_limit_requests = 100
|
611
|
+
config.rate_limit_window = 60
|
612
|
+
end
|
613
|
+
```
|
614
|
+
|
615
|
+
## Transport API
|
616
|
+
|
617
|
+
### A2A::Transport::Http
|
618
|
+
|
619
|
+
HTTP transport implementation using Faraday.
|
620
|
+
|
621
|
+
```ruby
|
622
|
+
transport = A2A::Transport::Http.new(
|
623
|
+
endpoint_url: "https://agent.example.com/a2a",
|
624
|
+
timeout: 30,
|
625
|
+
ssl_verify: true
|
626
|
+
)
|
627
|
+
|
628
|
+
response = transport.send_request(json_rpc_request)
|
629
|
+
```
|
630
|
+
|
631
|
+
### A2A::Transport::SSE
|
632
|
+
|
633
|
+
Server-Sent Events transport for streaming.
|
634
|
+
|
635
|
+
```ruby
|
636
|
+
sse = A2A::Transport::SSE.new(endpoint_url)
|
637
|
+
|
638
|
+
sse.stream(request) do |event|
|
639
|
+
case event.type
|
640
|
+
when 'message'
|
641
|
+
handle_message(JSON.parse(event.data))
|
642
|
+
when 'error'
|
643
|
+
handle_error(JSON.parse(event.data))
|
644
|
+
end
|
645
|
+
end
|
646
|
+
```
|
647
|
+
|
648
|
+
## Authentication API
|
649
|
+
|
650
|
+
### A2A::Client::Auth::OAuth2
|
651
|
+
|
652
|
+
OAuth 2.0 client credentials flow.
|
653
|
+
|
654
|
+
```ruby
|
655
|
+
auth = A2A::Client::Auth::OAuth2.new(
|
656
|
+
client_id: "your-client-id",
|
657
|
+
client_secret: "your-client-secret",
|
658
|
+
token_url: "https://auth.example.com/oauth/token",
|
659
|
+
scope: "a2a:read a2a:write" # Optional
|
660
|
+
)
|
661
|
+
|
662
|
+
# Manual token acquisition
|
663
|
+
token, expires_at = auth.get_token
|
664
|
+
|
665
|
+
# Automatic application to requests
|
666
|
+
client = A2A::Client::HttpClient.new(url, auth: auth)
|
667
|
+
```
|
668
|
+
|
669
|
+
### A2A::Client::Auth::JWT
|
670
|
+
|
671
|
+
JWT bearer token authentication.
|
672
|
+
|
673
|
+
```ruby
|
674
|
+
auth = A2A::Client::Auth::JWT.new(
|
675
|
+
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
676
|
+
header: "Authorization" # Optional, defaults to "Authorization"
|
677
|
+
)
|
678
|
+
```
|
679
|
+
|
680
|
+
### A2A::Client::Auth::ApiKey
|
681
|
+
|
682
|
+
API key authentication.
|
683
|
+
|
684
|
+
```ruby
|
685
|
+
# Header-based API key
|
686
|
+
auth = A2A::Client::Auth::ApiKey.new(
|
687
|
+
key: "your-api-key",
|
688
|
+
header: "X-API-Key"
|
689
|
+
)
|
690
|
+
|
691
|
+
# Query parameter API key
|
692
|
+
auth = A2A::Client::Auth::ApiKey.new(
|
693
|
+
key: "your-api-key",
|
694
|
+
parameter: "api_key"
|
695
|
+
)
|
696
|
+
```
|
697
|
+
|
698
|
+
### Custom Authentication
|
699
|
+
|
700
|
+
```ruby
|
701
|
+
class CustomAuth < A2A::Client::Auth::Base
|
702
|
+
def initialize(credentials)
|
703
|
+
@credentials = credentials
|
704
|
+
end
|
705
|
+
|
706
|
+
def apply_auth(request)
|
707
|
+
# Add custom authentication to request
|
708
|
+
request.headers['X-Custom-Auth'] = generate_signature(@credentials)
|
709
|
+
end
|
710
|
+
|
711
|
+
private
|
712
|
+
|
713
|
+
def generate_signature(credentials)
|
714
|
+
# Custom signature logic
|
715
|
+
end
|
716
|
+
end
|
717
|
+
```
|
718
|
+
|
719
|
+
## Error Handling
|
720
|
+
|
721
|
+
### Exception Hierarchy
|
722
|
+
|
723
|
+
```
|
724
|
+
A2A::Errors::A2AError
|
725
|
+
├── A2A::Errors::ParseError (-32700)
|
726
|
+
├── A2A::Errors::InvalidRequest (-32600)
|
727
|
+
├── A2A::Errors::MethodNotFound (-32601)
|
728
|
+
├── A2A::Errors::InvalidParams (-32602)
|
729
|
+
├── A2A::Errors::InternalError (-32603)
|
730
|
+
├── A2A::Errors::TaskNotFound (-32001)
|
731
|
+
├── A2A::Errors::TaskNotCancelable (-32002)
|
732
|
+
├── A2A::Errors::InvalidTaskState (-32003)
|
733
|
+
├── A2A::Errors::AuthenticationRequired (-32004)
|
734
|
+
├── A2A::Errors::InsufficientPermissions (-32005)
|
735
|
+
├── A2A::Errors::RateLimitExceeded (-32006)
|
736
|
+
├── A2A::Errors::InvalidAgentCard (-32007)
|
737
|
+
├── A2A::Errors::TransportNotSupported (-32008)
|
738
|
+
├── A2A::Errors::InvalidMessageFormat (-32009)
|
739
|
+
├── A2A::Errors::ServiceUnavailable (-32010)
|
740
|
+
├── A2A::Errors::ClientError
|
741
|
+
│ ├── A2A::Errors::HTTPError
|
742
|
+
│ ├── A2A::Errors::TimeoutError
|
743
|
+
│ └── A2A::Errors::AuthenticationError
|
744
|
+
└── A2A::Errors::ServerError
|
745
|
+
```
|
746
|
+
|
747
|
+
### Error Handling Patterns
|
748
|
+
|
749
|
+
```ruby
|
750
|
+
begin
|
751
|
+
response = client.send_message(message)
|
752
|
+
rescue A2A::Errors::AuthenticationError => e
|
753
|
+
# Handle auth errors
|
754
|
+
refresh_credentials
|
755
|
+
retry
|
756
|
+
rescue A2A::Errors::TaskNotFound => e
|
757
|
+
# Handle missing task
|
758
|
+
logger.warn "Task not found: #{e.message}"
|
759
|
+
rescue A2A::Errors::RateLimitExceeded => e
|
760
|
+
# Handle rate limiting
|
761
|
+
sleep(e.retry_after || 60)
|
762
|
+
retry
|
763
|
+
rescue A2A::Errors::A2AError => e
|
764
|
+
# Handle all A2A protocol errors
|
765
|
+
logger.error "A2A Error #{e.code}: #{e.message}"
|
766
|
+
handle_protocol_error(e)
|
767
|
+
rescue StandardError => e
|
768
|
+
# Handle unexpected errors
|
769
|
+
logger.error "Unexpected error: #{e.message}"
|
770
|
+
raise
|
771
|
+
end
|
772
|
+
```
|
773
|
+
|
774
|
+
### Error Response Format
|
775
|
+
|
776
|
+
A2A errors include structured information:
|
777
|
+
|
778
|
+
```ruby
|
779
|
+
begin
|
780
|
+
client.send_message(message)
|
781
|
+
rescue A2A::Errors::A2AError => e
|
782
|
+
puts "Error Code: #{e.code}"
|
783
|
+
puts "Message: #{e.message}"
|
784
|
+
puts "Data: #{e.data}" if e.data
|
785
|
+
|
786
|
+
# Convert to JSON-RPC error format
|
787
|
+
json_rpc_error = e.to_json_rpc_error
|
788
|
+
# => { code: -32001, message: "Task not found", data: {...} }
|
789
|
+
end
|
790
|
+
```
|
791
|
+
|
792
|
+
For complete API documentation with examples, see the [YARD documentation](https://rubydoc.info/gems/a2a-ruby).
|