e30e75b5d4
Changesets / Create Version PR (push) Has been cancelled
Deploy Shadcn Registry / Deploy Production (push) Has been cancelled
Template Metrics / LOC + Bundle Size (push) Has been cancelled
Code Quality / Oxlint + Oxfmt (push) Has been cancelled
Code Quality / Template Sync (push) Has been cancelled
Code Quality / Build Changed Packages (push) Has been cancelled
Code Quality / Test Changed Packages (push) Has been cancelled
Deploy Expo Example / Deploy Production (push) Has been cancelled
Deploy Ink Example / Deploy Production (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.12) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.12) (push) Has been cancelled
264 lines
6.3 KiB
TypeScript
264 lines
6.3 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import type { LangChainBaseMessage } from "./types";
|
|
import { findForkCheckpointInHistory } from "./findForkCheckpointInHistory";
|
|
|
|
const msg = (id: string | undefined): LangChainBaseMessage => ({
|
|
_getType: () => "human",
|
|
content: "",
|
|
id,
|
|
});
|
|
|
|
const makeClient = (history: unknown[]) => ({
|
|
threads: {
|
|
getHistory: vi.fn(async () => history as never),
|
|
},
|
|
});
|
|
|
|
type HistoryState = {
|
|
values: Record<string, unknown>;
|
|
checkpoint: { checkpoint_id?: string };
|
|
};
|
|
|
|
const makePaginatedClient = (states: HistoryState[]) => ({
|
|
threads: {
|
|
getHistory: vi.fn(
|
|
async (
|
|
_threadId: string,
|
|
options?: {
|
|
limit?: number;
|
|
before?: { configurable: { checkpoint_id: string } };
|
|
},
|
|
) => {
|
|
const limit = options?.limit ?? 10;
|
|
const beforeId = options?.before?.configurable.checkpoint_id;
|
|
const start = beforeId
|
|
? states.findIndex((s) => s.checkpoint.checkpoint_id === beforeId) + 1
|
|
: 0;
|
|
return states.slice(start, start + limit) as never;
|
|
},
|
|
),
|
|
},
|
|
});
|
|
|
|
describe("findForkCheckpointInHistory", () => {
|
|
it("returns the checkpoint_id of the state whose messages match by id", async () => {
|
|
const client = makeClient([
|
|
{
|
|
values: { messages: [msg("a"), msg("b"), msg("c")] },
|
|
checkpoint: { checkpoint_id: "cp-too-long" },
|
|
},
|
|
{
|
|
values: { messages: [msg("a"), msg("b")] },
|
|
checkpoint: { checkpoint_id: "cp-match" },
|
|
},
|
|
{
|
|
values: { messages: [msg("a")] },
|
|
checkpoint: { checkpoint_id: "cp-too-short" },
|
|
},
|
|
]);
|
|
|
|
const result = await findForkCheckpointInHistory(
|
|
client,
|
|
"thread-1",
|
|
[msg("a"), msg("b")],
|
|
"messages",
|
|
);
|
|
|
|
expect(result).toBe("cp-match");
|
|
expect(client.threads.getHistory).toHaveBeenCalledWith("thread-1", {
|
|
limit: 100,
|
|
});
|
|
});
|
|
|
|
it("returns null when no state has the same message ids", async () => {
|
|
const client = makeClient([
|
|
{
|
|
values: { messages: [msg("a"), msg("x")] },
|
|
checkpoint: { checkpoint_id: "cp-1" },
|
|
},
|
|
]);
|
|
|
|
const result = await findForkCheckpointInHistory(
|
|
client,
|
|
"thread-1",
|
|
[msg("a"), msg("b")],
|
|
"messages",
|
|
);
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it("returns null when message ids are unstable (missing)", async () => {
|
|
const client = makeClient([
|
|
{
|
|
values: { messages: [msg("a"), msg(undefined)] },
|
|
checkpoint: { checkpoint_id: "cp-1" },
|
|
},
|
|
]);
|
|
|
|
const result = await findForkCheckpointInHistory(
|
|
client,
|
|
"thread-1",
|
|
[msg("a"), msg(undefined)],
|
|
"messages",
|
|
);
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it("reads messages from a custom messagesKey", async () => {
|
|
const client = makeClient([
|
|
{
|
|
values: { history: [msg("a")] },
|
|
checkpoint: { checkpoint_id: "cp-custom" },
|
|
},
|
|
]);
|
|
|
|
const result = await findForkCheckpointInHistory(
|
|
client,
|
|
"thread-1",
|
|
[msg("a")],
|
|
"history",
|
|
);
|
|
|
|
expect(result).toBe("cp-custom");
|
|
});
|
|
|
|
it("returns null when the matching checkpoint has no checkpoint_id", async () => {
|
|
const client = makeClient([
|
|
{
|
|
values: { messages: [msg("a")] },
|
|
checkpoint: {},
|
|
},
|
|
]);
|
|
|
|
const result = await findForkCheckpointInHistory(
|
|
client,
|
|
"thread-1",
|
|
[msg("a")],
|
|
"messages",
|
|
);
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it("keeps scanning when a matching state has no checkpoint_id", async () => {
|
|
const client = makeClient([
|
|
{
|
|
values: { messages: [msg("a")] },
|
|
checkpoint: {},
|
|
},
|
|
{
|
|
values: { messages: [msg("a")] },
|
|
checkpoint: { checkpoint_id: "cp-second" },
|
|
},
|
|
]);
|
|
|
|
const result = await findForkCheckpointInHistory(
|
|
client,
|
|
"thread-1",
|
|
[msg("a")],
|
|
"messages",
|
|
);
|
|
|
|
expect(result).toBe("cp-second");
|
|
});
|
|
|
|
it("does not throw when a state's messages payload is not an array", async () => {
|
|
const client = makeClient([
|
|
{
|
|
values: { messages: "ab" },
|
|
checkpoint: { checkpoint_id: "cp-1" },
|
|
},
|
|
]);
|
|
|
|
const result = await findForkCheckpointInHistory(
|
|
client,
|
|
"thread-1",
|
|
[msg("a"), msg("b")],
|
|
"messages",
|
|
);
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it("forwards a custom history limit to getHistory", async () => {
|
|
const client = makeClient([]);
|
|
|
|
await findForkCheckpointInHistory(
|
|
client,
|
|
"thread-1",
|
|
[msg("a")],
|
|
"messages",
|
|
25,
|
|
);
|
|
|
|
expect(client.threads.getHistory).toHaveBeenCalledWith("thread-1", {
|
|
limit: 25,
|
|
});
|
|
});
|
|
|
|
it("pages through history to find a match beyond the first page", async () => {
|
|
const client = makePaginatedClient([
|
|
{
|
|
values: { messages: [msg("a"), msg("b"), msg("c"), msg("d")] },
|
|
checkpoint: { checkpoint_id: "cp-4" },
|
|
},
|
|
{
|
|
values: { messages: [msg("a"), msg("b"), msg("c")] },
|
|
checkpoint: { checkpoint_id: "cp-3" },
|
|
},
|
|
{
|
|
values: { messages: [msg("a"), msg("b")] },
|
|
checkpoint: { checkpoint_id: "cp-2" },
|
|
},
|
|
{
|
|
values: { messages: [msg("a")] },
|
|
checkpoint: { checkpoint_id: "cp-1" },
|
|
},
|
|
]);
|
|
|
|
const result = await findForkCheckpointInHistory(
|
|
client,
|
|
"thread-1",
|
|
[msg("a")],
|
|
"messages",
|
|
2,
|
|
);
|
|
|
|
expect(result).toBe("cp-1");
|
|
expect(client.threads.getHistory).toHaveBeenCalledTimes(2);
|
|
expect(client.threads.getHistory).toHaveBeenLastCalledWith("thread-1", {
|
|
limit: 2,
|
|
before: { configurable: { checkpoint_id: "cp-3" } },
|
|
});
|
|
});
|
|
|
|
it("stops instead of looping when the cursor does not advance", async () => {
|
|
const page = [
|
|
{
|
|
values: { messages: [msg("x"), msg("y")] },
|
|
checkpoint: { checkpoint_id: "cp-1" },
|
|
},
|
|
{
|
|
values: { messages: [msg("x")] },
|
|
checkpoint: { checkpoint_id: "cp-2" },
|
|
},
|
|
];
|
|
const client = {
|
|
threads: { getHistory: vi.fn(async () => page as never) },
|
|
};
|
|
|
|
const result = await findForkCheckpointInHistory(
|
|
client,
|
|
"thread-1",
|
|
[msg("a")],
|
|
"messages",
|
|
2,
|
|
);
|
|
|
|
expect(result).toBeNull();
|
|
expect(client.threads.getHistory).toHaveBeenCalledTimes(2);
|
|
});
|
|
});
|