NODEDC_1C/llm_normalizer/backend/tests/assistantDeepTurnAnalysisAt...

338 lines
14 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import {
runAssistantDeepTurnAnalysisAttemptRuntime,
type RunAssistantDeepTurnAnalysisAttemptRuntimeInput
} from "../src/services/assistantDeepTurnAnalysisAttemptRuntimeAdapter";
function buildInput(
overrides: Partial<RunAssistantDeepTurnAnalysisAttemptRuntimeInput> = {}
): RunAssistantDeepTurnAnalysisAttemptRuntimeInput {
return {
userMessage: "почему долг не закрылся",
normalizedPayload: { fragments: [] } as any,
routeSummary: { mode: "deterministic_v2", decisions: [] } as any,
runtimeAnalysisContext: {
active: true,
as_of_date: "2020-07-31",
period_from: null,
period_to: null,
source: "analysis_context"
},
followupUsage: { applied: true },
investigationState: { session_id: "asst-1", followup_context: { active_domain: "settlements_60_62" } } as any,
featureAnswerPolicyV11: true,
featureProblemCentricAnswerV1: true,
featureLifecycleAnswerV1: true,
resolveBusinessScopeAlignment: () => ({ route_summary_resolved: { mode: "deterministic_v2", decisions: [] } }),
inferP0DomainFromMessage: () => "settlements_60_62",
resolveBusinessScopeFromLiveContext: ({ current }) => current,
extractRequirements: () => ({
requirements: [{ id: "R1" }],
byFragment: new Map<string, string[]>([["F1", ["R1"]]])
}),
toExecutionPlan: () =>
[
{
fragment_id: "F1",
requirement_ids: ["R1"],
route: "store_canonical",
should_execute: true,
fragment_text: "fragment",
no_route_reason: null
}
] as any,
enforceRbpLiveRoutePlan: ({ executionPlan }) => ({ executionPlan, audit: { rbp: true } }),
enforceFaLiveRoutePlan: ({ executionPlan }) => ({ executionPlan, audit: { fa: true } }),
executeRouteRuntime: async () => ({
status: "ok",
result_type: "summary",
items: [],
summary: {},
evidence: [],
limitations: []
}),
mapNoRouteReason: () => "skipped",
buildSkippedResult: (item) =>
({
fragment_id: item.fragment_id,
requirement_ids: item.requirement_ids ?? [],
route: item.route,
status: "skipped"
}) as any,
evaluateCoverage: () => ({
requirements: [{ id: "R1" }],
coverage: { requirements_total: 1, requirements_covered: 1 }
}),
checkGrounding: () => ({
status: "grounded",
reasons: []
}),
collectRbpLiveRouteAudit: () => ({ routed: 1 }),
collectFaLiveRouteAudit: () => ({ routed: 1 }),
hasExplicitPeriodAnchor: () => false,
...overrides
} as RunAssistantDeepTurnAnalysisAttemptRuntimeInput;
}
describe("assistant deep turn analysis attempt runtime adapter", () => {
it("wires deep-analysis callbacks through delegated runtime", async () => {
const runDeepTurnContextRuntime = vi.fn(() => ({
companyAnchors: { accounts: ["60.01"] },
initialBusinessScopeResolution: { route_summary_resolved: { mode: "deterministic_v2", decisions: [] } },
inferredDomainByMessage: "settlements_60_62",
focusDomainForGuards: "settlements_60_62",
temporalGuard: { primary_period_window: { from: "2020-07-01", to: "2020-07-31" } },
domainPolarityGuardInitial: { polarity: "supplier_payable" },
claimAnchorAudit: { claim_type: "prove_settlement_closure_state" },
businessScopeResolution: {
route_summary_resolved: { mode: "deterministic_v2", decisions: [] },
business_scope_resolved: ["company_specific_accounting"]
},
resolvedRouteSummary: { mode: "deterministic_v2", decisions: [] },
liveTemporalHint: {
as_of_date: "2020-07-31",
period_from: null,
period_to: null,
source: "analysis_context"
}
}));
const runDeepTurnPlanRuntime = vi.fn(() => ({
requirementExtraction: {
requirements: [{ id: "R1" }],
byFragment: new Map<string, string[]>([["F1", ["R1"]]])
},
executionPlan: [
{
fragment_id: "F1",
requirement_ids: ["R1"],
route: "store_canonical",
should_execute: true,
fragment_text: "fragment",
no_route_reason: null
}
],
rbpRoutePlanEnforcement: { executionPlan: [], audit: { rbp: true } },
faRoutePlanEnforcement: { executionPlan: [], audit: { fa: true } }
}));
const executeRouteRuntime = vi.fn(async () => ({
status: "ok",
result_type: "summary",
items: [],
summary: {},
evidence: [],
limitations: []
}));
const runDeepTurnRetrievalRuntime = vi.fn(async (input) => {
expect(input.executeRouteRuntime).toBe(executeRouteRuntime);
return {
retrievalCalls: [{ fragment_id: "F1", route: "store_canonical" }],
retrievalResultsRaw: [{ fragment_id: "F1", route: "store_canonical", raw_result: {} }],
retrievalResults: [{ fragment_id: "F1", requirement_ids: ["R1"], route: "store_canonical" }]
} as any;
});
const runDeepTurnGuardRuntime = vi.fn(() => ({
retrievalResults: [{ fragment_id: "F1", requirement_ids: ["R1"], route: "store_canonical" }],
polarityGuardResult: { audit: { polarity: "supplier_payable" } },
targetedEvidenceResult: { audit: { targeted_evidence_hit_rate: 1 } },
evidenceGateResult: { audit: { admissible_evidence_count: 1 } }
}));
const runDeepTurnGroundingRuntime = vi.fn(() => ({
rbpLiveRouteAudit: { routed: 1 },
faLiveRouteAudit: { routed: 1 },
coverageEvaluation: {
requirements: [{ id: "R1" }],
coverage: { requirements_total: 1, requirements_covered: 1 }
},
groundedAnswerEligibilityGuard: { eligible: true },
groundingCheck: { status: "grounded", reasons: [] }
}));
const runDeepTurnCompositionRuntime = vi.fn(() => ({
questionTypeClass: "causal_trace",
composition: { reply_type: "factual_with_explanation" }
}));
const runDeepTurnAnalysisRuntime = vi.fn(async (input) => {
const contextRuntime = input.runContextRuntime();
const executionPlanRuntime = input.runExecutionPlanRuntime({
resolvedRouteSummary: contextRuntime.resolvedRouteSummary,
claimAnchorAudit: contextRuntime.claimAnchorAudit,
temporalGuard: contextRuntime.temporalGuard,
domainPolarityGuardInitial: contextRuntime.domainPolarityGuardInitial
});
const retrievalRuntime = await input.runRetrievalRuntime({
executionPlan: executionPlanRuntime.executionPlan,
liveTemporalHint: contextRuntime.liveTemporalHint
});
const guardRuntime = input.runGuardRuntime({
retrievalResults: retrievalRuntime.retrievalResults as any,
domainPolarityGuardInitial: contextRuntime.domainPolarityGuardInitial,
claimAnchorAudit: contextRuntime.claimAnchorAudit,
temporalGuard: contextRuntime.temporalGuard,
focusDomainForGuards: contextRuntime.focusDomainForGuards,
companyAnchors: contextRuntime.companyAnchors,
userMessage: "runtime-user-message"
});
const groundingRuntime = input.runGroundingRuntime({
claimType: contextRuntime.claimAnchorAudit.claim_type,
retrievalResults: guardRuntime.retrievalResults as any,
rbpPlanAudit: executionPlanRuntime.rbpRoutePlanEnforcement.audit,
faPlanAudit: executionPlanRuntime.faRoutePlanEnforcement.audit,
routeSummary: contextRuntime.resolvedRouteSummary,
requirementExtraction: executionPlanRuntime.requirementExtraction,
temporalGuard: contextRuntime.temporalGuard,
polarityAudit: guardRuntime.polarityGuardResult.audit,
evidenceAudit: guardRuntime.evidenceGateResult.audit,
claimAnchorAudit: contextRuntime.claimAnchorAudit,
targetedEvidenceHitRate: guardRuntime.targetedEvidenceResult.audit.targeted_evidence_hit_rate,
businessScopeResolved: contextRuntime.businessScopeResolution.business_scope_resolved
});
const compositionRuntime = input.runCompositionRuntime({
resolvedRouteSummary: contextRuntime.resolvedRouteSummary,
retrievalResults: guardRuntime.retrievalResults as any,
requirements: groundingRuntime.coverageEvaluation.requirements as any,
coverageReport: groundingRuntime.coverageEvaluation.coverage as any,
groundingCheck: groundingRuntime.groundingCheck as any,
companyAnchors: contextRuntime.companyAnchors
});
return {
companyAnchors: contextRuntime.companyAnchors,
temporalGuard: contextRuntime.temporalGuard,
claimAnchorAudit: contextRuntime.claimAnchorAudit,
businessScopeResolution: contextRuntime.businessScopeResolution,
resolvedRouteSummary: contextRuntime.resolvedRouteSummary,
requirementExtraction: executionPlanRuntime.requirementExtraction as any,
executionPlan: executionPlanRuntime.executionPlan as any,
retrievalCalls: retrievalRuntime.retrievalCalls as any,
retrievalResultsRaw: retrievalRuntime.retrievalResultsRaw as any,
retrievalResults: guardRuntime.retrievalResults as any,
polarityGuardResult: guardRuntime.polarityGuardResult as any,
targetedEvidenceResult: guardRuntime.targetedEvidenceResult as any,
evidenceGateResult: guardRuntime.evidenceGateResult as any,
rbpLiveRouteAudit: groundingRuntime.rbpLiveRouteAudit as any,
faLiveRouteAudit: groundingRuntime.faLiveRouteAudit as any,
coverageEvaluation: groundingRuntime.coverageEvaluation as any,
groundedAnswerEligibilityGuard: groundingRuntime.groundedAnswerEligibilityGuard as any,
groundingCheck: groundingRuntime.groundingCheck as any,
questionTypeClass: compositionRuntime.questionTypeClass as any,
composition: compositionRuntime.composition as any
};
});
const runtime = await runAssistantDeepTurnAnalysisAttemptRuntime(
buildInput({
executeRouteRuntime,
runDeepTurnAnalysisRuntime,
runDeepTurnContextRuntime,
runDeepTurnPlanRuntime,
runDeepTurnRetrievalRuntime,
runDeepTurnGuardRuntime,
runDeepTurnGroundingRuntime,
runDeepTurnCompositionRuntime
})
);
expect(runDeepTurnAnalysisRuntime).toHaveBeenCalledTimes(1);
expect(runDeepTurnContextRuntime).toHaveBeenCalledTimes(1);
expect(runDeepTurnPlanRuntime).toHaveBeenCalledTimes(1);
expect(runDeepTurnRetrievalRuntime).toHaveBeenCalledTimes(1);
expect(runDeepTurnGuardRuntime).toHaveBeenCalledTimes(1);
expect(runDeepTurnGroundingRuntime).toHaveBeenCalledTimes(1);
expect(runDeepTurnCompositionRuntime).toHaveBeenCalledTimes(1);
expect(runtime.questionTypeClass).toBe("causal_trace");
});
it("forwards composition feature flags and investigation state", async () => {
const runDeepTurnCompositionRuntime = vi.fn(() => ({
questionTypeClass: "single_fact_lookup",
composition: { reply_type: "partial_coverage" }
}));
const runDeepTurnAnalysisRuntime = vi.fn(async (input) => {
input.runContextRuntime();
input.runExecutionPlanRuntime({
resolvedRouteSummary: null,
claimAnchorAudit: { claim_type: "unknown" },
temporalGuard: {},
domainPolarityGuardInitial: {}
});
await input.runRetrievalRuntime({
executionPlan: [],
liveTemporalHint: null
});
input.runGuardRuntime({
retrievalResults: [],
domainPolarityGuardInitial: {},
claimAnchorAudit: { claim_type: "unknown" },
temporalGuard: {},
focusDomainForGuards: null,
companyAnchors: {},
userMessage: "message"
});
input.runGroundingRuntime({
claimType: "unknown",
retrievalResults: [],
rbpPlanAudit: {},
faPlanAudit: {},
routeSummary: null,
requirementExtraction: { requirements: [], byFragment: new Map() } as any,
temporalGuard: {},
polarityAudit: {},
evidenceAudit: {},
claimAnchorAudit: { claim_type: "unknown" },
targetedEvidenceHitRate: null,
businessScopeResolved: null
});
input.runCompositionRuntime({
resolvedRouteSummary: null,
retrievalResults: [],
requirements: [],
coverageReport: {},
groundingCheck: { status: "grounded", reasons: [] },
companyAnchors: {}
});
return {
companyAnchors: {},
temporalGuard: {},
claimAnchorAudit: { claim_type: "unknown" },
businessScopeResolution: {},
resolvedRouteSummary: null,
requirementExtraction: { requirements: [], byFragment: new Map() } as any,
executionPlan: [],
retrievalCalls: [],
retrievalResultsRaw: [],
retrievalResults: [],
polarityGuardResult: { audit: {} } as any,
targetedEvidenceResult: { audit: { targeted_evidence_hit_rate: null } } as any,
evidenceGateResult: { audit: {} } as any,
rbpLiveRouteAudit: {},
faLiveRouteAudit: {},
coverageEvaluation: { requirements: [], coverage: {} } as any,
groundedAnswerEligibilityGuard: {},
groundingCheck: { status: "grounded", reasons: [] } as any,
questionTypeClass: "single_fact_lookup" as any,
composition: { reply_type: "partial_coverage" } as any
};
});
const investigationState = { session_id: "asst-2" } as any;
await runAssistantDeepTurnAnalysisAttemptRuntime(
buildInput({
investigationState,
featureAnswerPolicyV11: false,
featureProblemCentricAnswerV1: false,
featureLifecycleAnswerV1: false,
runDeepTurnCompositionRuntime,
runDeepTurnAnalysisRuntime
})
);
expect(runDeepTurnCompositionRuntime).toHaveBeenCalledWith(
expect.objectContaining({
investigationState,
featureAnswerPolicyV11: false,
featureProblemCentricAnswerV1: false,
featureLifecycleAnswerV1: false
})
);
});
});