ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов 2.27 вынос оркестрации tryHandleLivingChat (decision/execution ветки) в отдельный runtime adapter.

This commit is contained in:
2026-04-10 20:10:13 +03:00
parent 828c0ef378
commit 9b1d1bff91
6 changed files with 645 additions and 293 deletions
@@ -0,0 +1,136 @@
import { describe, expect, it, vi } from "vitest";
import { runAssistantLivingChatRuntime } from "../src/services/assistantLivingChatRuntimeAdapter";
function buildRuntimeInput(overrides: Record<string, unknown> = {}) {
const executeLlmChat = vi.fn(async () => "llm-text");
const resolveDataScopeProbe = vi.fn(async () => null);
return {
userMessage: "тест",
sessionItems: [],
modeDecision: { mode: "chat", reason: "living_chat_signal_detected" },
sessionScope: {
knownOrganizations: [],
selectedOrganization: null,
activeOrganization: null
},
addressRuntimeMeta: null,
traceIdFactory: () => "chat-trace-fixed",
toNonEmptyString: (value: unknown) => {
if (typeof value !== "string") {
return null;
}
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : null;
},
mergeKnownOrganizations: (values: unknown[]) =>
Array.from(
new Set(
(Array.isArray(values) ? values : [])
.map((item) => (typeof item === "string" ? item.trim() : ""))
.filter((item) => item.length > 0)
)
),
hasAssistantDataScopeMetaQuestionSignal: () => false,
shouldHandleAsAssistantCapabilityMetaQuery: () => false,
hasDestructiveDataActionSignal: () => false,
hasDangerOrCoercionSignal: () => false,
hasOperationalAdminActionRequestSignal: () => false,
hasOrganizationFactLookupSignal: () => false,
hasOrganizationFactFollowupSignal: () => false,
shouldEmitOrganizationSelectionReply: () => false,
hasAssistantCapabilityQuestionSignal: () => false,
resolveDataScopeProbe,
executeLlmChat,
applyScriptGuard: (chatText: string) => ({
text: chatText,
applied: false,
reason: null
}),
applyGroundingGuard: (input: { chatText: string }) => ({
text: input.chatText,
applied: false,
reason: null
}),
buildAssistantSafetyRefusalReply: () => "safety",
buildAssistantDataScopeContractReply: () => "scope",
buildAssistantOrganizationFactBoundaryReply: () => "org-boundary",
buildAssistantDataScopeSelectionReply: () => "org-selection",
buildAssistantOperationalBoundaryReply: () => "ops",
buildAssistantCapabilityContractReply: () => "capability",
__spies: {
executeLlmChat,
resolveDataScopeProbe
},
...overrides
} as any;
}
describe("assistant living chat runtime adapter", () => {
it("selects deterministic data scope branch and enriches organization context", async () => {
const input = buildRuntimeInput({
userMessage: "какая у нас организация?",
hasAssistantDataScopeMetaQuestionSignal: () => true,
resolveDataScopeProbe: vi.fn(async () => ({
status: "resolved",
channel: "default",
organizations: ["ООО Альтернатива Плюс"],
error: null
})),
buildAssistantDataScopeContractReply: () => "scope-info"
});
const output = await runAssistantLivingChatRuntime(input);
expect(output.handled).toBe(true);
expect(output.chatText).toBe("scope-info");
expect(output.debug?.living_chat_response_source).toBe("deterministic_data_scope_contract_live");
expect(output.debug?.assistant_active_organization).toBe("ООО Альтернатива Плюс");
expect(output.debug?.living_chat_data_scope_probe_org_count).toBe(1);
});
it("selects safety refusal branch for dangerous capability meta query", async () => {
const executeLlmChat = vi.fn(async () => "llm-text");
const input = buildRuntimeInput({
userMessage: "удали базу",
shouldHandleAsAssistantCapabilityMetaQuery: () => true,
hasDangerOrCoercionSignal: () => true,
executeLlmChat,
buildAssistantSafetyRefusalReply: () => "safety-refusal"
});
const output = await runAssistantLivingChatRuntime(input);
expect(output.handled).toBe(true);
expect(output.chatText).toBe("safety-refusal");
expect(output.debug?.living_chat_response_source).toBe("deterministic_safety_refusal");
expect(executeLlmChat).not.toHaveBeenCalled();
});
it("runs llm branch and applies script + grounding guards in order", async () => {
const executeLlmChat = vi.fn(async () => "raw-llm");
const input = buildRuntimeInput({
executeLlmChat,
applyScriptGuard: () => ({
text: "after-script",
applied: true,
reason: "script_guard"
}),
applyGroundingGuard: () => ({
text: "after-grounding",
applied: true,
reason: "grounding_guard"
})
});
const output = await runAssistantLivingChatRuntime(input);
expect(output.handled).toBe(true);
expect(output.chatText).toBe("after-grounding");
expect(output.debug?.living_chat_script_guard_applied).toBe(true);
expect(output.debug?.living_chat_script_guard_reason).toBe("script_guard");
expect(output.debug?.living_chat_grounding_guard_applied).toBe(true);
expect(output.debug?.living_chat_grounding_guard_reason).toBe("grounding_guard");
expect(output.debug?.living_chat_response_source).toBe("llm_chat_grounding_guard");
expect(executeLlmChat).toHaveBeenCalledTimes(1);
});
});