Skip to content

fix: preserve per-session input drafts when switching sessions - #14267

Closed
uriva wants to merge 2 commits into
anomalyco:devfrom
uriva:fix/per-session-input-state
Closed

fix: preserve per-session input drafts when switching sessions#14267
uriva wants to merge 2 commits into
anomalyco:devfrom
uriva:fix/per-session-input-state

Conversation

@uriva

@urivauriva commented Feb 19, 2026

Copy link
Copy Markdown

Issue for this PR

Closes#14263

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

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 sessionID changes, 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

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

CopilotAI review requested due to automatic review settings February 19, 2026 10:29
@github-actionsgithub-actionsBot added the needs:compliance This means the issue will auto-close after 2 hours. label Feb 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

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.

CopilotAI 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.

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.

FileDescription
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsxAdds 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.tsxUpdates 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.tsxSaves 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 drafts won’t be restored when (re)entering a session via route navigation that remounts Prompt (e.g., session -> home -> session), and the draft will appear lost. Consider running this logic on mount as well (e.g., remove defer: true and use the prev value provided by on() to only save when prevSessionID is defined, while always restoring for nextSessionID).
 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())
}

CopilotAIFeb 19, 2026

Copy link

Choose a reason for hiding this comment

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

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).

Suggested change
// Reset mode on session change to avoid inheriting modes like "shell"
setStore("mode","normal")

Copilot uses AI. Check for mistakes.
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] })

CopilotAIFeb 19, 2026

Copy link

Choose a reason for hiding this comment

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

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").

Suggested change
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]})
}elseif(route.data.type==="session"){
// Clear any stale draft when there is no current input
drafts.delete(route.data.sessionID)

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +15
import { usePromptRef } from "../context/prompt"
import { drafts } from "./prompt"

CopilotAIFeb 19, 2026

Copy link

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
@github-actionsgithub-actionsBot removed the needs:compliance This means the issue will auto-close after 2 hours. label Feb 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

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.
Closesanomalyco#14263
- 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
@uriva
urivaforce-pushed the fix/per-session-input-state branch from b81cc18 to b93ae10CompareFebruary 26, 2026 09:32
@uriva

uriva commented Mar 6, 2026

Copy link
Copy Markdown
Author

Friendly ping @thdxr@adamdotdevin — this one's been rebased and CI is green. Would love a review when you get a chance!

@github-actions

Copy link
Copy Markdown
Contributor

Closing this pull request because it has had no updates for more than 60 days. If you plan to continue working on it, feel free to reopen or open a new PR.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Input text should be per-session: switching sessions should not carry over or lose draft text

2 participants

@uriva