NODEDC_1C/llm_normalizer/backend/tests/assistantLivingModePolicy.t...

82 lines
3.3 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { createAssistantLivingModePolicy } from "../src/services/assistantLivingModePolicy";
function buildPolicy() {
return createAssistantLivingModePolicy({
featureAssistantLivingChatRouterV1: true,
compactWhitespace: (text: string) => text.replace(/\s+/g, " ").trim(),
repairAddressMojibake: (text: string) => text,
toNonEmptyString: (value: unknown) => {
if (value === null || value === undefined) {
return null;
}
const text = String(value).trim();
return text.length > 0 ? text : null;
},
normalizeOrganizationScopeValue: (value: unknown) => {
if (value === null || value === undefined) {
return null;
}
const text = String(value).trim().replace(/^"+|"+$/g, "").replace(/^'+|'+$/g, "");
return text.length > 0 ? text : null;
},
hasReferentialPointer: (text: string) =>
/(по этому|по тому|это же|этой|этим|этому|этого|этот|эту|этом|это|эти|этих|из этого|из них|из этих|из тех|в этом|тот же|same thing|that one|po etomu|po tomu)/i.test(
text.toLowerCase()
),
hasSmallTalkSignal: (text: string) => /(привет|как дела|спасибо|благодарю|thanks|thank you|hello|hi)\b/i.test(text.toLowerCase()),
hasAssistantCapabilityQuestionSignal: (text: string) =>
/(?:кто ты|что ты можешь|какие фичи|полный список возможностей|чем ты можешь помочь|что ты умеешь)/i.test(text),
hasOperationalAdminActionRequestSignal: (text: string) =>
/(?:настро|установ|подключ|обнов|почин|исправ|удал|снеси|delete\s+database|drop\s+database)/i.test(text)
});
}
describe("assistantLivingModePolicy", () => {
it("routes data-scope question to chat mode", () => {
const policy = buildPolicy();
const decision = policy.resolveLivingAssistantModeDecision({
userMessage: "по какой компании мы можем работать?",
addressLaneTriggered: false,
useMock: false,
predecomposeMode: "unsupported",
predecomposeModeConfidence: "low"
});
expect(decision.mode).toBe("chat");
expect(decision.reason).toBe("assistant_data_scope_query_detected");
});
it("keeps explicit accounting question in deep mode", () => {
const policy = buildPolicy();
const decision = policy.resolveLivingAssistantModeDecision({
userMessage: "покажи документы по сверке за 2020",
addressLaneTriggered: false,
useMock: false,
predecomposeMode: "unsupported",
predecomposeModeConfidence: "low"
});
expect(decision.mode).toBe("deep_analysis");
expect(decision.reason).toBe("strong_data_signal_detected");
});
it("detects organization fact follow-up after prior boundary reply", () => {
const policy = buildPolicy();
const detected = policy.hasOrganizationFactFollowupSignal("давай", [
{
role: "assistant",
debug: {
living_chat_response_source: "deterministic_organization_fact_boundary",
living_chat_grounding_guard_reason: null
}
}
]);
expect(detected).toBe(true);
});
});