raix 0.4.0 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +8 -0
- data/lib/raix/chat_completion.rb +10 -4
- data/lib/raix/message_adapters/base.rb +50 -0
- data/lib/raix/response_format.rb +76 -0
- data/lib/raix/version.rb +1 -1
- data/lib/raix.rb +1 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd88f295667264948d2710fb7eb0bcd74e5ab0177e76678314c34958e79fa6bd
|
4
|
+
data.tar.gz: b86495b4b67c5259915a7ef20502005d90ededf6be991821703d1d83e876c572
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf1982b065312860c046a363486169a3d4572b65bd5ded3e82e270e3cbb689a173d6ff94cbcc897d6d8e5f27ef7e6558193ea3b266c18cc5bd1a8f2ca54fa6cd
|
7
|
+
data.tar.gz: 58eb7f54eb7d3a2656dbdd3e44a977c04b1dfb5ef5f7bd549ece96ecce9a931007edea5d364f189a1916883838c6a674e794799365914a1a5cab2402994da5f1
|
data/CHANGELOG.md
CHANGED
@@ -14,3 +14,7 @@
|
|
14
14
|
|
15
15
|
## [0.4.0] - 2024-10-18
|
16
16
|
- adds support for Anthropic-style prompt caching
|
17
|
+
- defaults to `max_completion_tokens` when using OpenAI directly
|
18
|
+
|
19
|
+
## [0.4.2] - 2024-11-05
|
20
|
+
- adds support for [Predicted Outputs](https://platform.openai.com/docs/guides/latency-optimization#use-predicted-outputs) with the `prediction` option for OpenAI
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -42,6 +42,14 @@ transcript << { role: "user", content: "What is the meaning of life?" }
|
|
42
42
|
|
43
43
|
One of the advantages of OpenRouter and the reason that it is used by default by this library is that it handles mapping message formats from the OpenAI standard to whatever other model you're wanting to use (Anthropic, Cohere, etc.)
|
44
44
|
|
45
|
+
### Predicted Outputs
|
46
|
+
|
47
|
+
Raix supports [Predicted Outputs](https://platform.openai.com/docs/guides/latency-optimization#use-predicted-outputs) with the `prediction` parameter for OpenAI.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
>> ai.chat_completion(openai: "gpt-4o", params: { prediction: })
|
51
|
+
```
|
52
|
+
|
45
53
|
### Prompt Caching
|
46
54
|
|
47
55
|
Raix supports [Anthropic-style prompt caching](https://openrouter.ai/docs/prompt-caching#anthropic-claude) when using Anthropic's Claud family of models. You can specify a `cache_at` parameter when doing a chat completion. If the character count for the content of a particular message is longer than the cache_at parameter, it will be sent to Anthropic as a multipart message with a cache control "breakpoint" set to "ephemeral".
|
data/lib/raix/chat_completion.rb
CHANGED
@@ -2,10 +2,11 @@
|
|
2
2
|
|
3
3
|
require "active_support/concern"
|
4
4
|
require "active_support/core_ext/object/blank"
|
5
|
-
require "raix/message_adapters/base"
|
6
5
|
require "open_router"
|
7
6
|
require "openai"
|
8
7
|
|
8
|
+
require_relative "message_adapters/base"
|
9
|
+
|
9
10
|
module Raix
|
10
11
|
# The `ChatCompletion`` module is a Rails concern that provides a way to interact
|
11
12
|
# with the OpenRouter Chat Completion API via its client. The module includes a few
|
@@ -19,7 +20,7 @@ module Raix
|
|
19
20
|
extend ActiveSupport::Concern
|
20
21
|
|
21
22
|
attr_accessor :cache_at, :frequency_penalty, :logit_bias, :logprobs, :loop, :min_p, :model, :presence_penalty,
|
22
|
-
:repetition_penalty, :response_format, :stream, :temperature, :max_completion_tokens,
|
23
|
+
:prediction, :repetition_penalty, :response_format, :stream, :temperature, :max_completion_tokens,
|
23
24
|
:max_tokens, :seed, :stop, :top_a, :top_k, :top_logprobs, :top_p, :tools, :tool_choice, :provider
|
24
25
|
|
25
26
|
# This method performs chat completion based on the provided transcript and parameters.
|
@@ -39,6 +40,7 @@ module Raix
|
|
39
40
|
params[:max_completion_tokens] ||= max_completion_tokens.presence || Raix.configuration.max_completion_tokens
|
40
41
|
params[:max_tokens] ||= max_tokens.presence || Raix.configuration.max_tokens
|
41
42
|
params[:min_p] ||= min_p.presence
|
43
|
+
params[:prediction] = { type: "content", content: params[:prediction] || prediction } if params[:prediction] || prediction.present?
|
42
44
|
params[:presence_penalty] ||= presence_penalty.presence
|
43
45
|
params[:provider] ||= provider.presence
|
44
46
|
params[:repetition_penalty] ||= repetition_penalty.presence
|
@@ -149,8 +151,12 @@ module Raix
|
|
149
151
|
private
|
150
152
|
|
151
153
|
def openai_request(params:, model:, messages:)
|
152
|
-
|
153
|
-
|
154
|
+
if params[:prediction]
|
155
|
+
params.delete(:max_completion_tokens)
|
156
|
+
else
|
157
|
+
params[:max_completion_tokens] ||= params[:max_tokens]
|
158
|
+
params.delete(:max_tokens)
|
159
|
+
end
|
154
160
|
|
155
161
|
params[:stream] ||= stream.presence
|
156
162
|
params[:stream_options] = { include_usage: true } if params[:stream]
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/module/delegation"
|
4
|
+
|
5
|
+
module Raix
|
6
|
+
module MessageAdapters
|
7
|
+
# Transforms messages into the format expected by the OpenAI API
|
8
|
+
class Base
|
9
|
+
attr_accessor :context
|
10
|
+
|
11
|
+
delegate :cache_at, :model, to: :context
|
12
|
+
|
13
|
+
def initialize(context)
|
14
|
+
@context = context
|
15
|
+
end
|
16
|
+
|
17
|
+
def transform(message)
|
18
|
+
return message if message[:role].present?
|
19
|
+
|
20
|
+
if message[:function].present?
|
21
|
+
{ role: "assistant", name: message.dig(:function, :name), content: message.dig(:function, :arguments).to_json }
|
22
|
+
elsif message[:result].present?
|
23
|
+
{ role: "function", name: message[:name], content: message[:result] }
|
24
|
+
else
|
25
|
+
content(message)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def content(message)
|
32
|
+
case message
|
33
|
+
in { system: content }
|
34
|
+
{ role: "system", content: }
|
35
|
+
in { user: content }
|
36
|
+
{ role: "user", content: }
|
37
|
+
in { assistant: content }
|
38
|
+
{ role: "assistant", content: }
|
39
|
+
else
|
40
|
+
raise ArgumentError, "Invalid message format: #{message.inspect}"
|
41
|
+
end.tap do |msg|
|
42
|
+
# convert to anthropic multipart format if model is claude-3 and cache_at is set
|
43
|
+
if model.to_s.include?("anthropic/claude-3") && cache_at && msg[:content].to_s.length > cache_at.to_i
|
44
|
+
msg[:content] = [{ type: "text", text: msg[:content], cache_control: { type: "ephemeral" } }]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/object/deep_dup"
|
4
|
+
|
5
|
+
module Raix
|
6
|
+
# Handles the formatting of responses for AI interactions.
|
7
|
+
#
|
8
|
+
# This class is responsible for converting input data into a JSON schema
|
9
|
+
# that can be used to structure and validate AI responses. It supports
|
10
|
+
# nested structures and arrays, ensuring that the output conforms to
|
11
|
+
# the expected format for AI model interactions.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# input = { name: { type: "string" }, age: { type: "integer" } }
|
15
|
+
# format = ResponseFormat.new("PersonInfo", input)
|
16
|
+
# schema = format.to_schema
|
17
|
+
#
|
18
|
+
# @attr_reader [String] name The name of the response format
|
19
|
+
# @attr_reader [Hash] input The input data to be formatted
|
20
|
+
class ResponseFormat
|
21
|
+
def initialize(name, input)
|
22
|
+
@name = name
|
23
|
+
@input = input
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_json(*)
|
27
|
+
JSON.pretty_generate(to_schema)
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_schema
|
31
|
+
{
|
32
|
+
type: "json_schema",
|
33
|
+
json_schema: {
|
34
|
+
name: @name,
|
35
|
+
schema: {
|
36
|
+
type: "object",
|
37
|
+
properties: decode(@input.deep_dup),
|
38
|
+
required: @input.keys,
|
39
|
+
additionalProperties: false
|
40
|
+
},
|
41
|
+
strict: true
|
42
|
+
}
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def decode(input)
|
49
|
+
{}.tap do |response|
|
50
|
+
case input
|
51
|
+
when Array
|
52
|
+
properties = {}
|
53
|
+
input.each { |item| properties.merge!(decode(item)) }
|
54
|
+
|
55
|
+
response[:type] = "array"
|
56
|
+
response[:items] = {
|
57
|
+
type: "object",
|
58
|
+
properties:,
|
59
|
+
required: properties.keys.select { |key| properties[key].delete(:required) },
|
60
|
+
additionalProperties: false
|
61
|
+
}
|
62
|
+
when Hash
|
63
|
+
input.each do |key, value|
|
64
|
+
response[key] = if value.is_a?(Hash) && value.key?(:type)
|
65
|
+
value
|
66
|
+
else
|
67
|
+
decode(value)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
else
|
71
|
+
raise "Invalid input"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/raix/version.rb
CHANGED
data/lib/raix.rb
CHANGED
@@ -4,6 +4,7 @@ require_relative "raix/version"
|
|
4
4
|
require_relative "raix/chat_completion"
|
5
5
|
require_relative "raix/function_dispatch"
|
6
6
|
require_relative "raix/prompt_declarations"
|
7
|
+
require_relative "raix/response_format"
|
7
8
|
|
8
9
|
# The Raix module provides configuration options for the Raix gem.
|
9
10
|
module Raix
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: raix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
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-
|
11
|
+
date: 2024-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -58,7 +58,9 @@ files:
|
|
58
58
|
- lib/raix.rb
|
59
59
|
- lib/raix/chat_completion.rb
|
60
60
|
- lib/raix/function_dispatch.rb
|
61
|
+
- lib/raix/message_adapters/base.rb
|
61
62
|
- lib/raix/prompt_declarations.rb
|
63
|
+
- lib/raix/response_format.rb
|
62
64
|
- lib/raix/version.rb
|
63
65
|
- raix.gemspec
|
64
66
|
- sig/raix.rbs
|
@@ -84,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
86
|
- !ruby/object:Gem::Version
|
85
87
|
version: '0'
|
86
88
|
requirements: []
|
87
|
-
rubygems_version: 3.
|
89
|
+
rubygems_version: 3.4.10
|
88
90
|
signing_key:
|
89
91
|
specification_version: 4
|
90
92
|
summary: Ruby AI eXtensions
|