--- id: NVIM-ISSUE-9MP5JYUO type: issue title: Session status never fetches or publishes model, context, and cost specs: - NVIM-SPEC-GMWDCMJZ --- # Session status never fetches or publishes model, context, and cost ## Symptom A pivi session surfaces none of the rich Pi status a user sees in Pi's own interface: model, thinking level, context usage percent, token counts, and accumulated cost. Only connection, run, tool, queue, and error states appear. ## Impact Violates the transport-and-status contract of [NVIM-SPEC-GMWDCMJZ](../../specs/NVIM-SPEC-GMWDCMJZ-pivi-native-neovim-integration/index.md): - "Status also exposes available model, thinking, session, context, usage, and extension-status data." - "Status changes redraw native status surfaces and emit a semantic event." Consumers reading `vim.g.pivi` can never show model, context, or cost, so a user-built statusline is starved of the data the spec promises to publish. Scope note: cwd, git branch, and editor version from the user's Pi TUI statusline are out of scope. The native-integration invariant makes pivi a producer of session status, not the owner of a statusline; those fields belong to the user's own statusline, not to pivi's published state. ## Generality The fix must not depend on the reporter's specific Pi extensions. - Core fields (model, thinking, context usage, cost, token counts) come from core Pi RPC `get_state` and `get_session_stats`, present for any Pi configuration. - The extra segments in the reporter's TUI line (tokens/s, credit balance, rate-limit window) are extension widgets delivered generically through `setStatus` / `setWidget`, keyed by an arbitrary string. `dialog.lua` already stores them by key and emits `PiviActivity`; nothing references a named extension, and the path works with zero extensions and with arbitrary ones. - Required: the published status snapshot is the single generic source that merges core fields with whatever extensions contributed by key, so a consumer reads one place. Today extension status/widget entries live only in `dialog.lua` tables and a separate `PiviActivity` event, decoupled from `vim.g.pivi.sessions[name]` and not scoped per session. ## Surface Pi's status is multi-segment and renders across multiple rows in the TUI; `setWidget` even delivers `widgetLines` as an array, so the data is inherently multi-line. A Neovim `statusline` (and `winbar`) is a single line. pivi therefore must not collapse status into one lossy statusline string as its only output. - pivi publishes structured per-field data plus multi-line widget arrays as data; the consumer owns the surface (a statusline segment, winbar, tabline, or a dedicated multi-line status buffer or float). - A compact single-line `summary` stays available for the trivial statusline case, but is a convenience over the structured data, never a replacement for it. - pivi's own winbar shows at most a compact subset; full multi-line detail belongs to the structured data and to an optional richer surface, not to the one winbar line. ## Evidence The reducers for the two status-bearing RPC responses exist but are never driven: - `status.reduce_state` (folds `get_state`: model, thinking, session) has no live caller. `session.refresh` issues `get_state` and is exported as `self.refresh`, but nothing ever calls it: no command, no lifecycle event, no poll. - `status.reduce_stats` (folds `get_session_stats`: context usage, cost) has no caller at all; it is dead code. - `command.lua` `subcommands.session` does request `get_session_stats`, but only prints a one-off `notify`; it neither folds the result into cached status nor publishes it. - `publish.session_status` forwards `model`, `thinking`, `session`, `context`, but omits `cost` and any token breakdown, so even a populated reducer would not reach consumers in full. Net effect: the published status carries only event-derived fields (connection, run, tool, queue, compacting, retry, error). The fields that require a request, model/thinking/context/usage/cost, stay `nil` for the entire run. ```mermaid sequenceDiagram participant Pi participant session as pivi.session participant status as pivi.status (reducer) participant publish as pivi.publish participant consumer as user statusline Pi-->>session: event stream (agent/tool/queue) session->>status: reduce(event) status->>publish: connection/run/tool/queue only Note over session,status: get_state / get_session_stats never requested Note over status: reduce_state, reduce_stats never called publish-->>consumer: vim.g.pivi without model/context/cost consumer-->>consumer: nothing to show ``` ## Expected - Model, thinking, session, context usage, and cost populate cached status during a normal run, refreshed on the events that change them and at settle, for any Pi configuration. - `publish.session_status` forwards the full set, including cost and token usage, plus generic extension status and widget entries merged by key, through `vim.g.pivi` and the semantic `User PiviStatus` event. - Published status is structured per-field data with multi-line widget arrays preserved; the single-line `summary` remains a convenience, not the only output. - Status evaluation still performs no RPC; refreshes are triggered by run lifecycle, not by consumers reading the variable. ## Reproduction 1. Start a session and submit a prompt that calls a model. 2. Inspect `vim.g.pivi.sessions[]` during and after the run. 3. Observe `model`, `thinking`, `context`, and `cost` remain `nil`; only connection/run/tool/queue/error are present.