coding-agent-cost 0.5.2__tar.gz → 0.5.3__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.5.2 → coding_agent_cost-0.5.3}/PKG-INFO +3 -1
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/agent_cost/__init__.py +1 -1
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/agent_cost/rates.json +124 -2
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/coding_agent_cost.egg-info/PKG-INFO +3 -1
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/coding_agent_cost.egg-info/SOURCES.txt +2 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/pyproject.toml +3 -1
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_astra_pricing.py +2 -2
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_billing_plan.py +27 -4
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_cli.py +1 -1
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_e0a_review3_hardening.py +3 -3
- coding_agent_cost-0.5.3/tests/test_fable_5_2_rates.py +83 -0
- coding_agent_cost-0.5.3/tests/test_gpt_6_1_rates.py +117 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_haiku_5_5_rates.py +1 -1
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_rates.py +2 -1
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_sonnet_5_5_rates.py +1 -1
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_version_consistency.py +6 -6
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/LICENSE +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/README.md +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/agent_cost/aggregate.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/agent_cost/billing_plan.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/agent_cost/cli.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/agent_cost/config.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/agent_cost/facts.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/agent_cost/rates.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/agent_cost/readers/__init__.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/agent_cost/readers/claude.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/agent_cost/readers/codex.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/agent_cost/renderers.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/coding_agent_cost.egg-info/dependency_links.txt +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/coding_agent_cost.egg-info/entry_points.txt +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/coding_agent_cost.egg-info/top_level.txt +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/setup.cfg +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_aggregate.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_e0a_fable_5_1_and_sonnet_5_correction.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_facts.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_measure_v1_contract.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_opus_5_5_rates.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_reader_claude.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_reader_codex.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_reader_dedup.py +0 -0
- {coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/tests/test_reader_output_lower_bound.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coding-agent-cost
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.3
|
|
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
|
|
@@ -17,6 +17,8 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
22
|
Classifier: Topic :: Software Development :: Build Tools
|
|
21
23
|
Classifier: Topic :: Utilities
|
|
22
24
|
Requires-Python: >=3.9
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": "2",
|
|
3
|
-
"catalog_version": "2026-10
|
|
3
|
+
"catalog_version": "2026-11-10",
|
|
4
4
|
"currency": "USD",
|
|
5
5
|
"unit": "per_mtok",
|
|
6
6
|
"usd_per_credit": "0.04",
|
|
@@ -14,7 +14,9 @@
|
|
|
14
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
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.",
|
|
16
16
|
"claude-haiku-5-5 added 2026-10-09: rate_id claude-haiku-5-5-launch-2026-10-07. effective_from 2026-10-07T00:00:00Z is 00:00:00Z of the official release date (platform.claude.com/docs/en/models/haiku-5-5/overview, 'Released October 7, 2026'); as with claude-sonnet-5-5, the release time of day is not published, but a transcript row whose raw model ID is claude-haiku-5-5 cannot predate the release. Its prices are tiered by prompt length: the period's top-level values (0.10/0.01/0.125/0.20/0.50) apply to prompts up to 100,000 tokens, and prompt_tiers[0] (prompt_tokens_over 100000: 0.50/0.05/0.625/1.0/2.50) to prompts over 100,000 tokens, per the pricing page's two Haiku 5.5 rows (no footnote: cache_read is the standard 0.1x). Prompt length follows the pricing page's Long context pricing section: it counts all of a request's input tokens including cache reads and cache writes, and each request is priced on its own, so a request over the threshold pays the higher prices for every token kind, output included. A fact whose prompt length is unknown (Codex, a conflicting Claude dedup group, inconsistent usage) is priced at the top-level values as a lower_bound. A separate entry, never an alias of claude-haiku-4-5. fast_multiplier 1.0: the pricing page's fast-mode table lists only the Opus models. Claude Code's CHANGELOG entry for 2.1.293 states Haiku 5.5 is now the default Haiku model, so the `haiku` alias resolves to it from that version onward. schema_version is 2 because prompt_tiers is new: agent-cost 0.3.0 and earlier reject schema_version 2 as unsupported instead of silently pricing every claude-haiku-5-5 request at the cheaper tier, and a schema_version 1 catalog may not carry prompt_tiers.",
|
|
17
|
-
"claude-sonnet-5-5 cache_read cut 2026-10-13: the launch period (rate_id claude-sonnet-5-5-launch-2026-09-28) now ends at 2026-10-07T00:00:00Z and a new period (rate_id claude-sonnet-5-5-cache-read-cut-2026-10-07) prices cache_read at 0.10 instead of 0.20 from that instant; input_nocache, cache_write_5m, cache_write_1h and output are unchanged (2.0/2.50/4.0/10.0). anthropic.com/claude-haiku-5-5 (dated October 7, 2026) states 'starting today, we're lowering the price of cache reads on Claude Sonnet 5.5' and 'Cache reads now cost 50% less: $0.10 per million tokens rather than $0.20'; the source gives a calendar date only, so effective_from is 00:00:00Z of that day, following the claude-sonnet-5-standard-2026-09-01 precedent. The pricing page (retrieved 2026-10-13) lists the Sonnet 5.5 row as $2 / $2.50 / $4 / $0.10 / $10 with footnote 2: cache hits and refreshes on Claude Opus 5.5 and Claude Sonnet 5.5 are 0.05x the base input price, so cache_read is now 0.05x like claude-opus-5-5. Claude Code's CHANGELOG entry for 2.1.296 (2026-10-09) updated /cost, the status line, --max-budget-usd and the SDK's cost figures to $0.10 per million Sonnet 5.5 cache-read tokens; that is the date Claude Code's own figures changed, not the API price's effective date. catalog 2026-10-09 priced claude-sonnet-5-5 cache_read at 0.20 for events from 2026-10-07 through 2026-10-13, overstating that component 2x; reports produced with it for windows touching 2026-10-07 or later should be regenerated. claude-sonnet-5 is unchanged (cache_read stays 0.20): the pricing page's footnote 3 covers its input/output prices only, and footnote 2 names Opus 5.5 and Sonnet 5.5, not Sonnet 5."
|
|
17
|
+
"claude-sonnet-5-5 cache_read cut 2026-10-13: the launch period (rate_id claude-sonnet-5-5-launch-2026-09-28) now ends at 2026-10-07T00:00:00Z and a new period (rate_id claude-sonnet-5-5-cache-read-cut-2026-10-07) prices cache_read at 0.10 instead of 0.20 from that instant; input_nocache, cache_write_5m, cache_write_1h and output are unchanged (2.0/2.50/4.0/10.0). anthropic.com/claude-haiku-5-5 (dated October 7, 2026) states 'starting today, we're lowering the price of cache reads on Claude Sonnet 5.5' and 'Cache reads now cost 50% less: $0.10 per million tokens rather than $0.20'; the source gives a calendar date only, so effective_from is 00:00:00Z of that day, following the claude-sonnet-5-standard-2026-09-01 precedent. The pricing page (retrieved 2026-10-13) lists the Sonnet 5.5 row as $2 / $2.50 / $4 / $0.10 / $10 with footnote 2: cache hits and refreshes on Claude Opus 5.5 and Claude Sonnet 5.5 are 0.05x the base input price, so cache_read is now 0.05x like claude-opus-5-5. Claude Code's CHANGELOG entry for 2.1.296 (2026-10-09) updated /cost, the status line, --max-budget-usd and the SDK's cost figures to $0.10 per million Sonnet 5.5 cache-read tokens; that is the date Claude Code's own figures changed, not the API price's effective date. catalog 2026-10-09 priced claude-sonnet-5-5 cache_read at 0.20 for events from 2026-10-07 through 2026-10-13, overstating that component 2x; reports produced with it for windows touching 2026-10-07 or later should be regenerated. claude-sonnet-5 is unchanged (cache_read stays 0.20): the pricing page's footnote 3 covers its input/output prices only, and footnote 2 names Opus 5.5 and Sonnet 5.5, not Sonnet 5.",
|
|
18
|
+
"gpt-6.1-terra, gpt-6.1-sol and codex-auto-review added 2026-11-09: standard tier, short context USD per MTok from the human-approved price table pricing-2026-11-v4 (developers.openai.com/api/docs/pricing, retrieved 2026-11-05); effective_from 2026-10-01T00:00:00Z is a placeholder before the first observed use (official launch date unconfirmed; rate_id *-launch-date-unconfirmed, following the claude-opus-5 placeholder precedent); usage from 2026-11-04 must be priced, so the retrieval date 2026-11-05 cannot be used. codex-auto-review is the model name of the Codex automatic review (guardian subagent) and has no published price; a human decision on 2026-11-06 prices it the same as gpt-6.1-terra. credits_per_mtok follow usd_per_credit=0.04. Existing entries (including gpt-5.6-terra) are unchanged.",
|
|
19
|
+
"claude-fable-5-2 and claude-mythos-5-2 added 2026-11-10: rate_ids claude-fable-5-2-launch-2026-11-09 / claude-mythos-5-2-launch-2026-11-09. effective_from 2026-11-09T00:00:00Z is 00:00:00Z of the official announcement date (anthropic.com/claude-fable-and-mythos-5-2, published November 9, 2026); the launch time of day is not published, but a transcript row whose raw model ID is claude-fable-5-2 or claude-mythos-5-2 cannot predate the launch. Values 8.0/0.20/10.0/16.0/40.0 per the pricing page (retrieved 2026-11-10): cache_read is 0.025x base input (footnote 1), like claude-fable-5-1. claude-mythos-5-2 (limited availability, verified organizations only) has the same prices; it is kept as a separate entry, never an alias of claude-fable-5-2. fast_multiplier 2.0 (fast mode $16/$80 per MTok on the pricing page). No prompt-length tiers (1M context at standard prices). Claude Code's CHANGELOG entry for 2.1.321 adds claude-fable-5-2 at $8/$40 with $0.20 cache reads. claude-fable-5-1 is unchanged (10.0/0.25/12.50/20.0/50.0). claude-mythos-5-1 stays absent (official release date unconfirmed), so its rows remain unpriced."
|
|
18
20
|
],
|
|
19
21
|
"sources": [
|
|
20
22
|
{
|
|
@@ -124,6 +126,20 @@
|
|
|
124
126
|
"url": "https://www.anthropic.com/claude-haiku-5-5",
|
|
125
127
|
"retrieved_at": "2026-10-13",
|
|
126
128
|
"note": "Haiku 5.5 announcement dated October 7, 2026, 'Further updates': starting that day, Claude Sonnet 5.5 cache reads cost $0.10 per million tokens rather than $0.20; the effective date of the claude-sonnet-5-5 cache_read cut"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"url": "https://developers.openai.com/api/docs/pricing",
|
|
132
|
+
"retrieved_at": "2026-11-05"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"url": "https://www.anthropic.com/claude-fable-and-mythos-5-2",
|
|
136
|
+
"retrieved_at": "2026-11-10",
|
|
137
|
+
"note": "Fable 5.2 / Mythos 5.2 announcement published November 9, 2026; the effective date of claude-fable-5-2 and claude-mythos-5-2"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"url": "https://platform.claude.com/docs/en/about-claude/pricing",
|
|
141
|
+
"retrieved_at": "2026-11-10",
|
|
142
|
+
"note": "Fable 5.2 / Mythos 5.2 rows: $8 input, $10 5m cache write, $16 1h cache write, $0.20 cache hits (footnote 1: 0.025x), $40 output; fast mode $16/$80"
|
|
127
143
|
}
|
|
128
144
|
],
|
|
129
145
|
"models": [
|
|
@@ -161,6 +177,23 @@
|
|
|
161
177
|
}
|
|
162
178
|
]
|
|
163
179
|
},
|
|
180
|
+
{
|
|
181
|
+
"model_key": "claude-fable-5-2",
|
|
182
|
+
"aliases": [],
|
|
183
|
+
"fast_multiplier": "2.0",
|
|
184
|
+
"rates": [
|
|
185
|
+
{
|
|
186
|
+
"rate_id": "claude-fable-5-2-launch-2026-11-09",
|
|
187
|
+
"effective_from": "2026-11-09T00:00:00+00:00",
|
|
188
|
+
"effective_until": null,
|
|
189
|
+
"input_nocache": "8.0",
|
|
190
|
+
"cache_read": "0.20",
|
|
191
|
+
"cache_write_5m": "10.0",
|
|
192
|
+
"cache_write_1h": "16.0",
|
|
193
|
+
"output": "40.0"
|
|
194
|
+
}
|
|
195
|
+
]
|
|
196
|
+
},
|
|
164
197
|
{
|
|
165
198
|
"model_key": "claude-mythos-5",
|
|
166
199
|
"aliases": [],
|
|
@@ -178,6 +211,23 @@
|
|
|
178
211
|
}
|
|
179
212
|
]
|
|
180
213
|
},
|
|
214
|
+
{
|
|
215
|
+
"model_key": "claude-mythos-5-2",
|
|
216
|
+
"aliases": [],
|
|
217
|
+
"fast_multiplier": "2.0",
|
|
218
|
+
"rates": [
|
|
219
|
+
{
|
|
220
|
+
"rate_id": "claude-mythos-5-2-launch-2026-11-09",
|
|
221
|
+
"effective_from": "2026-11-09T00:00:00+00:00",
|
|
222
|
+
"effective_until": null,
|
|
223
|
+
"input_nocache": "8.0",
|
|
224
|
+
"cache_read": "0.20",
|
|
225
|
+
"cache_write_5m": "10.0",
|
|
226
|
+
"cache_write_1h": "16.0",
|
|
227
|
+
"output": "40.0"
|
|
228
|
+
}
|
|
229
|
+
]
|
|
230
|
+
},
|
|
181
231
|
{
|
|
182
232
|
"model_key": "claude-opus-4-8",
|
|
183
233
|
"aliases": [],
|
|
@@ -689,6 +739,78 @@
|
|
|
689
739
|
"output": "50.0"
|
|
690
740
|
}
|
|
691
741
|
]
|
|
742
|
+
},
|
|
743
|
+
{
|
|
744
|
+
"model_key": "gpt-6.1-terra",
|
|
745
|
+
"aliases": [],
|
|
746
|
+
"fast_multiplier": "1.0",
|
|
747
|
+
"credits_per_mtok": {
|
|
748
|
+
"input_nocache": "25.0",
|
|
749
|
+
"cache_read": "1.25",
|
|
750
|
+
"cache_write_5m": null,
|
|
751
|
+
"cache_write_1h": null,
|
|
752
|
+
"output": "125.0"
|
|
753
|
+
},
|
|
754
|
+
"rates": [
|
|
755
|
+
{
|
|
756
|
+
"rate_id": "gpt-6.1-terra-launch-date-unconfirmed",
|
|
757
|
+
"effective_from": "2026-10-01T00:00:00+00:00",
|
|
758
|
+
"effective_until": null,
|
|
759
|
+
"input_nocache": "1.00",
|
|
760
|
+
"cache_read": "0.05",
|
|
761
|
+
"cache_write_5m": null,
|
|
762
|
+
"cache_write_1h": null,
|
|
763
|
+
"output": "5.00"
|
|
764
|
+
}
|
|
765
|
+
]
|
|
766
|
+
},
|
|
767
|
+
{
|
|
768
|
+
"model_key": "gpt-6.1-sol",
|
|
769
|
+
"aliases": [],
|
|
770
|
+
"fast_multiplier": "1.0",
|
|
771
|
+
"credits_per_mtok": {
|
|
772
|
+
"input_nocache": "50.0",
|
|
773
|
+
"cache_read": "2.5",
|
|
774
|
+
"cache_write_5m": null,
|
|
775
|
+
"cache_write_1h": null,
|
|
776
|
+
"output": "250.0"
|
|
777
|
+
},
|
|
778
|
+
"rates": [
|
|
779
|
+
{
|
|
780
|
+
"rate_id": "gpt-6.1-sol-launch-date-unconfirmed",
|
|
781
|
+
"effective_from": "2026-10-01T00:00:00+00:00",
|
|
782
|
+
"effective_until": null,
|
|
783
|
+
"input_nocache": "2.00",
|
|
784
|
+
"cache_read": "0.10",
|
|
785
|
+
"cache_write_5m": null,
|
|
786
|
+
"cache_write_1h": null,
|
|
787
|
+
"output": "10.00"
|
|
788
|
+
}
|
|
789
|
+
]
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
"model_key": "codex-auto-review",
|
|
793
|
+
"aliases": [],
|
|
794
|
+
"fast_multiplier": "1.0",
|
|
795
|
+
"credits_per_mtok": {
|
|
796
|
+
"input_nocache": "25.0",
|
|
797
|
+
"cache_read": "1.25",
|
|
798
|
+
"cache_write_5m": null,
|
|
799
|
+
"cache_write_1h": null,
|
|
800
|
+
"output": "125.0"
|
|
801
|
+
},
|
|
802
|
+
"rates": [
|
|
803
|
+
{
|
|
804
|
+
"rate_id": "codex-auto-review-2026-11-terra-equivalent",
|
|
805
|
+
"effective_from": "2026-10-01T00:00:00+00:00",
|
|
806
|
+
"effective_until": null,
|
|
807
|
+
"input_nocache": "1.00",
|
|
808
|
+
"cache_read": "0.05",
|
|
809
|
+
"cache_write_5m": null,
|
|
810
|
+
"cache_write_1h": null,
|
|
811
|
+
"output": "5.00"
|
|
812
|
+
}
|
|
813
|
+
]
|
|
692
814
|
}
|
|
693
815
|
]
|
|
694
816
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coding-agent-cost
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.3
|
|
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
|
|
@@ -17,6 +17,8 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
22
|
Classifier: Topic :: Software Development :: Build Tools
|
|
21
23
|
Classifier: Topic :: Utilities
|
|
22
24
|
Requires-Python: >=3.9
|
|
@@ -24,7 +24,9 @@ tests/test_billing_plan.py
|
|
|
24
24
|
tests/test_cli.py
|
|
25
25
|
tests/test_e0a_fable_5_1_and_sonnet_5_correction.py
|
|
26
26
|
tests/test_e0a_review3_hardening.py
|
|
27
|
+
tests/test_fable_5_2_rates.py
|
|
27
28
|
tests/test_facts.py
|
|
29
|
+
tests/test_gpt_6_1_rates.py
|
|
28
30
|
tests/test_haiku_5_5_rates.py
|
|
29
31
|
tests/test_measure_v1_contract.py
|
|
30
32
|
tests/test_opus_5_5_rates.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "coding-agent-cost"
|
|
7
|
-
version = "0.5.
|
|
7
|
+
version = "0.5.3"
|
|
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" }
|
|
@@ -31,6 +31,8 @@ classifiers = [
|
|
|
31
31
|
"Programming Language :: Python :: 3.10",
|
|
32
32
|
"Programming Language :: Python :: 3.11",
|
|
33
33
|
"Programming Language :: Python :: 3.12",
|
|
34
|
+
"Programming Language :: Python :: 3.13",
|
|
35
|
+
"Programming Language :: Python :: 3.14",
|
|
34
36
|
"Topic :: Software Development :: Build Tools",
|
|
35
37
|
"Topic :: Utilities",
|
|
36
38
|
]
|
|
@@ -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-10
|
|
48
|
+
assert catalog.catalog_version == "2026-11-10"
|
|
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-10
|
|
152
|
+
assert report["rates"]["catalog_version"] == "2026-11-10"
|
|
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
|
|
@@ -13,6 +13,8 @@ import copy
|
|
|
13
13
|
import hashlib
|
|
14
14
|
import json
|
|
15
15
|
import os
|
|
16
|
+
|
|
17
|
+
_REAL_FSTAT = os.fstat
|
|
16
18
|
import traceback
|
|
17
19
|
from datetime import datetime, timezone
|
|
18
20
|
from decimal import Decimal
|
|
@@ -583,11 +585,24 @@ def test_realpath_oserror_is_billing_plan_error(tmp_path, monkeypatch):
|
|
|
583
585
|
_assert_no_leak(info.value, path)
|
|
584
586
|
|
|
585
587
|
|
|
588
|
+
def _is_fd_of(fd, path):
|
|
589
|
+
"""True when fd refers to path. Keeps fakes scoped to the plan file: pytest's
|
|
590
|
+
capture machinery calls os.fstat/os.read/os.close on its own fds (pytest 9.2+)."""
|
|
591
|
+
try:
|
|
592
|
+
st = _REAL_FSTAT(fd)
|
|
593
|
+
except OSError:
|
|
594
|
+
return False
|
|
595
|
+
target = os.stat(path)
|
|
596
|
+
return (st.st_dev, st.st_ino) == (target.st_dev, target.st_ino)
|
|
597
|
+
|
|
598
|
+
|
|
586
599
|
def test_fstat_oserror_is_billing_plan_error(tmp_path, monkeypatch):
|
|
587
600
|
path = _write_plan(tmp_path, _base_plan())
|
|
588
601
|
|
|
589
602
|
def failing_fstat(fd):
|
|
590
|
-
|
|
603
|
+
if _is_fd_of(fd, path):
|
|
604
|
+
raise _oserror_on(path)
|
|
605
|
+
return _REAL_FSTAT(fd)
|
|
591
606
|
|
|
592
607
|
monkeypatch.setattr(bp.os, "fstat", failing_fstat)
|
|
593
608
|
with pytest.raises(bp.BillingPlanError) as info:
|
|
@@ -598,8 +613,12 @@ def test_fstat_oserror_is_billing_plan_error(tmp_path, monkeypatch):
|
|
|
598
613
|
def test_read_oserror_is_billing_plan_error(tmp_path, monkeypatch):
|
|
599
614
|
path = _write_plan(tmp_path, _base_plan())
|
|
600
615
|
|
|
616
|
+
real_read = os.read
|
|
617
|
+
|
|
601
618
|
def failing_read(fd, n):
|
|
602
|
-
|
|
619
|
+
if _is_fd_of(fd, path):
|
|
620
|
+
raise _oserror_on(path)
|
|
621
|
+
return real_read(fd, n)
|
|
603
622
|
|
|
604
623
|
monkeypatch.setattr(bp.os, "read", failing_read)
|
|
605
624
|
with pytest.raises(bp.BillingPlanError) as info:
|
|
@@ -612,8 +631,10 @@ def test_close_oserror_is_billing_plan_error(tmp_path, monkeypatch):
|
|
|
612
631
|
real_close = os.close
|
|
613
632
|
|
|
614
633
|
def failing_close(fd):
|
|
634
|
+
mine = _is_fd_of(fd, path)
|
|
615
635
|
real_close(fd)
|
|
616
|
-
|
|
636
|
+
if mine:
|
|
637
|
+
raise _oserror_on(path)
|
|
617
638
|
|
|
618
639
|
monkeypatch.setattr(bp.os, "close", failing_close)
|
|
619
640
|
with pytest.raises(bp.BillingPlanError) as info:
|
|
@@ -626,8 +647,10 @@ def test_close_oserror_does_not_replace_an_earlier_error(tmp_path, monkeypatch):
|
|
|
626
647
|
real_close = os.close
|
|
627
648
|
|
|
628
649
|
def failing_close(fd):
|
|
650
|
+
mine = _is_fd_of(fd, path)
|
|
629
651
|
real_close(fd)
|
|
630
|
-
|
|
652
|
+
if mine:
|
|
653
|
+
raise _oserror_on(path)
|
|
631
654
|
|
|
632
655
|
monkeypatch.setattr(bp.os, "close", failing_close)
|
|
633
656
|
with pytest.raises(bp.BillingPlanError) as info:
|
|
@@ -886,7 +886,7 @@ def test_rates_show_model_without_tiers_prints_no_prompt_tiers(capsys):
|
|
|
886
886
|
def test_rates_validate_packaged_catalog_with_prompt_tiers_exits_zero(capsys):
|
|
887
887
|
rc = cli.main(["rates", "validate"])
|
|
888
888
|
assert rc == 0
|
|
889
|
-
assert "catalog_version=2026-10
|
|
889
|
+
assert "catalog_version=2026-11-10" in capsys.readouterr().out
|
|
890
890
|
|
|
891
891
|
|
|
892
892
|
# ---------------------------------------------------------------------------
|
|
@@ -19,7 +19,7 @@ architect レビュー (3 巡目) と builder レビューで、既存テスト
|
|
|
19
19
|
かつ確定金額が計上されない。境界ちょうどは priced になる。
|
|
20
20
|
|
|
21
21
|
条件D (PR レビュー3点目・追加分): catalog は
|
|
22
|
-
catalog_version == "2026-10
|
|
22
|
+
catalog_version == "2026-11-10"(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-10
|
|
227
|
+
"""条件D: catalog_version == "2026-11-10"(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-10
|
|
236
|
+
assert catalog.catalog_version == "2026-11-10"
|
|
237
237
|
|
|
238
238
|
matches = [
|
|
239
239
|
s
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Acceptance tests for claude-fable-5-2 / claude-mythos-5-2 (catalog_version 2026-11-10).
|
|
2
|
+
|
|
3
|
+
Source: platform.claude.com/docs/en/about-claude/pricing (retrieved 2026-11-10) and the
|
|
4
|
+
announcement anthropic.com/claude-fable-and-mythos-5-2 (published 2026-11-09).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from decimal import Decimal
|
|
9
|
+
|
|
10
|
+
from agent_cost.rates import load_rates
|
|
11
|
+
|
|
12
|
+
USD = {
|
|
13
|
+
"input_nocache": "8.0",
|
|
14
|
+
"cache_read": "0.20",
|
|
15
|
+
"cache_write_5m": "10.0",
|
|
16
|
+
"cache_write_1h": "16.0",
|
|
17
|
+
"output": "40.0",
|
|
18
|
+
}
|
|
19
|
+
MODELS = ("claude-fable-5-2", "claude-mythos-5-2")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def dt(s):
|
|
23
|
+
return datetime.fromisoformat(s)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_fable_and_mythos_5_2_resolve_with_pricing_page_values_from_launch():
|
|
27
|
+
catalog = load_rates()
|
|
28
|
+
for model in MODELS:
|
|
29
|
+
for occurred_at in ("2026-11-09T00:00:00+00:00", "2026-11-10T03:00:00+00:00", "2027-06-01T00:00:00+00:00"):
|
|
30
|
+
resolved, period = catalog.rate_for(model, dt(occurred_at))
|
|
31
|
+
assert resolved == model
|
|
32
|
+
assert period is not None, (model, occurred_at)
|
|
33
|
+
assert period.rate_id == f"{model}-launch-2026-11-09"
|
|
34
|
+
assert period.effective_until is None
|
|
35
|
+
assert period.prompt_tiers == ()
|
|
36
|
+
for kind, value in USD.items():
|
|
37
|
+
assert period.values[kind] == Decimal(value), (model, kind)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_fable_and_mythos_5_2_are_unpriced_before_launch():
|
|
41
|
+
catalog = load_rates()
|
|
42
|
+
for model in MODELS:
|
|
43
|
+
resolved, period = catalog.rate_for(model, dt("2026-11-08T23:59:59+00:00"))
|
|
44
|
+
assert resolved == model
|
|
45
|
+
assert period is None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_cache_read_is_0_025x_and_fast_mode_is_2x():
|
|
49
|
+
catalog = load_rates()
|
|
50
|
+
for model in MODELS:
|
|
51
|
+
entry = catalog.models[model]
|
|
52
|
+
assert entry.aliases == ()
|
|
53
|
+
assert entry.fast_multiplier == Decimal("2.0") # fast mode $16 / $80
|
|
54
|
+
assert len(entry.rates) == 1
|
|
55
|
+
_, period = catalog.rate_for(model, dt("2026-11-10T00:00:00+00:00"))
|
|
56
|
+
assert period.values["cache_read"] == period.values["input_nocache"] * Decimal("0.025")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_separate_entries_not_aliases():
|
|
60
|
+
catalog = load_rates()
|
|
61
|
+
for model in MODELS:
|
|
62
|
+
for other in catalog.models.values():
|
|
63
|
+
assert model not in other.aliases
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_fable_5_1_is_unchanged_and_mythos_5_1_stays_unpriced():
|
|
67
|
+
catalog = load_rates()
|
|
68
|
+
_, period = catalog.rate_for("claude-fable-5-1", dt("2026-11-10T00:00:00+00:00"))
|
|
69
|
+
assert period.rate_id == "claude-fable-5-1-local-first-observed-2026-09-02"
|
|
70
|
+
assert period.values["input_nocache"] == Decimal("10.0")
|
|
71
|
+
assert period.values["cache_read"] == Decimal("0.25")
|
|
72
|
+
assert period.values["output"] == Decimal("50.0")
|
|
73
|
+
assert "claude-mythos-5-1" not in catalog.models
|
|
74
|
+
_, period = catalog.rate_for("claude-mythos-5-1", dt("2026-11-10T00:00:00+00:00"))
|
|
75
|
+
assert period is None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_catalog_version_and_sources_record_fable_5_2():
|
|
79
|
+
catalog = load_rates()
|
|
80
|
+
assert catalog.catalog_version == "2026-11-10"
|
|
81
|
+
urls = [(s.get("url"), s.get("retrieved_at")) for s in catalog.sources]
|
|
82
|
+
assert ("https://www.anthropic.com/claude-fable-and-mythos-5-2", "2026-11-10") in urls
|
|
83
|
+
assert ("https://platform.claude.com/docs/en/about-claude/pricing", "2026-11-10") in urls
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""Acceptance tests for gpt-6.1-terra / gpt-6.1-sol / codex-auto-review (catalog_version 2026-11-09).
|
|
2
|
+
|
|
3
|
+
Source: human-approved price table pricing-2026-11-v4 (developers.openai.com/api/docs/pricing,
|
|
4
|
+
retrieved 2026-11-05; standard tier, short context). codex-auto-review (Codex automatic
|
|
5
|
+
review / guardian subagent) has no published price; priced as gpt-6.1-terra by a human
|
|
6
|
+
decision on 2026-11-06.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from datetime import datetime, timezone
|
|
11
|
+
from decimal import Decimal
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
import agent_cost
|
|
15
|
+
from agent_cost.rates import load_rates
|
|
16
|
+
|
|
17
|
+
UTC = timezone.utc
|
|
18
|
+
|
|
19
|
+
EXPECTED = {
|
|
20
|
+
"gpt-6.1-terra": (
|
|
21
|
+
"gpt-6.1-terra-launch-date-unconfirmed",
|
|
22
|
+
{"input_nocache": "1.00", "cache_read": "0.05", "output": "5.00"},
|
|
23
|
+
{"input_nocache": "25.0", "cache_read": "1.25", "output": "125.0"},
|
|
24
|
+
),
|
|
25
|
+
"gpt-6.1-sol": (
|
|
26
|
+
"gpt-6.1-sol-launch-date-unconfirmed",
|
|
27
|
+
{"input_nocache": "2.00", "cache_read": "0.10", "output": "10.00"},
|
|
28
|
+
{"input_nocache": "50.0", "cache_read": "2.5", "output": "250.0"},
|
|
29
|
+
),
|
|
30
|
+
"codex-auto-review": (
|
|
31
|
+
"codex-auto-review-2026-11-terra-equivalent",
|
|
32
|
+
{"input_nocache": "1.00", "cache_read": "0.05", "output": "5.00"},
|
|
33
|
+
{"input_nocache": "25.0", "cache_read": "1.25", "output": "125.0"},
|
|
34
|
+
),
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def dt(s):
|
|
39
|
+
return datetime.fromisoformat(s)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_gpt_6_1_models_resolve_with_pricing_page_values_from_effective_from():
|
|
43
|
+
catalog = load_rates()
|
|
44
|
+
for model, (rate_id, usd, _credits) in EXPECTED.items():
|
|
45
|
+
for occurred_at in ("2026-10-01T00:00:00+00:00", "2026-11-04T07:49:42+00:00", "2027-01-01T00:00:00+00:00"):
|
|
46
|
+
resolved, period = catalog.rate_for(model, dt(occurred_at))
|
|
47
|
+
assert resolved == model
|
|
48
|
+
assert period is not None, (model, occurred_at)
|
|
49
|
+
assert period.rate_id == rate_id
|
|
50
|
+
assert period.effective_until is None
|
|
51
|
+
for kind, value in usd.items():
|
|
52
|
+
assert period.values[kind] == Decimal(value), (model, kind)
|
|
53
|
+
assert period.values["cache_write_5m"] is None
|
|
54
|
+
assert period.values["cache_write_1h"] is None
|
|
55
|
+
assert period.prompt_tiers == ()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_gpt_6_1_models_are_unpriced_before_effective_from():
|
|
59
|
+
catalog = load_rates()
|
|
60
|
+
for model in EXPECTED:
|
|
61
|
+
resolved, period = catalog.rate_for(model, dt("2026-09-30T23:59:59+00:00"))
|
|
62
|
+
assert resolved == model
|
|
63
|
+
assert period is None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_gpt_6_1_models_credits_follow_usd_per_credit_and_entry_shape():
|
|
67
|
+
catalog = load_rates()
|
|
68
|
+
usd_per_credit = Decimal(catalog.usd_per_credit)
|
|
69
|
+
for model, (_rate_id, usd, credits) in EXPECTED.items():
|
|
70
|
+
entry = catalog.models[model]
|
|
71
|
+
assert entry.aliases == ()
|
|
72
|
+
assert entry.fast_multiplier == Decimal("1.0")
|
|
73
|
+
assert entry.credits_per_mtok["cache_write_5m"] is None
|
|
74
|
+
assert entry.credits_per_mtok["cache_write_1h"] is None
|
|
75
|
+
for kind, value in credits.items():
|
|
76
|
+
assert entry.credits_per_mtok[kind] == Decimal(value), (model, kind)
|
|
77
|
+
assert entry.credits_per_mtok[kind] * usd_per_credit == Decimal(usd[kind])
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_codex_auto_review_is_priced_like_gpt_6_1_terra_but_is_its_own_entry():
|
|
81
|
+
catalog = load_rates()
|
|
82
|
+
at = dt("2026-11-06T00:00:00+00:00")
|
|
83
|
+
_, terra = catalog.rate_for("gpt-6.1-terra", at)
|
|
84
|
+
_, review = catalog.rate_for("codex-auto-review", at)
|
|
85
|
+
assert review.values == terra.values
|
|
86
|
+
assert review.rate_id != terra.rate_id
|
|
87
|
+
assert "codex-auto-review" not in catalog.models["gpt-6.1-terra"].aliases
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def test_unknown_gpt_6_1_luna_stays_unpriced():
|
|
91
|
+
catalog = load_rates()
|
|
92
|
+
assert "gpt-6.1-luna" not in catalog.models
|
|
93
|
+
resolved, period = catalog.rate_for("gpt-6.1-luna", dt("2026-11-06T00:00:00+00:00"))
|
|
94
|
+
assert period is None
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_existing_gpt_5_6_terra_values_are_unchanged():
|
|
98
|
+
catalog = load_rates()
|
|
99
|
+
entry = catalog.models["gpt-5.6-terra"]
|
|
100
|
+
assert len(entry.rates) == 1
|
|
101
|
+
_, period = catalog.rate_for("gpt-5.6-terra", dt("2026-11-06T00:00:00+00:00"))
|
|
102
|
+
assert period.rate_id == "gpt-5.6-terra-2026-07-secondary-sourced"
|
|
103
|
+
assert period.values["input_nocache"] == Decimal("2.50")
|
|
104
|
+
assert period.values["cache_read"] == Decimal("0.25")
|
|
105
|
+
assert period.values["output"] == Decimal("15.0")
|
|
106
|
+
assert entry.credits_per_mtok["input_nocache"] == Decimal("62.5")
|
|
107
|
+
assert entry.credits_per_mtok["cache_read"] == Decimal("6.25")
|
|
108
|
+
assert entry.credits_per_mtok["output"] == Decimal("375.0")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def test_catalog_version_and_source_record_the_gpt_6_1_pricing_page():
|
|
112
|
+
catalog = load_rates()
|
|
113
|
+
assert catalog.catalog_version >= "2026-11-09"
|
|
114
|
+
urls = [(s.get("url"), s.get("retrieved_at")) for s in catalog.sources]
|
|
115
|
+
assert urls.count(("https://developers.openai.com/api/docs/pricing", "2026-11-05")) == 1
|
|
116
|
+
raw = json.loads((Path(agent_cost.__file__).parent / "rates.json").read_text(encoding="utf-8"))
|
|
117
|
+
assert any("codex-auto-review" in n and "2026-11-06" in n for n in raw["notes"])
|
|
@@ -79,7 +79,7 @@ def test_claude_haiku_5_5_cache_multipliers_are_standard_in_every_tier_and_no_fa
|
|
|
79
79
|
|
|
80
80
|
def test_catalog_version_schema_version_and_sources_record_the_haiku_5_5_primary_sources():
|
|
81
81
|
catalog = load_rates()
|
|
82
|
-
assert catalog.catalog_version == "2026-10
|
|
82
|
+
assert catalog.catalog_version == "2026-11-10"
|
|
83
83
|
assert catalog.schema_version == "2"
|
|
84
84
|
urls = {(s.get("url"), s.get("retrieved_at")) for s in catalog.sources}
|
|
85
85
|
assert ("https://platform.claude.com/docs/en/about-claude/pricing", "2026-10-09") in urls
|
|
@@ -527,6 +527,7 @@ def test_packaged_catalog_existing_models_are_unchanged():
|
|
|
527
527
|
rows are never changed in place; a price change adds a new period.
|
|
528
528
|
"""
|
|
529
529
|
raw = json.loads(resources.files("agent_cost").joinpath("rates.json").read_bytes())
|
|
530
|
-
|
|
530
|
+
added_after = {"claude-haiku-5-5", "gpt-6.1-terra", "gpt-6.1-sol", "codex-auto-review", "claude-fable-5-2", "claude-mythos-5-2"}
|
|
531
|
+
existing = [m for m in raw["models"] if m["model_key"] not in added_after]
|
|
531
532
|
digest = hashlib.sha256(json.dumps(existing, sort_keys=True, separators=(",", ":")).encode()).hexdigest()
|
|
532
533
|
assert digest == _EXISTING_MODELS_SHA256
|
|
@@ -112,7 +112,7 @@ def test_claude_sonnet_5_5_cache_read_multiplier_per_period_and_no_fast_mode():
|
|
|
112
112
|
|
|
113
113
|
def test_catalog_version_and_sources_record_the_sonnet_5_5_primary_sources():
|
|
114
114
|
catalog = load_rates()
|
|
115
|
-
assert catalog.catalog_version == "2026-10
|
|
115
|
+
assert catalog.catalog_version == "2026-11-10"
|
|
116
116
|
urls = {(s.get("url"), s.get("retrieved_at")) for s in catalog.sources}
|
|
117
117
|
assert ("https://platform.claude.com/docs/en/about-claude/pricing", "2026-09-29") in urls
|
|
118
118
|
assert ("https://www.anthropic.com/claude-sonnet-5-5", "2026-09-29") in urls
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Spec: pyproject.toml's [project].version and agent_cost.__version__ must
|
|
2
|
-
agree, and both must read "0.5.
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
broken
|
|
2
|
+
agree, and both must read "0.5.3" for this change (the packaged catalog adds
|
|
3
|
+
claude-fable-5-2, claude-mythos-5-2, gpt-6.1-terra, gpt-6.1-sol and
|
|
4
|
+
codex-auto-review -- catalog entries only, with no code or schema change, so
|
|
5
|
+
it bumps the patch version). A broken
|
|
6
6
|
implementation would bump one file but not the other, or forget the bump
|
|
7
7
|
entirely.
|
|
8
8
|
|
|
@@ -31,5 +31,5 @@ def test_pyproject_version_matches_package_version():
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def test_version_is_0_5_2():
|
|
34
|
-
assert agent_cost.__version__ == "0.5.
|
|
35
|
-
assert _pyproject_version() == "0.5.
|
|
34
|
+
assert agent_cost.__version__ == "0.5.3"
|
|
35
|
+
assert _pyproject_version() == "0.5.3"
|
|
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
|
|
File without changes
|
|
File without changes
|
{coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/coding_agent_cost.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/coding_agent_cost.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{coding_agent_cost-0.5.2 → coding_agent_cost-0.5.3}/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
|
|
File without changes
|