llm_cost_tracker 0.14.2 → 0.15.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/CHANGELOG.md +116 -0
- data/LICENSE.txt +28 -0
- data/README.md +33 -41
- data/app/controllers/llm_cost_tracker/application_controller.rb +7 -1
- data/app/controllers/llm_cost_tracker/calls_controller.rb +12 -94
- data/app/controllers/llm_cost_tracker/dashboard_controller.rb +11 -12
- data/app/controllers/llm_cost_tracker/pricing_controller.rb +15 -4
- data/app/controllers/llm_cost_tracker/tags_controller.rb +21 -14
- data/app/helpers/llm_cost_tracker/application_helper.rb +22 -31
- data/app/helpers/llm_cost_tracker/chart_helper.rb +57 -108
- data/app/helpers/llm_cost_tracker/dashboard_query_helper.rb +30 -17
- data/app/helpers/llm_cost_tracker/sortable_table_helper.rb +18 -25
- data/app/helpers/llm_cost_tracker/token_usage_helper.rb +30 -0
- data/app/models/llm_cost_tracker/call.rb +6 -4
- data/app/models/llm_cost_tracker/call_rollup.rb +6 -6
- data/app/services/llm_cost_tracker/dashboard/call_order.rb +36 -0
- data/app/services/llm_cost_tracker/dashboard/calls_export.rb +68 -0
- data/app/services/llm_cost_tracker/dashboard/data_quality/stats_query.rb +77 -0
- data/app/services/llm_cost_tracker/dashboard/data_quality/summary.rb +47 -0
- data/app/services/llm_cost_tracker/dashboard/data_quality.rb +66 -210
- data/app/services/llm_cost_tracker/dashboard/filter.rb +2 -1
- data/app/services/llm_cost_tracker/dashboard/monthly_budget.rb +42 -35
- data/app/services/llm_cost_tracker/dashboard/percent.rb +12 -0
- data/app/services/llm_cost_tracker/dashboard/sort.rb +9 -0
- data/app/services/llm_cost_tracker/dashboard/spend_anomaly.rb +19 -17
- data/app/services/llm_cost_tracker/dashboard/spend_chart.rb +50 -0
- data/app/services/llm_cost_tracker/dashboard/tag_breakdown.rb +7 -8
- data/app/services/llm_cost_tracker/dashboard/tag_key_explorer.rb +1 -4
- data/app/services/llm_cost_tracker/dashboard/top_models.rb +3 -4
- data/app/views/layouts/llm_cost_tracker/application.html.erb +6 -6
- data/app/views/llm_cost_tracker/calls/index.html.erb +2 -1
- data/app/views/llm_cost_tracker/calls/show.html.erb +3 -14
- data/app/views/llm_cost_tracker/errors/query.html.erb +6 -0
- data/app/views/llm_cost_tracker/shared/_filter_pill_stream.html.erb +1 -1
- data/app/views/llm_cost_tracker/tags/show.html.erb +1 -1
- data/lib/llm_cost_tracker/budget/estimate.rb +35 -0
- data/lib/llm_cost_tracker/budget/global.rb +69 -0
- data/lib/llm_cost_tracker/budget/limit.rb +52 -0
- data/lib/llm_cost_tracker/budget/per_tag.rb +59 -27
- data/lib/llm_cost_tracker/budget/tagged.rb +74 -0
- data/lib/llm_cost_tracker/budget.rb +19 -157
- data/lib/llm_cost_tracker/capture/event_window.rb +16 -13
- data/lib/llm_cost_tracker/capture/sdk_payload.rb +22 -17
- data/lib/llm_cost_tracker/capture/sse.rb +7 -5
- data/lib/llm_cost_tracker/capture/stream_collector.rb +89 -96
- data/lib/llm_cost_tracker/capture/stream_tap.rb +2 -2
- data/lib/llm_cost_tracker/capture/stream_tracker.rb +32 -37
- data/lib/llm_cost_tracker/capture_verifier.rb +2 -3
- data/lib/llm_cost_tracker/charges/cost_status.rb +23 -19
- data/lib/llm_cost_tracker/charges/line_item.rb +31 -33
- data/lib/llm_cost_tracker/configuration/budgets.rb +49 -18
- data/lib/llm_cost_tracker/configuration/capture.rb +7 -1
- data/lib/llm_cost_tracker/configuration/mutability.rb +3 -3
- data/lib/llm_cost_tracker/doctor/ingestion_check.rb +20 -2
- data/lib/llm_cost_tracker/doctor/price_check.rb +24 -35
- data/lib/llm_cost_tracker/doctor/probe.rb +1 -1
- data/lib/llm_cost_tracker/doctor.rb +23 -20
- data/lib/llm_cost_tracker/engine.rb +8 -0
- data/lib/llm_cost_tracker/errors.rb +2 -4
- data/lib/llm_cost_tracker/event.rb +22 -29
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/create_llm_cost_tracker_calls.rb.erb +4 -2
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/initializer.rb.erb +6 -4
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_call_rollups_provider.rb.erb +1 -0
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_call_tags_key_value_index.rb.erb +1 -0
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_indexes.rb.erb +2 -1
- data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_per_tag_budgets.rb.erb +1 -0
- data/lib/llm_cost_tracker/ingestion/batch.rb +33 -19
- data/lib/llm_cost_tracker/ingestion/inbox.rb +20 -11
- data/lib/llm_cost_tracker/ingestion/worker.rb +58 -37
- data/lib/llm_cost_tracker/ingestion.rb +20 -35
- data/lib/llm_cost_tracker/integrations/anthropic/batch_results_capture.rb +40 -0
- data/lib/llm_cost_tracker/integrations/anthropic/patches.rb +56 -0
- data/lib/llm_cost_tracker/integrations/anthropic.rb +59 -120
- data/lib/llm_cost_tracker/integrations/base/patch_target.rb +35 -0
- data/lib/llm_cost_tracker/integrations/base.rb +65 -81
- data/lib/llm_cost_tracker/integrations/openai/batch_capture.rb +20 -19
- data/lib/llm_cost_tracker/integrations/openai/patches.rb +51 -40
- data/lib/llm_cost_tracker/integrations/openai/websocket_capture.rb +89 -0
- data/lib/llm_cost_tracker/integrations/openai.rb +114 -83
- data/lib/llm_cost_tracker/integrations/ruby_llm/v1/patches.rb +67 -0
- data/lib/llm_cost_tracker/integrations/ruby_llm/v1/reply.rb +155 -0
- data/lib/llm_cost_tracker/integrations/ruby_llm/v1.rb +154 -0
- data/lib/llm_cost_tracker/integrations/ruby_llm/v2/attempt/token_counts.rb +159 -0
- data/lib/llm_cost_tracker/integrations/ruby_llm/v2/attempt.rb +175 -0
- data/lib/llm_cost_tracker/integrations/ruby_llm/v2/frame.rb +75 -0
- data/lib/llm_cost_tracker/integrations/ruby_llm/v2/recorder.rb +70 -0
- data/lib/llm_cost_tracker/integrations/ruby_llm/v2/seams.rb +86 -0
- data/lib/llm_cost_tracker/integrations/ruby_llm/v2.rb +161 -0
- data/lib/llm_cost_tracker/integrations/ruby_llm.rb +7 -408
- data/lib/llm_cost_tracker/ledger/isolation.rb +15 -2
- data/lib/llm_cost_tracker/ledger/period/totals.rb +1 -1
- data/lib/llm_cost_tracker/ledger/rollups.rb +24 -8
- data/lib/llm_cost_tracker/ledger/schema/adapter.rb +23 -6
- data/lib/llm_cost_tracker/ledger/schema/base.rb +9 -5
- data/lib/llm_cost_tracker/ledger/store.rb +17 -35
- data/lib/llm_cost_tracker/ledger/tags/breakdown.rb +2 -2
- data/lib/llm_cost_tracker/middleware/faraday/body.rb +57 -0
- data/lib/llm_cost_tracker/middleware/faraday/exchange.rb +153 -0
- data/lib/llm_cost_tracker/middleware/faraday/response_reader.rb +75 -0
- data/lib/llm_cost_tracker/middleware/faraday/stream_tee.rb +47 -0
- data/lib/llm_cost_tracker/middleware/faraday.rb +2 -301
- data/lib/llm_cost_tracker/parsers.rb +12 -0
- data/lib/llm_cost_tracker/prices.json +1179 -208
- data/lib/llm_cost_tracker/pricing/backfill.rb +59 -29
- data/lib/llm_cost_tracker/pricing/calculation/iterations.rb +49 -0
- data/lib/llm_cost_tracker/pricing/calculation/quantities.rb +40 -0
- data/lib/llm_cost_tracker/pricing/calculation/snapshot.rb +51 -0
- data/lib/llm_cost_tracker/pricing/calculation/totals.rb +59 -0
- data/lib/llm_cost_tracker/pricing/calculation.rb +82 -173
- data/lib/llm_cost_tracker/pricing/matcher.rb +31 -14
- data/lib/llm_cost_tracker/pricing/mode.rb +6 -19
- data/lib/llm_cost_tracker/pricing/off_peak.rb +50 -0
- data/lib/llm_cost_tracker/pricing/rate.rb +1 -0
- data/lib/llm_cost_tracker/pricing/registry/normalizer.rb +110 -0
- data/lib/llm_cost_tracker/pricing/registry.rb +38 -111
- data/lib/llm_cost_tracker/pricing/sync/change_printer.rb +40 -20
- data/lib/llm_cost_tracker/pricing/sync/fetcher.rb +35 -34
- data/lib/llm_cost_tracker/pricing/sync/registry_writer.rb +29 -18
- data/lib/llm_cost_tracker/pricing/sync/remote_snapshot.rb +78 -0
- data/lib/llm_cost_tracker/pricing/sync/snapshot_guard.rb +2 -0
- data/lib/llm_cost_tracker/pricing/sync.rb +7 -53
- data/lib/llm_cost_tracker/pricing/unknown.rb +1 -1
- data/lib/llm_cost_tracker/providers/anthropic/parser.rb +30 -25
- data/lib/llm_cost_tracker/providers/anthropic/response_parser.rb +5 -3
- data/lib/llm_cost_tracker/providers/anthropic/usage_extractor.rb +122 -101
- data/lib/llm_cost_tracker/providers/azure/hosts.rb +1 -1
- data/lib/llm_cost_tracker/providers/azure/parser.rb +3 -6
- data/lib/llm_cost_tracker/providers/gemini/grounding.rb +87 -0
- data/lib/llm_cost_tracker/providers/gemini/parser.rb +120 -183
- data/lib/llm_cost_tracker/providers/gemini/usage_extractor.rb +66 -47
- data/lib/llm_cost_tracker/providers/openai/hosts.rb +11 -0
- data/lib/llm_cost_tracker/providers/openai/model_families.rb +1 -1
- data/lib/llm_cost_tracker/providers/openai/output_item.rb +84 -0
- data/lib/llm_cost_tracker/providers/openai/parser.rb +2 -1
- data/lib/llm_cost_tracker/providers/openai/response_parser.rb +81 -149
- data/lib/llm_cost_tracker/providers/openai/service_charges.rb +133 -156
- data/lib/llm_cost_tracker/providers/openai/stream_parser.rb +127 -0
- data/lib/llm_cost_tracker/providers/openai/usage_extractor.rb +72 -62
- data/lib/llm_cost_tracker/providers/openai_compatible/parser.rb +15 -4
- data/lib/llm_cost_tracker/providers.rb +3 -0
- data/lib/llm_cost_tracker/redaction.rb +13 -0
- data/lib/llm_cost_tracker/report/data.rb +25 -28
- data/lib/llm_cost_tracker/tags/context.rb +22 -7
- data/lib/llm_cost_tracker/tracker.rb +32 -26
- data/lib/llm_cost_tracker/usage/dimensions.yml +24 -0
- data/lib/llm_cost_tracker/usage/token_usage.rb +8 -4
- data/lib/llm_cost_tracker/version.rb +1 -1
- data/lib/llm_cost_tracker.rb +8 -4
- data/lib/tasks/llm_cost_tracker.rake +35 -5
- data/llm_cost_tracker.gemspec +6 -5
- metadata +58 -5
data/lib/llm_cost_tracker.rb
CHANGED
|
@@ -128,12 +128,16 @@ module LlmCostTracker
|
|
|
128
128
|
pricing_mode: pricing_mode,
|
|
129
129
|
metadata: tags
|
|
130
130
|
)
|
|
131
|
+
completed = false
|
|
131
132
|
yield collector
|
|
132
|
-
|
|
133
|
-
collector&.finish!(errored: true)
|
|
134
|
-
raise
|
|
135
|
-
else
|
|
133
|
+
completed = true
|
|
136
134
|
collector.finish!
|
|
135
|
+
rescue Exception # rubocop:disable Lint/RescueException
|
|
136
|
+
collector&.finish!(errored: true) unless completed
|
|
137
|
+
completed = true
|
|
138
|
+
raise
|
|
139
|
+
ensure
|
|
140
|
+
collector&.finish! unless completed
|
|
137
141
|
end
|
|
138
142
|
end
|
|
139
143
|
end
|
|
@@ -12,6 +12,34 @@ module LlmCostTrackerTasks
|
|
|
12
12
|
FileUtils.mkdir_p(File.dirname(path))
|
|
13
13
|
path
|
|
14
14
|
end
|
|
15
|
+
|
|
16
|
+
def self.batch_size(default)
|
|
17
|
+
text = ENV.fetch("BATCH_SIZE", default.to_s)
|
|
18
|
+
size = Integer(text, 10, exception: false)
|
|
19
|
+
return size if size&.positive?
|
|
20
|
+
|
|
21
|
+
abort("llm_cost_tracker: BATCH_SIZE=#{text} is not a positive integer, e.g. BATCH_SIZE=#{default}")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.backfill_after_refresh(path)
|
|
25
|
+
file = LlmCostTracker.configuration.pricing.file
|
|
26
|
+
return unless file && File.expand_path(file) == File.expand_path(path)
|
|
27
|
+
|
|
28
|
+
if ledger_reachable?
|
|
29
|
+
Rake::Task["llm_cost_tracker:backfill_unknown_pricing"].execute
|
|
30
|
+
else
|
|
31
|
+
puts "llm_cost_tracker: calls ledger not reachable; " \
|
|
32
|
+
"run bin/rails llm_cost_tracker:backfill_unknown_pricing where it is"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.ledger_reachable?
|
|
37
|
+
return false unless Rake::Task.task_defined?("environment")
|
|
38
|
+
|
|
39
|
+
LlmCostTracker::Call.with_connection { |connection| connection.table_exists?(LlmCostTracker::Call.table_name) }
|
|
40
|
+
rescue ActiveRecord::NoDatabaseError, ActiveRecord::ConnectionNotEstablished
|
|
41
|
+
false
|
|
42
|
+
end
|
|
15
43
|
end
|
|
16
44
|
|
|
17
45
|
# rubocop:disable-next Metrics/BlockLength
|
|
@@ -58,7 +86,7 @@ namespace :llm_cost_tracker do
|
|
|
58
86
|
"Use BATCH_SIZE=N to tune."
|
|
59
87
|
task backfill_unknown_pricing: :environment do
|
|
60
88
|
require_relative "../llm_cost_tracker/pricing/backfill"
|
|
61
|
-
batch_size = (
|
|
89
|
+
batch_size = LlmCostTrackerTasks.batch_size(LlmCostTracker::Pricing::Backfill::DEFAULT_BATCH_SIZE)
|
|
62
90
|
result = LlmCostTracker::Pricing::Backfill.call(batch_size: batch_size)
|
|
63
91
|
puts "llm_cost_tracker: examined #{result.examined} calls, recomputed #{result.recomputed}, " \
|
|
64
92
|
"still unknown #{result.still_unknown}"
|
|
@@ -73,7 +101,7 @@ namespace :llm_cost_tracker do
|
|
|
73
101
|
to_text = ENV["TO"].presence
|
|
74
102
|
to = to_text && Time.zone.parse(to_text)
|
|
75
103
|
abort("llm_cost_tracker: TO=#{to_text} is not a date, e.g. TO=2026-10-01") if to_text && !to
|
|
76
|
-
batch_size = (
|
|
104
|
+
batch_size = LlmCostTrackerTasks.batch_size(LlmCostTracker::Pricing::Backfill::DEFAULT_BATCH_SIZE)
|
|
77
105
|
scope = LlmCostTracker::Pricing::Backfill.reprice_scope(from...to)
|
|
78
106
|
result = LlmCostTracker::Pricing::Backfill.call(scope: scope, batch_size: batch_size, reprice: true)
|
|
79
107
|
puts "llm_cost_tracker: examined #{result.examined} calls, repriced #{result.recomputed}"
|
|
@@ -82,7 +110,7 @@ namespace :llm_cost_tracker do
|
|
|
82
110
|
desc "Delete llm_cost_tracker_calls and ingestion inbox rows older than DAYS (default: 90). Use BATCH_SIZE=N to tune."
|
|
83
111
|
task prune: :environment do
|
|
84
112
|
days = (ENV["DAYS"] || 90).to_i
|
|
85
|
-
batch_size = (
|
|
113
|
+
batch_size = LlmCostTrackerTasks.batch_size(LlmCostTracker::Retention::DEFAULT_BATCH_SIZE)
|
|
86
114
|
deleted = LlmCostTracker::Retention.prune(older_than: days, batch_size: batch_size)
|
|
87
115
|
puts "llm_cost_tracker: pruned #{deleted} calls older than #{days} days"
|
|
88
116
|
inbox_pruned = LlmCostTracker::Retention.prune_inbox(older_than: days)
|
|
@@ -105,14 +133,15 @@ namespace :llm_cost_tracker do
|
|
|
105
133
|
abort("llm_cost_tracker: llm_cost_tracker_call_tags is missing the cost columns; " \
|
|
106
134
|
"run the upgrade_per_tag_budgets generator and migrate first")
|
|
107
135
|
end
|
|
108
|
-
batch_size = (
|
|
136
|
+
batch_size = LlmCostTrackerTasks.batch_size(LlmCostTracker::Budget::PerTag::DEFAULT_BACKFILL_BATCH)
|
|
109
137
|
filled = LlmCostTracker::Budget::PerTag.backfill(batch_size: batch_size)
|
|
110
138
|
puts "llm_cost_tracker: filled cost and time on #{filled} tag rows"
|
|
111
139
|
end
|
|
112
140
|
|
|
113
141
|
namespace :prices do
|
|
114
142
|
desc(
|
|
115
|
-
"Refresh the configured pricing file from the maintained LLM Cost Tracker price snapshot
|
|
143
|
+
"Refresh the configured pricing file from the maintained LLM Cost Tracker price snapshot; after writing a new " \
|
|
144
|
+
"config.pricing.file, run llm_cost_tracker:backfill_unknown_pricing if the calls ledger is reachable. " \
|
|
116
145
|
"Review changes first with llm_cost_tracker:prices:check. Use FORCE=1 to accept suspicious price changes, " \
|
|
117
146
|
"URL=... to override the source, or OUTPUT=path/to/file.json."
|
|
118
147
|
)
|
|
@@ -130,6 +159,7 @@ namespace :llm_cost_tracker do
|
|
|
130
159
|
puts " source: #{result.source_url}"
|
|
131
160
|
puts " version: #{result.source_version.inspect}" if result.source_version
|
|
132
161
|
LlmCostTracker::Pricing::Sync::ChangePrinter.call(result.changes, suspicious: result.suspicious)
|
|
162
|
+
LlmCostTrackerTasks.backfill_after_refresh(result.path) if result.written
|
|
133
163
|
end
|
|
134
164
|
|
|
135
165
|
desc "Compare the current pricing file with the maintained LLM Cost Tracker price snapshot."
|
data/llm_cost_tracker.gemspec
CHANGED
|
@@ -8,11 +8,11 @@ Gem::Specification.new do |spec|
|
|
|
8
8
|
spec.authors = ["Sergii Khomenko"]
|
|
9
9
|
spec.email = ["sergey@mm.st"]
|
|
10
10
|
|
|
11
|
-
spec.summary = "LLM
|
|
12
|
-
spec.description = "
|
|
13
|
-
"or
|
|
14
|
-
"
|
|
15
|
-
"
|
|
11
|
+
spec.summary = "LLM spend tracking and budgets for Rails, in your own database"
|
|
12
|
+
spec.description = "Records every LLM call your Rails app makes through RubyLLM, the official OpenAI " \
|
|
13
|
+
"and Anthropic SDKs, Faraday, or any OpenAI-compatible API: tokens and cost, attributed " \
|
|
14
|
+
"by user, feature, or any tag. Calls go straight to the provider — no proxy. " \
|
|
15
|
+
"Includes budgets that can block the next call, bundled prices, and a dashboard."
|
|
16
16
|
spec.homepage = "https://github.com/sergey-homenko/llm_cost_tracker"
|
|
17
17
|
spec.license = "MIT"
|
|
18
18
|
|
|
@@ -50,6 +50,7 @@ Gem::Specification.new do |spec|
|
|
|
50
50
|
spec.add_dependency "railties", ">= 8.0", "< 9.0"
|
|
51
51
|
|
|
52
52
|
spec.add_development_dependency "anthropic", "~> 1.61"
|
|
53
|
+
spec.add_development_dependency "aws-eventstream", "~> 1.4"
|
|
53
54
|
spec.add_development_dependency "nokogiri", "~> 1.19"
|
|
54
55
|
spec.add_development_dependency "openai", "~> 0.80"
|
|
55
56
|
spec.add_development_dependency "pg", "~> 1.6"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: llm_cost_tracker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.15.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sergii Khomenko
|
|
@@ -117,6 +117,20 @@ dependencies:
|
|
|
117
117
|
- - "~>"
|
|
118
118
|
- !ruby/object:Gem::Version
|
|
119
119
|
version: '1.61'
|
|
120
|
+
- !ruby/object:Gem::Dependency
|
|
121
|
+
name: aws-eventstream
|
|
122
|
+
requirement: !ruby/object:Gem::Requirement
|
|
123
|
+
requirements:
|
|
124
|
+
- - "~>"
|
|
125
|
+
- !ruby/object:Gem::Version
|
|
126
|
+
version: '1.4'
|
|
127
|
+
type: :development
|
|
128
|
+
prerelease: false
|
|
129
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
130
|
+
requirements:
|
|
131
|
+
- - "~>"
|
|
132
|
+
- !ruby/object:Gem::Version
|
|
133
|
+
version: '1.4'
|
|
120
134
|
- !ruby/object:Gem::Dependency
|
|
121
135
|
name: nokogiri
|
|
122
136
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -263,9 +277,10 @@ dependencies:
|
|
|
263
277
|
- - "~>"
|
|
264
278
|
- !ruby/object:Gem::Version
|
|
265
279
|
version: '3.0'
|
|
266
|
-
description: '
|
|
267
|
-
or
|
|
268
|
-
|
|
280
|
+
description: 'Records every LLM call your Rails app makes through RubyLLM, the official
|
|
281
|
+
OpenAI and Anthropic SDKs, Faraday, or any OpenAI-compatible API: tokens and cost,
|
|
282
|
+
attributed by user, feature, or any tag. Calls go straight to the provider — no
|
|
283
|
+
proxy. Includes budgets that can block the next call, bundled prices, and a dashboard.'
|
|
269
284
|
email:
|
|
270
285
|
- sergey@mm.st
|
|
271
286
|
executables: []
|
|
@@ -303,7 +318,11 @@ files:
|
|
|
303
318
|
- app/models/llm_cost_tracker/call_tag.rb
|
|
304
319
|
- app/models/llm_cost_tracker/ingestion/inbox_entry.rb
|
|
305
320
|
- app/models/llm_cost_tracker/ingestion/lease.rb
|
|
321
|
+
- app/services/llm_cost_tracker/dashboard/call_order.rb
|
|
322
|
+
- app/services/llm_cost_tracker/dashboard/calls_export.rb
|
|
306
323
|
- app/services/llm_cost_tracker/dashboard/data_quality.rb
|
|
324
|
+
- app/services/llm_cost_tracker/dashboard/data_quality/stats_query.rb
|
|
325
|
+
- app/services/llm_cost_tracker/dashboard/data_quality/summary.rb
|
|
307
326
|
- app/services/llm_cost_tracker/dashboard/date_range.rb
|
|
308
327
|
- app/services/llm_cost_tracker/dashboard/filter.rb
|
|
309
328
|
- app/services/llm_cost_tracker/dashboard/masking.rb
|
|
@@ -311,11 +330,13 @@ files:
|
|
|
311
330
|
- app/services/llm_cost_tracker/dashboard/overview_stats.rb
|
|
312
331
|
- app/services/llm_cost_tracker/dashboard/pagination.rb
|
|
313
332
|
- app/services/llm_cost_tracker/dashboard/params.rb
|
|
333
|
+
- app/services/llm_cost_tracker/dashboard/percent.rb
|
|
314
334
|
- app/services/llm_cost_tracker/dashboard/pricing_overview.rb
|
|
315
335
|
- app/services/llm_cost_tracker/dashboard/provider_breakdown.rb
|
|
316
336
|
- app/services/llm_cost_tracker/dashboard/setup_state.rb
|
|
317
337
|
- app/services/llm_cost_tracker/dashboard/sort.rb
|
|
318
338
|
- app/services/llm_cost_tracker/dashboard/spend_anomaly.rb
|
|
339
|
+
- app/services/llm_cost_tracker/dashboard/spend_chart.rb
|
|
319
340
|
- app/services/llm_cost_tracker/dashboard/tag_breakdown.rb
|
|
320
341
|
- app/services/llm_cost_tracker/dashboard/tag_key_explorer.rb
|
|
321
342
|
- app/services/llm_cost_tracker/dashboard/time_series.rb
|
|
@@ -328,6 +349,7 @@ files:
|
|
|
328
349
|
- app/views/llm_cost_tracker/errors/database.html.erb
|
|
329
350
|
- app/views/llm_cost_tracker/errors/invalid_filter.html.erb
|
|
330
351
|
- app/views/llm_cost_tracker/errors/not_found.html.erb
|
|
352
|
+
- app/views/llm_cost_tracker/errors/query.html.erb
|
|
331
353
|
- app/views/llm_cost_tracker/models/index.html.erb
|
|
332
354
|
- app/views/llm_cost_tracker/pricing/index.html.erb
|
|
333
355
|
- app/views/llm_cost_tracker/shared/_bar.html.erb
|
|
@@ -345,7 +367,11 @@ files:
|
|
|
345
367
|
- lib/llm_cost_tracker.rb
|
|
346
368
|
- lib/llm_cost_tracker/assets.rb
|
|
347
369
|
- lib/llm_cost_tracker/budget.rb
|
|
370
|
+
- lib/llm_cost_tracker/budget/estimate.rb
|
|
371
|
+
- lib/llm_cost_tracker/budget/global.rb
|
|
372
|
+
- lib/llm_cost_tracker/budget/limit.rb
|
|
348
373
|
- lib/llm_cost_tracker/budget/per_tag.rb
|
|
374
|
+
- lib/llm_cost_tracker/budget/tagged.rb
|
|
349
375
|
- lib/llm_cost_tracker/capture/event_window.rb
|
|
350
376
|
- lib/llm_cost_tracker/capture/sdk_payload.rb
|
|
351
377
|
- lib/llm_cost_tracker/capture/sse.rb
|
|
@@ -401,11 +427,24 @@ files:
|
|
|
401
427
|
- lib/llm_cost_tracker/ingestion/worker.rb
|
|
402
428
|
- lib/llm_cost_tracker/integrations.rb
|
|
403
429
|
- lib/llm_cost_tracker/integrations/anthropic.rb
|
|
430
|
+
- lib/llm_cost_tracker/integrations/anthropic/batch_results_capture.rb
|
|
431
|
+
- lib/llm_cost_tracker/integrations/anthropic/patches.rb
|
|
404
432
|
- lib/llm_cost_tracker/integrations/base.rb
|
|
433
|
+
- lib/llm_cost_tracker/integrations/base/patch_target.rb
|
|
405
434
|
- lib/llm_cost_tracker/integrations/openai.rb
|
|
406
435
|
- lib/llm_cost_tracker/integrations/openai/batch_capture.rb
|
|
407
436
|
- lib/llm_cost_tracker/integrations/openai/patches.rb
|
|
437
|
+
- lib/llm_cost_tracker/integrations/openai/websocket_capture.rb
|
|
408
438
|
- lib/llm_cost_tracker/integrations/ruby_llm.rb
|
|
439
|
+
- lib/llm_cost_tracker/integrations/ruby_llm/v1.rb
|
|
440
|
+
- lib/llm_cost_tracker/integrations/ruby_llm/v1/patches.rb
|
|
441
|
+
- lib/llm_cost_tracker/integrations/ruby_llm/v1/reply.rb
|
|
442
|
+
- lib/llm_cost_tracker/integrations/ruby_llm/v2.rb
|
|
443
|
+
- lib/llm_cost_tracker/integrations/ruby_llm/v2/attempt.rb
|
|
444
|
+
- lib/llm_cost_tracker/integrations/ruby_llm/v2/attempt/token_counts.rb
|
|
445
|
+
- lib/llm_cost_tracker/integrations/ruby_llm/v2/frame.rb
|
|
446
|
+
- lib/llm_cost_tracker/integrations/ruby_llm/v2/recorder.rb
|
|
447
|
+
- lib/llm_cost_tracker/integrations/ruby_llm/v2/seams.rb
|
|
409
448
|
- lib/llm_cost_tracker/ledger.rb
|
|
410
449
|
- lib/llm_cost_tracker/ledger/isolation.rb
|
|
411
450
|
- lib/llm_cost_tracker/ledger/period.rb
|
|
@@ -427,18 +466,28 @@ files:
|
|
|
427
466
|
- lib/llm_cost_tracker/ledger/tags/query.rb
|
|
428
467
|
- lib/llm_cost_tracker/logging.rb
|
|
429
468
|
- lib/llm_cost_tracker/middleware/faraday.rb
|
|
469
|
+
- lib/llm_cost_tracker/middleware/faraday/body.rb
|
|
470
|
+
- lib/llm_cost_tracker/middleware/faraday/exchange.rb
|
|
471
|
+
- lib/llm_cost_tracker/middleware/faraday/response_reader.rb
|
|
472
|
+
- lib/llm_cost_tracker/middleware/faraday/stream_tee.rb
|
|
430
473
|
- lib/llm_cost_tracker/parsers.rb
|
|
431
474
|
- lib/llm_cost_tracker/prices.json
|
|
432
475
|
- lib/llm_cost_tracker/pricing.rb
|
|
433
476
|
- lib/llm_cost_tracker/pricing/backfill.rb
|
|
434
477
|
- lib/llm_cost_tracker/pricing/calculation.rb
|
|
478
|
+
- lib/llm_cost_tracker/pricing/calculation/iterations.rb
|
|
479
|
+
- lib/llm_cost_tracker/pricing/calculation/quantities.rb
|
|
480
|
+
- lib/llm_cost_tracker/pricing/calculation/snapshot.rb
|
|
481
|
+
- lib/llm_cost_tracker/pricing/calculation/totals.rb
|
|
435
482
|
- lib/llm_cost_tracker/pricing/effective_prices.rb
|
|
436
483
|
- lib/llm_cost_tracker/pricing/estimator.rb
|
|
437
484
|
- lib/llm_cost_tracker/pricing/matcher.rb
|
|
438
485
|
- lib/llm_cost_tracker/pricing/mode.rb
|
|
486
|
+
- lib/llm_cost_tracker/pricing/off_peak.rb
|
|
439
487
|
- lib/llm_cost_tracker/pricing/price_key.rb
|
|
440
488
|
- lib/llm_cost_tracker/pricing/rate.rb
|
|
441
489
|
- lib/llm_cost_tracker/pricing/registry.rb
|
|
490
|
+
- lib/llm_cost_tracker/pricing/registry/normalizer.rb
|
|
442
491
|
- lib/llm_cost_tracker/pricing/service_rates.rb
|
|
443
492
|
- lib/llm_cost_tracker/pricing/source.rb
|
|
444
493
|
- lib/llm_cost_tracker/pricing/sync.rb
|
|
@@ -446,6 +495,7 @@ files:
|
|
|
446
495
|
- lib/llm_cost_tracker/pricing/sync/fetcher.rb
|
|
447
496
|
- lib/llm_cost_tracker/pricing/sync/registry_diff.rb
|
|
448
497
|
- lib/llm_cost_tracker/pricing/sync/registry_writer.rb
|
|
498
|
+
- lib/llm_cost_tracker/pricing/sync/remote_snapshot.rb
|
|
449
499
|
- lib/llm_cost_tracker/pricing/sync/snapshot_guard.rb
|
|
450
500
|
- lib/llm_cost_tracker/pricing/unknown.rb
|
|
451
501
|
- lib/llm_cost_tracker/providers.rb
|
|
@@ -454,14 +504,17 @@ files:
|
|
|
454
504
|
- lib/llm_cost_tracker/providers/anthropic/usage_extractor.rb
|
|
455
505
|
- lib/llm_cost_tracker/providers/azure/hosts.rb
|
|
456
506
|
- lib/llm_cost_tracker/providers/azure/parser.rb
|
|
507
|
+
- lib/llm_cost_tracker/providers/gemini/grounding.rb
|
|
457
508
|
- lib/llm_cost_tracker/providers/gemini/model_families.rb
|
|
458
509
|
- lib/llm_cost_tracker/providers/gemini/parser.rb
|
|
459
510
|
- lib/llm_cost_tracker/providers/gemini/usage_extractor.rb
|
|
460
511
|
- lib/llm_cost_tracker/providers/openai/hosts.rb
|
|
461
512
|
- lib/llm_cost_tracker/providers/openai/model_families.rb
|
|
513
|
+
- lib/llm_cost_tracker/providers/openai/output_item.rb
|
|
462
514
|
- lib/llm_cost_tracker/providers/openai/parser.rb
|
|
463
515
|
- lib/llm_cost_tracker/providers/openai/response_parser.rb
|
|
464
516
|
- lib/llm_cost_tracker/providers/openai/service_charges.rb
|
|
517
|
+
- lib/llm_cost_tracker/providers/openai/stream_parser.rb
|
|
465
518
|
- lib/llm_cost_tracker/providers/openai/usage_extractor.rb
|
|
466
519
|
- lib/llm_cost_tracker/providers/openai_compatible/parser.rb
|
|
467
520
|
- lib/llm_cost_tracker/railtie.rb
|
|
@@ -508,5 +561,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
508
561
|
requirements: []
|
|
509
562
|
rubygems_version: 3.6.9
|
|
510
563
|
specification_version: 4
|
|
511
|
-
summary: LLM
|
|
564
|
+
summary: LLM spend tracking and budgets for Rails, in your own database
|
|
512
565
|
test_files: []
|