import type { AutopilotBlock, MessageBlock } from "@rakazo/contracts"; import { addAutopilotCheckpoint, markAutopilotLinesEnded } from "@rakazo/core"; import type { Prisma } from "./client.js"; import { appendEventInTransaction } from "./events.js"; import { createThreadMessageInTransaction } from "./messages.js"; /** Write one autopilot line in the thread; it never marks the thread unread. */ export async function postAutopilotLineInTransaction( tx: Prisma.TransactionClient, input: { spaceId: string; threadId: string; botId: string; block: AutopilotBlock }, ): Promise<{ messageId: string; seq: number }> { const message = await createThreadMessageInTransaction(tx, { threadId: input.threadId, role: "bot", blocks: [input.block], botId: input.botId, markUnread: false, }); const event = await appendEventInTransaction(tx, { spaceId: input.spaceId, threadId: input.threadId, botId: input.botId, type: "thread.message.created", payload: { messageId: message.id, role: "bot", blocks: [input.block] }, }); return { messageId: message.id, seq: event.seq }; } /** Take the Stop and Continue controls off an autopilot's earlier lines once it is over. */ export async function endAutopilotLinesInTransaction( tx: Prisma.TransactionClient, input: { spaceId: string; threadId: string; autopilotId: string }, ): Promise { const messages = await tx.message.findMany({ where: { threadId: input.threadId, blocks: { array_contains: [{ kind: "autopilot", autopilotId: input.autopilotId }] }, }, select: { id: true, role: true, botId: true, blocks: true }, }); let seq: number | null = null; for (const message of messages) { const blocks = markAutopilotLinesEnded(message.blocks as MessageBlock[], input.autopilotId); if (!blocks || !message.botId) continue; await tx.message.update({ where: { id: message.id }, data: { blocks: blocks as Prisma.InputJsonValue }, }); const event = await appendEventInTransaction(tx, { spaceId: input.spaceId, threadId: input.threadId, botId: message.botId, type: "thread.message.updated", payload: { messageId: message.id, role: message.role, blocks }, }); seq = event.seq; } return seq; } /** Count a checkpoint on the autopilot's start line, so the line shows live progress. */ export async function recordAutopilotCheckpointInTransaction( tx: Prisma.TransactionClient, input: { spaceId: string; threadId: string; messageId: string; autopilotId: string; checkpoint: { text: string; at: string }; steps: number; }, ): Promise { const message = await tx.message.findUnique({ where: { id: input.messageId }, select: { id: true, role: true, botId: true, blocks: true, threadId: true }, }); if (!message?.botId || message.threadId !== input.threadId) return null; const blocks = addAutopilotCheckpoint( message.blocks as MessageBlock[], input.autopilotId, input.checkpoint, input.steps, ); if (!blocks) return null; await tx.message.update({ where: { id: message.id }, data: { blocks: blocks as Prisma.InputJsonValue }, }); const event = await appendEventInTransaction(tx, { spaceId: input.spaceId, threadId: input.threadId, botId: message.botId, type: "thread.message.updated", payload: { messageId: message.id, role: message.role, blocks }, }); return event.seq; }