tokeymeter 0.31.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.
- tokeymeter-0.31.1/.github/ISSUE_TEMPLATE/bug_report.yml +38 -0
- tokeymeter-0.31.1/.github/ISSUE_TEMPLATE/false_positive.yml +32 -0
- tokeymeter-0.31.1/.github/pull_request_template.md +16 -0
- tokeymeter-0.31.1/.github/workflows/ci.yml +58 -0
- tokeymeter-0.31.1/.gitignore +47 -0
- tokeymeter-0.31.1/ACCEPTANCE.py +405 -0
- tokeymeter-0.31.1/AGENTS.md +185 -0
- tokeymeter-0.31.1/CHANGELOG.md +1152 -0
- tokeymeter-0.31.1/CODE_OF_CONDUCT.md +13 -0
- tokeymeter-0.31.1/CONTRIBUTING.md +51 -0
- tokeymeter-0.31.1/LICENSE +178 -0
- tokeymeter-0.31.1/MANIFEST.in +32 -0
- tokeymeter-0.31.1/PKG-INFO +982 -0
- tokeymeter-0.31.1/README.md +925 -0
- tokeymeter-0.31.1/SECURITY.md +49 -0
- tokeymeter-0.31.1/docs/ARCHITECTURE_AND_WORKING.md +253 -0
- tokeymeter-0.31.1/docs/ARCHITECTURE_MAP.md +281 -0
- tokeymeter-0.31.1/docs/COMPATIBILITY.md +103 -0
- tokeymeter-0.31.1/docs/ENGINE_MAP.md +16 -0
- tokeymeter-0.31.1/docs/EXCEPTION_POLICY.md +71 -0
- tokeymeter-0.31.1/docs/RELEASE_CHECKLIST.md +90 -0
- tokeymeter-0.31.1/docs/RouteLLM_Integration_Design.md +152 -0
- tokeymeter-0.31.1/docs/SELF_HOSTED_STACKS.md +124 -0
- tokeymeter-0.31.1/docs/STRESS_TEST_REPORT.md +160 -0
- tokeymeter-0.31.1/docs/THREAT_MODEL.md +201 -0
- tokeymeter-0.31.1/docs/TOKEYMETER_ARCHITECTURE.md +148 -0
- tokeymeter-0.31.1/docs/TOKEYMETER_FULL_ARCHITECTURE.md +242 -0
- tokeymeter-0.31.1/docs/agents-terminal.png +0 -0
- tokeymeter-0.31.1/docs/firstrun.png +0 -0
- tokeymeter-0.31.1/docs/novue-logo.png +0 -0
- tokeymeter-0.31.1/docs/report.png +0 -0
- tokeymeter-0.31.1/docs/self-hosted/BUILD_DOC.md +685 -0
- tokeymeter-0.31.1/docs/self-hosted/WINDOWS_PERFORMANCE.md +69 -0
- tokeymeter-0.31.1/docs/stalls.png +0 -0
- tokeymeter-0.31.1/examples/01_stuck_agent.py +53 -0
- tokeymeter-0.31.1/examples/02_batch_is_not_a_stall.py +47 -0
- tokeymeter-0.31.1/examples/03_choosing_thresholds.py +50 -0
- tokeymeter-0.31.1/examples/04_alerting.py +54 -0
- tokeymeter-0.31.1/examples/05_policy_file.py +54 -0
- tokeymeter-0.31.1/examples/06_compliance.py +69 -0
- tokeymeter-0.31.1/examples/README.md +25 -0
- tokeymeter-0.31.1/pyproject.toml +137 -0
- tokeymeter-0.31.1/scripts/build_manifest.py +85 -0
- tokeymeter-0.31.1/scripts/enterprise_live_sim.py +174 -0
- tokeymeter-0.31.1/scripts/perfection_baseline.json +11 -0
- tokeymeter-0.31.1/scripts/real_redis_smoke.py +145 -0
- tokeymeter-0.31.1/scripts/release.py +147 -0
- tokeymeter-0.31.1/scripts/run_all_checks.py +187 -0
- tokeymeter-0.31.1/scripts/run_perfection_gate.py +138 -0
- tokeymeter-0.31.1/scripts/soak.py +117 -0
- tokeymeter-0.31.1/scripts/stress_battery.py +167 -0
- tokeymeter-0.31.1/setup.cfg +4 -0
- tokeymeter-0.31.1/tests/conftest.py +46 -0
- tokeymeter-0.31.1/tests/contract_snapshot.json +112 -0
- tokeymeter-0.31.1/tests/test_admin.py +110 -0
- tokeymeter-0.31.1/tests/test_api_surface.py +300 -0
- tokeymeter-0.31.1/tests/test_async.py +366 -0
- tokeymeter-0.31.1/tests/test_async_parity.py +291 -0
- tokeymeter-0.31.1/tests/test_audit.py +733 -0
- tokeymeter-0.31.1/tests/test_audit_durability.py +103 -0
- tokeymeter-0.31.1/tests/test_benchmarks.py +195 -0
- tokeymeter-0.31.1/tests/test_cache_namespace_isolation.py +173 -0
- tokeymeter-0.31.1/tests/test_cache_optimize.py +204 -0
- tokeymeter-0.31.1/tests/test_capacity_recovery.py +518 -0
- tokeymeter-0.31.1/tests/test_cascade.py +96 -0
- tokeymeter-0.31.1/tests/test_chargeback.py +351 -0
- tokeymeter-0.31.1/tests/test_cli_demo_doctor.py +41 -0
- tokeymeter-0.31.1/tests/test_close_packet.py +481 -0
- tokeymeter-0.31.1/tests/test_cold_sweep_hardening.py +74 -0
- tokeymeter-0.31.1/tests/test_combinatorial.py +460 -0
- tokeymeter-0.31.1/tests/test_compliance.py +729 -0
- tokeymeter-0.31.1/tests/test_compression.py +485 -0
- tokeymeter-0.31.1/tests/test_conservative_compression.py +72 -0
- tokeymeter-0.31.1/tests/test_contract_surface.py +78 -0
- tokeymeter-0.31.1/tests/test_decision.py +116 -0
- tokeymeter-0.31.1/tests/test_decorator.py +191 -0
- tokeymeter-0.31.1/tests/test_engine_completion.py +211 -0
- tokeymeter-0.31.1/tests/test_engine_layout.py +147 -0
- tokeymeter-0.31.1/tests/test_event_preview_default.py +115 -0
- tokeymeter-0.31.1/tests/test_events.py +211 -0
- tokeymeter-0.31.1/tests/test_examples_and_repo.py +236 -0
- tokeymeter-0.31.1/tests/test_exception_policy.py +170 -0
- tokeymeter-0.31.1/tests/test_execution_rules.py +563 -0
- tokeymeter-0.31.1/tests/test_fidelity_breaker.py +119 -0
- tokeymeter-0.31.1/tests/test_fuzz_properties.py +226 -0
- tokeymeter-0.31.1/tests/test_group1_reachability.py +318 -0
- tokeymeter-0.31.1/tests/test_high_stakes.py +163 -0
- tokeymeter-0.31.1/tests/test_hybrid_placement.py +405 -0
- tokeymeter-0.31.1/tests/test_identity_binding.py +122 -0
- tokeymeter-0.31.1/tests/test_integrity.py +399 -0
- tokeymeter-0.31.1/tests/test_invariants.py +146 -0
- tokeymeter-0.31.1/tests/test_keys_hardening.py +298 -0
- tokeymeter-0.31.1/tests/test_ledger_crash_consistency.py +145 -0
- tokeymeter-0.31.1/tests/test_lifecycle_hardening.py +156 -0
- tokeymeter-0.31.1/tests/test_lineage.py +75 -0
- tokeymeter-0.31.1/tests/test_memory.py +628 -0
- tokeymeter-0.31.1/tests/test_metrics.py +171 -0
- tokeymeter-0.31.1/tests/test_nested_redaction.py +116 -0
- tokeymeter-0.31.1/tests/test_observability.py +101 -0
- tokeymeter-0.31.1/tests/test_overhead_and_modes.py +161 -0
- tokeymeter-0.31.1/tests/test_per_call_model.py +180 -0
- tokeymeter-0.31.1/tests/test_performance.py +120 -0
- tokeymeter-0.31.1/tests/test_plan.py +556 -0
- tokeymeter-0.31.1/tests/test_platform_portability.py +195 -0
- tokeymeter-0.31.1/tests/test_policy.py +115 -0
- tokeymeter-0.31.1/tests/test_pricing_registry.py +223 -0
- tokeymeter-0.31.1/tests/test_privacy.py +200 -0
- tokeymeter-0.31.1/tests/test_production_readiness.py +385 -0
- tokeymeter-0.31.1/tests/test_progress_scoreability.py +414 -0
- tokeymeter-0.31.1/tests/test_progress_signal.py +473 -0
- tokeymeter-0.31.1/tests/test_prompt_ir.py +209 -0
- tokeymeter-0.31.1/tests/test_record_parity.py +176 -0
- tokeymeter-0.31.1/tests/test_redis_store.py +438 -0
- tokeymeter-0.31.1/tests/test_refusal_propagation.py +203 -0
- tokeymeter-0.31.1/tests/test_restore_safety.py +118 -0
- tokeymeter-0.31.1/tests/test_review_round3_hardening.py +222 -0
- tokeymeter-0.31.1/tests/test_router.py +82 -0
- tokeymeter-0.31.1/tests/test_run_all_checks.py +89 -0
- tokeymeter-0.31.1/tests/test_runtime_adapters.py +322 -0
- tokeymeter-0.31.1/tests/test_runtime_enforcement.py +467 -0
- tokeymeter-0.31.1/tests/test_runtime_facade.py +211 -0
- tokeymeter-0.31.1/tests/test_runtime_integration.py +265 -0
- tokeymeter-0.31.1/tests/test_runtime_kernel.py +490 -0
- tokeymeter-0.31.1/tests/test_runtime_optimization.py +276 -0
- tokeymeter-0.31.1/tests/test_runtime_platform.py +411 -0
- tokeymeter-0.31.1/tests/test_runtime_proof.py +314 -0
- tokeymeter-0.31.1/tests/test_runtime_redteam_platform.py +391 -0
- tokeymeter-0.31.1/tests/test_runtime_regression_pins.py +186 -0
- tokeymeter-0.31.1/tests/test_runtime_resilience.py +375 -0
- tokeymeter-0.31.1/tests/test_runtime_security_redteam.py +408 -0
- tokeymeter-0.31.1/tests/test_runtime_stress_workload.py +294 -0
- tokeymeter-0.31.1/tests/test_runtime_traffic.py +225 -0
- tokeymeter-0.31.1/tests/test_runtime_universality.py +312 -0
- tokeymeter-0.31.1/tests/test_s1_1_token_recovery.py +213 -0
- tokeymeter-0.31.1/tests/test_safe_compress.py +123 -0
- tokeymeter-0.31.1/tests/test_salience.py +121 -0
- tokeymeter-0.31.1/tests/test_savings_ledger_health.py +141 -0
- tokeymeter-0.31.1/tests/test_secret_firewall_perf.py +144 -0
- tokeymeter-0.31.1/tests/test_selfhost_ledger_fields.py +316 -0
- tokeymeter-0.31.1/tests/test_semantic.py +246 -0
- tokeymeter-0.31.1/tests/test_shadow.py +180 -0
- tokeymeter-0.31.1/tests/test_shadow_reported_provenance.py +277 -0
- tokeymeter-0.31.1/tests/test_single_flight.py +186 -0
- tokeymeter-0.31.1/tests/test_single_flight_default_store.py +135 -0
- tokeymeter-0.31.1/tests/test_singleflight_inprocess.py +37 -0
- tokeymeter-0.31.1/tests/test_soak_concurrency.py +275 -0
- tokeymeter-0.31.1/tests/test_strict_redaction_fail_closed.py +117 -0
- tokeymeter-0.31.1/tests/test_suggest_and_drift.py +672 -0
- tokeymeter-0.31.1/tests/test_tags.py +73 -0
- tokeymeter-0.31.1/tests/test_task_boundary.py +634 -0
- tokeymeter-0.31.1/tests/test_tenant_isolation.py +187 -0
- tokeymeter-0.31.1/tests/test_tier1_embedding.py +708 -0
- tokeymeter-0.31.1/tests/test_tokeymeter_api.py +175 -0
- tokeymeter-0.31.1/tests/test_ttl.py +223 -0
- tokeymeter-0.31.1/tests/test_vec.py +155 -0
- tokeymeter-0.31.1/tests/test_warmup.py +181 -0
- tokeymeter-0.31.1/tests/test_watch.py +382 -0
- tokeymeter-0.31.1/tests/test_wire_integration_openai.py +216 -0
- tokeymeter-0.31.1/tokeymeter/__init__.py +436 -0
- tokeymeter-0.31.1/tokeymeter/__main__.py +136 -0
- tokeymeter-0.31.1/tokeymeter/_api.py +410 -0
- tokeymeter-0.31.1/tokeymeter/_fidelity.py +4 -0
- tokeymeter-0.31.1/tokeymeter/_manifest.json +158 -0
- tokeymeter-0.31.1/tokeymeter/admin.py +497 -0
- tokeymeter-0.31.1/tokeymeter/audit/__init__.py +7 -0
- tokeymeter-0.31.1/tokeymeter/backends/__init__.py +10 -0
- tokeymeter-0.31.1/tokeymeter/cache_admin.py +4 -0
- tokeymeter-0.31.1/tokeymeter/cache_optimize.py +4 -0
- tokeymeter-0.31.1/tokeymeter/cascade.py +4 -0
- tokeymeter-0.31.1/tokeymeter/compression.py +4 -0
- tokeymeter-0.31.1/tokeymeter/compression_eval.py +4 -0
- tokeymeter-0.31.1/tokeymeter/content/__init__.py +7 -0
- tokeymeter-0.31.1/tokeymeter/context_passport.py +4 -0
- tokeymeter-0.31.1/tokeymeter/decision.py +4 -0
- tokeymeter-0.31.1/tokeymeter/decorator.py +2406 -0
- tokeymeter-0.31.1/tokeymeter/degraded.py +4 -0
- tokeymeter-0.31.1/tokeymeter/demo.py +99 -0
- tokeymeter-0.31.1/tokeymeter/engines/__init__.py +1 -0
- tokeymeter-0.31.1/tokeymeter/engines/economics/__init__.py +1 -0
- tokeymeter-0.31.1/tokeymeter/engines/economics/capacity_report.py +366 -0
- tokeymeter-0.31.1/tokeymeter/engines/economics/chargeback.py +365 -0
- tokeymeter-0.31.1/tokeymeter/engines/economics/close_packet.py +503 -0
- tokeymeter-0.31.1/tokeymeter/engines/economics/hybrid.py +430 -0
- tokeymeter-0.31.1/tokeymeter/engines/economics/keys.py +274 -0
- tokeymeter-0.31.1/tokeymeter/engines/economics/pricing.py +496 -0
- tokeymeter-0.31.1/tokeymeter/engines/economics/reconcile.py +112 -0
- tokeymeter-0.31.1/tokeymeter/engines/economics/reporting.py +338 -0
- tokeymeter-0.31.1/tokeymeter/engines/economics/savings.py +779 -0
- tokeymeter-0.31.1/tokeymeter/engines/economics/usage.py +132 -0
- tokeymeter-0.31.1/tokeymeter/engines/execution/__init__.py +1 -0
- tokeymeter-0.31.1/tokeymeter/engines/execution/endpoint.py +92 -0
- tokeymeter-0.31.1/tokeymeter/engines/execution/halts.py +200 -0
- tokeymeter-0.31.1/tokeymeter/engines/execution/integrations/README.md +95 -0
- tokeymeter-0.31.1/tokeymeter/engines/execution/integrations/__init__.py +0 -0
- tokeymeter-0.31.1/tokeymeter/engines/execution/integrations/anthropic.py +203 -0
- tokeymeter-0.31.1/tokeymeter/engines/execution/integrations/openai.py +647 -0
- tokeymeter-0.31.1/tokeymeter/engines/execution/integrations/openai_async.py +421 -0
- tokeymeter-0.31.1/tokeymeter/engines/execution/integrations/universal.py +177 -0
- tokeymeter-0.31.1/tokeymeter/engines/execution/response_text.py +133 -0
- tokeymeter-0.31.1/tokeymeter/engines/execution/task.py +936 -0
- tokeymeter-0.31.1/tokeymeter/engines/governance/__init__.py +1 -0
- tokeymeter-0.31.1/tokeymeter/engines/governance/agents.py +557 -0
- tokeymeter-0.31.1/tokeymeter/engines/governance/agents_html.py +642 -0
- tokeymeter-0.31.1/tokeymeter/engines/governance/compliance.py +714 -0
- tokeymeter-0.31.1/tokeymeter/engines/governance/content/REDTEAM_REPORT.md +68 -0
- tokeymeter-0.31.1/tokeymeter/engines/governance/content/__init__.py +27 -0
- tokeymeter-0.31.1/tokeymeter/engines/governance/content/secrets.py +796 -0
- tokeymeter-0.31.1/tokeymeter/engines/governance/decision.py +208 -0
- tokeymeter-0.31.1/tokeymeter/engines/governance/identity.py +69 -0
- tokeymeter-0.31.1/tokeymeter/engines/governance/plan.py +489 -0
- tokeymeter-0.31.1/tokeymeter/engines/governance/policy.py +84 -0
- tokeymeter-0.31.1/tokeymeter/engines/governance/privacy.py +233 -0
- tokeymeter-0.31.1/tokeymeter/engines/governance/rules.py +609 -0
- tokeymeter-0.31.1/tokeymeter/engines/governance/simulate.py +391 -0
- tokeymeter-0.31.1/tokeymeter/engines/governance/suggest.py +467 -0
- tokeymeter-0.31.1/tokeymeter/engines/knowledge/__init__.py +1 -0
- tokeymeter-0.31.1/tokeymeter/engines/knowledge/context_passport.py +93 -0
- tokeymeter-0.31.1/tokeymeter/engines/knowledge/memory.py +1063 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/__init__.py +1 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/cache_admin.py +19 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/cache_optimize.py +346 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/cascade.py +338 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/compression.py +556 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/compression_eval.py +358 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/envelope.py +115 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/prompt_ir.py +297 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/query_compress.py +421 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/redis_store.py +400 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/router.py +380 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/safe_compress.py +187 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/salience.py +305 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/semantic.py +699 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/semantic_eval.py +404 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/semantic_verify.py +284 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/storage.py +286 -0
- tokeymeter-0.31.1/tokeymeter/engines/optimization/warmup.py +271 -0
- tokeymeter-0.31.1/tokeymeter/engines/reliability/__init__.py +1 -0
- tokeymeter-0.31.1/tokeymeter/engines/reliability/_fidelity.py +192 -0
- tokeymeter-0.31.1/tokeymeter/engines/reliability/degraded.py +125 -0
- tokeymeter-0.31.1/tokeymeter/engines/reliability/overhead.py +51 -0
- tokeymeter-0.31.1/tokeymeter/engines/trust/__init__.py +1 -0
- tokeymeter-0.31.1/tokeymeter/engines/trust/audit/__init__.py +90 -0
- tokeymeter-0.31.1/tokeymeter/engines/trust/audit/log.py +921 -0
- tokeymeter-0.31.1/tokeymeter/engines/trust/audit/proof.py +391 -0
- tokeymeter-0.31.1/tokeymeter/engines/trust/audit/signers.py +193 -0
- tokeymeter-0.31.1/tokeymeter/engines/trust/cipher.py +105 -0
- tokeymeter-0.31.1/tokeymeter/engines/trust/integrity.py +634 -0
- tokeymeter-0.31.1/tokeymeter/envelope.py +4 -0
- tokeymeter-0.31.1/tokeymeter/events.py +156 -0
- tokeymeter-0.31.1/tokeymeter/firstrun.py +215 -0
- tokeymeter-0.31.1/tokeymeter/identity.py +4 -0
- tokeymeter-0.31.1/tokeymeter/integrations/__init__.py +9 -0
- tokeymeter-0.31.1/tokeymeter/integrity.py +4 -0
- tokeymeter-0.31.1/tokeymeter/keys.py +4 -0
- tokeymeter-0.31.1/tokeymeter/memory.py +4 -0
- tokeymeter-0.31.1/tokeymeter/metrics.py +216 -0
- tokeymeter-0.31.1/tokeymeter/overhead.py +4 -0
- tokeymeter-0.31.1/tokeymeter/paths.py +79 -0
- tokeymeter-0.31.1/tokeymeter/policy.py +4 -0
- tokeymeter-0.31.1/tokeymeter/pricing.py +4 -0
- tokeymeter-0.31.1/tokeymeter/privacy.py +4 -0
- tokeymeter-0.31.1/tokeymeter/prompt_ir.py +4 -0
- tokeymeter-0.31.1/tokeymeter/py.typed +0 -0
- tokeymeter-0.31.1/tokeymeter/query_compress.py +4 -0
- tokeymeter-0.31.1/tokeymeter/reporting.py +4 -0
- tokeymeter-0.31.1/tokeymeter/router.py +4 -0
- tokeymeter-0.31.1/tokeymeter/runtime/__init__.py +108 -0
- tokeymeter-0.31.1/tokeymeter/runtime/adapters.py +198 -0
- tokeymeter-0.31.1/tokeymeter/runtime/bus.py +83 -0
- tokeymeter-0.31.1/tokeymeter/runtime/catalog.py +157 -0
- tokeymeter-0.31.1/tokeymeter/runtime/config.py +92 -0
- tokeymeter-0.31.1/tokeymeter/runtime/conformance.py +167 -0
- tokeymeter-0.31.1/tokeymeter/runtime/container.py +71 -0
- tokeymeter-0.31.1/tokeymeter/runtime/economics.py +134 -0
- tokeymeter-0.31.1/tokeymeter/runtime/enforcement.py +290 -0
- tokeymeter-0.31.1/tokeymeter/runtime/engine.py +75 -0
- tokeymeter-0.31.1/tokeymeter/runtime/engines.py +286 -0
- tokeymeter-0.31.1/tokeymeter/runtime/errors.py +129 -0
- tokeymeter-0.31.1/tokeymeter/runtime/facade.py +478 -0
- tokeymeter-0.31.1/tokeymeter/runtime/frameworks.py +91 -0
- tokeymeter-0.31.1/tokeymeter/runtime/hotreload.py +88 -0
- tokeymeter-0.31.1/tokeymeter/runtime/kernel.py +239 -0
- tokeymeter-0.31.1/tokeymeter/runtime/oidc.py +165 -0
- tokeymeter-0.31.1/tokeymeter/runtime/optimization.py +111 -0
- tokeymeter-0.31.1/tokeymeter/runtime/optimize.py +225 -0
- tokeymeter-0.31.1/tokeymeter/runtime/plugins.py +229 -0
- tokeymeter-0.31.1/tokeymeter/runtime/proof.py +374 -0
- tokeymeter-0.31.1/tokeymeter/runtime/providers.py +167 -0
- tokeymeter-0.31.1/tokeymeter/runtime/resilience.py +344 -0
- tokeymeter-0.31.1/tokeymeter/runtime/telemetry.py +155 -0
- tokeymeter-0.31.1/tokeymeter/runtime/tools.py +178 -0
- tokeymeter-0.31.1/tokeymeter/safe_compress.py +4 -0
- tokeymeter-0.31.1/tokeymeter/salience.py +4 -0
- tokeymeter-0.31.1/tokeymeter/savings.py +4 -0
- tokeymeter-0.31.1/tokeymeter/semantic.py +4 -0
- tokeymeter-0.31.1/tokeymeter/semantic_eval.py +4 -0
- tokeymeter-0.31.1/tokeymeter/semantic_verify.py +4 -0
- tokeymeter-0.31.1/tokeymeter/storage.py +4 -0
- tokeymeter-0.31.1/tokeymeter/usage.py +4 -0
- tokeymeter-0.31.1/tokeymeter/utils.py +42 -0
- tokeymeter-0.31.1/tokeymeter/warmup.py +4 -0
- tokeymeter-0.31.1/tokeymeter/watch.py +438 -0
- tokeymeter-0.31.1/tokeymeter.egg-info/PKG-INFO +982 -0
- tokeymeter-0.31.1/tokeymeter.egg-info/SOURCES.txt +307 -0
- tokeymeter-0.31.1/tokeymeter.egg-info/dependency_links.txt +1 -0
- tokeymeter-0.31.1/tokeymeter.egg-info/entry_points.txt +2 -0
- tokeymeter-0.31.1/tokeymeter.egg-info/requires.txt +39 -0
- tokeymeter-0.31.1/tokeymeter.egg-info/top_level.txt +1 -0
- tokeymeter-0.31.1/walkthrough_seed.py +169 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something behaves differently from what the docs say
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Before anything else, please run `tokeymeter doctor` and paste the output.
|
|
9
|
+
It reports overhead, ledger health and package integrity, and it answers
|
|
10
|
+
most of the questions we would otherwise have to ask you.
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: doctor
|
|
13
|
+
attributes:
|
|
14
|
+
label: tokeymeter doctor
|
|
15
|
+
render: text
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: what
|
|
20
|
+
attributes:
|
|
21
|
+
label: What happened, and what you expected instead
|
|
22
|
+
validations:
|
|
23
|
+
required: true
|
|
24
|
+
- type: textarea
|
|
25
|
+
id: repro
|
|
26
|
+
attributes:
|
|
27
|
+
label: Smallest code that shows it
|
|
28
|
+
description: |
|
|
29
|
+
A runnable snippet beats a description. Please redact prompts — we do
|
|
30
|
+
not want them, and we do not need them to reproduce a bug.
|
|
31
|
+
render: python
|
|
32
|
+
- type: input
|
|
33
|
+
id: version
|
|
34
|
+
attributes:
|
|
35
|
+
label: Version and Python
|
|
36
|
+
placeholder: "tokeymeter 0.23.2, Python 3.12, Windows 11"
|
|
37
|
+
validations:
|
|
38
|
+
required: true
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: A working agent was stopped
|
|
2
|
+
description: Stall detection halted a task that was actually making progress
|
|
3
|
+
labels: [false-positive, priority]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
This is the most important kind of report we can get. A ceiling that
|
|
9
|
+
stops working agents gets switched off, and then it protects nobody —
|
|
10
|
+
so a false positive is treated as a priority bug, not a tuning question.
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: halt
|
|
13
|
+
attributes:
|
|
14
|
+
label: The halt message
|
|
15
|
+
render: text
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: why
|
|
20
|
+
attributes:
|
|
21
|
+
label: Why the agent was actually working
|
|
22
|
+
description: |
|
|
23
|
+
What was it doing? Does it legitimately repeat an answer for several
|
|
24
|
+
turns — retrying an upstream, polling, waiting on a job?
|
|
25
|
+
validations:
|
|
26
|
+
required: true
|
|
27
|
+
- type: textarea
|
|
28
|
+
id: suggest
|
|
29
|
+
attributes:
|
|
30
|
+
label: Output of `tokeymeter agents --suggest`
|
|
31
|
+
description: This tells us what your traffic looks like without sending us any of it.
|
|
32
|
+
render: text
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
## What this changes
|
|
2
|
+
|
|
3
|
+
<!-- One or two sentences. -->
|
|
4
|
+
|
|
5
|
+
## Checklist
|
|
6
|
+
|
|
7
|
+
- [ ] `pytest` passes
|
|
8
|
+
- [ ] `python scripts/run_all_checks.py` passes (17/17)
|
|
9
|
+
- [ ] If this adds or changes a **control**: it works on all four execution
|
|
10
|
+
routes — sync decorator, async decorator, `cache_stream`, and the runtime
|
|
11
|
+
kernel. A control that exists on one path is only as strong as the path a
|
|
12
|
+
team happens to pick.
|
|
13
|
+
- [ ] If this adds or changes a **control**: `simulate` was updated in the same
|
|
14
|
+
commit, so `plan` does not report that a real rule does nothing.
|
|
15
|
+
- [ ] No prompt or response text can reach the ledger as a result of this change.
|
|
16
|
+
- [ ] `CHANGELOG.md` updated if the behaviour is user-visible.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
# The matrix is the point: this library runs inside other people's
|
|
11
|
+
# processes, so "works on my Python" is not a claim worth making.
|
|
12
|
+
runs-on: ${{ matrix.os }}
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
17
|
+
python: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
- uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python }}
|
|
23
|
+
- run: pip install -e ".[dev]"
|
|
24
|
+
- run: pytest -q --ignore=tests/test_benchmarks.py
|
|
25
|
+
|
|
26
|
+
gate:
|
|
27
|
+
# The release gate: integrity manifest, ASCII-only CLI output, no
|
|
28
|
+
# placeholder text, docs in step with the code. A green test suite is not
|
|
29
|
+
# the same as a shippable package.
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v4
|
|
33
|
+
- uses: actions/setup-python@v5
|
|
34
|
+
with:
|
|
35
|
+
python-version: "3.12"
|
|
36
|
+
- run: pip install -e ".[dev]"
|
|
37
|
+
- run: python scripts/run_all_checks.py
|
|
38
|
+
|
|
39
|
+
zero-dependency:
|
|
40
|
+
# The property a security reviewer checks first. If a runtime dependency
|
|
41
|
+
# ever sneaks in, this fails loudly rather than being discovered by them.
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@v4
|
|
45
|
+
- uses: actions/setup-python@v5
|
|
46
|
+
with:
|
|
47
|
+
python-version: "3.12"
|
|
48
|
+
- run: pip install .
|
|
49
|
+
- name: base install must pull in nothing
|
|
50
|
+
run: |
|
|
51
|
+
python - <<'PY'
|
|
52
|
+
import tomllib
|
|
53
|
+
deps = tomllib.load(open("pyproject.toml","rb"))["project"]["dependencies"]
|
|
54
|
+
assert deps == [], f"runtime dependencies appeared: {deps}"
|
|
55
|
+
print("zero runtime dependencies, confirmed")
|
|
56
|
+
PY
|
|
57
|
+
- name: it must work with nothing else installed
|
|
58
|
+
run: python -m tokeymeter firstrun
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.mypy_cache/
|
|
10
|
+
.ruff_cache/
|
|
11
|
+
.coverage
|
|
12
|
+
htmlcov/
|
|
13
|
+
|
|
14
|
+
# Environments
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
env/
|
|
18
|
+
ENV/
|
|
19
|
+
|
|
20
|
+
# Tokeymeter's own output — NEVER commit a ledger. It contains no prompt or
|
|
21
|
+
# response text, but task ids, agent names and spend describe your operations
|
|
22
|
+
# the way an application log does.
|
|
23
|
+
tokeymeter-demo/
|
|
24
|
+
tokeymeter-real/
|
|
25
|
+
*.jsonl
|
|
26
|
+
tokeymeter-agents.html
|
|
27
|
+
tokeymeter-savings.html
|
|
28
|
+
tokeymeter-savings.json
|
|
29
|
+
real-report.html
|
|
30
|
+
report.html
|
|
31
|
+
|
|
32
|
+
# Scratch from a local walkthrough
|
|
33
|
+
check.py
|
|
34
|
+
diag.py
|
|
35
|
+
harness.py
|
|
36
|
+
fake_openai.py
|
|
37
|
+
|
|
38
|
+
# Secrets. Belt and braces — keys belong in the environment, never a file.
|
|
39
|
+
.env
|
|
40
|
+
*.pem
|
|
41
|
+
*.key
|
|
42
|
+
|
|
43
|
+
# Editors and OS
|
|
44
|
+
.vscode/
|
|
45
|
+
.idea/
|
|
46
|
+
.DS_Store
|
|
47
|
+
Thumbs.db
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ACCEPTANCE.py — run this on YOUR Windows machine, in VS Code, before publishing.
|
|
3
|
+
|
|
4
|
+
WHAT THIS IS FOR
|
|
5
|
+
================
|
|
6
|
+
Every workload this product has been tested against was written by the same
|
|
7
|
+
person who wrote the product. That is the one gap no amount of test coverage
|
|
8
|
+
closes. This script walks the actual journey a new user takes, on a real
|
|
9
|
+
Windows console, and reports two different things:
|
|
10
|
+
|
|
11
|
+
PASS/FAIL does it work
|
|
12
|
+
FRICTION what a first-time user would find confusing, slow, or missing
|
|
13
|
+
|
|
14
|
+
The second column is the point. A green suite tells you the code is correct.
|
|
15
|
+
It cannot tell you the product is usable.
|
|
16
|
+
|
|
17
|
+
HOW TO RUN
|
|
18
|
+
==========
|
|
19
|
+
In VS Code, open a terminal in an empty folder and:
|
|
20
|
+
|
|
21
|
+
python -m venv .venv
|
|
22
|
+
.venv\\Scripts\\activate
|
|
23
|
+
pip install <path-to>\\novue-tokeymeter-<version>.tar.gz
|
|
24
|
+
python ACCEPTANCE.py
|
|
25
|
+
|
|
26
|
+
Run it a SECOND time in a plain `cmd.exe` window (not the VS Code terminal),
|
|
27
|
+
because cmd.exe defaults to a legacy code page and that is where console
|
|
28
|
+
encoding problems appear.
|
|
29
|
+
|
|
30
|
+
Nothing here needs an API key, a network connection, or an account.
|
|
31
|
+
"""
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import io
|
|
35
|
+
import json
|
|
36
|
+
import os
|
|
37
|
+
import platform
|
|
38
|
+
import shutil
|
|
39
|
+
import subprocess
|
|
40
|
+
import sys
|
|
41
|
+
import tempfile
|
|
42
|
+
import time
|
|
43
|
+
|
|
44
|
+
RESULTS = []
|
|
45
|
+
FRICTION = []
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def check(name, fn, *, note=None):
|
|
49
|
+
"""Run one step and record the outcome without ever stopping the walk —
|
|
50
|
+
a first-time user does not get to skip the rest of the product because
|
|
51
|
+
step three raised."""
|
|
52
|
+
t0 = time.perf_counter()
|
|
53
|
+
try:
|
|
54
|
+
detail = fn()
|
|
55
|
+
ok = True
|
|
56
|
+
except Exception as exc:
|
|
57
|
+
detail = f"{type(exc).__name__}: {exc}"
|
|
58
|
+
ok = False
|
|
59
|
+
ms = (time.perf_counter() - t0) * 1000
|
|
60
|
+
RESULTS.append((ok, name, detail, ms))
|
|
61
|
+
print(f" [{'PASS' if ok else 'FAIL'}] {name:<44} {ms:7.0f} ms")
|
|
62
|
+
if detail and (not ok or note == "show"):
|
|
63
|
+
for line in str(detail).splitlines()[:6]:
|
|
64
|
+
print(f" {line}")
|
|
65
|
+
return ok
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def friction(what):
|
|
69
|
+
FRICTION.append(what)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def run_cli(*args, timeout=180):
|
|
73
|
+
"""Invoke the CLI the way a user does, capturing BYTES.
|
|
74
|
+
|
|
75
|
+
Decoding as UTF-8 would fail on correctly-encoded legacy-code-page output
|
|
76
|
+
and report a crash that never happened — the claim being tested is "the
|
|
77
|
+
command completes", not "the output is UTF-8".
|
|
78
|
+
"""
|
|
79
|
+
p = subprocess.run([sys.executable, "-m", "tokeymeter", *args],
|
|
80
|
+
capture_output=True, timeout=timeout)
|
|
81
|
+
out = (p.stdout or b"").decode("utf-8", "replace")
|
|
82
|
+
err = (p.stderr or b"").decode("utf-8", "replace")
|
|
83
|
+
return p.returncode, out + err
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def main() -> int:
|
|
87
|
+
print()
|
|
88
|
+
print("=" * 72)
|
|
89
|
+
print(" TOKEYMETER — user-perspective acceptance")
|
|
90
|
+
print("=" * 72)
|
|
91
|
+
print(f" python {sys.version.split()[0]}")
|
|
92
|
+
print(f" platform {platform.platform()}")
|
|
93
|
+
print(f" stdout enc {getattr(sys.stdout, 'encoding', '?')}")
|
|
94
|
+
print(f" cwd {os.getcwd()}")
|
|
95
|
+
print()
|
|
96
|
+
|
|
97
|
+
home = tempfile.mkdtemp(prefix="tokeymeter-acceptance-")
|
|
98
|
+
os.environ["TOKEYMETER_HOME"] = home
|
|
99
|
+
print(f" scratch {home}")
|
|
100
|
+
print()
|
|
101
|
+
|
|
102
|
+
# ── 1. it installed and is honest about what it is ──────────────────
|
|
103
|
+
print("-- 1. install and identity " + "-" * 45)
|
|
104
|
+
import tokeymeter
|
|
105
|
+
|
|
106
|
+
check("import tokeymeter", lambda: f"v{tokeymeter.__version__}", note="show")
|
|
107
|
+
check("the package verifies its own integrity",
|
|
108
|
+
lambda: __import__(
|
|
109
|
+
"tokeymeter.engines.trust.integrity", fromlist=["x"]
|
|
110
|
+
).verify_self(require_signature=False).status,
|
|
111
|
+
note="show")
|
|
112
|
+
check("a newcomer can see what the product IS",
|
|
113
|
+
lambda: f"{len(tokeymeter.PRIMARY_API)} primary of "
|
|
114
|
+
f"{len(tokeymeter.__all__)} public names", note="show")
|
|
115
|
+
|
|
116
|
+
# ── 2. the first run ────────────────────────────────────────────────
|
|
117
|
+
print()
|
|
118
|
+
print("-- 2. the first 60 seconds " + "-" * 45)
|
|
119
|
+
|
|
120
|
+
def first_run():
|
|
121
|
+
code, out = run_cli("firstrun")
|
|
122
|
+
if code != 0:
|
|
123
|
+
raise RuntimeError(f"exit {code}\n{out[:400]}")
|
|
124
|
+
if "was" not in out or "stopped" not in out.lower():
|
|
125
|
+
raise RuntimeError("the demo did not show a before/after")
|
|
126
|
+
return "showed a stuck agent being stopped"
|
|
127
|
+
|
|
128
|
+
check("tokeymeter firstrun", first_run, note="show")
|
|
129
|
+
|
|
130
|
+
def help_discovers_the_product():
|
|
131
|
+
code, out = run_cli()
|
|
132
|
+
missing = [c for c in ("firstrun", "agents", "plan", "doctor")
|
|
133
|
+
if c not in out]
|
|
134
|
+
if missing:
|
|
135
|
+
raise RuntimeError(f"help does not mention: {', '.join(missing)}")
|
|
136
|
+
return "help lists the commands that matter"
|
|
137
|
+
|
|
138
|
+
check("the CLI tells you what it can do", help_discovers_the_product)
|
|
139
|
+
|
|
140
|
+
# ── 3. the developer's own path ─────────────────────────────────────
|
|
141
|
+
print()
|
|
142
|
+
print("-- 3. wrapping one agent " + "-" * 47)
|
|
143
|
+
from tokeymeter.storage import MemoryStore
|
|
144
|
+
from tokeymeter.engines.economics.usage import set_reported_usage
|
|
145
|
+
|
|
146
|
+
tokeymeter.set_default_store(MemoryStore())
|
|
147
|
+
tokeymeter.set_savings_path(os.path.join(home, "savings.jsonl"))
|
|
148
|
+
tokeymeter.register_pricing("gpt-4o", input_per_1m=2.5, output_per_1m=10.0)
|
|
149
|
+
|
|
150
|
+
@tokeymeter.cache(model="gpt-4o", tag="support-api")
|
|
151
|
+
def agent_turn(messages, tokens, stuck, i, j):
|
|
152
|
+
set_reported_usage(tokens, 300)
|
|
153
|
+
return "tool error: cannot parse" if stuck else f"found {i}-{j}"
|
|
154
|
+
|
|
155
|
+
def wrap_and_halt():
|
|
156
|
+
stopped = 0
|
|
157
|
+
for i in range(12):
|
|
158
|
+
history = []
|
|
159
|
+
try:
|
|
160
|
+
with tokeymeter.task(f"ticket-{i}", agent="support",
|
|
161
|
+
stall_window=8, enforce=True):
|
|
162
|
+
for j in range(14):
|
|
163
|
+
history.append(f"turn {j}")
|
|
164
|
+
agent_turn(tuple(history) + (i,), 1100 + j * 420,
|
|
165
|
+
i % 4 == 0, i, j)
|
|
166
|
+
except tokeymeter.TaskStalled:
|
|
167
|
+
stopped += 1
|
|
168
|
+
if stopped == 0:
|
|
169
|
+
raise RuntimeError("no stuck task was stopped")
|
|
170
|
+
return f"{stopped} of 12 tickets stopped as stuck"
|
|
171
|
+
|
|
172
|
+
check("a stuck agent is halted", wrap_and_halt, note="show")
|
|
173
|
+
|
|
174
|
+
def report_card():
|
|
175
|
+
from tokeymeter.engines.governance.agents import (agent_report,
|
|
176
|
+
render_agents)
|
|
177
|
+
text = render_agents(agent_report())
|
|
178
|
+
if "support" not in text:
|
|
179
|
+
raise RuntimeError("the agent is missing from its own report")
|
|
180
|
+
non_ascii = [c for c in text if ord(c) > 127]
|
|
181
|
+
if non_ascii:
|
|
182
|
+
raise RuntimeError(f"report contains non-ASCII: {non_ascii[:5]!r}")
|
|
183
|
+
return text.splitlines()[2].strip()
|
|
184
|
+
|
|
185
|
+
check("tokeymeter agents shows the estate", report_card, note="show")
|
|
186
|
+
|
|
187
|
+
# ── 4. the platform owner's path ────────────────────────────────────
|
|
188
|
+
print()
|
|
189
|
+
print("-- 4. one policy across every service " + "-" * 34)
|
|
190
|
+
policy_path = os.path.join(home, "ai-execution.json")
|
|
191
|
+
with open(policy_path, "w", encoding="utf-8") as f:
|
|
192
|
+
json.dump({"version": 1, "rules": [
|
|
193
|
+
{"name": "agent-guard",
|
|
194
|
+
"then": {"envelope": 2.00, "reserve": 0.10,
|
|
195
|
+
"stall_window": 8, "enforce": True}},
|
|
196
|
+
{"name": "phi-handling", "when": {"data_class": "PHI"},
|
|
197
|
+
"then": {"only": ["gpt-4o-secure"], "never_cache": True}},
|
|
198
|
+
]}, f)
|
|
199
|
+
|
|
200
|
+
def plan_runs():
|
|
201
|
+
code, out = run_cli("plan", "--policy", policy_path)
|
|
202
|
+
if code not in (0, 2):
|
|
203
|
+
raise RuntimeError(f"exit {code}\n{out[:400]}")
|
|
204
|
+
if "Coverage" not in out:
|
|
205
|
+
raise RuntimeError("plan did not report coverage")
|
|
206
|
+
return next((l.strip() for l in out.splitlines()
|
|
207
|
+
if "would halt" in l), "ran")
|
|
208
|
+
|
|
209
|
+
check("tokeymeter plan previews a policy", plan_runs, note="show")
|
|
210
|
+
|
|
211
|
+
def plan_gates_ci():
|
|
212
|
+
code, _ = run_cli("plan", "--policy", policy_path,
|
|
213
|
+
"--protect", "support")
|
|
214
|
+
if code not in (0, 2):
|
|
215
|
+
raise RuntimeError(f"unexpected exit {code}")
|
|
216
|
+
return f"exit {code} (2 means it would block a protected agent)"
|
|
217
|
+
|
|
218
|
+
check("plan can fail a CI step", plan_gates_ci, note="show")
|
|
219
|
+
|
|
220
|
+
def bad_policy_is_loud():
|
|
221
|
+
bad = os.path.join(home, "bad.json")
|
|
222
|
+
with open(bad, "w", encoding="utf-8") as f:
|
|
223
|
+
json.dump({"rules": [{"name": "oops",
|
|
224
|
+
"then": {"enevelope": 1.0}}]}, f)
|
|
225
|
+
code, out = run_cli("plan", "--policy", bad)
|
|
226
|
+
if code == 0:
|
|
227
|
+
raise RuntimeError("a typo'd policy was accepted silently")
|
|
228
|
+
if "oops" not in out:
|
|
229
|
+
raise RuntimeError("the error does not name the offending rule")
|
|
230
|
+
return "a typo is rejected and the rule is named"
|
|
231
|
+
|
|
232
|
+
check("a bad policy fails loudly", bad_policy_is_loud, note="show")
|
|
233
|
+
|
|
234
|
+
# ── 5. the compliance officer's path ────────────────────────────────
|
|
235
|
+
print()
|
|
236
|
+
print("-- 5. what is allowed, and proving it " + "-" * 34)
|
|
237
|
+
from tokeymeter.engines.governance import rules as R
|
|
238
|
+
|
|
239
|
+
def phi_is_refused():
|
|
240
|
+
R.set_rules(R.load_rules([
|
|
241
|
+
{"name": "phi", "when": {"data_class": "PHI"},
|
|
242
|
+
"then": {"only": ["gpt-4o-secure"], "never_cache": True}}]))
|
|
243
|
+
tokeymeter.register_pricing("gpt-4o-secure", input_per_1m=2.5,
|
|
244
|
+
output_per_1m=10.0)
|
|
245
|
+
|
|
246
|
+
@tokeymeter.cache(model="gpt-4o")
|
|
247
|
+
def unapproved(p):
|
|
248
|
+
set_reported_usage(1000, 200)
|
|
249
|
+
return "x"
|
|
250
|
+
|
|
251
|
+
@tokeymeter.cache(model="gpt-4o-secure")
|
|
252
|
+
def approved(p):
|
|
253
|
+
set_reported_usage(1000, 200)
|
|
254
|
+
return "x"
|
|
255
|
+
|
|
256
|
+
refused = 0
|
|
257
|
+
for i in range(5):
|
|
258
|
+
try:
|
|
259
|
+
with tokeymeter.data_class("PHI"):
|
|
260
|
+
unapproved(f"patient {i}")
|
|
261
|
+
except tokeymeter.ModelNotPermitted:
|
|
262
|
+
refused += 1
|
|
263
|
+
for i in range(10):
|
|
264
|
+
with tokeymeter.data_class("PHI"):
|
|
265
|
+
approved(f"patient {i}")
|
|
266
|
+
if refused != 5:
|
|
267
|
+
raise RuntimeError(f"only {refused} of 5 were refused")
|
|
268
|
+
return "5 of 5 attempts to send PHI to an unapproved model refused"
|
|
269
|
+
|
|
270
|
+
check("PHI cannot reach an unapproved model", phi_is_refused, note="show")
|
|
271
|
+
|
|
272
|
+
def auditor_answer():
|
|
273
|
+
rep = tokeymeter.policy_report()
|
|
274
|
+
models = rep["by_data_class"].get("PHI", {}).get("models")
|
|
275
|
+
if models != ["gpt-4o-secure"]:
|
|
276
|
+
raise RuntimeError(f"PHI reached: {models}")
|
|
277
|
+
return f"every model PHI reached: {models}"
|
|
278
|
+
|
|
279
|
+
check("the report answers 'prove it'", auditor_answer, note="show")
|
|
280
|
+
|
|
281
|
+
def nothing_is_stored():
|
|
282
|
+
recs = [json.loads(l) for l in
|
|
283
|
+
open(os.path.join(home, "savings.jsonl"), encoding="utf-8")
|
|
284
|
+
if l.strip()]
|
|
285
|
+
blob = json.dumps(recs)
|
|
286
|
+
leaked = [s for s in ("patient", "tool error", "found 0-0", "turn 1")
|
|
287
|
+
if s in blob]
|
|
288
|
+
if leaked:
|
|
289
|
+
raise RuntimeError(f"content found in the ledger: {leaked}")
|
|
290
|
+
return f"{len(recs)} records on disk, none containing prompt or response"
|
|
291
|
+
|
|
292
|
+
R.clear_rules()
|
|
293
|
+
check("no prompt or response reached the ledger", nothing_is_stored,
|
|
294
|
+
note="show")
|
|
295
|
+
|
|
296
|
+
# ── 6. Windows-specific reality ─────────────────────────────────────
|
|
297
|
+
print()
|
|
298
|
+
print("-- 6. this machine, specifically " + "-" * 39)
|
|
299
|
+
|
|
300
|
+
def console_survives_legacy_codepage():
|
|
301
|
+
env = dict(os.environ, PYTHONIOENCODING="cp1252")
|
|
302
|
+
bad = []
|
|
303
|
+
for cmd in ("firstrun", "doctor", "pricing", "agents"):
|
|
304
|
+
p = subprocess.run([sys.executable, "-m", "tokeymeter", cmd],
|
|
305
|
+
capture_output=True, env=env, timeout=300)
|
|
306
|
+
if p.returncode != 0:
|
|
307
|
+
bad.append(f"{cmd}(exit {p.returncode})")
|
|
308
|
+
if bad:
|
|
309
|
+
raise RuntimeError("crashed under cp1252: " + ", ".join(bad))
|
|
310
|
+
return "every command survives a legacy console code page"
|
|
311
|
+
|
|
312
|
+
check("CLI works on a legacy code page", console_survives_legacy_codepage,
|
|
313
|
+
note="show")
|
|
314
|
+
|
|
315
|
+
def home_is_respected():
|
|
316
|
+
found = [f for f in os.listdir(home) if f.endswith(".jsonl")]
|
|
317
|
+
if not found:
|
|
318
|
+
raise RuntimeError("nothing was written to TOKEYMETER_HOME")
|
|
319
|
+
stray = os.path.join(os.path.expanduser("~"), ".tokeymeter")
|
|
320
|
+
note = ""
|
|
321
|
+
if os.path.isdir(stray):
|
|
322
|
+
note = " (note: ~/.tokeymeter also exists from an earlier run)"
|
|
323
|
+
return f"wrote {found} into TOKEYMETER_HOME{note}"
|
|
324
|
+
|
|
325
|
+
check("TOKEYMETER_HOME is respected", home_is_respected, note="show")
|
|
326
|
+
|
|
327
|
+
def ledger_write_speed():
|
|
328
|
+
tokeymeter.set_default_store(MemoryStore())
|
|
329
|
+
|
|
330
|
+
@tokeymeter.cache(model="gpt-4o")
|
|
331
|
+
def s(p):
|
|
332
|
+
set_reported_usage(400, 150)
|
|
333
|
+
return "x"
|
|
334
|
+
|
|
335
|
+
t0 = time.perf_counter()
|
|
336
|
+
for i in range(2000):
|
|
337
|
+
with tokeymeter.task(f"perf-{i}", agent="perf"):
|
|
338
|
+
s(f"{i}")
|
|
339
|
+
rate = 2000 / (time.perf_counter() - t0)
|
|
340
|
+
if rate < 100:
|
|
341
|
+
friction(f"ledger writes are slow here ({rate:,.0f}/s). On Windows "
|
|
342
|
+
f"this is usually antivirus scanning every file open — "
|
|
343
|
+
f"set_buffered_savings(True) cuts opens ~65x.")
|
|
344
|
+
return f"{rate:,.0f} tasks/s writing to a real file"
|
|
345
|
+
|
|
346
|
+
check("ledger throughput on this disk", ledger_write_speed, note="show")
|
|
347
|
+
|
|
348
|
+
def overhead():
|
|
349
|
+
tokeymeter.set_default_store(MemoryStore())
|
|
350
|
+
tokeymeter.set_in_memory_savings(True)
|
|
351
|
+
|
|
352
|
+
@tokeymeter.cache(model="gpt-4o")
|
|
353
|
+
def s(p):
|
|
354
|
+
set_reported_usage(400, 200)
|
|
355
|
+
return "x" * 2000
|
|
356
|
+
|
|
357
|
+
s("warm")
|
|
358
|
+
lat = []
|
|
359
|
+
for _ in range(2000):
|
|
360
|
+
t0 = time.perf_counter_ns()
|
|
361
|
+
with tokeymeter.task("bench", agent="b", stall_window=8):
|
|
362
|
+
s("warm")
|
|
363
|
+
lat.append((time.perf_counter_ns() - t0) / 1000)
|
|
364
|
+
lat.sort()
|
|
365
|
+
p50, p95 = lat[len(lat) // 2], lat[int(len(lat) * 0.95)]
|
|
366
|
+
if p50 > 500:
|
|
367
|
+
friction(f"per-call overhead is high here (p50 {p50:.0f}us).")
|
|
368
|
+
return f"p50 {p50:.1f}us p95 {p95:.1f}us (fully governed call)"
|
|
369
|
+
|
|
370
|
+
check("per-call overhead on this machine", overhead, note="show")
|
|
371
|
+
|
|
372
|
+
# ── verdict ─────────────────────────────────────────────────────────
|
|
373
|
+
passed = sum(1 for ok, *_ in RESULTS if ok)
|
|
374
|
+
total = len(RESULTS)
|
|
375
|
+
print()
|
|
376
|
+
print("=" * 72)
|
|
377
|
+
print(f" {passed}/{total} checks passed")
|
|
378
|
+
failed = [(n, d) for ok, n, d, _ in RESULTS if not ok]
|
|
379
|
+
if failed:
|
|
380
|
+
print()
|
|
381
|
+
print(" FAILURES — these are what a user would hit:")
|
|
382
|
+
for n, d in failed:
|
|
383
|
+
print(f" - {n}")
|
|
384
|
+
for line in str(d).splitlines()[:3]:
|
|
385
|
+
print(f" {line}")
|
|
386
|
+
if FRICTION:
|
|
387
|
+
print()
|
|
388
|
+
print(" FRICTION — works, but a user would notice:")
|
|
389
|
+
for f in FRICTION:
|
|
390
|
+
print(f" - {f}")
|
|
391
|
+
print()
|
|
392
|
+
print(" WORTH ANSWERING YOURSELF, since no test can:")
|
|
393
|
+
print(" 1. After `tokeymeter firstrun`, did you know what to do next?")
|
|
394
|
+
print(" 2. Was anything on screen confusing or unexplained?")
|
|
395
|
+
print(" 3. Would you have wrapped one of your own agents after this?")
|
|
396
|
+
print(" 4. What did you expect to exist that did not?")
|
|
397
|
+
print()
|
|
398
|
+
print(f" scratch dir left in place for inspection:\n {home}")
|
|
399
|
+
print("=" * 72)
|
|
400
|
+
print()
|
|
401
|
+
return 0 if not failed else 1
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
if __name__ == "__main__":
|
|
405
|
+
sys.exit(main())
|