Repository navigation
Conversation
This fix addresses issue anthropics#2 where Max subscription users encounter a KeyError when the API response doesn't include the 'cost_usd' field. Changes: - Modified ResultMessage dataclass to make cost_usd and total_cost_usd optional (float | None) - Updated client.py to use .get() with None default for cost-related fields - Maintains backward compatibility for users with cost data This ensures the SDK works for all subscription types, including Max subscriptions that don't have access to cost information. By: Unclecode <https://github.com/unclecode>
arun-pathiban-ddog
approved these changes
Jun 17, 2025
Collaborator
|
thank you @unclecode . Closing this PR as this issue is fixed with latest release |
This was referenced Apr 19, 2026
qing-ant
added a commit
that referenced
this pull request
Apr 21, 2026
…ist-all (#847) ## Problem `list_sessions_from_store()` calls `store.list_sessions()` for IDs, then `store.load()` **per session** to derive title/first-prompt/branch/etc. With N sessions that's N full-transcript round-trips just to render a list. #846 (`load_range`) cut bytes-per-session but not round-trips — 500 sessions still meant 500+ store calls. ## Public API change — additive only, no breaking changes ```python # New TypedDict (3 fields; `data` is opaque, stores persist verbatim) class SessionSummaryEntry(TypedDict): session_id: str mtime: int data: dict[str, Any] # New helper — adapters call this from append() def fold_session_summary( prev: SessionSummaryEntry | None, key: SessionKey, entries: list[SessionStoreEntry], ) -> SessionSummaryEntry: ... # New optional Protocol method (default: raise NotImplementedError) class SessionStore(Protocol): async def list_session_summaries(self, project_key: str) -> list[SessionSummaryEntry]: ... ``` **Unchanged:** `SessionStore.{append,load,list_sessions,delete,list_subkeys}`, `list_sessions_from_store()` signature/return, `get_session_info_from_store()`, `SDKSessionInfo`, `SessionStoreListEntry`, `InMemorySessionStore` public methods. Stores that don't implement `list_session_summaries` work exactly as before. ## Approach Every field the list view needs is **append-incremental**: 4 are set-once from the first entries (`is_sidechain`, `created_at`, `cwd`, `first_prompt`), 7 are last-write-wins from the tail (`custom_title`, `ai_title`, `last_prompt`, `summary_hint`, `git_branch`, `tag`, `mtime`), 0 require a full scan. So a store can maintain a small summary record alongside each session, updated inside `append()` with the entries already in hand — no re-reads. This PR adds: - **`SessionSummaryEntry`** (TypedDict) — 3-field record (`session_id`, `mtime`, opaque `data`). Stores persist it verbatim and never interpret `data`. - **`fold_session_summary(prev, key, entries)`** — pure helper that folds new entries into the previous summary. Adapters call this from `append()` so derivation logic lives in one place (no per-adapter drift). `created_at` latches the first *parseable* entry timestamp — a documented divergence from the lite-parse path only when the very first entry lacks a timestamp (never happens in CLI-produced transcripts). - **`SessionStore.list_session_summaries(project_key)`** — optional Protocol method returning all summaries for a project in one call. - **Fast path in `list_sessions_from_store()`** — when the store implements `list_session_summaries`: build a unified slot list (summary-derived slots + gap-fill placeholders for sessions present in `list_sessions()` but lacking a sidecar), sort by `mtime`, apply `offset`/`limit`, then `load()` only the placeholders that landed in the page. Summary-backed sidechain/empty sessions are pre-filtered *before* pagination so they don't consume page positions (matching disk/slow-path filter-then-paginate); only gap-fill placeholders that resolve to `None` after load can short-page, so a store with complete sidecars never short-pages. `load()` count is bounded by page size, not total missing — zero `load()` calls when sidecars are complete. Gap-fill is best-effort: if the store lacks `list_sessions` it's skipped with a debug log. Otherwise falls back to the existing per-session `load()` path (bounded at 16 concurrent). - **`InMemorySessionStore`** reference impl (entry-timestamp-derived `mtime` so fast/slow paths sort on one clock) + conformance contract #14. `get_session_info_from_store()` (single session) is unchanged — full `load()` is fine there. ## Correctness `tests/test_session_summary.py::TestParityWithLiteParse` proves `summary_entry_to_sdk_info(fold_session_summary(...))` produces the same `SDKSessionInfo` as the existing `_parse_session_info_from_lite` batch path on the same entry stream. ## For reviewers - `_internal/session_summary.py` — fold logic, esp. first-prompt skip filter (mirrors `_extract_first_prompt_from_head`) - `_internal/sessions.py` fast-path block — fallback semantics - `types.py` — public surface: `SessionSummaryEntry`, `fold_session_summary`, `list_session_summaries` Supersedes #846. TS port: anthropics/claude-cli-internal#30520.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR fixes issue #2 where Max subscription users encounter a
KeyErrorwhen the API response doesn't include thecost_usdfield.Problem
Users with Max subscriptions were getting the following error:
This occurs because the SDK was expecting
cost_usdto always be present in the response, but Max subscription responses don't include cost information.Solution
ResultMessagedataclass to makecost_usdandtotal_cost_usdoptional (float | None)client.pyto use.get()method withNonedefault for cost-related fieldsTesting
Fixes #2