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.
53 lines
2.0 KiB
TypeScript
53 lines
2.0 KiB
TypeScript
import type { MessageBlock } from "@rakazo/contracts";
|
|
|
|
type PresentableMessage = {
|
|
runId?: string;
|
|
blocks: readonly MessageBlock[];
|
|
};
|
|
|
|
export type UserVisibleMessagesOptions = {
|
|
/**
|
|
* Keep `bot_message_sent` / `bot_message_received` rows as compact chips
|
|
* (web CollaborationMarker; mobile AgentEventLabel). Peer bodies stay hidden.
|
|
*/
|
|
includePeerReceipts?: boolean;
|
|
/** Peer-run ids from `run.trigger === "bot_message"` when receipts may be out of window. */
|
|
knownPeerRunIds?: Iterable<string>;
|
|
/**
|
|
* Surface a peer-run's own `text` reply (e.g. a delegating bot's summary to the user)
|
|
* alongside `ask` cards. Defaults to true for chat-thread rendering; set false for
|
|
* contexts like sidebar previews that should stay ask-only and never echo peer chatter.
|
|
*/
|
|
includeDelegatedReplyText?: boolean;
|
|
};
|
|
|
|
export function isPeerReceiptBlocks(blocks: readonly MessageBlock[]): boolean {
|
|
return blocks.some(
|
|
(block) => block.kind === "bot_message_sent" || block.kind === "bot_message_received",
|
|
);
|
|
}
|
|
|
|
/** Drop peer-run activity/replies; optionally keep sent/received receipt rows. */
|
|
export function userVisibleMessages<T extends PresentableMessage>(
|
|
messages: readonly T[],
|
|
options: UserVisibleMessagesOptions = {},
|
|
): T[] {
|
|
const peerRunIds = new Set([
|
|
...(options.knownPeerRunIds ?? []),
|
|
...messages
|
|
.filter((message) => message.blocks.some((block) => block.kind === "bot_message_received"))
|
|
.flatMap((message) => (message.runId ? [message.runId] : [])),
|
|
]);
|
|
const includePeerReceipts = options.includePeerReceipts === true;
|
|
|
|
return messages.filter((message) => {
|
|
if (isPeerReceiptBlocks(message.blocks)) return includePeerReceipts;
|
|
if (!message.runId || !peerRunIds.has(message.runId)) return true;
|
|
// Keep peer-run ask cards, and (unless the caller opts out) the bot's own text reply.
|
|
const includeText = options.includeDelegatedReplyText !== false;
|
|
return message.blocks.some(
|
|
(block) => block.kind === "ask" || (includeText && block.kind === "text"),
|
|
);
|
|
});
|
|
}
|