197 lines
6.8 KiB
TypeScript
197 lines
6.8 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import { runAssistantAddressAttemptRuntime } from "../src/services/assistantAddressAttemptRuntimeAdapter";
|
|
|
|
function buildInput(overrides: Record<string, unknown> = {}) {
|
|
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<string, unknown> | 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<string, unknown>) => 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
|
|
})
|
|
);
|
|
});
|
|
});
|