ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов 2.2 - Усилена оркестрацию в deep/address гейте и follow-up binding в assistantService.ts. Починен кейс UTF-8 follow-up refinement (теперь followup_state_usage.applied=true в нужном сценарии). Убраны регрессии по assistantLivingRouter и stage3 lifecycle probe. Корректное поведение для llm canonical candidate (чтобы не уезжало в clarification_required там, где должен быть address factual).

This commit is contained in:
2026-04-11 14:56:14 +03:00
parent 19f5f19d8e
commit b5bd4fd737
46 changed files with 2471 additions and 370 deletions
@@ -16,12 +16,6 @@ const KNOWN_GUARD_DOMAINS = [
"month_close_costs_20_44",
"fixed_asset_amortization"
];
function toRecordObject(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return null;
}
return value;
}
function toStringArray(value) {
if (!Array.isArray(value)) {
return [];
@@ -31,10 +25,10 @@ function toStringArray(value) {
.filter((item) => item.length > 0);
}
function toCompanyAnchorSet(value) {
const source = toRecordObject(value);
if (!source) {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return null;
}
const source = value;
return {
contract_numbers: toStringArray(source.contract_numbers),
document_numbers: toStringArray(source.document_numbers),
@@ -47,13 +41,12 @@ function toCompanyAnchorSet(value) {
};
}
function toClaimBoundPrimaryPeriod(value) {
const source = toRecordObject(value);
if (!source) {
if (!value || typeof value !== "object") {
return null;
}
const from = typeof source.from === "string" ? source.from.trim() : "";
const to = typeof source.to === "string" ? source.to.trim() : "";
const granularity = source.granularity === "day" || source.granularity === "month" ? source.granularity : null;
const from = typeof value.from === "string" ? value.from.trim() : "";
const to = typeof value.to === "string" ? value.to.trim() : "";
const granularity = value.granularity === "day" || value.granularity === "month" ? value.granularity : null;
if (!from || !to || !granularity) {
return null;
}
@@ -2,13 +2,16 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildAssistantDeepTurnNormalizationRuntime = buildAssistantDeepTurnNormalizationRuntime;
async function buildAssistantDeepTurnNormalizationRuntime(input) {
const followupBinding = input.featureInvestigationStateV1 &&
const investigationState = input.sessionInvestigationState;
const canUseFollowupBinding = input.featureInvestigationStateV1 &&
input.featureStateFollowupBindingV1 &&
Boolean(input.sessionInvestigationState)
investigationState !== null &&
investigationState !== undefined;
const followupBinding = canUseFollowupBinding
? input.buildFollowupStateBinding({
userMessage: input.userMessage,
payloadContext: input.payload.context,
investigationState: input.sessionInvestigationState
investigationState
})
: {
normalizedQuestion: input.userMessage,
@@ -6,9 +6,16 @@ const assistantContractsBundleAssembler_1 = require("./assistantContractsBundleA
const assistantDeepResponseAssembler_1 = require("./assistantDeepResponseAssembler");
const assistantDebugPayloadAssembler_1 = require("./assistantDebugPayloadAssembler");
const assistantMessageLogAssembler_1 = require("./assistantMessageLogAssembler");
function extractNormalizedFragments(normalized) {
if (!normalized || typeof normalized !== "object") {
return [];
}
const source = normalized;
return Array.isArray(source.fragments) ? source.fragments : [];
}
function assembleAssistantDeepTurnPackaging(input) {
const normalizedPayload = (input.normalized.normalized ?? null);
const normalizedFragments = Array.isArray(normalizedPayload?.["fragments"]) ? normalizedPayload?.["fragments"] : [];
const normalizedPayload = input.normalized.normalized ?? null;
const normalizedFragments = extractNormalizedFragments(normalizedPayload);
const evidenceBundleAssembly = (0, assistantEvidenceBundleAssembler_1.assembleAssistantEvidenceBundle)({
retrievalCalls: input.retrievalCalls,
retrievalResults: input.retrievalResults
@@ -3,12 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.runAssistantDeepTurnResponseRuntime = runAssistantDeepTurnResponseRuntime;
const assistantDeepTurnPackagingRuntimeAdapter_1 = require("./assistantDeepTurnPackagingRuntimeAdapter");
const assistantDeepTurnFinalizeRuntimeAdapter_1 = require("./assistantDeepTurnFinalizeRuntimeAdapter");
function toRecordObject(value) {
if (!value || typeof value !== "object") {
return null;
}
return value;
}
function toNullableString(value) {
if (typeof value !== "string") {
return null;
@@ -31,31 +25,17 @@ function normalizeExecutionPlan(value) {
if (!Array.isArray(value)) {
return [];
}
return value.map((item, index) => {
const source = toRecordObject(item);
return {
fragment_id: toNullableString(source?.fragment_id) ?? `fragment_${index + 1}`,
requirement_ids: toStringArray(source?.requirement_ids),
route: toNullableString(source?.route) ?? "unknown_route",
should_execute: Boolean(source?.should_execute),
no_route_reason: toNullableString(source?.no_route_reason),
clarification_reason: toNullableString(source?.clarification_reason)
};
});
}
function normalizeRecordArray(value) {
if (!Array.isArray(value)) {
return [];
}
return value
.map((item) => toRecordObject(item))
.filter((item) => Boolean(item));
}
function normalizeRecord(value) {
return toRecordObject(value) ?? {};
return value.map((item, index) => ({
fragment_id: toNullableString(item.fragment_id) ?? `fragment_${index + 1}`,
requirement_ids: toStringArray(item.requirement_ids),
route: toNullableString(item.route) ?? "unknown_route",
should_execute: Boolean(item.should_execute),
no_route_reason: toNullableString(item.no_route_reason ?? null),
clarification_reason: toNullableString(item.clarification_reason ?? null)
}));
}
function normalizeRuntimeAnalysisContext(value) {
const source = toRecordObject(value);
const source = value;
return {
active: Boolean(source?.active),
as_of_date: toNullableString(source?.as_of_date),
@@ -66,7 +46,7 @@ function normalizeRuntimeAnalysisContext(value) {
};
}
function normalizeBusinessScopeResolution(value) {
const source = toRecordObject(value);
const source = value;
return {
business_scope_raw: toStringArray(source?.business_scope_raw),
business_scope_resolved: toStringArray(source?.business_scope_resolved),
@@ -75,7 +55,7 @@ function normalizeBusinessScopeResolution(value) {
};
}
function normalizeAddressRuntimeMetaForDeep(value) {
const source = toRecordObject(value);
const source = value;
if (!source) {
return null;
}
@@ -87,8 +67,8 @@ function normalizeAddressRuntimeMetaForDeep(value) {
fallbackRuleHit: toNullableString(source.fallbackRuleHit),
toolGateDecision: toNullableString(source.toolGateDecision),
toolGateReason: toNullableString(source.toolGateReason),
predecomposeContract: toRecordObject(source.predecomposeContract),
orchestrationContract: toRecordObject(source.orchestrationContract)
predecomposeContract: source.predecomposeContract ?? null,
orchestrationContract: source.orchestrationContract ?? null
};
}
function runAssistantDeepTurnResponseRuntime(input) {
@@ -107,21 +87,21 @@ function runAssistantDeepTurnResponseRuntime(input) {
coverageEvaluationRequirements: input.coverageEvaluationRequirements,
coverageReport: input.coverageReport,
groundingCheck: input.groundingCheck,
retrievalCalls: normalizeRecordArray(input.retrievalCalls),
retrievalResultsRaw: Array.isArray(input.retrievalResultsRaw) ? input.retrievalResultsRaw : [],
retrievalCalls: input.retrievalCalls,
retrievalResultsRaw: input.retrievalResultsRaw,
retrievalResults: input.retrievalResults,
questionTypeClass: input.questionTypeClass,
companyAnchors: input.companyAnchors,
runtimeAnalysisContext: normalizeRuntimeAnalysisContext(input.runtimeAnalysisContext),
businessScopeResolution: normalizeBusinessScopeResolution(input.businessScopeResolution),
temporalGuard: normalizeRecord(input.temporalGuard),
polarityAudit: normalizeRecord(input.polarityAudit),
claimAnchorAudit: normalizeRecord(input.claimAnchorAudit),
temporalGuard: input.temporalGuard,
polarityAudit: input.polarityAudit,
claimAnchorAudit: input.claimAnchorAudit,
targetedEvidenceAudit: input.targetedEvidenceAudit,
evidenceAdmissibilityGateAudit: input.evidenceAdmissibilityGateAudit,
rbpLiveRouteAudit: input.rbpLiveRouteAudit ?? null,
faLiveRouteAudit: input.faLiveRouteAudit ?? null,
groundedAnswerEligibilityGuard: normalizeRecord(input.groundedAnswerEligibilityGuard),
groundedAnswerEligibilityGuard: input.groundedAnswerEligibilityGuard,
followupStateUsage: input.followupStateUsage,
followupApplied: input.followupApplied,
composition: input.composition,
@@ -20,6 +20,21 @@ function buildRouteExecutorErrorRawResult(route, message) {
errors: [message]
};
}
function normalizeRawResult(value) {
if (value === null || value === undefined) {
return null;
}
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
return value;
}
if (Array.isArray(value)) {
return value;
}
if (typeof value === "object") {
return value;
}
return null;
}
async function executeAssistantDeepTurnRetrievalPlan(input) {
const normalizeRetrievalResultSafe = input.normalizeRetrievalResultFn ?? retrievalResultNormalizer_1.normalizeRetrievalResult;
const retrievalCalls = [];
@@ -50,12 +65,13 @@ async function executeAssistantDeepTurnRetrievalPlan(input) {
const raw = await input.executeRouteRuntime(planItem.route, planItem.fragment_text, {
temporalHint: input.liveTemporalHint
});
const normalizedRaw = normalizeRawResult(raw);
retrievalResultsRaw.push({
fragment_id: planItem.fragment_id,
route: planItem.route,
raw_result: raw
raw_result: normalizedRaw
});
retrievalResults.push(normalizeRetrievalResultSafe(planItem.fragment_id, planItem.requirement_ids, planItem.route, raw));
retrievalResults.push(normalizeRetrievalResultSafe(planItem.fragment_id, planItem.requirement_ids, planItem.route, normalizedRaw));
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
@@ -4,12 +4,12 @@ exports.buildAssistantTurnRuntimeDeps = buildAssistantTurnRuntimeDeps;
function buildAssistantTurnRuntimeDeps(input) {
return {
...input.helpers,
ensureSession: input.sessions.ensureSession,
appendItem: input.sessions.appendItem,
getSession: input.sessions.getSession,
persistSession: input.sessionLogger.persistSession,
setInvestigationState: input.sessions.setInvestigationState,
normalize: input.normalizerService.normalize,
ensureSession: (sessionId) => input.sessions.ensureSession(sessionId),
appendItem: (sessionId, item) => input.sessions.appendItem(sessionId, item),
getSession: (sessionId) => input.sessions.getSession(sessionId),
persistSession: (session) => input.sessionLogger.persistSession(session),
setInvestigationState: (sessionId, state) => input.sessions.setInvestigationState(sessionId, state),
normalize: (payload) => input.normalizerService.normalize(payload),
executeRouteRuntime: (route, fragmentText, options) => input.dataLayer.executeRouteRuntime(route, fragmentText, options),
tryAddressQueryHandle: (messageUsed, options) => input.addressQueryService.tryHandle(messageUsed, options),
chatClient: input.chatClient,