mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 20:47:03 +01:00
- Subagents that outlived /clear land in a new session's subagents/ dir with no meta: borrow the spawning session's agent-<id>.meta.json, else the first prompt line. Clears the $35.93 '?' row; no launch lacked a description. - bash_tokens_per_call rose 41% with Bash tokens/day flat (cheap calls fell 28%). Compare bash_tokens_per_day and bash_big_result_share (results >2k) instead; the Large-Bash lever keys on the share. Tool counters grouped in ToolPayloads. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TjyHmRrjZssaxXDWcGuCeQ
128 lines
4.8 KiB
Python
128 lines
4.8 KiB
Python
"""Find transcript files and read the per-file metadata around them.
|
|
|
|
Two layouts hold billed turns:
|
|
|
|
* ``<root>/<project-slug>/<session-id>.jsonl`` -- the main conversation.
|
|
* ``<root>/<project-slug>/<session-id>/subagents/agent-<id>.jsonl`` -- one per
|
|
``Agent`` call, with a sibling ``agent-<id>.meta.json`` naming the agentType
|
|
and description. Before 2026-10-04 the audit globbed only the first layout
|
|
and reported subagents at 0.0% while they were 35% of real spend.
|
|
|
|
A background agent outlives ``/clear``: the rest of its transcript lands in the
|
|
*new* session's ``subagents/`` under the same ``agent-<id>`` name, starting
|
|
mid-conversation and with no ``.meta.json`` (or one without a description).
|
|
:func:`agent_meta` borrows the label from the spawning session's copy; on
|
|
2026-10-10 that was all 14 unlabelled files, 5.2% of a week's spend.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import re
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
if TYPE_CHECKING:
|
|
from pathlib import Path
|
|
|
|
PATTERNS: tuple[str, ...] = ("*/*.jsonl", "*/*/subagents/agent-*.jsonl")
|
|
|
|
# Harness-injected ``<tag>...</tag>`` blocks (``<fork-boilerplate>``,
|
|
# ``<system-reminder>``): identical across agents, so never a useful label.
|
|
WRAPPER = re.compile(r"<([\w-]+)[^>]*>.*?</\1>", re.DOTALL)
|
|
|
|
|
|
def find_transcripts(root: Path, since: float) -> list[Path]:
|
|
"""Return transcripts that may hold records after ``since``, newest first.
|
|
|
|
A file last written before ``since`` cannot hold an in-window record, so
|
|
mtime prunes those. There is deliberately no mtime upper bound: a file
|
|
still being appended to after the window closed holds in-window records
|
|
too, and the per-record timestamp filter in :func:`parse.iter_events`
|
|
trims whatever falls outside.
|
|
"""
|
|
found: list[tuple[float, Path]] = []
|
|
for pattern in PATTERNS:
|
|
for path in sorted(root.glob(pattern)):
|
|
mtime = path.stat().st_mtime
|
|
if mtime >= since:
|
|
found.append((mtime, path))
|
|
return [path for _, path in sorted(found, reverse=True)]
|
|
|
|
|
|
def _record(line: str) -> dict[str, Any] | None:
|
|
"""Parse one JSON object, or ``None``."""
|
|
try:
|
|
loaded = json.loads(line)
|
|
except ValueError:
|
|
return None
|
|
return loaded if isinstance(loaded, dict) else None
|
|
|
|
|
|
def first_cwd(path: Path) -> str | None:
|
|
"""Return the working directory a transcript was recorded in."""
|
|
with path.open(encoding="utf-8", errors="replace") as handle:
|
|
for line in handle:
|
|
record = _record(line)
|
|
if record is not None:
|
|
cwd = record.get("cwd")
|
|
if isinstance(cwd, str):
|
|
return cwd
|
|
return None
|
|
|
|
|
|
def _meta_file(meta: Path) -> dict[str, Any]:
|
|
"""Read one ``.meta.json``, ``{}`` when missing or unreadable."""
|
|
if not meta.exists():
|
|
return {}
|
|
return _record(meta.read_text(encoding="utf-8", errors="replace")) or {}
|
|
|
|
|
|
def agent_meta(path: Path) -> dict[str, Any]:
|
|
"""Return a subagent transcript's metadata, or ``{}``.
|
|
|
|
The sibling ``.meta.json`` wins; any field it lacks is filled from the same
|
|
agent's meta in another session directory (see the module docstring).
|
|
"""
|
|
own = _meta_file(path.with_suffix(".meta.json"))
|
|
if own.get("description"):
|
|
return own
|
|
projects = path.parents[3]
|
|
for other in sorted(projects.glob(f"*/*/subagents/{path.stem}.meta.json")):
|
|
borrowed = _meta_file(other)
|
|
if borrowed.get("description"):
|
|
return {**borrowed, **{k: v for k, v in own.items() if v}}
|
|
return own
|
|
|
|
|
|
def _prompt_text(record: dict[str, Any]) -> str | None:
|
|
"""The typed text of a ``user`` record, ignoring tool results."""
|
|
if record.get("type") != "user":
|
|
return None
|
|
message = record.get("message")
|
|
content = message.get("content") if isinstance(message, dict) else None
|
|
if isinstance(content, str):
|
|
return content
|
|
if isinstance(content, list):
|
|
for block in content:
|
|
if isinstance(block, dict) and block.get("type") == "text":
|
|
return str(block.get("text") or "")
|
|
return None
|
|
|
|
|
|
def first_prompt(path: Path, limit: int = 60) -> str:
|
|
"""First non-blank line of a transcript's first user prompt, truncated.
|
|
|
|
The label of last resort for a subagent nobody described: better than
|
|
``?`` because it names the work, and an empty result means none exists.
|
|
"""
|
|
with path.open(encoding="utf-8", errors="replace") as handle:
|
|
for line in handle:
|
|
record = _record(line)
|
|
text = _prompt_text(record) if record is not None else None
|
|
text = WRAPPER.sub("", text or "")
|
|
lines = [part.strip() for part in text.splitlines()]
|
|
first = next((part for part in lines if part), "")
|
|
if first:
|
|
return first if len(first) <= limit else first[: limit - 1] + "…"
|
|
return ""
|