evOo-local/apps/web/src/lib/peer-messages.ts
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

78 lines
2.4 KiB
TypeScript

import type { MessageBlock, ThreadMessage } from "@rakazo/contracts";
export interface PeerMessage {
messageId: string;
direction: "sent" | "received";
peerBotId: string;
peerBotName: string;
text: string;
createdAt: string;
}
export interface PeerConversation {
peerBotId: string;
peerBotName: string;
messages: PeerMessage[];
lastText: string;
lastAt: string;
}
type PeerBlock = Extract<MessageBlock, { kind: "bot_message_sent" | "bot_message_received" }>;
export function isPeerBlock(block: MessageBlock): block is PeerBlock {
return block.kind === "bot_message_sent" || block.kind === "bot_message_received";
}
export function peerMessagesFrom(messages: readonly ThreadMessage[]): PeerMessage[] {
const collected: PeerMessage[] = [];
for (const message of messages) {
for (const block of message.blocks) {
if (!isPeerBlock(block)) continue;
collected.push(
block.kind === "bot_message_sent"
? {
messageId: message.id,
direction: "sent",
peerBotId: block.toBotId,
peerBotName: block.toBotName,
text: block.text,
createdAt: message.createdAt,
}
: {
messageId: message.id,
direction: "received",
peerBotId: block.fromBotId,
peerBotName: block.fromBotName,
text: block.text,
createdAt: message.createdAt,
},
);
}
}
return collected;
}
/** One conversation per peer, most recently active first. */
export function peerConversations(messages: readonly ThreadMessage[]): PeerConversation[] {
const byPeer = new Map<string, PeerConversation>();
for (const peerMessage of peerMessagesFrom(messages)) {
const existing = byPeer.get(peerMessage.peerBotId);
if (existing) {
existing.messages.push(peerMessage);
// Names can change; the newest one wins.
existing.peerBotName = peerMessage.peerBotName;
existing.lastText = peerMessage.text;
existing.lastAt = peerMessage.createdAt;
continue;
}
byPeer.set(peerMessage.peerBotId, {
peerBotId: peerMessage.peerBotId,
peerBotName: peerMessage.peerBotName,
messages: [peerMessage],
lastText: peerMessage.text,
lastAt: peerMessage.createdAt,
});
}
return [...byPeer.values()].sort((a, b) => b.lastAt.localeCompare(a.lastAt));
}