Class: LLM::Stream
- Inherits:
-
Object
- Object
- LLM::Stream
- Defined in:
- lib/llm/stream.rb,
lib/llm/stream/io.rb,
lib/llm/stream/queue.rb,
lib/llm/stream/disabled.rb
Overview
The on_* callbacks run inline with the streaming parser. They
therefore block streaming progress and should generally return as
quickly as possible.
The LLM::Stream class provides the callback interface for streamed model output in llm.rb.
A stream object can be an instance of LLM::Stream or a
subclass that overrides the callbacks it needs. For basic streaming,
llm.rb also accepts any object that implements #<<. #queue provides
a small helper for collecting asynchronous tool work started from a
callback.
The most common callback is #on_content, which also maps to #<<.
Providers may also call #on_reasoning_content and #on_tool_call when
that data is available. Runtime features such as context compaction may
also emit lifecycle callbacks like #on_filter or #on_compaction.
Direct Known Subclasses
Defined Under Namespace
Public callbacks collapse
-
#on_content(content) ⇒ nil
(also: #<<)
Called when visible assistant output is streamed.
-
#on_reasoning_content(content) ⇒ nil
Called when reasoning output is streamed separately from visible content.
-
#on_tool_call(tool) ⇒ nil
This method is called when the model requests a tool call.
-
#on_tool_return(tool, result) ⇒ nil
Called when queued streamed tool work returns.
-
#on_step(ctx, res) ⇒ nil
Called when a request in a turn has completed.
-
#on_filter(filter) ⇒ nil
Called before a message filter rewrites a prompt.
-
#on_filter_finish(filter) ⇒ nil
Called after a message filter finishes rewriting a prompt.
-
#on_compaction(compactor) ⇒ nil
Called before a context compaction starts.
-
#on_compaction_finish(compactor) ⇒ nil
Called after a context compaction finishes.
-
#on_retry(error, attempt) ⇒ nil
(also: #on_rate_limit)
Called when a request is retried because it was rate limited or timed out.
Finders collapse
-
#__find__(name) ⇒ LLM::Function?
Resolves a streamed tool call against the current request tools first, then falls back to the global function registry.
Class Method Summary collapse
-
.try(obj, extra: {}) ⇒ LLM::Stream
This method will try to convert its argument into an instance of LLM::Stream or a subclass of it.
Instance Method Summary collapse
-
#extra ⇒ Hash
Returns extra context associated with the current streamed request.
-
#ctx ⇒ LLM::Context?
Returns the current context, if one was attached to the stream.
-
#queue ⇒ LLM::Stream::Queue
Returns a lazily-initialized queue for tool results or spawned work.
-
#wait ⇒ Array<LLM::Function::Return>
Waits for queued tool work to finish and returns function results.
- #enabled? ⇒ Boolean
Class Method Details
.try(obj, extra: {}) ⇒ LLM::Stream
This method will try to convert its argument into an instance of LLM::Stream or a subclass of it.
Acceptable inputs include: LLM::Stream
objects, IO objects who implement #<<, true, false,
and nil. Anything else raises a TypeError.
The stream it answers with is ready to be told about a step: LLM::Step is prepended onto it here, once, rather than by every caller that means to save a conversation.
63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/llm/stream.rb', line 63 def self.try(obj, extra: {}) if LLM::Stream === obj obj.tap { _1.extra.merge!(extra) }.tap { _1.singleton_class.prepend(LLM::Step) } elsif obj.respond_to?(:<<) LLM::Stream::IO.new(obj).tap { _1.extra.merge!(extra) }.tap { _1.singleton_class.prepend(LLM::Step) } elsif obj == true LLM::Stream.new.tap { _1.extra.merge!(extra) }.tap { _1.singleton_class.prepend(LLM::Step) } elsif obj.nil? || obj == false LLM::Stream::Disabled.new.tap { _1.extra.merge!(extra) }.tap { _1.singleton_class.prepend(LLM::Step) } else raise TypeError, "invalid stream object" end end |
Instance Method Details
#__find__(name) ⇒ LLM::Function?
Resolves a streamed tool call against the current request tools first, then falls back to the global function registry.
242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/llm/stream.rb', line 242 def __find__(name) tools = extra[:tools] || ctx&.params&.dig(:tools) || [] tool = tools.find do candidate = _1.respond_to?(:function) ? _1.function.name : _1.name candidate.to_s == name.to_s end if tool tool.respond_to?(:function) ? tool.function : tool else LLM::Function.find_by_name(name) end end |
#extra ⇒ Hash
Returns extra context associated with the current streamed request.
80 81 82 |
# File 'lib/llm/stream.rb', line 80 def extra @extra ||= LLM::Object.from({}) end |
#ctx ⇒ LLM::Context?
Returns the current context, if one was attached to the stream.
87 88 89 |
# File 'lib/llm/stream.rb', line 87 def ctx extra[:ctx] end |
#queue ⇒ LLM::Stream::Queue
Returns a lazily-initialized queue for tool results or spawned work.
94 95 96 |
# File 'lib/llm/stream.rb', line 94 def queue @queue ||= Queue.new(self) end |
#wait ⇒ Array<LLM::Function::Return>
Waits for queued tool work to finish and returns function results. Any passed arguments are ignored because queued work is waited according to the actual task types already present in the queue.
103 104 105 |
# File 'lib/llm/stream.rb', line 103 def wait(*) queue.wait end |
#enabled? ⇒ Boolean
109 110 111 |
# File 'lib/llm/stream.rb', line 109 def enabled? true end |
#on_content(content) ⇒ nil Also known as: <<
Called when visible assistant output is streamed.
120 121 122 |
# File 'lib/llm/stream.rb', line 120 def on_content(content) nil end |
#on_reasoning_content(content) ⇒ nil
Called when reasoning output is streamed separately from visible content.
130 131 132 |
# File 'lib/llm/stream.rb', line 130 def on_reasoning_content(content) nil end |
#on_tool_call(tool) ⇒ nil
This method is called when the model requests a tool call. A little known feature: it is possible to spawn a tool call during a stream through:
@queue << tool.task(:thread).tap(&:spawn)
145 146 147 |
# File 'lib/llm/stream.rb', line 145 def on_tool_call(tool) nil end |
#on_tool_return(tool, result) ⇒ nil
Called when queued streamed tool work returns. This callback runs when #wait resolves work queued from #on_tool_call.
158 159 160 |
# File 'lib/llm/stream.rb', line 158 def on_tool_return(tool, result) nil end |
#on_step(ctx, res) ⇒ nil
Called when a request in a turn has completed.
This is the boundary between one request and the next: the response is in the context's message history, and a turn that asked for tools runs them after this while a turn that is finished ends here.
It is emitted once per successful request, so a request that is retried after a rate limit or a timeout calls this when it lands and not once per attempt. It is also emitted when the stream is disabled: a disabled stream has no output to report, but it is still told that a step ended.
The context is passed with the response so that a stream does not have to reach for it: LLM::Step, which saves the conversation the context holds, is written against this callback alone.
184 185 186 |
# File 'lib/llm/stream.rb', line 184 def on_step(ctx, res) nil end |
#on_filter(filter) ⇒ nil
Called before a message filter rewrites a prompt.
192 193 194 |
# File 'lib/llm/stream.rb', line 192 def on_filter(filter) nil end |
#on_filter_finish(filter) ⇒ nil
Called after a message filter finishes rewriting a prompt.
200 201 202 |
# File 'lib/llm/stream.rb', line 200 def on_filter_finish(filter) nil end |
#on_compaction(compactor) ⇒ nil
Called before a context compaction starts.
208 209 210 |
# File 'lib/llm/stream.rb', line 208 def on_compaction(compactor) nil end |
#on_compaction_finish(compactor) ⇒ nil
Called after a context compaction finishes.
216 217 218 |
# File 'lib/llm/stream.rb', line 216 def on_compaction_finish(compactor) nil end |
#on_retry(error, attempt) ⇒ nil Also known as: on_rate_limit
Called when a request is retried because it was rate limited or timed out.
228 229 230 |
# File 'lib/llm/stream.rb', line 228 def on_retry(error, attempt) nil end |