Этап 4 / Волна 18 закрытие блокеров по времени, доменной полярности и допуску доказательной базы
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user