llm_cost_tracker 0.15.0 → 0.15.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3fbd251f06208de2aaeb887d9e8603fe7614e365c1d5d5e9aef0c27dba5f54d2
4
- data.tar.gz: 78600f3f5844d367c4dd9030c3af8b024937f90f501b9bab51a792df085ab9a7
3
+ metadata.gz: 380c06ddfdda1e5df94061a377dc703fd1f52c4b5ab92ab1f786ef1fce591be1
4
+ data.tar.gz: e58224c8eb4d538faea70fe867d33be5000611a35ec58ab33feb72d39fca9ef6
5
5
  SHA512:
6
- metadata.gz: 11e337b545c34c40b5ce468278a3a7d15f562bd016269b1dd59c41053fd0eb7602b2025aaa286c9dd603dd2740502b37afca51689ba843d5d039e1d8385490f7
7
- data.tar.gz: b918914d2b8b7671d02597d8f08000818f38d890609ae2a81286fa279da5ab3efaec230690c31ec5e060d2b02dcab6d4bc93bf129804233158c8681cf4575aa8
6
+ metadata.gz: 2cd2b3c33e60e7638c58044220f2e43336be78f2cd085d253cdf99badb9af8586f411d1ced9e332a7255b81f08267407a52e7610b5dedc33fc2623cbca681a34
7
+ data.tar.gz: 70c17315f8a243cc59ebaf036f480151320a4ecb3adc53d152f5f15bfe50b51d81fdc0722e784d026d540e94d64d9a64443cc6f8cf51bcaf5585093b80ee049a
data/CHANGELOG.md CHANGED
@@ -2,6 +2,29 @@
2
2
 
3
3
  Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versioning: [SemVer](https://semver.org/spec/v2.0.0.html).
4
4
 
5
+ ## [0.15.2] - 2026-10-29
6
+
7
+ ### Changed
8
+
9
+ - Bundled prices add OpenAI GPT-6.1 Terra.
10
+
11
+ ### Fixed
12
+
13
+ - OpenAI Decisions API calls through the official openai gem and Faraday are recorded.
14
+ - OpenAI Decisions output tokens are not billed, RubyLLM 2.x judgments included, as OpenAI prices them.
15
+
16
+ ## [0.15.1] - 2026-10-26
17
+
18
+ ### Changed
19
+
20
+ - Bundled prices add Cohere Rerank 5, Gemini 4 Argon, Mistral OCR 3, Voxtral 3 and Voxtral Realtime, and OpenAI 12-hour cache-write and xAI batch rates, double Mistral Large 4 rates after its sale ended, and drop the OpenAI models shut down on 2026-10-23.
21
+
22
+ ### Fixed
23
+
24
+ - anthropic gem 1.81+ `messages.stream` and `beta.messages.stream` are recorded once instead of twice.
25
+ - OpenAI Responses 12-hour prompt cache writes are priced at `cache_write_extended_input` instead of the 30-minute rate.
26
+ - RubyLLM 2.x Cohere rerank takes its input tokens from `meta.billed_units` and records the response id.
27
+
5
28
  ## [0.15.0] - 2026-10-10
6
29
 
7
30
  ### Added
@@ -9,10 +9,18 @@ module LlmCostTracker
9
9
  end
10
10
 
11
11
  def stream(*args, **kwargs)
12
- Integrations::Anthropic.wrap_stream(args, kwargs, **Integrations::Anthropic.stream_seam(@client)) { super }
12
+ Integrations::Anthropic.wrap_stream(args, kwargs, **Integrations::Anthropic.stream_seam(@client)) do
13
+ nested = Thread.current[:llm_cost_tracker_anthropic_stream]
14
+ Thread.current[:llm_cost_tracker_anthropic_stream] = true
15
+ super
16
+ ensure
17
+ Thread.current[:llm_cost_tracker_anthropic_stream] = nested
18
+ end
13
19
  end
14
20
 
15
21
  def stream_raw(*args, **kwargs)
22
+ return super if Thread.current[:llm_cost_tracker_anthropic_stream]
23
+
16
24
  Integrations::Anthropic.wrap_stream(args, kwargs, **Integrations::Anthropic.stream_seam(@client)) { super }
17
25
  end
18
26
  end
@@ -47,6 +47,7 @@ module LlmCostTracker
47
47
  patch_target("OpenAI::Resources::Audio::Translations", with: TranslationsPatch, optional: true),
48
48
  patch_target("OpenAI::Resources::Audio::Speech", with: SpeechPatch, optional: true),
49
49
  patch_target("OpenAI::Resources::Moderations", with: ModerationsPatch, optional: true),
50
+ patch_target("OpenAI::Resources::Decisions", with: CreatePatch, optional: true, since: "0.101.0"),
50
51
  patch_target("OpenAI::Resources::Batches", with: BatchesPatch, optional: true)
51
52
  ]
52
53
  end
@@ -152,7 +152,7 @@ module LlmCostTracker
152
152
  usage["type"] == "duration")
153
153
  end
154
154
 
155
- def bodies(own) = [own&.body, *@events&.map { |event| event[:data] }].grep(Hash)
155
+ def bodies(own) = [own&.body, *@events&.map { |event| event[:data] }, (result.try(:raw) if @final)].grep(Hash)
156
156
 
157
157
  def response_id(own) = bodies(own).filter_map { |body| body["id"] || body["responseId"] }.first
158
158