evOo-local/apps/mobile/lib/message-presentation.ts
cynarAI dbf37f86a8
feat: show routines the bot sets up from chat as one quiet line (#133)
* feat: show routines the bot sets up from chat as one quiet line

When someone mentions something recurring in passing ("every Sunday I plan the
week"), the bot now creates the routine right away and the conversation shows a
single line with the schedule, Edit and Undo, on web and mobile.

- New `event` message block for routine lines, kept in history so later turns
  know what was set up or removed.
- schedule_create reuses an active repeating routine of the same name instead
  of adding a duplicate, caps a bot at 50 active schedules, and falls back to
  default times when none was given.
- Removing a routine (Undo, the editor, or schedule_cancel) marks its lines
  removed via the new routines.noticeMessageId column.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UmSCnoCgXqBp2fU3vwz4o1

* test: give the routine notice test a complete job publisher

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UmSCnoCgXqBp2fU3vwz4o1

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-04 20:36:53 +02:00

32 lines
982 B
TypeScript

import type { MessageBlock } from "@rakazo/contracts";
import { isToolActivityBlock } from "@rakazo/core";
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" ||
block.kind === "event",
);
}
export type MessagePresentationSegment = {
kind: "content";
blocks: MessageBlock[];
};
export function messagePresentationSegments(
blocks: readonly MessageBlock[],
): MessagePresentationSegment[] {
const content = blocks.filter(
(block) => block.kind !== "app_connect" && !isToolActivityBlock(block),
);
return content.length > 0 ? [{ kind: "content", blocks: content }] : [];
}
export function hasVisibleMessagePresentation(blocks: readonly MessageBlock[]): boolean {
return blocks.some((block) => !isToolActivityBlock(block));
}