ДОМЕНЫ - ВОПРОСЫ - СКЛАД - Склад: усилить follow-up оркестрацию и business-first формат ответов
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const { executeAddressMcpQueryMock } = vi.hoisted(() => ({
|
||||
executeAddressMcpQueryMock: vi.fn()
|
||||
}));
|
||||
|
||||
vi.mock("../src/services/addressMcpClient", async () => {
|
||||
const actual = await vi.importActual<typeof import("../src/services/addressMcpClient")>(
|
||||
"../src/services/addressMcpClient"
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
executeAddressMcpQuery: executeAddressMcpQueryMock
|
||||
};
|
||||
});
|
||||
|
||||
import { AddressQueryService } from "../src/services/addressQueryService";
|
||||
|
||||
afterEach(() => {
|
||||
executeAddressMcpQueryMock.mockReset();
|
||||
});
|
||||
|
||||
describe("inventory purchase-date selected-object follow-up", () => {
|
||||
it("routes short 'когда' follow-up to purchase provenance and reuses the active item", async () => {
|
||||
executeAddressMcpQueryMock.mockResolvedValueOnce({
|
||||
fetched_rows: 1,
|
||||
matched_rows: 1,
|
||||
raw_rows: [
|
||||
{
|
||||
Period: "2020-02-11T00:00:00Z",
|
||||
Registrator: "Поступление товаров и услуг 00000000077 от 11.02.2020 0:00:00",
|
||||
AccountDt: "41.01",
|
||||
AccountKt: "60.01",
|
||||
Amount: 165.83,
|
||||
SubcontoDt1: "Кромка с клеем 33 альмяндин 137 м",
|
||||
SubcontoDt3: "Основной склад",
|
||||
SubcontoKt1: "Торговый дом \\Союз МСК\\",
|
||||
SubcontoKt2: "Договор поставки № 12 от 01.02.2020",
|
||||
Organization: "ООО \\Альтернатива Плюс\\"
|
||||
}
|
||||
],
|
||||
rows: [],
|
||||
error: null
|
||||
});
|
||||
|
||||
const service = new AddressQueryService();
|
||||
const result = await service.tryHandle("когда", {
|
||||
followupContext: {
|
||||
previous_intent: "inventory_purchase_provenance_for_item",
|
||||
previous_filters: {
|
||||
item: "Кромка с клеем 33 альмяндин 137 м",
|
||||
warehouse: "Основной склад",
|
||||
as_of_date: "2020-03-31"
|
||||
},
|
||||
previous_anchor_type: "unknown",
|
||||
previous_anchor_value: null
|
||||
}
|
||||
});
|
||||
|
||||
expect(result?.handled).toBe(true);
|
||||
expect(result?.response_type).toBe("FACTUAL_SUMMARY");
|
||||
expect(result?.debug.detected_intent).toBe("inventory_purchase_provenance_for_item");
|
||||
expect(result?.debug.extracted_filters?.item).toBe("Кромка с клеем 33 альмяндин 137 м");
|
||||
expect(result?.debug.extracted_filters?.as_of_date).toBe("2020-03-31");
|
||||
const replyLines = String(result?.reply_text ?? "").split("\n");
|
||||
expect(replyLines[0]).toContain("11.02.2020");
|
||||
expect(replyLines[0]).toContain("Кромка");
|
||||
expect(String(result?.reply_text ?? "")).not.toContain("Блок 1");
|
||||
expect(String(result?.reply_text ?? "")).toContain("Подтверждение");
|
||||
expect(result?.debug.reasons).toContain("address_followup_context_applied");
|
||||
});
|
||||
|
||||
it("routes bare 'когда' follow-up to purchase provenance with the carried active item", async () => {
|
||||
executeAddressMcpQueryMock.mockResolvedValueOnce({
|
||||
fetched_rows: 1,
|
||||
matched_rows: 1,
|
||||
raw_rows: [
|
||||
{
|
||||
Period: "2019-02-12T00:00:00Z",
|
||||
Registrator: "Поступление товаров и услуг 00000000003 от 12.02.2019 0:00:00",
|
||||
AccountDt: "41.01",
|
||||
AccountKt: "60.01",
|
||||
Amount: 3724.17,
|
||||
SubcontoDt1: "Столешница 600*3050*26 дуб ниагара",
|
||||
SubcontoDt3: "Основной склад",
|
||||
SubcontoKt1: "Торговый дом \\Союз МСК\\",
|
||||
SubcontoKt2: "Договор поставки № 12 от 01.02.2019",
|
||||
Organization: "ООО \\Альтернатива Плюс\\"
|
||||
}
|
||||
],
|
||||
rows: [],
|
||||
error: null
|
||||
});
|
||||
|
||||
const service = new AddressQueryService();
|
||||
const result = await service.tryHandle("когда", {
|
||||
followupContext: {
|
||||
previous_intent: "inventory_purchase_provenance_for_item",
|
||||
previous_filters: {
|
||||
item: "Столешница 600*3050*26 дуб ниагара",
|
||||
warehouse: "Основной склад",
|
||||
as_of_date: "2019-03-31"
|
||||
},
|
||||
previous_anchor_type: "unknown",
|
||||
previous_anchor_value: null
|
||||
}
|
||||
});
|
||||
|
||||
expect(result?.handled).toBe(true);
|
||||
expect(result?.debug.detected_intent).toBe("inventory_purchase_provenance_for_item");
|
||||
expect(result?.debug.extracted_filters?.item).toBe("Столешница 600*3050*26 дуб ниагара");
|
||||
expect(result?.debug.extracted_filters?.as_of_date).toBe("2019-03-31");
|
||||
expect(String(result?.reply_text ?? "").split("\n")[0]).toContain("12.02.2019");
|
||||
expect(String(result?.reply_text ?? "")).not.toContain("Блок 1");
|
||||
});
|
||||
|
||||
it("routes 'когда примерно мы купили' follow-up to compact purchase-date answer with the carried item", async () => {
|
||||
executeAddressMcpQueryMock.mockResolvedValueOnce({
|
||||
fetched_rows: 1,
|
||||
matched_rows: 1,
|
||||
raw_rows: [
|
||||
{
|
||||
Period: "2020-02-11T00:00:00Z",
|
||||
Registrator: "Поступление товаров и услуг 00000000077 от 11.02.2020 0:00:00",
|
||||
AccountDt: "41.01",
|
||||
AccountKt: "60.01",
|
||||
Amount: 833.33,
|
||||
SubcontoDt1: "Четки Пост (84*117)",
|
||||
SubcontoDt3: "Основной склад",
|
||||
SubcontoKt1: "Торговый дом \\Союз МСК\\",
|
||||
SubcontoKt2: "Договор поставки № 12 от 01.02.2020",
|
||||
Organization: "ООО \\Альтернатива Плюс\\"
|
||||
}
|
||||
],
|
||||
rows: [],
|
||||
error: null
|
||||
});
|
||||
|
||||
const service = new AddressQueryService();
|
||||
const result = await service.tryHandle("когда примерно мы купили?", {
|
||||
followupContext: {
|
||||
previous_intent: "inventory_purchase_provenance_for_item",
|
||||
previous_filters: {
|
||||
item: "Четки Пост (84*117)",
|
||||
warehouse: "Основной склад",
|
||||
as_of_date: "2020-03-31"
|
||||
},
|
||||
previous_anchor_type: "unknown",
|
||||
previous_anchor_value: null
|
||||
}
|
||||
});
|
||||
|
||||
expect(result?.handled).toBe(true);
|
||||
expect(result?.debug.detected_intent).toBe("inventory_purchase_provenance_for_item");
|
||||
expect(result?.debug.extracted_filters?.item).toBe("Четки Пост (84*117)");
|
||||
expect(result?.debug.extracted_filters?.as_of_date).toBe("2020-03-31");
|
||||
expect(String(result?.reply_text ?? "").split("\n")[0]).toContain("11.02.2020");
|
||||
expect(String(result?.reply_text ?? "")).toContain("Подтверждение");
|
||||
expect(String(result?.reply_text ?? "")).not.toContain("Блок 1");
|
||||
});
|
||||
});
|
||||
@@ -206,4 +206,51 @@ describe("inventory selected-object follow-up", () => {
|
||||
expect(result?.debug.extracted_filters?.as_of_date).toBe("2019-03-31");
|
||||
expect(String(result?.reply_text ?? "")).toContain("Поступление товаров и услуг 00000000077");
|
||||
});
|
||||
|
||||
it("routes buyer follow-up over the same selected item into sale trace instead of replaying provenance", async () => {
|
||||
executeAddressMcpQueryMock.mockResolvedValueOnce({
|
||||
fetched_rows: 1,
|
||||
matched_rows: 1,
|
||||
raw_rows: [
|
||||
{
|
||||
Period: "2020-04-12T00:00:00Z",
|
||||
Registrator: "Реализация товаров и услуг 00000000112 от 12.04.2020 0:00:00",
|
||||
AccountDt: "90.02",
|
||||
AccountKt: "41.01",
|
||||
Amount: 833.33,
|
||||
SubcontoKt1: "Четки Пост (84*117)",
|
||||
SubcontoKt3: "Основной склад",
|
||||
SubcontoDt1: "ИП Покупатель",
|
||||
Organization: "ООО \\Альтернатива Плюс\\"
|
||||
}
|
||||
],
|
||||
rows: [],
|
||||
error: null
|
||||
});
|
||||
|
||||
const service = new AddressQueryService();
|
||||
const result = await service.tryHandle("кому в итоге мы продали этот товар?", {
|
||||
followupContext: {
|
||||
previous_intent: "inventory_purchase_provenance_for_item",
|
||||
previous_filters: {
|
||||
as_of_date: "2020-03-31",
|
||||
period_from: "2020-03-01",
|
||||
period_to: "2020-03-31",
|
||||
item: "Четки Пост (84*117)",
|
||||
warehouse: "Основной склад"
|
||||
},
|
||||
previous_anchor_type: "unknown",
|
||||
previous_anchor_value: null
|
||||
}
|
||||
});
|
||||
|
||||
expect(result?.handled).toBe(true);
|
||||
expect(result?.response_type).toBe("FACTUAL_LIST");
|
||||
expect(result?.debug.detected_intent).toBe("inventory_sale_trace_for_item");
|
||||
expect(result?.debug.selected_recipe).toBe("address_inventory_sale_trace_for_item_v1");
|
||||
expect(result?.debug.extracted_filters?.item).toBe("Четки Пост (84*117)");
|
||||
expect(result?.debug.extracted_filters?.as_of_date).toBe("2020-03-31");
|
||||
expect(String(result?.reply_text ?? "").split("\n")[0]).toContain("ИП Покупатель");
|
||||
expect(String(result?.reply_text ?? "")).toContain("Документы выбытия");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -111,4 +111,37 @@ describe("address navigation state", () => {
|
||||
expect(evolved.session_context.date_scope.period_from).toBe("2020-01-01");
|
||||
expect(evolved.session_context.date_scope.period_to).toBe("2020-12-31");
|
||||
});
|
||||
|
||||
it("captures item focus from inventory answers when no anchor is materialized", () => {
|
||||
const base = createEmptyAddressNavigationState("asst-4", "2026-04-12T10:00:00.000Z");
|
||||
const assistantItem = {
|
||||
message_id: "msg-a3",
|
||||
session_id: "asst-4",
|
||||
role: "assistant",
|
||||
text: "Собран подтвержденный закупочный след по товару Диван трехместный до 14.04.2026.\n\n1. Авансовый отчет 00000000004 от 24.08.2018 12:00:04 | дата: 24.08.2018 | сумма: 34.490,00 ₽ | склад: Основной склад",
|
||||
reply_type: "factual",
|
||||
created_at: "2026-04-12T10:03:00.000Z",
|
||||
trace_id: "address-789",
|
||||
debug: {
|
||||
detected_mode: "address_query",
|
||||
detected_intent: "inventory_purchase_provenance_for_item",
|
||||
selected_recipe: "address_inventory_purchase_provenance_for_item_v1",
|
||||
extracted_filters: {
|
||||
item: "Диван трехместный",
|
||||
warehouse: "Основной склад",
|
||||
as_of_date: "2026-04-14"
|
||||
},
|
||||
anchor_type: "unknown",
|
||||
anchor_value_resolved: null,
|
||||
anchor_value_raw: null,
|
||||
dialog_continuation_contract_v2: {
|
||||
decision: "new_topic"
|
||||
}
|
||||
}
|
||||
} as any;
|
||||
|
||||
const evolved = evolveAddressNavigationStateWithAssistantItem(base, assistantItem, 3);
|
||||
expect(evolved.session_context.active_focus_object?.label).toBe("Диван трехместный");
|
||||
expect(evolved.session_context.active_focus_object?.provenance_result_set_id).toBe("rs-msg-a3");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -293,7 +293,7 @@ describe("address query shape classifier", () => {
|
||||
useRubCurrency: true
|
||||
}
|
||||
);
|
||||
expect(reply.text.split("\n")[0]).toContain("поставщиком");
|
||||
expect(reply.text.split("\n")[0]).toContain("документов закупки");
|
||||
expect(reply.text).toContain("Шкаф картотечный");
|
||||
expect(reply.text).toContain("Поступление товаров и услуг 0001");
|
||||
expect(reply.semantics?.result_mode).toBe("confirmed_balance");
|
||||
@@ -321,7 +321,8 @@ describe("address query shape classifier", () => {
|
||||
}
|
||||
);
|
||||
expect(reply.text.split("\n")[0]).toContain("поставщиком");
|
||||
expect(reply.text).toContain("закупочный след");
|
||||
expect(reply.text).toContain("Подтверждение");
|
||||
expect(reply.text).not.toContain("Блок 1");
|
||||
expect(reply.text).toContain("Гамма-мебель, ООО");
|
||||
expect(reply.semantics?.balance_confirmed).toBe(true);
|
||||
});
|
||||
@@ -348,7 +349,8 @@ describe("address query shape classifier", () => {
|
||||
}
|
||||
);
|
||||
expect(reply.text.split("\n")[0]).toContain("покупатель");
|
||||
expect(reply.text).toContain("след выбытия");
|
||||
expect(reply.text).toContain("Документы выбытия");
|
||||
expect(reply.text).not.toContain("Блок 1");
|
||||
expect(reply.text).toContain("Реализация товаров и услуг 0007");
|
||||
expect(reply.text).toContain("Департамент капитального ремонта города Москвы");
|
||||
});
|
||||
@@ -385,7 +387,7 @@ describe("address query shape classifier", () => {
|
||||
useRubCurrency: true
|
||||
}
|
||||
);
|
||||
expect(reply.text).toContain("документальная цепочка");
|
||||
expect(reply.text.split("\n")[0]).toContain("цепочка поставки и продажи");
|
||||
expect(reply.text).toContain("Поступление товаров и услуг 0001");
|
||||
expect(reply.text).toContain("Реализация товаров и услуг 0007");
|
||||
expect(reply.semantics?.result_mode).toBe("confirmed_balance");
|
||||
@@ -3968,10 +3970,28 @@ describe("address decompose stage follow-up carryover", () => {
|
||||
expect(result?.filters.extracted_filters.as_of_date).toBe("2019-03-31");
|
||||
expect(
|
||||
result?.baseReasons?.includes("intent_adjusted_to_inventory_followup_context") ||
|
||||
result?.intent.reasons.includes("inventory_selected_object_purchase_documents_signal_detected")
|
||||
result?.intent.reasons.includes("inventory_selected_object_purchase_documents_signal_detected")
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("promotes conversational buyer follow-up into inventory sale trace with inherited date context", () => {
|
||||
const result = runAddressDecomposeStage("кому в итоге мы продали этот товар?", {
|
||||
previous_intent: "inventory_purchase_provenance_for_item",
|
||||
previous_filters: {
|
||||
as_of_date: "2020-03-31",
|
||||
period_from: "2020-03-01",
|
||||
period_to: "2020-03-31",
|
||||
item: "Четки Пост (84*117)"
|
||||
},
|
||||
previous_anchor_type: "unknown",
|
||||
previous_anchor_value: null
|
||||
});
|
||||
expect(result).not.toBeNull();
|
||||
expect(result?.intent.intent).toBe("inventory_sale_trace_for_item");
|
||||
expect(result?.filters.extracted_filters.item).toBe("Четки Пост (84*117)");
|
||||
expect(result?.filters.extracted_filters.as_of_date).toBe("2020-03-31");
|
||||
});
|
||||
|
||||
it("keeps slang all-customers-all-time wording in address lane via resolved intent fallback", () => {
|
||||
const result = runAddressDecomposeStage("выведи всех заков за все время", null);
|
||||
expect(result).not.toBeNull();
|
||||
@@ -4791,8 +4811,9 @@ it("routes old purchase residue questions to aging-by-purchase-date", () => {
|
||||
);
|
||||
|
||||
expect(reply.responseType).toBe("FACTUAL_LIST");
|
||||
expect(reply.text).toContain("Собран подтвержденный срез товаров на складах");
|
||||
expect(reply.text.split("\n")[0]).toContain("На 31.03.2020 на складе подтверждено");
|
||||
expect(reply.text).toContain("Контур: остатки по счету 41.01");
|
||||
expect(reply.text).not.toContain("Блок 1");
|
||||
expect(reply.text).toContain("Шкаф картотечный");
|
||||
expect(reply.text).toContain("Основной склад");
|
||||
expect(reply.semantics?.result_mode).toBe("confirmed_balance");
|
||||
@@ -4828,6 +4849,11 @@ it("routes old purchase residue questions to aging-by-purchase-date", () => {
|
||||
expect(result.intent).toBe("inventory_purchase_to_sale_chain");
|
||||
});
|
||||
|
||||
it("routes conversational buyer wording to inventory sale trace intent", () => {
|
||||
const result = resolveAddressIntent("Кому в итоге мы продали товар Шкаф картоотечный?");
|
||||
expect(result.intent).toBe("inventory_sale_trace_for_item");
|
||||
});
|
||||
|
||||
it("keeps inventory provenance wording out of inventory-on-hand routing", () => {
|
||||
const result = resolveAddressIntent("От кого куплен товар Шкаф картоотечный и когда был куплен?");
|
||||
expect(result.intent).toBe("inventory_purchase_provenance_for_item");
|
||||
|
||||
@@ -278,6 +278,101 @@ describe("assistant address follow-up carryover", () => {
|
||||
expect(normalizerService.normalize).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("treats bare 'когда' as a selected-item inventory follow-up for the active provenance object", async () => {
|
||||
const calls: Array<{ message: string; options?: any }> = [];
|
||||
const followupMessage = "когда";
|
||||
const provenanceResult = {
|
||||
handled: true,
|
||||
reply_text: "Товар Столешница 600*3050*26 дуб ниагара по доступным закупочным движениям связан с поставщиком: Торговый дом \\Союз\\.",
|
||||
reply_type: "factual",
|
||||
response_type: "FACTUAL_SUMMARY",
|
||||
debug: {
|
||||
detected_mode: "address_query",
|
||||
detected_intent: "inventory_purchase_provenance_for_item",
|
||||
detected_intent_confidence: "high",
|
||||
extracted_filters: {
|
||||
item: "Столешница 600*3050*26 дуб ниагара",
|
||||
warehouse: "Основной склад",
|
||||
as_of_date: "2019-03-31"
|
||||
},
|
||||
missing_required_filters: [],
|
||||
selected_recipe: "address_inventory_purchase_provenance_for_item_v1",
|
||||
anchor_type: "unknown",
|
||||
anchor_value_raw: null,
|
||||
anchor_value_resolved: null,
|
||||
reasons: ["address_action_detected", "address_entity_detected"],
|
||||
dialog_continuation_contract_v2: {
|
||||
decision: "continue_previous"
|
||||
}
|
||||
}
|
||||
} as any;
|
||||
|
||||
const addressQueryService = {
|
||||
tryHandle: vi.fn(async (message: string, options?: any) => {
|
||||
calls.push({ message, options });
|
||||
if (message === followupMessage && !options?.followupContext) {
|
||||
return null;
|
||||
}
|
||||
if (message === followupMessage && options?.followupContext) {
|
||||
return {
|
||||
...provenanceResult,
|
||||
reply_text: "Позиция Столешница 600*3050*26 дуб ниагара куплена 12.02.2019.\n\nПодтверждение:\n- Первый подтверждающий документ: Поступление товаров и услуг 00000000003 от 12.02.2019.",
|
||||
debug: {
|
||||
...provenanceResult.debug,
|
||||
reasons: ["address_action_detected", "address_entity_detected", "address_followup_context_applied"]
|
||||
}
|
||||
};
|
||||
}
|
||||
return provenanceResult;
|
||||
})
|
||||
} 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-when-${Date.now()}`;
|
||||
sessions.appendItem(sessionId, {
|
||||
message_id: "msg-inventory-provenance-seed",
|
||||
session_id: sessionId,
|
||||
role: "assistant",
|
||||
text: provenanceResult.reply_text,
|
||||
reply_type: provenanceResult.reply_type,
|
||||
created_at: "2026-04-14T18:00:00.000Z",
|
||||
trace_id: "address-seed",
|
||||
debug: provenanceResult.debug
|
||||
} as any);
|
||||
|
||||
const second = await service.handleMessage({
|
||||
session_id: sessionId,
|
||||
user_message: followupMessage,
|
||||
useMock: true
|
||||
} as any);
|
||||
|
||||
expect(second.ok).toBe(true);
|
||||
expect(second.reply_type).toBe("factual");
|
||||
expect(calls).toHaveLength(1);
|
||||
expect(calls[0].message).toBe(followupMessage);
|
||||
expect(calls[0].options?.followupContext?.previous_intent).toBe("inventory_purchase_provenance_for_item");
|
||||
expect(calls[0].options?.followupContext?.previous_filters?.item).toBe("Столешница 600*3050*26 дуб ниагара");
|
||||
expect(calls[0].options?.followupContext?.previous_filters?.warehouse).toBe("Основной склад");
|
||||
expect(calls[0].options?.followupContext?.previous_filters?.as_of_date).toBe("2019-03-31");
|
||||
expect(normalizerService.normalize).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("treats typo imperative 'показывыай' as implicit continuation and switches to suggested follow-up intent", async () => {
|
||||
const calls: Array<{ message: string; options?: any }> = [];
|
||||
const firstMessage = "покажи документы по свк за 2020";
|
||||
|
||||
@@ -259,7 +259,7 @@ describe("assistant orchestration contract", () => {
|
||||
|
||||
expect(decision.runAddressLane).toBe(true);
|
||||
expect(decision.toolGateDecision).toBe("run_address_lane");
|
||||
expect(decision.toolGateReason).toBe("address_mode_classifier_detected");
|
||||
expect(["address_mode_classifier_detected", "address_intent_resolver_detected"]).toContain(String(decision.toolGateReason));
|
||||
expect(decision.livingMode).toBe("address_data");
|
||||
expect(decision.livingReason).toBe("address_lane_triggered");
|
||||
});
|
||||
@@ -289,7 +289,44 @@ describe("assistant orchestration contract", () => {
|
||||
|
||||
expect(decision.runAddressLane).toBe(true);
|
||||
expect(decision.toolGateDecision).toBe("run_address_lane");
|
||||
expect(decision.toolGateReason).toBe("address_mode_classifier_detected");
|
||||
expect(["address_mode_classifier_detected", "address_intent_resolver_detected"]).toContain(String(decision.toolGateReason));
|
||||
expect(decision.livingMode).toBe("address_data");
|
||||
expect(decision.livingReason).toBe("address_lane_triggered");
|
||||
});
|
||||
|
||||
it("keeps short inventory follow-up 'когда' in address lane when a selected-item provenance context exists", () => {
|
||||
const decision = resolveAssistantOrchestrationDecision({
|
||||
rawUserMessage: "когда",
|
||||
effectiveAddressUserMessage: "когда",
|
||||
followupContext: {
|
||||
previous_intent: "inventory_purchase_provenance_for_item",
|
||||
previous_filters: {
|
||||
item: "Столешница 600*3050*26 дуб ниагара",
|
||||
warehouse: "Основной склад",
|
||||
as_of_date: "2019-03-31"
|
||||
}
|
||||
},
|
||||
llmPreDecomposeMeta: {
|
||||
applied: false,
|
||||
reason: "normalized_fragment_rejected_semantic_guard",
|
||||
llmCanonicalCandidateDetected: true,
|
||||
predecomposeContract: {
|
||||
mode: "unsupported",
|
||||
mode_confidence: "low",
|
||||
intent: "unknown",
|
||||
intent_confidence: "low"
|
||||
},
|
||||
semanticExtractionContract: {
|
||||
valid: false,
|
||||
apply_canonical_recommended: false,
|
||||
reason_codes: ["unsupported_low_confidence_contract"]
|
||||
}
|
||||
} as any,
|
||||
useMock: false
|
||||
});
|
||||
|
||||
expect(decision.runAddressLane).toBe(true);
|
||||
expect(decision.toolGateDecision).toBe("run_address_lane");
|
||||
expect(decision.livingMode).toBe("address_data");
|
||||
expect(decision.livingReason).toBe("address_lane_triggered");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user