robot_lab 0.2.7 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.envrc +6 -2
- data/.loki +5 -0
- data/Archspec.rb +44 -0
- data/CHANGELOG.md +70 -1
- data/CLAUDE.md +4 -2
- data/README.md +15 -17
- data/Rakefile +6 -111
- data/_typos.toml +21 -0
- data/docs/api/index.md +2 -2
- data/docs/api/skills.md +53 -149
- data/docs/api/support.md +1 -1
- data/docs/architecture/core-concepts.md +1 -1
- data/docs/architecture/index.md +5 -4
- data/docs/architecture/state-management.md +4 -4
- data/docs/concepts.md +1 -1
- data/docs/getting-started/configuration.md +4 -1
- data/docs/getting-started/installation.md +1 -4
- data/docs/guides/hooks.md +122 -0
- data/docs/guides/memory.md +2 -2
- data/docs/guides/using-tools.md +10 -1
- data/examples/.envrc +2 -0
- data/examples/02_tools.rb +8 -8
- data/examples/03_network.rb +1 -1
- data/examples/04_mcp.rb +7 -5
- data/examples/08_llm_config.rb +5 -5
- data/examples/09_chaining.rb +3 -3
- data/examples/14_rusty_circuit/comic.rb +8 -8
- data/examples/14_rusty_circuit/scout.rb +4 -4
- data/examples/15_memory_network_and_bus/README.md +66 -0
- data/examples/15_memory_network_and_bus/output/combined_article.md +5 -7
- data/examples/15_memory_network_and_bus/output/final_article.md +5 -10
- data/examples/15_memory_network_and_bus/output/linux_draft.md +3 -3
- data/examples/15_memory_network_and_bus/output/mac_draft.md +3 -3
- data/examples/15_memory_network_and_bus/output/memory.json +6 -6
- data/examples/15_memory_network_and_bus/output/revision_1.md +21 -10
- data/examples/15_memory_network_and_bus/output/revision_2.md +43 -6
- data/examples/15_memory_network_and_bus/output/revision_3.md +8 -0
- data/examples/15_memory_network_and_bus/output/windows_draft.md +3 -3
- data/examples/16_writers_room/tools.rb +14 -14
- data/examples/19_token_tracking.rb +2 -2
- data/examples/20_circuit_breaker.rb +3 -3
- data/examples/22_context_compression.rb +1 -1
- data/examples/27_incident_response/README.md +65 -0
- data/examples/28_mcp_discovery.rb +2 -2
- data/examples/29_ractor_tools.rb +4 -4
- data/examples/30_ractor_network.rb +2 -2
- data/examples/33_stock_predictor.rb +8 -8
- data/examples/35_hooks.rb +3 -3
- data/examples/README.md +17 -0
- data/examples/common.rb +55 -23
- data/examples/run_all.rb +60 -0
- data/lib/robot_lab/agent_skill_catalog.rb +1 -0
- data/lib/robot_lab/ask_user.rb +5 -3
- data/lib/robot_lab/bus_poller.rb +2 -0
- data/lib/robot_lab/capabilities.rb +4 -0
- data/lib/robot_lab/config/defaults.yml +5 -5
- data/lib/robot_lab/config.rb +10 -2
- data/lib/robot_lab/doom_loop_detector.rb +6 -3
- data/lib/robot_lab/history_compressor.rb +5 -0
- data/lib/robot_lab/hook.rb +1 -0
- data/lib/robot_lab/hook_context.rb +4 -0
- data/lib/robot_lab/hook_registry.rb +1 -0
- data/lib/robot_lab/hooks.rb +6 -3
- data/lib/robot_lab/mcp/client.rb +2 -2
- data/lib/robot_lab/mcp/connection_poller.rb +16 -8
- data/lib/robot_lab/mcp/server_discovery.rb +1 -0
- data/lib/robot_lab/mcp/transports/sse.rb +3 -0
- data/lib/robot_lab/mcp/transports/stdio.rb +5 -0
- data/lib/robot_lab/mcp/transports/streamable_http.rb +5 -3
- data/lib/robot_lab/mcp/transports/websocket.rb +3 -0
- data/lib/robot_lab/memory.rb +39 -13
- data/lib/robot_lab/memory_change.rb +1 -0
- data/lib/robot_lab/message.rb +3 -0
- data/lib/robot_lab/names.rb +2 -4
- data/lib/robot_lab/network.rb +13 -6
- data/lib/robot_lab/robot/agent_skill_matching.rb +2 -0
- data/lib/robot_lab/robot/bus_messaging.rb +3 -0
- data/lib/robot_lab/robot/history_search.rb +2 -0
- data/lib/robot_lab/robot/hooking.rb +29 -0
- data/lib/robot_lab/robot/mcp_management.rb +11 -3
- data/lib/robot_lab/robot/result_building.rb +119 -0
- data/lib/robot_lab/robot/template_rendering.rb +13 -4
- data/lib/robot_lab/robot.rb +88 -130
- data/lib/robot_lab/robot_result.rb +3 -0
- data/lib/robot_lab/run_config.rb +57 -20
- data/lib/robot_lab/script_tool.rb +20 -39
- data/lib/robot_lab/state_proxy.rb +1 -0
- data/lib/robot_lab/streaming/context.rb +1 -0
- data/lib/robot_lab/streaming/events.rb +1 -0
- data/lib/robot_lab/task.rb +2 -0
- data/lib/robot_lab/tool.rb +11 -12
- data/lib/robot_lab/user_message.rb +1 -0
- data/lib/robot_lab/utils.rb +2 -0
- data/lib/robot_lab/version.rb +1 -1
- data/lib/robot_lab/waiter.rb +3 -0
- data/lib/robot_lab.rb +9 -6
- metadata +23 -32
- data/lib/robot_lab/sandbox/null.rb +0 -13
- data/lib/robot_lab/sandbox/seatbelt.rb +0 -104
- data/lib/robot_lab/sandbox.rb +0 -52
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 411c496dec788609f2ac0d2e1eb02ce7fd0523f40424b9437de0ffb24c00c644
|
|
4
|
+
data.tar.gz: 9fb9bb55b865734dc7c9ae1ac8d1994685575c1ee206d6cf9865c0af3d3a522c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b34ce72ebe6443c5f25423a595c0ffd468416ea1be02531b125efed33289ae8ea898c5413697fe373cebd658bddb510f322ef09623bb7b74f7587cf58b9ad064
|
|
7
|
+
data.tar.gz: e9884f0c8b501bfc57eafdc6c5492fea7455eb807267c370fc68b59e7322f97c0360e3af6f7e61b7c2493df3e2026f72095b9c287e65e6bf5f1ec5274948ef7d
|
data/.envrc
CHANGED
data/.loki
CHANGED
|
@@ -18,6 +18,11 @@ class Tasks
|
|
|
18
18
|
sh "ruby -Ilib:test \"#{path}\""
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
+
desc "Check architecture boundaries with ArchSpec"
|
|
22
|
+
def archspec
|
|
23
|
+
sh "bundle exec archspec check"
|
|
24
|
+
end
|
|
25
|
+
|
|
21
26
|
class DocsCommands < Tasks
|
|
22
27
|
desc "Build YARD + MkDocs documentation"
|
|
23
28
|
def build
|
data/Archspec.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
component :robot, in: "lib/robot_lab/robot.rb"
|
|
2
|
+
component :robot_support, in: "lib/robot_lab/robot/**/*.rb"
|
|
3
|
+
component :network, in: ["lib/robot_lab/network.rb", "lib/robot_lab/bus_poller.rb"]
|
|
4
|
+
component :memory, in: ["lib/robot_lab/memory.rb", "lib/robot_lab/memory_change.rb"]
|
|
5
|
+
component :mcp, in: "lib/robot_lab/mcp/**/*.rb"
|
|
6
|
+
component :sandbox, in: ["lib/robot_lab/sandbox.rb", "lib/robot_lab/sandbox/**/*.rb"]
|
|
7
|
+
component :streaming, in: "lib/robot_lab/streaming/**/*.rb"
|
|
8
|
+
component :budget, in: "lib/robot_lab/budget/**/*.rb"
|
|
9
|
+
component :hooks, in: %w[
|
|
10
|
+
lib/robot_lab/hook.rb
|
|
11
|
+
lib/robot_lab/hook_context.rb
|
|
12
|
+
lib/robot_lab/hook_registry.rb
|
|
13
|
+
lib/robot_lab/hooks.rb
|
|
14
|
+
]
|
|
15
|
+
component :tools, in: %w[
|
|
16
|
+
lib/robot_lab/tool.rb
|
|
17
|
+
lib/robot_lab/tool_config.rb
|
|
18
|
+
lib/robot_lab/tool_manifest.rb
|
|
19
|
+
lib/robot_lab/script_tool.rb
|
|
20
|
+
]
|
|
21
|
+
component :config, in: ["lib/robot_lab/config.rb", "lib/robot_lab/run_config.rb"]
|
|
22
|
+
|
|
23
|
+
# NOTE: every file here reopens `module RobotLab`, so a `dependencies.forbid`
|
|
24
|
+
# rule keyed on components (e.g. `memory.cannot_use :robot`) treats a plain
|
|
25
|
+
# `RobotLab.config` call as "depends on every component" — every file
|
|
26
|
+
# "defines" the bare RobotLab constant. Naming the actual target constants
|
|
27
|
+
# instead of components sidesteps that ambiguity.
|
|
28
|
+
|
|
29
|
+
# Memory is a low-level primitive shared by Robot and Network; it must not
|
|
30
|
+
# depend back on the things that depend on it.
|
|
31
|
+
memory.cannot_reference_constants "RobotLab::Robot", "RobotLab::Network"
|
|
32
|
+
|
|
33
|
+
# MCP is an external-tool integration layer that Robot/Network consume; it
|
|
34
|
+
# must not reach back into the objects that use it.
|
|
35
|
+
mcp.cannot_reference_constants "RobotLab::Robot", "RobotLab::Network"
|
|
36
|
+
|
|
37
|
+
# Sandbox runs untrusted/generated code paths and should have the smallest
|
|
38
|
+
# possible surface area — no reaching into orchestration or memory internals.
|
|
39
|
+
sandbox.cannot_reference_constants "RobotLab::Robot", "RobotLab::Network", "RobotLab::Memory"
|
|
40
|
+
|
|
41
|
+
# Config/RunConfig sits at the bottom of the configuration cascade
|
|
42
|
+
# (RobotLab.config -> Network -> Robot -> template -> task -> runtime) and
|
|
43
|
+
# must not depend upward on the objects it configures.
|
|
44
|
+
config.cannot_reference_constants "RobotLab::Robot", "RobotLab::Network"
|
data/CHANGELOG.md
CHANGED
|
@@ -6,7 +6,60 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
## [
|
|
9
|
+
## [0.3.0] - 2026-09-18
|
|
10
|
+
|
|
11
|
+
The ruby_llm 2.0 release. Core moves from ruby_llm 1.x to the official 2.0.0
|
|
12
|
+
release; every `robot_lab-*` extension gem releases in lockstep at 0.3.0 and
|
|
13
|
+
now requires `robot_lab ~> 0.3.0`.
|
|
14
|
+
|
|
15
|
+
### Changed (BREAKING)
|
|
16
|
+
- **ruby_llm 1.x → 2.0.** The gemspec now requires `ruby_llm "~> 2.0"`
|
|
17
|
+
(official release). Robot tools written with the 1.x DSL must migrate:
|
|
18
|
+
`param` → `parameter`, `desc:` → `description:`; `halt` is gone (the caller
|
|
19
|
+
controls the loop). Token counts moved to `response.tokens.input/.output`,
|
|
20
|
+
and `finish_reason` (Symbol) replaces `stop_reason`. The `claude-sonnet-4`
|
|
21
|
+
registry alias no longer resolves; the default models are now
|
|
22
|
+
`claude-sonnet-4-6` (production) and `claude-haiku-4-5` (test).
|
|
23
|
+
- **Dropped hard dependencies** on `ruby_llm-mcp`, `ruby_llm-schema`, and
|
|
24
|
+
`ruby_llm-semantic_cache`. Semantic caching is now optional: `Memory#cache`
|
|
25
|
+
returns `nil` when `ruby_llm-semantic_cache` is not installed and Memory
|
|
26
|
+
runs with caching disabled. (Its released versions still pin ruby_llm 1.x,
|
|
27
|
+
so it cannot co-resolve with 2.0 yet.)
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- `ruby_llm-providers-apfel` and `ruby_llm-providers-lms` (`~> 0.2.1`) as
|
|
31
|
+
runtime dependencies, consumed as released gems — the local `path:`
|
|
32
|
+
overrides for sibling checkouts are gone from the Gemfiles.
|
|
33
|
+
- `Robot::ResultBuilding` — extracted module that adapts a ruby_llm response
|
|
34
|
+
into a `RobotResult` (token accounting, stop-reason normalization, message
|
|
35
|
+
coercion).
|
|
36
|
+
- `examples/run_all.rb` — runs every executable `NN_*.rb` demo serially with
|
|
37
|
+
a banner between each; works from any cwd, and Ctrl-C terminates only the
|
|
38
|
+
demo currently running (the runner notes it and moves on).
|
|
39
|
+
- READMEs for the subdirectory demos: `15_memory_network_and_bus`,
|
|
40
|
+
`26_document_store` (corpus), and `27_incident_response`.
|
|
41
|
+
- Fasterer quality gate now actually runs: `fasterer` added to the
|
|
42
|
+
development group, with a `.fasterer.yml` documenting the disabled
|
|
43
|
+
speed-over-readability checks.
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
- Robot, Tool, RunConfig, and the hook system adapted to the ruby_llm 2.0
|
|
47
|
+
API; docs and examples synced to match.
|
|
48
|
+
- Examples run against a local LM Studio server through the `:lms` provider;
|
|
49
|
+
`examples/common.rb` anchors `BUNDLE_GEMFILE` to the gem root so demos run
|
|
50
|
+
from any directory, and `examples/README.md` notes that demo speed and
|
|
51
|
+
answer quality depend on the provider/model in use.
|
|
52
|
+
- `.envrc` no longer exports `BUNDLE_GEMFILE`; it is inherited from the
|
|
53
|
+
project root (`asgard dev` / `asgard prod`).
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
- amazing_print 3.0 crash at demo startup (`undefined method 'try' for
|
|
57
|
+
module ActiveSupport`): robot_lab's dependencies load parts of
|
|
58
|
+
ActiveSupport, which tricked amazing_print into loading its Rails
|
|
59
|
+
extension; `examples/common.rb` now preloads
|
|
60
|
+
`active_support/core_ext/object/try` and `active_support/log_subscriber`.
|
|
61
|
+
|
|
62
|
+
## [0.2.8] - 2026-09-09
|
|
10
63
|
|
|
11
64
|
### Added
|
|
12
65
|
- `BusMessaging#respond_to_tasks` and `#serve` — a member auto-answers inbound
|
|
@@ -16,6 +69,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
16
69
|
without hand-wiring `on_message`.
|
|
17
70
|
- `.loki` Asgard task file: `test`, `rubocop`, `rubocop_fix`, `flog`, `flay`, `quality`, `build`, `install`, `release`, `integration`, `docs`, and `examples` tasks via the Asgard task runner
|
|
18
71
|
|
|
72
|
+
### Changed (BREAKING)
|
|
73
|
+
- **Sandboxing extracted to `robot_lab-sandbox`.** `RobotLab::Sandbox`,
|
|
74
|
+
`RobotLab::Sandbox::Seatbelt`, and `RobotLab::Sandbox::Null` no longer live
|
|
75
|
+
in core; they moved verbatim to the new `robot_lab-sandbox` gem. Core has no
|
|
76
|
+
execution limitations of its own: `ScriptTool.execute` now delegates to an
|
|
77
|
+
optional `ScriptTool.executor` (`nil` by default, in which case it runs the
|
|
78
|
+
unconfined `Open3.capture2e` path with no timeout exactly as before).
|
|
79
|
+
Applications that want confined skill-script execution must add
|
|
80
|
+
`gem "robot_lab-sandbox"` and `require "robot_lab/sandbox"`, which installs
|
|
81
|
+
itself as the executor; `config.sandbox.*` behavior is unchanged from there.
|
|
82
|
+
`RobotLab::Capabilities` (the declarative fs_read/fs_write/network/timeout/
|
|
83
|
+
trust manifest parsed from `SKILL.md`) stays in core since `AgentSkill` needs
|
|
84
|
+
it regardless of whether sandboxing is enforced.
|
|
85
|
+
- `ScriptTool.run_with_timeout` and `ScriptTool.terminate` moved to
|
|
86
|
+
`RobotLab::Sandbox::Executor` in `robot_lab-sandbox`.
|
|
87
|
+
|
|
19
88
|
### Fixed
|
|
20
89
|
- `BusMessaging` now synchronizes its message counter and outbox with a mutex, so
|
|
21
90
|
concurrent sends and poller-thread reply correlation can't clobber each other.
|
data/CLAUDE.md
CHANGED
|
@@ -55,7 +55,7 @@ bundle exec rake examples:run[1]
|
|
|
55
55
|
|
|
56
56
|
### Memory System
|
|
57
57
|
|
|
58
|
-
- **`Memory`** (`lib/robot_lab/memory.rb`): Key-value store with reserved keys (`:data`, `:results`, `:messages`, `:session_id`, `:cache`). Supports Redis backend.
|
|
58
|
+
- **`Memory`** (`lib/robot_lab/memory.rb`): Key-value store with reserved keys (`:data`, `:results`, `:messages`, `:session_id`, `:cache`). Supports Redis backend. Semantic caching via RubyLLM::SemanticCache when the optional ruby_llm-semantic_cache gem is installed (`memory.cache` is nil otherwise)
|
|
59
59
|
|
|
60
60
|
### MCP (Model Context Protocol)
|
|
61
61
|
|
|
@@ -119,7 +119,9 @@ Router receives `Router::Args` with: `context`, `network`, `stack`, `call_count`
|
|
|
119
119
|
|
|
120
120
|
## Dependencies
|
|
121
121
|
|
|
122
|
-
Core: zeitwerk, ruby_llm (~>
|
|
122
|
+
Core: zeitwerk, ruby_llm (~> 2.0.0.rc3), prompt_manager, async, simple_flow, state_machines
|
|
123
|
+
|
|
124
|
+
Optional: ruby_llm-semantic_cache (Memory#cache; no ruby_llm 2.0-compatible release yet — Memory runs with caching disabled when absent), classifier (compress_history), ruby_llm-providers-lms (local LM Studio provider used by the examples: qwen/qwen3.8-27b for complex work, openai/gpt-oss-20b for simple demos)
|
|
123
125
|
|
|
124
126
|
### Templates
|
|
125
127
|
|
data/README.md
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
- <strong>Human-in-the-Loop</strong> - AskUser tool for interactive prompting<br>
|
|
22
22
|
- <strong>Content Streaming</strong> - Stored callbacks, per-call blocks, or both<br>
|
|
23
23
|
- <strong>MCP Integration</strong> - Connect to external tool servers with timeouts and retry<br>
|
|
24
|
-
- <strong>Local LLM Providers</strong> - Ollama and GPUStack via provider passthrough<br>
|
|
24
|
+
- <strong>Local LLM Providers</strong> - LM Studio (via ruby_llm-providers-lms), Ollama, and GPUStack via provider passthrough<br>
|
|
25
25
|
- <strong>Shared Memory</strong> - Reactive key-value store with subscriptions<br>
|
|
26
26
|
- <strong>Message Bus</strong> - Bidirectional robot communication via TypedBus<br>
|
|
27
27
|
- <strong>Dynamic Spawning</strong> - Robots create new robots at runtime<br>
|
|
@@ -82,17 +82,15 @@ puts result.last_text_content
|
|
|
82
82
|
|
|
83
83
|
### Local LLM Providers
|
|
84
84
|
|
|
85
|
-
For local LLM providers, use the `provider:` parameter. RubyLLM's provider list is the authority on valid values — `:ollama` and `:gpustack` are
|
|
86
|
-
|
|
87
|
-
```bash
|
|
88
|
-
export ROBOT_LAB_RUBY_LLM__OLLAMA_API_BASE=http://localhost:11434/v1
|
|
89
|
-
```
|
|
85
|
+
For local LLM providers, use the `provider:` parameter. RubyLLM's provider list is the authority on valid values — `:ollama` and `:gpustack` are built in, and provider gems add more (alongside `:anthropic`, `:azure`, `:bedrock`, `:deepseek`, `:gemini`, `:mistral`, `:openai`, `:openrouter`, `:perplexity`, `:vertexai`, and `:xai`). The examples in this repo use LM Studio through the [ruby_llm-providers-lms](https://github.com/madbomber/ruby_llm-providers-lms) gem, which registers the `:lms` provider (defaults to `http://localhost:1234/v1`, no API key needed):
|
|
90
86
|
|
|
91
87
|
```ruby
|
|
88
|
+
require "ruby_llm/providers/lms"
|
|
89
|
+
|
|
92
90
|
robot = RobotLab.build(
|
|
93
91
|
name: "local_bot",
|
|
94
|
-
model: "
|
|
95
|
-
provider: :
|
|
92
|
+
model: "qwen/qwen3.8-27b", # complex work; use "openai/gpt-oss-20b" for simple chat
|
|
93
|
+
provider: :lms,
|
|
96
94
|
system_prompt: "You are a helpful assistant."
|
|
97
95
|
)
|
|
98
96
|
```
|
|
@@ -113,12 +111,12 @@ RobotLab uses [MywayConfig](https://github.com/MadBomber/myway_config) for layer
|
|
|
113
111
|
# Set API keys via environment variables (double underscore for nesting)
|
|
114
112
|
export ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY=sk-ant-...
|
|
115
113
|
export ROBOT_LAB_RUBY_LLM__OPENAI_API_KEY=sk-...
|
|
116
|
-
export ROBOT_LAB_RUBY_LLM__MODEL=claude-sonnet-4
|
|
114
|
+
export ROBOT_LAB_RUBY_LLM__MODEL=claude-sonnet-4-6
|
|
117
115
|
```
|
|
118
116
|
|
|
119
117
|
```ruby
|
|
120
118
|
# Access configuration values
|
|
121
|
-
RobotLab.config.ruby_llm.model #=> "claude-sonnet-4"
|
|
119
|
+
RobotLab.config.ruby_llm.model #=> "claude-sonnet-4-6"
|
|
122
120
|
RobotLab.config.ruby_llm.request_timeout #=> 120
|
|
123
121
|
```
|
|
124
122
|
|
|
@@ -126,7 +124,7 @@ Or create a project config file at `./config/robot_lab.yml`:
|
|
|
126
124
|
|
|
127
125
|
```yaml
|
|
128
126
|
ruby_llm:
|
|
129
|
-
model: claude-sonnet-4
|
|
127
|
+
model: claude-sonnet-4-6
|
|
130
128
|
anthropic_api_key: sk-ant-...
|
|
131
129
|
request_timeout: 180
|
|
132
130
|
```
|
|
@@ -202,7 +200,7 @@ mcp:
|
|
|
202
200
|
type: stdio
|
|
203
201
|
command: npx
|
|
204
202
|
args: ["-y", "@modelcontextprotocol/server-github"]
|
|
205
|
-
model: claude-sonnet-4
|
|
203
|
+
model: claude-sonnet-4-6
|
|
206
204
|
---
|
|
207
205
|
You are a GitHub assistant. Use available tools to help with repository tasks.
|
|
208
206
|
```
|
|
@@ -265,7 +263,7 @@ robot = RobotLab.build(
|
|
|
265
263
|
```ruby
|
|
266
264
|
# Create a shared config
|
|
267
265
|
shared = RobotLab::RunConfig.new(
|
|
268
|
-
model: "claude-sonnet-4",
|
|
266
|
+
model: "claude-sonnet-4-6",
|
|
269
267
|
temperature: 0.7,
|
|
270
268
|
max_tokens: 2000
|
|
271
269
|
)
|
|
@@ -302,16 +300,16 @@ RunConfig supports keyword construction, block DSL, and merge semantics:
|
|
|
302
300
|
```ruby
|
|
303
301
|
# Block DSL
|
|
304
302
|
config = RobotLab::RunConfig.new do |c|
|
|
305
|
-
c.model "claude-sonnet-4"
|
|
303
|
+
c.model "claude-sonnet-4-6"
|
|
306
304
|
c.temperature 0.7
|
|
307
305
|
end
|
|
308
306
|
|
|
309
307
|
# Merge (more-specific wins)
|
|
310
|
-
network_config = RobotLab::RunConfig.new(model: "claude-sonnet-4", temperature: 0.5)
|
|
308
|
+
network_config = RobotLab::RunConfig.new(model: "claude-sonnet-4-6", temperature: 0.5)
|
|
311
309
|
robot_config = RobotLab::RunConfig.new(temperature: 0.9)
|
|
312
310
|
effective = network_config.merge(robot_config)
|
|
313
311
|
effective.temperature #=> 0.9
|
|
314
|
-
effective.model #=> "claude-sonnet-4"
|
|
312
|
+
effective.model #=> "claude-sonnet-4-6"
|
|
315
313
|
```
|
|
316
314
|
|
|
317
315
|
### Chaining Configuration
|
|
@@ -323,7 +321,7 @@ robot = RobotLab.build(name: "writer", system_prompt: "You are a creative writer
|
|
|
323
321
|
|
|
324
322
|
result = robot
|
|
325
323
|
.with_temperature(0.9)
|
|
326
|
-
.with_model("claude-sonnet-4")
|
|
324
|
+
.with_model("claude-sonnet-4-6")
|
|
327
325
|
.run("Write a haiku about Ruby programming")
|
|
328
326
|
```
|
|
329
327
|
|
data/Rakefile
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
# Quality gates (quality, rubocop_check, flog_check, flay_check,
|
|
4
|
+
# archspec_check, ...), doc *serving*, and the gem lifecycle (build, install,
|
|
5
|
+
# release) live in asgard — see .loki and the shared dev/*.loki files it
|
|
6
|
+
# imports. This Rakefile keeps the tasks asgard delegates to (tests,
|
|
7
|
+
# integration, examples, docs:build).
|
|
5
8
|
|
|
6
|
-
|
|
9
|
+
require "rake/testtask"
|
|
7
10
|
|
|
8
11
|
Rake::TestTask.new(:test) do |t|
|
|
9
12
|
t.libs << "test"
|
|
@@ -36,100 +39,6 @@ Rake::TestTask.new(:integration) do |t|
|
|
|
36
39
|
t.ruby_opts << "-rtest_helper"
|
|
37
40
|
end
|
|
38
41
|
|
|
39
|
-
desc "Check code complexity with Flog (warn ≥20, fail ≥50)"
|
|
40
|
-
task :flog_check do
|
|
41
|
-
require 'flog'
|
|
42
|
-
|
|
43
|
-
# Target to work toward; methods above this are warned but don't fail the gate.
|
|
44
|
-
METHOD_WARN = 20.0
|
|
45
|
-
# Current baseline floor — established from first run. Reduce incrementally.
|
|
46
|
-
METHOD_FAIL = 50.0
|
|
47
|
-
|
|
48
|
-
flogger = Flog.new(all: true)
|
|
49
|
-
flogger.flog(*Dir.glob('lib/**/*.rb'))
|
|
50
|
-
|
|
51
|
-
warnings = []
|
|
52
|
-
failures = []
|
|
53
|
-
|
|
54
|
-
flogger.each_by_score do |method, score|
|
|
55
|
-
next if method.end_with?('#none') # skip file-level non-method code
|
|
56
|
-
if score > METHOD_FAIL
|
|
57
|
-
failures << "#{'%.1f' % score}: #{method}"
|
|
58
|
-
elsif score > METHOD_WARN
|
|
59
|
-
warnings << "#{'%.1f' % score}: #{method}"
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
unless warnings.empty?
|
|
64
|
-
puts "\nFlog warnings (#{METHOD_WARN}–#{METHOD_FAIL}) — target for future refactoring:"
|
|
65
|
-
warnings.each { |v| puts " #{v}" }
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
if failures.empty?
|
|
69
|
-
puts "\nFlog: no methods exceed the failure threshold (≥#{METHOD_FAIL})"
|
|
70
|
-
else
|
|
71
|
-
puts "\nFlog failures (≥#{METHOD_FAIL}) — must be refactored:"
|
|
72
|
-
failures.each { |v| puts " #{v}" }
|
|
73
|
-
abort "\nFlog quality gate failed: #{failures.size} method(s) exceed #{METHOD_FAIL}"
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
desc "Check for structural code duplication with Flay (mass >= 50)"
|
|
78
|
-
task :flay_check do
|
|
79
|
-
require 'flay'
|
|
80
|
-
|
|
81
|
-
mass_threshold = 50
|
|
82
|
-
|
|
83
|
-
flay = Flay.new({ mass: mass_threshold, diff: false, verbose: false, summary: false, timeout: 60 })
|
|
84
|
-
flay.process(*Dir.glob('lib/**/*.rb'))
|
|
85
|
-
flay.analyze
|
|
86
|
-
|
|
87
|
-
if flay.hashes.empty?
|
|
88
|
-
puts "\nFlay: no structural duplication detected (mass >= #{mass_threshold})"
|
|
89
|
-
else
|
|
90
|
-
puts "\nFlay found structural duplication (mass >= #{mass_threshold}):"
|
|
91
|
-
flay.report
|
|
92
|
-
abort "\nFlay quality gate failed: #{flay.hashes.length} pattern(s) detected"
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
desc "Run all quality checks: tests (with coverage), RuboCop, Flog, and Flay"
|
|
97
|
-
task :quality do
|
|
98
|
-
results = {}
|
|
99
|
-
|
|
100
|
-
puts "\n#{'=' * 60}"
|
|
101
|
-
puts "Quality Gate: Tests + Coverage"
|
|
102
|
-
puts '=' * 60
|
|
103
|
-
results[:tests] = system("bundle exec rake test") ? :pass : :fail
|
|
104
|
-
|
|
105
|
-
puts "\n#{'=' * 60}"
|
|
106
|
-
puts "Quality Gate: RuboCop"
|
|
107
|
-
puts '=' * 60
|
|
108
|
-
results[:rubocop] = system(RUBOCOP_ENV, "bundle exec rubocop") ? :pass : :fail
|
|
109
|
-
|
|
110
|
-
puts "\n#{'=' * 60}"
|
|
111
|
-
puts "Quality Gate: Flog Complexity"
|
|
112
|
-
puts '=' * 60
|
|
113
|
-
results[:flog] = system("bundle exec rake flog_check") ? :pass : :fail
|
|
114
|
-
|
|
115
|
-
puts "\n#{'=' * 60}"
|
|
116
|
-
puts "Quality Gate: Flay Duplication"
|
|
117
|
-
puts '=' * 60
|
|
118
|
-
results[:flay] = system("bundle exec rake flay_check") ? :pass : :fail
|
|
119
|
-
|
|
120
|
-
puts "\n#{'=' * 60}"
|
|
121
|
-
puts "Quality Summary"
|
|
122
|
-
puts '=' * 60
|
|
123
|
-
results.each do |gate, status|
|
|
124
|
-
icon = status == :pass ? 'PASS' : 'FAIL'
|
|
125
|
-
puts " [#{icon}] #{gate}"
|
|
126
|
-
end
|
|
127
|
-
puts '=' * 60
|
|
128
|
-
|
|
129
|
-
abort "\nQuality gate failed" if results.values.any?(:fail)
|
|
130
|
-
puts "\nAll quality gates passed."
|
|
131
|
-
end
|
|
132
|
-
|
|
133
42
|
namespace :examples do
|
|
134
43
|
# Map of subdirectory-based demos to their entry point scripts
|
|
135
44
|
SUBDIR_ENTRY_POINTS = {
|
|
@@ -277,22 +186,8 @@ namespace :docs do
|
|
|
277
186
|
sh "yard doc"
|
|
278
187
|
end
|
|
279
188
|
|
|
280
|
-
namespace :yard do
|
|
281
|
-
desc "Serve YARD documentation locally"
|
|
282
|
-
task :serve do
|
|
283
|
-
sh "yard server --reload"
|
|
284
|
-
end
|
|
285
|
-
end
|
|
286
|
-
|
|
287
189
|
desc "Build MkDocs documentation"
|
|
288
190
|
task :mkdocs do
|
|
289
191
|
sh "mkdocs build"
|
|
290
192
|
end
|
|
291
|
-
|
|
292
|
-
namespace :mkdocs do
|
|
293
|
-
desc "Serve MkDocs documentation locally"
|
|
294
|
-
task :serve do
|
|
295
|
-
sh "mkdocs serve"
|
|
296
|
-
end
|
|
297
|
-
end
|
|
298
193
|
end
|
data/_typos.toml
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# False-positive suppressions for the typos quality gate (asgard).
|
|
2
|
+
# Everything here was reviewed by hand — see git history for context.
|
|
3
|
+
|
|
4
|
+
[files]
|
|
5
|
+
extend-exclude = [
|
|
6
|
+
# Example transcripts / articles: prose quotes real names ("Damon Clark")
|
|
7
|
+
# and SQL-ish plurals ("SELECTs") that typos mis-parses.
|
|
8
|
+
"examples/ruboruby.md",
|
|
9
|
+
"examples/25_history_search/conversation.jsonl",
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
[default.extend-identifiers]
|
|
13
|
+
# Robot names in lib/robot_lab/names.rb
|
|
14
|
+
BATs = "BATs"
|
|
15
|
+
Damon = "Damon"
|
|
16
|
+
Mata_Nui = "Mata_Nui"
|
|
17
|
+
Pris = "Pris"
|
|
18
|
+
S1MONE = "S1MONE"
|
|
19
|
+
# Test-local variable names
|
|
20
|
+
ba = "ba" # b→a similarity (convergence_test.rb)
|
|
21
|
+
thr = "thr" # thread handle (connection_poller_test.rb)
|
data/docs/api/index.md
CHANGED
|
@@ -41,8 +41,8 @@ confines them:
|
|
|
41
41
|
| [AgentSkill](skills.md#robotlabagentskill) | One skill bundle: instructions + `scripts/` |
|
|
42
42
|
| [AgentSkillCatalog](skills.md#robotlabagentskillcatalog) | Lazy registry over `~/.prompts/skills/` |
|
|
43
43
|
| [Capabilities](skills.md#robotlabcapabilities) | Declared vs. ceiling filesystem / network / timeout grant |
|
|
44
|
-
| [ScriptTool](skills.md#robotlabscripttool) | Wraps an executable script as a `Tool` |
|
|
45
|
-
| [Sandbox](skills.md#
|
|
44
|
+
| [ScriptTool](skills.md#robotlabscripttool) | Wraps an executable script as a `Tool`; `ScriptTool.executor` is the confinement extension point |
|
|
45
|
+
| [Sandbox](skills.md#confinement-robot_lab-sandbox) | macOS Seatbelt confinement, or a passthrough — ships in the optional `robot_lab-sandbox` gem |
|
|
46
46
|
|
|
47
47
|
## Support Classes
|
|
48
48
|
|