import assert from "node:assert/strict"; import { describe, it } from "node:test"; import { createMockLlmClient } from "../../src/lib/llm/mock"; import { getLlmConfig } from "../../src/lib/llm/config"; import { runAgentChat } from "../../src/modules/agent/server/run"; describe("mock llm provider", () => { it("returns a plain assistant message by default", async () => { const client = createMockLlmClient(); const result = await client.chatCompletion({ messages: [{ role: "user", content: "hello" }], tools: [], }); assert.equal(result.message.role, "assistant"); assert.ok(result.message.content?.includes("mock provider")); }); it("requests add_list_item when the user mentions milk", async () => { const client = createMockLlmClient(); const result = await client.chatCompletion({ messages: [{ role: "user", content: "add milk to shopping list" }], tools: [ { type: "function", function: { name: "add_list_item", description: "add", parameters: { type: "object", properties: {} }, }, }, ], }); assert.equal(result.message.tool_calls?.[0]?.function.name, "add_list_item"); }); }); describe("getLlmConfig", () => { it("uses mock provider when base url is unset", () => { const original = process.env.LLM_BASE_URL; const originalProvider = process.env.LLM_PROVIDER; delete process.env.LLM_BASE_URL; delete process.env.LLM_PROVIDER; const config = getLlmConfig(); assert.equal(config.provider, "mock"); if (original === undefined) delete process.env.LLM_BASE_URL; else process.env.LLM_BASE_URL = original; if (originalProvider === undefined) delete process.env.LLM_PROVIDER; else process.env.LLM_PROVIDER = originalProvider; }); }); describe("runAgentChat", () => { it("executes tool calls and returns a final assistant message", async () => { const executed: string[] = []; const result = await runAgentChat({ messages: [{ role: "user", content: "add milk to the shopping list" }], request: new Request("http://localhost:3000/api/agent/chat"), llm: createMockLlmClient(), executeTool: async (name) => { executed.push(name); return JSON.stringify({ status: 201, body: { id: "item-1", text: "milk" } }); }, }); assert.deepEqual(executed, ["add_list_item"]); assert.equal(result.message.role, "assistant"); assert.ok(result.message.content.length > 0); assert.equal(result.toolCalls.length, 1); assert.equal(result.toolCalls[0]?.name, "add_list_item"); assert.equal(result.toolCalls[0]?.status, 201); }); it("accepts a custom system prompt override", async () => { const result = await runAgentChat({ messages: [{ role: "user", content: "hello" }], request: new Request("http://localhost:3000/api/agent/chat"), systemPrompt: "You are a pirate.", llm: createMockLlmClient(), }); assert.equal(result.message.role, "assistant"); assert.ok(result.message.content.length > 0); }); it("appends runtime clock context to the system prompt", async () => { const original = process.env.HOUSEHOLD_TIMEZONE; process.env.HOUSEHOLD_TIMEZONE = "America/Chicago"; let systemContent = ""; const result = await runAgentChat({ messages: [{ role: "user", content: "hello" }], request: new Request("http://localhost:3000/api/agent/chat"), systemPrompt: "You are a pirate.", llm: { async chatCompletion(request) { const system = request.messages.find((message) => message.role === "system"); systemContent = typeof system?.content === "string" ? system.content : ""; return { message: { role: "assistant", content: "Ahoy" }, finishReason: "stop", }; }, }, }); assert.equal(result.message.content, "Ahoy"); assert.match(systemContent, /^You are a pirate\./); assert.match(systemContent, /Current time:/); assert.match(systemContent, /America\/Chicago/); if (original === undefined) delete process.env.HOUSEHOLD_TIMEZONE; else process.env.HOUSEHOLD_TIMEZONE = original; }); }); it("passes a model override to the OpenAI-compatible client", async () => { const originalBaseUrl = process.env.LLM_BASE_URL; const originalModel = process.env.LLM_MODEL; const originalProvider = process.env.LLM_PROVIDER; const originalFetch = globalThis.fetch; let requestBody: unknown = null; process.env.LLM_BASE_URL = "https://llm.example.test/v1"; process.env.LLM_MODEL = "llama3.2"; delete process.env.LLM_PROVIDER; globalThis.fetch = (async (_input: RequestInfo | URL, init?: RequestInit) => { requestBody = JSON.parse(String(init?.body)); return Response.json({ choices: [{ message: { role: "assistant", content: "done" }, finish_reason: "stop" }], }); }) as typeof fetch; const { createLlmClient } = await import("../../src/lib/llm/index"); const client = createLlmClient({ model: "qwen2.5-coder" }); await client.chatCompletion({ messages: [{ role: "user", content: "hello" }] }); assert.equal((requestBody as { model?: string }).model, "qwen2.5-coder"); globalThis.fetch = originalFetch; if (originalBaseUrl === undefined) delete process.env.LLM_BASE_URL; else process.env.LLM_BASE_URL = originalBaseUrl; if (originalModel === undefined) delete process.env.LLM_MODEL; else process.env.LLM_MODEL = originalModel; if (originalProvider === undefined) delete process.env.LLM_PROVIDER; else process.env.LLM_PROVIDER = originalProvider; });