Class: LLM::Context
- Inherits:
-
Object
- Object
- LLM::Context
- Includes:
- Deserializer, Serializer
- Defined in:
- lib/llm/context.rb,
lib/llm/context/serializer.rb,
lib/llm/context/deserializer.rb
Overview
LLM::Context is the stateful execution boundary in llm.rb.
It holds the evolving runtime state for an LLM workflow: conversation history, tool calls and returns, schema and streaming configuration, accumulated usage, and request ownership for interruption.
This is broader than prompt context alone. A context is the object that lets one-off prompts, streaming turns, tool execution, persistence, retries, and serialized long-lived workflows all run through the same model.
A context can drive the chat completions API that all providers support or the Responses API on providers that expose it.
Defined Under Namespace
Modules: Deserializer, Serializer
Instance Attribute Summary collapse
-
#llm ⇒ LLM::Provider
readonly
Returns a provider.
-
#messages ⇒ LLM::Buffer<LLM::Message>
readonly
Returns the accumulated message history for this context.
-
#mode ⇒ Symbol
readonly
Returns the context mode.
Instance Method Summary collapse
-
#call(target) ⇒ Array<LLM::Function::Return>
Calls a named collection of work through the context.
-
#context_window ⇒ Integer
Returns the model’s context window.
-
#cost ⇒ LLM::Cost
Returns an approximate cost for a given context based on both the provider, and model.
-
#functions ⇒ Array<LLM::Function>
Returns an array of functions that can be called.
-
#image_url(url) ⇒ LLM::Object
Recongize an object as a URL to an image.
-
#initialize(llm, params = {}) ⇒ Context
constructor
A new instance of Context.
- #inspect ⇒ String
-
#interrupt! ⇒ nil
(also: #cancel!)
Interrupt the active request, if any.
-
#local_file(path) ⇒ LLM::Object
Recongize an object as a local file.
-
#model ⇒ String
Returns the model a Context is actively using.
-
#prompt(&b) ⇒ LLM::Prompt
(also: #build_prompt)
Build a role-aware prompt for a single request.
-
#remote_file(res) ⇒ LLM::Object
Reconginize an object as a remote file.
-
#respond(prompt, params = {}) ⇒ LLM::Response
Interact with the context via the responses API.
-
#returns ⇒ Array<LLM::Function::Return>
Returns tool returns accumulated in this context.
-
#serialize(path:) ⇒ void
(also: #save)
Save the current context state.
-
#talk(prompt, params = {}) ⇒ LLM::Response
(also: #chat)
Interact with the context via the chat completions API.
- #to_h ⇒ Hash
- #to_json ⇒ String
-
#tracer ⇒ LLM::Tracer
Returns an LLM tracer.
-
#usage ⇒ LLM::Object?
Returns token usage accumulated in this context This method returns token usage for the latest assistant message, and it returns nil for non-assistant messages.
-
#wait(strategy) ⇒ Array<LLM::Function::Return>
Waits for queued tool work to finish.
Methods included from Deserializer
#deserialize, #deserialize_message
Constructor Details
#initialize(llm, params = {}) ⇒ Context
Returns a new instance of Context.
67 68 69 70 71 72 73 |
# File 'lib/llm/context.rb', line 67 def initialize(llm, params = {}) @llm = llm @mode = params.delete(:mode) || :completions @params = {model: llm.default_model, schema: nil}.compact.merge!(params) @messages = LLM::Buffer.new(llm) @owner = Fiber.current end |
Instance Attribute Details
#llm ⇒ LLM::Provider (readonly)
Returns a provider
50 51 52 |
# File 'lib/llm/context.rb', line 50 def llm @llm end |
#messages ⇒ LLM::Buffer<LLM::Message> (readonly)
Returns the accumulated message history for this context
45 46 47 |
# File 'lib/llm/context.rb', line 45 def @messages end |
#mode ⇒ Symbol (readonly)
Returns the context mode
55 56 57 |
# File 'lib/llm/context.rb', line 55 def mode @mode end |
Instance Method Details
#call(target) ⇒ Array<LLM::Function::Return>
Calls a named collection of work through the context.
This currently supports ‘:functions`, forwarding to `functions.call`.
158 159 160 161 162 163 |
# File 'lib/llm/context.rb', line 158 def call(target) case target when :functions then functions.call else raise ArgumentError, "Unknown target: #{target.inspect}. Expected :functions" end end |
#context_window ⇒ Integer
This method returns 0 when the provider or model can’t be found within Registry.
Returns the model’s context window. The context window is the maximum amount of input and output tokens a model can consider in a single request.
329 330 331 332 333 334 335 336 |
# File 'lib/llm/context.rb', line 329 def context_window LLM .registry_for(llm) .limit(model:) .context rescue LLM::NoSuchModelError, LLM::NoSuchRegistryError 0 end |
#cost ⇒ LLM::Cost
Returns an approximate cost for a given context based on both the provider, and model
312 313 314 315 316 317 318 319 |
# File 'lib/llm/context.rb', line 312 def cost return LLM::Cost.new(0, 0) unless usage cost = LLM.registry_for(llm).cost(model:) LLM::Cost.new( (cost.input.to_f / 1_000_000.0) * usage.input_tokens, (cost.output.to_f / 1_000_000.0) * usage.output_tokens ) end |
#functions ⇒ Array<LLM::Function>
Returns an array of functions that can be called
137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/llm/context.rb', line 137 def functions return_ids = returns.map(&:id) @messages .select(&:assistant?) .flat_map do |msg| fns = msg.functions.select { _1.pending? && !return_ids.include?(_1.id) } fns.each do |fn| fn.tracer = tracer fn.model = msg.model end end.extend(LLM::Function::Array) end |
#image_url(url) ⇒ LLM::Object
Recongize an object as a URL to an image
243 244 245 |
# File 'lib/llm/context.rb', line 243 def image_url(url) LLM::Object.from(value: url, kind: :image_url) end |
#inspect ⇒ String
128 129 130 131 132 |
# File 'lib/llm/context.rb', line 128 def inspect "#<#{self.class.name}:0x#{object_id.to_s(16)} " \ "@llm=#{@llm.class}, @mode=#{@mode.inspect}, @params=#{@params.inspect}, " \ "@messages=#{@messages.inspect}>" end |
#interrupt! ⇒ nil Also known as: cancel!
Interrupt the active request, if any. This is inspired by Go’s context cancellation model.
201 202 203 |
# File 'lib/llm/context.rb', line 201 def interrupt! llm.interrupt!(@owner) end |
#local_file(path) ⇒ LLM::Object
Recongize an object as a local file
253 254 255 |
# File 'lib/llm/context.rb', line 253 def local_file(path) LLM::Object.from(value: LLM.File(path), kind: :local_file) end |
#model ⇒ String
Returns the model a Context is actively using
277 278 279 |
# File 'lib/llm/context.rb', line 277 def model .find(&:assistant?)&.model || @params[:model] end |
#prompt(&b) ⇒ LLM::Prompt Also known as: build_prompt
Build a role-aware prompt for a single request.
Prefer this method over #build_prompt. The older method name is kept for backward compatibility.
232 233 234 |
# File 'lib/llm/context.rb', line 232 def prompt(&b) LLM::Prompt.new(@llm, &b) end |
#remote_file(res) ⇒ LLM::Object
Reconginize an object as a remote file
263 264 265 |
# File 'lib/llm/context.rb', line 263 def remote_file(res) LLM::Object.from(value: res, kind: :remote_file) end |
#respond(prompt, params = {}) ⇒ LLM::Response
Not all LLM providers support this API
Interact with the context via the responses API. This method immediately sends a request to the LLM and returns the response.
114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/llm/context.rb', line 114 def respond(prompt, params = {}) params = @params.merge(params) bind!(params[:stream], params[:model]) res_id = params[:store] == false ? nil : @messages.find(&:assistant?)&.response&.response_id params = params.merge(previous_response_id: res_id, input: @messages.to_a).compact res = @llm.responses.create(prompt, params) role = params[:role] || @llm.user_role @messages.concat LLM::Prompt === prompt ? prompt.to_a : [LLM::Message.new(role, prompt)] @messages.concat [res.choices[-1]] res end |
#returns ⇒ Array<LLM::Function::Return>
Returns tool returns accumulated in this context
168 169 170 171 172 173 174 175 176 |
# File 'lib/llm/context.rb', line 168 def returns @messages .select(&:tool_return?) .flat_map do |msg| LLM::Function::Return === msg.content ? [msg.content] : [*msg.content].grep(LLM::Function::Return) end end |
#serialize(path:) ⇒ void Also known as: save
This method returns an undefined value.
Save the current context state
303 304 305 |
# File 'lib/llm/context.rb', line 303 def serialize(path:) ::File.binwrite path, LLM.json.dump(to_h) end |
#talk(prompt, params = {}) ⇒ LLM::Response Also known as: chat
Interact with the context via the chat completions API. This method immediately sends a request to the LLM and returns the response.
87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/llm/context.rb', line 87 def talk(prompt, params = {}) return respond(prompt, params) if mode == :responses params = params.merge(messages: @messages.to_a) params = @params.merge(params) bind!(params[:stream], params[:model]) res = @llm.complete(prompt, params) role = params[:role] || @llm.user_role role = @llm.tool_role if params[:role].nil? && [*prompt].grep(LLM::Function::Return).any? @messages.concat LLM::Prompt === prompt ? prompt.to_a : [LLM::Message.new(role, prompt)] @messages.concat [res.choices[-1]] res end |
#to_h ⇒ Hash
283 284 285 |
# File 'lib/llm/context.rb', line 283 def to_h {schema_version: 1, model:, messages: @messages.map { (_1) }} end |
#to_json ⇒ String
289 290 291 |
# File 'lib/llm/context.rb', line 289 def to_json(...) to_h.to_json(...) end |
#tracer ⇒ LLM::Tracer
Returns an LLM tracer
270 271 272 |
# File 'lib/llm/context.rb', line 270 def tracer @llm.tracer end |
#usage ⇒ LLM::Object?
Returns token usage accumulated in this context This method returns token usage for the latest assistant message, and it returns nil for non-assistant messages.
213 214 215 |
# File 'lib/llm/context.rb', line 213 def usage @messages.find(&:assistant?)&.usage end |
#wait(strategy) ⇒ Array<LLM::Function::Return>
Waits for queued tool work to finish.
This prefers queued streamed tool work when the configured stream exposes a non-empty queue. Otherwise it falls back to waiting on the context’s pending functions directly.
188 189 190 191 192 193 194 195 |
# File 'lib/llm/context.rb', line 188 def wait(strategy) stream = @params[:stream] if LLM::Stream === stream && !stream.queue.empty? stream.wait(strategy) else functions.wait(strategy) end end |