omniai-openai 2.6.5 → 3.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 +4 -4
- data/lib/omniai/openai/chat/choice_serializer.rb +27 -0
- data/lib/omniai/openai/chat/content_serializer.rb +20 -0
- data/lib/omniai/openai/chat/file_serializer.rb +24 -0
- data/lib/omniai/openai/chat/message_serializer.rb +93 -0
- data/lib/omniai/openai/chat/response_serializer.rb +35 -0
- data/lib/omniai/openai/chat/stream.rb +31 -0
- data/lib/omniai/openai/chat/text_serializer.rb +27 -0
- data/lib/omniai/openai/chat/tool_call_message_serializer.rb +30 -0
- data/lib/omniai/openai/chat/tool_call_result_serializer.rb +31 -0
- data/lib/omniai/openai/chat/tool_call_serializer.rb +32 -0
- data/lib/omniai/openai/chat/tool_serializer.rb +22 -0
- data/lib/omniai/openai/chat/url_serializer.rb +23 -0
- data/lib/omniai/openai/chat.rb +92 -56
- data/lib/omniai/openai/client.rb +5 -8
- data/lib/omniai/openai/version.rb +1 -1
- data/lib/omniai/openai.rb +1 -0
- metadata +29 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d06da3f28613c3f683a2b6ddc712843451726d7c6d14a728d16ab383d6093fc1
|
|
4
|
+
data.tar.gz: e3f02890b984ef9522f39e0f28e80ee8cbb0b6b058af7232d260964858066b6f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 29bb8f139c1337201b695aee14303b0d2ed62b76f140898b068b765bf5112dc589037ec021a2454cf4e2c7113911c643fd5173b8efd7da8f347c8c0525a3db43
|
|
7
|
+
data.tar.gz: 8d12830098e2d63ad1d4555ee781f1515e9624e1dafc7db90c041832e9fed005c3bfa05b21b6d2b16ed8cff0ed66d2cf87a6ec0009b8aeebe8ce7e2024b3d8a7
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OmniAI
|
|
4
|
+
module OpenAI
|
|
5
|
+
class Chat
|
|
6
|
+
# Overrides choice serialize / deserialize.
|
|
7
|
+
module ChoiceSerializer
|
|
8
|
+
# @param choice [OmniAI::Chat::Choice]
|
|
9
|
+
# @param context [Context]
|
|
10
|
+
#
|
|
11
|
+
# @return [Hash]
|
|
12
|
+
def self.serialize(choice, context:)
|
|
13
|
+
choice.message.serialize(context:)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @param data [Hash]
|
|
17
|
+
# @param context [Context]
|
|
18
|
+
#
|
|
19
|
+
# @return [OmniAI::Chat::Choice]
|
|
20
|
+
def self.deserialize(data, context:)
|
|
21
|
+
message = OmniAI::Chat::Message.deserialize(data, context:)
|
|
22
|
+
OmniAI::Chat::Choice.new(message:)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OmniAI
|
|
4
|
+
module OpenAI
|
|
5
|
+
class Chat
|
|
6
|
+
# Overrides content serialize / deserialize.
|
|
7
|
+
module ContentSerializer
|
|
8
|
+
# @param data [Hash]
|
|
9
|
+
# @param context [Context]
|
|
10
|
+
#
|
|
11
|
+
# @return [OmniAI::Chat::Text, OmniAI::Chat::ToolCall]
|
|
12
|
+
def self.deserialize(data, context:)
|
|
13
|
+
case data["type"]
|
|
14
|
+
when /(input|output)_text/ then OmniAI::Chat::Text.deserialize(data, context:)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OmniAI
|
|
4
|
+
module OpenAI
|
|
5
|
+
class Chat
|
|
6
|
+
# Overrides file serialize / deserialize.
|
|
7
|
+
module FileSerializer
|
|
8
|
+
# @param file [OmniAI::Chat::File]
|
|
9
|
+
# @param direction [String] "input" or "output"
|
|
10
|
+
#
|
|
11
|
+
# @return [Hash]
|
|
12
|
+
def self.serialize(file, direction:, **)
|
|
13
|
+
type = file.image? ? "image" : "file"
|
|
14
|
+
|
|
15
|
+
{
|
|
16
|
+
type: "#{direction}_#{type}",
|
|
17
|
+
"#{type}_data": file.data,
|
|
18
|
+
filename: file.filename,
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OmniAI
|
|
4
|
+
module OpenAI
|
|
5
|
+
class Chat
|
|
6
|
+
# Overrides message serialize / deserialize.
|
|
7
|
+
module MessageSerializer
|
|
8
|
+
# @param message [OmniAI::Chat::Message]
|
|
9
|
+
# @param context [OmniAI::Context]
|
|
10
|
+
#
|
|
11
|
+
# @return [Hash]
|
|
12
|
+
def self.serialize(message, context:)
|
|
13
|
+
if message.tool?
|
|
14
|
+
serialize_for_tool_call(message, context:)
|
|
15
|
+
else
|
|
16
|
+
serialize_for_content(message, context:)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @param message [OmniAI::Chat::Message]
|
|
21
|
+
# @param context [OmniAI::Context]
|
|
22
|
+
#
|
|
23
|
+
# @return [Hash]
|
|
24
|
+
def self.serialize_for_tool_call(message, context:)
|
|
25
|
+
tool_call_list = message.tool_call_list
|
|
26
|
+
tool_call = tool_call_list[0]
|
|
27
|
+
tool_call.serialize(context:)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @param message [OmniAI::Chat::Message]
|
|
31
|
+
# @param context [OmniAI::Context]
|
|
32
|
+
#
|
|
33
|
+
# @return [Hash]
|
|
34
|
+
def self.serialize_for_content(message, context:)
|
|
35
|
+
role = message.role
|
|
36
|
+
direction = message.direction
|
|
37
|
+
parts = arrayify(message.content)
|
|
38
|
+
|
|
39
|
+
content = parts.map do |part|
|
|
40
|
+
case part
|
|
41
|
+
when String then { type: "#{direction}_text", text: part }
|
|
42
|
+
else part.serialize(context:, direction:)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
{ role:, content: }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @param data [Hash]
|
|
50
|
+
# @param context [OmniAI::Context]
|
|
51
|
+
#
|
|
52
|
+
# @return [OmniAI::Chat::Message]
|
|
53
|
+
def self.deserialize(data, context:)
|
|
54
|
+
case data["type"]
|
|
55
|
+
when "message" then deserialize_for_content(data, context:)
|
|
56
|
+
when "function_call" then deserialize_for_tool_call(data, context:)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @param data [Hash]
|
|
61
|
+
# @param context [OmniAI::Context]
|
|
62
|
+
#
|
|
63
|
+
# @return [OmniAI::Chat::Message]
|
|
64
|
+
def self.deserialize_for_content(data, context:)
|
|
65
|
+
role = data["role"]
|
|
66
|
+
content = data["content"].map do |content|
|
|
67
|
+
OmniAI::Chat::Content.deserialize(content, context:)
|
|
68
|
+
end
|
|
69
|
+
OmniAI::Chat::Message.new(role:, content:)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @param data [Hash]
|
|
73
|
+
# @param context [OmniAI::Context]
|
|
74
|
+
#
|
|
75
|
+
# @return [OmniAI::Chat::Message]
|
|
76
|
+
def self.deserialize_for_tool_call(data, context:)
|
|
77
|
+
entry = OmniAI::Chat::ToolCall.deserialize(data, context:)
|
|
78
|
+
tool_call_list = OmniAI::Chat::ToolCallList.new(entries: [entry])
|
|
79
|
+
OmniAI::Chat::Message.new(role: OmniAI::Chat::Role::TOOL, content: nil, tool_call_list:)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# @param content [Object]
|
|
83
|
+
#
|
|
84
|
+
# @return [Array<Object>]
|
|
85
|
+
def self.arrayify(content)
|
|
86
|
+
return [] if content.nil?
|
|
87
|
+
|
|
88
|
+
content.is_a?(Array) ? content : [content]
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OmniAI
|
|
4
|
+
module OpenAI
|
|
5
|
+
class Chat
|
|
6
|
+
# Overrides response serialize / deserialize.
|
|
7
|
+
module ResponseSerializer
|
|
8
|
+
# @param response [OmniAI::Chat::Response]
|
|
9
|
+
# @param context [OmniAI::Context]
|
|
10
|
+
#
|
|
11
|
+
# @return [Hash]
|
|
12
|
+
def self.serialize(response, context:)
|
|
13
|
+
usage = response.usage.serialize(context:)
|
|
14
|
+
output = response.choices.serialize(context:)
|
|
15
|
+
|
|
16
|
+
{
|
|
17
|
+
usage:,
|
|
18
|
+
output:,
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @param data [Hash]
|
|
23
|
+
# @param context [OmniAI::Context]
|
|
24
|
+
#
|
|
25
|
+
# @return [OmniAI::Chat::Response]
|
|
26
|
+
def self.deserialize(data, context:)
|
|
27
|
+
usage = OmniAI::Chat::Usage.deserialize(data["usage"], context:) if data["usage"]
|
|
28
|
+
choices = data["output"].map { |choice_data| OmniAI::Chat::Choice.deserialize(choice_data, context:) }
|
|
29
|
+
|
|
30
|
+
OmniAI::Chat::Response.new(data:, choices:, usage:)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OmniAI
|
|
4
|
+
module OpenAI
|
|
5
|
+
class Chat
|
|
6
|
+
# For each chunk yield the text delta. Parse the final content into a response.
|
|
7
|
+
class Stream < OmniAI::Chat::Stream
|
|
8
|
+
# @yield [delta]
|
|
9
|
+
# @yieldparam delta [OmniAI::Chat::Delta]
|
|
10
|
+
#
|
|
11
|
+
# @return [Hash]
|
|
12
|
+
def stream!(&block)
|
|
13
|
+
response = {}
|
|
14
|
+
|
|
15
|
+
@chunks.each do |chunk|
|
|
16
|
+
parser.feed(chunk) do |type, data, _id|
|
|
17
|
+
case type
|
|
18
|
+
when /response\.(.*)_text\.delta/
|
|
19
|
+
block.call(OmniAI::Chat::Delta.new(text: JSON.parse(data)["delta"]))
|
|
20
|
+
when "response.completed"
|
|
21
|
+
response = JSON.parse(data)["response"]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
response
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OmniAI
|
|
4
|
+
module OpenAI
|
|
5
|
+
class Chat
|
|
6
|
+
# Overrides text serialize / deserialize.
|
|
7
|
+
module TextSerializer
|
|
8
|
+
# @param text [OmniAI::Chat::Text]
|
|
9
|
+
# @param direction [String] "input" or "output"
|
|
10
|
+
#
|
|
11
|
+
# @return [Hash]
|
|
12
|
+
def self.serialize(text, direction:, **)
|
|
13
|
+
raise text.inspect if direction.nil?
|
|
14
|
+
|
|
15
|
+
{ type: "#{direction}_text", text: text.text }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @param data [Hash]
|
|
19
|
+
#
|
|
20
|
+
# @return [OmniAI::Chat::Text]
|
|
21
|
+
def self.deserialize(data, *)
|
|
22
|
+
OmniAI::Chat::Text.new(data["text"])
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OmniAI
|
|
4
|
+
module OpenAI
|
|
5
|
+
class Chat
|
|
6
|
+
# Overrides tool-call message serialize / deserialize.
|
|
7
|
+
module ToolCallMessageSerializer
|
|
8
|
+
# @param message [OmniAI::Chat::ToolCallMessage]
|
|
9
|
+
#
|
|
10
|
+
# @return [Hash]
|
|
11
|
+
def self.serialize(message, *)
|
|
12
|
+
{
|
|
13
|
+
type: "function_call_output",
|
|
14
|
+
call_id: message.tool_call_id,
|
|
15
|
+
output: JSON.generate(message.content),
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @param data [Hash]
|
|
20
|
+
#
|
|
21
|
+
# @return [OmniAI::Chat::ToolCallMessage]
|
|
22
|
+
def self.deserialize(data, *)
|
|
23
|
+
content = data["content"]
|
|
24
|
+
tool_call_id = data["call_id"]
|
|
25
|
+
OmniAI::Chat::ToolCallMessage.new(content:, tool_call_id:)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OmniAI
|
|
4
|
+
module OpenAI
|
|
5
|
+
class Chat
|
|
6
|
+
# Overrides tool-call response serialize / deserialize.
|
|
7
|
+
module ToolCallResultSerializer
|
|
8
|
+
# @param tool_call_result [OmniAI::Chat::ToolCallResult]
|
|
9
|
+
#
|
|
10
|
+
# @return [Hash]
|
|
11
|
+
def self.serialize(tool_call_result, *)
|
|
12
|
+
{
|
|
13
|
+
type: "function_call_output",
|
|
14
|
+
call_id: tool_call_result.tool_call_id,
|
|
15
|
+
output: tool_call_result.text,
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @param data [Hash]
|
|
20
|
+
#
|
|
21
|
+
# @return [OmniAI::Chat::ToolCallResult]
|
|
22
|
+
def self.deserialize(data, *)
|
|
23
|
+
tool_call_id = data["call_id"]
|
|
24
|
+
content = data["output"]
|
|
25
|
+
|
|
26
|
+
OmniAI::Chat::ToolCallResult.new(content:, tool_call_id:)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OmniAI
|
|
4
|
+
module OpenAI
|
|
5
|
+
class Chat
|
|
6
|
+
# Overrides tool-call serialize / deserialize.
|
|
7
|
+
module ToolCallSerializer
|
|
8
|
+
# @param tool_call [OmniAI::Chat::ToolCall]
|
|
9
|
+
# @param context [OmniAI::Context]
|
|
10
|
+
#
|
|
11
|
+
# @return [Hash]
|
|
12
|
+
def self.serialize(tool_call, context:)
|
|
13
|
+
function = tool_call.function.serialize(context:)
|
|
14
|
+
|
|
15
|
+
{
|
|
16
|
+
call_id: tool_call.id,
|
|
17
|
+
type: "function_call",
|
|
18
|
+
}.merge(function)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @param data [Hash]
|
|
22
|
+
# @param context [OmniAI::Context]
|
|
23
|
+
#
|
|
24
|
+
# @return [OmniAI::Chat::ToolCall]
|
|
25
|
+
def self.deserialize(data, context:)
|
|
26
|
+
function = OmniAI::Chat::Function.deserialize(data, context:)
|
|
27
|
+
OmniAI::Chat::ToolCall.new(id: data["id"], function:)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OmniAI
|
|
4
|
+
module OpenAI
|
|
5
|
+
class Chat
|
|
6
|
+
# Overrides text serialize / deserialize.
|
|
7
|
+
module ToolSerializer
|
|
8
|
+
# @param tool [OmniAI::Tool]
|
|
9
|
+
# @return [Hash]
|
|
10
|
+
def self.serialize(tool, *)
|
|
11
|
+
{
|
|
12
|
+
type: "function",
|
|
13
|
+
name: tool.name,
|
|
14
|
+
description: tool.description,
|
|
15
|
+
parameters: tool.parameters.is_a?(Schema::Object) ? tool.parameters.serialize : tool.parameters,
|
|
16
|
+
strict: true,
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OmniAI
|
|
4
|
+
module OpenAI
|
|
5
|
+
class Chat
|
|
6
|
+
# Overrides media serialize / deserialize.
|
|
7
|
+
module URLSerializer
|
|
8
|
+
# @param url [OmniAI::Chat::URL]
|
|
9
|
+
# @param direction [String] "input" or "output"
|
|
10
|
+
#
|
|
11
|
+
# @return [Hash]
|
|
12
|
+
def self.serialize(url, direction:, **)
|
|
13
|
+
type = url.image? ? "image" : "file"
|
|
14
|
+
|
|
15
|
+
{
|
|
16
|
+
type: "#{direction}_#{type}",
|
|
17
|
+
"#{type}_url": url.uri,
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/omniai/openai/chat.rb
CHANGED
|
@@ -12,8 +12,6 @@ module OmniAI
|
|
|
12
12
|
# end
|
|
13
13
|
# completion.choice.message.content # '...'
|
|
14
14
|
class Chat < OmniAI::Chat
|
|
15
|
-
DEFAULT_STREAM_OPTIONS = { include_usage: ENV.fetch("OMNIAI_STREAM_USAGE", "on").eql?("on") }.freeze
|
|
16
|
-
|
|
17
15
|
module ResponseFormat
|
|
18
16
|
TEXT_TYPE = "text"
|
|
19
17
|
JSON_TYPE = "json_object"
|
|
@@ -53,23 +51,71 @@ module OmniAI
|
|
|
53
51
|
O3 = "o3"
|
|
54
52
|
end
|
|
55
53
|
|
|
56
|
-
DEFAULT_MODEL = Model::
|
|
54
|
+
DEFAULT_MODEL = Model::GPT_5_1
|
|
55
|
+
|
|
56
|
+
# @return [Context]
|
|
57
|
+
CONTEXT = Context.build do |context|
|
|
58
|
+
context.serializers[:choice] = ChoiceSerializer.method(:serialize)
|
|
59
|
+
context.deserializers[:choice] = ChoiceSerializer.method(:deserialize)
|
|
60
|
+
context.serializers[:message] = MessageSerializer.method(:serialize)
|
|
61
|
+
context.deserializers[:message] = MessageSerializer.method(:deserialize)
|
|
62
|
+
context.serializers[:text] = TextSerializer.method(:serialize)
|
|
63
|
+
context.deserializers[:text] = TextSerializer.method(:deserialize)
|
|
64
|
+
context.serializers[:response] = ResponseSerializer.method(:serialize)
|
|
65
|
+
context.deserializers[:response] = ResponseSerializer.method(:deserialize)
|
|
66
|
+
context.deserializers[:content] = ContentSerializer.method(:deserialize)
|
|
67
|
+
context.serializers[:file] = FileSerializer.method(:serialize)
|
|
68
|
+
context.serializers[:url] = URLSerializer.method(:serialize)
|
|
69
|
+
context.serializers[:tool] = ToolSerializer.method(:serialize)
|
|
70
|
+
context.serializers[:tool_call] = ToolCallSerializer.method(:serialize)
|
|
71
|
+
context.deserializers[:tool_call] = ToolCallSerializer.method(:deserialize)
|
|
72
|
+
context.serializers[:tool_call_result] = ToolCallResultSerializer.method(:serialize)
|
|
73
|
+
context.deserializers[:tool_call_result] = ToolCallResultSerializer.method(:deserialize)
|
|
74
|
+
context.serializers[:tool_call_message] = ToolCallMessageSerializer.method(:serialize)
|
|
75
|
+
context.deserializers[:tool_call_message] = ToolCallMessageSerializer.method(:deserialize)
|
|
76
|
+
end
|
|
57
77
|
|
|
58
78
|
protected
|
|
59
79
|
|
|
80
|
+
# @return [Context]
|
|
81
|
+
def context
|
|
82
|
+
CONTEXT
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# @return [Array<Hash>]
|
|
86
|
+
def input
|
|
87
|
+
@prompt
|
|
88
|
+
.messages
|
|
89
|
+
.reject(&:system?)
|
|
90
|
+
.map { |message| message.serialize(context:) }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# @return [String, nil]
|
|
94
|
+
def instructions
|
|
95
|
+
parts = @prompt
|
|
96
|
+
.messages
|
|
97
|
+
.filter(&:system?)
|
|
98
|
+
.filter(&:text?)
|
|
99
|
+
.map(&:text)
|
|
100
|
+
|
|
101
|
+
return if parts.empty?
|
|
102
|
+
|
|
103
|
+
parts.join("\n\n")
|
|
104
|
+
end
|
|
105
|
+
|
|
60
106
|
# @return [Float, nil]
|
|
61
107
|
def temperature
|
|
62
108
|
return if @temperature.nil?
|
|
63
109
|
|
|
64
|
-
|
|
65
|
-
Model::
|
|
66
|
-
Model::
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
110
|
+
return if [
|
|
111
|
+
Model::GPT_5,
|
|
112
|
+
Model::GPT_5_MINI,
|
|
113
|
+
Model::GPT_5_NANO,
|
|
114
|
+
Model::GPT_5_1,
|
|
115
|
+
Model::O1_MINI,
|
|
116
|
+
Model::O1,
|
|
117
|
+
Model::O3_MINI,
|
|
118
|
+
].include?(@model)
|
|
73
119
|
|
|
74
120
|
@temperature
|
|
75
121
|
end
|
|
@@ -77,71 +123,61 @@ module OmniAI
|
|
|
77
123
|
# @return [Hash]
|
|
78
124
|
def payload
|
|
79
125
|
OmniAI::OpenAI.config.chat_options.merge({
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
126
|
+
instructions:,
|
|
127
|
+
input:,
|
|
128
|
+
model: @model || DEFAULT_MODEL,
|
|
83
129
|
stream: stream? || nil,
|
|
84
|
-
stream_options: (DEFAULT_STREAM_OPTIONS if stream?),
|
|
85
130
|
temperature:,
|
|
86
|
-
tools
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
131
|
+
tools:,
|
|
132
|
+
text:,
|
|
133
|
+
reasoning:,
|
|
134
|
+
}).compact
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# @return [Array<Hash>]
|
|
138
|
+
def tools
|
|
139
|
+
return unless @tools&.any?
|
|
140
|
+
|
|
141
|
+
@tools.map { |tool| tool.serialize(context:) }
|
|
90
142
|
end
|
|
91
143
|
|
|
92
144
|
# @return [String]
|
|
93
145
|
def path
|
|
94
|
-
"#{@client.api_prefix}/#{OmniAI::OpenAI::Client::VERSION}/
|
|
146
|
+
"#{@client.api_prefix}/#{OmniAI::OpenAI::Client::VERSION}/responses"
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# @return [Hash]
|
|
150
|
+
def text
|
|
151
|
+
options = @options.fetch(:text, {}).merge(format:).compact
|
|
152
|
+
options unless options.empty?
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# @return [Hash]
|
|
156
|
+
def reasoning
|
|
157
|
+
options = @options.fetch(:reasoning, {})
|
|
158
|
+
options unless options.empty?
|
|
95
159
|
end
|
|
96
160
|
|
|
97
161
|
# @raise [ArgumentError]
|
|
98
162
|
#
|
|
99
163
|
# @return [Hash, nil]
|
|
100
|
-
def
|
|
164
|
+
def format
|
|
101
165
|
return if @format.nil?
|
|
102
166
|
|
|
103
167
|
case @format
|
|
104
168
|
when :text then { type: ResponseFormat::TEXT_TYPE }
|
|
105
169
|
when :json then { type: ResponseFormat::JSON_TYPE }
|
|
106
|
-
when OmniAI::Schema::Format
|
|
170
|
+
when OmniAI::Schema::Format
|
|
171
|
+
@format.serialize.merge({ type: ResponseFormat::SCHEMA_TYPE, strict: true })
|
|
107
172
|
else raise ArgumentError, "unknown format=#{@format}"
|
|
108
173
|
end
|
|
109
174
|
end
|
|
110
175
|
|
|
111
|
-
# @
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return if @reasoning.nil?
|
|
116
|
-
|
|
117
|
-
effort = @reasoning[:effort] || @reasoning["effort"]
|
|
118
|
-
return if effort.nil?
|
|
119
|
-
|
|
120
|
-
valid_efforts = [ReasoningEffort::NONE, ReasoningEffort::LOW, ReasoningEffort::MEDIUM, ReasoningEffort::HIGH]
|
|
121
|
-
unless valid_efforts.include?(effort)
|
|
122
|
-
raise ArgumentError,
|
|
123
|
-
"reasoning effort must be one of #{valid_efforts.join(', ')}"
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
effort
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
# @raise [ArgumentError]
|
|
130
|
-
#
|
|
131
|
-
# @return [String, nil]
|
|
132
|
-
def verbosity_payload
|
|
133
|
-
return if @verbosity.nil?
|
|
134
|
-
|
|
135
|
-
text = @verbosity[:text] || @verbosity["text"]
|
|
136
|
-
return if text.nil?
|
|
137
|
-
|
|
138
|
-
valid_text_levels = [VerbosityText::LOW, VerbosityText::MEDIUM, VerbosityText::HIGH]
|
|
139
|
-
unless valid_text_levels.include?(text)
|
|
140
|
-
raise ArgumentError,
|
|
141
|
-
"verbosity text must be one of #{valid_text_levels.join(', ')}"
|
|
176
|
+
# @return [Array<ToolCallMessage>]
|
|
177
|
+
def build_tool_call_messages(tool_call_list)
|
|
178
|
+
tool_call_list.map do |tool_call|
|
|
179
|
+
ToolCallMessage.new(tool_call_id: tool_call.id, content: execute_tool_call(tool_call))
|
|
142
180
|
end
|
|
143
|
-
|
|
144
|
-
text
|
|
145
181
|
end
|
|
146
182
|
end
|
|
147
183
|
end
|
data/lib/omniai/openai/client.rb
CHANGED
|
@@ -71,22 +71,19 @@ module OmniAI
|
|
|
71
71
|
|
|
72
72
|
# @raise [OmniAI::Error]
|
|
73
73
|
#
|
|
74
|
-
# @param
|
|
75
|
-
# @param model [String] optional
|
|
76
|
-
# @param format [Symbol] optional
|
|
74
|
+
# @param prompt [String, OmniAI::Chat::Prompt, nil] optional
|
|
75
|
+
# @param model [String, nil] optional
|
|
76
|
+
# @param format [Symbol, OmniAI::Schema::Format, nil] optional (e.g. `:text`, `:json`, `OmniAI::Schema.format(...)`)
|
|
77
77
|
# @param temperature [Float, nil] optional
|
|
78
78
|
# @param stream [Proc, nil] optional
|
|
79
79
|
# @param tools [Array<OmniAI::Tool>, nil] optional
|
|
80
|
-
# @param reasoning [Hash, nil] optional reasoning configuration
|
|
81
|
-
# @param verbosity [Hash, nil] optional verbosity configuration
|
|
82
80
|
#
|
|
83
81
|
# @yield [prompt]
|
|
84
82
|
# @yieldparam prompt [OmniAI::Chat::Prompt]
|
|
85
83
|
#
|
|
86
84
|
# @return [OmniAI::Chat::Completion]
|
|
87
|
-
def chat(
|
|
88
|
-
|
|
89
|
-
Chat.process!(messages, model:, temperature:, format:, stream:, tools:, reasoning:, verbosity:, client: self, &)
|
|
85
|
+
def chat(prompt = nil, model: Chat::DEFAULT_MODEL, temperature: nil, format: nil, stream: nil, tools: nil, **, &)
|
|
86
|
+
Chat.process!(prompt, model:, temperature:, format:, stream:, tools:, client: self, **, &)
|
|
90
87
|
end
|
|
91
88
|
|
|
92
89
|
# @raise [OmniAI::Error]
|
data/lib/omniai/openai.rb
CHANGED
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:
|
|
4
|
+
version: 3.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kevin Sylvestre
|
|
@@ -29,14 +29,28 @@ dependencies:
|
|
|
29
29
|
requirements:
|
|
30
30
|
- - "~>"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: '
|
|
32
|
+
version: '3.0'
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: '
|
|
39
|
+
version: '3.0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: openssl
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
40
54
|
- !ruby/object:Gem::Dependency
|
|
41
55
|
name: zeitwerk
|
|
42
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -62,6 +76,18 @@ files:
|
|
|
62
76
|
- README.md
|
|
63
77
|
- lib/omniai/openai.rb
|
|
64
78
|
- lib/omniai/openai/chat.rb
|
|
79
|
+
- lib/omniai/openai/chat/choice_serializer.rb
|
|
80
|
+
- lib/omniai/openai/chat/content_serializer.rb
|
|
81
|
+
- lib/omniai/openai/chat/file_serializer.rb
|
|
82
|
+
- lib/omniai/openai/chat/message_serializer.rb
|
|
83
|
+
- lib/omniai/openai/chat/response_serializer.rb
|
|
84
|
+
- lib/omniai/openai/chat/stream.rb
|
|
85
|
+
- lib/omniai/openai/chat/text_serializer.rb
|
|
86
|
+
- lib/omniai/openai/chat/tool_call_message_serializer.rb
|
|
87
|
+
- lib/omniai/openai/chat/tool_call_result_serializer.rb
|
|
88
|
+
- lib/omniai/openai/chat/tool_call_serializer.rb
|
|
89
|
+
- lib/omniai/openai/chat/tool_serializer.rb
|
|
90
|
+
- lib/omniai/openai/chat/url_serializer.rb
|
|
65
91
|
- lib/omniai/openai/client.rb
|
|
66
92
|
- lib/omniai/openai/config.rb
|
|
67
93
|
- lib/omniai/openai/embed.rb
|