A resources timer samples host CPU, RAM, swap and per-session tokens into samples.jsonl; the hub serves them and a Resources view charts them. Committed below the bar on the operator's word 2026-11-12 (no further per-bundle tests, one gate after the merge): the W4 e2e never ran in a real browser. 🎯 Fix: 92 % 💥 Break: 6 % 💸 Cost: 100 % ⏱️ Time: 100 % 🛡️ Security: 100 % 🏆 Score: 86 🚦 Gate: ⛔ break 6 % > 5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
213 lines
13 KiB
Python
213 lines
13 KiB
Python
from __future__ import annotations
|
|
|
|
import ast
|
|
import datetime
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest import mock
|
|
|
|
import hub_support
|
|
import resources as sampler
|
|
|
|
SCRIPT = hub_support.HUB / "client" / "resources.py"
|
|
NOW = 1_800_000_000
|
|
HOUR = 3600
|
|
SESSION, OTHER = "5d88e9aa-0000-4000-8000-000000000001", "f45bf5bb-0000-4000-8000-000000000002"
|
|
OPUS, HAIKU = "claude-opus-5-5", "claude-haiku-4-5"
|
|
|
|
|
|
def iso(ts: float) -> str:
|
|
return datetime.datetime.fromtimestamp(ts, datetime.UTC).isoformat().replace("+00:00", "Z")
|
|
|
|
|
|
def assistant(ts: float, session: str, model: str, ident: str, counts: tuple[int, int, int, int], request: str = "") -> dict:
|
|
usage = dict(zip(("input_tokens", "output_tokens", "cache_read_input_tokens", "cache_creation_input_tokens"), counts, strict=True))
|
|
message = {"id": ident, "type": "message", "role": "assistant", "model": model, "content": [{"type": "text", "text": "ok"}], "usage": {**usage, "service_tier": "standard"}}
|
|
return {"type": "assistant", "sessionId": session, "timestamp": iso(ts), "message": message, **({"requestId": request} if request else {})}
|
|
|
|
|
|
def lines(rows: list[dict]) -> str:
|
|
return "".join(json.dumps(entry) + "\n" for entry in rows)
|
|
|
|
|
|
class TokensCase(unittest.TestCase):
|
|
def setUp(self):
|
|
tmp = tempfile.TemporaryDirectory()
|
|
self.addCleanup(tmp.cleanup)
|
|
base = Path(tmp.name)
|
|
self.projects, self.council, self.state = base / "projects", base / "council", base / "state"
|
|
for folder in (self.projects / "-repo", self.council / "work" / "s1", self.state):
|
|
folder.mkdir(parents=True)
|
|
(self.council / "work" / "s1" / "claim.json").write_text(json.dumps({"office": "work/s1", "session": SESSION, "name": " Skills ", "beat": NOW}), encoding="utf-8")
|
|
self.transcript = self.projects / "-repo" / f"{SESSION}.jsonl"
|
|
|
|
def count(self, now: float = NOW + 120, budget: int = sampler.BUDGET) -> list[dict]:
|
|
return sampler.count_tokens(self.projects, self.council, self.state, now, budget)
|
|
|
|
def offsets(self) -> dict:
|
|
return json.loads((self.state / "offsets.json").read_text(encoding="utf-8"))
|
|
|
|
def written(self) -> list[dict]:
|
|
path = self.state / "tokens.jsonl"
|
|
return [json.loads(line) for line in path.read_text(encoding="utf-8").splitlines()] if path.exists() else []
|
|
|
|
def totals(self) -> dict[tuple[int, str, str], tuple[int, ...]]:
|
|
found: dict[tuple[int, str, str], tuple[int, ...]] = {}
|
|
for entry in self.written():
|
|
key = (entry["t"], entry["agent"], entry["model"])
|
|
before = found.get(key, (0, 0, 0, 0))
|
|
found[key] = tuple(a + b for a, b in zip(before, (entry["input"], entry["output"], entry["cache_read"], entry["cache_write"]), strict=True))
|
|
return found
|
|
|
|
|
|
class TestTokens(TokensCase):
|
|
def test_usage_fields_add_up_per_hour_agent_and_model_and_a_message_split_over_lines_counts_once(self):
|
|
hour = NOW
|
|
rows = [
|
|
{"type": "user", "sessionId": SESSION, "timestamp": iso(NOW + 5), "message": {"role": "user", "content": "x", "usage": {"input_tokens": 999}}},
|
|
assistant(NOW + 10, SESSION, OPUS, "msg_1", (10, 20, 300, 40)),
|
|
assistant(NOW + 10, SESSION, OPUS, "msg_1", (10, 20, 300, 40)),
|
|
assistant(NOW + 20, SESSION, HAIKU, "msg_2", (1, 2, 3, 4)),
|
|
assistant(NOW + 30, SESSION, OPUS, "msg_3", (5, 6, 7, 8)),
|
|
assistant(NOW + 40, SESSION, "<synthetic>", "msg_4", (0, 0, 0, 0)),
|
|
assistant(NOW - HOUR + 10, OTHER, OPUS, "msg_5", (100, 200, 0, 0)),
|
|
]
|
|
self.transcript.write_text(lines(rows) + "{not json\n", encoding="utf-8")
|
|
added = self.count()
|
|
self.assertEqual(sorted((entry["t"], entry["agent"], entry["model"]) for entry in added), sorted(self.totals()))
|
|
self.assertEqual(self.totals(), {
|
|
(hour, "Skills", OPUS): (15, 26, 307, 48),
|
|
(hour, "Skills", HAIKU): (1, 2, 3, 4),
|
|
(hour - HOUR, OTHER[:8], OPUS): (100, 200, 0, 0),
|
|
})
|
|
self.assertEqual(sorted(self.written()[0]), ["agent", "cache_read", "cache_write", "input", "model", "output", "t"])
|
|
|
|
def test_a_second_run_adds_only_the_bytes_after_the_last_offset(self):
|
|
hour = NOW
|
|
self.transcript.write_text(lines([assistant(NOW + 10, SESSION, OPUS, "msg_1", (10, 20, 30, 40))]), encoding="utf-8")
|
|
self.count()
|
|
self.assertEqual(self.offsets()["files"], {f"-repo/{SESSION}.jsonl": self.transcript.stat().st_size})
|
|
self.assertEqual(self.count(), [])
|
|
last = json.dumps(assistant(NOW + 50, SESSION, OPUS, "msg_3", (7, 7, 7, 7)))
|
|
more = [assistant(NOW + 10, SESSION, OPUS, "msg_1", (10, 20, 30, 40)), assistant(NOW + 40, SESSION, OPUS, "msg_2", (1, 1, 1, 1))]
|
|
with self.transcript.open("a", encoding="utf-8") as handle:
|
|
handle.write(lines(more) + last[:40])
|
|
self.count()
|
|
self.assertEqual(self.totals(), {(hour, "Skills", OPUS): (11, 21, 31, 41)})
|
|
with self.transcript.open("a", encoding="utf-8") as handle:
|
|
handle.write(last[40:] + "\n")
|
|
self.count()
|
|
self.assertEqual(self.totals(), {(hour, "Skills", OPUS): (18, 28, 38, 48)})
|
|
self.assertEqual(self.offsets()["files"][f"-repo/{SESSION}.jsonl"], self.transcript.stat().st_size)
|
|
|
|
def test_a_byte_budget_spreads_a_long_backlog_over_runs_without_losing_tokens(self):
|
|
rows = [assistant(NOW + index, SESSION, OPUS, f"msg_{index}", (1, 0, 0, 0)) for index in range(40)]
|
|
self.transcript.write_text(lines(rows), encoding="utf-8")
|
|
line = len(lines(rows[:1]))
|
|
self.count(budget=10 * line)
|
|
self.assertEqual(sum(entry["input"] for entry in self.written()), 10)
|
|
for _ in range(3):
|
|
self.count(budget=10 * line)
|
|
self.assertEqual(sum(entry["input"] for entry in self.written()), 40)
|
|
|
|
def test_a_shrunk_file_restarts_at_zero_a_vanished_one_leaves_the_offsets_and_an_old_one_starts_at_its_end(self):
|
|
self.transcript.write_text(lines([assistant(NOW - 40, SESSION, OPUS, "msg_1", (5, 0, 0, 0)), assistant(NOW - 30, SESSION, OPUS, "msg_2", (5, 0, 0, 0))]), encoding="utf-8")
|
|
old = self.projects / "-repo" / f"{OTHER}.jsonl"
|
|
old.write_text(lines([assistant(NOW - 100 * 86400, OTHER, OPUS, "msg_9", (9, 0, 0, 0))]), encoding="utf-8")
|
|
os.utime(old, (NOW - 100 * 86400, NOW - 100 * 86400))
|
|
self.count()
|
|
self.assertEqual(sum(entry["input"] for entry in self.written()), 10)
|
|
self.transcript.write_text(lines([assistant(NOW - 20, SESSION, OPUS, "msg_7", (1, 0, 0, 0))]), encoding="utf-8")
|
|
old.unlink()
|
|
self.count()
|
|
self.assertEqual(sum(entry["input"] for entry in self.written()), 11)
|
|
self.assertEqual(sorted(self.offsets()["files"]), [f"-repo/{SESSION}.jsonl"])
|
|
|
|
def test_a_message_that_fork_transcripts_copy_counts_once_across_files_and_runs(self):
|
|
shared = assistant(NOW + 10, SESSION, OPUS, "msg_1", (10, 20, 30, 40), "req_1")
|
|
subagents = self.projects / "-repo" / SESSION / "subagents"
|
|
subagents.mkdir(parents=True)
|
|
self.transcript.write_text(lines([shared]), encoding="utf-8")
|
|
(subagents / "agent-a.jsonl").write_text(lines([{**shared, "timestamp": iso(NOW + 40)}, assistant(NOW + 50, SESSION, OPUS, "msg_2", (1, 1, 1, 1), "req_2")]), encoding="utf-8")
|
|
self.count()
|
|
self.assertEqual(self.totals(), {(NOW, "Skills", OPUS): (11, 21, 31, 41)})
|
|
(subagents / "agent-b.jsonl").write_text(lines([shared, assistant(NOW + 60, SESSION, OPUS, "msg_1", (5, 5, 5, 5), "req_9")]), encoding="utf-8")
|
|
self.count(now=NOW + 180)
|
|
self.assertEqual(self.totals(), {(NOW, "Skills", OPUS): (16, 26, 36, 46)})
|
|
|
|
def test_the_seen_messages_keep_the_hours_of_this_run_and_the_last_two_hours(self):
|
|
self.transcript.write_text(lines([assistant(NOW - 5 * HOUR, SESSION, OPUS, "msg_1", (1, 0, 0, 0), "req_1"), assistant(NOW + 10, SESSION, OPUS, "msg_2", (1, 0, 0, 0), "req_2")]), encoding="utf-8")
|
|
self.count()
|
|
self.assertEqual({hour: len(keys) for hour, keys in self.offsets()["seen"].items()}, {str(NOW - 5 * HOUR): 1, str(NOW): 1})
|
|
self.count(now=NOW + HOUR + 120)
|
|
self.assertEqual(sorted(self.offsets()["seen"]), [str(NOW)])
|
|
self.count(now=NOW + 2 * HOUR + 120)
|
|
self.assertEqual(self.offsets()["seen"], {})
|
|
|
|
def test_a_transcript_that_fails_to_read_keeps_its_offset_and_counts_nothing_twice(self):
|
|
old = NOW - 5 * HOUR
|
|
self.transcript.write_text(lines([assistant(old + 10, SESSION, OPUS, "msg_1", (5, 0, 0, 0), "req_1")]), encoding="utf-8")
|
|
self.count()
|
|
end = self.transcript.stat().st_size
|
|
with self.transcript.open("a", encoding="utf-8") as handle:
|
|
handle.write(lines([assistant(old + 20, SESSION, OPUS, "msg_2", (1, 0, 0, 0), "req_2")]))
|
|
with mock.patch.object(sampler, "scan", side_effect=PermissionError("denied")):
|
|
self.assertEqual(self.count(now=NOW + HOUR + 120), [])
|
|
self.assertEqual(self.offsets()["files"], {f"-repo/{SESSION}.jsonl": end})
|
|
self.count(now=NOW + 2 * HOUR + 120)
|
|
self.assertEqual(self.totals(), {(old, "Skills", OPUS): (6, 0, 0, 0)})
|
|
|
|
def test_a_run_without_new_bytes_leaves_offsets_json_unwritten(self):
|
|
self.transcript.write_text(lines([assistant(NOW + 10, SESSION, OPUS, "msg_1", (1, 0, 0, 0), "req_1")]), encoding="utf-8")
|
|
self.count()
|
|
stored = self.offsets()
|
|
with mock.patch.object(sampler, "replace", side_effect=AssertionError("offsets.json rewritten")):
|
|
self.assertEqual(self.count(now=NOW + 180), [])
|
|
self.assertEqual(self.offsets(), stored)
|
|
|
|
def test_the_first_minute_of_an_hour_merges_rows_and_drops_those_older_than_ninety_days(self):
|
|
hour = NOW
|
|
stale = {"t": hour - 91 * 86400, "agent": "Old", "model": OPUS, "input": 1, "output": 1, "cache_read": 1, "cache_write": 1}
|
|
parts = [{"t": hour - HOUR, "agent": "Skills", "model": OPUS, "input": value, "output": 0, "cache_read": 0, "cache_write": 0} for value in (1, 2, 3)]
|
|
(self.state / "tokens.jsonl").write_text(lines([stale, *parts]), encoding="utf-8")
|
|
self.transcript.write_text(lines([assistant(NOW + 10, SESSION, OPUS, "msg_1", (4, 0, 0, 0))]), encoding="utf-8")
|
|
self.count(now=hour + 1800)
|
|
self.assertEqual(len(self.written()), 5)
|
|
self.count(now=hour + 30)
|
|
self.assertEqual(self.written(), [{**parts[0], "input": 6}, {"t": hour, "agent": "Skills", "model": OPUS, "input": 4, "output": 0, "cache_read": 0, "cache_write": 0}])
|
|
|
|
|
|
class TestNoLanguageModel(unittest.TestCase):
|
|
def test_the_sampler_and_the_parser_import_no_network_client(self):
|
|
tree = ast.parse(SCRIPT.read_text(encoding="utf-8"))
|
|
imported = {alias.name.split(".")[0] for node in ast.walk(tree) if isinstance(node, ast.Import) for alias in node.names}
|
|
imported |= {node.module.split(".")[0] for node in ast.walk(tree) if isinstance(node, ast.ImportFrom) and node.module}
|
|
self.assertEqual(imported & {"urllib", "http", "socket", "ssl", "requests", "hub_api", "anthropic", "openai"}, set())
|
|
|
|
|
|
class TestTokensInScratchHome(unittest.TestCase):
|
|
def test_the_tokens_command_reads_the_scratch_home_transcripts_and_writes_beside_the_samples(self):
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
home, council = Path(tmp) / "home", Path(tmp) / "council"
|
|
folder = home / ".claude" / "projects" / "-repo"
|
|
folder.mkdir(parents=True)
|
|
council.mkdir()
|
|
ts = datetime.datetime.now(datetime.UTC).timestamp() - 60
|
|
(folder / f"{SESSION}.jsonl").write_text(lines([assistant(ts, SESSION, OPUS, "msg_1", (3, 4, 5, 6))]), encoding="utf-8")
|
|
state = home / ".local" / "state" / "agents-council" / "resources"
|
|
argv = [sys.executable, str(SCRIPT), "tokens", "--state", str(state), "--council", str(council), "--transcripts", str(home / ".claude" / "projects")]
|
|
done = subprocess.run(argv, env={**os.environ, "HOME": str(home), "PATH": "/usr/bin:/bin"}, capture_output=True, text=True, timeout=60, check=False)
|
|
self.assertEqual(done.returncode, 0, done.stderr)
|
|
self.assertEqual(sorted(path.name for path in state.iterdir()), ["offsets.json", "tokens.jsonl"])
|
|
written = [json.loads(line) for line in (state / "tokens.jsonl").read_text(encoding="utf-8").splitlines()]
|
|
self.assertEqual(written, [{"t": int(ts - ts % HOUR), "agent": SESSION[:8], "model": OPUS, "input": 3, "output": 4, "cache_read": 5, "cache_write": 6}])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|