Files
kandev/apps/web/hooks/domains/session/use-session-context-window.ts
T
2026-08-02 17:25:55 +01:00

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;
}