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

129 lines
5.1 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { describe, expect, it } from "vitest";
import { createAssistantLivingModePolicy } from "../src/services/assistantLivingModePolicy";
function buildPolicy(options?: { repairAddressMojibake?: (text: string) => string }) {
return createAssistantLivingModePolicy({
featureAssistantLivingChatRouterV1: true,
compactWhitespace: (text: string) => text.replace(/\s+/g, " ").trim(),
repairAddressMojibake: options?.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|this one)/i.test(text.toLowerCase()),
hasSmallTalkSignal: (text: string) => /(thanks|thank you|hello|hi)\b/i.test(text.toLowerCase()),
hasAssistantCapabilityQuestionSignal: (text: string) =>
/(?:what can you do|capabilities|features)/i.test(text),
hasOperationalAdminActionRequestSignal: (text: string) =>
/(?:install|update|delete\s+database|drop\s+database)/i.test(text),
resolveProviderExecutionState: (input: { useMock?: unknown }) => ({
living_mode_forced_deep: Boolean(input?.useMock),
living_mode_forced_reason: Boolean(input?.useMock) ? "mock_mode_keeps_deep_pipeline" : null
})
});
}
describe("assistantLivingModePolicy", () => {
const colloquialGreeting = "\u043f\u0440\u0438\u0432\u0435\u0442\u0438\u043a - \u0447\u0435 \u043a\u0430\u043a \u0442\u0430\u043c \u0434\u0435\u043b\u0430";
it("detects explicit recap wording as memory signal even when selected-object words are present", () => {
const policy = buildPolicy();
expect(
policy.hasConversationMemoryRecallFollowupSignal("а ты помнишь, что мы по этой позиции уже выяснили?")
).toBe(true);
});
it("detects bare recap wording without 'помнишь' as memory signal", () => {
const policy = buildPolicy();
expect(policy.hasConversationMemoryRecallFollowupSignal("а что мы уже выяснили по этой позиции?")).toBe(true);
});
it("detects final executive summary wording as memory signal", () => {
const policy = buildPolicy();
expect(
policy.hasConversationMemoryRecallFollowupSignal(
"Финально собери executive summary по всему диалогу: где подтверждено, где proxy и что смотреть руками"
)
).toBe(true);
});
it("detects answer inspection wording for previous answer correction", () => {
const policy = buildPolicy();
expect(policy.hasAnswerInspectionFollowupSignal("у тебя написано кто контрагент: рабочая станция - это ошибка?")).toBe(true);
});
it("routes casual small-talk to chat mode", () => {
const policy = buildPolicy();
const decision = policy.resolveLivingAssistantModeDecision({
userMessage: "hello",
addressLaneTriggered: false,
useMock: false,
predecomposeMode: "unsupported",
predecomposeModeConfidence: "low"
});
expect(decision.mode).toBe("chat");
expect(decision.reason).toBe("living_chat_signal_detected");
});
it("detects colloquial greeting with extra words as living chat signal", () => {
const policy = buildPolicy();
expect(policy.hasLivingChatSignal(colloquialGreeting)).toBe(true);
});
it("detects mojibake colloquial greeting after repair", () => {
const policy = buildPolicy({
repairAddressMojibake: (text: string) =>
text === "приветик - че как там дела" ? colloquialGreeting : text
});
expect(policy.hasLivingChatSignal("приветик - че как там дела")).toBe(true);
});
it("keeps explicit inventory question in deep mode", () => {
const policy = buildPolicy();
const decision = policy.resolveLivingAssistantModeDecision({
userMessage: "show warehouse inventory for 2020",
addressLaneTriggered: false,
useMock: false,
predecomposeMode: "unsupported",
predecomposeModeConfidence: "low"
});
expect(decision.mode).toBe("deep_analysis");
expect(decision.reason).toBe("strong_data_signal_detected");
});
it("keeps deep pipeline in mock mode via provider execution policy", () => {
const policy = buildPolicy();
const decision = policy.resolveLivingAssistantModeDecision({
userMessage: "hello",
addressLaneTriggered: false,
useMock: true,
predecomposeMode: "unsupported",
predecomposeModeConfidence: "low"
});
expect(decision.mode).toBe("deep_analysis");
expect(decision.reason).toBe("mock_mode_keeps_deep_pipeline");
});
});