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.
- checksums.yaml +4 -4
- data/.github/workflows/deploy-github-pages.yml +9 -9
- data/.irbrc +6 -0
- data/CHANGELOG.md +90 -0
- data/README.md +203 -46
- data/Rakefile +70 -1
- data/docs/api/core/index.md +12 -0
- data/docs/api/core/robot.md +478 -130
- data/docs/api/core/tool.md +205 -209
- data/docs/api/history/active-record-adapter.md +174 -94
- data/docs/api/history/config.md +186 -93
- data/docs/api/history/index.md +57 -61
- data/docs/api/history/thread-manager.md +123 -73
- data/docs/api/mcp/client.md +119 -48
- data/docs/api/mcp/index.md +75 -60
- data/docs/api/mcp/server.md +120 -136
- data/docs/api/mcp/transports.md +172 -184
- data/docs/api/streaming/context.md +157 -74
- data/docs/api/streaming/events.md +114 -166
- data/docs/api/streaming/index.md +74 -72
- data/docs/architecture/core-concepts.md +361 -112
- data/docs/architecture/index.md +97 -59
- data/docs/architecture/message-flow.md +138 -129
- data/docs/architecture/network-orchestration.md +197 -50
- data/docs/architecture/robot-execution.md +199 -146
- data/docs/architecture/state-management.md +255 -187
- data/docs/concepts.md +312 -48
- data/docs/examples/basic-chat.md +89 -77
- data/docs/examples/index.md +222 -47
- data/docs/examples/mcp-server.md +207 -203
- data/docs/examples/multi-robot-network.md +129 -35
- data/docs/examples/rails-application.md +159 -160
- data/docs/examples/tool-usage.md +295 -204
- data/docs/getting-started/configuration.md +275 -162
- data/docs/getting-started/index.md +1 -1
- data/docs/getting-started/installation.md +22 -13
- data/docs/getting-started/quick-start.md +166 -121
- data/docs/guides/building-robots.md +417 -212
- data/docs/guides/creating-networks.md +94 -24
- data/docs/guides/mcp-integration.md +152 -113
- data/docs/guides/memory.md +220 -164
- data/docs/guides/streaming.md +80 -110
- data/docs/guides/using-tools.md +259 -212
- data/docs/index.md +50 -37
- data/examples/01_simple_robot.rb +6 -9
- data/examples/02_tools.rb +6 -9
- data/examples/03_network.rb +13 -14
- data/examples/04_mcp.rb +5 -8
- data/examples/05_streaming.rb +5 -8
- data/examples/06_prompt_templates.rb +42 -37
- data/examples/07_network_memory.rb +13 -14
- data/examples/08_llm_config.rb +140 -0
- data/examples/09_chaining.rb +223 -0
- data/examples/10_memory.rb +331 -0
- data/examples/11_network_introspection.rb +230 -0
- data/examples/12_message_bus.rb +74 -0
- data/examples/13_spawn.rb +90 -0
- data/examples/14_rusty_circuit/comic.rb +143 -0
- data/examples/14_rusty_circuit/display.rb +203 -0
- data/examples/14_rusty_circuit/heckler.rb +57 -0
- data/examples/14_rusty_circuit/open_mic.rb +121 -0
- data/examples/14_rusty_circuit/prompts/open_mic_comic.md +20 -0
- data/examples/14_rusty_circuit/prompts/open_mic_heckler.md +23 -0
- data/examples/14_rusty_circuit/prompts/open_mic_scout.md +20 -0
- data/examples/14_rusty_circuit/scout.rb +173 -0
- data/examples/14_rusty_circuit/scout_notes.md +89 -0
- data/examples/14_rusty_circuit/show.log +234 -0
- data/examples/15_memory_network_and_bus/editor_in_chief.rb +24 -0
- data/examples/15_memory_network_and_bus/editorial_pipeline.rb +206 -0
- data/examples/15_memory_network_and_bus/linux_writer.rb +80 -0
- data/examples/15_memory_network_and_bus/os_editor.rb +46 -0
- data/examples/15_memory_network_and_bus/os_writer.rb +46 -0
- data/examples/15_memory_network_and_bus/output/combined_article.md +13 -0
- data/examples/15_memory_network_and_bus/output/final_article.md +15 -0
- data/examples/15_memory_network_and_bus/output/linux_draft.md +5 -0
- data/examples/15_memory_network_and_bus/output/mac_draft.md +7 -0
- data/examples/15_memory_network_and_bus/output/memory.json +13 -0
- data/examples/15_memory_network_and_bus/output/revision_1.md +19 -0
- data/examples/15_memory_network_and_bus/output/revision_2.md +15 -0
- data/examples/15_memory_network_and_bus/output/windows_draft.md +7 -0
- data/examples/15_memory_network_and_bus/prompts/os_advocate.md +13 -0
- data/examples/15_memory_network_and_bus/prompts/os_chief.md +13 -0
- data/examples/15_memory_network_and_bus/prompts/os_editor.md +13 -0
- data/examples/README.md +197 -0
- data/examples/prompts/{assistant/system.txt.erb → assistant.md} +3 -0
- data/examples/prompts/{billing/system.txt.erb → billing.md} +3 -0
- data/examples/prompts/{classifier/system.txt.erb → classifier.md} +3 -0
- data/examples/prompts/comedian.md +6 -0
- data/examples/prompts/comedy_critic.md +10 -0
- data/examples/prompts/configurable.md +9 -0
- data/examples/prompts/dispatcher.md +12 -0
- data/examples/prompts/{entity_extractor/system.txt.erb → entity_extractor.md} +3 -0
- data/examples/prompts/{escalation/system.txt.erb → escalation.md} +7 -0
- data/examples/prompts/frontmatter_mcp_test.md +9 -0
- data/examples/prompts/frontmatter_named_test.md +5 -0
- data/examples/prompts/frontmatter_tools_test.md +6 -0
- data/examples/prompts/{general/system.txt.erb → general.md} +3 -0
- data/examples/prompts/{github_assistant/system.txt.erb → github_assistant.md} +8 -0
- data/examples/prompts/{helper/system.txt.erb → helper.md} +3 -0
- data/examples/prompts/{keyword_extractor/system.txt.erb → keyword_extractor.md} +3 -0
- data/examples/prompts/llm_config_demo.md +20 -0
- data/examples/prompts/{order_support/system.txt.erb → order_support.md} +8 -0
- data/examples/prompts/os_advocate.md +13 -0
- data/examples/prompts/os_chief.md +13 -0
- data/examples/prompts/os_editor.md +13 -0
- data/examples/prompts/{product_support/system.txt.erb → product_support.md} +7 -0
- data/examples/prompts/{sentiment_analyzer/system.txt.erb → sentiment_analyzer.md} +3 -0
- data/examples/prompts/{synthesizer/system.txt.erb → synthesizer.md} +3 -0
- data/examples/prompts/{technical/system.txt.erb → technical.md} +3 -0
- data/examples/prompts/{triage/system.txt.erb → triage.md} +6 -0
- data/lib/generators/robot_lab/templates/initializer.rb.tt +1 -1
- data/lib/robot_lab/adapters/openai.rb +2 -1
- data/lib/robot_lab/ask_user.rb +75 -0
- data/lib/robot_lab/config/defaults.yml +121 -0
- data/lib/robot_lab/config.rb +183 -0
- data/lib/robot_lab/error.rb +6 -0
- data/lib/robot_lab/mcp/client.rb +1 -1
- data/lib/robot_lab/memory.rb +2 -2
- data/lib/robot_lab/robot.rb +523 -249
- data/lib/robot_lab/robot_message.rb +44 -0
- data/lib/robot_lab/robot_result.rb +1 -0
- data/lib/robot_lab/robotic_model.rb +1 -1
- data/lib/robot_lab/streaming/context.rb +1 -1
- data/lib/robot_lab/tool.rb +108 -172
- data/lib/robot_lab/tool_config.rb +1 -1
- data/lib/robot_lab/tool_manifest.rb +2 -18
- data/lib/robot_lab/version.rb +1 -1
- data/lib/robot_lab.rb +66 -55
- metadata +107 -116
- data/examples/prompts/assistant/user.txt.erb +0 -1
- data/examples/prompts/billing/user.txt.erb +0 -1
- data/examples/prompts/classifier/user.txt.erb +0 -1
- data/examples/prompts/entity_extractor/user.txt.erb +0 -3
- data/examples/prompts/escalation/user.txt.erb +0 -34
- data/examples/prompts/general/user.txt.erb +0 -1
- data/examples/prompts/github_assistant/user.txt.erb +0 -1
- data/examples/prompts/helper/user.txt.erb +0 -1
- data/examples/prompts/keyword_extractor/user.txt.erb +0 -3
- data/examples/prompts/order_support/user.txt.erb +0 -22
- data/examples/prompts/product_support/user.txt.erb +0 -32
- data/examples/prompts/sentiment_analyzer/user.txt.erb +0 -3
- data/examples/prompts/synthesizer/user.txt.erb +0 -15
- data/examples/prompts/technical/user.txt.erb +0 -1
- data/examples/prompts/triage/user.txt.erb +0 -17
- data/lib/robot_lab/configuration.rb +0 -143
|
@@ -2,93 +2,67 @@
|
|
|
2
2
|
|
|
3
3
|
Build your first RobotLab application in 5 minutes.
|
|
4
4
|
|
|
5
|
-
## Step 1:
|
|
5
|
+
## Step 1: Set Up API Keys
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
RobotLab reads configuration from environment variables automatically. Set your API key before running any code:
|
|
8
8
|
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
RobotLab.configure do |config|
|
|
13
|
-
config.anthropic_api_key = ENV["ANTHROPIC_API_KEY"]
|
|
14
|
-
config.default_model = "claude-sonnet-4"
|
|
15
|
-
end
|
|
9
|
+
```bash
|
|
10
|
+
export ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY="sk-ant-..."
|
|
16
11
|
```
|
|
17
12
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
Build a simple assistant robot:
|
|
21
|
-
|
|
22
|
-
```ruby
|
|
23
|
-
assistant = RobotLab.build do
|
|
24
|
-
name "assistant"
|
|
25
|
-
description "A helpful AI assistant"
|
|
13
|
+
Or create a config file at `./config/robot_lab.yml`:
|
|
26
14
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
end
|
|
15
|
+
```yaml
|
|
16
|
+
defaults:
|
|
17
|
+
ruby_llm:
|
|
18
|
+
anthropic_api_key: <%= ENV['ANTHROPIC_API_KEY'] %>
|
|
32
19
|
```
|
|
33
20
|
|
|
34
|
-
|
|
21
|
+
See [Configuration](configuration.md) for all configuration options.
|
|
22
|
+
|
|
23
|
+
## Step 2: Create a Robot
|
|
35
24
|
|
|
36
|
-
|
|
25
|
+
Build a simple assistant robot using keyword arguments:
|
|
37
26
|
|
|
38
27
|
```ruby
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
require "robot_lab"
|
|
29
|
+
|
|
30
|
+
assistant = RobotLab.build(
|
|
31
|
+
name: "assistant",
|
|
32
|
+
system_prompt: "You are a helpful AI assistant. You provide clear, accurate, and concise answers."
|
|
33
|
+
)
|
|
43
34
|
```
|
|
44
35
|
|
|
45
|
-
## Step
|
|
36
|
+
## Step 3: Run It
|
|
46
37
|
|
|
47
|
-
|
|
38
|
+
Send a message and get a response:
|
|
48
39
|
|
|
49
40
|
```ruby
|
|
50
|
-
|
|
51
|
-
state = RobotLab.create_state(message: "What is Ruby on Rails?")
|
|
41
|
+
result = assistant.run("What is Ruby on Rails?")
|
|
52
42
|
|
|
53
|
-
|
|
54
|
-
result = network.run(state: state)
|
|
55
|
-
|
|
56
|
-
# Get the response
|
|
57
|
-
response = result.last_result.output.first.content
|
|
58
|
-
puts response
|
|
43
|
+
puts result.last_text_content
|
|
59
44
|
```
|
|
60
45
|
|
|
46
|
+
The `run` method takes a positional string message and returns a `RobotResult`. Use `last_text_content` to extract the response text.
|
|
47
|
+
|
|
61
48
|
## Complete Example
|
|
62
49
|
|
|
63
|
-
Here
|
|
50
|
+
Here is everything together in one file:
|
|
64
51
|
|
|
65
52
|
```ruby title="hello_robot.rb"
|
|
66
53
|
require "robot_lab"
|
|
67
54
|
|
|
68
|
-
#
|
|
69
|
-
RobotLab.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
# Build robot
|
|
75
|
-
assistant = RobotLab.build do
|
|
76
|
-
name "assistant"
|
|
77
|
-
description "A helpful AI assistant"
|
|
78
|
-
template "You are a helpful AI assistant."
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# Create network
|
|
82
|
-
network = RobotLab.create_network do
|
|
83
|
-
name "hello_network"
|
|
84
|
-
add_robot assistant
|
|
85
|
-
end
|
|
55
|
+
# Build a robot with an inline system prompt
|
|
56
|
+
assistant = RobotLab.build(
|
|
57
|
+
name: "assistant",
|
|
58
|
+
system_prompt: "You are a helpful AI assistant. Be concise and friendly."
|
|
59
|
+
)
|
|
86
60
|
|
|
87
|
-
# Run
|
|
88
|
-
|
|
89
|
-
result = network.run(state: state)
|
|
61
|
+
# Run the robot with a message
|
|
62
|
+
result = assistant.run("Hello! What can you help me with?")
|
|
90
63
|
|
|
91
|
-
|
|
64
|
+
# Print the response
|
|
65
|
+
puts result.last_text_content
|
|
92
66
|
```
|
|
93
67
|
|
|
94
68
|
Run it:
|
|
@@ -97,90 +71,161 @@ Run it:
|
|
|
97
71
|
ruby hello_robot.rb
|
|
98
72
|
```
|
|
99
73
|
|
|
100
|
-
##
|
|
74
|
+
## Using Templates
|
|
75
|
+
|
|
76
|
+
Instead of inline prompts, you can use template files managed by `prompt_manager`. Templates are `.md` files with YAML front matter:
|
|
77
|
+
|
|
78
|
+
```markdown title="prompts/helper.md"
|
|
79
|
+
---
|
|
80
|
+
description: A helpful assistant
|
|
81
|
+
parameters:
|
|
82
|
+
company_name: null
|
|
83
|
+
---
|
|
84
|
+
You are a helpful assistant for <%= company_name %>.
|
|
85
|
+
Be concise and friendly in your responses.
|
|
86
|
+
```
|
|
101
87
|
|
|
102
|
-
|
|
88
|
+
Create the robot with a template reference and context:
|
|
103
89
|
|
|
104
90
|
```ruby
|
|
105
|
-
|
|
106
|
-
name "
|
|
107
|
-
|
|
91
|
+
robot = RobotLab.build(
|
|
92
|
+
name: "helper",
|
|
93
|
+
template: :helper,
|
|
94
|
+
context: { company_name: "Acme Corp" }
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
result = robot.run("What services do you offer?")
|
|
98
|
+
puts result.last_text_content
|
|
99
|
+
```
|
|
108
100
|
|
|
109
|
-
|
|
110
|
-
You are a helpful assistant. Use the current_time tool
|
|
111
|
-
when users ask about the time.
|
|
112
|
-
PROMPT
|
|
101
|
+
Templates are loaded from the `prompts/` directory by default (or `app/prompts/` in Rails). You can change this in your config.
|
|
113
102
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
103
|
+
## Adding a Tool
|
|
104
|
+
|
|
105
|
+
Give your robot custom capabilities by defining a `RubyLLM::Tool` subclass:
|
|
106
|
+
|
|
107
|
+
```ruby title="hello_tools.rb"
|
|
108
|
+
require "robot_lab"
|
|
109
|
+
|
|
110
|
+
class CurrentTime < RubyLLM::Tool
|
|
111
|
+
description "Get the current date and time"
|
|
112
|
+
|
|
113
|
+
param :timezone,
|
|
114
|
+
type: "string",
|
|
115
|
+
desc: "Timezone name (e.g., 'UTC', 'US/Eastern')",
|
|
116
|
+
required: false
|
|
117
|
+
|
|
118
|
+
def execute(timezone: "UTC")
|
|
119
|
+
Time.now.getlocal(timezone_offset(timezone)).strftime("%Y-%m-%d %H:%M:%S %Z")
|
|
120
|
+
rescue => e
|
|
121
|
+
Time.now.utc.strftime("%Y-%m-%d %H:%M:%S UTC")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
private
|
|
125
|
+
|
|
126
|
+
def timezone_offset(tz)
|
|
127
|
+
case tz
|
|
128
|
+
when "UTC" then "+00:00"
|
|
129
|
+
when "US/Eastern" then "-05:00"
|
|
130
|
+
when "US/Pacific" then "-08:00"
|
|
131
|
+
else "+00:00"
|
|
132
|
+
end
|
|
117
133
|
end
|
|
118
134
|
end
|
|
135
|
+
|
|
136
|
+
# Pass tools via the local_tools: parameter
|
|
137
|
+
assistant = RobotLab.build(
|
|
138
|
+
name: "time_bot",
|
|
139
|
+
system_prompt: "You are a helpful assistant. Use the current_time tool when users ask about the time.",
|
|
140
|
+
local_tools: [CurrentTime]
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
result = assistant.run("What time is it right now?")
|
|
144
|
+
puts result.last_text_content
|
|
119
145
|
```
|
|
120
146
|
|
|
121
|
-
|
|
147
|
+
Tools are passed to the robot via the `local_tools:` keyword argument as an array of `RubyLLM::Tool` subclasses.
|
|
122
148
|
|
|
123
|
-
##
|
|
149
|
+
## Method Chaining
|
|
124
150
|
|
|
125
|
-
|
|
151
|
+
Robots support a chaining API for runtime adjustments:
|
|
126
152
|
|
|
127
153
|
```ruby
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
154
|
+
robot = RobotLab.build(name: "writer")
|
|
155
|
+
|
|
156
|
+
result = robot
|
|
157
|
+
.with_instructions("You are a creative fiction writer.")
|
|
158
|
+
.with_temperature(0.9)
|
|
159
|
+
.with_model("claude-sonnet-4")
|
|
160
|
+
.run("Write a haiku about programming.")
|
|
161
|
+
|
|
162
|
+
puts result.last_text_content
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Available chaining methods include `with_instructions`, `with_temperature`, `with_model`, `with_max_tokens`, `with_top_p`, `with_tools`, and more.
|
|
166
|
+
|
|
167
|
+
## Multi-Robot Network
|
|
168
|
+
|
|
169
|
+
Create a pipeline of robots using `RobotLab.create_network`. Networks use `SimpleFlow::Pipeline` under the hood with `task` definitions and dependency tracking:
|
|
170
|
+
|
|
171
|
+
```ruby title="hello_network.rb"
|
|
172
|
+
require "robot_lab"
|
|
173
|
+
|
|
174
|
+
# Build specialized robots
|
|
175
|
+
analyst = RobotLab.build(
|
|
176
|
+
name: "analyst",
|
|
177
|
+
system_prompt: <<~PROMPT
|
|
178
|
+
You are a text analyst. Analyze the given text and provide a brief
|
|
179
|
+
summary of its key themes and sentiment. Be concise -- 2-3 sentences max.
|
|
139
180
|
PROMPT
|
|
140
|
-
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
writer = RobotLab.build(
|
|
184
|
+
name: "writer",
|
|
185
|
+
system_prompt: <<~PROMPT
|
|
186
|
+
You are a professional copywriter. Based on the analysis you receive,
|
|
187
|
+
write a short, engaging summary suitable for a newsletter. Keep it
|
|
188
|
+
to one paragraph.
|
|
189
|
+
PROMPT
|
|
190
|
+
)
|
|
141
191
|
|
|
142
|
-
#
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
template "You answer general knowledge questions accurately."
|
|
192
|
+
# Create a sequential pipeline
|
|
193
|
+
network = RobotLab.create_network(name: "content_pipeline") do
|
|
194
|
+
task :analyst, analyst, depends_on: :none
|
|
195
|
+
task :writer, writer, depends_on: [:analyst]
|
|
147
196
|
end
|
|
148
197
|
|
|
149
|
-
#
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
198
|
+
# Run the network
|
|
199
|
+
result = network.run(
|
|
200
|
+
message: "Ruby 3.4 was released with significant performance improvements..."
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# The final result is from the last robot in the pipeline
|
|
204
|
+
if result.value.is_a?(RobotLab::RobotResult)
|
|
205
|
+
puts result.value.last_text_content
|
|
154
206
|
end
|
|
155
207
|
|
|
156
|
-
#
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
add_robot classifier
|
|
160
|
-
add_robot answerer
|
|
161
|
-
add_robot calculator
|
|
162
|
-
|
|
163
|
-
router ->(args) {
|
|
164
|
-
case args.call_count
|
|
165
|
-
when 0
|
|
166
|
-
:classifier
|
|
167
|
-
when 1
|
|
168
|
-
result = args.last_result&.output&.first&.content&.strip
|
|
169
|
-
case result
|
|
170
|
-
when "QUESTION" then :answerer
|
|
171
|
-
when "MATH" then :calculator
|
|
172
|
-
else :answerer
|
|
173
|
-
end
|
|
174
|
-
else
|
|
175
|
-
nil
|
|
176
|
-
end
|
|
177
|
-
}
|
|
208
|
+
# Access intermediate results by task name
|
|
209
|
+
if result.context[:analyst]
|
|
210
|
+
puts "\nAnalysis: #{result.context[:analyst].last_text_content}"
|
|
178
211
|
end
|
|
179
212
|
```
|
|
180
213
|
|
|
214
|
+
### Network Task Dependencies
|
|
215
|
+
|
|
216
|
+
Tasks declare their dependencies to control execution order:
|
|
217
|
+
|
|
218
|
+
| Dependency | Meaning |
|
|
219
|
+
|-----------|---------|
|
|
220
|
+
| `depends_on: :none` | Entry point -- runs first with no dependencies |
|
|
221
|
+
| `depends_on: [:task_name]` | Runs after the named task(s) complete |
|
|
222
|
+
| `depends_on: :optional` | Only runs if explicitly activated by a preceding task |
|
|
223
|
+
|
|
224
|
+
Tasks with non-overlapping dependencies can execute in parallel automatically.
|
|
225
|
+
|
|
181
226
|
## What's Next?
|
|
182
227
|
|
|
183
|
-
You
|
|
228
|
+
You have built your first RobotLab application. Here is where to go next:
|
|
184
229
|
|
|
185
230
|
<div class="grid cards" markdown>
|
|
186
231
|
|