import { describe, expect, it, vi } from "vitest"; import { buildAssistantLivingChatHandlerRuntimeInput, buildAssistantLivingChatLlmRuntimeInput } from "../src/services/assistantLivingChatAttemptRuntimeInputBuilder"; describe("assistant living chat attempt runtime input builder", () => { it("builds living-chat llm runtime input", () => { const runtimeInput = buildAssistantLivingChatLlmRuntimeInput({ userMessage: "hello", sessionItems: [{ role: "user", text: "ctx" }], payload: { llmProvider: "openai" } as any, chatClient: {} as any, loadAssistantCanonExcerpt: vi.fn(() => "canon"), sanitizeOutgoingAssistantText: vi.fn((value: unknown) => String(value ?? "")), defaultModel: "gpt-5", defaultBaseUrl: "http://localhost", defaultApiKey: "key" }); expect(runtimeInput.userMessage).toBe("hello"); expect(runtimeInput.sessionItems).toEqual([{ role: "user", text: "ctx" }]); expect(runtimeInput.defaultModel).toBe("gpt-5"); expect(runtimeInput.defaultBaseUrl).toBe("http://localhost"); expect(runtimeInput.defaultApiKey).toBe("key"); }); it("builds living-chat handler runtime input with execute callback", async () => { const executeLlmChat = vi.fn(async () => "llm-answer"); const runtimeInput = buildAssistantLivingChatHandlerRuntimeInput({ sessionId: "asst-1", userMessage: "hello", sessionItems: [], modeDecision: { mode: "chat", reason: "living_chat_signal_detected" }, sessionScope: { knownOrganizations: [], selectedOrganization: null, activeOrganization: null }, addressRuntimeMeta: null, traceIdFactory: vi.fn(() => "chat-1"), toNonEmptyString: vi.fn((value: unknown) => typeof value === "string" && value.trim().length > 0 ? value.trim() : null ), mergeKnownOrganizations: vi.fn((values: string[]) => values), hasAssistantDataScopeMetaQuestionSignal: vi.fn(() => false), shouldHandleAsAssistantCapabilityMetaQuery: vi.fn(() => false), hasDestructiveDataActionSignal: vi.fn(() => false), hasDangerOrCoercionSignal: vi.fn(() => false), hasOperationalAdminActionRequestSignal: vi.fn(() => false), hasOrganizationFactLookupSignal: vi.fn(() => false), hasOrganizationFactFollowupSignal: vi.fn(() => false), hasLivingChatSignal: vi.fn(() => false), shouldEmitOrganizationSelectionReply: vi.fn(() => false), hasAssistantCapabilityQuestionSignal: vi.fn(() => false), resolveOrganizationSelectionFromMessage: vi.fn(() => null), resolveDataScopeProbe: vi.fn(async () => null), executeLlmChat, applyScriptGuard: vi.fn((text: string) => ({ text, applied: false, reason: null })), applyGroundingGuard: vi.fn((payload: { chatText: string }) => ({ text: payload.chatText, applied: false, reason: null })), buildAssistantSafetyRefusalReply: vi.fn(() => "safety"), buildAssistantDataScopeContractReply: vi.fn(() => "scope"), buildAssistantProactiveOrganizationOfferReply: vi.fn(() => "offer"), buildAssistantOrganizationFactBoundaryReply: vi.fn(() => "boundary"), buildAssistantDataScopeSelectionReply: vi.fn(() => "selection"), buildAssistantOperationalBoundaryReply: vi.fn(() => "operational"), buildAssistantCapabilityContractReply: vi.fn(() => "capability"), appendItem: vi.fn(), getSession: vi.fn(), persistSession: vi.fn(), cloneConversation: vi.fn((items: unknown[]) => items), logEvent: vi.fn(), messageIdFactory: vi.fn(() => "msg-1"), nowIso: vi.fn(() => "2026-04-11T00:00:00.000Z"), runLivingChatRuntime: vi.fn(async () => null), finalizeLivingChatTurn: vi.fn() }); await runtimeInput.executeLlmChat(); expect(executeLlmChat).toHaveBeenCalledTimes(1); expect(runtimeInput.modeDecision).toEqual({ mode: "chat", reason: "living_chat_signal_detected" }); }); });