ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов 2.45 - объединены три выделенных слоя (NormalizationAttempt + AnalysisAttempt + ResponseAttempt) в один assistantDeepTurnAttemptRuntimeAdapter, после чего в handleMessage остался один вызов вместо трёх
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
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
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user