agentshim 0.23.1__tar.gz → 0.24.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.
- {agentshim-0.23.1 → agentshim-0.24.1}/CHANGELOG.md +116 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/PKG-INFO +5 -2
- {agentshim-0.23.1 → agentshim-0.24.1}/README.md +4 -1
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/__init__.py +81 -1
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/__init__.py +61 -2
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/plugin.py +39 -0
- agentshim-0.24.1/agentshim/core/rates.py +235 -0
- agentshim-0.24.1/agentshim/core/transcripts.py +279 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/usage.py +98 -2
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/pricing.py +9 -2
- agentshim-0.24.1/agentshim/providers/claude/cost.py +236 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/events.py +3 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/model_data.py +29 -44
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/parser.py +38 -11
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/plugin.py +5 -1
- agentshim-0.24.1/agentshim/providers/claude/prices_generated.py +158 -0
- agentshim-0.24.1/agentshim/providers/claude/transcripts.py +342 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/app_server/transport.py +34 -9
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/model_data.py +15 -40
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/plugin.py +4 -1
- agentshim-0.24.1/agentshim/providers/codex/prices_generated.py +285 -0
- agentshim-0.24.1/agentshim/providers/codex/speed.py +14 -0
- agentshim-0.24.1/agentshim/providers/codex/transcripts.py +402 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/static_plugin.py +24 -1
- agentshim-0.24.1/agentshim/rates.py +577 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/testing/__init__.py +3 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/testing/codex_app_server.py +8 -1
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/testing/contracts.py +28 -0
- agentshim-0.24.1/agentshim/testing/rates.py +55 -0
- agentshim-0.24.1/agentshim/transcripts.py +565 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/pyproject.toml +1 -1
- agentshim-0.24.1/tests/fixtures/claude_session/README.md +19 -0
- agentshim-0.23.1/agentshim/providers/claude/cost.py +0 -140
- {agentshim-0.23.1 → agentshim-0.24.1}/.gitignore +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/LICENSE +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/agent.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/_files.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/auth.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/checkpoints.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/clock.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/conversation.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/env.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/errors.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/events.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/home.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/ids.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/mcp.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/models.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/permissions.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/pricing.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/profile.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/provider.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/schema.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/session_policy.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/skills.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/status.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/stream.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/core/turn.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/execution/__init__.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/execution/confinement.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/execution/docker.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/execution/executor.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/execution/host.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/execution/process.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/execution/readiness.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/execution/transform.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/models.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/oneshot.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/probe.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/__init__.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/_testing.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/catalog.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/__init__.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/failures.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/hooks/__init__.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/hooks/confine_reads.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/probe.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/provider.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/rate_limits.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/sandbox.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/scripted.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/stream_argv.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/stream_transport.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/testing.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/tools.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/claude/user_hooks.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/__init__.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/_toml.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/app_server/__init__.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/app_server/_wire.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/app_server/approvals.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/app_server/channel.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/app_server/errors.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/app_server/items.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/app_server/mcp.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/app_server/permissions.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/app_server/profile.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/app_server/protocol.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/app_server/rate_limits.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/app_server/usage.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/events.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/failures.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/mcp_scope.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/parser.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/probe.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/provider.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/rules.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/sandbox.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/scripted.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/skills.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/codex/testing.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/copilot/__init__.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/copilot/events.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/copilot/parser.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/copilot/plugin.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/copilot/probe.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/copilot/provider.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/copilot/scripted.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/copilot/testing.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/gemini/__init__.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/gemini/events.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/gemini/parser.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/gemini/plugin.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/gemini/probe.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/gemini/provider.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/gemini/scripted.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/gemini/testing.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/opencode/__init__.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/opencode/events.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/opencode/model_data.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/opencode/parser.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/opencode/plugin.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/opencode/probe.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/opencode/provider.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/opencode/scripted.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/providers/opencode/testing.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/py.typed +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/runtime.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/session.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/testing/claude_stream.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/testing/clock.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/testing/confinement.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/testing/conversation.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/testing/probe.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/agentshim/testing/process.py +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/tests/fixtures/claude/README.md +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/tests/fixtures/claude_stream/README.md +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/tests/fixtures/codex/README.md +0 -0
- {agentshim-0.23.1 → agentshim-0.24.1}/tests/fixtures/codex_app_server/README.md +0 -0
|
@@ -1,5 +1,121 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.24.1 (2026-10-31)
|
|
4
|
+
|
|
5
|
+
Fixes the usage numbers 0.24.0 got wrong. Recorded cost does not move for any single-result turn:
|
|
6
|
+
every price, `price_for` and `cost_usd` are as in 0.24.0, and `tests/fixtures/recorded_costs.json`
|
|
7
|
+
still proves it.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **Claude transcripts undercounted output by about a third.** The CLI writes one line per content
|
|
12
|
+
block of a message, and the lines do not repeat the same usage: the prompt side is identical, but
|
|
13
|
+
`output_tokens` grows as the reply streams, from a few tokens on the first line to the whole reply
|
|
14
|
+
on the last. 0.24.0 kept the first line and dropped the rest. A message is now counted once, at
|
|
15
|
+
the most any line reported, and the records of a message add up to its final usage: the first
|
|
16
|
+
line yields the request (`turns=1`), each later line yields only the tokens it added (`turns=0`,
|
|
17
|
+
usually only output). Sum tokens over records, and count requests by summing `turns`. An advisor
|
|
18
|
+
call that shows only on a later line is counted too. A position saved by 0.24.0 has no such
|
|
19
|
+
counts, so it is refused and the file is read again from the start (`reset`), which also corrects
|
|
20
|
+
what 0.24.0 missed.
|
|
21
|
+
- **`ProviderUsage.by_model` counted the first turn after a steer twice.** `modelUsage` is
|
|
22
|
+
cumulative over the CLI process, and the parser added each result's rows to the last. The rows of
|
|
23
|
+
a run are now those of its last result, which cover the run once, and the rows sum to
|
|
24
|
+
`total_cost_usd`. The same seam is fixed for the primary row's `turns` (the run's, not the last
|
|
25
|
+
result's) and for the one-hour share of cache writes (the run's, applied to the run's writes), so a
|
|
26
|
+
steered run whose results differ in cache TTL is no longer priced at the last result's share.
|
|
27
|
+
A single result is unchanged.
|
|
28
|
+
- **A moved Codex session file was counted twice.** Codex archives a rollout by moving it from
|
|
29
|
+
`sessions` to `archived_sessions` under the same name. agentshim now owns that: a file with the
|
|
30
|
+
name of one already read is read on from the furthest position held for it (after the usual check
|
|
31
|
+
of the bytes before that position), and a copy that is shorter than what was read holds nothing
|
|
32
|
+
new. Keep one `known` mapping for all roots of a provider, as before. A caller no longer
|
|
33
|
+
de-duplicates anything. **Removed:** `TranscriptRoot.shared_sessions` and
|
|
34
|
+
`TranscriptFormat.shared_sessions`, which only told the caller to do this itself; a format sets
|
|
35
|
+
`session_file` (the name every copy of a session's file has) instead.
|
|
36
|
+
- **A fetched LiteLLM document took known prices away.** It replaced the pinned table whole, so a
|
|
37
|
+
model LiteLLM dropped or renamed lost its estimate, and a row listed at zero before its price was
|
|
38
|
+
known turned a known price into $0. A document is now laid over the pinned table: a model it lacks
|
|
39
|
+
keeps its pinned rates, a row with no input or output price does not replace a pinned price, and a
|
|
40
|
+
speed tier with no price under a priced standard is dropped. A model only the document knows is
|
|
41
|
+
taken as listed, free or not. `RateRead.known_models` counts the result.
|
|
42
|
+
- A `modelUsage` key with no name no longer raises out of the parser; its tokens are the row
|
|
43
|
+
`unknown`, which has no price, so the turn is `UNKNOWN_MODEL` as in 0.23.1. The CLI's
|
|
44
|
+
`<synthetic>` placeholder bills nothing and no longer makes a turn `UNKNOWN_MODEL`.
|
|
45
|
+
- `ultrafast` is read as `UsageSpeed.ULTRAFAST` in a Claude result and in a transcript (it read as
|
|
46
|
+
none, and as standard). A speed agentshim has no name for is still `None` (read as standard).
|
|
47
|
+
- `read_rates` and `refresh_rates` reject a naive `now` with `ValueError` before anything is
|
|
48
|
+
fetched. A clock set back is tolerated: a time stamped ahead of `now` by more than the floor has an
|
|
49
|
+
unknown age and counts as expired (it was fresh until the clock caught up), and an attempt more than
|
|
50
|
+
the floor away no longer holds off a refresh.
|
|
51
|
+
- The Codex app-server transport skips the `by_model` row of a model name that is blank.
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
|
|
55
|
+
- `read_transcript_usage(..., include_cwd=False)`: records carry `cwd` only when asked. It is an
|
|
56
|
+
absolute path on the user's machine, so a record a caller stores or sends holds no personal path by
|
|
57
|
+
default.
|
|
58
|
+
- `ModelUsage.recorded_usd` is documented as what it was: the pinned table's standard-tier list
|
|
59
|
+
price, no bill. A row whose `speed` is fast or ultrafast was billed more; docs/pricing.md shows
|
|
60
|
+
how to price the tier with `rates_for`, `price_tokens` and `speed_premium_usd`. Recorded cost still
|
|
61
|
+
does not model speed tiers.
|
|
62
|
+
- docs/transcripts.md states that `since` selects files, not records (filter on `timestamp`), and
|
|
63
|
+
that a line is held in memory whole while it is read.
|
|
64
|
+
|
|
65
|
+
### Added
|
|
66
|
+
|
|
67
|
+
- Tests built from data shaped like what the CLIs write, not idealised input:
|
|
68
|
+
`tests/unit/transcripts/shapes.py` (streamed Claude messages whose output grows, advisor calls
|
|
69
|
+
that show late, Codex session files that grow, move and are copied),
|
|
70
|
+
`tests/unit/stream_shapes.py` (a steered Claude process with cumulative `modelUsage`),
|
|
71
|
+
`tests/unit/rate_shapes.py` (partial, renamed and placeholder LiteLLM documents), and a synthetic
|
|
72
|
+
session file shaped like a real streamed message (`tests/fixtures/claude_session`). Properties over
|
|
73
|
+
them: records summed over any read split equal the final usage; a moved or copied session is
|
|
74
|
+
counted once; steered results equal one result of the whole run; no known price becomes 0.
|
|
75
|
+
|
|
76
|
+
## 0.24.0 (2026-10-30)
|
|
77
|
+
|
|
78
|
+
Everything here is additive. Recorded cost does not move: every price, `price_for`, `cost_usd`,
|
|
79
|
+
`PricingTable` and `ModelPricing` behave as in 0.23.1, and `tests/fixtures/recorded_costs.json`
|
|
80
|
+
(recorded on 0.23.1) proves the costs equal.
|
|
81
|
+
|
|
82
|
+
### Added
|
|
83
|
+
|
|
84
|
+
- Pinned prices are generated from a LiteLLM snapshot instead of kept by hand.
|
|
85
|
+
`scripts/generate_prices.py` reads `tests/fixtures/litellm/snapshot.json` (trimmed to the priced
|
|
86
|
+
models, with the day it was read and the SHA-256 of the whole file) and writes
|
|
87
|
+
`providers/{claude,codex}/prices_generated.py`; a test fails if they differ. All 29 rows already
|
|
88
|
+
matched LiteLLM, so no price changes. `PricingTable.version` is now `litellm-<snapshot date>`
|
|
89
|
+
(`litellm-2026-10-30`) and every entry's `checked` is that date. The test that every catalogue
|
|
90
|
+
model is priced or a documented exclusion stays; `gemini-3-pro-preview` is still unpriced.
|
|
91
|
+
- `RateTable`, `RateEntry` and `Rates`: flat per-model rates for estimates, a separate type from the
|
|
92
|
+
recorded-cost table (a zero rate is allowed, there are fast and ultrafast tiers, and no function
|
|
93
|
+
takes both kinds). `parse_litellm` reads LiteLLM's price file, `price_tokens` splits a cost by
|
|
94
|
+
token class, and `speed_premium_usd` and `cache_savings_usd` give the other report figures.
|
|
95
|
+
`UsageSpeed` is the service speed.
|
|
96
|
+
- `read_rates` and `refresh_rates` keep a rate document fresh for a caller-supplied `RateSource` and
|
|
97
|
+
`RateStore` (24 hour TTL, 60 second floor that also holds after a failure; an empty or invalid
|
|
98
|
+
document never replaces a good one). `bundled_rates` is the pinned table with speed tiers, the
|
|
99
|
+
fallback when nothing was fetched. `rates_for` maps a provider's model names onto the table.
|
|
100
|
+
agentshim still has no HTTP client. `FakeRateSource`, `FakeRateStore` and `RateStoreContract` are
|
|
101
|
+
in `agentshim.testing`.
|
|
102
|
+
- `ProviderUsage.by_model`: a `ModelUsage` row for every model a turn ran, with its tokens, its
|
|
103
|
+
recorded price (the pinned-table price, never the CLI's), the turn's speed and turn count on one
|
|
104
|
+
primary row. Claude reads it from `modelUsage`, so Task subagents and advisors are visible
|
|
105
|
+
(`ProviderUsage.tokens` is still the main conversation only, so budgets do not move);
|
|
106
|
+
`thinkingTokens` fills reasoning. The Codex app-server transport reports one row at the model and
|
|
107
|
+
service tier the server started the thread with. `merge_model_usage` adds two turns.
|
|
108
|
+
`ProviderUsage.to_dict` gains a `by_model` key. `CodexScript(service_tier=...)` scripts the tier.
|
|
109
|
+
- `read_transcript_usage`, `transcript_roots` and `transcript_providers`: token usage from the CLIs'
|
|
110
|
+
own session files, for work done outside agentshim. Claude (`projects/**.jsonl`) and Codex
|
|
111
|
+
(`sessions` and `archived_sessions`) are read. The reader keeps no state: the caller passes back a
|
|
112
|
+
`FilePosition` per file and gets only what is new. It resumes only when the file did not shrink
|
|
113
|
+
and the 64 bytes before the resume point hash the same, otherwise it rereads (`reset`); stops at a
|
|
114
|
+
line boundary after a byte budget and reports `pending`; skips files by modification time; lists
|
|
115
|
+
files it cannot read in `failed`; and reduces a line over 8 MiB to the fields it needs. A Claude
|
|
116
|
+
message repeated per content block counts once; subagent files take their parent's session.
|
|
117
|
+
`TranscriptSource`, `RateCatalog` and `RateNaming` are new optional plugin capabilities.
|
|
118
|
+
|
|
3
119
|
## 0.23.1 (2026-10-30)
|
|
4
120
|
|
|
5
121
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agentshim
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.24.1
|
|
4
4
|
Summary: Provider-agnostic coding-agent CLI shims
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -28,7 +28,10 @@ No required runtime dependencies. Python 3.10+.
|
|
|
28
28
|
- typed events delivered on the calling thread
|
|
29
29
|
- normalized token accounting (total input, cache reads, cache writes,
|
|
30
30
|
uncached input, output and reasoning) on every provider, plus a static,
|
|
31
|
-
versioned pricing table
|
|
31
|
+
versioned pricing table generated from a LiteLLM snapshot (see
|
|
32
|
+
[Usage and Pricing](docs/pricing.md)), usage by model, list-price estimates
|
|
33
|
+
from LiteLLM's rates, and usage read from the CLIs' own session files (see
|
|
34
|
+
[Usage Outside agentshim](docs/transcripts.md))
|
|
32
35
|
- declared capabilities on `ProviderProfile`, so no caller probes a provider
|
|
33
36
|
- injectable `CommandExecutor`s for running the CLI in a container or over a
|
|
34
37
|
remote shell
|
|
@@ -16,7 +16,10 @@ No required runtime dependencies. Python 3.10+.
|
|
|
16
16
|
- typed events delivered on the calling thread
|
|
17
17
|
- normalized token accounting (total input, cache reads, cache writes,
|
|
18
18
|
uncached input, output and reasoning) on every provider, plus a static,
|
|
19
|
-
versioned pricing table
|
|
19
|
+
versioned pricing table generated from a LiteLLM snapshot (see
|
|
20
|
+
[Usage and Pricing](docs/pricing.md)), usage by model, list-price estimates
|
|
21
|
+
from LiteLLM's rates, and usage read from the CLIs' own session files (see
|
|
22
|
+
[Usage Outside agentshim](docs/transcripts.md))
|
|
20
23
|
- declared capabilities on `ProviderProfile`, so no caller probes a provider
|
|
21
24
|
- injectable `CommandExecutor`s for running the CLI in a container or over a
|
|
22
25
|
remote shell
|
|
@@ -36,6 +36,7 @@ from .core import (
|
|
|
36
36
|
ContinuityError,
|
|
37
37
|
Conversation,
|
|
38
38
|
ConversationSpec,
|
|
39
|
+
CostBreakdown,
|
|
39
40
|
CostSource,
|
|
40
41
|
CredentialKind,
|
|
41
42
|
CredentialSource,
|
|
@@ -45,6 +46,8 @@ from .core import (
|
|
|
45
46
|
ExternalCredential,
|
|
46
47
|
FailureKind,
|
|
47
48
|
FileCredential,
|
|
49
|
+
FilePosition,
|
|
50
|
+
FileScan,
|
|
48
51
|
FlagsInstallation,
|
|
49
52
|
HostAuthGap,
|
|
50
53
|
HostAuthUnplannableError,
|
|
@@ -59,6 +62,7 @@ from .core import (
|
|
|
59
62
|
McpScope,
|
|
60
63
|
McpServer,
|
|
61
64
|
McpTransport,
|
|
65
|
+
ModelUsage,
|
|
62
66
|
NativeMode,
|
|
63
67
|
NativePermissions,
|
|
64
68
|
NoopInstallation,
|
|
@@ -78,7 +82,13 @@ from .core import (
|
|
|
78
82
|
ProviderStatus,
|
|
79
83
|
ProviderUsage,
|
|
80
84
|
RandomIds,
|
|
85
|
+
RateCatalog,
|
|
86
|
+
RateDocumentError,
|
|
87
|
+
RateEntry,
|
|
81
88
|
RateLimitStatus,
|
|
89
|
+
RateNaming,
|
|
90
|
+
Rates,
|
|
91
|
+
RateTable,
|
|
82
92
|
RawOutput,
|
|
83
93
|
ReapError,
|
|
84
94
|
Reasoning,
|
|
@@ -115,6 +125,12 @@ from .core import (
|
|
|
115
125
|
ToolCall,
|
|
116
126
|
ToolResult,
|
|
117
127
|
ToolTracker,
|
|
128
|
+
TranscriptFormat,
|
|
129
|
+
TranscriptParser,
|
|
130
|
+
TranscriptRecord,
|
|
131
|
+
TranscriptRoot,
|
|
132
|
+
TranscriptScan,
|
|
133
|
+
TranscriptSource,
|
|
118
134
|
Transport,
|
|
119
135
|
TransportKind,
|
|
120
136
|
TurnCancelledError,
|
|
@@ -124,6 +140,8 @@ from .core import (
|
|
|
124
140
|
TurnResult,
|
|
125
141
|
TurnTimeoutError,
|
|
126
142
|
UsageReport,
|
|
143
|
+
UsageSpeed,
|
|
144
|
+
cache_savings_usd,
|
|
127
145
|
compact_json,
|
|
128
146
|
compose_event_handlers,
|
|
129
147
|
dialect_problems,
|
|
@@ -131,11 +149,15 @@ from .core import (
|
|
|
131
149
|
install_config_file,
|
|
132
150
|
interactive_env,
|
|
133
151
|
materialize,
|
|
152
|
+
merge_model_usage,
|
|
134
153
|
normalize,
|
|
135
154
|
normalized_usage,
|
|
136
155
|
parse_json_object,
|
|
156
|
+
parse_timestamp,
|
|
137
157
|
plan_auth,
|
|
138
158
|
prepare_config_home,
|
|
159
|
+
price_tokens,
|
|
160
|
+
speed_premium_usd,
|
|
139
161
|
)
|
|
140
162
|
from .execution import (
|
|
141
163
|
CallbackCommandStreamSink,
|
|
@@ -183,10 +205,28 @@ from .providers.codex.app_server import CodexAppServerTransport
|
|
|
183
205
|
from .providers.copilot import CopilotProvider
|
|
184
206
|
from .providers.gemini import GeminiProvider
|
|
185
207
|
from .providers.opencode import OpencodeProvider
|
|
208
|
+
from .rates import (
|
|
209
|
+
LITELLM_ENDPOINTS,
|
|
210
|
+
RATES_TTL,
|
|
211
|
+
REFRESH_FLOOR,
|
|
212
|
+
RateEndpoint,
|
|
213
|
+
RateFetchError,
|
|
214
|
+
RateRead,
|
|
215
|
+
RateSnapshot,
|
|
216
|
+
RateSource,
|
|
217
|
+
RateStatus,
|
|
218
|
+
RateStore,
|
|
219
|
+
bundled_rates,
|
|
220
|
+
parse_litellm,
|
|
221
|
+
rates_for,
|
|
222
|
+
read_rates,
|
|
223
|
+
refresh_rates,
|
|
224
|
+
)
|
|
186
225
|
from .runtime import Agent
|
|
187
226
|
from .session import Session, Turn, TurnTicket, map_mcp_servers
|
|
227
|
+
from .transcripts import read_transcript_usage, transcript_providers, transcript_roots
|
|
188
228
|
|
|
189
|
-
__version__ = "0.
|
|
229
|
+
__version__ = "0.24.1"
|
|
190
230
|
|
|
191
231
|
__all__ = [ # noqa: RUF022 - public API test uses Python's case-sensitive order
|
|
192
232
|
"Agent",
|
|
@@ -235,6 +275,7 @@ __all__ = [ # noqa: RUF022 - public API test uses Python's case-sensitive order
|
|
|
235
275
|
"Conversation",
|
|
236
276
|
"ConversationSpec",
|
|
237
277
|
"CopilotProvider",
|
|
278
|
+
"CostBreakdown",
|
|
238
279
|
"CostSource",
|
|
239
280
|
"CredentialKind",
|
|
240
281
|
"CredentialSource",
|
|
@@ -246,6 +287,8 @@ __all__ = [ # noqa: RUF022 - public API test uses Python's case-sensitive order
|
|
|
246
287
|
"ExternalCredential",
|
|
247
288
|
"FailureKind",
|
|
248
289
|
"FileCredential",
|
|
290
|
+
"FilePosition",
|
|
291
|
+
"FileScan",
|
|
249
292
|
"FlagsInstallation",
|
|
250
293
|
"GeminiProvider",
|
|
251
294
|
"HostAuthGap",
|
|
@@ -255,6 +298,7 @@ __all__ = [ # noqa: RUF022 - public API test uses Python's case-sensitive order
|
|
|
255
298
|
"HttpMcpServer",
|
|
256
299
|
"IdAllocator",
|
|
257
300
|
"InMemoryCheckpointStore",
|
|
301
|
+
"LITELLM_ENDPOINTS",
|
|
258
302
|
"Lifecycle",
|
|
259
303
|
"LoginSpec",
|
|
260
304
|
"McpConfigError",
|
|
@@ -266,6 +310,7 @@ __all__ = [ # noqa: RUF022 - public API test uses Python's case-sensitive order
|
|
|
266
310
|
"ModelPricing",
|
|
267
311
|
"ModelSpec",
|
|
268
312
|
"ModelTable",
|
|
313
|
+
"ModelUsage",
|
|
269
314
|
"NativeMode",
|
|
270
315
|
"NativePermissions",
|
|
271
316
|
"NoRunningTurnError",
|
|
@@ -294,8 +339,23 @@ __all__ = [ # noqa: RUF022 - public API test uses Python's case-sensitive order
|
|
|
294
339
|
"ProviderStatus",
|
|
295
340
|
"ProviderTestSupport",
|
|
296
341
|
"ProviderUsage",
|
|
342
|
+
"RATES_TTL",
|
|
343
|
+
"REFRESH_FLOOR",
|
|
297
344
|
"RandomIds",
|
|
345
|
+
"RateCatalog",
|
|
346
|
+
"RateDocumentError",
|
|
347
|
+
"RateEndpoint",
|
|
348
|
+
"RateEntry",
|
|
349
|
+
"RateFetchError",
|
|
298
350
|
"RateLimitStatus",
|
|
351
|
+
"RateNaming",
|
|
352
|
+
"RateRead",
|
|
353
|
+
"RateSnapshot",
|
|
354
|
+
"RateSource",
|
|
355
|
+
"RateStatus",
|
|
356
|
+
"RateStore",
|
|
357
|
+
"RateTable",
|
|
358
|
+
"Rates",
|
|
299
359
|
"RawOutput",
|
|
300
360
|
"ReapError",
|
|
301
361
|
"Reasoning",
|
|
@@ -337,6 +397,12 @@ __all__ = [ # noqa: RUF022 - public API test uses Python's case-sensitive order
|
|
|
337
397
|
"ToolCall",
|
|
338
398
|
"ToolResult",
|
|
339
399
|
"ToolTracker",
|
|
400
|
+
"TranscriptFormat",
|
|
401
|
+
"TranscriptParser",
|
|
402
|
+
"TranscriptRecord",
|
|
403
|
+
"TranscriptRoot",
|
|
404
|
+
"TranscriptScan",
|
|
405
|
+
"TranscriptSource",
|
|
340
406
|
"TransformingExecutor",
|
|
341
407
|
"Transport",
|
|
342
408
|
"TransportKind",
|
|
@@ -349,7 +415,10 @@ __all__ = [ # noqa: RUF022 - public API test uses Python's case-sensitive order
|
|
|
349
415
|
"TurnTicket",
|
|
350
416
|
"TurnTimeoutError",
|
|
351
417
|
"UsageReport",
|
|
418
|
+
"UsageSpeed",
|
|
352
419
|
"__version__",
|
|
420
|
+
"bundled_rates",
|
|
421
|
+
"cache_savings_usd",
|
|
353
422
|
"compact_json",
|
|
354
423
|
"compose_event_handlers",
|
|
355
424
|
"confine",
|
|
@@ -364,14 +433,25 @@ __all__ = [ # noqa: RUF022 - public API test uses Python's case-sensitive order
|
|
|
364
433
|
"interactive_env",
|
|
365
434
|
"map_mcp_servers",
|
|
366
435
|
"materialize",
|
|
436
|
+
"merge_model_usage",
|
|
367
437
|
"model_spec",
|
|
368
438
|
"normalize",
|
|
369
439
|
"normalized_usage",
|
|
370
440
|
"parse_json_object",
|
|
441
|
+
"parse_litellm",
|
|
442
|
+
"parse_timestamp",
|
|
371
443
|
"plan_auth",
|
|
372
444
|
"prepare_config_home",
|
|
373
445
|
"price_for",
|
|
446
|
+
"price_tokens",
|
|
374
447
|
"probe_provider",
|
|
375
448
|
"provider_names",
|
|
449
|
+
"rates_for",
|
|
450
|
+
"read_rates",
|
|
451
|
+
"read_transcript_usage",
|
|
452
|
+
"refresh_rates",
|
|
453
|
+
"speed_premium_usd",
|
|
376
454
|
"stream_provider_names",
|
|
455
|
+
"transcript_providers",
|
|
456
|
+
"transcript_roots",
|
|
377
457
|
]
|
|
@@ -98,7 +98,15 @@ from .mcp import (
|
|
|
98
98
|
)
|
|
99
99
|
from .models import ModelSpec, ModelTable
|
|
100
100
|
from .permissions import ApprovalPolicy, NativeMode, NativePermissions
|
|
101
|
-
from .plugin import
|
|
101
|
+
from .plugin import (
|
|
102
|
+
ConnectionOptions,
|
|
103
|
+
PricingContext,
|
|
104
|
+
ProviderPlugin,
|
|
105
|
+
ProviderTestSupport,
|
|
106
|
+
RateCatalog,
|
|
107
|
+
RateNaming,
|
|
108
|
+
TranscriptSource,
|
|
109
|
+
)
|
|
102
110
|
from .pricing import ModelPricing, PricingTable, cost_usd
|
|
103
111
|
from .profile import (
|
|
104
112
|
ConfigScope,
|
|
@@ -120,13 +128,42 @@ from .provider import (
|
|
|
120
128
|
Provider,
|
|
121
129
|
StreamParser,
|
|
122
130
|
)
|
|
131
|
+
from .rates import (
|
|
132
|
+
CostBreakdown,
|
|
133
|
+
RateDocumentError,
|
|
134
|
+
RateEntry,
|
|
135
|
+
Rates,
|
|
136
|
+
RateTable,
|
|
137
|
+
cache_savings_usd,
|
|
138
|
+
price_tokens,
|
|
139
|
+
speed_premium_usd,
|
|
140
|
+
)
|
|
123
141
|
from .schema import compact_json, dialect_problems, materialize, normalize
|
|
124
142
|
from .session_policy import Continuity, PolicyConfig, RetryPolicy, SessionPolicy, SessionState
|
|
125
143
|
from .skills import SkillSummary, SkillTracker
|
|
126
144
|
from .status import AuthState, ProviderStatus
|
|
127
145
|
from .stream import ToolTracker, parse_json_object
|
|
146
|
+
from .transcripts import (
|
|
147
|
+
FilePosition,
|
|
148
|
+
FileScan,
|
|
149
|
+
TranscriptFormat,
|
|
150
|
+
TranscriptParser,
|
|
151
|
+
TranscriptRecord,
|
|
152
|
+
TranscriptRoot,
|
|
153
|
+
TranscriptScan,
|
|
154
|
+
parse_timestamp,
|
|
155
|
+
)
|
|
128
156
|
from .turn import OutputSchema, TurnRequest, TurnResult
|
|
129
|
-
from .usage import
|
|
157
|
+
from .usage import (
|
|
158
|
+
CostSource,
|
|
159
|
+
ModelUsage,
|
|
160
|
+
ProviderUsage,
|
|
161
|
+
TokenUsage,
|
|
162
|
+
TokenWeights,
|
|
163
|
+
UsageSpeed,
|
|
164
|
+
merge_model_usage,
|
|
165
|
+
normalized_usage,
|
|
166
|
+
)
|
|
130
167
|
|
|
131
168
|
__all__ = [
|
|
132
169
|
"AgentEvent",
|
|
@@ -157,6 +194,7 @@ __all__ = [
|
|
|
157
194
|
"ContinuityError",
|
|
158
195
|
"Conversation",
|
|
159
196
|
"ConversationSpec",
|
|
197
|
+
"CostBreakdown",
|
|
160
198
|
"CostSource",
|
|
161
199
|
"CredentialKind",
|
|
162
200
|
"CredentialSource",
|
|
@@ -166,6 +204,8 @@ __all__ = [
|
|
|
166
204
|
"ExternalCredential",
|
|
167
205
|
"FailureKind",
|
|
168
206
|
"FileCredential",
|
|
207
|
+
"FilePosition",
|
|
208
|
+
"FileScan",
|
|
169
209
|
"FlagsInstallation",
|
|
170
210
|
"HostAuthGap",
|
|
171
211
|
"HostAuthUnplannableError",
|
|
@@ -183,6 +223,7 @@ __all__ = [
|
|
|
183
223
|
"ModelPricing",
|
|
184
224
|
"ModelSpec",
|
|
185
225
|
"ModelTable",
|
|
226
|
+
"ModelUsage",
|
|
186
227
|
"NativeMode",
|
|
187
228
|
"NativePermissions",
|
|
188
229
|
"NoRunningTurnError",
|
|
@@ -205,7 +246,13 @@ __all__ = [
|
|
|
205
246
|
"ProviderTestSupport",
|
|
206
247
|
"ProviderUsage",
|
|
207
248
|
"RandomIds",
|
|
249
|
+
"RateCatalog",
|
|
250
|
+
"RateDocumentError",
|
|
251
|
+
"RateEntry",
|
|
208
252
|
"RateLimitStatus",
|
|
253
|
+
"RateNaming",
|
|
254
|
+
"RateTable",
|
|
255
|
+
"Rates",
|
|
209
256
|
"RawOutput",
|
|
210
257
|
"ReapError",
|
|
211
258
|
"Reasoning",
|
|
@@ -242,6 +289,12 @@ __all__ = [
|
|
|
242
289
|
"ToolCall",
|
|
243
290
|
"ToolResult",
|
|
244
291
|
"ToolTracker",
|
|
292
|
+
"TranscriptFormat",
|
|
293
|
+
"TranscriptParser",
|
|
294
|
+
"TranscriptRecord",
|
|
295
|
+
"TranscriptRoot",
|
|
296
|
+
"TranscriptScan",
|
|
297
|
+
"TranscriptSource",
|
|
245
298
|
"Transport",
|
|
246
299
|
"TransportKind",
|
|
247
300
|
"TurnCancelledError",
|
|
@@ -251,6 +304,8 @@ __all__ = [
|
|
|
251
304
|
"TurnResult",
|
|
252
305
|
"TurnTimeoutError",
|
|
253
306
|
"UsageReport",
|
|
307
|
+
"UsageSpeed",
|
|
308
|
+
"cache_savings_usd",
|
|
254
309
|
"compact_json",
|
|
255
310
|
"compose_event_handlers",
|
|
256
311
|
"cost_usd",
|
|
@@ -259,9 +314,13 @@ __all__ = [
|
|
|
259
314
|
"install_config_file",
|
|
260
315
|
"interactive_env",
|
|
261
316
|
"materialize",
|
|
317
|
+
"merge_model_usage",
|
|
262
318
|
"normalize",
|
|
263
319
|
"normalized_usage",
|
|
264
320
|
"parse_json_object",
|
|
321
|
+
"parse_timestamp",
|
|
265
322
|
"plan_auth",
|
|
266
323
|
"prepare_config_home",
|
|
324
|
+
"price_tokens",
|
|
325
|
+
"speed_premium_usd",
|
|
267
326
|
]
|
|
@@ -20,7 +20,9 @@ if TYPE_CHECKING:
|
|
|
20
20
|
from .pricing import ModelPricing, PricingTable
|
|
21
21
|
from .profile import ProviderProfile
|
|
22
22
|
from .provider import Provider
|
|
23
|
+
from .rates import RateTable
|
|
23
24
|
from .status import AuthState, ProviderStatus
|
|
25
|
+
from .transcripts import TranscriptFormat
|
|
24
26
|
from .usage import TokenUsage
|
|
25
27
|
|
|
26
28
|
|
|
@@ -170,3 +172,40 @@ class ProviderPlugin(Protocol):
|
|
|
170
172
|
def test_support(self) -> ProviderTestSupport | None:
|
|
171
173
|
"""Return consumer-test adapters, if provided."""
|
|
172
174
|
...
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@runtime_checkable
|
|
178
|
+
class RateCatalog(Protocol):
|
|
179
|
+
"""Optional: a plugin that ships rates, with speed tiers, for the models it prices.
|
|
180
|
+
|
|
181
|
+
A plugin without it ships none. These are the rates of the pinned table
|
|
182
|
+
shipped in the wheel, which :func:`agentshim.rates.bundled_rates` collects.
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
def known_rates(self) -> RateTable:
|
|
186
|
+
"""Rates for the models this provider prices."""
|
|
187
|
+
...
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@runtime_checkable
|
|
191
|
+
class RateNaming(Protocol):
|
|
192
|
+
"""Optional: a plugin that knows which flat names a model may be filed under.
|
|
193
|
+
|
|
194
|
+
A provider not implementing it gets :func:`agentshim.core.rates.candidate_names`.
|
|
195
|
+
"""
|
|
196
|
+
|
|
197
|
+
def rate_names(self, model: str) -> tuple[str, ...]:
|
|
198
|
+
"""Candidate flat names for *model*, most specific first; none if it has no price."""
|
|
199
|
+
...
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@runtime_checkable
|
|
203
|
+
class TranscriptSource(Protocol):
|
|
204
|
+
"""Optional: a plugin whose CLI keeps session files agentshim can read for usage.
|
|
205
|
+
|
|
206
|
+
A plugin without it, or answering ``None``, has no readable transcripts.
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
def transcripts(self) -> TranscriptFormat | None:
|
|
210
|
+
"""The format of this provider's session files, or ``None`` if it has none readable."""
|
|
211
|
+
...
|