coding-agent-cost 0.2.0__tar.gz → 0.2.2__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.
- {coding_agent_cost-0.2.0/coding_agent_cost.egg-info → coding_agent_cost-0.2.2}/PKG-INFO +5 -5
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/README.md +4 -4
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/agent_cost/__init__.py +1 -1
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/agent_cost/rates.json +76 -5
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2/coding_agent_cost.egg-info}/PKG-INFO +5 -5
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/coding_agent_cost.egg-info/SOURCES.txt +2 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/pyproject.toml +1 -1
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/tests/test_astra_pricing.py +2 -2
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/tests/test_e0a_review3_hardening.py +3 -3
- coding_agent_cost-0.2.2/tests/test_opus_5_5_rates.py +74 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/tests/test_rates.py +1 -1
- coding_agent_cost-0.2.2/tests/test_sonnet_5_5_rates.py +69 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/tests/test_version_consistency.py +4 -4
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/LICENSE +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/agent_cost/aggregate.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/agent_cost/cli.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/agent_cost/config.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/agent_cost/facts.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/agent_cost/rates.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/agent_cost/readers/__init__.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/agent_cost/readers/claude.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/agent_cost/readers/codex.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/agent_cost/renderers.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/coding_agent_cost.egg-info/dependency_links.txt +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/coding_agent_cost.egg-info/entry_points.txt +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/coding_agent_cost.egg-info/top_level.txt +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/setup.cfg +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/tests/test_aggregate.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/tests/test_cli.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/tests/test_e0a_fable_5_1_and_sonnet_5_correction.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/tests/test_facts.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/tests/test_measure_v1_contract.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/tests/test_reader_claude.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/tests/test_reader_codex.py +0 -0
- {coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/tests/test_reader_dedup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coding-agent-cost
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Estimate AI coding agent (Claude Code / Codex CLI) token usage and cost from local logs
|
|
5
5
|
Author: shiki-yusuke
|
|
6
6
|
License: MIT
|
|
@@ -73,7 +73,8 @@ agent-cost report
|
|
|
73
73
|
The PyPI distribution is named [`coding-agent-cost`](https://pypi.org/project/coding-agent-cost/),
|
|
74
74
|
while the command remains `agent-cost` and the import remains `agent_cost`. The shorter PyPI
|
|
75
75
|
name is unavailable because of PyPI's similarity rule; this project is not affiliated with the
|
|
76
|
-
unrelated `agentcost` distribution.
|
|
76
|
+
unrelated `agentcost` distribution. Releases are published from a `v*` tag by GitHub Actions
|
|
77
|
+
through PyPI's Trusted Publisher; see [docs/release.md](docs/release.md).
|
|
77
78
|
|
|
78
79
|
## Synthetic output example
|
|
79
80
|
|
|
@@ -266,8 +267,7 @@ network, never calls `gh`, and never resolves branches or PRs.
|
|
|
266
267
|
in the report's `data_quality` block instead of being silently dropped or
|
|
267
268
|
clamped to zero.
|
|
268
269
|
- **Known catalog gaps**, tracked in `agent_cost/rates.json`'s `notes`:
|
|
269
|
-
`
|
|
270
|
-
source, so its rate period's `effective_from` is a placeholder. `gpt-5.6`
|
|
270
|
+
`gpt-5.6`
|
|
271
271
|
(Sol/Terra/Luna) credits could not be confirmed from the primary source
|
|
272
272
|
(`help.openai.com`'s Codex rate card returns HTTP 403 to automated
|
|
273
273
|
fetches); the values in the catalog come from several independent
|
|
@@ -342,7 +342,7 @@ agent-cost measure --session-id <id> [--session-id <id> ...] \
|
|
|
342
342
|
```json
|
|
343
343
|
{
|
|
344
344
|
"protocol_version": "measure/v1",
|
|
345
|
-
"producer_version": "0.2.
|
|
345
|
+
"producer_version": "0.2.2",
|
|
346
346
|
"accounting_basis": "agent-cost-raw-total/v2",
|
|
347
347
|
"generated_at": "...",
|
|
348
348
|
"window": { "since": "...", "until": null },
|
|
@@ -47,7 +47,8 @@ agent-cost report
|
|
|
47
47
|
The PyPI distribution is named [`coding-agent-cost`](https://pypi.org/project/coding-agent-cost/),
|
|
48
48
|
while the command remains `agent-cost` and the import remains `agent_cost`. The shorter PyPI
|
|
49
49
|
name is unavailable because of PyPI's similarity rule; this project is not affiliated with the
|
|
50
|
-
unrelated `agentcost` distribution.
|
|
50
|
+
unrelated `agentcost` distribution. Releases are published from a `v*` tag by GitHub Actions
|
|
51
|
+
through PyPI's Trusted Publisher; see [docs/release.md](docs/release.md).
|
|
51
52
|
|
|
52
53
|
## Synthetic output example
|
|
53
54
|
|
|
@@ -240,8 +241,7 @@ network, never calls `gh`, and never resolves branches or PRs.
|
|
|
240
241
|
in the report's `data_quality` block instead of being silently dropped or
|
|
241
242
|
clamped to zero.
|
|
242
243
|
- **Known catalog gaps**, tracked in `agent_cost/rates.json`'s `notes`:
|
|
243
|
-
`
|
|
244
|
-
source, so its rate period's `effective_from` is a placeholder. `gpt-5.6`
|
|
244
|
+
`gpt-5.6`
|
|
245
245
|
(Sol/Terra/Luna) credits could not be confirmed from the primary source
|
|
246
246
|
(`help.openai.com`'s Codex rate card returns HTTP 403 to automated
|
|
247
247
|
fetches); the values in the catalog come from several independent
|
|
@@ -316,7 +316,7 @@ agent-cost measure --session-id <id> [--session-id <id> ...] \
|
|
|
316
316
|
```json
|
|
317
317
|
{
|
|
318
318
|
"protocol_version": "measure/v1",
|
|
319
|
-
"producer_version": "0.2.
|
|
319
|
+
"producer_version": "0.2.2",
|
|
320
320
|
"accounting_basis": "agent-cost-raw-total/v2",
|
|
321
321
|
"generated_at": "...",
|
|
322
322
|
"window": { "since": "...", "until": null },
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": "1",
|
|
3
|
-
"catalog_version": "2026-09-
|
|
3
|
+
"catalog_version": "2026-09-29",
|
|
4
4
|
"currency": "USD",
|
|
5
5
|
"unit": "per_mtok",
|
|
6
6
|
"usd_per_credit": "0.04",
|
|
7
7
|
"notes": [
|
|
8
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
|
|
9
|
+
"claude-opus-5 effective_from corrected 2026-09-23: the 2026-07-01 placeholder (rate_id claude-opus-5-launch-date-unconfirmed) is replaced by the official launch date 2026-07-24 (anthropic.com/news/claude-opus-5, dated 'Jul 24, 2026'), rate_id claude-opus-5-launch-2026-07-24 -- the period is replaced rather than edited in place, following the claude-sonnet-5-standard -> claude-sonnet-5-standard-2026-09-01 correction precedent (rate_id is not consumed by any reader or report field; reports pin catalog_version + sha256). The source gives a calendar date only, so effective_from is 00:00:00Z of that day: a transcript row carrying this model ID cannot predate the public launch, so nothing on the launch day is mispriced by the earlier-of-day boundary. The earliest claude-opus-5 row across local transcripts is 2026-07-28T18:22:52Z, so no locally observed event moves from priced to unpriced; events between 2026-07-01 and 2026-07-23 that were priced under the placeholder are now unpriced, which is the correct treatment for a model that did not exist yet.",
|
|
10
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
11
|
"gpt-6-astra: Codex standard token-based rates only; not API pricing, legacy message metering, or actual contractual charges. Confirmed 2026-09-06 JST (2026-09-05T17:18:23Z). effective_from is this observation cutoff, NOT an official launch or price-start time; earlier events remain unpriced. No Codex long-context surcharge or cache-write charge is applied. Fast multiplier 2.5 applies to explicit priority request settings with matching owned turn/model context; explicit default uses Standard. Missing or ambiguous Astra modes remain unpriced. These settings do not confirm the backend processing tier. See docs/astra-pricing.md for compatibility limits and the separate GPT-5.6 discrepancy report.",
|
|
12
12
|
"claude-fable-5-1 added 2026-09-09: rate_id claude-fable-5-1-local-first-observed-2026-09-02. effective_from (2026-09-02T01:17:55Z) is the timestamp the raw model ID was first observed across all 54 local transcript files (none found in August), not a confirmed official launch date -- if an authoritative launch date is confirmed later, add it as a separate rate_id with effective_until on this one rather than editing this period in place. Values (cache_read $0.25/MTok = 0.025x base input) differ from claude-fable-5's cache_read ($1.00/MTok = 0.1x); this is a genuine per-model price difference confirmed against the primary source (see sources below), not an inconsistency to reconcile.",
|
|
13
|
-
"claude-sonnet-5 corrected 2026-09-09: a prior period (rate_id claude-sonnet-5-standard, effective_from 2026-09-01, values 3.0/0.30/3.75/6.0/15.0) priced a previously-announced rate increase that the pricing page's claude-sonnet-5-introductory-pricing note states did not occur (\"The previously scheduled increase to $3/$15 ... on September 1, 2026 will not occur\"). That period has been replaced by claude-sonnet-5-standard-2026-09-01, which carries the same $2/$0.20/$2.50/$4/$10 values as the preceding claude-sonnet-5-launch-promo period, since the launch price is confirmed to be the ongoing price with no change at the 2026-09-01 boundary. Any measure/v1 or report output computed against the pre-correction catalog for claude-sonnet-5 sessions occurring on or after 2026-09-01 overstated cost by 1.5x for that model. To detect this class of error going forward, cross-check each priced model's rate periods against its primary pricing page's Note text on a recurring (e.g. monthly) basis for mentions of a rate-change announcement being withdrawn or not taking effect -- a period can be internally valid (schema-wise) and still price a rate that was announced but never actually charged."
|
|
13
|
+
"claude-sonnet-5 corrected 2026-09-09: a prior period (rate_id claude-sonnet-5-standard, effective_from 2026-09-01, values 3.0/0.30/3.75/6.0/15.0) priced a previously-announced rate increase that the pricing page's claude-sonnet-5-introductory-pricing note states did not occur (\"The previously scheduled increase to $3/$15 ... on September 1, 2026 will not occur\"). That period has been replaced by claude-sonnet-5-standard-2026-09-01, which carries the same $2/$0.20/$2.50/$4/$10 values as the preceding claude-sonnet-5-launch-promo period, since the launch price is confirmed to be the ongoing price with no change at the 2026-09-01 boundary. Any measure/v1 or report output computed against the pre-correction catalog for claude-sonnet-5 sessions occurring on or after 2026-09-01 overstated cost by 1.5x for that model. To detect this class of error going forward, cross-check each priced model's rate periods against its primary pricing page's Note text on a recurring (e.g. monthly) basis for mentions of a rate-change announcement being withdrawn or not taking effect -- a period can be internally valid (schema-wise) and still price a rate that was announced but never actually charged.",
|
|
14
|
+
"claude-opus-5-5 added 2026-09-23: rate_id claude-opus-5-5-launch-2026-09-22. effective_from 2026-09-22T00:00:00Z is 00:00:00Z of the official public launch date (anthropic.com/claude-opus-5-5, 'September 22, 2026'); the launch time of day is not published, but a transcript row whose raw model ID is claude-opus-5-5 cannot predate the launch, so pricing from the start of that UTC day cannot price a pre-launch event. Values 4.0/0.20/5.0/8.0/20.0 per the pricing page: cache_read is 0.05x base input (pricing-page footnote 2), a genuine per-model difference from the standard 0.1x and from claude-fable-5-1's 0.025x. fast_multiplier 2.0 (fast mode $8/$40 per MTok on the pricing page). Claude Code's CHANGELOG entry for 2.1.280 states Opus 5.5 became the default model (see sources); rows whose raw model ID is claude-opus-5-5 would be unpriced without this entry. Claude Sonnet 5.5 and Claude Haiku 5.5 are announced to follow 'in the coming weeks' -- add them as separate entries when their model IDs and prices are published, never as aliases of the 5.x entries.",
|
|
15
|
+
"claude-sonnet-5-5 added 2026-09-29: rate_id claude-sonnet-5-5-launch-2026-09-28. effective_from 2026-09-28T00:00:00Z is 00:00:00Z of the official public launch date (anthropic.com/claude-sonnet-5-5, 'September 28, 2026'); as with claude-opus-5-5, the launch time of day is not published, but a transcript row whose raw model ID is claude-sonnet-5-5 cannot predate the launch, so pricing from the start of that UTC day cannot price a pre-launch event. Values 2.0/0.20/2.50/4.0/10.0 per the pricing page (Sonnet 5.5 row, no footnote: cache_read is the standard 0.1x, unlike claude-opus-5-5's 0.05x and claude-fable-5-1's 0.025x). Identical to claude-sonnet-5's ongoing values, but kept as a separate entry, never an alias: the pricing page lists the two rows independently and a future change to one need not apply to the other. fast_multiplier 1.0: the pricing page's fast-mode table lists only the Opus models. Claude Code's CHANGELOG entry for 2.1.284 states Sonnet 5.5 is now the default Sonnet model, so the `sonnet` alias in agent frontmatter resolves to it and rows whose raw model ID is claude-sonnet-5-5 are expected from that version onward; no such row existed in the local transcripts on 2026-09-29. Claude Haiku 5.5 is announced to follow 'in the coming weeks' -- add it as a separate entry when its model ID and prices are published."
|
|
14
16
|
],
|
|
15
17
|
"sources": [
|
|
16
18
|
{
|
|
@@ -60,6 +62,41 @@
|
|
|
60
62
|
"url": "https://platform.claude.com/docs/en/build-with-claude/prompt-caching",
|
|
61
63
|
"retrieved_at": "2026-09-09",
|
|
62
64
|
"note": "cache write TTL multipliers (5m = 1.25x, 1h = 2x), cross-checked against the pricing page cache columns"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"url": "https://platform.claude.com/docs/en/about-claude/pricing",
|
|
68
|
+
"retrieved_at": "2026-09-23",
|
|
69
|
+
"note": "used for claude-opus-5-5 (Opus 5.5 row: $4 / $5 / $8 / $0.20 / $20, footnote 2 cache_read 0.05x, fast mode $8/$40); fetched via WebFetch, no local snapshot"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"url": "https://www.anthropic.com/claude-opus-5-5",
|
|
73
|
+
"retrieved_at": "2026-09-23",
|
|
74
|
+
"note": "Opus 5.5 announcement: public launch date September 22, 2026, model ID claude-opus-5-5, Sonnet 5.5 / Haiku 5.5 to follow"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"url": "https://www.anthropic.com/news/claude-opus-5",
|
|
78
|
+
"retrieved_at": "2026-09-23",
|
|
79
|
+
"note": "Opus 5 announcement dated Jul 24, 2026; used to replace the claude-opus-5 effective_from placeholder"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"url": "https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md",
|
|
83
|
+
"retrieved_at": "2026-09-23",
|
|
84
|
+
"note": "Claude Code 2.1.280 entry: Claude Opus 5.5 became the default model (1M context, $4/$20 per MTok, $0.20/MTok cache reads); the reason claude-opus-5-5 rows are expected in transcripts from that version"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"url": "https://platform.claude.com/docs/en/about-claude/pricing",
|
|
88
|
+
"retrieved_at": "2026-09-29",
|
|
89
|
+
"note": "used for claude-sonnet-5-5 (Sonnet 5.5 row: $2 / $2.50 / $4 / $0.20 / $10, no footnote so cache_read is the standard 0.1x; fast-mode table lists Opus models only); fetched via WebFetch, no local snapshot"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"url": "https://www.anthropic.com/claude-sonnet-5-5",
|
|
93
|
+
"retrieved_at": "2026-09-29",
|
|
94
|
+
"note": "Sonnet 5.5 announcement: public launch date September 28, 2026, model ID claude-sonnet-5-5, $2/$10 per MTok, Haiku 5.5 to follow in the coming weeks"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"url": "https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md",
|
|
98
|
+
"retrieved_at": "2026-09-29",
|
|
99
|
+
"note": "Claude Code 2.1.284 entry: added Claude Sonnet 5.5 (claude-sonnet-5-5), now the default Sonnet model; the reason claude-sonnet-5-5 rows are expected in transcripts from that version"
|
|
63
100
|
}
|
|
64
101
|
],
|
|
65
102
|
"models": [
|
|
@@ -137,8 +174,8 @@
|
|
|
137
174
|
"fast_multiplier": "2.0",
|
|
138
175
|
"rates": [
|
|
139
176
|
{
|
|
140
|
-
"rate_id": "claude-opus-5-launch-
|
|
141
|
-
"effective_from": "2026-07-
|
|
177
|
+
"rate_id": "claude-opus-5-launch-2026-07-24",
|
|
178
|
+
"effective_from": "2026-07-24T00:00:00+00:00",
|
|
142
179
|
"effective_until": null,
|
|
143
180
|
"input_nocache": "5.0",
|
|
144
181
|
"cache_read": "0.50",
|
|
@@ -148,6 +185,23 @@
|
|
|
148
185
|
}
|
|
149
186
|
]
|
|
150
187
|
},
|
|
188
|
+
{
|
|
189
|
+
"model_key": "claude-opus-5-5",
|
|
190
|
+
"aliases": [],
|
|
191
|
+
"fast_multiplier": "2.0",
|
|
192
|
+
"rates": [
|
|
193
|
+
{
|
|
194
|
+
"rate_id": "claude-opus-5-5-launch-2026-09-22",
|
|
195
|
+
"effective_from": "2026-09-22T00:00:00+00:00",
|
|
196
|
+
"effective_until": null,
|
|
197
|
+
"input_nocache": "4.0",
|
|
198
|
+
"cache_read": "0.20",
|
|
199
|
+
"cache_write_5m": "5.0",
|
|
200
|
+
"cache_write_1h": "8.0",
|
|
201
|
+
"output": "20.0"
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
},
|
|
151
205
|
{
|
|
152
206
|
"model_key": "claude-opus-4-7",
|
|
153
207
|
"aliases": [],
|
|
@@ -226,6 +280,23 @@
|
|
|
226
280
|
}
|
|
227
281
|
]
|
|
228
282
|
},
|
|
283
|
+
{
|
|
284
|
+
"model_key": "claude-sonnet-5-5",
|
|
285
|
+
"aliases": [],
|
|
286
|
+
"fast_multiplier": "1.0",
|
|
287
|
+
"rates": [
|
|
288
|
+
{
|
|
289
|
+
"rate_id": "claude-sonnet-5-5-launch-2026-09-28",
|
|
290
|
+
"effective_from": "2026-09-28T00:00:00+00:00",
|
|
291
|
+
"effective_until": null,
|
|
292
|
+
"input_nocache": "2.0",
|
|
293
|
+
"cache_read": "0.20",
|
|
294
|
+
"cache_write_5m": "2.50",
|
|
295
|
+
"cache_write_1h": "4.0",
|
|
296
|
+
"output": "10.0"
|
|
297
|
+
}
|
|
298
|
+
]
|
|
299
|
+
},
|
|
229
300
|
{
|
|
230
301
|
"model_key": "claude-haiku-4-5",
|
|
231
302
|
"aliases": [],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coding-agent-cost
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Estimate AI coding agent (Claude Code / Codex CLI) token usage and cost from local logs
|
|
5
5
|
Author: shiki-yusuke
|
|
6
6
|
License: MIT
|
|
@@ -73,7 +73,8 @@ agent-cost report
|
|
|
73
73
|
The PyPI distribution is named [`coding-agent-cost`](https://pypi.org/project/coding-agent-cost/),
|
|
74
74
|
while the command remains `agent-cost` and the import remains `agent_cost`. The shorter PyPI
|
|
75
75
|
name is unavailable because of PyPI's similarity rule; this project is not affiliated with the
|
|
76
|
-
unrelated `agentcost` distribution.
|
|
76
|
+
unrelated `agentcost` distribution. Releases are published from a `v*` tag by GitHub Actions
|
|
77
|
+
through PyPI's Trusted Publisher; see [docs/release.md](docs/release.md).
|
|
77
78
|
|
|
78
79
|
## Synthetic output example
|
|
79
80
|
|
|
@@ -266,8 +267,7 @@ network, never calls `gh`, and never resolves branches or PRs.
|
|
|
266
267
|
in the report's `data_quality` block instead of being silently dropped or
|
|
267
268
|
clamped to zero.
|
|
268
269
|
- **Known catalog gaps**, tracked in `agent_cost/rates.json`'s `notes`:
|
|
269
|
-
`
|
|
270
|
-
source, so its rate period's `effective_from` is a placeholder. `gpt-5.6`
|
|
270
|
+
`gpt-5.6`
|
|
271
271
|
(Sol/Terra/Luna) credits could not be confirmed from the primary source
|
|
272
272
|
(`help.openai.com`'s Codex rate card returns HTTP 403 to automated
|
|
273
273
|
fetches); the values in the catalog come from several independent
|
|
@@ -342,7 +342,7 @@ agent-cost measure --session-id <id> [--session-id <id> ...] \
|
|
|
342
342
|
```json
|
|
343
343
|
{
|
|
344
344
|
"protocol_version": "measure/v1",
|
|
345
|
-
"producer_version": "0.2.
|
|
345
|
+
"producer_version": "0.2.2",
|
|
346
346
|
"accounting_basis": "agent-cost-raw-total/v2",
|
|
347
347
|
"generated_at": "...",
|
|
348
348
|
"window": { "since": "...", "until": null },
|
|
@@ -24,8 +24,10 @@ tests/test_e0a_fable_5_1_and_sonnet_5_correction.py
|
|
|
24
24
|
tests/test_e0a_review3_hardening.py
|
|
25
25
|
tests/test_facts.py
|
|
26
26
|
tests/test_measure_v1_contract.py
|
|
27
|
+
tests/test_opus_5_5_rates.py
|
|
27
28
|
tests/test_rates.py
|
|
28
29
|
tests/test_reader_claude.py
|
|
29
30
|
tests/test_reader_codex.py
|
|
30
31
|
tests/test_reader_dedup.py
|
|
32
|
+
tests/test_sonnet_5_5_rates.py
|
|
31
33
|
tests/test_version_consistency.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "coding-agent-cost"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "Estimate AI coding agent (Claude Code / Codex CLI) token usage and cost from local logs"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -45,7 +45,7 @@ def test_standard_fast_and_unknown_mode_prices(kind, usd, credits, mode, multipl
|
|
|
45
45
|
|
|
46
46
|
def test_catalog_observation_boundary_is_not_backdated():
|
|
47
47
|
catalog = load_rates()
|
|
48
|
-
assert catalog.catalog_version == "2026-09-
|
|
48
|
+
assert catalog.catalog_version == "2026-09-29"
|
|
49
49
|
entry = catalog.models["gpt-6-astra"]
|
|
50
50
|
assert entry.aliases == ()
|
|
51
51
|
assert entry.rates[0].effective_from == CUTOFF
|
|
@@ -149,7 +149,7 @@ def test_measure_reads_isolated_synthetic_astra_with_existing_contract(tmp_path,
|
|
|
149
149
|
assert cli.main(["measure", "--session-id", "synthetic-astra", "--agent", "codex"]) == 0
|
|
150
150
|
report = json.loads(capsys.readouterr().out)
|
|
151
151
|
assert report["protocol_version"] == "measure/v1"
|
|
152
|
-
assert report["rates"]["catalog_version"] == "2026-09-
|
|
152
|
+
assert report["rates"]["catalog_version"] == "2026-09-29"
|
|
153
153
|
assert len(report["rates"]["sha256"]) == 64
|
|
154
154
|
assert report["sessions"]["synthetic-astra"]["totals"]["estimated_cost_usd"] == 122
|
|
155
155
|
assert report["total"]["totals"]["credits"] == 3050
|
|
@@ -19,7 +19,7 @@ architect レビュー (3 巡目) と builder レビューで、既存テスト
|
|
|
19
19
|
かつ確定金額が計上されない。境界ちょうどは priced になる。
|
|
20
20
|
|
|
21
21
|
条件D (PR レビュー3点目・追加分): catalog は
|
|
22
|
-
catalog_version == "2026-09-
|
|
22
|
+
catalog_version == "2026-09-29"(rates.json の現行値)であり、sources の中に url
|
|
23
23
|
"https://platform.claude.com/docs/en/about-claude/pricing" の
|
|
24
24
|
entry があって、その note に
|
|
25
25
|
"sha256=d79ad28567196bd55dd50e2fd89341b9da9774a45c1d02fcf387078507fd15e0"
|
|
@@ -224,7 +224,7 @@ def test_condition_c_claude_fable_5_1_at_effective_from_boundary_is_priced_contr
|
|
|
224
224
|
|
|
225
225
|
|
|
226
226
|
def test_condition_d_catalog_version_and_pricing_source_sha256_note():
|
|
227
|
-
"""条件D: catalog_version == "2026-09-
|
|
227
|
+
"""条件D: catalog_version == "2026-09-29"(rates.json の現行値)であり、sources に url
|
|
228
228
|
"https://platform.claude.com/docs/en/about-claude/pricing" の entry が
|
|
229
229
|
あって、その note に指定の sha256 文字列を含むこと。
|
|
230
230
|
|
|
@@ -233,7 +233,7 @@ def test_condition_d_catalog_version_and_pricing_source_sha256_note():
|
|
|
233
233
|
ダイジェストを貼り付けてしまう。
|
|
234
234
|
"""
|
|
235
235
|
catalog = load_rates()
|
|
236
|
-
assert catalog.catalog_version == "2026-09-
|
|
236
|
+
assert catalog.catalog_version == "2026-09-29"
|
|
237
237
|
|
|
238
238
|
matches = [
|
|
239
239
|
s
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Acceptance tests for the claude-opus-5-5 rate entry and the claude-opus-5
|
|
2
|
+
effective_from correction (catalog_version 2026-09-23).
|
|
3
|
+
|
|
4
|
+
Primary sources: platform.claude.com/docs/en/about-claude/pricing (Opus 5.5
|
|
5
|
+
row + footnote 2), anthropic.com/claude-opus-5-5 (launch 2026-09-22),
|
|
6
|
+
anthropic.com/news/claude-opus-5 (launch 2026-07-24).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from datetime import datetime, timezone
|
|
10
|
+
from decimal import Decimal
|
|
11
|
+
|
|
12
|
+
from agent_cost.rates import load_rates
|
|
13
|
+
|
|
14
|
+
UTC = timezone.utc
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def dt(s):
|
|
18
|
+
return datetime.fromisoformat(s).replace(tzinfo=UTC)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_claude_opus_5_5_resolves_with_pricing_page_values_on_or_after_launch():
|
|
22
|
+
catalog = load_rates()
|
|
23
|
+
for occurred_at in ("2026-09-22T00:00:00+00:00", "2026-12-01T00:00:00+00:00"):
|
|
24
|
+
resolved, period = catalog.rate_for("claude-opus-5-5", dt(occurred_at))
|
|
25
|
+
assert resolved == "claude-opus-5-5"
|
|
26
|
+
assert period is not None
|
|
27
|
+
assert period.rate_id == "claude-opus-5-5-launch-2026-09-22"
|
|
28
|
+
assert period.values["input_nocache"] == Decimal("4.0")
|
|
29
|
+
assert period.values["cache_read"] == Decimal("0.20")
|
|
30
|
+
assert period.values["cache_write_5m"] == Decimal("5.0")
|
|
31
|
+
assert period.values["cache_write_1h"] == Decimal("8.0")
|
|
32
|
+
assert period.values["output"] == Decimal("20.0")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_claude_opus_5_5_is_unpriced_before_launch_date():
|
|
36
|
+
catalog = load_rates()
|
|
37
|
+
resolved, before = catalog.rate_for("claude-opus-5-5", dt("2026-09-21T23:59:59+00:00"))
|
|
38
|
+
assert resolved == "claude-opus-5-5"
|
|
39
|
+
assert before is None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_claude_opus_5_5_cache_read_is_0_05x_base_input_not_standard_0_1x():
|
|
43
|
+
# Footnote 2 on the pricing page: Opus 5.5 cache hits are 0.05x base input.
|
|
44
|
+
catalog = load_rates()
|
|
45
|
+
_, period = catalog.rate_for("claude-opus-5-5", dt("2026-10-01T00:00:00+00:00"))
|
|
46
|
+
assert period.values["cache_read"] == period.values["input_nocache"] * Decimal("0.05")
|
|
47
|
+
assert period.values["cache_read"] != period.values["input_nocache"] * Decimal("0.1")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_claude_opus_5_5_fast_multiplier_2x():
|
|
51
|
+
catalog = load_rates()
|
|
52
|
+
assert catalog.models["claude-opus-5-5"].fast_multiplier == Decimal("2.0")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_claude_opus_5_5_is_not_an_alias_of_claude_opus_5():
|
|
56
|
+
catalog = load_rates()
|
|
57
|
+
assert "claude-opus-5-5" not in catalog.models["claude-opus-5"].aliases
|
|
58
|
+
assert catalog.models["claude-opus-5-5"].aliases == ()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_claude_opus_5_effective_from_is_the_official_launch_date():
|
|
62
|
+
catalog = load_rates()
|
|
63
|
+
resolved, before = catalog.rate_for("claude-opus-5", dt("2026-07-23T23:59:59+00:00"))
|
|
64
|
+
assert resolved == "claude-opus-5"
|
|
65
|
+
assert before is None
|
|
66
|
+
_, on_launch = catalog.rate_for("claude-opus-5", dt("2026-07-24T00:00:00+00:00"))
|
|
67
|
+
assert on_launch is not None
|
|
68
|
+
assert on_launch.rate_id == "claude-opus-5-launch-2026-07-24"
|
|
69
|
+
assert on_launch.values["input_nocache"] == Decimal("5.0")
|
|
70
|
+
assert on_launch.values["cache_read"] == Decimal("0.50")
|
|
71
|
+
assert on_launch.values["cache_write_5m"] == Decimal("6.25")
|
|
72
|
+
assert on_launch.values["cache_write_1h"] == Decimal("10.0")
|
|
73
|
+
assert on_launch.values["output"] == Decimal("25.0")
|
|
74
|
+
assert on_launch.effective_until is None
|
|
@@ -88,7 +88,7 @@ def test_claude_opus_5_is_priced_with_fast_multiplier_2x():
|
|
|
88
88
|
catalog = load_rates()
|
|
89
89
|
entry = catalog.models["claude-opus-5"]
|
|
90
90
|
assert entry.fast_multiplier == Decimal("2.0")
|
|
91
|
-
_, period = catalog.rate_for("claude-opus-5", dt("2026-
|
|
91
|
+
_, period = catalog.rate_for("claude-opus-5", dt("2026-08-01T00:00:00+00:00"))
|
|
92
92
|
assert period.values["input_nocache"] == Decimal("5.0")
|
|
93
93
|
assert period.values["output"] == Decimal("25.0")
|
|
94
94
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Acceptance tests for the claude-sonnet-5-5 rate entry (catalog_version 2026-09-29).
|
|
2
|
+
|
|
3
|
+
Primary sources: platform.claude.com/docs/en/about-claude/pricing (Sonnet 5.5
|
|
4
|
+
row, no cache_read footnote), anthropic.com/claude-sonnet-5-5 (launch
|
|
5
|
+
2026-09-28), Claude Code CHANGELOG 2.1.284 (Sonnet 5.5 is the default Sonnet).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from datetime import datetime, timezone
|
|
9
|
+
from decimal import Decimal
|
|
10
|
+
|
|
11
|
+
from agent_cost.rates import load_rates
|
|
12
|
+
|
|
13
|
+
UTC = timezone.utc
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def dt(s):
|
|
17
|
+
return datetime.fromisoformat(s).replace(tzinfo=UTC)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_claude_sonnet_5_5_resolves_with_pricing_page_values_on_or_after_launch():
|
|
21
|
+
catalog = load_rates()
|
|
22
|
+
for occurred_at in ("2026-09-28T00:00:00+00:00", "2026-12-01T00:00:00+00:00"):
|
|
23
|
+
resolved, period = catalog.rate_for("claude-sonnet-5-5", dt(occurred_at))
|
|
24
|
+
assert resolved == "claude-sonnet-5-5"
|
|
25
|
+
assert period is not None
|
|
26
|
+
assert period.rate_id == "claude-sonnet-5-5-launch-2026-09-28"
|
|
27
|
+
assert period.values["input_nocache"] == Decimal("2.0")
|
|
28
|
+
assert period.values["cache_read"] == Decimal("0.20")
|
|
29
|
+
assert period.values["cache_write_5m"] == Decimal("2.50")
|
|
30
|
+
assert period.values["cache_write_1h"] == Decimal("4.0")
|
|
31
|
+
assert period.values["output"] == Decimal("10.0")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_claude_sonnet_5_5_is_unpriced_before_launch_date():
|
|
35
|
+
catalog = load_rates()
|
|
36
|
+
resolved, before = catalog.rate_for("claude-sonnet-5-5", dt("2026-09-27T23:59:59+00:00"))
|
|
37
|
+
assert resolved == "claude-sonnet-5-5"
|
|
38
|
+
assert before is None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_claude_sonnet_5_5_is_its_own_entry_not_an_alias_of_sonnet_5():
|
|
42
|
+
# Same values as claude-sonnet-5 today, but the pricing page lists the rows
|
|
43
|
+
# independently; a future change to one must not silently apply to the other.
|
|
44
|
+
catalog = load_rates()
|
|
45
|
+
assert "claude-sonnet-5-5" in catalog.models
|
|
46
|
+
assert catalog.models["claude-sonnet-5-5"].aliases == ()
|
|
47
|
+
assert "claude-sonnet-5-5" not in catalog.models["claude-sonnet-5"].aliases
|
|
48
|
+
_, s5 = catalog.rate_for("claude-sonnet-5", dt("2026-09-28T00:00:00+00:00"))
|
|
49
|
+
_, s55 = catalog.rate_for("claude-sonnet-5-5", dt("2026-09-28T00:00:00+00:00"))
|
|
50
|
+
assert s5.rate_id != s55.rate_id
|
|
51
|
+
assert s5.values == s55.values
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_claude_sonnet_5_5_cache_read_is_standard_multiplier_and_no_fast_mode():
|
|
55
|
+
catalog = load_rates()
|
|
56
|
+
entry = catalog.models["claude-sonnet-5-5"]
|
|
57
|
+
assert entry.fast_multiplier == Decimal("1.0")
|
|
58
|
+
period = entry.rates[0]
|
|
59
|
+
assert period.values["cache_read"] == period.values["input_nocache"] * Decimal("0.1")
|
|
60
|
+
assert period.values["cache_write_5m"] == period.values["input_nocache"] * Decimal("1.25")
|
|
61
|
+
assert period.values["cache_write_1h"] == period.values["input_nocache"] * Decimal("2")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_catalog_version_and_sources_record_the_sonnet_5_5_primary_sources():
|
|
65
|
+
catalog = load_rates()
|
|
66
|
+
assert catalog.catalog_version == "2026-09-29"
|
|
67
|
+
urls = {(s.get("url"), s.get("retrieved_at")) for s in catalog.sources}
|
|
68
|
+
assert ("https://platform.claude.com/docs/en/about-claude/pricing", "2026-09-29") in urls
|
|
69
|
+
assert ("https://www.anthropic.com/claude-sonnet-5-5", "2026-09-29") in urls
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Spec: pyproject.toml's [project].version and agent_cost.__version__ must
|
|
2
|
-
agree, and both must read "0.2.
|
|
3
|
-
version
|
|
2
|
+
agree, and both must read "0.2.2" for this change (the Sonnet 5.5 catalog-only release bumps
|
|
3
|
+
the package version, as the Opus 5.5 catalog release did for 0.2.1). A broken
|
|
4
4
|
implementation would bump one file but not the other, or forget the bump
|
|
5
5
|
entirely.
|
|
6
6
|
|
|
@@ -29,5 +29,5 @@ def test_pyproject_version_matches_package_version():
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
def test_version_is_0_2_0():
|
|
32
|
-
assert agent_cost.__version__ == "0.2.
|
|
33
|
-
assert _pyproject_version() == "0.2.
|
|
32
|
+
assert agent_cost.__version__ == "0.2.2"
|
|
33
|
+
assert _pyproject_version() == "0.2.2"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/coding_agent_cost.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/coding_agent_cost.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{coding_agent_cost-0.2.0 → coding_agent_cost-0.2.2}/coding_agent_cost.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|