Skip to content

fix(jetbrains): keep unsent chat drafts during session navigation - #15132

Open
hdcodedev wants to merge 7 commits into
Kilo-Org:mainfrom
hdcodedev:fix/jetbrains-preserve-session-drafts
Open

hdcodedev wants to merge 7 commits into
Kilo-Org:mainfrom
hdcodedev:fix/jetbrains-preserve-session-drafts

Conversation

@hdcodedev

@hdcodedev hdcodedev commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Issue

Fixes #15066

Context

Unsent prompts and attachments could be lost when navigating between sessions or opening History. Starting a new session should also restore a retained anonymous draft.

Implementation

Keep draft text and attachments in memory separately from inactive session UIs. Timeout cleanup still disposes the UI and controller. Reopening an existing session reloads its history under the same session ID and restores the draft. Saved drafts are cleared when their session is deleted or the host closes.

Reuse hidden anonymous drafts during navigation. When worktree session creation recovers after a backend failure, transfer the fallback composer's draft into the persisted session and dispose the fallback UI.

Screenshots / Video

Before

new-chat-draft-lost-on-history.mp4

After

new-chat-draft-lost-on-history-after.mp4

How to Test

Manual/local verification

  • (agent) ./gradlew typecheck passed from packages/kilo-jetbrains/.
  • (agent) ./gradlew :frontend:test --tests ai.kilocode.client.session.SessionSidePanelManagerTest --tests ai.kilocode.client.agentManager.worktree.WorktreeSessionEditorManagerTest --tests ai.kilocode.client.session.ui.PromptPanelTest --tests ai.kilocode.client.session.subagent.SubagentSessionEditorHostTest passed: 189 tests.
  • (agent) Timeout coverage asserts UI disposal, the same session ID, reloaded history, restored text and attachments, and zero backend session-creation calls. Recovery coverage asserts draft transfer and fallback UI disposal.
  • (agent) git diff --cached --check passed.
  • (agent) git diff --check passed.
  • (human) Verified the implementation.

Reviewer test steps

  1. From packages/kilo-jetbrains/, run ./gradlew --no-configuration-cache runIdeSplitMode.
  2. In the Kilo tool window, start a new session, type a prompt, and attach a file. Open History and return. Confirm the prompt and attachment remain.
  3. Open another session, then start a new session. Confirm the earlier anonymous draft returns.
  4. Open an existing session with messages, enter a draft, attach a file, and open History. Wait longer than the configured inactivity timeout (kilo.session.inactive.disposeTimeoutMs), then reopen that session from History. Confirm its history and session ID remain, and the draft text and attachment return.
  5. Run the focused test command above. The worktree tests simulate failed creation followed by recovery, including recovery that finds an existing listed session, and assert that the fallback draft remains accessible.

Blocked checks and substitute verification

  • (agent) ./gradlew :frontend:detekt reports 2,196 existing findings under Java 21. Comparing against the current PR commit found the same findings and no added diagnostics. Typechecking and the focused tests pass.

Checklist

  • Issue linked above, or exception explained
  • Tests/verification described
  • Screenshots/video included for visual changes, or marked N/A
  • Changeset considered for user-facing changes
  • I personally reviewed the diff and can explain the changes, including any AI-assisted work.

@github-actions github-actions Bot added area:jetbrains JetBrains plugin community Opened by someone outside the Kilo team needs-triage Waiting for a maintainer to look labels Oct 15, 2026
@hdcodedev
hdcodedev marked this pull request as ready for review October 15, 2026 21:01
@hdcodedev hdcodedev changed the title fix(jetbrains): preserve session drafts during navigation fix(jetbrains): preserve session drafts during navigation and timeout cleanup Oct 15, 2026
@kilo-code-bot

kilo-code-bot Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

The incremental change (fix(jetbrains): preserve drafts through cleanup and recovery) resolves the two previously raised items. The timeout path now captures the composer draft and attachments into SessionHost.drafts before disposing the UI, and reopening reloads history under the same session id and restores the draft via create()/SessionUi.restore(). The worktree recovery gap is closed: WorktreeSessionEditorManager routes its create/reload success paths through SessionHost.recover(), which transfers the fallback composer's draft into the recovered persisted session and disposes the fallback UI.

Coverage matches the new behavior: test hidden session draft survives history timeout (disposal, same id, reloaded history, restored text + attachments, zero creates), test cleared restored draft stays empty after another timeout, test expired drafts stay with their own sessions, and test deleting expired session discards retained draft. The worktree retry tests now assert draft transfer and fallback disposal, including recovery that finds an already-listed session.

One design tradeoff, not a finding: a retained draft (which can hold a pasted image as a full base64 data URL) now survives kilo.session.inactive.disposeTimeoutMs until its session is reopened or deleted, or the host closes. That retention is the intended fix for #15066, and the heavyweight SessionUi (Swing tree, controller, model listeners) is still disposed, so only composer data is pinned.

Files Reviewed (8 files)
  • .changeset/quiet-drafts-remain.md
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeSessionEditorManager.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/SessionHost.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/SessionUi.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/model/PromptDraft.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/prompt/PromptPanel.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeSessionEditorManagerTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/SessionSidePanelManagerTest.kt
Previous Review Summaries (2 snapshots, latest commit 6194cde)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 6194cde)

Status: No Issues Found | Recommendation: Merge

The incremental change (fix(jetbrains): dispose inactive sessions after timeout) resolves the previously raised suggestion: the timeout callback no longer exempts draft-bearing hidden sessions, so a hidden session that holds a draft is disposed once kilo.session.inactive.disposeTimeoutMs elapses. The updated test test hidden session draft is discarded after timeout asserts the new behavior directly. The draft-preservation fix for navigation (release early-return for draft-bearing anonymous sessions, newSessionUi() reuse) is unaffected and remains covered by test anonymous draft survives history and back and test new session reuses hidden anonymous draft.

Note: the PR description and title still describe preserving drafts "during timeout cleanup" and manual test step 4 says to confirm the draft remains after the timeout, which no longer matches the implementation. Since that line is unchanged relative to main in the net PR diff, it is left to the human to reconcile the description rather than raised as a finding.

Files Reviewed (2 files)
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/SessionHost.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/SessionSidePanelManagerTest.kt

Previous review (commit 432e4ab)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 1
Issue Details (click to expand)

SUGGESTION

File Line Issue
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/SessionHost.kt 228 Draft-bearing hidden sessions are exempt from inactive disposal indefinitely; the timer returns without rescheduling, so the UI is never reconsidered for cleanup while hidden.

The core change is sound: reusing a retained anonymous draft for newSession/showNewSession and exempting draft-bearing UIs from release/timeout disposal correctly preserves prompts and attachments across navigation, history, and the inactivity timeout. Tests cover the history/back, reuse, and timeout/reopen paths.

One resource consideration: Schedule (SessionHost.kt:228) now returns when ui.hasDraft() after already removing the timer from activeTimers, so a hidden session with a draft is pinned (full SessionUi plus its Swing tree, controller, and model listeners) until it is shown and released again. Since a draft can hold a pasted image as a full base64 data URL, this can pin megabytes per hidden session. If indefinite retention is intended, a short comment would help; otherwise rescheduling the timer or disposing once the draft is cleared keeps cleanup bounded.

Fix these issues in Kilo Cloud

Files Reviewed (5 files)
  • .changeset/quiet-drafts-remain.md
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeSessionEditorManager.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/SessionHost.kt - 1 issue
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/SessionUi.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/SessionSidePanelManagerTest.kt

Reviewed by deepseek-v4.1-flash · Input: 86.2K · Output: 26.9K · Cached: 1.3M

Review guidance: REVIEW.md from base branch main

@hdcodedev hdcodedev changed the title fix(jetbrains): preserve session drafts during navigation and timeout cleanup fix(jetbrains): keep unsent chat drafts during session navigation Oct 15, 2026

@WebReflection WebReflection 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.

Thanks for fixing the immediate navigation loss. The 77 existing session/worktree tests pass, but independent preservation assertions reproduced the two gaps below. Please address them before treating this as a complete fix for #15066.

assertEquals(listOf("/test" to "ses_1", "/test" to "ses_2", "/test" to "ses_1"), created)
}

fun `test hidden session draft is discarded after timeout`() {

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.

The timeout case from #15066 remains unresolved: type a draft in an existing session, open History, wait for the inactivity timeout, then reopen the session. Its composer is empty. This test now asserts that loss rather than the issue requested behavior. Could we retain text and attachments separately from the disposable UI and assert restoration after expiry? This is an incomplete part of the original fix, not a new regression.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Draft text and attachments now survive timeout cleanup and return when reopening the same session, with regression coverage.

// mirrors the tool window; WorktreeSessionEditorPanel re-runs start() once
// migration finishes to create the real session.
if (currentUi() == null) showBlank()
if (currentUi() == null) showNewSession()

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.

The retained fallback draft can become unreachable on recovery: let initial creation fail, enter a draft in the fallback composer, then retry after the backend recovers. The success branch opens a fresh persisted UI with an empty composer. The new release guard retains the old draft/UI, but the worktree New Session override bypasses draft reuse and no list row exposes it. Please transfer/reuse the draft during recovery and extend the existing retry test to cover this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The fallback draft now moves into the recovered worktree session, and the retry test verifies that text and attachments survive

@github-actions github-actions Bot added awaiting-contributor Waiting for the contributor to reply priority:p1 High: fixes and regressions. Set from the title. Change by hand. and removed needs-triage Waiting for a maintainer to look labels Oct 16, 2026
@hdcodedev

Copy link
Copy Markdown
Contributor Author

@WebReflection I've addressed the latest changes as requested. It would probably be a good idea to retest everything, since I haven't tested the latest changes myself. I can help with that, but I don't have time today.

@hdcodedev

hdcodedev commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor Author

@WebReflection

1 . Each existing session keeps its own unique draft when switching between sessions

multiple-session-drafts-after.mp4
  1. After the inactivity cleanup timer fires, reopening the same session restores its saved messages and unsent draft.
session-timeout-draft-after.mp4
  1. When session creation initially fails, retrying after recovery creates a saved session and preserves the fallback draft.
worktree-recovery-draft-after.mp4

Note

Automatic database cleanup can delete an expired session even when it has an unsent draft, because drafts don’t protect sessions from deletion.

@github-actions github-actions Bot added needs-triage Waiting for a maintainer to look and removed awaiting-contributor Waiting for the contributor to reply labels Oct 19, 2026

This branch has not been deployed

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

Labels

area:jetbrains JetBrains plugin community Opened by someone outside the Kilo team needs-triage Waiting for a maintainer to look priority:p1 High: fixes and regressions. Set from the title. Change by hand.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Text typed in a new chat is lost after opening History

2 participants