Release 1.16.0 · crmne/ruby_llm · GitHub
//releases/show" data-turbo-transient="true" />
Skip to content
Search or jump to...
Search code, repositories, users, issues, pull requests...
-->
Search
Clear
Search syntax tips
Provide feedback
--><br>We read every piece of feedback, and take your input very seriously.
Include my email address so I can be contacted
Cancel
Submit feedback
Saved searches
Use saved searches to filter your results more quickly
-->
Name
Query
To see all available qualifiers, see our documentation.
Cancel
Create saved search
Sign in
//releases/show;ref_cta:Sign up;ref_loc:header logged out"}"<br>Sign up
Appearance settings
Resetting focus
You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.
Dismiss alert
{{ message }}
crmne
ruby_llm
Public
Uh oh!
There was an error while loading. Please reload this page.
Notifications<br>You must be signed in to change notification settings
Fork<br>453
Star<br>4k
1.16.0
Latest
Latest
Compare
Choose a tag to compare
Sorry, something went wrong.
Filter
Loading
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
No results found
View all tags
crmne
released this
09 Jun 11:14
1.16.0
2cf34b9
This commit was signed with the committer’s verified signature .
crmne<br>Carmine Paolino
SSH Key Fingerprint: 0XaNsf6l/KlR9SjsIVBprJm8G1HG++OpKhtntZMNflo<br>Verified
Learn about vigilant mode.
RubyLLM 1.16: Concurrent Tool Execution + Instrumentation + Proxies Everywhere
RubyLLM 1.16 makes your tools run concurrently in threads or fibers, makes RubyLLM observable without monkey patching, and lets every native provider sit behind a proxy.
Concurrent Tool Execution
RubyLLM.Concurrent.Tool.Executions.mp4
When a model returns multiple tool calls in one response, RubyLLM has always run them one at a time. Incredibly useful for I/O-bound tools like HTTP calls, database lookups, other LLM requests.
Turn it on for every chat from one place:
RubyLLM.configure do |config|<br>config.tool_concurrency = true # :threads, :fibers, true, or false<br>end
true uses Ruby threads and needs no extra dependencies. :fibers mode uses the optional async gem.
You can also override it per PORO or Rails chat record, when a particular conversation needs different behaviour:
chat.with_tools(Weather, StockPrice, Currency, concurrency: true)<br>chat.with_tools(Weather, StockPrice, Currency, concurrency: :threads)<br>chat.with_tools(Weather, StockPrice, Currency, concurrency: :fibers)<br>chat.with_tools(Weather, StockPrice, concurrency: false)<br>chat_record.with_tools(Weather, StockPrice, concurrency: :threads)
Inside Rails, each concurrent tool call runs wrapped in the Rails executor, so connection pools, CurrentAttributes, and reloading behave the way the rest of your app expects.
Streaming Results as They Finish
Concurrency doesn't make you wait for the slowest tool to start showing progress. Each tool result is added back to the conversation the moment that tool finishes, in completion order. RubyLLM still waits for every result before asking the model for its next response, but your callbacks and streaming UI see results stream in as they land instead of all at once at the end.
This way, simply adding
RubyLLM.configure do |config|<br>config.tool_concurrency = :fibers # or :threads<br>end
gives you and your users the best performance and user experience.
Rails-Style Instrumentation
RubyLLM now emits structured events for the work it does. No specific observability backend required.
In Rails, events flow through ActiveSupport::Notifications automatically. Subscribe the same way you'd subscribe to any framework event:
# config/initializers/ruby_llm_instrumentation.rb<br>ActiveSupport::Notifications.subscribe('chat.ruby_llm') do |_name, _start, _finish, _id, payload|<br>Rails.logger.info(<br>provider: payload[:provider],<br>model: payload[:model],<br>input_tokens: payload[:input_tokens],<br>output_tokens: payload[:output_tokens]<br>end
Outside Rails, point config.instrumenter at any object that responds to instrument(name, payload) { ... }. Wire it into OpenTelemetry, StatsD, or your own logger:
RubyLLM.configure do |config|<br>config.instrumenter = AppInstrumenter.new<br>end
The events RubyLLM emits:
request.ruby_llm: HTTP request metadata: provider, method, URL, status
chat.ruby_llm: chat completion metadata: model, provider, messages, response, token usage
tool_call.ruby_llm: tool name, arguments, result
embedding.ruby_llm: embedding model, input, result, token usage, vector dimensions
models.refresh.ruby_llm: model registry refresh metadata
Payloads carry the Ruby objects observability adapters need. Message content, tool arguments, and provider responses can be sensitive, so export or log those fields only when your application policy allows it. See the new...