robot_lab 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +60 -0
  3. data/README.md +29 -19
  4. data/lib/robot_lab/errors.rb +4 -0
  5. data/lib/robot_lab/hook_context.rb +9 -2
  6. data/lib/robot_lab/mcp/registry.rb +99 -0
  7. data/lib/robot_lab/mcp/server.rb +47 -83
  8. data/lib/robot_lab/mcp/server_discovery.rb +22 -9
  9. data/lib/robot_lab/mcp.rb +259 -0
  10. data/lib/robot_lab/robot/mcp_management.rb +159 -105
  11. data/lib/robot_lab/robot/tool_call_gating.rb +144 -0
  12. data/lib/robot_lab/robot.rb +72 -99
  13. data/lib/robot_lab/run_config.rb +3 -2
  14. data/lib/robot_lab/tool.rb +8 -23
  15. data/lib/robot_lab/version.rb +1 -1
  16. data/lib/robot_lab.rb +1 -4
  17. metadata +16 -292
  18. data/.architecture/AGENTS.md +0 -32
  19. data/.architecture/config.yml +0 -8
  20. data/.architecture/members.yml +0 -60
  21. data/.architecture/reviews/feature-free-will.md +0 -490
  22. data/.architecture/reviews/overall-codebase.md +0 -427
  23. data/.claude/settings.local.json +0 -57
  24. data/.codex/config.toml +0 -2
  25. data/.envrc +0 -6
  26. data/.github/workflows/deploy-github-pages.yml +0 -52
  27. data/.irbrc +0 -6
  28. data/.loki +0 -65
  29. data/.quality/reek_baseline.txt +0 -43
  30. data/.rubocop.yml +0 -10
  31. data/Archspec.rb +0 -44
  32. data/CLAUDE.md +0 -141
  33. data/COMMITS.md +0 -196
  34. data/Rakefile +0 -193
  35. data/_typos.toml +0 -21
  36. data/agent2agent_review.md +0 -192
  37. data/agentf_improvements.md +0 -253
  38. data/agents.md +0 -14
  39. data/docs/api/core/index.md +0 -147
  40. data/docs/api/core/memory.md +0 -578
  41. data/docs/api/core/network.md +0 -553
  42. data/docs/api/core/result.md +0 -211
  43. data/docs/api/core/robot.md +0 -1667
  44. data/docs/api/core/state.md +0 -145
  45. data/docs/api/core/tool.md +0 -520
  46. data/docs/api/errors.md +0 -323
  47. data/docs/api/hooks.md +0 -469
  48. data/docs/api/index.md +0 -137
  49. data/docs/api/mcp/client.md +0 -387
  50. data/docs/api/mcp/index.md +0 -267
  51. data/docs/api/mcp/server.md +0 -252
  52. data/docs/api/mcp/transports.md +0 -339
  53. data/docs/api/messages/index.md +0 -126
  54. data/docs/api/messages/text-message.md +0 -170
  55. data/docs/api/messages/tool-call-message.md +0 -206
  56. data/docs/api/messages/tool-result-message.md +0 -242
  57. data/docs/api/messages/user-message.md +0 -232
  58. data/docs/api/skills.md +0 -423
  59. data/docs/api/streaming/context.md +0 -280
  60. data/docs/api/streaming/events.md +0 -185
  61. data/docs/api/streaming/index.md +0 -156
  62. data/docs/api/support.md +0 -846
  63. data/docs/architecture/core-concepts.md +0 -575
  64. data/docs/architecture/index.md +0 -252
  65. data/docs/architecture/message-flow.md +0 -366
  66. data/docs/architecture/network-orchestration.md +0 -478
  67. data/docs/architecture/robot-execution.md +0 -396
  68. data/docs/architecture/state-management.md +0 -410
  69. data/docs/assets/css/custom.css +0 -56
  70. data/docs/assets/images/robot_lab.jpg +0 -0
  71. data/docs/concepts.md +0 -641
  72. data/docs/examples/basic-chat.md +0 -258
  73. data/docs/examples/index.md +0 -425
  74. data/docs/examples/mcp-server.md +0 -403
  75. data/docs/examples/multi-robot-network.md +0 -476
  76. data/docs/examples/tool-usage.md +0 -468
  77. data/docs/getting-started/configuration.md +0 -645
  78. data/docs/getting-started/index.md +0 -56
  79. data/docs/getting-started/installation.md +0 -197
  80. data/docs/getting-started/quick-start.md +0 -293
  81. data/docs/guides/building-robots.md +0 -1187
  82. data/docs/guides/creating-networks.md +0 -736
  83. data/docs/guides/hooks.md +0 -1206
  84. data/docs/guides/index.md +0 -78
  85. data/docs/guides/knowledge.md +0 -219
  86. data/docs/guides/mcp-integration.md +0 -740
  87. data/docs/guides/memory.md +0 -458
  88. data/docs/guides/observability.md +0 -733
  89. data/docs/guides/streaming.md +0 -323
  90. data/docs/guides/using-tools.md +0 -780
  91. data/docs/index.md +0 -280
  92. data/docs/superpowers/plans/2026-05-06-agentskills.md +0 -1303
  93. data/docs/superpowers/specs/2026-05-06-agentskills-design.md +0 -247
  94. data/examples/.envrc +0 -3
  95. data/examples/01_simple_robot.rb +0 -31
  96. data/examples/02_tools.rb +0 -109
  97. data/examples/03_network.rb +0 -118
  98. data/examples/04_mcp.rb +0 -217
  99. data/examples/05_streaming.rb +0 -137
  100. data/examples/06_prompt_templates.rb +0 -325
  101. data/examples/07_network_memory.rb +0 -313
  102. data/examples/08_llm_config.rb +0 -162
  103. data/examples/09_chaining.rb +0 -251
  104. data/examples/10_memory.rb +0 -315
  105. data/examples/11_network_introspection.rb +0 -239
  106. data/examples/12_message_bus.rb +0 -67
  107. data/examples/13_spawn.rb +0 -85
  108. data/examples/14_rusty_circuit/.envrc +0 -1
  109. data/examples/14_rusty_circuit/.gitignore +0 -1
  110. data/examples/14_rusty_circuit/README.md +0 -1
  111. data/examples/14_rusty_circuit/comic.rb +0 -149
  112. data/examples/14_rusty_circuit/display.rb +0 -217
  113. data/examples/14_rusty_circuit/heckler.rb +0 -65
  114. data/examples/14_rusty_circuit/open_mic.rb +0 -132
  115. data/examples/14_rusty_circuit/prompts/open_mic_comic.md +0 -20
  116. data/examples/14_rusty_circuit/prompts/open_mic_heckler.md +0 -23
  117. data/examples/14_rusty_circuit/prompts/open_mic_scout.md +0 -20
  118. data/examples/14_rusty_circuit/scout.rb +0 -165
  119. data/examples/14_rusty_circuit/show.log +0 -234
  120. data/examples/15_memory_network_and_bus/.envrc +0 -1
  121. data/examples/15_memory_network_and_bus/README.md +0 -66
  122. data/examples/15_memory_network_and_bus/editor_in_chief.rb +0 -24
  123. data/examples/15_memory_network_and_bus/editorial_pipeline.rb +0 -213
  124. data/examples/15_memory_network_and_bus/linux_writer.rb +0 -80
  125. data/examples/15_memory_network_and_bus/os_editor.rb +0 -48
  126. data/examples/15_memory_network_and_bus/os_writer.rb +0 -49
  127. data/examples/15_memory_network_and_bus/output/combined_article.md +0 -11
  128. data/examples/15_memory_network_and_bus/output/final_article.md +0 -8
  129. data/examples/15_memory_network_and_bus/output/linux_draft.md +0 -7
  130. data/examples/15_memory_network_and_bus/output/mac_draft.md +0 -7
  131. data/examples/15_memory_network_and_bus/output/memory.json +0 -13
  132. data/examples/15_memory_network_and_bus/output/revision_1.md +0 -29
  133. data/examples/15_memory_network_and_bus/output/revision_2.md +0 -50
  134. data/examples/15_memory_network_and_bus/output/revision_3.md +0 -8
  135. data/examples/15_memory_network_and_bus/output/windows_draft.md +0 -7
  136. data/examples/15_memory_network_and_bus/prompts/os_advocate.md +0 -13
  137. data/examples/15_memory_network_and_bus/prompts/os_chief.md +0 -13
  138. data/examples/15_memory_network_and_bus/prompts/os_editor.md +0 -13
  139. data/examples/16_writers_room/.envrc +0 -1
  140. data/examples/16_writers_room/display.rb +0 -158
  141. data/examples/16_writers_room/output/.gitignore +0 -4
  142. data/examples/16_writers_room/output/README.md +0 -69
  143. data/examples/16_writers_room/output/opus_001.md +0 -263
  144. data/examples/16_writers_room/output/opus_001_notes.log +0 -470
  145. data/examples/16_writers_room/output/opus_002.md +0 -245
  146. data/examples/16_writers_room/output/opus_002_notes.log +0 -546
  147. data/examples/16_writers_room/output/opus_002_screenplay.md +0 -7989
  148. data/examples/16_writers_room/output/opus_002_screenplay_notes.md +0 -993
  149. data/examples/16_writers_room/prompts/screenplay_writer.md +0 -66
  150. data/examples/16_writers_room/prompts/writer.md +0 -37
  151. data/examples/16_writers_room/room.rb +0 -186
  152. data/examples/16_writers_room/tools.rb +0 -173
  153. data/examples/16_writers_room/writer.rb +0 -121
  154. data/examples/16_writers_room/writers_room.rb +0 -256
  155. data/examples/17_skills.rb +0 -234
  156. data/examples/18_rails/.envrc +0 -3
  157. data/examples/18_rails/.gitignore +0 -5
  158. data/examples/18_rails/Gemfile +0 -11
  159. data/examples/18_rails/README.md +0 -67
  160. data/examples/18_rails/Rakefile +0 -4
  161. data/examples/18_rails/app/controllers/application_controller.rb +0 -4
  162. data/examples/18_rails/app/controllers/chat_controller.rb +0 -50
  163. data/examples/18_rails/app/jobs/application_job.rb +0 -4
  164. data/examples/18_rails/app/jobs/robot_run_job.rb +0 -25
  165. data/examples/18_rails/app/models/application_record.rb +0 -5
  166. data/examples/18_rails/app/models/robot_lab_result.rb +0 -36
  167. data/examples/18_rails/app/models/robot_lab_thread.rb +0 -23
  168. data/examples/18_rails/app/robots/chat_robot.rb +0 -25
  169. data/examples/18_rails/app/tools/time_tool.rb +0 -9
  170. data/examples/18_rails/app/views/chat/_user_message.html.erb +0 -1
  171. data/examples/18_rails/app/views/chat/index.html.erb +0 -67
  172. data/examples/18_rails/app/views/layouts/application.html.erb +0 -49
  173. data/examples/18_rails/bin/dev +0 -7
  174. data/examples/18_rails/bin/rails +0 -6
  175. data/examples/18_rails/bin/setup +0 -15
  176. data/examples/18_rails/config/application.rb +0 -33
  177. data/examples/18_rails/config/cable.yml +0 -2
  178. data/examples/18_rails/config/database.yml +0 -5
  179. data/examples/18_rails/config/environment.rb +0 -4
  180. data/examples/18_rails/config/initializers/robot_lab.rb +0 -11
  181. data/examples/18_rails/config/routes.rb +0 -6
  182. data/examples/18_rails/config.ru +0 -4
  183. data/examples/18_rails/db/migrate/001_create_robot_lab_tables.rb +0 -32
  184. data/examples/19_token_tracking.rb +0 -138
  185. data/examples/20_circuit_breaker.rb +0 -147
  186. data/examples/21_learning_loop.rb +0 -181
  187. data/examples/22_context_compression.rb +0 -172
  188. data/examples/23_convergence.rb +0 -133
  189. data/examples/24_structured_delegation.rb +0 -151
  190. data/examples/25_history_search/conversation.jsonl +0 -30
  191. data/examples/25_history_search.rb +0 -133
  192. data/examples/26_document_store/api_versioning_adr.md +0 -52
  193. data/examples/26_document_store/incident_postmortem.md +0 -46
  194. data/examples/26_document_store/postgres_runbook.md +0 -49
  195. data/examples/26_document_store/redis_caching_guide.md +0 -48
  196. data/examples/26_document_store/sidekiq_guide.md +0 -51
  197. data/examples/26_document_store.rb +0 -140
  198. data/examples/27_incident_response/README.md +0 -65
  199. data/examples/27_incident_response/incident_response.rb +0 -261
  200. data/examples/28_mcp_discovery.rb +0 -113
  201. data/examples/29_ractor_tools.rb +0 -240
  202. data/examples/30_ractor_network.rb +0 -252
  203. data/examples/31_launch_assessment.rb +0 -246
  204. data/examples/32_newsletter_reader.rb +0 -193
  205. data/examples/33_stock_generator.rb +0 -80
  206. data/examples/33_stock_predictor.rb +0 -327
  207. data/examples/34_agentskills.rb +0 -76
  208. data/examples/35_hooks.rb +0 -266
  209. data/examples/README.md +0 -550
  210. data/examples/common.rb +0 -180
  211. data/examples/prompts/assistant.md +0 -5
  212. data/examples/prompts/audit_trail.md +0 -8
  213. data/examples/prompts/billing.md +0 -10
  214. data/examples/prompts/classifier.md +0 -7
  215. data/examples/prompts/comedian.md +0 -6
  216. data/examples/prompts/comedy_critic.md +0 -10
  217. data/examples/prompts/configurable.md +0 -9
  218. data/examples/prompts/dispatcher.md +0 -12
  219. data/examples/prompts/entity_extractor.md +0 -14
  220. data/examples/prompts/escalation.md +0 -42
  221. data/examples/prompts/frontmatter_mcp_test.md +0 -9
  222. data/examples/prompts/frontmatter_named_test.md +0 -5
  223. data/examples/prompts/frontmatter_tools_test.md +0 -6
  224. data/examples/prompts/general.md +0 -7
  225. data/examples/prompts/github_assistant.md +0 -14
  226. data/examples/prompts/helper.md +0 -4
  227. data/examples/prompts/incident_responder.md +0 -18
  228. data/examples/prompts/keyword_extractor.md +0 -11
  229. data/examples/prompts/llm_config_demo.md +0 -20
  230. data/examples/prompts/order_support.md +0 -35
  231. data/examples/prompts/os_advocate.md +0 -13
  232. data/examples/prompts/os_chief.md +0 -13
  233. data/examples/prompts/os_editor.md +0 -13
  234. data/examples/prompts/parameterized_main_test.md +0 -6
  235. data/examples/prompts/pii_redactor.md +0 -7
  236. data/examples/prompts/product_support.md +0 -37
  237. data/examples/prompts/runbook_protocol.md +0 -12
  238. data/examples/prompts/sentiment_analyzer.md +0 -12
  239. data/examples/prompts/skill_a_test.md +0 -4
  240. data/examples/prompts/skill_b_test.md +0 -4
  241. data/examples/prompts/skill_config_test.md +0 -5
  242. data/examples/prompts/skill_cycle_a_test.md +0 -6
  243. data/examples/prompts/skill_cycle_b_test.md +0 -6
  244. data/examples/prompts/skill_description_test.md +0 -4
  245. data/examples/prompts/skill_leaf_test.md +0 -4
  246. data/examples/prompts/skill_nested_test.md +0 -6
  247. data/examples/prompts/skill_refs_main_test.md +0 -6
  248. data/examples/prompts/skill_self_ref_test.md +0 -6
  249. data/examples/prompts/skill_with_mcp_test.md +0 -9
  250. data/examples/prompts/skill_with_params_test.md +0 -6
  251. data/examples/prompts/skill_with_robot_name_test.md +0 -5
  252. data/examples/prompts/skill_with_tools_test.md +0 -6
  253. data/examples/prompts/sre_compliance.md +0 -10
  254. data/examples/prompts/structured_output.md +0 -7
  255. data/examples/prompts/synthesizer.md +0 -17
  256. data/examples/prompts/technical.md +0 -10
  257. data/examples/prompts/template_with_skills_test.md +0 -6
  258. data/examples/prompts/triage.md +0 -22
  259. data/examples/ruboruby.md +0 -423
  260. data/examples/run_all.rb +0 -60
  261. data/examples/xyzzy.rb +0 -97
  262. data/lib/robot_lab/mcp/client.rb +0 -223
  263. data/lib/robot_lab/mcp/connection_poller.rb +0 -195
  264. data/lib/robot_lab/mcp/transports/base.rb +0 -64
  265. data/lib/robot_lab/mcp/transports/sse.rb +0 -120
  266. data/lib/robot_lab/mcp/transports/stdio.rb +0 -170
  267. data/lib/robot_lab/mcp/transports/streamable_http.rb +0 -141
  268. data/lib/robot_lab/mcp/transports/websocket.rb +0 -111
  269. data/logfile +0 -8
  270. data/mkdocs.yml +0 -209
  271. data/robot_concurrency.md +0 -38
  272. data/simple_acp_review.md +0 -298
  273. data/temp.md +0 -6
  274. data/tool_manifest_plan.md +0 -155
data/docs/guides/index.md DELETED
@@ -1,78 +0,0 @@
1
- # Guides
2
-
3
- Practical guides for building applications with RobotLab.
4
-
5
- ## Getting Started
6
-
7
- If you're new to RobotLab, start here:
8
-
9
- <div class="grid cards" markdown>
10
-
11
- - [:octicons-cpu-24: **Building Robots**](building-robots.md)
12
-
13
- Create specialized AI agents with personalities and tools
14
-
15
- - [:octicons-git-branch-24: **Creating Networks**](creating-networks.md)
16
-
17
- Orchestrate multiple robots for complex workflows
18
-
19
- </div>
20
-
21
- ## Core Features
22
-
23
- <div class="grid cards" markdown>
24
-
25
- - [:octicons-tools-24: **Using Tools**](using-tools.md)
26
-
27
- Give robots custom capabilities to interact with external systems
28
-
29
- - [:octicons-server-24: **MCP Integration**](mcp-integration.md)
30
-
31
- Connect to Model Context Protocol servers
32
-
33
- - [:octicons-broadcast-24: **Streaming Responses**](streaming.md)
34
-
35
- Real-time streaming of LLM responses
36
-
37
- - [:octicons-cpu-24: **Memory System**](memory.md)
38
-
39
- Share data between robots with the memory system
40
-
41
- - [:octicons-pulse-24: **Observability & Safety**](observability.md)
42
-
43
- Token tracking, circuit breakers, doom loop detection, auto compaction, and learning accumulation
44
-
45
- - [:octicons-zap-24: **Hook System**](hooks.md)
46
-
47
- Lifecycle hooks for instrumentation, response caching, extensions, and cross-cutting concerns
48
-
49
- - [:octicons-search-24: **Knowledge & Retrieval**](knowledge.md)
50
-
51
- Chat history search and embedding-based document store for RAG workflows
52
-
53
- </div>
54
-
55
- ## Guide Index
56
-
57
- | Guide | Description | Time |
58
- |-------|-------------|------|
59
- | [Building Robots](building-robots.md) | Create and configure robots | 10 min |
60
- | [Creating Networks](creating-networks.md) | Multi-robot orchestration | 15 min |
61
- | [Using Tools](using-tools.md) | Add custom capabilities | 10 min |
62
- | [MCP Integration](mcp-integration.md) | External tool servers | 10 min |
63
- | [Streaming](streaming.md) | Real-time responses | 5 min |
64
- | [Memory](memory.md) | Shared data store | 5 min |
65
- | [Observability & Safety](observability.md) | Token tracking, circuit breaker, doom loop detection, auto compaction, learning loop | 10 min |
66
- | [Hook System](hooks.md) | Lifecycle hooks, extensions, response caching, instrumentation | 15 min |
67
- | [Knowledge & Retrieval](knowledge.md) | Chat history search and embedding-based document store (RAG) | 10 min |
68
-
69
- ## Extension Gems
70
-
71
- Additional capabilities are available as separate gems:
72
-
73
- | Gem | Description | Docs |
74
- |-----|-------------|------|
75
- | [robot_lab-rails](https://github.com/MadBomber/robot_lab-rails) | Rails generators, background jobs, Turbo Stream broadcasting | [Rails Integration guide](https://github.com/MadBomber/robot_lab-rails/blob/main/docs/guides/rails-integration.md) |
76
- | [robot_lab-ractor](https://github.com/MadBomber/robot_lab-ractor) | True CPU parallelism for tools and robot pipelines via Ruby Ractors | [Ractor Parallelism guide](https://github.com/MadBomber/robot_lab-ractor/blob/main/docs/guides/ractor-parallelism.md) |
77
- | [robot_lab-durable](https://github.com/MadBomber/robot_lab-durable) | Cross-session knowledge persistence with YAML-backed storage | [robot_lab-durable README](https://github.com/MadBomber/robot_lab-durable) |
78
- | [robot_lab-document_store](https://github.com/MadBomber/robot_lab-document_store) | Embedding-based semantic document search via fastembed | [robot_lab-document_store README](https://github.com/MadBomber/robot_lab-document_store) |
@@ -1,219 +0,0 @@
1
- # Knowledge & Retrieval
2
-
3
- Facilities for searching and retrieving knowledge from a robot's history and from external documents:
4
-
5
- - **Chat History Search** — semantic search over accumulated conversation turns
6
- - **Embedding-Based Document Store** — lightweight RAG: store arbitrary text, search by meaning
7
-
8
- ---
9
-
10
- ## Chat History Search
11
-
12
- ### The Problem
13
-
14
- Long-running robots accumulate many conversation turns. When you need to recall what was discussed earlier on a specific topic, re-sending the full history wastes tokens. `search_history` gives you a focused slice of the most relevant past messages without touching the LLM.
15
-
16
- ### robot.search_history
17
-
18
- ```ruby
19
- results = robot.search_history(query, limit: 5)
20
- ```
21
-
22
- Scores every message in the robot's conversation history against `query` using stemmed term-frequency cosine similarity (via the `classifier` gem). Returns up to `limit` `HistoryResult` objects sorted by score descending.
23
-
24
- > [!NOTE]
25
- > **Every** message in `@chat.messages` is scored — there is no role filter.
26
- > Results routinely include the `:system` prompt and raw `:tool` result payloads
27
- > (often JSON) alongside `:user` and `:assistant` turns. Filter by role yourself
28
- > if you only want the conversation:
29
- >
30
- > ```ruby
31
- > hits = robot.search_history(query, limit: 20)
32
- > .select { |r| %i[user assistant].include?(r.role) }
33
- > .first(3)
34
- > ```
35
-
36
- ```ruby
37
- results = robot.search_history("quarterly revenue", limit: 3)
38
-
39
- results.each do |r|
40
- puts "[#{r.role}] score=#{r.score.round(3)} idx=#{r.index}"
41
- puts " #{r.text}"
42
- end
43
- ```
44
-
45
- ### HistoryResult Fields
46
-
47
- | Field | Type | Description |
48
- |-------|------|-------------|
49
- | `text` | String | The message text |
50
- | `role` | Symbol | The message's role — `:user`, `:assistant`, `:system`, or `:tool` |
51
- | `score` | Float (0.0–1.0) | Cosine similarity with the query |
52
- | `index` | Integer | Position in `@chat.messages` |
53
-
54
- ### Typical Scores
55
-
56
- | Relationship | Typical Score |
57
- |---|---|
58
- | Direct answer to the query | 0.50 – 0.80 |
59
- | Same topic, different phrasing | 0.20 – 0.50 |
60
- | Unrelated | < 0.10 |
61
-
62
- ### Short Messages
63
-
64
- Messages shorter than 20 characters are skipped — they produce no meaningful term vector.
65
-
66
- ### Full Example
67
-
68
- ```ruby
69
- robot = RobotLab.build(name: "analyst", system_prompt: "You are a financial analyst.")
70
-
71
- # … after several robot.run() calls …
72
-
73
- hits = robot.search_history("customer acquisition cost")
74
- hits.each { |r| puts "#{r.role} (#{r.score.round(2)}): #{r.text}" }
75
- ```
76
-
77
- ### RAG Pattern — Retrieve Then Generate
78
-
79
- Use `search_history` to inject only the relevant past context into the next call:
80
-
81
- ```ruby
82
- hits = robot.search_history(user_query, limit: 3)
83
- context = hits.map(&:text).join("\n")
84
-
85
- robot.run("Recall context:\n#{context}\n\nNew question: #{user_query}")
86
- ```
87
-
88
- ### Optional Dependency
89
-
90
- `search_history` requires the `classifier` gem:
91
-
92
- ```ruby
93
- gem "classifier", "~> 2.3"
94
- ```
95
-
96
- Without it, calling `search_history` raises `RobotLab::DependencyError` with an install hint.
97
-
98
- ---
99
-
100
- ## Embedding-Based Document Store
101
-
102
- ### The Problem
103
-
104
- Sometimes the knowledge you need isn't in the conversation history — it's in a README, a product spec, a changelog. `store_document` / `search_documents` embed arbitrary text and retrieve the most relevant chunk at query time. Embeddings come from `fastembed` when it is installed, and from a built-in TF-IDF fallback when it is not (see [Embedding Model](#embedding-model)).
105
-
106
- ### memory.store_document / memory.search_documents
107
-
108
- ```ruby
109
- memory.store_document(:readme, File.read("README.md"))
110
- memory.store_document(:changelog, File.read("CHANGELOG.md"))
111
-
112
- hits = memory.search_documents("how to configure redis", limit: 3)
113
- hits.each { |h| puts "#{h[:key]} (#{h[:score].round(3)}): #{h[:text][0..80]}" }
114
- ```
115
-
116
- Each result hash contains:
117
-
118
- | Key | Type | Description |
119
- |-----|------|-------------|
120
- | `:key` | Symbol | The key the document was stored under |
121
- | `:text` | String | The full stored text |
122
- | `:score` | Float (0.0–1.0) | Cosine similarity with the query |
123
-
124
- ### Standalone DocumentStore
125
-
126
- The `Memory` methods delegate to `RobotLab::DocumentStore`, which can also be used directly:
127
-
128
- ```ruby
129
- store = RobotLab::DocumentStore.new
130
- store.store(:doc_a, "Ruby on Rails is a full-stack web framework.")
131
- store.store(:doc_b, "Postgres is an advanced relational database.")
132
-
133
- results = store.search("relational database SQL", limit: 2)
134
- puts results.first[:key] # => :doc_b
135
- ```
136
-
137
- Management methods:
138
-
139
- ```ruby
140
- store.size # => 2
141
- store.keys # => [:doc_a, :doc_b]
142
- store.empty? # => false
143
- store.delete(:doc_a)
144
- store.clear
145
- ```
146
-
147
- ### Embedding Model
148
-
149
- Default: `BAAI/bge-small-en-v1.5` (~23 MB, downloaded on first use, cached in `~/.cache/fastembed/`).
150
-
151
- Documents and queries are embedded asymmetrically: stored text goes through `Fastembed::TextEmbedding#passage_embed`, query text through `#query_embed`. RobotLab does **not** prepend any literal `"passage: "` / `"query: "` string of its own — it hands the raw text to the two methods and lets fastembed handle whatever instruction prefixing the model expects.
152
-
153
- Custom model:
154
-
155
- ```ruby
156
- store = RobotLab::DocumentStore.new(model_name: "BAAI/bge-base-en-v1.5")
157
- ```
158
-
159
- ### TF-IDF Fallback
160
-
161
- `DocumentStore` decides once, at load time, whether `fastembed` is available
162
- (`RobotLab::DocumentStore::FASTEMBED_AVAILABLE`). When it is **not**, the store
163
- still works — it silently falls back to a stemmed, stop-word-filtered,
164
- L2-normalised term-frequency embedder and compares those sparse vectors by
165
- cosine similarity. Nothing is downloaded and everything runs offline, which
166
- makes it convenient for development and CI.
167
-
168
- > [!WARNING]
169
- > The fallback is **lexical, not semantic**. It matches shared word stems only,
170
- > so a query and a document that mean the same thing in different words score
171
- > `0.0`. There is no error, no warning, and no change to the API — only
172
- > noticeably worse results. Check `RobotLab::DocumentStore::FASTEMBED_AVAILABLE`
173
- > if you need to know which path you are on, and note that `model_name:` is
174
- > ignored entirely when it is `false`.
175
-
176
- ### RAG Pattern
177
-
178
- ```ruby
179
- # 1. Index your knowledge base at startup
180
- memory.store_document(:readme, File.read("README.md"))
181
- memory.store_document(:changelog, File.read("CHANGELOG.md"))
182
- memory.store_document(:api_docs, File.read("docs/api.md"))
183
-
184
- # 2. At query time, retrieve the most relevant chunks
185
- hits = memory.search_documents(user_query, limit: 3)
186
- context = hits.map { |h| h[:text] }.join("\n\n")
187
-
188
- # 3. Pass context to your robot
189
- result = robot.run("Use the following context:\n#{context}\n\nQuestion: #{user_query}")
190
- ```
191
-
192
- ### Memory API Summary
193
-
194
- | Method | Description |
195
- |--------|-------------|
196
- | `memory.store_document(key, text)` | Embed and store a document |
197
- | `memory.search_documents(query, limit: 5)` | Search by semantic similarity |
198
- | `memory.document_keys` | List stored keys |
199
- | `memory.delete_document(key)` | Remove a document |
200
-
201
- ### Dependency
202
-
203
- The embedding-based document store requires the [`robot_lab-document_store`](https://github.com/MadBomber/robot_lab-document_store) extension gem. Add it to your Gemfile:
204
-
205
- ```ruby
206
- gem "robot_lab-document_store"
207
- ```
208
-
209
- The gem uses `fastembed` for ONNX-based embeddings when it is installed: the `BAAI/bge-small-en-v1.5` model (~23 MB) is downloaded on first use and cached in `~/.cache/fastembed/`. If `fastembed` cannot be loaded, `DocumentStore` still works via the lexical [TF-IDF fallback](#tf-idf-fallback).
210
-
211
- Without `robot_lab-document_store` itself loaded, calling `memory.store_document`, `memory.search_documents`, `memory.document_keys`, or `memory.delete_document` raises `RobotLab::DependencyError`.
212
-
213
- ---
214
-
215
- ## See Also
216
-
217
- - [Observability Guide](observability.md)
218
- - [examples/25_history_search.rb](https://github.com/MadBomber/robot_lab/blob/main/examples/25_history_search.rb) — Chat History Search
219
- - [examples/26_document_store.rb](https://github.com/MadBomber/robot_lab/blob/main/examples/26_document_store.rb) — Embedding-Based Document Store