fix(message-input): persist draft across restarts by keying on conversation id

This commit is contained in:
xintaofei
2026-04-24 12:32:35 +08:00
parent f8d7c8966a
commit e9c3076197
3 changed files with 9 additions and 31 deletions

View File

@@ -407,7 +407,7 @@ export function MessageInput({
[tExperts] [tExperts]
) )
const { shortcuts } = useShortcutSettings() const { shortcuts } = useShortcutSettings()
const effectiveDraftStorageKey = draftStorageKey ?? attachmentTabId ?? null const effectiveDraftStorageKey = draftStorageKey ?? null
const resolvedPlaceholder = placeholder ?? t("askAnything") const resolvedPlaceholder = placeholder ?? t("askAnything")
const [text, setText] = useState(() => { const [text, setText] = useState(() => {
if (!effectiveDraftStorageKey) return "" if (!effectiveDraftStorageKey) return ""

View File

@@ -66,7 +66,7 @@ import {
import { import {
buildConversationDraftStorageKey, buildConversationDraftStorageKey,
buildNewConversationDraftStorageKey, buildNewConversationDraftStorageKey,
moveMessageInputDraft, clearMessageInputDraft,
} from "@/lib/message-input-draft" } from "@/lib/message-input-draft"
import { import {
ContextMenu, ContextMenu,
@@ -268,10 +268,10 @@ const ConversationTabView = memo(function ConversationTabView({
const externalId = detail?.summary.external_id ?? undefined const externalId = detail?.summary.external_id ?? undefined
const draftStorageKey = useMemo(() => { const draftStorageKey = useMemo(() => {
if (dbConversationId != null) { if (dbConversationId != null) {
return buildConversationDraftStorageKey(selectedAgent, dbConversationId) return buildConversationDraftStorageKey(dbConversationId)
} }
return buildNewConversationDraftStorageKey({ tabId }) return buildNewConversationDraftStorageKey()
}, [dbConversationId, tabId, selectedAgent]) }, [dbConversationId])
// Use the per-tab workingDir (derived from the tab's own folderId by the // Use the per-tab workingDir (derived from the tab's own folderId by the
// parent) rather than the active folder's path — otherwise switching tabs // parent) rather than the active folder's path — otherwise switching tabs
// briefly exposes the previous folder's path to the ACP auto-connect // briefly exposes the previous folder's path to the ACP auto-connect
@@ -625,10 +625,7 @@ const ConversationTabView = memo(function ConversationTabView({
title, title,
effectiveConversationId effectiveConversationId
) )
moveMessageInputDraft( clearMessageInputDraft(buildNewConversationDraftStorageKey())
buildNewConversationDraftStorageKey({ tabId }),
buildConversationDraftStorageKey(selectedAgent, newConversationId)
)
statusUpdatedRef.current = false statusUpdatedRef.current = false
// If the turn already finished while we were creating the // If the turn already finished while we were creating the
// conversation, apply the deferred status directly instead // conversation, apply the deferred status directly instead

View File

@@ -1,7 +1,5 @@
"use client" "use client"
import type { AgentType } from "@/lib/types"
interface PersistedDraftState { interface PersistedDraftState {
text: string text: string
} }
@@ -83,16 +81,13 @@ function scheduleDraftPersistence(): void {
} }
export function buildConversationDraftStorageKey( export function buildConversationDraftStorageKey(
agentType: AgentType,
conversationId: number conversationId: number
): string { ): string {
return `conv:${agentType}:${conversationId}` return `conv:${conversationId}`
} }
export function buildNewConversationDraftStorageKey(params: { export function buildNewConversationDraftStorageKey(): string {
tabId: string return "new"
}): string {
return `new:${params.tabId}`
} }
export function loadMessageInputDraft(draftKey: string): string | null { export function loadMessageInputDraft(draftKey: string): string | null {
@@ -137,17 +132,3 @@ export function clearMessageInputDraft(draftKey: string): void {
/* ignore */ /* ignore */
} }
} }
export function moveMessageInputDraft(
fromDraftKey: string,
toDraftKey: string
): void {
if (fromDraftKey === toDraftKey) return
const sourceText = loadMessageInputDraft(fromDraftKey)
const targetText = loadMessageInputDraft(toDraftKey)
if (sourceText && !targetText) {
saveMessageInputDraft(toDraftKey, sourceText)
}
clearMessageInputDraft(fromDraftKey)
}