NODEDC_1C/llm_normalizer/backend/src/services/assistantOrganizationScopeR...

133 lines
5.4 KiB
TypeScript

import type { AddressNavigationState } from "../types/addressNavigation";
import { resolveAssistantOrganizationAuthority } from "./assistantContinuityPolicy";
export interface AssistantSessionOrganizationScopeContext {
knownOrganizations: string[];
selectedOrganization: string | null;
activeOrganization: string | null;
}
export interface ResolveSessionOrganizationScopeContextRuntimeInput<ItemType = unknown> {
userMessage: string;
items: ItemType[];
addressNavigationState?: AddressNavigationState | null;
extractKnownOrganizationsFromHistory: (items: ItemType[]) => string[];
resolveOrganizationSelectionFromMessage: (userMessage: string, knownOrganizations: string[]) => string | null;
normalizeOrganizationScopeValue: (value: unknown) => string | null;
}
export interface MergeFollowupContextWithOrganizationScopeRuntimeInput {
followupContext: unknown;
organization: unknown;
normalizeOrganizationScopeValue: (value: unknown) => string | null;
toNonEmptyString: (value: unknown) => string | null;
}
function extractOrganizationsFromNavigationState(
addressNavigationState: AddressNavigationState | null | undefined,
normalizeOrganizationScopeValue: ResolveSessionOrganizationScopeContextRuntimeInput["normalizeOrganizationScopeValue"]
): string[] {
if (!addressNavigationState || typeof addressNavigationState !== "object") {
return [];
}
const collected: string[] = [];
const directOrganization = normalizeOrganizationScopeValue(addressNavigationState.session_context?.organization_scope);
if (directOrganization) {
collected.push(directOrganization);
}
for (const resultSet of Array.isArray(addressNavigationState.result_sets) ? addressNavigationState.result_sets : []) {
const scopedOrganization = normalizeOrganizationScopeValue(resultSet?.filters?.organization);
if (scopedOrganization) {
collected.push(scopedOrganization);
}
}
return Array.from(new Map(collected.map((value) => [value.toLowerCase(), value])).values());
}
function resolveActiveOrganizationFromNavigationState(
addressNavigationState: AddressNavigationState | null | undefined,
normalizeOrganizationScopeValue: ResolveSessionOrganizationScopeContextRuntimeInput["normalizeOrganizationScopeValue"]
): string | null {
if (!addressNavigationState || typeof addressNavigationState !== "object") {
return null;
}
return normalizeOrganizationScopeValue(addressNavigationState.session_context?.organization_scope);
}
export function resolveSessionOrganizationScopeContextRuntime<ItemType = unknown>(
input: ResolveSessionOrganizationScopeContextRuntimeInput<ItemType>
): AssistantSessionOrganizationScopeContext {
const continuityAuthority = resolveAssistantOrganizationAuthority({
sessionItems: Array.isArray(input.items) ? input.items : [],
toNonEmptyString: input.normalizeOrganizationScopeValue,
normalizeOrganizationScopeValue: input.normalizeOrganizationScopeValue
});
const continuityKnownOrganizations = Array.isArray(continuityAuthority.knownOrganizations)
? continuityAuthority.knownOrganizations
: [];
const continuityActiveOrganization = input.normalizeOrganizationScopeValue(
continuityAuthority.activeOrganization
);
const knownOrganizations = Array.from(
new Map(
[
...continuityKnownOrganizations,
...extractOrganizationsFromNavigationState(input.addressNavigationState, input.normalizeOrganizationScopeValue),
...input.extractKnownOrganizationsFromHistory(input.items)
].map((value) => [String(value).toLowerCase(), value])
).values()
);
const selectedOrganization = input.resolveOrganizationSelectionFromMessage(
input.userMessage,
knownOrganizations
);
const navigationActiveOrganization = resolveActiveOrganizationFromNavigationState(
input.addressNavigationState,
input.normalizeOrganizationScopeValue
);
const activeOrganization =
selectedOrganization ??
navigationActiveOrganization ??
continuityActiveOrganization ??
(knownOrganizations.length === 1 ? knownOrganizations[0] : null);
return {
knownOrganizations,
selectedOrganization,
activeOrganization
};
}
export function mergeFollowupContextWithOrganizationScopeRuntime(
input: MergeFollowupContextWithOrganizationScopeRuntimeInput
): Record<string, unknown> | null {
const normalizedOrganization = input.normalizeOrganizationScopeValue(input.organization);
const hasBase = input.followupContext && typeof input.followupContext === "object";
const base = hasBase ? { ...(input.followupContext as Record<string, unknown>) } : {};
if (!normalizedOrganization) {
return hasBase ? base : null;
}
const previousFiltersRaw = base.previous_filters;
const previousFilters =
previousFiltersRaw && typeof previousFiltersRaw === "object"
? { ...(previousFiltersRaw as Record<string, unknown>) }
: {};
if (!input.toNonEmptyString(previousFilters.organization)) {
previousFilters.organization = normalizedOrganization;
}
base.previous_filters = previousFilters;
const rootFiltersRaw = base.root_filters;
const rootFilters =
rootFiltersRaw && typeof rootFiltersRaw === "object"
? { ...(rootFiltersRaw as Record<string, unknown>) }
: {};
if (!input.toNonEmptyString(rootFilters.organization)) {
rootFilters.organization = normalizedOrganization;
}
if (Object.keys(rootFilters).length > 0) {
base.root_filters = rootFilters;
}
return base;
}