之前是会话tab激活的会话不被空闲回收,现在改为会话tab所有的会话都不被空闲回收

This commit is contained in:
xintaofei
2026-03-22 21:45:45 +08:00
parent 06ac2be0b1
commit 046289748b
2 changed files with 37 additions and 3 deletions

View File

@@ -1,6 +1,13 @@
"use client" "use client"
import { Suspense, useCallback, useEffect, useRef, useState } from "react" import {
Suspense,
useMemo,
useCallback,
useEffect,
useRef,
useState,
} from "react"
import { useSearchParams } from "next/navigation" import { useSearchParams } from "next/navigation"
import type { ImperativePanelGroupHandle } from "react-resizable-panels" import type { ImperativePanelGroupHandle } from "react-resizable-panels"
import { FolderTitleBar } from "@/components/layout/folder-title-bar" import { FolderTitleBar } from "@/components/layout/folder-title-bar"
@@ -9,9 +16,12 @@ import { StatusBar } from "@/components/layout/status-bar"
import { FolderProvider } from "@/contexts/folder-context" import { FolderProvider } from "@/contexts/folder-context"
import { TaskProvider } from "@/contexts/task-context" import { TaskProvider } from "@/contexts/task-context"
import { AlertProvider } from "@/contexts/alert-context" import { AlertProvider } from "@/contexts/alert-context"
import { AcpConnectionsProvider } from "@/contexts/acp-connections-context" import {
AcpConnectionsProvider,
useAcpActions,
} from "@/contexts/acp-connections-context"
import { ConversationRuntimeProvider } from "@/contexts/conversation-runtime-context" import { ConversationRuntimeProvider } from "@/contexts/conversation-runtime-context"
import { TabProvider } from "@/contexts/tab-context" import { TabProvider, useTabContext } from "@/contexts/tab-context"
import { SessionStatsProvider } from "@/contexts/session-stats-context" import { SessionStatsProvider } from "@/contexts/session-stats-context"
import { SidebarProvider, useSidebarContext } from "@/contexts/sidebar-context" import { SidebarProvider, useSidebarContext } from "@/contexts/sidebar-context"
import { import {
@@ -58,6 +68,17 @@ const MIN_CENTER_WIDTH_PX = 420
const MIN_WORKSPACE_HEIGHT_PX = 220 const MIN_WORKSPACE_HEIGHT_PX = 220
const LAYOUT_EPSILON = 0.25 const LAYOUT_EPSILON = 0.25
/** Syncs open tab keys from TabProvider to AcpConnectionsProvider */
function TabKeysSync() {
const { tabs } = useTabContext()
const { registerOpenTabKeys } = useAcpActions()
const keys = useMemo(() => new Set(tabs.map((t) => t.id)), [tabs])
useEffect(() => {
registerOpenTabKeys(keys)
}, [keys, registerOpenTabKeys])
return null
}
function isSameLayout(a: number[], b: number[]): boolean { function isSameLayout(a: number[], b: number[]): boolean {
if (a.length !== b.length) return false if (a.length !== b.length) return false
return a.every((value, index) => Math.abs(value - b[index]) <= LAYOUT_EPSILON) return a.every((value, index) => Math.abs(value - b[index]) <= LAYOUT_EPSILON)
@@ -649,6 +670,7 @@ function FolderLayoutInner({ children }: { children: React.ReactNode }) {
<ConversationRuntimeProvider> <ConversationRuntimeProvider>
<WorkspaceProvider key={`workspace-${normalizedFolderId}`}> <WorkspaceProvider key={`workspace-${normalizedFolderId}`}>
<TabProvider> <TabProvider>
<TabKeysSync />
<SessionStatsProvider> <SessionStatsProvider>
<SidebarProvider <SidebarProvider
key={`left-sidebar-${normalizedFolderId}`} key={`left-sidebar-${normalizedFolderId}`}

View File

@@ -1082,6 +1082,7 @@ export interface AcpActionsValue {
): Promise<void> ): Promise<void>
setActiveKey(key: string | null): void setActiveKey(key: string | null): void
touchActivity(contextKey: string): void touchActivity(contextKey: string): void
registerOpenTabKeys(keys: Set<string>): void
} }
const AcpActionsContext = createContext<AcpActionsValue | null>(null) const AcpActionsContext = createContext<AcpActionsValue | null>(null)
@@ -1147,6 +1148,9 @@ export function AcpConnectionsProvider({ children }: { children: ReactNode }) {
// connectionId → contextKey reverse mapping // connectionId → contextKey reverse mapping
const reverseMapRef = useRef(new Map<string, string>()) const reverseMapRef = useRef(new Map<string, string>())
// Open tab keys — updated by child TabProvider via registerOpenTabKeys
const openTabKeysRef = useRef(new Set<string>())
// Guard against concurrent connect() calls // Guard against concurrent connect() calls
const connectingKeysRef = useRef(new Set<string>()) const connectingKeysRef = useRef(new Set<string>())
// Keys whose disconnect was requested while connect was still in flight // Keys whose disconnect was requested while connect was still in flight
@@ -1309,6 +1313,10 @@ export function AcpConnectionsProvider({ children }: { children: ReactNode }) {
lastActivityRef.current.set(contextKey, Date.now()) lastActivityRef.current.set(contextKey, Date.now())
}, []) }, [])
const registerOpenTabKeys = useCallback((keys: Set<string>) => {
openTabKeysRef.current = keys
}, [])
const flushStreamingQueue = useCallback(() => { const flushStreamingQueue = useCallback(() => {
flushTimerRef.current = null flushTimerRef.current = null
const queued = streamingQueueRef.current const queued = streamingQueueRef.current
@@ -1649,9 +1657,11 @@ export function AcpConnectionsProvider({ children }: { children: ReactNode }) {
const now = Date.now() const now = Date.now()
const currentActiveKey = storeRef.current.activeKey const currentActiveKey = storeRef.current.activeKey
const currentOpenTabKeys = openTabKeysRef.current
const toDisconnect: { contextKey: string; connectionId: string }[] = [] const toDisconnect: { contextKey: string; connectionId: string }[] = []
for (const [contextKey, conn] of storeRef.current.connections) { for (const [contextKey, conn] of storeRef.current.connections) {
if (contextKey === currentActiveKey) continue if (contextKey === currentActiveKey) continue
if (currentOpenTabKeys.has(contextKey)) continue
if ( if (
conn.status === "prompting" || conn.status === "prompting" ||
conn.status === "connecting" || conn.status === "connecting" ||
@@ -1923,6 +1933,7 @@ export function AcpConnectionsProvider({ children }: { children: ReactNode }) {
respondPermission, respondPermission,
setActiveKey, setActiveKey,
touchActivity, touchActivity,
registerOpenTabKeys,
}), }),
[ [
connect, connect,
@@ -1935,6 +1946,7 @@ export function AcpConnectionsProvider({ children }: { children: ReactNode }) {
respondPermission, respondPermission,
setActiveKey, setActiveKey,
touchActivity, touchActivity,
registerOpenTabKeys,
] ]
) )