import { describe, expect, it, vi } from "vitest"; import { runAssistantLivingChatLlmRuntime } from "../src/services/assistantLivingChatLlmRuntimeAdapter"; describe("assistant living chat llm runtime adapter", () => { it("builds prompt/context internally and calls chat client with bounded output tokens", async () => { const chatClient = { chat: vi.fn(async () => ({ outputText: " llm-answer " })) }; const loadAssistantCanonExcerpt = vi.fn(() => "canon-chunk"); const sanitizeOutgoingAssistantText = vi.fn((value: unknown) => String(value ?? "").trim()); const result = await runAssistantLivingChatLlmRuntime({ userMessage: "question", sessionItems: [{ role: "user", text: "prev" }], payload: { llmProvider: "openai", apiKey: "k", model: "m", baseUrl: "https://api.example.com", temperature: 0.2, maxOutputTokens: 5000 }, chatClient, loadAssistantCanonExcerpt, sanitizeOutgoingAssistantText, defaultModel: "gpt-default", defaultBaseUrl: "https://api.default.com", defaultApiKey: "fallback-key" }); expect(loadAssistantCanonExcerpt).toHaveBeenCalledWith(520); expect(chatClient.chat).toHaveBeenCalledWith( expect.objectContaining({ llmProvider: "openai", apiKey: "k", model: "m", baseUrl: "https://api.example.com", temperature: 0.2, maxOutputTokens: 900 }), expect.objectContaining({ userMessage: expect.stringContaining("Сообщение пользователя:\nquestion"), maxOutputTokens: 900, temperature: 0.2, systemPrompt: expect.stringContaining("canon-chunk") }) ); const promptPayload = chatClient.chat.mock.calls[0]?.[1]; expect(promptPayload.userMessage).toContain("user: prev"); expect(sanitizeOutgoingAssistantText).toHaveBeenCalledWith(" llm-answer ", expect.any(String)); expect(result).toBe("llm-answer"); }); it("uses defaults and fallback text when model output is empty", async () => { const sanitizeOutgoingAssistantText = vi.fn((_value: unknown, fallback?: string) => String(fallback ?? "")); const result = await runAssistantLivingChatLlmRuntime({ userMessage: "question", sessionItems: [], payload: {}, chatClient: { chat: async () => ({ outputText: "" }) }, loadAssistantCanonExcerpt: () => "canon", sanitizeOutgoingAssistantText, defaultModel: "gpt-default", defaultBaseUrl: "https://api.default.com", defaultApiKey: "fallback-key" }); expect(sanitizeOutgoingAssistantText).toHaveBeenCalledWith("", expect.any(String)); expect(result.length).toBeGreaterThan(0); }); });