Expose session and tree browsing/editing to RPC protocol#1762
Expose session and tree browsing/editing to RPC protocol#1762dnouri wants to merge 13 commits intobadlogic:mainfrom
Conversation
|
Here's a bit of a teaser video to show how this works out in the Emacs client: rpc-browsing-surface.mp4 |
484c521 to
45e8597
Compare
45e8597 to
899cfae
Compare
|
Setting this to draft because it has a couple of issues. I can't figure out why you split I'm afraid that won't fly. Can you explain why that split was needed? |
|
You're right, sorry for the confusion. I got confused by main's behaviour where The way this surfaced for me was that Maybe the right thing to do is to change cross-project session switching such that it updates cwd everywhere and re-creates tools? For now I'll remove |
Add five RPC commands that let external clients browse sessions and navigate the conversation tree without reimplementing the session file format or shelling out to the TUI: - list_sessions (scope: current | all) - get_tree (lightweight tree projection with optional full content) - navigate_tree (with optional branch summarization and labeling) - set_label (set or clear a label on any tree entry) - abort_branch_summary (cancel in-progress branch summarization) Tree projection filters metadata entries (label, session_info, custom) and re-parents their children to keep the tree structurally valid. Tool-result nodes are enriched with metadata from the corresponding tool_use, using branch-local resolution to prevent cross-branch contamination when the same toolCallId appears on sibling branches. Traversal is iterative to handle deep trees. Extract formatToolCall from tree-selector.ts into core/format-tool-call.ts so the RPC tree projection and TUI share the same tool call previews: [read: ~/file.ts:10-29] [bash: git status && git diff] Split setSessionFile() and syncLocation() in session-manager so session file loading no longer implicitly mutates cwd and sessionDir. allMessagesText is now always populated on session list items (the includeSearchText toggle added no meaningful savings since I/O dominates regardless).
Inline narrow *Like interfaces from rpc-command-wiring into rpc-mode.ts handlers -- the indirection did not earn its keep for what are 3-5 line case bodies. Remove wrapper type aliases (RpcListSessionsResult, RpcGetTreeResult) and inline their shapes directly into the RpcResponse union. Guard navigate_tree and set_label with try/catch so invalid entry IDs return typed RPC errors instead of falling through to the outer parse-error handler. Add assistant to toRpcMessageRole switch for robustness against future refactoring. Delete mock-based rpc-client unit tests that spied on the private send() method. The E2E tests in rpc.test.ts and the pure-function wiring unit tests provide sufficient coverage without coupling to client internals. Add comprehensive Tree Node Types reference to rpc.md documenting all 7 node variants with field descriptions and JSON examples. Add per-type unit tests for non-message tree projection (compaction, model_change, thinking_level_change, branch_summary, custom_message). Split monolithic E2E browsing test into individual per-operation tests. Reorganize RPC sections: list_sessions moves into Session, abort_branch_summary moves into Tree.
Pick navigate_tree option fields explicitly instead of spreading the full RPC command object into the domain method. Prevents leaking transport-level fields (id, type, targetId) into AgentSession.navigateTree(). Move error checking from getData() into send() so all commands -- including void methods like setLabel -- throw on server errors. Previously void methods silently swallowed error responses.
No consumer passes includeContent: true. Remove the flag, the conditional content fields on three RpcTreeNode variants, and the parameter threading through six internal functions.
…Call default case
…consistency with production code
…File + syncLocation
… after cross-project switch syncLocation updated sessionManager.getCwd() and getSessionDir() after a cross-project session switch, but left agentSession._cwd, tool cwds, and process.cwd() unchanged. This made session listing follow the switch while tool execution stayed in the original directory — worse than main where everything consistently reflects the launch directory. Remove syncLocation entirely. list_sessions scope:current now always returns sessions for the project directory pi was started in, matching the TUI session selector behaviour on main.
ffccabb to
94d7b4e
Compare
|
i'm currently refactoring all the things, and that will include rpc mode, which will likely sit on top of the new server mode. as such, rpc should have full feature parity going foward. will take a week or two to finisht. this will cover this PR. |
Reopening #1628 (auto-closed by bot).
Motivation
The RPC protocol already covers prompting, streaming, model/thinking configuration, compaction, forking, session switching, and message retrieval. What's missing is session discovery and tree-structured navigation, the operations the TUI's session selector and tree selector provide interactively.
This PR adds five new RPC commands that close that gap, plus a shared tool-call formatting module extracted from the TUI.
What this adds
RPC commands
Five new commands with typed client helpers, transport types, and docs:
"current"or"all". Each session item always includesallMessagesTextfor client-side search.rpc.md> Tree Node Types for node variants.AgentSession.navigateTreewith normalized options. Supports optional branch summarization and labeling.navigate_treebehavior.abortcommand only aborts the agent loop, not the separate summarizationAbortController.Command shapes live in
rpc-types.tsand are exported viamodes/index.tsfor SDK consumers.Shared
formatToolCallTool-call preview formatting was extracted from the TUI's
tree-selector.tsintocore/format-tool-call.tsand is now shared by both the TUI and RPC tree projection. Previews went from generic JSON truncation to human-readable bracket expressions:Intentionally deferred
Two session management operations that the TUI supports are not included:
rename_session: The TUI renames any session by temporarily opening the target file and writing asession_infoentry. The existingset_session_nameRPC command only works on the current session.delete_session: The TUI deletes sessions via thetrashCLI with a fallback tounlink. No RPC equivalent exists.Both are scoped out to keep this PR focused on read and navigate operations. They're straightforward to add as a follow-up.
Design decisions
Internal
toolResultsession entries carry only atoolCallId, not the tool name or arguments: those live on the originating assistant message. The projector resolves eachtool_resultagainst tool calls seen along its branch path, populating toolName, toolArgs, and formattedToolCall on the projected node. Branch-scoped resolution prevents cross-contamination when the sametoolCallIdappears in different branches.Iterative traversal: Tree projection and leaf resolution use explicit stacks instead of recursion. Deep trees (long sessions with many branches) can exceed call-stack limits under recursion.
Architecture
Command handlers are inlined in
rpc-mode.tscase bodies, matching the pattern of existing RPC commands. Two helper modules provide reusable logic:rpc-tree-projection.ts: projects the rawSessionTreeNodetree into transport-safeRpcTreeNodearrays, resolves tool-call metadata, and finds the projected leaf.rpc-command-wiring.ts: transport mapping (toRpcSessionListItem,toRpcNavigateTreeResult) and label normalization.syncLocation() is added to SessionManager, called after
setSessionFile()during session switches. The newlist_sessions(scope="current")command reads cwd and sessionDir to scope results; without this, switching sessions via RPC would leave those fields pointing at the previous project.Error handling:
navigate_treeandset_labelcatch thrown errors (invalid entry IDs) and return typed RPC errors. The remaining new commands cannot fail under normal operation and propagate exceptions to the top-level handler.