robot_lab 0.3.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +1 -1
- data/lib/robot_lab/mcp/transports/streamable_http.rb +1 -1
- data/lib/robot_lab/version.rb +1 -1
- metadata +3 -253
- data/.architecture/AGENTS.md +0 -32
- data/.architecture/config.yml +0 -8
- data/.architecture/members.yml +0 -60
- data/.architecture/reviews/feature-free-will.md +0 -490
- data/.architecture/reviews/overall-codebase.md +0 -427
- data/.claude/settings.local.json +0 -57
- data/.codex/config.toml +0 -2
- data/.envrc +0 -6
- data/.github/workflows/deploy-github-pages.yml +0 -52
- data/.irbrc +0 -6
- data/.loki +0 -65
- data/.quality/reek_baseline.txt +0 -43
- data/.rubocop.yml +0 -10
- data/Archspec.rb +0 -44
- data/CLAUDE.md +0 -141
- data/COMMITS.md +0 -196
- data/Rakefile +0 -193
- data/_typos.toml +0 -21
- data/agent2agent_review.md +0 -192
- data/agentf_improvements.md +0 -253
- data/agents.md +0 -14
- data/docs/api/core/index.md +0 -147
- data/docs/api/core/memory.md +0 -578
- data/docs/api/core/network.md +0 -553
- data/docs/api/core/result.md +0 -211
- data/docs/api/core/robot.md +0 -1667
- data/docs/api/core/state.md +0 -145
- data/docs/api/core/tool.md +0 -520
- data/docs/api/errors.md +0 -323
- data/docs/api/hooks.md +0 -469
- data/docs/api/index.md +0 -137
- data/docs/api/mcp/client.md +0 -387
- data/docs/api/mcp/index.md +0 -267
- data/docs/api/mcp/server.md +0 -252
- data/docs/api/mcp/transports.md +0 -339
- data/docs/api/messages/index.md +0 -126
- data/docs/api/messages/text-message.md +0 -170
- data/docs/api/messages/tool-call-message.md +0 -206
- data/docs/api/messages/tool-result-message.md +0 -242
- data/docs/api/messages/user-message.md +0 -232
- data/docs/api/skills.md +0 -423
- data/docs/api/streaming/context.md +0 -280
- data/docs/api/streaming/events.md +0 -185
- data/docs/api/streaming/index.md +0 -156
- data/docs/api/support.md +0 -846
- data/docs/architecture/core-concepts.md +0 -575
- data/docs/architecture/index.md +0 -252
- data/docs/architecture/message-flow.md +0 -366
- data/docs/architecture/network-orchestration.md +0 -478
- data/docs/architecture/robot-execution.md +0 -396
- data/docs/architecture/state-management.md +0 -410
- data/docs/assets/css/custom.css +0 -56
- data/docs/assets/images/robot_lab.jpg +0 -0
- data/docs/concepts.md +0 -641
- data/docs/examples/basic-chat.md +0 -258
- data/docs/examples/index.md +0 -425
- data/docs/examples/mcp-server.md +0 -403
- data/docs/examples/multi-robot-network.md +0 -476
- data/docs/examples/tool-usage.md +0 -468
- data/docs/getting-started/configuration.md +0 -645
- data/docs/getting-started/index.md +0 -56
- data/docs/getting-started/installation.md +0 -197
- data/docs/getting-started/quick-start.md +0 -293
- data/docs/guides/building-robots.md +0 -1187
- data/docs/guides/creating-networks.md +0 -736
- data/docs/guides/hooks.md +0 -1206
- data/docs/guides/index.md +0 -78
- data/docs/guides/knowledge.md +0 -219
- data/docs/guides/mcp-integration.md +0 -740
- data/docs/guides/memory.md +0 -458
- data/docs/guides/observability.md +0 -733
- data/docs/guides/streaming.md +0 -323
- data/docs/guides/using-tools.md +0 -780
- data/docs/index.md +0 -280
- data/docs/superpowers/plans/2026-05-06-agentskills.md +0 -1303
- data/docs/superpowers/specs/2026-05-06-agentskills-design.md +0 -247
- data/examples/.envrc +0 -3
- data/examples/01_simple_robot.rb +0 -31
- data/examples/02_tools.rb +0 -109
- data/examples/03_network.rb +0 -118
- data/examples/04_mcp.rb +0 -217
- data/examples/05_streaming.rb +0 -137
- data/examples/06_prompt_templates.rb +0 -325
- data/examples/07_network_memory.rb +0 -313
- data/examples/08_llm_config.rb +0 -162
- data/examples/09_chaining.rb +0 -251
- data/examples/10_memory.rb +0 -315
- data/examples/11_network_introspection.rb +0 -239
- data/examples/12_message_bus.rb +0 -67
- data/examples/13_spawn.rb +0 -85
- data/examples/14_rusty_circuit/.envrc +0 -1
- data/examples/14_rusty_circuit/.gitignore +0 -1
- data/examples/14_rusty_circuit/README.md +0 -1
- data/examples/14_rusty_circuit/comic.rb +0 -149
- data/examples/14_rusty_circuit/display.rb +0 -217
- data/examples/14_rusty_circuit/heckler.rb +0 -65
- data/examples/14_rusty_circuit/open_mic.rb +0 -132
- data/examples/14_rusty_circuit/prompts/open_mic_comic.md +0 -20
- data/examples/14_rusty_circuit/prompts/open_mic_heckler.md +0 -23
- data/examples/14_rusty_circuit/prompts/open_mic_scout.md +0 -20
- data/examples/14_rusty_circuit/scout.rb +0 -165
- data/examples/14_rusty_circuit/show.log +0 -234
- data/examples/15_memory_network_and_bus/.envrc +0 -1
- data/examples/15_memory_network_and_bus/README.md +0 -66
- data/examples/15_memory_network_and_bus/editor_in_chief.rb +0 -24
- data/examples/15_memory_network_and_bus/editorial_pipeline.rb +0 -213
- data/examples/15_memory_network_and_bus/linux_writer.rb +0 -80
- data/examples/15_memory_network_and_bus/os_editor.rb +0 -48
- data/examples/15_memory_network_and_bus/os_writer.rb +0 -49
- data/examples/15_memory_network_and_bus/output/combined_article.md +0 -11
- data/examples/15_memory_network_and_bus/output/final_article.md +0 -8
- data/examples/15_memory_network_and_bus/output/linux_draft.md +0 -7
- data/examples/15_memory_network_and_bus/output/mac_draft.md +0 -7
- data/examples/15_memory_network_and_bus/output/memory.json +0 -13
- data/examples/15_memory_network_and_bus/output/revision_1.md +0 -29
- data/examples/15_memory_network_and_bus/output/revision_2.md +0 -50
- data/examples/15_memory_network_and_bus/output/revision_3.md +0 -8
- data/examples/15_memory_network_and_bus/output/windows_draft.md +0 -7
- data/examples/15_memory_network_and_bus/prompts/os_advocate.md +0 -13
- data/examples/15_memory_network_and_bus/prompts/os_chief.md +0 -13
- data/examples/15_memory_network_and_bus/prompts/os_editor.md +0 -13
- data/examples/16_writers_room/.envrc +0 -1
- data/examples/16_writers_room/display.rb +0 -158
- data/examples/16_writers_room/output/.gitignore +0 -4
- data/examples/16_writers_room/output/README.md +0 -69
- data/examples/16_writers_room/output/opus_001.md +0 -263
- data/examples/16_writers_room/output/opus_001_notes.log +0 -470
- data/examples/16_writers_room/output/opus_002.md +0 -245
- data/examples/16_writers_room/output/opus_002_notes.log +0 -546
- data/examples/16_writers_room/output/opus_002_screenplay.md +0 -7989
- data/examples/16_writers_room/output/opus_002_screenplay_notes.md +0 -993
- data/examples/16_writers_room/prompts/screenplay_writer.md +0 -66
- data/examples/16_writers_room/prompts/writer.md +0 -37
- data/examples/16_writers_room/room.rb +0 -186
- data/examples/16_writers_room/tools.rb +0 -173
- data/examples/16_writers_room/writer.rb +0 -121
- data/examples/16_writers_room/writers_room.rb +0 -256
- data/examples/17_skills.rb +0 -234
- data/examples/18_rails/.envrc +0 -3
- data/examples/18_rails/.gitignore +0 -5
- data/examples/18_rails/Gemfile +0 -11
- data/examples/18_rails/README.md +0 -67
- data/examples/18_rails/Rakefile +0 -4
- data/examples/18_rails/app/controllers/application_controller.rb +0 -4
- data/examples/18_rails/app/controllers/chat_controller.rb +0 -50
- data/examples/18_rails/app/jobs/application_job.rb +0 -4
- data/examples/18_rails/app/jobs/robot_run_job.rb +0 -25
- data/examples/18_rails/app/models/application_record.rb +0 -5
- data/examples/18_rails/app/models/robot_lab_result.rb +0 -36
- data/examples/18_rails/app/models/robot_lab_thread.rb +0 -23
- data/examples/18_rails/app/robots/chat_robot.rb +0 -25
- data/examples/18_rails/app/tools/time_tool.rb +0 -9
- data/examples/18_rails/app/views/chat/_user_message.html.erb +0 -1
- data/examples/18_rails/app/views/chat/index.html.erb +0 -67
- data/examples/18_rails/app/views/layouts/application.html.erb +0 -49
- data/examples/18_rails/bin/dev +0 -7
- data/examples/18_rails/bin/rails +0 -6
- data/examples/18_rails/bin/setup +0 -15
- data/examples/18_rails/config/application.rb +0 -33
- data/examples/18_rails/config/cable.yml +0 -2
- data/examples/18_rails/config/database.yml +0 -5
- data/examples/18_rails/config/environment.rb +0 -4
- data/examples/18_rails/config/initializers/robot_lab.rb +0 -11
- data/examples/18_rails/config/routes.rb +0 -6
- data/examples/18_rails/config.ru +0 -4
- data/examples/18_rails/db/migrate/001_create_robot_lab_tables.rb +0 -32
- data/examples/19_token_tracking.rb +0 -138
- data/examples/20_circuit_breaker.rb +0 -147
- data/examples/21_learning_loop.rb +0 -181
- data/examples/22_context_compression.rb +0 -172
- data/examples/23_convergence.rb +0 -133
- data/examples/24_structured_delegation.rb +0 -151
- data/examples/25_history_search/conversation.jsonl +0 -30
- data/examples/25_history_search.rb +0 -133
- data/examples/26_document_store/api_versioning_adr.md +0 -52
- data/examples/26_document_store/incident_postmortem.md +0 -46
- data/examples/26_document_store/postgres_runbook.md +0 -49
- data/examples/26_document_store/redis_caching_guide.md +0 -48
- data/examples/26_document_store/sidekiq_guide.md +0 -51
- data/examples/26_document_store.rb +0 -140
- data/examples/27_incident_response/README.md +0 -65
- data/examples/27_incident_response/incident_response.rb +0 -261
- data/examples/28_mcp_discovery.rb +0 -113
- data/examples/29_ractor_tools.rb +0 -240
- data/examples/30_ractor_network.rb +0 -252
- data/examples/31_launch_assessment.rb +0 -246
- data/examples/32_newsletter_reader.rb +0 -193
- data/examples/33_stock_generator.rb +0 -80
- data/examples/33_stock_predictor.rb +0 -327
- data/examples/34_agentskills.rb +0 -76
- data/examples/35_hooks.rb +0 -266
- data/examples/README.md +0 -550
- data/examples/common.rb +0 -180
- data/examples/prompts/assistant.md +0 -5
- data/examples/prompts/audit_trail.md +0 -8
- data/examples/prompts/billing.md +0 -10
- data/examples/prompts/classifier.md +0 -7
- data/examples/prompts/comedian.md +0 -6
- data/examples/prompts/comedy_critic.md +0 -10
- data/examples/prompts/configurable.md +0 -9
- data/examples/prompts/dispatcher.md +0 -12
- data/examples/prompts/entity_extractor.md +0 -14
- data/examples/prompts/escalation.md +0 -42
- data/examples/prompts/frontmatter_mcp_test.md +0 -9
- data/examples/prompts/frontmatter_named_test.md +0 -5
- data/examples/prompts/frontmatter_tools_test.md +0 -6
- data/examples/prompts/general.md +0 -7
- data/examples/prompts/github_assistant.md +0 -14
- data/examples/prompts/helper.md +0 -4
- data/examples/prompts/incident_responder.md +0 -18
- data/examples/prompts/keyword_extractor.md +0 -11
- data/examples/prompts/llm_config_demo.md +0 -20
- data/examples/prompts/order_support.md +0 -35
- data/examples/prompts/os_advocate.md +0 -13
- data/examples/prompts/os_chief.md +0 -13
- data/examples/prompts/os_editor.md +0 -13
- data/examples/prompts/parameterized_main_test.md +0 -6
- data/examples/prompts/pii_redactor.md +0 -7
- data/examples/prompts/product_support.md +0 -37
- data/examples/prompts/runbook_protocol.md +0 -12
- data/examples/prompts/sentiment_analyzer.md +0 -12
- data/examples/prompts/skill_a_test.md +0 -4
- data/examples/prompts/skill_b_test.md +0 -4
- data/examples/prompts/skill_config_test.md +0 -5
- data/examples/prompts/skill_cycle_a_test.md +0 -6
- data/examples/prompts/skill_cycle_b_test.md +0 -6
- data/examples/prompts/skill_description_test.md +0 -4
- data/examples/prompts/skill_leaf_test.md +0 -4
- data/examples/prompts/skill_nested_test.md +0 -6
- data/examples/prompts/skill_refs_main_test.md +0 -6
- data/examples/prompts/skill_self_ref_test.md +0 -6
- data/examples/prompts/skill_with_mcp_test.md +0 -9
- data/examples/prompts/skill_with_params_test.md +0 -6
- data/examples/prompts/skill_with_robot_name_test.md +0 -5
- data/examples/prompts/skill_with_tools_test.md +0 -6
- data/examples/prompts/sre_compliance.md +0 -10
- data/examples/prompts/structured_output.md +0 -7
- data/examples/prompts/synthesizer.md +0 -17
- data/examples/prompts/technical.md +0 -10
- data/examples/prompts/template_with_skills_test.md +0 -6
- data/examples/prompts/triage.md +0 -22
- data/examples/ruboruby.md +0 -423
- data/examples/run_all.rb +0 -60
- data/examples/xyzzy.rb +0 -97
- data/logfile +0 -8
- data/mkdocs.yml +0 -209
- data/robot_concurrency.md +0 -38
- data/simple_acp_review.md +0 -298
- data/temp.md +0 -6
- data/tool_manifest_plan.md +0 -155
data/examples/35_hooks.rb
DELETED
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Example 35: Hooks Architecture with robot_lab-xyzzy
|
|
5
|
-
#
|
|
6
|
-
# Demonstrates the hook handler class pattern. Hooks are named classes that
|
|
7
|
-
# inherit from RobotLab::Hook and implement class methods for each lifecycle
|
|
8
|
-
# phase they care about. All hooks are Ractor-safe by default.
|
|
9
|
-
#
|
|
10
|
-
# Usage:
|
|
11
|
-
# bundle exec ruby examples/35_hooks.rb
|
|
12
|
-
|
|
13
|
-
require_relative "common"
|
|
14
|
-
|
|
15
|
-
# RobotLab::Hook has no logger accessor — handlers own their own output.
|
|
16
|
-
# xyzzy.rb freezes its log destination into a constant at load time, so the
|
|
17
|
-
# redirect has to happen before the require.
|
|
18
|
-
XYZZY_LOG = File.join(__dir__, "xyzzy_hooks.log")
|
|
19
|
-
ENV["XYZZY_LOG_PATH"] = XYZZY_LOG
|
|
20
|
-
|
|
21
|
-
require_relative "xyzzy"
|
|
22
|
-
|
|
23
|
-
# ---------------------------------------------------------------------------
|
|
24
|
-
# Handler classes used in this demo
|
|
25
|
-
# ---------------------------------------------------------------------------
|
|
26
|
-
|
|
27
|
-
class RuntimeDemoHook < RobotLab::Hook
|
|
28
|
-
self.namespace = :runtime_demo
|
|
29
|
-
|
|
30
|
-
def self.after_run(ctx)
|
|
31
|
-
ctx.local.reply_seen = ctx.response.reply
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
class LocalDemoHook < RobotLab::Hook
|
|
36
|
-
self.namespace = :local_demo
|
|
37
|
-
|
|
38
|
-
def self.before_run(ctx)
|
|
39
|
-
ctx.local.note = "local robot hook state"
|
|
40
|
-
ctx.local.demo = "robot_run"
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
class PerfHook < RobotLab::Hook
|
|
45
|
-
self.namespace = :perf
|
|
46
|
-
@timings = []
|
|
47
|
-
@mutex = Mutex.new
|
|
48
|
-
|
|
49
|
-
class << self
|
|
50
|
-
def reset!
|
|
51
|
-
@mutex.synchronize { @timings = [] }
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def timings
|
|
55
|
-
@mutex.synchronize { @timings.dup }
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def around_run(ctx, &block)
|
|
59
|
-
t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
60
|
-
result = block.call
|
|
61
|
-
elapsed = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0) * 1_000).round(3)
|
|
62
|
-
@mutex.synchronize { @timings << elapsed }
|
|
63
|
-
puts " [perf] #{ctx.request.inspect} — #{elapsed}ms"
|
|
64
|
-
result
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
class GenerationTracerHook < RobotLab::Hook
|
|
70
|
-
self.namespace = :tracer
|
|
71
|
-
|
|
72
|
-
def self.before_llm_generation(ctx)
|
|
73
|
-
puts " [tracer] llm_generation start request=#{ctx.request.inspect}"
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def self.after_llm_generation(ctx)
|
|
77
|
-
msg = ctx.generation_response
|
|
78
|
-
puts " [tracer] llm_generation done model=#{msg&.model_id} tokens=#{msg&.output_tokens}"
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
class GenCacheHook < RobotLab::Hook
|
|
83
|
-
self.namespace = :gen_cache
|
|
84
|
-
@cache = {}
|
|
85
|
-
@mutex = Mutex.new
|
|
86
|
-
@call_count = 0
|
|
87
|
-
|
|
88
|
-
class << self
|
|
89
|
-
def reset!
|
|
90
|
-
@mutex.synchronize do
|
|
91
|
-
@cache = {}
|
|
92
|
-
@call_count = 0
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def call_count
|
|
97
|
-
@mutex.synchronize { @call_count }
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def around_llm_generation(ctx, &block)
|
|
101
|
-
cached = @mutex.synchronize { @cache[ctx.request] }
|
|
102
|
-
if cached
|
|
103
|
-
puts " [gen_cache] HIT — skipping LLM"
|
|
104
|
-
cached
|
|
105
|
-
else
|
|
106
|
-
puts " [gen_cache] MISS — calling LLM"
|
|
107
|
-
@mutex.synchronize { @call_count += 1 }
|
|
108
|
-
block.call.tap { |r| @mutex.synchronize { @cache[ctx.request] = r } }
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
class NetworkDemoHook < RobotLab::Hook
|
|
115
|
-
self.namespace = :network_demo
|
|
116
|
-
|
|
117
|
-
def self.before_task(ctx)
|
|
118
|
-
ctx.local.task_note = "network-scoped task hook"
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
# ---------------------------------------------------------------------------
|
|
123
|
-
|
|
124
|
-
HookDemoResponse = Data.define(:content, :tool_calls, :stop_reason) do
|
|
125
|
-
def initialize(content:, tool_calls: nil, stop_reason: "end_turn")
|
|
126
|
-
super
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
class HookDemoTool < RobotLab::Tool
|
|
131
|
-
description "Returns a deterministic hook demo value"
|
|
132
|
-
parameter :label, type: "string", description: "The label to echo"
|
|
133
|
-
|
|
134
|
-
def execute(label:)
|
|
135
|
-
{ label: label, status: "handled by HookDemoTool" }
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
class HookDemo
|
|
140
|
-
def run
|
|
141
|
-
banner "Hooks Architecture with robot_lab-xyzzy"
|
|
142
|
-
|
|
143
|
-
explain_setup
|
|
144
|
-
run_robot
|
|
145
|
-
run_llm_loop
|
|
146
|
-
run_tool
|
|
147
|
-
run_network
|
|
148
|
-
run_error
|
|
149
|
-
|
|
150
|
-
hr
|
|
151
|
-
puts "Hook demo complete."
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
private
|
|
155
|
-
|
|
156
|
-
def explain_setup
|
|
157
|
-
section "Extension Registration"
|
|
158
|
-
puts <<~TEXT
|
|
159
|
-
xyzzy.rb is a single-file hook extension loaded from examples/.
|
|
160
|
-
|
|
161
|
-
It is a RobotLab::Hook subclass registered under namespace :#{RobotLab::Xyzzy.namespace}.
|
|
162
|
-
stdout : [xyzzy] timestamp hook_name (one line per call)
|
|
163
|
-
logfile : full context snapshot → #{XYZZY_LOG}
|
|
164
|
-
TEXT
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
def run_robot
|
|
168
|
-
section "Robot Run Hooks"
|
|
169
|
-
robot = hooked_robot("hook_demo_robot")
|
|
170
|
-
robot.on(LocalDemoHook)
|
|
171
|
-
|
|
172
|
-
result = robot.run("show the hook pipeline", hooks: RuntimeDemoHook)
|
|
173
|
-
|
|
174
|
-
puts "Robot reply: #{result.reply}"
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
def run_llm_loop
|
|
178
|
-
section "LLM Request/Response Loop"
|
|
179
|
-
puts <<~TEXT
|
|
180
|
-
Demonstrates before/around/after_llm_generation hooks.
|
|
181
|
-
GenCacheHook implements around_llm_generation: on a cache hit the block
|
|
182
|
-
(the real LLM call) is never invoked. PerfHook times each robot.run call.
|
|
183
|
-
TEXT
|
|
184
|
-
|
|
185
|
-
GenCacheHook.reset!
|
|
186
|
-
PerfHook.reset!
|
|
187
|
-
|
|
188
|
-
puts " provider=#{LLM[:default].provider} model=#{LLM[:default].model}\n\n"
|
|
189
|
-
|
|
190
|
-
# with_model alone would leave the provider unset, and an LM Studio model is
|
|
191
|
-
# not in RubyLLM's registry — pass provider and model together.
|
|
192
|
-
robot = RobotLab.build(
|
|
193
|
-
name: "loop_demo_robot",
|
|
194
|
-
system_prompt: "You are a helpful assistant. Answer every question in one concise sentence.",
|
|
195
|
-
**llm_opts
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
robot.on(PerfHook)
|
|
199
|
-
robot.on(GenerationTracerHook)
|
|
200
|
-
robot.on(GenCacheHook)
|
|
201
|
-
|
|
202
|
-
queries = [
|
|
203
|
-
"what is the boiling point of water?",
|
|
204
|
-
"what is 6 * 7?",
|
|
205
|
-
"what is the boiling point of water?",
|
|
206
|
-
"what is 6 * 7?"
|
|
207
|
-
]
|
|
208
|
-
|
|
209
|
-
queries.each_with_index do |query, i|
|
|
210
|
-
puts "\n--- query #{i + 1}: #{query.inspect} ---"
|
|
211
|
-
result = robot.run(query)
|
|
212
|
-
puts " reply: #{result.reply}"
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
timings = PerfHook.timings
|
|
216
|
-
cache_hits = queries.size - GenCacheHook.call_count
|
|
217
|
-
avg_ms = (timings.sum / timings.size).round(3)
|
|
218
|
-
puts "\n--- summary ---"
|
|
219
|
-
puts " robot.run calls : #{queries.size}"
|
|
220
|
-
puts " LLM calls made : #{GenCacheHook.call_count} (#{cache_hits} served from gen_cache)"
|
|
221
|
-
puts " avg run time : #{avg_ms}ms"
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
def run_tool
|
|
225
|
-
section "Tool Call Hooks"
|
|
226
|
-
tool = HookDemoTool.new
|
|
227
|
-
result = tool.call(**{ "label" => "tool hook payload" })
|
|
228
|
-
puts "Tool result: #{result.inspect}"
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
def run_network
|
|
232
|
-
section "Network and Task Hooks"
|
|
233
|
-
network = RobotLab::Network.new(name: "hook_demo_network")
|
|
234
|
-
network.on(NetworkDemoHook)
|
|
235
|
-
network.task(:summarize, hooked_robot("network_worker"), depends_on: :none)
|
|
236
|
-
|
|
237
|
-
result = network.run(message: "summarize hook activity")
|
|
238
|
-
reply = result.respond_to?(:reply) ? result.reply : result&.value&.reply
|
|
239
|
-
puts "Network result: #{reply}"
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
def run_error
|
|
243
|
-
section "Error Hook"
|
|
244
|
-
failing_robot = RobotLab.build(name: "failing_hook_robot", system_prompt: "raise", **llm_opts)
|
|
245
|
-
# Robot#chat is a public reader — no need to reach for @chat.
|
|
246
|
-
failing_robot.chat.define_singleton_method(:ask) do |_message = nil, **_kwargs|
|
|
247
|
-
raise "planned hook demo failure"
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
failing_robot.run("trigger the on_error hook")
|
|
251
|
-
rescue RuntimeError => e
|
|
252
|
-
puts "Caught expected error: #{e.message}"
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
# Stubs the chat so the hook pipeline is exercised deterministically with no
|
|
256
|
-
# LLM traffic. Robot#chat is public, so this needs no ivar surgery.
|
|
257
|
-
def hooked_robot(name)
|
|
258
|
-
RobotLab.build(name: name, system_prompt: "deterministic hook demo", **llm_opts).tap do |robot|
|
|
259
|
-
robot.chat.define_singleton_method(:ask) do |message = nil, **_kwargs, &_block|
|
|
260
|
-
HookDemoResponse.new(content: "deterministic response to #{message.inspect}")
|
|
261
|
-
end
|
|
262
|
-
end
|
|
263
|
-
end
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
HookDemo.new.run
|