feat: update Makelore modules and conversations
This commit is contained in:
134
shared/project-conversations.ts
Normal file
134
shared/project-conversations.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
export type ProjectSessionMetadata = {
|
||||
sessionId: string;
|
||||
agentId: string;
|
||||
archivedAt: string | null;
|
||||
unreadCount: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type ProjectConversationState = {
|
||||
schemaVersion: 1;
|
||||
sessions: ProjectSessionMetadata[];
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
function cleanString(value: unknown): string {
|
||||
return typeof value === 'string' ? value.trim() : '';
|
||||
}
|
||||
|
||||
function normalizeSession(value: unknown): ProjectSessionMetadata | null {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
|
||||
const record = value as Partial<ProjectSessionMetadata>;
|
||||
const sessionId = cleanString(record.sessionId);
|
||||
const agentId = cleanString(record.agentId);
|
||||
if (!sessionId || !/^[a-z0-9][a-z0-9_-]{0,127}$/i.test(sessionId) || !agentId) return null;
|
||||
const now = new Date().toISOString();
|
||||
const createdAt = cleanString(record.createdAt) || now;
|
||||
const updatedAt = cleanString(record.updatedAt) || createdAt;
|
||||
const unreadCount = typeof record.unreadCount === 'number' && Number.isFinite(record.unreadCount)
|
||||
? Math.max(0, Math.floor(record.unreadCount))
|
||||
: 0;
|
||||
return {
|
||||
sessionId,
|
||||
agentId,
|
||||
archivedAt: cleanString(record.archivedAt) || null,
|
||||
unreadCount,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
};
|
||||
}
|
||||
|
||||
export function createProjectConversationState(now = new Date().toISOString()): ProjectConversationState {
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
sessions: [],
|
||||
updatedAt: now,
|
||||
};
|
||||
}
|
||||
|
||||
export function normalizeProjectConversationState(value: unknown): ProjectConversationState {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
||||
throw new Error('Project conversation state must be an object');
|
||||
}
|
||||
const record = value as Partial<ProjectConversationState>;
|
||||
if (record.schemaVersion !== 1) throw new Error('Unsupported project conversation state schema');
|
||||
const sessions = Array.isArray(record.sessions)
|
||||
? record.sessions.map(normalizeSession).filter((item): item is ProjectSessionMetadata => Boolean(item))
|
||||
: [];
|
||||
const deduped = new Map<string, ProjectSessionMetadata>();
|
||||
for (const session of sessions) deduped.set(session.sessionId, session);
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
sessions: [...deduped.values()],
|
||||
updatedAt: cleanString(record.updatedAt) || new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
export function upsertProjectSessionMetadata(
|
||||
state: ProjectConversationState,
|
||||
sessionId: string,
|
||||
agentId: string,
|
||||
now = new Date().toISOString(),
|
||||
): ProjectConversationState {
|
||||
const current = state.sessions.find((item) => item.sessionId === sessionId);
|
||||
const next: ProjectSessionMetadata = {
|
||||
sessionId,
|
||||
agentId,
|
||||
archivedAt: current?.archivedAt ?? null,
|
||||
unreadCount: current?.unreadCount ?? 0,
|
||||
createdAt: current?.createdAt ?? now,
|
||||
updatedAt: now,
|
||||
};
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
sessions: [next, ...state.sessions.filter((item) => item.sessionId !== sessionId)],
|
||||
updatedAt: now,
|
||||
};
|
||||
}
|
||||
|
||||
export function patchProjectSessionMetadata(
|
||||
state: ProjectConversationState,
|
||||
sessionId: string,
|
||||
patch: Partial<Pick<ProjectSessionMetadata, 'agentId' | 'archivedAt' | 'unreadCount'>>,
|
||||
now = new Date().toISOString(),
|
||||
): ProjectConversationState {
|
||||
const sessions = state.sessions.map((item) => item.sessionId === sessionId
|
||||
? {
|
||||
...item,
|
||||
...(patch.agentId ? { agentId: patch.agentId } : {}),
|
||||
...(patch.archivedAt !== undefined ? { archivedAt: patch.archivedAt } : {}),
|
||||
...(patch.unreadCount !== undefined ? { unreadCount: Math.max(0, Math.floor(patch.unreadCount)) } : {}),
|
||||
updatedAt: now,
|
||||
}
|
||||
: item);
|
||||
return { schemaVersion: 1, sessions, updatedAt: now };
|
||||
}
|
||||
|
||||
export function removeProjectSessionMetadata(
|
||||
state: ProjectConversationState,
|
||||
sessionId: string,
|
||||
now = new Date().toISOString(),
|
||||
): ProjectConversationState {
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
sessions: state.sessions.filter((item) => item.sessionId !== sessionId),
|
||||
updatedAt: now,
|
||||
};
|
||||
}
|
||||
|
||||
export function completeProjectSession(
|
||||
state: ProjectConversationState,
|
||||
sessionId: string,
|
||||
incrementUnread: boolean,
|
||||
now = new Date().toISOString(),
|
||||
): ProjectConversationState {
|
||||
const current = state.sessions.find((item) => item.sessionId === sessionId);
|
||||
if (!current) return state;
|
||||
return patchProjectSessionMetadata(
|
||||
state,
|
||||
sessionId,
|
||||
{ unreadCount: current.unreadCount + (incrementUnread ? 1 : 0) },
|
||||
now,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user