import type { AddressNavigationState } from "../types/addressNavigation"; import { resolveAssistantOrganizationAuthority } from "./assistantContinuityPolicy"; export interface AssistantSessionOrganizationScopeContext { knownOrganizations: string[]; selectedOrganization: string | null; activeOrganization: string | null; } export interface ResolveSessionOrganizationScopeContextRuntimeInput { 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( input: ResolveSessionOrganizationScopeContextRuntimeInput ): 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 continuitySelectedOrganization = input.normalizeOrganizationScopeValue( continuityAuthority.selectedOrganization ); 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 ?? continuitySelectedOrganization ?? continuityActiveOrganization ?? navigationActiveOrganization ?? (knownOrganizations.length === 1 ? knownOrganizations[0] : null); return { knownOrganizations, selectedOrganization, activeOrganization }; } export function mergeFollowupContextWithOrganizationScopeRuntime( input: MergeFollowupContextWithOrganizationScopeRuntimeInput ): Record | null { const normalizedOrganization = input.normalizeOrganizationScopeValue(input.organization); const hasBase = input.followupContext && typeof input.followupContext === "object"; const base = hasBase ? { ...(input.followupContext as Record) } : {}; if (!normalizedOrganization) { return hasBase ? base : null; } const previousFiltersRaw = base.previous_filters; const previousFilters = previousFiltersRaw && typeof previousFiltersRaw === "object" ? { ...(previousFiltersRaw as Record) } : {}; const previousOrganization = input.toNonEmptyString(previousFilters.organization); if (!previousOrganization || previousOrganization !== normalizedOrganization) { previousFilters.organization = normalizedOrganization; } base.previous_filters = previousFilters; const rootFiltersRaw = base.root_filters; const rootFilters = rootFiltersRaw && typeof rootFiltersRaw === "object" ? { ...(rootFiltersRaw as Record) } : {}; const rootOrganization = input.toNonEmptyString(rootFilters.organization); if (!rootOrganization || rootOrganization !== normalizedOrganization) { rootFilters.organization = normalizedOrganization; } if (Object.keys(rootFilters).length > 0) { base.root_filters = rootFilters; } return base; }