import { createSignal } from "solid-js" import type { Session, Agent, Provider } from "../types/session" export interface SessionInfo { cost: number contextWindow: number isSubscriptionModel: boolean inputTokens: number outputTokens: number reasoningTokens: number actualUsageTokens: number modelOutputLimit: number contextAvailableTokens: number | null } const [sessions, setSessions] = createSignal>>(new Map()) const [activeSessionId, setActiveSessionId] = createSignal>(new Map()) const [activeParentSessionId, setActiveParentSessionId] = createSignal>(new Map()) const [agents, setAgents] = createSignal>(new Map()) const [providers, setProviders] = createSignal>(new Map()) const [sessionDraftPrompts, setSessionDraftPrompts] = createSignal>(new Map()) const [loading, setLoading] = createSignal({ fetchingSessions: new Map(), creatingSession: new Map(), deletingSession: new Map>(), loadingMessages: new Map>(), }) const [messagesLoaded, setMessagesLoaded] = createSignal>>(new Map()) const [sessionInfoByInstance, setSessionInfoByInstance] = createSignal>>(new Map()) function getDraftKey(instanceId: string, sessionId: string): string { return `${instanceId}:${sessionId}` } function getSessionDraftPrompt(instanceId: string, sessionId: string): string { if (!instanceId || !sessionId) return "" const key = getDraftKey(instanceId, sessionId) return sessionDraftPrompts().get(key) ?? "" } function setSessionDraftPrompt(instanceId: string, sessionId: string, value: string) { const key = getDraftKey(instanceId, sessionId) setSessionDraftPrompts((prev) => { const next = new Map(prev) if (!value) { next.delete(key) } else { next.set(key, value) } return next }) } function clearSessionDraftPrompt(instanceId: string, sessionId: string) { const key = getDraftKey(instanceId, sessionId) setSessionDraftPrompts((prev) => { if (!prev.has(key)) return prev const next = new Map(prev) next.delete(key) return next }) } function clearInstanceDraftPrompts(instanceId: string) { if (!instanceId) return setSessionDraftPrompts((prev) => { let changed = false const next = new Map(prev) const prefix = `${instanceId}:` for (const key of Array.from(next.keys())) { if (key.startsWith(prefix)) { next.delete(key) changed = true } } return changed ? next : prev }) } function pruneDraftPrompts(instanceId: string, validSessionIds: Set) { setSessionDraftPrompts((prev) => { let changed = false const next = new Map(prev) const prefix = `${instanceId}:` for (const key of Array.from(next.keys())) { if (key.startsWith(prefix)) { const sessionId = key.slice(prefix.length) if (!validSessionIds.has(sessionId)) { next.delete(key) changed = true } } } return changed ? next : prev }) } function withSession(instanceId: string, sessionId: string, updater: (session: Session) => void) { const instanceSessions = sessions().get(instanceId) if (!instanceSessions) return const session = instanceSessions.get(sessionId) if (!session) return updater(session) const updatedSession = { ...session, } setSessions((prev) => { const next = new Map(prev) const newInstanceSessions = new Map(instanceSessions) newInstanceSessions.set(sessionId, updatedSession) next.set(instanceId, newInstanceSessions) return next }) } function setSessionCompactionState(instanceId: string, sessionId: string, isCompacting: boolean): void { withSession(instanceId, sessionId, (session) => { const time = { ...(session.time ?? {}) } time.compacting = isCompacting ? Date.now() : 0 session.time = time }) } function setSessionPendingPermission(instanceId: string, sessionId: string, pending: boolean): void { withSession(instanceId, sessionId, (session) => { if (session.pendingPermission === pending) return session.pendingPermission = pending }) } function setActiveSession(instanceId: string, sessionId: string): void { setActiveSessionId((prev) => { const next = new Map(prev) next.set(instanceId, sessionId) return next }) } function setActiveParentSession(instanceId: string, parentSessionId: string): void { setActiveParentSessionId((prev) => { const next = new Map(prev) next.set(instanceId, parentSessionId) return next }) setActiveSession(instanceId, parentSessionId) } function clearActiveParentSession(instanceId: string): void { setActiveParentSessionId((prev) => { const next = new Map(prev) next.delete(instanceId) return next }) setActiveSessionId((prev) => { const next = new Map(prev) next.delete(instanceId) return next }) } function getActiveParentSession(instanceId: string): Session | null { const parentId = activeParentSessionId().get(instanceId) if (!parentId) return null const instanceSessions = sessions().get(instanceId) return instanceSessions?.get(parentId) || null } function getActiveSession(instanceId: string): Session | null { const sessionId = activeSessionId().get(instanceId) if (!sessionId) return null const instanceSessions = sessions().get(instanceId) return instanceSessions?.get(sessionId) || null } function getSessions(instanceId: string): Session[] { const instanceSessions = sessions().get(instanceId) return instanceSessions ? Array.from(instanceSessions.values()) : [] } function getParentSessions(instanceId: string): Session[] { const allSessions = getSessions(instanceId) return allSessions.filter((s) => s.parentId === null) } function getChildSessions(instanceId: string, parentId: string): Session[] { const allSessions = getSessions(instanceId) return allSessions.filter((s) => s.parentId === parentId) } function getSessionFamily(instanceId: string, parentId: string): Session[] { const parent = sessions().get(instanceId)?.get(parentId) if (!parent) return [] const children = getChildSessions(instanceId, parentId) return [parent, ...children] } function isSessionBusy(instanceId: string, sessionId: string): boolean { const instanceSessions = sessions().get(instanceId) if (!instanceSessions) return false if (!instanceSessions.has(sessionId)) return false return true } function isSessionMessagesLoading(instanceId: string, sessionId: string): boolean { return Boolean(loading().loadingMessages.get(instanceId)?.has(sessionId)) } function getSessionInfo(instanceId: string, sessionId: string): SessionInfo | undefined { return sessionInfoByInstance().get(instanceId)?.get(sessionId) } export { sessions, setSessions, activeSessionId, setActiveSessionId, activeParentSessionId, setActiveParentSessionId, agents, setAgents, providers, setProviders, loading, setLoading, messagesLoaded, setMessagesLoaded, sessionInfoByInstance, setSessionInfoByInstance, getSessionDraftPrompt, setSessionDraftPrompt, clearSessionDraftPrompt, clearInstanceDraftPrompts, pruneDraftPrompts, withSession, setSessionCompactionState, setSessionPendingPermission, setActiveSession, setActiveParentSession, clearActiveParentSession, getActiveSession, getActiveParentSession, getSessions, getParentSessions, getChildSessions, getSessionFamily, isSessionBusy, isSessionMessagesLoading, getSessionInfo, }