ruby_llm 1.0.0 → 1.1.0rc1
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 +58 -19
- data/lib/ruby_llm/active_record/acts_as.rb +46 -7
- data/lib/ruby_llm/aliases.json +65 -0
- data/lib/ruby_llm/aliases.rb +56 -0
- data/lib/ruby_llm/chat.rb +11 -10
- data/lib/ruby_llm/configuration.rb +4 -0
- data/lib/ruby_llm/error.rb +15 -4
- data/lib/ruby_llm/models.json +1489 -283
- data/lib/ruby_llm/models.rb +57 -22
- data/lib/ruby_llm/provider.rb +44 -41
- data/lib/ruby_llm/providers/anthropic/capabilities.rb +8 -9
- data/lib/ruby_llm/providers/anthropic/chat.rb +31 -4
- data/lib/ruby_llm/providers/anthropic/streaming.rb +12 -6
- data/lib/ruby_llm/providers/anthropic.rb +4 -0
- data/lib/ruby_llm/providers/bedrock/capabilities.rb +168 -0
- data/lib/ruby_llm/providers/bedrock/chat.rb +108 -0
- data/lib/ruby_llm/providers/bedrock/models.rb +84 -0
- data/lib/ruby_llm/providers/bedrock/signing.rb +831 -0
- data/lib/ruby_llm/providers/bedrock/streaming/base.rb +46 -0
- data/lib/ruby_llm/providers/bedrock/streaming/content_extraction.rb +63 -0
- data/lib/ruby_llm/providers/bedrock/streaming/message_processing.rb +79 -0
- data/lib/ruby_llm/providers/bedrock/streaming/payload_processing.rb +90 -0
- data/lib/ruby_llm/providers/bedrock/streaming/prelude_handling.rb +91 -0
- data/lib/ruby_llm/providers/bedrock/streaming.rb +36 -0
- data/lib/ruby_llm/providers/bedrock.rb +83 -0
- data/lib/ruby_llm/providers/deepseek/chat.rb +17 -0
- data/lib/ruby_llm/providers/deepseek.rb +5 -0
- data/lib/ruby_llm/providers/gemini/capabilities.rb +50 -34
- data/lib/ruby_llm/providers/gemini/chat.rb +8 -15
- data/lib/ruby_llm/providers/gemini/images.rb +5 -10
- data/lib/ruby_llm/providers/gemini/models.rb +0 -8
- data/lib/ruby_llm/providers/gemini/streaming.rb +35 -76
- data/lib/ruby_llm/providers/gemini/tools.rb +12 -12
- data/lib/ruby_llm/providers/gemini.rb +4 -0
- data/lib/ruby_llm/providers/openai/capabilities.rb +154 -177
- data/lib/ruby_llm/providers/openai/streaming.rb +9 -13
- data/lib/ruby_llm/providers/openai.rb +4 -0
- data/lib/ruby_llm/streaming.rb +96 -0
- data/lib/ruby_llm/tool.rb +15 -7
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/ruby_llm.rb +8 -3
- data/lib/tasks/browser_helper.rb +97 -0
- data/lib/tasks/capability_generator.rb +123 -0
- data/lib/tasks/capability_scraper.rb +224 -0
- data/lib/tasks/cli_helper.rb +22 -0
- data/lib/tasks/code_validator.rb +29 -0
- data/lib/tasks/model_updater.rb +66 -0
- data/lib/tasks/models.rake +28 -197
- data/lib/tasks/vcr.rake +97 -0
- metadata +42 -19
- data/.github/workflows/cicd.yml +0 -109
- data/.github/workflows/docs.yml +0 -53
- data/.gitignore +0 -58
- data/.overcommit.yml +0 -26
- data/.rspec +0 -3
- data/.rspec_status +0 -50
- data/.rubocop.yml +0 -10
- data/.yardopts +0 -12
- data/Gemfile +0 -32
- data/Rakefile +0 -9
- data/bin/console +0 -17
- data/bin/setup +0 -6
- data/ruby_llm.gemspec +0 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f1ca42c438f99a40f6ada6ab87e23377403d9d6c8db6049d54960308b6dd42f
|
4
|
+
data.tar.gz: 0467734c40a0a64505b8f4de2eea4b929e2b0c615fedb3fe88d75f8cf20040de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed886fb15081ce27309c0e583223e62adf171907f0f047344763e9eae5ede4dbb96657bb1b69dde9e68bc1ed56acedb93717273067236e40104dddcc09886f33
|
7
|
+
data.tar.gz: 7f2aa9c50cfd1a525273256ff014712944c976229f6b90fe338decaf2525bcb82f19dec187d14795ce0891a7fceadb5c048905c8afa8066b0ddbe37d54c48edd
|
data/README.md
CHANGED
@@ -2,13 +2,16 @@
|
|
2
2
|
|
3
3
|
A delightful Ruby way to work with AI. No configuration madness, no complex callbacks, no handler hell – just beautiful, expressive Ruby code.
|
4
4
|
|
5
|
-
<div style="display: flex; align-items: center; flex-wrap: wrap;
|
5
|
+
<div style="display: flex; align-items: center; flex-wrap: wrap; margin-bottom: 1em">
|
6
6
|
<img src="https://upload.wikimedia.org/wikipedia/commons/4/4d/OpenAI_Logo.svg" alt="OpenAI" height="40" width="120">
|
7
|
-
 
|
7
|
+
|
8
8
|
<img src="https://upload.wikimedia.org/wikipedia/commons/7/78/Anthropic_logo.svg" alt="Anthropic" height="40" width="120">
|
9
|
-
 
|
9
|
+
|
10
10
|
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8a/Google_Gemini_logo.svg" alt="Google" height="40" width="120">
|
11
|
-
 
|
11
|
+
|
12
|
+
<img src="https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/bedrock-color.svg" alt="Bedrock" height="40">
|
13
|
+
<img src="https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/bedrock-text.svg" alt="Bedrock" height="40" width="120">
|
14
|
+
|
12
15
|
<img src="https://upload.wikimedia.org/wikipedia/commons/e/ec/DeepSeek_logo.svg" alt="DeepSeek" height="40" width="120">
|
13
16
|
</div>
|
14
17
|
|
@@ -27,7 +30,7 @@ RubyLLM fixes all that. One beautiful API for everything. One consistent format.
|
|
27
30
|
|
28
31
|
## Features
|
29
32
|
|
30
|
-
- 💬 **Chat** with OpenAI, Anthropic, Gemini, and DeepSeek models
|
33
|
+
- 💬 **Chat** with OpenAI, Anthropic, Gemini, AWS Bedrock Anthropic, and DeepSeek models
|
31
34
|
- 👁️ **Vision and Audio** understanding
|
32
35
|
- 📄 **PDF Analysis** for analyzing documents
|
33
36
|
- 🖼️ **Image generation** with DALL-E and other providers
|
@@ -52,6 +55,11 @@ chat.ask "Describe this meeting", with: { audio: "meeting.wav" }
|
|
52
55
|
# Analyze documents
|
53
56
|
chat.ask "Summarize this document", with: { pdf: "contract.pdf" }
|
54
57
|
|
58
|
+
# Stream responses in real-time
|
59
|
+
chat.ask "Tell me a story about a Ruby programmer" do |chunk|
|
60
|
+
print chunk.content
|
61
|
+
end
|
62
|
+
|
55
63
|
# Generate images
|
56
64
|
RubyLLM.paint "a sunset over mountains in watercolor style"
|
57
65
|
|
@@ -59,16 +67,22 @@ RubyLLM.paint "a sunset over mountains in watercolor style"
|
|
59
67
|
RubyLLM.embed "Ruby is elegant and expressive"
|
60
68
|
|
61
69
|
# Let AI use your code
|
62
|
-
class
|
63
|
-
description "
|
64
|
-
param :
|
65
|
-
|
66
|
-
|
67
|
-
|
70
|
+
class Weather < RubyLLM::Tool
|
71
|
+
description "Gets current weather for a location"
|
72
|
+
param :latitude, desc: "Latitude (e.g., 52.5200)"
|
73
|
+
param :longitude, desc: "Longitude (e.g., 13.4050)"
|
74
|
+
|
75
|
+
def execute(latitude:, longitude:)
|
76
|
+
url = "https://api.open-meteo.com/v1/forecast?latitude=#{latitude}&longitude=#{longitude}¤t=temperature_2m,wind_speed_10m"
|
77
|
+
|
78
|
+
response = Faraday.get(url)
|
79
|
+
data = JSON.parse(response.body)
|
80
|
+
rescue => e
|
81
|
+
{ error: e.message }
|
68
82
|
end
|
69
83
|
end
|
70
84
|
|
71
|
-
chat.with_tool(
|
85
|
+
chat.with_tool(Weather).ask "What's the weather in Berlin? (52.5200, 13.4050)"
|
72
86
|
```
|
73
87
|
|
74
88
|
## Installation
|
@@ -88,10 +102,16 @@ Configure with your API keys:
|
|
88
102
|
|
89
103
|
```ruby
|
90
104
|
RubyLLM.configure do |config|
|
91
|
-
config.openai_api_key = ENV
|
92
|
-
config.anthropic_api_key = ENV
|
93
|
-
config.gemini_api_key = ENV
|
94
|
-
config.deepseek_api_key = ENV
|
105
|
+
config.openai_api_key = ENV.fetch('OPENAI_API_KEY', nil)
|
106
|
+
config.anthropic_api_key = ENV.fetch('ANTHROPIC_API_KEY', nil)
|
107
|
+
config.gemini_api_key = ENV.fetch('GEMINI_API_KEY', nil)
|
108
|
+
config.deepseek_api_key = ENV.fetch('DEEPSEEK_API_KEY', nil)
|
109
|
+
|
110
|
+
# Bedrock
|
111
|
+
config.bedrock_api_key = ENV.fetch('AWS_ACCESS_KEY_ID', nil)
|
112
|
+
config.bedrock_secret_key = ENV.fetch('AWS_SECRET_ACCESS_KEY', nil)
|
113
|
+
config.bedrock_region = ENV.fetch('AWS_REGION', nil)
|
114
|
+
config.bedrock_session_token = ENV.fetch('AWS_SESSION_TOKEN', nil)
|
95
115
|
end
|
96
116
|
```
|
97
117
|
|
@@ -115,6 +135,9 @@ chat.ask "Tell me a story about a Ruby programmer" do |chunk|
|
|
115
135
|
print chunk.content
|
116
136
|
end
|
117
137
|
|
138
|
+
# Set personality or behavior with instructions (aka system prompts) - available from 1.1.0
|
139
|
+
chat.with_instructions "You are a friendly Ruby expert who loves to help beginners"
|
140
|
+
|
118
141
|
# Understand content in multiple forms
|
119
142
|
chat.ask "Compare these diagrams", with: { image: ["diagram1.png", "diagram2.png"] }
|
120
143
|
chat.ask "Summarize this document", with: { pdf: "contract.pdf" }
|
@@ -145,8 +168,12 @@ class ToolCall < ApplicationRecord
|
|
145
168
|
acts_as_tool_call
|
146
169
|
end
|
147
170
|
|
148
|
-
# In
|
149
|
-
chat = Chat.create!
|
171
|
+
# In a background job
|
172
|
+
chat = Chat.create! model_id: "gpt-4o-mini"
|
173
|
+
|
174
|
+
# Set personality or behavior with instructions (aka system prompts) - they're persisted too! - available from 1.1.0
|
175
|
+
chat.with_instructions "You are a friendly Ruby expert who loves to help beginners"
|
176
|
+
|
150
177
|
chat.ask("What's your favorite Ruby gem?") do |chunk|
|
151
178
|
Turbo::StreamsChannel.broadcast_append_to(
|
152
179
|
chat,
|
@@ -182,6 +209,18 @@ chat.with_tool(Search).ask "Find documents about Ruby 3.3 features"
|
|
182
209
|
|
183
210
|
Check out the guides at https://rubyllm.com for deeper dives into conversations with tools, streaming responses, embedding generations, and more.
|
184
211
|
|
212
|
+
## Contributing
|
213
|
+
|
214
|
+
We welcome contributions to RubyLLM!
|
215
|
+
|
216
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed instructions on how to:
|
217
|
+
- Run the test suite
|
218
|
+
- Add new features
|
219
|
+
- Update documentation
|
220
|
+
- Re-record VCR cassettes when needed
|
221
|
+
|
222
|
+
We appreciate your help making RubyLLM better!
|
223
|
+
|
185
224
|
## License
|
186
225
|
|
187
|
-
Released under the MIT License.
|
226
|
+
Released under the MIT License.
|
@@ -9,7 +9,7 @@ module RubyLLM
|
|
9
9
|
extend ActiveSupport::Concern
|
10
10
|
|
11
11
|
class_methods do # rubocop:disable Metrics/BlockLength
|
12
|
-
def acts_as_chat(message_class: 'Message', tool_call_class: 'ToolCall')
|
12
|
+
def acts_as_chat(message_class: 'Message', tool_call_class: 'ToolCall')
|
13
13
|
include ChatMethods
|
14
14
|
|
15
15
|
@message_class = message_class.to_s
|
@@ -21,12 +21,6 @@ module RubyLLM
|
|
21
21
|
dependent: :destroy
|
22
22
|
|
23
23
|
delegate :complete,
|
24
|
-
:with_tool,
|
25
|
-
:with_tools,
|
26
|
-
:with_model,
|
27
|
-
:with_temperature,
|
28
|
-
:on_new_message,
|
29
|
-
:on_end_message,
|
30
24
|
:add_message,
|
31
25
|
to: :to_llm
|
32
26
|
end
|
@@ -85,6 +79,51 @@ module RubyLLM
|
|
85
79
|
.on_end_message { |msg| persist_message_completion(msg) }
|
86
80
|
end
|
87
81
|
|
82
|
+
def with_instructions(instructions, replace: false)
|
83
|
+
transaction do
|
84
|
+
# If replace is true, remove existing system messages
|
85
|
+
messages.where(role: :system).destroy_all if replace
|
86
|
+
|
87
|
+
# Create the new system message
|
88
|
+
messages.create!(
|
89
|
+
role: :system,
|
90
|
+
content: instructions
|
91
|
+
)
|
92
|
+
end
|
93
|
+
to_llm.with_instructions(instructions)
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
def with_tool(tool)
|
98
|
+
to_llm.with_tool(tool)
|
99
|
+
self
|
100
|
+
end
|
101
|
+
|
102
|
+
def with_tools(*tools)
|
103
|
+
to_llm.with_tools(*tools)
|
104
|
+
self
|
105
|
+
end
|
106
|
+
|
107
|
+
def with_model(model_id, provider: nil)
|
108
|
+
to_llm.with_model(model_id, provider: provider)
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
def with_temperature(temperature)
|
113
|
+
to_llm.with_temperature(temperature)
|
114
|
+
self
|
115
|
+
end
|
116
|
+
|
117
|
+
def on_new_message(&)
|
118
|
+
to_llm.on_new_message(&)
|
119
|
+
self
|
120
|
+
end
|
121
|
+
|
122
|
+
def on_end_message(&)
|
123
|
+
to_llm.on_end_message(&)
|
124
|
+
self
|
125
|
+
end
|
126
|
+
|
88
127
|
def ask(message, &)
|
89
128
|
message = { role: :user, content: message }
|
90
129
|
messages.create!(**message)
|
@@ -0,0 +1,65 @@
|
|
1
|
+
{
|
2
|
+
"claude-3-5-sonnet": {
|
3
|
+
"anthropic": "claude-3-5-sonnet-20241022",
|
4
|
+
"bedrock": "anthropic.claude-3-5-sonnet-20241022-v2:0"
|
5
|
+
},
|
6
|
+
"claude-3-5-haiku": {
|
7
|
+
"anthropic": "claude-3-5-haiku-20241022",
|
8
|
+
"bedrock": "anthropic.claude-3-5-haiku-20241022-v1:0"
|
9
|
+
},
|
10
|
+
"claude-3-7-sonnet": {
|
11
|
+
"anthropic": "claude-3-7-sonnet-20250219",
|
12
|
+
"bedrock": "us.anthropic.claude-3-7-sonnet-20250219-v1:0"
|
13
|
+
},
|
14
|
+
"claude-3-opus": {
|
15
|
+
"anthropic": "claude-3-opus-20240229",
|
16
|
+
"bedrock": "anthropic.claude-3-opus-20240229-v1:0"
|
17
|
+
},
|
18
|
+
"claude-3-sonnet": {
|
19
|
+
"anthropic": "claude-3-sonnet-20240229",
|
20
|
+
"bedrock": "anthropic.claude-3-sonnet-20240229-v1:0"
|
21
|
+
},
|
22
|
+
"claude-3-haiku": {
|
23
|
+
"anthropic": "claude-3-haiku-20240307",
|
24
|
+
"bedrock": "anthropic.claude-3-haiku-20240307-v1:0"
|
25
|
+
},
|
26
|
+
"claude-3": {
|
27
|
+
"anthropic": "claude-3-sonnet-20240229",
|
28
|
+
"bedrock": "anthropic.claude-3-sonnet-20240229-v1:0"
|
29
|
+
},
|
30
|
+
"claude-2": {
|
31
|
+
"anthropic": "claude-2.0",
|
32
|
+
"bedrock": "anthropic.claude-2.0"
|
33
|
+
},
|
34
|
+
"claude-2-1": {
|
35
|
+
"anthropic": "claude-2.1",
|
36
|
+
"bedrock": "anthropic.claude-2.1"
|
37
|
+
},
|
38
|
+
"gpt-4o": {
|
39
|
+
"openai": "gpt-4o-2024-11-20"
|
40
|
+
},
|
41
|
+
"gpt-4o-mini": {
|
42
|
+
"openai": "gpt-4o-mini-2024-07-18"
|
43
|
+
},
|
44
|
+
"gpt-4-turbo": {
|
45
|
+
"openai": "gpt-4-turbo-2024-04-09"
|
46
|
+
},
|
47
|
+
"gemini-1.5-flash": {
|
48
|
+
"gemini": "gemini-1.5-flash-002"
|
49
|
+
},
|
50
|
+
"gemini-1.5-flash-8b": {
|
51
|
+
"gemini": "gemini-1.5-flash-8b-001"
|
52
|
+
},
|
53
|
+
"gemini-1.5-pro": {
|
54
|
+
"gemini": "gemini-1.5-pro-002"
|
55
|
+
},
|
56
|
+
"gemini-2.0-flash": {
|
57
|
+
"gemini": "gemini-2.0-flash-001"
|
58
|
+
},
|
59
|
+
"o1": {
|
60
|
+
"openai": "o1-2024-12-17"
|
61
|
+
},
|
62
|
+
"o3-mini": {
|
63
|
+
"openai": "o3-mini-2025-01-31"
|
64
|
+
}
|
65
|
+
}
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLLM
|
4
|
+
# Manages model aliases, allowing users to reference models by simpler names
|
5
|
+
# that map to specific model versions across different providers.
|
6
|
+
#
|
7
|
+
# Aliases are defined in aliases.json and follow the format:
|
8
|
+
# {
|
9
|
+
# "simple-name": {
|
10
|
+
# "provider1": "specific-version-for-provider1",
|
11
|
+
# "provider2": "specific-version-for-provider2"
|
12
|
+
# }
|
13
|
+
# }
|
14
|
+
class Aliases
|
15
|
+
class << self
|
16
|
+
# Resolves a model ID to its provider-specific version
|
17
|
+
#
|
18
|
+
# @param model_id [String] the model identifier or alias
|
19
|
+
# @param provider_slug [String, Symbol, nil] optional provider to resolve for
|
20
|
+
# @return [String] the resolved model ID or the original if no alias exists
|
21
|
+
def resolve(model_id, provider = nil)
|
22
|
+
return model_id unless aliases[model_id]
|
23
|
+
|
24
|
+
if provider
|
25
|
+
aliases[model_id][provider.to_s] || model_id
|
26
|
+
else
|
27
|
+
# Get native provider's version
|
28
|
+
aliases[model_id].values.first || model_id
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns the loaded aliases mapping
|
33
|
+
# @return [Hash] the aliases mapping
|
34
|
+
def aliases
|
35
|
+
@aliases ||= load_aliases
|
36
|
+
end
|
37
|
+
|
38
|
+
# Loads aliases from the JSON file
|
39
|
+
# @return [Hash] the loaded aliases
|
40
|
+
def load_aliases
|
41
|
+
file_path = File.expand_path('aliases.json', __dir__)
|
42
|
+
if File.exist?(file_path)
|
43
|
+
JSON.parse(File.read(file_path))
|
44
|
+
else
|
45
|
+
{}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Reloads aliases from disk
|
50
|
+
# @return [Hash] the reloaded aliases
|
51
|
+
def reload!
|
52
|
+
@aliases = load_aliases
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/ruby_llm/chat.rb
CHANGED
@@ -13,10 +13,10 @@ module RubyLLM
|
|
13
13
|
|
14
14
|
attr_reader :model, :messages, :tools
|
15
15
|
|
16
|
-
def initialize(model: nil)
|
16
|
+
def initialize(model: nil, provider: nil)
|
17
17
|
model_id = model || RubyLLM.config.default_model
|
18
|
-
|
19
|
-
@temperature =
|
18
|
+
with_model(model_id, provider: provider)
|
19
|
+
@temperature = 0.7
|
20
20
|
@messages = []
|
21
21
|
@tools = {}
|
22
22
|
@on = {
|
@@ -32,6 +32,11 @@ module RubyLLM
|
|
32
32
|
|
33
33
|
alias say ask
|
34
34
|
|
35
|
+
def with_instructions(instructions)
|
36
|
+
add_message role: :system, content: instructions
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
35
40
|
def with_tool(tool)
|
36
41
|
unless @model.supports_functions
|
37
42
|
raise UnsupportedFunctionsError, "Model #{@model.id} doesn't support function calling"
|
@@ -47,13 +52,9 @@ module RubyLLM
|
|
47
52
|
self
|
48
53
|
end
|
49
54
|
|
50
|
-
def
|
51
|
-
@model = Models.find model_id
|
52
|
-
@provider =
|
53
|
-
end
|
54
|
-
|
55
|
-
def with_model(model_id)
|
56
|
-
self.model = model_id
|
55
|
+
def with_model(model_id, provider: nil)
|
56
|
+
@model = Models.find model_id, provider
|
57
|
+
@provider = Provider.providers[@model.provider.to_sym] || raise(Error, "Unknown provider: #{@model.provider}")
|
57
58
|
self
|
58
59
|
end
|
59
60
|
|
data/lib/ruby_llm/error.rb
CHANGED
@@ -19,15 +19,21 @@ module RubyLLM
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
|
22
|
+
# Error classes for non-HTTP errors
|
23
|
+
class ConfigurationError < StandardError; end
|
23
24
|
class InvalidRoleError < StandardError; end
|
25
|
+
class ModelNotFoundError < StandardError; end
|
24
26
|
class UnsupportedFunctionsError < StandardError; end
|
25
|
-
|
26
|
-
|
27
|
-
class ServiceUnavailableError < Error; end
|
27
|
+
|
28
|
+
# Error classes for different HTTP status codes
|
28
29
|
class BadRequestError < Error; end
|
30
|
+
class ForbiddenError < Error; end
|
31
|
+
class OverloadedError < Error; end
|
32
|
+
class PaymentRequiredError < Error; end
|
29
33
|
class RateLimitError < Error; end
|
30
34
|
class ServerError < Error; end
|
35
|
+
class ServiceUnavailableError < Error; end
|
36
|
+
class UnauthorizedError < Error; end
|
31
37
|
|
32
38
|
# Faraday middleware that maps provider-specific API errors to RubyLLM errors.
|
33
39
|
# Uses provider's parse_error method to extract meaningful error messages.
|
@@ -56,12 +62,17 @@ module RubyLLM
|
|
56
62
|
raise UnauthorizedError.new(response, message || 'Invalid API key - check your credentials')
|
57
63
|
when 402
|
58
64
|
raise PaymentRequiredError.new(response, message || 'Payment required - please top up your account')
|
65
|
+
when 403
|
66
|
+
raise ForbiddenError.new(response,
|
67
|
+
message || 'Forbidden - you do not have permission to access this resource')
|
59
68
|
when 429
|
60
69
|
raise RateLimitError.new(response, message || 'Rate limit exceeded - please wait a moment')
|
61
70
|
when 500
|
62
71
|
raise ServerError.new(response, message || 'API server error - please try again')
|
63
72
|
when 502..503
|
64
73
|
raise ServiceUnavailableError.new(response, message || 'API server unavailable - please try again later')
|
74
|
+
when 529
|
75
|
+
raise OverloadedError.new(response, message || 'Service overloaded - please try again later')
|
65
76
|
else
|
66
77
|
raise Error.new(response, message || 'An unknown error occurred')
|
67
78
|
end
|