Skip to content

Add option to fork from current state (include last model response) #439

Description

@Hrovatin

Summary

Add a way to fork a session from the current state, with the last model response included, as an alternative to the existing fork behavior, which always rewinds to before a selected user message (dropping that message and everything after it).

Today the /fork selector only offers user messages as fork points, and forking rewinds to the parent of the selected message. The selected user message is returned only as pre-fill text for the editor. As a consequence, the final assistant/model response can never be captured in a fork — the tail of any forked branch is always the assistant response that precedes some user message.

Current Behavior

For a conversation U1, A1, U2, A2, U3, A3:

  • The fork selector offers only U1, U2, U3 (user messages) — see getUserMessagesForForking() in agent-session.ts.
  • Forking at the latest question U3 branches from its parent A2 (createBranchedSession(selectedEntry.parentId) in agent-session.ts fork()), so the new branch tail is A2. Both U3 and the final response A3 are dropped.
  • U3's text is returned as selectedText to pre-fill the editor, letting the user re-run or edit that question — but there is no way to fork in a state that keeps A3.

There is no fork point after the last assistant response, because fork points are user-message-only and forking always excludes the selected message forward.

Proposed Behavior

Offer a fork option that branches from the current leaf / last entry (including the final model response A3), producing a new branch whose tail is the latest assistant answer, with an empty editor ready for the next turn. This is complementary to the existing "fork at a user message (re-ask that question)" flow.

Both behaviors should remain available:

  • Fork from current state — include everything up to and including the last model response; start a fresh turn on top of it.
  • Fork at a previous question — existing behavior; rewind to before a chosen user message and pre-fill it as an editable/re-runnable prompt.

Acceptance Criteria

  • Users can fork so that the resulting branch includes the last model response (A3), not just up through A2.
  • The existing "fork at a user message" behavior remains available and unchanged.
  • The choice is discoverable in the /fork UI (e.g. an explicit "fork from current state / here" entry alongside the user-message list).
  • Works consistently across the interactive TUI and the dashboard fork flows (getForkMessages / fork RPC), and print/RPC modes where applicable.
  • Session tree parenting is correct (new branch's parent is the current leaf) and extension session_before_fork / session_fork events fire as they do today.
  • Covered by tests.

Technical Notes

Relevant code:

  • packages/coding-agent/src/core/agent-session.ts
    • fork(entryId) (~L3630): rewinds via createBranchedSession(selectedEntry.parentId) and only accepts role === "user" entries.
    • getUserMessagesForForking() (~L3919): filters to user messages, so assistant responses are never offered as fork points.
  • packages/coding-agent/src/core/session-manager.ts
    • createBranchedSession(leafId) (~L1216): builds the branch up to and including leafId. Forking from the current state likely means calling this with the current leaf id (see getLeafId()), rather than a user message's parent.
  • packages/coding-agent/src/modes/interactive/interactive-mode.ts
    • showUserMessageSelector() (~L4298): the /fork selector UI (UserMessageSelectorComponent).
  • Dashboard / RPC: getForkMessages() and fork(entryId) in modes/rpc/rpc-client.ts, handlers in modes/rpc/rpc-mode.ts, dashboard endpoints in packages/dashboard/src/server/server.ts (/fork-messages, /fork).

Design considerations:

  • fork() currently asserts the entry is a user message and returns selectedText for editor pre-fill. A "fork from current state" path needs a different contract (no pre-fill, branch includes the tail). Consider either a dedicated method or an option flag on fork().
  • Note the existing navigateTree() can land on other nodes in-place but creates no new session file; this feature is specifically about creating a new forked branch that includes the latest answer.
  • Ensure the UI clearly distinguishes "re-ask this question" (rewind) from "continue from here" (keep last answer).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions