omniai-openai 3.0.1 → 3.1.2
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 +38 -0
- data/lib/omniai/openai/chat/content_serializer.rb +2 -1
- data/lib/omniai/openai/chat/message_serializer.rb +15 -2
- data/lib/omniai/openai/chat/response_serializer.rb +1 -1
- data/lib/omniai/openai/chat/stream.rb +4 -2
- data/lib/omniai/openai/chat/thinking_serializer.rb +37 -0
- data/lib/omniai/openai/chat.rb +20 -3
- data/lib/omniai/openai/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6c84d3becf5f93c58078e182e156861262bafc112e59ccb2c67d6ff08d0bb399
|
|
4
|
+
data.tar.gz: 31cb3de11d80088728a2f80193903f2740db4fd13c058b72db780561b25fc317
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8b789a962479764a1de021ee658cf27d82550e8d2699777bf7cc8294ffe099c9748ec4411d2296ece309e3dbd039685d0d2da0ed1f4380c573180fe042a7aa94
|
|
7
|
+
data.tar.gz: 180e1daaebcddb697f9e63d2b41e2adcd25a3e22e2845a184d43669497d415e350afeced8aa8cc99ec55c19dd67233685d034e138e80dcc0a26b7a089d216ca0
|
data/README.md
CHANGED
|
@@ -146,6 +146,44 @@ JSON.parse(completion.content) # { "name": "Ringo" }
|
|
|
146
146
|
|
|
147
147
|
> When using JSON mode, you must also instruct the model to produce JSON yourself via a system or user message.
|
|
148
148
|
|
|
149
|
+
#### Reasoning
|
|
150
|
+
|
|
151
|
+
OpenAI o1 and o3 models support reasoning, which provides a summary of the model's thought process.
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
# Enable reasoning with unified thinking API
|
|
155
|
+
response = client.chat("What is 25 * 25?", model: "o3-mini", thinking: true)
|
|
156
|
+
|
|
157
|
+
# Or use OpenAI-specific reasoning options
|
|
158
|
+
response = client.chat("What is 25 * 25?", model: "o3-mini", reasoning: { effort: "high", summary: "auto" })
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Reasoning Effort Levels:**
|
|
162
|
+
- `low` - Minimal reasoning
|
|
163
|
+
- `medium` - Balanced reasoning
|
|
164
|
+
- `high` - Maximum reasoning effort
|
|
165
|
+
|
|
166
|
+
#### Accessing Reasoning Content
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
response.choices.first.message.contents.each do |content|
|
|
170
|
+
case content
|
|
171
|
+
when OmniAI::Chat::Thinking
|
|
172
|
+
puts "Reasoning: #{content.thinking}"
|
|
173
|
+
when OmniAI::Chat::Text
|
|
174
|
+
puts "Response: #{content.text}"
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### Streaming with Reasoning
|
|
180
|
+
|
|
181
|
+
```ruby
|
|
182
|
+
client.chat("What are the prime factors of 1234567?", model: "o3-mini", thinking: true, stream: $stdout)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
[OpenAI API Reference `reasoning`](https://platform.openai.com/docs/guides/reasoning)
|
|
186
|
+
|
|
149
187
|
### Transcribe
|
|
150
188
|
|
|
151
189
|
A transcription is generated by passing in a path to a file:
|
|
@@ -8,10 +8,11 @@ module OmniAI
|
|
|
8
8
|
# @param data [Hash]
|
|
9
9
|
# @param context [Context]
|
|
10
10
|
#
|
|
11
|
-
# @return [OmniAI::Chat::Text, OmniAI::Chat::ToolCall]
|
|
11
|
+
# @return [OmniAI::Chat::Text, OmniAI::Chat::Thinking, OmniAI::Chat::ToolCall]
|
|
12
12
|
def self.deserialize(data, context:)
|
|
13
13
|
case data["type"]
|
|
14
14
|
when /(input|output)_text/ then OmniAI::Chat::Text.deserialize(data, context:)
|
|
15
|
+
when "reasoning" then OmniAI::Chat::Thinking.deserialize(data, context:)
|
|
15
16
|
end
|
|
16
17
|
end
|
|
17
18
|
end
|
|
@@ -30,11 +30,14 @@ module OmniAI
|
|
|
30
30
|
# @param message [OmniAI::Chat::Message]
|
|
31
31
|
# @param context [OmniAI::Context]
|
|
32
32
|
#
|
|
33
|
-
# @return [Hash]
|
|
33
|
+
# @return [Hash, nil]
|
|
34
34
|
def self.serialize_for_content(message, context:)
|
|
35
35
|
role = message.role
|
|
36
36
|
direction = message.direction
|
|
37
|
-
|
|
37
|
+
# Filter out thinking content - OpenAI doesn't accept it in input messages
|
|
38
|
+
parts = arrayify(message.content).reject { |part| part.is_a?(OmniAI::Chat::Thinking) }
|
|
39
|
+
|
|
40
|
+
return if parts.empty?
|
|
38
41
|
|
|
39
42
|
content = parts.map do |part|
|
|
40
43
|
case part
|
|
@@ -54,9 +57,19 @@ module OmniAI
|
|
|
54
57
|
case data["type"]
|
|
55
58
|
when "message" then deserialize_for_content(data, context:)
|
|
56
59
|
when "function_call" then deserialize_for_tool_call(data, context:)
|
|
60
|
+
when "reasoning" then deserialize_for_reasoning(data, context:)
|
|
57
61
|
end
|
|
58
62
|
end
|
|
59
63
|
|
|
64
|
+
# @param data [Hash]
|
|
65
|
+
# @param context [OmniAI::Context]
|
|
66
|
+
#
|
|
67
|
+
# @return [OmniAI::Chat::Message]
|
|
68
|
+
def self.deserialize_for_reasoning(data, context:)
|
|
69
|
+
thinking = OmniAI::Chat::Thinking.deserialize(data, context:)
|
|
70
|
+
OmniAI::Chat::Message.new(role: OmniAI::Chat::Role::ASSISTANT, content: [thinking])
|
|
71
|
+
end
|
|
72
|
+
|
|
60
73
|
# @param data [Hash]
|
|
61
74
|
# @param context [OmniAI::Context]
|
|
62
75
|
#
|
|
@@ -25,7 +25,7 @@ module OmniAI
|
|
|
25
25
|
# @return [OmniAI::Chat::Response]
|
|
26
26
|
def self.deserialize(data, context:)
|
|
27
27
|
usage = OmniAI::Chat::Usage.deserialize(data["usage"], context:) if data["usage"]
|
|
28
|
-
choices = data["output"].
|
|
28
|
+
choices = data["output"].filter_map { |choice_data| OmniAI::Chat::Choice.deserialize(choice_data, context:) }
|
|
29
29
|
|
|
30
30
|
OmniAI::Chat::Response.new(data:, choices:, usage:)
|
|
31
31
|
end
|
|
@@ -13,10 +13,12 @@ module OmniAI
|
|
|
13
13
|
response = {}
|
|
14
14
|
|
|
15
15
|
@chunks.each do |chunk|
|
|
16
|
-
parser.feed(chunk) do |type, data, _id|
|
|
16
|
+
parser.feed(chunk.b) do |type, data, _id|
|
|
17
17
|
case type
|
|
18
|
-
when
|
|
18
|
+
when "response.output_text.delta"
|
|
19
19
|
block.call(OmniAI::Chat::Delta.new(text: JSON.parse(data)["delta"]))
|
|
20
|
+
when "response.reasoning_summary_text.delta"
|
|
21
|
+
block.call(OmniAI::Chat::Delta.new(thinking: JSON.parse(data)["delta"]))
|
|
20
22
|
when "response.completed"
|
|
21
23
|
response = JSON.parse(data)["response"]
|
|
22
24
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OmniAI
|
|
4
|
+
module OpenAI
|
|
5
|
+
class Chat
|
|
6
|
+
# Overrides thinking serialize / deserialize.
|
|
7
|
+
module ThinkingSerializer
|
|
8
|
+
# @param data [Hash]
|
|
9
|
+
# @param context [Context]
|
|
10
|
+
#
|
|
11
|
+
# @return [OmniAI::Chat::Thinking]
|
|
12
|
+
def self.deserialize(data, context: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
13
|
+
summary = data["summary"]
|
|
14
|
+
|
|
15
|
+
thinking = case summary
|
|
16
|
+
when Array
|
|
17
|
+
summary.filter_map { |item| item["text"] if item["type"] == "summary_text" }.join("\n")
|
|
18
|
+
when String
|
|
19
|
+
summary
|
|
20
|
+
else
|
|
21
|
+
data["thinking"]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
OmniAI::Chat::Thinking.new(thinking)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @param thinking [OmniAI::Chat::Thinking]
|
|
28
|
+
# @param context [Context]
|
|
29
|
+
#
|
|
30
|
+
# @return [Hash]
|
|
31
|
+
def self.serialize(thinking, context: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
32
|
+
{ type: "reasoning", summary: thinking.thinking }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/omniai/openai/chat.rb
CHANGED
|
@@ -74,6 +74,8 @@ module OmniAI
|
|
|
74
74
|
context.deserializers[:tool_call_result] = ToolCallResultSerializer.method(:deserialize)
|
|
75
75
|
context.serializers[:tool_call_message] = ToolCallMessageSerializer.method(:serialize)
|
|
76
76
|
context.deserializers[:tool_call_message] = ToolCallMessageSerializer.method(:deserialize)
|
|
77
|
+
context.serializers[:thinking] = ThinkingSerializer.method(:serialize)
|
|
78
|
+
context.deserializers[:thinking] = ThinkingSerializer.method(:deserialize)
|
|
77
79
|
end
|
|
78
80
|
|
|
79
81
|
protected
|
|
@@ -88,7 +90,7 @@ module OmniAI
|
|
|
88
90
|
@prompt
|
|
89
91
|
.messages
|
|
90
92
|
.reject(&:system?)
|
|
91
|
-
.
|
|
93
|
+
.filter_map { |message| message.serialize(context:) }
|
|
92
94
|
end
|
|
93
95
|
|
|
94
96
|
# @return [String, nil]
|
|
@@ -155,9 +157,24 @@ module OmniAI
|
|
|
155
157
|
end
|
|
156
158
|
|
|
157
159
|
# @return [Hash]
|
|
160
|
+
# Accepts unified `thinking:` option and translates to OpenAI's `reasoning:` format.
|
|
161
|
+
# Example: `thinking: { effort: "high" }` becomes `reasoning: { effort: "high", summary: "auto" }`
|
|
158
162
|
def reasoning
|
|
159
|
-
|
|
160
|
-
options
|
|
163
|
+
# Support both native `reasoning:` and unified `thinking:` options
|
|
164
|
+
options = @options[:reasoning] || translate_thinking_to_reasoning
|
|
165
|
+
options unless options.nil? || options.empty?
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Translates unified thinking option to OpenAI reasoning format
|
|
169
|
+
# @return [Hash, nil]
|
|
170
|
+
def translate_thinking_to_reasoning
|
|
171
|
+
thinking = @options[:thinking]
|
|
172
|
+
return unless thinking
|
|
173
|
+
|
|
174
|
+
case thinking
|
|
175
|
+
when true then { effort: ReasoningEffort::HIGH, summary: "auto" }
|
|
176
|
+
when Hash then { summary: "auto" }.merge(thinking)
|
|
177
|
+
end
|
|
161
178
|
end
|
|
162
179
|
|
|
163
180
|
# @raise [ArgumentError]
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: omniai-openai
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kevin Sylvestre
|
|
@@ -83,6 +83,7 @@ files:
|
|
|
83
83
|
- lib/omniai/openai/chat/response_serializer.rb
|
|
84
84
|
- lib/omniai/openai/chat/stream.rb
|
|
85
85
|
- lib/omniai/openai/chat/text_serializer.rb
|
|
86
|
+
- lib/omniai/openai/chat/thinking_serializer.rb
|
|
86
87
|
- lib/omniai/openai/chat/tool_call_message_serializer.rb
|
|
87
88
|
- lib/omniai/openai/chat/tool_call_result_serializer.rb
|
|
88
89
|
- lib/omniai/openai/chat/tool_call_serializer.rb
|