robot_lab 0.0.1 → 0.0.4

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 (145) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/deploy-github-pages.yml +9 -9
  3. data/.irbrc +6 -0
  4. data/CHANGELOG.md +90 -0
  5. data/README.md +203 -46
  6. data/Rakefile +70 -1
  7. data/docs/api/core/index.md +12 -0
  8. data/docs/api/core/robot.md +478 -130
  9. data/docs/api/core/tool.md +205 -209
  10. data/docs/api/history/active-record-adapter.md +174 -94
  11. data/docs/api/history/config.md +186 -93
  12. data/docs/api/history/index.md +57 -61
  13. data/docs/api/history/thread-manager.md +123 -73
  14. data/docs/api/mcp/client.md +119 -48
  15. data/docs/api/mcp/index.md +75 -60
  16. data/docs/api/mcp/server.md +120 -136
  17. data/docs/api/mcp/transports.md +172 -184
  18. data/docs/api/streaming/context.md +157 -74
  19. data/docs/api/streaming/events.md +114 -166
  20. data/docs/api/streaming/index.md +74 -72
  21. data/docs/architecture/core-concepts.md +361 -112
  22. data/docs/architecture/index.md +97 -59
  23. data/docs/architecture/message-flow.md +138 -129
  24. data/docs/architecture/network-orchestration.md +197 -50
  25. data/docs/architecture/robot-execution.md +199 -146
  26. data/docs/architecture/state-management.md +255 -187
  27. data/docs/concepts.md +312 -48
  28. data/docs/examples/basic-chat.md +89 -77
  29. data/docs/examples/index.md +222 -47
  30. data/docs/examples/mcp-server.md +207 -203
  31. data/docs/examples/multi-robot-network.md +129 -35
  32. data/docs/examples/rails-application.md +159 -160
  33. data/docs/examples/tool-usage.md +295 -204
  34. data/docs/getting-started/configuration.md +275 -162
  35. data/docs/getting-started/index.md +1 -1
  36. data/docs/getting-started/installation.md +22 -13
  37. data/docs/getting-started/quick-start.md +166 -121
  38. data/docs/guides/building-robots.md +417 -212
  39. data/docs/guides/creating-networks.md +94 -24
  40. data/docs/guides/mcp-integration.md +152 -113
  41. data/docs/guides/memory.md +220 -164
  42. data/docs/guides/streaming.md +80 -110
  43. data/docs/guides/using-tools.md +259 -212
  44. data/docs/index.md +50 -37
  45. data/examples/01_simple_robot.rb +6 -9
  46. data/examples/02_tools.rb +6 -9
  47. data/examples/03_network.rb +13 -14
  48. data/examples/04_mcp.rb +5 -8
  49. data/examples/05_streaming.rb +5 -8
  50. data/examples/06_prompt_templates.rb +42 -37
  51. data/examples/07_network_memory.rb +13 -14
  52. data/examples/08_llm_config.rb +140 -0
  53. data/examples/09_chaining.rb +223 -0
  54. data/examples/10_memory.rb +331 -0
  55. data/examples/11_network_introspection.rb +230 -0
  56. data/examples/12_message_bus.rb +74 -0
  57. data/examples/13_spawn.rb +90 -0
  58. data/examples/14_rusty_circuit/comic.rb +143 -0
  59. data/examples/14_rusty_circuit/display.rb +203 -0
  60. data/examples/14_rusty_circuit/heckler.rb +57 -0
  61. data/examples/14_rusty_circuit/open_mic.rb +121 -0
  62. data/examples/14_rusty_circuit/prompts/open_mic_comic.md +20 -0
  63. data/examples/14_rusty_circuit/prompts/open_mic_heckler.md +23 -0
  64. data/examples/14_rusty_circuit/prompts/open_mic_scout.md +20 -0
  65. data/examples/14_rusty_circuit/scout.rb +173 -0
  66. data/examples/14_rusty_circuit/scout_notes.md +89 -0
  67. data/examples/14_rusty_circuit/show.log +234 -0
  68. data/examples/15_memory_network_and_bus/editor_in_chief.rb +24 -0
  69. data/examples/15_memory_network_and_bus/editorial_pipeline.rb +206 -0
  70. data/examples/15_memory_network_and_bus/linux_writer.rb +80 -0
  71. data/examples/15_memory_network_and_bus/os_editor.rb +46 -0
  72. data/examples/15_memory_network_and_bus/os_writer.rb +46 -0
  73. data/examples/15_memory_network_and_bus/output/combined_article.md +13 -0
  74. data/examples/15_memory_network_and_bus/output/final_article.md +15 -0
  75. data/examples/15_memory_network_and_bus/output/linux_draft.md +5 -0
  76. data/examples/15_memory_network_and_bus/output/mac_draft.md +7 -0
  77. data/examples/15_memory_network_and_bus/output/memory.json +13 -0
  78. data/examples/15_memory_network_and_bus/output/revision_1.md +19 -0
  79. data/examples/15_memory_network_and_bus/output/revision_2.md +15 -0
  80. data/examples/15_memory_network_and_bus/output/windows_draft.md +7 -0
  81. data/examples/15_memory_network_and_bus/prompts/os_advocate.md +13 -0
  82. data/examples/15_memory_network_and_bus/prompts/os_chief.md +13 -0
  83. data/examples/15_memory_network_and_bus/prompts/os_editor.md +13 -0
  84. data/examples/README.md +197 -0
  85. data/examples/prompts/{assistant/system.txt.erb → assistant.md} +3 -0
  86. data/examples/prompts/{billing/system.txt.erb → billing.md} +3 -0
  87. data/examples/prompts/{classifier/system.txt.erb → classifier.md} +3 -0
  88. data/examples/prompts/comedian.md +6 -0
  89. data/examples/prompts/comedy_critic.md +10 -0
  90. data/examples/prompts/configurable.md +9 -0
  91. data/examples/prompts/dispatcher.md +12 -0
  92. data/examples/prompts/{entity_extractor/system.txt.erb → entity_extractor.md} +3 -0
  93. data/examples/prompts/{escalation/system.txt.erb → escalation.md} +7 -0
  94. data/examples/prompts/frontmatter_mcp_test.md +9 -0
  95. data/examples/prompts/frontmatter_named_test.md +5 -0
  96. data/examples/prompts/frontmatter_tools_test.md +6 -0
  97. data/examples/prompts/{general/system.txt.erb → general.md} +3 -0
  98. data/examples/prompts/{github_assistant/system.txt.erb → github_assistant.md} +8 -0
  99. data/examples/prompts/{helper/system.txt.erb → helper.md} +3 -0
  100. data/examples/prompts/{keyword_extractor/system.txt.erb → keyword_extractor.md} +3 -0
  101. data/examples/prompts/llm_config_demo.md +20 -0
  102. data/examples/prompts/{order_support/system.txt.erb → order_support.md} +8 -0
  103. data/examples/prompts/os_advocate.md +13 -0
  104. data/examples/prompts/os_chief.md +13 -0
  105. data/examples/prompts/os_editor.md +13 -0
  106. data/examples/prompts/{product_support/system.txt.erb → product_support.md} +7 -0
  107. data/examples/prompts/{sentiment_analyzer/system.txt.erb → sentiment_analyzer.md} +3 -0
  108. data/examples/prompts/{synthesizer/system.txt.erb → synthesizer.md} +3 -0
  109. data/examples/prompts/{technical/system.txt.erb → technical.md} +3 -0
  110. data/examples/prompts/{triage/system.txt.erb → triage.md} +6 -0
  111. data/lib/generators/robot_lab/templates/initializer.rb.tt +1 -1
  112. data/lib/robot_lab/adapters/openai.rb +2 -1
  113. data/lib/robot_lab/ask_user.rb +75 -0
  114. data/lib/robot_lab/config/defaults.yml +121 -0
  115. data/lib/robot_lab/config.rb +183 -0
  116. data/lib/robot_lab/error.rb +6 -0
  117. data/lib/robot_lab/mcp/client.rb +1 -1
  118. data/lib/robot_lab/memory.rb +2 -2
  119. data/lib/robot_lab/robot.rb +523 -249
  120. data/lib/robot_lab/robot_message.rb +44 -0
  121. data/lib/robot_lab/robot_result.rb +1 -0
  122. data/lib/robot_lab/robotic_model.rb +1 -1
  123. data/lib/robot_lab/streaming/context.rb +1 -1
  124. data/lib/robot_lab/tool.rb +108 -172
  125. data/lib/robot_lab/tool_config.rb +1 -1
  126. data/lib/robot_lab/tool_manifest.rb +2 -18
  127. data/lib/robot_lab/version.rb +1 -1
  128. data/lib/robot_lab.rb +66 -55
  129. metadata +107 -116
  130. data/examples/prompts/assistant/user.txt.erb +0 -1
  131. data/examples/prompts/billing/user.txt.erb +0 -1
  132. data/examples/prompts/classifier/user.txt.erb +0 -1
  133. data/examples/prompts/entity_extractor/user.txt.erb +0 -3
  134. data/examples/prompts/escalation/user.txt.erb +0 -34
  135. data/examples/prompts/general/user.txt.erb +0 -1
  136. data/examples/prompts/github_assistant/user.txt.erb +0 -1
  137. data/examples/prompts/helper/user.txt.erb +0 -1
  138. data/examples/prompts/keyword_extractor/user.txt.erb +0 -3
  139. data/examples/prompts/order_support/user.txt.erb +0 -22
  140. data/examples/prompts/product_support/user.txt.erb +0 -32
  141. data/examples/prompts/sentiment_analyzer/user.txt.erb +0 -3
  142. data/examples/prompts/synthesizer/user.txt.erb +0 -15
  143. data/examples/prompts/technical/user.txt.erb +0 -1
  144. data/examples/prompts/triage/user.txt.erb +0 -17
  145. data/lib/robot_lab/configuration.rb +0 -143
@@ -1,226 +1,339 @@
1
1
  # Configuration
2
2
 
3
- RobotLab provides flexible configuration options at global, network, and robot levels.
3
+ RobotLab uses a layered configuration system powered by [MywayConfig](https://github.com/MadBomber/myway_config). Configuration is loaded automatically from multiple sources with no block-style `configure` method required.
4
4
 
5
- ## Global Configuration
5
+ ## How Configuration Works
6
6
 
7
- Configure RobotLab globally using the `configure` block:
7
+ Configuration values are loaded in priority order (lowest to highest):
8
8
 
9
- ```ruby
10
- RobotLab.configure do |config|
11
- # LLM Provider API Keys
12
- config.anthropic_api_key = ENV["ANTHROPIC_API_KEY"]
13
- config.openai_api_key = ENV["OPENAI_API_KEY"]
14
- config.gemini_api_key = ENV["GEMINI_API_KEY"]
9
+ 1. **Bundled defaults** -- `lib/robot_lab/config/defaults.yml` (shipped with the gem)
10
+ 2. **Environment-specific overrides** -- `development`, `test`, or `production` sections in defaults.yml
11
+ 3. **User config file** -- `~/.config/robot_lab/config.yml`
12
+ 4. **Project config file** -- `./config/robot_lab.yml`
13
+ 5. **Environment variables** -- `ROBOT_LAB_*` prefix
14
+ 6. **Runtime attributes** -- e.g., `RobotLab.config.logger = ...`
15
+
16
+ Higher-priority sources override lower-priority ones. You only need to set the values you want to change.
17
+
18
+ ## Accessing Configuration
19
+
20
+ Use `RobotLab.config` to access the configuration object:
15
21
 
16
- # Default settings
17
- config.default_provider = :anthropic
18
- config.default_model = "claude-sonnet-4"
22
+ ```ruby
23
+ # Access nested values with dot notation
24
+ RobotLab.config.ruby_llm.model #=> "claude-sonnet-4"
25
+ RobotLab.config.ruby_llm.anthropic_api_key #=> "sk-ant-..."
26
+ RobotLab.config.ruby_llm.request_timeout #=> 120
27
+ RobotLab.config.max_iterations #=> 10
28
+ RobotLab.config.streaming_enabled #=> true
29
+
30
+ # Check the environment
31
+ RobotLab.config.development? #=> true/false
32
+ ```
19
33
 
20
- # Execution limits
21
- config.max_iterations = 10 # Max robots per network run
22
- config.max_tool_iterations = 10 # Max tool calls per robot run
34
+ !!! warning "No configure block"
35
+ RobotLab does **not** use a `RobotLab.configure do |config| ... end` pattern. All configuration comes from config files, environment variables, or direct assignment on `RobotLab.config`.
23
36
 
24
- # Streaming
25
- config.streaming_enabled = true
37
+ ## Environment Variables
26
38
 
27
- # Logging
28
- config.logger = Logger.new($stdout)
39
+ Environment variables use the `ROBOT_LAB_` prefix. Use double underscores (`__`) for nested values:
29
40
 
30
- # Template path for prompt files
31
- config.template_path = "prompts"
32
- end
41
+ ```bash
42
+ # Top-level settings
43
+ export ROBOT_LAB_MAX_ITERATIONS=20
44
+ export ROBOT_LAB_STREAMING_ENABLED=false
45
+
46
+ # Nested ruby_llm settings (note the double underscore)
47
+ export ROBOT_LAB_RUBY_LLM__MODEL=claude-sonnet-4
48
+ export ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY=sk-ant-...
49
+ export ROBOT_LAB_RUBY_LLM__OPENAI_API_KEY=sk-...
50
+ export ROBOT_LAB_RUBY_LLM__GEMINI_API_KEY=...
51
+ export ROBOT_LAB_RUBY_LLM__REQUEST_TIMEOUT=180
52
+ export ROBOT_LAB_RUBY_LLM__MAX_RETRIES=5
33
53
  ```
34
54
 
35
- ## Configuration Options
55
+ The double underscore convention maps to nested YAML structure:
36
56
 
37
- ### API Keys
57
+ ```
58
+ ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY --> ruby_llm.anthropic_api_key
59
+ ROBOT_LAB_RUBY_LLM__MODEL --> ruby_llm.model
60
+ ROBOT_LAB_MAX_ITERATIONS --> max_iterations
61
+ ```
38
62
 
39
- | Option | Description |
40
- |--------|-------------|
41
- | `anthropic_api_key` | Anthropic Claude API key |
42
- | `openai_api_key` | OpenAI API key |
43
- | `gemini_api_key` | Google Gemini API key |
44
- | `bedrock_api_key` | AWS Bedrock API key |
45
- | `openrouter_api_key` | OpenRouter API key |
63
+ ## Config Files
46
64
 
47
- ### Defaults
65
+ ### Project Config
48
66
 
49
- | Option | Default | Description |
50
- |--------|---------|-------------|
51
- | `default_provider` | `:anthropic` | Default LLM provider |
52
- | `default_model` | `"claude-sonnet-4"` | Default model |
53
- | `max_iterations` | `10` | Max robots per network run |
54
- | `max_tool_iterations` | `10` | Max tool calls per robot |
55
- | `streaming_enabled` | `true` | Enable streaming by default |
67
+ Create `./config/robot_lab.yml` in your project root:
56
68
 
57
- ### Templates
69
+ ```yaml title="config/robot_lab.yml"
70
+ defaults:
71
+ ruby_llm:
72
+ anthropic_api_key: <%= ENV['ANTHROPIC_API_KEY'] %>
73
+ model: claude-sonnet-4
74
+ request_timeout: 120
58
75
 
59
- | Option | Default | Description |
60
- |--------|---------|-------------|
61
- | `template_path` | `"prompts"` (or `"app/prompts"` in Rails) | Directory for prompt templates |
76
+ max_iterations: 15
77
+ template_path: prompts
62
78
 
63
- ### Global MCP & Tools
79
+ development:
80
+ ruby_llm:
81
+ log_level: :debug
64
82
 
65
- ```ruby
66
- RobotLab.configure do |config|
67
- # Global MCP servers available to all networks
68
- config.mcp = [
69
- { name: "github", transport: { type: "stdio", command: "github-mcp" } }
70
- ]
71
-
72
- # Global tool whitelist
73
- config.tools = %w[search_code create_issue]
74
- end
83
+ test:
84
+ max_iterations: 3
85
+ streaming_enabled: false
86
+ ruby_llm:
87
+ model: claude-haiku-3-5
88
+ request_timeout: 30
89
+ max_retries: 1
90
+
91
+ production:
92
+ max_iterations: 20
93
+ ruby_llm:
94
+ request_timeout: 180
95
+ max_retries: 5
96
+ log_level: :warn
75
97
  ```
76
98
 
77
- ## Network-Level Configuration
99
+ !!! tip "ERB support"
100
+ Config files support ERB templating, so you can reference environment variables with `<%= ENV['...'] %>`. This is useful for keeping secrets out of config files while still using YAML structure.
78
101
 
79
- Override global settings at the network level:
102
+ ### User Config
80
103
 
81
- ```ruby
82
- network = RobotLab.create_network do
83
- name "my_network"
104
+ Create `~/.config/robot_lab/config.yml` for personal defaults that apply across all your projects:
84
105
 
85
- # Override default model for this network
86
- default_model "claude-sonnet-4"
106
+ ```yaml title="~/.config/robot_lab/config.yml"
107
+ defaults:
108
+ ruby_llm:
109
+ anthropic_api_key: <%= ENV['ANTHROPIC_API_KEY'] %>
110
+ model: claude-sonnet-4
111
+ ```
87
112
 
88
- # Network-specific MCP servers
89
- mcp [
90
- { name: "filesystem", transport: { type: "stdio", command: "mcp-fs" } }
91
- ]
113
+ ## Configuration Reference
92
114
 
93
- # Network-specific tool whitelist
94
- tools %w[read_file write_file]
115
+ ### Core Settings
95
116
 
96
- # Or inherit from global
97
- mcp :inherit
98
- tools :inherit
99
- end
117
+ | Key | Default | Description |
118
+ |-----|---------|-------------|
119
+ | `max_iterations` | `10` | Maximum robots per network run |
120
+ | `max_tool_iterations` | `10` | Maximum tool calls per robot run |
121
+ | `streaming_enabled` | `true` | Enable streaming by default |
122
+ | `template_path` | `null` (auto-detected) | Directory for prompt templates |
123
+ | `mcp` | `:none` | Global MCP server configuration |
124
+ | `tools` | `:none` | Global tool whitelist |
125
+
126
+ ### RubyLLM Settings (`ruby_llm:` section)
127
+
128
+ All settings under the `ruby_llm:` key are applied to `RubyLLM.configure` automatically on startup.
129
+
130
+ #### Provider API Keys
131
+
132
+ | Key | Description |
133
+ |-----|-------------|
134
+ | `ruby_llm.anthropic_api_key` | Anthropic Claude API key |
135
+ | `ruby_llm.openai_api_key` | OpenAI API key |
136
+ | `ruby_llm.gemini_api_key` | Google Gemini API key |
137
+ | `ruby_llm.deepseek_api_key` | DeepSeek API key |
138
+ | `ruby_llm.mistral_api_key` | Mistral API key |
139
+ | `ruby_llm.openrouter_api_key` | OpenRouter API key |
140
+ | `ruby_llm.bedrock_api_key` | AWS Bedrock access key |
141
+ | `ruby_llm.bedrock_secret_key` | AWS Bedrock secret key |
142
+ | `ruby_llm.bedrock_region` | AWS Bedrock region |
143
+ | `ruby_llm.xai_api_key` | xAI (Grok) API key |
144
+
145
+ #### Model Defaults
146
+
147
+ | Key | Default | Description |
148
+ |-----|---------|-------------|
149
+ | `ruby_llm.provider` | `:anthropic` | Default LLM provider |
150
+ | `ruby_llm.model` | `claude-sonnet-4` | Default model for robots |
151
+ | `ruby_llm.default_model` | `null` | RubyLLM default model override |
152
+ | `ruby_llm.default_embedding_model` | `null` | Default embedding model |
153
+ | `ruby_llm.default_image_model` | `null` | Default image model |
154
+
155
+ #### Connection Settings
156
+
157
+ | Key | Default | Description |
158
+ |-----|---------|-------------|
159
+ | `ruby_llm.request_timeout` | `120` | Request timeout in seconds |
160
+ | `ruby_llm.max_retries` | `3` | Maximum retry attempts |
161
+ | `ruby_llm.retry_interval` | `1` | Seconds between retries |
162
+ | `ruby_llm.retry_backoff_factor` | `2` | Exponential backoff factor |
163
+ | `ruby_llm.http_proxy` | `null` | HTTP proxy URL |
164
+
165
+ #### Provider Endpoints (self-hosted models)
166
+
167
+ | Key | Description |
168
+ |-----|-------------|
169
+ | `ruby_llm.openai_api_base` | Custom OpenAI-compatible endpoint |
170
+ | `ruby_llm.gemini_api_base` | Custom Gemini endpoint |
171
+ | `ruby_llm.ollama_api_base` | Ollama endpoint (e.g., `http://localhost:11434`) |
172
+ | `ruby_llm.gpustack_api_base` | GPUStack endpoint |
173
+
174
+ #### Logging
175
+
176
+ | Key | Default | Description |
177
+ |-----|---------|-------------|
178
+ | `ruby_llm.log_file` | `null` | Path to log file |
179
+ | `ruby_llm.log_level` | `:info` | Log level (`:debug`, `:info`, `:warn`, `:error`) |
180
+ | `ruby_llm.log_stream_debug` | `false` | Log streaming debug output |
181
+
182
+ ### Chat Configuration (`chat:` section)
183
+
184
+ Default chat parameters applied to all robots unless overridden:
185
+
186
+ | Key | Default | Description |
187
+ |-----|---------|-------------|
188
+ | `chat.with_temperature` | `0.7` | Controls randomness (0.0-2.0) |
189
+ | `chat.with_params.top_p` | `null` | Nucleus sampling threshold |
190
+ | `chat.with_params.top_k` | `null` | Top-k sampling |
191
+ | `chat.with_params.max_tokens` | `null` | Maximum tokens in response |
192
+ | `chat.with_params.presence_penalty` | `null` | Presence penalty (-2.0 to 2.0) |
193
+ | `chat.with_params.frequency_penalty` | `null` | Frequency penalty (-2.0 to 2.0) |
194
+ | `chat.with_params.stop` | `null` | Stop sequences |
195
+
196
+ ## Runtime-Only Attributes
197
+
198
+ Some attributes can only be set at runtime, not through config files:
199
+
200
+ ```ruby
201
+ # Logger (defaults to Rails.logger in Rails, or Logger.new($stdout) otherwise)
202
+ RobotLab.config.logger = Logger.new(nil) # silence logging
203
+ RobotLab.config.logger = Logger.new("robot.log") # log to file
100
204
  ```
101
205
 
102
- ## Robot-Level Configuration
206
+ ## Reloading Configuration
103
207
 
104
- Configure individual robots:
208
+ To reload configuration from all sources:
105
209
 
106
210
  ```ruby
107
- robot = RobotLab.build do
108
- name "specialist"
109
-
110
- # Robot-specific model
111
- model "claude-sonnet-4"
112
-
113
- # Robot-specific MCP (overrides network)
114
- mcp :inherit # Use network's MCP servers
115
- # or
116
- mcp :none # No MCP servers for this robot
117
- # or
118
- mcp [...] # Specific servers
119
-
120
- # Robot-specific tools
121
- tools :inherit # Use network's tools
122
- end
211
+ RobotLab.reload_config!
123
212
  ```
124
213
 
125
- ## Configuration Hierarchy
214
+ This clears the cached config and reloads from all sources on next access.
126
215
 
127
- Configuration cascades from global to network to robot:
216
+ ## Environment-Specific Configuration
128
217
 
129
- ```
130
- Global (RobotLab.configure)
131
- └── Network (create_network)
132
- └── Robot (build)
133
- └── Runtime (robot.run)
134
- ```
218
+ The `defaults.yml` shipped with RobotLab includes environment-specific overrides:
135
219
 
136
- Each level can:
220
+ === "Development"
137
221
 
138
- - `:inherit` - Use parent level's configuration
139
- - `:none` or `nil` or `[]` - No items allowed
140
- - `[items]` - Specific items only
222
+ ```yaml
223
+ development:
224
+ ruby_llm:
225
+ log_level: :debug
226
+ ```
141
227
 
142
- ## Rails Configuration
228
+ === "Test"
143
229
 
144
- In Rails, configure in an initializer:
230
+ ```yaml
231
+ test:
232
+ max_iterations: 3
233
+ streaming_enabled: false
234
+ ruby_llm:
235
+ model: claude-haiku-3-5
236
+ request_timeout: 30
237
+ max_retries: 1
238
+ log_level: :warn
239
+ ```
145
240
 
146
- ```ruby title="config/initializers/robot_lab.rb"
147
- RobotLab.configure do |config|
148
- # Use Rails credentials
149
- config.anthropic_api_key = Rails.application.credentials.anthropic_api_key
241
+ === "Production"
150
242
 
151
- # Use Rails logger
152
- config.logger = Rails.logger
243
+ ```yaml
244
+ production:
245
+ streaming_enabled: false
246
+ max_iterations: 20
247
+ ruby_llm:
248
+ request_timeout: 180
249
+ max_retries: 5
250
+ log_level: :warn
251
+ ```
153
252
 
154
- # Template path is automatically set to app/prompts
155
- end
156
- ```
253
+ The current environment is determined automatically (via `RAILS_ENV`, `RACK_ENV`, or defaults to `development`).
254
+
255
+ ## Rails Integration
157
256
 
158
- Or use `config/application.rb`:
257
+ In Rails, RobotLab is configured automatically via its Railtie. The logger defaults to `Rails.logger`, and templates default to `app/prompts/`.
159
258
 
160
- ```ruby title="config/application.rb"
161
- module MyApp
162
- class Application < Rails::Application
163
- config.robot_lab.default_model = "claude-sonnet-4"
164
- config.robot_lab.default_provider = :anthropic
165
- end
166
- end
259
+ Create a project config file for Rails-specific settings:
260
+
261
+ ```yaml title="config/robot_lab.yml"
262
+ defaults:
263
+ ruby_llm:
264
+ anthropic_api_key: <%= Rails.application.credentials.anthropic_api_key %>
265
+ model: claude-sonnet-4
266
+
267
+ template_path: null # auto-detects app/prompts in Rails
268
+
269
+ production:
270
+ ruby_llm:
271
+ request_timeout: 180
272
+ max_retries: 5
167
273
  ```
168
274
 
169
- ## Environment-Specific Configuration
275
+ You can also use Rails credentials:
170
276
 
171
- ```ruby title="config/initializers/robot_lab.rb"
172
- RobotLab.configure do |config|
173
- config.anthropic_api_key = ENV["ANTHROPIC_API_KEY"]
174
-
175
- case Rails.env
176
- when "development"
177
- config.logger = Logger.new($stdout, level: :debug)
178
- config.default_model = "claude-haiku-3" # Faster/cheaper for dev
179
- when "test"
180
- config.streaming_enabled = false
181
- when "production"
182
- config.logger = Rails.logger
183
- config.default_model = "claude-sonnet-4"
184
- end
185
- end
277
+ ```bash
278
+ rails credentials:edit
186
279
  ```
187
280
 
188
- ## Using Environment Variables
281
+ ```yaml
282
+ # config/credentials.yml.enc
283
+ anthropic_api_key: sk-ant-...
284
+ openai_api_key: sk-...
285
+ ```
189
286
 
190
- Recommended environment variables:
287
+ Then reference them in your config file with ERB:
191
288
 
192
- ```bash
193
- # Required - at least one provider
194
- ANTHROPIC_API_KEY=sk-ant-...
195
- OPENAI_API_KEY=sk-...
196
- GEMINI_API_KEY=...
197
-
198
- # Optional - override defaults
199
- ROBOT_LAB_DEFAULT_MODEL=claude-sonnet-4
200
- ROBOT_LAB_DEFAULT_PROVIDER=anthropic
201
- ROBOT_LAB_MAX_ITERATIONS=20
289
+ ```yaml title="config/robot_lab.yml"
290
+ defaults:
291
+ ruby_llm:
292
+ anthropic_api_key: <%= Rails.application.credentials.anthropic_api_key %>
202
293
  ```
203
294
 
204
- Load them in configuration:
295
+ ## Robot-Level Configuration
296
+
297
+ Individual robots can override the global model and other settings:
205
298
 
206
299
  ```ruby
207
- RobotLab.configure do |config|
208
- config.anthropic_api_key = ENV["ANTHROPIC_API_KEY"]
209
- config.default_model = ENV.fetch("ROBOT_LAB_DEFAULT_MODEL", "claude-sonnet-4")
210
- config.max_iterations = ENV.fetch("ROBOT_LAB_MAX_ITERATIONS", 10).to_i
211
- end
300
+ # Override model for a specific robot
301
+ robot = RobotLab.build(
302
+ name: "fast_bot",
303
+ system_prompt: "You are a quick responder.",
304
+ model: "claude-haiku-3-5",
305
+ temperature: 0.3,
306
+ max_tokens: 500
307
+ )
308
+
309
+ # Or use chaining at runtime
310
+ robot.with_temperature(0.9).with_max_tokens(2000).run("Tell me a story.")
212
311
  ```
213
312
 
214
- ## Accessing Configuration
313
+ ## Hierarchical MCP and Tools
215
314
 
216
- ```ruby
217
- # Get current configuration
218
- config = RobotLab.configuration
315
+ MCP servers and tools use a hierarchical configuration: `runtime > robot > network > global`. Each level can specify:
219
316
 
220
- # Check settings
221
- config.default_model # => "claude-sonnet-4"
222
- config.default_provider # => :anthropic
223
- config.streaming_enabled # => true
317
+ - `:inherit` -- Use the parent level's configuration
318
+ - `:none` -- No MCP servers or tools at this level
319
+ - An explicit array -- Specific servers or tools
320
+
321
+ ```ruby
322
+ # Robot inheriting network MCP config
323
+ robot = RobotLab.build(
324
+ name: "agent",
325
+ system_prompt: "You are helpful.",
326
+ mcp: :inherit,
327
+ tools: :inherit
328
+ )
329
+
330
+ # Robot with no MCP, specific tools
331
+ robot = RobotLab.build(
332
+ name: "calculator",
333
+ system_prompt: "You solve math problems.",
334
+ mcp: :none,
335
+ local_tools: [Calculator]
336
+ )
224
337
  ```
225
338
 
226
339
  ## Next Steps
@@ -15,7 +15,7 @@ In this section, you'll learn how to:
15
15
 
16
16
  Before you begin, make sure you have:
17
17
 
18
- - **Ruby 3.1+** installed
18
+ - **Ruby 3.2+** installed
19
19
  - An **API key** from at least one LLM provider:
20
20
  - [Anthropic](https://console.anthropic.com/) (recommended)
21
21
  - [OpenAI](https://platform.openai.com/)
@@ -4,7 +4,7 @@ This guide covers installing RobotLab in your Ruby project.
4
4
 
5
5
  ## Requirements
6
6
 
7
- - **Ruby**: 3.1 or higher
7
+ - **Ruby**: 3.2 or higher
8
8
  - **Bundler**: 2.0 or higher (recommended)
9
9
 
10
10
  ## Install via Bundler
@@ -31,13 +31,19 @@ gem install robot_lab
31
31
 
32
32
  ## Dependencies
33
33
 
34
- RobotLab automatically installs these dependencies:
34
+ RobotLab automatically installs these core dependencies:
35
35
 
36
36
  | Gem | Purpose |
37
37
  |-----|---------|
38
- | `ruby_llm` | LLM provider integrations |
39
- | `ruby_llm-template` | Template rendering for prompts |
40
- | `simple_flow` | Workflow execution |
38
+ | `ruby_llm` (~> 1.12) | LLM provider integrations (Anthropic, OpenAI, Gemini, etc.) |
39
+ | `prompt_manager` (~> 1.0) | Template-based prompt management with YAML front matter |
40
+ | `simple_flow` (~> 0.3) | Pipeline workflow execution for networks |
41
+ | `myway_config` (~> 0.1) | Layered configuration (defaults, env vars, config files) |
42
+ | `ruby_llm-mcp` | Model Context Protocol client for external tool servers |
43
+ | `ruby_llm-schema` | Schema validation for structured outputs |
44
+ | `ruby_llm-semantic_cache` | Semantic caching for LLM responses |
45
+ | `zeitwerk` (~> 2.6) | Autoloading and eager loading |
46
+ | `async` (~> 2.0) | Fiber-based concurrency |
41
47
 
42
48
  ### Optional Dependencies
43
49
 
@@ -78,7 +84,7 @@ Run it:
78
84
 
79
85
  ```bash
80
86
  ruby test_robot_lab.rb
81
- # => RobotLab version: 0.0.1
87
+ # => RobotLab version: 0.1.0
82
88
  # => Installation successful!
83
89
  ```
84
90
 
@@ -107,24 +113,24 @@ rails db:migrate
107
113
 
108
114
  ## Environment Setup
109
115
 
110
- Before using RobotLab, set up your API keys as environment variables:
116
+ RobotLab uses a layered configuration system (see [Configuration](configuration.md) for full details). The simplest way to get started is with environment variables:
111
117
 
112
118
  === "Anthropic (Recommended)"
113
119
 
114
120
  ```bash
115
- export ANTHROPIC_API_KEY="sk-ant-..."
121
+ export ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY="sk-ant-..."
116
122
  ```
117
123
 
118
124
  === "OpenAI"
119
125
 
120
126
  ```bash
121
- export OPENAI_API_KEY="sk-..."
127
+ export ROBOT_LAB_RUBY_LLM__OPENAI_API_KEY="sk-..."
122
128
  ```
123
129
 
124
130
  === "Google Gemini"
125
131
 
126
132
  ```bash
127
- export GEMINI_API_KEY="..."
133
+ export ROBOT_LAB_RUBY_LLM__GEMINI_API_KEY="..."
128
134
  ```
129
135
 
130
136
  !!! tip "Using dotenv"
@@ -132,14 +138,17 @@ Before using RobotLab, set up your API keys as environment variables:
132
138
 
133
139
  ```ruby
134
140
  # Gemfile
135
- gem "dotenv-rails", groups: [:development, :test]
141
+ gem "dotenv", groups: [:development, :test]
136
142
  ```
137
143
 
138
144
  ```bash
139
145
  # .env
140
- ANTHROPIC_API_KEY=sk-ant-...
146
+ ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY=sk-ant-...
141
147
  ```
142
148
 
149
+ !!! info "Direct provider env vars"
150
+ RubyLLM also reads provider-specific environment variables directly (e.g., `ANTHROPIC_API_KEY`). If you already have those set, they will be picked up automatically. The `ROBOT_LAB_RUBY_LLM__*` prefix gives you explicit control through RobotLab's config layer.
151
+
143
152
  ## Troubleshooting
144
153
 
145
154
  ### Gem Installation Fails
@@ -167,7 +176,7 @@ bundle add async-websocket
167
176
 
168
177
  If you see authentication errors:
169
178
 
170
- 1. Verify your API key is set: `echo $ANTHROPIC_API_KEY`
179
+ 1. Verify your API key is set: `echo $ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY`
171
180
  2. Check the key is valid in your provider's console
172
181
  3. Ensure you're using the correct environment variable name
173
182