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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1c2cc91a787673b5e875ee28c1d5e173b129e7eacb37ece64495bb25734ceba
4
- data.tar.gz: fb15b6963dd2f711248b853a3c4782d0b9762fcc05777d6f4ac90fe719ab34a6
3
+ metadata.gz: 33134e75816a15602fef0394b0be7527930e7bb8f3b8469e5b0acbe7f93edf23
4
+ data.tar.gz: 1ce3168ea82a7a943e1c6537839b2cec9286bd8684e80e873aca4133ed326c49
5
5
  SHA512:
6
- metadata.gz: 1f4ee8e419634378e0ef36954075b8ba52e682c75942a8bfeb6ad33b9f4d503d157bc294356eb33d4b174a44384956b9fd96fc09ff8824b48bad0f8cc881cdc2
7
- data.tar.gz: cd252893230465bd90742145a03c202ebe7b74b887d050d65e51c62f671913d74d03e4d44e7846582cb4b108b240b02ecddd31a56838a028e3bee57ae0d28812
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
- block&.call(OmniAI::Chat::Delta.new(text: part["text"])) if part["text"]
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
- if candidate["content"]["parts"][-1]&.key?("text") && part["text"]
86
- candidate["content"]["parts"][-1]["text"] += part["text"]
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
@@ -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 = GEMINI_3_0_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|
@@ -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
- Chat.process!(messages, model:, temperature:, format:, stream:, tools:, client: self, &)
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module OmniAI
4
4
  module Google
5
- VERSION = "3.3.3"
5
+ VERSION = "3.5.0"
6
6
  end
7
7
  end
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.3.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