Class: LLM::Agent
- Inherits:
-
Object
- Object
- LLM::Agent
- Defined in:
- lib/llm/agent.rb
Overview
LLM::Agent is the recommended entry point for most use-cases. It provides a class-level DSL for defining reusable, preconfigured assistants with defaults for model, tools, schema, and instructions.
It wraps the same stateful runtime surface as
LLM::Context: message history, usage, persistence,
streaming parameters, and provider-backed requests still flow through
an underlying context. The defining behavior of an agent is that it
automatically resolves pending tool calls for you during talk,
instead of leaving tool loops to the caller.
Notes:
- Instructions are injected once unless a system message is already present.
- An agent automatically executes tool loops (unlike LLM::Context).
- The automatic tool loop enables the wrapped context's
guardby default. The built-in LLM::LoopGuard detects repeated tool-call patterns and blocks stuck execution before more tool work is queued. - The default tool attempt budget is
25. After that, the agent sends advisory tool errors back through the model and keeps the loop in-band. Settool_attempts: nilto disable that advisory behavior. - Tool loop execution can be configured with
concurrency :sequential,:thread,:async,:fiber,:fork, or:ractor.
Instance Attribute Summary collapse
-
#llm ⇒ LLM::Provider
readonly
Returns a provider.
Class Method Summary collapse
-
.name(name = UNDEFINED, &block) ⇒ String
Set or get an agent's name.
-
.description(desc = UNDEFINED, &block) ⇒ String?
Set or get an agent's description.
-
.model(model = nil, &block) ⇒ String?
Set or get the default model.
-
.tools(*tools, &block) ⇒ Array<LLM::Function>
Set or get the default tools.
-
.skills(*skills, &block) ⇒ Array<String>?
Set or get the default skills.
-
.schema(schema = nil, &block) ⇒ #to_json?
Set or get the default schema.
-
.instructions(instructions = nil) ⇒ String?
Set or get the default instructions.
-
.concurrency(concurrency = nil) ⇒ Symbol, ...
Set or get the tool execution concurrency.
-
.tracer(tracer = nil, &block) ⇒ LLM::Tracer, ...
Set or get the default tracer.
-
.stream(stream = nil, &block) ⇒ Object, ...
Set or get the default stream.
-
.confirm(*tool_names, &block) ⇒ Array<String>, ...
Set or get the tool names that require confirmation before they can run.
-
.path(path = UNDEFINED, &block) ⇒ String?
Set the file path where an agent's memory can be restored from, and written to.
-
.set(properties)
Bulk-assign class-level agent defaults from a Hash.
Instance Method Summary collapse
-
#on_tool_confirmation(fn, strategy) ⇒ LLM::Function::Return
This method is called when confirmation is required before a tool can run.
-
#initialize(llm, params = {}) ⇒ Agent
constructor
A new instance of Agent.
-
#name ⇒ String
Returns the agent's name.
-
#path ⇒ String?
Returns a file path where an agent's memory is restored from, and written to after each turn.
-
#description ⇒ String?
Returns the agent's description.
-
#talk(prompt, params = {}) ⇒ LLM::Response
Maintain a conversation via the chat completions API.
- #ask(prompt, params = {}) ⇒ Object
- #messages ⇒ LLM::Buffer<LLM::Message>
- #pending_functions ⇒ Array<LLM::Function>
- #returns ⇒ Array<LLM::Function::Return>
- #wait ⇒ Array<LLM::Function::Return>
- #usage ⇒ LLM::Object
-
#interrupt! ⇒ nil
(also: #cancel!)
Interrupt the active request, if any.
- #prompt(&b) ⇒ LLM::Prompt (also: #build_prompt)
-
#image_url(url) ⇒ LLM::Object
Returns a tagged object.
-
#local_file(path) ⇒ LLM::Object
Returns a tagged object.
-
#remote_file(res) ⇒ LLM::Object
Returns a tagged object.
-
#tracer ⇒ LLM::Tracer
Returns an LLM tracer.
- #tracer=(other)
-
#stream ⇒ LLM::Stream, ...
Returns a stream object, or nil.
-
#model ⇒ String
Returns the model an Agent is actively using.
- #mode ⇒ Symbol
-
#concurrency ⇒ Symbol, ...
Returns the configured tool execution concurrency.
- #cost ⇒ LLM::Cost
- #context_window ⇒ Integer
-
#repl(name: self.name, path: nil, tools: [], skills: [], tracer: false, trace: nil)
Start a minimalist repl that can interact with the agent and its current state.
- #params ⇒ Hash
- #to_h ⇒ Hash
- #to_json ⇒ String
- #inspect ⇒ String
- #serialize(**kw) (also: #save)
- #deserialize(**kw) ⇒ LLM::Agent (also: #restore)
Constructor Details
#initialize(llm, params = {}) ⇒ Agent
Returns a new instance of Agent.
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
# File 'lib/llm/agent.rb', line 328 def initialize(llm, params = {}) params = {}.merge!(params) @llm = llm fields = %i[name description path model skills schema tracer stream tools concurrency instructions confirm] fields_ivar = %i[name description path tracer concurrency instructions confirm] fields.each do |field| resolvable = params.key?(field) ? params.delete(field) : self.class.public_send(field) resolve_symbol = !%i[concurrency].include?(field) resolved = resolvable != nil ? resolve_option(self, resolvable, resolve_symbol:) : resolvable resolved = [*resolved].map(&:to_s) if field == :confirm && resolved if field == :model params[field] = resolved unless resolved.nil? || params.key?(field) elsif resolved && !fields_ivar.include?(field) params[field] ||= resolved elsif fields_ivar.include?(field) instance_variable_set(:"@#{field}", resolved) end end @ctx = LLM::Context.new(llm, {guard: true}.merge(params)) @path and File.readable?(@path) ? @ctx.restore(path:) : nil end |
Instance Attribute Details
#llm ⇒ LLM::Provider (readonly)
Returns a provider
68 69 70 |
# File 'lib/llm/agent.rb', line 68 def llm @llm end |
Class Method Details
.name(name = UNDEFINED, &block) ⇒ String
This method serves as a self-documenting string and it is used by LLM::Repl. It is optional but recommended.
Set or get an agent's name
117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/llm/agent.rb', line 117 def self.name(name = UNDEFINED, &block) if name.equal?(UNDEFINED) if @name.nil? name = to_s.split("::").last @name = name.gsub(CASE_PATTERN, "-").downcase else @name end else @name = block || name end end |
.description(desc = UNDEFINED, &block) ⇒ String?
This method serves as a self-documenting string. It is optional but recommended.
Set or get an agent's description
139 140 141 142 143 144 145 |
# File 'lib/llm/agent.rb', line 139 def self.description(desc = UNDEFINED, &block) if desc.equal?(UNDEFINED) @desc else @desc = block || desc end end |
.model(model = nil, &block) ⇒ String?
Set or get the default model
153 154 155 156 |
# File 'lib/llm/agent.rb', line 153 def self.model(model = nil, &block) return @model if model.nil? && !block @model = block || model end |
.tools(*tools, &block) ⇒ Array<LLM::Function>
Set or get the default tools
164 165 166 167 168 169 170 171 |
# File 'lib/llm/agent.rb', line 164 def self.tools(*tools, &block) return @tools || [] if tools.empty? && !block if tools.size == 1 and tools.grep(Symbol).any? @tools = tools.first else @tools = block || tools.flatten end end |
.skills(*skills, &block) ⇒ Array<String>?
Set or get the default skills
179 180 181 182 183 184 185 186 |
# File 'lib/llm/agent.rb', line 179 def self.skills(*skills, &block) return @skills if skills.empty? && !block if skills.size == 1 and skills.grep(Symbol).any? @skills = skills.first else @skills = block || skills.flatten end end |
.schema(schema = nil, &block) ⇒ #to_json?
Set or get the default schema
194 195 196 197 |
# File 'lib/llm/agent.rb', line 194 def self.schema(schema = nil, &block) return @schema if schema.nil? && !block @schema = block || schema end |
.instructions(instructions = nil) ⇒ String?
Set or get the default instructions
205 206 207 208 |
# File 'lib/llm/agent.rb', line 205 def self.instructions(instructions = nil) return @instructions if instructions.nil? @instructions = instructions end |
.concurrency(concurrency = nil) ⇒ Symbol, ...
Set or get the tool execution concurrency.
225 226 227 228 |
# File 'lib/llm/agent.rb', line 225 def self.concurrency(concurrency = nil) return @concurrency if concurrency.nil? @concurrency = concurrency end |
.tracer(tracer = nil, &block) ⇒ LLM::Tracer, ...
Set or get the default tracer.
When a block is provided, it is stored and evaluated lazily against the agent instance during initialization so it can build a tracer from the resolved provider.
245 246 247 248 |
# File 'lib/llm/agent.rb', line 245 def self.tracer(tracer = nil, &block) return @tracer if tracer.nil? && !block @tracer = block || tracer end |
.stream(stream = nil, &block) ⇒ Object, ...
Set or get the default stream.
When a block is provided, it is stored and evaluated lazily against the agent instance during initialization so it can build a fresh stream for each agent.
265 266 267 268 |
# File 'lib/llm/agent.rb', line 265 def self.stream(stream = nil, &block) return @stream if stream.nil? && !block @stream = block || stream end |
.confirm(*tool_names, &block) ⇒ Array<String>, ...
Set or get the tool names that require confirmation before they can run.
When a single Symbol is given, it is stored as-is and resolved at initialization time by calling the method with that name on the agent instance. This allows dynamic tool confirmation lists.
291 292 293 294 295 296 297 298 |
# File 'lib/llm/agent.rb', line 291 def self.confirm(*tool_names, &block) return @confirm if tool_names.empty? && !block if tool_names.size == 1 && tool_names.grep(Symbol).any? @confirm = tool_names.first else @confirm = block || tool_names.flatten.map(&:to_s) end end |
.path(path = UNDEFINED, &block) ⇒ String?
Set the file path where an agent's memory can be restored from, and written to.
306 307 308 309 310 311 312 |
# File 'lib/llm/agent.rb', line 306 def self.path(path = UNDEFINED, &block) if path.equal?(UNDEFINED) @path else @path = path || block end end |
.set(properties)
This method returns an undefined value.
Bulk-assign class-level agent defaults from a Hash.
Each key is resolved by calling the corresponding class method on the agent subclass. An error is raised for unknown keys so that typos are caught early.
97 98 99 100 101 102 103 104 105 |
# File 'lib/llm/agent.rb', line 97 def self.set(properties) properties.each do if respond_to?(_1) public_send(_1, _2) else raise KeyError, "key not found: #{_1}" end end end |
Instance Method Details
#on_tool_confirmation(fn, strategy) ⇒ LLM::Function::Return
This method is called when confirmation is required before a tool can run.
631 632 633 |
# File 'lib/llm/agent.rb', line 631 def on_tool_confirmation(fn, strategy) fn.cancel end |
#name ⇒ String
Returns the agent's name
353 354 355 |
# File 'lib/llm/agent.rb', line 353 def name @name end |
#path ⇒ String?
Returns a file path where an agent's memory is restored from, and written to after each turn.
361 362 363 |
# File 'lib/llm/agent.rb', line 361 def path @path end |
#description ⇒ String?
Returns the agent's description
368 369 370 |
# File 'lib/llm/agent.rb', line 368 def description @description end |
#talk(prompt, params = {}) ⇒ LLM::Response
Maintain a conversation via the chat completions API. This method immediately sends a request to the LLM and returns the response.
388 389 390 391 392 |
# File 'lib/llm/agent.rb', line 388 def talk(prompt, params = {}) res = run_loop(prompt, params, :talk) path ? @ctx.save(path:) : nil res end |
#ask(prompt, params = {}) ⇒ Object
396 397 398 399 400 |
# File 'lib/llm/agent.rb', line 396 def ask(prompt, params = {}) res = run_loop(prompt, params, :ask) path ? @ctx.save(path:) : nil res end |
#pending_functions ⇒ Array<LLM::Function>
410 411 412 |
# File 'lib/llm/agent.rb', line 410 def pending_functions @tracer ? @llm.with_tracer(@tracer) { @ctx.pending_functions } : @ctx.pending_functions end |
#returns ⇒ Array<LLM::Function::Return>
417 418 419 |
# File 'lib/llm/agent.rb', line 417 def returns @ctx.returns end |
#wait ⇒ Array<LLM::Function::Return>
424 425 426 |
# File 'lib/llm/agent.rb', line 424 def wait(...) @tracer ? @llm.with_tracer(@tracer) { @ctx.wait(...) } : @ctx.wait(...) end |
#interrupt! ⇒ nil Also known as: cancel!
Interrupt the active request, if any.
437 438 439 |
# File 'lib/llm/agent.rb', line 437 def interrupt! @ctx.interrupt! end |
#prompt(&b) ⇒ LLM::Prompt Also known as: build_prompt
446 447 448 |
# File 'lib/llm/agent.rb', line 446 def prompt(&b) @ctx.prompt(&b) end |
#image_url(url) ⇒ LLM::Object
Returns a tagged object
456 457 458 |
# File 'lib/llm/agent.rb', line 456 def image_url(url) @ctx.image_url(url) end |
#local_file(path) ⇒ LLM::Object
Returns a tagged object
465 466 467 |
# File 'lib/llm/agent.rb', line 465 def local_file(path) @ctx.local_file(path) end |
#remote_file(res) ⇒ LLM::Object
Returns a tagged object
474 475 476 |
# File 'lib/llm/agent.rb', line 474 def remote_file(res) @ctx.remote_file(res) end |
#tracer ⇒ LLM::Tracer
Returns an LLM tracer
481 482 483 |
# File 'lib/llm/agent.rb', line 481 def tracer @tracer || @ctx.tracer end |
#tracer=(other)
This method returns an undefined value.
489 490 491 492 |
# File 'lib/llm/agent.rb', line 489 def tracer=(other) @ctx.tracer = other @tracer = other end |
#stream ⇒ LLM::Stream, ...
Returns a stream object, or nil
497 498 499 |
# File 'lib/llm/agent.rb', line 497 def stream @ctx.stream end |
#model ⇒ String
Returns the model an Agent is actively using
504 505 506 |
# File 'lib/llm/agent.rb', line 504 def model @ctx.model end |
#mode ⇒ Symbol
510 511 512 |
# File 'lib/llm/agent.rb', line 510 def mode @ctx.mode end |
#concurrency ⇒ Symbol, ...
Returns the configured tool execution concurrency.
517 518 519 |
# File 'lib/llm/agent.rb', line 517 def concurrency @concurrency end |
#context_window ⇒ Integer
531 532 533 |
# File 'lib/llm/agent.rb', line 531 def context_window @ctx.context_window end |
#repl(name: self.name, path: nil, tools: [], skills: [], tracer: false, trace: nil)
By default this method disables the tracer for the duration of the repl session, and restores it afterwards.
This method returns an undefined value.
Start a minimalist repl that can interact with the agent and its current state. This method requires the 'curses' gem to be installed and available to require.
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 |
# File 'lib/llm/agent.rb', line 559 def repl(name: self.name, path: nil, tools: [], skills: [], tracer: false, trace: nil) if trace != nil warn "llm.rb: trace option is deprecated, use tracer instead" tracer = trace end if !tracer previous = self.tracer self.tracer = nil end require_relative "repl" unless defined?(::LLM::Repl) LLM::Repl.new(agent: self, name:, path:, tools:, skills:).start ensure if !tracer self.tracer = previous end end |
#params ⇒ Hash
579 580 581 |
# File 'lib/llm/agent.rb', line 579 def params @ctx.params end |
#to_h ⇒ Hash
586 587 588 |
# File 'lib/llm/agent.rb', line 586 def to_h @ctx.to_h end |
#to_json ⇒ String
592 593 594 |
# File 'lib/llm/agent.rb', line 592 def to_json(...) LLM.json.dump(to_h, ...) end |
#inspect ⇒ String
598 599 600 601 |
# File 'lib/llm/agent.rb', line 598 def inspect "#<#{LLM::Utils.object_id(self)} " \ "@llm=#{@llm.class}, @mode=#{mode.inspect}, @messages=#{.inspect}>" end |
#serialize(**kw) Also known as: save
This method returns an undefined value.
606 607 608 |
# File 'lib/llm/agent.rb', line 606 def serialize(**kw) @ctx.serialize(**kw) end |
#deserialize(**kw) ⇒ LLM::Agent Also known as: restore
614 615 616 617 |
# File 'lib/llm/agent.rb', line 614 def deserialize(**kw) @ctx.deserialize(**kw) self end |