82 lines
3.3 KiB
TypeScript
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);
|
|
});
|
|
});
|