import type { Session, SessionStatus } from "../types/session" import type { MessageInfo } from "../types/message" import type { MessageRecord } from "./message-v2/types" import { sessions } from "./sessions" import { isSessionCompactionActive } from "./session-compaction" import { messageStoreBus } from "./message-v2/bus" function getSession(instanceId: string, sessionId: string): Session | null { const instanceSessions = sessions().get(instanceId) return instanceSessions?.get(sessionId) ?? null } function isSessionCompacting(session: Session): boolean { const time = (session.time as (Session["time"] & { compacting?: number }) | undefined) const compactingFlag = time?.compacting if (typeof compactingFlag === "number") { return compactingFlag > 0 } return Boolean(compactingFlag) } function getLatestInfoFromStore(instanceId: string, sessionId: string, role?: MessageInfo["role"]): MessageInfo | undefined { const store = messageStoreBus.getOrCreate(instanceId) const messageIds = store.getSessionMessageIds(sessionId) let latest: MessageInfo | undefined let latestTimestamp = Number.NEGATIVE_INFINITY for (const id of messageIds) { const info = store.getMessageInfo(id) if (!info) continue if (role && info.role !== role) continue const timestamp = info.time?.created ?? 0 if (timestamp >= latestTimestamp) { latest = info latestTimestamp = timestamp } } return latest } function getLastMessageFromStore(instanceId: string, sessionId: string): MessageRecord | undefined { const store = messageStoreBus.getOrCreate(instanceId) const messageIds = store.getSessionMessageIds(sessionId) let latest: MessageRecord | undefined let latestTimestamp = Number.NEGATIVE_INFINITY for (const id of messageIds) { const record = store.getMessage(id) if (!record) continue const info = store.getMessageInfo(id) const timestamp = info?.time?.created ?? record.createdAt ?? Number.NEGATIVE_INFINITY if (timestamp >= latestTimestamp) { latest = record latestTimestamp = timestamp } } return latest } function getInfoCreatedTimestamp(info?: MessageInfo): number { if (!info) { return Number.NEGATIVE_INFINITY } const created = info.time?.created if (typeof created === "number" && Number.isFinite(created)) { return created } return Number.NEGATIVE_INFINITY } function getAssistantCompletionTimestamp(info?: MessageInfo): number { if (!info) { return Number.NEGATIVE_INFINITY } const completed = (info.time as { completed?: number } | undefined)?.completed if (typeof completed === "number" && Number.isFinite(completed)) { return completed } return Number.NEGATIVE_INFINITY } function isAssistantInfoPending(info?: MessageInfo): boolean { if (!info) { return false } const completed = (info.time as { completed?: number } | undefined)?.completed if (completed === undefined || completed === null) { return true } const created = getInfoCreatedTimestamp(info) return completed < created } function isAssistantStillGeneratingRecord(record: MessageRecord, info?: MessageInfo): boolean { if (record.role !== "assistant") { return false } if (record.status === "error") { return false } if (record.status === "streaming" || record.status === "sending") { return true } const completedAt = (info?.time as { completed?: number } | undefined)?.completed if (completedAt !== undefined && completedAt !== null) { return false } return !(record.status === "complete" || record.status === "sent") } export function getSessionStatus(instanceId: string, sessionId: string): SessionStatus { const session = getSession(instanceId, sessionId) if (!session) { return "idle" } const store = messageStoreBus.getOrCreate(instanceId) if (isSessionCompactionActive(instanceId, sessionId) || isSessionCompacting(session)) { return "compacting" } const latestUserInfo = getLatestInfoFromStore(instanceId, sessionId, "user") const latestAssistantInfo = getLatestInfoFromStore(instanceId, sessionId, "assistant") const lastRecord = getLastMessageFromStore(instanceId, sessionId) if (!lastRecord) { const latestInfo = latestUserInfo ?? latestAssistantInfo if (!latestInfo) { return "idle" } if (latestInfo.role === "user") { return "working" } const infoCompleted = latestInfo.time?.completed return infoCompleted ? "idle" : "working" } if (lastRecord.role === "user") { return "working" } const infoForRecord = store.getMessageInfo(lastRecord.id) ?? latestAssistantInfo if (infoForRecord && isAssistantStillGeneratingRecord(lastRecord, infoForRecord)) { return "working" } if (isAssistantInfoPending(latestAssistantInfo)) { return "working" } const userTimestamp = getInfoCreatedTimestamp(latestUserInfo) const assistantCompletedAt = getAssistantCompletionTimestamp(latestAssistantInfo) if (userTimestamp > assistantCompletedAt) { return "working" } return "idle" } export function isSessionBusy(instanceId: string, sessionId: string): boolean { const status = getSessionStatus(instanceId, sessionId) return status === "working" || status === "compacting" }