fix: preserve per-session input drafts when switching sessions#14267
fix: preserve per-session input drafts when switching sessions#14267uriva wants to merge 2 commits intoanomalyco:devfrom
Conversation
Store each session's draft input in a module-level Map so that switching between sessions restores the text the user was typing. Previously, switching sessions either lost the draft or carried it to the new session. Closes anomalyco#14263
|
The following comment was made by an LLM, it may be inaccurate: Based on my search, I found one potentially related PR that may have addressed a similar concern: Related PR:
This PR (14267) appears to be the primary/only PR specifically focused on preserving per-session input drafts when switching between sessions. The related PR above handles a narrower case (new session creation), while your PR takes a broader approach by storing drafts in a Map for all session switches. No other duplicate PRs found for the specific feature of preserving input drafts across session switches. |
There was a problem hiding this comment.
Pull request overview
This PR adds per-session draft preservation for the TUI prompt so that switching between sessions (and navigating via dialogs/commands) no longer loses or leaks the input buffer between sessions.
Changes:
- Introduces a module-level
drafts: Map<string, PromptInfo>to persist drafts keyed by session ID. - Saves the current session’s draft on session switch / navigation, and restores the target session’s draft (or clears the prompt if none exists).
- Clears the stored draft for a session on submit to avoid resurrecting already-sent prompts.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx |
Adds the per-session drafts map and session-change effect to save/restore prompt drafts; clears draft on submit. |
packages/opencode/src/cli/cmd/tui/app.tsx |
Updates the “New session” command to save the current session draft into drafts instead of passing it to the home route. |
packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx |
Saves the current session draft before navigating to the selected session from the session list dialog. |
Comments suppressed due to low confidence (1)
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx:171
- The session-switch effect is deferred, so it won’t run on initial mount. This means drafts saved in
draftswon’t be restored when (re)entering a session via route navigation that remountsPrompt(e.g., session -> home -> session), and the draft will appear lost. Consider running this logic on mount as well (e.g., removedefer: trueand use theprevvalue provided byon()to only save whenprevSessionIDis defined, while always restoring fornextSessionID).
let previousSessionID: string | undefined = props.sessionID
createEffect(
on(
() => props.sessionID,
(nextSessionID) => {
// Save current draft for the previous session
if (previousSessionID && store.prompt.input) {
drafts.set(previousSessionID, { input: store.prompt.input, parts: [...store.prompt.parts] })
} else if (previousSessionID) {
drafts.delete(previousSessionID)
}
// Restore draft for the new session or clear
const draft = nextSessionID ? drafts.get(nextSessionID) : undefined
if (draft) {
input.setText(draft.input)
setStore("prompt", { input: draft.input, parts: draft.parts })
restoreExtmarksFromParts(draft.parts)
input.gotoBufferEnd()
} else {
input.clear()
input.extmarks.clear()
setStore("prompt", { input: "", parts: [] })
setStore("extmarkToPartIndex", new Map())
}
previousSessionID = nextSessionID
setStore("placeholder", Math.floor(Math.random() * PLACEHOLDERS.length))
},
{ defer: true },
),
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| setStore("prompt", { input: "", parts: [] }) | ||
| setStore("extmarkToPartIndex", new Map()) | ||
| } | ||
|
|
There was a problem hiding this comment.
On session switch, store.mode is not reset/restored. If the user is in shell mode in one session and switches sessions, the new session can inherit shell mode and submit the restored/empty input via sdk.client.session.shell(...) unexpectedly. Consider resetting mode to normal when changing sessions (or persisting/restoring mode per session along with the draft).
| // Reset mode on session change to avoid inheriting modes like "shell" | |
| setStore("mode", "normal") |
| const currentPrompt = current?.current?.input ? current.current : undefined | ||
| // Save draft for the current session instead of carrying it to home | ||
| if (current?.current?.input && route.data.type === "session") { | ||
| drafts.set(route.data.sessionID, { input: current.current.input, parts: [...current.current.parts] }) |
There was a problem hiding this comment.
When navigating to home via “New session”, this only drafts.set(...) when there is input, but never clears an existing draft when the prompt was emptied. If the user cleared the input and then triggers “New session”, the stale draft for that session will remain in drafts and be restored later. Mirror the session-switch behavior by drafts.delete(route.data.sessionID) when there’s no input (and only when route.data.type === "session").
| drafts.set(route.data.sessionID, { input: current.current.input, parts: [...current.current.parts] }) | |
| drafts.set(route.data.sessionID, { input: current.current.input, parts: [...current.current.parts] }) | |
| } else if (route.data.type === "session") { | |
| // Clear any stale draft when there is no current input | |
| drafts.delete(route.data.sessionID) |
| import { usePromptRef } from "../context/prompt" | ||
| import { drafts } from "./prompt" |
There was a problem hiding this comment.
With drafts now imported/used here, session deletion in this dialog (the delete keybind handler below) should also clear any saved draft for the deleted session. Otherwise drafts for deleted sessions can accumulate and potentially be restored later if the ID is referenced again.
- Reset mode to normal on session switch to prevent shell mode leaking - Delete stale drafts when input is empty in 'New session' handler - Clear draft when a session is deleted from session list dialog - Remove defer:true and use on() prev arg so drafts restore on remount
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
Issue for this PR
Closes #14263
Type of change
What does this PR do?
Switching sessions lost or leaked draft input text. This stores drafts in a per-session Map so each session keeps its own input state independently.
Three touch points save/restore drafts: the reactive effect in Prompt when
sessionIDchanges, the "new session" command in app.tsx, and the session list dialog. Drafts are cleared on submit and on session deletion.How did you verify your code works?
Typecheck passes. Manually tested: type text in session A, switch to session B (text gone, fresh input), switch back to A (text restored), submit (draft cleared). Also verified new session, child session cycling, and session deletion all behave correctly.
Screenshots / recordings
N/A — behavior change only, no visual changes.
Checklist