Repository navigation
feat(session-summary): on-view session summaries for agent sessions - #51
Merged
Merged
Conversation
When checking back in on a long-running agent session, the user had no way to catch up without scrolling the transcript. This adds a summary strip to the Activity thread detail pane: expanding it folds the session's provider transcript into a structured ledger (goal/plan/in-progress/done/blockers/ decisions) plus an append-only anchored timeline with a 'since you last looked' section. The summary is a materialized view built only while it is read: staleness facts are tracked for free at all times, the fold runs on explicit open, completed chunk extracts resume across close/reopen, and closing cancels in-flight work. Fold chunks extract in parallel and merge deterministically; a failed extract keeps the last good ledger.
The fold brain ran the default agent spec (Claude, default model) with no settings influence. It now resolves agent/model/thinking-level/custom command from the user's Source Control AI settings (Settings → Git) through the same resolver text generation uses, so summaries run the model the user already picked. The open request keeps an optional per-session override.
… kind-label exclusion
The summary panel's 15 `activity.sessionSummary.*` keys were never added to
en.json. That stayed hidden while the lint step failed first: with lint red, every
localization gate after it was skipped. Now that lint passes they run, and three
fail.
- Adds the keys with the panel's inline fallbacks (`pnpm run sync:localization-catalog`).
Without them localization extraction, catalog verification and coverage all fail.
- Adds a reviewed exclusion for `error: 'Error'` in TIMELINE_KIND_LABELS. The key is a
SessionSummaryTimelineKind discriminator, not a user-visible property, and the value
is the inline default for `translate('activity.sessionSummary.kind.error', ...)`, so
the audit's `object-property:error` heuristic is a false positive here.
nplez1
force-pushed
the
nplez1/Session-Summary
branch
from
October 6, 2026 04:50
e6b5fab to
d937fe5
Compare
nplez1
added a commit
that referenced
this pull request
Oct 6, 2026
) * feat(session-summary): on-view session summaries for agent sessions When checking back in on a long-running agent session, the user had no way to catch up without scrolling the transcript. This adds a summary strip to the Activity thread detail pane: expanding it folds the session's provider transcript into a structured ledger (goal/plan/in-progress/done/blockers/ decisions) plus an append-only anchored timeline with a 'since you last looked' section. The summary is a materialized view built only while it is read: staleness facts are tracked for free at all times, the fold runs on explicit open, completed chunk extracts resume across close/reopen, and closing cancels in-flight work. Fold chunks extract in parallel and merge deterministically; a failed extract keeps the last good ledger. * feat(session-summary): use text-generation settings for the fold model The fold brain ran the default agent spec (Claude, default model) with no settings influence. It now resolves agent/model/thinking-level/custom command from the user's Source Control AI settings (Settings → Git) through the same resolver text generation uses, so summaries run the model the user already picked. The open request keeps an optional per-session override. * fix(session-summary): register the panel's string keys and review the kind-label exclusion The summary panel's 15 `activity.sessionSummary.*` keys were never added to en.json. That stayed hidden while the lint step failed first: with lint red, every localization gate after it was skipped. Now that lint passes they run, and three fail. - Adds the keys with the panel's inline fallbacks (`pnpm run sync:localization-catalog`). Without them localization extraction, catalog verification and coverage all fail. - Adds a reviewed exclusion for `error: 'Error'` in TIMELINE_KIND_LABELS. The key is a SessionSummaryTimelineKind discriminator, not a user-visible property, and the value is the inline default for `translate('activity.sessionSummary.kind.error', ...)`, so the audit's `object-property:error` heuristic is a false positive here.
Merged
8 of 9 tasks
nplez1
added a commit
that referenced
this pull request
Oct 7, 2026
…and its own model setting (#56) * feat(session-summary): show the session summary in a right-sidebar tab The brief merged in #51 could never appear. It mounted only inside ActivityThreadDetailPane, which only ActivityPrototypePage renders, and nothing has called openActivityPage since the agent list became a sidebar tab (upstream stablyai#18222). The panel was dead UI in every build. Give it a live surface: a static right-sidebar `summary` tab, following the agent session focused in the active workspace and nothing else. - Strictly focus-driven (`getFocusedAgentPaneKeyForWorktree`). Another agent in the same workspace is not this pane's subject: showing the most recently active one reads as though it were the session the user is looking at. With nothing focused the pane asks the user to focus an agent session. - Finished sessions already qualify, now pinned by a test: the fold resolves its transcript from a provider session, and main retains a `providerSessionOnly` remnant row for a dropped status row (`server-cleanup.ts`), so a hibernated pane the user focuses summarizes like a live one. - The ledger view and header state are extracted from the activity strip (session-summary-ledger-view.tsx, session-summary-presentation.ts) so both hosts render one component instead of two copies. - The tab is declared in the three allowlists a static tab needs: the shared union, the client-ui schema, and the main-process persistence normalizer. Dropping any one makes the tab vanish or reset to Explorer on restart, so the regression test moves onto the new value. Wire-safe in both directions: an older host drops a value it cannot express (tolerateUnknownValues) instead of failing the whole ui.set batch, and an older client normalizes an unknown tab to Explorer. Also adds docs/reference/session-summary.md, which two source files already referenced but which did not exist. * feat(session-summary): give the fold its own agent and model setting A summary borrowed the commit-message Source Control AI recipe, so its cost could not be changed without changing commit messages — and editing the commit prompt looked like it should affect summaries when it never could. Give the fold its own setting, same shape, separate storage: - `sessionSummaryAi` (Settings → Agents → Session summaries): agent, model, per-model thinking effort, and the custom command for a custom agent. Resolved by `shared/session-summary-ai.ts`; the fold now reads it instead of operation 'commitMessage'. Unset means the default agent and that agent's default model and effort, so nothing has to be configured for summaries to work. - The selection rules (capability lookup, model/effort seeding on switch, patch building) move to `lib/ai-generation-settings.ts`, and the picker fields to `settings/ai-generation-fields.tsx`, so the AI-author card and this block share one implementation instead of two. The block is also registered in settings search, which is how the Agents pane is reached. - Primitive typography is left to the primitives: the moved fields no longer pass `text-xs` to <Label>/<SelectTrigger> or `font-mono text-xs` to <Input> (the design-system gate forbids restyling them), and the labels sit above their controls instead of in a 92px column that only fitted the smaller type. Tests: resolver units including "ignores the source-control AI choice entirely", the fold-params contract, and the settings block's own behaviour. Verified in the running app: the block shows Codex / GPT-5.4 / High from `sessionSummaryAi` while `commitMessageAi` stays null, and the value persists in profile state. * fix(agent-spec): declare effort levels for Copilot's Claude models Copilot's hosted Claude entries listed no thinking levels, so the model/effort pickers hid the effort control for exactly the models users pick when they want reasoning — while the CLI accepts `--effort` (an alias of `--reasoning-effort`) for any of its models and validates the value list globally, not per model. Declare the same low/medium/high/xhigh levels the GPT entries already use, with the same 'low' default, so those entries expose effort in Settings and in the per-action recipes. * feat(session-summary): list a dynamic agent's models from its own CLI The picker could not offer a model for a dynamic agent: Pi advertises a single `Config default` stub, and its real list only exists in its CLI output. Selecting Pi therefore gave no model choice and no effort control at all, even though the fold passes `--model` and `--thinking` and `parsePiModels` reports 60+ models with effort levels. Probe once per agent and cache the answer: - Resolve the selected agent through the spec, then replace its model list with whatever a probe reported for that agent (`discoveredModelsByAgent`, keyed by agent so another agent's probe can never be applied to this one). The existing panel only ever read discovered models in the resolver, never in the picker. - Probe through `git:discoverCommitMessageModels` with no worktree or connection: host-native, which is where the fold spawns the CLI. Cache only a real probe — a `spec`-origin result is the built-in list and caching it would retire the probe for that agent permanently. - Storage stays host-keyed (`discoveredModelsByAgentByHost.local`) while the pane resolves the local slot, because the fold reads the transcript locally too; a host-aware fold can then land without a migration. - The pane says `Discovering models…` while the probe runs and falls back to the built-in list with an explanation when it fails, instead of silently showing a one-entry list. Verified in the running app: selecting Pi exposes 63 probed models with effort levels (Model: Deepseek Deepseek Flash, Thinking effort: Low) and caches them in both slots. * feat(ai-settings): keep the effort control visible for every model The effort dropdown rendered only when the selected model declared thinking levels, so it silently vanished for models that take none — Pi's four `thinking: no` rows, Copilot's `auto` and `gpt-4.1` — which reads as a missing feature rather than as a property of the model. Render the row whenever a model is selected: enabled with that model's levels, or disabled showing `—` with a one-line explanation. Levels stay model-scoped, which is how `selectedThinkingByModel` is modelled. Verified in the running app with Pi: `deepseek/deepseek-flash` shows an enabled Low/…/Xhigh control, `omlx/Laguna-S-2.1-oQ4e` shows the disabled control and the explanation, and the Agent and Model dropdowns stay independent of it. * fix(session-summary): create the fold's scratch dir, and refuse an unusable agent Two ways a fold could not do what the user asked: - The scratch cwd (`<tmpdir>/orca-session-summary`) was never created, and the launcher passes it straight to spawn, so every fold failed with ENOENT on a machine that had never had that directory. The brain now creates it, because it is the component that requires it. - A resolver that reported "nothing usable is configured" (Custom with an empty command, or every candidate agent disabled) was turned into the default agent. That runs a provider the user did not choose — possibly one they disabled — with their transcript. It now fails the fold with a message naming the setting. * fix(session-summary): run the model and effort the pane displays The pane could show one model while the fold ran another, and an effort the user picked could be dropped: - Effort was resolved through the spec/synthesis helper, which guesses thinking support from the model id (`withOpenAiThinking` matches gpt-5/codex). A probed Pi model therefore produced no thinking level, so picking High changed nothing. Resolution now prefers the probed model's own levels. - A model a probe no longer lists was displayed as replaced while execution still passed the stale id; conversely, an unset choice displayed the probe's first model while execution passed `default`. The spec default now stays in the list, and a stored id is validated against the probe (or, for a static agent, the spec). Both sides now read one rule, so what the dropdown says is what the CLI is given. * fix(session-summary): follow the session, and stay honest about what it can do - The pane keyed only on the pane key, so a new session started in the pane the user was already focused on kept the previous session's brief. The key now includes the provider session id, which makes the service reset the ledger. - The tab was offered in every window, but a paired web client composes no `sessionSummary` bridge, so the pane would sit on its loading state forever. The activity bar now omits the tab when the bridge is missing, and the pane says so if it is somehow opened. - A successful probe was cached for the life of the install with no way to list again, so models the CLI began reporting were unreachable. The pane offers Refresh models for a dynamic agent. * fix(ci): prepare shared FPM tools before parallel Linux packaging
nplez1
pushed a commit
that referenced
this pull request
Oct 19, 2026
…iew off the deprecated owner resolver (stablyai#30562) * refactor(renderer): fold browser creation, file actions and doc-preview callers off the deprecated owner resolver The creation-action policy and browser creation (#3, #48) fold together, so the provider the policy offers is the one creation uses. Browser panes, page lifecycle and conversion, tab duplication, the explorer tree pane, doc-preview actions and editor path moves (#21, #43, #45-#47, #49, #50) read runtimeEnvironmentIdWithLegacyFallbackUnlessTwin. File-explorer writes on a folder (#51) take the owner from the rows alone, never from the focused server. Deprecated importers 16 -> 6. * refactor(renderer): fold file preview off the deprecated owner resolver; Open in Orca Browser refuses a twin A project two hosts publish reads as no server for the doc-preview plan, but the file:// path now refuses it with its own message instead of opening this machine's copy (#7). Deprecated importers 6 -> 5. * fix(renderer): a twin's file preview and open-externally refuse instead of opening this machine's copy Codex P2 on the F7 folds: a folder twin read as no server, so the preview plan built a local file:// tab and open-externally handed the path to this machine's OS. Both now check the owner for ambiguity first. Also fix two test fixtures that broke the renderer typecheck. * refactor(renderer): move the file:// open target out of file-preview.ts file-preview.ts crossed its line limit after main grew it; the file:// target, its type and its two refusal messages move to workspace-file-browser-open-target.ts, which they never depended on file-preview for. * test: mock the replacement resolver in the quick-action availability suite (Codex P2)
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
When you come back to a long-running agent session after being away, you currently have to scroll through everything it did to understand where things stand. This PR adds a "Session summary" strip to the agent detail view in Activity: click it open and you get a short written brief — what the agent is trying to do, what it has finished, what it is doing right now, anything blocking it, and a timeline of the highlights — with a "Since you last looked" section at the top so you see what is new first.
What Changed
Before: Checking in on an agent meant scrolling its terminal output — slow, and only shows a narrow slice of what happened.
After: The Activity thread detail pane has a collapsed "Session summary" strip with a one-line hint (e.g. "12 events to catch up on"). Expanding it shows the summary: current activity, goal, plan, completed work, blockers, decisions, and a timestamped timeline whose entries point back to the transcript message they came from. Collapsing it remembers what you have seen, so the next visit leads with what is new.
Mechanism: The summary is a cached "materialized view" over the session's own transcript file (the JSONL the agent CLI writes), folded into a structured ledger by an LLM call. Key properties:
Also included: the pane's UI follows the design system (tokens and existing primitives only), and the ledger cache lives in
userDataas a rebuildable cache.Why
The problem is not "summarize the transcript" — it is "what changed since I last looked". That reframe drove the design: entries are append-only and counted, so a per-session last-seen cursor can lead with what is new.
Alternatives considered:
Linked Issue
None — fork-local feature work (no external issue exists; happy to attach one if the maintainer wants tracking).
Visual Proof
Pending — a new strip and panel in the Activity detail pane; rendered before/after captures will be attached once the UI validation pass runs. Layout: one collapsed row below the session header (chevron + "Session summary" + hint), expanding to a scrollable brief with labeled sections and a timeline (kind badge, text,
#message-indexanchor).Testing
Automated tests added/updated: 26 tests across
src/main/session-summary/covering ledger merge semantics (facts updated in place, timeline append-only), fold chunking/caching/atomic failure/cancellation, service lifecycle (open → fold → push, close cancels, reopen resumes from cursor, session-identity change resets the ledger, failed fold keeps last good ledger), and the settings→fold-params contract.pnpm tcclean,pnpm testgreen for the new suites plus the touchedregister-core-handlerssuite,pnpm run check:code-quality:changedgate green,pnpm formatapplied.Platform: macOS. Manual rendered testing pending (noted above). No Windows-specific paths or processes are touched beyond the existing cross-platform spawn utilities (
spawnSourceControlAgent, sharedchild-process).I manually tested these changes locally
Automated tests added/updated, or explained why not below
AI Disclosure
Authored with the pi coding agent (model: xiaomi/mimo-v2.6-pro) under human direction; design decisions reviewed and chosen by the human.
Review
Agent skill upstream boundary
docs/reference/agent-skill-sharing-upstream-boundary.mdand copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.Notes
docs/reference/agent-status-store.md).userDatawith the same posture as existing scrollback/status caches; it is treated as rebuildable and never authoritative.spawnSourceControlAgentpath (WSL/Windows-aware) andpath.joinfor paths.Checklist
N/Awith reason — pending rendered pass (see Visual Proof)pnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred) — typecheck/tests/changed-lines gate pass locally; full lint and build left to CI