feat(code): session forking#2322
Draft
Basit-Balogun10 wants to merge 2 commits into
Draft
Conversation
Allows forking a task at any past message, creating an independent task with its own git worktree checked out at the historical commit and the conversation pre-loaded up to that point. - Emit `_posthog/agent_checkpoint` (HEAD SHA) after each prompt turn - filterEntriesUpToMessage helper slices S3 log to message N - WorkspaceService.createWorkspaceFromFork creates worktree at a commit - ForkService orchestrates the full fork pipeline - fork_relationships SQLite table stores lineage (title kept if parent deleted) - ForkedFromBanner shown at top of forked session with parent link - Fork button (GitBranch icon) on hover over each user message Generated-By: PostHog Code Task-Id: d612e6ba-d4b7-4e35-a0fc-27bf370a0db1
Three bugs prevented the forked session from loading its pre-seeded conversation: 1. writeLocalCache appended the source session's entries verbatim, so parseLogContent extracted the SOURCE session's sdkSessionId — pointing the agent at the wrong JSONL file. Fix: append a synthetic _posthog/fork_session_meta entry with the fork's own sdkSessionId. 2. The new task navigated to had no latest_run, so the session service's else-branch called createNewLocalSession — creating a third task run and ignoring the pre-seeded cache entirely. Fix: pass latest_run on the task object in useForkSession. 3. Even with latest_run.id set, log_url is null for a brand-new run, so the session service still hit the else-branch. Fix: before falling through to createNewLocalSession, check for an existing local cache; if present, reconnect to that run instead. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.
Summary
Closes: #330
What changed
Agent
jsonl-hydration.ts— addsfilterEntriesUpToMessageto slice a log up to message N, plus helpers to convert turns back to JSONL entries for seeding a new SDK sessionMain process
ForkService— orchestrates the full fork pipeline: fetch S3 log → slice at message index → extract git HEAD SHA from checkpoint → create worktree → write JSONL → seed local cacheWorkspaceService.createWorkspaceFromFork— creates a new worktree at a specific commit SHAAgentService— emits_posthog/agent_checkpoint(HEAD SHA) after each completed prompt turn so forks can check out the exact historical statefork-relationship-repository.ts+ migration0006_fork_relationships.sql— SQLite table storing lineage (parent task ID, title, run ID, message index) so the banner survives parent task deletionfork.tstRPC router — exposesprepareForkmutation andgetForkRelationshipqueryRenderer
useForkSession— hook that creates a new task + run via PostHog API, callsfork.prepareFork, then navigates to the new taskUserMessage— fork button wired up viaonForkpropConversationView— passesonForkwith the message index to eachUserMessageForkedFromBanner— shown at the top of forked sessions with a clickable link back to the parentSessionView— rendersForkedFromBannerwhen a fork relationship existsBug fixes included
Three bugs that caused the forked task to open with an empty conversation:
writeLocalCachecopied source session entries verbatim —parseLogContentextracted the wrong (source)sdkSessionId, pointing the agent at the wrong JSONL file. Fixed by appending a synthetic_posthog/fork_session_metaentry encoding the fork's own session ID.navigateToTaskhad nolatest_run, so the session service created a third task run instead of reconnecting to the pre-seeded one. Fixed by attachinglatest_runto the navigated task.latest_run.idset,log_urlis null for a brand-new run, sending the session service down thecreateNewLocalSessionpath. Fixed by checking for existing local cache before falling through.Reviewer notes
ForkServicefalls back to the current HEAD of the source worktreeworkspace.worktreePath = null) hit the early-exit toast inuseForkSession— the fork button is visible but non-functional; a follow-up can hide it for cloud tasks0006_fork_relationshipsmigration runsTest plan
~/.posthog-code/worktrees/;git logHEAD matches state after turn 1