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(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(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(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(); });