661 lines
24 KiB
TypeScript
661 lines
24 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
||
import {
|
||
buildAddressMemoryRecapReply,
|
||
buildBroadBusinessEvaluationReply,
|
||
buildSelectedObjectAnswerInspectionReply,
|
||
createAssistantMemoryRecapPolicy,
|
||
resolveAssistantLivingChatMemoryContext
|
||
} from "../src/services/assistantMemoryRecapPolicy";
|
||
|
||
const policy = createAssistantMemoryRecapPolicy({
|
||
hasHistoricalCapabilityFollowupSignal: (text: unknown) =>
|
||
/историческ|архив|раньше/i.test(String(text ?? "")),
|
||
hasConversationMemoryRecallFollowupSignal: (text: unknown) =>
|
||
/помнишь|remember/i.test(String(text ?? "")),
|
||
isGroundedInventoryContextDebug: (debug: unknown) =>
|
||
String((debug as Record<string, unknown> | null)?.detected_intent ?? "") === "inventory_on_hand_as_of_date"
|
||
});
|
||
|
||
describe("assistantMemoryRecapPolicy", () => {
|
||
it("detects contextual historical capability follow-up", () => {
|
||
const signals = policy.resolveRouteMemorySignals({
|
||
rawUserMessage: "а исторические остатки тоже можешь?",
|
||
repairedRawUserMessage: "",
|
||
effectiveAddressUserMessage: "",
|
||
repairedEffectiveAddressUserMessage: "",
|
||
dataScopeMetaQuery: false,
|
||
capabilityMetaQuery: true,
|
||
dataRetrievalSignal: false,
|
||
strongDataSignal: false,
|
||
aggregateBusinessAnalyticsSignal: false,
|
||
lastGroundedAddressDebug: {
|
||
detected_intent: "inventory_on_hand_as_of_date"
|
||
},
|
||
hasPriorAddressDebug: true
|
||
});
|
||
|
||
expect(signals.contextualHistoricalCapabilityFollowupDetected).toBe(true);
|
||
expect(signals.contextualMemoryRecapFollowupDetected).toBe(false);
|
||
});
|
||
|
||
it("detects contextual memory recap over prior address debug", () => {
|
||
const signals = policy.resolveRouteMemorySignals({
|
||
rawUserMessage: "а ты помнишь что мы обсуждали?",
|
||
repairedRawUserMessage: "",
|
||
effectiveAddressUserMessage: "",
|
||
repairedEffectiveAddressUserMessage: "",
|
||
dataScopeMetaQuery: false,
|
||
capabilityMetaQuery: false,
|
||
dataRetrievalSignal: false,
|
||
strongDataSignal: false,
|
||
aggregateBusinessAnalyticsSignal: false,
|
||
lastGroundedAddressDebug: null,
|
||
hasPriorAddressDebug: true,
|
||
sessionItems: [
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "address_query",
|
||
answer_grounding_check: {
|
||
status: "grounded"
|
||
},
|
||
detected_intent: "list_documents_by_counterparty"
|
||
}
|
||
}
|
||
]
|
||
});
|
||
|
||
expect(signals.contextualHistoricalCapabilityFollowupDetected).toBe(false);
|
||
expect(signals.contextualMemoryRecapFollowupDetected).toBe(true);
|
||
});
|
||
|
||
it("detects startup memory checkpoint without prior grounded context", () => {
|
||
const signals = policy.resolveRouteMemorySignals({
|
||
rawUserMessage:
|
||
"Сделай короткий стартовый чек контекста: есть ли уже выбранная компания или контрагент в текущем диалоге; если нет, скажи честно и не выдумывай память про Группа СВК.",
|
||
repairedRawUserMessage: "",
|
||
effectiveAddressUserMessage: "",
|
||
repairedEffectiveAddressUserMessage: "",
|
||
dataScopeMetaQuery: false,
|
||
capabilityMetaQuery: false,
|
||
dataRetrievalSignal: false,
|
||
strongDataSignal: true,
|
||
aggregateBusinessAnalyticsSignal: false,
|
||
lastGroundedAddressDebug: null,
|
||
hasPriorAddressDebug: false,
|
||
sessionItems: []
|
||
});
|
||
|
||
expect(signals.contextualHistoricalCapabilityFollowupDetected).toBe(false);
|
||
expect(signals.contextualMemoryRecapFollowupDetected).toBe(true);
|
||
});
|
||
|
||
it("treats explicit recap wording over selected-object phrasing as memory follow-up even when data cues are present", () => {
|
||
const signals = policy.resolveRouteMemorySignals({
|
||
rawUserMessage: "а ты помнишь, что мы по этой позиции уже выяснили?",
|
||
repairedRawUserMessage: "",
|
||
effectiveAddressUserMessage: "",
|
||
repairedEffectiveAddressUserMessage: "",
|
||
dataScopeMetaQuery: false,
|
||
capabilityMetaQuery: false,
|
||
dataRetrievalSignal: true,
|
||
strongDataSignal: true,
|
||
aggregateBusinessAnalyticsSignal: false,
|
||
lastGroundedAddressDebug: null,
|
||
hasPriorAddressDebug: true,
|
||
sessionItems: [
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "address_query",
|
||
answer_grounding_check: {
|
||
status: "grounded"
|
||
},
|
||
detected_intent: "inventory_purchase_provenance_for_item",
|
||
extracted_filters: {
|
||
item: "Рабочая станция",
|
||
as_of_date: "2022-02-28"
|
||
}
|
||
}
|
||
}
|
||
]
|
||
});
|
||
|
||
expect(signals.contextualHistoricalCapabilityFollowupDetected).toBe(false);
|
||
expect(signals.contextualMemoryRecapFollowupDetected).toBe(true);
|
||
});
|
||
|
||
it("keeps final executive summary in memory lane even with strong data wording", () => {
|
||
const executivePolicy = createAssistantMemoryRecapPolicy({
|
||
hasHistoricalCapabilityFollowupSignal: () => false,
|
||
hasConversationMemoryRecallFollowupSignal: (text: unknown) => /executive summary/i.test(String(text ?? "")),
|
||
isGroundedInventoryContextDebug: () => false
|
||
});
|
||
|
||
const signals = executivePolicy.resolveRouteMemorySignals({
|
||
rawUserMessage:
|
||
"Финально собери executive summary по всему диалогу: где подтверждено, где proxy и где не хватило доказательств.",
|
||
repairedRawUserMessage: "",
|
||
effectiveAddressUserMessage: "",
|
||
repairedEffectiveAddressUserMessage: "",
|
||
dataScopeMetaQuery: false,
|
||
capabilityMetaQuery: false,
|
||
dataRetrievalSignal: false,
|
||
strongDataSignal: true,
|
||
aggregateBusinessAnalyticsSignal: false,
|
||
sessionItems: [
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "address_query",
|
||
answer_grounding_check: { status: "grounded" },
|
||
detected_intent: "receivables_confirmed_as_of_date",
|
||
extracted_filters: {
|
||
organization: "ООО Альтернатива Плюс"
|
||
}
|
||
}
|
||
}
|
||
]
|
||
});
|
||
|
||
expect(signals.contextualMemoryRecapFollowupDetected).toBe(true);
|
||
});
|
||
|
||
it("does not trigger recap from ungrounded address history", () => {
|
||
const signals = policy.resolveRouteMemorySignals({
|
||
rawUserMessage: "а ты помнишь что мы обсуждали?",
|
||
repairedRawUserMessage: "",
|
||
effectiveAddressUserMessage: "",
|
||
repairedEffectiveAddressUserMessage: "",
|
||
dataScopeMetaQuery: false,
|
||
capabilityMetaQuery: false,
|
||
dataRetrievalSignal: false,
|
||
strongDataSignal: false,
|
||
aggregateBusinessAnalyticsSignal: false,
|
||
lastGroundedAddressDebug: null,
|
||
hasPriorAddressDebug: true,
|
||
sessionItems: [
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "address_query",
|
||
detected_intent: "inventory_purchase_documents_for_item",
|
||
extracted_filters: {
|
||
item: "Рабочая станция"
|
||
}
|
||
}
|
||
}
|
||
]
|
||
});
|
||
|
||
expect(signals.contextualMemoryRecapFollowupDetected).toBe(false);
|
||
});
|
||
|
||
it("detects contextual memory recap over prior grounded MCP discovery answer", () => {
|
||
const signals = policy.resolveRouteMemorySignals({
|
||
rawUserMessage: "а ты помнишь, что мы уже выяснили по свк?",
|
||
repairedRawUserMessage: "",
|
||
effectiveAddressUserMessage: "",
|
||
repairedEffectiveAddressUserMessage: "",
|
||
dataScopeMetaQuery: false,
|
||
capabilityMetaQuery: false,
|
||
dataRetrievalSignal: false,
|
||
strongDataSignal: false,
|
||
aggregateBusinessAnalyticsSignal: false,
|
||
lastGroundedAddressDebug: null,
|
||
hasPriorAddressDebug: true,
|
||
sessionItems: [
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "living_chat",
|
||
mcp_discovery_response_applied: true,
|
||
assistant_mcp_discovery_entry_point_v1: {
|
||
schema_version: "assistant_mcp_discovery_runtime_entry_point_v1",
|
||
entry_status: "bridge_executed",
|
||
turn_input: {
|
||
turn_meaning_ref: {
|
||
explicit_entity_candidates: ["Группа СВК"],
|
||
explicit_date_scope: "2020"
|
||
}
|
||
},
|
||
bridge: {
|
||
bridge_status: "answer_draft_ready",
|
||
business_fact_answer_allowed: true,
|
||
answer_draft: {
|
||
answer_mode: "confirmed_with_bounded_inference"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
]
|
||
});
|
||
|
||
expect(signals.contextualMemoryRecapFollowupDetected).toBe(true);
|
||
});
|
||
|
||
it("builds deterministic recap summary from recent selected-object facts", () => {
|
||
const context = resolveAssistantLivingChatMemoryContext({
|
||
modeDecisionReason: "memory_recap_followup_detected",
|
||
sessionItems: [
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "address_query",
|
||
answer_grounding_check: {
|
||
status: "grounded"
|
||
},
|
||
anchor_type: "item",
|
||
anchor_value_resolved: "Рабочая станция",
|
||
extracted_filters: {
|
||
item: "Рабочая станция",
|
||
as_of_date: "2022-02-28"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "address_query",
|
||
answer_grounding_check: {
|
||
status: "grounded"
|
||
},
|
||
detected_intent: "inventory_purchase_provenance_for_item",
|
||
extracted_filters: {
|
||
item: "Рабочая станция",
|
||
as_of_date: "2022-02-28"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "address_query",
|
||
answer_grounding_check: {
|
||
status: "grounded"
|
||
},
|
||
detected_intent: "inventory_purchase_documents_for_item",
|
||
extracted_filters: {
|
||
item: "Рабочая станция",
|
||
as_of_date: "2022-02-28"
|
||
}
|
||
}
|
||
}
|
||
]
|
||
});
|
||
|
||
const reply = buildAddressMemoryRecapReply({
|
||
organization: null,
|
||
addressDebug: context.lastMemoryAddressDebug,
|
||
sessionItems: [
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "address_query",
|
||
answer_grounding_check: {
|
||
status: "grounded"
|
||
},
|
||
detected_intent: "inventory_on_hand_as_of_date",
|
||
extracted_filters: {
|
||
organization: "ООО Альтернатива Плюс",
|
||
as_of_date: "2022-02-28"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "address_query",
|
||
answer_grounding_check: {
|
||
status: "grounded"
|
||
},
|
||
detected_intent: "inventory_purchase_provenance_for_item",
|
||
extracted_filters: {
|
||
item: "Рабочая станция",
|
||
as_of_date: "2022-02-28"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "address_query",
|
||
answer_grounding_check: {
|
||
status: "grounded"
|
||
},
|
||
detected_intent: "inventory_purchase_documents_for_item",
|
||
extracted_filters: {
|
||
item: "Рабочая станция",
|
||
as_of_date: "2022-02-28"
|
||
}
|
||
}
|
||
}
|
||
],
|
||
toNonEmptyString: (value: unknown) => {
|
||
const text = String(value ?? "").trim();
|
||
return text.length > 0 ? text : null;
|
||
}
|
||
});
|
||
|
||
expect(context.contextualMemoryRecapFollowup).toBe(true);
|
||
expect(reply).toContain("Рабочая станция");
|
||
expect(reply).toContain("мы уже выяснили");
|
||
expect(reply).toContain("разобрали, кто поставлял");
|
||
expect(reply).toContain("подняли документы закупки");
|
||
});
|
||
|
||
it("honestly reports empty memory when startup checkpoint has no selected context", () => {
|
||
const reply = buildAddressMemoryRecapReply({
|
||
organization: null,
|
||
addressDebug: null,
|
||
sessionItems: [],
|
||
userMessage:
|
||
"Сделай короткий стартовый чек контекста: есть ли уже выбранная компания или контрагент в текущем диалоге; если нет, скажи честно и не выдумывай память про Группа СВК.",
|
||
toNonEmptyString: (value: unknown) => {
|
||
const text = String(value ?? "").trim();
|
||
return text.length > 0 ? text : null;
|
||
}
|
||
});
|
||
|
||
expect(reply).toContain("Коротко: в текущем диалоге я не вижу выбранной компании");
|
||
expect(reply).toContain("Группа СВК");
|
||
expect(reply).toContain("не подтверждена");
|
||
expect(reply).not.toContain("Да, помню предыдущий адресный контур");
|
||
});
|
||
|
||
it("resolves grounded answer inspection from shared memory context", () => {
|
||
const context = resolveAssistantLivingChatMemoryContext({
|
||
modeDecisionReason: "answer_inspection_followup_detected",
|
||
sessionItems: [
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "address_query",
|
||
answer_grounding_check: {
|
||
status: "grounded"
|
||
},
|
||
detected_intent: "inventory_sale_trace_for_item",
|
||
extracted_filters: {
|
||
item: "Рабочая станция",
|
||
organization: "ООО Альтернатива Плюс",
|
||
as_of_date: "2016-03-31"
|
||
}
|
||
}
|
||
}
|
||
]
|
||
});
|
||
|
||
const reply = buildSelectedObjectAnswerInspectionReply({
|
||
addressDebug: context.lastAnswerInspectionAddressDebug,
|
||
sessionItems: [
|
||
{
|
||
role: "assistant",
|
||
text: "По товару Рабочая станция покупатель определен: Комитет государственных услуг г. Москвы.\nДокументы выбытия:\n1. Реализация товаров и услуг | товар: Рабочая станция | контрагент: Комитет государственных услуг г. Москвы",
|
||
trace_id: "address-sale-trace",
|
||
debug: {
|
||
trace_id: "address-sale-trace",
|
||
execution_lane: "address_query",
|
||
answer_grounding_check: {
|
||
status: "grounded"
|
||
},
|
||
detected_intent: "inventory_sale_trace_for_item",
|
||
extracted_filters: {
|
||
item: "Рабочая станция",
|
||
organization: "ООО Альтернатива Плюс",
|
||
as_of_date: "2016-03-31"
|
||
}
|
||
}
|
||
}
|
||
],
|
||
toNonEmptyString: (value: unknown) => {
|
||
const text = String(value ?? "").trim();
|
||
return text.length > 0 ? text : null;
|
||
}
|
||
});
|
||
|
||
expect(context.contextualAnswerInspectionFollowup).toBe(true);
|
||
expect(reply).toContain("не контрагент");
|
||
expect(reply).toContain("Рабочая станция");
|
||
expect(reply).toContain("Комитет государственных услуг г. Москвы");
|
||
expect(reply).not.toContain("Покупатель в доступных данных отдельно не выделен");
|
||
});
|
||
|
||
it("builds deterministic recap summary from grounded MCP discovery counterparty context", () => {
|
||
const sessionItems = [
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "living_chat",
|
||
mcp_discovery_response_applied: true,
|
||
assistant_mcp_discovery_entry_point_v1: {
|
||
schema_version: "assistant_mcp_discovery_runtime_entry_point_v1",
|
||
entry_status: "bridge_executed",
|
||
turn_input: {
|
||
turn_meaning_ref: {
|
||
explicit_entity_candidates: ["Группа СВК"],
|
||
explicit_organization_scope: "ООО Альтернатива Плюс",
|
||
explicit_date_scope: "2020"
|
||
}
|
||
},
|
||
bridge: {
|
||
bridge_status: "answer_draft_ready",
|
||
business_fact_answer_allowed: true,
|
||
answer_draft: {
|
||
answer_mode: "confirmed_with_bounded_inference"
|
||
},
|
||
pilot: {
|
||
pilot_scope: "counterparty_bidirectional_value_flow_query_movements_v1",
|
||
derived_bidirectional_value_flow: {
|
||
net_amount_human_ru: "3 865 501,50 руб.",
|
||
incoming_customer_revenue: {
|
||
total_amount_human_ru: "47 628 853,03 руб."
|
||
},
|
||
outgoing_supplier_payout: {
|
||
total_amount_human_ru: "43 763 351,53 руб."
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
];
|
||
const context = resolveAssistantLivingChatMemoryContext({
|
||
modeDecisionReason: "memory_recap_followup_detected",
|
||
sessionItems
|
||
});
|
||
|
||
const reply = buildAddressMemoryRecapReply({
|
||
organization: null,
|
||
addressDebug: context.lastMemoryAddressDebug,
|
||
sessionItems,
|
||
toNonEmptyString: (value: unknown) => {
|
||
const text = String(value ?? "").trim();
|
||
return text.length > 0 ? text : null;
|
||
}
|
||
});
|
||
|
||
expect(context.contextualMemoryRecapFollowup).toBe(true);
|
||
expect(reply).toContain("Группа СВК");
|
||
expect(reply).toContain("нетто");
|
||
expect(reply).toContain("47 628 853,03 руб.");
|
||
expect(reply).toContain("43 763 351,53 руб.");
|
||
});
|
||
|
||
it("builds deterministic recap summary from grounded MCP metadata discovery context", () => {
|
||
const sessionItems = [
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "living_chat",
|
||
mcp_discovery_response_applied: true,
|
||
assistant_mcp_discovery_entry_point_v1: {
|
||
schema_version: "assistant_mcp_discovery_runtime_entry_point_v1",
|
||
entry_status: "bridge_executed",
|
||
turn_input: {
|
||
turn_meaning_ref: {
|
||
explicit_entity_candidates: ["НДС"]
|
||
}
|
||
},
|
||
bridge: {
|
||
bridge_status: "answer_draft_ready",
|
||
business_fact_answer_allowed: true,
|
||
answer_draft: {
|
||
answer_mode: "confirmed_with_bounded_inference"
|
||
},
|
||
pilot: {
|
||
pilot_scope: "metadata_inspection_v1",
|
||
derived_metadata_surface: {
|
||
metadata_scope: "НДС",
|
||
matched_rows: 7,
|
||
matched_objects: ["РегистрНакопления.НДСПокупок"],
|
||
available_entity_sets: ["accumulation_register", "document"],
|
||
available_fields: ["amount", "vat_rate", "organization"]
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
];
|
||
const context = resolveAssistantLivingChatMemoryContext({
|
||
modeDecisionReason: "memory_recap_followup_detected",
|
||
sessionItems
|
||
});
|
||
|
||
const reply = buildAddressMemoryRecapReply({
|
||
organization: null,
|
||
addressDebug: context.lastMemoryAddressDebug,
|
||
sessionItems,
|
||
toNonEmptyString: (value: unknown) => {
|
||
const text = String(value ?? "").trim();
|
||
return text.length > 0 ? text : null;
|
||
}
|
||
});
|
||
|
||
expect(context.contextualMemoryRecapFollowup).toBe(true);
|
||
expect(reply).toContain("НДС");
|
||
expect(reply).toContain("схему 1С");
|
||
expect(reply).toContain("amount");
|
||
expect(reply).toContain("accumulation_register");
|
||
});
|
||
|
||
it("builds deterministic broad business evaluation summary from recent grounded organization facts", () => {
|
||
const sessionItems = [
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "address_query",
|
||
answer_grounding_check: {
|
||
status: "grounded"
|
||
},
|
||
detected_intent: "counterparty_activity_lifecycle",
|
||
extracted_filters: {
|
||
organization: "ООО Альтернатива Плюс"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "living_chat",
|
||
mcp_discovery_response_applied: true,
|
||
assistant_mcp_discovery_entry_point_v1: {
|
||
schema_version: "assistant_mcp_discovery_runtime_entry_point_v1",
|
||
entry_status: "bridge_executed",
|
||
turn_input: {
|
||
turn_meaning_ref: {
|
||
explicit_entity_candidates: ["Группа СВК"],
|
||
explicit_organization_scope: "ООО Альтернатива Плюс",
|
||
explicit_date_scope: "2020"
|
||
}
|
||
},
|
||
bridge: {
|
||
bridge_status: "answer_draft_ready",
|
||
business_fact_answer_allowed: true,
|
||
answer_draft: {
|
||
answer_mode: "confirmed_with_bounded_inference"
|
||
},
|
||
pilot: {
|
||
pilot_scope: "counterparty_bidirectional_value_flow_query_movements_v1",
|
||
derived_bidirectional_value_flow: {
|
||
net_amount_human_ru: "3 865 501,50 руб.",
|
||
incoming_customer_revenue: {
|
||
total_amount_human_ru: "47 628 853,03 руб."
|
||
},
|
||
outgoing_supplier_payout: {
|
||
total_amount_human_ru: "43 763 351,53 руб."
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
];
|
||
|
||
const reply = buildBroadBusinessEvaluationReply({
|
||
organization: "ООО Альтернатива Плюс",
|
||
addressDebug: sessionItems[1].debug as any,
|
||
sessionItems,
|
||
toNonEmptyString: (value: unknown) => {
|
||
const text = String(value ?? "").trim();
|
||
return text.length > 0 ? text : null;
|
||
}
|
||
});
|
||
|
||
expect(reply.toLowerCase()).toContain("оценка бизнеса");
|
||
expect(reply).toContain("ООО Альтернатива Плюс");
|
||
expect(reply).toContain("47 628 853,03");
|
||
});
|
||
|
||
it("builds grounded answer inspection reply for MCP discovery net answer", () => {
|
||
const context = resolveAssistantLivingChatMemoryContext({
|
||
modeDecisionReason: "answer_inspection_followup_detected",
|
||
sessionItems: [
|
||
{
|
||
role: "assistant",
|
||
debug: {
|
||
execution_lane: "living_chat",
|
||
mcp_discovery_response_applied: true,
|
||
assistant_mcp_discovery_entry_point_v1: {
|
||
schema_version: "assistant_mcp_discovery_runtime_entry_point_v1",
|
||
entry_status: "bridge_executed",
|
||
turn_input: {
|
||
turn_meaning_ref: {
|
||
explicit_entity_candidates: ["Группа СВК"],
|
||
explicit_date_scope: "2020"
|
||
}
|
||
},
|
||
bridge: {
|
||
bridge_status: "answer_draft_ready",
|
||
business_fact_answer_allowed: true,
|
||
answer_draft: {
|
||
answer_mode: "confirmed_with_bounded_inference"
|
||
},
|
||
pilot: {
|
||
pilot_scope: "counterparty_bidirectional_value_flow_query_movements_v1"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
]
|
||
});
|
||
|
||
const reply = buildSelectedObjectAnswerInspectionReply({
|
||
addressDebug: context.lastAnswerInspectionAddressDebug,
|
||
toNonEmptyString: (value: unknown) => {
|
||
const text = String(value ?? "").trim();
|
||
return text.length > 0 ? text : null;
|
||
}
|
||
});
|
||
|
||
expect(context.contextualAnswerInspectionFollowup).toBe(true);
|
||
expect(reply).toContain("Группа СВК");
|
||
expect(reply).toContain("Нетто");
|
||
expect(reply).toContain("проверенному периоду");
|
||
});
|
||
});
|