Class: RobotLab::Robot

Inherits:
RubyLLM::Agent
  • Object
show all
Includes:
AgentSkillMatching, BusMessaging, HistorySearch, MCPManagement, TemplateRendering
Defined in:
lib/robot_lab/robot.rb,
lib/robot_lab/robot/bus_messaging.rb,
lib/robot_lab/robot/history_search.rb,
lib/robot_lab/robot/mcp_management.rb,
lib/robot_lab/robot/template_rendering.rb,
lib/robot_lab/robot/agent_skill_matching.rb

Overview

LLM-powered robot built on RubyLLM::Agent

Robot is a subclass of RubyLLM::Agent that adds:

  • Template-based prompts via prompt_manager

  • Shared memory (standalone or network)

  • Tool integration with hierarchical MCP configuration

  • SimpleFlow pipeline integration

Memory Behavior

Standalone: Robot uses its own inherent memory (‘robot.memory`). *In a Network*: Robot uses the network’s shared memory.

Examples:

Simple robot with template

robot = Robot.new(name: "helper", template: :helper)
result = robot.run("Hello!")

Robot with inline system prompt

robot = Robot.new(name: "bot", system_prompt: "You are helpful.")
result = robot.run("What is 2+2?")

Bare robot configured via chaining

robot = Robot.new(name: "bot")
robot.with_instructions("Be concise.").run("Hello")

Robot with tools

robot = Robot.new(
  name: "support",
  template: :support,
  local_tools: [OrderLookup, RefundProcessor]
)

Defined Under Namespace

Modules: AgentSkillMatching, BusMessaging, HistorySearch, MCPManagement, TemplateRendering

Constant Summary

Constants included from HistorySearch

HistorySearch::MIN_SCORE_LENGTH

Constants included from TemplateRendering

TemplateRendering::FRONT_MATTER_CONFIG_KEYS, TemplateRendering::FRONT_MATTER_EXTRA_KEYS

Constants included from AgentSkillMatching

AgentSkillMatching::SIMILARITY_THRESHOLD

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from HistorySearch

#search_history

Methods included from BusMessaging

#assign_bus_poller, #on_message, #send_message, #send_reply, #spawn, #with_bus

Methods included from TemplateRendering

#with_template

Methods included from AgentSkillMatching

#rerender_template

Constructor Details

#initialize(name:, template: nil, system_prompt: nil, context: {}, description: nil, local_tools: [], model: nil, provider: nil, mcp_servers: [], mcp: :none, tools: :none, on_tool_call: nil, on_tool_result: nil, on_content: nil, enable_cache: true, bus: nil, skills: nil, temperature: nil, top_p: nil, top_k: nil, max_tokens: nil, presence_penalty: nil, frequency_penalty: nil, stop: nil, max_tool_rounds: nil, token_budget: nil, doom_loop_threshold: nil, mcp_discovery: false, config: nil, learn: false, learn_domain: nil, store_path: nil) ⇒ Robot

Creates a new Robot instance.

Parameters:

  • name (String)

    the unique identifier for the robot

  • template (Symbol, nil) (defaults to: nil)

    the prompt_manager template

  • system_prompt (String, nil) (defaults to: nil)

    inline system prompt

  • context (Hash, Proc) (defaults to: {})

    variables to pass to the template

  • description (String, nil) (defaults to: nil)

    optional description

  • local_tools (Array) (defaults to: [])

    tools defined locally

  • model (String, nil) (defaults to: nil)

    the LLM model to use

  • mcp_servers (Array) (defaults to: [])

    legacy parameter for MCP server configurations

  • mcp (Symbol, Array) (defaults to: :none)

    hierarchical MCP config

  • tools (Symbol, Array) (defaults to: :none)

    hierarchical tools config

  • on_tool_call (Proc, nil) (defaults to: nil)

    callback invoked when a tool is called

  • on_tool_result (Proc, nil) (defaults to: nil)

    callback invoked when a tool returns a result

  • on_content (Proc, nil) (defaults to: nil)

    callback invoked with each streaming content chunk

  • enable_cache (Boolean) (defaults to: true)

    whether to enable semantic caching

  • bus (TypedBus::MessageBus, nil) (defaults to: nil)

    optional message bus for inter-robot communication

  • temperature (Float, nil) (defaults to: nil)

    controls randomness

  • top_p (Float, nil) (defaults to: nil)

    nucleus sampling threshold

  • top_k (Integer, nil) (defaults to: nil)

    top-k sampling

  • max_tokens (Integer, nil) (defaults to: nil)

    maximum tokens in response

  • presence_penalty (Float, nil) (defaults to: nil)

    penalize based on presence

  • frequency_penalty (Float, nil) (defaults to: nil)

    penalize based on frequency

  • stop (String, Array, nil) (defaults to: nil)

    stop sequences

  • skills (Symbol, Array<Symbol>, nil) (defaults to: nil)

    skill templates to prepend

  • config (RunConfig, nil) (defaults to: nil)

    shared configuration (merged with explicit kwargs)



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/robot_lab/robot.rb', line 139

def initialize(
  name:,
  template: nil,
  system_prompt: nil,
  context: {},
  description: nil,
  local_tools: [],
  model: nil,
  provider: nil,
  mcp_servers: [],
  mcp: :none,
  tools: :none,
  on_tool_call: nil,
  on_tool_result: nil,
  on_content: nil,
  enable_cache: true,
  bus: nil,
  skills: nil,
  temperature: nil,
  top_p: nil,
  top_k: nil,
  max_tokens: nil,
  presence_penalty: nil,
  frequency_penalty: nil,
  stop: nil,
  max_tool_rounds: nil,
  token_budget: nil,
  doom_loop_threshold: nil,
  mcp_discovery: false,
  config: nil,
  learn: false,
  learn_domain: nil,
  store_path: nil
)
  assign_identity_ivars(name: name, template: template, system_prompt: system_prompt,
                        context: context, description: description, local_tools: local_tools,
                        skills: skills, mcp_discovery: mcp_discovery)

  build_effective_config(
    model: model, temperature: temperature, top_p: top_p, top_k: top_k,
    max_tokens: max_tokens, presence_penalty: presence_penalty,
    frequency_penalty: frequency_penalty, stop: stop,
    on_tool_call: on_tool_call, on_tool_result: on_tool_result,
    on_content: on_content, bus: bus, enable_cache: enable_cache,
    max_tool_rounds: max_tool_rounds, token_budget: token_budget,
    doom_loop_threshold: doom_loop_threshold, mcp_servers: mcp_servers,
    mcp: mcp, tools: tools, config: config
  )

  extract_config_ivars
  initialize_runtime_state
  initialize_memory
  configure_learning(learn: learn, learn_domain: learn_domain, store_path: store_path)

  lab_config = RobotLab.config
  resolved_model = @config.model || lab_config.ruby_llm.model
  chat_kwargs   = { model: resolved_model }

  # RubyLLM auto-sets assume_model_exists for local providers when provider is specified.
  @provider = provider
  if @provider
    chat_kwargs[:provider] = @provider
    chat_kwargs[:assume_model_exists] = true
  end

  super(chat: nil, **chat_kwargs)

  apply_template
  apply_system_prompt
  apply_chat_params
  register_chat_callbacks
end

Instance Attribute Details

#busObject (readonly)

Returns the value of attribute bus.



71
72
73
# File 'lib/robot_lab/robot.rb', line 71

def bus
  @bus
end

#configObject (readonly)

Returns the value of attribute config.



71
72
73
# File 'lib/robot_lab/robot.rb', line 71

def config
  @config
end

#descriptionString? (readonly)

Returns an optional description of the robot’s purpose.

Returns:

  • (String, nil)

    an optional description of the robot’s purpose



69
# File 'lib/robot_lab/robot.rb', line 69

attr_accessor :input, :output

#durable_storeObject (readonly)

Returns the value of attribute durable_store.



71
72
73
# File 'lib/robot_lab/robot.rb', line 71

def durable_store
  @durable_store
end

#inputIO

Returns input stream for user interaction (default: $stdin).

Returns:

  • (IO)

    input stream for user interaction (default: $stdin)



69
70
71
# File 'lib/robot_lab/robot.rb', line 69

def input
  @input
end

#learn_domainObject (readonly)

Returns the value of attribute learn_domain.



71
72
73
# File 'lib/robot_lab/robot.rb', line 71

def learn_domain
  @learn_domain
end

#learningsObject (readonly)

Returns the value of attribute learnings.



71
72
73
# File 'lib/robot_lab/robot.rb', line 71

def learnings
  @learnings
end

#local_toolsArray (readonly)

Returns the locally defined tools for this robot.

Returns:

  • (Array)

    the locally defined tools for this robot



69
# File 'lib/robot_lab/robot.rb', line 69

attr_accessor :input, :output

#mcp_clientsHash<String, MCP::Client> (readonly)

Returns connected MCP clients by server name.

Returns:

  • (Hash<String, MCP::Client>)

    connected MCP clients by server name



69
# File 'lib/robot_lab/robot.rb', line 69

attr_accessor :input, :output

#mcp_configSymbol, Array (readonly)

Returns build-time MCP configuration (raw, unresolved).

Returns:

  • (Symbol, Array)

    build-time MCP configuration (raw, unresolved)



81
82
83
# File 'lib/robot_lab/robot.rb', line 81

def mcp_config
  @mcp_config
end

#mcp_toolsArray<Tool> (readonly)

Returns tools discovered from MCP servers.

Returns:

  • (Array<Tool>)

    tools discovered from MCP servers



69
# File 'lib/robot_lab/robot.rb', line 69

attr_accessor :input, :output

#memoryMemory (readonly)

Returns the robot’s inherent memory (used when standalone, not in network).

Returns:

  • (Memory)

    the robot’s inherent memory (used when standalone, not in network)



69
# File 'lib/robot_lab/robot.rb', line 69

attr_accessor :input, :output

#nameString (readonly)

Returns the unique identifier for the robot.

Returns:

  • (String)

    the unique identifier for the robot



69
# File 'lib/robot_lab/robot.rb', line 69

attr_accessor :input, :output

#outboxObject (readonly)

Returns the value of attribute outbox.



71
72
73
# File 'lib/robot_lab/robot.rb', line 71

def outbox
  @outbox
end

#outputIO

Returns output stream for user interaction (default: $stdout).

Returns:

  • (IO)

    output stream for user interaction (default: $stdout)



69
# File 'lib/robot_lab/robot.rb', line 69

attr_accessor :input, :output

#providerObject (readonly)

Returns the value of attribute provider.



71
72
73
# File 'lib/robot_lab/robot.rb', line 71

def provider
  @provider
end

#skillsObject (readonly)

Returns the value of attribute skills.



71
72
73
# File 'lib/robot_lab/robot.rb', line 71

def skills
  @skills
end

#system_promptString? (readonly)

Returns inline system prompt (used alone or appended to template).

Returns:

  • (String, nil)

    inline system prompt (used alone or appended to template)



69
# File 'lib/robot_lab/robot.rb', line 69

attr_accessor :input, :output

#templateSymbol? (readonly)

Returns the prompt_manager template for the robot’s prompt.

Returns:

  • (Symbol, nil)

    the prompt_manager template for the robot’s prompt



69
# File 'lib/robot_lab/robot.rb', line 69

attr_accessor :input, :output

#tools_configObject (readonly)

Returns the value of attribute tools_config.



81
# File 'lib/robot_lab/robot.rb', line 81

attr_reader :mcp_config, :tools_config

#total_input_tokensObject (readonly)

Returns the value of attribute total_input_tokens.



71
72
73
# File 'lib/robot_lab/robot.rb', line 71

def total_input_tokens
  @total_input_tokens
end

#total_output_tokensObject (readonly)

Returns the value of attribute total_output_tokens.



71
72
73
# File 'lib/robot_lab/robot.rb', line 71

def total_output_tokens
  @total_output_tokens
end

Instance Method Details

#call(result) ⇒ SimpleFlow::Result

SimpleFlow step interface

Parameters:

  • result (SimpleFlow::Result)

    incoming result from previous step

Returns:

  • (SimpleFlow::Result)

    result with robot output



286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/robot_lab/robot.rb', line 286

def call(result)
  run_context = extract_run_context(result)

  # Extract the message from run context
  message = run_context.delete(:message)

  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  robot_result = run(message, **run_context)
  robot_result.duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time

  result
    .with_context(@name.to_sym, robot_result)
    .continue(robot_result)
rescue Exception => e # rubocop:disable Lint/RescueException
  # Catch all errors (including SecurityError, Timeout::Error, etc.)
  # so one failing robot doesn't crash the entire network pipeline.
  elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
  error_result = RobotResult.new(
    robot_name: @name,
    output: [TextMessage.new(role: 'assistant', content: "Error: #{e.class}: #{e.message}")]
  )
  error_result.duration = elapsed

  result
    .with_context(@name.to_sym, error_result)
    .continue(error_result)
end

#chatRubyLLM::Chat

Access the underlying RubyLLM::Chat instance. Useful for checkpoint/restore operations that need direct access to conversation state.

Returns:

  • (RubyLLM::Chat)


372
373
374
# File 'lib/robot_lab/robot.rb', line 372

def chat
  @chat
end

#chat_providerString?

Return the provider for this robot’s chat. Useful for displaying model/provider info without reaching into chat internals.

Returns:

  • (String, nil)


496
497
498
499
500
501
# File 'lib/robot_lab/robot.rb', line 496

def chat_provider
  m = @chat.model
  m.respond_to?(:provider) ? m.provider : nil
rescue StandardError
  nil
end

#clear_messages(keep_system: true) ⇒ self

Clear conversation messages, optionally keeping the system prompt.

Parameters:

  • keep_system (Boolean) (defaults to: true)

    whether to preserve the system message

Returns:

  • (self)


387
388
389
390
391
392
393
394
395
396
# File 'lib/robot_lab/robot.rb', line 387

def clear_messages(keep_system: true)
  if keep_system
    system_msg = @chat.messages.find { |m| m.role == :system }
    @chat.reset_messages!
    @chat.add_message(system_msg) if system_msg
  else
    @chat.reset_messages!
  end
  self
end

#compress_history(recent_turns: 3, keep_threshold: 0.6, drop_threshold: 0.2, summarizer: nil) ⇒ self

Compress conversation history using TF-IDF relevance scoring.

Old turns are tiered against the most recent context:

  • High relevance (score >= keep_threshold) → kept verbatim

  • Medium relevance (drop_threshold..keep_threshold) → summarized or dropped

  • Low relevance (score < drop_threshold) → dropped

System messages and tool call/result messages are always preserved. The most recent recent_turns pairs are also always kept verbatim.

Requires the optional ‘classifier’ gem (~> 2.3). Raises DependencyError if not installed.

Parameters:

  • recent_turns (Integer) (defaults to: 3)

    turn pairs to protect at the end (default 3)

  • keep_threshold (Float) (defaults to: 0.6)

    cosine score >= this → keep verbatim (default 0.6)

  • drop_threshold (Float) (defaults to: 0.2)

    cosine score < this → drop (default 0.2)

  • summarizer (#call, nil) (defaults to: nil)

    callable(text) -> String for medium-tier; nil drops medium-tier instead of summarizing

Returns:

  • (self)


427
428
429
430
431
432
433
434
435
436
# File 'lib/robot_lab/robot.rb', line 427

def compress_history(recent_turns: 3, keep_threshold: 0.6, drop_threshold: 0.2, summarizer: nil)
  compressed = HistoryCompressor.new(
    messages:       @chat.messages,
    recent_turns:   recent_turns,
    keep_threshold: keep_threshold,
    drop_threshold: drop_threshold,
    summarizer:     summarizer
  ).call
  replace_messages(compressed)
end

#connect_mcp!self

Eagerly connect to configured MCP servers and discover tools. Normally MCP connections are lazy (established on first run). Call this to connect early, e.g. to display connection status at startup.

Returns:

  • (self)


327
328
329
330
331
# File 'lib/robot_lab/robot.rb', line 327

def connect_mcp!
  resolved_mcp = resolve_mcp_hierarchy(@mcp_config)
  ensure_mcp_clients(resolved_mcp) if resolved_mcp.is_a?(Array) && resolved_mcp.any?
  self
end

#delegate(to:, task:, async: false) ⇒ RobotResult, DelegationFuture

Delegate a task to another robot, synchronously or asynchronously.

Synchronous (default, async: false): blocks until the delegatee finishes and returns a RobotResult annotated with delegated_by, duration, and token counts.

Asynchronous (+async: true+): starts the delegatee in a background thread and returns a DelegationFuture immediately. Call future.value to block for the result, or future.resolved? to poll.

Examples:

Synchronous

result = manager.delegate(to: analyst, task: "What are the risks?")
puts result.reply          # analyst's answer
puts result.delegated_by   # => "manager"
puts result.duration       # => 1.43 (seconds)

Async fan-out

f1 = manager.delegate(to: summarizer, task: "summarize ...", async: true)
f2 = manager.delegate(to: analyst,    task: "analyze ...",   async: true)
summary  = f1.value          # blocks if not yet done
analysis = f2.value(timeout: 30)

Parameters:

  • to (Robot)

    the robot to delegate to

  • task (String)

    the message to send

  • async (Boolean) (defaults to: false)

    when true, returns a DelegationFuture immediately

  • kwargs (Hash)

    additional keyword args forwarded to Robot#run

Returns:



466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
# File 'lib/robot_lab/robot.rb', line 466

def delegate(to:, task:, async: false, **)
  if async
    future = DelegationFuture.new(robot_name: to.name, delegated_by: @name)
    delegator_name = @name

    Thread.new do
      started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
      result = to.run(task, **)
      result.duration     = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at
      result.delegated_by = delegator_name
      future.resolve!(result)
    rescue => e
      future.reject!(e)
    end

    future
  else
    started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    result = to.run(task, **)
    result.duration     = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at
    result.delegated_by = @name
    result
  end
end

#disconnectself

Disconnect all MCP clients and bus channel.

Returns:

  • (self)


345
346
347
348
349
# File 'lib/robot_lab/robot.rb', line 345

def disconnect
  @mcp_clients.each_value(&:disconnect)
  teardown_bus_channel if @bus
  self
end

#effective_configHash

Returns the fully-merged configuration for this robot at runtime.

Reflects the result of merging the RunConfig hierarchy (global → network →constructor kwargs → template front matter). Nil fields are omitted.

Examples:

robot.effective_config
#=> { model: "claude-sonnet-4-6", temperature: 0.7, max_tokens: 4096 }

Returns:

  • (Hash)

    merged config keyed by field name



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/robot_lab/robot.rb', line 93

def effective_config
  {
    model:               @config.model,
    temperature:         @config.temperature,
    top_p:               @config.top_p,
    top_k:               @config.top_k,
    max_tokens:          @config.max_tokens,
    presence_penalty:    @config.presence_penalty,
    frequency_penalty:   @config.frequency_penalty,
    stop:                @config.stop,
    tools:               @config.tools,
    mcp:                 @config.mcp,
    max_tool_rounds:     @config.max_tool_rounds,
    doom_loop_threshold: @config.doom_loop_threshold,
    auto_compact:        @config.auto_compact,
    compact_threshold:   @config.compact_threshold,
    token_budget:        @config.token_budget
  }.compact
end

#failed_mcp_server_namesArray<String>

Returns server names that failed to connect.

Returns:

  • (Array<String>)


336
337
338
339
340
# File 'lib/robot_lab/robot.rb', line 336

def failed_mcp_server_names
  return [] unless @failed_mcp_configs

  @failed_mcp_configs.keys
end

#inject_mcp!(clients:, tools:) ⇒ self

Inject pre-connected MCP clients and their tools into this robot. Used by host applications (e.g. AIA) that manage MCP connections externally and need to pass them to robots without re-connecting.

Parameters:

  • clients (Hash<String, MCP::Client>)

    connected MCP clients by server name

  • tools (Array<Tool>)

    tools discovered from the MCP servers

Returns:

  • (self)


360
361
362
363
364
365
# File 'lib/robot_lab/robot.rb', line 360

def inject_mcp!(clients:, tools:)
  @mcp_clients = clients
  @mcp_tools = tools
  @mcp_initialized = true
  self
end

#learn(text) ⇒ self

Add a learning to this robot’s accumulation store.

Deduplicates by bidirectional substring matching: a new learning is skipped if it is already contained within an existing learning, or an existing learning is contained within the new one (the new one wins and replaces the weaker entry).

Learnings are persisted to the robot’s inherent memory under :learnings.

Parameters:

  • text (String)

    the insight to record

Returns:

  • (self)


522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
# File 'lib/robot_lab/robot.rb', line 522

def learn(text)
  text = text.to_s.strip
  return self if text.empty?

  # Remove any existing learning that is a substring of the new one
  @learnings.reject! { |existing| text.include?(existing) }

  # Skip if any existing learning already covers the new one
  unless @learnings.any? { |existing| existing.include?(text) }
    @learnings << text
    @memory.set(:learnings, @learnings.dup)
  end

  self
end

#mcp_client(server_name) ⇒ MCP::Client?

Find an MCP client by server name.

Parameters:

  • server_name (String)

    the MCP server name

Returns:



507
508
509
# File 'lib/robot_lab/robot.rb', line 507

def mcp_client(server_name)
  @mcp_clients[server_name]
end

#messagesArray<RubyLLM::Message>

Return the conversation messages from the underlying chat.

Returns:

  • (Array<RubyLLM::Message>)


379
380
381
# File 'lib/robot_lab/robot.rb', line 379

def messages
  @chat.messages
end

#modelString?

Returns the model identifier

Returns:

  • (String, nil)

    the LLM model ID string



215
216
217
218
219
220
# File 'lib/robot_lab/robot.rb', line 215

def model
  return nil unless @chat.respond_to?(:model)

  m = @chat.model
  m.respond_to?(:id) ? m.id : m.to_s
end

#replace_messages(messages) ⇒ self

Replace conversation messages with a saved set (for checkpoint restore).

Parameters:

  • messages (Array<RubyLLM::Message>)

    the messages to restore

Returns:

  • (self)


402
403
404
405
406
# File 'lib/robot_lab/robot.rb', line 402

def replace_messages(messages)
  @chat.reset_messages!
  messages.each { |m| @chat.add_message(m) }
  self
end

#reset_memoryself

Reset the robot’s inherent memory

Returns:

  • (self)


317
318
319
320
# File 'lib/robot_lab/robot.rb', line 317

def reset_memory
  @memory.reset
  self
end

#reset_token_totalsself

Reset cumulative token counters to zero.

Returns:

  • (self)


541
542
543
544
545
# File 'lib/robot_lab/robot.rb', line 541

def reset_token_totals
  @total_input_tokens = 0
  @total_output_tokens = 0
  self
end

#run(message = nil, network: nil, network_memory: nil, network_config: nil, memory: nil, mcp: :none, tools: :none, **kwargs) {|chunk| ... } ⇒ RobotResult

Send a message and get a response, with Robot’s extended capabilities

Parameters:

  • message (String) (defaults to: nil)

    the user message

  • network (NetworkRun, nil) (defaults to: nil)

    network context (legacy)

  • network_memory (Memory, nil) (defaults to: nil)

    shared network memory

  • memory (Memory, Hash, nil) (defaults to: nil)

    runtime memory to merge

  • mcp (Symbol, Array, nil) (defaults to: :none)

    runtime MCP override

  • tools (Symbol, Array, nil) (defaults to: :none)

    runtime tools override

Yields:

  • (chunk)

    optional streaming block called with each content chunk

Returns:



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/robot_lab/robot.rb', line 232

def run(message = nil, network: nil, network_memory: nil, network_config: nil,
        memory: nil, mcp: :none, tools: :none, **kwargs, &block)
  run_memory = resolve_run_memory(memory, network: network, network_memory: network_memory)
  previous_writer = run_memory.current_writer
  run_memory.current_writer = @name

  begin
    run_context = kwargs.except(:with)
    prepare_tools(message: message, mcp: mcp, tools: tools,
                  network: network, network_config: network_config)
    rerender_template(run_context) if @template && run_context.any?
    response = invoke_ask(message: message, kwargs: kwargs, block: block)
    result = build_result(response, run_memory)
    enforce_token_budget!
    result
  ensure
    remove_doom_loop_detection
    restore_tool_call_callback if @config.max_tool_rounds
    run_reflector if @durable_store
    run_memory.current_writer = previous_writer
  end
end

#to_hHash

Converts the robot to a hash representation

Returns:

  • (Hash)


550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
# File 'lib/robot_lab/robot.rb', line 550

def to_h
  {
    name: name,
    description: description,
    template: template,
    skills: @skills,
    system_prompt: system_prompt,
    local_tools: local_tools.map { |t| t.respond_to?(:name) ? t.name : t.to_s },
    mcp_tools: mcp_tools.map(&:name),
    mcp_config: @mcp_config,
    tools_config: @tools_config,
    mcp_servers: @mcp_clients.keys,
    model: model,
    config: (@config.empty? ? nil : @config.to_json_hash),
    bus: @bus ? true : nil
  }.compact
end

#update(template: nil, context: nil, system_prompt: nil, model: nil, temperature: nil, **kwargs) ⇒ self

Reconfigure the robot for a new context

Parameters:

  • template (Symbol, nil) (defaults to: nil)

    new template to apply

  • context (Hash, nil) (defaults to: nil)

    new context for the template

  • system_prompt (String, nil) (defaults to: nil)

    new system prompt

  • model (String, nil) (defaults to: nil)

    new model

  • temperature (Float, nil) (defaults to: nil)

    new temperature

Returns:

  • (self)


263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'lib/robot_lab/robot.rb', line 263

def update(template: nil, context: nil, system_prompt: nil, model: nil, temperature: nil, **kwargs)
  if template
    @template = template
    ctx = context || @build_context
    apply_template_to_chat(ctx)
  end

  @chat.with_instructions(system_prompt) if system_prompt
  @chat.with_model(model) if model
  @chat.with_temperature(temperature) if temperature

  kwargs.each do |key, value|
    method = :"with_#{key}"
    @chat.public_send(method, value) if value && @chat.respond_to?(method)
  end

  self
end