mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-28 11:41:04 +00:00
* feat(cli): add conversation rewind feature with double-ESC and /rewind command (#3186) Add the ability to rewind conversation to a previous user turn, similar to Claude Code's message selector. Users can trigger rewind via: - Double-ESC on empty prompt while idle - /rewind (or /rollback) slash command The RewindSelector component provides a two-phase UI: a scrollable pick-list of user turns followed by a confirmation dialog. On confirm, both UI history and API history are truncated consistently, the terminal is re-rendered, and the original prompt text is pre-populated in the input for editing. Key implementation details: - historyMapping.ts correctly handles tool-call loops (functionResponse entries) and the startup context pair when mapping UI turns to API Content[] indices - useDoublePress hook provides generic double-press detection with 800ms timeout and proper cleanup on unmount - ESC handler guards against WaitingForConfirmation state to prevent accidental rewind during tool approval - Chat recording service records rewind events with tree-branching via parentUuid for session replay support Closes #3186 Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix: call recordRewind() in handleRewindConfirm and simplify payload - Actually invoke chatRecordingService.recordRewind() after rewind - Remove tree-branching from recordRewind (no UI-to-recording UUID mapping exists yet) to avoid corrupting the parentUuid chain - Simplify RewindRecordPayload to just truncatedCount Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test: add tmux-based E2E script for rewind feature Automated verification of all 5 manual test items from PR description: 1. /rewind command flow (pick turn, confirm, verify truncation) 2. Double-ESC opens selector (with btw dismiss handling) 3. ESC during streaming cancels (no rewind) 4. /rewind with no history (guard blocks) 5. After rewind, model ignores removed turns Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(rewind): resolve resume persistence and IDE mode issues - chatRecordingService: add turnParentUuids tracking and rewindRecording() which re-roots the parentUuid chain so rewound messages land on a dead branch; reconstructHistory() then skips them automatically on resume. Add rebuildTurnBoundaries() for re-populating the index after /resume. - AppContainer: fix truncatedCount bug (was always 0 after loadHistory), wire handleRewindConfirm to rewindRecording() with correct targetTurnIndex, add config.getIdeMode() guard to openRewindSelector so rewind is disabled in IDE sessions where extra user Content entries break the API boundary mapping. - useResumeCommand: call rebuildTurnBoundaries() after startNewSession so rewind works correctly within resumed sessions. - resumeHistoryUtils: surface "Conversation rewound." info item when a rewind record is encountered during history reconstruction. - historyMapping.test.ts: add 9 unit tests for computeApiTruncationIndex covering normal flow, startup context pair, tool responses, and compression fallback. - Copyright headers: standardize new files to "Copyright 2025 Qwen Code". 🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code) * fix(rewind): close slash-command, compression, and IDE bypass holes Three bugs found by Codex review: 1. P1: `/rewind` slash command bypassed the IDE-mode guard because `slashCommandActions.openRewindSelector` called `setIsRewindSelectorOpen` directly. Fixed by introducing a ref bridge (`openRewindSelectorRef`) that delegates to the guarded callback. 2. P1: Slash-command invocations (`/help`, `/stats`, etc.) are stored as `type: 'user'` in UI history but never reach the API or recording service. The turn-index counter in `handleRewindConfirm` and `computeApiTruncationIndex` counted them, producing off-by-N errors. Added `isRealUserTurn()` helper that excludes items starting with `/` or `?`, applied in all three counting sites (AppContainer, historyMapping, RewindSelector). 3. P2: After chat compression, `computeApiTruncationIndex` returned `apiHistory.length` when the target turn was unreachable, silently keeping the full API history while the UI was truncated. Changed to return `-1`; `handleRewindConfirm` now aborts with an error message when the target turn was absorbed by compression. Tests: 14 unit tests for historyMapping (including slash-command and compression cases), full suite 616/616 passed. 🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code) --------- Co-authored-by: jinye.djy <jinye.djy@alibaba-inc.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|---|---|---|
| .. | ||
| src | ||
| index.ts | ||
| package.json | ||
| test-setup.ts | ||
| tsconfig.json | ||
| vitest.config.ts | ||