feat(chat): switch between session transcript branches from the chat header#110857
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a77908e338
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return tree.nodes.filter( | ||
| (node) => | ||
| !isSessionTranscriptLeafControl(node.entry) && | ||
| (node.id === tree.leafId || !referencedParents.has(node.id)), | ||
| ); |
There was a problem hiding this comment.
Exclude side append artifacts from branch tips
In sessions that contain side appends, this filter treats any non-leaf node without a child as a switchable transcript branch. Side artifacts are real today (for example src/auto-reply/reply/conversation-turn-capture.ts appends custom events with appendMode: "side"), and transcript-tree explicitly keeps those side branches out of prompts; listing them here both shows fake branches in the chat header and lets sessions.branches.switch repoint the active leaf to an audit/side artifact. Please exclude appendMode: "side" entries (or otherwise restrict this to visible conversation branch leaves) before using the same set for listing and validation.
Useful? React with 👍 / 👎.
|
Codex review: needs real behavior proof before merge. Reviewed July 18, 2026, 2:17 PM ET / 18:17 UTC. Summary PR surface: Source +739, Tests +320, Docs 0. Total +1059 across 26 files. Reproducibility: yes. from source inspection: append a Review metrics: 1 noteworthy metric.
Stored data model Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Mantis proof suggestion Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Restrict branch enumeration and switch validation to conversation-visible leaves, explicitly excluding Do we have a high-confidence way to reproduce the issue? Yes, from source inspection: append a Is this the best way to solve the issue? No. Generalizing the message-cut lifecycle is a sound direction, but its candidate set must be the visible conversation leaves rather than every non-control structural leaf; filtering only in the UI would leave the gateway mutation unsafe. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against b7f99d0ffd2a. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +739, Tests +320, Docs 0. Total +1059 across 26 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1021407619
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const matchesChat = sessionMessageMatchesChat(state, event); | ||
| if (matchesChat) { | ||
| void loadChatBranches(state); |
There was a problem hiding this comment.
Coalesce branch refreshes across transcript events
For long or tool-heavy sessions, every session.message event starts another sessions.branches.list request, while that handler loads and parses the entire unbounded transcript (src/config/sessions/session-accessor.sqlite-message-cut.ts:84) and walks its branch paths. chatBranchRequestVersions only prevents stale results from applying; it does not deduplicate or cancel the synchronous Gateway work, so a burst of persisted tool/message events repeatedly scans the same growing transcript and can block the Gateway event loop. Refresh once after the run settles or coalesce concurrent refreshes per session.
Useful? React with 👍 / 👎.
|
Merged via squash.
|
…header (openclaw#110857) * feat(chat): switch between session transcript branches from the chat header * fix(chat): type fixes and protocol regen for branch switcher CI
What Problem This Solves
#110660 made rewind non-destructive: the abandoned transcript branch stays in the append-only session DAG. But nothing surfaced those branches, so an accidental rewind (or a change of heart) had no way back. Follow-up agreed in #110660 ("branch switcher / un-rewind").
Why This Change Was Made
sessions.branches.list(operator.read) returns the transcript DAG's branch tips (headline from the branch's latest user/assistant message, message count, recency, active flag);sessions.branches.switch(operator.admin) repoints the active path to a chosen tip.switchmode (full-DAG copy to a rotated session identity plus a trailing leaf control targeting the selected tip) instead of duplicating it — same lifecycle discipline assessions.rewind: exclusive mutation, re-validation inside the lock, rejected while a run is active, queued sends cleared on success, external-harness-owned and legacy-JSONL sessions rejected with typed errors. Selecting the already-active branch is a typed error.wa-dropdown, git-branch icon) only when more than one branch exists. Selecting an inactive branch switches and refreshes the thread via the same cache-clear + refetch pattern as rewind. Disabled with distinct tooltips while the agent is working or without operator-admin access. Branch data refreshes on session load, connection epoch change, transcript/session events, and after rewind/switch — no polling.User Impact
Rewinds are now reversible from the UI: the chat header's branch menu lists every preserved transcript branch with its latest message and lets you switch back. Docs updated (
docs/web/control-ui.md).Evidence
node scripts/run-vitest.mjs src/config/sessions/session-accessor.sqlite-message-cut.test.ts— 12 tests: tip listing (active flag, headline, counts), switch repoint + projection, non-tip/unknown/already-active/unsupported-storage rejections.node scripts/run-vitest.mjs src/gateway/server-methods/sessions-rewind.test.ts— 13 tests: list/switch handler shapes, busy and external-harness rejections, queue-clear symmetry.node scripts/run-vitest.mjs ui/src/lib/sessions/message-cut.test.ts ui/src/pages/chat/chat-history.test.ts ui/src/pages/chat/components/chat-pane-header.test.ts— 30 tests: capability plumbing, switch flow cache-clear + refetch, header menu render/gating.origin/main(conflict resolution: docs bullet merge, header slot alongside the new faceControl element).pnpm ui:i18n:baselineno drift; fresh autoreview on the diff: clean, no actionable findings.