之前是会话tab激活的会话不被空闲回收,现在改为会话tab所有的会话都不被空闲回收
This commit is contained in:
@@ -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}`}
|
||||||
|
|||||||
@@ -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,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user