АРЧ АП11 - Вынести living-chat boundary policy из assistantService в отдельный модуль
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createAssistantBoundaryPolicy } from "../src/services/assistantBoundaryPolicy";
|
||||
|
||||
function createPolicy() {
|
||||
return createAssistantBoundaryPolicy({
|
||||
activeMcpChannel: "default",
|
||||
normalizeOrganizationScopeValue: (value: unknown) => {
|
||||
if (value === null || value === undefined) {
|
||||
return null;
|
||||
}
|
||||
const text = String(value ?? "").trim();
|
||||
return text.length > 0 ? text : null;
|
||||
},
|
||||
toNonEmptyString: (value: unknown) => {
|
||||
if (value === null || value === undefined) {
|
||||
return null;
|
||||
}
|
||||
const text = String(value ?? "").trim();
|
||||
return text.length > 0 ? text : null;
|
||||
},
|
||||
hasOrganizationFactLookupSignal: (message: string) => /возраст|дата регистрации/i.test(message)
|
||||
});
|
||||
}
|
||||
|
||||
describe("assistantBoundaryPolicy", () => {
|
||||
it("builds deterministic data-scope reply for single organization", () => {
|
||||
const policy = createPolicy();
|
||||
|
||||
const reply = policy.buildAssistantDataScopeContractReply({
|
||||
status: "resolved",
|
||||
channel: "finance",
|
||||
organizations: ["ООО Альтернатива Плюс"]
|
||||
});
|
||||
|
||||
expect(reply).toContain("MCP-канале `finance`");
|
||||
expect(reply).toContain("ООО Альтернатива Плюс");
|
||||
expect(reply.toLowerCase()).toContain("read-only");
|
||||
});
|
||||
|
||||
it("strips unexpected CJK fragments from live chat reply", () => {
|
||||
const policy = createPolicy();
|
||||
|
||||
const guarded = policy.applyLivingChatScriptGuard(
|
||||
"Прошу прощения, но я не могу продолжать этот разговор. 随时关注。",
|
||||
"че как"
|
||||
);
|
||||
|
||||
expect(guarded.applied).toBe(true);
|
||||
expect(guarded.reason).toBe("unexpected_cjk_fragment_stripped");
|
||||
expect(guarded.text).toContain("Прошу прощения");
|
||||
expect(/[\u3400-\u9FFF\uF900-\uFAFF]/u.test(guarded.text)).toBe(false);
|
||||
});
|
||||
|
||||
it("blocks ungrounded organization fact answer with deterministic boundary reply", () => {
|
||||
const policy = createPolicy();
|
||||
|
||||
const guarded = policy.applyLivingChatGroundingGuard({
|
||||
userMessage: "какой возраст у альтернативы?",
|
||||
chatText: "Для ООО Альтернатива Плюс дата регистрации 01.07.2015, возраст 8 лет.",
|
||||
organization: "ООО Альтернатива Плюс"
|
||||
});
|
||||
|
||||
expect(guarded.applied).toBe(true);
|
||||
expect(guarded.reason).toBe("organization_fact_without_live_source_blocked");
|
||||
expect(guarded.text.toLowerCase()).toContain("не буду называть");
|
||||
expect(guarded.text).not.toContain("01.07.2015");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user