agent-cost-tracker 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. agent_cost_tracker-0.2.1/LICENSE +21 -0
  2. agent_cost_tracker-0.2.1/PKG-INFO +227 -0
  3. agent_cost_tracker-0.2.1/README.md +205 -0
  4. agent_cost_tracker-0.2.1/pyproject.toml +37 -0
  5. agent_cost_tracker-0.2.1/setup.cfg +4 -0
  6. agent_cost_tracker-0.2.1/src/agent_cost/__init__.py +7 -0
  7. agent_cost_tracker-0.2.1/src/agent_cost/analyze.py +55 -0
  8. agent_cost_tracker-0.2.1/src/agent_cost/cli.py +141 -0
  9. agent_cost_tracker-0.2.1/src/agent_cost/compare.py +174 -0
  10. agent_cost_tracker-0.2.1/src/agent_cost/models.py +70 -0
  11. agent_cost_tracker-0.2.1/src/agent_cost/parsers/__init__.py +16 -0
  12. agent_cost_tracker-0.2.1/src/agent_cost/parsers/claude.py +148 -0
  13. agent_cost_tracker-0.2.1/src/agent_cost/parsers/codex.py +82 -0
  14. agent_cost_tracker-0.2.1/src/agent_cost/parsers/detect.py +190 -0
  15. agent_cost_tracker-0.2.1/src/agent_cost/parsers/hermes.py +36 -0
  16. agent_cost_tracker-0.2.1/src/agent_cost/parsers/opencode.py +318 -0
  17. agent_cost_tracker-0.2.1/src/agent_cost/pricing.py +191 -0
  18. agent_cost_tracker-0.2.1/src/agent_cost/report.py +187 -0
  19. agent_cost_tracker-0.2.1/src/agent_cost_tracker.egg-info/PKG-INFO +227 -0
  20. agent_cost_tracker-0.2.1/src/agent_cost_tracker.egg-info/SOURCES.txt +30 -0
  21. agent_cost_tracker-0.2.1/src/agent_cost_tracker.egg-info/dependency_links.txt +1 -0
  22. agent_cost_tracker-0.2.1/src/agent_cost_tracker.egg-info/entry_points.txt +2 -0
  23. agent_cost_tracker-0.2.1/src/agent_cost_tracker.egg-info/top_level.txt +1 -0
  24. agent_cost_tracker-0.2.1/tests/test_billing_modes.py +119 -0
  25. agent_cost_tracker-0.2.1/tests/test_claude_parser.py +17 -0
  26. agent_cost_tracker-0.2.1/tests/test_cli.py +38 -0
  27. agent_cost_tracker-0.2.1/tests/test_codex_parser.py +14 -0
  28. agent_cost_tracker-0.2.1/tests/test_compare.py +30 -0
  29. agent_cost_tracker-0.2.1/tests/test_detect.py +56 -0
  30. agent_cost_tracker-0.2.1/tests/test_hermes_parser.py +15 -0
  31. agent_cost_tracker-0.2.1/tests/test_opencode_parser.py +236 -0
  32. agent_cost_tracker-0.2.1/tests/test_pricing.py +65 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 yingxiangge
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,227 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-cost-tracker
3
+ Version: 0.2.1
4
+ Summary: Token, cache and context observability for AI coding agents.
5
+ Author: yingxiangge
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/yingxiangge/agent-cost
8
+ Project-URL: Repository, https://github.com/yingxiangge/agent-cost
9
+ Project-URL: Issues, https://github.com/yingxiangge/agent-cost/issues
10
+ Project-URL: Changelog, https://github.com/yingxiangge/agent-cost/blob/main/CHANGELOG.md
11
+ Keywords: llm,tokens,cost,observability,codex,hermes,agent,claude-code,opencode
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Software Development :: Quality Assurance
17
+ Classifier: Topic :: System :: Monitoring
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Dynamic: license-file
22
+
23
+ # agent-cost
24
+
25
+ [![CI](https://github.com/yingxiangge/agent-cost/actions/workflows/ci.yml/badge.svg)](https://github.com/yingxiangge/agent-cost/actions/workflows/ci.yml)
26
+ [![Python](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue)](https://www.python.org/)
27
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
28
+
29
+ **Token, cache and context observability for AI coding agents.**
30
+
31
+ AI coding agents are expensive not because they have no cache — they usually
32
+ have too much of it. `agent-cost` is a read-only CLI that shows you, per
33
+ session or across multiple agents, how many tokens were really burned, where
34
+ the context went, and which agent delivers the best prompt-caching efficiency.
35
+
36
+ It was built from real-world usage across Codex, Hermes, and Claude Code. Across
37
+ 72 real Claude Code sessions (63.7M characters of transcript), the context
38
+ attribution comes out as:
39
+
40
+ ```text
41
+ tool_output 94.8%
42
+ assistant 4.3%
43
+ user 0.5%
44
+ tool_calls 0.1%
45
+ ```
46
+
47
+ Those same sessions total 9.1B billed prompt tokens at a 98.7% cache hit rate —
48
+ a high hit rate does not protect you from unbounded context growth, it only
49
+ changes the unit price.
50
+
51
+ ## Install
52
+
53
+ ```bash
54
+ git clone https://github.com/yingxiangge/agent-cost.git
55
+ cd agent-cost
56
+ pip install -e .
57
+ ```
58
+
59
+ Requires Python 3.10+.
60
+
61
+ Not on PyPI yet. The distribution will be published as **`agent-cost-tracker`**
62
+ — `agent-cost` is taken on PyPI — while the command it installs stays
63
+ `agent-cost`:
64
+
65
+ ```bash
66
+ pip install agent-cost-tracker
67
+ pipx run --spec agent-cost-tracker agent-cost compare ~/.claude/projects/
68
+ ```
69
+
70
+ ## Usage
71
+
72
+ ```bash
73
+ # Compare usage, cache efficiency, and cost across multiple agents or sessions
74
+ agent-cost compare ~/.claude/projects/ ~/.codex/sessions/ ./hermes/
75
+
76
+ # Output structured JSON for analysis pipelines
77
+ agent-cost compare --json ~/.claude/projects/ ~/.codex/sessions/
78
+
79
+ # Inspect one session (Claude Code, Hermes, OpenCode, Codex, or a folder)
80
+ agent-cost inspect ~/.codex/sessions/2026/08/11/rollout-*.jsonl
81
+
82
+ # Context growth and actionable recommendations
83
+ agent-cost analyze ~/.codex/sessions/2026/08/11/
84
+
85
+ # Aggregate totals across sessions
86
+ agent-cost stats ~/.codex/sessions/2026/08/
87
+
88
+ # On a Claude Pro/Max subscription: report API-equivalent value, not spend
89
+ agent-cost --subscription compare ~/.claude/projects/
90
+ ```
91
+
92
+ ### Real example (`agent-cost compare`)
93
+
94
+ ```text
95
+ Agent Comparison Report
96
+ ══════════════════════════════════════════════════════════════════════════════
97
+ AGENT SESSIONS TOTAL TOKENS CACHED % TOOLS EST. USD AVG $/SESS
98
+ -------------------------------------------------------------------------------
99
+ hermes 2 2,071,557 89.9% 0 0.82* 0.41
100
+ claude-code 1 12,590 76.2% 1 0.02 0.02
101
+ opencode 1 8,130 83.1% 2 0.00 0.00
102
+ codex 1 111 0.0% 1 0.00 0.00
103
+ -------------------------------------------------------------------------------
104
+ TOTAL 5 2,092,388 0.84*
105
+
106
+ n/a / * = model has no rate card, excluded from dollar totals (1 of 5 sessions).
107
+
108
+ Key Insights:
109
+ • Highest cache efficiency: hermes (89.9% hit rate).
110
+ • Most tool intensive: opencode (2 total tool calls).
111
+ • Prompt caching saved approx. $0.03 across analyzed sessions.
112
+ • 1 of 5 sessions have no rate card and are excluded from every dollar
113
+ figure above. Supply rates with --pricing to include them.
114
+ ```
115
+
116
+ ### Real example (`agent-cost analyze`)
117
+
118
+ ```text
119
+ Analysis: 019feec8-4ee1-7560-9a9f-89952d1af2d3
120
+ ──────────────────────────────
121
+ Context growth: 24,072 -> 70,609 tokens (x2.93)
122
+ Largest context sources:
123
+ tool_output 83.6%
124
+ base_instructions 5.3%
125
+ assistant 4.5%
126
+ developer 3.3%
127
+ Compactions: 1
128
+ Prompt curve: 65K -> 66K -> 66K -> 70K -> 74K -> 80K
129
+
130
+ Recommendations:
131
+ - Prompt size is growing steeply; start a fresh session instead of continuing.
132
+ - Session was already compacted 1x; further work belongs in a new session.
133
+ - Tool output dominates context; consider truncating or filtering large command output.
134
+ ```
135
+
136
+ ## Supported data sources
137
+
138
+ - **Claude Code** (`~/.claude/projects/**/*.jsonl` or `.json`): real turn-by-turn
139
+ token usage with `input`, `output`, `cache_read_input_tokens`, and
140
+ `cache_creation_input_tokens` breakdown, plus tool calls.
141
+ - **Hermes** (`sessions.json`): real `input/output/cache_read/cache_write`
142
+ totals plus estimated cost when the agent has finalized them.
143
+ - **OpenCode** (`~/.local/share/opencode/opencode.db` SQLite database, or `.json` / `.jsonl` exports):
144
+ real turn-by-turn token usage, tool calls, and cache stats (`input`, `output`,
145
+ `cache.read`, `cache.write`).
146
+ - **Codex rollouts** (`~/.codex/sessions/**/*.jsonl`): turns, tool calls,
147
+ compaction events, prompt-size curve and context-source attribution.
148
+ Rollouts usually have no token counters, so prompt sizes are estimated from
149
+ content length (approx. 4 chars/token) and reported as estimates.
150
+
151
+ Parsing is intentionally read-only: files are only opened and counted, never
152
+ executed or modified. Database connections use read-only SQLite URIs.
153
+
154
+ ## Pricing
155
+
156
+ Costs are estimated from a built-in price table (see `pricing.py`) covering the
157
+ Claude family (Fable 5, Opus 5/4.8/4.7/4.6/4.5/4.1, Sonnet 5/4.6/4.5, Haiku 4.5,
158
+ plus the Claude 3.x generation), GPT-4o, GPT-5, o1, o3-mini, DeepSeek V3/R1,
159
+ Qwen 2.5 Coder, and Gemini. Anthropic rates are from the
160
+ [official pricing page](https://platform.claude.com/docs/en/about-claude/pricing)
161
+ as of 2026-08-16.
162
+
163
+ **A model that is not in the table is reported as `n/a`, never guessed.** It is
164
+ excluded from every dollar total, and the report says how many sessions that
165
+ covers. A wrong cost number is worse than no cost number, so there is no
166
+ default rate card to fall back on.
167
+
168
+ **Billing modes are priced per turn, not per session.** Fast mode and US-pinned
169
+ inference cost more and can be toggled mid-session, so usage is split into
170
+ `(speed, inference_geo)` buckets and each bucket is priced on its own card:
171
+
172
+ | Mode | Effect | Source |
173
+ |:---|:---|:---|
174
+ | `speed: "fast"` | Opus 5 / Opus 4.8 billed at **$10 / $50** instead of $5 / $25. Other models fall back to standard rates, matching the API. | `usage.speed` |
175
+ | `inference_geo: "us"` | **1.1x** on every token category. `global` / `not_available` are standard priced. | `usage.inference_geo` |
176
+
177
+ The two stack. `agent-cost inspect` lists the modes when a session used more
178
+ than one.
179
+
180
+ **On a subscription, pass `--subscription`.** Claude Pro/Max sessions do not
181
+ generate per-token charges, so the transcript's dollar value is what those
182
+ tokens *would* have cost on metered API billing — useful for comparing agents
183
+ and deciding when to restart a session, useless as a bill. The flag relabels
184
+ every figure as API-equivalent value. It has to be explicit: the transcript
185
+ carries no field distinguishing subscription from API usage.
186
+
187
+ One remaining approximation: `cache_write` uses the 5-minute rate (1.25x input),
188
+ because the usage payload does not record which cache TTL was used — sessions
189
+ on the 1-hour cache (2x input) are undercounted.
190
+
191
+ Supply your own rates to override any of this:
192
+
193
+ ```bash
194
+ agent-cost --pricing "$(cat my-pricing.json)" compare ~/.claude/projects/
195
+ export AGENT_COST_PRICING="$(cat my-pricing.json)"
196
+ ```
197
+
198
+ Your entries are merged over the built-in table, so overriding one model leaves
199
+ the rest intact. Copy [`pricing.example.json`](pricing.example.json) as a
200
+ starting template. Note that `--pricing` is a global flag and must come *before*
201
+ the subcommand.
202
+
203
+ Model names resolve by exact match first, then by longest matching prefix, so a
204
+ `claude-opus-4-5` entry also covers `claude-opus-4-5-20260101`, and `gpt-5-mini`
205
+ is never priced as `gpt-5`.
206
+
207
+ ## Roadmap
208
+
209
+ - [x] `agent-cost compare`: side-by-side agent comparison with `--by-agent` and `--json`
210
+ - [x] Claude Code / Codex / Hermes session parsing
211
+ - [x] OpenCode: SQLite database (`opencode.db`) and JSON export parsing
212
+ - [ ] Support Cursor (`composer.json` / workspace state) log formats
213
+ - [ ] Support Cline / Roo Code conversation history formats
214
+ - [ ] `agent-cost watch`: budget thresholds with warnings before a session blows up
215
+ - [ ] Tool-call-level cost attribution when providers expose per-request usage
216
+
217
+ ## Contributing
218
+
219
+ Bug reports are especially welcome — particularly a session that parses
220
+ incorrectly. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, tests, and how to
221
+ add support for a new session format. Please never attach a raw session file to
222
+ an issue; strip it first.
223
+
224
+ ## Security
225
+
226
+ See [SECURITY.md](SECURITY.md). Session files are untrusted input; this tool
227
+ never executes them, never renders them, and never sends data anywhere.
@@ -0,0 +1,205 @@
1
+ # agent-cost
2
+
3
+ [![CI](https://github.com/yingxiangge/agent-cost/actions/workflows/ci.yml/badge.svg)](https://github.com/yingxiangge/agent-cost/actions/workflows/ci.yml)
4
+ [![Python](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue)](https://www.python.org/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
6
+
7
+ **Token, cache and context observability for AI coding agents.**
8
+
9
+ AI coding agents are expensive not because they have no cache — they usually
10
+ have too much of it. `agent-cost` is a read-only CLI that shows you, per
11
+ session or across multiple agents, how many tokens were really burned, where
12
+ the context went, and which agent delivers the best prompt-caching efficiency.
13
+
14
+ It was built from real-world usage across Codex, Hermes, and Claude Code. Across
15
+ 72 real Claude Code sessions (63.7M characters of transcript), the context
16
+ attribution comes out as:
17
+
18
+ ```text
19
+ tool_output 94.8%
20
+ assistant 4.3%
21
+ user 0.5%
22
+ tool_calls 0.1%
23
+ ```
24
+
25
+ Those same sessions total 9.1B billed prompt tokens at a 98.7% cache hit rate —
26
+ a high hit rate does not protect you from unbounded context growth, it only
27
+ changes the unit price.
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ git clone https://github.com/yingxiangge/agent-cost.git
33
+ cd agent-cost
34
+ pip install -e .
35
+ ```
36
+
37
+ Requires Python 3.10+.
38
+
39
+ Not on PyPI yet. The distribution will be published as **`agent-cost-tracker`**
40
+ — `agent-cost` is taken on PyPI — while the command it installs stays
41
+ `agent-cost`:
42
+
43
+ ```bash
44
+ pip install agent-cost-tracker
45
+ pipx run --spec agent-cost-tracker agent-cost compare ~/.claude/projects/
46
+ ```
47
+
48
+ ## Usage
49
+
50
+ ```bash
51
+ # Compare usage, cache efficiency, and cost across multiple agents or sessions
52
+ agent-cost compare ~/.claude/projects/ ~/.codex/sessions/ ./hermes/
53
+
54
+ # Output structured JSON for analysis pipelines
55
+ agent-cost compare --json ~/.claude/projects/ ~/.codex/sessions/
56
+
57
+ # Inspect one session (Claude Code, Hermes, OpenCode, Codex, or a folder)
58
+ agent-cost inspect ~/.codex/sessions/2026/08/11/rollout-*.jsonl
59
+
60
+ # Context growth and actionable recommendations
61
+ agent-cost analyze ~/.codex/sessions/2026/08/11/
62
+
63
+ # Aggregate totals across sessions
64
+ agent-cost stats ~/.codex/sessions/2026/08/
65
+
66
+ # On a Claude Pro/Max subscription: report API-equivalent value, not spend
67
+ agent-cost --subscription compare ~/.claude/projects/
68
+ ```
69
+
70
+ ### Real example (`agent-cost compare`)
71
+
72
+ ```text
73
+ Agent Comparison Report
74
+ ══════════════════════════════════════════════════════════════════════════════
75
+ AGENT SESSIONS TOTAL TOKENS CACHED % TOOLS EST. USD AVG $/SESS
76
+ -------------------------------------------------------------------------------
77
+ hermes 2 2,071,557 89.9% 0 0.82* 0.41
78
+ claude-code 1 12,590 76.2% 1 0.02 0.02
79
+ opencode 1 8,130 83.1% 2 0.00 0.00
80
+ codex 1 111 0.0% 1 0.00 0.00
81
+ -------------------------------------------------------------------------------
82
+ TOTAL 5 2,092,388 0.84*
83
+
84
+ n/a / * = model has no rate card, excluded from dollar totals (1 of 5 sessions).
85
+
86
+ Key Insights:
87
+ • Highest cache efficiency: hermes (89.9% hit rate).
88
+ • Most tool intensive: opencode (2 total tool calls).
89
+ • Prompt caching saved approx. $0.03 across analyzed sessions.
90
+ • 1 of 5 sessions have no rate card and are excluded from every dollar
91
+ figure above. Supply rates with --pricing to include them.
92
+ ```
93
+
94
+ ### Real example (`agent-cost analyze`)
95
+
96
+ ```text
97
+ Analysis: 019feec8-4ee1-7560-9a9f-89952d1af2d3
98
+ ──────────────────────────────
99
+ Context growth: 24,072 -> 70,609 tokens (x2.93)
100
+ Largest context sources:
101
+ tool_output 83.6%
102
+ base_instructions 5.3%
103
+ assistant 4.5%
104
+ developer 3.3%
105
+ Compactions: 1
106
+ Prompt curve: 65K -> 66K -> 66K -> 70K -> 74K -> 80K
107
+
108
+ Recommendations:
109
+ - Prompt size is growing steeply; start a fresh session instead of continuing.
110
+ - Session was already compacted 1x; further work belongs in a new session.
111
+ - Tool output dominates context; consider truncating or filtering large command output.
112
+ ```
113
+
114
+ ## Supported data sources
115
+
116
+ - **Claude Code** (`~/.claude/projects/**/*.jsonl` or `.json`): real turn-by-turn
117
+ token usage with `input`, `output`, `cache_read_input_tokens`, and
118
+ `cache_creation_input_tokens` breakdown, plus tool calls.
119
+ - **Hermes** (`sessions.json`): real `input/output/cache_read/cache_write`
120
+ totals plus estimated cost when the agent has finalized them.
121
+ - **OpenCode** (`~/.local/share/opencode/opencode.db` SQLite database, or `.json` / `.jsonl` exports):
122
+ real turn-by-turn token usage, tool calls, and cache stats (`input`, `output`,
123
+ `cache.read`, `cache.write`).
124
+ - **Codex rollouts** (`~/.codex/sessions/**/*.jsonl`): turns, tool calls,
125
+ compaction events, prompt-size curve and context-source attribution.
126
+ Rollouts usually have no token counters, so prompt sizes are estimated from
127
+ content length (approx. 4 chars/token) and reported as estimates.
128
+
129
+ Parsing is intentionally read-only: files are only opened and counted, never
130
+ executed or modified. Database connections use read-only SQLite URIs.
131
+
132
+ ## Pricing
133
+
134
+ Costs are estimated from a built-in price table (see `pricing.py`) covering the
135
+ Claude family (Fable 5, Opus 5/4.8/4.7/4.6/4.5/4.1, Sonnet 5/4.6/4.5, Haiku 4.5,
136
+ plus the Claude 3.x generation), GPT-4o, GPT-5, o1, o3-mini, DeepSeek V3/R1,
137
+ Qwen 2.5 Coder, and Gemini. Anthropic rates are from the
138
+ [official pricing page](https://platform.claude.com/docs/en/about-claude/pricing)
139
+ as of 2026-08-16.
140
+
141
+ **A model that is not in the table is reported as `n/a`, never guessed.** It is
142
+ excluded from every dollar total, and the report says how many sessions that
143
+ covers. A wrong cost number is worse than no cost number, so there is no
144
+ default rate card to fall back on.
145
+
146
+ **Billing modes are priced per turn, not per session.** Fast mode and US-pinned
147
+ inference cost more and can be toggled mid-session, so usage is split into
148
+ `(speed, inference_geo)` buckets and each bucket is priced on its own card:
149
+
150
+ | Mode | Effect | Source |
151
+ |:---|:---|:---|
152
+ | `speed: "fast"` | Opus 5 / Opus 4.8 billed at **$10 / $50** instead of $5 / $25. Other models fall back to standard rates, matching the API. | `usage.speed` |
153
+ | `inference_geo: "us"` | **1.1x** on every token category. `global` / `not_available` are standard priced. | `usage.inference_geo` |
154
+
155
+ The two stack. `agent-cost inspect` lists the modes when a session used more
156
+ than one.
157
+
158
+ **On a subscription, pass `--subscription`.** Claude Pro/Max sessions do not
159
+ generate per-token charges, so the transcript's dollar value is what those
160
+ tokens *would* have cost on metered API billing — useful for comparing agents
161
+ and deciding when to restart a session, useless as a bill. The flag relabels
162
+ every figure as API-equivalent value. It has to be explicit: the transcript
163
+ carries no field distinguishing subscription from API usage.
164
+
165
+ One remaining approximation: `cache_write` uses the 5-minute rate (1.25x input),
166
+ because the usage payload does not record which cache TTL was used — sessions
167
+ on the 1-hour cache (2x input) are undercounted.
168
+
169
+ Supply your own rates to override any of this:
170
+
171
+ ```bash
172
+ agent-cost --pricing "$(cat my-pricing.json)" compare ~/.claude/projects/
173
+ export AGENT_COST_PRICING="$(cat my-pricing.json)"
174
+ ```
175
+
176
+ Your entries are merged over the built-in table, so overriding one model leaves
177
+ the rest intact. Copy [`pricing.example.json`](pricing.example.json) as a
178
+ starting template. Note that `--pricing` is a global flag and must come *before*
179
+ the subcommand.
180
+
181
+ Model names resolve by exact match first, then by longest matching prefix, so a
182
+ `claude-opus-4-5` entry also covers `claude-opus-4-5-20260101`, and `gpt-5-mini`
183
+ is never priced as `gpt-5`.
184
+
185
+ ## Roadmap
186
+
187
+ - [x] `agent-cost compare`: side-by-side agent comparison with `--by-agent` and `--json`
188
+ - [x] Claude Code / Codex / Hermes session parsing
189
+ - [x] OpenCode: SQLite database (`opencode.db`) and JSON export parsing
190
+ - [ ] Support Cursor (`composer.json` / workspace state) log formats
191
+ - [ ] Support Cline / Roo Code conversation history formats
192
+ - [ ] `agent-cost watch`: budget thresholds with warnings before a session blows up
193
+ - [ ] Tool-call-level cost attribution when providers expose per-request usage
194
+
195
+ ## Contributing
196
+
197
+ Bug reports are especially welcome — particularly a session that parses
198
+ incorrectly. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, tests, and how to
199
+ add support for a new session format. Please never attach a raw session file to
200
+ an issue; strip it first.
201
+
202
+ ## Security
203
+
204
+ See [SECURITY.md](SECURITY.md). Session files are untrusted input; this tool
205
+ never executes them, never renders them, and never sends data anywhere.
@@ -0,0 +1,37 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "agent-cost-tracker"
7
+ version = "0.2.1"
8
+ description = "Token, cache and context observability for AI coding agents."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ authors = [{ name = "yingxiangge" }]
13
+ keywords = ["llm", "tokens", "cost", "observability", "codex", "hermes", "agent", "claude-code", "opencode"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.10",
17
+ "Programming Language :: Python :: 3.11",
18
+ "Programming Language :: Python :: 3.12",
19
+ "Topic :: Software Development :: Quality Assurance",
20
+ "Topic :: System :: Monitoring",
21
+ ]
22
+
23
+ [project.urls]
24
+ Homepage = "https://github.com/yingxiangge/agent-cost"
25
+ Repository = "https://github.com/yingxiangge/agent-cost"
26
+ Issues = "https://github.com/yingxiangge/agent-cost/issues"
27
+ Changelog = "https://github.com/yingxiangge/agent-cost/blob/main/CHANGELOG.md"
28
+
29
+ [project.scripts]
30
+ agent-cost = "agent_cost.cli:main"
31
+
32
+ [tool.setuptools.packages.find]
33
+ where = ["src"]
34
+
35
+ [tool.pytest.ini_options]
36
+ testpaths = ["tests"]
37
+ pythonpath = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,7 @@
1
+ """Token, cache and context observability for AI coding agents."""
2
+
3
+ from .models import SessionStats
4
+ from .pricing import estimate_cost
5
+
6
+ __all__ = ["SessionStats", "estimate_cost"]
7
+ __version__ = "0.1.0"
@@ -0,0 +1,55 @@
1
+ from __future__ import annotations
2
+
3
+ from agent_cost.models import SessionStats
4
+
5
+
6
+ def analyze(stats: SessionStats) -> dict:
7
+ """Derive actionable signals from session statistics."""
8
+ signals: dict = {"recommendations": [], "context_growth": None, "largest_sources": []}
9
+
10
+ samples = [s["estimated_prompt_tokens"] for s in stats.context_samples]
11
+ if len(samples) >= 4:
12
+ half = len(samples) // 2
13
+ first = sum(samples[:half]) / half
14
+ second = sum(samples[half:]) / (len(samples) - half)
15
+ ratio = second / first if first else 0.0
16
+ signals["context_growth"] = {
17
+ "first_half_avg": round(first),
18
+ "second_half_avg": round(second),
19
+ "growth_ratio": round(ratio, 2),
20
+ }
21
+ if ratio >= 2.5:
22
+ signals["recommendations"].append(
23
+ "Prompt size is growing steeply; start a fresh session instead of continuing."
24
+ )
25
+ elif ratio >= 1.6:
26
+ signals["recommendations"].append(
27
+ "Context is growing steadily; budget a /compact or a new session soon."
28
+ )
29
+
30
+ if stats.compaction_events:
31
+ signals["recommendations"].append(
32
+ f"Session was already compacted {stats.compaction_events}x; further work belongs in a new session."
33
+ )
34
+
35
+ if stats.turns >= 25 and not stats.context_samples:
36
+ signals["recommendations"].append("High turn count; review whether a new session would be cheaper.")
37
+
38
+ has_cache_data = bool(stats.cache_read_tokens or stats.cache_write_tokens)
39
+ if has_cache_data and stats.cache_hit_rate < 0.4 and stats.prompt_tokens:
40
+ signals["recommendations"].append(
41
+ "Low cache hit rate; same-prefix reuse is low, which usually inflates input cost."
42
+ )
43
+
44
+ total_chars = sum(stats.source_chars.values())
45
+ if total_chars:
46
+ ranked = sorted(stats.source_chars.items(), key=lambda kv: kv[1], reverse=True)[:4]
47
+ signals["largest_sources"] = [
48
+ {"source": k, "percent": round(v * 100 / total_chars, 1)} for k, v in ranked
49
+ ]
50
+ if any(k == "tool_output" for k, _ in ranked[:2]):
51
+ signals["recommendations"].append(
52
+ "Tool output dominates context; consider truncating or filtering large command output."
53
+ )
54
+
55
+ return signals