NODEDC_1C/llm_normalizer/backend/dist/services/addressNavigationState.js

693 lines
31 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createEmptyAddressNavigationState = createEmptyAddressNavigationState;
exports.cloneAddressNavigationState = cloneAddressNavigationState;
exports.normalizeAddressNavigationState = normalizeAddressNavigationState;
exports.evolveAddressNavigationStateWithAssistantItem = evolveAddressNavigationStateWithAssistantItem;
const nanoid_1 = require("nanoid");
const assistantContinuityPolicy_1 = require("./assistantContinuityPolicy");
const addressNavigation_1 = require("../types/addressNavigation");
const MAX_RESULT_SETS = 40;
const MAX_NAVIGATION_EVENTS = 120;
const MAX_ENTITY_REFS_PER_RESULT_SET = 40;
const DISPLAY_ENTITY_TYPE_BY_INTENT = {
business_overview: "organization",
counterparty_activity_lifecycle: "counterparty",
customer_revenue_and_payments: "counterparty",
supplier_payouts_profile: "counterparty",
list_payables_counterparties: "counterparty",
receivables_confirmed_as_of_date: "counterparty",
list_receivables_counterparties: "counterparty",
list_contracts_by_counterparty: "contract",
list_documents_by_counterparty: "document_ref",
list_documents_by_contract: "document_ref",
bank_operations_by_counterparty: "document_ref",
bank_operations_by_contract: "document_ref",
open_items_by_counterparty_or_contract: "counterparty",
inventory_on_hand_as_of_date: "item",
inventory_purchase_provenance_for_item: "item",
inventory_purchase_documents_for_item: "item",
inventory_supplier_stock_overlap_as_of_date: "item",
inventory_sale_trace_for_item: "item",
inventory_margin_ranking_for_nomenclature: "item",
inventory_profitability_for_item: "item",
inventory_purchase_to_sale_chain: "item",
inventory_aging_by_purchase_date: "item"
};
const RESULT_SET_TYPE_BY_INTENT = {
business_overview: "profile_summary",
counterparty_activity_lifecycle: "counterparty_list",
customer_revenue_and_payments: "counterparty_list",
supplier_payouts_profile: "counterparty_list",
list_payables_counterparties: "counterparty_list",
payables_confirmed_as_of_date: "balance_snapshot",
vat_payable_confirmed_as_of_date: "balance_snapshot",
vat_liability_confirmed_for_tax_period: "balance_snapshot",
receivables_confirmed_as_of_date: "balance_snapshot",
list_receivables_counterparties: "counterparty_list",
list_contracts_by_counterparty: "contract_list",
list_documents_by_counterparty: "document_list",
list_documents_by_contract: "document_list",
bank_operations_by_counterparty: "bank_operations_list",
bank_operations_by_contract: "bank_operations_list",
open_items_by_counterparty_or_contract: "open_items_list",
inventory_on_hand_as_of_date: "inventory_snapshot",
inventory_purchase_provenance_for_item: "inventory_trace",
inventory_purchase_documents_for_item: "inventory_trace",
inventory_supplier_stock_overlap_as_of_date: "inventory_trace",
inventory_sale_trace_for_item: "inventory_trace",
inventory_margin_ranking_for_nomenclature: "inventory_trace",
inventory_profitability_for_item: "inventory_trace",
inventory_purchase_to_sale_chain: "inventory_trace",
inventory_aging_by_purchase_date: "inventory_trace",
period_coverage_profile: "profile_summary",
document_type_and_account_section_profile: "profile_summary",
counterparty_population_and_roles: "profile_summary",
contract_usage_overview: "profile_summary",
contract_usage_and_value: "profile_summary",
vat_payable_forecast: "profile_summary"
};
function toObject(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return null;
}
return value;
}
function cloneRecord(value) {
const record = toObject(value);
if (!record) {
return null;
}
try {
return JSON.parse(JSON.stringify(record));
}
catch {
return { ...record };
}
}
function toNonEmptyString(value) {
if (typeof value !== "string") {
return null;
}
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : null;
}
function candidateLabel(value) {
const direct = toNonEmptyString(value);
if (direct && direct !== "[object Object]") {
return direct;
}
const record = toObject(value);
if (!record) {
return null;
}
return (toNonEmptyString(record.value) ??
toNonEmptyString(record.name) ??
toNonEmptyString(record.ref) ??
toNonEmptyString(record.text));
}
function readNavigationDiscoveryCounterparty(debug) {
const entry = toObject(debug.assistant_mcp_discovery_entry_point_v1);
const turnInput = toObject(entry?.turn_input);
const turnMeaning = toObject(turnInput?.turn_meaning_ref);
const dataNeedGraph = toObject(turnInput?.data_need_graph);
const candidates = [
...(Array.isArray(turnMeaning?.business_overview_separate_entity_candidates)
? turnMeaning.business_overview_separate_entity_candidates
: []),
...(Array.isArray(turnMeaning?.explicit_entity_candidates) ? turnMeaning.explicit_entity_candidates : []),
...(Array.isArray(dataNeedGraph?.subject_candidates) ? dataNeedGraph.subject_candidates : [])
];
for (const candidate of candidates) {
const label = candidateLabel(candidate);
if (label) {
return label;
}
}
return null;
}
function toAddressFocusObjectType(value) {
const normalized = toNonEmptyString(value);
if (!normalized) {
return "unknown";
}
if (normalized === "counterparty" ||
normalized === "contract" ||
normalized === "document_ref" ||
normalized === "account" ||
normalized === "item" ||
normalized === "organization" ||
normalized === "warehouse") {
return normalized;
}
return "unknown";
}
function toAddressIntent(value) {
const normalized = toNonEmptyString(value);
return (normalized ?? "unknown");
}
function inferDisplayEntityType(intent) {
return DISPLAY_ENTITY_TYPE_BY_INTENT[intent] ?? "unknown";
}
function inferResultSetType(intent) {
return RESULT_SET_TYPE_BY_INTENT[intent] ?? "unknown";
}
function parseEntityCandidateFromLine(line) {
const compact = String(line ?? "").trim();
if (!compact) {
return null;
}
const numberedMatch = compact.match(/^(\d+)\.\s+(.+)$/);
if (!numberedMatch) {
return null;
}
const index = Number.parseInt(String(numberedMatch[1] ?? ""), 10);
if (!Number.isFinite(index) || index <= 0) {
return null;
}
const afterNumber = String(numberedMatch[2] ?? "");
const pieces = afterNumber.split("|").map((item) => item.trim()).filter(Boolean);
const valueCandidate = pieces.length > 0 ? pieces[0] : afterNumber;
const businessLabel = valueCandidate.split(/\s+[—–-]\s+(?=(?:выручка|сумма|количество|стоимость|маржа|себестоим|дата|склад))/iu)[0] ?? valueCandidate;
const cleaned = businessLabel.replace(/^["'«»“”„`]+|["'«»“”„`]+$/gu, "").trim();
if (!cleaned || cleaned.length < 2) {
return null;
}
return { index, value: cleaned };
}
function extractEntityRefsFromAssistantReply(replyText, intent, limit = MAX_ENTITY_REFS_PER_RESULT_SET) {
const entityType = inferDisplayEntityType(intent);
if (entityType === "unknown") {
return [];
}
const dedup = new Map();
const lines = String(replyText ?? "").split(/\r?\n/);
for (const line of lines) {
const parsed = parseEntityCandidateFromLine(line);
if (!parsed) {
continue;
}
const key = `${parsed.index}:${entityType}:${parsed.value.toLowerCase()}`;
if (!dedup.has(key)) {
dedup.set(key, {
index: parsed.index,
entity_type: entityType,
value: parsed.value
});
}
if (dedup.size >= limit) {
break;
}
}
return Array.from(dedup.values());
}
function extractOrganizationsFromAssistantReply(replyText, limit = 10) {
const dedup = new Map();
const lines = String(replyText ?? "").split(/\r?\n/);
for (const line of lines) {
const match = line.match(/(?:^|\|)\s*организац(?:ия|ии)\s*:\s*([^|]+)/iu);
if (!match) {
continue;
}
const organization = toNonEmptyString(match[1]);
if (!organization) {
continue;
}
const key = organization.toLowerCase();
if (!dedup.has(key)) {
dedup.set(key, organization);
}
if (dedup.size >= limit) {
break;
}
}
return Array.from(dedup.values());
}
function resolveDerivedOrganizationScope(debug, filters, replyText) {
const rootFrameContext = toObject(debug.address_root_frame_context) ?? {};
const candidates = [
toNonEmptyString(filters.organization),
toNonEmptyString(rootFrameContext.organization),
...extractOrganizationsFromAssistantReply(replyText)
].filter((value) => Boolean(value));
const dedup = Array.from(new Map(candidates.map((value) => [value.toLowerCase(), value])).values());
return dedup.length === 1 ? dedup[0] : null;
}
function cloneFocusObject(value) {
if (!value) {
return null;
}
return {
object_type: value.object_type,
object_id: value.object_id,
label: value.label,
provenance_result_set_id: value.provenance_result_set_id,
selected_at: value.selected_at
};
}
function cloneComparisonProofBundles(value) {
const record = toObject(value);
if (!record) {
return null;
}
const counterpartyValueFlowBundle = cloneRecord(record.counterparty_value_flow_bundle ?? record.previous_counterparty_value_flow_bundle);
const counterpartyDocumentBundle = cloneRecord(record.counterparty_document_bundle ?? record.previous_counterparty_document_bundle);
if (!counterpartyValueFlowBundle && !counterpartyDocumentBundle) {
return null;
}
return {
counterparty_value_flow_bundle: counterpartyValueFlowBundle,
counterparty_document_bundle: counterpartyDocumentBundle
};
}
function cloneResultSet(input) {
return {
result_set_id: input.result_set_id,
type: input.type,
intent: input.intent,
route_id: input.route_id,
filters: { ...input.filters },
source_refs: [...input.source_refs],
entity_refs: input.entity_refs.map((item) => ({
index: item.index,
entity_type: item.entity_type,
value: item.value
})),
created_from_turn: input.created_from_turn,
created_at: input.created_at
};
}
function cloneNavigationEvent(input) {
return {
event_id: input.event_id,
action: input.action,
source_result_set_id: input.source_result_set_id,
target_object_id: input.target_object_id,
derived_result_set_id: input.derived_result_set_id,
turn_index: input.turn_index,
created_at: input.created_at
};
}
function normalizeFilters(value) {
const record = toObject(value);
if (!record) {
return {};
}
return { ...record };
}
function resolveNavigationAction(debug, hasFocusObject) {
const continuationContract = toObject(debug.dialog_continuation_contract_v2);
const decision = toNonEmptyString(continuationContract?.decision);
if (decision === "new_topic") {
return "open";
}
if (decision === "continue_previous") {
return hasFocusObject ? "drilldown" : "refine";
}
if (decision === "switch_to_suggested") {
return "refine";
}
return hasFocusObject ? "drilldown" : "open";
}
function buildFocusObject(objectType, label, resultSetId, createdAt) {
return {
object_type: objectType,
object_id: `${objectType}:${label}`.toLowerCase(),
label,
provenance_result_set_id: resultSetId,
selected_at: createdAt
};
}
function cloneComparisonScope(value) {
if (!value || typeof value !== "object") {
return null;
}
return {
organization: cloneFocusObject(value.organization),
counterparty: cloneFocusObject(value.counterparty),
proof_bundles: cloneComparisonProofBundles(value.proof_bundles)
};
}
function sameBusinessLabel(left, right) {
const normalizedLeft = toNonEmptyString(left)?.toLocaleLowerCase("ru-RU");
const normalizedRight = toNonEmptyString(right)?.toLocaleLowerCase("ru-RU");
return Boolean(normalizedLeft && normalizedRight && normalizedLeft === normalizedRight);
}
function readBusinessOverviewComparisonProofBundles(debug) {
const entryPoint = toObject(debug.assistant_mcp_discovery_entry_point_v1);
const turnInput = toObject(entryPoint?.turn_input);
const turnMeaning = toObject(turnInput?.turn_meaning_ref);
const bridge = toObject(entryPoint?.bridge);
const pilot = toObject(bridge?.pilot);
const counterpartyValueFlowBundle = cloneRecord(turnMeaning?.previous_counterparty_value_flow_bundle) ??
cloneRecord(pilot?.derived_bidirectional_value_flow);
const counterpartyDocumentBundle = cloneRecord(turnMeaning?.previous_counterparty_document_bundle);
const counterparty = toNonEmptyString(counterpartyValueFlowBundle?.counterparty) ??
toNonEmptyString(counterpartyDocumentBundle?.counterparty) ??
readNavigationDiscoveryCounterparty(debug);
if (!counterparty) {
return null;
}
if (!counterpartyValueFlowBundle && !counterpartyDocumentBundle) {
return null;
}
return {
counterparty_value_flow_bundle: counterpartyValueFlowBundle,
counterparty_document_bundle: counterpartyDocumentBundle
};
}
function buildFocusObjectFromDebug(debug, resultSetId, createdAt) {
const extractedFilters = toObject(debug.extracted_filters) ?? {};
const selectedDiscoveryChain = toNonEmptyString(debug.mcp_discovery_selected_chain_id);
if (selectedDiscoveryChain === "business_overview" && debug.mcp_discovery_response_applied === true) {
const counterparty = (0, assistantContinuityPolicy_1.readAddressDebugCounterparty)(debug, toNonEmptyString) ?? readNavigationDiscoveryCounterparty(debug);
if (counterparty) {
return buildFocusObject("counterparty", counterparty, resultSetId, createdAt);
}
const organization = (0, assistantContinuityPolicy_1.readAddressDebugOrganization)(debug, toNonEmptyString);
if (organization) {
return buildFocusObject("organization", organization, resultSetId, createdAt);
}
}
if (selectedDiscoveryChain === "value_flow_comparison" && debug.mcp_discovery_response_applied === true) {
const counterparty = (0, assistantContinuityPolicy_1.readAddressDebugCounterparty)(debug, toNonEmptyString) ?? readNavigationDiscoveryCounterparty(debug);
if (counterparty) {
return buildFocusObject("counterparty", counterparty, resultSetId, createdAt);
}
}
const objectType = toAddressFocusObjectType(debug.anchor_type);
const detectedIntent = toAddressIntent(debug.detected_intent);
if (detectedIntent === "inventory_on_hand_as_of_date") {
const organization = (0, assistantContinuityPolicy_1.readAddressDebugOrganization)(debug, toNonEmptyString);
if (organization) {
return buildFocusObject("organization", organization, resultSetId, createdAt);
}
}
const canonicalType = objectType === "unknown" ? inferDisplayEntityType(detectedIntent) : objectType;
if (canonicalType === "item") {
const item = (0, assistantContinuityPolicy_1.readAddressDebugItem)(debug, toNonEmptyString);
return item ? buildFocusObject(canonicalType, item, resultSetId, createdAt) : null;
}
if (canonicalType === "counterparty" && debug.mcp_discovery_response_applied === true) {
const counterparty = (0, assistantContinuityPolicy_1.readAddressDebugCounterparty)(debug, toNonEmptyString);
return counterparty ? buildFocusObject(canonicalType, counterparty, resultSetId, createdAt) : null;
}
const rawValue = toNonEmptyString(debug.anchor_value_resolved) ??
toNonEmptyString(debug.anchor_value_raw) ??
toNonEmptyString(extractedFilters.item);
return rawValue ? buildFocusObject(canonicalType, rawValue, resultSetId, createdAt) : null;
}
function buildFocusObjectFromPrimaryEntityRef(resultSet, createdAt) {
if (resultSet.intent !== "inventory_margin_ranking_for_nomenclature") {
return null;
}
const primaryEntity = resultSet.entity_refs[0];
if (!primaryEntity || primaryEntity.entity_type !== "item") {
return null;
}
return buildFocusObject("item", primaryEntity.value, resultSet.result_set_id, createdAt);
}
function resolveFocusObjectForNavigation(state, intent, resultSet, debugFocusObject, primaryEntityFocusObject) {
if (intent !== "inventory_margin_ranking_for_nomenclature") {
return debugFocusObject ?? primaryEntityFocusObject;
}
if (primaryEntityFocusObject) {
return primaryEntityFocusObject;
}
const previousFocus = state.session_context.active_focus_object;
if (previousFocus?.object_type === "item" &&
(!debugFocusObject || debugFocusObject.object_type === "organization")) {
return cloneFocusObject(previousFocus);
}
return debugFocusObject;
}
function capResultSets(resultSets) {
if (resultSets.length <= MAX_RESULT_SETS) {
return resultSets;
}
return resultSets.slice(resultSets.length - MAX_RESULT_SETS);
}
function capNavigationEvents(events) {
if (events.length <= MAX_NAVIGATION_EVENTS) {
return events;
}
return events.slice(events.length - MAX_NAVIGATION_EVENTS);
}
function isAddressAssistantItem(item) {
if (item.role !== "assistant" || !item.debug) {
return false;
}
if (toNonEmptyString(item.debug.detected_mode) === "address_query") {
return true;
}
return item.debug.mcp_discovery_response_applied === true && Boolean(toNonEmptyString(item.debug.mcp_discovery_selected_chain_id));
}
function createEmptyAddressNavigationState(sessionId, nowIso = new Date().toISOString()) {
return {
schema_version: addressNavigation_1.ADDRESS_NAVIGATION_STATE_SCHEMA_VERSION,
session_id: sessionId,
updated_at: nowIso,
session_context: {
active_result_set_id: null,
active_focus_object: null,
comparison_scope: null,
last_confirmed_route: null,
date_scope: {
as_of_date: null,
period_from: null,
period_to: null
},
organization_scope: null
},
result_sets: [],
navigation_history: []
};
}
function cloneAddressNavigationState(value) {
if (!value) {
return null;
}
return {
schema_version: value.schema_version,
session_id: value.session_id,
updated_at: value.updated_at,
session_context: {
active_result_set_id: value.session_context.active_result_set_id,
active_focus_object: cloneFocusObject(value.session_context.active_focus_object),
comparison_scope: cloneComparisonScope(value.session_context.comparison_scope),
last_confirmed_route: value.session_context.last_confirmed_route,
date_scope: {
as_of_date: value.session_context.date_scope.as_of_date,
period_from: value.session_context.date_scope.period_from,
period_to: value.session_context.date_scope.period_to
},
organization_scope: value.session_context.organization_scope
},
result_sets: value.result_sets.map(cloneResultSet),
navigation_history: value.navigation_history.map(cloneNavigationEvent)
};
}
function normalizeAddressNavigationState(value, sessionId) {
const fallback = createEmptyAddressNavigationState(sessionId);
if (!value || typeof value !== "object") {
return fallback;
}
const normalizedSessionId = toNonEmptyString(value.session_id) ?? sessionId;
const normalizedUpdatedAt = toNonEmptyString(value.updated_at) ?? new Date().toISOString();
const context = toObject(value.session_context) ?? {};
const dateScope = toObject(context.date_scope) ?? {};
const resultSets = Array.isArray(value.result_sets) ? value.result_sets : [];
const navigationHistory = Array.isArray(value.navigation_history) ? value.navigation_history : [];
return {
schema_version: addressNavigation_1.ADDRESS_NAVIGATION_STATE_SCHEMA_VERSION,
session_id: normalizedSessionId,
updated_at: normalizedUpdatedAt,
session_context: {
active_result_set_id: toNonEmptyString(context.active_result_set_id),
active_focus_object: cloneFocusObject(context.active_focus_object),
comparison_scope: cloneComparisonScope(context.comparison_scope),
last_confirmed_route: toNonEmptyString(context.last_confirmed_route),
date_scope: {
as_of_date: toNonEmptyString(dateScope.as_of_date),
period_from: toNonEmptyString(dateScope.period_from),
period_to: toNonEmptyString(dateScope.period_to)
},
organization_scope: toNonEmptyString(context.organization_scope)
},
result_sets: resultSets
.map((item) => toObject(item))
.filter((item) => item !== null)
.map((item) => ({
result_set_id: toNonEmptyString(item.result_set_id) ?? `rs-${(0, nanoid_1.nanoid)(10)}`,
type: inferResultSetType(toAddressIntent(item.intent)),
intent: toAddressIntent(item.intent),
route_id: toNonEmptyString(item.route_id),
filters: normalizeFilters(item.filters),
source_refs: Array.isArray(item.source_refs)
? item.source_refs.map((v) => toNonEmptyString(v)).filter((v) => Boolean(v))
: [],
entity_refs: Array.isArray(item.entity_refs)
? item.entity_refs
.map((entry) => toObject(entry))
.filter((entry) => entry !== null)
.map((entry) => ({
index: Number.isFinite(Number(entry.index)) ? Number(entry.index) : 0,
entity_type: toAddressFocusObjectType(entry.entity_type),
value: toNonEmptyString(entry.value) ?? ""
}))
.filter((entry) => entry.index > 0 && entry.value.length > 0)
: [],
created_from_turn: Number.isFinite(Number(item.created_from_turn)) ? Number(item.created_from_turn) : 0,
created_at: toNonEmptyString(item.created_at) ?? normalizedUpdatedAt
})),
navigation_history: navigationHistory
.map((item) => toObject(item))
.filter((item) => item !== null)
.map((item) => ({
event_id: toNonEmptyString(item.event_id) ?? `nav-${(0, nanoid_1.nanoid)(10)}`,
action: toNonEmptyString(item.action) ?? "open",
source_result_set_id: toNonEmptyString(item.source_result_set_id),
target_object_id: toNonEmptyString(item.target_object_id),
derived_result_set_id: toNonEmptyString(item.derived_result_set_id),
turn_index: Number.isFinite(Number(item.turn_index)) ? Number(item.turn_index) : 0,
created_at: toNonEmptyString(item.created_at) ?? normalizedUpdatedAt
}))
};
}
function evolveAddressNavigationStateWithAssistantItem(state, item, turnIndex) {
if (!isAddressAssistantItem(item) || !item.debug) {
return state;
}
const debug = item.debug;
const selectedDiscoveryChain = toNonEmptyString(debug.mcp_discovery_selected_chain_id);
const discoveryIntent = selectedDiscoveryChain === "business_overview"
? "business_overview"
: selectedDiscoveryChain === "value_flow_comparison"
? "customer_revenue_and_payments"
: "unknown";
const detectedIntent = toNonEmptyString(debug.detected_intent);
const intent = toAddressIntent(detectedIntent && detectedIntent !== "unknown" ? detectedIntent : discoveryIntent);
const trackableDiscoveryTurn = debug.mcp_discovery_response_applied === true && Boolean(selectedDiscoveryChain);
if (intent === "unknown" && !trackableDiscoveryTurn) {
return state;
}
const createdAt = toNonEmptyString(item.created_at) ?? new Date().toISOString();
const resultSetId = `rs-${item.message_id}`;
const routeId = toNonEmptyString(debug.selected_recipe) ?? selectedDiscoveryChain;
const filters = normalizeFilters(debug.extracted_filters);
const derivedOrganizationScope = resolveDerivedOrganizationScope(debug, filters, item.text) ?? (0, assistantContinuityPolicy_1.readAddressDebugOrganization)(debug, toNonEmptyString);
const derivedCounterpartyScope = selectedDiscoveryChain === "value_flow_comparison" && debug.mcp_discovery_response_applied === true
? (0, assistantContinuityPolicy_1.readAddressDebugCounterparty)(debug, toNonEmptyString) ?? readNavigationDiscoveryCounterparty(debug)
: null;
const filtersWithDerivedScope = derivedOrganizationScope && !toNonEmptyString(filters.organization)
? {
...filters,
organization: derivedOrganizationScope,
...(derivedCounterpartyScope && !toNonEmptyString(filters.counterparty)
? { counterparty: derivedCounterpartyScope }
: {})
}
: derivedCounterpartyScope && !toNonEmptyString(filters.counterparty)
? {
...filters,
counterparty: derivedCounterpartyScope
}
: filters;
const sourceRefs = routeId ? [routeId] : [];
const entityRefs = extractEntityRefsFromAssistantReply(item.text, intent);
const resultSet = {
result_set_id: resultSetId,
type: inferResultSetType(intent),
intent,
route_id: routeId,
filters: filtersWithDerivedScope,
source_refs: sourceRefs,
entity_refs: entityRefs,
created_from_turn: turnIndex,
created_at: createdAt
};
const previousResultSetId = state.session_context.active_result_set_id;
const debugFocusObject = buildFocusObjectFromDebug(debug, resultSetId, createdAt);
const primaryEntityFocusObject = buildFocusObjectFromPrimaryEntityRef(resultSet, createdAt);
const focusObject = resolveFocusObjectForNavigation(state, intent, resultSet, debugFocusObject, primaryEntityFocusObject);
const comparisonCounterparty = selectedDiscoveryChain === "business_overview" && debug.mcp_discovery_response_applied === true
? readNavigationDiscoveryCounterparty(debug)
: null;
const comparisonOrganization = selectedDiscoveryChain === "business_overview" && debug.mcp_discovery_response_applied === true
? derivedOrganizationScope ?? toNonEmptyString(filtersWithDerivedScope.organization)
: null;
const currentComparisonProofBundles = selectedDiscoveryChain === "business_overview" && debug.mcp_discovery_response_applied === true
? readBusinessOverviewComparisonProofBundles(debug)
: null;
const inheritedComparisonScope = state.session_context.comparison_scope;
const inheritedComparisonProofBundles = comparisonCounterparty &&
sameBusinessLabel(inheritedComparisonScope?.counterparty?.label, comparisonCounterparty)
? cloneComparisonProofBundles(inheritedComparisonScope?.proof_bundles)
: null;
const comparisonProofBundles = currentComparisonProofBundles ?? inheritedComparisonProofBundles;
const comparisonOrganizationObject = comparisonOrganization
? buildFocusObject("organization", comparisonOrganization, resultSetId, createdAt)
: cloneFocusObject(inheritedComparisonScope?.organization ?? null);
const comparisonCounterpartyObject = comparisonCounterparty
? buildFocusObject("counterparty", comparisonCounterparty, resultSetId, createdAt)
: cloneFocusObject(inheritedComparisonScope?.counterparty ?? null);
const comparisonScope = comparisonOrganizationObject || comparisonCounterpartyObject || comparisonProofBundles
? {
organization: comparisonOrganizationObject,
counterparty: comparisonCounterpartyObject,
proof_bundles: comparisonProofBundles
}
: null;
const action = resolveNavigationAction(debug, Boolean(focusObject));
const navigationEvent = {
event_id: `nav-${(0, nanoid_1.nanoid)(10)}`,
action,
source_result_set_id: previousResultSetId,
target_object_id: focusObject?.object_id ?? null,
derived_result_set_id: resultSetId,
turn_index: turnIndex,
created_at: createdAt
};
const discoveryTemporalScope = (0, assistantContinuityPolicy_1.readAddressDebugTemporalScope)(debug, toNonEmptyString);
const normalizedDateScope = {
as_of_date: toNonEmptyString(filtersWithDerivedScope.as_of_date) ?? discoveryTemporalScope.asOfDate,
period_from: toNonEmptyString(filtersWithDerivedScope.period_from) ?? discoveryTemporalScope.periodFrom,
period_to: toNonEmptyString(filtersWithDerivedScope.period_to) ?? discoveryTemporalScope.periodTo
};
const organizationScope = toNonEmptyString(filtersWithDerivedScope.organization);
const nextResultSets = capResultSets([...state.result_sets.filter((itemSet) => itemSet.result_set_id !== resultSetId), resultSet].sort((left, right) => left.created_from_turn - right.created_from_turn));
const nextEvents = capNavigationEvents([...state.navigation_history, navigationEvent]);
const nextSessionContext = action === "open"
? {
active_result_set_id: resultSetId,
active_focus_object: focusObject ?? null,
comparison_scope: comparisonScope,
last_confirmed_route: routeId ?? null,
date_scope: {
as_of_date: normalizedDateScope.as_of_date,
period_from: normalizedDateScope.period_from,
period_to: normalizedDateScope.period_to
},
organization_scope: organizationScope ?? state.session_context.organization_scope
}
: {
active_result_set_id: resultSetId,
active_focus_object: focusObject ?? state.session_context.active_focus_object,
comparison_scope: comparisonScope ?? state.session_context.comparison_scope,
last_confirmed_route: routeId ?? state.session_context.last_confirmed_route,
date_scope: {
as_of_date: normalizedDateScope.as_of_date ?? state.session_context.date_scope.as_of_date,
period_from: normalizedDateScope.period_from ?? state.session_context.date_scope.period_from,
period_to: normalizedDateScope.period_to ?? state.session_context.date_scope.period_to
},
organization_scope: organizationScope ?? state.session_context.organization_scope
};
return {
...state,
updated_at: createdAt,
session_context: nextSessionContext,
result_sets: nextResultSets,
navigation_history: nextEvents
};
}