Skip to content

Add a task time-profiler: llm/tool/operator-wait gap analysis over transcripts#349

Draft
dkrattiger wants to merge 1 commit into
mainfrom
panopticon/task-time-profiler
Draft

Add a task time-profiler: llm/tool/operator-wait gap analysis over transcripts#349
dkrattiger wants to merge 1 commit into
mainfrom
panopticon/task-time-profiler

Conversation

@dkrattiger

Copy link
Copy Markdown
Contributor

Summary

Answers the operator goal ("profile tasks so I know how long the agent is spending working on various things including waiting on tests, waiting on other calls, vs waiting on the llm to respond") retroactively, with no agent-side instrumentation — pure gap analysis over the timestamps already in every claude session transcript. Plan: plan.md on this task.

  • profiler/ (new, pure/LLM-free package): categories.py is the tool-time category table — one ordered list of matchers (Bash sub-classified by regex into tests/vcs/deps/pty-verify; Read/Write/Edit/Grep/Glob → code-nav; Task/Agent → subagents — one bucket, its sidechain is never walked separately; mcp__* → orchestration; the rest → other-tools) — easy to extend in one place. parse.py's profile_transcripts(paths) -> dict merges same-message.id assistant lines into one turn (claude streams thinking/text/tool_use as separate JSONL lines per block), then classifies every gap: user → assistant is always LLM time; assistant → user is tool time (when the turn has tool_use) or operator wait (when it doesn't — the agent stopped and handed back to the human). AskUserQuestion spans are routed to operator wait, not a tool category, since the turn-flip hooks make that a blocked-on-human wait, not tool execution. A same-session restart (two consecutive user-type lines with no assistant turn between them — e.g. claude's "You were interrupted. Continue." landing right after an abandoned tool_result) is billed to operator wait too, rather than silently vanishing. Multiple session files (restarts/phases) are concatenated by timestamp, with between-session gaps reported as their own bucket. Everything is defensive — malformed/old-format lines are skipped, never crash the parser; unattributed time is surfaced, not hidden.

  • sessionservice/transcripts.py: the transcripts live in a per-task named Docker volume (panopticon-config-<task_id>) that outlives the container — there was no existing host-accessible path to it. task_session_paths reads it via docker run (find/cat, reusing the already-built panopticon-base image), behind an injectable command-runner. It checks the volume exists first — a bare docker run --volume <missing-name> would otherwise silently create an empty one. Local-runner scope only for v1 (remote hosts are a natural follow-up via the same ssh-wrap pattern terminal/attach.py::attach_command already uses).

  • CLI: panopticon profile <task-id-or-slug> — total wall / operator wait / between-sessions / agent-active split by category (counts + totals + top 5 longest individual tool calls). --all-tasks aggregates per-repo totals and medians, e.g. answering "what fraction of tarot agent time is pytest?" in one command.

  • Dashboard: a new P hotkey time-profiles the highlighted task on demand and shows a one-line summary in the detail pane (agent 4.3h: llm 43% tests 19% tools 38% | waited on user 9.2h). Deliberately not automatic (unlike the rest of the detail pane) — it shells out to docker per task, which is too expensive to redo on every arrow-key highlight.

Known limitation / pending

This container has no docker access, so I couldn't run the profiler against real tarot task transcripts myself. Per discussion on the task, I'll add real-data output from 3 completed tarot tasks to this description before merge.

…anscripts

Retroactively answers "where does agent time go" by gap-analyzing claude
session transcripts (no agent-side instrumentation needed): a pure
profiler/ package classifies every tool_use<->tool_result span by
category (tests/vcs/deps/pty-verify/code-nav/subagents/orchestration),
bills user->assistant gaps to LLM time, and assistant->user gaps to
either tool time or operator wait (including AskUserQuestion spans and
same-session restarts). sessionservice/transcripts.py reads a task's
session files out of its per-task docker config volume after the
container is gone. `panopticon profile <task>` / `--all-tasks` surface
it on the CLI; the dashboard's new `P` hotkey shows an on-demand summary
line in the detail pane.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant