104 lines
3.3 KiB
TypeScript
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();
|
|
});
|