NODEDC_1C/llm_normalizer/backend/tests/assistantOrganizationScopeR...

142 lines
5.0 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import {
mergeFollowupContextWithOrganizationScopeRuntime,
resolveSessionOrganizationScopeContextRuntime
} from "../src/services/assistantOrganizationScopeRuntimeAdapter";
describe("assistant organization scope runtime adapter", () => {
it("resolves selected organization from user message and promotes it to active scope", () => {
const extractKnownOrganizationsFromHistory = vi.fn(() => ["Org A", "Org B"]);
const resolveOrganizationSelectionFromMessage = vi.fn(() => "Org B");
const findLastAssistantActiveOrganization = vi.fn(() => "Org A");
const normalizeOrganizationScopeValue = vi.fn((value: unknown) =>
typeof value === "string" && value.trim() ? value.trim() : null
);
const context = resolveSessionOrganizationScopeContextRuntime({
userMessage: "по Org B покажи",
items: [] as any[],
extractKnownOrganizationsFromHistory,
resolveOrganizationSelectionFromMessage,
findLastAssistantActiveOrganization,
normalizeOrganizationScopeValue
});
expect(context).toEqual({
knownOrganizations: ["Org A", "Org B"],
selectedOrganization: "Org B",
activeOrganization: "Org B"
});
});
it("falls back active organization to last assistant scope when selection is absent", () => {
const normalizeOrganizationScopeValue = vi.fn((value: unknown) =>
typeof value === "string" ? value.trim() : null
);
const context = resolveSessionOrganizationScopeContextRuntime({
userMessage: "просто обсуждаем",
items: [] as any[],
extractKnownOrganizationsFromHistory: () => ["Org A"],
resolveOrganizationSelectionFromMessage: () => null,
findLastAssistantActiveOrganization: () => "Org A",
normalizeOrganizationScopeValue
});
expect(context).toEqual({
knownOrganizations: ["Org A"],
selectedOrganization: null,
activeOrganization: "Org A"
});
expect(normalizeOrganizationScopeValue).toHaveBeenCalledWith("Org A");
});
it("prefers organization scope from address navigation state when present", () => {
const normalizeOrganizationScopeValue = vi.fn((value: unknown) =>
typeof value === "string" && value.trim() ? value.trim() : null
);
const context = resolveSessionOrganizationScopeContextRuntime({
userMessage: "просто продолжай",
items: [] as any[],
addressNavigationState: {
schema_version: "address_navigation_state_v1",
session_id: "asst-nav-org",
updated_at: "2026-04-15T10:00:00.000Z",
session_context: {
active_result_set_id: "rs-1",
active_focus_object: null,
last_confirmed_route: "address_inventory_on_hand_as_of_date_v1",
date_scope: {
as_of_date: "2020-05-31",
period_from: null,
period_to: null
},
organization_scope: "Org B"
},
result_sets: [],
navigation_history: []
} as any,
extractKnownOrganizationsFromHistory: () => ["Org A"],
resolveOrganizationSelectionFromMessage: () => null,
findLastAssistantActiveOrganization: () => "Org A",
normalizeOrganizationScopeValue
});
expect(context).toEqual({
knownOrganizations: ["Org B", "Org A"],
selectedOrganization: null,
activeOrganization: "Org B"
});
});
it("merges organization into followup previous filters when organization is missing", () => {
const merged = mergeFollowupContextWithOrganizationScopeRuntime({
followupContext: {
previous_filters: {
period: "2020-07"
}
},
organization: " Org A ",
normalizeOrganizationScopeValue: (value: unknown) =>
typeof value === "string" && value.trim() ? value.trim() : null,
toNonEmptyString: (value: unknown) =>
typeof value === "string" && value.trim().length > 0 ? value.trim() : null
});
expect(merged).toEqual({
previous_filters: {
period: "2020-07",
organization: "Org A"
},
root_filters: {
organization: "Org A"
}
});
});
it("keeps existing organization in followup filters and returns null for empty context without org", () => {
const preserved = mergeFollowupContextWithOrganizationScopeRuntime({
followupContext: {
previous_filters: {
organization: "Org Existing"
}
},
organization: "Org A",
normalizeOrganizationScopeValue: (value: unknown) =>
typeof value === "string" && value.trim() ? value.trim() : null,
toNonEmptyString: (value: unknown) =>
typeof value === "string" && value.trim().length > 0 ? value.trim() : null
});
const empty = mergeFollowupContextWithOrganizationScopeRuntime({
followupContext: null,
organization: "",
normalizeOrganizationScopeValue: () => null,
toNonEmptyString: () => null
});
expect((preserved as any).previous_filters.organization).toBe("Org Existing");
expect(empty).toBeNull();
});
});