ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов 2.46: склейка всего address-потока в отдельный assistantAddressAttemptRuntimeAdapter, для того чтобы из handleMessage убрать три локальных closure целиком. Все три моста (lane, response, living chat) прокидываются и не ломают контракт.
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
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
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user