import { describe, expect, it } from "vitest"; import { createAssistantTransitionPolicy } from "../src/services/assistantTransitionPolicy"; import { buildRootScopedCarryoverFilters } from "../src/services/assistantContinuityPolicy"; function toNonEmptyString(value: unknown): string | null { if (value === null || value === undefined) { return null; } const text = String(value).trim(); return text.length > 0 ? text : null; } function buildPolicy(overrides: Record = {}) { return createAssistantTransitionPolicy({ compactWhitespace: (value: string) => String(value ?? "").replace(/\s+/g, " ").trim(), repairAddressMojibake: (value: string) => value, countTokens: (value: string) => String(value ?? "").split(/\s+/).filter(Boolean).length, shouldHandleAsAssistantCapabilityMetaQuery: () => false, hasDataRetrievalRequestSignal: () => false, findLastAddressAssistantItem: () => ({ text: "1. Рабочая станция", debug: { detected_intent: "inventory_purchase_documents_for_item", extracted_filters: { item: "Рабочая станция" }, anchor_type: "item", anchor_value_resolved: "Рабочая станция" } }), findLastOrganizationClarificationAddressDebug: () => null, mergeKnownOrganizations: (values: unknown[]) => values, resolveOrganizationSelectionFromMessage: () => null, toNonEmptyString, buildAddressFollowupOffer: () => null, isImplicitAddressContinuationByLlm: () => false, isInventorySelectedObjectIntent: (intent: unknown) => [ "inventory_purchase_provenance_for_item", "inventory_purchase_documents_for_item", "inventory_sale_trace_for_item", "inventory_profitability_for_item", "inventory_purchase_to_sale_chain", "inventory_aging_by_purchase_date" ].includes(String(intent ?? "")), hasShortInventoryObjectFollowupSignal: () => false, resolveDebtRoleSwapFollowupIntent: () => null, hasAddressFollowupContextSignal: () => false, extractDisplayedEntityIndexMention: () => null, findRecentInventoryRootFrame: () => ({ intent: "inventory_on_hand_as_of_date", filters: { as_of_date: "2020-03-31", organization: 'ООО "Альтернатива Плюс"' }, anchorType: "organization", anchorValue: 'ООО "Альтернатива Плюс"' }), hasInventoryRootTemporalFollowupSignal: (message: string) => /март 2020/i.test(message), hasFollowupMarker: () => false, hasReferentialPointer: () => false, hasStandaloneAddressTopicSignal: () => false, resolveAddressIntent: () => ({ intent: "unknown" }), resolveAddressIntentFamily: (intent: unknown) => (intent ? String(intent) : null), readAddressFilterString: (debug: Record, key: string) => debug?.extracted_filters && typeof debug.extracted_filters === "object" ? toNonEmptyString((debug.extracted_filters as Record)[key]) : null, normalizeOrganizationScopeValue: (value: unknown) => toNonEmptyString(value), isInventoryDrilldownFrameIntent: (intent: unknown) => [ "inventory_purchase_provenance_for_item", "inventory_purchase_documents_for_item", "inventory_sale_trace_for_item", "inventory_profitability_for_item", "inventory_purchase_to_sale_chain", "inventory_aging_by_purchase_date" ].includes(String(intent ?? "")), isInventoryRootFrameIntent: (intent: unknown) => String(intent ?? "") === "inventory_on_hand_as_of_date", findRecentAddressFilterValue: () => null, hasForeignAccountingPivotOverInventoryMessage: () => false, buildRootScopedCarryoverFilters: ( previousFilters: Record, inventoryRootFrame: Record ) => ({ organization: toNonEmptyString(inventoryRootFrame?.filters?.organization) ?? toNonEmptyString(previousFilters?.organization), warehouse: toNonEmptyString(inventoryRootFrame?.filters?.warehouse) ?? toNonEmptyString(previousFilters?.warehouse), as_of_date: toNonEmptyString(previousFilters?.as_of_date) ?? toNonEmptyString(inventoryRootFrame?.filters?.as_of_date), period_from: toNonEmptyString(previousFilters?.period_from) ?? toNonEmptyString(inventoryRootFrame?.filters?.period_from), period_to: toNonEmptyString(previousFilters?.period_to) ?? toNonEmptyString(inventoryRootFrame?.filters?.period_to) }), inferDisplayedEntityTypeFromIntent: () => "item", extractDisplayedAddressEntityCandidates: () => [], resolveDisplayedAddressEntityMention: () => null, ...overrides }); } describe("assistantTransitionPolicy", () => { it("promotes inventory temporal follow-up into root-scoped carryover", () => { const policy = buildPolicy(); const carryover = policy.resolveAddressFollowupCarryoverContext( "остатки на март 2020", [], null, null, { session_context: { active_focus_object: { object_type: "item", label: "Рабочая станция" } } } ); expect(carryover?.followupSelectionMode).toBe("carry_root_context"); expect(carryover?.followupContext?.root_context_only).toBe(true); expect(carryover?.followupContext?.target_intent).toBe("inventory_on_hand_as_of_date"); expect(carryover?.followupContext?.root_intent).toBe("inventory_on_hand_as_of_date"); expect(carryover?.followupContext?.previous_filters).toMatchObject({ as_of_date: "2020-03-31", organization: 'ООО "Альтернатива Плюс"' }); }); it("promotes same-date inventory restatement after drilldown into root-scoped carryover", () => { const policy = buildPolicy({ hasInventoryRootTemporalFollowupSignal: () => false }); const carryover = policy.resolveAddressFollowupCarryoverContext( "покажи еще раз остатки на эту же дату", [], null, null, null ); expect(carryover?.followupSelectionMode).toBe("carry_root_context"); expect(carryover?.followupContext?.root_context_only).toBe(true); expect(carryover?.followupContext?.previous_intent).toBeUndefined(); expect(carryover?.followupContext?.previous_filters).toMatchObject({ as_of_date: "2020-03-31", organization: 'ООО "Альтернатива Плюс"' }); expect(carryover?.followupContext?.root_intent).toBe("inventory_on_hand_as_of_date"); }); it("builds continuation contract from extracted root carryover", () => { const policy = buildPolicy(); const contract = policy.buildAddressDialogContinuationContractV2( "остатки на эту дату", "остатки на эту дату", { followupContext: { root_intent: "inventory_on_hand_as_of_date", previous_anchor_type: "item", previous_anchor_value: "Рабочая станция" }, previousSourceIntent: "inventory_purchase_documents_for_item", previousAddressIntent: null, followupSelectionMode: "carry_root_context", hasImplicitContinuationSignal: true }, { predecomposeContract: { intent: "unknown" } } ); expect(contract.decision).toBe("continue_previous"); expect(contract.target_intent).toBe("inventory_on_hand_as_of_date"); expect(contract.decision_reasons).toContain("root_context_only_carryover"); expect(contract.decision_reasons).toContain("implicit_continuation_by_llm"); expect(contract.anchor_type).toBe("item"); expect(contract.anchor_value).toBe("Рабочая станция"); }); it("prefers carryover target intent over llm contract drift in continuation contract", () => { const policy = buildPolicy(); const contract = policy.buildAddressDialogContinuationContractV2( "покажи договор по гамме", "покажи договор по гамме", { followupContext: { previous_intent: "customer_revenue_and_payments", target_intent: "list_contracts_by_counterparty", previous_anchor_type: "counterparty", previous_anchor_value: "Гамма-мебель, ООО" }, previousSourceIntent: "customer_revenue_and_payments", previousAddressIntent: "customer_revenue_and_payments", followupSelectionMode: "carry_referenced_entity", hasImplicitContinuationSignal: false }, { predecomposeContract: { intent: "unknown" } } ); expect(contract.target_intent).toBe("list_contracts_by_counterparty"); expect(contract.decision).toBe("continue_previous"); }); it("retargets displayed counterparty follow-up through shared referenced-entity carryover", () => { const policy = buildPolicy({ findLastAddressAssistantItem: () => ({ text: "1. SVK Group\n2. Gamma", debug: { detected_intent: "customer_revenue_and_payments", extracted_filters: { organization: 'РћРћРћ "Альтернатива Плюс"', period_from: "2017-01-01", period_to: "2017-12-31" } } }), hasAddressFollowupContextSignal: () => true, inferDisplayedEntityTypeFromIntent: () => "counterparty", extractDisplayedAddressEntityCandidates: () => [{ entityType: "counterparty", value: "SVK Group" }], resolveDisplayedAddressEntityMention: () => ({ entityType: "counterparty", value: "SVK Group" }), resolveAddressIntent: () => ({ intent: "unknown" }) }); const carryover = policy.resolveAddressFollowupCarryoverContext( "покажи договоры по СВК", [], null, null, null ); expect(carryover?.followupSelectionMode).toBe("carry_referenced_entity"); expect(carryover?.followupContext?.target_intent).toBe("list_contracts_by_counterparty"); expect(carryover?.followupContext?.previous_anchor_type).toBe("counterparty"); expect(carryover?.followupContext?.previous_anchor_value).toBe("SVK Group"); expect(carryover?.followupContext?.previous_filters).toMatchObject({ organization: 'РћРћРћ "Альтернатива Плюс"', counterparty: "SVK Group", period_from: "2017-01-01", period_to: "2017-12-31" }); expect(carryover?.followupContext?.resolved_counterparty_from_display).toBe(true); }); it("retargets same-date inventory follow-up away from receivables intent", () => { const policy = buildPolicy({ findLastAddressAssistantItem: () => ({ text: "Подтвержденная дебиторская задолженность на 31.03.2020 собрана.", debug: { detected_intent: "receivables_confirmed_as_of_date", extracted_filters: { organization: 'ООО "Альтернатива Плюс"', as_of_date: "2020-03-31", period_from: "2020-03-01", period_to: "2020-03-31" }, anchor_type: "organization", anchor_value_resolved: 'ООО "Альтернатива Плюс"' } }), hasAddressFollowupContextSignal: () => true, hasReferentialPointer: () => true, findRecentInventoryRootFrame: () => null, resolveAddressIntent: () => ({ intent: "unknown" }) }); const carryover = policy.resolveAddressFollowupCarryoverContext( "остатки по складу на эту же дату", [], null, null, null ); expect(carryover?.followupSelectionMode).toBe("carry_previous_intent"); expect(carryover?.followupContext?.previous_intent).toBe("receivables_confirmed_as_of_date"); expect(carryover?.followupContext?.target_intent).toBe("inventory_on_hand_as_of_date"); expect(carryover?.followupContext?.previous_filters).toMatchObject({ organization: 'ООО "Альтернатива Плюс"', as_of_date: "2020-03-31", period_from: "2020-03-01", period_to: "2020-03-31" }); expect(carryover?.followupContext?.root_context_only).toBeUndefined(); }); it("hydrates selected-item carryover through shared continuity helper for short object follow-up", () => { const policy = buildPolicy({ findLastAddressAssistantItem: () => ({ text: "Подтвержден складской срез по выбранной позиции.", debug: { detected_intent: "inventory_on_hand_as_of_date", extracted_filters: { organization: 'РћРћРћ "Альтернатива Плюс"', as_of_date: "2020-03-31" } } }), hasAddressFollowupContextSignal: () => true, hasShortInventoryObjectFollowupSignal: () => true, findRecentInventoryRootFrame: () => null, resolveAddressIntent: () => ({ intent: "unknown" }) }); const carryover = policy.resolveAddressFollowupCarryoverContext( "по этой позиции покажи документы", [], null, null, { session_context: { active_focus_object: { object_type: "item", label: "Workstation Focus" } } } ); expect(carryover?.followupContext?.previous_filters).toMatchObject({ organization: 'РћРћРћ "Альтернатива Плюс"', as_of_date: "2020-03-31", item: "Workstation Focus" }); expect(carryover?.followupContext?.previous_anchor_type).toBe("item"); expect(carryover?.followupContext?.previous_anchor_value).toBe("Workstation Focus"); }); it("hydrates follow-up organization from shared assistant authority when local history filters are empty", () => { const policy = buildPolicy({ findLastAddressAssistantItem: () => ({ text: "Подтвержденная дебиторская задолженность на 31.03.2020 собрана.", debug: { detected_intent: "receivables_confirmed_as_of_date", extracted_filters: { as_of_date: "2020-03-31", period_from: "2020-03-01", period_to: "2020-03-31" }, anchor_type: "organization", anchor_value_resolved: null } }), hasAddressFollowupContextSignal: () => true, hasReferentialPointer: () => true, findRecentInventoryRootFrame: () => null, findRecentAddressFilterValue: () => null, resolveAddressIntent: () => ({ intent: "unknown" }) }); const carryover = policy.resolveAddressFollowupCarryoverContext( "остатки по складу на эту же дату", [ { role: "assistant", text: "Компания уже выбрана в живом чате.", debug: { assistant_active_organization: 'ООО "Альтернатива Плюс"', assistant_known_organizations: ['ООО "Альтернатива Плюс"', 'ООО "Лайт"'] } } ], null, null, null ); expect(carryover?.followupContext?.previous_filters).toMatchObject({ organization: 'ООО "Альтернатива Плюс"', as_of_date: "2020-03-31", period_from: "2020-03-01", period_to: "2020-03-31" }); expect(carryover?.followupContext?.target_intent).toBe("inventory_on_hand_as_of_date"); }); it("hydrates carryover anchor from shared debug helpers when explicit anchor fields are absent", () => { const policy = buildPolicy({ findLastAddressAssistantItem: () => ({ text: "Подтвержденный складской срез собран.", debug: { detected_intent: "inventory_on_hand_as_of_date", extracted_filters: { item: "Рабочая станция", period_from: "2020-03-01" }, address_root_frame_context: { as_of_date: "2020-03-31", period_to: "2020-03-31" }, anchor_type: null, anchor_value_resolved: null } }), hasAddressFollowupContextSignal: () => true, hasReferentialPointer: () => true, findRecentInventoryRootFrame: () => null, findRecentAddressFilterValue: () => null, resolveAddressIntent: () => ({ intent: "unknown" }) }); const carryover = policy.resolveAddressFollowupCarryoverContext("по этой позиции", [], null, null, null); expect(carryover?.followupContext?.previous_anchor_type).toBe("item"); expect(carryover?.followupContext?.previous_anchor_value).toBe("Рабочая станция"); expect(carryover?.followupContext?.previous_filters).toMatchObject({ item: "Рабочая станция", period_from: "2020-03-01" }); }); it("bridges selected-item purchase provenance into a VAT period follow-up", () => { const item = "Рабочая станция универсального специалиста"; const policy = buildPolicy({ findLastAddressAssistantItem: () => ({ text: [ `По позиции ${item} однозначный поставщик не подтвержден.`, "Подтверждение:", "- Первая найденная дата закупки: 05.02.2015.", "- Последняя найденная дата закупки: 22.07.2015." ].join("\n"), debug: { detected_intent: "inventory_purchase_provenance_for_item", extracted_filters: { item, organization: 'ООО "Альтернатива Плюс"', as_of_date: "2016-03-31" }, anchor_type: "item", anchor_value_resolved: item } }), hasAddressFollowupContextSignal: () => false, findRecentInventoryRootFrame: () => null, resolveAddressIntent: () => ({ intent: "unknown" }) }); const carryover = policy.resolveAddressFollowupCarryoverContext( "ндс можешь прикинуть на дату покупки рабочей станции?", [], null, null, { session_context: { active_focus_object: { object_type: "item", label: item, provenance_result_set_id: "rs-provenance" }, active_result_set_id: "rs-provenance" }, result_sets: [ { result_set_id: "rs-provenance", intent: "inventory_purchase_provenance_for_item", entity_refs: [ { index: 1, entity_type: "item", value: "Поступление товаров и услуг 00000000023 от 05.02.2015 0:00:00" } ] } ] } ); expect(carryover?.followupContext?.previous_intent).toBe("inventory_purchase_provenance_for_item"); expect(carryover?.followupContext?.target_intent).toBe("vat_liability_confirmed_for_tax_period"); expect(carryover?.followupContext?.previous_filters).toMatchObject({ item, organization: 'ООО "Альтернатива Плюс"', period_from: "2015-02-01", period_to: "2015-02-28" }); }); it("keeps selected-object continuity for purchase-date VAT bridge even when an inventory root frame exists", () => { const item = "Рабочая станция универсального специалиста"; const policy = buildPolicy({ findLastAddressAssistantItem: () => ({ text: [ `По позиции ${item} однозначный поставщик не подтвержден.`, "Подтверждение:", "- Первая найденная дата закупки: 05.02.2015." ].join("\n"), debug: { detected_intent: "inventory_purchase_provenance_for_item", extracted_filters: { item, organization: 'ООО "Альтернатива Плюс"', as_of_date: "2016-03-31" }, anchor_type: "item", anchor_value_resolved: item } }), hasAddressFollowupContextSignal: () => false, hasForeignAccountingPivotOverInventoryMessage: () => true, resolveAddressIntent: () => ({ intent: "unknown" }) }); const carryover = policy.resolveAddressFollowupCarryoverContext( "ндс можешь прикинуть на дату покупки рабочей станции?", [], null, null, { session_context: { active_focus_object: { object_type: "item", label: item, provenance_result_set_id: "rs-provenance" }, active_result_set_id: "rs-provenance" }, result_sets: [ { result_set_id: "rs-provenance", intent: "inventory_purchase_provenance_for_item", entity_refs: [ { index: 1, entity_type: "item", value: "Поступление товаров и услуг 00000000023 от 05.02.2015 0:00:00" } ] } ] } ); expect(carryover?.followupSelectionMode).toBe("carry_previous_intent"); expect(carryover?.followupContext?.root_context_only).toBeUndefined(); expect(carryover?.followupContext?.previous_intent).toBe("inventory_purchase_provenance_for_item"); expect(carryover?.followupContext?.target_intent).toBe("vat_liability_confirmed_for_tax_period"); }); it("keeps purchase-date VAT bridge after unsupported verification interrupt", () => { const item = "Рабочая станция универрсального специалиста"; const provenanceItem = { role: "assistant", text: [ `РџРѕ позиции ${item} однозначный поставщик РЅРµ подтвержден.`, "Подтверждение:", "- Первая найденная дата закупки: 05.02.2015." ].join("\n"), debug: { execution_lane: "address_query", answer_grounding_check: { status: "grounded" }, detected_intent: "inventory_purchase_provenance_for_item", extracted_filters: { item, organization: 'РћРћРћ "Альтернатива Плюс"', as_of_date: "2016-03-31" }, anchor_type: "item", anchor_value_resolved: item } } as any; const unsupportedInterrupt = { role: "assistant", text: "РџРѕРєР° РЅРµ РјРѕРіСѓ точно подтвердить, что именно это ты имеешь РІ РІРёРґСѓ.", debug: { execution_lane: "address_query", detected_intent: "unknown", answer_grounding_check: { status: "unsupported" } } } as any; const policy = buildPolicy({ findLastAddressAssistantItem: () => unsupportedInterrupt, hasAddressFollowupContextSignal: () => false, findRecentInventoryRootFrame: () => null, resolveAddressIntent: () => ({ intent: "unknown" }) }); const carryover = policy.resolveAddressFollowupCarryoverContext( "ндс можешь прикинуть на дату покупки рабочей станции?", [provenanceItem, unsupportedInterrupt], null, null, { session_context: { active_focus_object: { object_type: "item", label: item, provenance_result_set_id: "rs-provenance-interrupt" }, active_result_set_id: "rs-provenance-interrupt" }, result_sets: [ { result_set_id: "rs-provenance-interrupt", intent: "inventory_purchase_provenance_for_item", entity_refs: [ { index: 1, entity_type: "item", value: "Поступление товаров и услуг 00000000023 от 05.02.2015 0:00:00" } ] } ] } ); expect(carryover?.followupContext?.previous_intent).toBe("inventory_purchase_provenance_for_item"); expect(carryover?.followupContext?.target_intent).toBe("vat_liability_confirmed_for_tax_period"); expect(carryover?.followupContext?.previous_filters).toMatchObject({ item, organization: 'РћРћРћ "Альтернатива Плюс"', period_from: "2015-02-01", period_to: "2015-02-28" }); }); it("drops stale carryover for a fresh standalone topic from another intent family", () => { const policy = buildPolicy({ findLastAddressAssistantItem: () => ({ text: "Прогноз НДС на март 2020 собран.", debug: { detected_intent: "vat_payable_forecast", extracted_filters: { period_from: "2020-03-01", period_to: "2020-03-31" } } }), hasAddressFollowupContextSignal: () => true, hasStandaloneAddressTopicSignal: () => true, resolveAddressIntent: () => ({ intent: "inventory_on_hand_as_of_date" }), resolveAddressIntentFamily: (intent: unknown) => { if (String(intent ?? "").startsWith("vat_")) return "vat"; if (String(intent ?? "").startsWith("inventory_")) return "inventory"; return null; } }); const carryover = policy.resolveAddressFollowupCarryoverContext( "остаток на складе за май 2020", [], null, null, null ); expect(carryover).toBeNull(); }); it("keeps document intent for short counterparty retarget wording with action verb", () => { const policy = buildPolicy({ findLastAddressAssistantItem: () => ({ text: "Собран список документов по контрагенту Чапурнов.", debug: { detected_intent: "list_documents_by_counterparty", extracted_filters: { counterparty: "Чапурнов" }, anchor_type: "counterparty", anchor_value_resolved: "Чапурнов" } }), buildAddressFollowupOffer: () => ({ enabled: true, source_intent: "list_documents_by_counterparty", suggested_intents: ["bank_operations_by_counterparty"] }), isImplicitAddressContinuationByLlm: () => true }); const carryover = policy.resolveAddressFollowupCarryoverContext("покажи по свк", [], null, null, null); expect(carryover?.followupContext?.previous_intent).toBe("list_documents_by_counterparty"); expect(carryover?.followupSelectionMode).toBe("carry_previous_intent"); }); it("keeps root-scoped carryover for foreign accounting pivot over inventory drilldown", () => { const policy = buildPolicy({ findLastAddressAssistantItem: () => ({ text: "Собран sale trace по позиции.", debug: { detected_intent: "inventory_sale_trace_for_item", extracted_filters: { item: "Кромка с клеем 33 дуб ниагара 137 м", organization: 'ООО "Альтернатива Плюс"', as_of_date: "2021-03-31" }, anchor_type: "item", anchor_value_resolved: "Кромка с клеем 33 дуб ниагара 137 м" } }), hasAddressFollowupContextSignal: () => true, resolveAddressIntent: () => ({ intent: "vat_payable_confirmed_as_of_date" }), resolveAddressIntentFamily: (intent: unknown) => { if (String(intent ?? "").startsWith("vat_")) return "vat"; if (String(intent ?? "").startsWith("inventory_")) return "inventory"; return null; }, hasForeignAccountingPivotOverInventoryMessage: () => true, findRecentInventoryRootFrame: () => ({ intent: "inventory_on_hand_as_of_date", filters: { organization: 'ООО "Альтернатива Плюс"', warehouse: "Основной склад", as_of_date: "2021-03-31", period_from: "2021-03-01", period_to: "2021-03-31" }, anchorType: "organization", anchorValue: 'ООО "Альтернатива Плюс"' }) }); const carryover = policy.resolveAddressFollowupCarryoverContext("а ндс?", [], null, null, null); expect(carryover?.followupSelectionMode).toBe("carry_root_context"); expect(carryover?.followupContext?.root_context_only).toBe(true); expect(carryover?.followupContext?.previous_intent).toBeUndefined(); expect(carryover?.followupContext?.root_intent).toBe("inventory_on_hand_as_of_date"); expect(carryover?.followupContext?.previous_filters).toEqual({ organization: 'ООО "Альтернатива Плюс"', warehouse: "Основной склад", as_of_date: "2021-03-31", period_from: "2021-03-01", period_to: "2021-03-31" }); }); it("prefers the freshest previous date scope over a stale inventory root frame during same-date pivot", () => { const filters = buildRootScopedCarryoverFilters( { organization: 'ООО "Альтернатива Плюс"', as_of_date: "2020-03-31", period_from: "2020-03-01", period_to: "2020-03-31" }, { filters: { organization: 'ООО "Альтернатива Плюс"', warehouse: "Основной склад", as_of_date: "2021-03-31", period_from: "2021-03-01", period_to: "2021-03-31" } } ); expect(filters).toEqual({ organization: 'ООО "Альтернатива Плюс"', warehouse: "Основной склад", as_of_date: "2020-03-31", period_from: "2020-03-01", period_to: "2020-03-31" }); }); it("does not attach address follow-up carryover to explicit capability-meta questions", () => { const policy = buildPolicy({ shouldHandleAsAssistantCapabilityMetaQuery: (message: unknown) => /дельт[ауы]?\s+по\s+договорам/iu.test(String(message ?? "")), hasAddressFollowupContextSignal: () => true }); const carryover = policy.resolveAddressFollowupCarryoverContext( "ты умеешь считать дельту по договорам?", [], "проверить возможность расчета дельты по договорам", { predecomposeContract: { mode: "address_query", intent: "unknown" } }, null ); expect(carryover).toBeNull(); }); it("retargets selected-object provenance follow-up from inventory root when semantic scope is already detected", () => { const policy = buildPolicy({ findLastAddressAssistantItem: () => ({ text: "На 31.03.2016 на складе подтверждено 2 позиции.", debug: { detected_intent: "inventory_on_hand_as_of_date", extracted_filters: { organization: 'ООО "Альтернатива Плюс"', warehouse: "Основной склад", as_of_date: "2016-03-31", period_from: "2016-03-01", period_to: "2016-03-31" }, anchor_type: "organization", anchor_value_resolved: 'ООО "Альтернатива Плюс"' } }), hasAddressFollowupContextSignal: () => true }); const carryover = policy.resolveAddressFollowupCarryoverContext( 'По выбранному объекту "Рабочая станция универсального специалиста (индивидуальное изготовление)": где взяли это?', [], null, { predecomposeContract: { mode: "address_query", intent: "unknown", semantics: { selected_object_scope_detected: true } } }, null ); expect(carryover?.followupContext?.target_intent).toBe("inventory_purchase_provenance_for_item"); expect(carryover?.followupContext?.previous_filters).toMatchObject({ organization: 'ООО "Альтернатива Плюс"', item: "Рабочая станция универсального специалиста (индивидуальное изготовление)" }); expect(carryover?.followupContext?.previous_anchor_type).toBe("item"); }); it("prefers root-frame dates over stale drilldown filters when hydrating previous filters", () => { const organization = "Org Alt"; const policy = buildPolicy({ findLastAddressAssistantItem: (_items: unknown[]) => ({ text: "Workstation drilldown", debug: { detected_intent: "inventory_purchase_documents_for_item", extracted_filters: { item: "Workstation", organization, as_of_date: "2021-04-15" }, anchor_type: "item", anchor_value_resolved: "Workstation", address_root_frame_context: { root_intent: "inventory_on_hand_as_of_date", root_filters: { organization, warehouse: "Main Warehouse", as_of_date: "2021-03-31", period_from: "2021-03-01", period_to: "2021-03-31" }, root_anchor_type: "organization", root_anchor_value: organization, current_frame_kind: "inventory_drilldown" } } }), findRecentInventoryRootFrame: () => null, hasInventoryRootTemporalFollowupSignal: (message: string) => /эту же дату/i.test(message) }); const items = [ { role: "assistant", text: "Workstation drilldown", debug: { execution_lane: "address_query", answer_grounding_check: { status: "grounded" }, detected_intent: "inventory_purchase_documents_for_item", extracted_filters: { item: "Workstation", organization, as_of_date: "2021-04-15" }, anchor_type: "item", anchor_value_resolved: "Workstation", address_root_frame_context: { root_intent: "inventory_on_hand_as_of_date", root_filters: { organization, warehouse: "Main Warehouse", as_of_date: "2021-03-31", period_from: "2021-03-01", period_to: "2021-03-31" }, root_anchor_type: "organization", root_anchor_value: organization, current_frame_kind: "inventory_drilldown" } } } ]; const carryover = policy.resolveAddressFollowupCarryoverContext( "остатки на эту же дату", items as any, null, null, null ); expect(carryover?.followupContext?.root_context_only).toBe(true); expect(carryover?.followupContext?.previous_filters).toMatchObject({ organization, warehouse: "Main Warehouse", as_of_date: "2021-03-31", period_from: "2021-03-01", period_to: "2021-03-31" }); expect(carryover?.followupContext?.previous_filters?.as_of_date).not.toBe("2021-04-15"); }); it("drops carryover when current-turn meaning forbids stale replay", () => { const policy = buildPolicy({ findLastAddressAssistantItem: () => ({ text: "Documents by previous counterparty", debug: { execution_lane: "address_query", answer_grounding_check: { status: "grounded" }, detected_intent: "list_documents_by_counterparty", extracted_filters: { counterparty: "Previous Counterparty", organization: "Org Alt" }, anchor_type: "counterparty", anchor_value_resolved: "Previous Counterparty" } }), hasAddressFollowupContextSignal: () => true, resolveAssistantTurnMeaning: () => ({ schema_version: "assistant_turn_meaning_v1", asked_domain_family: "counterparty", asked_action_family: "counterparty_value_or_turnover", unsupported_but_understood_family: "counterparty_value_or_turnover", explicit_entity_candidates: [ { type: "counterparty", value: "svk", source: "current_turn_loose_entity_tail" } ], stale_replay_forbidden: true }) }); const carryover = policy.resolveAddressFollowupCarryoverContext( "\u043a\u0430\u043a\u043e\u0439 \u043e\u0431\u043e\u0440\u043e\u0442 \u0431\u044b\u043b \u0441\u0432\u043a", [], null, null, null ); expect(carryover).toBeNull(); }); it("drops carryover for a supported current-turn counterparty revenue pivot with a new entity", () => { const policy = buildPolicy({ findLastAddressAssistantItem: () => ({ text: "Documents by previous counterparty", debug: { execution_lane: "address_query", answer_grounding_check: { status: "grounded" }, detected_intent: "list_documents_by_counterparty", extracted_filters: { counterparty: "Previous Counterparty", organization: "Org Alt" }, anchor_type: "counterparty", anchor_value_resolved: "Previous Counterparty" } }), hasAddressFollowupContextSignal: () => true, isImplicitAddressContinuationByLlm: () => true, resolveAssistantTurnMeaning: () => ({ schema_version: "assistant_turn_meaning_v1", asked_domain_family: "counterparty", asked_action_family: "counterparty_value_or_turnover", explicit_intent_candidate: "customer_revenue_and_payments", intent_override_strength: "explicit_current_turn_intent", explicit_entity_candidates: [ { type: "counterparty", value: "svk", source: "current_turn_loose_entity_tail" } ], stale_replay_forbidden: false }), resolveAddressIntent: () => ({ intent: "customer_revenue_and_payments" }), resolveAddressIntentFamily: () => "counterparty" }); const carryover = policy.resolveAddressFollowupCarryoverContext( "\u043a\u0430\u043a\u043e\u0439 \u043e\u0431\u043e\u0440\u043e\u0442 \u0431\u044b\u043b \u0441\u0432\u043a", [], null, null, null ); expect(carryover).toBeNull(); }); });