NODEDC_1C/llm_normalizer/backend/tests/assistantDeepTurnAttemptRun...

222 lines
7.8 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { runAssistantDeepTurnAttemptRuntime } from "../src/services/assistantDeepTurnAttemptRuntimeAdapter";
function buildInput(overrides: Record<string, unknown> = {}) {
return {
sessionId: "asst-1",
questionId: "msg-q1",
userMessage: "почему не закрыт долг",
payload: {
llmProvider: "openai",
apiKey: "key",
model: "gpt-5",
baseUrl: "http://localhost",
temperature: 0.2,
maxOutputTokens: 400,
context: {}
},
runtimeAnalysisContext: {
active: true,
as_of_date: "2020-07-31",
period_from: null,
period_to: null,
source: "analysis_context"
},
sessionInvestigationState: null,
addressRuntimeMetaForDeep: null,
featureInvestigationStateV1: true,
featureStateFollowupBindingV1: true,
featureContractsV11: true,
featureAnswerPolicyV11: true,
featureProblemCentricAnswerV1: true,
featureLifecycleAnswerV1: true,
buildFollowupStateBinding: () => ({
normalizedQuestion: "normalized-question",
mergedContext: {},
usage: null
}),
normalize: async () =>
({
trace_id: "trace-1",
prompt_version: "normalizer_v2_0_2",
schema_version: "normalized_query_v2_0_2",
normalized: { fragments: [] },
route_hint_summary: { mode: "deterministic_v2", decisions: [] }
}) as any,
resolveBusinessScopeAlignment: ({ routeSummary }) => ({
route_summary_resolved: routeSummary
}),
inferP0DomainFromMessage: () => null,
resolveBusinessScopeFromLiveContext: ({ current }) => current,
extractRequirements: () => ({ requirements: [], byFragment: new Map() }),
toExecutionPlan: () => [],
enforceRbpLiveRoutePlan: ({ executionPlan }) => ({ executionPlan, audit: {} }),
enforceFaLiveRoutePlan: ({ executionPlan }) => ({ executionPlan, audit: {} }),
executeRouteRuntime: async () => ({
status: "ok",
result_type: "summary",
items: [],
summary: {},
evidence: [],
limitations: []
}),
mapNoRouteReason: () => "no_route",
buildSkippedResult: () => ({}) as any,
evaluateCoverage: () => ({ requirements: [], coverage: {} }),
checkGrounding: () => ({ status: "no_grounded_answer", reasons: [] }),
collectRbpLiveRouteAudit: () => ({}),
collectFaLiveRouteAudit: () => ({}),
hasExplicitPeriodAnchor: () => false,
extractDroppedIntentSegments: () => [],
buildDebugRoutes: () => [],
extractExecutionState: () => [],
sanitizeReply: (value: string) => value,
persistInvestigationState: () => {},
messageIdFactory: () => "msg-a1",
appendItem: () => {},
getSession: () => ({ session_id: "asst-1", items: [] }),
persistSession: () => {},
cloneConversation: () => [],
logEvent: () => {},
...overrides
} as any;
}
describe("assistant deep turn attempt runtime adapter", () => {
it("orchestrates normalization, analysis and response attempts in order", async () => {
const callOrder: string[] = [];
const normalizationRuntime = {
followupBinding: {
normalizedQuestion: "NQ",
mergedContext: {},
usage: { applied: true }
},
normalizePayload: { userQuestion: "NQ" },
normalized: {
trace_id: "trace-1",
prompt_version: "normalizer_v2_0_2",
schema_version: "normalized_query_v2_0_2",
normalized: { fragments: [] },
route_hint_summary: { mode: "deterministic_v2", decisions: [] }
}
} as any;
const analysisRuntime = {
resolvedRouteSummary: { mode: "deterministic_v2", decisions: [] },
requirementExtraction: { requirements: [], byFragment: new Map() },
coverageEvaluation: { requirements: [], coverage: {} },
groundingCheck: { status: "no_grounded_answer", reasons: [] },
executionPlan: [],
retrievalCalls: [],
retrievalResultsRaw: [],
retrievalResults: [],
questionTypeClass: "single_fact_lookup",
companyAnchors: {},
businessScopeResolution: {},
temporalGuard: {},
polarityGuardResult: { audit: {} },
claimAnchorAudit: { claim_type: "unknown" },
targetedEvidenceResult: { audit: {} },
evidenceGateResult: { audit: {} },
rbpLiveRouteAudit: {},
faLiveRouteAudit: {},
groundedAnswerEligibilityGuard: {},
composition: { reply_type: "partial_coverage" }
} as any;
const runDeepTurnNormalizationRuntime = vi.fn(async () => {
callOrder.push("normalization");
return normalizationRuntime;
});
const runDeepTurnAnalysisAttemptRuntime = vi.fn(async (input) => {
callOrder.push("analysis");
expect(input.normalizedPayload).toEqual(normalizationRuntime.normalized.normalized);
expect(input.routeSummary).toEqual(normalizationRuntime.normalized.route_hint_summary);
expect(input.followupUsage).toEqual({ applied: true });
return analysisRuntime;
});
const runDeepTurnResponseAttemptRuntime = vi.fn((input) => {
callOrder.push("response");
expect(input.normalizedQuestion).toBe("NQ");
expect(input.deepTurnAnalysisRuntime).toBe(analysisRuntime);
expect(input.followupApplied).toBe(true);
return {
response: { ok: true },
debug: { trace_id: "trace-1" }
};
});
const runtime = await runAssistantDeepTurnAttemptRuntime(
buildInput({
runDeepTurnNormalizationRuntime,
runDeepTurnAnalysisAttemptRuntime,
runDeepTurnResponseAttemptRuntime
})
);
expect(callOrder).toEqual(["normalization", "analysis", "response"]);
expect(runtime.response).toEqual({ ok: true });
expect(runtime.debug).toEqual({ trace_id: "trace-1" });
});
it("computes followupApplied=false when followup usage is absent", async () => {
const runDeepTurnNormalizationRuntime = vi.fn(async () => ({
followupBinding: {
normalizedQuestion: "NQ",
mergedContext: {},
usage: null
},
normalizePayload: {},
normalized: {
trace_id: "trace-1",
prompt_version: "normalizer_v2_0_2",
schema_version: "normalized_query_v2_0_2",
normalized: { fragments: [] },
route_hint_summary: null
}
}));
const runDeepTurnResponseAttemptRuntime = vi.fn(() => ({
response: { ok: true },
debug: {}
}));
const investigationState = { session_id: "asst-1" } as any;
await runAssistantDeepTurnAttemptRuntime(
buildInput({
sessionInvestigationState: investigationState,
runDeepTurnNormalizationRuntime,
runDeepTurnAnalysisAttemptRuntime: async () =>
({
resolvedRouteSummary: null,
requirementExtraction: { requirements: [], byFragment: new Map() },
coverageEvaluation: { requirements: [], coverage: {} },
groundingCheck: { status: "no_grounded_answer", reasons: [] },
executionPlan: [],
retrievalCalls: [],
retrievalResultsRaw: [],
retrievalResults: [],
questionTypeClass: "single_fact_lookup",
companyAnchors: {},
businessScopeResolution: {},
temporalGuard: {},
polarityGuardResult: { audit: {} },
claimAnchorAudit: { claim_type: "unknown" },
targetedEvidenceResult: { audit: {} },
evidenceGateResult: { audit: {} },
rbpLiveRouteAudit: {},
faLiveRouteAudit: {},
groundedAnswerEligibilityGuard: {},
composition: { reply_type: "partial_coverage" }
}) as any,
runDeepTurnResponseAttemptRuntime
})
);
expect(runDeepTurnResponseAttemptRuntime).toHaveBeenCalledWith(
expect.objectContaining({
followupApplied: false,
previousInvestigationState: investigationState
})
);
});
});