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 and
respond, 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, or:ractor.
Instance Attribute Summary collapse
-
#llm ⇒ LLM::Provider
readonly
Returns a provider.
Class Method Summary collapse
-
.concurrency(concurrency = nil) ⇒ Symbol, ...
Set or get the tool execution concurrency.
-
.confirm(*tool_names, &block) ⇒ Array<String>, ...
Set or get the tool names that require confirmation before they can run.
-
.instructions(instructions = nil) ⇒ String?
Set or get the default instructions.
-
.model(model = nil, &block) ⇒ String?
Set or get the default model.
-
.name(name = UNDEFINED, &block) ⇒ String
Set or get an agent's name.
-
.schema(schema = nil, &block) ⇒ #to_json?
Set or get the default schema.
-
.set(properties) ⇒ void
Bulk-assign class-level agent defaults from a Hash.
-
.skills(*skills, &block) ⇒ Array<String>?
Set or get the default skills.
-
.stream(stream = nil, &block) ⇒ Object, ...
Set or get the default stream.
-
.tools(*tools, &block) ⇒ Array<LLM::Function>
Set or get the default tools.
-
.tracer(tracer = nil, &block) ⇒ LLM::Tracer, ...
Set or get the default tracer.
Instance Method Summary collapse
- #ask(prompt, params = {}) ⇒ Object
-
#concurrency ⇒ Symbol, ...
Returns the configured tool execution concurrency.
- #context_window ⇒ Integer
- #cost ⇒ LLM::Cost
- #deserialize(**kw) ⇒ LLM::Agent (also: #restore)
-
#image_url(url) ⇒ LLM::Object
Returns a tagged object.
-
#initialize(llm, params = {}) ⇒ Agent
constructor
A new instance of Agent.
- #inspect ⇒ String
-
#interrupt! ⇒ nil
(also: #cancel!)
Interrupt the active request, if any.
-
#local_file(path) ⇒ LLM::Object
Returns a tagged object.
- #messages ⇒ LLM::Buffer<LLM::Message>
- #mode ⇒ Symbol
-
#model ⇒ String
Returns the model an Agent is actively using.
-
#name ⇒ String
Returns the agent's name.
-
#on_tool_confirmation(fn, strategy) ⇒ LLM::Function::Return
This method is called when confirmation is required before a tool can run.
- #params ⇒ Hash
- #pending_functions ⇒ Array<LLM::Function>
- #prompt(&b) ⇒ LLM::Prompt (also: #build_prompt)
-
#remote_file(res) ⇒ LLM::Object
Returns a tagged object.
-
#repl(name: self.name, path: nil, tools: [], skills: [], tracer: false, trace: nil) ⇒ void
Start a minimalist repl that can interact with the agent and its current state.
- #returns ⇒ Array<LLM::Function::Return>
- #serialize(**kw) ⇒ void (also: #save)
-
#stream ⇒ LLM::Stream, ...
Returns a stream object, or nil.
-
#talk(prompt, params = {}) ⇒ LLM::Response
Maintain a conversation via the chat completions API.
- #to_h ⇒ Hash
- #to_json ⇒ String
-
#tracer ⇒ LLM::Tracer
Returns an LLM tracer.
- #tracer=(other) ⇒ void
- #usage ⇒ LLM::Object
- #wait ⇒ Array<LLM::Function::Return>
Constructor Details
#initialize(llm, params = {}) ⇒ Agent
Returns a new instance of Agent.
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
# File 'lib/llm/agent.rb', line 278 def initialize(llm, params = {}) @llm = llm fields = %i[name model skills schema tracer stream tools concurrency instructions confirm] fields_ivar = %i[name 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)) end |
Instance Attribute Details
#llm ⇒ LLM::Provider (readonly)
Returns a provider
58 59 60 |
# File 'lib/llm/agent.rb', line 58 def llm @llm end |
Class Method Details
.concurrency(concurrency = nil) ⇒ Symbol, ...
Set or get the tool execution concurrency.
189 190 191 192 |
# File 'lib/llm/agent.rb', line 189 def self.concurrency(concurrency = nil) return @concurrency if concurrency.nil? @concurrency = concurrency 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.
255 256 257 258 259 260 261 262 |
# File 'lib/llm/agent.rb', line 255 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 |
.instructions(instructions = nil) ⇒ String?
Set or get the default instructions
169 170 171 172 |
# File 'lib/llm/agent.rb', line 169 def self.instructions(instructions = nil) return @instructions if instructions.nil? @instructions = instructions end |
.model(model = nil, &block) ⇒ String?
Set or get the default model
117 118 119 120 |
# File 'lib/llm/agent.rb', line 117 def self.model(model = nil, &block) return @model if model.nil? && !block @model = block || model end |
.name(name = UNDEFINED, &block) ⇒ String
Set or get an agent's name
103 104 105 106 107 108 109 |
# File 'lib/llm/agent.rb', line 103 def self.name(name = UNDEFINED, &block) if name.equal?(UNDEFINED) @name || self.to_s.gsub(/(.)([A-Z])/, '\\1-\\2').downcase else @name = block || name end end |
.schema(schema = nil, &block) ⇒ #to_json?
Set or get the default schema
158 159 160 161 |
# File 'lib/llm/agent.rb', line 158 def self.schema(schema = nil, &block) return @schema if schema.nil? && !block @schema = block || schema end |
.set(properties) ⇒ void
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.
87 88 89 90 91 92 93 94 95 |
# File 'lib/llm/agent.rb', line 87 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 |
.skills(*skills, &block) ⇒ Array<String>?
Set or get the default skills
143 144 145 146 147 148 149 150 |
# File 'lib/llm/agent.rb', line 143 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 |
.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.
229 230 231 232 |
# File 'lib/llm/agent.rb', line 229 def self.stream(stream = nil, &block) return @stream if stream.nil? && !block @stream = block || stream end |
.tools(*tools, &block) ⇒ Array<LLM::Function>
Set or get the default tools
128 129 130 131 132 133 134 135 |
# File 'lib/llm/agent.rb', line 128 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 |
.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.
209 210 211 212 |
# File 'lib/llm/agent.rb', line 209 def self.tracer(tracer = nil, &block) return @tracer if tracer.nil? && !block @tracer = block || tracer end |
Instance Method Details
#ask(prompt, params = {}) ⇒ Object
327 328 329 |
# File 'lib/llm/agent.rb', line 327 def ask(prompt, params = {}) run_loop(prompt, params, :ask) end |
#concurrency ⇒ Symbol, ...
Returns the configured tool execution concurrency.
446 447 448 |
# File 'lib/llm/agent.rb', line 446 def concurrency @concurrency end |
#context_window ⇒ Integer
460 461 462 |
# File 'lib/llm/agent.rb', line 460 def context_window @ctx.context_window end |
#deserialize(**kw) ⇒ LLM::Agent Also known as: restore
543 544 545 546 |
# File 'lib/llm/agent.rb', line 543 def deserialize(**kw) @ctx.deserialize(**kw) self end |
#image_url(url) ⇒ LLM::Object
Returns a tagged object
385 386 387 |
# File 'lib/llm/agent.rb', line 385 def image_url(url) @ctx.image_url(url) end |
#inspect ⇒ String
527 528 529 530 |
# File 'lib/llm/agent.rb', line 527 def inspect "#<#{LLM::Utils.object_id(self)} " \ "@llm=#{@llm.class}, @mode=#{mode.inspect}, @messages=#{.inspect}>" end |
#interrupt! ⇒ nil Also known as: cancel!
Interrupt the active request, if any.
366 367 368 |
# File 'lib/llm/agent.rb', line 366 def interrupt! @ctx.interrupt! end |
#local_file(path) ⇒ LLM::Object
Returns a tagged object
394 395 396 |
# File 'lib/llm/agent.rb', line 394 def local_file(path) @ctx.local_file(path) end |
#mode ⇒ Symbol
439 440 441 |
# File 'lib/llm/agent.rb', line 439 def mode @ctx.mode end |
#model ⇒ String
Returns the model an Agent is actively using
433 434 435 |
# File 'lib/llm/agent.rb', line 433 def model @ctx.model end |
#name ⇒ String
Returns the agent's name
301 302 303 |
# File 'lib/llm/agent.rb', line 301 def name @name end |
#on_tool_confirmation(fn, strategy) ⇒ LLM::Function::Return
This method is called when confirmation is required before a tool can run.
560 561 562 |
# File 'lib/llm/agent.rb', line 560 def on_tool_confirmation(fn, strategy) fn.cancel end |
#params ⇒ Hash
508 509 510 |
# File 'lib/llm/agent.rb', line 508 def params @ctx.params end |
#pending_functions ⇒ Array<LLM::Function>
339 340 341 |
# File 'lib/llm/agent.rb', line 339 def pending_functions @tracer ? @llm.with_tracer(@tracer) { @ctx.pending_functions } : @ctx.pending_functions end |
#prompt(&b) ⇒ LLM::Prompt Also known as: build_prompt
375 376 377 |
# File 'lib/llm/agent.rb', line 375 def prompt(&b) @ctx.prompt(&b) end |
#remote_file(res) ⇒ LLM::Object
Returns a tagged object
403 404 405 |
# File 'lib/llm/agent.rb', line 403 def remote_file(res) @ctx.remote_file(res) end |
#repl(name: self.name, path: nil, tools: [], skills: [], tracer: false, trace: nil) ⇒ void
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.
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 |
# File 'lib/llm/agent.rb', line 488 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 |
#returns ⇒ Array<LLM::Function::Return>
346 347 348 |
# File 'lib/llm/agent.rb', line 346 def returns @ctx.returns end |
#serialize(**kw) ⇒ void Also known as: save
This method returns an undefined value.
535 536 537 |
# File 'lib/llm/agent.rb', line 535 def serialize(**kw) @ctx.serialize(**kw) end |
#stream ⇒ LLM::Stream, ...
Returns a stream object, or nil
426 427 428 |
# File 'lib/llm/agent.rb', line 426 def stream @ctx.stream 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.
321 322 323 |
# File 'lib/llm/agent.rb', line 321 def talk(prompt, params = {}) run_loop(prompt, params, :talk) end |
#to_h ⇒ Hash
515 516 517 |
# File 'lib/llm/agent.rb', line 515 def to_h @ctx.to_h end |
#to_json ⇒ String
521 522 523 |
# File 'lib/llm/agent.rb', line 521 def to_json(...) LLM.json.dump(to_h, ...) end |
#tracer ⇒ LLM::Tracer
Returns an LLM tracer
410 411 412 |
# File 'lib/llm/agent.rb', line 410 def tracer @tracer || @ctx.tracer end |
#tracer=(other) ⇒ void
This method returns an undefined value.
418 419 420 421 |
# File 'lib/llm/agent.rb', line 418 def tracer=(other) @ctx.tracer = other @tracer = other end |
#wait ⇒ Array<LLM::Function::Return>
353 354 355 |
# File 'lib/llm/agent.rb', line 353 def wait(...) @tracer ? @llm.with_tracer(@tracer) { @ctx.wait(...) } : @ctx.wait(...) end |