Repository navigation
feat(session-summary): give the session summary a right-sidebar home and its own model setting - #56
Merged
Merged
Conversation
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.
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.
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.
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.
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.
…usable 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.
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.
…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.
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
Orca can write a short brief about what an agent session did: what it is working on, what it finished, what is blocking it, and a timeline of highlights. That feature was merged, but it never appeared anywhere — the panel only existed inside a page the app can no longer open. This puts it in the right sidebar, next to Agents, and gives it its own agent/model/effort setting so its cost can be tuned on its own.
What Changed
Before: there was no way to see a session summary. The panel was mounted only inside the Activity page's detail pane, and nothing has opened that page since the agent list became a sidebar tab (upstream stablyai#18222), so no build ever rendered it. Its model settings were also borrowed from the commit-message Source Control AI recipe: editing commit-message AI silently changed summary cost, and editing the commit prompt looked like it should change summaries when it could not.
After:
pi --list-models. Copilot's hosted Claude models expose effort like its GPT models already did.This model has no effort setting.Mechanism:
summarytab renders the panel inRightSidebarPanelContent. The ledger view and header state moved out of the Activity strip (activity/session-summary-ledger-view.tsx,activity/session-summary-presentation.ts) so both hosts render one component instead of two copies.getFocusedAgentPaneKeyForWorktree(right-sidebar/session-summary-subject.ts). The pane keys on the pane and its provider session, because a new session can start in the pane you are already focused on.sessionSummaryAiblock (shared/session-summary-ai.ts) instead of Source Control AI'scommitMessageoperation. Resolution and the picker share one rule for the effective model and effort, so the dropdown always names what the CLI is actually given.git:discoverCommitMessageModelspath; only a real probe result is cached, keyed by agent, with a Refresh models control.Why
selectedThinkingByModel), so a model that advertises none cannot be given one; hiding the control made that read as a missing feature.Linked Issue
None — fork-local feature work (no external issue exists; happy to attach one if the maintainer wants tracking).
Fixes #
Visual Proof
A "before" capture is impossible: the panel rendered in no build, so there was no screen to photograph. Evidence instead, both from a hidden dev instance over CDP:
After — the new tab and pane (info icon, focus prompt when nothing is focused):
After — the new setting with a probed dynamic agent (Pi,
Deepseek Deepseek Flash, effortLow, Refresh models):The setting's before/after is real and visible: Pi previously offered a single
Config defaultentry and no effort control at all, because its model list exists only in its CLI output.Testing
pnpm tcclean. Changed-code quality gate, localization coverage/catalogs/extraction, and the fork's newer gates (check:upstream-identity-literals,check:max-lines-ratchet,check:dead-classes) all pass.10,438 tests pass across 1,140 files in the touched areas (settings, right-sidebar, lib, shared,
main/session-summary). New tests cover: refusing an unusable agent instead of substituting one, creating the fold's scratch directory, honouring a probed model's effort, keeping the spec default in the picker list, the session-identity remount, the missing-bridge pane state, and the fields component's three effort states.Rendered checks (hidden dev instance, no window shown): the tab and pane render; the setting drives
sessionSummaryAiwhilecommitMessageAistays untouched; Pi's probe caches 63 models in both the agent slot and the host-keyed slot; athinking: noPi model shows the disabled effort control with its explanation; the value persists in profile state.macOS only. No Windows/Linux/SSH run, and no real end-to-end fold against a live agent CLI — the fold's own behaviour is unchanged from feat(session-summary): on-view session summaries for agent sessions #51 and covered by its unit tests.
I manually tested these changes locally
Automated tests added/updated, or explained why not below
AI Disclosure
Authored with the pi coding agent (xiaomi/mimo workhorse models) under human direction, then reviewed by
github-copilot/gpt-6.1-solat high effort. The review raised two blockers and several should-fix findings, all fixed in the last three commits:<tmpdir>/orca-session-summary) was never created, so every fold would have failed with ENOENT — created before spawning.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
spawnSourceControlAgent; no barerg, no shell-string spawning, no new path handling. The right sidebar and settings are desktop surfaces.sessionSummaryAiis an optional settings key that older builds ignore, and the newsummarytab is dropped by an older host's tolerantui.setpath (tolerateUnknownValues) rather than failing the batch.parsePiModelsdouble-labels Pi models ("Deepseek Deepseek Flash"), which Native Chat's picker shares.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)