runcost-ai 0.1.1__tar.gz
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.
- runcost_ai-0.1.1/LICENSE +21 -0
- runcost_ai-0.1.1/PKG-INFO +286 -0
- runcost_ai-0.1.1/README.md +263 -0
- runcost_ai-0.1.1/packages/python/runcost/__init__.py +169 -0
- runcost_ai-0.1.1/packages/python/runcost/cli.py +175 -0
- runcost_ai-0.1.1/packages/python/runcost/core.py +3526 -0
- runcost_ai-0.1.1/packages/python/runcost/generated/__init__.py +2 -0
- runcost_ai-0.1.1/packages/python/runcost/generated/taxonomy.py +202 -0
- runcost_ai-0.1.1/packages/python/runcost/types.py +306 -0
- runcost_ai-0.1.1/packages/python/runcost_ai.egg-info/PKG-INFO +286 -0
- runcost_ai-0.1.1/packages/python/runcost_ai.egg-info/SOURCES.txt +15 -0
- runcost_ai-0.1.1/packages/python/runcost_ai.egg-info/dependency_links.txt +1 -0
- runcost_ai-0.1.1/packages/python/runcost_ai.egg-info/entry_points.txt +2 -0
- runcost_ai-0.1.1/packages/python/runcost_ai.egg-info/requires.txt +4 -0
- runcost_ai-0.1.1/packages/python/runcost_ai.egg-info/top_level.txt +1 -0
- runcost_ai-0.1.1/pyproject.toml +38 -0
- runcost_ai-0.1.1/setup.cfg +4 -0
runcost_ai-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Adam Allcock
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: runcost-ai
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Alpha cost ledger utility for LLM and agent API responses.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/adamallcock/runcost
|
|
7
|
+
Project-URL: Repository, https://github.com/adamallcock/runcost
|
|
8
|
+
Project-URL: Issues, https://github.com/adamallcock/runcost/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/adamallcock/runcost/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: llm,ai,pricing,tokens,cost,agents,openai,anthropic,usage
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Provides-Extra: smoke
|
|
20
|
+
Requires-Dist: langchain-core; extra == "smoke"
|
|
21
|
+
Requires-Dist: langchain-openai; extra == "smoke"
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# RunCost
|
|
25
|
+
|
|
26
|
+
RunCost is a small alpha utility for answering one question:
|
|
27
|
+
|
|
28
|
+
> What did this LLM or agent API call cost, and why?
|
|
29
|
+
|
|
30
|
+
It turns provider responses, framework usage objects, or normalized usage into a
|
|
31
|
+
componentized cost ledger with input, cached input, output, reasoning, tool
|
|
32
|
+
units, discounts, price sources, and warnings.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
Current alpha install paths:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Python from the repo
|
|
40
|
+
python3 -m pip install git+https://github.com/adamallcock/runcost.git
|
|
41
|
+
|
|
42
|
+
# JavaScript/TypeScript from a checkout
|
|
43
|
+
npm pack ./packages/javascript/core
|
|
44
|
+
npm install ./runcost-0.1.1.tgz
|
|
45
|
+
|
|
46
|
+
# Go
|
|
47
|
+
go get github.com/adamallcock/runcost/packages/go/ledger
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
First registry release commands, once publishing is enabled:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install runcost-ai
|
|
54
|
+
npm install runcost
|
|
55
|
+
go get github.com/adamallcock/runcost/packages/go/ledger
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The Python distribution name is `runcost-ai`; the import package and CLI are
|
|
59
|
+
`runcost`.
|
|
60
|
+
|
|
61
|
+
## One-Minute Examples
|
|
62
|
+
|
|
63
|
+
Python:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from runcost import from_response
|
|
67
|
+
|
|
68
|
+
response = {
|
|
69
|
+
"model": "gpt-4.1-mini-2025-04-14",
|
|
70
|
+
"usage": {
|
|
71
|
+
"input_tokens": 36,
|
|
72
|
+
"input_tokens_details": {"cached_tokens": 6},
|
|
73
|
+
"output_tokens": 87,
|
|
74
|
+
"output_tokens_details": {"reasoning_tokens": 12},
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
price_cards = [{
|
|
79
|
+
"schema_version": "0.1",
|
|
80
|
+
"id": "openai:gpt-4.1-mini:example",
|
|
81
|
+
"provider": "openai",
|
|
82
|
+
"surface": "openai.responses",
|
|
83
|
+
"model": "gpt-4.1-mini",
|
|
84
|
+
"aliases": ["gpt-4.1-mini-2025-04-14"],
|
|
85
|
+
"components": [
|
|
86
|
+
{"usage_component": "input_uncached_tokens", "unit": "token", "price": {"amount": "0.40", "currency": "USD", "per": "1000000"}},
|
|
87
|
+
{"usage_component": "input_cache_read_tokens", "unit": "token", "price": {"amount": "0.10", "currency": "USD", "per": "1000000"}},
|
|
88
|
+
{"usage_component": "output_text_tokens", "unit": "token", "price": {"amount": "1.60", "currency": "USD", "per": "1000000"}},
|
|
89
|
+
{"usage_component": "output_reasoning_tokens", "unit": "token", "price": {"amount": "1.60", "currency": "USD", "per": "1000000"}},
|
|
90
|
+
],
|
|
91
|
+
"source": {"name": "example"},
|
|
92
|
+
}]
|
|
93
|
+
|
|
94
|
+
ledger = from_response(
|
|
95
|
+
response,
|
|
96
|
+
provider="openai",
|
|
97
|
+
surface="openai.responses",
|
|
98
|
+
model="gpt-4.1-mini",
|
|
99
|
+
price_cards=price_cards,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
print(ledger["total"])
|
|
103
|
+
print(ledger["components"])
|
|
104
|
+
print(ledger["warnings"])
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
TypeScript:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { fromResponse } from "runcost";
|
|
111
|
+
|
|
112
|
+
// Using the same response and priceCards shape as the Python example above.
|
|
113
|
+
const ledger = fromResponse(response, {
|
|
114
|
+
provider: "openai",
|
|
115
|
+
surface: "openai.responses",
|
|
116
|
+
model: "gpt-4.1-mini",
|
|
117
|
+
priceCards
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
console.log(ledger.total);
|
|
121
|
+
console.log(ledger.components);
|
|
122
|
+
console.log(ledger.warnings);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Go:
|
|
126
|
+
|
|
127
|
+
```go
|
|
128
|
+
package main
|
|
129
|
+
|
|
130
|
+
import (
|
|
131
|
+
"fmt"
|
|
132
|
+
|
|
133
|
+
ledger "github.com/adamallcock/runcost/packages/go/ledger"
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
func main() {
|
|
137
|
+
cost := ledger.FromResponse(
|
|
138
|
+
ledger.Object{
|
|
139
|
+
"model": "gpt-4.1-mini-2025-04-14",
|
|
140
|
+
"usage": ledger.Object{
|
|
141
|
+
"input_tokens": 36,
|
|
142
|
+
"output_tokens": 87,
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
ledger.Object{
|
|
146
|
+
"provider": "openai",
|
|
147
|
+
"surface": "openai.responses",
|
|
148
|
+
"model": "gpt-4.1-mini",
|
|
149
|
+
"price_cards": []any{
|
|
150
|
+
ledger.Object{
|
|
151
|
+
"schema_version": "0.1",
|
|
152
|
+
"id": "openai:gpt-4.1-mini:example",
|
|
153
|
+
"provider": "openai",
|
|
154
|
+
"surface": "openai.responses",
|
|
155
|
+
"model": "gpt-4.1-mini",
|
|
156
|
+
"aliases": []any{"gpt-4.1-mini-2025-04-14"},
|
|
157
|
+
"components": []any{
|
|
158
|
+
ledger.Object{
|
|
159
|
+
"usage_component": "input_uncached_tokens",
|
|
160
|
+
"unit": "token",
|
|
161
|
+
"price": ledger.Object{"amount": "0.40", "currency": "USD", "per": "1000000"},
|
|
162
|
+
},
|
|
163
|
+
ledger.Object{
|
|
164
|
+
"usage_component": "output_text_tokens",
|
|
165
|
+
"unit": "token",
|
|
166
|
+
"price": ledger.Object{"amount": "1.60", "currency": "USD", "per": "1000000"},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
"source": ledger.Object{"name": "example"},
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
fmt.Println(cost["total"])
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Already have normalized usage? Use the deterministic calculator directly:
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
from runcost import calculate_cost
|
|
183
|
+
|
|
184
|
+
ledger = calculate_cost(
|
|
185
|
+
usage_ledger={
|
|
186
|
+
"schema_version": "0.1",
|
|
187
|
+
"provider": "openai",
|
|
188
|
+
"surface": "openai.responses",
|
|
189
|
+
"model": {"requested": "gpt-4.1-mini"},
|
|
190
|
+
"components": [
|
|
191
|
+
{"name": "input_uncached_tokens", "quantity": "30", "unit": "token"},
|
|
192
|
+
{"name": "output_text_tokens", "quantity": "75", "unit": "token"},
|
|
193
|
+
],
|
|
194
|
+
},
|
|
195
|
+
price_cards=price_cards,
|
|
196
|
+
)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Main APIs
|
|
200
|
+
|
|
201
|
+
| Job | Python | JavaScript/TypeScript | Go |
|
|
202
|
+
|---|---|---|---|
|
|
203
|
+
| Price normalized usage | `calculate_cost(...)` | `calculateCost(options)` | `CalculateCost(options)` |
|
|
204
|
+
| Price a provider response | `from_response(...)` | `fromResponse(response, options)` | `FromResponse(response, options)` |
|
|
205
|
+
| Aggregate call ledgers | `aggregate_cost_ledgers(...)` | `aggregateCostLedgers(options)` | `AggregateCostLedgers(...)` |
|
|
206
|
+
| Use framework outputs | `from_langsmith_run(...)`, `track_langchain_costs(...)`, and more | `fromVercelAISDKStreamFinish(...)`, `createRunCostVercelOnFinish(...)`, and more | `FromLangSmithRun(...)`, `FromSemanticKernelTelemetry(...)`, and more |
|
|
207
|
+
| Load price sources | `price_cards_from_json_file(...)`, `price_cards_from_openrouter_models(...)` | `priceCardsFromJSONFile(...)`, `priceCardsFromOpenRouterModels(...)` | `PriceCardsFromJSONFile(...)`, `PriceCardsFromOpenRouterModels(...)` |
|
|
208
|
+
| Add custom prices | Pass `price_cards` | Pass `priceCards` | Pass `price_cards` in options |
|
|
209
|
+
| Apply discounts | Pass `discount_policies` | Pass `discountPolicies` | Pass `discount_policies` in options |
|
|
210
|
+
| Audit decisions | `debug_trace=True` | `debugTrace: true` | `"debug_trace": true` |
|
|
211
|
+
| Fail on ambiguity | `mode="strict"` | `mode: "strict"` | `mode: "strict"` |
|
|
212
|
+
| CLI checks | `runcost price-cards`, `runcost fixture-check` | N/A | N/A |
|
|
213
|
+
|
|
214
|
+
## Supported Inputs
|
|
215
|
+
|
|
216
|
+
Fixture-backed surfaces include OpenAI Responses and Chat Completions, Anthropic
|
|
217
|
+
Messages, OpenRouter, Gemini and Vertex `generateContent`, AWS Bedrock Converse,
|
|
218
|
+
Cohere Chat and Rerank, OpenAI-compatible providers such as Groq, xAI, Mistral,
|
|
219
|
+
DeepSeek, Azure OpenAI, and Hugging Face Inference Providers, plus selected
|
|
220
|
+
framework objects from LangChain, Vercel AI SDK, OpenAI Agents SDK, LlamaIndex,
|
|
221
|
+
Haystack, LiteLLM, AutoGen/AG2, LangSmith, Semantic Kernel, and OpenRouter SDK
|
|
222
|
+
paths.
|
|
223
|
+
|
|
224
|
+
See [supported surfaces](docs/reference/supported-surfaces.md) for the current
|
|
225
|
+
matrix.
|
|
226
|
+
|
|
227
|
+
## Custom Prices And Discounts
|
|
228
|
+
|
|
229
|
+
RunCost treats provider pricing as data. You can pass user price cards for
|
|
230
|
+
private rates, exact aliases, service tiers, long-context prices, historical
|
|
231
|
+
effective dates, tool units, or internal billing units.
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
discounts = [{
|
|
235
|
+
"schema_version": "0.1",
|
|
236
|
+
"id": "openai-contract-4pct",
|
|
237
|
+
"match": {"provider": "openai"},
|
|
238
|
+
"adjustment": {"type": "percentage_discount", "value": "4"},
|
|
239
|
+
}]
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The returned ledger records selected price sources, applied discounts, and any
|
|
243
|
+
warning that prevents the total from being fully explained.
|
|
244
|
+
|
|
245
|
+
Fixtures are behavioral conformance tests, not a complete model-price database.
|
|
246
|
+
Use source adapters and reviewed source-cache snapshots for upstream catalog
|
|
247
|
+
data; see [price data strategy](docs/reference/price-data-strategy.md).
|
|
248
|
+
|
|
249
|
+
## Warnings
|
|
250
|
+
|
|
251
|
+
RunCost is designed to be boring. When it cannot confidently price something, it
|
|
252
|
+
returns a structured warning such as `unknown_model`, `component_unpriced`,
|
|
253
|
+
`price_stale`, `stream_usage_missing`, or `provider_reported_cost_mismatch`.
|
|
254
|
+
Use strict mode in tests or reconciliation flows when warnings should fail.
|
|
255
|
+
|
|
256
|
+
## CLI
|
|
257
|
+
|
|
258
|
+
The Python package installs a lightweight CLI:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
runcost price-cards --source-type user-pricing --input prices.json
|
|
262
|
+
runcost fixture-check fixtures/my-case.json
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Read Next
|
|
266
|
+
|
|
267
|
+
- [Quickstart](docs/guides/quickstart.md)
|
|
268
|
+
- [Package installation](docs/guides/package-installation.md)
|
|
269
|
+
- [Migration from hand-written formulas](docs/guides/2026-05-26-migration-from-hand-written-formulas.md)
|
|
270
|
+
- [API reference](docs/reference/api-reference.md)
|
|
271
|
+
- [Supported surfaces](docs/reference/supported-surfaces.md)
|
|
272
|
+
- [Custom pricing and discounts](docs/reference/custom-pricing-and-discounts.md)
|
|
273
|
+
- [Source adapters](docs/reference/source-adapters.md)
|
|
274
|
+
- [Price data strategy](docs/reference/price-data-strategy.md)
|
|
275
|
+
- [Aggregation and streaming](docs/reference/aggregation-and-streaming.md)
|
|
276
|
+
- [Warnings and limitations](docs/reference/warnings-and-limitations.md)
|
|
277
|
+
- [Contributing](CONTRIBUTING.md)
|
|
278
|
+
- [Security](SECURITY.md)
|
|
279
|
+
- [Changelog](CHANGELOG.md)
|
|
280
|
+
|
|
281
|
+
## Status
|
|
282
|
+
|
|
283
|
+
RunCost is alpha software. The core behavior is fixture-backed across Python,
|
|
284
|
+
JavaScript/TypeScript, and Go, but registry publishing is still held until the
|
|
285
|
+
release gates are complete. Smoke costs may use sample price cards; use provider
|
|
286
|
+
exports or dashboard reconciliation before treating a total as invoice-exact.
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# RunCost
|
|
2
|
+
|
|
3
|
+
RunCost is a small alpha utility for answering one question:
|
|
4
|
+
|
|
5
|
+
> What did this LLM or agent API call cost, and why?
|
|
6
|
+
|
|
7
|
+
It turns provider responses, framework usage objects, or normalized usage into a
|
|
8
|
+
componentized cost ledger with input, cached input, output, reasoning, tool
|
|
9
|
+
units, discounts, price sources, and warnings.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
Current alpha install paths:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Python from the repo
|
|
17
|
+
python3 -m pip install git+https://github.com/adamallcock/runcost.git
|
|
18
|
+
|
|
19
|
+
# JavaScript/TypeScript from a checkout
|
|
20
|
+
npm pack ./packages/javascript/core
|
|
21
|
+
npm install ./runcost-0.1.1.tgz
|
|
22
|
+
|
|
23
|
+
# Go
|
|
24
|
+
go get github.com/adamallcock/runcost/packages/go/ledger
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
First registry release commands, once publishing is enabled:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install runcost-ai
|
|
31
|
+
npm install runcost
|
|
32
|
+
go get github.com/adamallcock/runcost/packages/go/ledger
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The Python distribution name is `runcost-ai`; the import package and CLI are
|
|
36
|
+
`runcost`.
|
|
37
|
+
|
|
38
|
+
## One-Minute Examples
|
|
39
|
+
|
|
40
|
+
Python:
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from runcost import from_response
|
|
44
|
+
|
|
45
|
+
response = {
|
|
46
|
+
"model": "gpt-4.1-mini-2025-04-14",
|
|
47
|
+
"usage": {
|
|
48
|
+
"input_tokens": 36,
|
|
49
|
+
"input_tokens_details": {"cached_tokens": 6},
|
|
50
|
+
"output_tokens": 87,
|
|
51
|
+
"output_tokens_details": {"reasoning_tokens": 12},
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
price_cards = [{
|
|
56
|
+
"schema_version": "0.1",
|
|
57
|
+
"id": "openai:gpt-4.1-mini:example",
|
|
58
|
+
"provider": "openai",
|
|
59
|
+
"surface": "openai.responses",
|
|
60
|
+
"model": "gpt-4.1-mini",
|
|
61
|
+
"aliases": ["gpt-4.1-mini-2025-04-14"],
|
|
62
|
+
"components": [
|
|
63
|
+
{"usage_component": "input_uncached_tokens", "unit": "token", "price": {"amount": "0.40", "currency": "USD", "per": "1000000"}},
|
|
64
|
+
{"usage_component": "input_cache_read_tokens", "unit": "token", "price": {"amount": "0.10", "currency": "USD", "per": "1000000"}},
|
|
65
|
+
{"usage_component": "output_text_tokens", "unit": "token", "price": {"amount": "1.60", "currency": "USD", "per": "1000000"}},
|
|
66
|
+
{"usage_component": "output_reasoning_tokens", "unit": "token", "price": {"amount": "1.60", "currency": "USD", "per": "1000000"}},
|
|
67
|
+
],
|
|
68
|
+
"source": {"name": "example"},
|
|
69
|
+
}]
|
|
70
|
+
|
|
71
|
+
ledger = from_response(
|
|
72
|
+
response,
|
|
73
|
+
provider="openai",
|
|
74
|
+
surface="openai.responses",
|
|
75
|
+
model="gpt-4.1-mini",
|
|
76
|
+
price_cards=price_cards,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
print(ledger["total"])
|
|
80
|
+
print(ledger["components"])
|
|
81
|
+
print(ledger["warnings"])
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
TypeScript:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { fromResponse } from "runcost";
|
|
88
|
+
|
|
89
|
+
// Using the same response and priceCards shape as the Python example above.
|
|
90
|
+
const ledger = fromResponse(response, {
|
|
91
|
+
provider: "openai",
|
|
92
|
+
surface: "openai.responses",
|
|
93
|
+
model: "gpt-4.1-mini",
|
|
94
|
+
priceCards
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
console.log(ledger.total);
|
|
98
|
+
console.log(ledger.components);
|
|
99
|
+
console.log(ledger.warnings);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Go:
|
|
103
|
+
|
|
104
|
+
```go
|
|
105
|
+
package main
|
|
106
|
+
|
|
107
|
+
import (
|
|
108
|
+
"fmt"
|
|
109
|
+
|
|
110
|
+
ledger "github.com/adamallcock/runcost/packages/go/ledger"
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
func main() {
|
|
114
|
+
cost := ledger.FromResponse(
|
|
115
|
+
ledger.Object{
|
|
116
|
+
"model": "gpt-4.1-mini-2025-04-14",
|
|
117
|
+
"usage": ledger.Object{
|
|
118
|
+
"input_tokens": 36,
|
|
119
|
+
"output_tokens": 87,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
ledger.Object{
|
|
123
|
+
"provider": "openai",
|
|
124
|
+
"surface": "openai.responses",
|
|
125
|
+
"model": "gpt-4.1-mini",
|
|
126
|
+
"price_cards": []any{
|
|
127
|
+
ledger.Object{
|
|
128
|
+
"schema_version": "0.1",
|
|
129
|
+
"id": "openai:gpt-4.1-mini:example",
|
|
130
|
+
"provider": "openai",
|
|
131
|
+
"surface": "openai.responses",
|
|
132
|
+
"model": "gpt-4.1-mini",
|
|
133
|
+
"aliases": []any{"gpt-4.1-mini-2025-04-14"},
|
|
134
|
+
"components": []any{
|
|
135
|
+
ledger.Object{
|
|
136
|
+
"usage_component": "input_uncached_tokens",
|
|
137
|
+
"unit": "token",
|
|
138
|
+
"price": ledger.Object{"amount": "0.40", "currency": "USD", "per": "1000000"},
|
|
139
|
+
},
|
|
140
|
+
ledger.Object{
|
|
141
|
+
"usage_component": "output_text_tokens",
|
|
142
|
+
"unit": "token",
|
|
143
|
+
"price": ledger.Object{"amount": "1.60", "currency": "USD", "per": "1000000"},
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
"source": ledger.Object{"name": "example"},
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
fmt.Println(cost["total"])
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Already have normalized usage? Use the deterministic calculator directly:
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from runcost import calculate_cost
|
|
160
|
+
|
|
161
|
+
ledger = calculate_cost(
|
|
162
|
+
usage_ledger={
|
|
163
|
+
"schema_version": "0.1",
|
|
164
|
+
"provider": "openai",
|
|
165
|
+
"surface": "openai.responses",
|
|
166
|
+
"model": {"requested": "gpt-4.1-mini"},
|
|
167
|
+
"components": [
|
|
168
|
+
{"name": "input_uncached_tokens", "quantity": "30", "unit": "token"},
|
|
169
|
+
{"name": "output_text_tokens", "quantity": "75", "unit": "token"},
|
|
170
|
+
],
|
|
171
|
+
},
|
|
172
|
+
price_cards=price_cards,
|
|
173
|
+
)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Main APIs
|
|
177
|
+
|
|
178
|
+
| Job | Python | JavaScript/TypeScript | Go |
|
|
179
|
+
|---|---|---|---|
|
|
180
|
+
| Price normalized usage | `calculate_cost(...)` | `calculateCost(options)` | `CalculateCost(options)` |
|
|
181
|
+
| Price a provider response | `from_response(...)` | `fromResponse(response, options)` | `FromResponse(response, options)` |
|
|
182
|
+
| Aggregate call ledgers | `aggregate_cost_ledgers(...)` | `aggregateCostLedgers(options)` | `AggregateCostLedgers(...)` |
|
|
183
|
+
| Use framework outputs | `from_langsmith_run(...)`, `track_langchain_costs(...)`, and more | `fromVercelAISDKStreamFinish(...)`, `createRunCostVercelOnFinish(...)`, and more | `FromLangSmithRun(...)`, `FromSemanticKernelTelemetry(...)`, and more |
|
|
184
|
+
| Load price sources | `price_cards_from_json_file(...)`, `price_cards_from_openrouter_models(...)` | `priceCardsFromJSONFile(...)`, `priceCardsFromOpenRouterModels(...)` | `PriceCardsFromJSONFile(...)`, `PriceCardsFromOpenRouterModels(...)` |
|
|
185
|
+
| Add custom prices | Pass `price_cards` | Pass `priceCards` | Pass `price_cards` in options |
|
|
186
|
+
| Apply discounts | Pass `discount_policies` | Pass `discountPolicies` | Pass `discount_policies` in options |
|
|
187
|
+
| Audit decisions | `debug_trace=True` | `debugTrace: true` | `"debug_trace": true` |
|
|
188
|
+
| Fail on ambiguity | `mode="strict"` | `mode: "strict"` | `mode: "strict"` |
|
|
189
|
+
| CLI checks | `runcost price-cards`, `runcost fixture-check` | N/A | N/A |
|
|
190
|
+
|
|
191
|
+
## Supported Inputs
|
|
192
|
+
|
|
193
|
+
Fixture-backed surfaces include OpenAI Responses and Chat Completions, Anthropic
|
|
194
|
+
Messages, OpenRouter, Gemini and Vertex `generateContent`, AWS Bedrock Converse,
|
|
195
|
+
Cohere Chat and Rerank, OpenAI-compatible providers such as Groq, xAI, Mistral,
|
|
196
|
+
DeepSeek, Azure OpenAI, and Hugging Face Inference Providers, plus selected
|
|
197
|
+
framework objects from LangChain, Vercel AI SDK, OpenAI Agents SDK, LlamaIndex,
|
|
198
|
+
Haystack, LiteLLM, AutoGen/AG2, LangSmith, Semantic Kernel, and OpenRouter SDK
|
|
199
|
+
paths.
|
|
200
|
+
|
|
201
|
+
See [supported surfaces](docs/reference/supported-surfaces.md) for the current
|
|
202
|
+
matrix.
|
|
203
|
+
|
|
204
|
+
## Custom Prices And Discounts
|
|
205
|
+
|
|
206
|
+
RunCost treats provider pricing as data. You can pass user price cards for
|
|
207
|
+
private rates, exact aliases, service tiers, long-context prices, historical
|
|
208
|
+
effective dates, tool units, or internal billing units.
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
discounts = [{
|
|
212
|
+
"schema_version": "0.1",
|
|
213
|
+
"id": "openai-contract-4pct",
|
|
214
|
+
"match": {"provider": "openai"},
|
|
215
|
+
"adjustment": {"type": "percentage_discount", "value": "4"},
|
|
216
|
+
}]
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
The returned ledger records selected price sources, applied discounts, and any
|
|
220
|
+
warning that prevents the total from being fully explained.
|
|
221
|
+
|
|
222
|
+
Fixtures are behavioral conformance tests, not a complete model-price database.
|
|
223
|
+
Use source adapters and reviewed source-cache snapshots for upstream catalog
|
|
224
|
+
data; see [price data strategy](docs/reference/price-data-strategy.md).
|
|
225
|
+
|
|
226
|
+
## Warnings
|
|
227
|
+
|
|
228
|
+
RunCost is designed to be boring. When it cannot confidently price something, it
|
|
229
|
+
returns a structured warning such as `unknown_model`, `component_unpriced`,
|
|
230
|
+
`price_stale`, `stream_usage_missing`, or `provider_reported_cost_mismatch`.
|
|
231
|
+
Use strict mode in tests or reconciliation flows when warnings should fail.
|
|
232
|
+
|
|
233
|
+
## CLI
|
|
234
|
+
|
|
235
|
+
The Python package installs a lightweight CLI:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
runcost price-cards --source-type user-pricing --input prices.json
|
|
239
|
+
runcost fixture-check fixtures/my-case.json
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Read Next
|
|
243
|
+
|
|
244
|
+
- [Quickstart](docs/guides/quickstart.md)
|
|
245
|
+
- [Package installation](docs/guides/package-installation.md)
|
|
246
|
+
- [Migration from hand-written formulas](docs/guides/2026-05-26-migration-from-hand-written-formulas.md)
|
|
247
|
+
- [API reference](docs/reference/api-reference.md)
|
|
248
|
+
- [Supported surfaces](docs/reference/supported-surfaces.md)
|
|
249
|
+
- [Custom pricing and discounts](docs/reference/custom-pricing-and-discounts.md)
|
|
250
|
+
- [Source adapters](docs/reference/source-adapters.md)
|
|
251
|
+
- [Price data strategy](docs/reference/price-data-strategy.md)
|
|
252
|
+
- [Aggregation and streaming](docs/reference/aggregation-and-streaming.md)
|
|
253
|
+
- [Warnings and limitations](docs/reference/warnings-and-limitations.md)
|
|
254
|
+
- [Contributing](CONTRIBUTING.md)
|
|
255
|
+
- [Security](SECURITY.md)
|
|
256
|
+
- [Changelog](CHANGELOG.md)
|
|
257
|
+
|
|
258
|
+
## Status
|
|
259
|
+
|
|
260
|
+
RunCost is alpha software. The core behavior is fixture-backed across Python,
|
|
261
|
+
JavaScript/TypeScript, and Go, but registry publishing is still held until the
|
|
262
|
+
release gates are complete. Smoke costs may use sample price cards; use provider
|
|
263
|
+
exports or dashboard reconciliation before treating a total as invoice-exact.
|