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,520 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../types"
|
4
|
+
require_relative "../errors"
|
5
|
+
require_relative "task_manager"
|
6
|
+
require_relative "push_notification_manager"
|
7
|
+
|
8
|
+
##
|
9
|
+
# Standard A2A protocol method implementations
|
10
|
+
#
|
11
|
+
# This module provides implementations for all core A2A JSON-RPC methods
|
12
|
+
# including message handling, task management, and push notifications.
|
13
|
+
#
|
14
|
+
module A2A
|
15
|
+
module Server
|
16
|
+
module A2AMethods
|
17
|
+
def self.included(base)
|
18
|
+
base.extend(ClassMethods)
|
19
|
+
|
20
|
+
# Register all standard A2A methods when included
|
21
|
+
base.register_a2a_methods
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
##
|
26
|
+
# Register all standard A2A protocol methods
|
27
|
+
def register_a2a_methods
|
28
|
+
# Core messaging methods
|
29
|
+
a2a_method "message/send" do |params, context|
|
30
|
+
handle_message_send(params, context)
|
31
|
+
end
|
32
|
+
|
33
|
+
a2a_method "message/stream", streaming: true do |params, context|
|
34
|
+
handle_message_stream(params, context)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Task management methods
|
38
|
+
a2a_method "tasks/get" do |params, context|
|
39
|
+
handle_tasks_get(params, context)
|
40
|
+
end
|
41
|
+
|
42
|
+
a2a_method "tasks/cancel" do |params, context|
|
43
|
+
handle_tasks_cancel(params, context)
|
44
|
+
end
|
45
|
+
|
46
|
+
a2a_method "tasks/resubscribe", streaming: true do |params, context|
|
47
|
+
handle_tasks_resubscribe(params, context)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Push notification methods
|
51
|
+
a2a_method "tasks/pushNotificationConfig/set" do |params, context|
|
52
|
+
handle_push_notification_config_set(params, context)
|
53
|
+
end
|
54
|
+
|
55
|
+
a2a_method "tasks/pushNotificationConfig/get" do |params, context|
|
56
|
+
handle_push_notification_config_get(params, context)
|
57
|
+
end
|
58
|
+
|
59
|
+
a2a_method "tasks/pushNotificationConfig/list" do |params, context|
|
60
|
+
handle_push_notification_config_list(params, context)
|
61
|
+
end
|
62
|
+
|
63
|
+
a2a_method "tasks/pushNotificationConfig/delete" do |params, context|
|
64
|
+
handle_push_notification_config_delete(params, context)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Agent card methods
|
68
|
+
a2a_method "agent/getCard" do |params, context|
|
69
|
+
handle_agent_get_card(params, context)
|
70
|
+
end
|
71
|
+
|
72
|
+
a2a_method "agent/getAuthenticatedExtendedCard" do |params, context|
|
73
|
+
handle_agent_get_authenticated_extended_card(params, context)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# Handle message/send method
|
80
|
+
#
|
81
|
+
# @param params [Hash] Method parameters
|
82
|
+
# @param context [A2A::Server::Context] Request context
|
83
|
+
# @return [Hash] Response with task information
|
84
|
+
def handle_message_send(params, context)
|
85
|
+
validate_required_params(params, %w[message])
|
86
|
+
|
87
|
+
message_data = params["message"]
|
88
|
+
blocking = params.fetch("blocking", true)
|
89
|
+
|
90
|
+
# Parse message
|
91
|
+
message = A2A::Types::Message.from_h(message_data)
|
92
|
+
|
93
|
+
# Create task for message processing
|
94
|
+
task = task_manager.create_task(
|
95
|
+
type: "message_processing",
|
96
|
+
params: { message: message.to_h, blocking: blocking },
|
97
|
+
context_id: message.context_id,
|
98
|
+
metadata: {
|
99
|
+
message_id: message.message_id,
|
100
|
+
role: message.role
|
101
|
+
}
|
102
|
+
)
|
103
|
+
|
104
|
+
# Process message (delegate to subclass implementation)
|
105
|
+
if blocking
|
106
|
+
# Update task to working state first
|
107
|
+
task_manager.update_task_status(
|
108
|
+
task.id,
|
109
|
+
A2A::Types::TaskStatus.new(
|
110
|
+
state: A2A::Types::TASK_STATE_WORKING,
|
111
|
+
message: "Processing message",
|
112
|
+
updated_at: Time.now.utc.iso8601
|
113
|
+
)
|
114
|
+
)
|
115
|
+
|
116
|
+
# Synchronous processing
|
117
|
+
result = process_message_sync(message, task, context)
|
118
|
+
|
119
|
+
# Update task with result
|
120
|
+
task_manager.update_task_status(
|
121
|
+
task.id,
|
122
|
+
A2A::Types::TaskStatus.new(
|
123
|
+
state: A2A::Types::TASK_STATE_COMPLETED,
|
124
|
+
result: result,
|
125
|
+
updated_at: Time.now.utc.iso8601
|
126
|
+
)
|
127
|
+
)
|
128
|
+
|
129
|
+
{
|
130
|
+
task_id: task.id,
|
131
|
+
context_id: task.context_id,
|
132
|
+
result: result
|
133
|
+
}
|
134
|
+
else
|
135
|
+
# Asynchronous processing
|
136
|
+
process_message_async(message, task, context)
|
137
|
+
|
138
|
+
{
|
139
|
+
task_id: task.id,
|
140
|
+
context_id: task.context_id,
|
141
|
+
status: task.status.to_h
|
142
|
+
}
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# Handle message/stream method
|
148
|
+
#
|
149
|
+
# @param params [Hash] Method parameters
|
150
|
+
# @param context [A2A::Server::Context] Request context
|
151
|
+
# @return [Enumerator] Stream of responses
|
152
|
+
def handle_message_stream(params, context)
|
153
|
+
validate_required_params(params, %w[message])
|
154
|
+
|
155
|
+
message_data = params["message"]
|
156
|
+
message = A2A::Types::Message.from_h(message_data)
|
157
|
+
|
158
|
+
# Create task for streaming message processing
|
159
|
+
task = task_manager.create_task(
|
160
|
+
type: "message_streaming",
|
161
|
+
params: { message: message.to_h },
|
162
|
+
context_id: message.context_id,
|
163
|
+
metadata: {
|
164
|
+
message_id: message.message_id,
|
165
|
+
role: message.role,
|
166
|
+
streaming: true
|
167
|
+
}
|
168
|
+
)
|
169
|
+
|
170
|
+
# Return enumerator for streaming responses
|
171
|
+
Enumerator.new do |yielder|
|
172
|
+
# Update task to working state
|
173
|
+
task_manager.update_task_status(
|
174
|
+
task.id,
|
175
|
+
A2A::Types::TaskStatus.new(
|
176
|
+
state: A2A::Types::TASK_STATE_WORKING,
|
177
|
+
message: "Processing message stream",
|
178
|
+
updated_at: Time.now.utc.iso8601
|
179
|
+
)
|
180
|
+
)
|
181
|
+
|
182
|
+
# Process message stream (delegate to subclass implementation)
|
183
|
+
process_message_stream(message, task, context) do |response|
|
184
|
+
yielder << {
|
185
|
+
task_id: task.id,
|
186
|
+
context_id: task.context_id,
|
187
|
+
response: response
|
188
|
+
}
|
189
|
+
end
|
190
|
+
|
191
|
+
# Mark task as completed
|
192
|
+
task_manager.update_task_status(
|
193
|
+
task.id,
|
194
|
+
A2A::Types::TaskStatus.new(
|
195
|
+
state: A2A::Types::TASK_STATE_COMPLETED,
|
196
|
+
message: "Stream completed",
|
197
|
+
updated_at: Time.now.utc.iso8601
|
198
|
+
)
|
199
|
+
)
|
200
|
+
rescue StandardError => e
|
201
|
+
# Mark task as failed
|
202
|
+
task_manager.update_task_status(
|
203
|
+
task.id,
|
204
|
+
A2A::Types::TaskStatus.new(
|
205
|
+
state: A2A::Types::TASK_STATE_FAILED,
|
206
|
+
error: { message: e.message, type: e.class.name },
|
207
|
+
updated_at: Time.now.utc.iso8601
|
208
|
+
)
|
209
|
+
)
|
210
|
+
raise
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
##
|
215
|
+
# Handle tasks/get method
|
216
|
+
#
|
217
|
+
# @param params [Hash] Method parameters
|
218
|
+
# @param context [A2A::Server::Context] Request context
|
219
|
+
# @return [Hash] Task information
|
220
|
+
def handle_tasks_get(params, _context)
|
221
|
+
validate_required_params(params, %w[id])
|
222
|
+
|
223
|
+
task_id = params["id"]
|
224
|
+
history_length = params["historyLength"]
|
225
|
+
|
226
|
+
task = task_manager.get_task(task_id, history_length: history_length)
|
227
|
+
|
228
|
+
{
|
229
|
+
task: task.to_h
|
230
|
+
}
|
231
|
+
end
|
232
|
+
|
233
|
+
##
|
234
|
+
# Handle tasks/cancel method
|
235
|
+
#
|
236
|
+
# @param params [Hash] Method parameters
|
237
|
+
# @param context [A2A::Server::Context] Request context
|
238
|
+
# @return [Hash] Cancellation result
|
239
|
+
def handle_tasks_cancel(params, _context)
|
240
|
+
validate_required_params(params, %w[id])
|
241
|
+
|
242
|
+
task_id = params["id"]
|
243
|
+
reason = params["reason"]
|
244
|
+
|
245
|
+
task = task_manager.cancel_task(task_id, reason: reason)
|
246
|
+
|
247
|
+
{
|
248
|
+
task_id: task.id,
|
249
|
+
status: task.status.to_h
|
250
|
+
}
|
251
|
+
end
|
252
|
+
|
253
|
+
##
|
254
|
+
# Handle tasks/resubscribe method
|
255
|
+
#
|
256
|
+
# @param params [Hash] Method parameters
|
257
|
+
# @param context [A2A::Server::Context] Request context
|
258
|
+
# @return [Enumerator] Stream of task updates
|
259
|
+
def handle_tasks_resubscribe(params, _context)
|
260
|
+
validate_required_params(params, %w[id])
|
261
|
+
|
262
|
+
task_id = params["id"]
|
263
|
+
|
264
|
+
# Verify task exists
|
265
|
+
task = task_manager.get_task(task_id)
|
266
|
+
|
267
|
+
# Return enumerator for task update stream
|
268
|
+
Enumerator.new do |yielder|
|
269
|
+
# Register for task updates
|
270
|
+
client_id = push_notification_manager.register_sse_client(task_id, yielder)
|
271
|
+
|
272
|
+
begin
|
273
|
+
# Send current task state immediately
|
274
|
+
yielder << {
|
275
|
+
event_type: "task_status_update",
|
276
|
+
event_data: {
|
277
|
+
task_id: task.id,
|
278
|
+
context_id: task.context_id,
|
279
|
+
status: task.status.to_h
|
280
|
+
}
|
281
|
+
}
|
282
|
+
|
283
|
+
# Keep connection alive until client disconnects
|
284
|
+
# The actual updates will be sent via the push notification manager
|
285
|
+
loop do
|
286
|
+
sleep 1
|
287
|
+
# Check if client is still connected (implementation specific)
|
288
|
+
break unless client_connected?(yielder)
|
289
|
+
end
|
290
|
+
ensure
|
291
|
+
# Unregister client when done
|
292
|
+
push_notification_manager.unregister_sse_client(task_id, client_id)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
##
|
298
|
+
# Handle tasks/pushNotificationConfig/set method
|
299
|
+
#
|
300
|
+
# @param params [Hash] Method parameters
|
301
|
+
# @param context [A2A::Server::Context] Request context
|
302
|
+
# @return [Hash] Configuration result
|
303
|
+
def handle_push_notification_config_set(params, _context)
|
304
|
+
validate_required_params(params, %w[taskId config])
|
305
|
+
|
306
|
+
task_id = params["taskId"]
|
307
|
+
config_data = params["config"]
|
308
|
+
|
309
|
+
# Verify task exists
|
310
|
+
task_manager.get_task(task_id)
|
311
|
+
|
312
|
+
# Create push notification config
|
313
|
+
config = push_notification_manager.set_push_notification_config(task_id, config_data)
|
314
|
+
|
315
|
+
{
|
316
|
+
task_id: task_id,
|
317
|
+
config: config.push_notification_config.to_h
|
318
|
+
}
|
319
|
+
end
|
320
|
+
|
321
|
+
##
|
322
|
+
# Handle tasks/pushNotificationConfig/get method
|
323
|
+
#
|
324
|
+
# @param params [Hash] Method parameters
|
325
|
+
# @param context [A2A::Server::Context] Request context
|
326
|
+
# @return [Hash] Configuration information
|
327
|
+
def handle_push_notification_config_get(params, _context)
|
328
|
+
validate_required_params(params, %w[taskId])
|
329
|
+
|
330
|
+
task_id = params["taskId"]
|
331
|
+
config_id = params["configId"]
|
332
|
+
|
333
|
+
config = push_notification_manager.get_push_notification_config(
|
334
|
+
task_id,
|
335
|
+
config_id: config_id
|
336
|
+
)
|
337
|
+
|
338
|
+
raise A2A::Errors::NotFound, "Push notification config not found" unless config
|
339
|
+
|
340
|
+
{
|
341
|
+
task_id: task_id,
|
342
|
+
config: config.push_notification_config.to_h
|
343
|
+
}
|
344
|
+
end
|
345
|
+
|
346
|
+
##
|
347
|
+
# Handle tasks/pushNotificationConfig/list method
|
348
|
+
#
|
349
|
+
# @param params [Hash] Method parameters
|
350
|
+
# @param context [A2A::Server::Context] Request context
|
351
|
+
# @return [Hash] List of configurations
|
352
|
+
def handle_push_notification_config_list(params, _context)
|
353
|
+
validate_required_params(params, %w[taskId])
|
354
|
+
|
355
|
+
task_id = params["taskId"]
|
356
|
+
|
357
|
+
configs = push_notification_manager.list_push_notification_configs(task_id)
|
358
|
+
|
359
|
+
{
|
360
|
+
task_id: task_id,
|
361
|
+
configs: configs.map { |config| config.push_notification_config.to_h }
|
362
|
+
}
|
363
|
+
end
|
364
|
+
|
365
|
+
##
|
366
|
+
# Handle tasks/pushNotificationConfig/delete method
|
367
|
+
#
|
368
|
+
# @param params [Hash] Method parameters
|
369
|
+
# @param context [A2A::Server::Context] Request context
|
370
|
+
# @return [Hash] Deletion result
|
371
|
+
def handle_push_notification_config_delete(params, _context)
|
372
|
+
validate_required_params(params, %w[taskId configId])
|
373
|
+
|
374
|
+
task_id = params["taskId"]
|
375
|
+
config_id = params["configId"]
|
376
|
+
|
377
|
+
deleted = push_notification_manager.delete_push_notification_config(task_id, config_id)
|
378
|
+
|
379
|
+
raise A2A::Errors::NotFound, "Push notification config not found" unless deleted
|
380
|
+
|
381
|
+
{
|
382
|
+
task_id: task_id,
|
383
|
+
config_id: config_id,
|
384
|
+
deleted: true
|
385
|
+
}
|
386
|
+
end
|
387
|
+
|
388
|
+
##
|
389
|
+
# Handle agent/getCard method
|
390
|
+
#
|
391
|
+
# @param params [Hash] Method parameters
|
392
|
+
# @param context [A2A::Server::Context] Request context
|
393
|
+
# @return [Hash] Agent card
|
394
|
+
def handle_agent_get_card(_params, context)
|
395
|
+
# Generate agent card from registered capabilities
|
396
|
+
card = generate_agent_card(context)
|
397
|
+
|
398
|
+
{
|
399
|
+
agent_card: card.to_h
|
400
|
+
}
|
401
|
+
end
|
402
|
+
|
403
|
+
##
|
404
|
+
# Handle agent/getAuthenticatedExtendedCard method
|
405
|
+
#
|
406
|
+
# @param params [Hash] Method parameters
|
407
|
+
# @param context [A2A::Server::Context] Request context
|
408
|
+
# @return [Hash] Extended agent card
|
409
|
+
def handle_agent_get_authenticated_extended_card(_params, context)
|
410
|
+
# Verify authentication
|
411
|
+
raise A2A::Errors::AuthenticationRequired, "Authentication required for extended agent card" unless context.authenticated?
|
412
|
+
|
413
|
+
# Generate extended agent card with authentication context
|
414
|
+
card = generate_extended_agent_card(context)
|
415
|
+
|
416
|
+
{
|
417
|
+
agent_card: card.to_h
|
418
|
+
}
|
419
|
+
end
|
420
|
+
|
421
|
+
##
|
422
|
+
# Get task manager instance
|
423
|
+
#
|
424
|
+
# @return [A2A::Server::TaskManager] Task manager
|
425
|
+
def task_manager
|
426
|
+
@task_manager ||= A2A::Server::TaskManager.new
|
427
|
+
end
|
428
|
+
|
429
|
+
##
|
430
|
+
# Get push notification manager instance
|
431
|
+
#
|
432
|
+
# @return [A2A::Server::PushNotificationManager] Push notification manager
|
433
|
+
def push_notification_manager
|
434
|
+
@push_notification_manager ||= A2A::Server::PushNotificationManager.new
|
435
|
+
end
|
436
|
+
|
437
|
+
protected
|
438
|
+
|
439
|
+
##
|
440
|
+
# Process message synchronously (to be implemented by subclasses)
|
441
|
+
#
|
442
|
+
# @param message [A2A::Types::Message] The message to process
|
443
|
+
# @param task [A2A::Types::Task] The associated task
|
444
|
+
# @param context [A2A::Server::Context] Request context
|
445
|
+
# @return [Object] Processing result
|
446
|
+
def process_message_sync(message, task, context)
|
447
|
+
raise NotImplementedError, "Subclasses must implement process_message_sync"
|
448
|
+
end
|
449
|
+
|
450
|
+
##
|
451
|
+
# Process message asynchronously (to be implemented by subclasses)
|
452
|
+
#
|
453
|
+
# @param message [A2A::Types::Message] The message to process
|
454
|
+
# @param task [A2A::Types::Task] The associated task
|
455
|
+
# @param context [A2A::Server::Context] Request context
|
456
|
+
# @return [void]
|
457
|
+
def process_message_async(message, task, context)
|
458
|
+
raise NotImplementedError, "Subclasses must implement process_message_async"
|
459
|
+
end
|
460
|
+
|
461
|
+
##
|
462
|
+
# Process message stream (to be implemented by subclasses)
|
463
|
+
#
|
464
|
+
# @param message [A2A::Types::Message] The message to process
|
465
|
+
# @param task [A2A::Types::Task] The associated task
|
466
|
+
# @param context [A2A::Server::Context] Request context
|
467
|
+
# @yield [response] Yields each response in the stream
|
468
|
+
# @return [void]
|
469
|
+
def process_message_stream(message, task, context)
|
470
|
+
raise NotImplementedError, "Subclasses must implement process_message_stream"
|
471
|
+
end
|
472
|
+
|
473
|
+
##
|
474
|
+
# Generate agent card (to be implemented by subclasses)
|
475
|
+
#
|
476
|
+
# @param context [A2A::Server::Context] Request context
|
477
|
+
# @return [A2A::Types::AgentCard] The agent card
|
478
|
+
def generate_agent_card(context)
|
479
|
+
raise NotImplementedError, "Subclasses must implement generate_agent_card"
|
480
|
+
end
|
481
|
+
|
482
|
+
##
|
483
|
+
# Generate extended agent card (to be implemented by subclasses)
|
484
|
+
#
|
485
|
+
# @param context [A2A::Server::Context] Request context
|
486
|
+
# @return [A2A::Types::AgentCard] The extended agent card
|
487
|
+
def generate_extended_agent_card(context)
|
488
|
+
# Default implementation returns the same as regular card
|
489
|
+
generate_agent_card(context)
|
490
|
+
end
|
491
|
+
|
492
|
+
private
|
493
|
+
|
494
|
+
##
|
495
|
+
# Validate required parameters
|
496
|
+
#
|
497
|
+
# @param params [Hash] Parameters to validate
|
498
|
+
# @param required [Array<String>] Required parameter names
|
499
|
+
# @raise [A2A::Errors::InvalidParams] If required parameters are missing
|
500
|
+
def validate_required_params(params, required)
|
501
|
+
missing = required.reject { |param| params.key?(param) }
|
502
|
+
|
503
|
+
return if missing.empty?
|
504
|
+
|
505
|
+
raise A2A::Errors::InvalidParams, "Missing required parameters: #{missing.join(', ')}"
|
506
|
+
end
|
507
|
+
|
508
|
+
##
|
509
|
+
# Check if client is still connected (implementation specific)
|
510
|
+
#
|
511
|
+
# @param yielder [Object] The yielder object
|
512
|
+
# @return [Boolean] True if client is connected
|
513
|
+
def client_connected?(_yielder)
|
514
|
+
# This is a placeholder - actual implementation depends on the server framework
|
515
|
+
# For now, assume client is always connected
|
516
|
+
true
|
517
|
+
end
|
518
|
+
end
|
519
|
+
end
|
520
|
+
end
|