86 lines
3.1 KiB
TypeScript
86 lines
3.1 KiB
TypeScript
import { useEffect, useMemo } from "react";
|
|
import { useAppStore } from "@/components/state-provider";
|
|
import { getWebSocketClient } from "@/lib/ws/connection";
|
|
import type { ContextWindowEntry } from "@/lib/state/store";
|
|
import { parseContextWindowEntry } from "@/lib/state/slices/session-runtime/context-window";
|
|
|
|
export function useSessionContextWindow(sessionId: string | null): ContextWindowEntry | undefined {
|
|
// Subscribe to individual primitive values to ensure reactivity
|
|
const size = useAppStore((state) =>
|
|
sessionId ? state.contextWindow.bySessionId[sessionId]?.size : undefined,
|
|
);
|
|
const used = useAppStore((state) =>
|
|
sessionId ? state.contextWindow.bySessionId[sessionId]?.used : undefined,
|
|
);
|
|
const remaining = useAppStore((state) =>
|
|
sessionId ? state.contextWindow.bySessionId[sessionId]?.remaining : undefined,
|
|
);
|
|
const efficiency = useAppStore((state) =>
|
|
sessionId ? state.contextWindow.bySessionId[sessionId]?.efficiency : undefined,
|
|
);
|
|
const compactionCount = useAppStore((state) =>
|
|
sessionId ? state.contextWindow.bySessionId[sessionId]?.compactionCount : undefined,
|
|
);
|
|
const source = useAppStore((state) =>
|
|
sessionId ? state.contextWindow.bySessionId[sessionId]?.source : undefined,
|
|
);
|
|
const timestamp = useAppStore((state) =>
|
|
sessionId ? state.contextWindow.bySessionId[sessionId]?.timestamp : undefined,
|
|
);
|
|
|
|
// Memoize the combined object
|
|
const contextWindow = useMemo(() => {
|
|
if (size === undefined) return undefined;
|
|
return {
|
|
size,
|
|
used: used ?? 0,
|
|
remaining: remaining ?? 0,
|
|
efficiency: efficiency ?? 0,
|
|
compactionCount: compactionCount ?? 0,
|
|
source,
|
|
timestamp,
|
|
};
|
|
}, [size, used, remaining, efficiency, compactionCount, source, timestamp]);
|
|
|
|
const session = useAppStore((state) =>
|
|
sessionId ? state.taskSessions.items[sessionId] : undefined,
|
|
);
|
|
const setContextWindow = useAppStore((state) => state.setContextWindow);
|
|
const connectionStatus = useAppStore((state) => state.connection.status);
|
|
|
|
// Populate context window from session metadata if not already in store
|
|
useEffect(() => {
|
|
if (!sessionId || contextWindow) return;
|
|
|
|
// Try to extract context_window from session metadata
|
|
const metadata = session?.metadata;
|
|
if (!metadata || typeof metadata !== "object") return;
|
|
|
|
const storedContextWindow = (metadata as Record<string, unknown>).context_window;
|
|
const entry = parseContextWindowEntry(
|
|
storedContextWindow,
|
|
undefined,
|
|
(metadata as Record<string, unknown>).context_compaction_count,
|
|
);
|
|
if (!entry) return;
|
|
|
|
setContextWindow(sessionId, entry);
|
|
}, [sessionId, contextWindow, session?.metadata, setContextWindow]);
|
|
|
|
// Subscribe to session updates via WebSocket
|
|
useEffect(() => {
|
|
if (!sessionId) return;
|
|
if (connectionStatus !== "connected") return;
|
|
const client = getWebSocketClient();
|
|
if (client) {
|
|
const unsubscribe = client.subscribeSession(sessionId);
|
|
return () => {
|
|
unsubscribe();
|
|
// Don't clear context window on cleanup - keep it cached
|
|
};
|
|
}
|
|
}, [sessionId, connectionStatus]);
|
|
|
|
return contextWindow;
|
|
}
|