Этап 4 / Волна 18 закрытие блокеров по времени, доменной полярности и допуску доказательной базы

This commit is contained in:
2026-03-29 00:40:06 +03:00
parent 7eb1410501
commit d7e145010b
140 changed files with 417053 additions and 42196 deletions
@@ -10,6 +10,7 @@ import * as investigationState_1 from "./investigationState";
import * as retrievalResultNormalizer_1 from "./retrievalResultNormalizer";
import * as questionTypeResolver_1 from "./questionTypeResolver";
import * as companyAnchorResolver_1 from "./companyAnchorResolver";
import * as assistantRuntimeGuards_1 from "./assistantRuntimeGuards";
function retrievalSummaryForRoute(route) {
if (route === "store_canonical")
return "Canonical accounting data path selected.";
@@ -859,6 +860,43 @@ function extractFollowupAccountAnchorsLoose(text) {
}
return Array.from(new Set(anchors));
}
function accountPrefixToken(value) {
const token = String(value ?? "").trim();
const match = token.match(/^(\d{2})/);
return match ? match[1] : null;
}
function hasCrossScopeConflictWithState(userMessage, state) {
const explicitPeriod = extractNormalizedPeriodLiteral(userMessage);
const statePeriod = compactWhitespace(state.focus.period ?? "");
if (explicitPeriod && statePeriod && explicitPeriod !== statePeriod) {
return true;
}
const inferredDomain = inferP0DomainFromMessage(userMessage);
const stateDomain = compactWhitespace(state.followup_context?.active_domain ?? state.focus.domain ?? "");
if (inferredDomain && stateDomain && inferredDomain !== stateDomain) {
return true;
}
const explicitAccounts = extractAccountTokens(userMessage);
const fallbackAccounts = explicitAccounts.length > 0 ? explicitAccounts : extractFollowupAccountAnchorsLoose(userMessage);
const knownAccounts = Array.isArray(state.focus.primary_accounts) ? state.focus.primary_accounts : [];
if (fallbackAccounts.length > 0 && knownAccounts.length > 0) {
const knownPrefixes = new Set(knownAccounts.map((item) => accountPrefixToken(item)).filter(Boolean));
const newPrefixes = new Set(fallbackAccounts.map((item) => accountPrefixToken(item)).filter(Boolean));
if (newPrefixes.size > 0 && knownPrefixes.size > 0) {
let intersects = false;
for (const prefix of newPrefixes) {
if (knownPrefixes.has(prefix)) {
intersects = true;
break;
}
}
if (!intersects) {
return true;
}
}
}
return false;
}
function inferP0DomainFromMessage(text) {
const lower = String(text ?? "").toLowerCase();
const accountTokens = extractAccountTokens(lower);
@@ -971,9 +1009,11 @@ function buildFollowupStateBinding(input) {
Boolean(problemState) &&
((problemState?.active_problem_units.length ?? 0) > 0 || (problemState?.focus_problem_types.length ?? 0) > 0);
const strongNewAnchorDetected = hasStrongFollowupAnchors(userMessage, input.investigationState);
const scopeConflictDetected = hasCrossScopeConflictWithState(userMessage, input.investigationState);
const periodRefinementFollowup = hasPeriodLiteral(userMessage) && problemContinuityAvailable;
const shouldBind = !smallTalkSignal &&
!strongNewAnchorDetected &&
!scopeConflictDetected &&
(followupMarker || referentialPointer || periodRefinementFollowup || (!strongSignal && shortPrompt));
if (!shouldBind) {
return {
@@ -1078,7 +1118,10 @@ function buildFollowupStateBinding(input) {
problem_continuity_available: problemContinuityAvailable,
problem_continuity_applied: problemContinuityApplied,
problem_continuity_skipped_reason: problemContinuityApplied ? null : problemContinuitySkippedReason,
strong_new_anchor_detected: strongNewAnchorDetected
strong_new_anchor_detected: strongNewAnchorDetected,
scope_isolation_applied: true,
scope_carryover_allowed: !scopeConflictDetected,
scope_reset_reason: scopeConflictDetected ? "cross_scope_conflict" : null
}
}
};
@@ -1147,11 +1190,30 @@ export class AssistantService {
useMock: Boolean(payload.useMock)
};
const normalized = await this.normalizerService.normalize(normalizePayload);
const companyAnchors = (0, companyAnchorResolver_1.resolveCompanyAnchors)(userMessage);
const inferredDomainByMessage = inferP0DomainFromMessage(userMessage);
const focusDomainForGuards = inferredDomainByMessage === "settlements_60_62" ||
inferredDomainByMessage === "vat_document_register_book" ||
inferredDomainByMessage === "month_close_costs_20_44"
? inferredDomainByMessage
: null;
const temporalGuard = (0, assistantRuntimeGuards_1.resolveTemporalGuard)({
userMessage,
normalized: normalized.normalized,
companyAnchors
});
const domainPolarityGuardInitial = (0, assistantRuntimeGuards_1.resolveDomainPolarityGuard)({
userMessage,
companyAnchors,
focusDomainHint: focusDomainForGuards
});
const requirementExtraction = extractRequirements(normalized.route_hint_summary, normalized.normalized, userMessage);
const executionPlan = toExecutionPlan(normalized.route_hint_summary, normalized.normalized, userMessage, requirementExtraction.byFragment);
let executionPlan = toExecutionPlan(normalized.route_hint_summary, normalized.normalized, userMessage, requirementExtraction.byFragment);
executionPlan = (0, assistantRuntimeGuards_1.applyTemporalHintToExecutionPlan)(executionPlan, temporalGuard);
executionPlan = (0, assistantRuntimeGuards_1.applyPolarityHintToExecutionPlan)(executionPlan, domainPolarityGuardInitial);
const retrievalCalls = [];
const retrievalResultsRaw = [];
const retrievalResults = [];
let retrievalResults = [];
for (const planItem of executionPlan) {
if (!planItem.should_execute) {
retrievalCalls.push({
@@ -1210,13 +1272,32 @@ export class AssistantService {
retrievalResults.push((0, retrievalResultNormalizer_1.normalizeRetrievalResult)(planItem.fragment_id, planItem.requirement_ids, planItem.route, rawError));
}
}
const polarityGuardResult = (0, assistantRuntimeGuards_1.applyDomainPolarityGuardToRetrievalResults)({
retrievalResults,
guard: domainPolarityGuardInitial
});
retrievalResults = polarityGuardResult.retrievalResults;
const evidenceGateResult = (0, assistantRuntimeGuards_1.applyEvidenceAdmissibilityGate)({
retrievalResults,
temporal: temporalGuard,
focusDomainHint: focusDomainForGuards,
polarity: polarityGuardResult.audit.polarity,
companyAnchors,
userMessage
});
retrievalResults = evidenceGateResult.retrievalResults;
const coverageEvaluation = evaluateCoverage(requirementExtraction.requirements, retrievalResults);
const groundingCheck = checkGrounding(userMessage, coverageEvaluation.requirements, coverageEvaluation.coverage, retrievalResults);
const groundingCheckBase = checkGrounding(userMessage, coverageEvaluation.requirements, coverageEvaluation.coverage, retrievalResults);
const groundedAnswerEligibilityGuard = (0, assistantRuntimeGuards_1.evaluateGroundedAnswerEligibility)({
temporal: temporalGuard,
polarity: polarityGuardResult.audit,
evidence: evidenceGateResult.audit
});
const groundingCheck = (0, assistantRuntimeGuards_1.applyEligibilityToGroundingCheck)(groundingCheckBase, groundedAnswerEligibilityGuard);
const focusDomainHint = followupBinding.usage?.applied
? session.investigation_state?.followup_context?.active_domain ?? session.investigation_state?.focus.domain ?? null
: null;
const questionTypeClass = (0, questionTypeResolver_1.resolveQuestionType)(userMessage);
const companyAnchors = (0, companyAnchorResolver_1.resolveCompanyAnchors)(userMessage);
const hasPeriodInCompanyAnchors = (Array.isArray(companyAnchors?.dates) && companyAnchors.dates.some((item) => String(item ?? "").trim().length > 0)) ||
(Array.isArray(companyAnchors?.periods) && companyAnchors.periods.some((item) => String(item ?? "").trim().length > 0));
const normalizationPeriodExplicit = hasExplicitPeriodAnchorFromNormalized(normalized.normalized) || hasPeriodInCompanyAnchors;
@@ -1260,7 +1341,8 @@ export class AssistantService {
requirements: coverageEvaluation.requirements,
coverageReport: coverageEvaluation.coverage,
retrievalResults,
replyType: composition.reply_type
replyType: composition.reply_type,
followupApplied: Boolean(followupBinding.usage?.applied)
})
: null;
if (config_1.FEATURE_ASSISTANT_INVESTIGATION_STATE_V1 && investigationStateSnapshot) {
@@ -1288,6 +1370,15 @@ export class AssistantService {
dropped_intent_segments: extractDiscardedIntentSegments(normalized.normalized),
question_type_class: questionTypeClass,
company_anchors: companyAnchors,
raw_time_anchor: temporalGuard.raw_time_anchor,
resolved_time_anchor: temporalGuard.resolved_time_anchor,
temporal_resolution_source: temporalGuard.temporal_resolution_source,
temporal_guard_applied: temporalGuard.temporal_guard_applied,
temporal_guard_outcome: temporalGuard.temporal_guard_outcome,
temporal_guard: temporalGuard,
domain_polarity_guard: polarityGuardResult.audit,
evidence_admissibility_gate: evidenceGateResult.audit,
grounded_answer_eligibility_guard: groundedAnswerEligibilityGuard,
...(followupBinding.usage ? { followup_state_usage: followupBinding.usage } : {}),
problem_centric_answer_applied: composition.problem_centric_answer_applied ?? false,
problem_units_used_count: composition.problem_units_used_count ?? 0,
@@ -1353,6 +1444,15 @@ export class AssistantService {
dropped_intent_segments: extractDiscardedIntentSegments(normalized.normalized),
question_type_class: questionTypeClass,
company_anchors: companyAnchors,
raw_time_anchor: temporalGuard.raw_time_anchor,
resolved_time_anchor: temporalGuard.resolved_time_anchor,
temporal_resolution_source: temporalGuard.temporal_resolution_source,
temporal_guard_applied: temporalGuard.temporal_guard_applied,
temporal_guard_outcome: temporalGuard.temporal_guard_outcome,
temporal_guard: temporalGuard,
domain_polarity_guard: polarityGuardResult.audit,
evidence_admissibility_gate: evidenceGateResult.audit,
grounded_answer_eligibility_guard: groundedAnswerEligibilityGuard,
...(followupBinding.usage ? { followup_state_usage: followupBinding.usage } : {}),
problem_centric_answer_applied: composition.problem_centric_answer_applied ?? false,
problem_units_used_count: composition.problem_units_used_count ?? 0,