ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов 2.12.23: декомпозиция deep-turn пайплайна ассистента в runtime-адаптеры
This commit is contained in:
@@ -683,11 +683,97 @@ function toTemporalGuardInput(window: TemporalWindow | null, fallback: string |
|
||||
return value || null;
|
||||
}
|
||||
|
||||
function normalizeIsoDate(value: unknown): string | null {
|
||||
if (typeof value !== "string") {
|
||||
return null;
|
||||
}
|
||||
const trimmed = value.trim();
|
||||
const match = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
const year = Number(match[1]);
|
||||
const month = Number(match[2]);
|
||||
const day = Number(match[3]);
|
||||
if (!Number.isFinite(year) || !Number.isFinite(month) || !Number.isFinite(day)) {
|
||||
return null;
|
||||
}
|
||||
const candidate = new Date(Date.UTC(year, month - 1, day));
|
||||
if (
|
||||
candidate.getUTCFullYear() !== year ||
|
||||
candidate.getUTCMonth() + 1 !== month ||
|
||||
candidate.getUTCDate() !== day
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return `${match[1]}-${match[2]}-${match[3]}`;
|
||||
}
|
||||
|
||||
function normalizeTemporalWindow(input: {
|
||||
asOfDate?: unknown;
|
||||
periodFrom?: unknown;
|
||||
periodTo?: unknown;
|
||||
}): TemporalWindow | null {
|
||||
const asOfDate = normalizeIsoDate(input.asOfDate);
|
||||
if (asOfDate) {
|
||||
return {
|
||||
from: asOfDate,
|
||||
to: asOfDate,
|
||||
granularity: "day"
|
||||
};
|
||||
}
|
||||
const from = normalizeIsoDate(input.periodFrom);
|
||||
const to = normalizeIsoDate(input.periodTo);
|
||||
if (!from || !to) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
from,
|
||||
to,
|
||||
granularity: from === to ? "day" : "month"
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveTemporalGuard(input: {
|
||||
userMessage: string;
|
||||
normalized: NormalizedPayload | null | undefined;
|
||||
companyAnchors?: CompanyAnchorSet | null;
|
||||
analysisContext?: {
|
||||
as_of_date?: string | null;
|
||||
period_from?: string | null;
|
||||
period_to?: string | null;
|
||||
source?: string | null;
|
||||
} | null;
|
||||
}): TemporalGuardAudit {
|
||||
const analysisWindow = normalizeTemporalWindow({
|
||||
asOfDate: input.analysisContext?.as_of_date,
|
||||
periodFrom: input.analysisContext?.period_from,
|
||||
periodTo: input.analysisContext?.period_to
|
||||
});
|
||||
if (analysisWindow) {
|
||||
const source = String(input.analysisContext?.source ?? "").trim() || "analysis_context";
|
||||
const guardInput = toTemporalGuardInput(analysisWindow, analysisWindow.from);
|
||||
return {
|
||||
raw_time_anchor: analysisWindow.from,
|
||||
raw_time_scope: guardInput,
|
||||
resolved_time_anchor: analysisWindow.granularity === "day" ? analysisWindow.from : null,
|
||||
resolved_primary_period: analysisWindow,
|
||||
effective_primary_period: analysisWindow,
|
||||
temporal_guard_input: guardInput,
|
||||
temporal_alignment_status: "aligned",
|
||||
temporal_resolution_source: source,
|
||||
temporal_guard_basis: "raw_time_scope_unlocked",
|
||||
temporal_guard_applied: false,
|
||||
temporal_guard_outcome: "passed",
|
||||
primary_period_window: null,
|
||||
allowed_context_window: null,
|
||||
controlled_temporal_expansion_enabled: false,
|
||||
context_expansion_reasons_allowed: ["prehistory", "carryover", "post_period_closure", "long_running_contract_context"],
|
||||
normalized_anchor_drift_detected: false,
|
||||
reason_codes: ["analysis_context_applied"]
|
||||
};
|
||||
}
|
||||
|
||||
const rawAnchorText = collectRawTemporalAnchorText(input.userMessage, input.companyAnchors);
|
||||
const julyAnchor = resolveJulyAnchor(rawAnchorText);
|
||||
const normalizedAnchor = normalizedAnchorFromFragments(input.normalized);
|
||||
@@ -762,10 +848,15 @@ export function applyTemporalHintToExecutionPlan<
|
||||
return executionPlan;
|
||||
}
|
||||
const primaryWindow = temporal.effective_primary_period ?? temporal.primary_period_window;
|
||||
const periodLabel = primaryWindow
|
||||
? `${primaryWindow.from}..${primaryWindow.to}`
|
||||
: temporal.resolved_time_anchor
|
||||
? temporal.resolved_time_anchor
|
||||
: "active_period";
|
||||
const hint =
|
||||
primaryWindow?.granularity === "day" && temporal.resolved_time_anchor
|
||||
? `primary period ${temporal.resolved_time_anchor}; controlled temporal expansion only for linked entities`
|
||||
: `primary period July 2020 (${primaryWindow?.from ?? JULY_WINDOW.from}..${primaryWindow?.to ?? JULY_WINDOW.to}); controlled temporal expansion only for linked entities`;
|
||||
: `primary period ${periodLabel}; controlled temporal expansion only for linked entities`;
|
||||
return executionPlan.map((item) => {
|
||||
if (!item.should_execute) {
|
||||
return item;
|
||||
@@ -1590,15 +1681,15 @@ export function applyEligibilityToGroundingCheck<T extends { status: string; rea
|
||||
? "no_grounded_answer"
|
||||
: "partial";
|
||||
const reasonMap: Record<string, string> = {
|
||||
admissible_evidence_count_zero: "Недостаточно допустимого evidence для обоснованного ответа.",
|
||||
critical_domain_or_account_contradiction: "Есть критическое противоречие по domain/account scope.",
|
||||
temporal_guard_failed_out_of_snapshot_window: "Temporal anchor вышел за окно company snapshot (июль 2020).",
|
||||
temporal_guard_ambiguous_limited: "Temporal anchor не разрешен надежно в пределах company snapshot.",
|
||||
business_scope_generic_unresolved: "Business scope остался generic и не подтвержден как company-specific для доказательного ответа.",
|
||||
polarity_guard_limited_unresolved_polarity: "Не удалось надежно определить supplier/customer polarity.",
|
||||
polarity_guard_blocked_conflict: "Обнаружен конфликт supplier/customer polarity в retrieval-контуре.",
|
||||
claim_anchor_coverage_insufficient: "Недостаточно покрытия required anchors для claim-bound grounding.",
|
||||
targeted_evidence_hit_rate_zero: "Targeted evidence acquisition не дал допустимых попаданий по claim target path."
|
||||
admissible_evidence_count_zero: "Недостаточно подтвержденных данных для уверенного ответа.",
|
||||
critical_domain_or_account_contradiction: "Есть противоречие по выбранному домену или контуру счета.",
|
||||
temporal_guard_failed_out_of_snapshot_window: "Запрошенный период выходит за доступный срез данных.",
|
||||
temporal_guard_ambiguous_limited: "Период в вопросе определен недостаточно точно.",
|
||||
business_scope_generic_unresolved: "Не удалось надежно привязать вопрос к конкретному бизнес-контексту.",
|
||||
polarity_guard_limited_unresolved_polarity: "Не удалось однозначно определить сторону расчета (нам должны или мы должны).",
|
||||
polarity_guard_blocked_conflict: "В данных есть конфликт по стороне расчета.",
|
||||
claim_anchor_coverage_insufficient: "Не хватает ключевых ориентиров в вопросе (период, объект или контрагент).",
|
||||
targeted_evidence_hit_rate_zero: "Не хватило целевых подтверждений по выбранному сценарию."
|
||||
};
|
||||
const reasons = [
|
||||
...(Array.isArray(groundingCheck.reasons) ? groundingCheck.reasons : []),
|
||||
|
||||
Reference in New Issue
Block a user