agent2agent 1.1.1 → 2.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 +4 -4
- data/lib/a2a/agent.rb +98 -241
- data/lib/a2a/{faraday → client}/middleware/json_rpc/request.rb +10 -8
- data/lib/a2a/{faraday → client}/middleware/json_rpc/response.rb +10 -9
- data/lib/a2a/{faraday → client}/middleware/rest/request.rb +24 -18
- data/lib/a2a/{faraday → client}/middleware/rest/response.rb +12 -8
- data/lib/a2a/{faraday → client}/middleware/schema_request.rb +9 -8
- data/lib/a2a/client.rb +40 -39
- data/lib/a2a/errors/json_rpc_error.rb +1 -2
- data/lib/a2a/errors/rest_error.rb +1 -2
- data/lib/a2a/errors.rb +1 -2
- data/lib/a2a/protocol/json_schema/definition.rb +276 -0
- data/lib/a2a/protocol/json_schema/validation_error.rb +132 -0
- data/lib/a2a/{schema.rb → protocol/json_schema.rb} +211 -208
- data/lib/a2a/protocol/protobuf.rb +447 -0
- data/lib/a2a/protocol.rb +31 -0
- data/lib/a2a/server/bindings/grpc.rb +37 -0
- data/lib/a2a/server/bindings/json_rpc.rb +29 -9
- data/lib/a2a/server/bindings/rest.rb +26 -13
- data/lib/a2a/server/middleware/extract_message.rb +145 -0
- data/lib/a2a/{middleware → server/middleware}/fetch_task.rb +82 -89
- data/lib/a2a/{middleware → server/middleware}/limit_history_length.rb +40 -49
- data/lib/a2a/{middleware → server/middleware}/limit_pagination_size.rb +36 -42
- data/lib/a2a/server/middleware/sse_stream.rb +236 -0
- data/lib/a2a/{sse → server/sse}/event_parser.rb +70 -69
- data/lib/a2a/server/sse/json_rpc_stream.rb +89 -0
- data/lib/a2a/server/sse/rest_stream.rb +63 -0
- data/lib/a2a/server/sse/stream.rb +261 -0
- data/lib/a2a/server/triage.rb +35 -4
- data/lib/a2a/server/well_known.rb +27 -0
- data/lib/a2a/server.rb +44 -58
- data/lib/a2a/test_helpers.rb +34 -75
- data/lib/a2a/version.rb +1 -1
- data/lib/a2a.rb +7 -11
- data/lib/traces/provider/a2a/agent.rb +25 -0
- data/lib/traces/provider/a2a.rb +1 -1
- metadata +39 -37
- data/lib/a2a/middleware/extract_message.rb +0 -120
- data/lib/a2a/middleware/sse_stream.rb +0 -235
- data/lib/a2a/proto.rb +0 -444
- data/lib/a2a/schema/definition.rb +0 -148
- data/lib/a2a/schema/validation_error.rb +0 -129
- data/lib/a2a/server/dispatcher.rb +0 -127
- data/lib/a2a/sse/json_rpc_stream.rb +0 -88
- data/lib/a2a/sse/rest_stream.rb +0 -62
- data/lib/a2a/sse/stream.rb +0 -257
- data/lib/traces/provider/a2a/server/dispatcher.rb +0 -26
- /data/lib/a2a/{middleware.rb → server/middleware.rb} +0 -0
- /data/lib/a2a/{sse.rb → server/sse.rb} +0 -0
|
@@ -6,7 +6,7 @@ require "faraday"
|
|
|
6
6
|
require "json"
|
|
7
7
|
|
|
8
8
|
module A2A
|
|
9
|
-
|
|
9
|
+
class Client
|
|
10
10
|
module Middleware
|
|
11
11
|
module REST
|
|
12
12
|
# Faraday response middleware for the A2A HTTP+JSON/REST binding.
|
|
@@ -32,6 +32,9 @@ module A2A
|
|
|
32
32
|
message = parsed.to_s
|
|
33
33
|
data = nil
|
|
34
34
|
end
|
|
35
|
+
# Streaming requests consume the body via on_data, leaving
|
|
36
|
+
# nothing here — fall back to the HTTP status.
|
|
37
|
+
message = "HTTP #{env.status}" if message.to_s.empty?
|
|
35
38
|
raise A2A::RestError.new(message, http_status: env.status, data: data)
|
|
36
39
|
end
|
|
37
40
|
|
|
@@ -59,11 +62,12 @@ module A2A
|
|
|
59
62
|
end
|
|
60
63
|
end
|
|
61
64
|
|
|
62
|
-
::Faraday::Response.register_middleware(a2a_rest: A2A::
|
|
65
|
+
::Faraday::Response.register_middleware(a2a_rest: A2A::Client::Middleware::REST::Response)
|
|
63
66
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
__END__
|
|
68
|
+
describe "A2A::Client::Middleware::REST::Response" do
|
|
69
|
+
middleware = A2A::Client::Middleware::REST::Response
|
|
70
|
+
operation = A2A::Protocol::Protobuf.operation("GetTask")
|
|
67
71
|
|
|
68
72
|
it "wraps response body in Schema object directly (no envelope)" do
|
|
69
73
|
env = ::Faraday::Env.new
|
|
@@ -77,13 +81,13 @@ test do
|
|
|
77
81
|
|
|
78
82
|
middleware.new(nil).on_complete(env)
|
|
79
83
|
|
|
80
|
-
env.body.should.be.kind_of(A2A::
|
|
84
|
+
env.body.should.be.kind_of(A2A::Protocol::JsonSchema::Definition)
|
|
81
85
|
env.body.id.should == "task-123"
|
|
82
86
|
env.body.context_id.should == "ctx-456"
|
|
83
87
|
end
|
|
84
88
|
|
|
85
89
|
it "returns raw hash when response_schema is nil" do
|
|
86
|
-
op = A2A::
|
|
90
|
+
op = A2A::Protocol::Protobuf.operation("DeleteTaskPushNotificationConfig")
|
|
87
91
|
env = ::Faraday::Env.new
|
|
88
92
|
env.status = 200
|
|
89
93
|
env.body = {}
|
|
@@ -138,7 +142,7 @@ test do
|
|
|
138
142
|
|
|
139
143
|
middleware.new(nil).on_complete(env)
|
|
140
144
|
|
|
141
|
-
env.body.should.be.kind_of(A2A::
|
|
145
|
+
env.body.should.be.kind_of(A2A::Protocol::JsonSchema::Definition)
|
|
142
146
|
env.body.id.should == "task-1"
|
|
143
147
|
end
|
|
144
148
|
end
|
|
@@ -6,9 +6,9 @@ require "faraday"
|
|
|
6
6
|
require "json"
|
|
7
7
|
|
|
8
8
|
module A2A
|
|
9
|
-
|
|
9
|
+
class Client
|
|
10
10
|
module Middleware
|
|
11
|
-
# Faraday request middleware that converts A2A::
|
|
11
|
+
# Faraday request middleware that converts A2A::Protocol::JsonSchema::Definition
|
|
12
12
|
# objects into their hash representation for JSON serialization.
|
|
13
13
|
#
|
|
14
14
|
# Place this before the :json request middleware in the stack so
|
|
@@ -18,7 +18,7 @@ module A2A
|
|
|
18
18
|
class SchemaRequest < ::Faraday::Middleware
|
|
19
19
|
def on_request(env)
|
|
20
20
|
body = env.body
|
|
21
|
-
return unless body.is_a?(A2A::
|
|
21
|
+
return unless body.is_a?(A2A::Protocol::JsonSchema::Definition)
|
|
22
22
|
|
|
23
23
|
env.body = body.to_h
|
|
24
24
|
env.request_headers["content-type"] ||= "application/json"
|
|
@@ -28,13 +28,14 @@ module A2A
|
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
::Faraday::Request.register_middleware(a2a_schema: A2A::
|
|
31
|
+
::Faraday::Request.register_middleware(a2a_schema: A2A::Client::Middleware::SchemaRequest)
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
__END__
|
|
34
|
+
describe "A2A::Client::Middleware::SchemaRequest" do
|
|
35
|
+
middleware = A2A::Client::Middleware::SchemaRequest
|
|
35
36
|
|
|
36
37
|
it "converts Schema::Definition to hash" do
|
|
37
|
-
schema_obj = A2A::
|
|
38
|
+
schema_obj = A2A::Protocol::JsonSchema["Agent Capabilities"].new(streaming: true)
|
|
38
39
|
env = ::Faraday::Env.new
|
|
39
40
|
env.body = schema_obj
|
|
40
41
|
env.request_headers = {}
|
|
@@ -57,7 +58,7 @@ test do
|
|
|
57
58
|
end
|
|
58
59
|
|
|
59
60
|
it "does not overwrite existing content-type" do
|
|
60
|
-
schema_obj = A2A::
|
|
61
|
+
schema_obj = A2A::Protocol::JsonSchema["Agent Capabilities"].new(streaming: true)
|
|
61
62
|
env = ::Faraday::Env.new
|
|
62
63
|
env.body = schema_obj
|
|
63
64
|
env.request_headers = { "content-type" => "application/a2a+json" }
|
data/lib/a2a/client.rb
CHANGED
|
@@ -31,15 +31,15 @@ module A2A
|
|
|
31
31
|
|
|
32
32
|
# GET /.well-known/agent-card.json
|
|
33
33
|
#
|
|
34
|
-
# Returns an A2A::
|
|
34
|
+
# Returns an A2A::Protocol::JsonSchema["Agent Card"] instance.
|
|
35
35
|
def agent_card
|
|
36
|
-
response = @conn.get("
|
|
36
|
+
response = @conn.get(".well-known/agent-card.json")
|
|
37
37
|
parsed = response.body
|
|
38
|
-
A2A::
|
|
38
|
+
A2A::Protocol::JsonSchema["Agent Card"].new(parsed)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
# Operations — each maps to a Proto operation name.
|
|
42
|
-
|
|
42
|
+
Protocol::Protobuf.operations.each do |op|
|
|
43
43
|
method_name = op.name.gsub(/([A-Z])/) { "_#{$1.downcase}" }.sub(/^_/, "")
|
|
44
44
|
|
|
45
45
|
if op.server_streaming?
|
|
@@ -98,7 +98,7 @@ module A2A
|
|
|
98
98
|
request = operation.request_schema.new(params)
|
|
99
99
|
request.valid!
|
|
100
100
|
|
|
101
|
-
response = @conn.post
|
|
101
|
+
response = @conn.post do |req|
|
|
102
102
|
req.options.context = { a2a_operation: operation }
|
|
103
103
|
req.body = request
|
|
104
104
|
end
|
|
@@ -110,9 +110,9 @@ module A2A
|
|
|
110
110
|
request = operation.request_schema.new(params)
|
|
111
111
|
request.valid!
|
|
112
112
|
|
|
113
|
-
parser = A2A::SSE::EventParser.new(binding: @binding)
|
|
113
|
+
parser = A2A::Server::SSE::EventParser.new(binding: @binding)
|
|
114
114
|
|
|
115
|
-
@conn.post
|
|
115
|
+
@conn.post do |req|
|
|
116
116
|
req.options.context = { a2a_operation: operation }
|
|
117
117
|
req.body = request
|
|
118
118
|
req.headers["Accept"] = "text/event-stream"
|
|
@@ -127,13 +127,14 @@ module A2A
|
|
|
127
127
|
end
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
__END__
|
|
131
|
+
describe "A2A::Client" do
|
|
131
132
|
# --- JSON-RPC binding (default) ---
|
|
132
133
|
|
|
133
134
|
it "generates methods for all Proto operations" do
|
|
134
135
|
client = A2A::Client.new("http://localhost:9292") do |f|
|
|
135
136
|
f.adapter :test do |stub|
|
|
136
|
-
stub.post("/
|
|
137
|
+
stub.post("/") { |env|
|
|
137
138
|
[200, { "content-type" => "application/json" }, JSON.generate({ "jsonrpc" => "2.0", "id" => 1, "result" => {} })]
|
|
138
139
|
}
|
|
139
140
|
end
|
|
@@ -172,7 +173,7 @@ test do
|
|
|
172
173
|
end
|
|
173
174
|
|
|
174
175
|
card = client.agent_card
|
|
175
|
-
card.should.be.kind_of(A2A::
|
|
176
|
+
card.should.be.kind_of(A2A::Protocol::JsonSchema::Definition)
|
|
176
177
|
card.name.should == "Test Agent"
|
|
177
178
|
card.version.should == "1.0.0"
|
|
178
179
|
end
|
|
@@ -180,7 +181,7 @@ test do
|
|
|
180
181
|
it "json_rpc: send_message validates, wraps in JSON-RPC, returns Schema" do
|
|
181
182
|
client = A2A::Client.new("http://localhost:9292") do |f|
|
|
182
183
|
f.adapter :test do |stub|
|
|
183
|
-
stub.post("/
|
|
184
|
+
stub.post("/") { |env|
|
|
184
185
|
parsed = JSON.parse(env.body)
|
|
185
186
|
parsed["method"].should == "SendMessage"
|
|
186
187
|
parsed["params"]["message"]["role"].should == "ROLE_USER"
|
|
@@ -210,13 +211,13 @@ test do
|
|
|
210
211
|
parts: [{ text: "Hello" }]
|
|
211
212
|
}
|
|
212
213
|
)
|
|
213
|
-
result.should.be.kind_of(A2A::
|
|
214
|
+
result.should.be.kind_of(A2A::Protocol::JsonSchema::Definition)
|
|
214
215
|
end
|
|
215
216
|
|
|
216
217
|
it "json_rpc: get_task returns a Task" do
|
|
217
218
|
client = A2A::Client.new("http://localhost:9292") do |f|
|
|
218
219
|
f.adapter :test do |stub|
|
|
219
|
-
stub.post("/
|
|
220
|
+
stub.post("/") { |env|
|
|
220
221
|
parsed = JSON.parse(env.body)
|
|
221
222
|
parsed["method"].should == "GetTask"
|
|
222
223
|
parsed["params"]["id"].should == "task-123"
|
|
@@ -236,7 +237,7 @@ test do
|
|
|
236
237
|
end
|
|
237
238
|
|
|
238
239
|
result = client.get_task(id: "task-123")
|
|
239
|
-
result.should.be.kind_of(A2A::
|
|
240
|
+
result.should.be.kind_of(A2A::Protocol::JsonSchema::Definition)
|
|
240
241
|
result.id.should == "task-123"
|
|
241
242
|
result.context_id.should == "ctx-456"
|
|
242
243
|
end
|
|
@@ -244,7 +245,7 @@ test do
|
|
|
244
245
|
it "json_rpc: raises on JSON-RPC error" do
|
|
245
246
|
client = A2A::Client.new("http://localhost:9292") do |f|
|
|
246
247
|
f.adapter :test do |stub|
|
|
247
|
-
stub.post("/
|
|
248
|
+
stub.post("/") { |env|
|
|
248
249
|
[200, { "content-type" => "application/json" }, JSON.generate({
|
|
249
250
|
"jsonrpc" => "2.0",
|
|
250
251
|
"id" => 1,
|
|
@@ -263,18 +264,18 @@ test do
|
|
|
263
264
|
it "json_rpc: raises ValidationError on invalid params" do
|
|
264
265
|
client = A2A::Client.new("http://localhost:9292") do |f|
|
|
265
266
|
f.adapter :test do |stub|
|
|
266
|
-
stub.post("/
|
|
267
|
+
stub.post("/") { |env| [200, { "content-type" => "application/json" }, "{}"] }
|
|
267
268
|
end
|
|
268
269
|
end
|
|
269
270
|
|
|
270
|
-
lambda { client.send_message(message: "not_a_hash") }.should.raise(A2A::
|
|
271
|
+
lambda { client.send_message(message: "not_a_hash") }.should.raise(A2A::Protocol::JsonSchema::ValidationError)
|
|
271
272
|
end
|
|
272
273
|
|
|
273
274
|
it "json_rpc: send_streaming_message sends correct method and Accept header" do
|
|
274
275
|
captured_env = nil
|
|
275
276
|
client = A2A::Client.new("http://localhost:9292") do |f|
|
|
276
277
|
f.adapter :test do |stub|
|
|
277
|
-
stub.post("/
|
|
278
|
+
stub.post("/") { |env|
|
|
278
279
|
captured_env = env
|
|
279
280
|
[200, { "content-type" => "text/event-stream" }, ""]
|
|
280
281
|
}
|
|
@@ -301,7 +302,7 @@ test do
|
|
|
301
302
|
captured_env = nil
|
|
302
303
|
client = A2A::Client.new("http://localhost:9292", binding: :rest) do |f|
|
|
303
304
|
f.adapter :test do |stub|
|
|
304
|
-
stub.post("/message:send") { |env|
|
|
305
|
+
stub.post("/rest/message:send") { |env|
|
|
305
306
|
captured_env = env
|
|
306
307
|
[200, { "content-type" => "application/a2a+json" }, JSON.generate({
|
|
307
308
|
"task" => {
|
|
@@ -323,14 +324,14 @@ test do
|
|
|
323
324
|
parts: [{ text: "Hello" }]
|
|
324
325
|
}
|
|
325
326
|
)
|
|
326
|
-
result.should.be.kind_of(A2A::
|
|
327
|
+
result.should.be.kind_of(A2A::Protocol::JsonSchema::Definition)
|
|
327
328
|
captured_env.request_headers["content-type"].should == "application/a2a+json"
|
|
328
329
|
end
|
|
329
330
|
|
|
330
331
|
it "rest: get_task uses GET /tasks/{id}" do
|
|
331
332
|
client = A2A::Client.new("http://localhost:9292", binding: :rest) do |f|
|
|
332
333
|
f.adapter :test do |stub|
|
|
333
|
-
stub.get("/tasks/task-123") { |env|
|
|
334
|
+
stub.get("/rest/tasks/task-123") { |env|
|
|
334
335
|
[200, { "content-type" => "application/a2a+json" }, JSON.generate({
|
|
335
336
|
"id" => "task-123",
|
|
336
337
|
"contextId" => "ctx-456",
|
|
@@ -343,14 +344,14 @@ test do
|
|
|
343
344
|
end
|
|
344
345
|
|
|
345
346
|
result = client.get_task(id: "task-123")
|
|
346
|
-
result.should.be.kind_of(A2A::
|
|
347
|
+
result.should.be.kind_of(A2A::Protocol::JsonSchema::Definition)
|
|
347
348
|
result.id.should == "task-123"
|
|
348
349
|
end
|
|
349
350
|
|
|
350
351
|
it "rest: list_tasks uses GET /tasks" do
|
|
351
352
|
client = A2A::Client.new("http://localhost:9292", binding: :rest) do |f|
|
|
352
353
|
f.adapter :test do |stub|
|
|
353
|
-
stub.get("/tasks") { |env|
|
|
354
|
+
stub.get("/rest/tasks") { |env|
|
|
354
355
|
[200, { "content-type" => "application/a2a+json" }, JSON.generate({
|
|
355
356
|
"tasks" => [
|
|
356
357
|
{ "id" => "t-1", "contextId" => "c-1", "status" => { "state" => "TASK_STATE_COMPLETED" } }
|
|
@@ -361,13 +362,13 @@ test do
|
|
|
361
362
|
end
|
|
362
363
|
|
|
363
364
|
result = client.list_tasks
|
|
364
|
-
result.should.be.kind_of(A2A::
|
|
365
|
+
result.should.be.kind_of(A2A::Protocol::JsonSchema::Definition)
|
|
365
366
|
end
|
|
366
367
|
|
|
367
368
|
it "rest: cancel_task uses POST /tasks/{id}:cancel" do
|
|
368
369
|
client = A2A::Client.new("http://localhost:9292", binding: :rest) do |f|
|
|
369
370
|
f.adapter :test do |stub|
|
|
370
|
-
stub.post("/tasks/task-123:cancel") { |env|
|
|
371
|
+
stub.post("/rest/tasks/task-123:cancel") { |env|
|
|
371
372
|
[200, { "content-type" => "application/a2a+json" }, JSON.generate({
|
|
372
373
|
"id" => "task-123", "contextId" => "ctx-456",
|
|
373
374
|
"status" => { "state" => "TASK_STATE_CANCELED" }
|
|
@@ -377,14 +378,14 @@ test do
|
|
|
377
378
|
end
|
|
378
379
|
|
|
379
380
|
result = client.cancel_task(id: "task-123")
|
|
380
|
-
result.should.be.kind_of(A2A::
|
|
381
|
+
result.should.be.kind_of(A2A::Protocol::JsonSchema::Definition)
|
|
381
382
|
result.id.should == "task-123"
|
|
382
383
|
end
|
|
383
384
|
|
|
384
385
|
it "rest: create_task_push_notification_config uses POST /tasks/{task_id}/pushNotificationConfigs" do
|
|
385
386
|
client = A2A::Client.new("http://localhost:9292", binding: :rest) do |f|
|
|
386
387
|
f.adapter :test do |stub|
|
|
387
|
-
stub.post("/tasks/task-123/pushNotificationConfigs") { |env|
|
|
388
|
+
stub.post("/rest/tasks/task-123/pushNotificationConfigs") { |env|
|
|
388
389
|
[200, { "content-type" => "application/a2a+json" }, JSON.generate({
|
|
389
390
|
"id" => "config-1", "taskId" => "task-123",
|
|
390
391
|
"url" => "https://example.com/webhook"
|
|
@@ -396,13 +397,13 @@ test do
|
|
|
396
397
|
result = client.create_task_push_notification_config(
|
|
397
398
|
task_id: "task-123", url: "https://example.com/webhook"
|
|
398
399
|
)
|
|
399
|
-
result.should.be.kind_of(A2A::
|
|
400
|
+
result.should.be.kind_of(A2A::Protocol::JsonSchema::Definition)
|
|
400
401
|
end
|
|
401
402
|
|
|
402
403
|
it "rest: get_task_push_notification_config uses GET /tasks/{task_id}/pushNotificationConfigs/{id}" do
|
|
403
404
|
client = A2A::Client.new("http://localhost:9292", binding: :rest) do |f|
|
|
404
405
|
f.adapter :test do |stub|
|
|
405
|
-
stub.get("/tasks/task-123/pushNotificationConfigs/config-1") { |env|
|
|
406
|
+
stub.get("/rest/tasks/task-123/pushNotificationConfigs/config-1") { |env|
|
|
406
407
|
[200, { "content-type" => "application/a2a+json" }, JSON.generate({
|
|
407
408
|
"id" => "config-1", "taskId" => "task-123",
|
|
408
409
|
"url" => "https://example.com/webhook"
|
|
@@ -412,13 +413,13 @@ test do
|
|
|
412
413
|
end
|
|
413
414
|
|
|
414
415
|
result = client.get_task_push_notification_config(id: "config-1", task_id: "task-123")
|
|
415
|
-
result.should.be.kind_of(A2A::
|
|
416
|
+
result.should.be.kind_of(A2A::Protocol::JsonSchema::Definition)
|
|
416
417
|
end
|
|
417
418
|
|
|
418
419
|
it "rest: list_task_push_notification_configs uses GET /tasks/{task_id}/pushNotificationConfigs" do
|
|
419
420
|
client = A2A::Client.new("http://localhost:9292", binding: :rest) do |f|
|
|
420
421
|
f.adapter :test do |stub|
|
|
421
|
-
stub.get("/tasks/task-123/pushNotificationConfigs") { |env|
|
|
422
|
+
stub.get("/rest/tasks/task-123/pushNotificationConfigs") { |env|
|
|
422
423
|
[200, { "content-type" => "application/a2a+json" }, JSON.generate({
|
|
423
424
|
"pushNotificationConfigs" => []
|
|
424
425
|
})]
|
|
@@ -427,13 +428,13 @@ test do
|
|
|
427
428
|
end
|
|
428
429
|
|
|
429
430
|
result = client.list_task_push_notification_configs(task_id: "task-123")
|
|
430
|
-
result.should.be.kind_of(A2A::
|
|
431
|
+
result.should.be.kind_of(A2A::Protocol::JsonSchema::Definition)
|
|
431
432
|
end
|
|
432
433
|
|
|
433
434
|
it "rest: delete_task_push_notification_config uses DELETE /tasks/{task_id}/pushNotificationConfigs/{id}" do
|
|
434
435
|
client = A2A::Client.new("http://localhost:9292", binding: :rest) do |f|
|
|
435
436
|
f.adapter :test do |stub|
|
|
436
|
-
stub.delete("/tasks/task-123/pushNotificationConfigs/config-1") { |env|
|
|
437
|
+
stub.delete("/rest/tasks/task-123/pushNotificationConfigs/config-1") { |env|
|
|
437
438
|
[200, { "content-type" => "application/a2a+json" }, JSON.generate({})]
|
|
438
439
|
}
|
|
439
440
|
end
|
|
@@ -446,7 +447,7 @@ test do
|
|
|
446
447
|
it "rest: get_extended_agent_card uses GET /extendedAgentCard" do
|
|
447
448
|
client = A2A::Client.new("http://localhost:9292", binding: :rest) do |f|
|
|
448
449
|
f.adapter :test do |stub|
|
|
449
|
-
stub.get("/extendedAgentCard") { |env|
|
|
450
|
+
stub.get("/rest/extendedAgentCard") { |env|
|
|
450
451
|
[200, { "content-type" => "application/a2a+json" }, JSON.generate({
|
|
451
452
|
"name" => "Extended Agent",
|
|
452
453
|
"version" => "2.0.0",
|
|
@@ -460,7 +461,7 @@ test do
|
|
|
460
461
|
end
|
|
461
462
|
|
|
462
463
|
result = client.get_extended_agent_card
|
|
463
|
-
result.should.be.kind_of(A2A::
|
|
464
|
+
result.should.be.kind_of(A2A::Protocol::JsonSchema::Definition)
|
|
464
465
|
result.name.should == "Extended Agent"
|
|
465
466
|
end
|
|
466
467
|
|
|
@@ -468,7 +469,7 @@ test do
|
|
|
468
469
|
captured_env = nil
|
|
469
470
|
client = A2A::Client.new("http://localhost:9292", binding: :rest) do |f|
|
|
470
471
|
f.adapter :test do |stub|
|
|
471
|
-
stub.get("/tasks/task-1:subscribe") { |env|
|
|
472
|
+
stub.get("/rest/tasks/task-1:subscribe") { |env|
|
|
472
473
|
captured_env = env
|
|
473
474
|
[200, { "content-type" => "text/event-stream" }, ""]
|
|
474
475
|
}
|
|
@@ -484,7 +485,7 @@ test do
|
|
|
484
485
|
it "rest: raises on HTTP 400 error" do
|
|
485
486
|
client = A2A::Client.new("http://localhost:9292", binding: :rest) do |f|
|
|
486
487
|
f.adapter :test do |stub|
|
|
487
|
-
stub.get("/tasks/bad-id") { |env|
|
|
488
|
+
stub.get("/rest/tasks/bad-id") { |env|
|
|
488
489
|
[400, { "content-type" => "application/problem+json" }, JSON.generate({
|
|
489
490
|
"type" => "error",
|
|
490
491
|
"title" => "Bad Request","status" => 400
|
|
@@ -499,10 +500,10 @@ test do
|
|
|
499
500
|
it "rest: raises ValidationError on invalid params" do
|
|
500
501
|
client = A2A::Client.new("http://localhost:9292", binding: :rest) do |f|
|
|
501
502
|
f.adapter :test do |stub|
|
|
502
|
-
stub.post("/message:send") { |env| [200, { "content-type" => "application/a2a+json" }, "{}"] }
|
|
503
|
+
stub.post("/rest/message:send") { |env| [200, { "content-type" => "application/a2a+json" }, "{}"] }
|
|
503
504
|
end
|
|
504
505
|
end
|
|
505
506
|
|
|
506
|
-
lambda { client.send_message(message: "not_a_hash") }.should.raise(A2A::
|
|
507
|
+
lambda { client.send_message(message: "not_a_hash") }.should.raise(A2A::Protocol::JsonSchema::ValidationError)
|
|
507
508
|
end
|
|
508
509
|
end
|
|
@@ -23,7 +23,7 @@ module A2A
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
__END__
|
|
27
27
|
describe "A2A::JsonRpcError" do
|
|
28
28
|
it "has correct code and message" do
|
|
29
29
|
err = A2A::JsonRpcError.new("Task not found", code: -32001)
|
|
@@ -68,4 +68,3 @@ test do
|
|
|
68
68
|
h[:data].should == data
|
|
69
69
|
end
|
|
70
70
|
end
|
|
71
|
-
end
|
|
@@ -20,7 +20,7 @@ module A2A
|
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
__END__
|
|
24
24
|
describe "A2A::RestError" do
|
|
25
25
|
it "has correct http_status and message" do
|
|
26
26
|
err = A2A::RestError.new("Not Found", http_status: 404)
|
|
@@ -65,4 +65,3 @@ test do
|
|
|
65
65
|
h[:data].should == data
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
|
-
end
|
data/lib/a2a/errors.rb
CHANGED
|
@@ -337,7 +337,7 @@ require "a2a/errors/rest_error"
|
|
|
337
337
|
# | ExtendedAgentCardNotConfiguredError | The agent lacks a configured extended agent card when required.
|
|
338
338
|
# | ExtensionSupportRequiredError | A required extension was not declared as supported by the client.
|
|
339
339
|
# | VersionNotSupportedError | The requested A2A-Version is not supported by the agent.
|
|
340
|
-
|
|
340
|
+
__END__
|
|
341
341
|
describe "A2A::Error" do
|
|
342
342
|
it "has code, http_status, and message" do
|
|
343
343
|
err = A2A::Error.new("boom", code: -32000, http_status: 500)
|
|
@@ -532,4 +532,3 @@ test do
|
|
|
532
532
|
err.is_a?(A2A::Error).should == true
|
|
533
533
|
end
|
|
534
534
|
end
|
|
535
|
-
end
|