ARCH: удержать counterparty scope после contracts pivot в payments
This commit is contained in:
@@ -1496,6 +1496,125 @@ describe("assistant address follow-up carryover", () => {
|
||||
expect(String(calls[0].message).toLowerCase()).toContain("свк");
|
||||
expect(chatClient.chat).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
it("keeps counterparty scope when pivoting from contracts list to payments by pronoun", async () => {
|
||||
const calls: Array<{ message: string; options?: any }> = [];
|
||||
const firstMessage = "Покажи документы по Жуковке 51.";
|
||||
const secondMessage = "А по нему договоры?";
|
||||
const thirdMessage = "А по нему платежи?";
|
||||
|
||||
const addressQueryService = {
|
||||
tryHandle: vi.fn(async (message: string, options?: any) => {
|
||||
calls.push({ message, options });
|
||||
const normalizedMessage = String(message ?? "").toLowerCase();
|
||||
if (normalizedMessage.includes("документ") && normalizedMessage.includes("жуков")) {
|
||||
return buildAddressLaneResult({
|
||||
reply_text: "Собран список документов по контрагенту ТСЖ \\Жуковка 51\\.",
|
||||
debug: {
|
||||
...buildAddressLaneResult().debug,
|
||||
detected_intent: "list_documents_by_counterparty",
|
||||
selected_recipe: "address_documents_by_counterparty_v1",
|
||||
extracted_filters: {
|
||||
counterparty: "ТСЖ \\Жуковка 51\\"
|
||||
},
|
||||
anchor_type: "counterparty",
|
||||
anchor_value_raw: "Жуковке 51",
|
||||
anchor_value_resolved: "ТСЖ \\Жуковка 51\\",
|
||||
reasons: ["documents_by_counterparty_signal_detected"]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (normalizedMessage.includes("договор")) {
|
||||
return buildAddressLaneResult({
|
||||
reply_text: [
|
||||
"Коротко: найдено 1 договоров по контрагенту.",
|
||||
"Контрагент: ТСЖ \\Жуковка 51\\.",
|
||||
"1. Счет № 5 от 05.04.2017"
|
||||
].join("\n"),
|
||||
debug: {
|
||||
...buildAddressLaneResult().debug,
|
||||
detected_intent: "list_contracts_by_counterparty",
|
||||
selected_recipe: "address_contracts_by_counterparty_v1",
|
||||
extracted_filters: {
|
||||
counterparty: "ТСЖ \\Жуковка 51\\"
|
||||
},
|
||||
anchor_type: "counterparty",
|
||||
anchor_value_raw: "нему",
|
||||
anchor_value_resolved: "ТСЖ \\Жуковка 51\\",
|
||||
reasons: ["contracts_by_counterparty_signal_detected", "address_followup_context_applied"]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (normalizedMessage.includes("плат") || normalizedMessage.includes("банк")) {
|
||||
return buildAddressLaneResult({
|
||||
reply_text: "Собран список банковских операций по контрагенту ТСЖ \\Жуковка 51\\.",
|
||||
debug: {
|
||||
...buildAddressLaneResult().debug,
|
||||
detected_intent: "bank_operations_by_counterparty",
|
||||
selected_recipe: "address_bank_operations_by_counterparty_v1",
|
||||
extracted_filters: {
|
||||
counterparty: "ТСЖ \\Жуковка 51\\"
|
||||
},
|
||||
anchor_type: "counterparty",
|
||||
anchor_value_raw: "нему",
|
||||
anchor_value_resolved: "ТСЖ \\Жуковка 51\\",
|
||||
reasons: ["bank_operations_by_counterparty_signal_detected", "address_followup_context_applied"]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
} as any;
|
||||
|
||||
const normalizerService = {
|
||||
normalize: vi.fn(async () => ({
|
||||
assistant_reply: "normalizer_fallback_should_not_be_used",
|
||||
reply_type: "partial_coverage",
|
||||
debug: {}
|
||||
}))
|
||||
} as any;
|
||||
|
||||
const sessions = new AssistantSessionStore();
|
||||
const service = new AssistantService(
|
||||
normalizerService,
|
||||
sessions as any,
|
||||
{} as any,
|
||||
{ persistSession: vi.fn() } as any,
|
||||
addressQueryService
|
||||
);
|
||||
|
||||
const sessionId = `asst-address-followup-contracts-payments-${Date.now()}`;
|
||||
const first = await service.handleMessage({
|
||||
session_id: sessionId,
|
||||
user_message: firstMessage,
|
||||
useMock: true
|
||||
} as any);
|
||||
expect(first.ok).toBe(true);
|
||||
expect(first.reply_type).toBe("factual");
|
||||
|
||||
const second = await service.handleMessage({
|
||||
session_id: sessionId,
|
||||
user_message: secondMessage,
|
||||
useMock: true
|
||||
} as any);
|
||||
expect(second.ok).toBe(true);
|
||||
expect(second.reply_type).toBe("factual");
|
||||
expect(second.debug?.detected_intent).toBe("list_contracts_by_counterparty");
|
||||
|
||||
const third = await service.handleMessage({
|
||||
session_id: sessionId,
|
||||
user_message: thirdMessage,
|
||||
useMock: true
|
||||
} as any);
|
||||
expect(third.ok).toBe(true);
|
||||
expect(third.reply_type).toBe("factual");
|
||||
expect(third.debug?.detected_intent).toBe("bank_operations_by_counterparty");
|
||||
expect(third.debug?.dialog_continuation_contract_v2?.target_intent).toBe("bank_operations_by_counterparty");
|
||||
expect(normalizerService.normalize).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("keeps debt lifecycle follow-up context for 'а нам кто должен?.' after payables as-of answer", async () => {
|
||||
const calls: Array<{ message: string; options?: any }> = [];
|
||||
const firstMessage =
|
||||
|
||||
Reference in New Issue
Block a user