BangSo/apps/mobile/lib/message-presentation.ts

86 lines
2.6 KiB
TypeScript
Raw Normal View History

2026-09-01 16:51:19 +00:00
import type { MessageBlock } from "@rakazo/contracts";
export function isCenteredAgentEvent(blocks: readonly MessageBlock[]): boolean {
return blocks.some(
(block) =>
block.kind === "handoff" ||
block.kind === "bot_message_sent" ||
block.kind === "bot_message_received" ||
block.kind === "channel_message",
);
}
type ToolBlock = Extract<MessageBlock, { kind: "progress" | "steps" }>;
export type MessagePresentationSegment =
| { kind: "content"; blocks: MessageBlock[] }
| { kind: "tool"; block: ToolBlock };
export function toolBlocksForMessage(blocks: readonly MessageBlock[]): ToolBlock[] {
const visible: ToolBlock[] = [];
for (const block of blocks) {
if (!isToolBlock(block)) continue;
if (block.kind === "steps") {
const steps = block.steps.filter((step) => !isMessageBotName(step.label));
if (steps.length > 0) visible.push({ ...block, steps });
continue;
}
const pendingToolNames = (block.pendingToolNames ?? []).filter(
(name) => !isMessageBotName(name),
);
if (pendingToolNames.length > 0 || !isMessageBotName(block.text)) {
visible.push({ ...block, pendingToolNames });
}
}
return visible;
}
export function messagePresentationSegments(
blocks: readonly MessageBlock[],
): MessagePresentationSegment[] {
const segments: MessagePresentationSegment[] = [];
let content: MessageBlock[] = [];
const flushContent = () => {
if (content.length === 0) return;
segments.push({ kind: "content", blocks: content });
content = [];
};
for (const block of blocks) {
if (block.kind === "app_connect") continue;
if (!isToolBlock(block)) {
content.push(block);
continue;
}
const visibleTool = toolBlocksForMessage([block])[0];
if (!visibleTool) continue;
flushContent();
segments.push({ kind: "tool", block: visibleTool });
}
flushContent();
return segments;
}
export function toolOwnerId(
message: { botId?: string; blocks: readonly MessageBlock[] },
inGroup: boolean,
): string | undefined {
return inGroup && toolBlocksForMessage(message.blocks).length > 0 ? message.botId : undefined;
}
export function hasVisibleMessagePresentation(blocks: readonly MessageBlock[]): boolean {
return blocks.some((block) => !isToolBlock(block) || toolBlocksForMessage([block]).length > 0);
}
export function isToolBlock(block: MessageBlock): block is ToolBlock {
return (
block.kind === "steps" ||
(block.kind === "progress" &&
((block.pendingToolNames?.length ?? 0) > 0 || /^Using\s+/i.test(block.text)))
);
}
function isMessageBotName(value: string): boolean {
return /(?:^|\b)message[ _-]?bot(?:\b|$)/i.test(value);
}