tokenjam 0.2.0__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.
- tokenjam/__init__.py +1 -0
- tokenjam/api/__init__.py +0 -0
- tokenjam/api/app.py +104 -0
- tokenjam/api/deps.py +18 -0
- tokenjam/api/middleware.py +28 -0
- tokenjam/api/routes/__init__.py +0 -0
- tokenjam/api/routes/agents.py +33 -0
- tokenjam/api/routes/alerts.py +77 -0
- tokenjam/api/routes/budget.py +96 -0
- tokenjam/api/routes/cost.py +43 -0
- tokenjam/api/routes/drift.py +63 -0
- tokenjam/api/routes/logs.py +511 -0
- tokenjam/api/routes/metrics.py +81 -0
- tokenjam/api/routes/otlp.py +63 -0
- tokenjam/api/routes/spans.py +202 -0
- tokenjam/api/routes/status.py +84 -0
- tokenjam/api/routes/tools.py +22 -0
- tokenjam/api/routes/traces.py +92 -0
- tokenjam/cli/__init__.py +0 -0
- tokenjam/cli/cmd_alerts.py +94 -0
- tokenjam/cli/cmd_budget.py +119 -0
- tokenjam/cli/cmd_cost.py +90 -0
- tokenjam/cli/cmd_demo.py +82 -0
- tokenjam/cli/cmd_doctor.py +173 -0
- tokenjam/cli/cmd_drift.py +238 -0
- tokenjam/cli/cmd_export.py +200 -0
- tokenjam/cli/cmd_mcp.py +78 -0
- tokenjam/cli/cmd_onboard.py +779 -0
- tokenjam/cli/cmd_serve.py +85 -0
- tokenjam/cli/cmd_status.py +153 -0
- tokenjam/cli/cmd_stop.py +87 -0
- tokenjam/cli/cmd_tools.py +45 -0
- tokenjam/cli/cmd_traces.py +161 -0
- tokenjam/cli/cmd_uninstall.py +159 -0
- tokenjam/cli/main.py +110 -0
- tokenjam/core/__init__.py +0 -0
- tokenjam/core/alerts.py +619 -0
- tokenjam/core/api_backend.py +235 -0
- tokenjam/core/config.py +360 -0
- tokenjam/core/cost.py +102 -0
- tokenjam/core/db.py +718 -0
- tokenjam/core/drift.py +256 -0
- tokenjam/core/ingest.py +265 -0
- tokenjam/core/models.py +225 -0
- tokenjam/core/pricing.py +54 -0
- tokenjam/core/retention.py +21 -0
- tokenjam/core/schema_validator.py +156 -0
- tokenjam/demo/__init__.py +0 -0
- tokenjam/demo/env.py +96 -0
- tokenjam/mcp/__init__.py +0 -0
- tokenjam/mcp/server.py +1067 -0
- tokenjam/otel/__init__.py +0 -0
- tokenjam/otel/exporters.py +26 -0
- tokenjam/otel/provider.py +207 -0
- tokenjam/otel/semconv.py +144 -0
- tokenjam/pricing/models.toml +70 -0
- tokenjam/py.typed +0 -0
- tokenjam/sdk/__init__.py +21 -0
- tokenjam/sdk/agent.py +206 -0
- tokenjam/sdk/bootstrap.py +120 -0
- tokenjam/sdk/http_exporter.py +109 -0
- tokenjam/sdk/integrations/__init__.py +0 -0
- tokenjam/sdk/integrations/anthropic.py +200 -0
- tokenjam/sdk/integrations/autogen.py +97 -0
- tokenjam/sdk/integrations/base.py +27 -0
- tokenjam/sdk/integrations/bedrock.py +103 -0
- tokenjam/sdk/integrations/crewai.py +96 -0
- tokenjam/sdk/integrations/gemini.py +131 -0
- tokenjam/sdk/integrations/langchain.py +156 -0
- tokenjam/sdk/integrations/langgraph.py +101 -0
- tokenjam/sdk/integrations/litellm.py +323 -0
- tokenjam/sdk/integrations/llamaindex.py +52 -0
- tokenjam/sdk/integrations/nemoclaw.py +139 -0
- tokenjam/sdk/integrations/openai.py +159 -0
- tokenjam/sdk/integrations/openai_agents_sdk.py +47 -0
- tokenjam/sdk/transport.py +98 -0
- tokenjam/ui/index.html +1213 -0
- tokenjam/utils/__init__.py +0 -0
- tokenjam/utils/formatting.py +43 -0
- tokenjam/utils/ids.py +15 -0
- tokenjam/utils/time_parse.py +54 -0
- tokenjam-0.2.0.dist-info/METADATA +622 -0
- tokenjam-0.2.0.dist-info/RECORD +86 -0
- tokenjam-0.2.0.dist-info/WHEEL +4 -0
- tokenjam-0.2.0.dist-info/entry_points.txt +2 -0
- tokenjam-0.2.0.dist-info/licenses/LICENSE +21 -0
|
File without changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from rich.console import Console
|
|
2
|
+
from rich.table import Table
|
|
3
|
+
from rich import box
|
|
4
|
+
|
|
5
|
+
console = Console()
|
|
6
|
+
err_console = Console(stderr=True)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def severity_colour(severity: str) -> str:
|
|
10
|
+
return {"critical": "red", "warning": "yellow", "info": "blue"}.get(severity, "white")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def status_icon(status: str) -> str:
|
|
14
|
+
return {
|
|
15
|
+
"ok": "\u2713",
|
|
16
|
+
"error": "\u2717",
|
|
17
|
+
"active": "\u25cf",
|
|
18
|
+
"idle": "\u25cb",
|
|
19
|
+
"completed": "\u25cf",
|
|
20
|
+
"stale": "\u25cb",
|
|
21
|
+
}.get(status, "?")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def format_cost(usd: float) -> str:
|
|
25
|
+
if usd < 0.001:
|
|
26
|
+
return f"${usd:.6f}"
|
|
27
|
+
return f"${usd:.4f}"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def format_tokens(n: int) -> str:
|
|
31
|
+
if n >= 1_000_000:
|
|
32
|
+
return f"{n/1_000_000:.1f}M"
|
|
33
|
+
if n >= 1_000:
|
|
34
|
+
return f"{n/1_000:.1f}k"
|
|
35
|
+
return str(n)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def make_table(*headers: str, box_style=box.SIMPLE) -> Table:
|
|
39
|
+
"""Create a pre-styled Rich table."""
|
|
40
|
+
t = Table(box=box_style, show_header=True, header_style="bold dim")
|
|
41
|
+
for h in headers:
|
|
42
|
+
t.add_column(h)
|
|
43
|
+
return t
|
tokenjam/utils/ids.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def new_uuid() -> str:
|
|
5
|
+
return str(uuid.uuid4())
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def new_trace_id() -> str:
|
|
9
|
+
"""Generate a 32-char hex trace ID (OTel format)."""
|
|
10
|
+
return uuid.uuid4().hex
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def new_span_id() -> str:
|
|
14
|
+
"""Generate a 16-char hex span ID (OTel format)."""
|
|
15
|
+
return uuid.uuid4().hex[:16]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from datetime import datetime, timedelta, timezone
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
_RELATIVE_PATTERN = re.compile(r"^(\d+)([mhd])$")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def parse_since(value: str) -> datetime:
|
|
9
|
+
"""
|
|
10
|
+
Parse a --since value and return the corresponding UTC datetime.
|
|
11
|
+
Raises ValueError with a descriptive message for unrecognised formats.
|
|
12
|
+
|
|
13
|
+
Supported formats:
|
|
14
|
+
- 30m, 1h, 12h, 1d, 7d (relative)
|
|
15
|
+
- 2026-03-01 (date, treated as start of day UTC)
|
|
16
|
+
- 2026-03-01T10:00:00Z (ISO datetime)
|
|
17
|
+
"""
|
|
18
|
+
value = value.strip()
|
|
19
|
+
|
|
20
|
+
match = _RELATIVE_PATTERN.match(value)
|
|
21
|
+
if match:
|
|
22
|
+
amount = int(match.group(1))
|
|
23
|
+
unit = match.group(2)
|
|
24
|
+
if amount == 0:
|
|
25
|
+
raise ValueError(f"Invalid --since value: {value!r} (amount must be > 0)")
|
|
26
|
+
delta_map = {"m": "minutes", "h": "hours", "d": "days"}
|
|
27
|
+
delta = timedelta(**{delta_map[unit]: amount})
|
|
28
|
+
return utcnow() - delta
|
|
29
|
+
|
|
30
|
+
# Try ISO datetime with timezone
|
|
31
|
+
try:
|
|
32
|
+
dt = datetime.fromisoformat(value)
|
|
33
|
+
if dt.tzinfo is None:
|
|
34
|
+
dt = dt.replace(tzinfo=timezone.utc)
|
|
35
|
+
return dt
|
|
36
|
+
except ValueError:
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
# Try date-only format
|
|
40
|
+
try:
|
|
41
|
+
dt = datetime.strptime(value, "%Y-%m-%d")
|
|
42
|
+
return dt.replace(tzinfo=timezone.utc)
|
|
43
|
+
except ValueError:
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
raise ValueError(
|
|
47
|
+
f"Unrecognised --since format: {value!r}. "
|
|
48
|
+
f"Expected: 30m, 1h, 7d, 2026-03-01, or 2026-03-01T10:00:00Z"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def utcnow() -> datetime:
|
|
53
|
+
"""Return current UTC time, timezone-aware."""
|
|
54
|
+
return datetime.now(tz=timezone.utc)
|