import { describe, expect, it, vi } from "vitest"; import { runAssistantAddressAttemptRuntime } from "../src/services/assistantAddressAttemptRuntimeAdapter"; function buildInput(overrides: Record = {}) { return { featureAssistantAddressQueryV1: true, sessionId: "asst-1", userMessage: "where are overdue docs", sessionItems: [], payload: { llmProvider: "openai", useMock: 1, context: { period_hint: "2020-07-31" }, apiKey: "key", model: "gpt-5", baseUrl: "http://localhost" }, sessionScope: { knownOrganizations: ["Org A"], selectedOrganization: "Org A", activeOrganization: "Org A" }, featureAddressLlmPredecomposeV1: true, runAddressLlmPreDecompose: async () => ({}), buildAddressLlmPredecomposeContractV1: () => ({}), sanitizeAddressMessageForFallback: (value: string) => value, toNonEmptyString: (value: unknown) => typeof value === "string" && value.trim().length > 0 ? value.trim() : null, resolveAddressFollowupCarryoverContext: () => null, resolveAssistantOrchestrationDecision: () => ({ mode: "address_query", runAddressLane: true }), buildAddressDialogContinuationContractV2: () => ({}), runtimeAnalysisContextAsOfDate: "2020-07-31", compactWhitespace: (value: string) => String(value ?? "").replace(/\s+/g, " ").trim(), mergeFollowupContextWithOrganizationScope: (followupContext: Record | null) => followupContext, runAddressQueryTryHandle: async () => ({ response_type: "READY" }), isRetryableAddressLimitedResult: () => false, mergeKnownOrganizations: (knownOrganizations: string[], selectedOrganization: string | null) => ({ knownOrganizations, selectedOrganization }), hasAssistantDataScopeMetaQuestionSignal: () => false, shouldHandleAsAssistantCapabilityMetaQuery: () => false, hasDestructiveDataActionSignal: () => false, hasDangerOrCoercionSignal: () => false, hasOperationalAdminActionRequestSignal: () => false, hasOrganizationFactLookupSignal: () => false, hasOrganizationFactFollowupSignal: () => false, shouldEmitOrganizationSelectionReply: () => false, hasAssistantCapabilityQuestionSignal: () => false, resolveDataScopeProbe: () => null, applyScriptGuard: (chatText: string) => chatText, applyGroundingGuard: (guardInput: Record) => guardInput, buildAssistantSafetyRefusalReply: () => "safety", buildAssistantDataScopeContractReply: () => "scope", buildAssistantOrganizationFactBoundaryReply: () => "boundary", buildAssistantDataScopeSelectionReply: () => "selection", buildAssistantOperationalBoundaryReply: () => "operational", buildAssistantCapabilityContractReply: () => "capability", chatClient: {} as any, loadAssistantCanonExcerpt: () => "", sanitizeOutgoingAssistantText: (value: unknown, fallback = "") => { const text = typeof value === "string" ? value.trim() : ""; return text || fallback; }, defaultModel: "gpt-5", defaultBaseUrl: "http://localhost", defaultApiKey: "key", buildAddressDebugPayload: () => ({}), buildAddressFollowupOffer: () => null, appendItem: () => {}, getSession: () => ({ session_id: "asst-1", updated_at: "", items: [], investigation_state: null }), persistSession: () => {}, cloneConversation: (items: unknown[]) => items, logEvent: () => {}, messageIdFactory: () => "msg-111", nowIso: () => "2026-01-01T00:00:00.000Z", ...overrides } as any; } describe("assistant address attempt runtime adapter", () => { it("wires lane, response and living-chat attempt runtimes through one boundary", async () => { const runAddressLaneAttemptRuntime = vi.fn(async () => ({ response_type: "READY" })); const runAddressLaneResponseAttemptRuntime = vi.fn(() => ({ kind: "address" })); const runLivingChatAttemptRuntime = vi.fn(async () => ({ kind: "chat" })); const runAddressRuntime = vi.fn(async (input: any) => { const laneResult = await input.runAddressLaneAttempt( "lane-message", { followupContext: { previous_intent: "docs_by_counterparty" } }, "2020-08-31" ); expect(laneResult).toEqual({ response_type: "READY" }); const livingChatResult = await input.tryHandleLivingChat( { mode: "chat", reason: "living_chat_signal_detected" }, { source: "address_runtime" } ); expect(livingChatResult).toEqual({ kind: "chat" }); const response = input.finalizeAddressLaneResponse( { reply_text: "address reply", reply_type: "factual_with_explanation" }, "lane-message", { previousReplyType: "partial_coverage" }, { mode: "supported", confidence: "high" } ); expect(response).toEqual({ kind: "address" }); return { handled: true, response: { ok: true, lane: "address" }, addressRuntimeMetaForDeep: { source: "address_runtime" } }; }); const runtime = await runAssistantAddressAttemptRuntime( buildInput({ runAddressRuntime, runAddressLaneAttemptRuntime, runAddressLaneResponseAttemptRuntime, runLivingChatAttemptRuntime }) ); expect(runtime).toEqual({ handled: true, response: { ok: true, lane: "address" }, addressRuntimeMetaForDeep: { source: "address_runtime" } }); expect(runAddressRuntime).toHaveBeenCalledWith( expect.objectContaining({ llmProvider: "openai", useMock: true, payloadContextPeriodHint: "2020-07-31" }) ); expect(runAddressLaneAttemptRuntime).toHaveBeenCalledWith( expect.objectContaining({ messageUsed: "lane-message", analysisDateHint: "2020-08-31", activeOrganization: "Org A" }) ); expect(runLivingChatAttemptRuntime).toHaveBeenCalledWith( expect.objectContaining({ sessionId: "asst-1", sessionScope: expect.objectContaining({ selectedOrganization: "Org A" }) }) ); expect(runAddressLaneResponseAttemptRuntime).toHaveBeenCalledWith( expect.objectContaining({ sessionId: "asst-1", effectiveAddressUserMessage: "lane-message", knownOrganizations: ["Org A"] }) ); }); it("passes empty payload fields to address runtime without breaking defaults", async () => { const runAddressRuntime = vi.fn(async () => ({ handled: false, response: null, addressRuntimeMetaForDeep: null })); await runAssistantAddressAttemptRuntime( buildInput({ payload: {}, runAddressRuntime }) ); expect(runAddressRuntime).toHaveBeenCalledWith( expect.objectContaining({ llmProvider: undefined, useMock: false, payloadContextPeriodHint: undefined }) ); }); });