ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов 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
@@ -1,4 +1,12 @@
import type { AssistantDebugPayload, AssistantMessageResponsePayload } from "../types/assistant";
import type {
AssistantAddressRuntimeMetaForDeep,
AssistantDebugPayload,
AssistantDebugRouteRecord,
AssistantExecutionStateRecord,
AssistantMessageResponsePayload,
FaLiveRouteAuditDebug,
RbpLiveRouteAuditDebug
} from "../types/assistant";
import type { NormalizeResponsePayload, RouteHintSummary } from "../types/normalizer";
import type { InvestigationStateWithProblemUnits } from "../types/stage2ProblemUnits";
import {
@@ -7,10 +15,23 @@ import {
type AssistantDeepTurnPackagingRuntimeOutput
} from "./assistantDeepTurnPackagingRuntimeAdapter";
import type { RunAssistantDeepTurnAnalysisRuntimeOutput } from "./assistantDeepTurnAnalysisRuntimeAdapter";
import type { AssistantExecutionPlanItem } from "./assistantQueryPlanning";
import {
finalizeAssistantDeepTurn,
type FinalizeAssistantDeepTurnInput
} from "./assistantDeepTurnFinalizeRuntimeAdapter";
import type { ClaimBoundAnchorAudit, TargetedEvidenceAcquisitionAudit } from "./assistantClaimBoundEvidence";
import type { CompanyAnchorSet } from "./companyAnchorResolver";
import type {
DomainPolarityGuardAudit,
EvidenceAdmissibilityAudit,
GroundedAnswerEligibilityAudit,
TemporalGuardAudit
} from "./assistantRuntimeGuards";
import type {
AssistantRetrievalCallRecord,
AssistantRetrievalRawResultRecord
} from "./assistantDeepTurnRetrievalRuntimeAdapter";
export interface RunAssistantDeepTurnResponseRuntimeInput {
featureInvestigationStateV1: boolean;
@@ -27,16 +48,16 @@ export interface RunAssistantDeepTurnResponseRuntimeInput {
};
normalizedQuestion: string;
routeSummary: RouteHintSummary | null;
executionPlan: unknown[];
executionPlan: AssistantExecutionPlanItem[];
requirementExtractionRequirements: AssistantDeepTurnPackagingRuntimeInput["requirementExtractionRequirements"];
coverageEvaluationRequirements: AssistantDeepTurnPackagingRuntimeInput["coverageEvaluationRequirements"];
coverageReport: AssistantDeepTurnPackagingRuntimeInput["coverageReport"];
groundingCheck: AssistantDeepTurnPackagingRuntimeInput["groundingCheck"];
retrievalCalls: unknown[];
retrievalResultsRaw: unknown[];
retrievalCalls: AssistantRetrievalCallRecord[];
retrievalResultsRaw: AssistantRetrievalRawResultRecord[];
retrievalResults: AssistantDeepTurnPackagingRuntimeInput["retrievalResults"];
questionTypeClass: AssistantDeepTurnPackagingRuntimeInput["questionTypeClass"];
companyAnchors: RunAssistantDeepTurnAnalysisRuntimeOutput["companyAnchors"];
companyAnchors: CompanyAnchorSet | null;
runtimeAnalysisContext: {
active: boolean;
as_of_date: string | null;
@@ -46,22 +67,22 @@ export interface RunAssistantDeepTurnResponseRuntimeInput {
snapshot_mode?: "auto" | "force_snapshot" | "force_live";
};
businessScopeResolution: RunAssistantDeepTurnAnalysisRuntimeOutput["businessScopeResolution"];
temporalGuard: unknown;
polarityAudit: unknown;
claimAnchorAudit: unknown;
targetedEvidenceAudit: unknown;
evidenceAdmissibilityGateAudit: unknown;
rbpLiveRouteAudit: unknown;
faLiveRouteAudit: unknown;
groundedAnswerEligibilityGuard: unknown;
temporalGuard: TemporalGuardAudit;
polarityAudit: DomainPolarityGuardAudit;
claimAnchorAudit: ClaimBoundAnchorAudit;
targetedEvidenceAudit: TargetedEvidenceAcquisitionAudit;
evidenceAdmissibilityGateAudit: EvidenceAdmissibilityAudit;
rbpLiveRouteAudit: RbpLiveRouteAuditDebug | null;
faLiveRouteAudit: FaLiveRouteAuditDebug | null;
groundedAnswerEligibilityGuard: GroundedAnswerEligibilityAudit;
followupStateUsage: AssistantDeepTurnPackagingRuntimeInput["followupStateUsage"];
followupApplied: boolean;
composition: AssistantDeepTurnPackagingRuntimeInput["composition"];
previousInvestigationState: AssistantDeepTurnPackagingRuntimeInput["previousInvestigationState"];
addressRuntimeMetaForDeep: AssistantDeepTurnPackagingRuntimeInput["addressRuntimeMetaForDeep"];
extractDroppedIntentSegments: (normalizedPayload: NormalizeResponsePayload["normalized"]) => string[];
buildDebugRoutes: (routeSummary: RouteHintSummary | null) => Array<Record<string, unknown>>;
extractExecutionState: (normalizedPayload: NormalizeResponsePayload["normalized"]) => unknown[];
buildDebugRoutes: (routeSummary: RouteHintSummary | null) => AssistantDebugRouteRecord[];
extractExecutionState: (normalizedPayload: NormalizeResponsePayload["normalized"]) => AssistantExecutionStateRecord[];
sanitizeReply: (value: string, fallback?: string) => string;
persistInvestigationState: (sessionId: string, snapshot: InvestigationStateWithProblemUnits) => void;
messageIdFactory: () => string;
@@ -81,14 +102,7 @@ export interface RunAssistantDeepTurnResponseRuntimeOutput {
debug: AssistantDebugPayload;
}
function toRecordObject(value: unknown): Record<string, unknown> | null {
if (!value || typeof value !== "object") {
return null;
}
return value as Record<string, unknown>;
}
function toNullableString(value: unknown): string | null {
function toNullableString(value: string | null | undefined): string | null {
if (typeof value !== "string") {
return null;
}
@@ -96,7 +110,7 @@ function toNullableString(value: unknown): string | null {
return trimmed.length > 0 ? trimmed : null;
}
function toStringArray(value: unknown): string[] {
function toStringArray(value: string[] | null | undefined): string[] {
if (!Array.isArray(value)) {
return [];
}
@@ -105,44 +119,30 @@ function toStringArray(value: unknown): string[] {
.filter((item) => item.length > 0);
}
function toSnapshotMode(value: unknown): "auto" | "force_snapshot" | "force_live" {
function toSnapshotMode(value: string | null | undefined): "auto" | "force_snapshot" | "force_live" {
return value === "force_snapshot" || value === "force_live" ? value : "auto";
}
function normalizeExecutionPlan(value: unknown[]): AssistantDeepTurnPackagingRuntimeInput["executionPlan"] {
function normalizeExecutionPlan(
value: AssistantExecutionPlanItem[]
): AssistantDeepTurnPackagingRuntimeInput["executionPlan"] {
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: unknown[]): Array<Record<string, unknown>> {
if (!Array.isArray(value)) {
return [];
}
return value
.map((item) => toRecordObject(item))
.filter((item): item is Record<string, unknown> => Boolean(item));
}
function normalizeRecord(value: unknown): Record<string, unknown> {
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: unknown
value: RunAssistantDeepTurnResponseRuntimeInput["runtimeAnalysisContext"] | null | undefined
): AssistantDeepTurnPackagingRuntimeInput["runtimeAnalysisContext"] {
const source = toRecordObject(value);
const source = value;
return {
active: Boolean(source?.active),
as_of_date: toNullableString(source?.as_of_date),
@@ -154,9 +154,9 @@ function normalizeRuntimeAnalysisContext(
}
function normalizeBusinessScopeResolution(
value: unknown
value: RunAssistantDeepTurnAnalysisRuntimeOutput["businessScopeResolution"] | null | undefined
): AssistantDeepTurnPackagingRuntimeInput["businessScopeResolution"] {
const source = toRecordObject(value);
const source = value;
return {
business_scope_raw: toStringArray(source?.business_scope_raw),
business_scope_resolved: toStringArray(source?.business_scope_resolved),
@@ -166,9 +166,9 @@ function normalizeBusinessScopeResolution(
}
function normalizeAddressRuntimeMetaForDeep(
value: unknown
): AssistantDeepTurnPackagingRuntimeInput["addressRuntimeMetaForDeep"] {
const source = toRecordObject(value);
value: AssistantAddressRuntimeMetaForDeep | null | undefined
): AssistantAddressRuntimeMetaForDeep | null {
const source = value;
if (!source) {
return null;
}
@@ -180,8 +180,8 @@ function normalizeAddressRuntimeMetaForDeep(
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
};
}
@@ -204,21 +204,21 @@ export function runAssistantDeepTurnResponseRuntime(
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,