fix(desktop): make draft persistence actually fire — new-chat sentinel, reload flush, session-switch clears
Manual testing of the salvaged draft persistence showed none of it worked end-to-end. Three distinct bugs, all invisible to the store-level unit tests: 1. New-chat drafts were never written. The skip-one-persist sentinel was reset to null after consuming, but null IS a real scope (the unsaved new-session draft) — so in a new chat every persist run matched the "consumed" sentinel and bailed. This silently killed the headline #38498 fix. Use undefined as the no-skip sentinel, which can never collide with a scope. 2. Cmd+R inside the debounce window dropped the trailing text. React does not run effect cleanups on a page reload, so the flush-on-unmount never fired; with the 400ms debounce that meant type-then-reload lost the draft every time. Flush pending writes on pagehide. 3. Session switch/new/resume/branch paths in use-session-actions cleared the composer stores synchronously with the session-id updates. React batches those, so by the time ChatBar's scope-change cleanup ran to stash the departing session's attachments, the store was already empty — the stash recorded [] and the chips were lost anyway. The composer's per-scope restore now owns composer contents wholesale on scope change, so drop the upstream clears (clearComposerDraft only touched the vestigial $composerDraft atom nothing reads). Co-authored-by: mollusk <roger@roger.local> Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
This commit is contained in:
co-authored by
mollusk
Teknium
parent
65ddc7c4a1
commit
fdc0d19566
@@ -8,7 +8,6 @@ import { type ChatMessage, chatMessageText, preserveLocalAssistantErrors, toChat
|
||||
import { normalizePersonalityValue } from '@/lib/chat-runtime'
|
||||
import { embeddedImageUrls, textWithoutEmbeddedImages } from '@/lib/embedded-images'
|
||||
import { setSessionYolo } from '@/lib/yolo-session'
|
||||
import { clearComposerAttachments, clearComposerDraft } from '@/store/composer'
|
||||
import { clearQueuedPrompts } from '@/store/composer-queue'
|
||||
import { $pinnedSessionIds } from '@/store/layout'
|
||||
import { clearNotifications, notify, notifyError } from '@/store/notifications'
|
||||
@@ -19,7 +18,6 @@ import {
|
||||
$messages,
|
||||
$sessions,
|
||||
$yoloActive,
|
||||
workspaceCwdForNewSession,
|
||||
sessionPinId,
|
||||
setActiveSessionId,
|
||||
setAwaitingResponse,
|
||||
@@ -41,7 +39,8 @@ import {
|
||||
setSessionStartedAt,
|
||||
setSessionsTotal,
|
||||
setTurnStartedAt,
|
||||
setYoloActive
|
||||
setYoloActive,
|
||||
workspaceCwdForNewSession
|
||||
} from '@/store/session'
|
||||
import { reportBackendContract } from '@/store/updates'
|
||||
import type { SessionCreateResponse, SessionInfo, SessionResumeResponse, UsageStats } from '@/types/hermes'
|
||||
@@ -329,8 +328,10 @@ export function useSessionActions({
|
||||
setYoloActive(false)
|
||||
setCurrentCwd(workspaceCwdForNewSession())
|
||||
setCurrentBranch('')
|
||||
clearComposerDraft()
|
||||
clearComposerAttachments()
|
||||
// Composer contents are owned by ChatBar's per-scope draft persistence:
|
||||
// the scope change triggered by the session-id updates above stashes the
|
||||
// departing session's attachments and restores this scope's draft.
|
||||
// Clearing here would wipe the departing stash before it's saved.
|
||||
setFreshDraftReady(true)
|
||||
},
|
||||
[activeSessionIdRef, busyRef, navigate, selectedStoredSessionIdRef]
|
||||
@@ -352,11 +353,13 @@ export function useSessionActions({
|
||||
// Pass the owning profile so a new chat under a non-launch profile (global
|
||||
// remote mode) builds its agent + persists against THAT profile's home/db.
|
||||
const newChatProfile = $newChatProfile.get()
|
||||
|
||||
const created = await requestGateway<SessionCreateResponse>('session.create', {
|
||||
cols: 96,
|
||||
...(cwd && { cwd }),
|
||||
...(newChatProfile ? { profile: newChatProfile } : {})
|
||||
})
|
||||
|
||||
const stored = created.stored_session_id ?? null
|
||||
|
||||
if (
|
||||
@@ -475,8 +478,6 @@ export function useSessionActions({
|
||||
setCurrentCwd(cachedState.cwd)
|
||||
setCurrentBranch(cachedState.branch)
|
||||
setSessionStartedAt(Date.now())
|
||||
clearComposerDraft()
|
||||
clearComposerAttachments()
|
||||
|
||||
try {
|
||||
const usage = await requestGateway<UsageStats>('session.usage', { session_id: cachedRuntimeId })
|
||||
@@ -606,8 +607,6 @@ export function useSessionActions({
|
||||
}),
|
||||
storedSessionId
|
||||
)
|
||||
clearComposerDraft()
|
||||
clearComposerAttachments()
|
||||
} catch (err) {
|
||||
if (!isCurrentResume()) {
|
||||
return
|
||||
@@ -730,8 +729,6 @@ export function useSessionActions({
|
||||
selectedStoredSessionIdRef.current = routedSessionId
|
||||
navigate(sessionRoute(routedSessionId))
|
||||
|
||||
clearComposerDraft()
|
||||
clearComposerAttachments()
|
||||
const runtimeInfo = applyRuntimeInfo(branched.info)
|
||||
|
||||
patchSessionWorkspace(routedSessionId, runtimeInfo?.cwd)
|
||||
|
||||
Reference in New Issue
Block a user