Split workspace into electron and ui packages
This commit is contained in:
261
packages/ui/src/stores/session-state.ts
Normal file
261
packages/ui/src/stores/session-state.ts
Normal file
@@ -0,0 +1,261 @@
|
||||
import { createSignal } from "solid-js"
|
||||
|
||||
import type { Session, Agent, Provider } from "../types/session"
|
||||
|
||||
export interface SessionInfo {
|
||||
tokens: number
|
||||
cost: number
|
||||
contextWindow: number
|
||||
isSubscriptionModel: boolean
|
||||
contextUsageTokens: number
|
||||
contextUsagePercent: 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,
|
||||
messages: [...session.messages],
|
||||
messagesInfo: new Map(session.messagesInfo),
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
Reference in New Issue
Block a user