临时会话被顶替后立即断开连接

This commit is contained in:
itpkcn@gmail.com
2026-03-21 10:45:41 +08:00
parent 954e5e60e0
commit e002280cf6
2 changed files with 36 additions and 0 deletions

View File

@@ -13,6 +13,7 @@ import { Plus, RefreshCw, X } from "lucide-react"
import { useTranslations } from "next-intl" import { useTranslations } from "next-intl"
import { toast } from "sonner" import { toast } from "sonner"
import { disposeTauriListener } from "@/lib/tauri-listener" import { disposeTauriListener } from "@/lib/tauri-listener"
import { useAcpActions } from "@/contexts/acp-connections-context"
import { useFolderContext } from "@/contexts/folder-context" import { useFolderContext } from "@/contexts/folder-context"
import { useTabContext } from "@/contexts/tab-context" import { useTabContext } from "@/contexts/tab-context"
import { useSessionStats } from "@/contexts/session-stats-context" import { useSessionStats } from "@/contexts/session-stats-context"
@@ -941,7 +942,9 @@ export function ConversationDetailPanel() {
openNewConversationTab, openNewConversationTab,
closeTab, closeTab,
switchTab, switchTab,
onPreviewTabReplaced,
} = useTabContext() } = useTabContext()
const { disconnect: disconnectByKey } = useAcpActions()
const [reloadByTabId, setReloadByTabId] = useState<Record<string, number>>({}) const [reloadByTabId, setReloadByTabId] = useState<Record<string, number>>({})
const tabsRef = useRef(tabs) const tabsRef = useRef(tabs)
const conversationsRef = useRef(conversations) const conversationsRef = useRef(conversations)
@@ -954,6 +957,13 @@ export function ConversationDetailPanel() {
conversationsRef.current = conversations conversationsRef.current = conversations
}, [conversations]) }, [conversations])
// Disconnect the old connection immediately when a preview tab is replaced
useEffect(() => {
return onPreviewTabReplaced((replacedTabId) => {
disconnectByKey(replacedTabId).catch(() => {})
})
}, [onPreviewTabReplaced, disconnectByKey])
// Background turn_complete handler: for conversations not open in tabs // Background turn_complete handler: for conversations not open in tabs
useEffect(() => { useEffect(() => {
let cancelled = false let cancelled = false

View File

@@ -67,6 +67,7 @@ interface TabContextValue {
runtimeConversationId: number runtimeConversationId: number
) => void ) => void
reorderTabs: (reorderedTabs: TabItem[]) => void reorderTabs: (reorderedTabs: TabItem[]) => void
onPreviewTabReplaced: (callback: (tabId: string) => void) => () => void
} }
const TabContext = createContext<TabContextValue | null>(null) const TabContext = createContext<TabContextValue | null>(null)
@@ -166,6 +167,20 @@ export function TabProvider({ children }: TabProviderProps) {
conversationsRef.current = conversations conversationsRef.current = conversations
}, [conversations]) }, [conversations])
// Callback set for preview tab replacement notifications
const previewReplacedCallbacksRef = useRef(
new Set<(tabId: string) => void>()
)
const onPreviewTabReplaced = useCallback(
(callback: (tabId: string) => void) => {
previewReplacedCallbacksRef.current.add(callback)
return () => {
previewReplacedCallbacksRef.current.delete(callback)
}
},
[]
)
// Restore tabs from folder.opened_conversations when folder first loads // Restore tabs from folder.opened_conversations when folder first loads
const [restoredFolderId, setRestoredFolderId] = useState<number | null>(() => const [restoredFolderId, setRestoredFolderId] = useState<number | null>(() =>
selectedConversation ? folderId : null selectedConversation ? folderId : null
@@ -328,6 +343,7 @@ export function TabProvider({ children }: TabProviderProps) {
title?: string title?: string
) => { ) => {
let activateTabId: string | undefined let activateTabId: string | undefined
let replacedPreviewTabId: string | undefined
setTabs((prev) => { setTabs((prev) => {
const existingIndex = findTabIndexForConversation( const existingIndex = findTabIndexForConversation(
@@ -375,6 +391,7 @@ export function TabProvider({ children }: TabProviderProps) {
// Preview (not pinned): replace existing preview tab // Preview (not pinned): replace existing preview tab
const previewIndex = prev.findIndex((t) => !t.isPinned) const previewIndex = prev.findIndex((t) => !t.isPinned)
if (previewIndex >= 0) { if (previewIndex >= 0) {
replacedPreviewTabId = prev[previewIndex].id
const updated = [...prev] const updated = [...prev]
updated[previewIndex] = newTab updated[previewIndex] = newTab
return updated return updated
@@ -383,6 +400,13 @@ export function TabProvider({ children }: TabProviderProps) {
return [...prev, newTab] return [...prev, newTab]
}) })
// Notify listeners about the replaced preview tab
if (replacedPreviewTabId) {
for (const cb of previewReplacedCallbacksRef.current) {
cb(replacedPreviewTabId)
}
}
if (activateTabId) { if (activateTabId) {
setActiveTabId(activateTabId) setActiveTabId(activateTabId)
} }
@@ -642,6 +666,7 @@ export function TabProvider({ children }: TabProviderProps) {
bindConversationTab, bindConversationTab,
setTabRuntimeConversationId, setTabRuntimeConversationId,
reorderTabs, reorderTabs,
onPreviewTabReplaced,
}), }),
[ [
tabs, tabs,
@@ -659,6 +684,7 @@ export function TabProvider({ children }: TabProviderProps) {
bindConversationTab, bindConversationTab,
setTabRuntimeConversationId, setTabRuntimeConversationId,
reorderTabs, reorderTabs,
onPreviewTabReplaced,
] ]
) )