Skip to content

feat(chat): rewind and fork a session from a message bubble#110660

Merged
steipete merged 4 commits into
mainfrom
claude/bubble-replay-session-state-58d23c
Jul 18, 2026
Merged

feat(chat): rewind and fork a session from a message bubble#110660
steipete merged 4 commits into
mainfrom
claude/bubble-replay-session-state-58d23c

Conversation

@steipete

Copy link
Copy Markdown
Contributor

What Problem This Solves

There is no way to return a session to an earlier state from the chat. Once a user message is sent, the only recovery paths are /clear (loses everything) or whole-session fork from the Sessions page (keeps everything, including the part you wanted to undo). Claude Code desktop's per-bubble rewind shows how useful "take that back and rephrase" is; OpenClaw's transcript DAG already supported it internally (AgentSessionTree.navigateTree semantics) but nothing exposed it.

Why This Change Was Made

  • Rewind (bubble hover button + right-click "Rewind to here" on user messages): the session's active branch repoints to just before that message, and the message text returns to the composer for edit/resend. Nothing is deleted — the transcript is copied to a rotated session identity with a trailing leaf control, so the operation is a pointer move in the append-only DAG, and identity rotation fences any stale live SessionManager from clobbering the repoint with a snapshot-replace.
  • Fork from here (right-click on user messages): creates a new session from the exact active-path prefix before that message, navigates to it, and seeds its composer with the message text. The source session is untouched. Only user/runtime selection (model/provider/thinking overrides) is inherited; delivery routes, CLI bindings, runtime identity, accounting, and lifecycle state are detached.
  • New gateway RPCs sessions.rewind (operator.admin) and sessions.fork (operator.write) follow the sessions.compaction.branch/restore lifecycle discipline: exclusive lifecycle mutation, re-validation inside the lock, and both operations are rejected while a run is active. Sessions owned by an external agent harness (upstream-linked) are rejected with a typed error. Legacy JSONL transcript storage returns a typed unsupported error; SQLite is fully supported.
  • Protocol additions are additive (no version bump). inheritSessionSelection moved from session-create-service.ts to session-entry-selection.ts for reuse rather than duplication.

User Impact

User-message bubbles in the Control UI chat gain a rewind hover action (with confirm popover and a "Don't ask again" option) and right-click "Rewind to here" / "Fork from here" menu items. Both are disabled with an explanatory tooltip while the agent is working. Rewind refreshes the visible thread and puts the message text back in the composer; fork opens the new session with the composer pre-filled. Rewind moves chat context only — files edited, messages sent, and other tool side effects are not reverted.

Evidence

  • node scripts/run-vitest.mjs src/config/sessions/session-accessor.sqlite-message-cut.test.ts src/gateway/server-methods/sessions-rewind.test.ts — leaf repoint + editor text, active message count drops, exact fork prefix, source untouched, typed errors (missing entry, non-user entry, off-active-path, external harness, unsupported storage), busy rejection for both methods.
  • node scripts/run-vitest.mjs ui/src/pages/chat/chat-history.test.ts ui/src/pages/chat/chat-pane.test.ts ui/src/lib/sessions/index.test.ts ui/src/pages/chat/components/chat-message.test.ts ui/src/pages/chat/chat-view.test.ts ui/src/pages/chat/chat-thread.test.ts — cache invalidation + refetch + composer refill, race handling (connection replaced, late fork, newer draft preserved), entry-id eligibility (optimistic bubbles excluded), context-menu contents and busy gating, confirm popover, tooltips.
  • pnpm tsgo:core / tsgo:ui / tsgo:test:src / tsgo:test:ui green; oxfmt clean; pnpm ui:i18n:baseline no drift (en-only keys per contributor flow).
  • Autoreview (codex gpt-5.6-sol, xhigh): clean, no accepted/actionable findings.
  • Focused suites re-run green after rebase onto latest origin/main.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation app: web-ui App: web-ui gateway Gateway runtime size: XL maintainer Maintainer-authored PR labels Jul 18, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. feature: ✨ showcase ClawSweeper spotlight: unusually compelling feature idea for maintainer attention. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. labels Jul 18, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 495360cb2b

ℹ️ 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".

Comment on lines +252 to +253
usageFamilyKey: params.forked ? undefined : params.currentEntry.usageFamilyKey,
usageFamilySessionIds: params.forked ? undefined : params.currentEntry.usageFamilySessionIds,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve rotated session lineage on rewind

When rewinding a normal session that has no existing usageFamilySessionIds, this copies undefined while the row is moved to a new sessionId, so the old transcript identity drops out of the entry. The usage and cleanup paths only include the current sessionId plus entry.usageFamilySessionIds (src/gateway/server-methods/usage.ts and src/config/sessions/session-accessor.sqlite-lifecycle-state.ts), so pre-rewind usage disappears from family reports and deleting the session cannot collect the rotated-out transcript rows. Use the same lineage preservation as other same-key session-id rotations.

Useful? React with 👍 / 👎.

const text = content
.flatMap((block) => {
const record = asRecord(block);
return record?.type === "text" && typeof record.text === "string" ? [record.text] : [];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reuse transcript text extraction for editor text

For persisted user messages whose content blocks use the supported Responses/OpenAI input_text shape, this returns no editorText, so rewind/fork succeeds but the composer is blank instead of being refilled with the message. Other transcript/UI readers accept text, input_text, and output_text blocks (for example src/config/sessions/session-transcript-projection-rebuild.ts and ui/src/lib/chat/message-extract.ts), so this extraction should follow the same content contract.

Useful? React with 👍 / 👎.

const sessionKey = state.sessionKey;
const agentParams = scopedAgentParamsForSession(state, sessionKey);
try {
const result = await state.sessions.rewind(sessionKey, entryId, agentParams);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fence late message-cut results by connection

If the Gateway connection is replaced while sessions.rewind is in flight, createSessionCapability can still resolve the committed result from the old client (see ui/src/lib/sessions/index.test.ts), but this path does not capture/check the client or connectionEpoch after the await. A same-key reconnect can therefore clear the current cache, persist the old editorText, and reload the current gateway from a stale operation; guard this like createSession/isConnectionScopeCurrent before mutating state or storage.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jul 18, 2026
@clawsweeper

clawsweeper Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 18, 2026, 9:34 AM ET / 13:34 UTC.

Summary
Adds Control UI rewind and fork actions for persisted user-message bubbles, implemented through new sessions.rewind and sessions.fork gateway RPCs plus SQLite transcript/session mutations.

PR surface: Source +1077, Tests +845, Docs +1, Other +2. Total +1925 across 35 files.

Reproducibility: not applicable. This PR proposes a new session-navigation capability rather than reporting broken existing behavior. The supplied focused tests describe the intended server and UI paths, but they are not a real-session demonstration.

Review metrics: 2 noteworthy metrics.

  • Gateway session operations: 2 added public RPCs. Both operations create long-lived protocol, permission, and session-lifecycle contracts beyond the Control UI.
  • Persisted state mutation modes: 2 added: rewind and fork. One rewrites the active session identity/path while the other creates a detached session, so upgrade behavior needs explicit review.

Stored data model
Persistent data-model change detected: persistent cache schema: ui/src/pages/chat/chat-history.test.ts, serialized state: packages/gateway-protocol/src/schema/sessions.ts, serialized state: src/config/sessions/session-accessor.message-cut.ts, serialized state: src/config/sessions/session-accessor.sqlite-message-cut.test.ts, serialized state: src/config/sessions/session-accessor.sqlite-message-cut.ts, serialized state: src/config/sessions/session-accessor.sqlite.ts, and 15 more. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🐚 platinum hermit
Result: blocked until real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add a redacted recording or screenshot sequence of a persisted-message rewind and fork, showing the resulting thread and composer state.
  • Obtain a session-state owner decision on the permanent core/API and permission model.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body provides tests and static validation claims, but no inspectable after-fix live Control UI session recording, screenshot sequence, terminal output, or redacted runtime log. Please add redacted proof of rewind and fork against a persisted SQLite session; updating the PR body should trigger re-review, or a maintainer can request @clawsweeper re-review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Mantis proof suggestion
Mantis can provide the missing redacted evidence for this Control UI chat interaction without changing the branch. A maintainer can ask Mantis to capture proof by posting this exact PR comment:

@openclaw-mantis web UI chat proof: verify and capture rewind and fork from a persisted user message, including the refreshed transcript and composer draft.

Risk before merge

  • [P1] Rewind rotates persisted session identity while preserving an append-only transcript; maintainer approval should explicitly cover upgrade semantics for usage lineage, cleanup, durable delivery state, and reconnecting clients.
  • [P1] The new sessions.rewind and sessions.fork RPCs become public gateway behavior with distinct operator.admin and operator.write scopes; user-facing intent and permission expectations need maintainer confirmation before landing.
  • [P1] No inspectable real-session evidence currently proves that the Control UI refreshes the correct thread, preserves the source on fork, and restores the editor draft after rewind.

Maintainer options:

  1. Prove and document the session transition (recommended)
    Capture a redacted live Control UI session showing rewind and fork, and retain focused coverage for lineage, delivery cleanup, reconnect races, and both RPC permissions.
  2. Accept the new lifecycle contract
    A session-state owner may explicitly accept the identity rotation and public RPC permission model after reviewing the upgrade and operator consequences.
  3. Pause pending product scope
    Pause the PR if maintainers do not want per-message rewind to become a core persisted-session operation.

Next step before merge

  • [P1] A protected maintainer-labeled feature needs product sponsorship and contributor-provided real behavior proof, not an automated repair attempt.

Maintainer decision needed

  • Question: Should OpenClaw expose per-message rewind and fork as durable core gateway/session operations, with the proposed operator.admin versus operator.write permission split?
  • Rationale: This is a new user-facing core capability that changes persisted session lifecycle behavior and expands the public gateway contract; automated review cannot choose its permanent UX, authorization, or upgrade policy.
  • Likely owner: steipete — The supplied change history identifies this contributor as the active implementer most able to clarify the proposed session and UI behavior; final sponsorship remains a repository-owner decision.
  • Options:
    • Sponsor the core feature (recommended): Confirm the core session and authorization direction, require redacted real-session proof, and continue normal merge review.
    • Narrow the scope: Keep a safer UI-only or fork-only subset if maintainers do not want rewind to repoint the active persisted session.
    • Defer the feature: Pause the PR until a durable product and gateway API decision is recorded.

Security
Cleared: No concrete security or supply-chain regression is evident from the supplied diff: it adds scoped gateway handlers, session logic, UI, docs, and tests without changing dependencies, workflows, permissions, or publishing paths.

Review details

Best possible solution:

Adopt the feature only if a session-state owner confirms the core product direction, then add redacted Control UI proof showing rewind and fork against a persisted SQLite session, including the refreshed transcript and composer result.

Do we have a high-confidence way to reproduce the issue?

Not applicable: this PR proposes a new session-navigation capability rather than reporting broken existing behavior. The supplied focused tests describe the intended server and UI paths, but they are not a real-session demonstration.

Is this the best way to solve the issue?

Unclear: exposing existing transcript-DAG capability through the chat UI is coherent, but making it a core persisted-session and public gateway API needs explicit maintainer confirmation of the lifecycle and permission contract.

AGENTS.md: unclear because the file could not be read completely.

Codex review notes: model internal, reasoning high; reviewed against 42133d0c3c3e.

Label changes

Label justifications:

  • P2: This is a substantial but non-emergency feature affecting Control UI session recovery and gateway behavior.
  • merge-risk: 🚨 compatibility: The PR adds public gateway methods and a persisted-session lifecycle behavior that existing clients and operator permissions may need to understand.
  • merge-risk: 🚨 session-state: Rewind and fork directly change active transcript paths, session identity, and composer/session selection state.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🐚 platinum hermit.
  • feature: ✨ showcase: ClawSweeper spotlight: unusually compelling feature idea for maintainer attention. Per-message session recovery can make chat iteration materially safer and more fluid than clearing or manually creating whole-session forks.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body provides tests and static validation claims, but no inspectable after-fix live Control UI session recording, screenshot sequence, terminal output, or redacted runtime log. Please add redacted proof of rewind and fork against a persisted SQLite session; updating the PR body should trigger re-review, or a maintainer can request @clawsweeper re-review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +1077, Tests +845, Docs +1, Other +2. Total +1925 across 35 files.

View PR surface stats
Area Files Added Removed Net
Source 25 1194 117 +1077
Tests 8 846 1 +845
Docs 1 1 0 +1
Config 0 0 0 0
Generated 0 0 0 0
Other 1 2 0 +2
Total 35 2043 118 +1925

What I checked:

  • Public protocol surface: The branch adds separate closed request/result schemas and exported validators for sessions.rewind and sessions.fork, making this an additive gateway contract rather than a UI-only change. (packages/gateway-protocol/src/schema/sessions.ts:520, 31322034554c)
  • Lifecycle and state boundary: The branch introduces dedicated server handlers and SQLite message-cut mutations for a session rewind/fork operation, so the feature changes persisted transcript identity and session selection behavior. (src/gateway/server-methods/sessions-rewind.ts:1, 31322034554c)
  • Prior review continuity: The supplied review history records earlier lineage, content extraction, connection-fencing, protocol-registry, lock, and pending-delivery concerns; the current PR body describes focused tests for those behavioral classes, but it supplies no inspectable live Control UI artifact. (ui/src/pages/chat/chat-pane.ts:1314, 31322034554c)
  • Merge gate: The PR has the protected maintainer label and a status: 📣 needs proof label. Its body lists unit tests, typechecks, and CI claims but does not provide a recording, screenshot sequence, terminal/live output, or redacted runtime log demonstrating an actual post-fix session rewind and fork. (31322034554c)
  • Security and supply-chain scope: The supplied changed-file list covers session, gateway protocol, Android protocol enum, UI, docs, and tests; it does not show dependency, lockfile, workflow, publishing, permissions, or installer changes. (31322034554c)

Likely related people:

  • steipete: The supplied PR history attributes all four commits implementing the Control UI, gateway, protocol, and session-state changes to this account; current-main feature-history provenance could not be completed in the read-only inspection environment. (role: active feature author and recent chat/session contributor; confidence: low; commits: 3b646750aa96, d280f5b976c6, 245efbf47aab; files: src/gateway/server-methods/sessions-rewind.ts, src/config/sessions/session-accessor.sqlite-message-cut.ts, ui/src/pages/chat/chat-pane.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (3 earlier review cycles)
  • reviewed 2026-07-18T11:40:56.543Z sha 495360c :: needs real behavior proof before merge. :: [P2] Preserve rotated session lineage on rewind | [P2] Extract supported input_text blocks for the composer | [P2] Fence rewind results against a replaced gateway connection
  • reviewed 2026-07-18T12:21:35.971Z sha c0ea53e :: needs real behavior proof before merge. :: [P2] Register the session-cut schemas with the protocol registry
  • reviewed 2026-07-18T13:04:11.971Z sha c0ea53e :: needs real behavior proof before merge. :: [P2] Register session-cut schemas in the protocol registry | [P2] Clear pending final-delivery state on rewind

@openclaw-barnacle openclaw-barnacle Bot added the app: android App: android label Jul 18, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ed26bff77e

ℹ️ 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 targetKey =
action === "fork" ? buildDashboardSessionKey(current.target.agentId) : current.canonicalKey;
const result = await (action === "fork"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject locked sessions before message cuts

When the target row has current.entry.modelSelectionLocked === true (for example catalog-created sessions or durable harness-owned rows), this path still performs sessions.fork/sessions.rewind; the clone then clears modelSelectionLocked and agentHarnessId in src/config/sessions/session-accessor.sqlite-message-cut.ts:250, and rewind also rotates the transcript sessionId. Existing parent-fork and checkpoint restore paths reject locked rows, so these new RPCs let operator.write/admin callers bypass the lock and detach owner/runtime identity. Please reject locked entries before dispatching the cut.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c70135879c

ℹ️ 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".

Comment on lines +524 to +528
export const SessionsRewindParamsSchema = closedObject({
sessionKey: NonEmptyString,
agentId: Type.Optional(NonEmptyString),
entryId: NonEmptyString,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Register session-cut schemas with protocol registry

Adding these public request/result schemas without also adding them to ProtocolSchemas leaves the generated native/JSON protocol surface incomplete: repo-wide search shows SessionsRewind/SessionsFork are absent from packages/gateway-protocol/src/schema/protocol-schemas.ts and from the generated Swift/Kotlin protocol artifacts, even though the Android method enum was updated. Native clients and protocol generation therefore cannot see the new sessions.rewind/sessions.fork payload types until the registry and generated files are refreshed.

Useful? React with 👍 / 👎.

const sourceKey = state.sessionKey;
const agentParams = scopedAgentParamsForSession(state, sourceKey);
try {
const result = await state.sessions.forkAtMessage(sourceKey, entryId, agentParams);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fence late fork results by connection scope

If sessions.fork completes after the Gateway connection has been replaced, SessionCapability.forkAtMessage still returns the committed result while skipping only the refresh; this handler then persists the draft and opens result.sessionKey as long as the same source session is still selected. In a same-key reconnect, a stale fork from the retired client can therefore navigate the current pane to an old connection's branch; capture the pane connection scope and re-check it after the await before persisting or switching, like the other async pane actions do.

Useful? React with 👍 / 👎.

@steipete
steipete force-pushed the claude/bubble-replay-session-state-58d23c branch from c701358 to c0ea53e Compare July 18, 2026 12:20

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c0ea53ea73

ℹ️ 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".

? inheritSessionSelection(params.currentEntry)
: params.currentEntry;
return {
...baseEntry,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clear pending delivery state on rewind

When rewinding a channel-backed session that still has a durable pendingFinalDelivery* retry from an unsettled final reply, this spread preserves that stale delivery marker while the transcript is rotated to an earlier leaf. The pending-final machinery treats those fields as a live retry (src/config/sessions/types.ts, src/auto-reply/reply/pending-final-delivery.ts), so a later recovery/settlement can send the old final answer after the user rewound and edited the prompt; clear the pending-final fields with the other tail/runtime state for rewind.

Useful? React with 👍 / 👎.

@steipete

Copy link
Copy Markdown
Contributor Author

QA Smoke CI failure provenance: pre-existing on main, not introduced by this PR.

The four failing QA Smoke profiles all report the startup CSS budget violation (42.0 KiB exceeds 42.0 KiB, bundle control-ui-core-B_E8B0aR.css). Evidence that this is main's state, not this branch's:

  • The failing bundle hash is byte-identical across three different heads of this PR (before/after a CSS trim, before/after rebasing across 46+ main commits) — this branch's CSS lives in the lazy chat chunk, not the startup bundle.
  • A local build of origin/main tip (74880cb) with the exact QA job env (OPENCLAW_BUILD_PRIVATE_QA=1, node scripts/build-all.mjs qaRuntime && pnpm ui:build) produces the same control-ui-core-B_E8B0aR.css at 42.0 KiB and the same violation.
  • The same local build of this PR's head produces the identical bundle — zero startup-CSS delta from this PR.
  • main's green QA Smoke runs report control-ui-core-Bfj575dV.css at 41.1 KiB — a bundle that a fresh build of the same commit does not produce, consistent with those lanes building against an older sticky dependency snapshot.

So a fresh dependency install currently puts main's startup CSS exactly over the 42.0 KiB budget in scripts/check-control-ui-performance.mjs, and any PR lane that doesn't share the old snapshot fails. Needs a maintainer decision on main (bump the budget or trim the drift); this PR will go green on rerun once that lands.

@steipete
steipete force-pushed the claude/bubble-replay-session-state-58d23c branch from c0ea53e to 3132203 Compare July 18, 2026 13:31

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3132203455

ℹ️ 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".

Comment on lines +213 to +215
const baseEntry = params.forked
? inheritSessionSelection(params.currentEntry)
: params.currentEntry;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve workspace metadata for message forks

When the source session is bound to a dashboard cwd or managed worktree, this uses inheritSessionSelection() as the fork base, which keeps only model/provider selection and drops spawnedCwd/worktree. Later agent runs derive workspace and cwd from the session entry (agent-run-execution-phase.ts / resolveSessionRuntimeCwd), so a message fork from a worktree session will run in the default workspace instead of the branch the user forked from. Preserve or explicitly clone the workspace binding for forked message branches.

Useful? React with 👍 / 👎.

if (!visibleSessionMatches(state, sessionKey, agentParams.agentId)) {
return null;
}
state.chatMessages = [];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clear stale reply targets after rewind

If the user has a reply target selected and rewinds to before that message, this reloads the transcript but leaves state.chatReplyTarget intact. The next send still runs through prependReplyQuote() in chat-send.ts, so the edited prompt can quote a message that is no longer on the active transcript; clear the reply target along with the transcript state, like the clear-history path does.

Useful? React with 👍 / 👎.

Comment on lines +2593 to +2594
onRewindMessage: (entryId) => this.rewindToMessage(entryId),
onForkMessage: (entryId) => this.forkFromMessage(entryId),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Hide unavailable rewind and fork actions

These callbacks are passed even when the connected Gateway does not advertise sessions.rewind or sessions.fork (for example a write-only/limited operator token omits admin-only sessions.rewind, and older gateways omit both). ChatThread will still render the actions and only fail after the user clicks; gate each callback with isGatewayMethodAdvertised(...) before exposing it.

Useful? React with 👍 / 👎.

@steipete
steipete merged commit 0acece4 into main Jul 18, 2026
124 checks passed
@steipete
steipete deleted the claude/bubble-replay-session-state-58d23c branch July 18, 2026 13:46
@steipete

Copy link
Copy Markdown
Contributor Author

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 19, 2026
…#110660)

* feat(chat): rewind and fork a session from a message bubble

* docs(web): document chat rewind and fork bubble actions

* fix(chat): lint cleanups, protocol regen, and test splits for rewind/fork CI

* fix(ui): fit chat rewind disabled styles inside the startup CSS budget
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: android App: android app: web-ui App: web-ui docs Improvements or additions to documentation feature: ✨ showcase ClawSweeper spotlight: unusually compelling feature idea for maintainer attention. gateway Gateway runtime maintainer Maintainer-authored PR merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: XL status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant