From 31e6c31acf670ca1be59deb6174e460213c1fe94 Mon Sep 17 00:00:00 2001 From: Alan Wizemann Date: Fri, 1 May 2026 15:28:59 +0200 Subject: [PATCH] fix(chat): scope composer state to active session id (#62) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `RichChatInputBar`'s `@State` `text` and `attachments` survived session switches because the surrounding view tree is structurally identical across sessions — SwiftUI happily reused the same instance and leaked the previous session's unsent draft into the new one. Bind the composer's identity to `richChat.sessionId` so SwiftUI rebuilds the view (and its `@State`) on session change. A stable fallback string covers the brief "no session selected" window; using `UUID()` here would mint a fresh id on every render and trash the composer per body re-eval. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Features/Chat/Views/ChatTranscriptPane.swift | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scarf/scarf/Features/Chat/Views/ChatTranscriptPane.swift b/scarf/scarf/Features/Chat/Views/ChatTranscriptPane.swift index f3e9a0f..eaa8294 100644 --- a/scarf/scarf/Features/Chat/Views/ChatTranscriptPane.swift +++ b/scarf/scarf/Features/Chat/Views/ChatTranscriptPane.swift @@ -44,12 +44,23 @@ struct ChatTranscriptPane: View { if let hint = richChat.transientHint { steeringToast(hint) } + // Issue #62: bind composer identity to the active session + // ID so SwiftUI rebuilds `RichChatInputBar` (and its + // `@State` `text`/`attachments`) when the user switches + // conversations. Without this the composer is structurally + // identical across sessions and SwiftUI happily reuses the + // instance, leaking the unsent draft into the new session. + // A stable fallback id covers the brief "no session + // selected" window — using `UUID()` here would mint a + // fresh value per render and trash the composer on every + // body re-eval. RichChatInputBar( onSend: onSend, isEnabled: isEnabled, commands: richChat.availableCommands, showCompressButton: richChat.supportsCompress && !richChat.hasBroaderCommandMenu ) + .id(richChat.sessionId ?? "scarf.chat.no-session") } .background(ScarfColor.backgroundPrimary) }