Repository navigation
fix(session-summary): make the summary panel work, and stop reporting an empty fold as up to date - #57
Merged
Conversation
…'s real state The panel could not summarize the sessions this reported from, and when it could not it said it was up to date. Both are fixed here, because either alone still leaves a reader with an empty pane and a false assurance. Transcripts the fold could never resolve. `readSessionSummaryTranscriptEvents` resolved a file only through the native-chat resolver, which names Claude/OpenClaude, Codex, Grok, OMP and OpenCode — so a Pi or Copilot session got `null`, the service settled on `unavailable`, and the pane kept the empty state for the life of the install. On the machine this was reported from that is 462 Pi sessions and 16 Copilot ones against 11 OpenCode. Both now resolve: - Pi and Prime Agent post `session_file` on every hook, and `agent-session-resume.ts` only returns their provider session at all when that path exists, so the hook's path *is* the transcript and there is nothing to search for. - Copilot reports no path, but its `session_id` is the name of its session directory, so the file is `$COPILOT_HOME/session-state/<id>/events.jsonl`. The id is shape checked, because joining a hook string onto a root path unchecked is a traversal; a hook path that exists is preferred, and a directory is never mistaken for a transcript. - `COPILOT_SESSIONS_DIR` is exported rather than re-derived, so the AI Vault scanner and this reader cannot drift apart on where Copilot keeps sessions. Everything downstream already worked: `parseAgentSessionFile` dispatches on `candidate.agent`, and both parsers publish into the consumer channel, so the fold needed only a path and a parser name. Agents with neither still return null, and the pane says so. A fold reported "Up to date" while it was running, and after it failed. Two causes: - `fold.running` was set only once a chunk came back from the model, so the entire first fold — the whole window a reader actually watches — rendered "Up to date" over a loading skeleton, and a fold that could not start never set it at all. It is now set when the fold starts. - The header hint ignored `status`, so `unavailable` and `failed` both fell through to "Up to date". They now name what happened. A failed fold over a session that already has a good ledger keeps counting its backlog instead, because that ledger is still on screen and the events behind it are genuinely unfolded. Verified: `pnpm tc` clean; 2150 tests across session-summary, activity, right-sidebar, settings and text-generation; `check:code-quality:changed`, oxlint and the localization verifiers pass. End to end on this machine with the reporter's own settings (`sessionSummaryAi` = pi/deepseek-flash) and a real Pi transcript, the service reaches `ready` in 7.4s with a populated ledger, which it could not do before this change.
Copilot's entries in the agent model picker were a hand-written array frozen at the CLI build the list was read from. It ended at `gpt-5.5` and `claude-opus-4.7` while the installed CLI offers 31 ids — `claude-sonnet-5.5`, `claude-opus-5.5`, `gpt-6.1-sol`, `gpt-6-luna`, `grok-4.7`, `kimi-k3` among them — so the picker could offer retired models and could never offer current ones. Every model released after that array was written was unreachable. The CLI publishes no `models` subcommand (`copilot help models` is an unknown topic, and the interactive picker is policy-filtered per account), but `copilot help config` documents the `model` setting as the list of ids it accepts. That list is the CLI's own catalog, so probing it is what keeps the picker current. The parser reads only that setting's bullet list, stops at the next documented setting, and adds `auto` back: `--model` documents it as "let Copilot pick automatically" while the setting's value list omits it. Two things that would otherwise regress: - Model discovery replaces the spec's list wholesale rather than merging metadata into it, so the parsed models carry the same low/medium/high/xhigh levels and `low` default the static entries did. Without that, every Copilot model would lose its effort control. - The array stays as `COPILOT_FALLBACK_MODELS` for a machine with no `copilot` on PATH, refreshed to the catalog the CLI ships now. A help format change parses to nothing, which falls back to it and is not cached, so the next probe tries again instead of retiring the probe for the life of the install. Also spells the effort flag the documented way. The earlier Copilot effort commit relied on `--effort` being an alias of `--reasoning-effort`; that still works, but it is absent from both `--help` and the CLI's own shell completion, so a fold would break silently if the alias were dropped. Verified with a live one-shot prompt, not only with `--help`. Copilot's spec is the Source Control AI catalog as well, so commit-message model selection gets the same live list. The probe lives in its own module because `commit-message-model-parsers.ts` was already at its `max-lines` cap — extracted, not suppressed. Verified: the real main-process discovery path (`discoverCommitMessageModelsLocal`) spawns `copilot help config` and returns 31 models with `catalogOrigin: 'probe'`, carrying labels and effort levels; `pnpm tc` clean; the agent-spec, session-summary-ai, ai-generation-settings and text-generation suites pass.
The Summary tab and the pane header both used a generic "info" circle, which is the icon the app already uses for informational notices — it says nothing about a written brief, and it made the tab read like a warning rather than a place to catch up on a session. Both now use a sticky note, the same icon the sidebar already uses for a worktree's notes. SSR test updated from `lucide-info` to `lucide-sticky-note`.
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.
ELI5
The Summary tab next to the Agents list is supposed to be a quick written brief of what an agent session is doing, so you don't have to scroll back through a terminal. It never showed a brief — not once, for any session — and it often claimed it was "Up to date" while the pane was empty. Separately, picking GitHub Copilot as the agent that writes those briefs offered a model list that stopped somewhere in the past. This PR fixes all three, plus the tab's icon.
What Changed
Before: opening the Summary tab on an agent session showed a loading skeleton forever, then settled on "Up to date" with nothing under it. Hiding and re-showing the panel changed nothing. Choosing Copilot in Settings → Agents → Session summaries listed models no longer offered and never listed current ones.
After: the tab produces a real brief for a session, using the transcript of the session itself — goal, what the agent is doing now, what it has finished, blockers, decisions, and a timeline. Copilot's model list is read from the installed CLI, so it always matches what that CLI actually accepts.
There are three independent causes, and each is fixed at its own layer.
1. The brief could not find the session's transcript
A summary is built from the agent CLI's own transcript file, not by re-reading the terminal. The code that located that file only knew the "native chat" agents — Claude, Codex, Grok, OMP, OpenCode. For anything else it returned nothing, so the pane settled on "No readable transcript for this session yet." and stayed there permanently.
On the machine this was reported from, the sessions are Pi (462), Copilot (16), OpenCode (11) and Cursor (2) — so almost every session was one the brief could not read. That is why it never worked.
It now also resolves:
$COPILOT_HOME/session-state/<id>/events.jsonl. The id is validated before being joined onto that path, so a malformed one cannot escape the sessions root.The decoding side already understood every one of these formats, so no parser changed.
2. "Up to date" was reported for folds that were running, or had failed
Two bugs in the header line:
3. Copilot's model list was a hand-written snapshot
An array pinned 16 model ids, ending at
gpt-5.5. The installed CLI offers 31, includingclaude-sonnet-5.5,claude-opus-5.5,gpt-6.1-sol,gpt-6-luna,grok-4.7andkimi-k3. Anything released after that array was written was unreachable, and retired ids stayed on offer.The CLI has no "list models" command and its interactive picker is filtered per account, but
copilot help configdocuments themodelsetting as the list of ids it accepts — the CLI's own catalog. The probe now reads that list. An unparseable help format parses to nothing, which falls back to a refreshed pinned copy and is not cached, so the next attempt probes again rather than retiring the probe forever.4. The icon
The tab and the pane header used a generic information circle — the same icon the app uses for notices, so the tab read as a warning rather than a place to read a brief. Both now use a sticky note.
Why
Why probe
help configrather than refresh the array. A refreshed array is stale again the next time GitHub ships a model; the CLI's own catalog is the thing that tracks that, and we already have a probe pipeline for every other dynamic agent.Why not fix only Copilot's list. The reporting user's own settings select Pi as the summarizing agent, and the sessions were Pi. The model list and the missing brief are genuinely separate defects that happened to be reported together.
Why the header changes are in the same commit as the transcript coverage. They are the two halves of one symptom: a user cannot tell "nothing is here yet" from "everything is done" if the header lies. Fixing only the first would have replaced a silent empty pane with a pane that still claimed to be up to date whenever a fold failed.
Linked Issue
N/A — this is a fork PR against
nplez1/main, reported directly by the fork owner rather than filed as an issue first.Visual Proof
Not attached: this work was done headlessly in a worktree, and the rendered check was not run. Recording it needs the app driven by CDP on a focused agent session plus a completed fold, which is more than the change warrants; say the word and I'll capture it before this goes anywhere near upstream.
The visual deltas are exact and pinned by tests, so a reviewer can see them without a screenshot:
lucide-infotolucide-sticky-note(SessionSummaryPane.test.tsxasserts the class).Testing
Full runs, against the pushed head
Every command below was run in this worktree against
f6adc4ca02— the head of this PR — after the commits were made, so the evidence describes exactly what is being reviewed. An earlier, narrower run during development produced 80 failures; 42 of them were phantom, because a barepnpm exec vitest rundoes not exportORCA_BACKGROUND_LAUNCH=1the way the repo'spnpm testwrapper does, which turned 41 greenbrowser-managercases red. Running the documented commands is what separated the real signal from that noise.pnpm tcpnpm lintoxlintwith itsmax-linesrulepnpm testAll 57 failures are pre-existing and unrelated to this change. None of the 14 failing files is one this PR touches, and none of them has been modified since the upstream merge (
git log 7c0a53a148..HEAD -- <paths>is empty, so they arrived red and unchanged). They fall into three classes:agent-session-*,agent-launch-*,structured-agent-session-*LOCAL-PATCHES.mdas "proved not ours"; they reproduce on pre-merge807aa6062ccloud/workspace (pg)bunprojectdaemon/repro-13767-shell-ready-marker-lost-to-exec,daemon/shell-ready,shell-startup-feature-channel,orcad-bundled-runtime.integrationproduce no child output under thebunruntime and pass under the node project — a test-project assignment gap, the same class upstream re-seated in stablyai#26028The third class only becomes visible with
buninstalled (pinned atconfig/.bun-version, 1.4.2); it is a property of this test environment, not of this diff — none of those four files is touched here.Focused tests added or updated for this change
src/main/session-summary/session-summary-transcript-source.test.ts(5 cases): a Pi session read from its hook-reported file, a Copilot session read from its session-state directory, a traversal-shaped Copilot id refused, a directory refused as a transcript, and an agent the fold cannot parse returning nothing.session-summary-service.test.ts: the fold reports itself in flight before its first chunk returns.session-summary-presentation.test.ts: "no readable transcript" and the failure case are named instead of "Up to date"; a failed fold over an existing brief still counts its backlog.commit-message-agent-spec.test.ts: Copilot probeshelp config; the id parser reads only themodelsetting's block, addsautoback, and parses to nothing on a format change.pnpm run check:code-quality:changedand the localization verifiers pass.End to end
On the reporting machine, with the reporter's own settings (
sessionSummaryAi= Pi /deepseek/deepseek-flash) and a real Pi transcript: the service reachesreadyin 7.4s with a populated brief. Before this change the same call returned "no readable transcript". The Copilot probe was likewise run through the real main-process discovery path, returning 31 models withcatalogOrigin: 'probe'.Platforms actually exercised: macOS only, local worktree, no SSH. The Copilot path is macOS-verified (
/opt/homebrew/bin/copilot); the Pi path depends only on the hook's reported path, which is platform-neutral, but Windows and Linux were not run.Notes
sessionSummaryis local-only, and a paired web client still gets no tab. Transcript resolution deliberately stays local because the fold spawns the agent CLI locally.statper open, plus one spawn ofcopilot help configwhen the probe runs (it reads local documentation, makes no network call, and is cached).thinkingand tool-call blocks use shapes the shared decoder does not read, so a Pi brief is text-only. That decoder is shared with Claude, Codex and OpenCode, so it is deliberately out of scope. OpenCode sessions still need a hook-supplied transcript path.AI Disclosure
Written by an AI agent (Pi, running a
github-copilotmodel) working directly in this worktree, under the fork owner's direction and review.Review
Agent skill upstream boundary