tokeymeter 0.31.1__py3-none-any.whl
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/__init__.py +436 -0
- tokeymeter/__main__.py +136 -0
- tokeymeter/_api.py +410 -0
- tokeymeter/_fidelity.py +4 -0
- tokeymeter/_manifest.json +158 -0
- tokeymeter/admin.py +497 -0
- tokeymeter/audit/__init__.py +7 -0
- tokeymeter/backends/__init__.py +10 -0
- tokeymeter/cache_admin.py +4 -0
- tokeymeter/cache_optimize.py +4 -0
- tokeymeter/cascade.py +4 -0
- tokeymeter/compression.py +4 -0
- tokeymeter/compression_eval.py +4 -0
- tokeymeter/content/__init__.py +7 -0
- tokeymeter/context_passport.py +4 -0
- tokeymeter/decision.py +4 -0
- tokeymeter/decorator.py +2406 -0
- tokeymeter/degraded.py +4 -0
- tokeymeter/demo.py +99 -0
- tokeymeter/engines/__init__.py +1 -0
- tokeymeter/engines/economics/__init__.py +1 -0
- tokeymeter/engines/economics/capacity_report.py +366 -0
- tokeymeter/engines/economics/chargeback.py +365 -0
- tokeymeter/engines/economics/close_packet.py +503 -0
- tokeymeter/engines/economics/hybrid.py +430 -0
- tokeymeter/engines/economics/keys.py +274 -0
- tokeymeter/engines/economics/pricing.py +496 -0
- tokeymeter/engines/economics/reconcile.py +112 -0
- tokeymeter/engines/economics/reporting.py +338 -0
- tokeymeter/engines/economics/savings.py +779 -0
- tokeymeter/engines/economics/usage.py +132 -0
- tokeymeter/engines/execution/__init__.py +1 -0
- tokeymeter/engines/execution/endpoint.py +92 -0
- tokeymeter/engines/execution/halts.py +200 -0
- tokeymeter/engines/execution/integrations/README.md +95 -0
- tokeymeter/engines/execution/integrations/__init__.py +0 -0
- tokeymeter/engines/execution/integrations/anthropic.py +203 -0
- tokeymeter/engines/execution/integrations/openai.py +647 -0
- tokeymeter/engines/execution/integrations/openai_async.py +421 -0
- tokeymeter/engines/execution/integrations/universal.py +177 -0
- tokeymeter/engines/execution/response_text.py +133 -0
- tokeymeter/engines/execution/task.py +936 -0
- tokeymeter/engines/governance/__init__.py +1 -0
- tokeymeter/engines/governance/agents.py +557 -0
- tokeymeter/engines/governance/agents_html.py +642 -0
- tokeymeter/engines/governance/compliance.py +714 -0
- tokeymeter/engines/governance/content/REDTEAM_REPORT.md +68 -0
- tokeymeter/engines/governance/content/__init__.py +27 -0
- tokeymeter/engines/governance/content/secrets.py +796 -0
- tokeymeter/engines/governance/decision.py +208 -0
- tokeymeter/engines/governance/identity.py +69 -0
- tokeymeter/engines/governance/plan.py +489 -0
- tokeymeter/engines/governance/policy.py +84 -0
- tokeymeter/engines/governance/privacy.py +233 -0
- tokeymeter/engines/governance/rules.py +609 -0
- tokeymeter/engines/governance/simulate.py +391 -0
- tokeymeter/engines/governance/suggest.py +467 -0
- tokeymeter/engines/knowledge/__init__.py +1 -0
- tokeymeter/engines/knowledge/context_passport.py +93 -0
- tokeymeter/engines/knowledge/memory.py +1063 -0
- tokeymeter/engines/optimization/__init__.py +1 -0
- tokeymeter/engines/optimization/cache_admin.py +19 -0
- tokeymeter/engines/optimization/cache_optimize.py +346 -0
- tokeymeter/engines/optimization/cascade.py +338 -0
- tokeymeter/engines/optimization/compression.py +556 -0
- tokeymeter/engines/optimization/compression_eval.py +358 -0
- tokeymeter/engines/optimization/envelope.py +115 -0
- tokeymeter/engines/optimization/prompt_ir.py +297 -0
- tokeymeter/engines/optimization/query_compress.py +421 -0
- tokeymeter/engines/optimization/redis_store.py +400 -0
- tokeymeter/engines/optimization/router.py +380 -0
- tokeymeter/engines/optimization/safe_compress.py +187 -0
- tokeymeter/engines/optimization/salience.py +305 -0
- tokeymeter/engines/optimization/semantic.py +699 -0
- tokeymeter/engines/optimization/semantic_eval.py +404 -0
- tokeymeter/engines/optimization/semantic_verify.py +284 -0
- tokeymeter/engines/optimization/storage.py +286 -0
- tokeymeter/engines/optimization/warmup.py +271 -0
- tokeymeter/engines/reliability/__init__.py +1 -0
- tokeymeter/engines/reliability/_fidelity.py +192 -0
- tokeymeter/engines/reliability/degraded.py +125 -0
- tokeymeter/engines/reliability/overhead.py +51 -0
- tokeymeter/engines/trust/__init__.py +1 -0
- tokeymeter/engines/trust/audit/__init__.py +90 -0
- tokeymeter/engines/trust/audit/log.py +921 -0
- tokeymeter/engines/trust/audit/proof.py +391 -0
- tokeymeter/engines/trust/audit/signers.py +193 -0
- tokeymeter/engines/trust/cipher.py +105 -0
- tokeymeter/engines/trust/integrity.py +634 -0
- tokeymeter/envelope.py +4 -0
- tokeymeter/events.py +156 -0
- tokeymeter/firstrun.py +215 -0
- tokeymeter/identity.py +4 -0
- tokeymeter/integrations/__init__.py +9 -0
- tokeymeter/integrity.py +4 -0
- tokeymeter/keys.py +4 -0
- tokeymeter/memory.py +4 -0
- tokeymeter/metrics.py +216 -0
- tokeymeter/overhead.py +4 -0
- tokeymeter/paths.py +79 -0
- tokeymeter/policy.py +4 -0
- tokeymeter/pricing.py +4 -0
- tokeymeter/privacy.py +4 -0
- tokeymeter/prompt_ir.py +4 -0
- tokeymeter/py.typed +0 -0
- tokeymeter/query_compress.py +4 -0
- tokeymeter/reporting.py +4 -0
- tokeymeter/router.py +4 -0
- tokeymeter/runtime/__init__.py +108 -0
- tokeymeter/runtime/adapters.py +198 -0
- tokeymeter/runtime/bus.py +83 -0
- tokeymeter/runtime/catalog.py +157 -0
- tokeymeter/runtime/config.py +92 -0
- tokeymeter/runtime/conformance.py +167 -0
- tokeymeter/runtime/container.py +71 -0
- tokeymeter/runtime/economics.py +134 -0
- tokeymeter/runtime/enforcement.py +290 -0
- tokeymeter/runtime/engine.py +75 -0
- tokeymeter/runtime/engines.py +286 -0
- tokeymeter/runtime/errors.py +129 -0
- tokeymeter/runtime/facade.py +478 -0
- tokeymeter/runtime/frameworks.py +91 -0
- tokeymeter/runtime/hotreload.py +88 -0
- tokeymeter/runtime/kernel.py +239 -0
- tokeymeter/runtime/oidc.py +165 -0
- tokeymeter/runtime/optimization.py +111 -0
- tokeymeter/runtime/optimize.py +225 -0
- tokeymeter/runtime/plugins.py +229 -0
- tokeymeter/runtime/proof.py +374 -0
- tokeymeter/runtime/providers.py +167 -0
- tokeymeter/runtime/resilience.py +344 -0
- tokeymeter/runtime/telemetry.py +155 -0
- tokeymeter/runtime/tools.py +178 -0
- tokeymeter/safe_compress.py +4 -0
- tokeymeter/salience.py +4 -0
- tokeymeter/savings.py +4 -0
- tokeymeter/semantic.py +4 -0
- tokeymeter/semantic_eval.py +4 -0
- tokeymeter/semantic_verify.py +4 -0
- tokeymeter/storage.py +4 -0
- tokeymeter/usage.py +4 -0
- tokeymeter/utils.py +42 -0
- tokeymeter/warmup.py +4 -0
- tokeymeter/watch.py +438 -0
- tokeymeter-0.31.1.dist-info/METADATA +982 -0
- tokeymeter-0.31.1.dist-info/RECORD +150 -0
- tokeymeter-0.31.1.dist-info/WHEEL +5 -0
- tokeymeter-0.31.1.dist-info/entry_points.txt +2 -0
- tokeymeter-0.31.1.dist-info/licenses/LICENSE +178 -0
- tokeymeter-0.31.1.dist-info/top_level.txt +1 -0
tokeymeter/__init__.py
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tokeymeter — industrial-grade LLM cost optimization.
|
|
3
|
+
|
|
4
|
+
Two-tier cache (exact + semantic) with TTL, single-flight dedup, optional
|
|
5
|
+
sqlite-vec acceleration, sync + async + streaming. Plus a trust layer:
|
|
6
|
+
observable events, shadow mode, PII redaction, workload tagging.
|
|
7
|
+
|
|
8
|
+
Quick start:
|
|
9
|
+
|
|
10
|
+
import tokeymeter
|
|
11
|
+
|
|
12
|
+
@tokeymeter.cache(
|
|
13
|
+
model="gpt-4o-mini",
|
|
14
|
+
semantic=True, # paraphrase matching
|
|
15
|
+
ttl=3600, # entries expire after 1 hour
|
|
16
|
+
shadow=False, # set True to measure without serving cached
|
|
17
|
+
redactor=tokeymeter.privacy.default_redactor, # strip PII before caching
|
|
18
|
+
tag="support", # workload label for reporting
|
|
19
|
+
)
|
|
20
|
+
async def ask(prompt: str) -> str:
|
|
21
|
+
return await openai_call(prompt)
|
|
22
|
+
|
|
23
|
+
# Wire observability
|
|
24
|
+
@tokeymeter.events.on_event
|
|
25
|
+
def to_datadog(event):
|
|
26
|
+
statsd.increment("tokeymeter.lookup",
|
|
27
|
+
tags=[f"hit_type:{event.hit_type or 'miss'}"])
|
|
28
|
+
|
|
29
|
+
print(tokeymeter.savings_report())
|
|
30
|
+
"""
|
|
31
|
+
from . import admin, audit, backends, compression, events, integrity, memory, metrics, privacy, warmup
|
|
32
|
+
from .cache_admin import clear_cache
|
|
33
|
+
from .compression import (
|
|
34
|
+
Compressor,
|
|
35
|
+
CompressionResult,
|
|
36
|
+
LLMLinguaCompressor,
|
|
37
|
+
StructuralCompressor,
|
|
38
|
+
compose,
|
|
39
|
+
safe_compress,
|
|
40
|
+
)
|
|
41
|
+
from .salience import SalienceCompressor
|
|
42
|
+
from .safe_compress import SafeCompressor, compression_stats, reset_compression_stats
|
|
43
|
+
from .router import Router, RouteDecision, Cascade, CascadeResult
|
|
44
|
+
from .cache_optimize import CacheOptimizer, CacheReport, VolatileFinding
|
|
45
|
+
from .decorator import (
|
|
46
|
+
cache,
|
|
47
|
+
cache_stream,
|
|
48
|
+
lineage,
|
|
49
|
+
tenant_scope,
|
|
50
|
+
set_compression_max_reduction,
|
|
51
|
+
set_fidelity_circuit_breaker,
|
|
52
|
+
compression_breaker_state,
|
|
53
|
+
set_event_preview_policy,
|
|
54
|
+
set_runtime_guards,
|
|
55
|
+
enterprise_defaults,
|
|
56
|
+
compression_verification_log,
|
|
57
|
+
memory_fidelity_log,
|
|
58
|
+
set_default_redactor,
|
|
59
|
+
set_default_semantic_cache,
|
|
60
|
+
set_default_store,
|
|
61
|
+
with_memory,
|
|
62
|
+
)
|
|
63
|
+
from .envelope import unwrap, wrap
|
|
64
|
+
from . import prompt_ir # Phase 0 Prompt IR substrate (namespaced; consumes nothing yet)
|
|
65
|
+
from .policy import (
|
|
66
|
+
SecurityPolicy,
|
|
67
|
+
SecurityPolicyError,
|
|
68
|
+
set_security_policy,
|
|
69
|
+
get_security_policy,
|
|
70
|
+
reset_security_policy,
|
|
71
|
+
)
|
|
72
|
+
from .decision import (
|
|
73
|
+
DecisionRecord,
|
|
74
|
+
on_decision,
|
|
75
|
+
remove_decision_subscriber,
|
|
76
|
+
clear_decision_subscribers,
|
|
77
|
+
)
|
|
78
|
+
from .memory import (
|
|
79
|
+
CallableSummarizer,
|
|
80
|
+
ConversationMemory,
|
|
81
|
+
InMemoryMemoryStore,
|
|
82
|
+
SQLiteMemoryStore,
|
|
83
|
+
Summarizer,
|
|
84
|
+
Turn,
|
|
85
|
+
TruncationSummarizer,
|
|
86
|
+
)
|
|
87
|
+
from .metrics import PrometheusCollector
|
|
88
|
+
from .integrity import scan_environment, self_check, verify_self
|
|
89
|
+
from .backends import RedisStore, FernetCipher, NoOpCipher
|
|
90
|
+
from .privacy import DefaultRedactor, default_redactor, redact
|
|
91
|
+
from .savings import (reset_savings, savings_report, savings_ledger_health, set_home,
|
|
92
|
+
set_savings_path, set_buffered_savings, set_in_memory_savings, flush_savings,
|
|
93
|
+
capacity_report)
|
|
94
|
+
from .identity import set_principal, get_principal, principal
|
|
95
|
+
from .engines.governance.rules import (
|
|
96
|
+
RuleSet, Rule, Condition, RulePolicyError,
|
|
97
|
+
load_rules, load_rules_file, set_rules, get_rules, clear_rules,
|
|
98
|
+
rules_version, set_env, current_env)
|
|
99
|
+
from .engines.execution.halts import (
|
|
100
|
+
HaltEvent, on_halt, remove_halt_handler, clear_halt_handlers,
|
|
101
|
+
halt_handler_count)
|
|
102
|
+
from .engines.governance.compliance import (
|
|
103
|
+
data_class, set_data_class, current_data_class,
|
|
104
|
+
region, set_region, current_region,
|
|
105
|
+
PolicyViolation, ModelNotPermitted, EndpointNotPermitted,
|
|
106
|
+
resolve_compliance,
|
|
107
|
+
STARTER_POLICIES, starter_policy, list_starter_policies, policy_report)
|
|
108
|
+
from .engines.governance.simulate import simulate_rules
|
|
109
|
+
from .engines.governance.plan import (
|
|
110
|
+
plan_report, coverage_report, render_plan)
|
|
111
|
+
from .engines.governance.agents import (
|
|
112
|
+
agent_report, render_agents, compare_reports, render_comparison)
|
|
113
|
+
from .engines.governance.suggest import suggest_thresholds, render_suggestions
|
|
114
|
+
from .engines.governance.agents_html import render_agents_html, write_agents_html
|
|
115
|
+
# LangChain / LlamaIndex adapters. Importing this module never requires either
|
|
116
|
+
# package to be installed — the adapters duck-type whatever is handed to them.
|
|
117
|
+
from .runtime.frameworks import wrap_langchain_llm, wrap_llamaindex_llm
|
|
118
|
+
from .engines.execution.task import (
|
|
119
|
+
task, bind_task, set_task, get_task, current_task_id, current_agent,
|
|
120
|
+
task_snapshot,
|
|
121
|
+
TaskLimitExceeded, TaskEnvelopeExceeded, TaskLoopDetected,
|
|
122
|
+
TaskStalled, TaskCallLimitExceeded)
|
|
123
|
+
from .engines.execution.endpoint import set_endpoint, get_endpoint, endpoint
|
|
124
|
+
from .usage import set_queue_wait_ms
|
|
125
|
+
from .keys import (register_key, unregister_key, clear_keys, key,
|
|
126
|
+
key_status, leak_scan, get_current_key, KeyBudgetExceeded)
|
|
127
|
+
from . import context_passport
|
|
128
|
+
from .pricing import (register_pricing, unregister_pricing, clear_registered_pricing,
|
|
129
|
+
registered_pricing, pricing_info, estimate_cost_with_source,
|
|
130
|
+
derive_selfhost_rate, register_selfhost_pricing, capacity_reclaimed,
|
|
131
|
+
register_cluster_costs, derive_cluster_gpu_hour_rate)
|
|
132
|
+
from .engines.economics.capacity_report import capacity_recovery_report
|
|
133
|
+
from .engines.economics.chargeback import chargeback_report, chargeback_csv
|
|
134
|
+
from .engines.economics.hybrid import hybrid_placement_report, hybrid_placement_csv
|
|
135
|
+
from .engines.economics.close_packet import (
|
|
136
|
+
close_packet, general_ledger_rows, general_ledger_csv)
|
|
137
|
+
from .storage import MemoryStore, SQLiteStore
|
|
138
|
+
|
|
139
|
+
# Semantic primitives are imported lazily to avoid hard-failing when
|
|
140
|
+
# extras aren't installed.
|
|
141
|
+
try:
|
|
142
|
+
from .semantic import SemanticCache, is_available as semantic_available
|
|
143
|
+
from .semantic import is_vec_index_available
|
|
144
|
+
except ImportError:
|
|
145
|
+
SemanticCache = None # type: ignore[assignment]
|
|
146
|
+
|
|
147
|
+
def semantic_available() -> bool: # type: ignore[no-redef]
|
|
148
|
+
return False
|
|
149
|
+
|
|
150
|
+
def is_vec_index_available() -> bool: # type: ignore[no-redef]
|
|
151
|
+
return False
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
__version__ = "0.31.1"
|
|
155
|
+
|
|
156
|
+
# ---------------------------------------------------------------------------
|
|
157
|
+
# THE PRIMARY SURFACE
|
|
158
|
+
#
|
|
159
|
+
# 164 public names is a complete toolbox and a poor first impression: someone
|
|
160
|
+
# opening this package has no way to tell which twenty things ARE the product
|
|
161
|
+
# and which hundred-and-forty are the machinery underneath.
|
|
162
|
+
#
|
|
163
|
+
# Nothing is removed — deleting public API from a shipped package breaks
|
|
164
|
+
# working code and buys nothing. Instead the product is NAMED here, so docs,
|
|
165
|
+
# tooling and a new reader all have one honest entry point. Everything absent
|
|
166
|
+
# from this list still works exactly as before.
|
|
167
|
+
# ---------------------------------------------------------------------------
|
|
168
|
+
PRIMARY_API = (
|
|
169
|
+
# Install it: one decorator on the function that calls a model.
|
|
170
|
+
"cache", "cache_stream",
|
|
171
|
+
# Bound a unit of agent work. An agent task is 10-100 calls; this is the
|
|
172
|
+
# boundary everything else keys on.
|
|
173
|
+
"task", "bind_task", "TaskLimitExceeded",
|
|
174
|
+
# Price what you use, on an API or on your own hardware.
|
|
175
|
+
"register_pricing", "register_cluster_costs",
|
|
176
|
+
# Declare the rules once; the node enforces them everywhere.
|
|
177
|
+
"load_rules_file", "set_rules",
|
|
178
|
+
# See what happened, and what a rule WOULD do before you apply it.
|
|
179
|
+
"agent_report", "plan_report", "savings_report", "report",
|
|
180
|
+
# Money, in the shape finance already works in.
|
|
181
|
+
"chargeback_report", "close_packet", "general_ledger_csv",
|
|
182
|
+
# Owned hardware.
|
|
183
|
+
"capacity_recovery_report", "hybrid_placement_report",
|
|
184
|
+
# Is it healthy, and is it what we shipped?
|
|
185
|
+
"doctor", "verify_self",
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def primary_api() -> "list[tuple[str, str]]":
|
|
190
|
+
"""The product's main surface, with the first line of each docstring.
|
|
191
|
+
|
|
192
|
+
Written for a person opening this package for the first time and for the
|
|
193
|
+
docs build — not as a substitute for `__all__`, which remains the complete
|
|
194
|
+
public API.
|
|
195
|
+
"""
|
|
196
|
+
out = []
|
|
197
|
+
for name in PRIMARY_API:
|
|
198
|
+
obj = globals().get(name)
|
|
199
|
+
doc = (getattr(obj, "__doc__", "") or "").strip().split("\n")[0]
|
|
200
|
+
out.append((name, doc))
|
|
201
|
+
return out
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
__all__ = [
|
|
205
|
+
"PRIMARY_API",
|
|
206
|
+
"primary_api",
|
|
207
|
+
# Core
|
|
208
|
+
"cache",
|
|
209
|
+
"no_optimize",
|
|
210
|
+
"lineage",
|
|
211
|
+
"tenant_scope",
|
|
212
|
+
"set_compression_max_reduction",
|
|
213
|
+
"set_fidelity_circuit_breaker",
|
|
214
|
+
"compression_breaker_state",
|
|
215
|
+
"set_event_preview_policy",
|
|
216
|
+
"set_runtime_guards",
|
|
217
|
+
"enterprise_defaults",
|
|
218
|
+
"cache_stream",
|
|
219
|
+
"savings_report",
|
|
220
|
+
"capacity_report",
|
|
221
|
+
# Identity binding (v0.14 keystone)
|
|
222
|
+
"set_principal",
|
|
223
|
+
"get_principal",
|
|
224
|
+
"principal",
|
|
225
|
+
"set_endpoint",
|
|
226
|
+
"get_endpoint",
|
|
227
|
+
"endpoint",
|
|
228
|
+
"task",
|
|
229
|
+
"bind_task",
|
|
230
|
+
"RuleSet",
|
|
231
|
+
"Rule",
|
|
232
|
+
"Condition",
|
|
233
|
+
"RulePolicyError",
|
|
234
|
+
"load_rules",
|
|
235
|
+
"load_rules_file",
|
|
236
|
+
"set_rules",
|
|
237
|
+
"get_rules",
|
|
238
|
+
"clear_rules",
|
|
239
|
+
"rules_version",
|
|
240
|
+
"set_env",
|
|
241
|
+
"current_env",
|
|
242
|
+
"data_class",
|
|
243
|
+
"set_data_class",
|
|
244
|
+
"current_data_class",
|
|
245
|
+
"region",
|
|
246
|
+
"set_region",
|
|
247
|
+
"current_region",
|
|
248
|
+
"PolicyViolation",
|
|
249
|
+
"ModelNotPermitted",
|
|
250
|
+
"EndpointNotPermitted",
|
|
251
|
+
"resolve_compliance",
|
|
252
|
+
"STARTER_POLICIES",
|
|
253
|
+
"starter_policy",
|
|
254
|
+
"list_starter_policies",
|
|
255
|
+
"policy_report",
|
|
256
|
+
"HaltEvent",
|
|
257
|
+
"on_halt",
|
|
258
|
+
"remove_halt_handler",
|
|
259
|
+
"clear_halt_handlers",
|
|
260
|
+
"halt_handler_count",
|
|
261
|
+
"simulate_rules",
|
|
262
|
+
"plan_report",
|
|
263
|
+
"coverage_report",
|
|
264
|
+
"render_plan",
|
|
265
|
+
"agent_report",
|
|
266
|
+
"render_agents",
|
|
267
|
+
"compare_reports",
|
|
268
|
+
"render_comparison",
|
|
269
|
+
"suggest_thresholds",
|
|
270
|
+
"render_suggestions",
|
|
271
|
+
"render_agents_html",
|
|
272
|
+
"write_agents_html",
|
|
273
|
+
"wrap_langchain_llm",
|
|
274
|
+
"wrap_llamaindex_llm",
|
|
275
|
+
"set_task",
|
|
276
|
+
"get_task",
|
|
277
|
+
"current_task_id",
|
|
278
|
+
"current_agent",
|
|
279
|
+
"task_snapshot",
|
|
280
|
+
"TaskLimitExceeded",
|
|
281
|
+
"TaskEnvelopeExceeded",
|
|
282
|
+
"TaskLoopDetected",
|
|
283
|
+
"TaskStalled",
|
|
284
|
+
"TaskCallLimitExceeded",
|
|
285
|
+
"set_queue_wait_ms",
|
|
286
|
+
# Budget-Enforced Keys (T3.3)
|
|
287
|
+
"register_key",
|
|
288
|
+
"unregister_key",
|
|
289
|
+
"clear_keys",
|
|
290
|
+
"key",
|
|
291
|
+
"key_status",
|
|
292
|
+
"leak_scan",
|
|
293
|
+
"get_current_key",
|
|
294
|
+
"KeyBudgetExceeded",
|
|
295
|
+
"context_passport",
|
|
296
|
+
"savings_ledger_health",
|
|
297
|
+
# Pricing registry (v0.13) — anti-fabrication layer
|
|
298
|
+
"register_pricing",
|
|
299
|
+
"unregister_pricing",
|
|
300
|
+
"clear_registered_pricing",
|
|
301
|
+
"registered_pricing",
|
|
302
|
+
"pricing_info",
|
|
303
|
+
"estimate_cost_with_source",
|
|
304
|
+
"derive_selfhost_rate",
|
|
305
|
+
"register_selfhost_pricing",
|
|
306
|
+
"register_cluster_costs",
|
|
307
|
+
"derive_cluster_gpu_hour_rate",
|
|
308
|
+
"capacity_recovery_report",
|
|
309
|
+
"chargeback_report",
|
|
310
|
+
"chargeback_csv",
|
|
311
|
+
"hybrid_placement_report",
|
|
312
|
+
"hybrid_placement_csv",
|
|
313
|
+
"close_packet",
|
|
314
|
+
"general_ledger_rows",
|
|
315
|
+
"general_ledger_csv",
|
|
316
|
+
"capacity_reclaimed",
|
|
317
|
+
"set_home",
|
|
318
|
+
"set_savings_path",
|
|
319
|
+
"set_buffered_savings",
|
|
320
|
+
"set_in_memory_savings",
|
|
321
|
+
"flush_savings",
|
|
322
|
+
"doctor",
|
|
323
|
+
"reset_savings",
|
|
324
|
+
"clear_cache",
|
|
325
|
+
# Configuration
|
|
326
|
+
"set_default_store",
|
|
327
|
+
"set_default_semantic_cache",
|
|
328
|
+
"set_default_redactor",
|
|
329
|
+
# Storage
|
|
330
|
+
"MemoryStore",
|
|
331
|
+
"SQLiteStore",
|
|
332
|
+
"SemanticCache",
|
|
333
|
+
"semantic_available",
|
|
334
|
+
"is_vec_index_available",
|
|
335
|
+
# Trust + ops layer
|
|
336
|
+
"events",
|
|
337
|
+
"privacy",
|
|
338
|
+
"admin",
|
|
339
|
+
"metrics",
|
|
340
|
+
"warmup",
|
|
341
|
+
"compression",
|
|
342
|
+
"memory",
|
|
343
|
+
"audit",
|
|
344
|
+
"integrity",
|
|
345
|
+
"verify_self",
|
|
346
|
+
"scan_environment",
|
|
347
|
+
"self_check",
|
|
348
|
+
"backends",
|
|
349
|
+
"RedisStore",
|
|
350
|
+
"FernetCipher",
|
|
351
|
+
"NoOpCipher",
|
|
352
|
+
"DefaultRedactor",
|
|
353
|
+
"default_redactor",
|
|
354
|
+
"redact",
|
|
355
|
+
"PrometheusCollector",
|
|
356
|
+
# Compression (v0.6)
|
|
357
|
+
"Compressor",
|
|
358
|
+
"CompressionResult",
|
|
359
|
+
"StructuralCompressor",
|
|
360
|
+
"LLMLinguaCompressor",
|
|
361
|
+
"SalienceCompressor",
|
|
362
|
+
"SafeCompressor",
|
|
363
|
+
"compression_stats",
|
|
364
|
+
"reset_compression_stats",
|
|
365
|
+
"Router",
|
|
366
|
+
"RouteDecision",
|
|
367
|
+
"Cascade",
|
|
368
|
+
"CascadeResult",
|
|
369
|
+
"CacheOptimizer",
|
|
370
|
+
"CacheReport",
|
|
371
|
+
"VolatileFinding",
|
|
372
|
+
"compress_tools",
|
|
373
|
+
"compose",
|
|
374
|
+
"safe_compress",
|
|
375
|
+
"compression_verification_log",
|
|
376
|
+
# Memory (v0.7)
|
|
377
|
+
"with_memory",
|
|
378
|
+
"ConversationMemory",
|
|
379
|
+
"Turn",
|
|
380
|
+
"Summarizer",
|
|
381
|
+
"TruncationSummarizer",
|
|
382
|
+
"CallableSummarizer",
|
|
383
|
+
"InMemoryMemoryStore",
|
|
384
|
+
"SQLiteMemoryStore",
|
|
385
|
+
"memory_fidelity_log",
|
|
386
|
+
# Envelope (advanced)
|
|
387
|
+
"wrap",
|
|
388
|
+
"unwrap",
|
|
389
|
+
"prompt_ir",
|
|
390
|
+
"SecurityPolicy",
|
|
391
|
+
"SecurityPolicyError",
|
|
392
|
+
"set_security_policy",
|
|
393
|
+
"get_security_policy",
|
|
394
|
+
"reset_security_policy",
|
|
395
|
+
"DecisionRecord",
|
|
396
|
+
"on_decision",
|
|
397
|
+
"remove_decision_subscriber",
|
|
398
|
+
"clear_decision_subscribers",
|
|
399
|
+
]
|
|
400
|
+
|
|
401
|
+
# ---------------------------------------------------------------------------
|
|
402
|
+
# Tokeymeter public product surface (the curated facade). Re-exported here so
|
|
403
|
+
# `from tokeymeter import meter, report, ...` works. Implemented in _api.py to
|
|
404
|
+
# keep this module focused on the engine's symbol table. The facade's
|
|
405
|
+
# compress_tools/no_optimize intentionally rebind the engine names above to the
|
|
406
|
+
# product-facing wrappers.
|
|
407
|
+
# ---------------------------------------------------------------------------
|
|
408
|
+
from ._api import ( # noqa: E402
|
|
409
|
+
meter,
|
|
410
|
+
report,
|
|
411
|
+
reset,
|
|
412
|
+
doctor,
|
|
413
|
+
compressor,
|
|
414
|
+
router,
|
|
415
|
+
metered_route,
|
|
416
|
+
cascade,
|
|
417
|
+
optimize_cache,
|
|
418
|
+
check_cache,
|
|
419
|
+
compress_tools,
|
|
420
|
+
no_optimize,
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
__all__ += [
|
|
424
|
+
"meter",
|
|
425
|
+
"report",
|
|
426
|
+
"reset",
|
|
427
|
+
"compressor",
|
|
428
|
+
"router",
|
|
429
|
+
"metered_route",
|
|
430
|
+
"cascade",
|
|
431
|
+
"optimize_cache",
|
|
432
|
+
"check_cache",
|
|
433
|
+
]
|
|
434
|
+
|
|
435
|
+
# K4 (W3): the one-line Runtime facade — `Runtime(client=...).execute(prompt)`.
|
|
436
|
+
from .runtime.facade import Runtime, RuntimeConfigurationError # noqa: E402
|
tokeymeter/__main__.py
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tokeymeter command-line entry point.
|
|
3
|
+
|
|
4
|
+
tokeymeter firstrun # 60 seconds: watch a stuck agent stop
|
|
5
|
+
tokeymeter watch # see tasks as they run, live
|
|
6
|
+
tokeymeter agents # how your agents behave: cost per task,
|
|
7
|
+
# progress, and which ones stalled
|
|
8
|
+
tokeymeter plan --policy FILE # what an execution policy WOULD do,
|
|
9
|
+
# replayed against your own history
|
|
10
|
+
tokeymeter doctor # verdict + overhead p50/p95/p99 + ledger health
|
|
11
|
+
tokeymeter report --demo # savings report (no keys)
|
|
12
|
+
tokeymeter report --provider openai # against your real OPENAI_API_KEY
|
|
13
|
+
tokeymeter demo # self-hosted walkthrough (offline, no keys)
|
|
14
|
+
tokeymeter pricing # list-table age + registered overrides
|
|
15
|
+
tokeymeter version
|
|
16
|
+
|
|
17
|
+
`python -m tokeymeter ...` and the installed `tokeymeter` script both land here.
|
|
18
|
+
"""
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import sys
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _make_console_resilient() -> None:
|
|
25
|
+
"""Ensure CLI output can never crash on a legacy console code page.
|
|
26
|
+
|
|
27
|
+
Windows consoles still default to cp1252 in many environments, and a single
|
|
28
|
+
non-ASCII character in an otherwise fine report (an arrow, a middle dot)
|
|
29
|
+
raises UnicodeEncodeError and takes the whole command down. `tokeymeter
|
|
30
|
+
demo` did exactly that on '\\u2192'.
|
|
31
|
+
|
|
32
|
+
We keep the stream's own encoding — rewriting it to UTF-8 would emit bytes a
|
|
33
|
+
cp1252 console renders as mojibake — and only switch the error handler to
|
|
34
|
+
'replace'. On a UTF-8 terminal output is unchanged; on a legacy one an
|
|
35
|
+
unrepresentable glyph degrades to '?' instead of aborting the command.
|
|
36
|
+
A diagnostic tool that dies while printing diagnostics is worse than one
|
|
37
|
+
that prints an imperfect character."""
|
|
38
|
+
for stream in (sys.stdout, sys.stderr):
|
|
39
|
+
reconfigure = getattr(stream, "reconfigure", None)
|
|
40
|
+
if reconfigure is None: # not a TextIOWrapper (piped/captured)
|
|
41
|
+
continue
|
|
42
|
+
try:
|
|
43
|
+
reconfigure(errors="replace")
|
|
44
|
+
except Exception:
|
|
45
|
+
# Console setup must never be the reason a command fails.
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _print_doctor() -> None:
|
|
50
|
+
"""Render tokeymeter.doctor() — one-line verdict first, then cache-hit
|
|
51
|
+
overhead percentiles, savings mode, ledger health, degraded counts."""
|
|
52
|
+
import json
|
|
53
|
+
import tokeymeter
|
|
54
|
+
d = tokeymeter.doctor()
|
|
55
|
+
oh = d["cache_hit_overhead"]
|
|
56
|
+
h = d["ledger_health"]
|
|
57
|
+
|
|
58
|
+
def ms(v):
|
|
59
|
+
return "n/a" if v is None else f"{v}ms"
|
|
60
|
+
|
|
61
|
+
degraded = bool(h.get("degraded")) or (d.get("degraded_events", 0) or 0) > 0
|
|
62
|
+
if degraded:
|
|
63
|
+
why = []
|
|
64
|
+
if h.get("degraded"):
|
|
65
|
+
why.append("ledger degraded")
|
|
66
|
+
if (d.get("degraded_events", 0) or 0) > 0:
|
|
67
|
+
why.append(f"{d['degraded_events']} degraded event(s)")
|
|
68
|
+
verdict = "DEGRADED — " + ", ".join(why)
|
|
69
|
+
else:
|
|
70
|
+
verdict = "HEALTHY"
|
|
71
|
+
|
|
72
|
+
print(f"tokeymeter doctor | {verdict}")
|
|
73
|
+
print(" cache-hit overhead: "
|
|
74
|
+
f"p50={ms(oh['p50_ms'])} p95={ms(oh['p95_ms'])} "
|
|
75
|
+
f"p99={ms(oh['p99_ms'])} (n={oh['samples']})")
|
|
76
|
+
print(f" savings mode: {d['savings_mode']}")
|
|
77
|
+
print(f" ledger: writable={h['writable']} degraded={h['degraded']} "
|
|
78
|
+
f"records={h['records_written']} write_failures={h['write_failures']}")
|
|
79
|
+
print(f" degraded events: {d['degraded_events']} by_source={d['degraded_by_source']}")
|
|
80
|
+
# machine-readable line for scripting (kept stable)
|
|
81
|
+
print(json.dumps(d))
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def main(argv=None) -> None:
|
|
85
|
+
_make_console_resilient()
|
|
86
|
+
argv = list(sys.argv[1:] if argv is None else argv)
|
|
87
|
+
if not argv or argv[0] in ("-h", "--help", "help"):
|
|
88
|
+
print(__doc__.strip())
|
|
89
|
+
return
|
|
90
|
+
cmd, rest = argv[0], argv[1:]
|
|
91
|
+
if cmd == "report":
|
|
92
|
+
from tokeymeter import reporting
|
|
93
|
+
sys.argv = ["tokeymeter report", *rest]
|
|
94
|
+
reporting.main()
|
|
95
|
+
elif cmd == "doctor":
|
|
96
|
+
_print_doctor()
|
|
97
|
+
elif cmd == "pricing":
|
|
98
|
+
from tokeymeter import pricing as _pr
|
|
99
|
+
age = _pr.pricing_age_days()
|
|
100
|
+
stale = age > 45
|
|
101
|
+
print(f"tokeymeter pricing | list table as of {_pr.PRICING_AS_OF} "
|
|
102
|
+
f"({age}d old){' | STALE - refresh recommended' if stale else ''}")
|
|
103
|
+
reg = _pr.registered_pricing()
|
|
104
|
+
if reg:
|
|
105
|
+
print(f" registered overrides ({len(reg)}):")
|
|
106
|
+
for m, e in sorted(reg.items()):
|
|
107
|
+
print(f" {m:<28} in=${e['input']:.4f}/1M out=${e['output']:.4f}/1M")
|
|
108
|
+
else:
|
|
109
|
+
print(" registered overrides: none")
|
|
110
|
+
print(" note: registered rates always take precedence over the list table.")
|
|
111
|
+
elif cmd == "firstrun":
|
|
112
|
+
from tokeymeter import firstrun as _firstrun
|
|
113
|
+
sys.exit(_firstrun.main(rest))
|
|
114
|
+
elif cmd == "watch":
|
|
115
|
+
from tokeymeter import watch as _watch
|
|
116
|
+
sys.exit(_watch.main(rest))
|
|
117
|
+
elif cmd == "agents":
|
|
118
|
+
from tokeymeter.engines.governance import agents as _agents
|
|
119
|
+
sys.exit(_agents.main(rest))
|
|
120
|
+
elif cmd == "plan":
|
|
121
|
+
from tokeymeter.engines.governance import plan as _plan
|
|
122
|
+
sys.exit(_plan.main(rest))
|
|
123
|
+
elif cmd == "demo":
|
|
124
|
+
from tokeymeter import demo
|
|
125
|
+
sys.exit(demo.run())
|
|
126
|
+
elif cmd in ("version", "--version", "-V"):
|
|
127
|
+
import tokeymeter
|
|
128
|
+
print("tokeymeter", getattr(tokeymeter, "__version__", "unknown"))
|
|
129
|
+
else:
|
|
130
|
+
print(f"unknown command: {cmd}\n")
|
|
131
|
+
print(__doc__.strip())
|
|
132
|
+
sys.exit(2)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
if __name__ == "__main__":
|
|
136
|
+
main()
|