263 lines
7.5 KiB
TypeScript
263 lines
7.5 KiB
TypeScript
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<Map<string, Map<string, Session>>>(new Map())
|
|
const [activeSessionId, setActiveSessionId] = createSignal<Map<string, string>>(new Map())
|
|
const [activeParentSessionId, setActiveParentSessionId] = createSignal<Map<string, string>>(new Map())
|
|
const [agents, setAgents] = createSignal<Map<string, Agent[]>>(new Map())
|
|
const [providers, setProviders] = createSignal<Map<string, Provider[]>>(new Map())
|
|
const [sessionDraftPrompts, setSessionDraftPrompts] = createSignal<Map<string, string>>(new Map())
|
|
|
|
const [loading, setLoading] = createSignal({
|
|
fetchingSessions: new Map<string, boolean>(),
|
|
creatingSession: new Map<string, boolean>(),
|
|
deletingSession: new Map<string, Set<string>>(),
|
|
loadingMessages: new Map<string, Set<string>>(),
|
|
})
|
|
|
|
const [messagesLoaded, setMessagesLoaded] = createSignal<Map<string, Set<string>>>(new Map())
|
|
const [sessionInfoByInstance, setSessionInfoByInstance] = createSignal<Map<string, Map<string, SessionInfo>>>(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<string>) {
|
|
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,
|
|
}
|