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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a93aba25cb96e636386ff6124b516fd580fd1535b215d0e5152dd02873f01f5
4
- data.tar.gz: cb2aae6801e85efb8b2e1603797ca2186ed696a019e29839d7fa5509573958e5
3
+ metadata.gz: 617d2bf77818298ec2a2b1f3c56ffd8ae344a969b2e3875c65017cbe9462d084
4
+ data.tar.gz: 0a1f88cc14ed99e96f1a54629ddbfb0139626235824c15edb6aa693df149a39c
5
5
  SHA512:
6
- metadata.gz: 8cbcf5b988d5a709d7de4289aa3dccd470af4975e8f9a37a826ff5df097f0fee04328a9fa3877a3299d1c5849370aeab3f3bada91617efcc10ab13a8116523d3
7
- data.tar.gz: 91d41c29aee465880f59c1b6bcc121f559c929da2c7dec9be55ecc68f992031fa0c096655af0aa56942c9cd4076506e9dbf22d898c274d9fb653222269a871e0
6
+ metadata.gz: '0787bb54df0cf1f38eba5263a58c7840a48d0aa5f4ddb1bef4eb47f95b2b4568ee934b4ab1d666d927a09e94f06a68ad5ade55f54ae6fed0d9af4ef78ec7f0e1'
7
+ data.tar.gz: bd2bf9db26382fea15ab814336e937fb73f1c7fa117d404311c82489a8248254af7ea7a593e74c57ceee43b4a573cf48650887facdf19758e4558c5df94f3a53
data/.rubocop.yml CHANGED
@@ -1,5 +1,29 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.6
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.0)
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 [🤖 OpenRouter](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!
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
- Fetch the list of available models from the OpenRouter API:
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).
@@ -1,31 +1,50 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'http'
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, defaults to 'openrouter/auto'
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: 'openrouter/auto', providers: [], transforms: [], extras: {}, stream: nil)
23
- parameters = { model:, messages: }
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
- json_post(path: "/chat/completions", parameters:)
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.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenRouter
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.1"
5
5
  end
data/lib/open_router.rb CHANGED
@@ -17,7 +17,7 @@ module OpenRouter
17
17
 
18
18
  DEFAULT_API_VERSION = "v1"
19
19
  DEFAULT_REQUEST_TIMEOUT = 120
20
- DEFAULT_URI_BASE = 'https://openrouter.ai/api'
20
+ DEFAULT_URI_BASE = "https://openrouter.ai/api"
21
21
 
22
22
  def initialize
23
23
  @access_token = nil
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?('.gem') || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor])
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.0
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-19 00:00:00.000000000 Z
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