open_router_enhanced 1.0.0
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 +7 -0
- data/.env.example +1 -0
- data/.rspec +3 -0
- data/.rubocop.yml +13 -0
- data/.rubocop_todo.yml +130 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +41 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/CONTRIBUTING.md +384 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +138 -0
- data/LICENSE.txt +21 -0
- data/MIGRATION.md +556 -0
- data/README.md +1660 -0
- data/Rakefile +334 -0
- data/SECURITY.md +150 -0
- data/VCR_CONFIGURATION.md +80 -0
- data/docs/model_selection.md +637 -0
- data/docs/observability.md +430 -0
- data/docs/prompt_templates.md +422 -0
- data/docs/streaming.md +467 -0
- data/docs/structured_outputs.md +466 -0
- data/docs/tools.md +1016 -0
- data/examples/basic_completion.rb +122 -0
- data/examples/model_selection_example.rb +141 -0
- data/examples/observability_example.rb +199 -0
- data/examples/prompt_template_example.rb +184 -0
- data/examples/smart_completion_example.rb +89 -0
- data/examples/streaming_example.rb +176 -0
- data/examples/structured_outputs_example.rb +191 -0
- data/examples/tool_calling_example.rb +149 -0
- data/lib/open_router/client.rb +552 -0
- data/lib/open_router/http.rb +118 -0
- data/lib/open_router/json_healer.rb +263 -0
- data/lib/open_router/model_registry.rb +378 -0
- data/lib/open_router/model_selector.rb +462 -0
- data/lib/open_router/prompt_template.rb +290 -0
- data/lib/open_router/response.rb +371 -0
- data/lib/open_router/schema.rb +288 -0
- data/lib/open_router/streaming_client.rb +210 -0
- data/lib/open_router/tool.rb +221 -0
- data/lib/open_router/tool_call.rb +180 -0
- data/lib/open_router/usage_tracker.rb +277 -0
- data/lib/open_router/version.rb +5 -0
- data/lib/open_router.rb +123 -0
- data/sig/open_router.rbs +20 -0
- metadata +186 -0
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
open_router_enhanced (1.0.0)
|
|
5
|
+
activesupport (>= 6.0)
|
|
6
|
+
dotenv (>= 2)
|
|
7
|
+
faraday (>= 1)
|
|
8
|
+
faraday-multipart (>= 1)
|
|
9
|
+
json-schema (~> 4.0)
|
|
10
|
+
|
|
11
|
+
GEM
|
|
12
|
+
remote: https://rubygems.org/
|
|
13
|
+
specs:
|
|
14
|
+
activesupport (8.0.2.1)
|
|
15
|
+
base64
|
|
16
|
+
benchmark (>= 0.3)
|
|
17
|
+
bigdecimal
|
|
18
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
19
|
+
connection_pool (>= 2.2.5)
|
|
20
|
+
drb
|
|
21
|
+
i18n (>= 1.6, < 2)
|
|
22
|
+
logger (>= 1.4.2)
|
|
23
|
+
minitest (>= 5.1)
|
|
24
|
+
securerandom (>= 0.3)
|
|
25
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
|
26
|
+
uri (>= 0.13.1)
|
|
27
|
+
addressable (2.8.7)
|
|
28
|
+
public_suffix (>= 2.0.2, < 7.0)
|
|
29
|
+
ast (2.4.3)
|
|
30
|
+
base64 (0.3.0)
|
|
31
|
+
benchmark (0.4.1)
|
|
32
|
+
bigdecimal (3.2.2)
|
|
33
|
+
coderay (1.1.3)
|
|
34
|
+
concurrent-ruby (1.3.5)
|
|
35
|
+
connection_pool (2.5.3)
|
|
36
|
+
crack (1.0.0)
|
|
37
|
+
bigdecimal
|
|
38
|
+
rexml
|
|
39
|
+
diff-lcs (1.6.2)
|
|
40
|
+
dotenv (3.1.8)
|
|
41
|
+
drb (2.2.3)
|
|
42
|
+
faraday (2.13.4)
|
|
43
|
+
faraday-net_http (>= 2.0, < 3.5)
|
|
44
|
+
json
|
|
45
|
+
logger
|
|
46
|
+
faraday-multipart (1.1.1)
|
|
47
|
+
multipart-post (~> 2.0)
|
|
48
|
+
faraday-net_http (3.4.1)
|
|
49
|
+
net-http (>= 0.5.0)
|
|
50
|
+
hashdiff (1.2.0)
|
|
51
|
+
i18n (1.14.7)
|
|
52
|
+
concurrent-ruby (~> 1.0)
|
|
53
|
+
json (2.13.2)
|
|
54
|
+
json-schema (4.3.1)
|
|
55
|
+
addressable (>= 2.8)
|
|
56
|
+
language_server-protocol (3.17.0.5)
|
|
57
|
+
lint_roller (1.1.0)
|
|
58
|
+
logger (1.7.0)
|
|
59
|
+
method_source (1.1.0)
|
|
60
|
+
minitest (5.25.5)
|
|
61
|
+
multipart-post (2.4.1)
|
|
62
|
+
net-http (0.6.0)
|
|
63
|
+
uri
|
|
64
|
+
parallel (1.27.0)
|
|
65
|
+
parser (3.3.9.0)
|
|
66
|
+
ast (~> 2.4.1)
|
|
67
|
+
racc
|
|
68
|
+
prism (1.4.0)
|
|
69
|
+
pry (0.15.2)
|
|
70
|
+
coderay (~> 1.1)
|
|
71
|
+
method_source (~> 1.0)
|
|
72
|
+
public_suffix (6.0.2)
|
|
73
|
+
racc (1.8.1)
|
|
74
|
+
rainbow (3.1.1)
|
|
75
|
+
rake (13.3.0)
|
|
76
|
+
regexp_parser (2.11.2)
|
|
77
|
+
rexml (3.4.1)
|
|
78
|
+
rspec (3.13.1)
|
|
79
|
+
rspec-core (~> 3.13.0)
|
|
80
|
+
rspec-expectations (~> 3.13.0)
|
|
81
|
+
rspec-mocks (~> 3.13.0)
|
|
82
|
+
rspec-core (3.13.5)
|
|
83
|
+
rspec-support (~> 3.13.0)
|
|
84
|
+
rspec-expectations (3.13.5)
|
|
85
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
86
|
+
rspec-support (~> 3.13.0)
|
|
87
|
+
rspec-mocks (3.13.5)
|
|
88
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
89
|
+
rspec-support (~> 3.13.0)
|
|
90
|
+
rspec-support (3.13.4)
|
|
91
|
+
rubocop (1.79.2)
|
|
92
|
+
json (~> 2.3)
|
|
93
|
+
language_server-protocol (~> 3.17.0.2)
|
|
94
|
+
lint_roller (~> 1.1.0)
|
|
95
|
+
parallel (~> 1.10)
|
|
96
|
+
parser (>= 3.3.0.2)
|
|
97
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
98
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
99
|
+
rubocop-ast (>= 1.46.0, < 2.0)
|
|
100
|
+
ruby-progressbar (~> 1.7)
|
|
101
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
102
|
+
rubocop-ast (1.46.0)
|
|
103
|
+
parser (>= 3.3.7.2)
|
|
104
|
+
prism (~> 1.4)
|
|
105
|
+
ruby-progressbar (1.13.0)
|
|
106
|
+
securerandom (0.4.1)
|
|
107
|
+
tzinfo (2.0.6)
|
|
108
|
+
concurrent-ruby (~> 1.0)
|
|
109
|
+
unicode-display_width (3.1.5)
|
|
110
|
+
unicode-emoji (~> 4.0, >= 4.0.4)
|
|
111
|
+
unicode-emoji (4.0.4)
|
|
112
|
+
uri (1.0.3)
|
|
113
|
+
vcr (6.3.1)
|
|
114
|
+
base64
|
|
115
|
+
webmock (3.25.1)
|
|
116
|
+
addressable (>= 2.8.0)
|
|
117
|
+
crack (>= 0.3.2)
|
|
118
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
|
119
|
+
|
|
120
|
+
PLATFORMS
|
|
121
|
+
arm64-darwin-21
|
|
122
|
+
arm64-darwin-24
|
|
123
|
+
x86_64-linux
|
|
124
|
+
|
|
125
|
+
DEPENDENCIES
|
|
126
|
+
activesupport (>= 6.0)
|
|
127
|
+
dotenv (>= 2)
|
|
128
|
+
json-schema
|
|
129
|
+
open_router_enhanced!
|
|
130
|
+
pry (>= 0.14)
|
|
131
|
+
rake (~> 13.0)
|
|
132
|
+
rspec (~> 3.0)
|
|
133
|
+
rubocop
|
|
134
|
+
vcr (~> 6.2)
|
|
135
|
+
webmock (~> 3.19)
|
|
136
|
+
|
|
137
|
+
BUNDLED WITH
|
|
138
|
+
2.4.12
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Eric Stiens
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/MIGRATION.md
ADDED
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
# Migration Guide: From OpenRouter to OpenRouter Enhanced
|
|
2
|
+
|
|
3
|
+
This guide helps you migrate from the [original OpenRouter gem](https://github.com/OlympiaAI/open_router) to OpenRouter Enhanced.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
OpenRouter Enhanced is a comprehensive fork that adds enterprise-grade AI development features while maintaining **100% backward compatibility** with the original gem.
|
|
8
|
+
|
|
9
|
+
**Good News**: Your existing code will continue to work without modifications!
|
|
10
|
+
|
|
11
|
+
## Quick Migration Checklist
|
|
12
|
+
|
|
13
|
+
- [ ] Update `Gemfile` to use `open_router_enhanced`
|
|
14
|
+
- [ ] Run `bundle install`
|
|
15
|
+
- [ ] Test existing code (should work unchanged)
|
|
16
|
+
- [ ] Optionally adopt new features as needed
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
### Update Gemfile
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
# Before
|
|
24
|
+
gem "open_router"
|
|
25
|
+
|
|
26
|
+
# After
|
|
27
|
+
gem "open_router_enhanced"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Then run:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
bundle install
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Alternative: Try Before Migrating
|
|
37
|
+
|
|
38
|
+
You can test the enhanced gem alongside the original:
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
gem "open_router", require: false
|
|
42
|
+
gem "open_router_enhanced"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Backward Compatibility
|
|
46
|
+
|
|
47
|
+
### All Existing Code Works Unchanged
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
# This code from the original gem works identically
|
|
51
|
+
client = OpenRouter::Client.new
|
|
52
|
+
response = client.complete(
|
|
53
|
+
[{ role: "user", content: "Hello!" }],
|
|
54
|
+
model: "openai/gpt-4o-mini"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
puts response["choices"][0]["message"]["content"] # Hash access still works
|
|
58
|
+
puts response.content # New accessor methods also available
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Response Object Compatibility
|
|
62
|
+
|
|
63
|
+
The Response object maintains full backward compatibility through delegation:
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
response = client.complete(messages, model: "openai/gpt-4o-mini")
|
|
67
|
+
|
|
68
|
+
# Original hash-style access (still works)
|
|
69
|
+
response["choices"]
|
|
70
|
+
response["model"]
|
|
71
|
+
response["usage"]["total_tokens"]
|
|
72
|
+
response.dig("choices", 0, "message", "content")
|
|
73
|
+
|
|
74
|
+
# New convenience methods (enhanced)
|
|
75
|
+
response.choices
|
|
76
|
+
response.model
|
|
77
|
+
response.total_tokens
|
|
78
|
+
response.content
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## What's New
|
|
82
|
+
|
|
83
|
+
OpenRouter Enhanced adds these features while keeping everything you know working:
|
|
84
|
+
|
|
85
|
+
### 1. Tool Calling (Function Calling)
|
|
86
|
+
|
|
87
|
+
**New capability** - The original gem had no built-in tool calling support.
|
|
88
|
+
|
|
89
|
+
```ruby
|
|
90
|
+
# Define tools with Ruby DSL
|
|
91
|
+
weather_tool = OpenRouter::Tool.define do
|
|
92
|
+
name "get_weather"
|
|
93
|
+
description "Get current weather"
|
|
94
|
+
parameters do
|
|
95
|
+
string :location, required: true, description: "City name"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Use in completion
|
|
100
|
+
response = client.complete(
|
|
101
|
+
messages,
|
|
102
|
+
model: "anthropic/claude-3.5-sonnet",
|
|
103
|
+
tools: [weather_tool]
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Handle tool calls
|
|
107
|
+
if response.has_tool_calls?
|
|
108
|
+
response.tool_calls.each do |call|
|
|
109
|
+
result = call.execute do |name, args|
|
|
110
|
+
# Execute tool
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 2. Structured Outputs
|
|
117
|
+
|
|
118
|
+
**New capability** - Get guaranteed JSON responses with schema validation.
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
# Define schema
|
|
122
|
+
user_schema = OpenRouter::Schema.define("user") do
|
|
123
|
+
string :name, required: true
|
|
124
|
+
integer :age, minimum: 0, maximum: 120
|
|
125
|
+
string :email, format: "email"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Request structured output
|
|
129
|
+
response = client.complete(
|
|
130
|
+
messages,
|
|
131
|
+
model: "openai/gpt-4o-mini",
|
|
132
|
+
response_format: user_schema
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Get parsed JSON
|
|
136
|
+
user = response.structured_output
|
|
137
|
+
# => { "name" => "John", "age" => 30, "email" => "john@example.com" }
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 3. Smart Model Selection
|
|
141
|
+
|
|
142
|
+
**New capability** - Intelligent model selection based on requirements.
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
# Original gem - manual model selection
|
|
146
|
+
model = "anthropic/claude-3-5-sonnet"
|
|
147
|
+
|
|
148
|
+
# Enhanced gem - intelligent selection
|
|
149
|
+
model = OpenRouter::ModelSelector.new
|
|
150
|
+
.require(:function_calling, :vision)
|
|
151
|
+
.optimize_for(:cost)
|
|
152
|
+
.within_budget(max_cost: 0.01)
|
|
153
|
+
.choose
|
|
154
|
+
|
|
155
|
+
# Use selected model
|
|
156
|
+
response = client.complete(messages, model: model)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### 4. Usage Tracking & Cost Monitoring
|
|
160
|
+
|
|
161
|
+
**New capability** - Automatic usage and cost tracking.
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
# Enable tracking
|
|
165
|
+
client = OpenRouter::Client.new(track_usage: true)
|
|
166
|
+
|
|
167
|
+
# Make requests
|
|
168
|
+
response = client.complete(messages, model: "openai/gpt-4o-mini")
|
|
169
|
+
|
|
170
|
+
# View metrics
|
|
171
|
+
tracker = client.usage_tracker
|
|
172
|
+
puts "Total cost: $#{tracker.total_cost}"
|
|
173
|
+
puts "Total tokens: #{tracker.total_tokens}"
|
|
174
|
+
puts "Cache hit rate: #{tracker.cache_hit_rate}%"
|
|
175
|
+
|
|
176
|
+
# Export data
|
|
177
|
+
csv_data = tracker.export_csv
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 5. Streaming Support
|
|
181
|
+
|
|
182
|
+
**Enhanced** - The original gem had basic streaming, now with callbacks.
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
# Original streaming still works
|
|
186
|
+
client.complete(messages, model: model, stream: true) do |chunk|
|
|
187
|
+
print chunk.dig("choices", 0, "delta", "content")
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Enhanced streaming client with callbacks
|
|
191
|
+
streaming_client = OpenRouter::StreamingClient.new
|
|
192
|
+
|
|
193
|
+
streaming_client.on(:stream_start) { puts "Starting..." }
|
|
194
|
+
streaming_client.on(:stream_chunk) { |chunk| print chunk }
|
|
195
|
+
streaming_client.on(:stream_end) { puts "\nDone!" }
|
|
196
|
+
|
|
197
|
+
streaming_client.stream(messages, model: model)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### 6. Prompt Templates
|
|
201
|
+
|
|
202
|
+
**New capability** - Reusable prompt templates.
|
|
203
|
+
|
|
204
|
+
```ruby
|
|
205
|
+
template = OpenRouter::PromptTemplate.define("summarizer") do
|
|
206
|
+
system "You are a helpful summarization assistant."
|
|
207
|
+
user "Summarize this text:\n{{text}}"
|
|
208
|
+
|
|
209
|
+
examples([
|
|
210
|
+
{ input: { text: "Long text..." }, output: "Brief summary..." }
|
|
211
|
+
])
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Use template
|
|
215
|
+
messages = template.build(text: "Your text here")
|
|
216
|
+
response = client.complete(messages, model: model)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### 7. Response Healing
|
|
220
|
+
|
|
221
|
+
**New capability** - Automatic JSON healing for malformed responses.
|
|
222
|
+
|
|
223
|
+
```ruby
|
|
224
|
+
OpenRouter.configure do |config|
|
|
225
|
+
config.auto_heal_responses = true
|
|
226
|
+
config.healer_model = "openai/gpt-4o-mini"
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# If model returns malformed JSON, it's automatically healed
|
|
230
|
+
response = client.complete(
|
|
231
|
+
messages,
|
|
232
|
+
model: "some-model",
|
|
233
|
+
response_format: schema
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
# Returns valid JSON even if original response was malformed
|
|
237
|
+
data = response.structured_output
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### 8. Model Fallbacks
|
|
241
|
+
|
|
242
|
+
**New capability** - Automatic failover between models.
|
|
243
|
+
|
|
244
|
+
```ruby
|
|
245
|
+
# Try multiple models in order
|
|
246
|
+
response = client.complete(
|
|
247
|
+
messages,
|
|
248
|
+
model: [
|
|
249
|
+
"openai/gpt-4o", # Try first
|
|
250
|
+
"anthropic/claude-3.5-sonnet", # Fallback
|
|
251
|
+
"openai/gpt-4o-mini" # Last resort
|
|
252
|
+
]
|
|
253
|
+
)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### 9. Callback System
|
|
257
|
+
|
|
258
|
+
**New capability** - Hook into request lifecycle.
|
|
259
|
+
|
|
260
|
+
```ruby
|
|
261
|
+
client.on(:before_request) do |params|
|
|
262
|
+
puts "Sending request with model: #{params[:model]}"
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
client.on(:after_response) do |response|
|
|
266
|
+
puts "Received #{response.total_tokens} tokens"
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
client.on(:on_tool_call) do |tool_calls|
|
|
270
|
+
puts "Tools called: #{tool_calls.map(&:name).join(", ")}"
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
client.on(:on_error) do |error|
|
|
274
|
+
puts "Error: #{error.message}"
|
|
275
|
+
end
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Configuration Changes
|
|
279
|
+
|
|
280
|
+
### Original Configuration
|
|
281
|
+
|
|
282
|
+
```ruby
|
|
283
|
+
# This still works exactly the same
|
|
284
|
+
OpenRouter.configure do |config|
|
|
285
|
+
config.access_token = ENV["OPENROUTER_API_KEY"]
|
|
286
|
+
config.site_name = "My App"
|
|
287
|
+
config.site_url = "https://example.com"
|
|
288
|
+
end
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Enhanced Configuration (Optional New Features)
|
|
292
|
+
|
|
293
|
+
```ruby
|
|
294
|
+
OpenRouter.configure do |config|
|
|
295
|
+
# Original settings (unchanged)
|
|
296
|
+
config.access_token = ENV["OPENROUTER_API_KEY"]
|
|
297
|
+
config.site_name = "My App"
|
|
298
|
+
config.site_url = "https://example.com"
|
|
299
|
+
|
|
300
|
+
# New optional settings
|
|
301
|
+
config.auto_heal_responses = false # Enable response healing
|
|
302
|
+
config.healer_model = "openai/gpt-4o-mini" # Model for healing
|
|
303
|
+
config.max_heal_attempts = 2 # Retry limit
|
|
304
|
+
config.strict_mode = false # Strict schema validation
|
|
305
|
+
config.cache_ttl = 604800 # Model registry cache (7 days)
|
|
306
|
+
end
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Migration Strategies
|
|
310
|
+
|
|
311
|
+
### Strategy 1: No Changes (Recommended Start)
|
|
312
|
+
|
|
313
|
+
Simply swap the gem and continue using existing code:
|
|
314
|
+
|
|
315
|
+
```ruby
|
|
316
|
+
# Gemfile
|
|
317
|
+
gem "open_router_enhanced"
|
|
318
|
+
|
|
319
|
+
# Code - no changes needed
|
|
320
|
+
client = OpenRouter::Client.new
|
|
321
|
+
response = client.complete(messages, model: "openai/gpt-4o-mini")
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Strategy 2: Gradual Enhancement
|
|
325
|
+
|
|
326
|
+
Adopt new features incrementally:
|
|
327
|
+
|
|
328
|
+
**Week 1**: Enable usage tracking
|
|
329
|
+
```ruby
|
|
330
|
+
client = OpenRouter::Client.new(track_usage: true)
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Week 2**: Add model selection
|
|
334
|
+
```ruby
|
|
335
|
+
model = OpenRouter::ModelSelector.new.optimize_for(:cost).choose
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
**Week 3**: Implement tool calling
|
|
339
|
+
```ruby
|
|
340
|
+
response = client.complete(messages, model: model, tools: tools)
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**Week 4**: Add structured outputs
|
|
344
|
+
```ruby
|
|
345
|
+
response = client.complete(messages, model: model, response_format: schema)
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Strategy 3: Full Feature Adoption
|
|
349
|
+
|
|
350
|
+
Leverage all enhanced features:
|
|
351
|
+
|
|
352
|
+
```ruby
|
|
353
|
+
# Configuration
|
|
354
|
+
OpenRouter.configure do |config|
|
|
355
|
+
config.access_token = ENV["OPENROUTER_API_KEY"]
|
|
356
|
+
config.auto_heal_responses = true
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
# Smart model selection
|
|
360
|
+
model = OpenRouter::ModelSelector.new
|
|
361
|
+
.require(:function_calling)
|
|
362
|
+
.optimize_for(:cost)
|
|
363
|
+
.choose
|
|
364
|
+
|
|
365
|
+
# Client with tracking
|
|
366
|
+
client = OpenRouter::Client.new(track_usage: true)
|
|
367
|
+
|
|
368
|
+
# Callbacks for monitoring
|
|
369
|
+
client.on(:after_response) { |r| puts "Cost: $#{r.cost_estimate}" }
|
|
370
|
+
|
|
371
|
+
# Structured completion with tools
|
|
372
|
+
response = client.complete(
|
|
373
|
+
messages,
|
|
374
|
+
model: model,
|
|
375
|
+
tools: tools,
|
|
376
|
+
response_format: schema
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
# Process results
|
|
380
|
+
if response.has_tool_calls?
|
|
381
|
+
# Handle tools
|
|
382
|
+
elsif response.structured_output
|
|
383
|
+
# Handle structured data
|
|
384
|
+
else
|
|
385
|
+
# Handle text response
|
|
386
|
+
end
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
## Common Patterns
|
|
390
|
+
|
|
391
|
+
### Pattern: Simple Upgrade
|
|
392
|
+
|
|
393
|
+
```ruby
|
|
394
|
+
# Before (original gem)
|
|
395
|
+
response = OpenRouter::Client.new.complete(
|
|
396
|
+
[{ role: "user", content: "Hello" }],
|
|
397
|
+
model: "openai/gpt-4o-mini"
|
|
398
|
+
)
|
|
399
|
+
puts response["choices"][0]["message"]["content"]
|
|
400
|
+
|
|
401
|
+
# After (enhanced gem - same code works)
|
|
402
|
+
response = OpenRouter::Client.new.complete(
|
|
403
|
+
[{ role: "user", content: "Hello" }],
|
|
404
|
+
model: "openai/gpt-4o-mini"
|
|
405
|
+
)
|
|
406
|
+
puts response.content # New convenience method
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Pattern: Add Usage Tracking
|
|
410
|
+
|
|
411
|
+
```ruby
|
|
412
|
+
# Original
|
|
413
|
+
client = OpenRouter::Client.new
|
|
414
|
+
|
|
415
|
+
# Enhanced
|
|
416
|
+
client = OpenRouter::Client.new(track_usage: true)
|
|
417
|
+
|
|
418
|
+
# Check usage after requests
|
|
419
|
+
puts client.usage_tracker.summary
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### Pattern: Cost Optimization
|
|
423
|
+
|
|
424
|
+
```ruby
|
|
425
|
+
# Original - manual model selection
|
|
426
|
+
model = "openai/gpt-4o-mini" # Hope it's cheap enough
|
|
427
|
+
|
|
428
|
+
# Enhanced - guarantee cost constraints
|
|
429
|
+
model = OpenRouter::ModelSelector.new
|
|
430
|
+
.within_budget(max_cost: 0.01)
|
|
431
|
+
.require(:chat)
|
|
432
|
+
.choose
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
## Testing Your Migration
|
|
436
|
+
|
|
437
|
+
### 1. Run Existing Tests
|
|
438
|
+
|
|
439
|
+
Your existing tests should pass unchanged:
|
|
440
|
+
|
|
441
|
+
```ruby
|
|
442
|
+
# spec/my_test_spec.rb
|
|
443
|
+
RSpec.describe "OpenRouter" do
|
|
444
|
+
it "works the same as before" do
|
|
445
|
+
client = OpenRouter::Client.new
|
|
446
|
+
response = client.complete(
|
|
447
|
+
[{ role: "user", content: "Test" }],
|
|
448
|
+
model: "openai/gpt-4o-mini"
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
expect(response["choices"]).to be_present # Old style
|
|
452
|
+
expect(response.choices).to be_present # New style
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### 2. Test New Features
|
|
458
|
+
|
|
459
|
+
Add tests for enhanced capabilities:
|
|
460
|
+
|
|
461
|
+
```ruby
|
|
462
|
+
RSpec.describe "Enhanced Features" do
|
|
463
|
+
it "tracks usage" do
|
|
464
|
+
client = OpenRouter::Client.new(track_usage: true)
|
|
465
|
+
client.complete(messages, model: model)
|
|
466
|
+
|
|
467
|
+
expect(client.usage_tracker.total_tokens).to be > 0
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
it "supports tool calling" do
|
|
471
|
+
response = client.complete(messages, model: model, tools: tools)
|
|
472
|
+
expect(response.has_tool_calls?).to be_truthy
|
|
473
|
+
end
|
|
474
|
+
end
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
## Breaking Changes
|
|
478
|
+
|
|
479
|
+
**None!** 🎉
|
|
480
|
+
|
|
481
|
+
OpenRouter Enhanced maintains 100% backward compatibility. All original functionality works identically.
|
|
482
|
+
|
|
483
|
+
## Deprecation Notices
|
|
484
|
+
|
|
485
|
+
No methods or features from the original gem have been deprecated. You can continue using all original patterns indefinitely.
|
|
486
|
+
|
|
487
|
+
## Performance Considerations
|
|
488
|
+
|
|
489
|
+
The enhanced gem adds minimal overhead:
|
|
490
|
+
|
|
491
|
+
- **Model Registry**: Caches model data locally (7-day TTL by default)
|
|
492
|
+
- **Usage Tracking**: Optional, disabled by default
|
|
493
|
+
- **Response Processing**: Adds ~1ms for enhanced features
|
|
494
|
+
- **Memory**: +2-5MB for model registry cache
|
|
495
|
+
|
|
496
|
+
To minimize overhead:
|
|
497
|
+
|
|
498
|
+
```ruby
|
|
499
|
+
# Disable optional features if not needed
|
|
500
|
+
client = OpenRouter::Client.new(track_usage: false)
|
|
501
|
+
|
|
502
|
+
# Clear model registry cache if memory constrained
|
|
503
|
+
OpenRouter::ModelRegistry.clear_cache!
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
## Getting Help
|
|
507
|
+
|
|
508
|
+
If you encounter issues during migration:
|
|
509
|
+
|
|
510
|
+
1. **Check Compatibility**: Verify the original code works unchanged
|
|
511
|
+
2. **Review Examples**: Check `/examples` directory for patterns
|
|
512
|
+
3. **Read Documentation**: Full docs at `/docs` directory
|
|
513
|
+
4. **Ask Questions**: Open a GitHub issue
|
|
514
|
+
5. **Report Bugs**: Use GitHub issues with "migration" label
|
|
515
|
+
|
|
516
|
+
## Rollback Plan
|
|
517
|
+
|
|
518
|
+
If you need to rollback to the original gem:
|
|
519
|
+
|
|
520
|
+
```ruby
|
|
521
|
+
# Gemfile
|
|
522
|
+
gem "open_router" # Original gem
|
|
523
|
+
|
|
524
|
+
# Remove enhanced-specific code
|
|
525
|
+
# - Remove tool definitions
|
|
526
|
+
# - Remove schema definitions
|
|
527
|
+
# - Remove model selector usage
|
|
528
|
+
# - Remove tracking calls
|
|
529
|
+
|
|
530
|
+
# Original basic calls will work immediately
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
## Next Steps
|
|
534
|
+
|
|
535
|
+
After migrating:
|
|
536
|
+
|
|
537
|
+
1. **Read Feature Docs**: Learn about new capabilities in `/docs`
|
|
538
|
+
2. **Try Examples**: Run example files in `/examples`
|
|
539
|
+
3. **Explore Guides**: Check README for comprehensive guides
|
|
540
|
+
4. **Join Community**: Contribute feedback and improvements
|
|
541
|
+
|
|
542
|
+
## Version Mapping
|
|
543
|
+
|
|
544
|
+
| Original Gem | Enhanced Gem | Notes |
|
|
545
|
+
|--------------|--------------|-------|
|
|
546
|
+
| 0.1.x | 1.0.0 | Full backward compatibility |
|
|
547
|
+
| 0.2.x | 1.0.0 | Full backward compatibility |
|
|
548
|
+
| 0.3.x | 1.0.0 | Full backward compatibility |
|
|
549
|
+
|
|
550
|
+
## Summary
|
|
551
|
+
|
|
552
|
+
- ✅ **100% Backward Compatible** - Your code works unchanged
|
|
553
|
+
- ✅ **Enhanced Features** - Adopt new capabilities at your own pace
|
|
554
|
+
- ✅ **No Breaking Changes** - Safe upgrade with zero risk
|
|
555
|
+
- ✅ **Better Developer Experience** - More intuitive APIs
|
|
556
|
+
- ✅ **Production Ready** - Thoroughly tested and documented
|