cc-session-tools 3.10.2__tar.gz → 3.10.4__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.
- {cc_session_tools-3.10.2/src/cc_session_tools.egg-info → cc_session_tools-3.10.4}/PKG-INFO +1 -1
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/pyproject.toml +1 -1
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-pdata-do-init/SKILL.md +3 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4/src/cc_session_tools.egg-info}/PKG-INFO +1 -1
- cc_session_tools-3.10.4/src/claude_code_usage/data/pricing.json +181 -0
- cc_session_tools-3.10.4/src/claude_code_usage/pricing.py +134 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/context_window_warning.py +73 -17
- cc_session_tools-3.10.4/src/hooks/model_info.py +83 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_context_window_warning.py +159 -16
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_model_info.py +34 -18
- cc_session_tools-3.10.4/tests/test_pricing.py +189 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_query.py +4 -4
- cc_session_tools-3.10.2/src/claude_code_usage/data/pricing.json +0 -102
- cc_session_tools-3.10.2/src/claude_code_usage/pricing.py +0 -97
- cc_session_tools-3.10.2/src/hooks/model_info.py +0 -79
- cc_session_tools-3.10.2/tests/test_pricing.py +0 -70
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/LICENSE +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/README.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/setup.cfg +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/__init__.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/__init__.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/ccd.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/ccmsg.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/ccr.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/ccs.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/ccsched.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/ccst.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/migrate_ccmsg.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/migrate_ccsched.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/migrate_sessions_db.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/migrate_telemetry.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/config/hooks-bundle.json +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/config/session-tag-hook.json +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/hooks_install.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/__init__.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/bun_tools.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/claude_flags.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/claude_md_install.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/context_overrides.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/db.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/debug.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/doctor.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/doctor_mutes.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/hook_registry.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/install_sync.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/levenshtein.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/machine_identity.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/__init__.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/addressing.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/cursor.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/lock.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/message.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/move_safety.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/repository.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/retention.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/service.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/store.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/occupancy.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/paths.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/__init__.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/backup.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/classify.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/cutover.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/dump.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/formatting.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/importers.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/init_paths.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/init_service.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/manifest.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/naming.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/readiness.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/rehydrate.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/rename_group.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/reorganize.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/repository.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/resolve.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/service.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/session_output.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/store.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/sync_check.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/sync_lock.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/sync_notify.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/vector_clock.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/vector_clock_store.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/verify.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/write_log.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/picker.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/proc_lock.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/prompts.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/roots.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/rules.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/__init__.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/bundled_jobs.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/cadence.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/cursor.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/digest.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/due.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/duration.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/jobspec.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/ledger.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/lock.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/notify.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/reconcile.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/registry.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/runner.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/state.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/store.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/surface.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/throttle.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/worker.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/session_gc.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/sessions.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/sessions_db.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/sessions_repair.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/shell_install.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/tasklist.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/telemetry_store.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/text_wrap.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/analyse-cc-usage/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/clean-hook-sessions/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/clean-hook-sessions/scripts/clean-hook-sessions.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/compact-smart/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/context-override/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/delete-sessions/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/delete-sessions/scripts/delete_sessions.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/do-executor-critic-assessor-loop/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/extract-pptx/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/extract-pptx/scripts/extract_pptx.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/extract-to-text/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/extract-to-text/scripts/extract_to_text.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/find-claude-code-session/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/generate-8digit-code/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/generate-8digit-code/scripts/generate_8digit_code.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/list-empty-sessions/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/list-empty-sessions/scripts/list_empty_sessions.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/manage-recurring-cc-jobs-using-ccsched/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/move-session/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/move-session/hooks/sessionstart-pending-rename.sh +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/move-session/scripts/cc_session_rules.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/move-session/scripts/move_session.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-pdata-design-schema/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-pdata-do-audit-and-prepare-to-migrate/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-pdata-do-manual-migration/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-pdata-do-update-consuming-skills/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-pdata-do-update-project-docs/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-pdata-resolve-conflicts/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-project-layout-reference/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-update-central-files/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/CALIBRATION.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/scripts/analyze_context.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/scripts/duplicates.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/scripts/measure.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/scripts/report.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/scripts/tokens.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/scripts/usage.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/select-agent-model/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/send-session-message/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/update-command-cache/SKILL.md +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/update-command-cache/scripts/update_command_cache.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools.egg-info/SOURCES.txt +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools.egg-info/dependency_links.txt +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools.egg-info/entry_points.txt +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools.egg-info/requires.txt +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/cc_session_tools.egg-info/top_level.txt +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/claude_code_usage/__init__.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/claude_code_usage/attribution.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/claude_code_usage/cache.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/claude_code_usage/ccusage_wrapper.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/claude_code_usage/cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/claude_code_usage/parent_inference.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/claude_code_usage/parser.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/claude_code_usage/query.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/claude_code_usage/report.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/claude_code_usage/schema.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/claude_code_usage/session_names.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/__init__.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/after_response.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/bash_hard_deny.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/bash_security_review.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/cache.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/catchup.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/confirm_8digit.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/last_screenshot.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/marker_allow.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/markers.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/messaging_deliver.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/normalise.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/pdata_sync.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/pending_migration.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/pending_rename.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/script_allowlist.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/session_tag.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/stats.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/telemetry.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/telemetry_query.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/telemetry_trim.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/transcript.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/src/hooks/worklog_guard.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_after_response.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_attribution.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_bash_hard_deny.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_bash_security_review.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_bash_security_review_allowlist.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_bun_tools.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_cache.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_cache_sqlite.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccr_orphans.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccs_emptiness.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccs_eta.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccs_list_mode.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccs_scope_flags.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccs_sentinel_sort.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccs_session_counts.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_bundle_discovery.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_ccsched_jobs_cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_context_override_cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_doctor.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_gc_prune.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_gc_report.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_hook_dispatcher.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_hooks_allowlist.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_hooks_install_prune.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_hooks_install_zero_arg.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_hooks_uninstall.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_install_everything.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_machine_identity_cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_main_gate.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_init_cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_readiness_cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_reconcile_cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_rename_group_cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_reorganize_cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_sync_cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_verify_cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_repair_sessions_cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_sessions_cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_shell_install.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_skills_install.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_skills_uninstall.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_telemetry_query.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccst_telemetry_trim.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_ccusage_wrapper.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_claude_flags.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_claude_md_install.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_cli.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_cli_ccd.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_cli_ccd_dry_run.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_cli_ccr.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_cli_ccs.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_cli_version.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_confirm_8digit.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_context_overrides.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_db.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_debug.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_doctor_mutes.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_empty_session.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_hook_cache.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_hooks_install.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_hooks_install_records.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_install_sync.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_last_screenshot.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_levenshtein.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_machine_identity.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_marker_allow.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_migrate_ccmsg.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_migrate_ccsched.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_migrate_sessions_db.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_migrate_telemetry.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_normalise.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_occupancy.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_parent_inference.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_parser.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_paths.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_pdata_audit_skill.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_pdata_post_migration_skills.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_pending_migration_hook.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_picker.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_proc_lock.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_prompts.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_report.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_roots.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_rules.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_scheduler_bundled_jobs.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_schema.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_script_allowlist.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_session_names.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_session_tag.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_sessions.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_sessions_db.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_sessions_db_migration_chain.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_sessions_repair.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_tasklist.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_telemetry.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_telemetry_store.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_text_wrap.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_transcript.py +0 -0
- {cc_session_tools-3.10.2 → cc_session_tools-3.10.4}/tests/test_worklog_guard.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cc-session-tools"
|
|
7
|
-
version = "3.10.
|
|
7
|
+
version = "3.10.4"
|
|
8
8
|
description = "Claude Code session management CLI tools (ccd, ccr, ccs, claude-code-usage, ccst) and hook library (hooks package)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -141,6 +141,9 @@ relative to a subfolder rather than the project root (e.g. an index-of-a-subfold
|
|
|
141
141
|
root) - `--write`'s file_path-resolution verification will fail with a bare "does not resolve
|
|
142
142
|
under `<project_root>`" and no further guidance. Instead, map that column to a plain named field
|
|
143
143
|
(e.g. `source_file_path`) and note in the field's `description` what path it's relative to.
|
|
144
|
+
Likewise, a column documented to use multiple or shorthand path notations (e.g. brace expansion
|
|
145
|
+
alongside plain paths) is unsafe to map to `file_path_column` at all - map it to a plain named TEXT
|
|
146
|
+
field instead, exactly as for the subfolder-relative case.
|
|
144
147
|
|
|
145
148
|
**`content_column: null` default caveat:** an entry with `content_column` left unset falls back to
|
|
146
149
|
a raw `json.dumps(row)` dump as every record's content - rarely what you want for readable `ccst
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_source": "Anthropic published first-party API pricing (https://platform.claude.com/docs/en/about-claude/pricing), hand-curated. Per-token USD. Rows for retired models not on that page keep their historical list price.",
|
|
3
|
+
"_refreshed_at": "2026-09-29",
|
|
4
|
+
"models": {
|
|
5
|
+
"<synthetic>": {
|
|
6
|
+
"input": 0.0,
|
|
7
|
+
"output": 0.0,
|
|
8
|
+
"cache_creation_5m": 0.0,
|
|
9
|
+
"cache_creation_1h": 0.0,
|
|
10
|
+
"cache_read": 0.0
|
|
11
|
+
},
|
|
12
|
+
"claude-fable-5-1": {
|
|
13
|
+
"input": 0.00001,
|
|
14
|
+
"output": 0.00005,
|
|
15
|
+
"cache_creation_5m": 0.0000125,
|
|
16
|
+
"cache_creation_1h": 0.00002,
|
|
17
|
+
"cache_read": 0.00000025
|
|
18
|
+
},
|
|
19
|
+
"claude-mythos-5-1": {
|
|
20
|
+
"input": 0.00001,
|
|
21
|
+
"output": 0.00005,
|
|
22
|
+
"cache_creation_5m": 0.0000125,
|
|
23
|
+
"cache_creation_1h": 0.00002,
|
|
24
|
+
"cache_read": 0.00000025
|
|
25
|
+
},
|
|
26
|
+
"claude-fable-5": {
|
|
27
|
+
"input": 0.00001,
|
|
28
|
+
"output": 0.00005,
|
|
29
|
+
"cache_creation_5m": 0.0000125,
|
|
30
|
+
"cache_creation_1h": 0.00002,
|
|
31
|
+
"cache_read": 0.000001
|
|
32
|
+
},
|
|
33
|
+
"claude-mythos-5": {
|
|
34
|
+
"input": 0.00001,
|
|
35
|
+
"output": 0.00005,
|
|
36
|
+
"cache_creation_5m": 0.0000125,
|
|
37
|
+
"cache_creation_1h": 0.00002,
|
|
38
|
+
"cache_read": 0.000001
|
|
39
|
+
},
|
|
40
|
+
"claude-opus-5-5": {
|
|
41
|
+
"input": 0.000004,
|
|
42
|
+
"output": 0.00002,
|
|
43
|
+
"cache_creation_5m": 0.000005,
|
|
44
|
+
"cache_creation_1h": 0.000008,
|
|
45
|
+
"cache_read": 0.0000002
|
|
46
|
+
},
|
|
47
|
+
"claude-opus-5": {
|
|
48
|
+
"input": 0.000005,
|
|
49
|
+
"output": 0.000025,
|
|
50
|
+
"cache_creation_5m": 0.00000625,
|
|
51
|
+
"cache_creation_1h": 0.00001,
|
|
52
|
+
"cache_read": 0.0000005
|
|
53
|
+
},
|
|
54
|
+
"claude-opus-4-8": {
|
|
55
|
+
"input": 0.000005,
|
|
56
|
+
"output": 0.000025,
|
|
57
|
+
"cache_creation_5m": 0.00000625,
|
|
58
|
+
"cache_creation_1h": 0.00001,
|
|
59
|
+
"cache_read": 0.0000005
|
|
60
|
+
},
|
|
61
|
+
"claude-opus-4-7": {
|
|
62
|
+
"input": 0.000005,
|
|
63
|
+
"output": 0.000025,
|
|
64
|
+
"cache_creation_5m": 0.00000625,
|
|
65
|
+
"cache_creation_1h": 0.00001,
|
|
66
|
+
"cache_read": 0.0000005
|
|
67
|
+
},
|
|
68
|
+
"claude-opus-4-6": {
|
|
69
|
+
"input": 0.000005,
|
|
70
|
+
"output": 0.000025,
|
|
71
|
+
"cache_creation_5m": 0.00000625,
|
|
72
|
+
"cache_creation_1h": 0.00001,
|
|
73
|
+
"cache_read": 0.0000005
|
|
74
|
+
},
|
|
75
|
+
"claude-opus-4-5": {
|
|
76
|
+
"input": 0.000005,
|
|
77
|
+
"output": 0.000025,
|
|
78
|
+
"cache_creation_5m": 0.00000625,
|
|
79
|
+
"cache_creation_1h": 0.00001,
|
|
80
|
+
"cache_read": 0.0000005
|
|
81
|
+
},
|
|
82
|
+
"claude-opus-4-1": {
|
|
83
|
+
"input": 0.000015,
|
|
84
|
+
"output": 0.000075,
|
|
85
|
+
"cache_creation_5m": 0.00001875,
|
|
86
|
+
"cache_creation_1h": 0.00003,
|
|
87
|
+
"cache_read": 0.0000015
|
|
88
|
+
},
|
|
89
|
+
"claude-opus-4": {
|
|
90
|
+
"input": 0.000015,
|
|
91
|
+
"output": 0.000075,
|
|
92
|
+
"cache_creation_5m": 0.00001875,
|
|
93
|
+
"cache_creation_1h": 0.00003,
|
|
94
|
+
"cache_read": 0.0000015
|
|
95
|
+
},
|
|
96
|
+
"claude-sonnet-5-5": {
|
|
97
|
+
"input": 0.000002,
|
|
98
|
+
"output": 0.00001,
|
|
99
|
+
"cache_creation_5m": 0.0000025,
|
|
100
|
+
"cache_creation_1h": 0.000004,
|
|
101
|
+
"cache_read": 0.0000002
|
|
102
|
+
},
|
|
103
|
+
"claude-sonnet-5": {
|
|
104
|
+
"input": 0.000002,
|
|
105
|
+
"output": 0.00001,
|
|
106
|
+
"cache_creation_5m": 0.0000025,
|
|
107
|
+
"cache_creation_1h": 0.000004,
|
|
108
|
+
"cache_read": 0.0000002
|
|
109
|
+
},
|
|
110
|
+
"claude-sonnet-4-6": {
|
|
111
|
+
"input": 0.000003,
|
|
112
|
+
"output": 0.000015,
|
|
113
|
+
"cache_creation_5m": 0.00000375,
|
|
114
|
+
"cache_creation_1h": 0.000006,
|
|
115
|
+
"cache_read": 0.0000003
|
|
116
|
+
},
|
|
117
|
+
"claude-sonnet-4-5": {
|
|
118
|
+
"input": 0.000003,
|
|
119
|
+
"output": 0.000015,
|
|
120
|
+
"cache_creation_5m": 0.00000375,
|
|
121
|
+
"cache_creation_1h": 0.000006,
|
|
122
|
+
"cache_read": 0.0000003
|
|
123
|
+
},
|
|
124
|
+
"claude-sonnet-4": {
|
|
125
|
+
"input": 0.000003,
|
|
126
|
+
"output": 0.000015,
|
|
127
|
+
"cache_creation_5m": 0.00000375,
|
|
128
|
+
"cache_creation_1h": 0.000006,
|
|
129
|
+
"cache_read": 0.0000003
|
|
130
|
+
},
|
|
131
|
+
"claude-haiku-4-5": {
|
|
132
|
+
"input": 0.000001,
|
|
133
|
+
"output": 0.000005,
|
|
134
|
+
"cache_creation_5m": 0.00000125,
|
|
135
|
+
"cache_creation_1h": 0.000002,
|
|
136
|
+
"cache_read": 0.0000001
|
|
137
|
+
},
|
|
138
|
+
"claude-haiku-4": {
|
|
139
|
+
"input": 0.0000008,
|
|
140
|
+
"output": 0.000004,
|
|
141
|
+
"cache_creation_5m": 0.000001,
|
|
142
|
+
"cache_creation_1h": 0.0000016,
|
|
143
|
+
"cache_read": 0.00000008
|
|
144
|
+
},
|
|
145
|
+
"claude-3-7-sonnet-20250219": {
|
|
146
|
+
"input": 0.000003,
|
|
147
|
+
"output": 0.000015,
|
|
148
|
+
"cache_creation_5m": 0.00000375,
|
|
149
|
+
"cache_creation_1h": 0.000006,
|
|
150
|
+
"cache_read": 0.0000003
|
|
151
|
+
},
|
|
152
|
+
"claude-3-5-sonnet-20241022": {
|
|
153
|
+
"input": 0.000003,
|
|
154
|
+
"output": 0.000015,
|
|
155
|
+
"cache_creation_5m": 0.00000375,
|
|
156
|
+
"cache_creation_1h": 0.000006,
|
|
157
|
+
"cache_read": 0.0000003
|
|
158
|
+
},
|
|
159
|
+
"claude-3-5-haiku-20241022": {
|
|
160
|
+
"input": 0.0000008,
|
|
161
|
+
"output": 0.000004,
|
|
162
|
+
"cache_creation_5m": 0.000001,
|
|
163
|
+
"cache_creation_1h": 0.0000016,
|
|
164
|
+
"cache_read": 0.00000008
|
|
165
|
+
},
|
|
166
|
+
"claude-3-opus-20240229": {
|
|
167
|
+
"input": 0.000015,
|
|
168
|
+
"output": 0.000075,
|
|
169
|
+
"cache_creation_5m": 0.00001875,
|
|
170
|
+
"cache_creation_1h": 0.00003,
|
|
171
|
+
"cache_read": 0.0000015
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"family_fallbacks": {
|
|
175
|
+
"fable": "claude-fable-5-1",
|
|
176
|
+
"mythos": "claude-mythos-5-1",
|
|
177
|
+
"opus": "claude-opus-5-5",
|
|
178
|
+
"sonnet": "claude-sonnet-5-5",
|
|
179
|
+
"haiku": "claude-haiku-4-5"
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""Per-token pricing data and dollar calculations.
|
|
2
|
+
|
|
3
|
+
`data/pricing.json` is a hand-curated copy of Anthropic's published
|
|
4
|
+
first-party API rates (its `_source` / `_refreshed_at` fields say where
|
|
5
|
+
from and when); re-check it whenever a new model ships. Resolution order
|
|
6
|
+
for a model id:
|
|
7
|
+
|
|
8
|
+
1. an exact row;
|
|
9
|
+
2. a dated snapshot (`<id>-YYYYMMDD`, exactly eight digits, stripped
|
|
10
|
+
once) resolves to the undated row;
|
|
11
|
+
3. an id containing `claude-<family>-` for a family in `family_fallbacks`
|
|
12
|
+
is priced as that family's newest model - an estimate, which
|
|
13
|
+
`add_cost_column()` reports in a warning. Claude 3 ids (`claude-3-...`)
|
|
14
|
+
and non-Claude ids never match, so an unlisted old model is reported as
|
|
15
|
+
unpriced rather than given a newer model's price;
|
|
16
|
+
4. otherwise `lookup()` raises `KeyError`.
|
|
17
|
+
|
|
18
|
+
`<synthetic>` (Claude Code's zero-usage stub entries) has an explicit
|
|
19
|
+
all-zero row.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import json
|
|
25
|
+
import logging
|
|
26
|
+
import re
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
from typing import Any
|
|
29
|
+
|
|
30
|
+
import pandas as pd
|
|
31
|
+
|
|
32
|
+
_THIS_DIR = Path(__file__).resolve().parent
|
|
33
|
+
_PRICING_PATH = _THIS_DIR / "data" / "pricing.json"
|
|
34
|
+
_DATED_SNAPSHOT = re.compile(r"(.+)-\d{8}")
|
|
35
|
+
|
|
36
|
+
logger = logging.getLogger(__name__)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _load() -> dict[str, Any]:
|
|
40
|
+
return json.loads(_PRICING_PATH.read_text())
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def resolve(model: str) -> tuple[str, bool]:
|
|
44
|
+
"""Return (pricing row key, True if the row came from a family fallback).
|
|
45
|
+
Raises KeyError if `model` has no row and no family match."""
|
|
46
|
+
data = _load()
|
|
47
|
+
models = data["models"]
|
|
48
|
+
if model in models:
|
|
49
|
+
return model, False
|
|
50
|
+
dated = _DATED_SNAPSHOT.fullmatch(model)
|
|
51
|
+
if dated and dated.group(1) in models:
|
|
52
|
+
return dated.group(1), False
|
|
53
|
+
for family, fallback_model in data["family_fallbacks"].items():
|
|
54
|
+
if f"claude-{family}-" in model:
|
|
55
|
+
return fallback_model, True
|
|
56
|
+
raise KeyError(model)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def lookup(model: str) -> dict[str, float]:
|
|
60
|
+
"""Return per-token rates for `model`. Raises KeyError if unknown."""
|
|
61
|
+
row, _ = resolve(model)
|
|
62
|
+
rates: dict[str, float] = _load()["models"][row]
|
|
63
|
+
return rates
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def cost_for_usage(
|
|
67
|
+
model: str,
|
|
68
|
+
input_tokens: int,
|
|
69
|
+
output_tokens: int,
|
|
70
|
+
cache_creation_5m: int = 0,
|
|
71
|
+
cache_creation_1h: int = 0,
|
|
72
|
+
cache_read: int = 0,
|
|
73
|
+
) -> float:
|
|
74
|
+
"""Return the dollar cost of one assistant message's token mix."""
|
|
75
|
+
rates = lookup(model)
|
|
76
|
+
return (
|
|
77
|
+
input_tokens * rates["input"]
|
|
78
|
+
+ output_tokens * rates["output"]
|
|
79
|
+
+ cache_creation_5m * rates["cache_creation_5m"]
|
|
80
|
+
+ cache_creation_1h * rates["cache_creation_1h"]
|
|
81
|
+
+ cache_read * rates["cache_read"]
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def add_cost_column(df: pd.DataFrame) -> pd.DataFrame:
|
|
86
|
+
"""Return `df` with a `cost_usd` column added.
|
|
87
|
+
|
|
88
|
+
Vectorised over rows: builds a per-row rates frame from the model
|
|
89
|
+
column then dot-products against the token columns. Models that
|
|
90
|
+
can't be resolved (after family fallback) get cost = 0 with a
|
|
91
|
+
warning - we don't want a single unknown model to break a report.
|
|
92
|
+
Models priced by family fallback are named in a separate warning, so
|
|
93
|
+
an estimated price is never silent.
|
|
94
|
+
"""
|
|
95
|
+
out = df.copy()
|
|
96
|
+
if out.empty:
|
|
97
|
+
out["cost_usd"] = pd.Series(dtype=float)
|
|
98
|
+
return out
|
|
99
|
+
models = _load()["models"]
|
|
100
|
+
zero = {"input": 0.0, "output": 0.0, "cache_creation_5m": 0.0,
|
|
101
|
+
"cache_creation_1h": 0.0, "cache_read": 0.0}
|
|
102
|
+
rates_by_model: dict[str, dict[str, float]] = {}
|
|
103
|
+
unknown: set[str] = set()
|
|
104
|
+
fallback: dict[str, str] = {}
|
|
105
|
+
for model in out["model"].unique():
|
|
106
|
+
try:
|
|
107
|
+
row, is_fallback = resolve(model)
|
|
108
|
+
except KeyError:
|
|
109
|
+
unknown.add(model)
|
|
110
|
+
rates_by_model[model] = zero
|
|
111
|
+
continue
|
|
112
|
+
rates_by_model[model] = models[row]
|
|
113
|
+
if is_fallback:
|
|
114
|
+
fallback[model] = row
|
|
115
|
+
rates_records = [rates_by_model[model] for model in out["model"]]
|
|
116
|
+
rates_df = pd.DataFrame(rates_records, index=out.index)
|
|
117
|
+
out["cost_usd"] = (
|
|
118
|
+
out["input_tokens"] * rates_df["input"]
|
|
119
|
+
+ out["output_tokens"] * rates_df["output"]
|
|
120
|
+
+ out["cache_creation_5m"] * rates_df["cache_creation_5m"]
|
|
121
|
+
+ out["cache_creation_1h"] * rates_df["cache_creation_1h"]
|
|
122
|
+
+ out["cache_read"] * rates_df["cache_read"]
|
|
123
|
+
)
|
|
124
|
+
if unknown:
|
|
125
|
+
logger.warning(
|
|
126
|
+
"no pricing for models: %s (cost set to 0 for those rows)",
|
|
127
|
+
sorted(unknown),
|
|
128
|
+
)
|
|
129
|
+
if fallback:
|
|
130
|
+
logger.warning(
|
|
131
|
+
"no exact pricing for models, priced by family fallback: %s",
|
|
132
|
+
", ".join(f"{model} as {row}" for model, row in sorted(fallback.items())),
|
|
133
|
+
)
|
|
134
|
+
return out
|
|
@@ -26,6 +26,7 @@ from __future__ import annotations
|
|
|
26
26
|
|
|
27
27
|
import datetime
|
|
28
28
|
import json
|
|
29
|
+
import re
|
|
29
30
|
import sys
|
|
30
31
|
from decimal import ROUND_DOWN, Decimal
|
|
31
32
|
from pathlib import Path
|
|
@@ -41,10 +42,16 @@ class TranscriptError(Exception):
|
|
|
41
42
|
not a single parseable JSON line."""
|
|
42
43
|
|
|
43
44
|
|
|
45
|
+
SYNTHETIC_MODEL = "<synthetic>"
|
|
46
|
+
|
|
47
|
+
|
|
44
48
|
def _current_context_tokens(transcript_path: Path) -> tuple[int, str]:
|
|
45
49
|
"""(token count, model id) from the last non-sidechain assistant message's
|
|
46
50
|
usage. (0, "") for a fresh session with no assistant usage yet - that is a
|
|
47
|
-
legitimate state, not an error.
|
|
51
|
+
legitimate state, not an error. Entries whose model is `<synthetic>` are
|
|
52
|
+
skipped: Claude Code writes them (with all-zero usage) for things that are
|
|
53
|
+
not API responses, such as a usage-limit notice, so they say nothing about
|
|
54
|
+
the context size."""
|
|
48
55
|
if not transcript_path.is_file():
|
|
49
56
|
raise TranscriptError(f"transcript not found: {transcript_path}")
|
|
50
57
|
|
|
@@ -68,9 +75,10 @@ def _current_context_tokens(transcript_path: Path) -> tuple[int, str]:
|
|
|
68
75
|
continue
|
|
69
76
|
message = obj.get("message") or {}
|
|
70
77
|
usage = message.get("usage")
|
|
71
|
-
|
|
78
|
+
model = message.get("model") or ""
|
|
79
|
+
if isinstance(usage, dict) and model != SYNTHETIC_MODEL:
|
|
72
80
|
last_usage = usage
|
|
73
|
-
last_model =
|
|
81
|
+
last_model = model
|
|
74
82
|
except OSError as exc:
|
|
75
83
|
raise TranscriptError(f"cannot read transcript: {exc}") from exc
|
|
76
84
|
|
|
@@ -102,19 +110,18 @@ def _window_label(window: int) -> str:
|
|
|
102
110
|
return f"{(window + 500) // 1000}k"
|
|
103
111
|
|
|
104
112
|
|
|
105
|
-
def _format_cost(*, tokens: int,
|
|
106
|
-
"""
|
|
107
|
-
(not rounded) to 2dp - matches `bc`'s `scale=2`
|
|
108
|
-
original. Uses Decimal rather than native float
|
|
109
|
-
math.floor(raw * 100) / 100 on a float hits
|
|
110
|
-
ordinary inputs (e.g. tokens=
|
|
111
|
-
0.
|
|
112
|
-
|
|
113
|
-
hypothetical. Decimal(str(price_per_mtok)) avoids reintroducing the same
|
|
113
|
+
def _format_cost(*, tokens: int, cache_read_price_per_mtok: float) -> str:
|
|
114
|
+
"""Cost of reading `tokens` from the prompt cache at the model's cache-read
|
|
115
|
+
price, truncated (not rounded) to 2dp - matches `bc`'s `scale=2`
|
|
116
|
+
semantics from the bash original. Uses Decimal rather than native float
|
|
117
|
+
arithmetic: a naive math.floor(raw * 100) / 100 on a float hits
|
|
118
|
+
representation error for ordinary inputs (e.g. tokens=350_000,
|
|
119
|
+
price=0.20 evaluates to 0.06999999999999999 in float, one cent short of
|
|
120
|
+
the correct 0.07). Decimal(str(price)) avoids reintroducing the same
|
|
114
121
|
float-representation problem by round-tripping the price through its
|
|
115
122
|
float form first.
|
|
116
123
|
"""
|
|
117
|
-
raw = Decimal(tokens) / Decimal(1_000_000) * Decimal(str(
|
|
124
|
+
raw = Decimal(tokens) / Decimal(1_000_000) * Decimal(str(cache_read_price_per_mtok))
|
|
118
125
|
return str(raw.quantize(Decimal("0.01"), rounding=ROUND_DOWN))
|
|
119
126
|
|
|
120
127
|
|
|
@@ -134,7 +141,7 @@ def _reason(*, tokens: int, window: int, price: float, name: str, now: str, red:
|
|
|
134
141
|
k = _k_tokens(tokens)
|
|
135
142
|
pct = _pct_of_window(tokens, window)
|
|
136
143
|
label = _window_label(window)
|
|
137
|
-
cost = _format_cost(tokens=tokens,
|
|
144
|
+
cost = _format_cost(tokens=tokens, cache_read_price_per_mtok=price)
|
|
138
145
|
emoji = "🔴" if red else "🟠"
|
|
139
146
|
when = "when you get a natural break" if red else "whenever convenient"
|
|
140
147
|
return (
|
|
@@ -149,6 +156,48 @@ def _reason(*, tokens: int, window: int, price: float, name: str, now: str, red:
|
|
|
149
156
|
)
|
|
150
157
|
|
|
151
158
|
|
|
159
|
+
REMEDIATION_HINT = (
|
|
160
|
+
"To fix: add the id to src/hooks/model_info.py in claude-code-session-tools; if ccst is just out "
|
|
161
|
+
"of date, run `uv tool upgrade cc-session-tools` (installed from PyPI with uv) or "
|
|
162
|
+
"`uv tool install --reinstall <path to your checkout>` (local checkout)."
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
_ID_DISALLOWED = re.compile(r"[^A-Za-z0-9._:<>\[\]-]")
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _model_phrase(model_id: str) -> str:
|
|
169
|
+
"""How the unknown model is named in the message. Characters outside the set real ids use are
|
|
170
|
+
replaced, so a corrupt or hostile transcript value cannot break the quoted lines the assistant
|
|
171
|
+
is told to echo."""
|
|
172
|
+
if not model_id:
|
|
173
|
+
return "an unknown model (no model id was recorded)"
|
|
174
|
+
return f"model `{_ID_DISALLOWED.sub('?', model_id)}`"
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _reason_unknown(*, tokens: int, window: int, price: float, model_id: str, now: str, red: bool) -> str:
|
|
178
|
+
"""Message for a model id missing from model_info's table: the window and price are
|
|
179
|
+
assumptions and the text says so, instead of presenting them as facts."""
|
|
180
|
+
k = _k_tokens(tokens)
|
|
181
|
+
pct = _pct_of_window(tokens, window)
|
|
182
|
+
label = _window_label(window)
|
|
183
|
+
cost = _format_cost(tokens=tokens, cache_read_price_per_mtok=price)
|
|
184
|
+
model = _model_phrase(model_id)
|
|
185
|
+
emoji = "🔴" if red else "🟠"
|
|
186
|
+
when = "when you get a natural break" if red else "whenever convenient"
|
|
187
|
+
return (
|
|
188
|
+
f"The context window has passed {k}k tokens. The session's {model} is not in ccst's model "
|
|
189
|
+
f"table, so the window size is ASSUMED to be {label} tokens; the real window may be much "
|
|
190
|
+
f"larger (1M for current models) and any percentage may be wrong. THIS IS A WARNING ONLY - "
|
|
191
|
+
f"output the two lines below at the start of your response, then end your turn as you "
|
|
192
|
+
f"normally would. Do not restart or repeat any work.\n"
|
|
193
|
+
f"'{emoji} CONTEXT ({now}): ~{k}k tokens used; window size ASSUMED ({label}) for {model} - "
|
|
194
|
+
f"the real window may be much larger, so ~{pct}% is unreliable. ~${cost}/turn assumes the "
|
|
195
|
+
f"default ${price:.2f}/MTok cache-read price. This is a nudge, not a limit - keep going; "
|
|
196
|
+
f"/compact {when}. {REMEDIATION_HINT}'\n"
|
|
197
|
+
f"'(To silence this warning for the rest of the session, run /context-override.)'"
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
|
|
152
201
|
def main(argv: list[str] | None = None) -> int:
|
|
153
202
|
try:
|
|
154
203
|
stdin_obj = json.loads(sys.stdin.read() or "{}")
|
|
@@ -176,12 +225,19 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
176
225
|
return 0
|
|
177
226
|
|
|
178
227
|
window = model_info.context_window(model_id)
|
|
179
|
-
price = model_info.
|
|
180
|
-
name = model_info.display_name(model_id)
|
|
228
|
+
price = model_info.cache_read_price_per_mtok(model_id)
|
|
181
229
|
now = datetime.datetime.now().strftime("%H:%M")
|
|
182
230
|
red = tokens >= THRESHOLD_RED
|
|
183
231
|
|
|
184
|
-
|
|
232
|
+
if model_info.is_known(model_id):
|
|
233
|
+
reason = _reason(
|
|
234
|
+
tokens=tokens, window=window, price=price, name=model_info.display_name(model_id),
|
|
235
|
+
now=now, red=red,
|
|
236
|
+
)
|
|
237
|
+
else:
|
|
238
|
+
reason = _reason_unknown(
|
|
239
|
+
tokens=tokens, window=window, price=price, model_id=model_id, now=now, red=red,
|
|
240
|
+
)
|
|
185
241
|
print(json.dumps({"decision": "block", "reason": reason}))
|
|
186
242
|
return 0
|
|
187
243
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Model id -> context window size, cache-read price, display name.
|
|
2
|
+
|
|
3
|
+
Consumed by context_window_warning to phrase its nudge in terms of "% of the
|
|
4
|
+
model's actual window" and to estimate a per-turn cache-read cost.
|
|
5
|
+
|
|
6
|
+
Context windows as of 2026-09-29: Fable 5 / Mythos 5 / Opus 5 / Opus 4.6-4.8 /
|
|
7
|
+
Sonnet 5 / Sonnet 5.5 / Opus 5.5 / Fable 5.1 / Mythos 5.1 / Sonnet 4.6 all 1,000,000 tokens
|
|
8
|
+
(the default, not a beta long-context mode); Haiku 4.5 stays at 200,000.
|
|
9
|
+
Prices are each model's published first-party cache-read ("cache hits and
|
|
10
|
+
refreshes") rate per million tokens, from
|
|
11
|
+
https://platform.claude.com/docs/en/about-claude/pricing (checked 2026-09-29).
|
|
12
|
+
They are not a fixed fraction of the input price: Fable 5.1 and Mythos 5.1 read at 0.025x
|
|
13
|
+
and Opus 5.5 at 0.05x, every other model here at 0.1x.
|
|
14
|
+
|
|
15
|
+
Re-check this table whenever a new model ships. A model not matched by any
|
|
16
|
+
case (`is_known` is False) falls through to the default window and price
|
|
17
|
+
(200000 tokens / $0.50 per MTok) - deliberately the same window as every
|
|
18
|
+
pre-Claude-5 model, so an unknown model degrades to conservative,
|
|
19
|
+
already-correct-for-most-history behaviour rather than going quiet or firing
|
|
20
|
+
too early. Those defaults are assumptions, and the warning says so; only
|
|
21
|
+
`display_name` has no default (it raises KeyError for an unknown id).
|
|
22
|
+
|
|
23
|
+
Deliberately not `claude_code_usage.pricing`: that module imports pandas, too
|
|
24
|
+
heavy for a hook that runs on every Stop event. tests/test_pricing.py asserts
|
|
25
|
+
that every cache-read price here matches that module's table.
|
|
26
|
+
"""
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import re
|
|
30
|
+
|
|
31
|
+
_WINDOW_1M = {
|
|
32
|
+
"claude-fable-5", "claude-mythos-5",
|
|
33
|
+
"claude-opus-5", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6",
|
|
34
|
+
"claude-sonnet-5", "claude-sonnet-4-6",
|
|
35
|
+
"claude-sonnet-5-5", "claude-opus-5-5", "claude-fable-5-1", "claude-mythos-5-1",
|
|
36
|
+
}
|
|
37
|
+
_CACHE_READ_PRICE = {
|
|
38
|
+
"claude-fable-5-1": 0.25, "claude-mythos-5-1": 0.25, "claude-fable-5": 1.00, "claude-mythos-5": 1.00,
|
|
39
|
+
"claude-opus-5-5": 0.20,
|
|
40
|
+
"claude-opus-5": 0.50, "claude-opus-4-8": 0.50, "claude-opus-4-7": 0.50, "claude-opus-4-6": 0.50,
|
|
41
|
+
"claude-sonnet-5-5": 0.20, "claude-sonnet-5": 0.20, "claude-sonnet-4-6": 0.30,
|
|
42
|
+
"claude-haiku-4-5": 0.10,
|
|
43
|
+
}
|
|
44
|
+
_NAME = {
|
|
45
|
+
"claude-fable-5": "Fable 5", "claude-mythos-5": "Mythos 5",
|
|
46
|
+
"claude-opus-5": "Opus 5", "claude-opus-4-8": "Opus 4.8",
|
|
47
|
+
"claude-opus-4-7": "Opus 4.7", "claude-opus-4-6": "Opus 4.6",
|
|
48
|
+
"claude-sonnet-5": "Sonnet 5", "claude-sonnet-4-6": "Sonnet 4.6",
|
|
49
|
+
"claude-sonnet-5-5": "Sonnet 5.5", "claude-opus-5-5": "Opus 5.5",
|
|
50
|
+
"claude-fable-5-1": "Fable 5.1", "claude-mythos-5-1": "Mythos 5.1",
|
|
51
|
+
"claude-haiku-4-5": "Haiku 4.5",
|
|
52
|
+
}
|
|
53
|
+
_DEFAULT_WINDOW = 200_000
|
|
54
|
+
_DEFAULT_CACHE_READ_PRICE = 0.50
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
_DATED_SNAPSHOT = re.compile(r"(.+)-\d{8}")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _canonical(model_id: str) -> str:
|
|
61
|
+
"""A dated snapshot id (`<id>-YYYYMMDD`) resolves to its undated row. Applied once, and
|
|
62
|
+
only for an exactly-eight-digit suffix: any other suffix (or a snapshot of an unknown id)
|
|
63
|
+
stays unknown. `[1m]`/`-latest` are not handled - transcripts' `message.model` never
|
|
64
|
+
carries them."""
|
|
65
|
+
match = _DATED_SNAPSHOT.fullmatch(model_id)
|
|
66
|
+
return match.group(1) if match else model_id
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def context_window(model_id: str) -> int:
|
|
70
|
+
return 1_000_000 if _canonical(model_id) in _WINDOW_1M else _DEFAULT_WINDOW
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def cache_read_price_per_mtok(model_id: str) -> float:
|
|
74
|
+
return _CACHE_READ_PRICE.get(_canonical(model_id), _DEFAULT_CACHE_READ_PRICE)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def is_known(model_id: str) -> bool:
|
|
78
|
+
return _canonical(model_id) in _NAME
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def display_name(model_id: str) -> str:
|
|
82
|
+
"""Raises KeyError for an unknown id: callers check `is_known` first."""
|
|
83
|
+
return _NAME[_canonical(model_id)]
|