146 lines
6.4 KiB
TypeScript
146 lines
6.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
||
import { createAssistantMetaFollowupPolicy } from "../src/services/assistantMetaFollowupPolicy";
|
||
|
||
const policy = createAssistantMetaFollowupPolicy({
|
||
hasAssistantDataScopeMetaQuestionSignal: (text: unknown) =>
|
||
/по какой компании|какая база/i.test(String(text ?? "")),
|
||
shouldHandleAsAssistantCapabilityMetaQuery: (text: unknown) =>
|
||
/что ты можешь|что ты умеешь/i.test(String(text ?? "")),
|
||
hasMetaAnswerFollowupSignal: (text: unknown) =>
|
||
/это норм|что думаешь/i.test(String(text ?? "")),
|
||
hasAnswerInspectionFollowupSignal: (text: unknown) =>
|
||
/это ошибка|у тебя написано кто контрагент/i.test(String(text ?? ""))
|
||
});
|
||
|
||
describe("assistantMetaFollowupPolicy", () => {
|
||
it("collects meta signals across message variants", () => {
|
||
const signals = policy.resolveMetaSignalSet({
|
||
rawUserMessage: "",
|
||
repairedRawUserMessage: "",
|
||
effectiveAddressUserMessage: "по какой компании мы можем работать?",
|
||
repairedEffectiveAddressUserMessage: ""
|
||
});
|
||
|
||
expect(signals.dataScopeMetaQuery).toBe(true);
|
||
expect(signals.capabilityMetaQuery).toBe(false);
|
||
expect(signals.metaAnswerFollowupSignal).toBe(false);
|
||
expect(signals.answerInspectionFollowupSignal).toBe(false);
|
||
});
|
||
|
||
it("treats historical capability phrasing as capability meta follow-up", () => {
|
||
const signals = policy.resolveMetaSignalSet({
|
||
rawUserMessage: "а исторические остатки тоже можешь?",
|
||
repairedRawUserMessage: "",
|
||
effectiveAddressUserMessage: "",
|
||
repairedEffectiveAddressUserMessage: ""
|
||
});
|
||
|
||
expect(signals.capabilityMetaQuery).toBe(true);
|
||
});
|
||
|
||
it("resolves hard meta mode with data retrieval guard", () => {
|
||
expect(
|
||
policy.resolveHardMetaMode({
|
||
dataScopeMetaQuery: true,
|
||
capabilityMetaQuery: false,
|
||
dataRetrievalSignal: false
|
||
})
|
||
).toBe("data_scope");
|
||
|
||
expect(
|
||
policy.resolveHardMetaMode({
|
||
dataScopeMetaQuery: false,
|
||
capabilityMetaQuery: true,
|
||
dataRetrievalSignal: true
|
||
})
|
||
).toBeNull();
|
||
});
|
||
|
||
it("detects 1C schema/catalog questions as data-scope meta even when base detector misses them", () => {
|
||
const signals = policy.resolveMetaSignalSet({
|
||
rawUserMessage:
|
||
"\u041a\u0430\u043a\u0438\u0435 \u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a\u0438 1\u0421 \u0435\u0441\u0442\u044c \u043f\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430\u043c?",
|
||
repairedRawUserMessage: "",
|
||
effectiveAddressUserMessage: "",
|
||
repairedEffectiveAddressUserMessage: ""
|
||
});
|
||
|
||
expect(signals.dataScopeMetaQuery).toBe(true);
|
||
expect(signals.capabilityMetaQuery).toBe(false);
|
||
});
|
||
|
||
it("detects document field/link questions as schema meta rather than fake counterparty documents", () => {
|
||
const signals = policy.resolveMetaSignalSet({
|
||
rawUserMessage:
|
||
"\u041a\u0430\u043a\u0438\u0435 \u043f\u043e\u043b\u044f \u0438 \u0441\u0432\u044f\u0437\u0438 \u0441\u0442\u043e\u0438\u0442 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0443 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f?",
|
||
repairedRawUserMessage: "",
|
||
effectiveAddressUserMessage: "",
|
||
repairedEffectiveAddressUserMessage: ""
|
||
});
|
||
|
||
expect(signals.dataScopeMetaQuery).toBe(true);
|
||
expect(signals.capabilityMetaQuery).toBe(false);
|
||
});
|
||
|
||
it("does not turn debt classification wording into capability meta help", () => {
|
||
const noisyPolicy = createAssistantMetaFollowupPolicy({
|
||
hasAssistantDataScopeMetaQuestionSignal: () => false,
|
||
shouldHandleAsAssistantCapabilityMetaQuery: () => true,
|
||
hasMetaAnswerFollowupSignal: () => false,
|
||
hasAnswerInspectionFollowupSignal: () => false
|
||
});
|
||
|
||
const signals = noisyPolicy.resolveMetaSignalSet({
|
||
rawUserMessage:
|
||
"\u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0440\u043e\u0447\u043a\u043e\u0439 \u0438\u043b\u0438 \u043f\u043e\u043a\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u0439 \u0437\u0430\u0434\u043e\u043b\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u044c\u044e?",
|
||
repairedRawUserMessage: "",
|
||
effectiveAddressUserMessage: "",
|
||
repairedEffectiveAddressUserMessage: ""
|
||
});
|
||
|
||
expect(signals.capabilityMetaQuery).toBe(false);
|
||
});
|
||
|
||
it("detects evaluative meta follow-up over grounded answer", () => {
|
||
const detected = policy.isMetaFollowupOverGroundedAnswer({
|
||
followupContext: { previous_intent: "vat_payable_forecast" },
|
||
hasPriorAddressAnswerContext: true,
|
||
metaAnswerFollowupSignal: true,
|
||
vatEvaluativeFollowupSignal: false,
|
||
dataScopeMetaQuery: false,
|
||
capabilityMetaQuery: false,
|
||
aggregateBusinessAnalyticsSignal: false,
|
||
dataRetrievalSignal: false,
|
||
strongDataSignal: false,
|
||
resolvedMode: "unsupported",
|
||
resolvedIntent: "unknown",
|
||
llmContractIntent: "unknown",
|
||
llmContractMode: "unsupported"
|
||
});
|
||
|
||
expect(detected).toBe(true);
|
||
});
|
||
|
||
it("detects answer inspection follow-up over grounded answer", () => {
|
||
const signals = policy.resolveMetaSignalSet({
|
||
rawUserMessage: "у тебя написано кто контрагент: рабочая станция - это ошибка?",
|
||
repairedRawUserMessage: "",
|
||
effectiveAddressUserMessage: "",
|
||
repairedEffectiveAddressUserMessage: ""
|
||
});
|
||
|
||
expect(signals.answerInspectionFollowupSignal).toBe(true);
|
||
|
||
const detected = policy.isAnswerInspectionFollowupOverGroundedAnswer({
|
||
followupContext: { previous_intent: "inventory_sale_trace_for_item", previous_anchor_type: "item" },
|
||
hasPriorAddressAnswerContext: true,
|
||
answerInspectionFollowupSignal: true,
|
||
dataScopeMetaQuery: false,
|
||
capabilityMetaQuery: false,
|
||
aggregateBusinessAnalyticsSignal: false
|
||
});
|
||
|
||
expect(detected).toBe(true);
|
||
});
|
||
});
|