omniai-anthropic 3.6.0 → 3.7.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 +18 -0
- data/lib/omniai/anthropic/chat/usage_serializer.rb +5 -0
- data/lib/omniai/anthropic/chat.rb +42 -5
- data/lib/omniai/anthropic/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 20cd61e7e110c59273cb86062c34630d07d66b14a5da7be33cfb11f3a3f29514
|
|
4
|
+
data.tar.gz: 44dfedfa87d0cb07ca36fc155efd5ddb8507eef146202a41e98be1c1bbd0010c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 815f8ed94a51cdbe222754218ab865a17227971e6d58d0c39aa6a87425919127af507871bd25263f355d22c5e46c5849c2bc34d6f3a955b6cebc6a06ce944c49
|
|
7
|
+
data.tar.gz: c4303f54ed395240b18c054f1776ac680323c89ba609c9c0c8dba57f5ad0c641d71eaa34a4713d9d6cc3356fdda59d4f020a186bc7b0d6aca5ec66f9bf2fe34d
|
data/README.md
CHANGED
|
@@ -170,3 +170,21 @@ client.chat("What are the prime factors of 1234567?", model: "claude-sonnet-4-20
|
|
|
170
170
|
The thinking content will stream first, followed by the response.
|
|
171
171
|
|
|
172
172
|
[Anthropic API Reference `thinking`](https://docs.anthropic.com/en/docs/build-with-claude/thinking)
|
|
173
|
+
|
|
174
|
+
### Prompt Caching
|
|
175
|
+
|
|
176
|
+
Prompt caching is opt-in. When enabled, the system prompt (or the last tool, when there is no system prompt) and the last block of the last message are marked with `cache_control`, so each round of a tool-call loop reads the history the previous round wrote.
|
|
177
|
+
|
|
178
|
+
```ruby
|
|
179
|
+
client.chat(prompt, tools:, cache: true) # 5-minute TTL
|
|
180
|
+
client.chat(prompt, tools:, cache: { ttl: "1h" }) # 1-hour TTL
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`usage.input_tokens` reports the whole prompt, including cached tokens. The cache breakdown is on each response's raw usage:
|
|
184
|
+
|
|
185
|
+
```ruby
|
|
186
|
+
response.response_chain.sum { |r| r.data.dig("usage", "cache_read_input_tokens").to_i }
|
|
187
|
+
response.response_chain.sum { |r| r.data.dig("usage", "cache_creation_input_tokens").to_i }
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
[Anthropic API Reference `prompt caching`](https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching)
|
|
@@ -24,6 +24,11 @@ module OmniAI
|
|
|
24
24
|
thinking_tokens = data.dig("output_tokens_details", "thinking_tokens")
|
|
25
25
|
usage.thinking_tokens = thinking_tokens unless thinking_tokens.nil?
|
|
26
26
|
|
|
27
|
+
# Anthropic's `input_tokens` excludes cache reads and writes; adding them back keeps it the whole prompt, as
|
|
28
|
+
# for every other provider. A base-serialized payload has neither key and is already whole.
|
|
29
|
+
cache_tokens = data.values_at("cache_creation_input_tokens", "cache_read_input_tokens").compact
|
|
30
|
+
usage.input_tokens = (usage.input_tokens || 0) + cache_tokens.sum if cache_tokens.any?
|
|
31
|
+
|
|
27
32
|
usage
|
|
28
33
|
end
|
|
29
34
|
end
|
|
@@ -165,19 +165,40 @@ module OmniAI
|
|
|
165
165
|
end
|
|
166
166
|
end
|
|
167
167
|
|
|
168
|
+
# When caching, the last block of the last message is marked so each tool-loop round reads the history the
|
|
169
|
+
# previous round wrote.
|
|
170
|
+
#
|
|
168
171
|
# @return [Array<Hash>]
|
|
169
172
|
def messages
|
|
170
|
-
messages = @prompt.messages.reject(&:system?)
|
|
171
|
-
messages
|
|
173
|
+
messages = @prompt.messages.reject(&:system?).map { |message| message.serialize(context:) }
|
|
174
|
+
return messages unless cache_control && messages.any?
|
|
175
|
+
|
|
176
|
+
*history, last = messages
|
|
177
|
+
history + [last.merge(content: with_cache_control(last[:content]))]
|
|
172
178
|
end
|
|
173
179
|
|
|
174
|
-
#
|
|
180
|
+
# When caching, a single marked text block. Tools render before system, so this breakpoint covers both.
|
|
181
|
+
#
|
|
182
|
+
# @return [String, Array<Hash>, nil]
|
|
175
183
|
def system
|
|
176
184
|
parts = @prompt.messages.filter(&:system?).filter(&:text?).map(&:text)
|
|
177
185
|
parts << formatting if formatting?
|
|
178
186
|
return if parts.empty?
|
|
179
187
|
|
|
180
|
-
parts.join("\n\n")
|
|
188
|
+
text = parts.join("\n\n")
|
|
189
|
+
cache_control ? [{ type: "text", text:, cache_control: }] : text
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Translates the opt-in `cache` option to Anthropic's `cache_control`.
|
|
193
|
+
# Example: `cache: true` becomes `{ type: "ephemeral" }` (5-minute TTL)
|
|
194
|
+
# Example: `cache: { ttl: "1h" }` becomes `{ type: "ephemeral", ttl: "1h" }`
|
|
195
|
+
#
|
|
196
|
+
# @return [Hash, nil]
|
|
197
|
+
def cache_control
|
|
198
|
+
case @options[:cache]
|
|
199
|
+
when true then { type: "ephemeral" }
|
|
200
|
+
when Hash then { type: "ephemeral" }.merge(@options[:cache])
|
|
201
|
+
end
|
|
181
202
|
end
|
|
182
203
|
|
|
183
204
|
# @return [String]
|
|
@@ -217,9 +238,25 @@ module OmniAI
|
|
|
217
238
|
end
|
|
218
239
|
end
|
|
219
240
|
|
|
241
|
+
# When caching without a system prompt, the last tool carries the breakpoint instead.
|
|
242
|
+
#
|
|
220
243
|
# @return [Array<Hash>, nil]
|
|
221
244
|
def tools_payload
|
|
222
|
-
|
|
245
|
+
return unless @tools&.any?
|
|
246
|
+
|
|
247
|
+
tools = @tools.map { |tool| tool.serialize(context:) }
|
|
248
|
+
cache_control && system.nil? ? with_cache_control(tools) : tools
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Relies on `MessageSerializer` normalizing every content part into a block Hash; a bare String would raise.
|
|
252
|
+
#
|
|
253
|
+
# @param blocks [Array<Hash>]
|
|
254
|
+
# @return [Array<Hash>]
|
|
255
|
+
def with_cache_control(blocks)
|
|
256
|
+
return blocks if blocks.empty?
|
|
257
|
+
|
|
258
|
+
*head, last = blocks
|
|
259
|
+
head + [last.merge(cache_control:)]
|
|
223
260
|
end
|
|
224
261
|
|
|
225
262
|
# @return [Boolean]
|