open_router 0.1.0 → 0.2.1
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/.rubocop.yml +25 -4
- data/Gemfile +3 -2
- data/Gemfile.lock +34 -1
- data/README.md +26 -2
- data/lib/open_router/client.rb +25 -6
- data/lib/open_router/version.rb +1 -1
- data/lib/open_router.rb +1 -1
- data/open_router.gemspec +4 -1
- metadata +30 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 617d2bf77818298ec2a2b1f3c56ffd8ae344a969b2e3875c65017cbe9462d084
|
4
|
+
data.tar.gz: 0a1f88cc14ed99e96f1a54629ddbfb0139626235824c15edb6aa693df149a39c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0787bb54df0cf1f38eba5263a58c7840a48d0aa5f4ddb1bef4eb47f95b2b4568ee934b4ab1d666d927a09e94f06a68ad5ade55f54ae6fed0d9af4ef78ec7f0e1'
|
7
|
+
data.tar.gz: bd2bf9db26382fea15ab814336e937fb73f1c7fa117d404311c82489a8248254af7ea7a593e74c57ceee43b4a573cf48650887facdf19758e4558c5df94f3a53
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,29 @@
|
|
1
1
|
AllCops:
|
2
|
-
TargetRubyVersion: 2
|
2
|
+
TargetRubyVersion: 3.2
|
3
|
+
|
4
|
+
Layout/LineLength:
|
5
|
+
Enabled: false
|
6
|
+
|
7
|
+
Metrics/AbcSize:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
Metrics/BlockLength:
|
11
|
+
Enabled: false
|
12
|
+
|
13
|
+
Metrics/CyclomaticComplexity:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
Metrics/MethodLength:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Metrics/ParameterLists:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
Metrics/PerceivedComplexity:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
Style/Documentation:
|
26
|
+
Enabled: false
|
3
27
|
|
4
28
|
Style/StringLiterals:
|
5
29
|
Enabled: true
|
@@ -8,6 +32,3 @@ Style/StringLiterals:
|
|
8
32
|
Style/StringLiteralsInInterpolation:
|
9
33
|
Enabled: true
|
10
34
|
EnforcedStyle: double_quotes
|
11
|
-
|
12
|
-
Layout/LineLength:
|
13
|
-
Max: 120
|
data/Gemfile
CHANGED
@@ -5,8 +5,9 @@ source "https://rubygems.org"
|
|
5
5
|
# Specify your gem's dependencies in open_router.gemspec
|
6
6
|
gemspec
|
7
7
|
|
8
|
+
gem "activesupport", ">= 6.0"
|
9
|
+
gem "dotenv", ">= 2"
|
10
|
+
gem "pry", ">= 0.14"
|
8
11
|
gem "rake", "~> 13.0"
|
9
|
-
|
10
12
|
gem "rspec", "~> 3.0"
|
11
|
-
|
12
13
|
gem "rubocop", "~> 1.21"
|
data/Gemfile.lock
CHANGED
@@ -1,28 +1,55 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
open_router (0.1
|
4
|
+
open_router (0.2.1)
|
5
|
+
activesupport (>= 6.0)
|
6
|
+
dotenv (>= 2)
|
5
7
|
faraday (>= 1)
|
6
8
|
faraday-multipart (>= 1)
|
7
9
|
|
8
10
|
GEM
|
9
11
|
remote: https://rubygems.org/
|
10
12
|
specs:
|
13
|
+
activesupport (7.1.3.2)
|
14
|
+
base64
|
15
|
+
bigdecimal
|
16
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
17
|
+
connection_pool (>= 2.2.5)
|
18
|
+
drb
|
19
|
+
i18n (>= 1.6, < 2)
|
20
|
+
minitest (>= 5.1)
|
21
|
+
mutex_m
|
22
|
+
tzinfo (~> 2.0)
|
11
23
|
ast (2.4.2)
|
24
|
+
base64 (0.2.0)
|
25
|
+
bigdecimal (3.1.7)
|
26
|
+
coderay (1.1.3)
|
27
|
+
concurrent-ruby (1.2.3)
|
28
|
+
connection_pool (2.4.1)
|
12
29
|
diff-lcs (1.5.0)
|
30
|
+
dotenv (3.1.0)
|
31
|
+
drb (2.2.1)
|
13
32
|
faraday (2.7.10)
|
14
33
|
faraday-net_http (>= 2.0, < 3.1)
|
15
34
|
ruby2_keywords (>= 0.0.4)
|
16
35
|
faraday-multipart (1.0.4)
|
17
36
|
multipart-post (~> 2)
|
18
37
|
faraday-net_http (3.0.2)
|
38
|
+
i18n (1.14.4)
|
39
|
+
concurrent-ruby (~> 1.0)
|
19
40
|
json (2.6.3)
|
20
41
|
language_server-protocol (3.17.0.3)
|
42
|
+
method_source (1.0.0)
|
43
|
+
minitest (5.22.3)
|
21
44
|
multipart-post (2.3.0)
|
45
|
+
mutex_m (0.2.0)
|
22
46
|
parallel (1.23.0)
|
23
47
|
parser (3.2.2.3)
|
24
48
|
ast (~> 2.4.1)
|
25
49
|
racc
|
50
|
+
pry (0.14.2)
|
51
|
+
coderay (~> 1.1)
|
52
|
+
method_source (~> 1.0)
|
26
53
|
racc (1.7.1)
|
27
54
|
rainbow (3.1.1)
|
28
55
|
rake (13.0.6)
|
@@ -56,13 +83,19 @@ GEM
|
|
56
83
|
parser (>= 3.2.1.0)
|
57
84
|
ruby-progressbar (1.13.0)
|
58
85
|
ruby2_keywords (0.0.5)
|
86
|
+
tzinfo (2.0.6)
|
87
|
+
concurrent-ruby (~> 1.0)
|
59
88
|
unicode-display_width (2.4.2)
|
60
89
|
|
61
90
|
PLATFORMS
|
62
91
|
arm64-darwin-21
|
92
|
+
x86_64-linux
|
63
93
|
|
64
94
|
DEPENDENCIES
|
95
|
+
activesupport (>= 6.0)
|
96
|
+
dotenv (>= 2)
|
65
97
|
open_router!
|
98
|
+
pry (>= 0.14)
|
66
99
|
rake (~> 13.0)
|
67
100
|
rspec (~> 3.0)
|
68
101
|
rubocop (~> 1.21)
|
data/README.md
CHANGED
@@ -10,7 +10,7 @@ The [OpenRouter API](https://openrouter.ai/docs) is a single unified interface f
|
|
10
10
|
- **Standardized API**: No need to change your code when switching between models or providers. You can even let users choose and pay for their own.
|
11
11
|
- **Easy integration**: This Ruby gem provides a simple and intuitive interface to interact with the OpenRouter API, making it effortless to integrate AI capabilities into your Ruby applications.
|
12
12
|
|
13
|
-
👬 This Ruby library was originally bootstrapped from the [🤖
|
13
|
+
👬 This Ruby library was originally bootstrapped from the [🤖 Anthropic](https://github.com/alexrudall/anthropic) gem by Alex Rudall, and subsequently extracted from the codebase of my fast-growing AI startup called [Olympia](https://olympia.chat?utm_source=open_router_gem&utm_medium=github) that lets you add AI-powered consultants to your startup!
|
14
14
|
|
15
15
|
🚢 Need someone to develop AI software for you using modern Ruby on Rails? My other company Magma Labs does exactly that: [magmalabs.io](https://www.magmalabs.io/?utm_source=open_router_gem&utm_medium=github). In fact, we also sell off-the-shelf solutions based on my early work on the field, via a platform called [MagmaChat](https://magmachat.ai?utm_source=open_router_gem&utm_medium=github)
|
16
16
|
|
@@ -91,7 +91,27 @@ puts response["choices"][0]["message"]["content"]
|
|
91
91
|
|
92
92
|
### Models
|
93
93
|
|
94
|
-
|
94
|
+
Pass an array to the `model` parameter to enable [explicit model routing](https://openrouter.ai/docs#model-routing).
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
OpenRouter::Client.new.complete(
|
98
|
+
[
|
99
|
+
{ role: "system", content: SYSTEM_PROMPT },
|
100
|
+
{ role: "user", content: "Provide analysis of the data formatted as JSON:" }
|
101
|
+
],
|
102
|
+
model: [
|
103
|
+
"mistralai/mixtral-8x7b-instruct:nitro",
|
104
|
+
"mistralai/mixtral-8x7b-instruct"
|
105
|
+
],
|
106
|
+
extras: {
|
107
|
+
response_format: {
|
108
|
+
type: "json_object"
|
109
|
+
}
|
110
|
+
}
|
111
|
+
)
|
112
|
+
```
|
113
|
+
|
114
|
+
[Browse full list of models available](https://openrouter.ai/models) or fetch from the OpenRouter API:
|
95
115
|
|
96
116
|
```ruby
|
97
117
|
models = client.models
|
@@ -110,6 +130,10 @@ puts stats
|
|
110
130
|
# => {"id"=>"generation-abcdefg", "object"=>"generation", "created"=>1684195200, "model"=>"openrouter/auto", "usage"=>{"prompt_tokens"=>10, "completion_tokens"=>50, "total_tokens"=>60}, "cost"=>0.0006}
|
111
131
|
```
|
112
132
|
|
133
|
+
## Errors
|
134
|
+
|
135
|
+
The client will raise an `OpenRouter::ServerError` in the case of an error returned from a completion (or empty response).
|
136
|
+
|
113
137
|
## Contributing
|
114
138
|
|
115
139
|
Bug reports and pull requests are welcome on GitHub at <https://github.com/OlympiaAI/open_router>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/OlympiaAI/open_router/blob/main/CODE_OF_CONDUCT.md).
|
data/lib/open_router/client.rb
CHANGED
@@ -1,31 +1,50 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require "active_support/core_ext/object/blank"
|
4
|
+
require "active_support/core_ext/hash/indifferent_access"
|
5
|
+
|
6
|
+
require_relative "http"
|
4
7
|
|
5
8
|
module OpenRouter
|
9
|
+
class ServerError < StandardError; end
|
10
|
+
|
6
11
|
class Client
|
7
12
|
include OpenRouter::HTTP
|
8
13
|
|
9
14
|
# Initializes the client with optional configurations.
|
10
|
-
def initialize
|
15
|
+
def initialize(access_token: nil, request_timeout: nil, uri_base: nil, extra_headers: {})
|
16
|
+
OpenRouter.configuration.access_token = access_token if access_token
|
17
|
+
OpenRouter.configuration.request_timeout = request_timeout if request_timeout
|
18
|
+
OpenRouter.configuration.uri_base = uri_base if uri_base
|
19
|
+
OpenRouter.configuration.extra_headers = extra_headers if extra_headers.any?
|
11
20
|
yield(OpenRouter.configuration) if block_given?
|
12
21
|
end
|
13
22
|
|
14
23
|
# Performs a chat completion request to the OpenRouter API.
|
15
24
|
# @param messages [Array<Hash>] Array of message hashes with role and content, like [{role: "user", content: "What is the meaning of life?"}]
|
16
|
-
# @param model [String] Model identifier,
|
25
|
+
# @param model [String|Array] Model identifier, or array of model identifiers if you want to fallback to the next model in case of failure
|
17
26
|
# @param providers [Array<String>] Optional array of provider identifiers, ordered by priority
|
18
27
|
# @param transforms [Array<String>] Optional array of strings that tell OpenRouter to apply a series of transformations to the prompt before sending it to the model. Transformations are applied in-order
|
19
28
|
# @param extras [Hash] Optional hash of model-specific parameters to send to the OpenRouter API
|
20
29
|
# @param stream [Proc, nil] Optional callable object for streaming
|
21
30
|
# @return [Hash] The completion response.
|
22
|
-
def complete(messages, model:
|
23
|
-
parameters = {
|
31
|
+
def complete(messages, model: "openrouter/auto", providers: [], transforms: [], extras: {}, stream: nil)
|
32
|
+
parameters = { messages: }
|
33
|
+
if model.is_a?(String)
|
34
|
+
parameters[:model] = model
|
35
|
+
elsif model.is_a?(Array)
|
36
|
+
parameters[:models] = model
|
37
|
+
parameters[:route] = "fallback"
|
38
|
+
end
|
24
39
|
parameters[:provider] = { provider: { order: providers } } if providers.any?
|
25
40
|
parameters[:transforms] = transforms if transforms.any?
|
26
41
|
parameters[:stream] = stream if stream
|
27
42
|
parameters.merge!(extras)
|
28
|
-
|
43
|
+
|
44
|
+
json_post(path: "/chat/completions", parameters:).tap do |response|
|
45
|
+
raise ServerError, "Empty response from OpenRouter. Might be worth retrying once or twice." if response.blank?
|
46
|
+
raise ServerError, response.dig("error", "message") if response.dig("error", "message").present?
|
47
|
+
end.with_indifferent_access
|
29
48
|
end
|
30
49
|
|
31
50
|
# Fetches the list of available models from the OpenRouter API.
|
data/lib/open_router/version.rb
CHANGED
data/lib/open_router.rb
CHANGED
data/open_router.gemspec
CHANGED
@@ -19,7 +19,8 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.files = Dir.chdir(__dir__) do
|
21
21
|
`git ls-files -z`.split("\x0").reject do |f|
|
22
|
-
(File.expand_path(f) == __FILE__) || f.end_with?(
|
22
|
+
(File.expand_path(f) == __FILE__) || f.end_with?(".gem") || f.start_with?(*%w[bin/ test/ spec/ features/ .git
|
23
|
+
.circleci appveyor])
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
@@ -27,6 +28,8 @@ Gem::Specification.new do |spec|
|
|
27
28
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
28
29
|
spec.require_paths = ["lib"]
|
29
30
|
|
31
|
+
spec.add_dependency "activesupport", ">= 6.0"
|
32
|
+
spec.add_dependency "dotenv", ">= 2"
|
30
33
|
spec.add_dependency "faraday", ">= 1"
|
31
34
|
spec.add_dependency "faraday-multipart", ">= 1"
|
32
35
|
end
|
metadata
CHANGED
@@ -1,15 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: open_router
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Obie Fernandez
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-03-
|
11
|
+
date: 2024-03-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '6.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dotenv
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2'
|
13
41
|
- !ruby/object:Gem::Dependency
|
14
42
|
name: faraday
|
15
43
|
requirement: !ruby/object:Gem::Requirement
|