Repository navigation
feat: chat tabs on orchestration v2 - #152
Merged
adampeterhiggins merged 2 commits intoOct 5, 2026
Merged
Conversation
The orchestration v2 merge left the chat tab server as a stub, so tabs could not be listed, created, summarized, or settled as a group. Rebuild it on v2: - ThreadTabs service (thin threadTabs HTTP group) reads v2 shells, creates tabs with thread.create on the source's branch and worktree, and adds a fork endpoint that joins upstream's native thread.fork to the tab group. - Summaries read the v2 timeline (visible turn items), keeping the format the web preview parses. - Group settlement follows the stored v2 event stream and mirrors settles and wakes across a group, blocking on active runs, pending requests, background work, and queued turns. - Web restores fork-before-message, fork-to-model, and the account picker's New tab; Fork from this response opens a native fork as a new tab. - Mobile judges an empty tab from the thread shell. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
adampeterhiggins
added a commit
that referenced
this pull request
Oct 5, 2026
Brings in upstream's orchestrator v2 (pingdotgg#2829) and everything up to 51f7f77, with the fork's features ported onto it: - conflict resolution and v2 ports of every fork feature (chat tabs, Devin and Custom ACP drivers, agent access MCP, launch flow, PR watch extras, usage-limit extras, transcript export, conversation import, tool-call hover previews, Cursor per-instance usage) - the Agents sidebar panel restored next to Lineage, with in-panel agent inspection and the audited regressions fixed - Cursor out-of-usage stops shown as usage limits, Cursor turn usage and delegated-task usage recorded - Claude and Codex edits carry real unified diffs - fork migration 55 repaired so fork databases get upstream's v2 schema The fork's work was developed in #149 and the stacked PRs #152-#166 (history kept on t3code/sync-upstream-2026-10-05-backup) and squashed into this merge. Co-Authored-By: Claude Opus 5.5 (1M context) <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.
The orchestration v2 merge (#149) kept the chat tab clients compiling but turned the server into a stub: memberships returned nothing and list, create, and handoff failed. Tabs could not be opened, summarized, forked, or settled as one sidebar row, and the web entry points for forking into a tab were removed from
ChatView.How it works on v2
ThreadTabsservice (apps/server/src/threadTabs/ThreadTabs.ts) owns the tab logic, andthreadTabs/http.tsis now a thin transport. It reads shells and snapshots throughThreadManagementService, so migrated v1 threads hydrate their transcript before they are summarized. Creating a tab dispatches the v2thread.create(createdBy: "user",creationSourcefrom the client, defaulting toweb) on the source's branch and worktree. The membership row is written first and removed if the dispatch is rejected. The Linear and GitHub issue thread-link refresh calls are kept.POST /api/thread-tabs/:threadId/forkdispatches upstream'sthread.forkat a run and adds the fork to the open tab's group. In the web app, Fork from this response goes through it (forkResponseIntoTab), so the new tab continues the actual conversation instead of starting from a summary. When the server has no tabs (an upstream server, where no tab group loads), the button falls back to upstream's separate-thread fork.thread-tabsummary chip, because v2 has no native way to do either. Restored inChatView:onForkFromMessage,onForkModel,canForkModel, andmodelRequiresFork. The provider account picker's New tab option works again too, since it is driven byonForkModel.summary.tsnow reads the v2 timeline (visibleTurnItems, which includes history a fork inherited): dialogue, reasoning, commands and other tool calls, errors, checkpoint files, and the latest proposed plan. I kept the fork's extractive format rather than reusing upstream'sContextHandoffBudgetrendering. That renderer is built for replay to a provider (per-item attribution headers andt3_thread_readhints), while the web attach picker parses the fork's line format for its hover preview.settlement.tsfollowsOrchestratorV2.streamStoredEventsFrom, starting from the current end of the log, and resumes from the last event it saw if the stream fails.run.createdandthread.unsettledwake a group's settled tabs.thread.settledsettles the rest of the group. The settle is undone instead while a sibling has an active run, a pending runtime request, background work that holds completion, or a queued turn (threadHasQueuedTurnStartfromThreadSettlementService). For an automatic settle (server:auto-settle:command prefix), a sibling's open pull request also undoes it. It is wired inserver.tsthe same way asPullRequestWatchReactor.ThreadRouteScreendecided whether a tab was empty withselectedThreadDetail?.messages.length === 0, which is false until the detail loads. It now checks the shell (latestRun,latestUserMessageAt,runtime). Mobile tab creation sendscreationSource: "mobile".Not restored
sharedWorkspace.tsand the v1CheckpointReactorhook). Orchestration v2 has no branch-drift following for any thread;RunFinalizationServiceonly refreshes status when the recorded branch already matches. So there is no upstream behaviour to extend. Tabs get the source's branch and worktree when they are created or forked, so siblings stay consistent with each other, and tabs behave like any other v2 thread when someone switches branches by hand. If upstream brings drift following back, the sibling rule belongs there.afterMessageIdsummary path is still in the contract and on the server, but the web app now uses the native fork for responses.Contract and client-runtime changes (stacked PRs build on these)
CreateThreadTabInput.creationSource?: OrchestrationV2CreationSource, optional and defaulting toweb.ForkThreadTabInput { threadId, sourceThreadId, runId, title?, creationSource? }and thethreadTabs.forkendpoint (POST /api/thread-tabs/:threadId/fork, returnsThreadTabGroup).forkThreadTabFromRunin@t3tools/client-runtime/thread-tabs.ThreadTabsservice (create,fork,handoff,group,memberships) is the place MCP or agent entry points should call.Verification
npx tsc --noEmitinpackages/contracts,packages/client-runtime,apps/server,apps/web,apps/mobile: clean.npx vp test run src/threadTabs/inapps/server: 4 files, 16 tests. These port the fork's summary and settlement tests to v2, addThreadTabsservice tests for create, fork, and rollback, and port the "summarizes any other thread for a draft, never itself" handoff test that lived in the deletedserver.test.ts.npx vp test run src/threadTabs.test.tsinpackages/client-runtime.npx vp test run src/components/chat/ThreadTabs.test.tsx src/components/chat/threadAttachPickerSummary.test.tsinapps/web.npx vp check --fixon the changed files.Done by Claude Opus 5.5 in Claude Code (via T3 Code).
🤖 Generated with Claude Code