robot_lab 0.0.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.
- checksums.yaml +7 -0
- data/.envrc +1 -0
- data/.github/workflows/deploy-github-pages.yml +52 -0
- data/.github/workflows/deploy-yard-docs.yml +52 -0
- data/CHANGELOG.md +55 -0
- data/COMMITS.md +196 -0
- data/LICENSE.txt +21 -0
- data/README.md +332 -0
- data/Rakefile +67 -0
- data/docs/api/adapters/anthropic.md +121 -0
- data/docs/api/adapters/gemini.md +133 -0
- data/docs/api/adapters/index.md +104 -0
- data/docs/api/adapters/openai.md +134 -0
- data/docs/api/core/index.md +113 -0
- data/docs/api/core/memory.md +314 -0
- data/docs/api/core/network.md +291 -0
- data/docs/api/core/robot.md +273 -0
- data/docs/api/core/state.md +273 -0
- data/docs/api/core/tool.md +353 -0
- data/docs/api/history/active-record-adapter.md +195 -0
- data/docs/api/history/config.md +191 -0
- data/docs/api/history/index.md +132 -0
- data/docs/api/history/thread-manager.md +144 -0
- data/docs/api/index.md +82 -0
- data/docs/api/mcp/client.md +221 -0
- data/docs/api/mcp/index.md +111 -0
- data/docs/api/mcp/server.md +225 -0
- data/docs/api/mcp/transports.md +264 -0
- data/docs/api/messages/index.md +67 -0
- data/docs/api/messages/text-message.md +102 -0
- data/docs/api/messages/tool-call-message.md +144 -0
- data/docs/api/messages/tool-result-message.md +154 -0
- data/docs/api/messages/user-message.md +171 -0
- data/docs/api/streaming/context.md +174 -0
- data/docs/api/streaming/events.md +237 -0
- data/docs/api/streaming/index.md +108 -0
- data/docs/architecture/core-concepts.md +243 -0
- data/docs/architecture/index.md +138 -0
- data/docs/architecture/message-flow.md +320 -0
- data/docs/architecture/network-orchestration.md +216 -0
- data/docs/architecture/robot-execution.md +243 -0
- data/docs/architecture/state-management.md +323 -0
- data/docs/assets/css/custom.css +56 -0
- data/docs/assets/images/robot_lab.jpg +0 -0
- data/docs/concepts.md +216 -0
- data/docs/examples/basic-chat.md +193 -0
- data/docs/examples/index.md +129 -0
- data/docs/examples/mcp-server.md +290 -0
- data/docs/examples/multi-robot-network.md +312 -0
- data/docs/examples/rails-application.md +420 -0
- data/docs/examples/tool-usage.md +310 -0
- data/docs/getting-started/configuration.md +230 -0
- data/docs/getting-started/index.md +56 -0
- data/docs/getting-started/installation.md +179 -0
- data/docs/getting-started/quick-start.md +203 -0
- data/docs/guides/building-robots.md +376 -0
- data/docs/guides/creating-networks.md +366 -0
- data/docs/guides/history.md +359 -0
- data/docs/guides/index.md +68 -0
- data/docs/guides/mcp-integration.md +356 -0
- data/docs/guides/memory.md +309 -0
- data/docs/guides/rails-integration.md +432 -0
- data/docs/guides/streaming.md +314 -0
- data/docs/guides/using-tools.md +394 -0
- data/docs/index.md +160 -0
- data/examples/01_simple_robot.rb +38 -0
- data/examples/02_tools.rb +106 -0
- data/examples/03_network.rb +103 -0
- data/examples/04_mcp.rb +219 -0
- data/examples/05_streaming.rb +124 -0
- data/examples/06_prompt_templates.rb +324 -0
- data/examples/07_network_memory.rb +329 -0
- data/examples/prompts/assistant/system.txt.erb +2 -0
- data/examples/prompts/assistant/user.txt.erb +1 -0
- data/examples/prompts/billing/system.txt.erb +7 -0
- data/examples/prompts/billing/user.txt.erb +1 -0
- data/examples/prompts/classifier/system.txt.erb +4 -0
- data/examples/prompts/classifier/user.txt.erb +1 -0
- data/examples/prompts/entity_extractor/system.txt.erb +11 -0
- data/examples/prompts/entity_extractor/user.txt.erb +3 -0
- data/examples/prompts/escalation/system.txt.erb +35 -0
- data/examples/prompts/escalation/user.txt.erb +34 -0
- data/examples/prompts/general/system.txt.erb +4 -0
- data/examples/prompts/general/user.txt.erb +1 -0
- data/examples/prompts/github_assistant/system.txt.erb +6 -0
- data/examples/prompts/github_assistant/user.txt.erb +1 -0
- data/examples/prompts/helper/system.txt.erb +1 -0
- data/examples/prompts/helper/user.txt.erb +1 -0
- data/examples/prompts/keyword_extractor/system.txt.erb +8 -0
- data/examples/prompts/keyword_extractor/user.txt.erb +3 -0
- data/examples/prompts/order_support/system.txt.erb +27 -0
- data/examples/prompts/order_support/user.txt.erb +22 -0
- data/examples/prompts/product_support/system.txt.erb +30 -0
- data/examples/prompts/product_support/user.txt.erb +32 -0
- data/examples/prompts/sentiment_analyzer/system.txt.erb +9 -0
- data/examples/prompts/sentiment_analyzer/user.txt.erb +3 -0
- data/examples/prompts/synthesizer/system.txt.erb +14 -0
- data/examples/prompts/synthesizer/user.txt.erb +15 -0
- data/examples/prompts/technical/system.txt.erb +7 -0
- data/examples/prompts/technical/user.txt.erb +1 -0
- data/examples/prompts/triage/system.txt.erb +16 -0
- data/examples/prompts/triage/user.txt.erb +17 -0
- data/lib/generators/robot_lab/install_generator.rb +78 -0
- data/lib/generators/robot_lab/robot_generator.rb +55 -0
- data/lib/generators/robot_lab/templates/initializer.rb.tt +41 -0
- data/lib/generators/robot_lab/templates/migration.rb.tt +32 -0
- data/lib/generators/robot_lab/templates/result_model.rb.tt +52 -0
- data/lib/generators/robot_lab/templates/robot.rb.tt +46 -0
- data/lib/generators/robot_lab/templates/robot_test.rb.tt +32 -0
- data/lib/generators/robot_lab/templates/routing_robot.rb.tt +53 -0
- data/lib/generators/robot_lab/templates/thread_model.rb.tt +40 -0
- data/lib/robot_lab/adapters/anthropic.rb +163 -0
- data/lib/robot_lab/adapters/base.rb +85 -0
- data/lib/robot_lab/adapters/gemini.rb +193 -0
- data/lib/robot_lab/adapters/openai.rb +159 -0
- data/lib/robot_lab/adapters/registry.rb +81 -0
- data/lib/robot_lab/configuration.rb +143 -0
- data/lib/robot_lab/error.rb +32 -0
- data/lib/robot_lab/errors.rb +70 -0
- data/lib/robot_lab/history/active_record_adapter.rb +146 -0
- data/lib/robot_lab/history/config.rb +115 -0
- data/lib/robot_lab/history/thread_manager.rb +93 -0
- data/lib/robot_lab/mcp/client.rb +210 -0
- data/lib/robot_lab/mcp/server.rb +84 -0
- data/lib/robot_lab/mcp/transports/base.rb +56 -0
- data/lib/robot_lab/mcp/transports/sse.rb +117 -0
- data/lib/robot_lab/mcp/transports/stdio.rb +133 -0
- data/lib/robot_lab/mcp/transports/streamable_http.rb +139 -0
- data/lib/robot_lab/mcp/transports/websocket.rb +108 -0
- data/lib/robot_lab/memory.rb +882 -0
- data/lib/robot_lab/memory_change.rb +123 -0
- data/lib/robot_lab/message.rb +357 -0
- data/lib/robot_lab/network.rb +350 -0
- data/lib/robot_lab/rails/engine.rb +29 -0
- data/lib/robot_lab/rails/railtie.rb +42 -0
- data/lib/robot_lab/robot.rb +560 -0
- data/lib/robot_lab/robot_result.rb +205 -0
- data/lib/robot_lab/robotic_model.rb +324 -0
- data/lib/robot_lab/state_proxy.rb +188 -0
- data/lib/robot_lab/streaming/context.rb +144 -0
- data/lib/robot_lab/streaming/events.rb +95 -0
- data/lib/robot_lab/streaming/sequence_counter.rb +48 -0
- data/lib/robot_lab/task.rb +117 -0
- data/lib/robot_lab/tool.rb +223 -0
- data/lib/robot_lab/tool_config.rb +112 -0
- data/lib/robot_lab/tool_manifest.rb +234 -0
- data/lib/robot_lab/user_message.rb +118 -0
- data/lib/robot_lab/version.rb +5 -0
- data/lib/robot_lab/waiter.rb +73 -0
- data/lib/robot_lab.rb +195 -0
- data/mkdocs.yml +214 -0
- data/sig/robot_lab.rbs +4 -0
- metadata +442 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Basic Chat
|
|
2
|
+
|
|
3
|
+
A simple conversational robot example.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This example demonstrates the minimal setup for a conversational robot that can respond to user messages.
|
|
8
|
+
|
|
9
|
+
## Complete Example
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
#!/usr/bin/env ruby
|
|
13
|
+
# examples/basic_chat.rb
|
|
14
|
+
|
|
15
|
+
require "bundler/setup"
|
|
16
|
+
require "robot_lab"
|
|
17
|
+
|
|
18
|
+
# Configure RobotLab
|
|
19
|
+
RobotLab.configure do |config|
|
|
20
|
+
config.default_model = "claude-sonnet-4"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Build a simple assistant
|
|
24
|
+
assistant = RobotLab.build do
|
|
25
|
+
name "assistant"
|
|
26
|
+
description "A helpful conversational assistant"
|
|
27
|
+
|
|
28
|
+
template <<~PROMPT
|
|
29
|
+
You are a helpful, friendly assistant. You provide clear,
|
|
30
|
+
concise answers to questions. Be conversational but informative.
|
|
31
|
+
PROMPT
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Simple REPL
|
|
35
|
+
puts "Chat with the assistant (type 'quit' to exit)"
|
|
36
|
+
puts "-" * 50
|
|
37
|
+
|
|
38
|
+
loop do
|
|
39
|
+
print "\nYou: "
|
|
40
|
+
input = gets&.chomp
|
|
41
|
+
|
|
42
|
+
break if input.nil? || input.downcase == "quit"
|
|
43
|
+
next if input.empty?
|
|
44
|
+
|
|
45
|
+
# Create state and run
|
|
46
|
+
state = RobotLab.create_state(message: input)
|
|
47
|
+
result = assistant.run(state: state)
|
|
48
|
+
|
|
49
|
+
# Display response
|
|
50
|
+
response = result.output.first&.content || "No response"
|
|
51
|
+
puts "\nAssistant: #{response}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
puts "\nGoodbye!"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## With Streaming
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
#!/usr/bin/env ruby
|
|
61
|
+
# examples/streaming_chat.rb
|
|
62
|
+
|
|
63
|
+
require "bundler/setup"
|
|
64
|
+
require "robot_lab"
|
|
65
|
+
|
|
66
|
+
RobotLab.configure do |config|
|
|
67
|
+
config.default_model = "claude-sonnet-4"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
assistant = RobotLab.build do
|
|
71
|
+
name "assistant"
|
|
72
|
+
template "You are a helpful assistant."
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
puts "Chat with streaming (type 'quit' to exit)"
|
|
76
|
+
puts "-" * 50
|
|
77
|
+
|
|
78
|
+
loop do
|
|
79
|
+
print "\nYou: "
|
|
80
|
+
input = gets&.chomp
|
|
81
|
+
|
|
82
|
+
break if input.nil? || input.downcase == "quit"
|
|
83
|
+
next if input.empty?
|
|
84
|
+
|
|
85
|
+
state = RobotLab.create_state(message: input)
|
|
86
|
+
|
|
87
|
+
print "\nAssistant: "
|
|
88
|
+
assistant.run(state: state) do |event|
|
|
89
|
+
print event.text if event.type == :text_delta
|
|
90
|
+
end
|
|
91
|
+
puts
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
puts "\nGoodbye!"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## With Conversation History
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
#!/usr/bin/env ruby
|
|
101
|
+
# examples/chat_with_memory.rb
|
|
102
|
+
|
|
103
|
+
require "bundler/setup"
|
|
104
|
+
require "robot_lab"
|
|
105
|
+
|
|
106
|
+
RobotLab.configure do |config|
|
|
107
|
+
config.default_model = "claude-sonnet-4"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
assistant = RobotLab.build do
|
|
111
|
+
name "assistant"
|
|
112
|
+
template "You are a helpful assistant with memory of our conversation."
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# In-memory history store
|
|
116
|
+
HISTORY = {}
|
|
117
|
+
|
|
118
|
+
history_config = RobotLab::History::Config.new(
|
|
119
|
+
create_thread: ->(state:, **) {
|
|
120
|
+
id = SecureRandom.uuid
|
|
121
|
+
HISTORY[id] = []
|
|
122
|
+
{ id: id }
|
|
123
|
+
},
|
|
124
|
+
get: ->(thread_id:, **) {
|
|
125
|
+
HISTORY[thread_id] || []
|
|
126
|
+
},
|
|
127
|
+
append_results: ->(thread_id:, new_results:, **) {
|
|
128
|
+
HISTORY[thread_id].concat(new_results.map(&:to_h))
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
network = RobotLab.create_network do
|
|
133
|
+
name "chat"
|
|
134
|
+
history history_config
|
|
135
|
+
add_robot assistant
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
puts "Chat with memory (type 'quit' to exit)"
|
|
139
|
+
puts "-" * 50
|
|
140
|
+
|
|
141
|
+
thread_id = nil
|
|
142
|
+
|
|
143
|
+
loop do
|
|
144
|
+
print "\nYou: "
|
|
145
|
+
input = gets&.chomp
|
|
146
|
+
|
|
147
|
+
break if input.nil? || input.downcase == "quit"
|
|
148
|
+
next if input.empty?
|
|
149
|
+
|
|
150
|
+
message = thread_id ?
|
|
151
|
+
RobotLab::UserMessage.new(input, thread_id: thread_id) :
|
|
152
|
+
input
|
|
153
|
+
|
|
154
|
+
state = RobotLab.create_state(message: message)
|
|
155
|
+
result = network.run(state: state)
|
|
156
|
+
|
|
157
|
+
thread_id ||= result.state.thread_id
|
|
158
|
+
|
|
159
|
+
response = result.last_result&.output&.first&.content || "No response"
|
|
160
|
+
puts "\nAssistant: #{response}"
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
puts "\nGoodbye!"
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Running
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Set API key
|
|
170
|
+
export ANTHROPIC_API_KEY="your-key"
|
|
171
|
+
|
|
172
|
+
# Run basic chat
|
|
173
|
+
ruby examples/basic_chat.rb
|
|
174
|
+
|
|
175
|
+
# Run with streaming
|
|
176
|
+
ruby examples/streaming_chat.rb
|
|
177
|
+
|
|
178
|
+
# Run with memory
|
|
179
|
+
ruby examples/chat_with_memory.rb
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Key Concepts
|
|
183
|
+
|
|
184
|
+
1. **Robot Building**: Use `RobotLab.build` with a template
|
|
185
|
+
2. **State Creation**: Use `RobotLab.create_state` with a message
|
|
186
|
+
3. **Execution**: Call `robot.run(state: state)`
|
|
187
|
+
4. **Response**: Access via `result.output.first.content`
|
|
188
|
+
|
|
189
|
+
## See Also
|
|
190
|
+
|
|
191
|
+
- [Building Robots Guide](../guides/building-robots.md)
|
|
192
|
+
- [Streaming Guide](../guides/streaming.md)
|
|
193
|
+
- [History Guide](../guides/history.md)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
Complete working examples demonstrating RobotLab features.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
These examples show how to use RobotLab for common scenarios, from simple chatbots to complex multi-robot systems.
|
|
8
|
+
|
|
9
|
+
## Examples
|
|
10
|
+
|
|
11
|
+
| Example | Description |
|
|
12
|
+
|---------|-------------|
|
|
13
|
+
| [Basic Chat](basic-chat.md) | Simple conversational robot |
|
|
14
|
+
| [Multi-Robot Network](multi-robot-network.md) | Customer service with routing |
|
|
15
|
+
| [Tool Usage](tool-usage.md) | External API integration |
|
|
16
|
+
| [MCP Server](mcp-server.md) | Creating an MCP tool server |
|
|
17
|
+
| [Rails Application](rails-application.md) | Full Rails integration |
|
|
18
|
+
|
|
19
|
+
## Quick Links
|
|
20
|
+
|
|
21
|
+
### Simple Examples
|
|
22
|
+
|
|
23
|
+
- [Hello World Robot](#hello-world)
|
|
24
|
+
- [Robot with Tools](#robot-with-tools)
|
|
25
|
+
- [Network with Routing](#network-with-routing)
|
|
26
|
+
|
|
27
|
+
### Advanced Examples
|
|
28
|
+
|
|
29
|
+
- [Streaming Responses](basic-chat.md#with-streaming)
|
|
30
|
+
- [Persistent Conversations](basic-chat.md#with-conversation-history)
|
|
31
|
+
- [MCP Integration](mcp-server.md)
|
|
32
|
+
|
|
33
|
+
## Hello World
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
require "robot_lab"
|
|
37
|
+
|
|
38
|
+
RobotLab.configure do |config|
|
|
39
|
+
config.default_model = "claude-sonnet-4"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
robot = RobotLab.build do
|
|
43
|
+
name "greeter"
|
|
44
|
+
template "You are a friendly greeter. Say hello warmly."
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
state = RobotLab.create_state(message: "Hi there!")
|
|
48
|
+
result = robot.run(state: state)
|
|
49
|
+
|
|
50
|
+
puts result.output.first.content
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Robot with Tools
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
robot = RobotLab.build do
|
|
57
|
+
name "calculator"
|
|
58
|
+
template "You help with calculations."
|
|
59
|
+
|
|
60
|
+
tool :calculate do
|
|
61
|
+
description "Perform a calculation"
|
|
62
|
+
parameter :expression, type: :string, required: true
|
|
63
|
+
handler { |expression:, **_| eval(expression).to_s }
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
state = RobotLab.create_state(message: "What's 25 * 4?")
|
|
68
|
+
result = robot.run(state: state)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Network with Routing
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
classifier = RobotLab.build do
|
|
75
|
+
name "classifier"
|
|
76
|
+
template "Classify: BILLING, TECHNICAL, or GENERAL"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
billing = RobotLab.build do
|
|
80
|
+
name "billing"
|
|
81
|
+
template "You handle billing questions."
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
tech = RobotLab.build do
|
|
85
|
+
name "tech"
|
|
86
|
+
template "You handle technical issues."
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
network = RobotLab.create_network do
|
|
90
|
+
name "support"
|
|
91
|
+
add_robot classifier
|
|
92
|
+
add_robot billing
|
|
93
|
+
add_robot tech
|
|
94
|
+
|
|
95
|
+
router ->(args) {
|
|
96
|
+
case args.call_count
|
|
97
|
+
when 0 then :classifier
|
|
98
|
+
when 1
|
|
99
|
+
category = args.last_result&.output&.first&.content&.strip
|
|
100
|
+
category == "BILLING" ? :billing : :tech
|
|
101
|
+
end
|
|
102
|
+
}
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
result = network.run(state: state)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Running Examples
|
|
109
|
+
|
|
110
|
+
1. Install dependencies:
|
|
111
|
+
```bash
|
|
112
|
+
bundle install
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
2. Set API key:
|
|
116
|
+
```bash
|
|
117
|
+
export ANTHROPIC_API_KEY="your-key"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
3. Run example:
|
|
121
|
+
```bash
|
|
122
|
+
ruby examples/basic_chat.rb
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## See Also
|
|
126
|
+
|
|
127
|
+
- [Getting Started](../getting-started/index.md)
|
|
128
|
+
- [Guides](../guides/index.md)
|
|
129
|
+
- [API Reference](../api/index.md)
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# MCP Server
|
|
2
|
+
|
|
3
|
+
Creating and using Model Context Protocol servers.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This example demonstrates how to create MCP servers to expose tools and how to connect robots to external MCP servers.
|
|
8
|
+
|
|
9
|
+
## Creating an MCP Server
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
#!/usr/bin/env ruby
|
|
13
|
+
# examples/mcp_server.rb
|
|
14
|
+
|
|
15
|
+
require "bundler/setup"
|
|
16
|
+
require "robot_lab"
|
|
17
|
+
require "json"
|
|
18
|
+
|
|
19
|
+
# Create an MCP server with database tools
|
|
20
|
+
server = RobotLab::MCP::Server.new(
|
|
21
|
+
name: "database_tools",
|
|
22
|
+
version: "1.0.0"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# Mock database
|
|
26
|
+
USERS = {
|
|
27
|
+
"1" => { id: "1", name: "Alice", email: "alice@example.com", plan: "pro" },
|
|
28
|
+
"2" => { id: "2", name: "Bob", email: "bob@example.com", plan: "free" }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
ORDERS = {
|
|
32
|
+
"ORD001" => { id: "ORD001", user_id: "1", total: 99.99, status: "shipped" },
|
|
33
|
+
"ORD002" => { id: "ORD002", user_id: "1", total: 49.99, status: "pending" },
|
|
34
|
+
"ORD003" => { id: "ORD003", user_id: "2", total: 29.99, status: "delivered" }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Add tools to the server
|
|
38
|
+
server.add_tool(
|
|
39
|
+
name: "get_user",
|
|
40
|
+
description: "Get user by ID",
|
|
41
|
+
parameters: {
|
|
42
|
+
user_id: { type: "string", required: true, description: "User ID" }
|
|
43
|
+
},
|
|
44
|
+
handler: ->(user_id:) {
|
|
45
|
+
user = USERS[user_id]
|
|
46
|
+
user || { error: "User not found" }
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
server.add_tool(
|
|
51
|
+
name: "list_users",
|
|
52
|
+
description: "List all users",
|
|
53
|
+
parameters: {
|
|
54
|
+
plan: { type: "string", enum: ["free", "pro"], description: "Filter by plan" }
|
|
55
|
+
},
|
|
56
|
+
handler: ->(plan: nil) {
|
|
57
|
+
users = USERS.values
|
|
58
|
+
users = users.select { |u| u[:plan] == plan } if plan
|
|
59
|
+
users
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
server.add_tool(
|
|
64
|
+
name: "get_orders",
|
|
65
|
+
description: "Get orders for a user",
|
|
66
|
+
parameters: {
|
|
67
|
+
user_id: { type: "string", required: true },
|
|
68
|
+
status: { type: "string", enum: ["pending", "shipped", "delivered"] }
|
|
69
|
+
},
|
|
70
|
+
handler: ->(user_id:, status: nil) {
|
|
71
|
+
orders = ORDERS.values.select { |o| o[:user_id] == user_id }
|
|
72
|
+
orders = orders.select { |o| o[:status] == status } if status
|
|
73
|
+
orders
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
server.add_tool(
|
|
78
|
+
name: "update_order_status",
|
|
79
|
+
description: "Update an order's status",
|
|
80
|
+
parameters: {
|
|
81
|
+
order_id: { type: "string", required: true },
|
|
82
|
+
status: { type: "string", required: true, enum: ["pending", "shipped", "delivered"] }
|
|
83
|
+
},
|
|
84
|
+
handler: ->(order_id:, status:) {
|
|
85
|
+
order = ORDERS[order_id]
|
|
86
|
+
return { error: "Order not found" } unless order
|
|
87
|
+
order[:status] = status
|
|
88
|
+
{ success: true, order: order }
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Start the server (stdio for local use)
|
|
93
|
+
puts "Starting MCP server..."
|
|
94
|
+
server.start(transport: :stdio)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Using MCP Server in Robot
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
#!/usr/bin/env ruby
|
|
101
|
+
# examples/mcp_client.rb
|
|
102
|
+
|
|
103
|
+
require "bundler/setup"
|
|
104
|
+
require "robot_lab"
|
|
105
|
+
|
|
106
|
+
RobotLab.configure do |config|
|
|
107
|
+
config.default_model = "claude-sonnet-4"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Robot that uses the MCP server
|
|
111
|
+
admin_bot = RobotLab.build do
|
|
112
|
+
name "admin_assistant"
|
|
113
|
+
description "Helps with administrative tasks"
|
|
114
|
+
|
|
115
|
+
template <<~PROMPT
|
|
116
|
+
You are an administrative assistant with access to user and order data.
|
|
117
|
+
Help users look up information and manage orders.
|
|
118
|
+
PROMPT
|
|
119
|
+
|
|
120
|
+
mcp [
|
|
121
|
+
{
|
|
122
|
+
name: "database",
|
|
123
|
+
transport: {
|
|
124
|
+
type: "stdio",
|
|
125
|
+
command: "ruby",
|
|
126
|
+
args: ["examples/mcp_server.rb"]
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Interactive session
|
|
133
|
+
puts "Admin Assistant (uses MCP server)"
|
|
134
|
+
puts "-" * 50
|
|
135
|
+
|
|
136
|
+
state = RobotLab.create_state(message: "List all pro users and their orders")
|
|
137
|
+
|
|
138
|
+
admin_bot.run(state: state) do |event|
|
|
139
|
+
case event.type
|
|
140
|
+
when :text_delta
|
|
141
|
+
print event.text
|
|
142
|
+
when :tool_call
|
|
143
|
+
puts "\n[MCP: #{event.name}]"
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
puts
|
|
148
|
+
admin_bot.disconnect
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Network with MCP
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
# examples/network_with_mcp.rb
|
|
155
|
+
|
|
156
|
+
network = RobotLab.create_network do
|
|
157
|
+
name "support_with_mcp"
|
|
158
|
+
|
|
159
|
+
# MCP servers available to all robots
|
|
160
|
+
mcp [
|
|
161
|
+
{
|
|
162
|
+
name: "database",
|
|
163
|
+
transport: { type: "stdio", command: "ruby examples/mcp_server.rb" }
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
name: "filesystem",
|
|
167
|
+
transport: {
|
|
168
|
+
type: "stdio",
|
|
169
|
+
command: "npx",
|
|
170
|
+
args: ["@modelcontextprotocol/server-filesystem", "/data"]
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
|
|
175
|
+
add_robot RobotLab.build {
|
|
176
|
+
name "data_analyst"
|
|
177
|
+
template "You analyze user data."
|
|
178
|
+
mcp :inherit # Uses network's MCP servers
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
add_robot RobotLab.build {
|
|
182
|
+
name "file_manager"
|
|
183
|
+
template "You manage files."
|
|
184
|
+
mcp :inherit
|
|
185
|
+
tools %w[read_file list_directory] # Only these MCP tools
|
|
186
|
+
}
|
|
187
|
+
end
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## HTTP MCP Server
|
|
191
|
+
|
|
192
|
+
```ruby
|
|
193
|
+
#!/usr/bin/env ruby
|
|
194
|
+
# examples/http_mcp_server.rb
|
|
195
|
+
|
|
196
|
+
require "robot_lab"
|
|
197
|
+
require "sinatra"
|
|
198
|
+
|
|
199
|
+
server = RobotLab::MCP::Server.new(name: "api_tools")
|
|
200
|
+
|
|
201
|
+
server.add_tool(
|
|
202
|
+
name: "get_stats",
|
|
203
|
+
description: "Get system statistics",
|
|
204
|
+
parameters: {},
|
|
205
|
+
handler: -> {
|
|
206
|
+
{
|
|
207
|
+
uptime: `uptime`.strip,
|
|
208
|
+
memory: `free -m 2>/dev/null || vm_stat`.strip,
|
|
209
|
+
time: Time.now.iso8601
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
# Sinatra endpoint for MCP
|
|
215
|
+
post "/mcp" do
|
|
216
|
+
content_type :json
|
|
217
|
+
request_body = JSON.parse(request.body.read)
|
|
218
|
+
response = server.handle_request(request_body)
|
|
219
|
+
response.to_json
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Run: ruby examples/http_mcp_server.rb
|
|
223
|
+
# Connect with HTTP transport
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Connecting to HTTP Server
|
|
227
|
+
|
|
228
|
+
```ruby
|
|
229
|
+
robot = RobotLab.build do
|
|
230
|
+
name "remote_assistant"
|
|
231
|
+
template "You have access to remote tools."
|
|
232
|
+
|
|
233
|
+
mcp [
|
|
234
|
+
{
|
|
235
|
+
name: "remote",
|
|
236
|
+
transport: {
|
|
237
|
+
type: "http",
|
|
238
|
+
url: "https://mcp.example.com/mcp",
|
|
239
|
+
headers: { "Authorization" => "Bearer #{ENV['MCP_TOKEN']}" }
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
]
|
|
243
|
+
end
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## WebSocket Server
|
|
247
|
+
|
|
248
|
+
```ruby
|
|
249
|
+
#!/usr/bin/env ruby
|
|
250
|
+
# examples/websocket_mcp_server.rb
|
|
251
|
+
|
|
252
|
+
require "robot_lab"
|
|
253
|
+
|
|
254
|
+
server = RobotLab::MCP::Server.new(name: "realtime_tools")
|
|
255
|
+
|
|
256
|
+
server.add_tool(
|
|
257
|
+
name: "subscribe_events",
|
|
258
|
+
description: "Subscribe to real-time events",
|
|
259
|
+
parameters: { channel: { type: "string", required: true } },
|
|
260
|
+
handler: ->(channel:) { { subscribed: channel } }
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
# Start WebSocket server
|
|
264
|
+
server.start(transport: :websocket, port: 8765)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Running
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
# Start MCP server in one terminal
|
|
271
|
+
ruby examples/mcp_server.rb
|
|
272
|
+
|
|
273
|
+
# Run client in another terminal
|
|
274
|
+
export ANTHROPIC_API_KEY="your-key"
|
|
275
|
+
ruby examples/mcp_client.rb
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Key Concepts
|
|
279
|
+
|
|
280
|
+
1. **Server Creation**: Use `RobotLab::MCP::Server.new`
|
|
281
|
+
2. **Tool Registration**: Add tools with `server.add_tool`
|
|
282
|
+
3. **Transport**: Choose stdio, http, websocket, or sse
|
|
283
|
+
4. **Client Connection**: Configure in robot's `mcp` block
|
|
284
|
+
5. **Tool Filtering**: Use `tools` whitelist for security
|
|
285
|
+
|
|
286
|
+
## See Also
|
|
287
|
+
|
|
288
|
+
- [MCP Integration Guide](../guides/mcp-integration.md)
|
|
289
|
+
- [MCP API Reference](../api/mcp/index.md)
|
|
290
|
+
- [Transports](../api/mcp/transports.md)
|