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
data/docs/index.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
</td>
|
|
12
12
|
<td width="50%" valign="top">
|
|
13
13
|
RobotLab is a Ruby gem that enables you to build sophisticated AI applications using multiple specialized robots (LLM agents) that work together to accomplish complex tasks.<br><br>
|
|
14
|
-
Each robot
|
|
14
|
+
Each robot is backed by a persistent LLM chat, configured with keyword arguments, and run with a simple positional message. Robots can be orchestrated through networks with task-based pipelines, share information through a reactive memory system, and connect to external tools via the Model Context Protocol (MCP).
|
|
15
15
|
</td>
|
|
16
16
|
</tr>
|
|
17
17
|
</table>
|
|
@@ -24,7 +24,7 @@ Each robot has its own system prompt, tools, and capabilities. Robots can be orc
|
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
27
|
-
Build applications with multiple specialized AI agents, each with
|
|
27
|
+
Build applications with multiple specialized AI agents, each inheriting from `RubyLLM::Agent` with persistent chat and memory.
|
|
28
28
|
|
|
29
29
|
[:octicons-arrow-right-24: Learn more](architecture/core-concepts.md)
|
|
30
30
|
|
|
@@ -32,7 +32,7 @@ Each robot has its own system prompt, tools, and capabilities. Robots can be orc
|
|
|
32
32
|
|
|
33
33
|
---
|
|
34
34
|
|
|
35
|
-
Connect robots in
|
|
35
|
+
Connect robots in task-based pipelines using SimpleFlow with sequential, parallel, and conditional execution.
|
|
36
36
|
|
|
37
37
|
[:octicons-arrow-right-24: Creating Networks](guides/creating-networks.md)
|
|
38
38
|
|
|
@@ -40,7 +40,7 @@ Each robot has its own system prompt, tools, and capabilities. Robots can be orc
|
|
|
40
40
|
|
|
41
41
|
---
|
|
42
42
|
|
|
43
|
-
Give robots
|
|
43
|
+
Give robots tools via `RubyLLM::Tool` subclasses or `RobotLab::Tool.new` with block handlers.
|
|
44
44
|
|
|
45
45
|
[:octicons-arrow-right-24: Using Tools](guides/using-tools.md)
|
|
46
46
|
|
|
@@ -52,11 +52,19 @@ Each robot has its own system prompt, tools, and capabilities. Robots can be orc
|
|
|
52
52
|
|
|
53
53
|
[:octicons-arrow-right-24: MCP Guide](guides/mcp-integration.md)
|
|
54
54
|
|
|
55
|
-
- :material-
|
|
55
|
+
- :material-message-arrow-right-outline:{ .lg .middle } **Message Bus**
|
|
56
56
|
|
|
57
57
|
---
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
Enable bidirectional, cyclic communication between robots via TypedBus for negotiation loops and convergence patterns.
|
|
60
|
+
|
|
61
|
+
[:octicons-arrow-right-24: Message Bus](architecture/core-concepts.md#message-bus)
|
|
62
|
+
|
|
63
|
+
- :material-memory:{ .lg .middle } **Reactive Memory**
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
Robots share data through a reactive key-value memory system with subscriptions, blocking reads, and optional Redis backend.
|
|
60
68
|
|
|
61
69
|
[:octicons-arrow-right-24: Memory System](guides/memory.md)
|
|
62
70
|
|
|
@@ -75,33 +83,34 @@ Each robot has its own system prompt, tools, and capabilities. Robots can be orc
|
|
|
75
83
|
```ruby
|
|
76
84
|
require "robot_lab"
|
|
77
85
|
|
|
78
|
-
#
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
robot
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
add_robot robot
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# Run the network
|
|
100
|
-
state = RobotLab.create_state(message: "What is the capital of France?")
|
|
101
|
-
result = network.run(state: state)
|
|
102
|
-
|
|
103
|
-
puts result.last_result.output.first.content
|
|
86
|
+
# Configuration is automatic via environment variables, YAML files, or defaults.
|
|
87
|
+
# Set API keys via env vars:
|
|
88
|
+
# ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY=sk-ant-...
|
|
89
|
+
#
|
|
90
|
+
# Or place a config file at ~/.config/robot_lab/config.yml
|
|
91
|
+
# Access config values: RobotLab.config.ruby_llm.model #=> "claude-sonnet-4"
|
|
92
|
+
|
|
93
|
+
# Create a robot with keyword arguments
|
|
94
|
+
robot = RobotLab.build(
|
|
95
|
+
name: "assistant",
|
|
96
|
+
system_prompt: "You are a helpful assistant. Answer questions clearly and concisely.",
|
|
97
|
+
model: "claude-sonnet-4"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Run the robot with a positional string argument
|
|
101
|
+
result = robot.run("What is the capital of France?")
|
|
102
|
+
|
|
103
|
+
puts result.last_text_content
|
|
104
104
|
# => "The capital of France is Paris."
|
|
105
|
+
|
|
106
|
+
# Memory persists across runs
|
|
107
|
+
robot.run("Remember that my favorite color is blue.")
|
|
108
|
+
result = robot.run("What is my favorite color?")
|
|
109
|
+
puts result.last_text_content
|
|
110
|
+
# => "Your favorite color is blue."
|
|
111
|
+
|
|
112
|
+
# Chaining configuration
|
|
113
|
+
robot.with_instructions("Be extra concise.").with_temperature(0.3).run("Explain Ruby in one sentence.")
|
|
105
114
|
```
|
|
106
115
|
|
|
107
116
|
## Supported LLM Providers
|
|
@@ -110,12 +119,16 @@ RobotLab supports multiple LLM providers through the [ruby_llm](https://github.c
|
|
|
110
119
|
|
|
111
120
|
| Provider | Models |
|
|
112
121
|
|----------|--------|
|
|
113
|
-
| **Anthropic** | Claude 4, Claude Sonnet, Claude Haiku |
|
|
114
|
-
| **OpenAI** | GPT-4o, GPT-4,
|
|
115
|
-
| **Google** | Gemini Pro, Gemini
|
|
116
|
-
| **
|
|
117
|
-
| **Bedrock** | Claude models via AWS Bedrock |
|
|
122
|
+
| **Anthropic** | Claude Opus 4, Claude Sonnet 4, Claude Haiku 3.5 |
|
|
123
|
+
| **OpenAI** | GPT-4o, GPT-4, o1, o3 |
|
|
124
|
+
| **Google** | Gemini 2.5 Pro, Gemini 2.5 Flash |
|
|
125
|
+
| **DeepSeek** | DeepSeek V3, DeepSeek R1 |
|
|
126
|
+
| **AWS Bedrock** | Claude models via AWS Bedrock |
|
|
127
|
+
| **Google Vertex AI** | Gemini models via Vertex AI |
|
|
118
128
|
| **Ollama** | Local models via Ollama |
|
|
129
|
+
| **OpenRouter** | Multi-provider routing |
|
|
130
|
+
| **Mistral** | Mistral Large, Mistral Medium |
|
|
131
|
+
| **xAI** | Grok models |
|
|
119
132
|
|
|
120
133
|
## Installation
|
|
121
134
|
|
data/examples/01_simple_robot.rb
CHANGED
|
@@ -8,26 +8,23 @@
|
|
|
8
8
|
# Usage:
|
|
9
9
|
# ANTHROPIC_API_KEY=your_key ruby examples/01_simple_robot.rb
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
# Configure template path before loading (MywayConfig reads env vars on init)
|
|
12
|
+
ENV['ROBOT_LAB_TEMPLATE_PATH'] ||= File.join(__dir__, "prompts")
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
RobotLab.configure do |config|
|
|
15
|
-
config.anthropic_api_key = ENV.fetch("ANTHROPIC_API_KEY", nil)
|
|
16
|
-
config.template_path = File.join(__dir__, "prompts")
|
|
17
|
-
end
|
|
14
|
+
require_relative "../lib/robot_lab"
|
|
18
15
|
|
|
19
16
|
# Create a simple robot using a template
|
|
20
17
|
robot = RobotLab.build(
|
|
21
18
|
name: "helper",
|
|
22
19
|
template: :helper,
|
|
23
|
-
model: "claude-
|
|
20
|
+
model: "claude-3-haiku-20240307"
|
|
24
21
|
)
|
|
25
22
|
|
|
26
23
|
puts "Running simple robot..."
|
|
27
24
|
puts "-" * 40
|
|
28
25
|
|
|
29
|
-
# Run the robot
|
|
30
|
-
result = robot.run(
|
|
26
|
+
# Run the robot
|
|
27
|
+
result = robot.run("What is 2 + 2? Please explain your reasoning briefly.")
|
|
31
28
|
|
|
32
29
|
# Display the result
|
|
33
30
|
puts "Robot: #{robot.name}"
|
data/examples/02_tools.rb
CHANGED
|
@@ -8,13 +8,10 @@
|
|
|
8
8
|
# Usage:
|
|
9
9
|
# ANTHROPIC_API_KEY=your_key ruby examples/02_tools.rb
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
# Configure template path before loading (MywayConfig reads env vars on init)
|
|
12
|
+
ENV['ROBOT_LAB_TEMPLATE_PATH'] ||= File.join(__dir__, "prompts")
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
RobotLab.configure do |config|
|
|
15
|
-
config.anthropic_api_key = ENV.fetch("ANTHROPIC_API_KEY", nil)
|
|
16
|
-
config.template_path = File.join(__dir__, "prompts")
|
|
17
|
-
end
|
|
14
|
+
require_relative "../lib/robot_lab"
|
|
18
15
|
|
|
19
16
|
# Define tools using RubyLLM::Tool
|
|
20
17
|
class Calculator < RubyLLM::Tool
|
|
@@ -86,15 +83,15 @@ end
|
|
|
86
83
|
robot = RobotLab.build(
|
|
87
84
|
name: "assistant",
|
|
88
85
|
template: :assistant,
|
|
89
|
-
|
|
90
|
-
model: "claude-
|
|
86
|
+
local_tools: [Calculator, FortuneCookie],
|
|
87
|
+
model: "claude-3-haiku-20240307"
|
|
91
88
|
)
|
|
92
89
|
|
|
93
90
|
puts "Running robot with tools..."
|
|
94
91
|
puts "-" * 40
|
|
95
92
|
|
|
96
93
|
# Run the robot
|
|
97
|
-
result = robot.run(
|
|
94
|
+
result = robot.run("What is 15 multiplied by 7? Also, give me a fortune about my career.")
|
|
98
95
|
|
|
99
96
|
# Display results
|
|
100
97
|
puts "Robot: #{robot.name}"
|
data/examples/03_network.rb
CHANGED
|
@@ -9,25 +9,24 @@
|
|
|
9
9
|
# Usage:
|
|
10
10
|
# ANTHROPIC_API_KEY=your_key ruby examples/03_network.rb
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
# Configure template path before loading (MywayConfig reads env vars on init)
|
|
13
|
+
ENV['ROBOT_LAB_TEMPLATE_PATH'] ||= File.join(__dir__, "prompts")
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
RobotLab.configure do |config|
|
|
16
|
-
config.anthropic_api_key = ENV.fetch("ANTHROPIC_API_KEY", nil)
|
|
17
|
-
config.template_path = File.join(__dir__, "prompts")
|
|
18
|
-
end
|
|
15
|
+
require_relative "../lib/robot_lab"
|
|
19
16
|
|
|
20
17
|
# Classifier robot that activates the appropriate specialist
|
|
21
18
|
class ClassifierRobot < RobotLab::Robot
|
|
22
19
|
def call(result)
|
|
23
|
-
|
|
20
|
+
run_context = extract_run_context(result)
|
|
21
|
+
message = run_context.delete(:message)
|
|
22
|
+
robot_result = run(message, **run_context)
|
|
24
23
|
|
|
25
24
|
new_result = result
|
|
26
25
|
.with_context(@name.to_sym, robot_result)
|
|
27
26
|
.continue(robot_result)
|
|
28
27
|
|
|
29
28
|
# Examine LLM output and activate appropriate specialist
|
|
30
|
-
category = robot_result.
|
|
29
|
+
category = robot_result.reply.to_s.strip.downcase
|
|
31
30
|
|
|
32
31
|
case category
|
|
33
32
|
when /billing/
|
|
@@ -44,25 +43,25 @@ end
|
|
|
44
43
|
classifier = ClassifierRobot.new(
|
|
45
44
|
name: "classifier",
|
|
46
45
|
template: :classifier,
|
|
47
|
-
model: "claude-
|
|
46
|
+
model: "claude-3-haiku-20240307"
|
|
48
47
|
)
|
|
49
48
|
|
|
50
49
|
billing_robot = RobotLab.build(
|
|
51
50
|
name: "billing",
|
|
52
51
|
template: :billing,
|
|
53
|
-
model: "claude-
|
|
52
|
+
model: "claude-3-haiku-20240307"
|
|
54
53
|
)
|
|
55
54
|
|
|
56
55
|
technical_robot = RobotLab.build(
|
|
57
56
|
name: "technical",
|
|
58
57
|
template: :technical,
|
|
59
|
-
model: "claude-
|
|
58
|
+
model: "claude-3-haiku-20240307"
|
|
60
59
|
)
|
|
61
60
|
|
|
62
61
|
general_robot = RobotLab.build(
|
|
63
62
|
name: "general",
|
|
64
63
|
template: :general,
|
|
65
|
-
model: "claude-
|
|
64
|
+
model: "claude-3-haiku-20240307"
|
|
66
65
|
)
|
|
67
66
|
|
|
68
67
|
# Create network with optional task routing
|
|
@@ -90,13 +89,13 @@ puts "\nConversation flow:"
|
|
|
90
89
|
if result.context[:classifier]
|
|
91
90
|
classifier_result = result.context[:classifier]
|
|
92
91
|
puts "\n1. Robot: classifier"
|
|
93
|
-
puts " Classification: #{classifier_result.
|
|
92
|
+
puts " Classification: #{classifier_result.reply}"
|
|
94
93
|
end
|
|
95
94
|
|
|
96
95
|
# Show specialist result (the final value)
|
|
97
96
|
if result.value.is_a?(RobotLab::RobotResult)
|
|
98
97
|
puts "\n2. Robot: #{result.value.robot_name}"
|
|
99
|
-
content = result.value.
|
|
98
|
+
content = result.value.reply
|
|
100
99
|
puts " Response: #{content[0..200]}..." if content
|
|
101
100
|
end
|
|
102
101
|
|
data/examples/04_mcp.rb
CHANGED
|
@@ -21,13 +21,10 @@
|
|
|
21
21
|
# - Reading file contents and repository information
|
|
22
22
|
# - Managing branches and commits
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
# Configure template path before loading (MywayConfig reads env vars on init)
|
|
25
|
+
ENV['ROBOT_LAB_TEMPLATE_PATH'] ||= File.join(__dir__, "prompts")
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
RobotLab.configure do |config|
|
|
28
|
-
config.anthropic_api_key = ENV.fetch("ANTHROPIC_API_KEY", nil)
|
|
29
|
-
config.template_path = File.join(__dir__, "prompts")
|
|
30
|
-
end
|
|
27
|
+
require_relative "../lib/robot_lab"
|
|
31
28
|
|
|
32
29
|
# GitHub MCP server configuration using StdIO transport
|
|
33
30
|
github_server = {
|
|
@@ -151,7 +148,7 @@ begin
|
|
|
151
148
|
name: "github_assistant",
|
|
152
149
|
template: :github_assistant,
|
|
153
150
|
mcp_servers: [github_server],
|
|
154
|
-
model: "claude-
|
|
151
|
+
model: "claude-3-haiku-20240307"
|
|
155
152
|
)
|
|
156
153
|
|
|
157
154
|
puts "Robot created: #{robot.name}"
|
|
@@ -175,7 +172,7 @@ begin
|
|
|
175
172
|
puts "Query: 'What are the top 3 most starred Ruby web frameworks on GitHub?'"
|
|
176
173
|
puts "-" * 40
|
|
177
174
|
|
|
178
|
-
result = robot.run(
|
|
175
|
+
result = robot.run("What are the top 3 most starred Ruby web frameworks on GitHub? Just list their names and star counts.")
|
|
179
176
|
|
|
180
177
|
puts
|
|
181
178
|
puts "Robot Response:"
|
data/examples/05_streaming.rb
CHANGED
|
@@ -8,13 +8,10 @@
|
|
|
8
8
|
# Usage:
|
|
9
9
|
# ANTHROPIC_API_KEY=your_key ruby examples/05_streaming.rb
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
# Configure template path before loading (MywayConfig reads env vars on init)
|
|
12
|
+
ENV['ROBOT_LAB_TEMPLATE_PATH'] ||= File.join(__dir__, "prompts")
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
RobotLab.configure do |config|
|
|
15
|
-
config.anthropic_api_key = ENV.fetch("ANTHROPIC_API_KEY", nil)
|
|
16
|
-
config.template_path = File.join(__dir__, "prompts")
|
|
17
|
-
end
|
|
14
|
+
require_relative "../lib/robot_lab"
|
|
18
15
|
|
|
19
16
|
# Create a streaming handler
|
|
20
17
|
streaming_handler = lambda do |event|
|
|
@@ -97,11 +94,11 @@ puts <<~CODE
|
|
|
97
94
|
robot = RobotLab.build(
|
|
98
95
|
name: "streamer",
|
|
99
96
|
template: :helper,
|
|
100
|
-
model: "claude-
|
|
97
|
+
model: "claude-3-haiku-20240307"
|
|
101
98
|
)
|
|
102
99
|
|
|
103
100
|
# Run with streaming callback
|
|
104
|
-
result = robot.run(
|
|
101
|
+
result = robot.run("Tell me a story") do |event|
|
|
105
102
|
case event[:event]
|
|
106
103
|
when "text.delta"
|
|
107
104
|
print event[:data][:delta]
|
|
@@ -1,29 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
# Example 6: Prompt Templates with
|
|
4
|
+
# Example 6: Prompt Templates with prompt_manager
|
|
5
5
|
#
|
|
6
|
-
# Demonstrates using
|
|
6
|
+
# Demonstrates using prompt_manager for organized, reusable prompts
|
|
7
7
|
# within a RobotLab network. This example shows an e-commerce support
|
|
8
8
|
# system with dynamic context injection using SimpleFlow's optional task routing.
|
|
9
9
|
#
|
|
10
10
|
# Usage:
|
|
11
11
|
# ANTHROPIC_API_KEY=your_key ruby examples/06_prompt_templates.rb
|
|
12
12
|
#
|
|
13
|
-
# Template Structure:
|
|
13
|
+
# Template Structure (prompt_manager .md files with YAML front matter):
|
|
14
14
|
# examples/prompts/
|
|
15
|
-
# ├── triage
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
#
|
|
21
|
-
|
|
22
|
-
# │ ├── system.txt.erb
|
|
23
|
-
# │ └── user.txt.erb
|
|
24
|
-
# └── escalation/
|
|
25
|
-
# ├── system.txt.erb
|
|
26
|
-
# └── user.txt.erb
|
|
15
|
+
# ├── triage.md
|
|
16
|
+
# ├── order_support.md
|
|
17
|
+
# ├── product_support.md
|
|
18
|
+
# └── escalation.md
|
|
19
|
+
|
|
20
|
+
# Configure template path before loading (MywayConfig reads env vars on init)
|
|
21
|
+
ENV['ROBOT_LAB_TEMPLATE_PATH'] ||= File.join(__dir__, "prompts")
|
|
27
22
|
|
|
28
23
|
require_relative "../lib/robot_lab"
|
|
29
24
|
|
|
@@ -31,8 +26,14 @@ require_relative "../lib/robot_lab"
|
|
|
31
26
|
# Sample Data
|
|
32
27
|
# =============================================================================
|
|
33
28
|
# Simulated customer and business data that would come from your database.
|
|
29
|
+
# company_name is a template parameter (declared null in all four templates).
|
|
30
|
+
# AskUser gathers it from the user before building robots.
|
|
34
31
|
|
|
35
|
-
|
|
32
|
+
ask = RobotLab::AskUser.new
|
|
33
|
+
COMPANY_NAME = ask.call(
|
|
34
|
+
"question" => "What is your company name?",
|
|
35
|
+
"default" => "TechGear Pro"
|
|
36
|
+
)
|
|
36
37
|
|
|
37
38
|
SAMPLE_CUSTOMER = {
|
|
38
39
|
name: "Sarah Johnson",
|
|
@@ -149,14 +150,16 @@ ESCALATION_AUTHORITIES = [
|
|
|
149
150
|
# Custom triage robot that classifies and activates appropriate specialist
|
|
150
151
|
class TriageRobot < RobotLab::Robot
|
|
151
152
|
def call(result)
|
|
152
|
-
|
|
153
|
+
run_context = extract_run_context(result)
|
|
154
|
+
message = run_context.delete(:message)
|
|
155
|
+
robot_result = run(message, **run_context)
|
|
153
156
|
|
|
154
157
|
new_result = result
|
|
155
158
|
.with_context(@name.to_sym, robot_result)
|
|
156
159
|
.continue(robot_result)
|
|
157
160
|
|
|
158
161
|
# Examine LLM output and activate appropriate specialist
|
|
159
|
-
classification = robot_result.
|
|
162
|
+
classification = robot_result.reply.to_s.strip.downcase
|
|
160
163
|
|
|
161
164
|
case classification
|
|
162
165
|
when /order/
|
|
@@ -182,11 +185,7 @@ puts "E-Commerce Support Network with Dynamic Context"
|
|
|
182
185
|
puts "=" * 70
|
|
183
186
|
puts
|
|
184
187
|
|
|
185
|
-
#
|
|
186
|
-
RobotLab.configure do |config|
|
|
187
|
-
config.anthropic_api_key = ENV.fetch("ANTHROPIC_API_KEY", nil)
|
|
188
|
-
config.template_path = File.join(__dir__, "prompts")
|
|
189
|
-
end
|
|
188
|
+
# Template path is set via ROBOT_LAB_TEMPLATE_PATH env var (see top of file)
|
|
190
189
|
|
|
191
190
|
# -----------------------------------------------------------------------------
|
|
192
191
|
# Build Robots with Template-Based Prompts
|
|
@@ -197,11 +196,12 @@ triage_robot = TriageRobot.new(
|
|
|
197
196
|
name: "triage",
|
|
198
197
|
description: "Classifies incoming requests to route to specialists",
|
|
199
198
|
template: :triage,
|
|
199
|
+
local_tools: [RobotLab::AskUser],
|
|
200
200
|
context: {
|
|
201
201
|
company_name: COMPANY_NAME,
|
|
202
202
|
categories: CATEGORIES
|
|
203
203
|
},
|
|
204
|
-
model: "claude-
|
|
204
|
+
model: "claude-3-haiku-20240307"
|
|
205
205
|
)
|
|
206
206
|
|
|
207
207
|
# Order Support Robot
|
|
@@ -209,12 +209,13 @@ order_robot = RobotLab.build(
|
|
|
209
209
|
name: "order",
|
|
210
210
|
description: "Handles order-related inquiries with full order history",
|
|
211
211
|
template: :order_support,
|
|
212
|
+
local_tools: [RobotLab::AskUser],
|
|
212
213
|
context: {
|
|
213
214
|
company_name: COMPANY_NAME,
|
|
214
215
|
policies: POLICIES,
|
|
215
216
|
capabilities: ORDER_CAPABILITIES
|
|
216
217
|
},
|
|
217
|
-
model: "claude-
|
|
218
|
+
model: "claude-3-haiku-20240307"
|
|
218
219
|
)
|
|
219
220
|
|
|
220
221
|
# Product Support Robot
|
|
@@ -222,13 +223,14 @@ product_robot = RobotLab.build(
|
|
|
222
223
|
name: "product",
|
|
223
224
|
description: "Answers product questions with catalog knowledge",
|
|
224
225
|
template: :product_support,
|
|
226
|
+
local_tools: [RobotLab::AskUser],
|
|
225
227
|
context: {
|
|
226
228
|
company_name: COMPANY_NAME,
|
|
227
229
|
products: PRODUCTS,
|
|
228
230
|
promotions: PROMOTIONS,
|
|
229
231
|
product_categories: PRODUCT_CATEGORIES
|
|
230
232
|
},
|
|
231
|
-
model: "claude-
|
|
233
|
+
model: "claude-3-haiku-20240307"
|
|
232
234
|
)
|
|
233
235
|
|
|
234
236
|
# Escalation Robot
|
|
@@ -236,11 +238,12 @@ escalation_robot = RobotLab.build(
|
|
|
236
238
|
name: "escalation",
|
|
237
239
|
description: "Handles complex cases requiring special authority",
|
|
238
240
|
template: :escalation,
|
|
241
|
+
local_tools: [RobotLab::AskUser],
|
|
239
242
|
context: {
|
|
240
243
|
company_name: COMPANY_NAME,
|
|
241
244
|
authorities: ESCALATION_AUTHORITIES
|
|
242
245
|
},
|
|
243
|
-
model: "claude-
|
|
246
|
+
model: "claude-3-haiku-20240307"
|
|
244
247
|
)
|
|
245
248
|
|
|
246
249
|
# -----------------------------------------------------------------------------
|
|
@@ -291,14 +294,14 @@ demo_queries.each_with_index do |query, index|
|
|
|
291
294
|
# Display triage classification
|
|
292
295
|
if result.context[:triage]
|
|
293
296
|
triage_result = result.context[:triage]
|
|
294
|
-
puts "Classification: #{triage_result.
|
|
297
|
+
puts "Classification: #{triage_result.reply}"
|
|
295
298
|
puts
|
|
296
299
|
end
|
|
297
300
|
|
|
298
301
|
# Display specialist response (the final value)
|
|
299
302
|
if result.value.is_a?(RobotLab::RobotResult)
|
|
300
303
|
puts "Routed to: #{result.value.robot_name.upcase}"
|
|
301
|
-
content = result.value.
|
|
304
|
+
content = result.value.reply.to_s
|
|
302
305
|
# Truncate long responses for display
|
|
303
306
|
if content.length > 300
|
|
304
307
|
puts "Response: #{content[0..300]}..."
|
|
@@ -314,11 +317,13 @@ end
|
|
|
314
317
|
puts
|
|
315
318
|
puts "Demo Complete!"
|
|
316
319
|
puts
|
|
317
|
-
puts
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
320
|
+
puts <<~FOOTER
|
|
321
|
+
This example demonstrates:
|
|
322
|
+
- prompt_manager templates (.md with YAML front matter)
|
|
323
|
+
- Build-time context (robot identity/capabilities)
|
|
324
|
+
- Run-time context (customer data, order history)
|
|
325
|
+
- Multi-robot network with optional task routing
|
|
326
|
+
- SimpleFlow::Result for passing context between robots
|
|
327
|
+
|
|
328
|
+
Template files are located in: #{File.join(__dir__, 'prompts')}
|
|
329
|
+
FOOTER
|
|
@@ -41,15 +41,12 @@
|
|
|
41
41
|
# Usage:
|
|
42
42
|
# ANTHROPIC_API_KEY=your_key ruby examples/07_network_memory.rb
|
|
43
43
|
|
|
44
|
+
# Configure template path before loading (MywayConfig reads env vars on init)
|
|
45
|
+
ENV['ROBOT_LAB_TEMPLATE_PATH'] ||= File.join(__dir__, "prompts")
|
|
46
|
+
|
|
44
47
|
require_relative "../lib/robot_lab"
|
|
45
48
|
require "json"
|
|
46
49
|
|
|
47
|
-
# Configure RobotLab
|
|
48
|
-
RobotLab.configure do |config|
|
|
49
|
-
config.anthropic_api_key = ENV.fetch("ANTHROPIC_API_KEY", nil)
|
|
50
|
-
config.template_path = File.join(__dir__, "prompts")
|
|
51
|
-
end
|
|
52
|
-
|
|
53
50
|
puts "=" * 60
|
|
54
51
|
puts "Example 7: Network Memory with Concurrent Robots"
|
|
55
52
|
puts "=" * 60
|
|
@@ -69,12 +66,13 @@ class AnalysisRobot < RobotLab::Robot
|
|
|
69
66
|
def call(result)
|
|
70
67
|
run_context = extract_run_context(result)
|
|
71
68
|
network_memory = run_context.delete(:network_memory)
|
|
69
|
+
message = run_context.delete(:message)
|
|
72
70
|
|
|
73
|
-
robot_result = run(network_memory: network_memory, **run_context)
|
|
71
|
+
robot_result = run(message, network_memory: network_memory, **run_context)
|
|
74
72
|
|
|
75
73
|
# Parse the JSON response and write to shared memory
|
|
76
74
|
if network_memory
|
|
77
|
-
content = robot_result.
|
|
75
|
+
content = robot_result.reply.to_s
|
|
78
76
|
|
|
79
77
|
# Set writer before writing to memory
|
|
80
78
|
network_memory.current_writer = @name
|
|
@@ -101,6 +99,7 @@ class SynthesizerRobot < RobotLab::Robot
|
|
|
101
99
|
def call(result)
|
|
102
100
|
run_context = extract_run_context(result)
|
|
103
101
|
network_memory = run_context.delete(:network_memory)
|
|
102
|
+
message = run_context.delete(:message)
|
|
104
103
|
|
|
105
104
|
puts " [#{@name}] Reading analysis results from memory..."
|
|
106
105
|
|
|
@@ -125,7 +124,7 @@ class SynthesizerRobot < RobotLab::Robot
|
|
|
125
124
|
run_context[:keywords] = "Not available"
|
|
126
125
|
end
|
|
127
126
|
|
|
128
|
-
robot_result = run(network_memory: network_memory, **run_context)
|
|
127
|
+
robot_result = run(message, network_memory: network_memory, **run_context)
|
|
129
128
|
|
|
130
129
|
result
|
|
131
130
|
.with_context(@name.to_sym, robot_result)
|
|
@@ -154,27 +153,27 @@ sentiment_robot = AnalysisRobot.new(
|
|
|
154
153
|
name: "sentiment_analyzer",
|
|
155
154
|
template: :sentiment_analyzer,
|
|
156
155
|
memory_key: :sentiment,
|
|
157
|
-
model: "claude-
|
|
156
|
+
model: "claude-3-haiku-20240307"
|
|
158
157
|
)
|
|
159
158
|
|
|
160
159
|
entity_robot = AnalysisRobot.new(
|
|
161
160
|
name: "entity_extractor",
|
|
162
161
|
template: :entity_extractor,
|
|
163
162
|
memory_key: :entities,
|
|
164
|
-
model: "claude-
|
|
163
|
+
model: "claude-3-haiku-20240307"
|
|
165
164
|
)
|
|
166
165
|
|
|
167
166
|
keyword_robot = AnalysisRobot.new(
|
|
168
167
|
name: "keyword_extractor",
|
|
169
168
|
template: :keyword_extractor,
|
|
170
169
|
memory_key: :keywords,
|
|
171
|
-
model: "claude-
|
|
170
|
+
model: "claude-3-haiku-20240307"
|
|
172
171
|
)
|
|
173
172
|
|
|
174
173
|
synthesizer = SynthesizerRobot.new(
|
|
175
174
|
name: "synthesizer",
|
|
176
175
|
template: :synthesizer,
|
|
177
|
-
model: "claude-
|
|
176
|
+
model: "claude-3-haiku-20240307"
|
|
178
177
|
)
|
|
179
178
|
|
|
180
179
|
# -----------------------------------------------------------------------------
|
|
@@ -267,7 +266,7 @@ puts "=" * 60
|
|
|
267
266
|
puts
|
|
268
267
|
|
|
269
268
|
if result.value.is_a?(RobotLab::RobotResult)
|
|
270
|
-
puts result.value.
|
|
269
|
+
puts result.value.reply
|
|
271
270
|
end
|
|
272
271
|
|
|
273
272
|
puts
|