@open-mercato/search 0.6.6-develop.6296.1.5e8bdfee17 → 0.6.6-develop.6299.1.29224e2d86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +16 -2
- package/dist/modules/search/__integration__/TC-SEARCH-010.spec.js +45 -0
- package/dist/modules/search/__integration__/TC-SEARCH-010.spec.js.map +7 -0
- package/dist/modules/search/__integration__/TC-SEARCH-011.spec.js +25 -0
- package/dist/modules/search/__integration__/TC-SEARCH-011.spec.js.map +7 -0
- package/dist/modules/search/api/embeddings/route.js +50 -6
- package/dist/modules/search/api/embeddings/route.js.map +2 -2
- package/dist/modules/search/api/search/global/route.js +1 -1
- package/dist/modules/search/api/search/global/route.js.map +2 -2
- package/dist/modules/search/api/settings/global-search/route.js +8 -5
- package/dist/modules/search/api/settings/global-search/route.js.map +2 -2
- package/dist/modules/search/di.js +3 -1
- package/dist/modules/search/di.js.map +2 -2
- package/dist/modules/search/frontend/components/sections/VectorSearchSection.js +6 -3
- package/dist/modules/search/frontend/components/sections/VectorSearchSection.js.map +2 -2
- package/dist/modules/search/i18n/de.json +3 -0
- package/dist/modules/search/i18n/en.json +3 -0
- package/dist/modules/search/i18n/es.json +3 -0
- package/dist/modules/search/i18n/pl.json +3 -0
- package/dist/modules/search/lib/auto-indexing.js +4 -1
- package/dist/modules/search/lib/auto-indexing.js.map +2 -2
- package/dist/modules/search/lib/embedding-config.js +40 -3
- package/dist/modules/search/lib/embedding-config.js.map +2 -2
- package/dist/modules/search/lib/global-search-config.js +25 -3
- package/dist/modules/search/lib/global-search-config.js.map +2 -2
- package/dist/modules/search/lib/provider-probe.js +108 -0
- package/dist/modules/search/lib/provider-probe.js.map +7 -0
- package/package.json +4 -4
- package/src/modules/search/__integration__/TC-SEARCH-010.spec.ts +74 -0
- package/src/modules/search/__integration__/TC-SEARCH-011.spec.ts +46 -0
- package/src/modules/search/api/embeddings/__tests__/route.ollama-base-url.test.ts +3 -0
- package/src/modules/search/api/embeddings/route.ts +62 -6
- package/src/modules/search/api/search/global/route.ts +2 -2
- package/src/modules/search/api/settings/global-search/route.ts +9 -4
- package/src/modules/search/di.ts +2 -0
- package/src/modules/search/frontend/components/sections/VectorSearchSection.tsx +21 -2
- package/src/modules/search/i18n/de.json +3 -0
- package/src/modules/search/i18n/en.json +3 -0
- package/src/modules/search/i18n/es.json +3 -0
- package/src/modules/search/i18n/pl.json +3 -0
- package/src/modules/search/lib/__tests__/provider-probe.test.ts +137 -0
- package/src/modules/search/lib/__tests__/search-settings-scope.test.ts +152 -0
- package/src/modules/search/lib/auto-indexing.ts +6 -3
- package/src/modules/search/lib/embedding-config.ts +58 -5
- package/src/modules/search/lib/global-search-config.ts +36 -4
- package/src/modules/search/lib/provider-probe.ts +143 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/search/frontend/components/sections/VectorSearchSection.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useAppEvent } from '@open-mercato/ui/backend/injection/useAppEvent'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '@open-mercato/ui/primitives/tabs'\n\n// Types\ntype EmbeddingProviderId = 'openai' | 'google' | 'mistral' | 'cohere' | 'bedrock' | 'ollama'\n\ntype EmbeddingProviderConfig = {\n providerId: EmbeddingProviderId\n model: string\n dimension: number\n outputDimensionality?: number\n baseUrl?: string\n updatedAt: string\n}\n\ntype EmbeddingModelInfo = {\n id: string\n name: string\n dimension: number\n configurableDimension?: boolean\n minDimension?: number\n maxDimension?: number\n}\n\ntype EmbeddingProviderInfo = {\n name: string\n envKeyRequired: string\n defaultModel: string\n models: EmbeddingModelInfo[]\n}\n\ntype EmbeddingSettings = {\n openaiConfigured: boolean\n autoIndexingEnabled: boolean\n autoIndexingLocked: boolean\n lockReason: string | null\n embeddingConfig: EmbeddingProviderConfig | null\n configuredProviders: EmbeddingProviderId[]\n indexedDimension: number | null\n reindexRequired: boolean\n documentCount: number | null\n}\n\ntype EmbeddingSettingsResponse = {\n settings?: EmbeddingSettings\n error?: string\n}\n\ntype VectorDriverId = 'pgvector' | 'qdrant' | 'chromadb'\n\ntype VectorDriverEnvVar = {\n name: string\n set: boolean\n hint: string\n}\n\ntype VectorDriverStatus = {\n id: VectorDriverId\n name: string\n configured: boolean\n implemented: boolean\n envVars: VectorDriverEnvVar[]\n}\n\ntype VectorStoreConfigResponse = {\n currentDriver: VectorDriverId\n configured: boolean\n drivers: VectorDriverStatus[]\n}\n\ntype ReindexLock = {\n type: 'fulltext' | 'vector'\n action: string\n startedAt: string\n elapsedMinutes: number\n}\n\ntype ActivityLog = {\n id: string\n source: string\n handler: string\n level: 'info' | 'error' | 'warn'\n entityType: string | null\n recordId: string | null\n message: string\n details: unknown\n occurredAt: string\n}\n\nconst EMBEDDING_PROVIDERS: Record<EmbeddingProviderId, EmbeddingProviderInfo> = {\n openai: {\n name: 'OpenAI',\n envKeyRequired: 'OPENAI_API_KEY',\n defaultModel: 'text-embedding-3-small',\n models: [\n { id: 'text-embedding-3-small', name: 'text-embedding-3-small', dimension: 1536 },\n { id: 'text-embedding-3-large', name: 'text-embedding-3-large', dimension: 3072, configurableDimension: true, minDimension: 256, maxDimension: 3072 },\n { id: 'text-embedding-ada-002', name: 'text-embedding-ada-002', dimension: 1536 },\n ],\n },\n google: {\n name: 'Google Generative AI',\n envKeyRequired: 'GOOGLE_GENERATIVE_AI_API_KEY',\n defaultModel: 'text-embedding-004',\n models: [\n { id: 'text-embedding-004', name: 'text-embedding-004', dimension: 768, configurableDimension: true, minDimension: 1, maxDimension: 768 },\n { id: 'embedding-001', name: 'embedding-001', dimension: 768 },\n ],\n },\n mistral: {\n name: 'Mistral',\n envKeyRequired: 'MISTRAL_API_KEY',\n defaultModel: 'mistral-embed',\n models: [\n { id: 'mistral-embed', name: 'mistral-embed', dimension: 1024 },\n ],\n },\n cohere: {\n name: 'Cohere',\n envKeyRequired: 'COHERE_API_KEY',\n defaultModel: 'embed-english-v3.0',\n models: [\n { id: 'embed-english-v3.0', name: 'embed-english-v3.0', dimension: 1024 },\n { id: 'embed-multilingual-v3.0', name: 'embed-multilingual-v3.0', dimension: 1024 },\n { id: 'embed-english-light-v3.0', name: 'embed-english-light-v3.0', dimension: 384 },\n { id: 'embed-multilingual-light-v3.0', name: 'embed-multilingual-light-v3.0', dimension: 384 },\n ],\n },\n bedrock: {\n name: 'Amazon Bedrock',\n envKeyRequired: 'AWS_ACCESS_KEY_ID',\n defaultModel: 'amazon.titan-embed-text-v2:0',\n models: [\n { id: 'amazon.titan-embed-text-v2:0', name: 'Titan Embed Text v2', dimension: 1024, configurableDimension: true, minDimension: 256, maxDimension: 1024 },\n { id: 'amazon.titan-embed-text-v1', name: 'Titan Embed Text v1', dimension: 1536 },\n { id: 'cohere.embed-english-v3', name: 'Cohere Embed English v3', dimension: 1024 },\n { id: 'cohere.embed-multilingual-v3', name: 'Cohere Embed Multilingual v3', dimension: 1024 },\n ],\n },\n ollama: {\n name: 'Ollama (Local)',\n envKeyRequired: 'OLLAMA_BASE_URL',\n defaultModel: 'nomic-embed-text',\n models: [\n { id: 'nomic-embed-text', name: 'nomic-embed-text', dimension: 768 },\n { id: 'mxbai-embed-large', name: 'mxbai-embed-large', dimension: 1024 },\n { id: 'all-minilm', name: 'all-minilm', dimension: 384 },\n { id: 'snowflake-arctic-embed', name: 'snowflake-arctic-embed', dimension: 1024 },\n ],\n },\n}\n\nexport type VectorSearchSectionProps = {\n embeddingSettings: EmbeddingSettings | null\n embeddingLoading: boolean\n vectorStoreConfig: VectorStoreConfigResponse | null\n vectorStoreConfigLoading: boolean\n vectorReindexLock: ReindexLock | null\n onEmbeddingSettingsUpdate: (settings: EmbeddingSettings) => void\n onRefreshEmbeddings: () => Promise<void>\n}\n\nexport function VectorSearchSection({\n embeddingSettings,\n embeddingLoading,\n vectorStoreConfig,\n vectorStoreConfigLoading,\n vectorReindexLock,\n onEmbeddingSettingsUpdate,\n onRefreshEmbeddings,\n}: VectorSearchSectionProps) {\n const t = useT()\n const [embeddingSaving, setEmbeddingSaving] = React.useState(false)\n const autoIndexingPreviousRef = React.useRef<boolean>(true)\n\n // Staged embedding selection\n const [selectedProvider, setSelectedProvider] = React.useState<EmbeddingProviderId | null>(null)\n const [selectedModel, setSelectedModel] = React.useState<string | null>(null)\n const [customModelName, setCustomModelName] = React.useState<string>('')\n const [customDimension, setCustomDimension] = React.useState<number>(768)\n\n const [pendingEmbeddingConfig, setPendingEmbeddingConfig] = React.useState<EmbeddingProviderConfig | null>(null)\n const [showEmbeddingConfirmDialog, setShowEmbeddingConfirmDialog] = React.useState(false)\n\n // Vector reindex state\n const [vectorReindexing, setVectorReindexing] = React.useState(false)\n const [showVectorReindexDialog, setShowVectorReindexDialog] = React.useState(false)\n\n // Activity logs state\n const [activityLogs, setActivityLogs] = React.useState<ActivityLog[]>([])\n const [activityLoading, setActivityLoading] = React.useState(true)\n\n // Fetch activity logs\n const fetchActivityLogs = React.useCallback(async () => {\n setActivityLoading(true)\n try {\n const response = await fetch('/api/query_index/status')\n if (response.ok) {\n const body = await response.json() as { logs?: ActivityLog[]; errors?: ActivityLog[] }\n const allLogs: ActivityLog[] = []\n if (body.logs) {\n allLogs.push(...body.logs)\n }\n if (body.errors) {\n allLogs.push(...body.errors.map(err => ({ ...err, level: 'error' as const })))\n }\n // Filter for vector-related logs\n const vectorLogs = allLogs.filter(log => {\n const lowerSource = log.source?.toLowerCase() ?? ''\n const lowerMessage = log.message?.toLowerCase() ?? ''\n const lowerHandler = log.handler?.toLowerCase() ?? ''\n return lowerSource.includes('vector') || lowerMessage.includes('vector') ||\n lowerMessage.includes('embedding') || lowerHandler.includes('vector')\n })\n vectorLogs.sort((a, b) => new Date(b.occurredAt).getTime() - new Date(a.occurredAt).getTime())\n setActivityLogs(vectorLogs.slice(0, 50))\n }\n } catch {\n // Silently fail\n } finally {\n setActivityLoading(false)\n }\n }, [])\n\n React.useEffect(() => {\n fetchActivityLogs()\n }, [fetchActivityLogs])\n\n useAppEvent('progress.job.updated', () => {\n void fetchActivityLogs()\n }, [fetchActivityLogs])\n\n useAppEvent('progress.job.completed', () => {\n void fetchActivityLogs()\n }, [fetchActivityLogs])\n\n useAppEvent('om:bridge:reconnected', () => {\n void fetchActivityLogs()\n }, [fetchActivityLogs])\n\n // Update auto-indexing\n const updateAutoIndexing = React.useCallback(async (nextValue: boolean) => {\n autoIndexingPreviousRef.current = embeddingSettings?.autoIndexingEnabled ?? true\n if (embeddingSettings) {\n onEmbeddingSettingsUpdate({ ...embeddingSettings, autoIndexingEnabled: nextValue })\n }\n setEmbeddingSaving(true)\n try {\n const body = await readApiResultOrThrow<EmbeddingSettingsResponse>(\n '/api/search/embeddings',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ autoIndexingEnabled: nextValue }),\n },\n { errorMessage: t('search.settings.errors.saveFailed', 'Failed to save settings'), allowNullResult: true },\n )\n if (body?.settings) {\n onEmbeddingSettingsUpdate(body.settings)\n autoIndexingPreviousRef.current = body.settings.autoIndexingEnabled\n }\n flash(t('search.settings.messages.saved', 'Settings saved'), 'success')\n } catch {\n if (embeddingSettings) {\n onEmbeddingSettingsUpdate({ ...embeddingSettings, autoIndexingEnabled: autoIndexingPreviousRef.current })\n }\n } finally {\n setEmbeddingSaving(false)\n }\n }, [embeddingSettings, onEmbeddingSettingsUpdate, t])\n\n // Provider handlers\n const handleProviderChange = (providerId: EmbeddingProviderId) => {\n setSelectedProvider(providerId)\n setSelectedModel(null)\n setCustomModelName('')\n setCustomDimension(768)\n }\n\n const handleModelChange = (modelId: string) => {\n setSelectedModel(modelId)\n }\n\n const handleApplyEmbeddingChanges = () => {\n const newProviderId = selectedProvider ?? embeddingSettings?.embeddingConfig?.providerId ?? 'openai'\n const newProviderInfo = EMBEDDING_PROVIDERS[newProviderId]\n const newModelId = selectedModel ?? (selectedProvider ? newProviderInfo.defaultModel : embeddingSettings?.embeddingConfig?.model ?? newProviderInfo.defaultModel)\n\n let modelName: string\n let dimension: number\n\n if (newModelId === 'custom') {\n modelName = customModelName.trim()\n dimension = customDimension\n if (!modelName) {\n flash(t('search.settings.errors.modelRequired', 'Please enter a model name'), 'error')\n return\n }\n if (dimension <= 0) {\n flash(t('search.settings.errors.dimensionRequired', 'Please enter a valid dimension'), 'error')\n return\n }\n } else {\n const newModel = newProviderInfo.models.find((m) => m.id === newModelId) ?? newProviderInfo.models[0]\n modelName = newModel.id\n dimension = newModel.dimension\n }\n\n const newConfig: EmbeddingProviderConfig = {\n providerId: newProviderId,\n model: modelName,\n dimension,\n updatedAt: new Date().toISOString(),\n }\n\n if (embeddingSettings?.indexedDimension || embeddingSettings?.embeddingConfig) {\n setPendingEmbeddingConfig(newConfig)\n setShowEmbeddingConfirmDialog(true)\n } else {\n applyEmbeddingConfig(newConfig)\n }\n }\n\n const handleCancelEmbeddingSelection = () => {\n setSelectedProvider(null)\n setSelectedModel(null)\n setCustomModelName('')\n setCustomDimension(768)\n }\n\n const applyEmbeddingConfig = async (config: EmbeddingProviderConfig) => {\n setEmbeddingSaving(true)\n setShowEmbeddingConfirmDialog(false)\n setPendingEmbeddingConfig(null)\n\n try {\n await readApiResultOrThrow<EmbeddingSettingsResponse>(\n '/api/search/embeddings',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ embeddingConfig: config }),\n },\n { errorMessage: t('search.settings.errors.saveFailed', 'Failed to save settings'), allowNullResult: true },\n )\n setSelectedProvider(null)\n setSelectedModel(null)\n flash(t('search.settings.messages.providerSaved', 'Embedding provider saved'), 'success')\n await onRefreshEmbeddings()\n } catch {\n // Error handled by readApiResultOrThrow\n } finally {\n setEmbeddingSaving(false)\n }\n }\n\n const handleEmbeddingConfirmChange = () => {\n if (pendingEmbeddingConfig) {\n applyEmbeddingConfig(pendingEmbeddingConfig)\n }\n }\n\n const handleEmbeddingCancelChange = () => {\n setShowEmbeddingConfirmDialog(false)\n setPendingEmbeddingConfig(null)\n }\n\n // Vector reindex handlers\n const handleVectorReindexClick = () => {\n setShowVectorReindexDialog(true)\n }\n\n const handleVectorReindexConfirm = async () => {\n setShowVectorReindexDialog(false)\n setVectorReindexing(true)\n try {\n await readApiResultOrThrow<{ ok: boolean }>(\n '/api/search/embeddings/reindex',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ purgeFirst: true }),\n },\n { errorMessage: t('search.settings.errors.reindexFailed', 'Reindex failed'), allowNullResult: true },\n )\n flash(t('search.settings.messages.reindexStarted', 'Reindex started'), 'success')\n await fetchActivityLogs()\n } catch {\n // Error handled by readApiResultOrThrow\n } finally {\n setVectorReindexing(false)\n }\n }\n\n const handleVectorReindexCancel = () => {\n setShowVectorReindexDialog(false)\n }\n\n // Computed values\n const savedProvider = embeddingSettings?.embeddingConfig?.providerId ?? 'openai'\n const savedProviderInfo = EMBEDDING_PROVIDERS[savedProvider]\n const savedModel = embeddingSettings?.embeddingConfig?.model ?? savedProviderInfo.defaultModel\n const savedDimension = embeddingSettings?.embeddingConfig?.dimension ?? savedProviderInfo.models[0]?.dimension ?? 768\n\n const savedModelIsPredefined = savedProviderInfo.models.some((m) => m.id === savedModel)\n const savedCustomModel = !savedModelIsPredefined && savedModel ? { id: savedModel, name: savedModel, dimension: savedDimension } : null\n\n const displayProvider = selectedProvider ?? savedProvider\n const displayProviderInfo = EMBEDDING_PROVIDERS[displayProvider]\n const displayModel = selectedModel ?? (selectedProvider ? displayProviderInfo.defaultModel : savedModel)\n const isCustomModel = displayModel === 'custom'\n\n const displayModelIsSavedCustom = !isCustomModel && displayProvider === savedProvider && savedCustomModel && displayModel === savedCustomModel.id\n\n const displayModelInfo = isCustomModel\n ? null\n : displayModelIsSavedCustom\n ? savedCustomModel\n : displayProviderInfo.models.find((m) => m.id === displayModel) ?? displayProviderInfo.models[0]\n const displayDimension = isCustomModel ? customDimension : (displayModelInfo?.dimension ?? 768)\n\n const hasUnsavedEmbeddingChanges = (selectedProvider !== null && selectedProvider !== savedProvider) ||\n (selectedModel !== null && selectedModel !== savedModel) ||\n (selectedProvider !== null && selectedModel === null && displayProviderInfo.defaultModel !== savedModel) ||\n (isCustomModel && (customModelName.trim() !== '' || customDimension !== 768))\n\n const isEmbeddingConfigured = embeddingSettings?.configuredProviders?.includes(savedProvider)\n const providerOptions: EmbeddingProviderId[] = ['openai', 'google', 'mistral', 'cohere', 'bedrock', 'ollama']\n\n const autoIndexingChecked = embeddingSettings ? embeddingSettings.autoIndexingEnabled : true\n const autoIndexingDisabled = embeddingLoading || embeddingSaving || Boolean(embeddingSettings?.autoIndexingLocked)\n\n return (\n <div className=\"rounded-lg border border-border bg-card p-5 shadow-sm\">\n <h2 className=\"text-lg font-semibold mb-2\">\n {t('search.settings.vector.sectionTitle', 'Vector Search')}\n </h2>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.vector.sectionDescription', 'AI-powered semantic search using embeddings.')}\n </p>\n\n <Tabs defaultValue=\"configuration\">\n <TabsList className=\"mb-4\">\n <TabsTrigger value=\"configuration\">\n {t('search.settings.tabs.configuration', 'Configuration')}\n </TabsTrigger>\n <TabsTrigger value=\"index\">\n {t('search.settings.tabs.indexManagement', 'Index Management')}\n </TabsTrigger>\n <TabsTrigger value=\"activity\">\n {t('search.settings.tabs.activity', 'Activity')}\n </TabsTrigger>\n </TabsList>\n\n {/* Configuration Tab */}\n <TabsContent value=\"configuration\">\n {(embeddingLoading || vectorStoreConfigLoading) ? (\n <div className=\"flex items-center gap-2 text-muted-foreground\">\n <Spinner size=\"sm\" />\n <span>{t('search.settings.loadingLabel', 'Loading settings...')}</span>\n </div>\n ) : (\n <div className=\"space-y-4\">\n {/* Vector Store Driver Status */}\n <div>\n <h3 className=\"text-sm font-semibold mb-2\">{t('search.settings.vector.store', 'Vector Store')}</h3>\n <div className=\"grid gap-2 sm:grid-cols-3\">\n {vectorStoreConfig?.drivers.map((driver) => {\n const isCurrent = driver.id === vectorStoreConfig.currentDriver\n const isReady = driver.configured && driver.implemented\n return (\n <div\n key={driver.id}\n className={`flex items-start gap-3 p-3 rounded-md border ${\n isCurrent && isReady\n ? 'border-status-success-border bg-status-success-bg'\n : !driver.implemented\n ? 'border-border bg-muted/30 opacity-60'\n : 'border-border bg-muted/30'\n }`}\n >\n <div className={`flex h-8 w-8 items-center justify-center rounded-full flex-shrink-0 ${\n isCurrent && isReady\n ? 'bg-status-success-bg text-status-success-icon'\n : 'bg-muted text-muted-foreground'\n }`}>\n <svg className=\"h-4 w-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4\" />\n </svg>\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <p className={`text-sm font-medium ${isCurrent && isReady ? 'text-status-success-text' : ''}`}>\n {driver.name}\n </p>\n {isCurrent && (\n <span className=\"text-overline px-1.5 py-0.5 rounded bg-status-success-bg text-status-success-text\">\n {t('search.settings.vector.active', 'Active')}\n </span>\n )}\n {!driver.implemented && (\n <span className=\"text-overline px-1.5 py-0.5 rounded bg-muted text-muted-foreground\">\n {t('search.settings.vector.comingSoon', 'Coming soon')}\n </span>\n )}\n </div>\n <div className=\"mt-1 space-y-0.5\">\n {driver.envVars.map((envVar) => (\n <div key={envVar.name} className=\"flex items-center gap-1.5\">\n <div className={`h-1.5 w-1.5 rounded-full ${envVar.set ? 'bg-status-success-icon' : 'bg-muted-foreground/40'}`} />\n <code className=\"text-overline text-muted-foreground font-mono\">{envVar.name}</code>\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n })}\n </div>\n </div>\n\n {/* Embedding Provider Selection */}\n <div>\n <h3 className=\"text-sm font-semibold mb-2\">{t('search.settings.vector.providers', 'Embedding Provider')}</h3>\n <p className=\"text-xs text-muted-foreground mb-3\">{t('search.settings.vector.providersHint', 'Select a provider to generate embeddings. Only providers with configured API keys can be selected.')}</p>\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-3 items-start\">\n {providerOptions.map((providerId) => {\n const info = EMBEDDING_PROVIDERS[providerId]\n const isConfigured = embeddingSettings?.configuredProviders?.includes(providerId)\n const isSelected = displayProvider === providerId\n const isCurrentlySaved = savedProvider === providerId\n return (\n <button\n key={providerId}\n type=\"button\"\n onClick={() => isConfigured && handleProviderChange(providerId)}\n disabled={!isConfigured || embeddingLoading || embeddingSaving}\n className={`text-left p-3 rounded-lg border-2 transition-all ${\n isSelected\n ? 'border-primary bg-primary/5 ring-1 ring-primary/20'\n : isConfigured\n ? 'border-border hover:border-primary/50 hover:bg-muted/50 cursor-pointer'\n : 'border-border bg-muted/30 opacity-50 cursor-not-allowed'\n }`}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <p className={`text-sm font-medium ${isSelected ? 'text-primary' : isConfigured ? '' : 'text-muted-foreground'}`}>\n {info.name}\n </p>\n {isCurrentlySaved && isConfigured && (\n <span className=\"text-overline px-1.5 py-0.5 rounded bg-status-success-bg text-status-success-text\">\n {t('search.settings.vector.active', 'Active')}\n </span>\n )}\n </div>\n {isConfigured ? (\n <p className=\"text-xs text-muted-foreground mt-1\">\n {info.models.length} {t('search.settings.vector.modelsAvailable', 'models available')}\n </p>\n ) : (\n <p className=\"text-xs text-muted-foreground mt-1\">\n {t('search.settings.vector.setEnvVar', 'Set')} <code className=\"font-mono text-overline bg-muted px-1 rounded\">{info.envKeyRequired}</code>\n </p>\n )}\n </div>\n <div className={`flex h-5 w-5 items-center justify-center rounded-full flex-shrink-0 ${\n isSelected\n ? 'bg-primary text-primary-foreground'\n : isConfigured\n ? 'bg-status-success-bg text-status-success-icon'\n : 'bg-muted text-muted-foreground'\n }`}>\n {isSelected ? (\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n ) : isConfigured ? (\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n ) : (\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M12 4v16m8-8H4\" />\n </svg>\n )}\n </div>\n </div>\n\n {/* Model Selection */}\n {isSelected && isConfigured && (\n <div className=\"mt-3 pt-3 border-t border-border space-y-2\" onClick={(e) => e.stopPropagation()} onKeyDown={(e) => e.stopPropagation()} role=\"presentation\">\n <div className=\"space-y-1\">\n <Label htmlFor={`model-${providerId}`} className=\"text-xs font-medium\">\n {t('search.settings.model.label', 'Model')}\n </Label>\n <select\n id={`model-${providerId}`}\n className=\"w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50\"\n value={displayModel}\n onChange={(e) => handleModelChange(e.target.value)}\n disabled={embeddingLoading || embeddingSaving}\n >\n {savedCustomModel && displayProvider === savedProvider && (\n <option key={savedCustomModel.id} value={savedCustomModel.id}>\n {savedCustomModel.name} ({savedCustomModel.dimension}d)\n </option>\n )}\n {displayProviderInfo.models.map((model) => (\n <option key={model.id} value={model.id}>\n {model.name} ({model.dimension}d)\n </option>\n ))}\n <option value=\"custom\">{t('search.settings.model.custom', 'Custom...')}</option>\n </select>\n </div>\n\n {isCustomModel && (\n <div className=\"space-y-2 p-2 rounded border border-input bg-muted/30\">\n <input\n type=\"text\"\n className=\"w-full rounded border border-input bg-background px-2 py-1 text-sm\"\n value={customModelName}\n onChange={(e) => setCustomModelName(e.target.value)}\n placeholder={t('search.settings.model.namePlaceholder', 'Model name')}\n disabled={embeddingLoading || embeddingSaving}\n />\n <input\n type=\"number\"\n className=\"w-full rounded border border-input bg-background px-2 py-1 text-sm\"\n value={customDimension}\n onChange={(e) => setCustomDimension(Number(e.target.value) || 768)}\n placeholder=\"768\"\n min={1}\n disabled={embeddingLoading || embeddingSaving}\n />\n </div>\n )}\n\n <div className=\"flex items-center justify-between text-xs\">\n <span className=\"text-muted-foreground\">\n {t('search.settings.dimension.label', 'Dimensions')}: {displayDimension}\n </span>\n {embeddingSettings?.indexedDimension && embeddingSettings.indexedDimension !== displayDimension && (\n <span className=\"text-status-warning-text\">\n {t('search.settings.dimension.mismatch', 'mismatch')}: {embeddingSettings.indexedDimension}\n </span>\n )}\n </div>\n\n {hasUnsavedEmbeddingChanges && (\n <div className=\"flex gap-2 pt-1\">\n <Button type=\"button\" variant=\"default\" size=\"sm\" className=\"flex-1\" onClick={handleApplyEmbeddingChanges} disabled={embeddingLoading || embeddingSaving}>\n {embeddingSaving ? <Spinner size=\"sm\" className=\"mr-1\" /> : null}\n {t('search.settings.actions.apply', 'Apply')}\n </Button>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCancelEmbeddingSelection} disabled={embeddingLoading || embeddingSaving}>\n {t('search.settings.actions.cancel', 'Cancel')}\n </Button>\n </div>\n )}\n </div>\n )}\n </button>\n )\n })}\n </div>\n </div>\n\n {/* Setup Instructions */}\n <div className=\"p-3 rounded-md bg-status-info-bg border border-status-info-border\">\n <div className=\"flex items-start gap-2\">\n <svg className=\"h-5 w-5 text-status-info-icon flex-shrink-0 mt-0.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <div className=\"text-sm text-status-info-text\">\n <p className=\"font-medium mb-1\">{t('search.settings.vector.howTo', 'How to set up')}</p>\n <p className=\"text-xs\">{t('search.settings.vector.howToDescription', 'Add the API key for your preferred provider to your .env file. Only providers with configured API keys can be selected.')}</p>\n </div>\n </div>\n </div>\n </div>\n )}\n </TabsContent>\n\n {/* Index Management Tab */}\n <TabsContent value=\"index\">\n {embeddingLoading ? (\n <div className=\"flex items-center gap-2 text-muted-foreground\">\n <Spinner size=\"sm\" />\n <span>{t('search.settings.loadingLabel', 'Loading settings...')}</span>\n </div>\n ) : !isEmbeddingConfigured ? (\n <div className=\"p-4 rounded-md bg-status-warning-bg border border-status-warning-border\">\n <div className=\"flex items-start gap-3\">\n <svg className=\"h-5 w-5 text-status-warning-icon flex-shrink-0 mt-0.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n </svg>\n <div>\n <p className=\"text-sm font-medium text-status-warning-text\">\n {t('search.settings.vectorNotConfigured', 'No embedding provider configured')}\n </p>\n <p className=\"text-xs text-status-warning-text mt-1\">\n {t('search.settings.vectorNotConfiguredHint', 'Configure an embedding provider in the Configuration tab to enable indexing.')}\n </p>\n </div>\n </div>\n </div>\n ) : (\n <div className=\"space-y-4\">\n {/* Document Count */}\n {embeddingSettings?.documentCount !== null && embeddingSettings?.documentCount !== undefined && (\n <div className=\"rounded-md border border-border p-4 max-w-xs\">\n <p className=\"text-sm text-muted-foreground\">{t('search.settings.vectorDocumentsLabel', 'Embeddings')}</p>\n <p className=\"text-2xl font-bold\">{embeddingSettings.documentCount.toLocaleString()}</p>\n </div>\n )}\n\n {/* Auto-Indexing Toggle */}\n <div className=\"flex items-start gap-4 p-4 rounded-md border border-border\">\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <input\n id=\"search-auto-indexing\"\n type=\"checkbox\"\n className=\"h-4 w-4 rounded border-muted-foreground/40\"\n checked={autoIndexingChecked}\n onChange={(event) => updateAutoIndexing(event.target.checked)}\n disabled={autoIndexingDisabled}\n />\n <Label htmlFor=\"search-auto-indexing\" className=\"text-sm font-medium\">\n {t('search.settings.autoIndexing.label', 'Enable auto-indexing')}\n </Label>\n {embeddingSaving ? <Spinner size=\"sm\" className=\"text-muted-foreground\" /> : null}\n </div>\n <p className=\"text-xs text-muted-foreground mt-1 ml-6\">\n {t('search.settings.autoIndexing.description', 'Automatically index new and updated records for vector search.')}\n </p>\n {embeddingSettings?.autoIndexingLocked && (\n <p className=\"text-xs text-destructive mt-1 ml-6\">\n {t('search.settings.autoIndexing.locked', 'Disabled via environment variable.')}\n </p>\n )}\n </div>\n </div>\n\n {/* Reindex Actions */}\n <div className=\"space-y-3\">\n <h3 className=\"text-sm font-semibold\">{t('search.settings.vectorReindex.title', 'Reindex Data')}</h3>\n <p className=\"text-xs text-muted-foreground\">\n {t('search.settings.vectorReindex.description', 'Rebuild vector embeddings for all indexed entities. This will purge existing data and regenerate all embeddings.')}\n </p>\n\n {/* Active reindex lock banner */}\n {vectorReindexLock && (\n <div className=\"p-3 rounded-md bg-status-info-bg border border-status-info-border\">\n <div className=\"flex items-start gap-3\">\n <Spinner size=\"sm\" className=\"flex-shrink-0 mt-0.5 text-status-info-icon\" />\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-status-info-text\">\n {t('search.settings.reindexInProgress', 'Reindex operation in progress')}\n </p>\n <p className=\"text-xs text-status-info-text mt-1\">\n {t('search.settings.reindexInProgressDetails', 'Action: {{action}} | Started {{minutes}} minutes ago', {\n action: vectorReindexLock.action,\n minutes: vectorReindexLock.elapsedMinutes,\n })}\n </p>\n </div>\n </div>\n </div>\n )}\n\n <div className=\"flex items-center gap-2 p-2 rounded bg-status-warning-bg\">\n <svg className=\"h-4 w-4 text-status-warning-icon flex-shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n </svg>\n <p className=\"text-xs text-status-warning-text\">\n {t('search.settings.vectorReindex.warning', 'This may take a while for large datasets and will consume API credits.')}\n </p>\n </div>\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"sm\"\n onClick={handleVectorReindexClick}\n disabled={embeddingLoading || embeddingSaving || vectorReindexing || vectorReindexLock !== null}\n >\n {vectorReindexing || vectorReindexLock !== null ? (\n <>\n <Spinner size=\"sm\" className=\"mr-2\" />\n {t('search.settings.vectorReindex.running', 'Reindexing...')}\n </>\n ) : (\n t('search.settings.vectorReindex.button', 'Full Reindex')\n )}\n </Button>\n </div>\n </div>\n )}\n </TabsContent>\n\n {/* Activity Tab */}\n <TabsContent value=\"activity\">\n {activityLoading ? (\n <div className=\"flex items-center gap-2 text-muted-foreground\">\n <Spinner size=\"sm\" />\n <span>{t('search.settings.loadingLabel', 'Loading...')}</span>\n </div>\n ) : activityLogs.length === 0 ? (\n <div className=\"p-4 rounded-md bg-muted/50 text-center\">\n <p className=\"text-sm text-muted-foreground\">\n {t('search.settings.activity.noLogs', 'No recent indexing activity')}\n </p>\n </div>\n ) : (\n <div className=\"space-y-2 max-h-80 overflow-y-auto\">\n {activityLogs.map((log) => (\n <div\n key={log.id}\n className={`p-2 rounded-md text-sm ${\n log.level === 'error'\n ? 'bg-status-error-bg border border-status-error-border'\n : 'bg-muted/50'\n }`}\n >\n <div className=\"flex items-start gap-2\">\n {log.level === 'error' && (\n <svg className=\"h-4 w-4 text-status-error-icon flex-shrink-0 mt-0.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n )}\n <div className=\"flex-1 min-w-0\">\n <p className={`text-xs ${log.level === 'error' ? 'text-status-error-text' : 'text-foreground'}`}>\n {log.message}\n </p>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {(() => {\n const d = new Date(log.occurredAt)\n const pad = (n: number) => n.toString().padStart(2, '0')\n return `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}`\n })()}\n {log.entityType && ` \u00B7 ${log.entityType}`}\n </p>\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n <div className=\"mt-3\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={fetchActivityLogs}\n disabled={activityLoading}\n >\n {activityLoading ? (\n <>\n <Spinner size=\"sm\" className=\"mr-2\" />\n {t('search.settings.loadingLabel', 'Loading...')}\n </>\n ) : (\n t('search.settings.refreshLabel', 'Refresh')\n )}\n </Button>\n </div>\n </TabsContent>\n </Tabs>\n\n {/* Vector Reindex Confirmation Dialog */}\n {showVectorReindexDialog && (\n <div className=\"fixed inset-0 z-modal flex items-center justify-center bg-black/50\">\n <div className=\"mx-4 max-w-md rounded-lg border border-border bg-card p-6 shadow-lg\">\n <h3 className=\"text-lg font-semibold mb-2\">{t('search.settings.reindex.confirmTitle', 'Confirm Reindex')}</h3>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.reindex.confirmDescription', 'This will rebuild all vector embeddings. Existing data will be purged first.')}\n </p>\n <div className=\"flex justify-end gap-3\">\n <Button type=\"button\" variant=\"outline\" onClick={handleVectorReindexCancel}>\n {t('search.settings.actions.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" variant=\"default\" onClick={handleVectorReindexConfirm}>\n {t('search.settings.reindex.confirmButton', 'Start Reindex')}\n </Button>\n </div>\n </div>\n </div>\n )}\n\n {/* Embedding Provider Change Confirmation Dialog */}\n {showEmbeddingConfirmDialog && pendingEmbeddingConfig && (\n <div className=\"fixed inset-0 z-modal flex items-center justify-center bg-black/50\">\n <div className=\"mx-4 max-w-lg rounded-lg border border-border bg-card p-6 shadow-lg\">\n <h3 className=\"text-lg font-semibold mb-2\">{t('search.settings.change.title', 'Confirm Provider Change')}</h3>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.change.description', 'Changing the embedding provider will require reindexing all data.')}\n </p>\n <div className=\"mb-4 p-3 rounded-md bg-muted/50 text-sm\">\n <p className=\"font-medium\">\n {embeddingSettings?.embeddingConfig\n ? `${EMBEDDING_PROVIDERS[embeddingSettings.embeddingConfig.providerId].name} (${embeddingSettings.embeddingConfig.model})`\n : 'Default'}\n {' \u2192 '}\n {EMBEDDING_PROVIDERS[pendingEmbeddingConfig.providerId].name} ({pendingEmbeddingConfig.model})\n </p>\n <p className=\"text-muted-foreground\">\n {embeddingSettings?.indexedDimension ?? 'N/A'} \u2192 {pendingEmbeddingConfig.dimension} dimensions\n </p>\n </div>\n <ul className=\"mb-4 space-y-1 text-sm\">\n <li className=\"flex items-start gap-2\">\n <span className=\"text-destructive\">\u2022</span>\n <span>{t('search.settings.change.bullet1', 'Existing vector data will be cleared')}</span>\n </li>\n <li className=\"flex items-start gap-2\">\n <span className=\"text-destructive\">\u2022</span>\n <span>{t('search.settings.change.bullet2', 'Vector search will be unavailable during reindex')}</span>\n </li>\n </ul>\n <div className=\"flex justify-end gap-3\">\n <Button type=\"button\" variant=\"outline\" onClick={handleEmbeddingCancelChange} disabled={embeddingSaving}>\n {t('search.settings.actions.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" variant=\"destructive\" onClick={handleEmbeddingConfirmChange} disabled={embeddingSaving}>\n {embeddingSaving ? <Spinner size=\"sm\" className=\"mr-2\" /> : null}\n {t('search.settings.actions.confirm', 'Confirm')}\n </Button>\n </div>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default VectorSearchSection\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useAppEvent } from '@open-mercato/ui/backend/injection/useAppEvent'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '@open-mercato/ui/primitives/tabs'\n\n// Types\ntype EmbeddingProviderId = 'openai' | 'google' | 'mistral' | 'cohere' | 'bedrock' | 'ollama'\n\ntype EmbeddingProviderConfig = {\n providerId: EmbeddingProviderId\n model: string\n dimension: number\n outputDimensionality?: number\n baseUrl?: string\n updatedAt: string\n}\n\ntype EmbeddingModelInfo = {\n id: string\n name: string\n dimension: number\n configurableDimension?: boolean\n minDimension?: number\n maxDimension?: number\n}\n\ntype EmbeddingProviderInfo = {\n name: string\n envKeyRequired: string\n defaultModel: string\n models: EmbeddingModelInfo[]\n}\n\ntype EmbeddingSettings = {\n openaiConfigured: boolean\n autoIndexingEnabled: boolean\n autoIndexingLocked: boolean\n lockReason: string | null\n embeddingConfig: EmbeddingProviderConfig | null\n embeddingConfigSource?: 'tenant' | 'instance' | 'env'\n configuredProviders: EmbeddingProviderId[]\n providerAvailability?: { providerId: EmbeddingProviderId; available: boolean; reason?: string; models?: number }[]\n indexedDimension: number | null\n reindexRequired: boolean\n documentCount: number | null\n}\n\ntype EmbeddingSettingsResponse = {\n settings?: EmbeddingSettings\n error?: string\n}\n\ntype VectorDriverId = 'pgvector' | 'qdrant' | 'chromadb'\n\ntype VectorDriverEnvVar = {\n name: string\n set: boolean\n hint: string\n}\n\ntype VectorDriverStatus = {\n id: VectorDriverId\n name: string\n configured: boolean\n implemented: boolean\n envVars: VectorDriverEnvVar[]\n}\n\ntype VectorStoreConfigResponse = {\n currentDriver: VectorDriverId\n configured: boolean\n drivers: VectorDriverStatus[]\n}\n\ntype ReindexLock = {\n type: 'fulltext' | 'vector'\n action: string\n startedAt: string\n elapsedMinutes: number\n}\n\ntype ActivityLog = {\n id: string\n source: string\n handler: string\n level: 'info' | 'error' | 'warn'\n entityType: string | null\n recordId: string | null\n message: string\n details: unknown\n occurredAt: string\n}\n\nconst EMBEDDING_PROVIDERS: Record<EmbeddingProviderId, EmbeddingProviderInfo> = {\n openai: {\n name: 'OpenAI',\n envKeyRequired: 'OPENAI_API_KEY',\n defaultModel: 'text-embedding-3-small',\n models: [\n { id: 'text-embedding-3-small', name: 'text-embedding-3-small', dimension: 1536 },\n { id: 'text-embedding-3-large', name: 'text-embedding-3-large', dimension: 3072, configurableDimension: true, minDimension: 256, maxDimension: 3072 },\n { id: 'text-embedding-ada-002', name: 'text-embedding-ada-002', dimension: 1536 },\n ],\n },\n google: {\n name: 'Google Generative AI',\n envKeyRequired: 'GOOGLE_GENERATIVE_AI_API_KEY',\n defaultModel: 'text-embedding-004',\n models: [\n { id: 'text-embedding-004', name: 'text-embedding-004', dimension: 768, configurableDimension: true, minDimension: 1, maxDimension: 768 },\n { id: 'embedding-001', name: 'embedding-001', dimension: 768 },\n ],\n },\n mistral: {\n name: 'Mistral',\n envKeyRequired: 'MISTRAL_API_KEY',\n defaultModel: 'mistral-embed',\n models: [\n { id: 'mistral-embed', name: 'mistral-embed', dimension: 1024 },\n ],\n },\n cohere: {\n name: 'Cohere',\n envKeyRequired: 'COHERE_API_KEY',\n defaultModel: 'embed-english-v3.0',\n models: [\n { id: 'embed-english-v3.0', name: 'embed-english-v3.0', dimension: 1024 },\n { id: 'embed-multilingual-v3.0', name: 'embed-multilingual-v3.0', dimension: 1024 },\n { id: 'embed-english-light-v3.0', name: 'embed-english-light-v3.0', dimension: 384 },\n { id: 'embed-multilingual-light-v3.0', name: 'embed-multilingual-light-v3.0', dimension: 384 },\n ],\n },\n bedrock: {\n name: 'Amazon Bedrock',\n envKeyRequired: 'AWS_ACCESS_KEY_ID',\n defaultModel: 'amazon.titan-embed-text-v2:0',\n models: [\n { id: 'amazon.titan-embed-text-v2:0', name: 'Titan Embed Text v2', dimension: 1024, configurableDimension: true, minDimension: 256, maxDimension: 1024 },\n { id: 'amazon.titan-embed-text-v1', name: 'Titan Embed Text v1', dimension: 1536 },\n { id: 'cohere.embed-english-v3', name: 'Cohere Embed English v3', dimension: 1024 },\n { id: 'cohere.embed-multilingual-v3', name: 'Cohere Embed Multilingual v3', dimension: 1024 },\n ],\n },\n ollama: {\n name: 'Ollama (Local)',\n envKeyRequired: 'OLLAMA_BASE_URL',\n defaultModel: 'nomic-embed-text',\n models: [\n { id: 'nomic-embed-text', name: 'nomic-embed-text', dimension: 768 },\n { id: 'mxbai-embed-large', name: 'mxbai-embed-large', dimension: 1024 },\n { id: 'all-minilm', name: 'all-minilm', dimension: 384 },\n { id: 'snowflake-arctic-embed', name: 'snowflake-arctic-embed', dimension: 1024 },\n ],\n },\n}\n\nexport type VectorSearchSectionProps = {\n embeddingSettings: EmbeddingSettings | null\n embeddingLoading: boolean\n vectorStoreConfig: VectorStoreConfigResponse | null\n vectorStoreConfigLoading: boolean\n vectorReindexLock: ReindexLock | null\n onEmbeddingSettingsUpdate: (settings: EmbeddingSettings) => void\n onRefreshEmbeddings: () => Promise<void>\n}\n\nexport function VectorSearchSection({\n embeddingSettings,\n embeddingLoading,\n vectorStoreConfig,\n vectorStoreConfigLoading,\n vectorReindexLock,\n onEmbeddingSettingsUpdate,\n onRefreshEmbeddings,\n}: VectorSearchSectionProps) {\n const t = useT()\n const [embeddingSaving, setEmbeddingSaving] = React.useState(false)\n const autoIndexingPreviousRef = React.useRef<boolean>(true)\n\n // Staged embedding selection\n const [selectedProvider, setSelectedProvider] = React.useState<EmbeddingProviderId | null>(null)\n const [selectedModel, setSelectedModel] = React.useState<string | null>(null)\n const [customModelName, setCustomModelName] = React.useState<string>('')\n const [customDimension, setCustomDimension] = React.useState<number>(768)\n\n const [pendingEmbeddingConfig, setPendingEmbeddingConfig] = React.useState<EmbeddingProviderConfig | null>(null)\n const [showEmbeddingConfirmDialog, setShowEmbeddingConfirmDialog] = React.useState(false)\n\n // Vector reindex state\n const [vectorReindexing, setVectorReindexing] = React.useState(false)\n const [showVectorReindexDialog, setShowVectorReindexDialog] = React.useState(false)\n\n // Activity logs state\n const [activityLogs, setActivityLogs] = React.useState<ActivityLog[]>([])\n const [activityLoading, setActivityLoading] = React.useState(true)\n\n // Fetch activity logs\n const fetchActivityLogs = React.useCallback(async () => {\n setActivityLoading(true)\n try {\n const response = await fetch('/api/query_index/status')\n if (response.ok) {\n const body = await response.json() as { logs?: ActivityLog[]; errors?: ActivityLog[] }\n const allLogs: ActivityLog[] = []\n if (body.logs) {\n allLogs.push(...body.logs)\n }\n if (body.errors) {\n allLogs.push(...body.errors.map(err => ({ ...err, level: 'error' as const })))\n }\n // Filter for vector-related logs\n const vectorLogs = allLogs.filter(log => {\n const lowerSource = log.source?.toLowerCase() ?? ''\n const lowerMessage = log.message?.toLowerCase() ?? ''\n const lowerHandler = log.handler?.toLowerCase() ?? ''\n return lowerSource.includes('vector') || lowerMessage.includes('vector') ||\n lowerMessage.includes('embedding') || lowerHandler.includes('vector')\n })\n vectorLogs.sort((a, b) => new Date(b.occurredAt).getTime() - new Date(a.occurredAt).getTime())\n setActivityLogs(vectorLogs.slice(0, 50))\n }\n } catch {\n // Silently fail\n } finally {\n setActivityLoading(false)\n }\n }, [])\n\n React.useEffect(() => {\n fetchActivityLogs()\n }, [fetchActivityLogs])\n\n useAppEvent('progress.job.updated', () => {\n void fetchActivityLogs()\n }, [fetchActivityLogs])\n\n useAppEvent('progress.job.completed', () => {\n void fetchActivityLogs()\n }, [fetchActivityLogs])\n\n useAppEvent('om:bridge:reconnected', () => {\n void fetchActivityLogs()\n }, [fetchActivityLogs])\n\n // Update auto-indexing\n const updateAutoIndexing = React.useCallback(async (nextValue: boolean) => {\n autoIndexingPreviousRef.current = embeddingSettings?.autoIndexingEnabled ?? true\n if (embeddingSettings) {\n onEmbeddingSettingsUpdate({ ...embeddingSettings, autoIndexingEnabled: nextValue })\n }\n setEmbeddingSaving(true)\n try {\n const body = await readApiResultOrThrow<EmbeddingSettingsResponse>(\n '/api/search/embeddings',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ autoIndexingEnabled: nextValue }),\n },\n { errorMessage: t('search.settings.errors.saveFailed', 'Failed to save settings'), allowNullResult: true },\n )\n if (body?.settings) {\n onEmbeddingSettingsUpdate(body.settings)\n autoIndexingPreviousRef.current = body.settings.autoIndexingEnabled\n }\n flash(t('search.settings.messages.saved', 'Settings saved'), 'success')\n } catch {\n if (embeddingSettings) {\n onEmbeddingSettingsUpdate({ ...embeddingSettings, autoIndexingEnabled: autoIndexingPreviousRef.current })\n }\n } finally {\n setEmbeddingSaving(false)\n }\n }, [embeddingSettings, onEmbeddingSettingsUpdate, t])\n\n // Provider handlers\n const handleProviderChange = (providerId: EmbeddingProviderId) => {\n setSelectedProvider(providerId)\n setSelectedModel(null)\n setCustomModelName('')\n setCustomDimension(768)\n }\n\n const handleModelChange = (modelId: string) => {\n setSelectedModel(modelId)\n }\n\n const handleApplyEmbeddingChanges = () => {\n const newProviderId = selectedProvider ?? embeddingSettings?.embeddingConfig?.providerId ?? 'openai'\n const newProviderInfo = EMBEDDING_PROVIDERS[newProviderId]\n const newModelId = selectedModel ?? (selectedProvider ? newProviderInfo.defaultModel : embeddingSettings?.embeddingConfig?.model ?? newProviderInfo.defaultModel)\n\n let modelName: string\n let dimension: number\n\n if (newModelId === 'custom') {\n modelName = customModelName.trim()\n dimension = customDimension\n if (!modelName) {\n flash(t('search.settings.errors.modelRequired', 'Please enter a model name'), 'error')\n return\n }\n if (dimension <= 0) {\n flash(t('search.settings.errors.dimensionRequired', 'Please enter a valid dimension'), 'error')\n return\n }\n } else {\n const newModel = newProviderInfo.models.find((m) => m.id === newModelId) ?? newProviderInfo.models[0]\n modelName = newModel.id\n dimension = newModel.dimension\n }\n\n const newConfig: EmbeddingProviderConfig = {\n providerId: newProviderId,\n model: modelName,\n dimension,\n updatedAt: new Date().toISOString(),\n }\n\n if (embeddingSettings?.indexedDimension || embeddingSettings?.embeddingConfig) {\n setPendingEmbeddingConfig(newConfig)\n setShowEmbeddingConfirmDialog(true)\n } else {\n applyEmbeddingConfig(newConfig)\n }\n }\n\n const handleCancelEmbeddingSelection = () => {\n setSelectedProvider(null)\n setSelectedModel(null)\n setCustomModelName('')\n setCustomDimension(768)\n }\n\n const applyEmbeddingConfig = async (config: EmbeddingProviderConfig) => {\n setEmbeddingSaving(true)\n setShowEmbeddingConfirmDialog(false)\n setPendingEmbeddingConfig(null)\n\n try {\n await readApiResultOrThrow<EmbeddingSettingsResponse>(\n '/api/search/embeddings',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ embeddingConfig: config }),\n },\n { errorMessage: t('search.settings.errors.saveFailed', 'Failed to save settings'), allowNullResult: true },\n )\n setSelectedProvider(null)\n setSelectedModel(null)\n flash(t('search.settings.messages.providerSaved', 'Embedding provider saved'), 'success')\n await onRefreshEmbeddings()\n } catch {\n // Error handled by readApiResultOrThrow\n } finally {\n setEmbeddingSaving(false)\n }\n }\n\n const handleEmbeddingConfirmChange = () => {\n if (pendingEmbeddingConfig) {\n applyEmbeddingConfig(pendingEmbeddingConfig)\n }\n }\n\n const handleEmbeddingCancelChange = () => {\n setShowEmbeddingConfirmDialog(false)\n setPendingEmbeddingConfig(null)\n }\n\n // Vector reindex handlers\n const handleVectorReindexClick = () => {\n setShowVectorReindexDialog(true)\n }\n\n const handleVectorReindexConfirm = async () => {\n setShowVectorReindexDialog(false)\n setVectorReindexing(true)\n try {\n await readApiResultOrThrow<{ ok: boolean }>(\n '/api/search/embeddings/reindex',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ purgeFirst: true }),\n },\n { errorMessage: t('search.settings.errors.reindexFailed', 'Reindex failed'), allowNullResult: true },\n )\n flash(t('search.settings.messages.reindexStarted', 'Reindex started'), 'success')\n await fetchActivityLogs()\n } catch {\n // Error handled by readApiResultOrThrow\n } finally {\n setVectorReindexing(false)\n }\n }\n\n const handleVectorReindexCancel = () => {\n setShowVectorReindexDialog(false)\n }\n\n // Computed values\n const savedProvider = embeddingSettings?.embeddingConfig?.providerId ?? 'openai'\n const savedProviderInfo = EMBEDDING_PROVIDERS[savedProvider]\n const savedModel = embeddingSettings?.embeddingConfig?.model ?? savedProviderInfo.defaultModel\n const savedDimension = embeddingSettings?.embeddingConfig?.dimension ?? savedProviderInfo.models[0]?.dimension ?? 768\n\n const savedModelIsPredefined = savedProviderInfo.models.some((m) => m.id === savedModel)\n const savedCustomModel = !savedModelIsPredefined && savedModel ? { id: savedModel, name: savedModel, dimension: savedDimension } : null\n\n const displayProvider = selectedProvider ?? savedProvider\n const displayProviderInfo = EMBEDDING_PROVIDERS[displayProvider]\n const displayModel = selectedModel ?? (selectedProvider ? displayProviderInfo.defaultModel : savedModel)\n const isCustomModel = displayModel === 'custom'\n\n const displayModelIsSavedCustom = !isCustomModel && displayProvider === savedProvider && savedCustomModel && displayModel === savedCustomModel.id\n\n const displayModelInfo = isCustomModel\n ? null\n : displayModelIsSavedCustom\n ? savedCustomModel\n : displayProviderInfo.models.find((m) => m.id === displayModel) ?? displayProviderInfo.models[0]\n const displayDimension = isCustomModel ? customDimension : (displayModelInfo?.dimension ?? 768)\n\n const hasUnsavedEmbeddingChanges = (selectedProvider !== null && selectedProvider !== savedProvider) ||\n (selectedModel !== null && selectedModel !== savedModel) ||\n (selectedProvider !== null && selectedModel === null && displayProviderInfo.defaultModel !== savedModel) ||\n (isCustomModel && (customModelName.trim() !== '' || customDimension !== 768))\n\n const isEmbeddingConfigured = embeddingSettings?.configuredProviders?.includes(savedProvider)\n const providerOptions: EmbeddingProviderId[] = ['openai', 'google', 'mistral', 'cohere', 'bedrock', 'ollama']\n\n const autoIndexingChecked = embeddingSettings ? embeddingSettings.autoIndexingEnabled : true\n const autoIndexingDisabled = embeddingLoading || embeddingSaving || Boolean(embeddingSettings?.autoIndexingLocked)\n\n return (\n <div className=\"rounded-lg border border-border bg-card p-5 shadow-sm\">\n <h2 className=\"text-lg font-semibold mb-2\">\n {t('search.settings.vector.sectionTitle', 'Vector Search')}\n </h2>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.vector.sectionDescription', 'AI-powered semantic search using embeddings.')}\n </p>\n\n <Tabs defaultValue=\"configuration\">\n <TabsList className=\"mb-4\">\n <TabsTrigger value=\"configuration\">\n {t('search.settings.tabs.configuration', 'Configuration')}\n </TabsTrigger>\n <TabsTrigger value=\"index\">\n {t('search.settings.tabs.indexManagement', 'Index Management')}\n </TabsTrigger>\n <TabsTrigger value=\"activity\">\n {t('search.settings.tabs.activity', 'Activity')}\n </TabsTrigger>\n </TabsList>\n\n {/* Configuration Tab */}\n <TabsContent value=\"configuration\">\n {(embeddingLoading || vectorStoreConfigLoading) ? (\n <div className=\"flex items-center gap-2 text-muted-foreground\">\n <Spinner size=\"sm\" />\n <span>{t('search.settings.loadingLabel', 'Loading settings...')}</span>\n </div>\n ) : (\n <div className=\"space-y-4\">\n {/* Vector Store Driver Status */}\n <div>\n <h3 className=\"text-sm font-semibold mb-2\">{t('search.settings.vector.store', 'Vector Store')}</h3>\n <div className=\"grid gap-2 sm:grid-cols-3\">\n {vectorStoreConfig?.drivers.map((driver) => {\n const isCurrent = driver.id === vectorStoreConfig.currentDriver\n const isReady = driver.configured && driver.implemented\n return (\n <div\n key={driver.id}\n className={`flex items-start gap-3 p-3 rounded-md border ${\n isCurrent && isReady\n ? 'border-status-success-border bg-status-success-bg'\n : !driver.implemented\n ? 'border-border bg-muted/30 opacity-60'\n : 'border-border bg-muted/30'\n }`}\n >\n <div className={`flex h-8 w-8 items-center justify-center rounded-full flex-shrink-0 ${\n isCurrent && isReady\n ? 'bg-status-success-bg text-status-success-icon'\n : 'bg-muted text-muted-foreground'\n }`}>\n <svg className=\"h-4 w-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4\" />\n </svg>\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <p className={`text-sm font-medium ${isCurrent && isReady ? 'text-status-success-text' : ''}`}>\n {driver.name}\n </p>\n {isCurrent && (\n <span className=\"text-overline px-1.5 py-0.5 rounded bg-status-success-bg text-status-success-text\">\n {t('search.settings.vector.active', 'Active')}\n </span>\n )}\n {!driver.implemented && (\n <span className=\"text-overline px-1.5 py-0.5 rounded bg-muted text-muted-foreground\">\n {t('search.settings.vector.comingSoon', 'Coming soon')}\n </span>\n )}\n </div>\n <div className=\"mt-1 space-y-0.5\">\n {driver.envVars.map((envVar) => (\n <div key={envVar.name} className=\"flex items-center gap-1.5\">\n <div className={`h-1.5 w-1.5 rounded-full ${envVar.set ? 'bg-status-success-icon' : 'bg-muted-foreground/40'}`} />\n <code className=\"text-overline text-muted-foreground font-mono\">{envVar.name}</code>\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n })}\n </div>\n </div>\n\n {/* Embedding Provider Selection */}\n <div>\n <h3 className=\"text-sm font-semibold mb-2\">{t('search.settings.vector.providers', 'Embedding Provider')}</h3>\n <p className=\"text-xs text-muted-foreground mb-1\">{t('search.settings.vector.providersHint', 'Select a provider to generate embeddings. Only reachable providers can be selected.')}</p>\n {embeddingSettings?.embeddingConfigSource && embeddingSettings.embeddingConfigSource !== 'tenant' && (\n <p className=\"text-xs text-muted-foreground mb-3\">\n {t('search.settings.vector.inheritingDefault', 'This tenant is inheriting the instance/environment default. Saving a provider creates an override for this tenant.')}\n </p>\n )}\n {embeddingSettings?.embeddingConfigSource === 'tenant' && (\n <p className=\"text-xs text-muted-foreground mb-3\">\n {t('search.settings.vector.usingTenantConfig', 'This tenant is using its own embedding settings.')}\n </p>\n )}\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-3 items-start\">\n {providerOptions.map((providerId) => {\n const info = EMBEDDING_PROVIDERS[providerId]\n const availability = embeddingSettings?.providerAvailability?.find((entry) => entry.providerId === providerId)\n const isConfigured = availability\n ? availability.available\n : embeddingSettings?.configuredProviders?.includes(providerId)\n const isSelected = displayProvider === providerId\n const isCurrentlySaved = savedProvider === providerId\n return (\n <button\n key={providerId}\n type=\"button\"\n onClick={() => isConfigured && handleProviderChange(providerId)}\n disabled={!isConfigured || embeddingLoading || embeddingSaving}\n className={`text-left p-3 rounded-lg border-2 transition-all ${\n isSelected\n ? 'border-primary bg-primary/5 ring-1 ring-primary/20'\n : isConfigured\n ? 'border-border hover:border-primary/50 hover:bg-muted/50 cursor-pointer'\n : 'border-border bg-muted/30 opacity-50 cursor-not-allowed'\n }`}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <p className={`text-sm font-medium ${isSelected ? 'text-primary' : isConfigured ? '' : 'text-muted-foreground'}`}>\n {info.name}\n </p>\n {isCurrentlySaved && isConfigured && (\n <span className=\"text-overline px-1.5 py-0.5 rounded bg-status-success-bg text-status-success-text\">\n {t('search.settings.vector.active', 'Active')}\n </span>\n )}\n </div>\n {isConfigured ? (\n <p className=\"text-xs text-muted-foreground mt-1\">\n {info.models.length} {t('search.settings.vector.modelsAvailable', 'models available')}\n </p>\n ) : availability?.reason ? (\n <p className=\"text-xs text-status-warning-text mt-1\">\n {availability.reason}\n </p>\n ) : (\n <p className=\"text-xs text-muted-foreground mt-1\">\n {t('search.settings.vector.setEnvVar', 'Set')} <code className=\"font-mono text-overline bg-muted px-1 rounded\">{info.envKeyRequired}</code>\n </p>\n )}\n </div>\n <div className={`flex h-5 w-5 items-center justify-center rounded-full flex-shrink-0 ${\n isSelected\n ? 'bg-primary text-primary-foreground'\n : isConfigured\n ? 'bg-status-success-bg text-status-success-icon'\n : 'bg-muted text-muted-foreground'\n }`}>\n {isSelected ? (\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n ) : isConfigured ? (\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n ) : (\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M12 4v16m8-8H4\" />\n </svg>\n )}\n </div>\n </div>\n\n {/* Model Selection */}\n {isSelected && isConfigured && (\n <div className=\"mt-3 pt-3 border-t border-border space-y-2\" onClick={(e) => e.stopPropagation()} onKeyDown={(e) => e.stopPropagation()} role=\"presentation\">\n <div className=\"space-y-1\">\n <Label htmlFor={`model-${providerId}`} className=\"text-xs font-medium\">\n {t('search.settings.model.label', 'Model')}\n </Label>\n <select\n id={`model-${providerId}`}\n className=\"w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50\"\n value={displayModel}\n onChange={(e) => handleModelChange(e.target.value)}\n disabled={embeddingLoading || embeddingSaving}\n >\n {savedCustomModel && displayProvider === savedProvider && (\n <option key={savedCustomModel.id} value={savedCustomModel.id}>\n {savedCustomModel.name} ({savedCustomModel.dimension}d)\n </option>\n )}\n {displayProviderInfo.models.map((model) => (\n <option key={model.id} value={model.id}>\n {model.name} ({model.dimension}d)\n </option>\n ))}\n <option value=\"custom\">{t('search.settings.model.custom', 'Custom...')}</option>\n </select>\n </div>\n\n {isCustomModel && (\n <div className=\"space-y-2 p-2 rounded border border-input bg-muted/30\">\n <input\n type=\"text\"\n className=\"w-full rounded border border-input bg-background px-2 py-1 text-sm\"\n value={customModelName}\n onChange={(e) => setCustomModelName(e.target.value)}\n placeholder={t('search.settings.model.namePlaceholder', 'Model name')}\n disabled={embeddingLoading || embeddingSaving}\n />\n <input\n type=\"number\"\n className=\"w-full rounded border border-input bg-background px-2 py-1 text-sm\"\n value={customDimension}\n onChange={(e) => setCustomDimension(Number(e.target.value) || 768)}\n placeholder=\"768\"\n min={1}\n disabled={embeddingLoading || embeddingSaving}\n />\n </div>\n )}\n\n <div className=\"flex items-center justify-between text-xs\">\n <span className=\"text-muted-foreground\">\n {t('search.settings.dimension.label', 'Dimensions')}: {displayDimension}\n </span>\n {embeddingSettings?.indexedDimension && embeddingSettings.indexedDimension !== displayDimension && (\n <span className=\"text-status-warning-text\">\n {t('search.settings.dimension.mismatch', 'mismatch')}: {embeddingSettings.indexedDimension}\n </span>\n )}\n </div>\n\n {hasUnsavedEmbeddingChanges && (\n <div className=\"flex gap-2 pt-1\">\n <Button type=\"button\" variant=\"default\" size=\"sm\" className=\"flex-1\" onClick={handleApplyEmbeddingChanges} disabled={embeddingLoading || embeddingSaving}>\n {embeddingSaving ? <Spinner size=\"sm\" className=\"mr-1\" /> : null}\n {t('search.settings.actions.apply', 'Apply')}\n </Button>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCancelEmbeddingSelection} disabled={embeddingLoading || embeddingSaving}>\n {t('search.settings.actions.cancel', 'Cancel')}\n </Button>\n </div>\n )}\n </div>\n )}\n </button>\n )\n })}\n </div>\n </div>\n\n {/* Setup Instructions */}\n <div className=\"p-3 rounded-md bg-status-info-bg border border-status-info-border\">\n <div className=\"flex items-start gap-2\">\n <svg className=\"h-5 w-5 text-status-info-icon flex-shrink-0 mt-0.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <div className=\"text-sm text-status-info-text\">\n <p className=\"font-medium mb-1\">{t('search.settings.vector.howTo', 'How to set up')}</p>\n <p className=\"text-xs\">{t('search.settings.vector.howToDescription', 'Add the API key for your preferred provider to your .env file. Only providers with configured API keys can be selected.')}</p>\n </div>\n </div>\n </div>\n </div>\n )}\n </TabsContent>\n\n {/* Index Management Tab */}\n <TabsContent value=\"index\">\n {embeddingLoading ? (\n <div className=\"flex items-center gap-2 text-muted-foreground\">\n <Spinner size=\"sm\" />\n <span>{t('search.settings.loadingLabel', 'Loading settings...')}</span>\n </div>\n ) : !isEmbeddingConfigured ? (\n <div className=\"p-4 rounded-md bg-status-warning-bg border border-status-warning-border\">\n <div className=\"flex items-start gap-3\">\n <svg className=\"h-5 w-5 text-status-warning-icon flex-shrink-0 mt-0.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n </svg>\n <div>\n <p className=\"text-sm font-medium text-status-warning-text\">\n {t('search.settings.vectorNotConfigured', 'No embedding provider configured')}\n </p>\n <p className=\"text-xs text-status-warning-text mt-1\">\n {t('search.settings.vectorNotConfiguredHint', 'Configure an embedding provider in the Configuration tab to enable indexing.')}\n </p>\n </div>\n </div>\n </div>\n ) : (\n <div className=\"space-y-4\">\n {/* Document Count */}\n {embeddingSettings?.documentCount !== null && embeddingSettings?.documentCount !== undefined && (\n <div className=\"rounded-md border border-border p-4 max-w-xs\">\n <p className=\"text-sm text-muted-foreground\">{t('search.settings.vectorDocumentsLabel', 'Embeddings')}</p>\n <p className=\"text-2xl font-bold\">{embeddingSettings.documentCount.toLocaleString()}</p>\n </div>\n )}\n\n {/* Auto-Indexing Toggle */}\n <div className=\"flex items-start gap-4 p-4 rounded-md border border-border\">\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <input\n id=\"search-auto-indexing\"\n type=\"checkbox\"\n className=\"h-4 w-4 rounded border-muted-foreground/40\"\n checked={autoIndexingChecked}\n onChange={(event) => updateAutoIndexing(event.target.checked)}\n disabled={autoIndexingDisabled}\n />\n <Label htmlFor=\"search-auto-indexing\" className=\"text-sm font-medium\">\n {t('search.settings.autoIndexing.label', 'Enable auto-indexing')}\n </Label>\n {embeddingSaving ? <Spinner size=\"sm\" className=\"text-muted-foreground\" /> : null}\n </div>\n <p className=\"text-xs text-muted-foreground mt-1 ml-6\">\n {t('search.settings.autoIndexing.description', 'Automatically index new and updated records for vector search.')}\n </p>\n {embeddingSettings?.autoIndexingLocked && (\n <p className=\"text-xs text-destructive mt-1 ml-6\">\n {t('search.settings.autoIndexing.locked', 'Disabled via environment variable.')}\n </p>\n )}\n </div>\n </div>\n\n {/* Reindex Actions */}\n <div className=\"space-y-3\">\n <h3 className=\"text-sm font-semibold\">{t('search.settings.vectorReindex.title', 'Reindex Data')}</h3>\n <p className=\"text-xs text-muted-foreground\">\n {t('search.settings.vectorReindex.description', 'Rebuild vector embeddings for all indexed entities. This will purge existing data and regenerate all embeddings.')}\n </p>\n\n {/* Active reindex lock banner */}\n {vectorReindexLock && (\n <div className=\"p-3 rounded-md bg-status-info-bg border border-status-info-border\">\n <div className=\"flex items-start gap-3\">\n <Spinner size=\"sm\" className=\"flex-shrink-0 mt-0.5 text-status-info-icon\" />\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-status-info-text\">\n {t('search.settings.reindexInProgress', 'Reindex operation in progress')}\n </p>\n <p className=\"text-xs text-status-info-text mt-1\">\n {t('search.settings.reindexInProgressDetails', 'Action: {{action}} | Started {{minutes}} minutes ago', {\n action: vectorReindexLock.action,\n minutes: vectorReindexLock.elapsedMinutes,\n })}\n </p>\n </div>\n </div>\n </div>\n )}\n\n <div className=\"flex items-center gap-2 p-2 rounded bg-status-warning-bg\">\n <svg className=\"h-4 w-4 text-status-warning-icon flex-shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n </svg>\n <p className=\"text-xs text-status-warning-text\">\n {t('search.settings.vectorReindex.warning', 'This may take a while for large datasets and will consume API credits.')}\n </p>\n </div>\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"sm\"\n onClick={handleVectorReindexClick}\n disabled={embeddingLoading || embeddingSaving || vectorReindexing || vectorReindexLock !== null}\n >\n {vectorReindexing || vectorReindexLock !== null ? (\n <>\n <Spinner size=\"sm\" className=\"mr-2\" />\n {t('search.settings.vectorReindex.running', 'Reindexing...')}\n </>\n ) : (\n t('search.settings.vectorReindex.button', 'Full Reindex')\n )}\n </Button>\n </div>\n </div>\n )}\n </TabsContent>\n\n {/* Activity Tab */}\n <TabsContent value=\"activity\">\n {activityLoading ? (\n <div className=\"flex items-center gap-2 text-muted-foreground\">\n <Spinner size=\"sm\" />\n <span>{t('search.settings.loadingLabel', 'Loading...')}</span>\n </div>\n ) : activityLogs.length === 0 ? (\n <div className=\"p-4 rounded-md bg-muted/50 text-center\">\n <p className=\"text-sm text-muted-foreground\">\n {t('search.settings.activity.noLogs', 'No recent indexing activity')}\n </p>\n </div>\n ) : (\n <div className=\"space-y-2 max-h-80 overflow-y-auto\">\n {activityLogs.map((log) => (\n <div\n key={log.id}\n className={`p-2 rounded-md text-sm ${\n log.level === 'error'\n ? 'bg-status-error-bg border border-status-error-border'\n : 'bg-muted/50'\n }`}\n >\n <div className=\"flex items-start gap-2\">\n {log.level === 'error' && (\n <svg className=\"h-4 w-4 text-status-error-icon flex-shrink-0 mt-0.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n )}\n <div className=\"flex-1 min-w-0\">\n <p className={`text-xs ${log.level === 'error' ? 'text-status-error-text' : 'text-foreground'}`}>\n {log.message}\n </p>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {(() => {\n const d = new Date(log.occurredAt)\n const pad = (n: number) => n.toString().padStart(2, '0')\n return `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}`\n })()}\n {log.entityType && ` \u00B7 ${log.entityType}`}\n </p>\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n <div className=\"mt-3\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={fetchActivityLogs}\n disabled={activityLoading}\n >\n {activityLoading ? (\n <>\n <Spinner size=\"sm\" className=\"mr-2\" />\n {t('search.settings.loadingLabel', 'Loading...')}\n </>\n ) : (\n t('search.settings.refreshLabel', 'Refresh')\n )}\n </Button>\n </div>\n </TabsContent>\n </Tabs>\n\n {/* Vector Reindex Confirmation Dialog */}\n {showVectorReindexDialog && (\n <div className=\"fixed inset-0 z-modal flex items-center justify-center bg-black/50\">\n <div className=\"mx-4 max-w-md rounded-lg border border-border bg-card p-6 shadow-lg\">\n <h3 className=\"text-lg font-semibold mb-2\">{t('search.settings.reindex.confirmTitle', 'Confirm Reindex')}</h3>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.reindex.confirmDescription', 'This will rebuild all vector embeddings. Existing data will be purged first.')}\n </p>\n <div className=\"flex justify-end gap-3\">\n <Button type=\"button\" variant=\"outline\" onClick={handleVectorReindexCancel}>\n {t('search.settings.actions.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" variant=\"default\" onClick={handleVectorReindexConfirm}>\n {t('search.settings.reindex.confirmButton', 'Start Reindex')}\n </Button>\n </div>\n </div>\n </div>\n )}\n\n {/* Embedding Provider Change Confirmation Dialog */}\n {showEmbeddingConfirmDialog && pendingEmbeddingConfig && (\n <div className=\"fixed inset-0 z-modal flex items-center justify-center bg-black/50\">\n <div className=\"mx-4 max-w-lg rounded-lg border border-border bg-card p-6 shadow-lg\">\n <h3 className=\"text-lg font-semibold mb-2\">{t('search.settings.change.title', 'Confirm Provider Change')}</h3>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.change.description', 'Changing the embedding provider will require reindexing all data.')}\n </p>\n <div className=\"mb-4 p-3 rounded-md bg-muted/50 text-sm\">\n <p className=\"font-medium\">\n {embeddingSettings?.embeddingConfig\n ? `${EMBEDDING_PROVIDERS[embeddingSettings.embeddingConfig.providerId].name} (${embeddingSettings.embeddingConfig.model})`\n : 'Default'}\n {' \u2192 '}\n {EMBEDDING_PROVIDERS[pendingEmbeddingConfig.providerId].name} ({pendingEmbeddingConfig.model})\n </p>\n <p className=\"text-muted-foreground\">\n {embeddingSettings?.indexedDimension ?? 'N/A'} \u2192 {pendingEmbeddingConfig.dimension} dimensions\n </p>\n </div>\n <ul className=\"mb-4 space-y-1 text-sm\">\n <li className=\"flex items-start gap-2\">\n <span className=\"text-destructive\">\u2022</span>\n <span>{t('search.settings.change.bullet1', 'Existing vector data will be cleared')}</span>\n </li>\n <li className=\"flex items-start gap-2\">\n <span className=\"text-destructive\">\u2022</span>\n <span>{t('search.settings.change.bullet2', 'Vector search will be unavailable during reindex')}</span>\n </li>\n </ul>\n <div className=\"flex justify-end gap-3\">\n <Button type=\"button\" variant=\"outline\" onClick={handleEmbeddingCancelChange} disabled={embeddingSaving}>\n {t('search.settings.actions.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" variant=\"destructive\" onClick={handleEmbeddingConfirmChange} disabled={embeddingSaving}>\n {embeddingSaving ? <Spinner size=\"sm\" className=\"mr-2\" /> : null}\n {t('search.settings.actions.confirm', 'Confirm')}\n </Button>\n </div>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default VectorSearchSection\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"search.api.errors.missingQuery": "Suchanfrage ist erforderlich.",
|
|
13
13
|
"search.api.errors.noIndexableStrategy": "Keine indizierbare Strategie verfügbar.",
|
|
14
14
|
"search.api.errors.providerNotConfigured": "Anbieter ist nicht konfiguriert. Setzen Sie die erforderliche Umgebungsvariable.",
|
|
15
|
+
"search.api.errors.providerUnavailable": "Der ausgewählte Anbieter ist nicht verfügbar.",
|
|
15
16
|
"search.api.errors.purgeFailed": "Suchindex konnte nicht bereinigt werden.",
|
|
16
17
|
"search.api.errors.recreateFailed": "Fehler beim Neuerstellen der Vektortabelle mit neuer Dimension.",
|
|
17
18
|
"search.api.errors.reindexFailed": "Neuindizierung fehlgeschlagen.",
|
|
@@ -156,6 +157,7 @@
|
|
|
156
157
|
"search.settings.vector.comingSoon": "Demnächst verfügbar",
|
|
157
158
|
"search.settings.vector.howTo": "Konfigurationsanleitung",
|
|
158
159
|
"search.settings.vector.howToDescription": "Embedding-Anbieter für die Vektorsuche konfigurieren.",
|
|
160
|
+
"search.settings.vector.inheritingDefault": "Dieser Mandant erbt die Instanz-/Umgebungsvorgabe. Das Speichern eines Anbieters erstellt eine Überschreibung für diesen Mandanten.",
|
|
159
161
|
"search.settings.vector.modelsAvailable": "Verfügbare Modelle",
|
|
160
162
|
"search.settings.vector.providers": "Anbieter",
|
|
161
163
|
"search.settings.vector.providersHint": "Embedding-Anbieter über Umgebungsvariablen konfigurieren.",
|
|
@@ -163,6 +165,7 @@
|
|
|
163
165
|
"search.settings.vector.sectionTitle": "Vektorsuche",
|
|
164
166
|
"search.settings.vector.setEnvVar": "Umgebungsvariable setzen",
|
|
165
167
|
"search.settings.vector.store": "Vektorspeicher",
|
|
168
|
+
"search.settings.vector.usingTenantConfig": "Dieser Mandant verwendet eigene Embedding-Einstellungen.",
|
|
166
169
|
"search.settings.vectorDocumentsLabel": "Vektordokumente",
|
|
167
170
|
"search.settings.vectorNotConfigured": "Vektorsuche ist nicht konfiguriert.",
|
|
168
171
|
"search.settings.vectorNotConfiguredHint": "Embedding-Anbieter-API-Schlüssel für die Vektorsuche setzen.",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"search.api.errors.missingQuery": "Search query is required.",
|
|
13
13
|
"search.api.errors.noIndexableStrategy": "No indexable strategy is available.",
|
|
14
14
|
"search.api.errors.providerNotConfigured": "Provider is not configured. Set the required environment variable.",
|
|
15
|
+
"search.api.errors.providerUnavailable": "The selected provider is not available.",
|
|
15
16
|
"search.api.errors.purgeFailed": "Failed to purge search index.",
|
|
16
17
|
"search.api.errors.recreateFailed": "Failed to recreate vector table with new dimension.",
|
|
17
18
|
"search.api.errors.reindexFailed": "Reindex operation failed.",
|
|
@@ -156,6 +157,7 @@
|
|
|
156
157
|
"search.settings.vector.comingSoon": "Coming soon",
|
|
157
158
|
"search.settings.vector.howTo": "How to configure",
|
|
158
159
|
"search.settings.vector.howToDescription": "Set up an embedding provider to enable vector search.",
|
|
160
|
+
"search.settings.vector.inheritingDefault": "This tenant is inheriting the instance/environment default. Saving a provider creates an override for this tenant.",
|
|
159
161
|
"search.settings.vector.modelsAvailable": "Models available",
|
|
160
162
|
"search.settings.vector.providers": "Providers",
|
|
161
163
|
"search.settings.vector.providersHint": "Configure an embedding provider via environment variables.",
|
|
@@ -163,6 +165,7 @@
|
|
|
163
165
|
"search.settings.vector.sectionTitle": "Vector Search",
|
|
164
166
|
"search.settings.vector.setEnvVar": "Set environment variable",
|
|
165
167
|
"search.settings.vector.store": "Vector store",
|
|
168
|
+
"search.settings.vector.usingTenantConfig": "This tenant is using its own embedding settings.",
|
|
166
169
|
"search.settings.vectorDocumentsLabel": "Vector documents",
|
|
167
170
|
"search.settings.vectorNotConfigured": "Vector search is not configured.",
|
|
168
171
|
"search.settings.vectorNotConfiguredHint": "Set an embedding provider API key to enable vector search.",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"search.api.errors.missingQuery": "Se requiere una consulta de búsqueda.",
|
|
13
13
|
"search.api.errors.noIndexableStrategy": "No hay estrategia indexable disponible.",
|
|
14
14
|
"search.api.errors.providerNotConfigured": "El proveedor no está configurado. Configure la variable de entorno requerida.",
|
|
15
|
+
"search.api.errors.providerUnavailable": "El proveedor seleccionado no está disponible.",
|
|
15
16
|
"search.api.errors.purgeFailed": "Error al purgar el índice de búsqueda.",
|
|
16
17
|
"search.api.errors.recreateFailed": "No se pudo recrear la tabla vectorial con la nueva dimensión.",
|
|
17
18
|
"search.api.errors.reindexFailed": "La operación de reindexación falló.",
|
|
@@ -156,6 +157,7 @@
|
|
|
156
157
|
"search.settings.vector.comingSoon": "Próximamente",
|
|
157
158
|
"search.settings.vector.howTo": "Cómo configurar",
|
|
158
159
|
"search.settings.vector.howToDescription": "Configure un proveedor de embeddings para habilitar la búsqueda vectorial.",
|
|
160
|
+
"search.settings.vector.inheritingDefault": "Este inquilino hereda el valor predeterminado de la instancia/entorno. Guardar un proveedor crea una anulación para este inquilino.",
|
|
159
161
|
"search.settings.vector.modelsAvailable": "Modelos disponibles",
|
|
160
162
|
"search.settings.vector.providers": "Proveedores",
|
|
161
163
|
"search.settings.vector.providersHint": "Configure un proveedor de embeddings mediante variables de entorno.",
|
|
@@ -163,6 +165,7 @@
|
|
|
163
165
|
"search.settings.vector.sectionTitle": "Búsqueda vectorial",
|
|
164
166
|
"search.settings.vector.setEnvVar": "Configurar variable de entorno",
|
|
165
167
|
"search.settings.vector.store": "Almacén vectorial",
|
|
168
|
+
"search.settings.vector.usingTenantConfig": "Este inquilino usa su propia configuración de incrustaciones.",
|
|
166
169
|
"search.settings.vectorDocumentsLabel": "Documentos vectoriales",
|
|
167
170
|
"search.settings.vectorNotConfigured": "La búsqueda vectorial no está configurada.",
|
|
168
171
|
"search.settings.vectorNotConfiguredHint": "Configure una clave API del proveedor de embeddings para la búsqueda vectorial.",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"search.api.errors.missingQuery": "Zapytanie wyszukiwania jest wymagane.",
|
|
13
13
|
"search.api.errors.noIndexableStrategy": "Brak dostępnej strategii indeksowania.",
|
|
14
14
|
"search.api.errors.providerNotConfigured": "Dostawca nie jest skonfigurowany. Ustaw wymaganą zmienną środowiskową.",
|
|
15
|
+
"search.api.errors.providerUnavailable": "Wybrany dostawca jest niedostępny.",
|
|
15
16
|
"search.api.errors.purgeFailed": "Nie udało się wyczyścić indeksu wyszukiwania.",
|
|
16
17
|
"search.api.errors.recreateFailed": "Nie udało się odtworzyć tabeli wektorowej z nowym wymiarem.",
|
|
17
18
|
"search.api.errors.reindexFailed": "Operacja reindeksacji nie powiodła się.",
|
|
@@ -156,6 +157,7 @@
|
|
|
156
157
|
"search.settings.vector.comingSoon": "Wkrótce",
|
|
157
158
|
"search.settings.vector.howTo": "Jak skonfigurować",
|
|
158
159
|
"search.settings.vector.howToDescription": "Skonfiguruj dostawcę embeddingów, aby włączyć wyszukiwanie wektorowe.",
|
|
160
|
+
"search.settings.vector.inheritingDefault": "Ten najemca dziedziczy domyślne ustawienia instancji/środowiska. Zapisanie dostawcy tworzy nadpisanie dla tego najemcy.",
|
|
159
161
|
"search.settings.vector.modelsAvailable": "Dostępne modele",
|
|
160
162
|
"search.settings.vector.providers": "Dostawcy",
|
|
161
163
|
"search.settings.vector.providersHint": "Skonfiguruj dostawcę embeddingów za pomocą zmiennych środowiskowych.",
|
|
@@ -163,6 +165,7 @@
|
|
|
163
165
|
"search.settings.vector.sectionTitle": "Wyszukiwanie wektorowe",
|
|
164
166
|
"search.settings.vector.setEnvVar": "Ustaw zmienną środowiskową",
|
|
165
167
|
"search.settings.vector.store": "Magazyn wektorów",
|
|
168
|
+
"search.settings.vector.usingTenantConfig": "Ten najemca używa własnych ustawień osadzania.",
|
|
166
169
|
"search.settings.vectorDocumentsLabel": "Dokumenty wektorowe",
|
|
167
170
|
"search.settings.vectorNotConfigured": "Wyszukiwanie wektorowe nie jest skonfigurowane.",
|
|
168
171
|
"search.settings.vectorNotConfiguredHint": "Ustaw klucz API dostawcy embeddingów, aby włączyć wyszukiwanie wektorowe.",
|
|
@@ -15,7 +15,10 @@ async function resolveAutoIndexingEnabled(resolver, options) {
|
|
|
15
15
|
return fallback;
|
|
16
16
|
}
|
|
17
17
|
try {
|
|
18
|
-
const value = await service.getValue("vector", SEARCH_AUTO_INDEX_CONFIG_KEY, {
|
|
18
|
+
const value = await service.getValue("vector", SEARCH_AUTO_INDEX_CONFIG_KEY, {
|
|
19
|
+
defaultValue: fallback,
|
|
20
|
+
scope: options?.scope
|
|
21
|
+
});
|
|
19
22
|
return value !== false;
|
|
20
23
|
} catch {
|
|
21
24
|
return fallback;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/search/lib/auto-indexing.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ModuleConfigService } from '@open-mercato/core/modules/configs/lib/module-config-service'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\n\nexport const SEARCH_AUTO_INDEX_CONFIG_KEY = 'auto_index_enabled'\n\nexport function envDisablesAutoIndexing(): boolean {\n const raw =\n process.env.OM_DISABLE_VECTOR_SEARCH_AUTOINDEXING ??\n process.env.DISABLE_VECTOR_SEARCH_AUTOINDEXING\n if (!raw) return false\n return parseBooleanToken(raw) === true\n}\n\ntype Resolver = {\n resolve: <T = unknown>(name: string) => T\n}\n\nexport async function resolveAutoIndexingEnabled(\n resolver: Resolver,\n options?: { defaultValue?: boolean },\n): Promise<boolean> {\n if (envDisablesAutoIndexing()) return false\n const fallback = options?.defaultValue ?? true\n let service: ModuleConfigService\n try {\n service = resolver.resolve<ModuleConfigService>('moduleConfigService')\n } catch {\n return fallback\n }\n try {\n // Still use 'vector' module key for backwards compatibility\n const value = await service.getValue<boolean>('vector', SEARCH_AUTO_INDEX_CONFIG_KEY, {
|
|
5
|
-
"mappings": "AACA,SAAS,yBAAyB;AAE3B,MAAM,+BAA+B;AAErC,SAAS,0BAAmC;AACjD,QAAM,MACJ,QAAQ,IAAI,yCACZ,QAAQ,IAAI;AACd,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,kBAAkB,GAAG,MAAM;AACpC;AAMA,eAAsB,2BACpB,UACA,SACkB;AAClB,MAAI,wBAAwB,EAAG,QAAO;AACtC,QAAM,WAAW,SAAS,gBAAgB;AAC1C,MAAI;AACJ,MAAI;AACF,cAAU,SAAS,QAA6B,qBAAqB;AAAA,EACvE,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI;AAEF,UAAM,QAAQ,MAAM,QAAQ,SAAkB,UAAU,8BAA8B,
|
|
4
|
+
"sourcesContent": ["import type { ConfigScope, ModuleConfigService } from '@open-mercato/core/modules/configs/lib/module-config-service'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\n\nexport const SEARCH_AUTO_INDEX_CONFIG_KEY = 'auto_index_enabled'\n\nexport function envDisablesAutoIndexing(): boolean {\n const raw =\n process.env.OM_DISABLE_VECTOR_SEARCH_AUTOINDEXING ??\n process.env.DISABLE_VECTOR_SEARCH_AUTOINDEXING\n if (!raw) return false\n return parseBooleanToken(raw) === true\n}\n\ntype Resolver = {\n resolve: <T = unknown>(name: string) => T\n}\n\nexport async function resolveAutoIndexingEnabled(\n resolver: Resolver,\n options?: { defaultValue?: boolean; scope?: ConfigScope },\n): Promise<boolean> {\n if (envDisablesAutoIndexing()) return false\n const fallback = options?.defaultValue ?? true\n let service: ModuleConfigService\n try {\n service = resolver.resolve<ModuleConfigService>('moduleConfigService')\n } catch {\n return fallback\n }\n try {\n // Still use 'vector' module key for backwards compatibility\n const value = await service.getValue<boolean>('vector', SEARCH_AUTO_INDEX_CONFIG_KEY, {\n defaultValue: fallback,\n scope: options?.scope,\n })\n return value !== false\n } catch {\n return fallback\n }\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,yBAAyB;AAE3B,MAAM,+BAA+B;AAErC,SAAS,0BAAmC;AACjD,QAAM,MACJ,QAAQ,IAAI,yCACZ,QAAQ,IAAI;AACd,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,kBAAkB,GAAG,MAAM;AACpC;AAMA,eAAsB,2BACpB,UACA,SACkB;AAClB,MAAI,wBAAwB,EAAG,QAAO;AACtC,QAAM,WAAW,SAAS,gBAAgB;AAC1C,MAAI;AACJ,MAAI;AACF,cAAU,SAAS,QAA6B,qBAAqB;AAAA,EACvE,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI;AAEF,UAAM,QAAQ,MAAM,QAAQ,SAAkB,UAAU,8BAA8B;AAAA,MACpF,cAAc;AAAA,MACd,OAAO,SAAS;AAAA,IAClB,CAAC;AACD,WAAO,UAAU;AAAA,EACnB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -97,13 +97,16 @@ async function resolveEmbeddingConfig(resolver, options) {
|
|
|
97
97
|
return fallback;
|
|
98
98
|
}
|
|
99
99
|
try {
|
|
100
|
-
const value = await service.getValue("vector", EMBEDDING_CONFIG_KEY, {
|
|
100
|
+
const value = await service.getValue("vector", EMBEDDING_CONFIG_KEY, {
|
|
101
|
+
defaultValue: fallback,
|
|
102
|
+
scope: options?.scope
|
|
103
|
+
});
|
|
101
104
|
return value;
|
|
102
105
|
} catch {
|
|
103
106
|
return fallback;
|
|
104
107
|
}
|
|
105
108
|
}
|
|
106
|
-
async function saveEmbeddingConfig(resolver, config) {
|
|
109
|
+
async function saveEmbeddingConfig(resolver, config, options) {
|
|
107
110
|
let service;
|
|
108
111
|
try {
|
|
109
112
|
service = resolver.resolve("moduleConfigService");
|
|
@@ -113,19 +116,53 @@ async function saveEmbeddingConfig(resolver, config) {
|
|
|
113
116
|
await service.setValue("vector", EMBEDDING_CONFIG_KEY, {
|
|
114
117
|
...config,
|
|
115
118
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
116
|
-
});
|
|
119
|
+
}, options?.scope);
|
|
117
120
|
}
|
|
118
121
|
function createDefaultConfig() {
|
|
119
122
|
return { ...DEFAULT_EMBEDDING_CONFIG, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
120
123
|
}
|
|
124
|
+
function getEnvDerivedEmbeddingConfig() {
|
|
125
|
+
const configured = getConfiguredProviders();
|
|
126
|
+
if (configured.length === 0) return null;
|
|
127
|
+
const providerId = configured.includes(DEFAULT_EMBEDDING_CONFIG.providerId) ? DEFAULT_EMBEDDING_CONFIG.providerId : configured[0];
|
|
128
|
+
if (providerId === DEFAULT_EMBEDDING_CONFIG.providerId) {
|
|
129
|
+
return { ...DEFAULT_EMBEDDING_CONFIG, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
130
|
+
}
|
|
131
|
+
const info = EMBEDDING_PROVIDERS[providerId];
|
|
132
|
+
const model = info.models.find((entry) => entry.id === info.defaultModel) ?? info.models[0];
|
|
133
|
+
return {
|
|
134
|
+
providerId,
|
|
135
|
+
model: info.defaultModel,
|
|
136
|
+
dimension: model?.dimension ?? DEFAULT_EMBEDDING_CONFIG.dimension,
|
|
137
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
async function resolveEmbeddingConfigResult(resolver, options) {
|
|
141
|
+
let service;
|
|
142
|
+
try {
|
|
143
|
+
service = resolver.resolve("moduleConfigService");
|
|
144
|
+
} catch {
|
|
145
|
+
return { config: getEnvDerivedEmbeddingConfig(), source: "env" };
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
const record = await service.getRecord("vector", EMBEDDING_CONFIG_KEY, options?.scope);
|
|
149
|
+
if (record && record.value) {
|
|
150
|
+
return { config: record.value, source: record.source };
|
|
151
|
+
}
|
|
152
|
+
} catch {
|
|
153
|
+
}
|
|
154
|
+
return { config: getEnvDerivedEmbeddingConfig(), source: "env" };
|
|
155
|
+
}
|
|
121
156
|
export {
|
|
122
157
|
EMBEDDING_CONFIG_KEY,
|
|
123
158
|
createDefaultConfig,
|
|
124
159
|
detectConfigChange,
|
|
125
160
|
getConfiguredProviders,
|
|
126
161
|
getEffectiveDimension,
|
|
162
|
+
getEnvDerivedEmbeddingConfig,
|
|
127
163
|
isProviderConfigured,
|
|
128
164
|
resolveEmbeddingConfig,
|
|
165
|
+
resolveEmbeddingConfigResult,
|
|
129
166
|
saveEmbeddingConfig
|
|
130
167
|
};
|
|
131
168
|
//# sourceMappingURL=embedding-config.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/search/lib/embedding-config.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ModuleConfigService } from '@open-mercato/core/modules/configs/lib/module-config-service'\nimport type { EmbeddingProviderConfig, EmbeddingProviderId } from '../../../vector'\nimport { EMBEDDING_CONFIG_KEY, EMBEDDING_PROVIDERS, DEFAULT_EMBEDDING_CONFIG } from '../../../vector'\n\nexport { EMBEDDING_CONFIG_KEY }\n\nexport type EmbeddingConfigChange = {\n previousConfig: EmbeddingProviderConfig | null\n newConfig: EmbeddingProviderConfig\n requiresReindex: boolean\n reason: string | null\n}\n\nexport function detectConfigChange(\n previousConfig: EmbeddingProviderConfig | null,\n newConfig: EmbeddingProviderConfig,\n indexedDimension?: number | null\n): EmbeddingConfigChange {\n const newDimension = newConfig.outputDimensionality ?? newConfig.dimension\n\n if (!previousConfig) {\n // First time setup - check if indexed dimension differs from new config\n if (indexedDimension !== null && indexedDimension !== undefined && indexedDimension !== newDimension) {\n return {\n previousConfig,\n newConfig,\n requiresReindex: true,\n reason: `Indexed dimension (${indexedDimension}) differs from new config (${newDimension})`,\n }\n }\n return {\n previousConfig,\n newConfig,\n requiresReindex: false,\n reason: null,\n }\n }\n\n const previousDimension = previousConfig.outputDimensionality ?? previousConfig.dimension\n\n if (previousConfig.providerId !== newConfig.providerId) {\n return {\n previousConfig,\n newConfig,\n requiresReindex: true,\n reason: `Provider changed from ${EMBEDDING_PROVIDERS[previousConfig.providerId].name} to ${EMBEDDING_PROVIDERS[newConfig.providerId].name}`,\n }\n }\n\n if (previousConfig.model !== newConfig.model) {\n return {\n previousConfig,\n newConfig,\n requiresReindex: true,\n reason: `Model changed from ${previousConfig.model} to ${newConfig.model}`,\n }\n }\n\n if (previousDimension !== newDimension) {\n return {\n previousConfig,\n newConfig,\n requiresReindex: true,\n reason: `Dimension changed from ${previousDimension} to ${newDimension}`,\n }\n }\n\n // Also check if indexed dimension differs from config dimension\n if (indexedDimension !== null && indexedDimension !== undefined && indexedDimension !== newDimension) {\n return {\n previousConfig,\n newConfig,\n requiresReindex: true,\n reason: `Indexed dimension (${indexedDimension}) differs from config (${newDimension})`,\n }\n }\n\n return {\n previousConfig,\n newConfig,\n requiresReindex: false,\n reason: null,\n }\n}\n\nexport function isProviderConfigured(providerId: EmbeddingProviderId): boolean {\n switch (providerId) {\n case 'openai':\n return Boolean(process.env.OPENAI_API_KEY?.trim())\n case 'google':\n return Boolean(process.env.GOOGLE_GENERATIVE_AI_API_KEY?.trim())\n case 'mistral':\n return Boolean(process.env.MISTRAL_API_KEY?.trim())\n case 'cohere':\n return Boolean(process.env.COHERE_API_KEY?.trim())\n case 'bedrock':\n return Boolean(process.env.AWS_ACCESS_KEY_ID?.trim() && process.env.AWS_SECRET_ACCESS_KEY?.trim())\n case 'ollama':\n return true\n default:\n return false\n }\n}\n\nexport function getConfiguredProviders(): EmbeddingProviderId[] {\n const providers: EmbeddingProviderId[] = []\n const allProviders: EmbeddingProviderId[] = ['openai', 'google', 'mistral', 'cohere', 'bedrock', 'ollama']\n for (const providerId of allProviders) {\n if (isProviderConfigured(providerId)) {\n providers.push(providerId)\n }\n }\n return providers\n}\n\nexport function getEffectiveDimension(config: EmbeddingProviderConfig): number {\n return config.outputDimensionality ?? config.dimension\n}\n\ntype Resolver = {\n resolve: <T = unknown>(name: string) => T\n}\n\nexport async function resolveEmbeddingConfig(\n resolver: Resolver,\n options?: { defaultValue?: EmbeddingProviderConfig | null }\n): Promise<EmbeddingProviderConfig | null> {\n const fallback = options?.defaultValue ?? null\n let service: ModuleConfigService\n try {\n service = resolver.resolve<ModuleConfigService>('moduleConfigService')\n } catch {\n return fallback\n }\n try {\n const value = await service.getValue<EmbeddingProviderConfig>('vector', EMBEDDING_CONFIG_KEY, {
|
|
5
|
-
"mappings": "AAEA,SAAS,sBAAsB,qBAAqB,gCAAgC;AAW7E,SAAS,mBACd,gBACA,WACA,kBACuB;AACvB,QAAM,eAAe,UAAU,wBAAwB,UAAU;AAEjE,MAAI,CAAC,gBAAgB;AAEnB,QAAI,qBAAqB,QAAQ,qBAAqB,UAAa,qBAAqB,cAAc;AACpG,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,iBAAiB;AAAA,QACjB,QAAQ,sBAAsB,gBAAgB,8BAA8B,YAAY;AAAA,MAC1F;AAAA,IACF;AACA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,oBAAoB,eAAe,wBAAwB,eAAe;AAEhF,MAAI,eAAe,eAAe,UAAU,YAAY;AACtD,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB,QAAQ,yBAAyB,oBAAoB,eAAe,UAAU,EAAE,IAAI,OAAO,oBAAoB,UAAU,UAAU,EAAE,IAAI;AAAA,IAC3I;AAAA,EACF;AAEA,MAAI,eAAe,UAAU,UAAU,OAAO;AAC5C,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB,QAAQ,sBAAsB,eAAe,KAAK,OAAO,UAAU,KAAK;AAAA,IAC1E;AAAA,EACF;AAEA,MAAI,sBAAsB,cAAc;AACtC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB,QAAQ,0BAA0B,iBAAiB,OAAO,YAAY;AAAA,IACxE;AAAA,EACF;AAGA,MAAI,qBAAqB,QAAQ,qBAAqB,UAAa,qBAAqB,cAAc;AACpG,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB,QAAQ,sBAAsB,gBAAgB,0BAA0B,YAAY;AAAA,IACtF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,IACjB,QAAQ;AAAA,EACV;AACF;AAEO,SAAS,qBAAqB,YAA0C;AAC7E,UAAQ,YAAY;AAAA,IAClB,KAAK;AACH,aAAO,QAAQ,QAAQ,IAAI,gBAAgB,KAAK,CAAC;AAAA,IACnD,KAAK;AACH,aAAO,QAAQ,QAAQ,IAAI,8BAA8B,KAAK,CAAC;AAAA,IACjE,KAAK;AACH,aAAO,QAAQ,QAAQ,IAAI,iBAAiB,KAAK,CAAC;AAAA,IACpD,KAAK;AACH,aAAO,QAAQ,QAAQ,IAAI,gBAAgB,KAAK,CAAC;AAAA,IACnD,KAAK;AACH,aAAO,QAAQ,QAAQ,IAAI,mBAAmB,KAAK,KAAK,QAAQ,IAAI,uBAAuB,KAAK,CAAC;AAAA,IACnG,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEO,SAAS,yBAAgD;AAC9D,QAAM,YAAmC,CAAC;AAC1C,QAAM,eAAsC,CAAC,UAAU,UAAU,WAAW,UAAU,WAAW,QAAQ;AACzG,aAAW,cAAc,cAAc;AACrC,QAAI,qBAAqB,UAAU,GAAG;AACpC,gBAAU,KAAK,UAAU;AAAA,IAC3B;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,sBAAsB,QAAyC;AAC7E,SAAO,OAAO,wBAAwB,OAAO;AAC/C;AAMA,eAAsB,uBACpB,UACA,SACyC;AACzC,QAAM,WAAW,SAAS,gBAAgB;AAC1C,MAAI;AACJ,MAAI;AACF,cAAU,SAAS,QAA6B,qBAAqB;AAAA,EACvE,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,QAAQ,MAAM,QAAQ,SAAkC,UAAU,sBAAsB,
|
|
4
|
+
"sourcesContent": ["import type { ConfigScope, ModuleConfigService } from '@open-mercato/core/modules/configs/lib/module-config-service'\nimport type { EmbeddingProviderConfig, EmbeddingProviderId } from '../../../vector'\nimport { EMBEDDING_CONFIG_KEY, EMBEDDING_PROVIDERS, DEFAULT_EMBEDDING_CONFIG } from '../../../vector'\n\nexport { EMBEDDING_CONFIG_KEY }\n\nexport type EmbeddingConfigChange = {\n previousConfig: EmbeddingProviderConfig | null\n newConfig: EmbeddingProviderConfig\n requiresReindex: boolean\n reason: string | null\n}\n\nexport function detectConfigChange(\n previousConfig: EmbeddingProviderConfig | null,\n newConfig: EmbeddingProviderConfig,\n indexedDimension?: number | null\n): EmbeddingConfigChange {\n const newDimension = newConfig.outputDimensionality ?? newConfig.dimension\n\n if (!previousConfig) {\n // First time setup - check if indexed dimension differs from new config\n if (indexedDimension !== null && indexedDimension !== undefined && indexedDimension !== newDimension) {\n return {\n previousConfig,\n newConfig,\n requiresReindex: true,\n reason: `Indexed dimension (${indexedDimension}) differs from new config (${newDimension})`,\n }\n }\n return {\n previousConfig,\n newConfig,\n requiresReindex: false,\n reason: null,\n }\n }\n\n const previousDimension = previousConfig.outputDimensionality ?? previousConfig.dimension\n\n if (previousConfig.providerId !== newConfig.providerId) {\n return {\n previousConfig,\n newConfig,\n requiresReindex: true,\n reason: `Provider changed from ${EMBEDDING_PROVIDERS[previousConfig.providerId].name} to ${EMBEDDING_PROVIDERS[newConfig.providerId].name}`,\n }\n }\n\n if (previousConfig.model !== newConfig.model) {\n return {\n previousConfig,\n newConfig,\n requiresReindex: true,\n reason: `Model changed from ${previousConfig.model} to ${newConfig.model}`,\n }\n }\n\n if (previousDimension !== newDimension) {\n return {\n previousConfig,\n newConfig,\n requiresReindex: true,\n reason: `Dimension changed from ${previousDimension} to ${newDimension}`,\n }\n }\n\n // Also check if indexed dimension differs from config dimension\n if (indexedDimension !== null && indexedDimension !== undefined && indexedDimension !== newDimension) {\n return {\n previousConfig,\n newConfig,\n requiresReindex: true,\n reason: `Indexed dimension (${indexedDimension}) differs from config (${newDimension})`,\n }\n }\n\n return {\n previousConfig,\n newConfig,\n requiresReindex: false,\n reason: null,\n }\n}\n\nexport function isProviderConfigured(providerId: EmbeddingProviderId): boolean {\n switch (providerId) {\n case 'openai':\n return Boolean(process.env.OPENAI_API_KEY?.trim())\n case 'google':\n return Boolean(process.env.GOOGLE_GENERATIVE_AI_API_KEY?.trim())\n case 'mistral':\n return Boolean(process.env.MISTRAL_API_KEY?.trim())\n case 'cohere':\n return Boolean(process.env.COHERE_API_KEY?.trim())\n case 'bedrock':\n return Boolean(process.env.AWS_ACCESS_KEY_ID?.trim() && process.env.AWS_SECRET_ACCESS_KEY?.trim())\n case 'ollama':\n return true\n default:\n return false\n }\n}\n\nexport function getConfiguredProviders(): EmbeddingProviderId[] {\n const providers: EmbeddingProviderId[] = []\n const allProviders: EmbeddingProviderId[] = ['openai', 'google', 'mistral', 'cohere', 'bedrock', 'ollama']\n for (const providerId of allProviders) {\n if (isProviderConfigured(providerId)) {\n providers.push(providerId)\n }\n }\n return providers\n}\n\nexport function getEffectiveDimension(config: EmbeddingProviderConfig): number {\n return config.outputDimensionality ?? config.dimension\n}\n\ntype Resolver = {\n resolve: <T = unknown>(name: string) => T\n}\n\nexport async function resolveEmbeddingConfig(\n resolver: Resolver,\n options?: { defaultValue?: EmbeddingProviderConfig | null; scope?: ConfigScope }\n): Promise<EmbeddingProviderConfig | null> {\n const fallback = options?.defaultValue ?? null\n let service: ModuleConfigService\n try {\n service = resolver.resolve<ModuleConfigService>('moduleConfigService')\n } catch {\n return fallback\n }\n try {\n const value = await service.getValue<EmbeddingProviderConfig>('vector', EMBEDDING_CONFIG_KEY, {\n defaultValue: fallback,\n scope: options?.scope,\n })\n return value\n } catch {\n return fallback\n }\n}\n\nexport async function saveEmbeddingConfig(\n resolver: Resolver,\n config: EmbeddingProviderConfig,\n options?: { scope?: ConfigScope }\n): Promise<void> {\n let service: ModuleConfigService\n try {\n service = resolver.resolve<ModuleConfigService>('moduleConfigService')\n } catch {\n throw new Error('Configuration service unavailable')\n }\n await service.setValue('vector', EMBEDDING_CONFIG_KEY, {\n ...config,\n updatedAt: new Date().toISOString(),\n }, options?.scope)\n}\n\nexport function createDefaultConfig(): EmbeddingProviderConfig {\n return { ...DEFAULT_EMBEDDING_CONFIG, updatedAt: new Date().toISOString() }\n}\n\nexport type EmbeddingConfigSource = 'tenant' | 'instance' | 'env'\n\n/**\n * Compute the env-derived default embedding config: the platform default narrowed\n * to the first env-configured provider. Returns null when no provider is configured.\n */\nexport function getEnvDerivedEmbeddingConfig(): EmbeddingProviderConfig | null {\n const configured = getConfiguredProviders()\n if (configured.length === 0) return null\n const providerId = configured.includes(DEFAULT_EMBEDDING_CONFIG.providerId)\n ? DEFAULT_EMBEDDING_CONFIG.providerId\n : configured[0]\n if (providerId === DEFAULT_EMBEDDING_CONFIG.providerId) {\n return { ...DEFAULT_EMBEDDING_CONFIG, updatedAt: new Date().toISOString() }\n }\n const info = EMBEDDING_PROVIDERS[providerId]\n const model = info.models.find((entry) => entry.id === info.defaultModel) ?? info.models[0]\n return {\n providerId,\n model: info.defaultModel,\n dimension: model?.dimension ?? DEFAULT_EMBEDDING_CONFIG.dimension,\n updatedAt: new Date().toISOString(),\n }\n}\n\n/**\n * Resolve the embedding config together with its source discriminator:\n * `tenant` (own scoped row), `instance` (inherited global row), or `env`\n * (no stored row -> env-derived default).\n */\nexport async function resolveEmbeddingConfigResult(\n resolver: Resolver,\n options?: { scope?: ConfigScope },\n): Promise<{ config: EmbeddingProviderConfig | null; source: EmbeddingConfigSource }> {\n let service: ModuleConfigService\n try {\n service = resolver.resolve<ModuleConfigService>('moduleConfigService')\n } catch {\n return { config: getEnvDerivedEmbeddingConfig(), source: 'env' }\n }\n try {\n const record = await service.getRecord('vector', EMBEDDING_CONFIG_KEY, options?.scope)\n if (record && record.value) {\n return { config: record.value as EmbeddingProviderConfig, source: record.source }\n }\n } catch {}\n return { config: getEnvDerivedEmbeddingConfig(), source: 'env' }\n}\n"],
|
|
5
|
+
"mappings": "AAEA,SAAS,sBAAsB,qBAAqB,gCAAgC;AAW7E,SAAS,mBACd,gBACA,WACA,kBACuB;AACvB,QAAM,eAAe,UAAU,wBAAwB,UAAU;AAEjE,MAAI,CAAC,gBAAgB;AAEnB,QAAI,qBAAqB,QAAQ,qBAAqB,UAAa,qBAAqB,cAAc;AACpG,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,iBAAiB;AAAA,QACjB,QAAQ,sBAAsB,gBAAgB,8BAA8B,YAAY;AAAA,MAC1F;AAAA,IACF;AACA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,oBAAoB,eAAe,wBAAwB,eAAe;AAEhF,MAAI,eAAe,eAAe,UAAU,YAAY;AACtD,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB,QAAQ,yBAAyB,oBAAoB,eAAe,UAAU,EAAE,IAAI,OAAO,oBAAoB,UAAU,UAAU,EAAE,IAAI;AAAA,IAC3I;AAAA,EACF;AAEA,MAAI,eAAe,UAAU,UAAU,OAAO;AAC5C,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB,QAAQ,sBAAsB,eAAe,KAAK,OAAO,UAAU,KAAK;AAAA,IAC1E;AAAA,EACF;AAEA,MAAI,sBAAsB,cAAc;AACtC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB,QAAQ,0BAA0B,iBAAiB,OAAO,YAAY;AAAA,IACxE;AAAA,EACF;AAGA,MAAI,qBAAqB,QAAQ,qBAAqB,UAAa,qBAAqB,cAAc;AACpG,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB,QAAQ,sBAAsB,gBAAgB,0BAA0B,YAAY;AAAA,IACtF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,IACjB,QAAQ;AAAA,EACV;AACF;AAEO,SAAS,qBAAqB,YAA0C;AAC7E,UAAQ,YAAY;AAAA,IAClB,KAAK;AACH,aAAO,QAAQ,QAAQ,IAAI,gBAAgB,KAAK,CAAC;AAAA,IACnD,KAAK;AACH,aAAO,QAAQ,QAAQ,IAAI,8BAA8B,KAAK,CAAC;AAAA,IACjE,KAAK;AACH,aAAO,QAAQ,QAAQ,IAAI,iBAAiB,KAAK,CAAC;AAAA,IACpD,KAAK;AACH,aAAO,QAAQ,QAAQ,IAAI,gBAAgB,KAAK,CAAC;AAAA,IACnD,KAAK;AACH,aAAO,QAAQ,QAAQ,IAAI,mBAAmB,KAAK,KAAK,QAAQ,IAAI,uBAAuB,KAAK,CAAC;AAAA,IACnG,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEO,SAAS,yBAAgD;AAC9D,QAAM,YAAmC,CAAC;AAC1C,QAAM,eAAsC,CAAC,UAAU,UAAU,WAAW,UAAU,WAAW,QAAQ;AACzG,aAAW,cAAc,cAAc;AACrC,QAAI,qBAAqB,UAAU,GAAG;AACpC,gBAAU,KAAK,UAAU;AAAA,IAC3B;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,sBAAsB,QAAyC;AAC7E,SAAO,OAAO,wBAAwB,OAAO;AAC/C;AAMA,eAAsB,uBACpB,UACA,SACyC;AACzC,QAAM,WAAW,SAAS,gBAAgB;AAC1C,MAAI;AACJ,MAAI;AACF,cAAU,SAAS,QAA6B,qBAAqB;AAAA,EACvE,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,QAAQ,MAAM,QAAQ,SAAkC,UAAU,sBAAsB;AAAA,MAC5F,cAAc;AAAA,MACd,OAAO,SAAS;AAAA,IAClB,CAAC;AACD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,oBACpB,UACA,QACA,SACe;AACf,MAAI;AACJ,MAAI;AACF,cAAU,SAAS,QAA6B,qBAAqB;AAAA,EACvE,QAAQ;AACN,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AACA,QAAM,QAAQ,SAAS,UAAU,sBAAsB;AAAA,IACrD,GAAG;AAAA,IACH,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,EACpC,GAAG,SAAS,KAAK;AACnB;AAEO,SAAS,sBAA+C;AAC7D,SAAO,EAAE,GAAG,0BAA0B,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE;AAC5E;AAQO,SAAS,+BAA+D;AAC7E,QAAM,aAAa,uBAAuB;AAC1C,MAAI,WAAW,WAAW,EAAG,QAAO;AACpC,QAAM,aAAa,WAAW,SAAS,yBAAyB,UAAU,IACtE,yBAAyB,aACzB,WAAW,CAAC;AAChB,MAAI,eAAe,yBAAyB,YAAY;AACtD,WAAO,EAAE,GAAG,0BAA0B,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE;AAAA,EAC5E;AACA,QAAM,OAAO,oBAAoB,UAAU;AAC3C,QAAM,QAAQ,KAAK,OAAO,KAAK,CAAC,UAAU,MAAM,OAAO,KAAK,YAAY,KAAK,KAAK,OAAO,CAAC;AAC1F,SAAO;AAAA,IACL;AAAA,IACA,OAAO,KAAK;AAAA,IACZ,WAAW,OAAO,aAAa,yBAAyB;AAAA,IACxD,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,EACpC;AACF;AAOA,eAAsB,6BACpB,UACA,SACoF;AACpF,MAAI;AACJ,MAAI;AACF,cAAU,SAAS,QAA6B,qBAAqB;AAAA,EACvE,QAAQ;AACN,WAAO,EAAE,QAAQ,6BAA6B,GAAG,QAAQ,MAAM;AAAA,EACjE;AACA,MAAI;AACF,UAAM,SAAS,MAAM,QAAQ,UAAU,UAAU,sBAAsB,SAAS,KAAK;AACrF,QAAI,UAAU,OAAO,OAAO;AAC1B,aAAO,EAAE,QAAQ,OAAO,OAAkC,QAAQ,OAAO,OAAO;AAAA,IAClF;AAAA,EACF,QAAQ;AAAA,EAAC;AACT,SAAO,EAAE,QAAQ,6BAA6B,GAAG,QAAQ,MAAM;AACjE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|