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.
556 lines
16 KiB
TypeScript
556 lines
16 KiB
TypeScript
import type { PrismaClient } from "@rakazo/db";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
import {
|
|
isPeerRun,
|
|
loadAllMessages,
|
|
loadMessagePage,
|
|
shouldForwardPeerThreadEvent,
|
|
} from "./thread-message-pages.js";
|
|
|
|
describe("thread message pages", () => {
|
|
it("caches peer-run classification for live events", async () => {
|
|
const findUnique = vi.fn(async () => ({ trigger: "bot_message" }));
|
|
const prisma = { run: { findUnique } } as unknown as PrismaClient;
|
|
const cache = new Map<string, Promise<boolean>>();
|
|
|
|
await expect(isPeerRun(prisma, "run-peer", cache)).resolves.toBe(true);
|
|
await expect(isPeerRun(prisma, "run-peer", cache)).resolves.toBe(true);
|
|
expect(findUnique).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("forwards peer waiting, ask, and text events on an open thread", () => {
|
|
expect(shouldForwardPeerThreadEvent({ type: "run.waiting_input", payload: {} })).toBe(true);
|
|
expect(shouldForwardPeerThreadEvent({ type: "computer.takeover.requested", payload: {} })).toBe(
|
|
true,
|
|
);
|
|
expect(
|
|
shouldForwardPeerThreadEvent({
|
|
type: "thread.message.created",
|
|
payload: { blocks: [{ kind: "ask", text: "Pick one" }] },
|
|
}),
|
|
).toBe(true);
|
|
expect(
|
|
shouldForwardPeerThreadEvent({
|
|
type: "thread.message.created",
|
|
payload: { blocks: [{ kind: "text", text: "peer body" }] },
|
|
}),
|
|
).toBe(true);
|
|
expect(
|
|
shouldForwardPeerThreadEvent({
|
|
type: "thread.progress",
|
|
payload: {},
|
|
}),
|
|
).toBe(false);
|
|
});
|
|
|
|
it("keeps peer receipt rows when filtering peer-run output from pages", async () => {
|
|
const findMany = vi.fn(async () => [
|
|
{
|
|
id: "message-reply",
|
|
threadId: "thread-1",
|
|
seq: 3,
|
|
role: "bot",
|
|
blocks: [{ kind: "text", text: "Echoed peer reply" }],
|
|
botId: "bot-1",
|
|
replyToMessageId: null,
|
|
runId: "run-peer",
|
|
createdAt: new Date("2026-08-16T00:00:03.000Z"),
|
|
},
|
|
{
|
|
id: "message-received",
|
|
threadId: "thread-1",
|
|
seq: 2,
|
|
role: "user",
|
|
blocks: [
|
|
{
|
|
kind: "bot_message_received",
|
|
fromBotId: "bot-2",
|
|
fromBotName: "Coder",
|
|
text: "Done.",
|
|
},
|
|
],
|
|
botId: null,
|
|
replyToMessageId: null,
|
|
runId: "run-peer",
|
|
createdAt: new Date("2026-08-16T00:00:02.000Z"),
|
|
},
|
|
{
|
|
id: "message-user",
|
|
threadId: "thread-1",
|
|
seq: 1,
|
|
role: "bot",
|
|
blocks: [{ kind: "text", text: "Visible answer" }],
|
|
botId: "bot-1",
|
|
replyToMessageId: null,
|
|
runId: "run-user",
|
|
createdAt: new Date("2026-08-16T00:00:01.000Z"),
|
|
},
|
|
]);
|
|
const prisma = {
|
|
message: { findMany },
|
|
run: { findMany: vi.fn(async () => [{ id: "run-peer" }]) },
|
|
} as unknown as PrismaClient;
|
|
|
|
const page = await loadMessagePage(prisma, "thread-1", undefined, 3);
|
|
|
|
expect(page.messages.map((message) => message.id)).toEqual([
|
|
"message-user",
|
|
"message-received",
|
|
"message-reply",
|
|
]);
|
|
});
|
|
|
|
it("filters peer-run activity when its receipt is outside the loaded page", async () => {
|
|
const findMany = vi.fn(async () => [
|
|
{
|
|
id: "message-peer",
|
|
threadId: "thread-1",
|
|
seq: 2,
|
|
role: "bot",
|
|
blocks: [{ kind: "steps", steps: [{ label: "Echoed peer reply", count: 1 }] }],
|
|
botId: "bot-1",
|
|
replyToMessageId: null,
|
|
runId: "run-peer",
|
|
createdAt: new Date("2026-08-16T00:00:02.000Z"),
|
|
},
|
|
{
|
|
id: "message-user",
|
|
threadId: "thread-1",
|
|
seq: 1,
|
|
role: "bot",
|
|
blocks: [{ kind: "text", text: "Visible answer" }],
|
|
botId: "bot-1",
|
|
replyToMessageId: null,
|
|
runId: "run-user",
|
|
createdAt: new Date("2026-08-16T00:00:01.000Z"),
|
|
},
|
|
]);
|
|
const prisma = {
|
|
message: { findMany },
|
|
run: { findMany: vi.fn(async () => [{ id: "run-peer" }]) },
|
|
} as unknown as PrismaClient;
|
|
|
|
const page = await loadMessagePage(prisma, "thread-1", undefined, 2);
|
|
|
|
expect(page.messages.map((message) => message.id)).toEqual(["message-user"]);
|
|
});
|
|
|
|
it("keeps peer text around-page targets and omits peer activity", async () => {
|
|
const findMany = vi.fn(async () => [
|
|
{
|
|
id: "message-user",
|
|
threadId: "thread-1",
|
|
seq: 4,
|
|
role: "bot",
|
|
blocks: [{ kind: "text", text: "Visible answer" }],
|
|
botId: "bot-1",
|
|
replyToMessageId: null,
|
|
runId: "run-user",
|
|
createdAt: new Date("2026-08-16T00:00:04.000Z"),
|
|
},
|
|
{
|
|
id: "message-peer-activity",
|
|
threadId: "thread-1",
|
|
seq: 5,
|
|
role: "bot",
|
|
blocks: [{ kind: "steps", steps: [{ label: "Message bot", count: 1 }] }],
|
|
botId: "bot-1",
|
|
replyToMessageId: null,
|
|
runId: "run-peer",
|
|
createdAt: new Date("2026-08-16T00:00:05.000Z"),
|
|
},
|
|
{
|
|
id: "message-peer-target",
|
|
threadId: "thread-1",
|
|
seq: 6,
|
|
role: "bot",
|
|
blocks: [{ kind: "text", text: "Peer reply" }],
|
|
botId: "bot-1",
|
|
replyToMessageId: null,
|
|
runId: "run-peer",
|
|
createdAt: new Date("2026-08-16T00:00:06.000Z"),
|
|
},
|
|
]);
|
|
const count = vi.fn(async () => 1);
|
|
const runFindMany = vi.fn(async () => [{ id: "run-peer" }]);
|
|
const prisma = {
|
|
message: { findMany, count },
|
|
run: { findMany: runFindMany },
|
|
} as unknown as PrismaClient;
|
|
|
|
const page = await loadMessagePage(prisma, "thread-1", undefined, 4, {
|
|
messageId: "message-peer-target",
|
|
seq: 6,
|
|
});
|
|
|
|
expect(page.messages.map((message) => message.id)).toEqual([
|
|
"message-user",
|
|
"message-peer-target",
|
|
]);
|
|
expect(runFindMany).toHaveBeenCalled();
|
|
});
|
|
|
|
it("keeps peer receipt and text around-page targets in the normal transcript page", async () => {
|
|
const findMany = vi.fn(async () => [
|
|
{
|
|
id: "message-user",
|
|
threadId: "thread-1",
|
|
seq: 4,
|
|
role: "bot",
|
|
blocks: [{ kind: "text", text: "Visible answer" }],
|
|
botId: "bot-1",
|
|
replyToMessageId: null,
|
|
runId: "run-user",
|
|
createdAt: new Date("2026-08-16T00:00:04.000Z"),
|
|
},
|
|
{
|
|
id: "message-peer-receipt",
|
|
threadId: "thread-1",
|
|
seq: 5,
|
|
role: "user",
|
|
blocks: [
|
|
{
|
|
kind: "bot_message_received",
|
|
fromBotId: "bot-2",
|
|
fromBotName: "Coder",
|
|
text: "Done.",
|
|
},
|
|
],
|
|
botId: null,
|
|
replyToMessageId: null,
|
|
runId: "run-peer",
|
|
createdAt: new Date("2026-08-16T00:00:05.000Z"),
|
|
},
|
|
{
|
|
id: "message-peer-text",
|
|
threadId: "thread-1",
|
|
seq: 6,
|
|
role: "bot",
|
|
blocks: [{ kind: "text", text: "Peer reply" }],
|
|
botId: "bot-1",
|
|
replyToMessageId: null,
|
|
runId: "run-peer",
|
|
createdAt: new Date("2026-08-16T00:00:06.000Z"),
|
|
},
|
|
]);
|
|
const count = vi.fn(async () => 0);
|
|
const prisma = {
|
|
message: { findMany, count },
|
|
run: { findMany: vi.fn(async () => [{ id: "run-peer" }]) },
|
|
} as unknown as PrismaClient;
|
|
|
|
const page = await loadMessagePage(prisma, "thread-1", undefined, 4, {
|
|
messageId: "message-peer-receipt",
|
|
seq: 5,
|
|
});
|
|
|
|
expect(page.messages.map((message) => message.id)).toEqual([
|
|
"message-user",
|
|
"message-peer-receipt",
|
|
"message-peer-text",
|
|
]);
|
|
});
|
|
|
|
it("returns peer-run output for the dedicated bot messages view", async () => {
|
|
const findMany = vi.fn(async () => [
|
|
{
|
|
id: "message-peer",
|
|
threadId: "thread-1",
|
|
seq: 1,
|
|
role: "bot",
|
|
blocks: [{ kind: "text", text: "Peer reply" }],
|
|
botId: "bot-1",
|
|
replyToMessageId: null,
|
|
runId: "run-peer",
|
|
createdAt: new Date("2026-08-16T00:00:01.000Z"),
|
|
},
|
|
]);
|
|
const prisma = {
|
|
message: { findMany, count: vi.fn(async () => 0) },
|
|
} as unknown as PrismaClient;
|
|
|
|
const page = await loadMessagePage(
|
|
prisma,
|
|
"thread-1",
|
|
undefined,
|
|
2,
|
|
{ messageId: "message-peer", seq: 1 },
|
|
true,
|
|
);
|
|
|
|
expect(page.messages.map((message) => message.id)).toEqual(["message-peer"]);
|
|
});
|
|
|
|
it("scans past a page containing only hidden peer-run activity", async () => {
|
|
const row = (seq: number, runId: string, kind: "text" | "steps" = "text") => ({
|
|
id: `message-${seq}`,
|
|
threadId: "thread-1",
|
|
seq,
|
|
role: "bot",
|
|
blocks:
|
|
kind === "steps"
|
|
? [{ kind: "steps", steps: [{ label: String(seq), count: 1 }] }]
|
|
: [{ kind: "text", text: String(seq) }],
|
|
botId: "bot-1",
|
|
replyToMessageId: null,
|
|
runId,
|
|
createdAt: new Date("2026-08-16T00:00:00.000Z"),
|
|
});
|
|
const findMany = vi
|
|
.fn()
|
|
.mockResolvedValueOnce([
|
|
row(4, "run-peer", "steps"),
|
|
row(3, "run-peer", "steps"),
|
|
row(2, "run-peer", "steps"),
|
|
])
|
|
.mockResolvedValueOnce([row(1, "run-user")]);
|
|
const prisma = {
|
|
message: { findMany },
|
|
run: {
|
|
findMany: vi
|
|
.fn()
|
|
.mockResolvedValueOnce([{ id: "run-peer" }])
|
|
.mockResolvedValueOnce([]),
|
|
},
|
|
} as unknown as PrismaClient;
|
|
|
|
const page = await loadMessagePage(prisma, "thread-1", undefined, 2);
|
|
|
|
expect(page.messages.map((message) => message.id)).toEqual(["message-1"]);
|
|
expect(findMany).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
it("scans past a receipt-only page so web can reach older user-visible rows", async () => {
|
|
const receiptRows = [
|
|
{
|
|
id: "message-receipt-b",
|
|
threadId: "thread-1",
|
|
seq: 3,
|
|
role: "user",
|
|
blocks: [
|
|
{
|
|
kind: "bot_message_received",
|
|
fromBotId: "bot-2",
|
|
fromBotName: "Coder",
|
|
text: "Done.",
|
|
},
|
|
],
|
|
botId: null,
|
|
replyToMessageId: null,
|
|
runId: "run-peer",
|
|
createdAt: new Date("2026-08-16T00:00:03.000Z"),
|
|
},
|
|
{
|
|
id: "message-receipt-a",
|
|
threadId: "thread-1",
|
|
seq: 2,
|
|
role: "user",
|
|
blocks: [
|
|
{
|
|
kind: "bot_message_sent",
|
|
toBotId: "bot-2",
|
|
toBotName: "Coder",
|
|
text: "Check this.",
|
|
},
|
|
],
|
|
botId: null,
|
|
replyToMessageId: null,
|
|
runId: "run-user",
|
|
createdAt: new Date("2026-08-16T00:00:02.000Z"),
|
|
},
|
|
{
|
|
id: "message-lookahead",
|
|
threadId: "thread-1",
|
|
seq: 1,
|
|
role: "bot",
|
|
blocks: [{ kind: "text", text: "Older visible answer" }],
|
|
botId: "bot-1",
|
|
replyToMessageId: null,
|
|
runId: "run-user",
|
|
createdAt: new Date("2026-08-16T00:00:01.000Z"),
|
|
},
|
|
];
|
|
const olderRows = [
|
|
{
|
|
id: "message-user",
|
|
threadId: "thread-1",
|
|
seq: 1,
|
|
role: "bot",
|
|
blocks: [{ kind: "text", text: "Older visible answer" }],
|
|
botId: "bot-1",
|
|
replyToMessageId: null,
|
|
runId: "run-user",
|
|
createdAt: new Date("2026-08-16T00:00:01.000Z"),
|
|
},
|
|
];
|
|
const findMany = vi.fn().mockResolvedValueOnce(receiptRows).mockResolvedValueOnce(olderRows);
|
|
const prisma = {
|
|
message: { findMany },
|
|
run: {
|
|
findMany: vi
|
|
.fn()
|
|
.mockResolvedValueOnce([{ id: "run-peer" }])
|
|
.mockResolvedValueOnce([]),
|
|
},
|
|
} as unknown as PrismaClient;
|
|
|
|
const page = await loadMessagePage(prisma, "thread-1", undefined, 2);
|
|
|
|
expect(page.messages.map((message) => message.id)).toEqual(["message-user"]);
|
|
expect(findMany).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
it("returns a receipt-only page when the client displays peer receipts", async () => {
|
|
const receipt = (seq: number) => ({
|
|
id: `message-receipt-${seq}`,
|
|
threadId: "thread-1",
|
|
seq,
|
|
role: "user",
|
|
blocks: [
|
|
{
|
|
kind: "bot_message_received",
|
|
fromBotId: "bot-2",
|
|
fromBotName: "Coder",
|
|
text: "Done.",
|
|
},
|
|
],
|
|
botId: null,
|
|
replyToMessageId: null,
|
|
runId: "run-peer",
|
|
createdAt: new Date(`2026-08-16T00:00:0${seq}.000Z`),
|
|
});
|
|
const findMany = vi.fn(async () => [receipt(3), receipt(2), receipt(1)]);
|
|
const prisma = {
|
|
message: { findMany },
|
|
run: { findMany: vi.fn(async () => [{ id: "run-peer" }]) },
|
|
} as unknown as PrismaClient;
|
|
|
|
const page = await loadMessagePage(prisma, "thread-1", undefined, 2, undefined, false, true);
|
|
|
|
expect(page.messages.map((message) => message.id)).toEqual([
|
|
"message-receipt-2",
|
|
"message-receipt-3",
|
|
]);
|
|
expect(page.olderCursor).toBe(2);
|
|
expect(findMany).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("queries before the cursor and returns an ascending bounded page", async () => {
|
|
const findMany = vi.fn(async () =>
|
|
[5, 4, 3].map((seq) => ({
|
|
id: `message-${seq}`,
|
|
threadId: "thread-1",
|
|
seq,
|
|
role: "bot",
|
|
blocks: [{ kind: "text", text: String(seq) }],
|
|
runId: null,
|
|
createdAt: new Date(`2026-08-16T00:00:0${seq}.000Z`),
|
|
})),
|
|
);
|
|
const prisma = { message: { findMany } } as unknown as PrismaClient;
|
|
|
|
const page = await loadMessagePage(prisma, "thread-1", 6, 2);
|
|
|
|
expect(findMany).toHaveBeenCalledWith({
|
|
where: { threadId: "thread-1", seq: { lt: 6 } },
|
|
orderBy: { seq: "desc" },
|
|
take: 3,
|
|
});
|
|
expect(page.messages.map((message) => message.seq)).toEqual([4, 5]);
|
|
expect(page.olderCursor).toBe(4);
|
|
});
|
|
|
|
it("ends pagination when the database returns no lookahead row", async () => {
|
|
const findMany = vi.fn(async () => [
|
|
{
|
|
id: "message-0",
|
|
threadId: "thread-1",
|
|
seq: 0,
|
|
role: "user",
|
|
blocks: [],
|
|
runId: null,
|
|
createdAt: new Date("2026-08-16T00:00:00.000Z"),
|
|
},
|
|
]);
|
|
const prisma = { message: { findMany } } as unknown as PrismaClient;
|
|
|
|
const page = await loadMessagePage(prisma, "thread-1", 1, 2);
|
|
|
|
expect(page.messages.map((message) => message.seq)).toEqual([0]);
|
|
expect(page.olderCursor).toBeNull();
|
|
});
|
|
|
|
it("loads a page around a target sequence", async () => {
|
|
const findFirst = vi.fn(async () => ({ seq: 5 }));
|
|
const findMany = vi
|
|
.fn()
|
|
.mockResolvedValueOnce([
|
|
{
|
|
id: "message-3",
|
|
threadId: "thread-1",
|
|
seq: 3,
|
|
role: "bot",
|
|
blocks: [],
|
|
runId: null,
|
|
createdAt: new Date(),
|
|
},
|
|
{
|
|
id: "message-4",
|
|
threadId: "thread-1",
|
|
seq: 4,
|
|
role: "bot",
|
|
blocks: [],
|
|
runId: null,
|
|
createdAt: new Date(),
|
|
},
|
|
{
|
|
id: "message-5",
|
|
threadId: "thread-1",
|
|
seq: 5,
|
|
role: "bot",
|
|
blocks: [],
|
|
runId: null,
|
|
createdAt: new Date(),
|
|
},
|
|
])
|
|
.mockResolvedValueOnce(1);
|
|
const count = vi.fn(async () => 1);
|
|
const prisma = {
|
|
message: { findFirst, findMany, count },
|
|
} as unknown as PrismaClient;
|
|
|
|
const page = await loadMessagePage(prisma, "thread-1", undefined, 4, { seq: 5 });
|
|
|
|
expect(page.messages.map((message) => message.seq)).toEqual([3, 4, 5]);
|
|
expect(page.olderCursor).toBe(3);
|
|
expect(findMany).toHaveBeenCalledWith({
|
|
where: { threadId: "thread-1", seq: { gte: 3, lte: 7 } },
|
|
orderBy: { seq: "asc" },
|
|
take: 4,
|
|
});
|
|
});
|
|
|
|
it("collects bounded pages into chronological export order", async () => {
|
|
const row = (seq: number) => ({
|
|
id: `message-${seq}`,
|
|
threadId: "thread-1",
|
|
seq,
|
|
role: "bot",
|
|
blocks: [],
|
|
runId: null,
|
|
createdAt: new Date("2026-08-16T00:00:00.000Z"),
|
|
});
|
|
const findMany = vi
|
|
.fn()
|
|
.mockResolvedValueOnce([row(4), row(3), row(2)])
|
|
.mockResolvedValueOnce([row(2), row(1), row(0)])
|
|
.mockResolvedValueOnce([row(0)]);
|
|
const prisma = { message: { findMany } } as unknown as PrismaClient;
|
|
|
|
const messages = await loadAllMessages(prisma, "thread-1", 2);
|
|
|
|
expect(messages.map((message) => message.seq)).toEqual([0, 1, 2, 3, 4]);
|
|
expect(findMany.mock.calls.map(([query]) => query.where.seq?.lt)).toEqual([undefined, 3, 1]);
|
|
});
|
|
});
|