robot_lab 0.3.0 → 0.3.1

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 (256) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/README.md +1 -1
  4. data/lib/robot_lab/mcp/transports/streamable_http.rb +1 -1
  5. data/lib/robot_lab/version.rb +1 -1
  6. metadata +3 -253
  7. data/.architecture/AGENTS.md +0 -32
  8. data/.architecture/config.yml +0 -8
  9. data/.architecture/members.yml +0 -60
  10. data/.architecture/reviews/feature-free-will.md +0 -490
  11. data/.architecture/reviews/overall-codebase.md +0 -427
  12. data/.claude/settings.local.json +0 -57
  13. data/.codex/config.toml +0 -2
  14. data/.envrc +0 -6
  15. data/.github/workflows/deploy-github-pages.yml +0 -52
  16. data/.irbrc +0 -6
  17. data/.loki +0 -65
  18. data/.quality/reek_baseline.txt +0 -43
  19. data/.rubocop.yml +0 -10
  20. data/Archspec.rb +0 -44
  21. data/CLAUDE.md +0 -141
  22. data/COMMITS.md +0 -196
  23. data/Rakefile +0 -193
  24. data/_typos.toml +0 -21
  25. data/agent2agent_review.md +0 -192
  26. data/agentf_improvements.md +0 -253
  27. data/agents.md +0 -14
  28. data/docs/api/core/index.md +0 -147
  29. data/docs/api/core/memory.md +0 -578
  30. data/docs/api/core/network.md +0 -553
  31. data/docs/api/core/result.md +0 -211
  32. data/docs/api/core/robot.md +0 -1667
  33. data/docs/api/core/state.md +0 -145
  34. data/docs/api/core/tool.md +0 -520
  35. data/docs/api/errors.md +0 -323
  36. data/docs/api/hooks.md +0 -469
  37. data/docs/api/index.md +0 -137
  38. data/docs/api/mcp/client.md +0 -387
  39. data/docs/api/mcp/index.md +0 -267
  40. data/docs/api/mcp/server.md +0 -252
  41. data/docs/api/mcp/transports.md +0 -339
  42. data/docs/api/messages/index.md +0 -126
  43. data/docs/api/messages/text-message.md +0 -170
  44. data/docs/api/messages/tool-call-message.md +0 -206
  45. data/docs/api/messages/tool-result-message.md +0 -242
  46. data/docs/api/messages/user-message.md +0 -232
  47. data/docs/api/skills.md +0 -423
  48. data/docs/api/streaming/context.md +0 -280
  49. data/docs/api/streaming/events.md +0 -185
  50. data/docs/api/streaming/index.md +0 -156
  51. data/docs/api/support.md +0 -846
  52. data/docs/architecture/core-concepts.md +0 -575
  53. data/docs/architecture/index.md +0 -252
  54. data/docs/architecture/message-flow.md +0 -366
  55. data/docs/architecture/network-orchestration.md +0 -478
  56. data/docs/architecture/robot-execution.md +0 -396
  57. data/docs/architecture/state-management.md +0 -410
  58. data/docs/assets/css/custom.css +0 -56
  59. data/docs/assets/images/robot_lab.jpg +0 -0
  60. data/docs/concepts.md +0 -641
  61. data/docs/examples/basic-chat.md +0 -258
  62. data/docs/examples/index.md +0 -425
  63. data/docs/examples/mcp-server.md +0 -403
  64. data/docs/examples/multi-robot-network.md +0 -476
  65. data/docs/examples/tool-usage.md +0 -468
  66. data/docs/getting-started/configuration.md +0 -645
  67. data/docs/getting-started/index.md +0 -56
  68. data/docs/getting-started/installation.md +0 -197
  69. data/docs/getting-started/quick-start.md +0 -293
  70. data/docs/guides/building-robots.md +0 -1187
  71. data/docs/guides/creating-networks.md +0 -736
  72. data/docs/guides/hooks.md +0 -1206
  73. data/docs/guides/index.md +0 -78
  74. data/docs/guides/knowledge.md +0 -219
  75. data/docs/guides/mcp-integration.md +0 -740
  76. data/docs/guides/memory.md +0 -458
  77. data/docs/guides/observability.md +0 -733
  78. data/docs/guides/streaming.md +0 -323
  79. data/docs/guides/using-tools.md +0 -780
  80. data/docs/index.md +0 -280
  81. data/docs/superpowers/plans/2026-05-06-agentskills.md +0 -1303
  82. data/docs/superpowers/specs/2026-05-06-agentskills-design.md +0 -247
  83. data/examples/.envrc +0 -3
  84. data/examples/01_simple_robot.rb +0 -31
  85. data/examples/02_tools.rb +0 -109
  86. data/examples/03_network.rb +0 -118
  87. data/examples/04_mcp.rb +0 -217
  88. data/examples/05_streaming.rb +0 -137
  89. data/examples/06_prompt_templates.rb +0 -325
  90. data/examples/07_network_memory.rb +0 -313
  91. data/examples/08_llm_config.rb +0 -162
  92. data/examples/09_chaining.rb +0 -251
  93. data/examples/10_memory.rb +0 -315
  94. data/examples/11_network_introspection.rb +0 -239
  95. data/examples/12_message_bus.rb +0 -67
  96. data/examples/13_spawn.rb +0 -85
  97. data/examples/14_rusty_circuit/.envrc +0 -1
  98. data/examples/14_rusty_circuit/.gitignore +0 -1
  99. data/examples/14_rusty_circuit/README.md +0 -1
  100. data/examples/14_rusty_circuit/comic.rb +0 -149
  101. data/examples/14_rusty_circuit/display.rb +0 -217
  102. data/examples/14_rusty_circuit/heckler.rb +0 -65
  103. data/examples/14_rusty_circuit/open_mic.rb +0 -132
  104. data/examples/14_rusty_circuit/prompts/open_mic_comic.md +0 -20
  105. data/examples/14_rusty_circuit/prompts/open_mic_heckler.md +0 -23
  106. data/examples/14_rusty_circuit/prompts/open_mic_scout.md +0 -20
  107. data/examples/14_rusty_circuit/scout.rb +0 -165
  108. data/examples/14_rusty_circuit/show.log +0 -234
  109. data/examples/15_memory_network_and_bus/.envrc +0 -1
  110. data/examples/15_memory_network_and_bus/README.md +0 -66
  111. data/examples/15_memory_network_and_bus/editor_in_chief.rb +0 -24
  112. data/examples/15_memory_network_and_bus/editorial_pipeline.rb +0 -213
  113. data/examples/15_memory_network_and_bus/linux_writer.rb +0 -80
  114. data/examples/15_memory_network_and_bus/os_editor.rb +0 -48
  115. data/examples/15_memory_network_and_bus/os_writer.rb +0 -49
  116. data/examples/15_memory_network_and_bus/output/combined_article.md +0 -11
  117. data/examples/15_memory_network_and_bus/output/final_article.md +0 -8
  118. data/examples/15_memory_network_and_bus/output/linux_draft.md +0 -7
  119. data/examples/15_memory_network_and_bus/output/mac_draft.md +0 -7
  120. data/examples/15_memory_network_and_bus/output/memory.json +0 -13
  121. data/examples/15_memory_network_and_bus/output/revision_1.md +0 -29
  122. data/examples/15_memory_network_and_bus/output/revision_2.md +0 -50
  123. data/examples/15_memory_network_and_bus/output/revision_3.md +0 -8
  124. data/examples/15_memory_network_and_bus/output/windows_draft.md +0 -7
  125. data/examples/15_memory_network_and_bus/prompts/os_advocate.md +0 -13
  126. data/examples/15_memory_network_and_bus/prompts/os_chief.md +0 -13
  127. data/examples/15_memory_network_and_bus/prompts/os_editor.md +0 -13
  128. data/examples/16_writers_room/.envrc +0 -1
  129. data/examples/16_writers_room/display.rb +0 -158
  130. data/examples/16_writers_room/output/.gitignore +0 -4
  131. data/examples/16_writers_room/output/README.md +0 -69
  132. data/examples/16_writers_room/output/opus_001.md +0 -263
  133. data/examples/16_writers_room/output/opus_001_notes.log +0 -470
  134. data/examples/16_writers_room/output/opus_002.md +0 -245
  135. data/examples/16_writers_room/output/opus_002_notes.log +0 -546
  136. data/examples/16_writers_room/output/opus_002_screenplay.md +0 -7989
  137. data/examples/16_writers_room/output/opus_002_screenplay_notes.md +0 -993
  138. data/examples/16_writers_room/prompts/screenplay_writer.md +0 -66
  139. data/examples/16_writers_room/prompts/writer.md +0 -37
  140. data/examples/16_writers_room/room.rb +0 -186
  141. data/examples/16_writers_room/tools.rb +0 -173
  142. data/examples/16_writers_room/writer.rb +0 -121
  143. data/examples/16_writers_room/writers_room.rb +0 -256
  144. data/examples/17_skills.rb +0 -234
  145. data/examples/18_rails/.envrc +0 -3
  146. data/examples/18_rails/.gitignore +0 -5
  147. data/examples/18_rails/Gemfile +0 -11
  148. data/examples/18_rails/README.md +0 -67
  149. data/examples/18_rails/Rakefile +0 -4
  150. data/examples/18_rails/app/controllers/application_controller.rb +0 -4
  151. data/examples/18_rails/app/controllers/chat_controller.rb +0 -50
  152. data/examples/18_rails/app/jobs/application_job.rb +0 -4
  153. data/examples/18_rails/app/jobs/robot_run_job.rb +0 -25
  154. data/examples/18_rails/app/models/application_record.rb +0 -5
  155. data/examples/18_rails/app/models/robot_lab_result.rb +0 -36
  156. data/examples/18_rails/app/models/robot_lab_thread.rb +0 -23
  157. data/examples/18_rails/app/robots/chat_robot.rb +0 -25
  158. data/examples/18_rails/app/tools/time_tool.rb +0 -9
  159. data/examples/18_rails/app/views/chat/_user_message.html.erb +0 -1
  160. data/examples/18_rails/app/views/chat/index.html.erb +0 -67
  161. data/examples/18_rails/app/views/layouts/application.html.erb +0 -49
  162. data/examples/18_rails/bin/dev +0 -7
  163. data/examples/18_rails/bin/rails +0 -6
  164. data/examples/18_rails/bin/setup +0 -15
  165. data/examples/18_rails/config/application.rb +0 -33
  166. data/examples/18_rails/config/cable.yml +0 -2
  167. data/examples/18_rails/config/database.yml +0 -5
  168. data/examples/18_rails/config/environment.rb +0 -4
  169. data/examples/18_rails/config/initializers/robot_lab.rb +0 -11
  170. data/examples/18_rails/config/routes.rb +0 -6
  171. data/examples/18_rails/config.ru +0 -4
  172. data/examples/18_rails/db/migrate/001_create_robot_lab_tables.rb +0 -32
  173. data/examples/19_token_tracking.rb +0 -138
  174. data/examples/20_circuit_breaker.rb +0 -147
  175. data/examples/21_learning_loop.rb +0 -181
  176. data/examples/22_context_compression.rb +0 -172
  177. data/examples/23_convergence.rb +0 -133
  178. data/examples/24_structured_delegation.rb +0 -151
  179. data/examples/25_history_search/conversation.jsonl +0 -30
  180. data/examples/25_history_search.rb +0 -133
  181. data/examples/26_document_store/api_versioning_adr.md +0 -52
  182. data/examples/26_document_store/incident_postmortem.md +0 -46
  183. data/examples/26_document_store/postgres_runbook.md +0 -49
  184. data/examples/26_document_store/redis_caching_guide.md +0 -48
  185. data/examples/26_document_store/sidekiq_guide.md +0 -51
  186. data/examples/26_document_store.rb +0 -140
  187. data/examples/27_incident_response/README.md +0 -65
  188. data/examples/27_incident_response/incident_response.rb +0 -261
  189. data/examples/28_mcp_discovery.rb +0 -113
  190. data/examples/29_ractor_tools.rb +0 -240
  191. data/examples/30_ractor_network.rb +0 -252
  192. data/examples/31_launch_assessment.rb +0 -246
  193. data/examples/32_newsletter_reader.rb +0 -193
  194. data/examples/33_stock_generator.rb +0 -80
  195. data/examples/33_stock_predictor.rb +0 -327
  196. data/examples/34_agentskills.rb +0 -76
  197. data/examples/35_hooks.rb +0 -266
  198. data/examples/README.md +0 -550
  199. data/examples/common.rb +0 -180
  200. data/examples/prompts/assistant.md +0 -5
  201. data/examples/prompts/audit_trail.md +0 -8
  202. data/examples/prompts/billing.md +0 -10
  203. data/examples/prompts/classifier.md +0 -7
  204. data/examples/prompts/comedian.md +0 -6
  205. data/examples/prompts/comedy_critic.md +0 -10
  206. data/examples/prompts/configurable.md +0 -9
  207. data/examples/prompts/dispatcher.md +0 -12
  208. data/examples/prompts/entity_extractor.md +0 -14
  209. data/examples/prompts/escalation.md +0 -42
  210. data/examples/prompts/frontmatter_mcp_test.md +0 -9
  211. data/examples/prompts/frontmatter_named_test.md +0 -5
  212. data/examples/prompts/frontmatter_tools_test.md +0 -6
  213. data/examples/prompts/general.md +0 -7
  214. data/examples/prompts/github_assistant.md +0 -14
  215. data/examples/prompts/helper.md +0 -4
  216. data/examples/prompts/incident_responder.md +0 -18
  217. data/examples/prompts/keyword_extractor.md +0 -11
  218. data/examples/prompts/llm_config_demo.md +0 -20
  219. data/examples/prompts/order_support.md +0 -35
  220. data/examples/prompts/os_advocate.md +0 -13
  221. data/examples/prompts/os_chief.md +0 -13
  222. data/examples/prompts/os_editor.md +0 -13
  223. data/examples/prompts/parameterized_main_test.md +0 -6
  224. data/examples/prompts/pii_redactor.md +0 -7
  225. data/examples/prompts/product_support.md +0 -37
  226. data/examples/prompts/runbook_protocol.md +0 -12
  227. data/examples/prompts/sentiment_analyzer.md +0 -12
  228. data/examples/prompts/skill_a_test.md +0 -4
  229. data/examples/prompts/skill_b_test.md +0 -4
  230. data/examples/prompts/skill_config_test.md +0 -5
  231. data/examples/prompts/skill_cycle_a_test.md +0 -6
  232. data/examples/prompts/skill_cycle_b_test.md +0 -6
  233. data/examples/prompts/skill_description_test.md +0 -4
  234. data/examples/prompts/skill_leaf_test.md +0 -4
  235. data/examples/prompts/skill_nested_test.md +0 -6
  236. data/examples/prompts/skill_refs_main_test.md +0 -6
  237. data/examples/prompts/skill_self_ref_test.md +0 -6
  238. data/examples/prompts/skill_with_mcp_test.md +0 -9
  239. data/examples/prompts/skill_with_params_test.md +0 -6
  240. data/examples/prompts/skill_with_robot_name_test.md +0 -5
  241. data/examples/prompts/skill_with_tools_test.md +0 -6
  242. data/examples/prompts/sre_compliance.md +0 -10
  243. data/examples/prompts/structured_output.md +0 -7
  244. data/examples/prompts/synthesizer.md +0 -17
  245. data/examples/prompts/technical.md +0 -10
  246. data/examples/prompts/template_with_skills_test.md +0 -6
  247. data/examples/prompts/triage.md +0 -22
  248. data/examples/ruboruby.md +0 -423
  249. data/examples/run_all.rb +0 -60
  250. data/examples/xyzzy.rb +0 -97
  251. data/logfile +0 -8
  252. data/mkdocs.yml +0 -209
  253. data/robot_concurrency.md +0 -38
  254. data/simple_acp_review.md +0 -298
  255. data/temp.md +0 -6
  256. data/tool_manifest_plan.md +0 -155
@@ -1,192 +0,0 @@
1
- # Review: `agent2agent` Ruby Gem
2
-
3
- **Source:** https://github.com/general-intelligence-systems/agent2agent
4
- **Docs:** https://general-intelligence-systems.github.io/agent2agent/
5
- **License:** Apache 2.0
6
- **Ruby:** >= 3.2
7
- **Reviewed:** 2026-05-05
8
-
9
- ---
10
-
11
- ## What It Is
12
-
13
- A complete Ruby implementation of Google's A2A (Agent-to-Agent) protocol — an open standard for interoperable, cross-vendor AI agent communication over HTTP. The gem provides both a server (Rack app) and a client, plus SSE streaming, task persistence, and push notifications.
14
-
15
- ---
16
-
17
- ## Wire Protocol
18
-
19
- Two parallel transport bindings, both implemented:
20
-
21
- | Transport | Path | Format |
22
- |---|---|---|
23
- | JSON-RPC 2.0 | `POST /a2a` | `{"jsonrpc":"2.0","method":"SendMessage","params":{...}}` |
24
- | HTTP+JSON/REST | `POST /message:send`, `GET /tasks/{id}`, etc. | Plain JSON |
25
- | Agent Discovery | `GET /.well-known/agent-card.json` | Capabilities manifest |
26
-
27
- ### The 11 Protocol Operations
28
-
29
- 1. `SendMessage` — POST `/message:send` (synchronous)
30
- 2. `SendStreamingMessage` — POST `/message:stream` (SSE, server-streaming)
31
- 3. `GetTask` — GET `/tasks/{id}`
32
- 4. `ListTasks` — GET `/tasks`
33
- 5. `CancelTask` — POST `/tasks/{id}:cancel`
34
- 6. `SubscribeToTask` — SSE stream of task updates
35
- 7. `CreateTaskPushNotificationConfig` — POST `/tasks/{id}/push`
36
- 8. `GetTaskPushNotificationConfig` — GET `/tasks/{id}/push/{config_id}`
37
- 9. `ListTaskPushNotificationConfigs` — GET `/tasks/{id}/push`
38
- 10. `DeleteTaskPushNotificationConfig` — DELETE `/tasks/{id}/push/{config_id}`
39
- 11. `GetExtendedAgentCard` — GET extended agent card
40
-
41
- ### Task State Machine
42
-
43
- `SUBMITTED → WORKING → INPUT_REQUIRED → COMPLETED / FAILED / CANCELED / REJECTED`
44
-
45
- ---
46
-
47
- ## Key Classes and Their Roles
48
-
49
- | Class | Role |
50
- |---|---|
51
- | `A2A::Agent` | DSL: `on("SendMessage") { \|req\| respond(...) }` — registers operation handlers |
52
- | `A2A::Server` | Rack app — mountable in any Rack stack or Rails router |
53
- | `A2A::Client` | Async-HTTP client; all 11 ops auto-generated as snake_case methods |
54
- | `A2A::Proto` | Parses the real `data/a2a.proto` file — single source of truth for operations |
55
- | `A2A::Schema` | Loads 47-type `data/a2a.json`; validates with `json_schemer`; camelCase/snake_case |
56
- | `A2A::TaskStore` | In-memory task CRUD with `Thread::Queue` pub/sub and webhook delivery |
57
- | `A2A::Store::SQLite` | Production drop-in: WAL mode, indexed, fiber-safe `Async::Queue` pub/sub |
58
- | `A2A::SSE::Stream` | Subclasses `Protocol::HTTP::Body::Writable`; Falcon passes it untouched |
59
- | `A2A::Bindings::JsonRpc` | Rack middleware that parses JSON-RPC envelopes and wraps responses |
60
-
61
- ### Agent DSL Example
62
-
63
- ```ruby
64
- agent = A2A::Agent.new do
65
- on "SendMessage", "SendStreamingMessage" do |context|
66
- task = context.store.create(context.request)
67
- stream = context.stream
68
-
69
- Async do
70
- result = robot.run(context.request.params[:message])
71
- context.store.complete(task.id, result)
72
- stream.event(result, type: "result")
73
- stream.finish
74
- end
75
-
76
- context.respond(task)
77
- end
78
- end
79
-
80
- server = A2A::Server.new
81
- server.register(agent)
82
- run server
83
- ```
84
-
85
- ### Client Example
86
-
87
- ```ruby
88
- Async do
89
- client = A2A::Client.new("http://localhost:9292")
90
- card = client.agent_card
91
- result = client.send_message(message: { role: "user", parts: [{ text: "Hello" }] })
92
- puts result
93
- end
94
- ```
95
-
96
- ---
97
-
98
- ## Notable Patterns
99
-
100
- - **Duck-typed stores:** Any object implementing the task store interface can be swapped in — `TaskStore` (in-memory) or `Store::SQLite` (production), or a custom implementation.
101
- - **Proto as source of truth:** `Proto` parses `data/a2a.proto` directly to extract operation metadata — stays in sync with the Google A2A spec automatically.
102
- - **Fiber-native:** The SQLite store's pub/sub uses `Async::Queue`; SSE bodies use `Protocol::HTTP::Body::Writable`. Fully fiber-safe when run under Falcon.
103
- - **`returnImmediately` flag:** Background jobs return a task ID immediately; updates stream via SSE as work proceeds.
104
- - **`STATE_INPUT_REQUIRED`:** Multi-turn conversations — agent transitions to this state when it needs more user input before continuing. Client sends another `SendMessage` referencing the same task context.
105
- - **Inline tests via `scampi`:** Tests live inside source files (`test do ... end`), not a separate test directory.
106
- - **Tenant-prefixed paths:** Every REST route has a variant: `/{tenant}/message:send` for multi-tenant deployments.
107
-
108
- ---
109
-
110
- ## Authentication
111
-
112
- - **AgentCard** declares supported auth schemes in the capabilities manifest
113
- - **Push notification configs** carry per-webhook auth: `scheme` + `credentials` sent as `Authorization: Bearer <credentials>` on webhook delivery; optionally also `X-A2A-Notification-Token`
114
- - Incoming request authentication is left to the application layer (standard Rack middleware pattern)
115
-
116
- ---
117
-
118
- ## Dependencies
119
-
120
- **Runtime:**
121
- - `async (~> 2.0)`, `async-http (~> 0.95)` — fiber concurrency and HTTP
122
- - `rack (~> 3.0)` — server composition (pure Rack, Rails-mountable)
123
- - `json_schemer (~> 2.5)` — schema validation against 47 A2A types
124
- - `google-protobuf (~> 4.34)` — proto file parsing
125
- - `sqlite3` — persistent task store
126
- - `protocol-http (~> 0.62)` — `Body::Writable` for SSE
127
- - `scampi` — inline test framework
128
- - `console` — structured logging
129
-
130
- **Development:**
131
- - `falcon (~> 0.55)` — async HTTP server for running agents
132
-
133
- ---
134
-
135
- ## Applicability to Your Projects
136
-
137
- ### RobotLab — High Value
138
-
139
- The most compelling integration: expose each `Robot` or `Network` as a standard A2A service. This enables cross-language orchestration (Python LangChain, JS Genkit, Go agents, Google Cloud agents) without any shared code.
140
-
141
- **Robot-as-A2A-Service:**
142
- - `A2A::Agent` adapter delegates `SendMessage` → `robot.run(request.message)`, result becomes the A2A task result
143
- - Publish an AgentCard at `/.well-known/agent-card.json` advertising each robot's capabilities and tools
144
- - Use `A2A::Store::SQLite` to persist tasks across requests (stateless HTTP tier in front of stateful robots)
145
-
146
- **Streaming:**
147
- - `SendStreamingMessage` + `SSE::Stream` maps directly onto RubyLLM's streaming callbacks
148
- - Streaming events become real-time SSE — no additional infrastructure needed
149
-
150
- **Cross-process robot networks:**
151
- - Instead of `TypedBus` (in-process pub/sub only), robots in separate processes or machines call each other via `A2A::Client`
152
- - A Network router can delegate to remote robots via `client.send_message(...)` — standard HTTP replaces shared-memory message passing
153
-
154
- **Background jobs:**
155
- - A2A's push notification config CRUD gives external systems a standard webhook protocol for task completion
156
- - Maps cleanly onto RobotLab's existing async robot semantics
157
-
158
- **Multi-turn conversations:**
159
- - `STATE_INPUT_REQUIRED` maps directly to RobotLab's `AskUser` tool pattern — robot needs user input before continuing
160
- - Web clients get a proper protocol for handling confirmation flows rather than a terminal prompt
161
-
162
- **Compatibility note:** Both RobotLab and `agent2agent` use the `async` gem — they compose cleanly. The main requirement is running under Falcon rather than a plain Ruby process. `TypedBus` (`Async::Queue`) and `A2A::Store::PubSub` (`Async::Queue`) are both fiber-based and compatible.
163
-
164
- ### AIA — Moderate Value
165
-
166
- - `A2A::Client` could delegate tasks to remote A2A-compliant agents (specialized coding agents, search agents, etc.) instead of calling LLM APIs directly
167
- - AIA could optionally expose itself as a local A2A server on `localhost:PORT` so IDE plugins or other tools can send it tasks via standard protocol
168
- - AgentCard discovery would let AIA auto-configure available capabilities when connecting to remote agents
169
-
170
- ### Rails Apps Generally
171
-
172
- `A2A::Server` is pure Rack:
173
-
174
- ```ruby
175
- # config/routes.rb
176
- mount A2A::Server.new(agent: my_agent), at: "/agents/myagent"
177
- ```
178
-
179
- This works as-is. The 47-type schema validation via `json_schemer` is also useful standalone for validating A2A protocol payloads.
180
-
181
- ---
182
-
183
- ## Bottom Line
184
-
185
- Production-quality gem for its scope. Clean architecture: Rack middleware chain, duck-typed stores, fiber-safe pub/sub, SSE via `protocol-http`. Inline test coverage is extensive.
186
-
187
- **Highest-value opportunity for RobotLab:** Robot-as-A2A-Service — exposing robots as standards-compliant HTTP endpoints enables cross-language agent orchestration that the current `TypedBus` approach (in-process only) cannot support. This would position RobotLab robots as first-class participants in the emerging A2A ecosystem alongside Python, JavaScript, and Go agent frameworks.
188
-
189
- **Specific algorithms/patterns worth porting:**
190
- 1. `A2A::Store::SQLite` pub/sub pattern (Async::Queue-based) — applicable to RobotLab's Memory system
191
- 2. AgentCard capability manifest — useful for RobotLab's planned tool/capability discovery
192
- 3. `STATE_INPUT_REQUIRED` state machine entry — formalizes the `AskUser` pattern with a standard protocol state
@@ -1,253 +0,0 @@
1
- # `agentf` Gem Analysis
2
-
3
- **Repository:** https://github.com/nealdeters/agentf
4
- **Author:** Neal Deters
5
- **Ruby:** 3.3.0+ | **Runtime deps:** `redis ~> 4.8`, `dotenv ~> 2.8`
6
-
7
- ---
8
-
9
- ## What It Is
10
-
11
- A Ruby multi-agent workflow engine for software development. Orchestrates
12
- role-specialized agents (Planner, Engineer, QA, Reviewer, Security) that share
13
- Redis memory — but **never calls an LLM itself**. It runs as an MCP server over
14
- stdio and lets the IDE's AI (Copilot, OpenCode) do the actual inference.
15
- It is scaffolding, not an API wrapper.
16
-
17
- Three surfaces:
18
- - **CLI** (`agentf <subcommand>`) — memory management, code exploration, metrics, evals
19
- - **MCP server** (`agentf mcp-server`) — 19 tools over stdio for IDE integrations
20
- - **Ruby API** — `WorkflowEngine`, `Agents::*`, `RedisMemory` for programmatic use
21
-
22
- ---
23
-
24
- ## Architecture
25
-
26
- | Layer | Files | Role |
27
- |---|---|---|
28
- | Entry point | `agentf.rb`, `bin/agentf` | Config singleton + CLI boot |
29
- | CLI | `cli/router.rb`, `cli/memory.rb`, `cli/code.rb` | Subcommand dispatch |
30
- | Agents | `agents/base.rb`, role subclasses | Role-based agent classes |
31
- | Workflow | `workflow_engine.rb` | Orchestrator / sequencer |
32
- | Memory | `memory.rb`, `memory/confirmation_handler.rb` | Redis-backed storage |
33
- | Contracts | `workflow_contract.rb`, `agent_execution_contract.rb` | Constraint enforcement |
34
- | Tools | `tools/`, `tools.rb` | Primitive capabilities |
35
- | Commands | `commands/registry.rb`, `commands/*.rb` | Named command registry |
36
- | MCP | `mcp/server.rb`, `mcp/stub.rb` | stdio MCP protocol server |
37
- | Service | `service/providers.rb` | Provider adapters |
38
- | Installer | `installer.rb` | Manifest generation and provider setup |
39
-
40
- ---
41
-
42
- ## Patterns Worth Stealing
43
-
44
- ### 1. Agents That Describe Themselves at the Class Level
45
-
46
- All agent metadata — `description`, `deliverables`, `policy_boundaries`,
47
- `when_to_use`, `commands` — are class methods, not instance state or external
48
- YAML. Agents are self-documenting, introspectable at install time, and
49
- verifiable without instantiating anything. The `Installer` reads these at
50
- install time to generate markdown manifests.
51
-
52
- ### 2. Three-Mode Contract Enforcement (advisory / enforcing / off)
53
-
54
- A contract object wraps agent execution with `before!`/`after!` validation.
55
- Run workflows in `advisory` mode during development (log violations, don't
56
- stop), flip to `enforcing` for production. TDD phase discipline (`"red"` vs
57
- `"green"`) is enforced at the contract layer, not by convention.
58
-
59
- ### 3. Human-in-the-Loop Memory Writes
60
-
61
- `ConfirmationHandler` wraps Redis writes so that when confirmation is needed,
62
- instead of raising it returns `{ confirmation: true, payload: ..., instructions: ... }`.
63
- The caller re-invokes with `confirmedWrite: "confirmed"`. Works identically
64
- across CLI, MCP, and programmatic callers.
65
-
66
- ### 4. Deterministic Local Embeddings With No ML Dependency
67
-
68
- `EmbeddingProvider` SHA256-hashes tokens, uses the hash to pick a dimension in
69
- a 64-element float vector, then normalizes it. Zero API calls, zero latency,
70
- fully reproducible. Crude but sufficient for semantic memory search in a
71
- dev-tool context.
72
-
73
- ### 5. Black-Box Shell Script Evals
74
-
75
- Each eval scenario is three files: `prompt.txt`, `scenario.yml`, and
76
- `verify.sh`. The shell script asserts postconditions against real Redis state.
77
- Simple, portable, no mocking — `agentf eval run all` just executes them.
78
-
79
- ### 6. Graceful Redis Capability Degradation
80
-
81
- The memory layer detects at runtime whether Redis Stack's JSON/Search/Vector
82
- modules are present and degrades silently. Full semantic search if available;
83
- plain key-value otherwise. No config flag needed — baked into `RedisMemory`.
84
-
85
- ### 7. Ruby Generating Its Own TypeScript Integration
86
-
87
- The installer generates TypeScript plugin files (`agentf-plugin.ts`,
88
- `tsconfig.json`, `package.json`) from within Ruby for OpenCode integration.
89
- A Ruby gem producing its own typed IDE plugin layer is unusual and practical.
90
-
91
- ### 8. Policies Stored in Code, Not Config
92
-
93
- `policy_boundaries` returns `{ "always" => [...], "ask_first" => [...], "never" => [...] }`
94
- directly from Ruby class methods. Changing a policy means changing Ruby, not
95
- YAML — no config drift.
96
-
97
- ### 9. Workflow Profiles as Constants
98
-
99
- Workflow compositions are defined as constants in `WorkflowEngine::PROFILES`
100
- (e.g., `rails_standard`, `rails_37signals`), mapping task types to ordered
101
- agent sequences. One canonical source of truth for workflow shapes.
102
-
103
- ---
104
-
105
- ## RobotLab Applicability Analysis
106
-
107
- ### Patterns That Don't Apply
108
-
109
- **Pattern 7 — Ruby Generating Its Own TypeScript Integration**
110
- agentf is an IDE tool targeting Copilot/OpenCode. RobotLab is a Ruby library with no IDE integration surface. Not relevant.
111
-
112
- **Pattern 6 — Graceful Redis Capability Degradation**
113
- Already handled. `Memory` already degrades `redis → hash` fallback at initialization. `DocumentStore` uses fastembed, not Redis Stack — separate concern covered below.
114
-
115
- ---
116
-
117
- ### Patterns Worth Implementing
118
-
119
- ---
120
-
121
- #### Pattern 1 — Self-Describing Robots/Tools (HIGH VALUE)
122
-
123
- This is the missing piece for `tool_manifest_plan.md`. Nothing auto-registers today because there is nowhere to register *to* and no class-level metadata to register. agentf's insight: put descriptors at the class level, not in instances.
124
-
125
- ```ruby
126
- class MyTool < RobotLab::Tool
127
- self.description = "Fetch current weather for a location"
128
- self.tags = [:network, :read_only]
129
- end
130
- ```
131
-
132
- At class-load time, Zeitwerk triggers auto-registration into `RobotLab.tool_registry`. The selector-robot pattern becomes viable without any explicit registration ceremony. Live callable instances stay per-robot; the global registry holds lightweight descriptors only (name + description). This is the v1 the `tool_manifest_plan.md` actually needs — and avoids the MCP auto-registration problem identified in that plan's review notes.
133
-
134
- Robot subclasses get the same treatment:
135
- ```ruby
136
- class SupportBot < RobotLab::Robot
137
- self.description = "Handles tier-1 customer support"
138
- self.capabilities = [:search, :ticket_creation]
139
- end
140
- ```
141
-
142
- This also enables the `Installer`-style manifest generation: `RobotLab.tool_registry.summary` produces the compact name+description list the selector robot reasons over.
143
-
144
- ---
145
-
146
- #### Patterns 2 + 8 — Contract Enforcement + Policy Boundaries (HIGH VALUE, medium effort)
147
-
148
- RobotLab has a circuit breaker (`max_tool_rounds`) and an error hierarchy — but no *pre/post validation layer* on execution. As AIA drives RobotLab into production use, this gap is significant.
149
-
150
- The three modes map cleanly to the dev→prod lifecycle:
151
- - `advisory` — log violations, don't block (development default)
152
- - `enforcing` — raise on violation (production default)
153
- - `off` — no overhead (test default)
154
-
155
- Policies declared at the Tool class level:
156
- ```ruby
157
- class DeleteFileTool < RobotLab::Tool
158
- policy :ask_first # always prompt user before executing
159
- end
160
-
161
- class FormatDriveTool < RobotLab::Tool
162
- policy :never # contract blocks execution entirely in enforcing mode
163
- end
164
- ```
165
-
166
- The contract wraps `robot.run()` with `before!`/`after!` hooks — checks token budget, validates tool policies, enforces max cost. A `RunConfig` field (`contract: :advisory`) controls the mode and flows through the standard hierarchy. This pairs naturally with the existing `RunConfig` merge semantics and would be the first true safety/governance layer in RobotLab.
167
-
168
- ---
169
-
170
- #### Pattern 9 — Workflow Profiles (LOW EFFORT, good discoverability)
171
-
172
- Networks are currently built by hand each time. A `RobotLab::Profiles` module with named constants would reduce boilerplate and document canonical topologies:
173
-
174
- ```ruby
175
- RobotLab::Profiles::CONSENSUS # fan-out to N robots → reconciler
176
- RobotLab::Profiles::PIPELINE # sequential chain
177
- RobotLab::Profiles::PARALLEL # concurrent, no synthesis
178
- RobotLab::Profiles::MCP_FAN_OUT # one robot per MCP server
179
- ```
180
-
181
- Each profile is a lambda/factory that takes robots + optional router and returns a configured network. This also gives AIA's `RobotFactory` topologies a canonical home in the library itself rather than application-level code.
182
-
183
- ---
184
-
185
- #### Pattern 5 — Eval Framework (MEDIUM EFFORT, high long-term value)
186
-
187
- RobotLab has 22 example scripts but **zero assertions**. They are demos, not evals. agentf's `prompt.txt + scenario.yml + verify.sh` per scenario is the right shape.
188
-
189
- For RobotLab the natural form:
190
- - `evals/scenarios/convergence_basic/` — prompt, expected behavior description, `verify.rb` script
191
- - `rake eval:run[convergence_basic]` replays against a VCR cassette and asserts postconditions
192
- - `rake eval:run:all` becomes a regression suite for agent behavior
193
-
194
- This connects directly to AIA's EDD (Eval-Driven Development) vision and would give confidence before a 1.0 release. The existing VCR/WebMock infrastructure is the right foundation.
195
-
196
- ---
197
-
198
- #### Pattern 4 — Deterministic Embedding Fallback (LOW EFFORT)
199
-
200
- `DocumentStore` hard-requires fastembed — no fallback. On first use it downloads an ONNX model, which is slow and requires a working network. `word_hash` (stemmed TF vectors) already exists in the codebase and is used by `compress_history`, `search_history`, and `Convergence`.
201
-
202
- A simple degradation path: when fastembed raises `LoadError` or the model is unavailable, `DocumentStore` falls back to `word_hash` cosine similarity with a logged warning. Zero new infrastructure — just wiring what already exists into `DocumentStore#embed`.
203
-
204
- ---
205
-
206
- #### Pattern 3 — HITL Confirmation Protocol (LOW VALUE given AskUser)
207
-
208
- The agentf pattern — return `{ confirmation: true, payload: }` instead of raising, re-invoke with `confirmedWrite: "confirmed"` — is elegant for memory writes that need approval. However, RobotLab already has `AskUser` for the primary HITL use case. This pattern only becomes interesting if RobotLab needs programmatic HITL that doesn't require a terminal (e.g., web apps pausing for user approval via HTTP callback). Not urgent.
209
-
210
- ---
211
-
212
- ### Priority Ranking
213
-
214
- | Priority | Pattern | Effort | Connects To |
215
- |---|---|---|---|
216
- | 1 | Self-describing tools/robots (class-level metadata) | Medium | `tool_manifest_plan.md` — makes ToolManifest v1 actionable |
217
- | 2 | Contract enforcement + Policy boundaries | Medium | Production safety gap; RunConfig integration |
218
- | 3 | Eval framework | Medium | Long-term regression confidence; AIA EDD |
219
- | 4 | Workflow profiles | Low | AIA's RobotFactory; discoverability |
220
- | 5 | DocumentStore word_hash fallback | Low | Dev ergonomics; no ONNX download needed |
221
-
222
- **Natural weekly pairing:** Pattern 1 (self-describing classes → ToolManifest v1) + Pattern 9 (workflow profiles) form a coherent "discoverability and composability" theme. Patterns 2+8 are the right *next* architectural investment but scope to a separate week.
223
-
224
- ---
225
-
226
- ## Comparison to Other Agent Frameworks
227
-
228
- | Aspect | `agentf` | LangChain (Python) | CrewAI (Python) |
229
- |---|---|---|---|
230
- | Language | Ruby | Python | Python |
231
- | LLM calls | None (delegates to IDE) | Direct | Direct |
232
- | Agent communication | Shared Redis memory | In-process state | Sequential/hierarchical |
233
- | Memory | Episodic + semantic (Redis Stack) | Various vector stores | Basic |
234
- | IDE integration | MCP server (Copilot, OpenCode) | None native | None native |
235
- | Contract enforcement | 3-mode advisory/enforcing/off | None | None |
236
- | Self-describing agents | Class-method metadata | No | Role strings in YAML |
237
- | Eval framework | Black-box shell scripts | Unit tests | Unit tests |
238
- | TDD enforcement | Built-in (red/green contracts) | None | None |
239
-
240
- Within Ruby there is essentially no direct equivalent. `ruby-openai` and
241
- `omniai` handle LLM API calls but have no orchestration. `agentf` is novel in
242
- the Ruby ecosystem for combining Redis-backed episodic memory, role-specialized
243
- agent classes, contract enforcement, and an MCP stdio server in one gem.
244
-
245
- ---
246
-
247
- ## The Big Takeaway
248
-
249
- The most instructive thing about `agentf` is its **division of responsibility**:
250
- the gem owns memory, sequencing, policies, and tool-exposure via MCP — the
251
- IDE's AI owns inference. That separation means no API keys, no HTTP calls to
252
- LLM providers, and no model coupling. If building AI-assisted tooling in Ruby,
253
- that architecture is worth emulating.
data/agents.md DELETED
@@ -1,14 +0,0 @@
1
- ### Local Agent Context: Repository Root
2
-
3
- - Start here, then navigate to the closest directory AGENTS.md before coding.
4
- - Do not operate from root unless necessary.
5
-
6
- ## Table of Contents
7
-
8
- - [.architecture/reviews](./.architecture/reviews/AGENTS.md): Access `config.yml` for architecture-related settings.
9
- - [.github/workflows](./.github/workflows/AGENTS.md): Review `deploy-github-pages.yml` for CI/CD pipeline specifics.
10
- - [.ruby-lsp](./.ruby-lsp/AGENTS.md): Initialize your environment with `Gemfile` dependencies.
11
- - [docs](./docs/AGENTS.md): Consult `/docs/api/core/robot.md` for robot-related API documentation.
12
- - [examples](./examples/AGENTS.md): Explore `14_rusty_circuit/open_mic.rb` for demo scripts in action.
13
- - [lib/generators/robot_lab](./lib/generators/robot_lab/AGENTS.md): Use `templates/initializer.rb.tt` for custom project setup.
14
- - [test/robot_lab](./test/robot_lab/AGENTS.md): Implement new tests based on `test_helper.rb` configurations.
@@ -1,147 +0,0 @@
1
- # Core Classes
2
-
3
- The fundamental classes that power RobotLab.
4
-
5
- ## Overview
6
-
7
- ```mermaid
8
- classDiagram
9
- class Robot {
10
- +name: String
11
- +description: String
12
- +model: String
13
- +template: Symbol
14
- +local_tools: Array~Tool~
15
- +mcp_tools: Array~Tool~
16
- +tools_config: Symbol_or_Array
17
- +run(message) RobotResult
18
- }
19
-
20
- class RobotResult {
21
- +robot_name: String
22
- +reply: String
23
- +output: Array~TextMessage~
24
- +input_tokens: Integer
25
- +output_tokens: Integer
26
- +export() Hash
27
- }
28
-
29
- class Network {
30
- +name: String
31
- +robots: Hash
32
- +config: RunConfig
33
- +memory: Memory
34
- +run(message) SimpleFlow_Result
35
- }
36
-
37
- class RunConfig {
38
- +model: String
39
- +temperature: Float
40
- +merge(other) RunConfig
41
- +apply_to(chat)
42
- }
43
-
44
- class Tool {
45
- +name: String
46
- +description: String
47
- +robot: Robot
48
- +mcp: String
49
- +call(args)
50
- }
51
-
52
- class Memory {
53
- +set(key, value)
54
- +get(key)
55
- +delete(key)
56
- +data: StateProxy
57
- +results: Array
58
- +messages: Array
59
- +session_id: String
60
- }
61
-
62
- class RobotMessage {
63
- +id: Integer
64
- +from: String
65
- +content: String
66
- +in_reply_to: String
67
- +key()
68
- +reply?()
69
- }
70
-
71
- Network --> Robot : contains
72
- Network --> RunConfig : uses
73
- Robot --> RunConfig : uses
74
- Robot --> Tool : has
75
- Robot --> Memory : uses
76
- Robot ..> RobotResult : returns
77
- Network --> Memory : uses
78
- Robot ..> RobotMessage : sends/receives
79
- Memory --> StateProxy : data
80
- ```
81
-
82
- ## Classes
83
-
84
- | Class | Purpose |
85
- |-------|---------|
86
- | [Robot](robot.md) | LLM agent with templates, tools, memory, and model configuration |
87
- | [RobotResult](result.md) | Value object returned by `Robot#run` |
88
- | [Network](network.md) | Container for robots with DAG orchestration |
89
- | [RunConfig](robot.md#runconfig) | Shared configuration for LLM, tools, callbacks, and infrastructure |
90
- | [Tool](tool.md) | Callable function with parameters and an `execute` method |
91
- | [AskUser](tool.md#built-in-askuser) | Built-in tool for terminal-based user interaction |
92
- | [Memory](memory.md) | Reactive key-value store for sharing data |
93
- | [StateProxy](state.md) | Hash/method-access wrapper returned by `memory.data` |
94
- | RobotMessage | Typed envelope for bus-based inter-robot communication |
95
- | `RobotLab::Runnable` | Shared interface (`crew`, `chief`, `robot_count`, `network?`, `single?`) implemented by both `Robot` and `Network` — see [Runnable Protocol](../../architecture/core-concepts.md#runnable-protocol) |
96
-
97
- There is no `RobotLab::State` class and no `RobotLab::NetworkRun` class.
98
-
99
- ## Quick Examples
100
-
101
- ### Robot
102
-
103
- ```ruby
104
- robot = RobotLab.build(
105
- name: "assistant",
106
- model: "claude-sonnet-4",
107
- system_prompt: "You are helpful.",
108
- local_tools: [greet_tool]
109
- )
110
-
111
- result = robot.run("Hello!") # no tools sent — run() defaults to tools: :none
112
- result = robot.run("Hello!", tools: :inherit) # sends greet_tool
113
- result.reply # => String
114
- ```
115
-
116
- `Robot#run` returns a [`RobotLab::RobotResult`](result.md), not a `Message`.
117
-
118
- ### Network
119
-
120
- The builder DSL method is `task` (there is no `step`):
121
-
122
- ```ruby
123
- network = RobotLab.create_network(name: "my_network") do
124
- task :analyzer, analyzer_robot, depends_on: :none
125
- task :writer, writer_robot, depends_on: [:analyzer]
126
- end
127
-
128
- result = network.run(message: "Process this") # => SimpleFlow::Result
129
- result.value # => RobotResult of the last task
130
- ```
131
-
132
- ### Memory
133
-
134
- ```ruby
135
- memory = RobotLab.create_memory(data: { user_id: "123" })
136
- memory.set(:category, "billing")
137
- memory.get(:category) # => "billing"
138
- ```
139
-
140
- ### Tool
141
-
142
- ```ruby
143
- tool = RobotLab::Tool.create(
144
- name: "get_time",
145
- description: "Get current time"
146
- ) { |**_| Time.now.to_s }
147
- ```