agent2agent 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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/data/a2a.json +1961 -0
  3. data/data/a2a.proto +796 -0
  4. data/data/download-a2a-resources +4 -0
  5. data/data/spec.txt +3611 -0
  6. data/lib/a2a/agent.rb +243 -0
  7. data/lib/a2a/bindings/json_rpc.rb +110 -0
  8. data/lib/a2a/bindings/rest.rb +106 -0
  9. data/lib/a2a/client.rb +85 -0
  10. data/lib/a2a/proto.rb +444 -0
  11. data/lib/a2a/schema/definition.rb +114 -0
  12. data/lib/a2a/schema/validation_error.rb +129 -0
  13. data/lib/a2a/schema.rb +429 -0
  14. data/lib/a2a/server/cancel_task.rb +14 -0
  15. data/lib/a2a/server/create_task_push_notification_config.rb +14 -0
  16. data/lib/a2a/server/delete_task_push_notification_config.rb +14 -0
  17. data/lib/a2a/server/dispatcher.rb +127 -0
  18. data/lib/a2a/server/env.rb +28 -0
  19. data/lib/a2a/server/get_extended_agent_card.rb +15 -0
  20. data/lib/a2a/server/get_task.rb +14 -0
  21. data/lib/a2a/server/get_task_push_notification_config.rb +14 -0
  22. data/lib/a2a/server/list_task_push_notification_configs.rb +14 -0
  23. data/lib/a2a/server/list_tasks.rb +14 -0
  24. data/lib/a2a/server/send_message.rb +14 -0
  25. data/lib/a2a/server/send_streaming_message.rb +14 -0
  26. data/lib/a2a/server/subscribe_to_task.rb +14 -0
  27. data/lib/a2a/server/triage.rb +96 -0
  28. data/lib/a2a/server.rb +98 -0
  29. data/lib/a2a/sse/json_rpc_stream.rb +66 -0
  30. data/lib/a2a/sse/rest_stream.rb +50 -0
  31. data/lib/a2a/sse/stream.rb +129 -0
  32. data/lib/a2a/sse.rb +5 -0
  33. data/lib/a2a/store/processor.rb +136 -0
  34. data/lib/a2a/store/pub_sub.rb +149 -0
  35. data/lib/a2a/store/sqlite.rb +533 -0
  36. data/lib/a2a/store/webhooks.rb +94 -0
  37. data/lib/a2a/store.rb +6 -0
  38. data/lib/a2a/task_store.rb +315 -0
  39. data/lib/a2a/version.rb +5 -0
  40. data/lib/a2a.rb +26 -0
  41. metadata +216 -0
data/lib/a2a/schema.rb ADDED
@@ -0,0 +1,429 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "a2a"
5
+
6
+ module A2A
7
+ # Schema-validated A2A protocol objects, powered by json_schemer.
8
+ #
9
+ # Loads the bundled data/a2a.json schema, rewrites external $ref
10
+ # values to internal #/definitions/... pointers, and dynamically
11
+ # generates Definition subclasses for each type.
12
+ #
13
+ # A2A::Schema["Agent Capabilities"]
14
+ # #=> Class < Definition with .schema, .valid?, reader methods
15
+ #
16
+ # A2A::Schema["Agent Card"]
17
+ # #=> Class < Definition
18
+ #
19
+ # A2A::Schema.list_definitions
20
+ # #=> ["API Key Security Scheme", "Agent Capabilities", ...]
21
+ #
22
+ module Schema
23
+ DATA_PATH = File.expand_path("../../data/a2a.json", __dir__).freeze
24
+
25
+ @definition_classes = {}
26
+ @schemer = nil
27
+ @raw_schema = nil
28
+ @ref_map = nil
29
+
30
+ class << self
31
+ # Look up a definition by title.
32
+ #
33
+ # A2A::Schema["Agent Capabilities"]
34
+ # #=> Class < Definition
35
+ #
36
+ def [](name)
37
+ @definition_classes[name] ||= begin
38
+ definitions = raw_schema.fetch("definitions", {})
39
+
40
+ unless definitions.key?(name)
41
+ raise "No A2A definition found for #{name.inspect}!" \
42
+ "\nAvailable: #{list_definitions.join(", ")}"
43
+ end
44
+
45
+ encoded = URI::DEFAULT_PARSER.escape(name)
46
+ ref_schema = schemer.ref("#/definitions/#{encoded}")
47
+ build_definition_class(ref_schema, name, definitions[name])
48
+ end
49
+ end
50
+
51
+ # All available definition titles, sorted.
52
+ #
53
+ # A2A::Schema.list_definitions
54
+ # #=> ["API Key Security Scheme", "Agent Capabilities", ...]
55
+ #
56
+ def list_definitions
57
+ raw_schema.fetch("definitions", {}).keys.sort
58
+ end
59
+
60
+ # The JSONSchemer instance for the full A2A schema bundle.
61
+ # Cached after first access.
62
+ def schemer
63
+ @schemer ||= JSONSchemer.schema(raw_schema)
64
+ end
65
+
66
+ # The parsed + ref-rewritten JSON schema hash.
67
+ def raw_schema
68
+ @raw_schema ||= load_and_rewrite_schema
69
+ end
70
+
71
+ # Reset all cached state (useful for tests).
72
+ def reset!
73
+ @definition_classes.clear
74
+ @schemer = nil
75
+ @raw_schema = nil
76
+ @ref_map = nil
77
+ end
78
+
79
+ private
80
+
81
+ # Load data/a2a.json, build the $ref rewrite map, and
82
+ # walk the entire tree replacing external refs with internal ones.
83
+ def load_and_rewrite_schema
84
+ schema = JSON.parse(File.read(DATA_PATH))
85
+ map = build_ref_map(schema)
86
+ rewrite_refs!(schema, map)
87
+ schema
88
+ end
89
+
90
+ # Build a map from external $ref strings to internal
91
+ # #/definitions/Title pointers.
92
+ def build_ref_map(schema)
93
+ return @ref_map if @ref_map
94
+
95
+ definitions = schema.fetch("definitions", {})
96
+
97
+ pascal_to_title = {}
98
+ definitions.each_key do |title|
99
+ pascal = title.gsub(/\s+/, "")
100
+ pascal_to_title[pascal] = title
101
+ end
102
+
103
+ refs = collect_refs(schema)
104
+
105
+ map = {}
106
+ refs.each do |ref_str|
107
+ type_name = ref_str
108
+ .sub(/\.jsonschema\.json\z/, "")
109
+ .split(".")
110
+ .last
111
+
112
+ if (title = pascal_to_title[type_name])
113
+ encoded = URI::DEFAULT_PARSER.escape(title)
114
+ map[ref_str] = "#/definitions/#{encoded}"
115
+ end
116
+ end
117
+
118
+ @ref_map = map
119
+ end
120
+
121
+ # Recursively collect all $ref string values from a JSON tree.
122
+ def collect_refs(obj, refs = Set.new)
123
+ case obj
124
+ when Hash
125
+ obj.each do |k, v|
126
+ if k == "$ref" && v.is_a?(String) && !v.start_with?("#")
127
+ refs << v
128
+ else
129
+ collect_refs(v, refs)
130
+ end
131
+ end
132
+ when Array
133
+ obj.each { |v| collect_refs(v, refs) }
134
+ end
135
+ refs
136
+ end
137
+
138
+ # Walk the schema tree and replace all external $ref values
139
+ # with their internal #/definitions/... equivalents.
140
+ def rewrite_refs!(obj, map)
141
+ case obj
142
+ when Hash
143
+ obj.each do |k, v|
144
+ if k == "$ref" && v.is_a?(String) && map.key?(v)
145
+ obj[k] = map[v]
146
+ else
147
+ rewrite_refs!(v, map)
148
+ end
149
+ end
150
+ when Array
151
+ obj.each { |v| rewrite_refs!(v, map) }
152
+ end
153
+ end
154
+
155
+ # Build a Definition subclass for a specific A2A type.
156
+ def build_definition_class(schema_instance, definition_name, raw_definition)
157
+ properties = raw_definition.fetch("properties", {})
158
+ camel_keys = properties.keys
159
+ snake_to_camel = build_snake_to_camel(camel_keys)
160
+
161
+ reader_pairs = camel_keys.map { |ck| [camel_to_snake(ck).to_sym, ck] }
162
+
163
+ Class.new(Definition) do
164
+ @schema = schema_instance
165
+ @definition_name = definition_name
166
+ @schema_properties = camel_keys
167
+ @snake_to_camel = snake_to_camel
168
+
169
+ class << self
170
+ def schema = @schema
171
+ def definition_name = @definition_name
172
+ def schema_properties = @schema_properties
173
+ def snake_to_camel_map = @snake_to_camel
174
+ end
175
+
176
+ reader_pairs.each do |snake_sym, camel_key|
177
+ define_method(snake_sym) { @data[camel_key] }
178
+ end
179
+ end
180
+ end
181
+
182
+ def build_snake_to_camel(camel_keys)
183
+ map = {}
184
+ camel_keys.each do |camel|
185
+ snake = camel_to_snake(camel)
186
+ map[snake] = camel
187
+ map[camel] = camel
188
+ end
189
+ map
190
+ end
191
+
192
+ def camel_to_snake(str)
193
+ str.gsub(/([A-Z])/) { "_#{$1.downcase}" }
194
+ .delete_prefix("_")
195
+ end
196
+ end
197
+ end
198
+ end
199
+
200
+ test do
201
+ schema = A2A::Schema
202
+
203
+ it "loads the raw schema" do
204
+ schema.raw_schema.should.be.kind_of(Hash)
205
+ schema.raw_schema["definitions"].should.be.kind_of(Hash)
206
+ end
207
+
208
+ it "has a schemer instance" do
209
+ schema.schemer.should.be.kind_of(JSONSchemer::Schema)
210
+ end
211
+
212
+ it "rewrites $ref values to internal pointers" do
213
+ defs = schema.raw_schema["definitions"]
214
+ external_refs = []
215
+ walk = ->(obj) do
216
+ case obj
217
+ when Hash
218
+ obj.each do |k, v|
219
+ if k == "$ref" && v.is_a?(String) && !v.start_with?("#")
220
+ external_refs << v
221
+ else
222
+ walk.(v)
223
+ end
224
+ end
225
+ when Array
226
+ obj.each { |v| walk.(v) }
227
+ end
228
+ end
229
+ walk.(defs)
230
+ external_refs.should == []
231
+ end
232
+
233
+ it "lists all definitions sorted" do
234
+ defs = schema.list_definitions
235
+ defs.should.be.kind_of(Array)
236
+ defs.should.include?("Agent Capabilities")
237
+ defs.should.include?("Agent Card")
238
+ defs.should.include?("Task")
239
+ defs.should.include?("Message")
240
+ defs.should == defs.sort
241
+ end
242
+
243
+ it "returns a Class that subclasses Definition" do
244
+ klass = schema["Agent Capabilities"]
245
+ klass.should.be.kind_of(Class)
246
+ (klass < A2A::Schema::Definition).should == true
247
+ end
248
+
249
+ it "caches definition classes" do
250
+ a = schema["Agent Capabilities"]
251
+ b = schema["Agent Capabilities"]
252
+ a.object_id.should == b.object_id
253
+ end
254
+
255
+ it "raises for unknown definitions" do
256
+ lambda { schema["ThisDoesNotExist999"] }.should.raise(RuntimeError)
257
+ end
258
+
259
+ it "has schema_properties listing camelCase keys" do
260
+ klass = schema["Agent Capabilities"]
261
+ klass.schema_properties.should.include?("extendedAgentCard")
262
+ klass.schema_properties.should.include?("streaming")
263
+ klass.schema_properties.should.include?("pushNotifications")
264
+ end
265
+
266
+ it "has a definition_name" do
267
+ schema["Agent Capabilities"].definition_name.should == "Agent Capabilities"
268
+ end
269
+
270
+ it "creates instances from snake_case keys" do
271
+ caps = schema["Agent Capabilities"].new(
272
+ streaming: true,
273
+ push_notifications: false,
274
+ extended_agent_card: true
275
+ )
276
+ caps.streaming.should == true
277
+ caps.push_notifications.should == false
278
+ caps.extended_agent_card.should == true
279
+ end
280
+
281
+ it "creates instances from camelCase keys" do
282
+ caps = schema["Agent Capabilities"].new(
283
+ "streaming" => true,
284
+ "pushNotifications" => false
285
+ )
286
+ caps.streaming.should == true
287
+ caps.push_notifications.should == false
288
+ end
289
+
290
+ it "creates instances from symbol camelCase keys" do
291
+ caps = schema["Agent Capabilities"].new(
292
+ streaming: true,
293
+ pushNotifications: false
294
+ )
295
+ caps.streaming.should == true
296
+ caps.push_notifications.should == false
297
+ end
298
+
299
+ it "ignores unknown properties" do
300
+ caps = schema["Agent Capabilities"].new(bogus: "ignored", streaming: true)
301
+ caps.streaming.should == true
302
+ caps.to_h.keys.should.not.include?("bogus")
303
+ end
304
+
305
+ it "returns camelCase string keys in to_h" do
306
+ caps = schema["Agent Capabilities"].new(streaming: true, push_notifications: false)
307
+ h = caps.to_h
308
+ h.should.be.kind_of(Hash)
309
+ h["streaming"].should == true
310
+ h["pushNotifications"].should == false
311
+ end
312
+
313
+ it "validates correct data" do
314
+ caps = schema["Agent Capabilities"].new(streaming: true)
315
+ caps.valid?.should == true
316
+ end
317
+
318
+ it "valid! returns true for correct data" do
319
+ caps = schema["Agent Capabilities"].new(streaming: true)
320
+ caps.valid!.should == true
321
+ end
322
+
323
+ it "detects type violations" do
324
+ caps = schema["Agent Capabilities"].new(streaming: "not_a_bool")
325
+ caps.valid?.should == false
326
+ end
327
+
328
+ it "valid! raises ValidationError for invalid data" do
329
+ caps = schema["Agent Capabilities"].new(streaming: "not_a_bool")
330
+ lambda { caps.valid! }.should.raise(A2A::Schema::ValidationError)
331
+ end
332
+
333
+ it "detects additionalProperties violations" do
334
+ caps = schema["Agent Capabilities"].new(streaming: true)
335
+ caps.valid?.should == true
336
+ end
337
+
338
+ it "auto-coerces nested Definition instances in constructor" do
339
+ caps = schema["Agent Capabilities"].new(streaming: true)
340
+ card = schema["Agent Card"].new(
341
+ name: "Test Agent",
342
+ version: "1.0.0",
343
+ capabilities: caps
344
+ )
345
+ card.name.should == "Test Agent"
346
+ card.version.should == "1.0.0"
347
+ h = card.to_h
348
+ h["capabilities"].should.be.kind_of(Hash)
349
+ h["capabilities"]["streaming"].should == true
350
+ end
351
+
352
+ it "validates Agent Card with nested capabilities" do
353
+ card = schema["Agent Card"].new(
354
+ name: "Test Agent",
355
+ version: "1.0.0",
356
+ capabilities: schema["Agent Capabilities"].new(streaming: true)
357
+ )
358
+ card.valid?.should == true
359
+ end
360
+
361
+ it "validates Agent Card with skills array" do
362
+ card = schema["Agent Card"].new(
363
+ name: "Test Agent",
364
+ version: "1.0.0",
365
+ skills: [
366
+ { "id" => "search", "name" => "Web Search", "description" => "Searches the web" }
367
+ ]
368
+ )
369
+ card.valid?.should == true
370
+ end
371
+
372
+ it "has a useful inspect" do
373
+ caps = schema["Agent Capabilities"].new(streaming: true)
374
+ caps.inspect.should.include?("Agent Capabilities")
375
+ caps.inspect.should.include?("streaming")
376
+ end
377
+
378
+ it "considers two definitions equal when data matches" do
379
+ a = schema["Agent Capabilities"].new(streaming: true)
380
+ b = schema["Agent Capabilities"].new(streaming: true)
381
+ (a == b).should == true
382
+ end
383
+
384
+ it "considers two definitions unequal when data differs" do
385
+ a = schema["Agent Capabilities"].new(streaming: true)
386
+ b = schema["Agent Capabilities"].new(streaming: false)
387
+ (a == b).should == false
388
+ end
389
+
390
+ it "validates Task with nested TaskStatus" do
391
+ task = schema["Task"].new(
392
+ id: "task-123",
393
+ context_id: "ctx-456",
394
+ status: {
395
+ "state" => "TASK_STATE_SUBMITTED",
396
+ "timestamp" => "2025-01-01T00:00:00Z"
397
+ }
398
+ )
399
+ task.valid?.should == true
400
+ task.id.should == "task-123"
401
+ task.context_id.should == "ctx-456"
402
+ end
403
+
404
+ it "validates a Message with parts" do
405
+ msg = schema["Message"].new(
406
+ role: "ROLE_USER",
407
+ message_id: "msg-1",
408
+ parts: [{ "text" => "Hello" }]
409
+ )
410
+ msg.valid?.should == true
411
+ msg.role.should == "ROLE_USER"
412
+ msg.message_id.should == "msg-1"
413
+ end
414
+
415
+ it "validates a Part" do
416
+ part = schema["Part"].new(text: "Hello world", media_type: "text/plain")
417
+ part.valid?.should == true
418
+ part.text.should == "Hello world"
419
+ part.media_type.should == "text/plain"
420
+ end
421
+
422
+ it "can instantiate every definition without error" do
423
+ schema.list_definitions.each do |name|
424
+ klass = schema[name]
425
+ instance = klass.new
426
+ instance.is_a?(A2A::Schema::Definition).should == true
427
+ end
428
+ end
429
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "a2a"
5
+
6
+ module A2A
7
+ module Server
8
+ class CancelTask
9
+ def call(env)
10
+ env["a2a.result"] = Schema["Task"].new({})
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "a2a"
5
+
6
+ module A2A
7
+ module Server
8
+ class CreateTaskPushNotificationConfig
9
+ def call(env)
10
+ env["a2a.result"] = Schema["Task Push Notification Config"].new({})
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "a2a"
5
+
6
+ module A2A
7
+ module Server
8
+ class DeleteTaskPushNotificationConfig
9
+ def call(env)
10
+ env["a2a.result"] = nil # google.protobuf.Empty
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "console"
5
+ require "a2a"
6
+
7
+ module A2A
8
+ class Server
9
+ # Routes incoming A2A operations to registered handler objects.
10
+ #
11
+ # Each handler declares the operations it handles via `#operations`.
12
+ # When an operation arrives, the dispatcher finds all matching handlers
13
+ # and calls them. Errors in one handler do not prevent others from running.
14
+ #
15
+ # The Dispatcher is a Rack app (terminal, not middleware). It reads
16
+ # env["a2a.operation"] set by Triage and fans out to matching handlers.
17
+ #
18
+ class Dispatcher
19
+ def initialize
20
+ @handlers = Hash.new { |h, k| h[k] = [] }
21
+ end
22
+
23
+ # Register a handler object.
24
+ #
25
+ # The handler must respond to:
26
+ # #operations -> Array<String> (e.g. ["SendMessage", "GetTask"])
27
+ # #call(env) -> void (sets env["a2a.result"])
28
+ #
29
+ def register(handler)
30
+ handler.operations.each do |op|
31
+ @handlers[op] << handler
32
+ Console.info(self) { "Registered #{handler.class.name} for #{op}" }
33
+ end
34
+ end
35
+
36
+ def call(env)
37
+ operation = env["a2a.operation"]
38
+
39
+ if operation
40
+ dispatch(operation, env)
41
+ end
42
+
43
+ [200, {}, []]
44
+ end
45
+
46
+ def handler_count
47
+ @handlers.values.flatten.size
48
+ end
49
+
50
+ private
51
+
52
+ def dispatch(operation, env)
53
+ handlers = @handlers[operation]
54
+
55
+ if handlers.empty?
56
+ Console.debug(self) { "No handler for operation: #{operation}" }
57
+ else
58
+ handlers.each do |handler|
59
+ begin
60
+ handler.call(env)
61
+ rescue => e
62
+ Console.error(self) { "Handler #{handler.class.name} raised #{e.class}: #{e.message}" }
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ test do
72
+ describe "A2A::Server::Dispatcher" do
73
+ it "registers and dispatches to handlers" do
74
+ received = []
75
+ handler = Object.new
76
+ handler.define_singleton_method(:operations) { ["SendMessage"] }
77
+ handler.define_singleton_method(:call) { |env| received << env }
78
+
79
+ dispatcher = A2A::Server::Dispatcher.new
80
+ dispatcher.register(handler)
81
+ dispatcher.handler_count.should == 1
82
+
83
+ env = { "a2a.operation" => "SendMessage" }
84
+ dispatcher.call(env)
85
+ received.length.should == 1
86
+ end
87
+
88
+ it "ignores operations with no matching handler" do
89
+ dispatcher = A2A::Server::Dispatcher.new
90
+ env = { "a2a.operation" => "UnknownOp" }
91
+ lambda { dispatcher.call(env) }.should.not.raise
92
+ end
93
+
94
+ it "continues dispatching when a handler raises" do
95
+ results = []
96
+ bad_handler = Object.new
97
+ bad_handler.define_singleton_method(:operations) { ["SendMessage"] }
98
+ bad_handler.define_singleton_method(:call) { |_| raise "boom" }
99
+
100
+ good_handler = Object.new
101
+ good_handler.define_singleton_method(:operations) { ["SendMessage"] }
102
+ good_handler.define_singleton_method(:call) { |e| results << e }
103
+
104
+ dispatcher = A2A::Server::Dispatcher.new
105
+ dispatcher.register(bad_handler)
106
+ dispatcher.register(good_handler)
107
+
108
+ env = { "a2a.operation" => "SendMessage" }
109
+ dispatcher.call(env)
110
+ results.length.should == 1
111
+ end
112
+
113
+ it "dispatches to multiple operations from one handler" do
114
+ received = []
115
+ handler = Object.new
116
+ handler.define_singleton_method(:operations) { ["SendMessage", "GetTask"] }
117
+ handler.define_singleton_method(:call) { |env| received << env["a2a.operation"] }
118
+
119
+ dispatcher = A2A::Server::Dispatcher.new
120
+ dispatcher.register(handler)
121
+
122
+ dispatcher.call({ "a2a.operation" => "SendMessage" })
123
+ dispatcher.call({ "a2a.operation" => "GetTask" })
124
+ received.should == ["SendMessage", "GetTask"]
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "a2a"
5
+
6
+ module A2A
7
+ class Server
8
+ # Rack middleware that injects shared A2A context into the env.
9
+ #
10
+ # Sets env["a2a.store"] and env["a2a.agent_card"] so downstream
11
+ # middleware and handlers can access them without coupling to
12
+ # any particular configuration mechanism.
13
+ #
14
+ class Env
15
+ def initialize(app, agent_card: {}, store: TaskStore.new)
16
+ @app = app
17
+ @agent_card = agent_card
18
+ @store = store
19
+ end
20
+
21
+ def call(env)
22
+ env["a2a.store"] = @store
23
+ env["a2a.agent_card"] = @agent_card
24
+ @app.call(env)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "a2a"
5
+
6
+ module A2A
7
+ module Server
8
+ class GetExtendedAgentCard
9
+ def call(env)
10
+ card = env["a2a.agent_card"] || {}
11
+ env["a2a.result"] = Schema["Agent Card"].new(card)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "a2a"
5
+
6
+ module A2A
7
+ module Server
8
+ class GetTask
9
+ def call(env)
10
+ env["a2a.result"] = Schema["Task"].new({})
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "a2a"
5
+
6
+ module A2A
7
+ module Server
8
+ class GetTaskPushNotificationConfig
9
+ def call(env)
10
+ env["a2a.result"] = Schema["Task Push Notification Config"].new({})
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "a2a"
5
+
6
+ module A2A
7
+ module Server
8
+ class ListTaskPushNotificationConfigs
9
+ def call(env)
10
+ env["a2a.result"] = Schema["List Task Push Notification Configs Response"].new({})
11
+ end
12
+ end
13
+ end
14
+ end