ruby_llm 1.3.0 → 1.3.2beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +13 -9
- data/lib/ruby_llm/active_record/acts_as.rb +1 -0
- data/lib/ruby_llm/aliases.json +22 -18
- data/lib/ruby_llm/attachment.rb +1 -1
- data/lib/ruby_llm/chat.rb +22 -12
- data/lib/ruby_llm/configuration.rb +1 -0
- data/lib/ruby_llm/models.json +4036 -3956
- data/lib/ruby_llm/models.rb +2 -1
- data/lib/ruby_llm/provider.rb +1 -1
- data/lib/ruby_llm/providers/anthropic/tools.rb +5 -4
- data/lib/ruby_llm/providers/bedrock/streaming/prelude_handling.rb +7 -7
- data/lib/ruby_llm/providers/gemini/embeddings.rb +4 -2
- data/lib/ruby_llm/providers/openai/capabilities.rb +4 -1
- data/lib/ruby_llm/providers/openai/chat.rb +12 -8
- data/lib/ruby_llm/providers/openai/embeddings.rb +4 -3
- data/lib/ruby_llm/tool.rb +8 -8
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/ruby_llm.rb +1 -1
- data/lib/tasks/models_docs.rake +14 -8
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b069393971ae461a63487ba8a13d1f81a791d96fc0f537fceb02de88d9e690d0
|
4
|
+
data.tar.gz: c34f0884ffd9cffd3c0311ebbe8d7fbacc151b17512984b999dace24fa0bfe74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ba83dd19febb3070e0f127eb6dc87fd92664d8afae2f4024240588fdc8624dabdcc5c2b089e5147d22601c3505b966f4bed7383fbf6e36ce8dff5bea568ef87
|
7
|
+
data.tar.gz: b7940d1a6b8bf72ba08eb9d63440505935022d372ffdab6aac51599fb23a9e68af49085cb965488f7306d28143f7b39ec9c0138a93ba52ad3ca3ac574e03a442
|
data/README.md
CHANGED
@@ -37,7 +37,7 @@
|
|
37
37
|
|
38
38
|
Every AI provider comes with its own client library, its own response format, its own conventions for streaming, and its own way of handling errors. Want to use multiple providers? Prepare to juggle incompatible APIs and bloated dependencies.
|
39
39
|
|
40
|
-
RubyLLM fixes all that. One beautiful API for everything. One consistent format. Minimal dependencies — just Faraday and
|
40
|
+
RubyLLM fixes all that. One beautiful API for everything. One consistent format. Minimal dependencies — just Faraday, Zeitwerk, and Marcel. Because working with AI should be a joy, not a chore.
|
41
41
|
|
42
42
|
## What makes it great
|
43
43
|
|
@@ -46,14 +46,14 @@ RubyLLM fixes all that. One beautiful API for everything. One consistent format.
|
|
46
46
|
chat = RubyLLM.chat
|
47
47
|
chat.ask "What's the best way to learn Ruby?"
|
48
48
|
|
49
|
-
# Analyze images
|
50
|
-
chat.ask "What's in this image?", with:
|
49
|
+
# Analyze images, audio, documents, and text files
|
50
|
+
chat.ask "What's in this image?", with: "ruby_conf.jpg"
|
51
|
+
chat.ask "Describe this meeting", with: "meeting.wav"
|
52
|
+
chat.ask "Summarize this document", with: "contract.pdf"
|
53
|
+
chat.ask "Explain this code", with: "app.rb"
|
51
54
|
|
52
|
-
#
|
53
|
-
chat.ask "
|
54
|
-
|
55
|
-
# Analyze documents
|
56
|
-
chat.ask "Summarize this document", with: { pdf: "contract.pdf" }
|
55
|
+
# Multiple files at once - types automatically detected
|
56
|
+
chat.ask "Analyze these files", with: ["diagram.png", "report.pdf", "notes.txt"]
|
57
57
|
|
58
58
|
# Stream responses in real-time
|
59
59
|
chat.ask "Tell me a story about a Ruby programmer" do |chunk|
|
@@ -90,7 +90,7 @@ chat.with_tool(Weather).ask "What's the weather in Berlin? (52.5200, 13.4050)"
|
|
90
90
|
* 💬 **Unified Chat:** Converse with models from OpenAI, Anthropic, Gemini, Bedrock, OpenRouter, DeepSeek, Ollama, or any OpenAI-compatible API using `RubyLLM.chat`.
|
91
91
|
* 👁️ **Vision:** Analyze images within chats.
|
92
92
|
* 🔊 **Audio:** Transcribe and understand audio content.
|
93
|
-
* 📄 **
|
93
|
+
* 📄 **Document Analysis:** Extract information from PDFs, text files, and other documents.
|
94
94
|
* 🖼️ **Image Generation:** Create images with `RubyLLM.paint`.
|
95
95
|
* 📊 **Embeddings:** Generate text embeddings for vector search with `RubyLLM.embed`.
|
96
96
|
* 🔧 **Tools (Function Calling):** Let AI models call your Ruby code using `RubyLLM::Tool`.
|
@@ -143,6 +143,10 @@ end
|
|
143
143
|
# Now interacting with a Chat record persists the conversation:
|
144
144
|
chat_record = Chat.create!(model_id: "gpt-4.1-nano")
|
145
145
|
chat_record.ask("Explain Active Record callbacks.") # User & Assistant messages saved
|
146
|
+
|
147
|
+
# Works seamlessly with file attachments - types automatically detected
|
148
|
+
chat_record.ask("What's in this file?", with: "report.pdf")
|
149
|
+
chat_record.ask("Analyze these", with: ["image.jpg", "data.csv", "notes.txt"])
|
146
150
|
```
|
147
151
|
Check the [Rails Integration Guide](https://rubyllm.com/guides/rails) for more.
|
148
152
|
|
data/lib/ruby_llm/aliases.json
CHANGED
@@ -65,13 +65,21 @@
|
|
65
65
|
"gemini": "gemini-2.0-flash-lite-001",
|
66
66
|
"openrouter": "google/gemini-2.0-flash-lite-001"
|
67
67
|
},
|
68
|
-
"gemini-2.5-flash
|
69
|
-
"gemini": "gemini-2.5-flash
|
70
|
-
"openrouter": "google/gemini-2.5-flash
|
68
|
+
"gemini-2.5-flash": {
|
69
|
+
"gemini": "gemini-2.5-flash",
|
70
|
+
"openrouter": "google/gemini-2.5-flash"
|
71
71
|
},
|
72
|
-
"gemini-2.5-
|
73
|
-
"gemini": "gemini-2.5-
|
74
|
-
"openrouter": "google/gemini-2.5-
|
72
|
+
"gemini-2.5-flash-lite-preview-06-17": {
|
73
|
+
"gemini": "gemini-2.5-flash-lite-preview-06-17",
|
74
|
+
"openrouter": "google/gemini-2.5-flash-lite-preview-06-17"
|
75
|
+
},
|
76
|
+
"gemini-2.5-pro": {
|
77
|
+
"gemini": "gemini-2.5-pro",
|
78
|
+
"openrouter": "google/gemini-2.5-pro"
|
79
|
+
},
|
80
|
+
"gemini-2.5-pro-preview-05-06": {
|
81
|
+
"gemini": "gemini-2.5-pro-preview-05-06",
|
82
|
+
"openrouter": "google/gemini-2.5-pro-preview-05-06"
|
75
83
|
},
|
76
84
|
"gemma-3-12b-it": {
|
77
85
|
"gemini": "gemma-3-12b-it",
|
@@ -85,18 +93,14 @@
|
|
85
93
|
"gemini": "gemma-3-4b-it",
|
86
94
|
"openrouter": "google/gemma-3-4b-it"
|
87
95
|
},
|
96
|
+
"gemma-3n-e4b-it": {
|
97
|
+
"gemini": "gemma-3n-e4b-it",
|
98
|
+
"openrouter": "google/gemma-3n-e4b-it"
|
99
|
+
},
|
88
100
|
"gpt-3.5-turbo": {
|
89
101
|
"openai": "gpt-3.5-turbo",
|
90
102
|
"openrouter": "openai/gpt-3.5-turbo"
|
91
103
|
},
|
92
|
-
"gpt-3.5-turbo-0125": {
|
93
|
-
"openai": "gpt-3.5-turbo-0125",
|
94
|
-
"openrouter": "openai/gpt-3.5-turbo-0125"
|
95
|
-
},
|
96
|
-
"gpt-3.5-turbo-1106": {
|
97
|
-
"openai": "gpt-3.5-turbo-1106",
|
98
|
-
"openrouter": "openai/gpt-3.5-turbo-1106"
|
99
|
-
},
|
100
104
|
"gpt-3.5-turbo-16k": {
|
101
105
|
"openai": "gpt-3.5-turbo-16k",
|
102
106
|
"openrouter": "openai/gpt-3.5-turbo-16k"
|
@@ -133,10 +137,6 @@
|
|
133
137
|
"openai": "gpt-4.1-nano",
|
134
138
|
"openrouter": "openai/gpt-4.1-nano"
|
135
139
|
},
|
136
|
-
"gpt-4.5-preview": {
|
137
|
-
"openai": "gpt-4.5-preview",
|
138
|
-
"openrouter": "openai/gpt-4.5-preview"
|
139
|
-
},
|
140
140
|
"gpt-4o": {
|
141
141
|
"openai": "gpt-4o",
|
142
142
|
"openrouter": "openai/gpt-4o"
|
@@ -201,6 +201,10 @@
|
|
201
201
|
"openai": "o3-mini",
|
202
202
|
"openrouter": "openai/o3-mini"
|
203
203
|
},
|
204
|
+
"o3-pro": {
|
205
|
+
"openai": "o3-pro",
|
206
|
+
"openrouter": "openai/o3-pro"
|
207
|
+
},
|
204
208
|
"o4-mini": {
|
205
209
|
"openai": "o4-mini",
|
206
210
|
"openrouter": "openai/o4-mini"
|
data/lib/ruby_llm/attachment.rb
CHANGED
@@ -99,7 +99,7 @@ module RubyLLM
|
|
99
99
|
def determine_mime_type
|
100
100
|
return @mime_type = active_storage_content_type if active_storage? && active_storage_content_type.present?
|
101
101
|
|
102
|
-
@mime_type = RubyLLM::MimeType.for(@source, name: @filename)
|
102
|
+
@mime_type = RubyLLM::MimeType.for(url? ? nil : @source, name: @filename)
|
103
103
|
@mime_type = RubyLLM::MimeType.for(content) if @mime_type == 'application/octet-stream'
|
104
104
|
@mime_type = 'audio/wav' if @mime_type == 'audio/x-wav' # Normalize WAV type
|
105
105
|
end
|
data/lib/ruby_llm/chat.rb
CHANGED
@@ -93,18 +93,19 @@ module RubyLLM
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def complete(&)
|
96
|
-
@on[:new_message]&.call
|
97
96
|
response = @provider.complete(
|
98
97
|
messages,
|
99
98
|
tools: @tools,
|
100
99
|
temperature: @temperature,
|
101
100
|
model: @model.id,
|
102
101
|
connection: @connection,
|
103
|
-
&
|
102
|
+
&wrap_streaming_block(&)
|
104
103
|
)
|
105
|
-
@on[:end_message]&.call(response)
|
106
104
|
|
105
|
+
@on[:new_message]&.call unless block_given?
|
107
106
|
add_message response
|
107
|
+
@on[:end_message]&.call(response)
|
108
|
+
|
108
109
|
if response.tool_call?
|
109
110
|
handle_tool_calls(response, &)
|
110
111
|
else
|
@@ -124,11 +125,28 @@ module RubyLLM
|
|
124
125
|
|
125
126
|
private
|
126
127
|
|
128
|
+
def wrap_streaming_block(&block)
|
129
|
+
return nil unless block_given?
|
130
|
+
|
131
|
+
first_chunk_received = false
|
132
|
+
|
133
|
+
proc do |chunk|
|
134
|
+
# Create message on first content chunk
|
135
|
+
unless first_chunk_received
|
136
|
+
first_chunk_received = true
|
137
|
+
@on[:new_message]&.call
|
138
|
+
end
|
139
|
+
|
140
|
+
# Pass chunk to user's block
|
141
|
+
block.call chunk
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
127
145
|
def handle_tool_calls(response, &)
|
128
146
|
response.tool_calls.each_value do |tool_call|
|
129
147
|
@on[:new_message]&.call
|
130
148
|
result = execute_tool tool_call
|
131
|
-
message =
|
149
|
+
message = add_message role: :tool, content: result.to_s, tool_call_id: tool_call.id
|
132
150
|
@on[:end_message]&.call(message)
|
133
151
|
end
|
134
152
|
|
@@ -140,13 +158,5 @@ module RubyLLM
|
|
140
158
|
args = tool_call.arguments
|
141
159
|
tool.call(args)
|
142
160
|
end
|
143
|
-
|
144
|
-
def add_tool_result(tool_use_id, result)
|
145
|
-
add_message(
|
146
|
-
role: :tool,
|
147
|
-
content: result.is_a?(Hash) && result[:error] ? result[:error] : result.to_s,
|
148
|
-
tool_call_id: tool_use_id
|
149
|
-
)
|
150
|
-
end
|
151
161
|
end
|
152
162
|
end
|