137 lines
3.6 KiB
TypeScript
137 lines
3.6 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
|
|
|
|
import { ConversationStore } from "../../src/conversations/store.js";
|
|
import { SessionHistoryStore } from "../../src/history/store.js";
|
|
import { createTestDatabase } from "../helpers/postgres.js";
|
|
|
|
describe("SessionHistoryStore", () => {
|
|
let conversationStore: ConversationStore;
|
|
let store: SessionHistoryStore;
|
|
let dispose: (() => Promise<void>) | undefined;
|
|
|
|
beforeEach(async () => {
|
|
const testDb = await createTestDatabase();
|
|
conversationStore = new ConversationStore(testDb.db);
|
|
store = new SessionHistoryStore(testDb.db);
|
|
dispose = testDb.dispose;
|
|
await Promise.all([conversationStore.initialize(), store.initialize()]);
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await dispose?.();
|
|
});
|
|
|
|
it("stores ordered turns for the durable conversation id", async () => {
|
|
await conversationStore.ensure({
|
|
actorKey: "actor-1",
|
|
projectId: "project-1",
|
|
projectKey: "project-1",
|
|
sessionId: "thread-1",
|
|
userId: "user-1",
|
|
});
|
|
|
|
const first = await store.appendTurn(
|
|
{
|
|
actorKey: "actor-1",
|
|
projectKey: "project-1",
|
|
sessionId: "thread-1",
|
|
},
|
|
{
|
|
assistantMessage: "先检查泵站流量。",
|
|
toolCallCount: 1,
|
|
userMessage: "帮我看一下当前异常。",
|
|
},
|
|
);
|
|
|
|
expect(first.turns).toHaveLength(1);
|
|
|
|
const second = await store.appendTurn(
|
|
{
|
|
actorKey: "actor-1",
|
|
projectKey: "project-1",
|
|
sessionId: "thread-1",
|
|
},
|
|
{
|
|
assistantMessage: "已经定位到 3 条疑似异常支路。",
|
|
toolCallCount: 2,
|
|
userMessage: "继续分析这些支路。",
|
|
},
|
|
);
|
|
|
|
expect(second.sessionId).toBe("thread-1");
|
|
expect(second.turns).toHaveLength(2);
|
|
expect(second.turns[0]?.userMessage).toBe("帮我看一下当前异常。");
|
|
expect(second.turns[1]?.assistantMessage).toBe("已经定位到 3 条疑似异常支路。");
|
|
});
|
|
|
|
it("clones only the kept prefix when forking a thread", async () => {
|
|
await conversationStore.ensure({
|
|
actorKey: "actor-2",
|
|
projectId: "project-2",
|
|
projectKey: "project-2",
|
|
sessionId: "thread-source",
|
|
userId: "user-2",
|
|
});
|
|
await conversationStore.ensure({
|
|
actorKey: "actor-2",
|
|
projectId: "project-2",
|
|
projectKey: "project-2",
|
|
sessionId: "thread-fork",
|
|
userId: "user-2",
|
|
});
|
|
|
|
await store.appendTurn(
|
|
{
|
|
actorKey: "actor-2",
|
|
projectKey: "project-2",
|
|
sessionId: "thread-source",
|
|
},
|
|
{
|
|
assistantMessage: "第一轮回复",
|
|
toolCallCount: 0,
|
|
userMessage: "第一轮提问",
|
|
},
|
|
);
|
|
await store.appendTurn(
|
|
{
|
|
actorKey: "actor-2",
|
|
projectKey: "project-2",
|
|
sessionId: "thread-source",
|
|
},
|
|
{
|
|
assistantMessage: "第二轮回复",
|
|
toolCallCount: 0,
|
|
userMessage: "第二轮提问",
|
|
},
|
|
);
|
|
|
|
const cloned = await store.cloneThread(
|
|
{
|
|
actorKey: "actor-2",
|
|
projectKey: "project-2",
|
|
sessionId: "thread-source",
|
|
},
|
|
{
|
|
actorKey: "actor-2",
|
|
projectKey: "project-2",
|
|
sessionId: "thread-fork",
|
|
},
|
|
2,
|
|
);
|
|
|
|
expect(cloned.turns).toHaveLength(1);
|
|
expect(cloned.turns[0]?.userMessage).toBe("第一轮提问");
|
|
|
|
const forkRecentTurns = await store.getRecentTurns(
|
|
{
|
|
actorKey: "actor-2",
|
|
projectKey: "project-2",
|
|
sessionId: "thread-fork",
|
|
},
|
|
5,
|
|
);
|
|
expect(forkRecentTurns).toHaveLength(1);
|
|
expect(forkRecentTurns[0]?.assistantMessage).toBe("第一轮回复");
|
|
});
|
|
});
|