Replies: 5 comments 2 replies
|
I believe @bobbai00 has already implemented this but not merged. |
|
@sshiv012 thanks for proposing this design. Can you elaborate on "Redo" stack ? For "Revert" part, yes the current agent service already has the capability and you can easily implement an per-ReAct-step level revert. |
|
Per-turn is the right default, but snapshot rewind needs an optimistic concurrency precondition before it replaces the live canvas. Consider this sequence: the agent finishes turn T; the user manually edits the workflow; then the user clicks Revert on T. Reloading T.beforeWorkflowContent would silently erase the later human edit even though HEAD still points at T. I would bind each step to beforeRevision/beforeDigest and afterRevision/afterDigest, then require revert to include the client’s currently observed workflow revision. The backend compares that with the authoritative current revision:
For a later version, storing the agent turn as a reversible workflow patch would allow a three-way revert that removes only the agent’s changes while retaining compatible human edits. Until then, fail closed on revision mismatch is safer than snapshot replacement. Redo state and the step tree should also survive agent-service restart if workflow snapshots themselves persist; otherwise the UI advertises a history model that disappears independently of the workflow it governs. This backend-owned revision/projection split is how Better Agent keeps native Claude, Codex, and Gemini session state consistent across reconnects and concurrent clients. I maintain the project; it is source-available and free for non-commercial use, while commercial use requires separate permission: https://github.com/ofekron/better-agent AI-assistance disclosure: this comment was drafted by Codex under the maintainer’s authorization and reviewed in Better Agent. |
Uh oh!
There was an error while loading. Please reload this page.
Summary
The Texera AI agent edits the user's live workflow canvas, its tools add, modify, and delete operators (and the changes auto-persist). Today there is no agent-aware way to back out a turn that went wrong: you fix it by hand. This proposal adds a per-turn "Revert" control (rewind the workflow to the state before an agent turn) and a "Redo" control (undo the revert), implemented almost entirely on top of machinery the agent already has.
I have a working prototype (running locally) and would like feedback on the design, especially the UX granularity and the protocol additions, before opening a PR.
Motivation
Background — what already exists
The agent-service already models a conversation as a version tree of ReAct steps:
ReActStephas anidand aparentId(the tree), plusbeforeWorkflowContentandafterWorkflowContentsnapshots.HEADpointer marks the current step; the visible chat is the ancestor path from root toHEAD.HEADand applies any workflow snapshot to the canvas viaWorkflowActionService.reloadWorkflow(...).The only missing primitive was the ability to move
HEADbackward. There was no client command for it. That is the gap this proposal fills.Proposal
Revert (per turn)
A Revert control on each agent turn. Clicking it:
HEADto that turn's parent step.beforeWorkflowContentand replies with the new HEAD + workflow content.Redo
A single Redo control in the chat toolbar, shown only when a redo is available. The agent-service keeps a redo stack: a revert pushes the pre-revert HEAD; redo pops it and moves HEAD forward, restoring that step's
afterWorkflowContent. Sending a new prompt clears the redo stack (a new branch invalidates redo). Redo is repeatable for multiple consecutive reverts.How it works
Revert + Redo flow
sequenceDiagram actor U as User participant FE as Frontend (agent panel) participant AS as agent-service participant WA as WorkflowActionService (canvas) U->>FE: Click "Revert" on turn T FE->>AS: WsClientRevertCommand { messageId: T } Note over AS: HEAD ← parent(T)<br/>push old HEAD to redo stack<br/>restore workflow = T.beforeWorkflowContent AS-->>FE: WsServerHeadChangeEvent { headId, workflowContent, canRedo: true } FE->>FE: headId → recompute visible steps FE->>WA: reloadWorkflow(workflowContent) Note over FE: "Redo" button appears U->>FE: Click "Redo" FE->>AS: WsClientRedoCommand Note over AS: pop redo stack → HEAD ← oldHead<br/>restore workflow = step.afterWorkflowContent AS-->>FE: WsServerHeadChangeEvent { headId, workflowContent, canRedo: false } FE->>WA: reloadWorkflow(workflowContent)HEAD movement over the step tree
graph LR I[INITIAL] --> U1[turn 1 user] --> A1[turn 1 agent] A1 --> U2[turn 2 user] --> A2[turn 2 agent] classDef head fill:#2da44e,color:#fff,stroke:#2da44e; %% Revert(turn 2): HEAD moves A2 -> A1 ; Redo: HEAD moves A1 -> A2Revert(turn 2)movesHEADfromA2toA1(turn 2's parent). The turn-2 steps stay in thetree, so
Redocan moveHEADback toA2. A new prompt after a revert branches fromA1andclears the redo stack.
New WebSocket frames
Client → server:
WsClientRevertCommand { messageId }— rewind to before that turn.WsClientRedoCommand— undo the most recent revert.Server → client:
WsServerHeadChangeEvent { headId, workflowContent, canRedo }— HEAD moved without a new step.canRedoadded toWsServerSnapshotEventso a reconnecting client can render the Redo state.Both commands are rejected with an error frame while the agent is
GENERATING(a mid-run rewind would race the loop's own HEAD/workflow mutations).Design decisions & alternatives considered
UndoManager). Agent turns produce many fine-grained operator edits; routing through undo/redo would create dozens of entries per turn and tangle with manual edits.reloadWorkflowalready clears the undo stack, so snapshot-replay is a cleaner primitive here.Open questions (feedback welcome)
Out of scope (for the initial PR)
Happy to adjust the design based on feedback before opening the PR. Prototype branch and tests are ready.
All reactions