omniai-google 3.3.3 → 3.5.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/README.md +30 -0
- data/lib/omniai/google/chat/content_serializer.rb +2 -1
- data/lib/omniai/google/chat/message_serializer.rb +1 -0
- data/lib/omniai/google/chat/stream.rb +12 -3
- data/lib/omniai/google/chat/thinking_serializer.rb +27 -0
- data/lib/omniai/google/chat.rb +19 -1
- data/lib/omniai/google/client.rb +3 -2
- data/lib/omniai/google/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: 33134e75816a15602fef0394b0be7527930e7bb8f3b8469e5b0acbe7f93edf23
|
|
4
|
+
data.tar.gz: 1ce3168ea82a7a943e1c6537839b2cec9286bd8684e80e873aca4133ed326c49
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e6f3f3f81fa30d51fc892c09f5d13ff00c438b0f064549447a08a25cc814d52650e32ce2140c74b7fdbbdac80b94d8d210ac74978fe4e931837663fa43ae85cd
|
|
7
|
+
data.tar.gz: b2a5c9217496e893385f617c6250448ad8edfddb4aa6274deeab3e516044aa30e82ece923d2d64eaf4720218195cddfe7f6f07778985d8073063212c52f762e2
|
data/README.md
CHANGED
|
@@ -118,6 +118,36 @@ end
|
|
|
118
118
|
client.chat('Be poetic.', stream:)
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
+
#### Extended Thinking
|
|
122
|
+
|
|
123
|
+
Google Gemini 2.0+ models support extended thinking, which shows the model's reasoning process.
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
# Enable thinking
|
|
127
|
+
response = client.chat("What is 25 * 25?", model: "gemini-2.5-pro-preview-05-06", thinking: true)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### Accessing Thinking Content
|
|
131
|
+
|
|
132
|
+
```ruby
|
|
133
|
+
response.choices.first.message.contents.each do |content|
|
|
134
|
+
case content
|
|
135
|
+
when OmniAI::Chat::Thinking
|
|
136
|
+
puts "Thinking: #{content.thinking}"
|
|
137
|
+
when OmniAI::Chat::Text
|
|
138
|
+
puts "Response: #{content.text}"
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### Streaming with Thinking
|
|
144
|
+
|
|
145
|
+
```ruby
|
|
146
|
+
client.chat("What are the prime factors of 1234567?", model: "gemini-2.5-pro-preview-05-06", thinking: true, stream: $stdout)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
[Google API Reference `thinking`](https://ai.google.dev/gemini-api/docs/thinking)
|
|
150
|
+
|
|
121
151
|
### Upload
|
|
122
152
|
|
|
123
153
|
An upload is especially useful when processing audio / image / video / text files. To use:
|
|
@@ -7,9 +7,10 @@ module OmniAI
|
|
|
7
7
|
module ContentSerializer
|
|
8
8
|
# @param data [Hash]
|
|
9
9
|
# @param context [Context]
|
|
10
|
-
# @return [OmniAI::Chat::Text, OmniAI::Chat::ToolCall]
|
|
10
|
+
# @return [OmniAI::Chat::Text, OmniAI::Chat::Thinking, OmniAI::Chat::ToolCall]
|
|
11
11
|
def self.deserialize(data, context:)
|
|
12
12
|
case
|
|
13
|
+
when data["thought"] then OmniAI::Chat::Thinking.deserialize(data, context:)
|
|
13
14
|
when data["text"] then data["text"]
|
|
14
15
|
when data["functionCall"] then OmniAI::Chat::ToolCall.deserialize(data, context:)
|
|
15
16
|
end
|
|
@@ -27,6 +27,7 @@ module OmniAI
|
|
|
27
27
|
role = data["role"]
|
|
28
28
|
parts = arrayify(data["parts"]).map do |part|
|
|
29
29
|
case
|
|
30
|
+
when part["thought"] then OmniAI::Chat::Thinking.deserialize(part, context:)
|
|
30
31
|
when part["text"] then OmniAI::Chat::Text.deserialize(part, context:)
|
|
31
32
|
when part["functionCall"] then OmniAI::Chat::ToolCall.deserialize(part, context:)
|
|
32
33
|
when part["functionResponse"] then OmniAI::Chat::ToolCallResult.deserialize(part, context:)
|
|
@@ -57,7 +57,12 @@ module OmniAI
|
|
|
57
57
|
return unless candidate["content"]
|
|
58
58
|
|
|
59
59
|
candidate["content"]["parts"].each do |part|
|
|
60
|
-
|
|
60
|
+
if part["thought"]
|
|
61
|
+
# Google uses thought: true as a flag, content is in text
|
|
62
|
+
block&.call(OmniAI::Chat::Delta.new(thinking: part["text"]))
|
|
63
|
+
elsif part["text"]
|
|
64
|
+
block&.call(OmniAI::Chat::Delta.new(text: part["text"]))
|
|
65
|
+
end
|
|
61
66
|
end
|
|
62
67
|
|
|
63
68
|
merge_candidate!(candidate:, index:)
|
|
@@ -82,8 +87,12 @@ module OmniAI
|
|
|
82
87
|
# @param part [Hash]
|
|
83
88
|
# @param into [Hash]
|
|
84
89
|
def merge_part!(part:, candidate:)
|
|
85
|
-
|
|
86
|
-
|
|
90
|
+
last_part = candidate["content"]["parts"][-1]
|
|
91
|
+
|
|
92
|
+
if last_part&.key?("text") && part["text"]
|
|
93
|
+
last_part["text"] += part["text"]
|
|
94
|
+
elsif last_part&.key?("thought") && part["thought"]
|
|
95
|
+
last_part["thought"] += part["thought"]
|
|
87
96
|
else
|
|
88
97
|
candidate["content"]["parts"] << part
|
|
89
98
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OmniAI
|
|
4
|
+
module Google
|
|
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
|
+
# Google uses "thought: true" as a flag, with content in "text"
|
|
14
|
+
OmniAI::Chat::Thinking.new(data["text"])
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @param thinking [OmniAI::Chat::Thinking]
|
|
18
|
+
# @param context [Context]
|
|
19
|
+
#
|
|
20
|
+
# @return [Hash]
|
|
21
|
+
def self.serialize(thinking, context: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
22
|
+
{ thought: true, text: thinking.thinking }
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/omniai/google/chat.rb
CHANGED
|
@@ -17,11 +17,12 @@ module OmniAI
|
|
|
17
17
|
GEMINI_1_5_PRO = "gemini-1.5-pro"
|
|
18
18
|
GEMINI_2_5_PRO = "gemini-2.5-pro"
|
|
19
19
|
GEMINI_3_0_PRO = "gemini-3-pro-preview"
|
|
20
|
+
GEMINI_3_1_PRO = "gemini-3.1-pro-preview"
|
|
20
21
|
GEMINI_1_5_FLASH = "gemini-1.5-flash"
|
|
21
22
|
GEMINI_2_0_FLASH = "gemini-2.0-flash"
|
|
22
23
|
GEMINI_2_5_FLASH = "gemini-2.5-flash"
|
|
23
24
|
GEMINI_3_FLASH = "gemini-3-flash-preview"
|
|
24
|
-
GEMINI_PRO =
|
|
25
|
+
GEMINI_PRO = GEMINI_3_1_PRO
|
|
25
26
|
GEMINI_FLASH = GEMINI_3_FLASH
|
|
26
27
|
end
|
|
27
28
|
|
|
@@ -65,6 +66,9 @@ module OmniAI
|
|
|
65
66
|
context.deserializers[:content] = ContentSerializer.method(:deserialize)
|
|
66
67
|
|
|
67
68
|
context.serializers[:tool] = ToolSerializer.method(:serialize)
|
|
69
|
+
|
|
70
|
+
context.serializers[:thinking] = ThinkingSerializer.method(:serialize)
|
|
71
|
+
context.deserializers[:thinking] = ThinkingSerializer.method(:deserialize)
|
|
68
72
|
end
|
|
69
73
|
|
|
70
74
|
protected
|
|
@@ -129,6 +133,7 @@ module OmniAI
|
|
|
129
133
|
end
|
|
130
134
|
|
|
131
135
|
data[:temperature] = @temperature if @temperature
|
|
136
|
+
data[:thinkingConfig] = thinking_config if @options[:thinking]
|
|
132
137
|
|
|
133
138
|
data = data.compact
|
|
134
139
|
data unless data.empty?
|
|
@@ -144,6 +149,19 @@ module OmniAI
|
|
|
144
149
|
stream? ? "streamGenerateContent" : "generateContent"
|
|
145
150
|
end
|
|
146
151
|
|
|
152
|
+
# @return [Hash, nil]
|
|
153
|
+
def thinking_config
|
|
154
|
+
thinking = @options[:thinking]
|
|
155
|
+
return unless thinking
|
|
156
|
+
return { includeThoughts: true } unless thinking.is_a?(Hash)
|
|
157
|
+
|
|
158
|
+
config = { includeThoughts: true }
|
|
159
|
+
return config.merge(thinking) unless thinking.key?(:effort)
|
|
160
|
+
|
|
161
|
+
config[:thinkingLevel] = thinking[:effort].upcase if thinking[:effort]
|
|
162
|
+
config
|
|
163
|
+
end
|
|
164
|
+
|
|
147
165
|
# @return [Array<Message>]
|
|
148
166
|
def build_tool_call_messages(tool_call_list)
|
|
149
167
|
content = tool_call_list.map do |tool_call|
|
data/lib/omniai/google/client.rb
CHANGED
|
@@ -67,8 +67,9 @@ module OmniAI
|
|
|
67
67
|
# @yieldparam prompt [OmniAI::Chat::Prompt]
|
|
68
68
|
#
|
|
69
69
|
# @return [OmniAI::Chat::Completion]
|
|
70
|
-
def chat(messages = nil, model: Chat::DEFAULT_MODEL, temperature: nil, format: nil, stream: nil, tools: nil,
|
|
71
|
-
|
|
70
|
+
def chat(messages = nil, model: Chat::DEFAULT_MODEL, temperature: nil, format: nil, stream: nil, tools: nil,
|
|
71
|
+
**, &)
|
|
72
|
+
Chat.process!(messages, model:, temperature:, format:, stream:, tools:, client: self, **, &)
|
|
72
73
|
end
|
|
73
74
|
|
|
74
75
|
# @param io [File, String] required - a file or URL
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: omniai-google
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kevin Sylvestre
|
|
@@ -113,6 +113,7 @@ files:
|
|
|
113
113
|
- lib/omniai/google/chat/response_serializer.rb
|
|
114
114
|
- lib/omniai/google/chat/stream.rb
|
|
115
115
|
- lib/omniai/google/chat/text_serializer.rb
|
|
116
|
+
- lib/omniai/google/chat/thinking_serializer.rb
|
|
116
117
|
- lib/omniai/google/chat/tool_call_result_serializer.rb
|
|
117
118
|
- lib/omniai/google/chat/tool_call_serializer.rb
|
|
118
119
|
- lib/omniai/google/chat/tool_serializer.rb
|