The autopilot's start line counts its steps and folds open to the latest checkpoints, and its result reads as a card. The composer's plus menu starts an autopilot with the draft as the order and a choice of until done, tomorrow morning or a time. Today lists the autopilots that run, wait or ended within a day, and their step runs no longer show one by one. Autopilot runs send no completion or failure push; only a pause notifies. Claude-Session: https://claude.ai/code/session_01UmSCnoCgXqBp2fU3vwz4o1 Co-authored-by: Claude <noreply@anthropic.com>
98 lines
3.4 KiB
TypeScript
98 lines
3.4 KiB
TypeScript
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<number | null> {
|
|
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<number | null> {
|
|
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;
|
|
}
|