Repository navigation
Add native conversation fork/bifurcation into side chats or main threads - #143
Open
katulevskiy wants to merge 24 commits into
Open
katulevskiy wants to merge 24 commits into
katulevskiy wants to merge 24 commits into
Conversation
Source: zeronsh#622 Source revision: eb7736a
Contribution Managerneeds triage · medium risk · untriaged Open review workspace · Revision Next actions:
This summary is maintained by the review app. Decisions and test evidence are recorded in the workspace; the app does not merge PRs. |
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.
Upstream mirror
Source: zeronsh#622
Original author: @jsgrrchg
Original revision:
eb7736aacf68d0fac76306e215771977af778cfaThis PR is an isolated Contribution Manager pilot mirror. Its reviews, checks and merge state are separate from upstream. An empty
[skip ci]commit suppresses automatic bulk CI; the code tree matches the imported upstream revision.Summary
Add a native fork/bifurcation menu beneath completed Codex, Claude Code, OpenCode, and Pi replies. The menu offers Fork in side chat and Fork as main conversation. Either choice creates an independent native provider session containing the conversation through the selected reply and opens an empty composer. Side chats open in the right pane; main conversations appear in the left sidebar and open in the main chat area. Creating the fork does not send a prompt or start inference.
For
U1 → A1 → U2 → A2 → U3 → A3, forkingA1producesU1 → A1 → fork marker. The first new question resumes the child session without inheriting the later turns. The original chat retains its identity, history, and execution.User-visible behavior
Provider implementations
thread/forkwith explicitthreadId, inclusivelastTurnId, andephemeral: false.thread/read. Noturn/startduring creation. Live-tested with 0.158.0.forkSession(sourceSessionId, { dir, upToMessageId })through a small managed Node helper.@anthropic-ai/claude-agent-sdk@0.3.284; verify source and child usinggetSessionMessages, allowing the SDK's UUID remapping. PreserveCLAUDE_CONFIG_DIRand project cwd. Noquery()during creation. Live-tested with CLI 2.1.284 and Node 22.23.1./session/{id}/fork; v2/api/session/{id}/fork. Convert the inclusive product boundary into the next native message's exclusive boundary.SessionManager.createBranchedSession(entryId)through a managed storage-only Node helper. Copy the inclusive root-to-assistant path into an independent persistent session.@earendil-works/pi-coding-agent@0.85.1; verify source UUID, canonical cwd and format, then the child entry sequence, ancestry and reconstructed context. Record the exact native entry at authoritative completion. No prompt or active-parent session switch during creation. Verified with Pi 0.85.1 and Node 22.23.1 using a local mock provider.OpenCode 2.0.11's executable exposes the exclusive boundary as
beforein/openapi.json, while the website describesmessageID. Sending the website's field to that executable over-copied history; child verification detected the mismatch. The validated v2 implementation usesbefore, v1 usesmessageID, and unknown OpenCode versions stay unavailable. V2 history reading also handles envelopes and cursor pagination, sending ordering only on the first page.Codex boundaries represent completed native turns. A visible segment closed during steering is not automatically a valid cut point. None of the adapters infer native identities by matching text, timestamps, or bubble indexes.
Pi now supports both destinations
Pi was initially excluded while Zeron used an ACP adapter. After the migration to native RPC, this PR now gives Pi the same Fork in side chat and Fork as main conversation actions as the other supported providers.
turn_end. Require the same message object in the authoritative session manager andstopReason: stop; do not match text, timestamps or visual message indexes. Consume the metadata notification internally and associate the point with the explicit Zeron assistant ID beforeSteeredor terminalDone.fork, which changes the active session and cuts at a user message. Historical points can be forked while a later parent turn stays active. Check the inclusive prefix and effective model context, including labels, compaction and custom entries.@earendil-works/pi-coding-agent@0.85.1through the existing managed package installer. Node >=22.19.0 is required; npm is needed for first preparation. Only the verified Pi 0.85.1 fork contract is enabled; ordinary Pi RPC conversations retain their existing version range.Persistence, routing, and continuity
NativeForkPointwith typed provider boundaries, native session provenance, execution device, and cwd. Persist it on the exact logical reply through Loro writes, snapshots, continuation joins, and journal replay, before terminalDoneprocessing completes.ForkMessageSideChatand batchedGetNativeForkAvailabilityRPCs, advertised asnative-message-fork-v1. The creation request includes a typed visual destination; omitted destinations retain the existing side-chat behavior. Advertise main-conversation support separately asnative-message-fork-main-v1, and disable that menu option on older hosts while preserving their supported side-chat option. Public requests reference Zeron message IDs; the host resolves and validates native identities. Remote requests route to the execution device and use the existing provider-update execution lease.Prepared,ProviderCreated,Published,Failed, orIndeterminatelocally. Persist the child document and registry before acknowledging publication.ProviderCreatedpublishes the known child without creating another provider session. An ambiguous provider result is not automatically retried; there is no exactly-once guarantee across the provider and local storage.NativeForklineage and deriveRequireExistingfrom trusted document metadata. Cold starts, warm sends, steers, queues, startup recovery, and initial native commands do not add a textual<conversation>wrapper or silently create a fresh session after a rejected resume.The Claude helper is embedded and installed through the existing pinned-package mechanism. Node >=18 is required, npm prepares the package, and cancellation/timeouts reap preparation and helper processes before releasing the execution lease.
Regression fixes included
WorkspaceHost::flush()return persistence errors. Both initial publication and the existing-in-memory-row retry path remainProviderCreateduntil the registry is saved. Tests inject a real SQLite write failure and recover through both retry and restart without another provider creation.Why the remaining providers are out of scope
This feature requires an exact native historical boundary, independent persistent child identity, creation without inference, verified prefix contents, and strict resume behavior. General resume support alone does not establish those guarantees.
@cursor/sdk@1.0.32. Inspection of the published SDK declarations and documentation did not establish an equivalent public fork operation with a selected-message cutoff. The CLI documents/fork, but that does not establish the required historical-cutoff contract for Zeron's SDK integration. Native checkpoints and the public storage interfaces suggest a possible future implementation; that route has not been validated as a fork/resume workflow with authenticated Cursor access. This is a validation gap, not a claim that Cursor cannot support it.There is no automatic textual-history fallback for any unavailable provider or message.
Validation
Directed validation was performed on Linux during implementation and the subsequent fixes. Provider live probes ran separately from the ignored opt-in integration tests.
cargo test -p zeron-protocargo test -p zeron-doccargo test -p zeron-harness --test codexcargo test -p zeron-harness --test claudecargo test -p zeron-harness --lib opencode::native_fork/adapter_installfiltersnative_side_chats/native_points/side_chatspi_resumenative_forkunit filternative_fork/side_chatfilterspi::unit filter--features native-fixture --test pi_rpc)--test pi_live -- --ignored --nocapture)cargo check -p zeron-uigit diff --checkLatest Pi extension validation used
--locked. The suites above cover both fork destinations and strict child resume after engine restart. Pi's three real-process tests additionally check historical and final cuts, a parent held in an active later turn, unchanged parent bytes, first child send after process restart, missing-child rejection, tool-loop completion, exact native-point/assistant-ID associations during 43 steers, and extension-driven session-switch rejection. The SDK storage tests cover labels, compaction, custom entries and two generations of forks. Administrative helper tests cancel/time out after simulated provider creation, require anIndeterminateresult, and verify process reaping before the update lease is released.A requested Astra high audit found a Windows persistence issue: flushing a read-only index handle would fail after the provider had created the child. The implementation now opens the handle with write access and adds a cross-platform durability/reopen test. A follow-up audit found no additional actionable regressions. Native process tests were run on Linux; macOS/Windows execution remains unverified.
CI now runs Pi's offline unit/RPC/helper contracts and the host native-fork suites. The actual SDK storage tests require an explicit module path, and the real Pi tests stay opt-in; CI does not invoke a live provider or install a model-facing Pi runtime for these tests. The existing Windows harness unit job includes the new index durability test.
cargo fmt --all -- --checkis not green: the same files already have formatting differences in the original8f62632abaseline. Unrelated formatting changes are excluded from this feature.Live smoke probes passed for Codex 0.158.0, Claude Code 2.1.284, OpenCode v1 1.18.33 with
opencode/muse-spark-1.3-contributor-free, and OpenCode v2 2.0.11 withopencode/mimo-v2.6-flash-free. They verify a historical fork, exclusion of later context, first child send, a child-owned native point, and strict resume after reconstructing the driver. Engine tests separately cover engine restart. The OpenCode probe requires an explicit model containingfree.The GPUI fixture renders the real shell/transcript/composer and exercises the fork RPC with a synthetic provider, without inference. Physical two-device execution and macOS/Windows distribution were not exercised. Remote recovery is covered by simulated RPC/GPUI tests.
Evidence and limitations
Old replies without an exact mapping remain unavailable. Deleting a canonical provider session can make inherited replies unavailable. Forks share the current checkout; files are not restored. No iOS UI is added. No release version is changed and no final application is installed by this work.
The original implementation was based on
8f62632a(v0.2.98), followed by focused regression fixes, upstream updates, the destination-menu extension, and native Pi support described above.Screenshots
Captured from the native GPUI mockup with an isolated engine and synthetic provider; no model inference. These existing captures predate the destination menu, tighter action spacing, and simplified provenance label; they illustrate the original native side-chat workflow and were not refreshed for this update.
Timestamp → fork → Copy, dark theme:
The same action in the light theme:
A completed reply without a recorded native point shows only its timestamp and Copy:
Historical fork with the selected prefix and an empty child composer:
Compact window with the sidebar collapsed:
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.