tokenjam 0.7.0__tar.gz → 0.7.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.
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/core-architecture.md +1 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/web-ui.md +5 -2
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.github/scripts/archive_traffic.py +6 -2
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.github/workflows/traffic-archive.yml +48 -3
- {tokenjam-0.7.0 → tokenjam-0.7.1}/PKG-INFO +8 -2
- {tokenjam-0.7.0 → tokenjam-0.7.1}/README.md +7 -1
- tokenjam-0.7.1/RELEASE_NOTES_0.7.0.md +113 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/alerts.md +52 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/architecture.md +84 -2
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/backfill/langfuse.md +7 -5
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/cli-reference.md +84 -3
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/configuration.md +7 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/first-hour.md +20 -7
- tokenjam-0.7.1/docs/ledger/cloud-bridge.md +106 -0
- tokenjam-0.7.1/docs/ledger/hooks-and-notes.md +129 -0
- tokenjam-0.7.1/docs/ledger/overview.md +135 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/nemoclaw-integration.md +1 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/optimize/shipped.md +13 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/optimize/verbosity.md +9 -7
- {tokenjam-0.7.0 → tokenjam-0.7.1}/growth/README.md +22 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/npm-wrapper/package.json +1 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/plugin/.claude-plugin/plugin.json +1 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/pyproject.toml +1 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/sdk-ts/package.json +1 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_api.py +19 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_cli.py +117 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_cost_attribution.py +72 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_db.py +22 -0
- tokenjam-0.7.1/tests/integration/test_full_pipeline.py +1379 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_storage_backend_parity.py +44 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/rate_bands.py +5 -4
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/synthetic/test_ingest.py +314 -24
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_advertised_commands_are_invocable.py +1 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_api_backend_span_deserialize.py +2 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cmd_policy.py +18 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_config.py +18 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_context_diagnostic.py +25 -5
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cost.py +7 -6
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_db_helpers.py +11 -0
- tokenjam-0.7.1/tests/unit/test_doctor_paths.py +184 -0
- tokenjam-0.7.1/tests/unit/test_doctor_unattributed_spend.py +56 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_framing.py +14 -0
- tokenjam-0.7.1/tests/unit/test_http_exporter_auth.py +199 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_ingest_langfuse.py +194 -0
- tokenjam-0.7.1/tests/unit/test_lens_unattributed_spend.py +50 -0
- tokenjam-0.7.1/tests/unit/test_mast_channel.py +283 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize_verbosity.py +144 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_pricing_axes.py +13 -10
- tokenjam-0.7.1/tests/unit/test_pricing_current_lineup.py +205 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_provider_attribution.py +54 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_quickstart.py +14 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_schema_self_heal.py +1 -1
- tokenjam-0.7.1/tests/unit/test_ui_index_reload.py +143 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/app.py +35 -4
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/cost.py +9 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/sessions.py +2 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/status.py +10 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/traces.py +1 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_backfill.py +42 -2
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_cost.py +37 -3
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_doctor.py +71 -6
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_optimize.py +16 -4
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_policy.py +7 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_status.py +25 -2
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/alerts.py +111 -8
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/api_backend.py +30 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/config.py +7 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/context_diagnostic.py +6 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/cost.py +5 -4
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/db.py +352 -20
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/framing.py +1 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/ingest.py +197 -15
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/ingest_adapters/langfuse.py +97 -34
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/models.py +5 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/session_timeline.py +1 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/otel/provider.py +38 -1
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/pricing/models.toml +339 -20
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/bootstrap.py +9 -4
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/http_exporter.py +24 -6
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/ui/index.html +24 -2
- tokenjam-0.7.0/tests/integration/test_full_pipeline.py +0 -422
- tokenjam-0.7.0/tests/unit/test_doctor_paths.py +0 -53
- tokenjam-0.7.0/tests/unit/test_http_exporter_auth.py +0 -45
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/alerts.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/api.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/cli-output.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/config-toml.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/core-config-pricing.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/examples-and-incidents.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/growth-instrumentation.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/ingest-accounting.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/onboarding-dotfiles.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/optimize-analyzers.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/optimize-architecture.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/optimize-cost-figures.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/otel.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/release.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/sdk.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude/rules/tests.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.claude-plugin/marketplace.json +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.dockerignore +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.github/CODEOWNERS +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.github/ISSUE_TEMPLATE/integration_request.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.github/actions/docker-publish/action.yml +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.github/pull_request_template.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.github/scripts/contributor_label_guard.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.github/workflows/ci.yml +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.github/workflows/contributor-label-guard.yml +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.github/workflows/docker-publish.yml +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.github/workflows/publish-npm.yml +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.github/workflows/publish-pypi.yml +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/.gitignore +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/AGENTS.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/CLAUDE.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/CODE_OF_CONDUCT.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/CONTRIBUTING.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/Dockerfile +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/LICENSE +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/Makefile +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/SECURITY.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/agent-capability-matrix.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/assets/tj-quickstart-hero.png +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/assets/tokenjam-2d.png +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/assets/tokenjam-dashboard.png +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/assets/tokenjam-flow-band.svg +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/assets/tokenjam-token-flow.png +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/assets/tokenjam-waste-grid.svg +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/backfill/codex.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/backfill/helicone.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/backfill/otlp.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/backfill/overview.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/brand/README.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/brand/tokenjam-banner.png +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/brand/tokenjam-banner.svg +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/brand/tokenjam-icon.png +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/brand/tokenjam-icon.svg +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/brand/tokenjam-repo-header.png +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/brand/tokenjam-wordmark.png +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/brand/tokenjam-wordmark.svg +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/claude-code-integration.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/export.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/framework-support.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/getting-started.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/harness-integration.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/installation.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/internal/close-the-loop.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/internal/lens-vendor-versions.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/internal/release-smoke-checklist.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/internal/repeat-task-codification-measurement.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/internal/specs/.gitkeep +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/internal/specs/map-board-direction.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/openclaw.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/optimize/cache.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/optimize/downsize.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/optimize/reuse.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/optimize/script.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/optimize/subagent.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/optimize/trim.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/policy/overview.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/proxy/overview.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/python-sdk.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/screenshots/tj-budget.png +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/screenshots/tj-cost.png +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/screenshots/tj-dashboard-leaderboard.png +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/screenshots/tj-dashboard-tools.png +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/screenshots/tj-dashboard.png +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/screenshots/tj-status.png +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/screenshots/tj-traces.png +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/docs/typescript-sdk.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/README.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/alerts_and_drift/_shared.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/alerts_and_drift/budget_breach_demo.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/alerts_and_drift/drift_demo.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/alerts_and_drift/record_outcome_demo.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/alerts_and_drift/sensitive_actions_demo.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/multi/rag_pipeline.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/multi/research_team.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/multi/router_agent.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/multi/sample_docs/agent_patterns.txt +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/multi/sample_docs/cost_management.txt +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/multi/sample_docs/observability.txt +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/multi/sample_docs/safety.txt +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/openclaw/README.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/single_framework/autogen_agent.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/single_framework/crewai_agent.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/single_framework/langchain_agent.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/single_framework/langgraph_agent.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/single_framework/llamaindex_agent.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/single_provider/anthropic_agent.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/single_provider/bedrock_agent.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/single_provider/gemini_agent.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/single_provider/litellm_agent.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/single_provider/openai_agent.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/examples/single_provider/openai_agents_sdk_agent.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/incidents/hallucination-drift/BLOG.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/incidents/hallucination-drift/README.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/incidents/hallucination-drift/scenario.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/incidents/retry-loop/BLOG.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/incidents/retry-loop/README.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/incidents/retry-loop/scenario.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/incidents/surprise-cost/BLOG.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/incidents/surprise-cost/README.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/incidents/surprise-cost/scenario.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/npm-wrapper/README.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/npm-wrapper/bin/tj.js +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/plugin/README.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/plugin/commands/doctor.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/plugin/commands/onboard.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/plugin/commands/optimize.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/plugin/commands/status.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/plugin/commands/uninstall.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/scripts/release.sh +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/sdk-ts/README.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/sdk-ts/examples/record-outcome.ts +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/sdk-ts/package-lock.json +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/sdk-ts/src/client.test.ts +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/sdk-ts/src/client.ts +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/sdk-ts/src/index.ts +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/sdk-ts/src/record-outcome.test.ts +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/sdk-ts/src/semconv.test.ts +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/sdk-ts/src/semconv.ts +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/sdk-ts/src/span-builder.test.ts +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/sdk-ts/src/span-builder.ts +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/sdk-ts/src/types.ts +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/sdk-ts/tsconfig.json +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/agent-post-release-runner.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/agent-pre-release-runner.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/agents/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/agents/email_agent_budget_breach.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/agents/email_agent_drift.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/agents/email_agent_loop.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/agents/email_agent_normal.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/agents/mock_llm.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/agents/test_mock_scenarios.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/agents/test_record_outcome.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/conftest.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/e2e/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/e2e/conftest.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/e2e/test_real_llm.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/factories.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/fixtures/helicone_real_response.json +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/fixtures/langfuse_real_response.json +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/fixtures/otlp_sample.json +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_agents_and_tenants_dual_units.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_analytics.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_analyzers_off_the_request_path.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_cli_api_framing_parity.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_cli_uninstall.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_cmd_proxy.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_cmd_route.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_context_serve.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_cost_charts.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_cost_compare_serve.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_cost_components_reconcile.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_cost_components_recoverable_population.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_cost_framing_window.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_cost_proposals_api.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_daemon_lock_paths_770.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_data_access_parity.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_demo_live.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_demos.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_first_run_roundtrip_239.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_global_json_flag.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_inbox_headline_total_api.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_litellm_enrichment.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_logs_api.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_policy_api.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_proxy_app.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_proxy_policy.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_quota_audit_serve.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_relearn_api.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_relearn_window_api.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_rules_surface.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_sdk_config_discovery.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_summarize_api.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_summarize_cli.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_summarize_run_api.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_tokenmaxx_serve.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_trace_detail_payload.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/integration/test_xdist_isolation.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/ledger_fixtures.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/manual-new-release-tests.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/manual-pre-release-testing.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/summarize_fakes.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/synthetic/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/synthetic/test_alert_engine_restart.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/synthetic/test_alert_rules.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/synthetic/test_async_hooks_concurrency.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/synthetic/test_cost_tracking.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/synthetic/test_drift_detection.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/synthetic/test_request_capture.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/synthetic/test_schema_validation.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/token_aggregate_guard.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/toy_agent/toy_agent.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_agent_config.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_agent_kind.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_alerts.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_analysis_span_retention.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_analytics_metric_expr.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_analyzer_scope.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_analyzer_scope_isolation.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_api_backend_timeout.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_async_hooks.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_attribution_cache.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_backfill.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_backfill_codex.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_backfill_interrupted_flush.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_backfill_progress.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_batch_placement.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_budget_cap_policy.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_budget_group_cost.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_budget_route.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_bulk_insert_spans.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cache_efficacy.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cache_recommend.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cache_root_cause.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cache_root_cause_proposals.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cache_root_cause_render.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cli_cloud_init.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cli_entrypoint.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cli_help_descriptions.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cli_palette.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cli_status_registry.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cloud_sync.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cmd_cost.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cmd_mcp_config_discovery.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cmd_pricing.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cmd_resume_brief.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cmd_serve_port_precheck.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cmd_session_story.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cmd_status_ingest_freshness.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cmd_status_teaser.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cmd_stop.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cmd_stop_scoping.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cmd_tokenmaxx.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cmd_upgrade.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_commit_hooks.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_compare.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_config_discovery_guard.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_config_secret_divergence.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_config_write_target.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_context_resend.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_contributor_label_guard.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cost_accounting_guards.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cost_api_recoverable_presentation.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cost_compare_framing.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cost_proposal_persona_ledger.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cost_proposal_verbs.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cost_proposals.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cost_proposals_model.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cross_analyzer_recoverable_invariant.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cycle.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_cycle_provenance_record.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_dashboard_hero_netted_rollup.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_data_access.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_db_close_backfill.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_db_fatal_invalidation.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_deadweight.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_deadweight_apply.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_deadweight_plugins.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_delivery_kinds.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_demo_env.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_demo_live.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_demo_packaging.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_demo_scenarios.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_distill.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_doctor_capture_prompts.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_doctor_content_capture_gap.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_doctor_corpus_freshness.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_doctor_daemon_liveness.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_doctor_first_signal.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_doctor_ingest_secret.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_doctor_otlp_endpoint.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_doctor_spans_indexes.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_doctor_statusline_wiring.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_doctor_transcript_gap.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_downgrade_candidates_priceable.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_downsize_agent_pricing.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_downsize_applied_ledger_migration.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_downsize_driver_role.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_drift.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_export_claude_code.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_export_route_generators.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_fix_actionability.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_fix_catalog.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_fix_grounding.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_formatting.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_formatting_capped_table.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_global_ingest_secret.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_harness_setup.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_humanize.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_inbox_contribution.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_ingest_accounting.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_ingest_freshness.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_ingest_helicone.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_ingest_otlp.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_ingested_ids_endpoint.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_lens_dashboard_states.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_lens_module_parses.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_lens_optimize_switch_states.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_lens_persona_hidden_mirror.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_lens_select_all_behaviour.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_lens_sessions_zone_spacing.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_lens_ui_regression.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_litellm_client.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_litellm_integration.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_logs_converter.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_loop.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_loop_api.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_loop_transcript_path.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_main_lock_holder_hint.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_mcp_policy.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_mcp_probe.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_mcp_readonly_schema_gap.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_mcp_server.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_mcp_setup_project_tj_config.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_method_capture.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_method_spine.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_model_apply.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_model_tiers.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_models.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_mythos_premium_gates.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_no_fix_prose_outside_the_catalog.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_no_sentinel_timestamps.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_no_tracked_dev_secrets.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_no_tracker_ids_in_printed_strings.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_add_project.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_backfill_scope.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_budget_gate.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_capture_default.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_codex.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_daemon.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_detect.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_ephemeral_guard.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_first_run.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_hygiene.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_path_branch.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_path_resolution.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_plan.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_project_flag_removed.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_resume_hook.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_stack_detection.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_statusline.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_tool_inputs_default.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_verify.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_verify_cli.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_onboard_zshrc_otel.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_openclaw_ingest.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize_analyzers_route.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize_clustering.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize_plan_multiplier.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize_rank.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize_recoverable.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize_resend_render.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize_reuse.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize_savings_ci.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize_scoreboard.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize_subagent.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize_summarize.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize_threshold_rendering.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize_trim_provenance.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_optimize_validate.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_opus_quota_audit.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_past_overspend.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_persona_analyzer_gate.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_persona_population_scope.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_persona_scoped_endpoints.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_phases.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_ping.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_plan_tier_apply.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_plugin_command_docs_namespaced.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_policy_engine.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_pricing_coverage.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_pricing_lookup_forms.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_pricing_override.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_prompt_bloat.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_provider_attribution_194.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_provider_content_capture.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_provider_run_id.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_proxy_audit.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_proxy_gate.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_rate_profile.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_recommendations.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_relearn.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_relearn_apply.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_relearn_archive_and_cost.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_relearn_cli.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_relearn_families_and_boundary.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_relearn_otel.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_relearn_window.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_repeat_task.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_repo_context.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_report_roundtrip.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_report_window.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_reset.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_resume_brief.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_reuse_skeleton.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_rollup_covers_every_rendered_row.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_rollup_subagent_downsize_dedup.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_rule_placement.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_rule_presence.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_rulewrite_applied_detection.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_rulewrite_dismissal.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_rulewrite_legacy.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_rulewrite_lifecycle.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_runlink.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_scan_bar_truth.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_scan_cycle_provenance.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_scan_watermark.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_sdk_agent_session.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_sdk_attribution.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_serve_transcript_catchup.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_server_state.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_session_commits.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_session_cost_drift.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_session_label.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_session_provenance.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_session_repo_context.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_session_status_lifecycle.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_session_subagents.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_sessionmap.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_single_derivation.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_span_pricing.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_spans_stats_repair.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_status_overview.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_status_sdk.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_statusline.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_statusline_driver_staleness.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_stream_usage_analyzer.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_stream_usage_capture.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_subagent_rubric_contradiction.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_apply.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_backup.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_calibrate.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_candidates.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_catalog.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_classify.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_delivery.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_detect.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_estimate.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_invocations.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_load_semantics.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_numbering.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_prompt_fence.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_prune_quarantine.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_relocate.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_repo_roots.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_route.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_sections.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_session.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_summarize_wrap.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_time_parse.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_tj_db_guard.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_transcript.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_transcript_cache.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_transcript_refill.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_transcript_sync.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_transport_401.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_ui_offline.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_uninstall_persistent_install.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_uninstall_runner_detect.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_uninstall_wrapper.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_usage.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_workflow_restructure.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tests/unit/test_workmap.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/deps.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/middleware.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/_body.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/agents.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/alerts.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/analytics.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/backfill.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/budget.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/context.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/cost_compare.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/drift.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/logs.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/loop.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/metrics.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/optimize.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/otlp.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/persona.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/policy.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/quota_audit.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/recommendations.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/relearn.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/reuse.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/rules.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/runs.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/shipped.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/spans.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/summarize.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/summarize_run.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/tools.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/api/routes/version.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/backfill_progress.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/banner.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_alerts.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_budget.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_commit_note.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_context.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_demo.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_drift.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_export.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_loop.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_mcp.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_onboard.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_otel.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_ping.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_pricing.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_proxy.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_quickstart.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_quota_audit.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_relearn.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_report.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_reset.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_resume_brief.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_route.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_rules.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_serve.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_session_end.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_session_story.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_statusline.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_stop.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_summarize.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_tokenmaxx.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_tools.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_traces.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_uninstall.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cmd_upgrade.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/cost_proposal_verbs.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/data_access.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/entrypoint.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/home.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/json_option.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/ledger_cloud.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/ledger_hooks.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/main.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/onboard_detect.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/relearn_write_verbs.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/cli/tj_status.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/agent_config.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/agent_kind.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/analysis_span.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/atomic_write.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/attribution_cache.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/backfill.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/cloud_sync.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/commit_hooks.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/cycle.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/data_span.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/distill.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/drift.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/export/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/export/ccr.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/export/claude_code.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/export/common.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/export/litellm.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/export/reuse_report.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/export/reuse_skeleton.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/fixes/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/fixes/catalog.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/fixes/grounding.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/fixes/lint.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/fixes/registry.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/harness_setup.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/ingest_adapters/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/ingest_adapters/codex.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/ingest_adapters/helicone.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/ingest_adapters/otlp.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/ingest_freshness.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/loop.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/method_capture.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/method_spine.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/model_tiers.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/onboard_verify.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/README.md +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/accounting.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/batch_placement.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/budget_projection.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/cache_efficacy.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/cache_recommend.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/context_resend.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/deadweight.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/downsize_agents.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/model_downgrade.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/output_verbosity.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/plan_reuse.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/prompt_bloat.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/relearn.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/resend_tail.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/shipped.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/stream_usage.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/subagent_rightsizing.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/summarize.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/analyzers/workflow_restructure.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/clustering.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/cost_apply.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/cost_proposals.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/cycle_provenance.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/dismissals.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/inbox_contribution.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/ingest_watermark.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/mcp_probe.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/model_apply.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/projection.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/rank.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/rate_profile.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/registry.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/relearn_apply.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/relearn_otel.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/relearn_proposals.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/relearn_store.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/relearn_window.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/repeat_task.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/report_store.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/report_window.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/rule_placement.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/rule_scope.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/runner.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/scan_cycle.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/scope.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/single_derivation.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/span_pricing.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/stats.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/types.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/optimize/validate.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/persona_scope.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/phases.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/pricing.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/pricing_coverage.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/recommendations.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/repo_context.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/resume_brief.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/retention.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/rulewrite/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/rulewrite/apply.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/rulewrite/delivery.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/rulewrite/kinds.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/rulewrite/legacy.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/rulewrite/plan.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/rulewrite/presence.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/rulewrite/store.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/rulewrite/types.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/runlink.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/savings_log.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/schema_validator.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/server_state.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/sessionmap.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/shipped.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/agent_files.toml +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/apply.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/backup.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/calibrate.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/candidates.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/catalog.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/classify.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/delivery.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/detect.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/estimate.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/invocations.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/load_semantics.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/numbering.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/prune.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/quarantine.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/relocate.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/repo_roots.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/route.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/sections.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/session.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/summarize/wrap.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/system_prefix.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/transcript.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/transcript_cache.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/transcript_sync.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/usage.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/core/workmap.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/demo/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/demo/env.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/demo/live.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/hooks/post-commit +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/hooks/prepare-commit-msg +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/mcp/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/mcp/server.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/otel/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/otel/otlp_parsing.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/otel/semconv.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/proxy/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/proxy/app.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/proxy/audit.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/proxy/engine.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/proxy/gate.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/proxy/observer.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/proxy/recommend.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/proxy/server.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/proxy/stream_usage.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/proxy/wiring.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/py.typed +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/agent.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/attribution.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/client.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/integrations/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/integrations/_request_capture.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/integrations/anthropic.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/integrations/autogen.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/integrations/base.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/integrations/bedrock.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/integrations/crewai.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/integrations/gemini.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/integrations/langchain.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/integrations/langgraph.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/integrations/litellm.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/integrations/llamaindex.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/integrations/nemoclaw.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/integrations/openai.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/integrations/openai_agents_sdk.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/sdk/transport.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/ui/vendor/fonts/Geist-Variable.woff2 +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/ui/vendor/fonts/GeistMono-Variable.woff2 +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/ui/vendor/fonts/LICENSE-Geist.txt +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/ui/vendor/htm.js +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/ui/vendor/preact-hooks.js +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/ui/vendor/preact.js +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/ui/vendor/uplot.css +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/ui/vendor/uplot.js +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/utils/__init__.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/utils/formatting.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/utils/humanize.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/utils/ids.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/utils/signatures.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/utils/theme.py +0 -0
- {tokenjam-0.7.0 → tokenjam-0.7.1}/tokenjam/utils/time_parse.py +0 -0
|
@@ -74,7 +74,7 @@ joins the session of any sibling span on the same `trace_id`.
|
|
|
74
74
|
|
|
75
75
|
**Rule: both cache fields belong on both sides of every token sum and every price comparison** — an omission that recurs in `core/optimize/`. **(a) In aggregates**, sum cache reads AND cache writes in the same expression; `COALESCE(SUM(input_tokens + output_tokens + cache_tokens + cache_write_tokens), 0)` (the form in `optimize/runner.py`) is canonical for per-cluster and per-session totals — grep `SUM.*cache_tokens` when adding one. **(b) In pricing comparisons**, an actual-vs-alternative-model savings figure must price cache identically on both sides: a hand-rolled alt-price helper omitting cache-write while the actual `cost_usd` bills it inflates every derived saving by the candidate's full cache-write cost, and evades that grep because the SQL is correct and the Python pricing is not — the omission lives in a per-row helper, not a `SUM`. **Keep exactly one pricer:** route every alternative-side computation through `calculate_cost`, which covers all four token classes.
|
|
76
76
|
|
|
77
|
-
- **`alerts.py`** — `AlertEngine` (the kinds it can fire are the `AlertType` enum in `core/models.py`; read the enum, never a count kept here), `CooldownTracker` (in-memory, per agent+type, resets on restart), `AlertDispatcher` routing to the channel types the `_build_channel` factory knows (stdout, file, ntfy, webhook, Discord, Telegram — that factory is the live set). `AlertEngine.fire()` is the entry point for `SchemaValidator` and `DriftDetector`. Suppressed alerts are still persisted, just not dispatched. Thresholds are module-level constants, not config — read them for values: **retry loop** fires when the same tool call repeats often enough inside a trailing span window (`_RETRY_LOOP_THRESHOLD` / `_RETRY_LOOP_WINDOW`); **failure rate** when the error share over a trailing span window crosses a ceiling, re-evaluated only every Nth error to bound cost (`_FAILURE_RATE_THRESHOLD` / `_FAILURE_RATE_WINDOW` / `_FAILURE_RATE_CHECK_INTERVAL`); **session duration** past a default wall-clock ceiling (`_SESSION_DURATION_DEFAULT`). Stdout and file channels always include full detail regardless of `include_captured_content`.
|
|
77
|
+
- **`alerts.py`** — `AlertEngine` (the kinds it can fire are the `AlertType` enum in `core/models.py`; read the enum, never a count kept here), `CooldownTracker` (in-memory, per agent+type, resets on restart), `AlertDispatcher` routing to the channel types the `_build_channel` factory knows (stdout, file, ntfy, webhook, Discord, Telegram, Mast — that factory is the live set). `AlertEngine.fire()` is the entry point for `SchemaValidator` and `DriftDetector`. Suppressed alerts are still persisted, just not dispatched. Thresholds are module-level constants, not config — read them for values: **retry loop** fires when the same tool call repeats often enough inside a trailing span window (`_RETRY_LOOP_THRESHOLD` / `_RETRY_LOOP_WINDOW`); **failure rate** when the error share over a trailing span window crosses a ceiling, re-evaluated only every Nth error to bound cost (`_FAILURE_RATE_THRESHOLD` / `_FAILURE_RATE_WINDOW` / `_FAILURE_RATE_CHECK_INTERVAL`); **session duration** past a default wall-clock ceiling (`_SESSION_DURATION_DEFAULT`). Stdout and file channels always include full detail regardless of `include_captured_content`.
|
|
78
78
|
|
|
79
79
|
- **`drift.py`** — `DriftDetector`, Z-score based behavioral drift detection, fires at session end.
|
|
80
80
|
|
|
@@ -28,8 +28,11 @@ the sidebar wordmark, and the OpenAPI title, but never in module names, route pa
|
|
|
28
28
|
Screens: **Overview** (the default landing route — a triage front door), Status, Traces, Cost,
|
|
29
29
|
Alerts, Drift, Optimize (with **Summarize** and **Rules** sub-views), Budget.
|
|
30
30
|
|
|
31
|
-
`app.py`
|
|
32
|
-
|
|
31
|
+
`app.py` caches `index.html` in memory but re-reads it whenever the file's mtime changes (one `stat()` per
|
|
32
|
+
request), so edits show up on the next page reload against a running `tj serve` — no restart needed. The
|
|
33
|
+
`tj-api-key` / `tj-write-token` `<meta>` injection runs on every response, so it applies to the re-read HTML
|
|
34
|
+
too. Changes to `ui/vendor/*` are plain `StaticFiles` and were never cached by the app. Tests read the file
|
|
35
|
+
from disk directly and aren't affected.
|
|
33
36
|
|
|
34
37
|
- **Offline-first (Critical Rule 18, `.claude/rules/web-ui.md`):** every JS/CSS dep is vendored under `vendor/` — Preact + hooks + htm (ESM via `<script type="importmap">`) and **uPlot** (vendored IIFE global `uPlot` + CSS, pinned in `docs/internal/lens-vendor-versions.md`). No render-time external HTTP. `tests/unit/test_ui_offline.py` enforces this; clickable `<a href>` links are the only allowed external URLs.
|
|
35
38
|
- **Single compute path:** the UI reads everything from the REST API and **never re-implements analysis, aggregation, or plan-tier framing in JS** — it consumes the `framing` block (see `core/framing.py`). If the UI needs a number, extend the endpoint; don't compute it client-side. This applies to gating/filter sets too, not just numbers: if a Python-side map decides which analyzers/findings apply to a persona (e.g. `core/optimize/runner.py`'s `PERSONA_DISABLED_ANALYZERS`), the API already publishes the resolved set (`persona_disabled_analyzers` on `/optimize`) — read that field everywhere the gate is needed, never re-declare the map as a second JS literal. Two call sites deriving the same set from two different sources will silently desync the moment either side edits its copy.
|
|
@@ -14,8 +14,12 @@ automatically by GitHub Actions). The default workflow token works because the
|
|
|
14
14
|
workflow grants `administration: read`, which the Traffic API requires.
|
|
15
15
|
|
|
16
16
|
Failure mode: any API error raises and the process exits non-zero, so the run
|
|
17
|
-
shows red in the Actions tab
|
|
18
|
-
|
|
17
|
+
shows red in the Actions tab. **Nothing else watches it** — the health check that
|
|
18
|
+
this docstring used to promise was descoped before the workflow shipped (see
|
|
19
|
+
growth/README.md), and that gap is why a broken publish step went unnoticed from
|
|
20
|
+
2026-W26 to 2026-W41 while this script kept succeeding every week. If you are
|
|
21
|
+
relying on this archive, check the branch rather than assuming a green pipeline.
|
|
22
|
+
No-data weeks still write the file — its existence is the success signal.
|
|
19
23
|
"""
|
|
20
24
|
from __future__ import annotations
|
|
21
25
|
|
|
@@ -56,15 +56,60 @@ jobs:
|
|
|
56
56
|
GH_REPO: ${{ github.repository }}
|
|
57
57
|
WEEK: ${{ steps.archive.outputs.iso_week }}
|
|
58
58
|
run: |
|
|
59
|
+
set -euo pipefail
|
|
60
|
+
remote="https://x-access-token:${GH_TOKEN}@github.com/${GH_REPO}.git"
|
|
59
61
|
tmp="$(mktemp -d)"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
|
|
63
|
+
# Create traffic-data if it is missing rather than dying on it. The
|
|
64
|
+
# branch disappeared once (deleted, or never recreated after a repo
|
|
65
|
+
# operation) and every weekly run from 2026-W26 to 2026-W41 then
|
|
66
|
+
# failed on `fatal: Remote branch traffic-data not found`, AFTER the
|
|
67
|
+
# collect step had succeeded. Fifteen weeks of snapshots were
|
|
68
|
+
# gathered and thrown away; the Traffic API retains only 14 days, so
|
|
69
|
+
# every week before the current window is gone for good. A missing
|
|
70
|
+
# branch is a recoverable state, so recover from it: the archive's
|
|
71
|
+
# whole purpose is to outlive that 14-day window, and a publisher
|
|
72
|
+
# that cannot create its own destination defeats it on the one day
|
|
73
|
+
# it matters.
|
|
74
|
+
#
|
|
75
|
+
# Distinguish "no such branch" from "could not ask". `ls-remote
|
|
76
|
+
# --exit-code` returns 2 for no matching ref and 128 for a transport
|
|
77
|
+
# or auth failure, so swallowing every non-zero status would let a
|
|
78
|
+
# momentary network blip start a fresh local history against a branch
|
|
79
|
+
# that already exists -- the push then fails as a non-fast-forward,
|
|
80
|
+
# and the run looks like the very bug this step fixes. Only 2 means
|
|
81
|
+
# create; anything else re-raises with git's own message.
|
|
82
|
+
set +e
|
|
83
|
+
git ls-remote --exit-code --heads "$remote" traffic-data >/dev/null
|
|
84
|
+
ls_status=$?
|
|
85
|
+
set -e
|
|
86
|
+
if [ "$ls_status" -eq 0 ]; then
|
|
87
|
+
git clone --quiet --depth 1 --branch traffic-data "$remote" "$tmp"
|
|
88
|
+
elif [ "$ls_status" -ne 2 ]; then
|
|
89
|
+
echo "error: could not reach ${GH_REPO} to check for traffic-data" \
|
|
90
|
+
"(git ls-remote exit ${ls_status}). Refusing to guess that the" \
|
|
91
|
+
"branch is missing." >&2
|
|
92
|
+
git ls-remote --heads "$remote" traffic-data >/dev/null
|
|
93
|
+
exit "$ls_status"
|
|
94
|
+
else
|
|
95
|
+
echo "traffic-data does not exist on ${GH_REPO} — creating it."
|
|
96
|
+
git -C "$tmp" init --quiet --initial-branch=traffic-data
|
|
97
|
+
git -C "$tmp" remote add origin "$remote"
|
|
98
|
+
printf '%s\n' \
|
|
99
|
+
'# traffic-data' '' \
|
|
100
|
+
'Data-only orphan branch. Weekly GitHub Traffic API snapshots live under' \
|
|
101
|
+
'`traffic/<ISO-year>-W<week>.json`, written by .github/workflows/traffic-archive.yml' \
|
|
102
|
+
'on main. Nothing here is source; do not merge this branch into main.' \
|
|
103
|
+
> "$tmp/README.md"
|
|
104
|
+
git -C "$tmp" add README.md
|
|
105
|
+
fi
|
|
106
|
+
|
|
62
107
|
mkdir -p "$tmp/traffic"
|
|
63
108
|
cp "traffic/${WEEK}.json" "$tmp/traffic/${WEEK}.json"
|
|
64
109
|
git -C "$tmp" config user.name "github-actions[bot]"
|
|
65
110
|
git -C "$tmp" config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
66
111
|
git -C "$tmp" add traffic/
|
|
67
|
-
if git -C "$tmp" diff --cached --quiet; then
|
|
112
|
+
if git -C "$tmp" diff --cached --quiet && git -C "$tmp" rev-parse HEAD >/dev/null 2>&1; then
|
|
68
113
|
echo "No changes — archive already current for ${WEEK}."
|
|
69
114
|
exit 0
|
|
70
115
|
fi
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: tokenjam
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.1
|
|
4
4
|
Summary: TokenJam: a local-first, OTel-native cost-saving utility for AI agents
|
|
5
5
|
Project-URL: Homepage, https://tokenjam.dev
|
|
6
6
|
Project-URL: Repository, https://github.com/Metabuilder-Labs/tokenjam
|
|
@@ -94,7 +94,7 @@ One command sets up live capture:
|
|
|
94
94
|
npx tokenjam onboard # or: pipx install tokenjam && tj onboard
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
`tj onboard` asks how you use AI agents and wires that path: live capture, the analyzers your setup can act on, and Lens. Coding-agent users (Claude Code, Codex) also get their recent history backfilled and a zero-token status line wired in; restart the agent and you're live. SDK and API users add `@watch()` to their own code, or point an OTLP exporter at `tj serve`.
|
|
97
|
+
`tj init` is the same command (`tj onboard` is its original name, still there). It asks how you use AI agents and wires that path: live capture, the analyzers your setup can act on, and Lens. Coding-agent users (Claude Code, Codex) also get their recent history backfilled and a zero-token status line wired in; restart the agent and you're live. SDK and API users add `@watch()` to their own code, or point an OTLP exporter at `tj serve`.
|
|
98
98
|
|
|
99
99
|
Then open the dashboard:
|
|
100
100
|
|
|
@@ -184,9 +184,12 @@ subset with `tj optimize downsize resend relearn`.
|
|
|
184
184
|
| `verbosity` | — | ✅ | Sessions whose output runs long against a per-(tool, task-shape) baseline |
|
|
185
185
|
| `script` | — | ✅ | Deterministic tool sequences a plain script could replace |
|
|
186
186
|
| `reuse` | — | ✅ | Sessions where your agent re-plans work it has already planned |
|
|
187
|
+
| `shipped` | ✅ | ✅ | What your sessions left behind: commits joined to sessions, what the ones that shipped nothing cost, and what got rewritten |
|
|
187
188
|
|
|
188
189
|
They find where your agents are overspending. They also tell you where they are not, so you don't spend a week optimizing something that was never costing you anything.
|
|
189
190
|
|
|
191
|
+
`shipped` is the odd one out, and deliberately so. Every other analyzer asks what a session cost; this one asks what it produced. It joins each session to the commits it made, at a labelled confidence, and reports what the sessions that shipped nothing cost. Nothing in it is a saving: it is measured spend next to measured output, and a session can ship value without a commit. `tj init --hooks` makes commits you type by hand carry a session trailer, which raises how much of your work tj can join. [How the join works →](docs/ledger/overview.md)
|
|
192
|
+
|
|
190
193
|
That balance is why some checks stay dark for you: when the lever that would recover a category of spend belongs to your harness rather than to you, quoting the figure only makes you feel worse. A check also stays dark when its evidence does not exist on your setup; `summarize` reads agent instruction files off disk, which an SDK or API workload does not have, so it is not offered there. It is also why a quiet result is an answer rather than a failed scan. Optimizing has a price of its own, paid in your attention and sometimes in the agent's output, and a bill lowered by making your agent terser or dumber was never a saving.
|
|
191
194
|
|
|
192
195
|
---
|
|
@@ -213,6 +216,9 @@ Bench reports measured pass-rate on a suite, never "certified" or "quality prese
|
|
|
213
216
|
| Full CLI reference, every command and flag | [docs/cli-reference.md](docs/cli-reference.md) |
|
|
214
217
|
| Downsize / Cache / Script / Trim deep-dives | [docs/optimize/](docs/optimize/) |
|
|
215
218
|
| Reuse analyzer deep-dive | [docs/optimize/reuse.md](docs/optimize/reuse.md) |
|
|
219
|
+
| The ledger: sessions joined to commits | [docs/ledger/overview.md](docs/ledger/overview.md) |
|
|
220
|
+
| Commit hooks and git notes (`tj init --hooks` / `--notes`) | [docs/ledger/hooks-and-notes.md](docs/ledger/hooks-and-notes.md) |
|
|
221
|
+
| TokenJam Cloud bridge, and what leaves your machine | [docs/ledger/cloud-bridge.md](docs/ledger/cloud-bridge.md) |
|
|
216
222
|
| Prove a downsize candidate holds (TokenJam Bench) | [tokenjam-bench](https://github.com/Metabuilder-Labs/tokenjam-bench) |
|
|
217
223
|
| Claude Code & Codex integration | [docs/claude-code-integration.md](docs/claude-code-integration.md) |
|
|
218
224
|
| Claude Code vs. Codex vs. SDK vs. OTLP: capability matrix | [docs/agent-capability-matrix.md](docs/agent-capability-matrix.md) |
|
|
@@ -36,7 +36,7 @@ One command sets up live capture:
|
|
|
36
36
|
npx tokenjam onboard # or: pipx install tokenjam && tj onboard
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
`tj onboard` asks how you use AI agents and wires that path: live capture, the analyzers your setup can act on, and Lens. Coding-agent users (Claude Code, Codex) also get their recent history backfilled and a zero-token status line wired in; restart the agent and you're live. SDK and API users add `@watch()` to their own code, or point an OTLP exporter at `tj serve`.
|
|
39
|
+
`tj init` is the same command (`tj onboard` is its original name, still there). It asks how you use AI agents and wires that path: live capture, the analyzers your setup can act on, and Lens. Coding-agent users (Claude Code, Codex) also get their recent history backfilled and a zero-token status line wired in; restart the agent and you're live. SDK and API users add `@watch()` to their own code, or point an OTLP exporter at `tj serve`.
|
|
40
40
|
|
|
41
41
|
Then open the dashboard:
|
|
42
42
|
|
|
@@ -126,9 +126,12 @@ subset with `tj optimize downsize resend relearn`.
|
|
|
126
126
|
| `verbosity` | — | ✅ | Sessions whose output runs long against a per-(tool, task-shape) baseline |
|
|
127
127
|
| `script` | — | ✅ | Deterministic tool sequences a plain script could replace |
|
|
128
128
|
| `reuse` | — | ✅ | Sessions where your agent re-plans work it has already planned |
|
|
129
|
+
| `shipped` | ✅ | ✅ | What your sessions left behind: commits joined to sessions, what the ones that shipped nothing cost, and what got rewritten |
|
|
129
130
|
|
|
130
131
|
They find where your agents are overspending. They also tell you where they are not, so you don't spend a week optimizing something that was never costing you anything.
|
|
131
132
|
|
|
133
|
+
`shipped` is the odd one out, and deliberately so. Every other analyzer asks what a session cost; this one asks what it produced. It joins each session to the commits it made, at a labelled confidence, and reports what the sessions that shipped nothing cost. Nothing in it is a saving: it is measured spend next to measured output, and a session can ship value without a commit. `tj init --hooks` makes commits you type by hand carry a session trailer, which raises how much of your work tj can join. [How the join works →](docs/ledger/overview.md)
|
|
134
|
+
|
|
132
135
|
That balance is why some checks stay dark for you: when the lever that would recover a category of spend belongs to your harness rather than to you, quoting the figure only makes you feel worse. A check also stays dark when its evidence does not exist on your setup; `summarize` reads agent instruction files off disk, which an SDK or API workload does not have, so it is not offered there. It is also why a quiet result is an answer rather than a failed scan. Optimizing has a price of its own, paid in your attention and sometimes in the agent's output, and a bill lowered by making your agent terser or dumber was never a saving.
|
|
133
136
|
|
|
134
137
|
---
|
|
@@ -155,6 +158,9 @@ Bench reports measured pass-rate on a suite, never "certified" or "quality prese
|
|
|
155
158
|
| Full CLI reference, every command and flag | [docs/cli-reference.md](docs/cli-reference.md) |
|
|
156
159
|
| Downsize / Cache / Script / Trim deep-dives | [docs/optimize/](docs/optimize/) |
|
|
157
160
|
| Reuse analyzer deep-dive | [docs/optimize/reuse.md](docs/optimize/reuse.md) |
|
|
161
|
+
| The ledger: sessions joined to commits | [docs/ledger/overview.md](docs/ledger/overview.md) |
|
|
162
|
+
| Commit hooks and git notes (`tj init --hooks` / `--notes`) | [docs/ledger/hooks-and-notes.md](docs/ledger/hooks-and-notes.md) |
|
|
163
|
+
| TokenJam Cloud bridge, and what leaves your machine | [docs/ledger/cloud-bridge.md](docs/ledger/cloud-bridge.md) |
|
|
158
164
|
| Prove a downsize candidate holds (TokenJam Bench) | [tokenjam-bench](https://github.com/Metabuilder-Labs/tokenjam-bench) |
|
|
159
165
|
| Claude Code & Codex integration | [docs/claude-code-integration.md](docs/claude-code-integration.md) |
|
|
160
166
|
| Claude Code vs. Codex vs. SDK vs. OTLP: capability matrix | [docs/agent-capability-matrix.md](docs/agent-capability-matrix.md) |
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# TokenJam 0.7.0
|
|
2
|
+
|
|
3
|
+
> Working draft for the GitHub release. Not part of the shipped package.
|
|
4
|
+
|
|
5
|
+
The largest release since 0.6. TokenJam has always been able to tell you what your agent sessions
|
|
6
|
+
cost. This one starts answering the other half of the question: what those sessions actually
|
|
7
|
+
produced.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pipx install --upgrade tokenjam
|
|
11
|
+
tj optimize shipped
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## The shipped-value ledger
|
|
15
|
+
|
|
16
|
+
tj now records which repo a session ran in and who ran it, then joins each session to the commits
|
|
17
|
+
it produced.
|
|
18
|
+
|
|
19
|
+
- **Repo context and developer identity on every session.** Remote, repo root, branch and HEAD at
|
|
20
|
+
session start and end, the git author email, and a hashed `developer_id` derived from it. Git
|
|
21
|
+
shell-outs are read-only, time-bounded, and never on a request path. A value that cannot be
|
|
22
|
+
resolved is absent rather than guessed, so nothing joins on an invented key.
|
|
23
|
+
- **The session-to-commit join.** A new `session_commits` table, populated on the daemon's
|
|
24
|
+
background pass. Four match sources: a `git commit` tool call inside the session (`tool_span_git_log`),
|
|
25
|
+
a `TokenJam-Session:` or `Claude-Session:` trailer (`trailer_session`), a git note naming a
|
|
26
|
+
session (`git_note`), and an AI co-author trailer inside the session window (`trailer_window`).
|
|
27
|
+
The first three are `deterministic`; the last is `inferred`. A row is written once at the best
|
|
28
|
+
confidence found and never downgraded.
|
|
29
|
+
- **The `shipped` analyzer.** `tj optimize shipped` reports how many of the window's sessions
|
|
30
|
+
shipped a commit to the default branch, the measured cost of the ones that shipped nothing,
|
|
31
|
+
rework cost (commits whose added lines were mostly deleted again within 14 days), and loop cost
|
|
32
|
+
(repeated Edit/Write calls on one path with no content change). Sessions also carry a state:
|
|
33
|
+
shipped, committed, reverted, unshipped, or no repo.
|
|
34
|
+
- **Coverage next to every figure.** The share of your default-branch commits that tj could join.
|
|
35
|
+
Low coverage means tj is seeing part of your work. It does not mean the rest was unproductive.
|
|
36
|
+
- **Surfaces.** `tj optimize shipped` in the terminal, a shipped line on the `tj status` agent
|
|
37
|
+
card, `GET /api/v1/shipped`, commits and shipped state on the session detail route, and in Lens
|
|
38
|
+
the Sessions column and filter, the commit chips with a confidence glyph, the "Shipped this week"
|
|
39
|
+
tile and the Optimize page's Shipped card.
|
|
40
|
+
|
|
41
|
+
Nothing in the shipped finding is a saving. Every dollar in it is measured spend on sessions with
|
|
42
|
+
no joined commit, and a session can ship value without a commit: research, review, operations. The
|
|
43
|
+
caveat prints on every surface, and the finding sits outside the recoverable-waste rollup.
|
|
44
|
+
|
|
45
|
+
## First run and onboarding
|
|
46
|
+
|
|
47
|
+
- **`tj init` is the primary name.** One command object registered under two names, so `tj init`
|
|
48
|
+
and `tj onboard` take the same flags, ask the same questions and write the same config. Nothing
|
|
49
|
+
about `tj onboard` changed.
|
|
50
|
+
- **`tj init --hooks`** installs a `prepare-commit-msg` hook in the current repo so a commit you
|
|
51
|
+
make from a plain shell mid-session carries a `TokenJam-Session:` trailer. That joins it to the
|
|
52
|
+
session at deterministic confidence, which is the cheapest way to raise coverage. The hook lives
|
|
53
|
+
in a managed block, keeps a hook you already have, and refuses a `core.hooksPath` inside the
|
|
54
|
+
worktree because that is a tracked directory.
|
|
55
|
+
- **`tj init --notes`** adds a `post-commit` hook that writes the session's measured cost to
|
|
56
|
+
`refs/notes/tokenjam`. It implies `--hooks` and is off unless you ask for it. tj reads
|
|
57
|
+
`refs/notes/ai` (Git AI) and `refs/notes/exceeds-ink` too, so a repo already annotated by one of
|
|
58
|
+
those gets a stronger join with no setup. The hook reads the cost through the daemon, so it skips
|
|
59
|
+
in a few milliseconds when `tj serve` is not running and the commit gets its trailer but no note.
|
|
60
|
+
- **`tj commit-note [sha]`** writes that note by hand, for a commit the hook skipped or for a repo
|
|
61
|
+
with no hook installed. It never fails the commit it runs from.
|
|
62
|
+
- **`tj init --enforce`** turns on the enforcement proxy in suggest mode and prints what it does
|
|
63
|
+
and does not touch. Suggest mode forwards every request unmodified and records what a policy
|
|
64
|
+
would have done. Nothing is blocked or rewritten until you approve it. Subscription-plan traffic
|
|
65
|
+
is never intercepted and subscription OAuth credentials are never proxied or forwarded.
|
|
66
|
+
- **`tj init --cloud <key> --org <org>`** connects the machine to a TokenJam Cloud organization.
|
|
67
|
+
The daemon then forwards spans, sessions and the commit joins, resumable from a per-stream
|
|
68
|
+
high-water mark, so a machine that was offline catches up on its own. Before the first byte
|
|
69
|
+
leaves, the command prints what does and does not cross and waits for a yes. Token counts, model
|
|
70
|
+
names, cost, timestamps, tool names, file paths, identifiers, the hashed developer id and the git
|
|
71
|
+
author email leave. Prompt text, completions, tool outputs, file contents, diffs and secrets do
|
|
72
|
+
not, unless you turn on both your local capture toggles and `forward_content`.
|
|
73
|
+
`tj init --cloud off` stops forwarding in place.
|
|
74
|
+
- **Existing installs fill in.** The daemon refills repo context on sessions that were ingested
|
|
75
|
+
before any of this existed, and `tj init --cloud` refills and matches before its first push. You
|
|
76
|
+
get history rather than a ledger that starts the day you upgraded.
|
|
77
|
+
- **`tj doctor` and `tj uninstall` cover the new surfaces.** doctor reports hook state per repo,
|
|
78
|
+
whether a hand commit right now would carry a trailer, and whether the Cloud endpoint is
|
|
79
|
+
reachable and the key accepted. uninstall strips the managed blocks from every hooks directory tj
|
|
80
|
+
wrote to.
|
|
81
|
+
|
|
82
|
+
## Correctness
|
|
83
|
+
|
|
84
|
+
- An inherited session trailer now ranks below the tool span that ran the commit. A subagent
|
|
85
|
+
inherits its parent's session id, so a commit the subagent's own Bash tool ran carried the
|
|
86
|
+
parent's trailer and the parent absorbed it at top confidence. Such a row is now written at
|
|
87
|
+
`inferred`.
|
|
88
|
+
- Remote normalisation drops the query and fragment, and branch endpoints are picked by timestamp
|
|
89
|
+
rather than by file order (#762).
|
|
90
|
+
- The Cloud forwarder resumes in arrival order rather than event order, so a backfill that inserts
|
|
91
|
+
spans older than everything already sent no longer loses them. Resume marks are scoped to the
|
|
92
|
+
organization and to the database file. A batch the receiver refuses is split until the bad record
|
|
93
|
+
is isolated, then skipped and counted, so one row cannot wedge the stream.
|
|
94
|
+
- `sessions.updated_at` moves only when a session value actually changes, which stops the bridge
|
|
95
|
+
re-sending untouched rows forever.
|
|
96
|
+
- The transcript catch-up runs once per process, over a window-bounded tool-span index, with
|
|
97
|
+
producers keyed by repo.
|
|
98
|
+
- The serve-mode shim gates its write routes with the ingest secret rather than the optional API
|
|
99
|
+
key, and the backfill hand-off goes through the data-access seam instead of around it.
|
|
100
|
+
- `tj init --cloud` says so when history leaves without an install id.
|
|
101
|
+
- Lens: the hero call to action resolves to the surface that renders the analyzer, instead of a
|
|
102
|
+
retired route.
|
|
103
|
+
|
|
104
|
+
## Docs
|
|
105
|
+
|
|
106
|
+
New pages for the ledger, the commit hooks and notes, and the Cloud bridge, plus the ledger OTel
|
|
107
|
+
attributes in the architecture reference. See `docs/ledger/`.
|
|
108
|
+
|
|
109
|
+
## Upgrading
|
|
110
|
+
|
|
111
|
+
`pipx install --upgrade tokenjam`, or `pip install -U tokenjam` in a venv. Schema changes are
|
|
112
|
+
additive, so an existing database is migrated in place. Everything new in this release is opt-in:
|
|
113
|
+
the hooks, the notes and the Cloud bridge stay off until you run the flag that turns them on.
|
|
@@ -30,6 +30,12 @@ Configure where alerts go in `.tj/config.toml`. Multiple channels work simultane
|
|
|
30
30
|
type = "ntfy"
|
|
31
31
|
topic = "my-agent-alerts"
|
|
32
32
|
|
|
33
|
+
# Mast pager app for iPhone and Android. Free, with or without an account (limits below).
|
|
34
|
+
# The key in the URL is the only credential.
|
|
35
|
+
[[alerts.channels]]
|
|
36
|
+
type = "mast"
|
|
37
|
+
channel_url = "https://mast.tissue.dev/mk_0123456789abcdef0123456789abcdef01234567"
|
|
38
|
+
|
|
33
39
|
# Discord webhook
|
|
34
40
|
[[alerts.channels]]
|
|
35
41
|
type = "discord"
|
|
@@ -56,6 +62,51 @@ path = "~/.tj/alerts.log"
|
|
|
56
62
|
type = "stdout"
|
|
57
63
|
```
|
|
58
64
|
|
|
65
|
+
### Mast
|
|
66
|
+
|
|
67
|
+
[Mast](https://tissue.systems/mast) is a pager app for iPhone and Android. Install it, make a
|
|
68
|
+
channel, and paste the channel URL into the config above. It works without an account, but a
|
|
69
|
+
channel made that way is lost if the app is reinstalled, and the only sign on this side is a
|
|
70
|
+
"No such channel." line in the log. Sign in to a free Tissue account if you want the channel
|
|
71
|
+
to survive that.
|
|
72
|
+
|
|
73
|
+
Both ways are free but capped. With no account you get 2 channels and 1,000 messages a month;
|
|
74
|
+
a free account gets 10 channels and 10,000 messages. Mast keeps accepting sends past the monthly
|
|
75
|
+
number, but if your agents alert a lot, check [Mast's limits](https://tissue.systems/mast/docs/limits/)
|
|
76
|
+
before relying on it.
|
|
77
|
+
|
|
78
|
+
`tj` posts a JSON body with `title`, `body`, `priority` and `key`. Mast documents those fields
|
|
79
|
+
on its [sending page](https://tissue.systems/mast/docs/send/), which is the place to look if
|
|
80
|
+
sends start failing.
|
|
81
|
+
|
|
82
|
+
`tj` maps severity onto three of Mast's four priorities: `info` sends `quiet`, `warning`
|
|
83
|
+
sends `normal`, `critical` sends `loud`. Nothing maps to the fourth, `page`. It repeats until
|
|
84
|
+
someone acks it and ignores mute and quiet hours, so you have to ask for it, which is what
|
|
85
|
+
you'd do on a channel that's meant to wake someone up:
|
|
86
|
+
|
|
87
|
+
```toml
|
|
88
|
+
[[alerts.channels]]
|
|
89
|
+
type = "mast"
|
|
90
|
+
channel_url = "https://mast.tissue.dev/mk_..."
|
|
91
|
+
priority = "page"
|
|
92
|
+
min_severity = "critical"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Each channel also has a ceiling, shown as **Highest priority** in the app, and a send that
|
|
96
|
+
asks for more than that is delivered at the ceiling. It's set when the channel is created. The
|
|
97
|
+
iOS app doesn't go below `loud`, the Android app uses whatever default priority you picked, and
|
|
98
|
+
a channel made from an API token starts at `loud`. So a channel created on Android with the
|
|
99
|
+
default of `Normal` will deliver `critical` alerts as `normal`, and `priority = "page"` won't
|
|
100
|
+
page anyone until you raise the ceiling on the phone. Worth checking before you rely on it.
|
|
101
|
+
|
|
102
|
+
Each send carries a dedupe key built from the same things the cooldown uses: the alert type,
|
|
103
|
+
the agent, and for `cost_budget_session` and `session_duration` the session too. If the same
|
|
104
|
+
alert fires again inside the channel's dedupe window (5 minutes unless you change it), Mast
|
|
105
|
+
adds to the count on the card already on the phone instead of sending a new one. Two sessions
|
|
106
|
+
over their own budget are different alerts, so they get separate cards. The default cooldown
|
|
107
|
+
is 60 seconds, so a repeat usually lands inside the window; if you raise `cooldown_seconds`
|
|
108
|
+
past the window, repeats arrive as new cards.
|
|
109
|
+
|
|
59
110
|
## Sensitive actions
|
|
60
111
|
|
|
61
112
|
Define which tool calls should trigger immediate alerts:
|
|
@@ -88,7 +139,7 @@ Cooldown state survives a daemon restart: `AlertEngine` rehydrates it from the p
|
|
|
88
139
|
|
|
89
140
|
## Content stripping
|
|
90
141
|
|
|
91
|
-
By default, alert payloads sent to external channels (Discord, Telegram, webhook, ntfy) have sensitive content stripped: `prompt_content`, `completion_content`, `tool_input`, `tool_output`. To include full content:
|
|
142
|
+
By default, alert payloads sent to external channels (Discord, Telegram, webhook, ntfy, Mast) have sensitive content stripped: `prompt_content`, `completion_content`, `tool_input`, `tool_output`. To include full content:
|
|
92
143
|
|
|
93
144
|
```toml
|
|
94
145
|
[alerts]
|
|
@@ -35,7 +35,7 @@ flowchart TD
|
|
|
35
35
|
Ingest["IngestPipeline\nSanitization · Session continuity · Attribute extraction"]
|
|
36
36
|
|
|
37
37
|
Ingest --> Cost["CostEngine\npricing.toml"]
|
|
38
|
-
Ingest --> Alerts["AlertEngine\n13 types ·
|
|
38
|
+
Ingest --> Alerts["AlertEngine\n13 types · 7 channels"]
|
|
39
39
|
Ingest --> Schema["SchemaValidator\nexplicit JSON Schema"]
|
|
40
40
|
|
|
41
41
|
Cost --> DB["DuckDB\nlocal · embedded"]
|
|
@@ -179,7 +179,7 @@ The alert engine evaluates rules after every span ingest. Alert types fall into
|
|
|
179
179
|
|
|
180
180
|
### Dispatch and cooldown
|
|
181
181
|
|
|
182
|
-
`AlertDispatcher` routes fired alerts to
|
|
182
|
+
`AlertDispatcher` routes fired alerts to 7 channel types: stdout, file, ntfy, webhook, Discord, Telegram, Mast. `CooldownTracker` prevents alert storms by suppressing repeat alerts of the same type for the same agent within a configurable window. Suppressed alerts are still persisted to the database but not dispatched.
|
|
183
183
|
|
|
184
184
|
Content stripping removes `prompt_content`, `completion_content`, `tool_input`, `tool_output` from payloads sent to external channels unless `alerts.include_captured_content = true`. Stdout and file channels always receive the full payload.
|
|
185
185
|
|
|
@@ -426,6 +426,88 @@ Renderers (`tj optimize`, `tj cost`, the web UI cost views) read `pricing_mode`
|
|
|
426
426
|
|
|
427
427
|
`SessionRecord.plan_tier` defaults to `unknown` for backfilled rows (no plan signal in the source data). `tj status` surfaces a one-line note when unknown-tier sessions exist; `tj optimize` refuses to render dollar figures for those sessions until the user resolves them via `tj onboard --reconfigure`.
|
|
428
428
|
|
|
429
|
+
Optimize analyzers do not see unattributed spend; use `tj cost --group-by session` to inspect it.
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## OTel semconv extensions: repo context and developer identity
|
|
434
|
+
|
|
435
|
+
The shipped-value ledger needs to know which repo a session ran in and who ran it. That is a second
|
|
436
|
+
group of attribute names, defined in `TjAttributes` and `ResourceAttributes` in
|
|
437
|
+
`tokenjam/otel/semconv.py`, using the standard OTel spelling wherever one exists (`vcs.*`,
|
|
438
|
+
`user.email`, `host.name`) and `tokenjam.*` for the rest. Every one of them is optional: a value
|
|
439
|
+
that cannot be resolved is absent rather than a placeholder, so a downstream join can never match on
|
|
440
|
+
something invented.
|
|
441
|
+
|
|
442
|
+
**Where the values actually come from.** These names are not emitted by an agent wrapper. There are
|
|
443
|
+
three paths, and it is worth being precise about which is which:
|
|
444
|
+
|
|
445
|
+
- **Claude Code and Codex.** Nothing is stamped at emission time. The backfill and the daemon's
|
|
446
|
+
transcript catch-up derive the values from the transcript's `cwd` and branch
|
|
447
|
+
(`core/repo_context.py::session_context_for_cwd`) and write them straight onto the session row.
|
|
448
|
+
Sessions ingested before the columns existed are filled in later by
|
|
449
|
+
`core/transcript_sync.py::refill_session_context`.
|
|
450
|
+
- **Producers that stamp the names themselves.** The ingest path reads them off with
|
|
451
|
+
`session_context_from_attrs` and stores them on the session. Nothing in the Python or TypeScript
|
|
452
|
+
SDK sets them for you today, so this is for a producer that chooses to send them, and **the level
|
|
453
|
+
they have to be set at depends on the route**:
|
|
454
|
+
|
|
455
|
+
| Route | Reads from |
|
|
456
|
+
|---|---|
|
|
457
|
+
| in-process SDK exporter (`otel/provider.py`) | **resource attributes only** |
|
|
458
|
+
| Claude Code OTLP logs route (`api/routes/logs.py`) | **resource attributes only** |
|
|
459
|
+
| OTLP JSON span ingest (`otel/otlp_parsing.py`) | resource **or** span attributes, merged, span wins on conflict |
|
|
460
|
+
|
|
461
|
+
Set them at resource level. That is the one placement every route reads. A producer that puts them
|
|
462
|
+
on individual spans and exports through the in-process SDK loses its repo and developer context
|
|
463
|
+
silently, because the resource carries none of them and nothing errors.
|
|
464
|
+
- **Outbound to Cloud.** The bridge maps the stored session columns back onto these attribute names
|
|
465
|
+
on the wire, and adds `tokenjam.install_id` and `host.name` to the resource at that point.
|
|
466
|
+
|
|
467
|
+
`tj otel-resource-attrs` is **not** part of this. It prints `service.name`, plus
|
|
468
|
+
`service.namespace` when the project is set in config, and nothing else. The per-terminal `claude`
|
|
469
|
+
wrapper exports its output as `OTEL_RESOURCE_ATTRIBUTES`, which is how concurrent terminals land as
|
|
470
|
+
distinct tiles; the ledger columns arrive by the transcript path above, not through that variable.
|
|
471
|
+
|
|
472
|
+
**The attribute names, per process:**
|
|
473
|
+
|
|
474
|
+
| Attribute | Value | Source |
|
|
475
|
+
|---|---|---|
|
|
476
|
+
| `user.email` | git author email | `git config user.email` in the session cwd, else the global value, else absent |
|
|
477
|
+
| `tokenjam.developer_id` | `sha256(lower(user.email))[:16]` | derived; the pseudonymous id every ledger surface uses |
|
|
478
|
+
| `tokenjam.install_id` | uuid4, generated once | `~/.tj/install_id`; added to the resource by the Cloud bridge |
|
|
479
|
+
| `host.name` | hostname | `socket.gethostname()`; added to the resource by the Cloud bridge |
|
|
480
|
+
| `tokenjam.github_login` | GitHub login | reserved. Defined in `TjAttributes`, not set by this build |
|
|
481
|
+
| `vcs.repository.url.full` | normalised remote, `https://github.com/org/repo`, no `.git`, no credentials, no query or fragment | `git remote get-url origin` |
|
|
482
|
+
| `vcs.repository.name` | `org/repo` | derived from the remote |
|
|
483
|
+
|
|
484
|
+
**The attribute names, per session:**
|
|
485
|
+
|
|
486
|
+
| Attribute | Value |
|
|
487
|
+
|---|---|
|
|
488
|
+
| `vcs.ref.head.name` | branch at session start |
|
|
489
|
+
| `vcs.ref.head.revision` | HEAD sha at session start, only when the source records it. Codex rollouts do; Claude Code transcripts do not, and it is absent rather than guessed. The join keys on repo, branch and time, never on this sha |
|
|
490
|
+
| `tokenjam.repo_root` | absolute path of the repo root |
|
|
491
|
+
| `tokenjam.session.branch_end` | branch at session end |
|
|
492
|
+
| `tokenjam.session.head_end` | HEAD sha at session end |
|
|
493
|
+
|
|
494
|
+
**Never stamped by the client:** team, department, cost centre, display name. Those are org-side
|
|
495
|
+
maps and have no business on a local span.
|
|
496
|
+
|
|
497
|
+
`user.email` is the one personal identifier here. It stays on your machine unless you connect
|
|
498
|
+
[the Cloud bridge](ledger/cloud-bridge.md), which states it in the list it prints before the first
|
|
499
|
+
byte leaves.
|
|
500
|
+
|
|
501
|
+
### Ledger storage
|
|
502
|
+
|
|
503
|
+
`sessions` carries the same values as nullable columns (`repo_remote`, `repo_root`, `branch_start`,
|
|
504
|
+
`branch_end`, `head_sha_start`, `head_sha_end`, `developer_id`, `user_email`), and the
|
|
505
|
+
`session_commits` table holds the join, keyed `(session_id, commit_sha)` with its `confidence`,
|
|
506
|
+
`source`, author email, commit time and match delta. Three side tables keep every read in SQL: a
|
|
507
|
+
default-branch commit index, per-commit file statistics for the rework figure, and a per-session
|
|
508
|
+
scan watermark. Migrations are additive, as everywhere else in the schema. See
|
|
509
|
+
[the ledger overview](ledger/overview.md).
|
|
510
|
+
|
|
429
511
|
---
|
|
430
512
|
|
|
431
513
|
## SDK cost-attribution dimensions (multi-tenant cost breakdown)
|
|
@@ -7,13 +7,15 @@ Imports [Langfuse](https://langfuse.com) observations into the local TokenJam DB
|
|
|
7
7
|
```bash
|
|
8
8
|
tj backfill langfuse \
|
|
9
9
|
--source-url https://cloud.langfuse.com \
|
|
10
|
-
--api-key
|
|
10
|
+
--api-key pk-lf-...:sk-lf-... \
|
|
11
11
|
--since 30d
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
Reads from Langfuse's
|
|
14
|
+
Reads from Langfuse's Observations API v2 (`/api/public/v2/observations`) and follows its cursors automatically. The key is the project's public and secret key joined with a colon (`PUBLIC_KEY:SECRET_KEY`) and is sent with Basic auth. A Bearer public key only gets a scores-only scope in Langfuse, so it cannot read observations; a value without a colon is still sent as a Bearer token for proxies that expect one.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Langfuse Cloud removes the older observations endpoint on 16 November 2026, so v2 is the endpoint to rely on. For a self-hosted server that has no v2 endpoint (it answers 404), the adapter falls back to `/api/public/observations` with page numbers.
|
|
17
|
+
|
|
18
|
+
The `--source-url` value can be the bare base URL (`https://cloud.langfuse.com`) — the adapter appends the API path. A URL that already ends in `/api/public/observations` still works. Self-hosted Langfuse instances work the same way.
|
|
17
19
|
|
|
18
20
|
`--since` accepts the same syntax as `tj cost --since`: `30d`, `24h`, or an ISO-8601 timestamp.
|
|
19
21
|
|
|
@@ -45,9 +47,9 @@ Each Langfuse `Observation` becomes one TokenJam span:
|
|
|
45
47
|
| `type` (`GENERATION` / `SPAN` / `EVENT`) | `kind` + `name` |
|
|
46
48
|
| `startTime` / `endTime` | `start_time` / `end_time` |
|
|
47
49
|
| `model` | `model`, `provider` (derived), `billing_account` (derived) |
|
|
48
|
-
| `usage.input` / `usage.output` | `input_tokens` / `output_tokens` |
|
|
50
|
+
| `usageDetails.input` / `usageDetails.output` (v2), or `usage.input` / `usage.output` (v1) | `input_tokens` / `output_tokens` |
|
|
49
51
|
| `usageDetails.input_cache_read` | `cache_tokens` |
|
|
50
|
-
| `calculatedTotalCost` | `cost_usd` |
|
|
52
|
+
| `totalCost` (v2) or `calculatedTotalCost` (v1) | `cost_usd` |
|
|
51
53
|
| `level` / `statusMessage` | `status_code` / `status_message` |
|
|
52
54
|
|
|
53
55
|
`billing_account` is derived from the model name (`claude-*` → `anthropic`, `gpt-*`/`o3`/`o4` → `openai`, `gemini-*` → `google`). Unknown models leave it `NULL`; affected sessions will surface as `plan_tier = 'unknown'` in `tj optimize`.
|