Repository navigation
feat(http): take the last plain question and answer back - #1162
Draft
sosidudku1 wants to merge 2 commits into
Draft
sosidudku1 wants to merge 2 commits into
sosidudku1 wants to merge 2 commits into
Conversation
Adds truncateSessionAt, which cuts a chat back to an earlier row and
fixes every field that remembers a position in the transcript (macro-turn
boundaries, the held pack start, the rolling summary, the cloud context,
the context gauge), and planLastTurnRollback, which allows it only for a
turn that changed nothing outside the transcript.
POST /api/sessions/{id}/rollback-last-turn uses them so a client can ask
the same question again without the model reading the old answer.
Retry used to resend the question on top of the old pair, so the chat
showed it twice and the model saw both tries.
Refs ATO-1297, ATO-1298
This was referenced Nov 10, 2026
…tion A stop that lands during a tool batch leaves a local turn stored as [question, stop marker]: the cancelled step is not committed, so the transcript shows no tool even though one ran. Taking such a turn back and resending it could run the tool a second time and drops the only trace of the stop. Stopped turns are now refused with turn_stopped. expectText alone cannot tell two questions with the same text apart: when a failed "continue" never reached the store, the stored last question is an earlier "continue" with a real answer. Clients can now also send expectPriorQuestions, the number of questions before the one they mean (steers not counted); a different count refuses with turn_mismatch. Refs ATO-1298
This branch has not been deployed
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.
What
Adds
POST /api/sessions/{id}/rollback-last-turn. It removes the chat's last question and its answer and returns200 { id, text }with the question's text. The client then sendstextagain through/v1/chat/completions, so a retry runs the same path as a first try. Before this, "retry" in every client resent the question on top of the old pair: the chat showed it twice and the model read its first answer before answering again.src/session/session-truncate.ts:truncateSessionAt(state, index)cuts a chat back to an earlier row and fixes every field that remembers a transcript position:macroTurnStarts,turnCount, the heldconversationPackStart,rollingSummary, the cloud context mirror (trimmed so the next extension does not throw),contextUsage,lastError, status back topending. A compaction checkpoint that covers the cut is reported, not repaired. No tool policy here, so/rewindand editing a sent message can reuse it.planLastTurnRollback(state, { expectText? })allows it only for a turn that changed nothing outside the transcript: a question answered by one reply, or by nothing (a provider error). A stopped turn is refused (turn_stopped): a stop can cut a tool batch short, and a local turn stores no trace of that step, so a resend could run the tool twice.409with acode:turn_in_progress,turn_has_tools,turn_steered,turn_compacted,turn_stopped,nothing_to_undo,turn_unrecognized,turn_mismatch.expectTextandexpectPriorQuestionsname the question the client means, by its text and by how many questions come before it (steers not counted). If the stored last question differs in either (for example a failed "continue" that never reached the store, after an earlier "continue"), the answer isturn_mismatchand nothing is removed. An unknown chat is404 session_not_found. An agent without the route answers 404 with no code, which is how a client tells the two apart.Why
It is the base for a real Regenerate in the desktop and a real
[try again]in the terminal. Tool turns are refused on purpose: their effects stay, so a resend would not be a fresh try of the same question. Limits, also written insrc/http/README.md: what the turn's reflection already wrote to long-term memory stays, and a chat cut back to nothing keeps its title.Related PRs: #1164 (terminal retry, stacked on this branch) and #1165 (desktop bridge and buttons, on
rel/xp-build).How it was verified
src/session/session-truncate.test.ts,src/http/route-rollback-last-turn.test.ts.Refs ATO-1297, ATO-1298
Not yet checked on the second Mac.