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,247 +0,0 @@
1
- # AgentSkills.io Support — Design Spec
2
-
3
- **Date:** 2026-05-06
4
- **Status:** Approved
5
-
6
- ## Overview
7
-
8
- Add support for the [AgentSkills.io](https://agentskills.io) open standard to RobotLab's existing skills system. Skills are currently single `.md` prompt_manager template files referenced by symbol ID. This spec extends `skills:` to also recognize the AgentSkills folder format (`~/.prompts/skills/<name>/SKILL.md`) with bundled scripts auto-exposed as tools and runtime embedding-based matching for progressive disclosure.
9
-
10
- ## Goals
11
-
12
- - Unified `skills:` API — no new constructor params; format detected automatically
13
- - AgentSkills folder skills use runtime embedding similarity to decide injection per `run()` call
14
- - Scripts in `scripts/` auto-wrapped as `RobotLab::Tool` subclasses
15
- - Zero breakage to existing PM template skills behavior
16
- - Graceful degradation when embeddings fail or no skills match
17
-
18
- ## Non-Goals
19
-
20
- - Automatic catalog-wide skill discovery without explicit `skills:` listing
21
- - Fetching remote skills from registries
22
- - Skills referencing `references/` or `assets/` sub-folders (deferred)
23
- - Modifying the AgentSkills.io specification
24
-
25
- ---
26
-
27
- ## Discovery Path
28
-
29
- AgentSkill folders are resolved from a single fixed root: `~/.prompts/skills/`. Given `skills: [:check_style]`, the loader checks `~/.prompts/skills/check_style/SKILL.md`. If that file exists, it is an AgentSkill. If not, the existing PM template resolution applies.
30
-
31
- This root is not configurable in v1.
32
-
33
- ---
34
-
35
- ## New Classes
36
-
37
- ### `RobotLab::AgentSkill`
38
-
39
- Plain Ruby value object. Constructed by the catalog or the expand_skills loader.
40
-
41
- ```
42
- AgentSkill
43
- name: String # from SKILL.md front matter
44
- description: String # from SKILL.md front matter — used for embedding
45
- path: Pathname # directory path
46
- instructions: String # lazy: SKILL.md body — everything after the closing ---
47
- scripts: Array<Pathname> # lazy: glob of scripts/*
48
- ```
49
-
50
- - `instructions` and `scripts` are loaded on first access (lazy).
51
- - Raises `RobotLab::ConfigurationError` on construction if `SKILL.md` is missing `name` or `description`.
52
- - `description_vector` — memoized fastembed **passage** embedding of `description` (`DocumentStore#passage_vector`), computed on first match attempt.
53
-
54
- ### `RobotLab::AgentSkillCatalog`
55
-
56
- Module-level singleton (`RobotLab::AgentSkillCatalog`). Scans `~/.prompts/skills/` at process start (lazy, on first access). Caches `AgentSkill` objects keyed by name symbol.
57
-
58
- Responsibilities:
59
- - `find(id)` — return `AgentSkill` for a given symbol, or `nil`
60
- - `all` — return all discovered skills
61
- - Internal: compute and cache description vectors using the `DocumentStore` fastembed infrastructure
62
-
63
- ### `RobotLab::AgentSkillMatching`
64
-
65
- Module included in `Robot`. Contains the `run()` override and the similarity logic.
66
-
67
- ### `RobotLab::ScriptTool`
68
-
69
- Factory method `ScriptTool.from_path(path)` returns an anonymous `RobotLab::Tool` subclass. The tool:
70
- - Name: script filename without extension, underscored (e.g. `check_style`)
71
- - Description: first comment line of the script, or `"Run #{name}"`
72
- - Execution: shells out via `Open3.capture2e`, returns stdout+stderr as the tool result
73
- - Raises `RobotLab::ToolNotFoundError` if the script is not executable
74
-
75
- ---
76
-
77
- ## Modified Code
78
-
79
- ### `Robot::TemplateRendering#expand_skills`
80
-
81
- Before resolving a skill ID as a PM template, check `AgentSkillCatalog.find(skill_id)`:
82
-
83
- ```
84
- expand_skills([:runbook_protocol, :check_style], visited)
85
- :runbook_protocol → catalog.find → nil → PM template (existing path)
86
- :check_style → catalog.find → AgentSkill<check_style>
87
- → store in @pending_agent_skills
88
- → do NOT add to @expanded_skills
89
- ```
90
-
91
- `@expanded_skills` continues to hold only PM-format skill IDs, preserving all existing behavior.
92
-
93
- ### `Robot` constructor
94
-
95
- Add `@pending_agent_skills = []` alongside `@expanded_skills = nil`.
96
-
97
- ### `Robot::AgentSkillMatching#run`
98
-
99
- Prepended to `Robot` to intercept `run()`:
100
-
101
- ```ruby
102
- def run(message, **kwargs)
103
- activated = match_agent_skills(message)
104
- inject_agent_skills(activated)
105
- super
106
- ensure
107
- restore_after_agent_skills(activated)
108
- end
109
- ```
110
-
111
- **`match_agent_skills(message)`**
112
- 1. Return `[]` if `@pending_agent_skills` is empty
113
- 2. Embed `message` as a **query** vector (`DocumentStore#query_vector`) — distinct from the passage embedding used for skill descriptions
114
- 3. For each pending AgentSkill, compute cosine similarity between message query-vector and `skill.description_vector` (passage-vector)
115
- 4. Return skills where similarity >= `SIMILARITY_THRESHOLD` (default: `0.70`)
116
-
117
- **`inject_agent_skills(skills)`**
118
- 1. Prepend each skill's `instructions` to the chat's system prompt (using `with_instructions`)
119
- 2. Instantiate `ScriptTool` for each script in each skill's `scripts/`; add to `@local_tools`
120
-
121
- **`restore_after_agent_skills(skills)`**
122
- 1. Remove injected script tools from `@local_tools`
123
- 2. Restore system prompt to pre-injection state
124
-
125
- The system prompt is snapshotted before injection and restored in the `ensure` block so state does not accumulate across calls.
126
-
127
- ---
128
-
129
- ## SKILL.md Format
130
-
131
- Follows the AgentSkills.io specification. Front matter is YAML; body is Markdown.
132
-
133
- ```markdown
134
- ---
135
- name: check_style
136
- description: Review Ruby code style against project conventions
137
- ---
138
- When reviewing code, check for:
139
- - Frozen string literal comments
140
- - Method length under 20 lines
141
- - No inline rescue
142
- ```
143
-
144
- RobotLab reads only `name` and `description` from front matter. All other front matter keys are ignored (no LLM config via SKILL.md — that remains the PM template system's domain).
145
-
146
- ---
147
-
148
- ## Script Tools
149
-
150
- Given `~/.prompts/skills/check_style/scripts/run_rubocop.sh`:
151
-
152
- - Tool name: `run_rubocop`
153
- - Description: first `# comment` line in the file, else `"Run run_rubocop"`
154
- - Input: optional `args` string passed as CLI arguments
155
- - Execution: `Open3.capture2e("bash #{path} #{args}")`, returns combined output
156
- - Not executable → log warn, skip (no error raised to the robot)
157
-
158
- ---
159
-
160
- ## Similarity Threshold
161
-
162
- Default: `0.70` (cosine similarity, 0..1 range).
163
-
164
- Accessible as `RobotLab::AgentSkillMatching::SIMILARITY_THRESHOLD`. Not yet user-configurable in v1; a future `config.agent_skill_threshold` can override it.
165
-
166
- ---
167
-
168
- ## Error Handling
169
-
170
- | Situation | Behavior |
171
- |---|---|
172
- | `SKILL.md` missing `name` or `description` | `ConfigurationError` raised at catalog load |
173
- | fastembed fails on message | Log warn, skip all AgentSkill injection for that call |
174
- | Script not executable | Log warn, skip that tool; other scripts still wrap |
175
- | No skills match threshold | Normal `run()` with no injection |
176
- | Circular skill reference via AgentSkill | Existing cycle detection in `expand_skills` handles it |
177
-
178
- ---
179
-
180
- ## Testing
181
-
182
- ### Unit tests (`test/robot_lab/agent_skill_test.rb`)
183
- - Parses `SKILL.md` front matter correctly
184
- - Raises `ConfigurationError` when `name` or `description` missing
185
- - `instructions` lazy-loads body content
186
- - `scripts` lazy-globs `scripts/` directory
187
-
188
- ### Unit tests (`test/robot_lab/agent_skill_catalog_test.rb`)
189
- - Scans fixture skills directory
190
- - `find` returns correct `AgentSkill` by symbol
191
- - `find` returns `nil` for unknown ID
192
-
193
- ### Unit tests (`test/robot_lab/script_tool_test.rb`)
194
- - `from_path` produces a tool with correct name and description
195
- - Tool execution returns stdout+stderr
196
- - Non-executable script skipped with warning
197
-
198
- ### Unit tests (`test/robot_lab/robot/agent_skill_matching_test.rb`)
199
- - `match_agent_skills` returns skills above threshold (mock embeddings)
200
- - `match_agent_skills` returns empty when below threshold
201
- - `inject_agent_skills` prepends instructions to system prompt
202
- - `restore_after_agent_skills` removes injected tools and restores prompt
203
- - Empty `@pending_agent_skills` short-circuits without embedding
204
-
205
- ### Integration tests (`test/robot_lab/robot_test.rb`)
206
- - Robot with `skills: [:pm_template, :agent_skill_fixture]` correctly expands PM template eagerly and AgentSkill at runtime
207
- - AgentSkill scripts appear in tool list during run, absent after
208
-
209
- ### Fixtures
210
- - `test/fixtures/skills/test_skill/SKILL.md` — valid skill
211
- - `test/fixtures/skills/bad_skill/SKILL.md` — missing description
212
- - `test/fixtures/skills/scripted_skill/SKILL.md` + `scripts/hello.sh`
213
-
214
- ---
215
-
216
- ## File Layout
217
-
218
- ```
219
- lib/robot_lab/
220
- agent_skill.rb # AgentSkill value object
221
- agent_skill_catalog.rb # Singleton scanner/registry
222
- script_tool.rb # ScriptTool factory
223
- robot/
224
- agent_skill_matching.rb # run() override mixin
225
-
226
- test/robot_lab/
227
- agent_skill_test.rb
228
- agent_skill_catalog_test.rb
229
- script_tool_test.rb
230
- robot/
231
- agent_skill_matching_test.rb
232
-
233
- test/fixtures/skills/
234
- test_skill/SKILL.md
235
- bad_skill/SKILL.md
236
- scripted_skill/SKILL.md
237
- scripted_skill/scripts/hello.sh
238
- ```
239
-
240
- ---
241
-
242
- ## Open Questions (deferred)
243
-
244
- - `references/` and `assets/` subdirectories: make content available as context variables in future
245
- - User-configurable similarity threshold via `RobotLab.config`
246
- - Auto-catalog mode: discover all skills without explicit `skills:` listing
247
- - AgentSkill nesting (a SKILL.md referencing other skill IDs)
data/examples/.envrc DELETED
@@ -1,3 +0,0 @@
1
- source_up
2
-
3
- export ROBOT_LAB_TEMPLATE_PATH="${PWD}/prompts"
@@ -1,31 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Example 1: Simple Robot
5
- #
6
- # Demonstrates creating and running a basic robot with a template.
7
- #
8
- # Usage:
9
- # ruby examples/01_simple_robot.rb
10
-
11
- require_relative "common"
12
-
13
- # Create a simple robot using a template
14
- robot = RobotLab.build(
15
- **llm_opts,
16
- name: "helper",
17
- template: :helper
18
- )
19
-
20
- banner "Simple Robot"
21
-
22
- # Run the robot
23
- result = robot.run("What is 2 + 2? Please explain your reasoning briefly.")
24
-
25
- # Display the result
26
- puts "Robot: #{robot.name}"
27
- puts "Output:"
28
- result.output.each do |message|
29
- puts " #{message.content}" if message.respond_to?(:content)
30
- end
31
- hr
data/examples/02_tools.rb DELETED
@@ -1,109 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Example 2: Robot with Tools
5
- #
6
- # Demonstrates creating a robot with custom tools using RubyLLM::Tool.
7
- #
8
- # Usage:
9
- # ruby examples/02_tools.rb
10
-
11
- require_relative "common"
12
-
13
- # Define tools using RubyLLM::Tool
14
- class Calculator < RubyLLM::Tool
15
- description "Performs basic arithmetic operations"
16
-
17
- parameter :operation,
18
- type: "string",
19
- description: "The operation to perform (add, subtract, multiply, divide)"
20
-
21
- parameter :a,
22
- type: "number",
23
- description: "First operand"
24
-
25
- parameter :b,
26
- type: "number",
27
- description: "Second operand"
28
-
29
- def execute(operation:, a:, b:)
30
- case operation
31
- when "add" then a + b
32
- when "subtract" then a - b
33
- when "multiply" then a * b
34
- when "divide" then a.to_f / b
35
- else "Unknown operation: #{operation}"
36
- end
37
- end
38
- end
39
-
40
- class FortuneCookie < RubyLLM::Tool
41
- description "Get a fortune cookie message with wisdom and lucky numbers"
42
-
43
- parameter :category,
44
- type: "string",
45
- description: "The category of fortune (wisdom, love, career, adventure)"
46
-
47
- FORTUNES = {
48
- "wisdom" => [
49
- "The obstacle in the path becomes the path.",
50
- "A journey of a thousand miles begins with a single step.",
51
- "The best time to plant a tree was 20 years ago. The second best time is now."
52
- ],
53
- "love" => [
54
- "The heart that loves is always young.",
55
- "To love and be loved is to feel the sun from both sides.",
56
- "Love is not about finding the right person, but being the right person."
57
- ],
58
- "career" => [
59
- "Opportunity dances with those already on the dance floor.",
60
- "Your work is your signature. Sign it with excellence.",
61
- "The expert in anything was once a beginner."
62
- ],
63
- "adventure" => [
64
- "Life shrinks or expands in proportion to one's courage.",
65
- "Not all who wander are lost.",
66
- "The biggest adventure you can take is to live the life of your dreams."
67
- ]
68
- }.freeze
69
-
70
- def execute(category:)
71
- {
72
- category: category,
73
- fortune: FORTUNES.fetch(category, FORTUNES["wisdom"]).sample,
74
- lucky_numbers: Array.new(6) { rand(1..49) }.sort
75
- }
76
- end
77
- end
78
-
79
- # Create robot with tools
80
- robot = RobotLab.build(
81
- **llm_opts,
82
- name: "assistant",
83
- template: :assistant,
84
- local_tools: [Calculator, FortuneCookie]
85
- )
86
-
87
- banner "Robot with Tools"
88
-
89
- # Run the robot.
90
- #
91
- # tools: :inherit is REQUIRED to actually offer the tools to the model.
92
- # Robot#run defaults to tools: :none, which means "send zero tools this turn"
93
- # — the robot still holds them in local_tools, but the provider never sees
94
- # them and the LLM answers from memory instead of calling Calculator.
95
- # :inherit means "no per-turn filter, use every attached tool".
96
- result = robot.run(
97
- "What is 15 multiplied by 7? Also, give me a fortune about my career.",
98
- tools: :inherit
99
- )
100
-
101
- # Display results
102
- puts "Robot: #{robot.name}"
103
- puts "Tools offered: #{robot.local_tools.map(&:name).join(', ')}"
104
- puts "\nOutput:"
105
- result.output.each do |message|
106
- puts " #{message.content}" if message.respond_to?(:content)
107
- end
108
-
109
- hr
@@ -1,118 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Example 3: Multi-Robot Network
5
- #
6
- # Demonstrates creating a network of robots with conditional routing
7
- # using SimpleFlow's optional step activation.
8
- #
9
- # Usage:
10
- # ruby examples/03_network.rb
11
-
12
- require_relative "common"
13
-
14
- SPECIALIST_TASKS = %i[billing technical general].freeze
15
-
16
- # Classifier robot that activates the appropriate specialist
17
- class ClassifierRobot < RobotLab::Robot
18
- def call(result)
19
- run_context = extract_run_context(result)
20
- message = run_context.delete(:message)
21
- robot_result = run(message, **run_context)
22
-
23
- new_result = result
24
- .with_context(@name.to_sym, robot_result)
25
- .continue(robot_result)
26
-
27
- # Examine LLM output and activate appropriate specialist
28
- category = robot_result.reply.to_s.strip.downcase
29
-
30
- case category
31
- when /billing/
32
- new_result.activate(:billing)
33
- when /technical/
34
- new_result.activate(:technical)
35
- else
36
- new_result.activate(:general)
37
- end
38
- end
39
- end
40
-
41
- # Shared RunConfig — operational defaults every robot in this network inherits.
42
- #
43
- # RunConfig has no `provider` field (see RunConfig::FIELDS), and an LM Studio
44
- # model is absent from RubyLLM's registry, so provider and model still travel
45
- # together on each robot via **llm_opts. The RunConfig carries the settings
46
- # that genuinely are shared.
47
- shared_config = RobotLab::RunConfig.new(temperature: 0.3, max_tool_rounds: 5)
48
-
49
- classifier = ClassifierRobot.new(
50
- **llm_opts,
51
- name: "classifier",
52
- template: :classifier,
53
- config: shared_config
54
- )
55
-
56
- billing_robot = RobotLab.build(
57
- **llm_opts,
58
- name: "billing",
59
- template: :billing,
60
- config: shared_config
61
- )
62
-
63
- technical_robot = RobotLab.build(
64
- **llm_opts,
65
- name: "technical",
66
- template: :technical,
67
- config: shared_config
68
- )
69
-
70
- general_robot = RobotLab.build(
71
- **llm_opts,
72
- name: "general",
73
- template: :general,
74
- config: shared_config
75
- )
76
-
77
- # Create network with optional task routing and shared config
78
- network = RobotLab.create_network(name: "support_network", config: shared_config) do
79
- task :classifier, classifier, depends_on: :none
80
- task :billing, billing_robot, depends_on: :optional
81
- task :technical, technical_robot, depends_on: :optional
82
- task :general, general_robot, depends_on: :optional
83
- end
84
-
85
- banner "Multi-Robot Network"
86
- puts "Routing plan:"
87
- puts " Entry task: classifier"
88
- puts " Optional specialists: #{SPECIALIST_TASKS.join(', ')}"
89
- puts " Runtime behavior: classifier activates exactly one specialist"
90
- puts
91
- puts "Underlying SimpleFlow structure:"
92
- puts " Optional tasks: #{network.to_h[:optional_tasks].join(', ')}"
93
- hr
94
-
95
- # Run the network with a billing question
96
- result = network.run(message: "I was charged twice for my subscription last month. Can you help?")
97
-
98
- # Display results
99
- puts "Network: #{network.name}"
100
- puts "Executed tasks: #{result.context.keys.grep_v(:run_params).join(', ')}"
101
- puts "Skipped specialists: #{(SPECIALIST_TASKS - result.context.keys).join(', ')}"
102
- puts "\nConversation flow:"
103
-
104
- # Show classifier result
105
- if result.context[:classifier]
106
- classifier_result = result.context[:classifier]
107
- puts "\n1. Robot: classifier"
108
- puts " Classification: #{classifier_result.reply}"
109
- end
110
-
111
- # Show specialist result (the final value)
112
- if result.value.is_a?(RobotLab::RobotResult)
113
- puts "\n2. Robot: #{result.value.robot_name}"
114
- content = result.value.reply
115
- puts " Response: #{content[0..200]}..." if content
116
- end
117
-
118
- hr