NODEDC_1C/llm_normalizer/backend/tests/assistantLivingChatAttemptI...

97 lines
3.6 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { buildAssistantLivingChatAttemptRuntimeInput } from "../src/services/assistantLivingChatAttemptInputBuilder";
function buildInput(overrides: Record<string, unknown> = {}) {
return {
sessionId: "asst-1",
userMessage: "че там",
sessionItems: [],
modeDecision: {
mode: "chat",
reason: "living_chat_signal_detected"
},
sessionScope: {
knownOrganizations: ["Org A"],
selectedOrganization: "Org A",
activeOrganization: "Org A"
},
addressRuntimeMeta: {
source: "address_runtime"
},
toNonEmptyString: (value: unknown) =>
typeof value === "string" && value.trim().length > 0 ? 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: () => null,
applyScriptGuard: (chatText: string) => chatText,
applyGroundingGuard: (guardInput: Record<string, unknown>) => guardInput,
buildAssistantSafetyRefusalReply: () => "safety",
buildAssistantDataScopeContractReply: () => "scope",
buildAssistantOrganizationFactBoundaryReply: () => "boundary",
buildAssistantDataScopeSelectionReply: () => "selection",
buildAssistantOperationalBoundaryReply: () => "operational",
buildAssistantCapabilityContractReply: () => "capability",
appendItem: () => {},
getSession: () => null,
persistSession: () => {},
cloneConversation: (items: unknown[]) => items,
logEvent: () => {},
messageIdFactory: vi.fn(() => "msg-abc123"),
nowIso: () => "2026-04-11T00:00:00.000Z",
payload: {
llmProvider: "openai"
},
chatClient: {},
loadAssistantCanonExcerpt: () => "",
sanitizeOutgoingAssistantText: (value: unknown, fallback = "") => {
const text = typeof value === "string" ? value.trim() : "";
return text || fallback;
},
defaultModel: "gpt-5",
defaultBaseUrl: "http://localhost",
defaultApiKey: "key",
...overrides
} as any;
}
describe("assistant living chat attempt input builder", () => {
it("builds living-chat runtime input with derived trace id and session scope", () => {
const runtimeInput = buildAssistantLivingChatAttemptRuntimeInput(buildInput());
expect(runtimeInput.sessionId).toBe("asst-1");
expect(runtimeInput.userMessage).toBe("че там");
expect(runtimeInput.traceIdFactory()).toBe("chat-abc123");
expect(runtimeInput.sessionScope).toEqual({
knownOrganizations: ["Org A"],
selectedOrganization: "Org A",
activeOrganization: "Org A"
});
expect(runtimeInput.modeDecision).toEqual({
mode: "chat",
reason: "living_chat_signal_detected"
});
});
it("normalizes absent address runtime meta to null and preserves optional api key", () => {
const runtimeInput = buildAssistantLivingChatAttemptRuntimeInput(
buildInput({
addressRuntimeMeta: undefined,
defaultApiKey: undefined
})
);
expect(runtimeInput.addressRuntimeMeta).toBeNull();
expect(runtimeInput.defaultApiKey).toBeUndefined();
expect(runtimeInput.defaultBaseUrl).toBe("http://localhost");
expect(runtimeInput.defaultModel).toBe("gpt-5");
});
});