coding-agent-cost 0.1.0__py3-none-any.whl

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.
agent_cost/facts.py ADDED
@@ -0,0 +1,93 @@
1
+ """Canonical fact type shared by every reader.
2
+
3
+ A "fact" is one billing event: a single token count of a single kind,
4
+ charged against a single model, at a single point in time. Readers turn
5
+ whatever a given tool's local logs record (assistant messages, rollout
6
+ snapshots, ...) into a stream of these facts; every other layer (pricing,
7
+ aggregation, export) only ever has to understand this one shape.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import re
13
+ from dataclasses import dataclass
14
+ from datetime import datetime
15
+ from typing import Optional
16
+
17
+ TOKEN_KINDS = (
18
+ "input_nocache",
19
+ "cache_read",
20
+ "cache_write_5m",
21
+ "cache_write_1h",
22
+ "cache_write_unknown",
23
+ "output",
24
+ )
25
+
26
+ AGENTS = ("claude", "codex")
27
+ MODES = ("fast", "normal", "unknown")
28
+
29
+ # Closed set of source_quality values a reader may attach to a fact. "ok"
30
+ # covers the ordinary case; readers add a more specific value only when a
31
+ # fact's derivation has a real, nameable caveat worth surfacing downstream
32
+ # (e.g. Codex's first delta in a rollout is measured against an assumed
33
+ # zero baseline). This is never left unset -- every Fact defaults to "ok"
34
+ # so export never emits a null source_quality.
35
+ SOURCE_QUALITY_VALUES = ("ok", "first_event_delta")
36
+
37
+ _BRACKET_SUFFIX = re.compile(r"\[[^\]]*\]$")
38
+ _DATE_SUFFIX = re.compile(r"@\d{6,8}$")
39
+ _VARIANT_SUFFIX = re.compile(r"-(?:1m|200k|fast|latest)$", re.IGNORECASE)
40
+ _DOTTED_MINOR = re.compile(r"(?<=\d)\.(?=\d)")
41
+
42
+
43
+ def normalize_model_key(model_raw: Optional[str]) -> str:
44
+ """Collapse cosmetic model-name variants into one stable key.
45
+
46
+ Strips context-window / speed / snapshot-date suffixes (``[1m]``,
47
+ ``@20260101``, ``-fast``, ``-200k``, ``-latest``, applied repeatedly
48
+ since they can stack) and normalizes Claude's dotted minor-version
49
+ notation (``claude-opus-4.7`` -> ``claude-opus-4-7``). This is a pure
50
+ string transform with no knowledge of any rate catalog, so a fact's
51
+ ``model_key`` stays the same even when the catalog used to price it
52
+ is swapped out via ``--rates``.
53
+ """
54
+ if not model_raw:
55
+ return "(unknown)"
56
+ key = str(model_raw).strip()
57
+ key = _BRACKET_SUFFIX.sub("", key)
58
+ key = _DATE_SUFFIX.sub("", key)
59
+ while True:
60
+ stripped = _VARIANT_SUFFIX.sub("", key)
61
+ if stripped == key:
62
+ break
63
+ key = stripped
64
+ if key.startswith("claude-"):
65
+ key = _DOTTED_MINOR.sub("-", key)
66
+ return key or "(unknown)"
67
+
68
+
69
+ @dataclass(frozen=True)
70
+ class Fact:
71
+ occurred_at_utc: datetime
72
+ agent: str
73
+ session_id: Optional[str]
74
+ model_raw: Optional[str]
75
+ model_key: str
76
+ token_kind: str
77
+ tokens: int
78
+ mode: str = "unknown"
79
+ source_quality: str = "ok"
80
+
81
+ def __post_init__(self) -> None:
82
+ if self.agent not in AGENTS:
83
+ raise ValueError(f"invalid agent: {self.agent!r}")
84
+ if self.token_kind not in TOKEN_KINDS:
85
+ raise ValueError(f"invalid token_kind: {self.token_kind!r}")
86
+ if self.mode not in MODES:
87
+ raise ValueError(f"invalid mode: {self.mode!r}")
88
+ if self.source_quality not in SOURCE_QUALITY_VALUES:
89
+ raise ValueError(f"invalid source_quality: {self.source_quality!r}")
90
+ if self.tokens < 0:
91
+ raise ValueError(f"tokens must be >= 0, got {self.tokens}")
92
+ if self.occurred_at_utc.tzinfo is None:
93
+ raise ValueError("occurred_at_utc must be timezone-aware")
agent_cost/rates.json ADDED
@@ -0,0 +1,490 @@
1
+ {
2
+ "schema_version": "1",
3
+ "catalog_version": "2026-07-29",
4
+ "currency": "USD",
5
+ "unit": "per_mtok",
6
+ "usd_per_credit": "0.04",
7
+ "notes": [
8
+ "All Claude rates are standard (non-batch, non-priority) API prices. Batch API is roughly 50% off, but agent-cost's logs have no signal for whether a given request went through Batch, so batch usage is priced at standard rates and will overstate cost for anyone using Batch.",
9
+ "claude-opus-5's launch date could not be confirmed from an authoritative source as of this catalog_version; its rate period's effective_from (2026-07-01) is a placeholder -- update it once confirmed.",
10
+ "gpt-5.6 (sol/terra/luna) credits could not be confirmed from the primary source (help.openai.com's Codex rate card returned HTTP 403 to automated fetches). The values here were cross-checked across several independent secondary sources that agreed with each other and are internally consistent (Sol's $5/$30 per-MTok API price x 25 = 125/750 credits, matching usd_per_credit=0.04); see the gpt-5.6-* sources entries below. Treat effective_from (2026-07-01) as a placeholder and re-verify against the primary rate card when it becomes reachable."
11
+ ],
12
+ "sources": [
13
+ {
14
+ "url": "https://platform.claude.com/docs/en/pricing",
15
+ "retrieved_at": "2026-07-29"
16
+ },
17
+ {
18
+ "url": "https://help.openai.com/en/articles/20001106-codex-rate-card",
19
+ "retrieved_at": "2026-07-29"
20
+ },
21
+ {
22
+ "url": "https://www.aipricing.guru/openai-pricing/",
23
+ "retrieved_at": "2026-07-29",
24
+ "note": "secondary source, used only for gpt-5.6 (sol/terra/luna) credits pending primary confirmation"
25
+ },
26
+ {
27
+ "url": "https://techjacksolutions.com/ai-tools/chatgpt/gpt-5-6-pricing/",
28
+ "retrieved_at": "2026-07-29",
29
+ "note": "secondary source, used only for gpt-5.6 (sol/terra/luna) credits pending primary confirmation"
30
+ },
31
+ {
32
+ "url": "https://rohitai.com/blog/openai-gpt-5-6-codex-rate-card-agentic-credit-pool",
33
+ "retrieved_at": "2026-07-29",
34
+ "note": "secondary source, used only for gpt-5.6 (sol/terra/luna) credits pending primary confirmation"
35
+ }
36
+ ],
37
+ "models": [
38
+ {
39
+ "model_key": "claude-fable-5",
40
+ "aliases": [],
41
+ "fast_multiplier": "1.0",
42
+ "rates": [
43
+ {
44
+ "rate_id": "claude-fable-5-launch-2026-06-09",
45
+ "effective_from": "2026-06-09T00:00:00+00:00",
46
+ "effective_until": null,
47
+ "input_nocache": "10.0",
48
+ "cache_read": "1.00",
49
+ "cache_write_5m": "12.50",
50
+ "cache_write_1h": "20.0",
51
+ "output": "50.0"
52
+ }
53
+ ]
54
+ },
55
+ {
56
+ "model_key": "claude-mythos-5",
57
+ "aliases": [],
58
+ "fast_multiplier": "1.0",
59
+ "rates": [
60
+ {
61
+ "rate_id": "claude-mythos-5-launch-2026-06-09",
62
+ "effective_from": "2026-06-09T00:00:00+00:00",
63
+ "effective_until": null,
64
+ "input_nocache": "10.0",
65
+ "cache_read": "1.00",
66
+ "cache_write_5m": "12.50",
67
+ "cache_write_1h": "20.0",
68
+ "output": "50.0"
69
+ }
70
+ ]
71
+ },
72
+ {
73
+ "model_key": "claude-opus-4-8",
74
+ "aliases": [],
75
+ "fast_multiplier": "2.0",
76
+ "rates": [
77
+ {
78
+ "rate_id": "claude-opus-4-8-launch-2026-05-28",
79
+ "effective_from": "2026-05-28T00:00:00+00:00",
80
+ "effective_until": null,
81
+ "input_nocache": "5.0",
82
+ "cache_read": "0.50",
83
+ "cache_write_5m": "6.25",
84
+ "cache_write_1h": "10.0",
85
+ "output": "25.0"
86
+ }
87
+ ]
88
+ },
89
+ {
90
+ "model_key": "claude-opus-5",
91
+ "aliases": [],
92
+ "fast_multiplier": "2.0",
93
+ "rates": [
94
+ {
95
+ "rate_id": "claude-opus-5-launch-date-unconfirmed",
96
+ "effective_from": "2026-07-01T00:00:00+00:00",
97
+ "effective_until": null,
98
+ "input_nocache": "5.0",
99
+ "cache_read": "0.50",
100
+ "cache_write_5m": "6.25",
101
+ "cache_write_1h": "10.0",
102
+ "output": "25.0"
103
+ }
104
+ ]
105
+ },
106
+ {
107
+ "model_key": "claude-opus-4-7",
108
+ "aliases": [],
109
+ "fast_multiplier": "1.0",
110
+ "rates": [
111
+ {
112
+ "rate_id": "claude-opus-4-7-2026",
113
+ "effective_from": "2025-01-01T00:00:00+00:00",
114
+ "effective_until": null,
115
+ "input_nocache": "5.0",
116
+ "cache_read": "0.50",
117
+ "cache_write_5m": "6.25",
118
+ "cache_write_1h": "10.0",
119
+ "output": "25.0"
120
+ }
121
+ ]
122
+ },
123
+ {
124
+ "model_key": "claude-opus-4-6",
125
+ "aliases": [],
126
+ "fast_multiplier": "1.0",
127
+ "rates": [
128
+ {
129
+ "rate_id": "claude-opus-4-6-2026",
130
+ "effective_from": "2025-01-01T00:00:00+00:00",
131
+ "effective_until": null,
132
+ "input_nocache": "5.0",
133
+ "cache_read": "0.50",
134
+ "cache_write_5m": "6.25",
135
+ "cache_write_1h": "10.0",
136
+ "output": "25.0"
137
+ }
138
+ ]
139
+ },
140
+ {
141
+ "model_key": "claude-sonnet-4-6",
142
+ "aliases": [],
143
+ "fast_multiplier": "1.0",
144
+ "rates": [
145
+ {
146
+ "rate_id": "claude-sonnet-4-6-2026",
147
+ "effective_from": "2025-01-01T00:00:00+00:00",
148
+ "effective_until": null,
149
+ "input_nocache": "3.0",
150
+ "cache_read": "0.30",
151
+ "cache_write_5m": "3.75",
152
+ "cache_write_1h": "6.0",
153
+ "output": "15.0"
154
+ }
155
+ ]
156
+ },
157
+ {
158
+ "model_key": "claude-sonnet-5",
159
+ "aliases": [],
160
+ "fast_multiplier": "1.0",
161
+ "rates": [
162
+ {
163
+ "rate_id": "claude-sonnet-5-launch-promo",
164
+ "effective_from": "2026-06-30T00:00:00+00:00",
165
+ "effective_until": "2026-09-01T00:00:00+00:00",
166
+ "input_nocache": "2.0",
167
+ "cache_read": "0.20",
168
+ "cache_write_5m": "2.50",
169
+ "cache_write_1h": "4.0",
170
+ "output": "10.0"
171
+ },
172
+ {
173
+ "rate_id": "claude-sonnet-5-standard",
174
+ "effective_from": "2026-09-01T00:00:00+00:00",
175
+ "effective_until": null,
176
+ "input_nocache": "3.0",
177
+ "cache_read": "0.30",
178
+ "cache_write_5m": "3.75",
179
+ "cache_write_1h": "6.0",
180
+ "output": "15.0"
181
+ }
182
+ ]
183
+ },
184
+ {
185
+ "model_key": "claude-haiku-4-5",
186
+ "aliases": [],
187
+ "fast_multiplier": "1.0",
188
+ "rates": [
189
+ {
190
+ "rate_id": "claude-haiku-4-5-2026",
191
+ "effective_from": "2025-01-01T00:00:00+00:00",
192
+ "effective_until": null,
193
+ "input_nocache": "1.0",
194
+ "cache_read": "0.10",
195
+ "cache_write_5m": "1.25",
196
+ "cache_write_1h": "2.0",
197
+ "output": "5.0"
198
+ }
199
+ ]
200
+ },
201
+ {
202
+ "model_key": "gpt-5.6-sol",
203
+ "aliases": [],
204
+ "fast_multiplier": "1.0",
205
+ "credits_per_mtok": {
206
+ "input_nocache": "125.0",
207
+ "cache_read": "12.5",
208
+ "cache_write_5m": null,
209
+ "cache_write_1h": null,
210
+ "output": "750.0"
211
+ },
212
+ "rates": [
213
+ {
214
+ "rate_id": "gpt-5.6-sol-2026-07-secondary-sourced",
215
+ "effective_from": "2026-07-01T00:00:00+00:00",
216
+ "effective_until": null,
217
+ "input_nocache": "5.0",
218
+ "cache_read": "0.50",
219
+ "cache_write_5m": null,
220
+ "cache_write_1h": null,
221
+ "output": "30.0"
222
+ }
223
+ ]
224
+ },
225
+ {
226
+ "model_key": "gpt-5.6-terra",
227
+ "aliases": [],
228
+ "fast_multiplier": "1.0",
229
+ "credits_per_mtok": {
230
+ "input_nocache": "62.5",
231
+ "cache_read": "6.25",
232
+ "cache_write_5m": null,
233
+ "cache_write_1h": null,
234
+ "output": "375.0"
235
+ },
236
+ "rates": [
237
+ {
238
+ "rate_id": "gpt-5.6-terra-2026-07-secondary-sourced",
239
+ "effective_from": "2026-07-01T00:00:00+00:00",
240
+ "effective_until": null,
241
+ "input_nocache": "2.50",
242
+ "cache_read": "0.25",
243
+ "cache_write_5m": null,
244
+ "cache_write_1h": null,
245
+ "output": "15.0"
246
+ }
247
+ ]
248
+ },
249
+ {
250
+ "model_key": "gpt-5.6-luna",
251
+ "aliases": [],
252
+ "fast_multiplier": "1.0",
253
+ "credits_per_mtok": {
254
+ "input_nocache": "25.0",
255
+ "cache_read": "2.5",
256
+ "cache_write_5m": null,
257
+ "cache_write_1h": null,
258
+ "output": "150.0"
259
+ },
260
+ "rates": [
261
+ {
262
+ "rate_id": "gpt-5.6-luna-2026-07-secondary-sourced",
263
+ "effective_from": "2026-07-01T00:00:00+00:00",
264
+ "effective_until": null,
265
+ "input_nocache": "1.00",
266
+ "cache_read": "0.10",
267
+ "cache_write_5m": null,
268
+ "cache_write_1h": null,
269
+ "output": "6.0"
270
+ }
271
+ ]
272
+ },
273
+ {
274
+ "model_key": "gpt-5.5",
275
+ "aliases": ["gpt-5.5-codex"],
276
+ "fast_multiplier": "2.5",
277
+ "credits_per_mtok": {
278
+ "input_nocache": "125.0",
279
+ "cache_read": "12.5",
280
+ "cache_write_5m": null,
281
+ "cache_write_1h": null,
282
+ "output": "750.0"
283
+ },
284
+ "rates": [
285
+ {
286
+ "rate_id": "gpt-5.5-2026-07",
287
+ "effective_from": "2026-07-01T00:00:00+00:00",
288
+ "effective_until": null,
289
+ "input_nocache": "5.0",
290
+ "cache_read": "0.50",
291
+ "cache_write_5m": null,
292
+ "cache_write_1h": null,
293
+ "output": "30.0"
294
+ }
295
+ ]
296
+ },
297
+ {
298
+ "model_key": "gpt-5.5-cyber",
299
+ "aliases": [],
300
+ "fast_multiplier": "2.5",
301
+ "credits_per_mtok": {
302
+ "input_nocache": "500.0",
303
+ "cache_read": "50.0",
304
+ "cache_write_5m": null,
305
+ "cache_write_1h": null,
306
+ "output": "3000.0"
307
+ },
308
+ "rates": [
309
+ {
310
+ "rate_id": "gpt-5.5-cyber-2026-07",
311
+ "effective_from": "2026-07-01T00:00:00+00:00",
312
+ "effective_until": null,
313
+ "input_nocache": "20.0",
314
+ "cache_read": "2.0",
315
+ "cache_write_5m": null,
316
+ "cache_write_1h": null,
317
+ "output": "120.0"
318
+ }
319
+ ]
320
+ },
321
+ {
322
+ "model_key": "gpt-5.4",
323
+ "aliases": ["gpt-5.4-codex"],
324
+ "fast_multiplier": "2.0",
325
+ "credits_per_mtok": {
326
+ "input_nocache": "62.5",
327
+ "cache_read": "6.25",
328
+ "cache_write_5m": null,
329
+ "cache_write_1h": null,
330
+ "output": "375.0"
331
+ },
332
+ "rates": [
333
+ {
334
+ "rate_id": "gpt-5.4-2026-07",
335
+ "effective_from": "2026-07-01T00:00:00+00:00",
336
+ "effective_until": null,
337
+ "input_nocache": "2.5",
338
+ "cache_read": "0.25",
339
+ "cache_write_5m": null,
340
+ "cache_write_1h": null,
341
+ "output": "15.0"
342
+ }
343
+ ]
344
+ },
345
+ {
346
+ "model_key": "gpt-5.4-mini",
347
+ "aliases": [],
348
+ "fast_multiplier": "1.0",
349
+ "credits_per_mtok": {
350
+ "input_nocache": "18.75",
351
+ "cache_read": "1.875",
352
+ "cache_write_5m": null,
353
+ "cache_write_1h": null,
354
+ "output": "112.5"
355
+ },
356
+ "rates": [
357
+ {
358
+ "rate_id": "gpt-5.4-mini-2026-07",
359
+ "effective_from": "2026-07-01T00:00:00+00:00",
360
+ "effective_until": null,
361
+ "input_nocache": "0.75",
362
+ "cache_read": "0.075",
363
+ "cache_write_5m": null,
364
+ "cache_write_1h": null,
365
+ "output": "4.50"
366
+ }
367
+ ]
368
+ },
369
+ {
370
+ "model_key": "gpt-5.3-codex",
371
+ "aliases": [],
372
+ "fast_multiplier": "1.0",
373
+ "credits_per_mtok": {
374
+ "input_nocache": "43.75",
375
+ "cache_read": "4.375",
376
+ "cache_write_5m": null,
377
+ "cache_write_1h": null,
378
+ "output": "350.0"
379
+ },
380
+ "rates": [
381
+ {
382
+ "rate_id": "gpt-5.3-codex-2026-07",
383
+ "effective_from": "2026-07-01T00:00:00+00:00",
384
+ "effective_until": null,
385
+ "input_nocache": "1.75",
386
+ "cache_read": "0.175",
387
+ "cache_write_5m": null,
388
+ "cache_write_1h": null,
389
+ "output": "14.0"
390
+ }
391
+ ]
392
+ },
393
+ {
394
+ "model_key": "gpt-5.2",
395
+ "aliases": [],
396
+ "fast_multiplier": "1.0",
397
+ "credits_per_mtok": {
398
+ "input_nocache": "43.75",
399
+ "cache_read": "4.375",
400
+ "cache_write_5m": null,
401
+ "cache_write_1h": null,
402
+ "output": "350.0"
403
+ },
404
+ "rates": [
405
+ {
406
+ "rate_id": "gpt-5.2-2026-07",
407
+ "effective_from": "2026-07-01T00:00:00+00:00",
408
+ "effective_until": null,
409
+ "input_nocache": "1.75",
410
+ "cache_read": "0.175",
411
+ "cache_write_5m": null,
412
+ "cache_write_1h": null,
413
+ "output": "14.0"
414
+ }
415
+ ]
416
+ },
417
+ {
418
+ "model_key": "gpt-5.2-codex",
419
+ "aliases": [],
420
+ "fast_multiplier": "1.0",
421
+ "credits_per_mtok": {
422
+ "input_nocache": "43.75",
423
+ "cache_read": "4.375",
424
+ "cache_write_5m": null,
425
+ "cache_write_1h": null,
426
+ "output": "350.0"
427
+ },
428
+ "rates": [
429
+ {
430
+ "rate_id": "gpt-5.2-codex-2026-07",
431
+ "effective_from": "2026-07-01T00:00:00+00:00",
432
+ "effective_until": null,
433
+ "input_nocache": "1.75",
434
+ "cache_read": "0.175",
435
+ "cache_write_5m": null,
436
+ "cache_write_1h": null,
437
+ "output": "14.0"
438
+ }
439
+ ]
440
+ },
441
+ {
442
+ "model_key": "gpt-image-2",
443
+ "aliases": [],
444
+ "fast_multiplier": "1.0",
445
+ "credits_per_mtok": {
446
+ "input_nocache": "200.0",
447
+ "cache_read": "50.0",
448
+ "cache_write_5m": null,
449
+ "cache_write_1h": null,
450
+ "output": "750.0"
451
+ },
452
+ "rates": [
453
+ {
454
+ "rate_id": "gpt-image-2-2026-07",
455
+ "effective_from": "2026-07-01T00:00:00+00:00",
456
+ "effective_until": null,
457
+ "input_nocache": "8.0",
458
+ "cache_read": "2.0",
459
+ "cache_write_5m": null,
460
+ "cache_write_1h": null,
461
+ "output": "30.0"
462
+ }
463
+ ]
464
+ },
465
+ {
466
+ "model_key": "gpt-image-2-text",
467
+ "aliases": [],
468
+ "fast_multiplier": "1.0",
469
+ "credits_per_mtok": {
470
+ "input_nocache": "125.0",
471
+ "cache_read": "31.25",
472
+ "cache_write_5m": null,
473
+ "cache_write_1h": null,
474
+ "output": "250.0"
475
+ },
476
+ "rates": [
477
+ {
478
+ "rate_id": "gpt-image-2-text-2026-07",
479
+ "effective_from": "2026-07-01T00:00:00+00:00",
480
+ "effective_until": null,
481
+ "input_nocache": "5.0",
482
+ "cache_read": "1.25",
483
+ "cache_write_5m": null,
484
+ "cache_write_1h": null,
485
+ "output": "10.0"
486
+ }
487
+ ]
488
+ }
489
+ ]
490
+ }