llm-to-agent/src/extensions/chat.test.ts
2026-07-30 17:45:51 +08:00

104 lines
3.3 KiB
TypeScript

import assert from "node:assert/strict";
import { mkdir, mkdtemp, rm, readdir } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import test from "node:test";
import { Kernel } from "../kernel";
import { Hook } from "./catalog";
import {
createAgentExtension,
type AgentService,
} from "./shared/agent";
import { createDeepSeekExtension } from "./shared/deepseek";
import {
createWorkspaceExtension,
type WorkspaceService,
} from "./shared/workspace";
test("streams a reply, saves it, and restores the conversation after restart", async (t) => {
const temporaryDirectory = await mkdtemp(join(tmpdir(), "llm-to-agent-"));
const home = join(temporaryDirectory, "home");
const projectPath = join(temporaryDirectory, "project");
await mkdir(projectPath);
t.after(() => rm(temporaryDirectory, { recursive: true, force: true }));
const requests: Array<{
model: string;
messages: Array<{ role: string; content: string }>;
stream: boolean;
}> = [];
const answers = ["第一次回答", "第二次回答"];
const request = async (url: string, init: RequestInit) => {
assert.equal(url, "https://api.deepseek.com/chat/completions");
assert.equal(init.method, "POST");
const body = JSON.parse(String(init.body));
requests.push(body);
const answer = answers[requests.length - 1] as string;
const middle = Math.ceil(answer.length / 2);
const stream = [
`data: ${JSON.stringify({ choices: [{ delta: { content: answer.slice(0, middle) } }] })}`,
`data: ${JSON.stringify({ choices: [{ delta: { content: answer.slice(middle) } }] })}`,
"data: [DONE]",
"",
].join("\n\n");
return new Response(stream, {
status: 200,
headers: { "content-type": "text/event-stream" },
});
};
const firstKernel = new Kernel().use(
createWorkspaceExtension({ home, projectPath }),
createDeepSeekExtension({ apiKey: "test-key", request }),
createAgentExtension(),
);
await firstKernel.start();
let firstAnswer = "";
for await (const chunk of firstKernel.get<AgentService>(Hook.Agent).chat("第一次问题")) {
firstAnswer += chunk;
}
assert.equal(firstAnswer, "第一次回答");
await firstKernel.stop();
const secondKernel = new Kernel().use(
createWorkspaceExtension({ home, projectPath }),
createDeepSeekExtension({ apiKey: "test-key", request }),
createAgentExtension(),
);
await secondKernel.start();
let secondAnswer = "";
for await (const chunk of secondKernel.get<AgentService>(Hook.Agent).chat("第二次问题")) {
secondAnswer += chunk;
}
assert.equal(secondAnswer, "第二次回答");
assert.deepEqual(requests[1]?.messages, [
{ role: "user", content: "第一次问题" },
{ role: "assistant", content: "第一次回答" },
{ role: "user", content: "第二次问题" },
]);
const workspace = secondKernel.get<WorkspaceService>(Hook.Workspace);
assert.deepEqual(
(await workspace.messages()).map(({ role, content }) => ({ role, content })),
[
{ role: "user", content: "第一次问题" },
{ role: "assistant", content: "第一次回答" },
{ role: "user", content: "第二次问题" },
{ role: "assistant", content: "第二次回答" },
],
);
assert.deepEqual(await readdir(projectPath), []);
await secondKernel.stop();
});