ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов 2.41 - вынос склейки вызова live-chat из handleMessage в отдельный runtime-адаптер и переподключение на новый runtime bridge

This commit is contained in:
2026-04-10 23:23:35 +03:00
parent bac6ebe701
commit fbf2d6a19a
6 changed files with 401 additions and 111 deletions
@@ -0,0 +1,121 @@
import { describe, expect, it, vi } from "vitest";
import {
runAssistantLivingChatAttemptRuntime,
type RunAssistantLivingChatAttemptRuntimeInput
} from "../src/services/assistantLivingChatAttemptRuntimeAdapter";
type TestResponse = { ok: boolean; llm: string };
function buildInput(
overrides: Partial<RunAssistantLivingChatAttemptRuntimeInput<TestResponse>> = {}
): RunAssistantLivingChatAttemptRuntimeInput<TestResponse> {
return {
sessionId: "asst-1",
userMessage: "контрагенты со сверкой",
sessionItems: [{ role: "user", text: "контекст" }],
modeDecision: { mode: "chat", reason: "living_chat_signal_detected" },
sessionScope: {
knownOrganizations: [],
selectedOrganization: null,
activeOrganization: null
},
addressRuntimeMeta: null,
traceIdFactory: () => "chat-trace-1",
toNonEmptyString: (value: unknown) => (typeof value === "string" && value.trim() ? value.trim() : null),
mergeKnownOrganizations: (values: string[]) => values,
hasAssistantDataScopeMetaQuestionSignal: () => false,
shouldHandleAsAssistantCapabilityMetaQuery: () => false,
hasDestructiveDataActionSignal: () => false,
hasDangerOrCoercionSignal: () => false,
hasOperationalAdminActionRequestSignal: () => false,
hasOrganizationFactLookupSignal: () => false,
hasOrganizationFactFollowupSignal: () => false,
shouldEmitOrganizationSelectionReply: () => false,
hasAssistantCapabilityQuestionSignal: () => false,
resolveDataScopeProbe: async () => null,
applyScriptGuard: (text: string) => ({ text, applied: false, reason: null }),
applyGroundingGuard: (payload: { chatText: string }) => ({
text: payload.chatText,
applied: false,
reason: null
}),
buildAssistantSafetyRefusalReply: () => "safety",
buildAssistantDataScopeContractReply: () => "scope",
buildAssistantOrganizationFactBoundaryReply: () => "boundary",
buildAssistantDataScopeSelectionReply: () => "selection",
buildAssistantOperationalBoundaryReply: () => "operational",
buildAssistantCapabilityContractReply: () => "capability",
appendItem: () => {},
getSession: () => ({
session_id: "asst-1",
updated_at: "",
items: [],
investigation_state: null
}),
persistSession: () => {},
cloneConversation: (items: unknown[]) => items,
logEvent: () => {},
messageIdFactory: () => "msg-1",
nowIso: () => "2026-04-10T00:00:00.000Z",
payload: {
llmProvider: "openai",
apiKey: "key",
model: "gpt-5",
baseUrl: "http://localhost",
temperature: 0.2,
maxOutputTokens: 300
},
chatClient: {
chat: async () => ({ outputText: "chat-output" })
},
loadAssistantCanonExcerpt: () => "canon",
sanitizeOutgoingAssistantText: (value: unknown, fallback = "fallback") => {
const text = String(value ?? "").trim();
return text || fallback;
},
defaultModel: "gpt-5",
defaultBaseUrl: "http://localhost",
defaultApiKey: "key",
...overrides
};
}
describe("assistant living chat attempt runtime adapter", () => {
it("wires llm runtime output into living handler execute callback", async () => {
const runLivingChatLlm = vi.fn(async () => "llm-answer");
const runLivingChatHandler = vi.fn(async (input) => {
const llm = await input.executeLlmChat();
return { ok: true, llm };
});
const response = await runAssistantLivingChatAttemptRuntime(
buildInput({
runLivingChatHandler,
runLivingChatLlm
})
);
expect(runLivingChatHandler).toHaveBeenCalledTimes(1);
expect(runLivingChatLlm).toHaveBeenCalledWith(
expect.objectContaining({
userMessage: "контрагенты со сверкой"
})
);
expect(response).toEqual({ ok: true, llm: "llm-answer" });
});
it("returns null when delegated handler returns null", async () => {
const runLivingChatLlm = vi.fn(async () => "llm-answer");
const runLivingChatHandler = vi.fn(async () => null);
const response = await runAssistantLivingChatAttemptRuntime(
buildInput({
runLivingChatHandler,
runLivingChatLlm
})
);
expect(response).toBeNull();
expect(runLivingChatLlm).not.toHaveBeenCalled();
});
});