a2a-rails 0.1.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/CHANGELOG.md +43 -0
- data/LICENSE +21 -0
- data/README.md +499 -0
- data/app/controllers/a2a/rails/agent_cards_controller.rb +12 -0
- data/app/controllers/a2a/rails/application_controller.rb +8 -0
- data/app/controllers/a2a/rails/requests_controller.rb +18 -0
- data/config/routes.rb +6 -0
- data/lib/a2a/rails/agent.rb +106 -0
- data/lib/a2a/rails/agent_card/builder.rb +95 -0
- data/lib/a2a/rails/agent_card/validator.rb +109 -0
- data/lib/a2a/rails/configuration.rb +96 -0
- data/lib/a2a/rails/dispatcher.rb +47 -0
- data/lib/a2a/rails/engine.rb +24 -0
- data/lib/a2a/rails/errors.rb +42 -0
- data/lib/a2a/rails/protocol/adapter.rb +13 -0
- data/lib/a2a/rails/protocol/agent2agent_adapter.rb +125 -0
- data/lib/a2a/rails/protocol/request_handler.rb +172 -0
- data/lib/a2a/rails/protocol/task_mapper.rb +106 -0
- data/lib/a2a/rails/runtime.rb +43 -0
- data/lib/a2a/rails/skill.rb +92 -0
- data/lib/a2a/rails/task/artifact_mapper.rb +38 -0
- data/lib/a2a/rails/task/lifecycle.rb +98 -0
- data/lib/a2a/rails/task/memory_store.rb +161 -0
- data/lib/a2a/rails/task/result_mapper.rb +32 -0
- data/lib/a2a/rails/task/store.rb +29 -0
- data/lib/a2a/rails/task.rb +16 -0
- data/lib/a2a/rails/version.rb +7 -0
- data/lib/a2a-rails.rb +36 -0
- data/lib/generators/a2a/rails/agent_generator.rb +20 -0
- data/lib/generators/a2a/rails/install_generator.rb +16 -0
- data/lib/generators/a2a/rails/templates/agent.rb.tt +7 -0
- data/lib/generators/a2a/rails/templates/initializer.rb.tt +4 -0
- metadata +192 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 9b32fb9c3818579632e24051395d8f6e7820cde362a7068d861d0ee281b4a6c9
|
|
4
|
+
data.tar.gz: 1bbe7422de7f70a8e6c01e50f15b7d07a7232682fbac9c81276c8bd69867a6cf
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: a3c1f685fa38fb4b44f8329d7c0fea22a3ce3c5503e3904b4632e2cb933df2a904091021c530bcc78e24ddc015f392bf73dcfb94a4deded9fdb6343c18a353c4
|
|
7
|
+
data.tar.gz: 163d991b30b75f3096270fffe6f74e9fb5ba5744df8897aea595c55ccf516e278ef159385c1ea79f244a646350eb67ec0e05c4498d66e51ea42f1d9a61790747
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-10-06
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Rails-native A2A v1.0 server integration backed by `agent2agent ~> 2.0.0`.
|
|
12
|
+
- `A2A::Rails::Agent` and Skill DSL with application-owned Handler dispatch.
|
|
13
|
+
- Single-Skill automatic dispatch and multi-Skill Router support.
|
|
14
|
+
- Agent Card generation at `GET /.well-known/agent-card.json`.
|
|
15
|
+
- A2A JSON-RPC endpoint at `POST /a2a`.
|
|
16
|
+
- Synchronous Task lifecycle with `SUBMITTED`, `WORKING`, `COMPLETED`, `FAILED`, `REJECTED`, and `CANCELED` states.
|
|
17
|
+
- String, Hash, Array, and nil Handler-result mapping to A2A Artifacts.
|
|
18
|
+
- Thread-safe process-local in-memory Task Store.
|
|
19
|
+
- `SendMessage`, `GetTask`, `ListTasks`, and `CancelTask` support.
|
|
20
|
+
- `ListTasks` filtering, stable newest-first ordering, and opaque snapshot pagination.
|
|
21
|
+
- Lazy Rails configuration and Agent resolution.
|
|
22
|
+
- Automatically mounted Rails Engine and thin API controllers.
|
|
23
|
+
- Rails-facing logging boundary that suppresses the upstream SDK Rack-environment INFO log.
|
|
24
|
+
- `a2a:rails:install` and `a2a:rails:agent NAME` generators.
|
|
25
|
+
- Generator-backed Echo Quick Start verified through a real packaged `.gem` installed into a clean Rails application.
|
|
26
|
+
- CI coverage for Ruby 3.3, 3.4, and 4.0 with Rails 8.0 and 8.1.
|
|
27
|
+
|
|
28
|
+
### Compatibility
|
|
29
|
+
|
|
30
|
+
- Ruby `>= 3.3`.
|
|
31
|
+
- Rails `>= 8.0, < 8.2`.
|
|
32
|
+
- A2A protocol version `1.0`.
|
|
33
|
+
- `agent2agent ~> 2.0.0`.
|
|
34
|
+
|
|
35
|
+
### Known limitations
|
|
36
|
+
|
|
37
|
+
- Server-only; no A2A client.
|
|
38
|
+
- Non-streaming synchronous execution only.
|
|
39
|
+
- No Push Notifications, gRPC, ActiveJob execution, or durable Task Store.
|
|
40
|
+
- Default Task Store is process-local and is not shared across processes or preserved across restarts.
|
|
41
|
+
- Handler cancellation does not interrupt already-running application code or undo business side effects.
|
|
42
|
+
- `INPUT_REQUIRED` and `AUTH_REQUIRED` flows are not implemented.
|
|
43
|
+
- Continuing an existing Task via `message.taskId` is not supported in v0.1.
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 changquan.cui
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
# a2a-rails
|
|
2
|
+
|
|
3
|
+
Rails-native integration for exposing Rails applications as A2A agents.
|
|
4
|
+
|
|
5
|
+
> **Status: the v0.1.0 release candidate is prepared and CI-verified; the actual public release is next.**
|
|
6
|
+
|
|
7
|
+
## Current Status
|
|
8
|
+
|
|
9
|
+
The A2A v1.0 SDK integration path, Gem core, Protocol Adapter, Agent / Skill DSL, Task lifecycle, Configuration, Agent Card generation, Rails Engine HTTP endpoints, generators, source-tree Quick Start, packaged-gem installation path, and v0.1.0 release-candidate metadata are now verified.
|
|
10
|
+
|
|
11
|
+
**Current stage:** Step 15-13 completed — v0.1.0 release-candidate preparation
|
|
12
|
+
|
|
13
|
+
**Next step:** **Step 15-14 — Execute the v0.1.0 release: final artifact verification from the exact main commit, public-release readiness, `v0.1.0` tag, RubyGems publication, GitHub Release, and post-release smoke verification.**
|
|
14
|
+
|
|
15
|
+
Step 15-13 adds `CHANGELOG.md`, canonical v0.1.0 release notes, a pre-release / publish / post-release checklist, and final RubyGems metadata for source, changelog, documentation, issue tracker, and MFA. The packaged-gem smoke now verifies those metadata fields plus README, CHANGELOG, LICENSE, Ruby compatibility, generator discovery, clean-app installation, Agent Card retrieval, and Echo `SendMessage`. The release-candidate CI is **13 / 13 green**, while the Gem suite remains **70 tests / 240 assertions / 0 failures / 0 errors / 0 skips**. See [Draft PR #7](https://github.com/cuichangquan/a2a-rails/pull/7).
|
|
16
|
+
|
|
17
|
+
Step 15-12 verified the actual built gem in a clean Rails application. Step 15-11 added the intentionally small `install` / `agent` generators and the generator-backed source-tree Quick Start. Step 15-10 implemented the automatically mounted Rails Engine, thin API controllers, a process-local Runtime that shares the in-memory Task Store across HTTP requests, and the Rails-facing SDK logging boundary. Step 15-9 implemented lazy Configuration and Agent Card generation. Step 15-8 wired `SendMessage`, `GetTask`, `ListTasks`, and `CancelTask` through the real SDK. Step 15-7 implemented the SDK-independent Task core. Step 15-6 implemented the Rails-facing Agent / Skill / Dispatcher API. Step 15-5 introduced the loadable Gem skeleton and Protocol Adapter. Step 15-4 verified the `agent2agent 2.0.0` SDK path across the supported Ruby / Rails matrix.
|
|
18
|
+
|
|
19
|
+
## Development Progress
|
|
20
|
+
|
|
21
|
+
- [x] 1. Research A2A Protocol v1.0
|
|
22
|
+
- [x] 2. Research Ruby A2A SDKs / Gems
|
|
23
|
+
- [x] 3. Research Rails-oriented A2A alternatives
|
|
24
|
+
- [x] 4. Define the problem a2a-rails solves
|
|
25
|
+
- [x] 5. Define v0.1 scope
|
|
26
|
+
- [x] 6. Define terminology
|
|
27
|
+
- [x] 7. Define architecture
|
|
28
|
+
- [x] 8. Define Ruby SDK boundary
|
|
29
|
+
- [x] 9. Public API Design
|
|
30
|
+
- [x] 10. Agent Card Design
|
|
31
|
+
- [x] 11. Task Lifecycle Design
|
|
32
|
+
- [x] 12. Test Strategy
|
|
33
|
+
- [x] 13. Gem Structure
|
|
34
|
+
- [x] 14. Quick Start Design
|
|
35
|
+
- [ ] **15. Implementation / release preparation ← IN PROGRESS**
|
|
36
|
+
- [x] 15-4 SDK compatibility spike
|
|
37
|
+
- [x] 15-5 Gem skeleton + Protocol Adapter
|
|
38
|
+
- [x] 15-6 Agent / Skill DSL + Dispatcher
|
|
39
|
+
- [x] 15-7 Task core + MemoryStore
|
|
40
|
+
- [x] 15-8 Task operations through real SDK
|
|
41
|
+
- [x] 15-9 Configuration + Agent Card
|
|
42
|
+
- [x] 15-10 Rails Engine HTTP integration
|
|
43
|
+
- [x] 15-11 Generators + generated Quick Start
|
|
44
|
+
- [x] 15-12 Packaged-gem / release-readiness verification
|
|
45
|
+
- [x] 15-13 v0.1.0 release-candidate preparation
|
|
46
|
+
- [ ] 15-14 v0.1.0 release execution
|
|
47
|
+
|
|
48
|
+
## v0.1 Direction
|
|
49
|
+
|
|
50
|
+
v0.1 is **server-first** and focuses on exposing a Rails application as an A2A Agent.
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
A2A Protocol
|
|
54
|
+
↓
|
|
55
|
+
Ruby A2A SDK
|
|
56
|
+
↓
|
|
57
|
+
a2a-rails
|
|
58
|
+
↓
|
|
59
|
+
Rails Application
|
|
60
|
+
↓
|
|
61
|
+
Business Logic
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Main principles:
|
|
65
|
+
|
|
66
|
+
- Do not reimplement the A2A Protocol.
|
|
67
|
+
- Focus on Rails integration.
|
|
68
|
+
- Keep SDK-specific APIs out of the public API.
|
|
69
|
+
- Prefer a small, non-streaming server scope for v0.1.
|
|
70
|
+
- Keep a2a-rails independent from ActingFor.
|
|
71
|
+
|
|
72
|
+
## Quick Start
|
|
73
|
+
|
|
74
|
+
> The flow below is runtime-verified both from the repository source tree and from the built `a2a-rails-0.1.0` gem installed into a clean Rails application.
|
|
75
|
+
|
|
76
|
+
### 1. Add and install
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
bundle add a2a-rails
|
|
80
|
+
bin/rails generate a2a:rails:install
|
|
81
|
+
bin/rails generate a2a:rails:agent echo
|
|
82
|
+
mkdir -p app/services/echo
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`install` creates only:
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
config/initializers/a2a_rails.rb
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
with:
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
A2A::Rails.configure do |config|
|
|
95
|
+
config.agent = "YourAgent"
|
|
96
|
+
config.public_base_url = ENV["A2A_PUBLIC_BASE_URL"]
|
|
97
|
+
end
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`agent echo` creates only:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
app/agents/echo_agent.rb
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
with:
|
|
107
|
+
|
|
108
|
+
```ruby
|
|
109
|
+
class EchoAgent < A2A::Rails::Agent
|
|
110
|
+
name "Echo Agent"
|
|
111
|
+
description "TODO"
|
|
112
|
+
version "1.0"
|
|
113
|
+
|
|
114
|
+
# Add at least one skill.
|
|
115
|
+
end
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The generator deliberately does **not** create a Handler, route, controller, Task Store, job, migration, or registration side effect. It also does not reference a Handler that does not exist yet.
|
|
119
|
+
|
|
120
|
+
### 2. Create the Handler
|
|
121
|
+
|
|
122
|
+
Create `app/services/echo/reply.rb`:
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
class Echo::Reply
|
|
126
|
+
def self.call(message:, context:)
|
|
127
|
+
text = message[:parts]
|
|
128
|
+
.filter_map { |part| part[:text] }
|
|
129
|
+
.join("\n")
|
|
130
|
+
|
|
131
|
+
"Echo: #{text}"
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 3. Define the Skill
|
|
137
|
+
|
|
138
|
+
Replace `app/agents/echo_agent.rb` with:
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
class EchoAgent < A2A::Rails::Agent
|
|
142
|
+
name "Echo Agent"
|
|
143
|
+
description "Echo messages"
|
|
144
|
+
version "1.0"
|
|
145
|
+
|
|
146
|
+
skill :reply,
|
|
147
|
+
description: "Echo a message",
|
|
148
|
+
tags: %w[echo],
|
|
149
|
+
handler: Echo::Reply
|
|
150
|
+
end
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
A single Skill is selected automatically. No Router is required.
|
|
154
|
+
|
|
155
|
+
### 4. Register the Agent
|
|
156
|
+
|
|
157
|
+
Replace `config/initializers/a2a_rails.rb` with:
|
|
158
|
+
|
|
159
|
+
```ruby
|
|
160
|
+
A2A::Rails.configure do |config|
|
|
161
|
+
config.agent = "EchoAgent"
|
|
162
|
+
config.public_base_url = ENV["A2A_PUBLIC_BASE_URL"]
|
|
163
|
+
end
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
For localhost, leave `A2A_PUBLIC_BASE_URL` unset or set it to `http://localhost:3000`. The Agent class name remains a String until an A2A endpoint resolves it, preserving Rails autoload / reload behavior.
|
|
167
|
+
|
|
168
|
+
No explicit Engine mount or host `config/routes.rb` change is required.
|
|
169
|
+
|
|
170
|
+
### 5. Check the Agent Card
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
bin/rails server
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
curl -sS http://localhost:3000/.well-known/agent-card.json \
|
|
178
|
+
-H "A2A-Version: 1.0"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Expected essentials:
|
|
182
|
+
|
|
183
|
+
- HTTP 200
|
|
184
|
+
- Agent name `Echo Agent`
|
|
185
|
+
- Skill ID `reply`
|
|
186
|
+
- JSON-RPC A2A interface pointing to `http://localhost:3000/a2a`
|
|
187
|
+
|
|
188
|
+
### 6. Send the first message
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
curl -sS -X POST http://localhost:3000/a2a \
|
|
192
|
+
-H "Content-Type: application/json" \
|
|
193
|
+
-H "A2A-Version: 1.0" \
|
|
194
|
+
-d '{
|
|
195
|
+
"jsonrpc": "2.0",
|
|
196
|
+
"id": "1",
|
|
197
|
+
"method": "SendMessage",
|
|
198
|
+
"params": {
|
|
199
|
+
"message": {
|
|
200
|
+
"messageId": "msg-1",
|
|
201
|
+
"role": "ROLE_USER",
|
|
202
|
+
"parts": [{"text": "Hello"}]
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}'
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Success means:
|
|
209
|
+
|
|
210
|
+
```text
|
|
211
|
+
result.task.status.state == TASK_STATE_COMPLETED
|
|
212
|
+
Artifact Text Part == "Echo: Hello"
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
See [the complete Quick Start design and verification notes](docs/design/quick-start.md).
|
|
216
|
+
|
|
217
|
+
## Target Developer Experience
|
|
218
|
+
|
|
219
|
+
```ruby
|
|
220
|
+
class ShoppingAgent < A2A::Rails::Agent
|
|
221
|
+
name "Shopping Agent"
|
|
222
|
+
description "Search and purchase products"
|
|
223
|
+
version "1.0"
|
|
224
|
+
|
|
225
|
+
skill :search_products,
|
|
226
|
+
description: "Search products",
|
|
227
|
+
tags: %w[shopping search],
|
|
228
|
+
handler: Shopping::SearchProducts
|
|
229
|
+
end
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Handler:
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
class Shopping::SearchProducts
|
|
236
|
+
def self.call(message:, context:)
|
|
237
|
+
# Rails business logic
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Registration:
|
|
243
|
+
|
|
244
|
+
```ruby
|
|
245
|
+
A2A::Rails.configure do |config|
|
|
246
|
+
config.agent = "ShoppingAgent"
|
|
247
|
+
config.public_base_url = ENV["A2A_PUBLIC_BASE_URL"]
|
|
248
|
+
end
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
v0.1 targets **one public A2A Agent per Rails application**. Handlers receive SDK-independent Ruby Hashes for `message` and `context`.
|
|
252
|
+
|
|
253
|
+
For multiple Skills, the application supplies a Router. The Router receives `skills:` as a frozen `Array<Symbol>` of declared Skill IDs and may return a matching Symbol or String. Unknown selections raise `A2A::Rails::UnknownSkillError`; the Dispatcher never silently chooses the first Skill.
|
|
254
|
+
|
|
255
|
+
## Agent Card
|
|
256
|
+
|
|
257
|
+
The Gem automatically exposes:
|
|
258
|
+
|
|
259
|
+
```text
|
|
260
|
+
GET /.well-known/agent-card.json
|
|
261
|
+
POST /a2a
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Agent Card behavior:
|
|
265
|
+
|
|
266
|
+
- generated from the Agent / Skill DSL;
|
|
267
|
+
- Skill IDs and default display names are generated from Skill declarations;
|
|
268
|
+
- optional `examples`, `input_modes`, and `output_modes` map to A2A Agent Card fields;
|
|
269
|
+
- Handler internals are never exposed;
|
|
270
|
+
- `public_base_url` wins when configured, otherwise the request base URL is used;
|
|
271
|
+
- default input/output mode is `text/plain`;
|
|
272
|
+
- Streaming, Push Notifications, and Extended Agent Cards are disabled for v0.1;
|
|
273
|
+
- generated Cards pass the real `agent2agent 2.0.0` Agent Card schema.
|
|
274
|
+
|
|
275
|
+
## Task Lifecycle
|
|
276
|
+
|
|
277
|
+
Internally the Gem keeps SDK-independent Task states:
|
|
278
|
+
|
|
279
|
+
```text
|
|
280
|
+
SUBMITTED
|
|
281
|
+
↓
|
|
282
|
+
WORKING
|
|
283
|
+
├──→ COMPLETED
|
|
284
|
+
├──→ FAILED
|
|
285
|
+
└──→ REJECTED
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Cancellation can move a non-terminal Task to `CANCELED`.
|
|
289
|
+
|
|
290
|
+
Handler result mapping:
|
|
291
|
+
|
|
292
|
+
```text
|
|
293
|
+
normal return → COMPLETED
|
|
294
|
+
A2A::Rails::RejectedTask → REJECTED
|
|
295
|
+
unexpected exception → FAILED
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Artifact mapping:
|
|
299
|
+
|
|
300
|
+
```text
|
|
301
|
+
String → Text Part
|
|
302
|
+
Hash / Array → Data Part
|
|
303
|
+
nil → no Artifact
|
|
304
|
+
other object → ArtifactMappingError
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
v0.1 Task behavior:
|
|
308
|
+
|
|
309
|
+
- server-generated Task IDs;
|
|
310
|
+
- client Context ID preserved, otherwise server-generated;
|
|
311
|
+
- terminal states are immutable;
|
|
312
|
+
- thread-safe process-local `Task::MemoryStore` by default;
|
|
313
|
+
- `SendMessage`, `GetTask`, `ListTasks`, and `CancelTask` supported;
|
|
314
|
+
- `ListTasks` supports context/state/timestamp filters, stable newest-first ordering, page sizes 1–100, and opaque snapshot pagination;
|
|
315
|
+
- cancellation is atomic, but does not interrupt Handler execution or undo business side effects;
|
|
316
|
+
- v0.1 Handler execution accepts text Message Parts;
|
|
317
|
+
- continuing an existing Task via `message.taskId` is not supported;
|
|
318
|
+
- `INPUT_REQUIRED` and `AUTH_REQUIRED` are out of scope.
|
|
319
|
+
|
|
320
|
+
The default store is for development and simple synchronous workloads. Tasks and pagination cursors are process-local and are not durable across process restarts or shared between processes.
|
|
321
|
+
|
|
322
|
+
## Rails Integration
|
|
323
|
+
|
|
324
|
+
Step 15-10 provides:
|
|
325
|
+
|
|
326
|
+
- an automatically mounted Rails Engine;
|
|
327
|
+
- thin `ActionController::API` controllers;
|
|
328
|
+
- `/.well-known/agent-card.json` and `/a2a` routes;
|
|
329
|
+
- lazy application Agent resolution;
|
|
330
|
+
- one process-local Runtime that shares the default Task Store across HTTP requests;
|
|
331
|
+
- request-derived Agent Card URL fallback;
|
|
332
|
+
- a logging boundary that suppresses the upstream SDK `A2A::Server::Triage` INFO log containing the full Rack environment while restoring prior Console logging state afterward.
|
|
333
|
+
|
|
334
|
+
## Generators
|
|
335
|
+
|
|
336
|
+
Step 15-11 implements:
|
|
337
|
+
|
|
338
|
+
```text
|
|
339
|
+
a2a:rails:install
|
|
340
|
+
a2a:rails:agent NAME
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Verified contract:
|
|
344
|
+
|
|
345
|
+
- `install` creates only `config/initializers/a2a_rails.rb`;
|
|
346
|
+
- `agent echo` creates only `app/agents/echo_agent.rb`;
|
|
347
|
+
- the Agent scaffold has no dangling Handler reference;
|
|
348
|
+
- the generated Agent is not automatically registered;
|
|
349
|
+
- namespace-based generator invocation reproduces the documented files;
|
|
350
|
+
- the generated Echo setup boots under Rails and completes a real A2A `SendMessage` request.
|
|
351
|
+
|
|
352
|
+
Step 15-12 verifies the same generator contract from the **built and installed gem**, in a clean Rails application outside the repository source checkout.
|
|
353
|
+
|
|
354
|
+
## Packaged Gem Verification
|
|
355
|
+
|
|
356
|
+
Step 15-12 verifies the distribution artifact itself:
|
|
357
|
+
|
|
358
|
+
- `gem build a2a-rails.gemspec` produces `a2a-rails-0.1.0`;
|
|
359
|
+
- the package contains the Engine, generator classes, generator templates, and routes required at runtime;
|
|
360
|
+
- the clean app resolves `a2a-rails-0.1.0` from the installed RubyGems path, not from the repository checkout;
|
|
361
|
+
- actual `bin/rails generate` commands discover both generators;
|
|
362
|
+
- generated files match the documented scaffold contract;
|
|
363
|
+
- the clean app boots and serves the generated Agent Card;
|
|
364
|
+
- `SendMessage` completes with the Echo Artifact;
|
|
365
|
+
- Step 15-12 verified package SHA256: `09c55122c5d5e6cb5f9b735664d70b000f67d23dcaad9f4a8ff960dbe02dd410`.
|
|
366
|
+
|
|
367
|
+
Step 15-13 extends this verification to user-facing release files and RubyGems metadata. The final published artifact must still be rebuilt and hashed from the exact tagged release commit.
|
|
368
|
+
|
|
369
|
+
## Release Candidate
|
|
370
|
+
|
|
371
|
+
Step 15-13 prepares, but does not publish, v0.1.0:
|
|
372
|
+
|
|
373
|
+
- [CHANGELOG](CHANGELOG.md)
|
|
374
|
+
- [v0.1.0 release notes](docs/release/v0.1.0.md)
|
|
375
|
+
- [v0.1.0 release checklist](docs/release/v0.1.0-checklist.md)
|
|
376
|
+
|
|
377
|
+
The gemspec publishes canonical links for source code, changelog, documentation, and issue tracking, and requires RubyGems MFA. `README.md`, `CHANGELOG.md`, and `LICENSE` are verified as package contents.
|
|
378
|
+
|
|
379
|
+
No `v0.1.0` tag, RubyGems publication, GitHub Release, or repository-visibility change is performed in Step 15-13.
|
|
380
|
+
|
|
381
|
+
## Test Strategy
|
|
382
|
+
|
|
383
|
+
v0.1 uses **Minitest** with four layers:
|
|
384
|
+
|
|
385
|
+
```text
|
|
386
|
+
4. Protocol E2E / Smoke Tests
|
|
387
|
+
3. Rails Integration Tests
|
|
388
|
+
2. Adapter Contract Tests
|
|
389
|
+
1. Core Unit Tests
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
The current CI matrix covers:
|
|
393
|
+
|
|
394
|
+
- Gem: Ruby 3.3 / 3.4 / 4.0
|
|
395
|
+
- SDK spike: Ruby 3.3 / 3.4 / 4.0
|
|
396
|
+
- Rails: Ruby 3.3 / 3.4 / 4.0 × Rails 8.0 / 8.1
|
|
397
|
+
- Packaged gem: Ruby 3.4 + clean Rails 8.1 application
|
|
398
|
+
|
|
399
|
+
Current Step 15-13 result:
|
|
400
|
+
|
|
401
|
+
```text
|
|
402
|
+
13 / 13 CI jobs green
|
|
403
|
+
70 tests
|
|
404
|
+
240 assertions
|
|
405
|
+
0 failures
|
|
406
|
+
0 errors
|
|
407
|
+
0 skips
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Known warning-enabled output from upstream `agent2agent 2.0.0` remains, including circular-require / indentation / URI-parser warnings. Those warnings are distinct from the Rack-environment INFO logging that a2a-rails suppresses at the Rails-facing adapter boundary.
|
|
411
|
+
|
|
412
|
+
## Gem Structure
|
|
413
|
+
|
|
414
|
+
```text
|
|
415
|
+
lib/a2a/rails/
|
|
416
|
+
├── agent.rb
|
|
417
|
+
├── skill.rb
|
|
418
|
+
├── dispatcher.rb
|
|
419
|
+
├── configuration.rb
|
|
420
|
+
├── runtime.rb
|
|
421
|
+
├── engine.rb
|
|
422
|
+
├── agent_card/
|
|
423
|
+
├── task/
|
|
424
|
+
└── protocol/
|
|
425
|
+
|
|
426
|
+
lib/generators/a2a/rails/
|
|
427
|
+
├── install_generator.rb
|
|
428
|
+
├── agent_generator.rb
|
|
429
|
+
└── templates/
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
Key boundaries:
|
|
433
|
+
|
|
434
|
+
- Rails Engine / controllers / routes are only the Rails integration layer.
|
|
435
|
+
- SDK-specific behavior stays behind `Protocol::Adapter` / `Protocol::Agent2AgentAdapter`.
|
|
436
|
+
- A2A camelCase fields, `TASK_STATE_*`, SDK schema objects, and SDK errors stay in the Protocol layer.
|
|
437
|
+
- Agent / Handler application constants remain lazily resolved through Rails.
|
|
438
|
+
- ActiveRecord and ActiveJob are not runtime requirements.
|
|
439
|
+
- v0.1 targets Ruby `>= 3.3` and Rails `>= 8.0, < 8.2`.
|
|
440
|
+
|
|
441
|
+
Current main dependencies:
|
|
442
|
+
|
|
443
|
+
- `agent2agent ~> 2.0.0`
|
|
444
|
+
- `actionpack >= 8.0, < 8.2`
|
|
445
|
+
- `json < 3`
|
|
446
|
+
- `rack >= 3.0, < 4`
|
|
447
|
+
- `railties >= 8.0, < 8.2`
|
|
448
|
+
|
|
449
|
+
## v0.1 Scope
|
|
450
|
+
|
|
451
|
+
Included:
|
|
452
|
+
|
|
453
|
+
- Rails integration
|
|
454
|
+
- `A2A::Rails::Agent`
|
|
455
|
+
- Skill DSL and Handler dispatch
|
|
456
|
+
- Agent Card generation
|
|
457
|
+
- `/.well-known/agent-card.json`
|
|
458
|
+
- `POST /a2a`
|
|
459
|
+
- Task lifecycle
|
|
460
|
+
- `GetTask`, `ListTasks`, `CancelTask`
|
|
461
|
+
- `A2A-Version: 1.0` validation
|
|
462
|
+
- in-memory Task Store
|
|
463
|
+
- Rails Engine / Routes
|
|
464
|
+
- Configuration
|
|
465
|
+
- `install` / `agent` generators
|
|
466
|
+
- Rails logging boundary
|
|
467
|
+
- test support
|
|
468
|
+
|
|
469
|
+
Not included in v0.1:
|
|
470
|
+
|
|
471
|
+
- A2A Client
|
|
472
|
+
- ActiveRecord Task Store
|
|
473
|
+
- ActiveJob Task execution
|
|
474
|
+
- SSE / BiDi Streaming
|
|
475
|
+
- Push Notifications
|
|
476
|
+
- gRPC
|
|
477
|
+
- Human-in-the-loop
|
|
478
|
+
- `INPUT_REQUIRED` / `AUTH_REQUIRED` flows
|
|
479
|
+
- Agent Registry / Marketplace
|
|
480
|
+
- OAuth Server
|
|
481
|
+
- Authorization Engine
|
|
482
|
+
- ActingFor integration
|
|
483
|
+
- Admin UI
|
|
484
|
+
- LLM Agent Framework
|
|
485
|
+
- Orchestration Framework
|
|
486
|
+
|
|
487
|
+
## Design Documents
|
|
488
|
+
|
|
489
|
+
- [v0.1 Design Decisions](docs/design/v0.1-decisions.md)
|
|
490
|
+
- [v0.1 Test Strategy](docs/design/test-strategy.md)
|
|
491
|
+
- [v0.1 Gem Structure](docs/design/gem-structure.md)
|
|
492
|
+
- [v0.1 Quick Start Design](docs/design/quick-start.md)
|
|
493
|
+
- [Step 15 SDK compatibility findings](docs/design/sdk-compatibility-spike.md)
|
|
494
|
+
|
|
495
|
+
## Release Documents
|
|
496
|
+
|
|
497
|
+
- [CHANGELOG](CHANGELOG.md)
|
|
498
|
+
- [v0.1.0 Release Notes](docs/release/v0.1.0.md)
|
|
499
|
+
- [v0.1.0 Release Checklist](docs/release/v0.1.0-checklist.md)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module A2A
|
|
4
|
+
module Rails
|
|
5
|
+
class AgentCardsController < ApplicationController
|
|
6
|
+
def show
|
|
7
|
+
response.set_header("A2A-Version", Protocol::Agent2AgentAdapter::PROTOCOL_VERSION)
|
|
8
|
+
render json: A2A::Rails.runtime.agent_card(request_base_url: request.base_url)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module A2A
|
|
4
|
+
module Rails
|
|
5
|
+
class RequestsController < ApplicationController
|
|
6
|
+
def create
|
|
7
|
+
status, headers, body = A2A::Rails.runtime.call(
|
|
8
|
+
env: request.env,
|
|
9
|
+
request_base_url: request.base_url
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
self.status = status
|
|
13
|
+
headers.each { |name, value| response.set_header(name, value) }
|
|
14
|
+
self.response_body = body
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|