Add a task time-profiler: llm/tool/operator-wait gap analysis over transcripts#349
Draft
dkrattiger wants to merge 1 commit into
Draft
Add a task time-profiler: llm/tool/operator-wait gap analysis over transcripts#349dkrattiger wants to merge 1 commit into
dkrattiger wants to merge 1 commit into
Conversation
…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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.mdon this task.profiler/(new, pure/LLM-free package):categories.pyis 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'sprofile_transcripts(paths) -> dictmerges same-message.idassistant lines into one turn (claude streams thinking/text/tool_use as separate JSONL lines per block), then classifies every gap:user → assistantis always LLM time;assistant → useris tool time (when the turn hastool_use) or operator wait (when it doesn't — the agent stopped and handed back to the human).AskUserQuestionspans 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 consecutiveuser-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_pathsreads it viadocker run(find/cat, reusing the already-builtpanopticon-baseimage), behind an injectable command-runner. It checks the volume exists first — a baredocker 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 patternterminal/attach.py::attach_commandalready 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-tasksaggregates per-repo totals and medians, e.g. answering "what fraction of tarot agent time is pytest?" in one command.Dashboard: a new
Photkey 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.