@open-mercato/search 0.6.7-develop.6860.1.f796b22e80 → 0.6.7
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 +1 -7
- package/dist/lib/presenter-enricher.js +12 -12
- package/dist/lib/presenter-enricher.js.map +2 -2
- package/dist/modules/search/ai-tools.js +2 -5
- package/dist/modules/search/ai-tools.js.map +2 -2
- package/dist/modules/search/api/openapi.js +0 -2
- package/dist/modules/search/api/openapi.js.map +2 -2
- package/dist/modules/search/api/settings/vector-store/route.js +0 -34
- package/dist/modules/search/api/settings/vector-store/route.js.map +2 -2
- package/dist/modules/search/frontend/components/GlobalSearchDialog.js +9 -2
- package/dist/modules/search/frontend/components/GlobalSearchDialog.js.map +2 -2
- package/dist/modules/search/frontend/components/HybridSearchTable.js +11 -2
- package/dist/modules/search/frontend/components/HybridSearchTable.js.map +2 -2
- package/dist/modules/search/frontend/components/SearchSettingsPageClient.js.map +2 -2
- package/dist/modules/search/frontend/components/TopbarSearchInline.js +9 -2
- package/dist/modules/search/frontend/components/TopbarSearchInline.js.map +2 -2
- package/dist/modules/search/frontend/components/sections/VectorSearchSection.js +3 -15
- package/dist/modules/search/frontend/components/sections/VectorSearchSection.js.map +2 -2
- package/dist/modules/search/i18n/de.json +0 -49
- package/dist/modules/search/i18n/en.json +0 -49
- package/dist/modules/search/i18n/es.json +0 -49
- package/dist/modules/search/i18n/pl.json +0 -49
- package/dist/modules/search/lib/auto-indexing.js +8 -7
- package/dist/modules/search/lib/auto-indexing.js.map +2 -2
- package/dist/service.js +5 -2
- package/dist/service.js.map +2 -2
- package/dist/strategies/vector.strategy.js +1 -3
- package/dist/strategies/vector.strategy.js.map +2 -2
- package/dist/vector/drivers/pgvector/index.js +1 -55
- package/dist/vector/drivers/pgvector/index.js.map +2 -2
- package/dist/vector/types.js.map +2 -2
- package/package.json +10 -11
- package/src/__tests__/presenter-enricher.test.ts +0 -48
- package/src/lib/presenter-enricher.ts +14 -14
- package/src/modules/search/README.md +1 -4
- package/src/modules/search/ai-tools.ts +2 -5
- package/src/modules/search/api/openapi.ts +0 -2
- package/src/modules/search/api/settings/vector-store/route.ts +0 -43
- package/src/modules/search/frontend/components/GlobalSearchDialog.tsx +15 -2
- package/src/modules/search/frontend/components/HybridSearchTable.tsx +17 -2
- package/src/modules/search/frontend/components/SearchSettingsPageClient.tsx +0 -2
- package/src/modules/search/frontend/components/TopbarSearchInline.tsx +15 -2
- package/src/modules/search/frontend/components/sections/VectorSearchSection.tsx +2 -32
- package/src/modules/search/frontend/components/sections/__tests__/VectorSearchSection.test.tsx +1 -36
- package/src/modules/search/i18n/de.json +0 -49
- package/src/modules/search/i18n/en.json +0 -49
- package/src/modules/search/i18n/es.json +0 -49
- package/src/modules/search/i18n/pl.json +0 -49
- package/src/modules/search/lib/auto-indexing.ts +12 -7
- package/src/service.ts +7 -2
- package/src/strategies/vector.strategy.ts +1 -7
- package/src/vector/drivers/pgvector/index.ts +1 -77
- package/src/vector/types.ts +0 -14
- package/dist/modules/search/events.js +0 -13
- package/dist/modules/search/events.js.map +0 -7
- package/dist/modules/search/frontend/lib/entityTypeLabel.js +0 -19
- package/dist/modules/search/frontend/lib/entityTypeLabel.js.map +0 -7
- package/dist/modules/search/i18n/ko.json +0 -239
- package/src/__tests__/pgvector-extension-availability.test.ts +0 -158
- package/src/__tests__/presenter-locale.test.ts +0 -76
- package/src/modules/search/api/__tests__/global-search.routes.test.ts +0 -167
- package/src/modules/search/events.ts +0 -10
- package/src/modules/search/frontend/lib/__tests__/entityTypeLabel.test.ts +0 -25
- package/src/modules/search/frontend/lib/entityTypeLabel.ts +0 -22
- package/src/modules/search/i18n/ko.json +0 -239
|
@@ -49,7 +49,6 @@ import { Button } from '@open-mercato/ui/primitives/button'
|
|
|
49
49
|
import { cn } from '@open-mercato/shared/lib/utils'
|
|
50
50
|
import type { SearchResult, SearchResultLink, SearchStrategyId } from '@open-mercato/shared/modules/search'
|
|
51
51
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
52
|
-
import { resolveEntityTypeLabel } from '../lib/entityTypeLabel'
|
|
53
52
|
import {
|
|
54
53
|
getCurrentOrganizationScope,
|
|
55
54
|
subscribeOrganizationScopeChanged,
|
|
@@ -88,6 +87,14 @@ function hasActiveOrganizationSelection(): boolean {
|
|
|
88
87
|
return !isAllOrganizationsSelection(cookieValue);
|
|
89
88
|
}
|
|
90
89
|
|
|
90
|
+
function humanizeSegment(segment: string): string {
|
|
91
|
+
return segment
|
|
92
|
+
.split(/[_-]+/)
|
|
93
|
+
.filter(Boolean)
|
|
94
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
95
|
+
.join(' ')
|
|
96
|
+
}
|
|
97
|
+
|
|
91
98
|
const ICON_MAP: Record<string, LucideIcon> = {
|
|
92
99
|
bolt: Zap,
|
|
93
100
|
zap: Zap,
|
|
@@ -133,6 +140,12 @@ function resolveIcon(name?: string): LucideIcon | null {
|
|
|
133
140
|
return ICON_MAP[name.toLowerCase()] ?? null
|
|
134
141
|
}
|
|
135
142
|
|
|
143
|
+
function formatEntityId(entityId: string): string {
|
|
144
|
+
if (!entityId.includes(':')) return humanizeSegment(entityId)
|
|
145
|
+
const [module, entity] = entityId.split(':')
|
|
146
|
+
return `${humanizeSegment(module)} · ${humanizeSegment(entity)}`
|
|
147
|
+
}
|
|
148
|
+
|
|
136
149
|
export type GlobalSearchDialogProps = {
|
|
137
150
|
/** Whether embedding provider is configured for vector search */
|
|
138
151
|
embeddingConfigured: boolean
|
|
@@ -410,7 +423,7 @@ export function GlobalSearchDialog({
|
|
|
410
423
|
<div className="flex flex-wrap items-center gap-2">
|
|
411
424
|
<span className={cn('font-medium text-base whitespace-normal break-all', !hasLink && 'text-muted-foreground')}>{presenter?.title ?? result.recordId}</span>
|
|
412
425
|
<span className="rounded-full border border-muted-foreground/30 px-2 py-0.5 text-xs text-muted-foreground">
|
|
413
|
-
{
|
|
426
|
+
{formatEntityId(result.entityId)}
|
|
414
427
|
</span>
|
|
415
428
|
{!hasLink && (
|
|
416
429
|
<span className="rounded-full border border-status-warning-border bg-status-warning-bg px-2 py-0.5 text-xs text-status-warning-text">
|
|
@@ -11,7 +11,6 @@ import type { SearchResult, SearchStrategyId } from '@open-mercato/shared/module
|
|
|
11
11
|
import { cn } from '@open-mercato/shared/lib/utils'
|
|
12
12
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
13
13
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
14
|
-
import { resolveEntityTypeLabel } from '../lib/entityTypeLabel'
|
|
15
14
|
import {
|
|
16
15
|
getCurrentOrganizationScope,
|
|
17
16
|
subscribeOrganizationScopeChanged,
|
|
@@ -61,7 +60,7 @@ function createColumns(t: Translator): ColumnDef<Row>[] {
|
|
|
61
60
|
const title = resolveRowTitle(item)
|
|
62
61
|
const iconName = item.presenter?.icon
|
|
63
62
|
const Icon = iconName ? resolveIcon(iconName) : null
|
|
64
|
-
const typeLabel =
|
|
63
|
+
const typeLabel = formatEntityId(item.entityId)
|
|
65
64
|
const snapshot = item.presenter?.subtitle ?? extractSnapshot(item.metadata)
|
|
66
65
|
const links = normalizeLinks(item.links)
|
|
67
66
|
return (
|
|
@@ -161,6 +160,22 @@ function resolveIcon(name?: string): LucideIcon | null {
|
|
|
161
160
|
return null
|
|
162
161
|
}
|
|
163
162
|
|
|
163
|
+
function humanizeSegment(segment: string): string {
|
|
164
|
+
return segment
|
|
165
|
+
.split(/[_-]+/)
|
|
166
|
+
.filter(Boolean)
|
|
167
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
168
|
+
.join(' ')
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function formatEntityId(entityId: string): string {
|
|
172
|
+
if (!entityId.includes(':')) return humanizeSegment(entityId)
|
|
173
|
+
const [module, entity] = entityId.split(':')
|
|
174
|
+
const moduleLabel = humanizeSegment(module)
|
|
175
|
+
const entityLabel = humanizeSegment(entity)
|
|
176
|
+
return `${moduleLabel} · ${entityLabel}`
|
|
177
|
+
}
|
|
178
|
+
|
|
164
179
|
function resolveRowTitle(row: Row): string {
|
|
165
180
|
const presenterTitle = row.presenter?.title
|
|
166
181
|
if (typeof presenterTitle === 'string') {
|
|
@@ -49,7 +49,6 @@ import type { LucideIcon } from 'lucide-react'
|
|
|
49
49
|
import { cn } from '@open-mercato/shared/lib/utils'
|
|
50
50
|
import type { SearchResult, SearchResultLink } from '@open-mercato/shared/modules/search'
|
|
51
51
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
52
|
-
import { resolveEntityTypeLabel } from '../lib/entityTypeLabel'
|
|
53
52
|
import {
|
|
54
53
|
getCurrentOrganizationScope,
|
|
55
54
|
subscribeOrganizationScopeChanged,
|
|
@@ -85,6 +84,14 @@ function hasActiveOrganizationSelection(): boolean {
|
|
|
85
84
|
return !isAllOrganizationsSelection(cookieValue)
|
|
86
85
|
}
|
|
87
86
|
|
|
87
|
+
function humanizeSegment(segment: string): string {
|
|
88
|
+
return segment
|
|
89
|
+
.split(/[_-]+/)
|
|
90
|
+
.filter(Boolean)
|
|
91
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
92
|
+
.join(' ')
|
|
93
|
+
}
|
|
94
|
+
|
|
88
95
|
const ICON_MAP: Record<string, LucideIcon> = {
|
|
89
96
|
bolt: Zap,
|
|
90
97
|
zap: Zap,
|
|
@@ -130,6 +137,12 @@ function resolveIcon(name?: string): LucideIcon | null {
|
|
|
130
137
|
return ICON_MAP[name.toLowerCase()] ?? null
|
|
131
138
|
}
|
|
132
139
|
|
|
140
|
+
function formatEntityId(entityId: string): string {
|
|
141
|
+
if (!entityId.includes(':')) return humanizeSegment(entityId)
|
|
142
|
+
const [module, entity] = entityId.split(':')
|
|
143
|
+
return `${humanizeSegment(module)} · ${humanizeSegment(entity)}`
|
|
144
|
+
}
|
|
145
|
+
|
|
133
146
|
export type TopbarSearchInlineProps = {
|
|
134
147
|
/** Whether embedding provider is configured for vector search */
|
|
135
148
|
embeddingConfigured: boolean
|
|
@@ -508,7 +521,7 @@ export function TopbarSearchInline({
|
|
|
508
521
|
</span>
|
|
509
522
|
</span>
|
|
510
523
|
<span className="flex items-center gap-2 text-overline text-muted-foreground">
|
|
511
|
-
<span className="truncate">{
|
|
524
|
+
<span className="truncate">{formatEntityId(result.entityId)}</span>
|
|
512
525
|
{presenter?.subtitle ? (
|
|
513
526
|
<>
|
|
514
527
|
<span aria-hidden="true">·</span>
|
|
@@ -79,8 +79,6 @@ type VectorDriverStatus = {
|
|
|
79
79
|
name: string
|
|
80
80
|
configured: boolean
|
|
81
81
|
implemented: boolean
|
|
82
|
-
available?: boolean | null
|
|
83
|
-
unavailableReason?: string | null
|
|
84
82
|
envVars: VectorDriverEnvVar[]
|
|
85
83
|
}
|
|
86
84
|
|
|
@@ -449,31 +447,6 @@ export function VectorSearchSection({
|
|
|
449
447
|
const isEmbeddingConfigured = embeddingSettings?.configuredProviders?.includes(savedProvider)
|
|
450
448
|
const providerOptions: EmbeddingProviderId[] = ['openai', 'google', 'mistral', 'cohere', 'bedrock', 'ollama']
|
|
451
449
|
|
|
452
|
-
const activeDriver = vectorStoreConfig?.drivers.find((driver) => driver.id === vectorStoreConfig.currentDriver)
|
|
453
|
-
const isStoreUnavailable = activeDriver?.available === false
|
|
454
|
-
const storeUnavailableReason = activeDriver?.unavailableReason ?? null
|
|
455
|
-
|
|
456
|
-
const storeUnavailableBanner = isStoreUnavailable ? (
|
|
457
|
-
<div className="p-4 rounded-md bg-status-warning-bg border border-status-warning-border">
|
|
458
|
-
<div className="flex items-start gap-3">
|
|
459
|
-
<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">
|
|
460
|
-
<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" />
|
|
461
|
-
</svg>
|
|
462
|
-
<div>
|
|
463
|
-
<p className="text-sm font-medium text-status-warning-text">
|
|
464
|
-
{t('search.settings.vector.storeUnavailable', 'Vector store is not available')}
|
|
465
|
-
</p>
|
|
466
|
-
<p className="text-xs text-status-warning-text mt-1">
|
|
467
|
-
{t('search.settings.vector.storeUnavailableHint', 'Vector indexing and semantic search are skipped until the store is reachable. Install the pgvector extension on your PostgreSQL server; the status is rechecked about once a minute.')}
|
|
468
|
-
</p>
|
|
469
|
-
{storeUnavailableReason ? (
|
|
470
|
-
<p className="text-xs text-status-warning-text mt-1 font-mono">{storeUnavailableReason}</p>
|
|
471
|
-
) : null}
|
|
472
|
-
</div>
|
|
473
|
-
</div>
|
|
474
|
-
</div>
|
|
475
|
-
) : null
|
|
476
|
-
|
|
477
450
|
const autoIndexingChecked = embeddingSettings ? embeddingSettings.autoIndexingEnabled : true
|
|
478
451
|
const autoIndexingDisabled = embeddingLoading || embeddingSaving || Boolean(embeddingSettings?.autoIndexingLocked)
|
|
479
452
|
|
|
@@ -508,14 +481,13 @@ export function VectorSearchSection({
|
|
|
508
481
|
</div>
|
|
509
482
|
) : (
|
|
510
483
|
<div className="space-y-4">
|
|
511
|
-
{storeUnavailableBanner}
|
|
512
484
|
{/* Vector Store Driver Status */}
|
|
513
485
|
<div>
|
|
514
486
|
<h3 className="text-sm font-semibold mb-2">{t('search.settings.vector.store', 'Vector Store')}</h3>
|
|
515
487
|
<div className="grid gap-2 sm:grid-cols-3">
|
|
516
488
|
{vectorStoreConfig?.drivers.map((driver) => {
|
|
517
489
|
const isCurrent = driver.id === vectorStoreConfig.currentDriver
|
|
518
|
-
const isReady = driver.configured && driver.implemented
|
|
490
|
+
const isReady = driver.configured && driver.implemented
|
|
519
491
|
return (
|
|
520
492
|
<div
|
|
521
493
|
key={driver.id}
|
|
@@ -774,8 +746,6 @@ export function VectorSearchSection({
|
|
|
774
746
|
<Spinner size="sm" />
|
|
775
747
|
<span>{t('search.settings.loadingLabel', 'Loading settings...')}</span>
|
|
776
748
|
</div>
|
|
777
|
-
) : isStoreUnavailable ? (
|
|
778
|
-
storeUnavailableBanner
|
|
779
749
|
) : !isEmbeddingConfigured ? (
|
|
780
750
|
<div className="p-4 rounded-md bg-status-warning-bg border border-status-warning-border">
|
|
781
751
|
<div className="flex items-start gap-3">
|
|
@@ -1009,7 +979,7 @@ export function VectorSearchSection({
|
|
|
1009
979
|
<Button type="button" variant="outline" onClick={handleEmbeddingCancelChange} disabled={embeddingSaving}>
|
|
1010
980
|
{t('search.settings.actions.cancel', 'Cancel')}
|
|
1011
981
|
</Button>
|
|
1012
|
-
<Button type="button" variant="destructive
|
|
982
|
+
<Button type="button" variant="destructive" onClick={handleEmbeddingConfirmChange} disabled={embeddingSaving}>
|
|
1013
983
|
{embeddingSaving ? <Spinner size="sm" className="mr-2" /> : null}
|
|
1014
984
|
{t('search.settings.actions.confirm', 'Confirm')}
|
|
1015
985
|
</Button>
|
package/src/modules/search/frontend/components/sections/__tests__/VectorSearchSection.test.tsx
CHANGED
|
@@ -50,14 +50,13 @@ const vectorStoreConfig: NonNullable<VectorSearchSectionProps['vectorStoreConfig
|
|
|
50
50
|
|
|
51
51
|
function renderSection(
|
|
52
52
|
settings: NonNullable<VectorSearchSectionProps['embeddingSettings']> = embeddingSettings,
|
|
53
|
-
storeConfig: NonNullable<VectorSearchSectionProps['vectorStoreConfig']> = vectorStoreConfig,
|
|
54
53
|
) {
|
|
55
54
|
return render(
|
|
56
55
|
<I18nProvider locale="en" dict={{}}>
|
|
57
56
|
<VectorSearchSection
|
|
58
57
|
embeddingSettings={settings}
|
|
59
58
|
embeddingLoading={false}
|
|
60
|
-
vectorStoreConfig={
|
|
59
|
+
vectorStoreConfig={vectorStoreConfig}
|
|
61
60
|
vectorStoreConfigLoading={false}
|
|
62
61
|
vectorReindexLock={null}
|
|
63
62
|
onEmbeddingSettingsUpdate={jest.fn()}
|
|
@@ -114,37 +113,3 @@ describe('VectorSearchSection provider controls', () => {
|
|
|
114
113
|
expect(document.getElementById('provider-ollama-configuration')).toBeNull()
|
|
115
114
|
})
|
|
116
115
|
})
|
|
117
|
-
|
|
118
|
-
describe('VectorSearchSection store availability', () => {
|
|
119
|
-
beforeEach(() => {
|
|
120
|
-
Object.defineProperty(globalThis, 'fetch', {
|
|
121
|
-
configurable: true,
|
|
122
|
-
value: jest.fn(() => new Promise(() => undefined)),
|
|
123
|
-
})
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
it('warns that the vector store is unavailable and surfaces the driver reason', () => {
|
|
127
|
-
renderSection(embeddingSettings, {
|
|
128
|
-
...vectorStoreConfig,
|
|
129
|
-
drivers: [
|
|
130
|
-
{
|
|
131
|
-
...vectorStoreConfig.drivers[0],
|
|
132
|
-
available: false,
|
|
133
|
-
unavailableReason: 'extension "vector" is not available on this PostgreSQL server',
|
|
134
|
-
},
|
|
135
|
-
],
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
expect(screen.getByText('Vector store is not available')).toBeTruthy()
|
|
139
|
-
expect(screen.getByText(/extension "vector" is not available/)).toBeTruthy()
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
it('keeps the banner hidden while the store is reachable', () => {
|
|
143
|
-
renderSection(embeddingSettings, {
|
|
144
|
-
...vectorStoreConfig,
|
|
145
|
-
drivers: [{ ...vectorStoreConfig.drivers[0], available: true, unavailableReason: null }],
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
expect(screen.queryByText('Vector store is not available')).toBeNull()
|
|
149
|
-
})
|
|
150
|
-
})
|
|
@@ -50,53 +50,6 @@
|
|
|
50
50
|
"search.dialog.strategies.toggle": "Suchoptionen",
|
|
51
51
|
"search.dialog.title": "Globale Suche",
|
|
52
52
|
"search.dialog.warnings.configureLink": "Sucheinstellungen konfigurieren",
|
|
53
|
-
"search.entityType.catalog.catalog_offer": "Angebot",
|
|
54
|
-
"search.entityType.catalog.catalog_option_schema_template": "Optionsvorlage",
|
|
55
|
-
"search.entityType.catalog.catalog_price_kind": "Preistyp",
|
|
56
|
-
"search.entityType.catalog.catalog_product": "Produkt",
|
|
57
|
-
"search.entityType.catalog.catalog_product_category": "Kategorie",
|
|
58
|
-
"search.entityType.catalog.catalog_product_tag": "Tag",
|
|
59
|
-
"search.entityType.catalog.catalog_product_unit_conversion": "Einheitenumrechnung",
|
|
60
|
-
"search.entityType.catalog.catalog_product_variant": "Variante",
|
|
61
|
-
"search.entityType.customer_accounts.customer_role": "Kundenrolle",
|
|
62
|
-
"search.entityType.customer_accounts.customer_user": "Kundenbenutzer",
|
|
63
|
-
"search.entityType.customers.customer_activity": "Aktivität",
|
|
64
|
-
"search.entityType.customers.customer_comment": "Kommentar",
|
|
65
|
-
"search.entityType.customers.customer_company_profile": "Unternehmen",
|
|
66
|
-
"search.entityType.customers.customer_deal": "Deal",
|
|
67
|
-
"search.entityType.customers.customer_entity": "Kunde",
|
|
68
|
-
"search.entityType.customers.customer_person_profile": "Person",
|
|
69
|
-
"search.entityType.customers.customer_todo_link": "Aufgabe",
|
|
70
|
-
"search.entityType.inbox_ops.inbox_proposal": "Posteingang-Vorschlag",
|
|
71
|
-
"search.entityType.messages.message": "Nachricht",
|
|
72
|
-
"search.entityType.planner.planner_availability_rule_set": "Verfügbarkeitsregeln",
|
|
73
|
-
"search.entityType.resources.resources_resource": "Ressource",
|
|
74
|
-
"search.entityType.resources.resources_resource_type": "Ressourcentyp",
|
|
75
|
-
"search.entityType.sales.sales_channel": "Kanal",
|
|
76
|
-
"search.entityType.sales.sales_credit_memo": "Gutschrift",
|
|
77
|
-
"search.entityType.sales.sales_credit_memo_line": "Gutschriftsposition",
|
|
78
|
-
"search.entityType.sales.sales_delivery_window": "Lieferfenster",
|
|
79
|
-
"search.entityType.sales.sales_document_address": "Dokumentadresse",
|
|
80
|
-
"search.entityType.sales.sales_document_tag": "Dokument-Tag",
|
|
81
|
-
"search.entityType.sales.sales_invoice": "Rechnung",
|
|
82
|
-
"search.entityType.sales.sales_invoice_line": "Rechnungsposition",
|
|
83
|
-
"search.entityType.sales.sales_note": "Notiz",
|
|
84
|
-
"search.entityType.sales.sales_order": "Bestellung",
|
|
85
|
-
"search.entityType.sales.sales_order_adjustment": "Bestellanpassung",
|
|
86
|
-
"search.entityType.sales.sales_order_line": "Bestellposition",
|
|
87
|
-
"search.entityType.sales.sales_payment": "Zahlung",
|
|
88
|
-
"search.entityType.sales.sales_payment_allocation": "Zahlungszuordnung",
|
|
89
|
-
"search.entityType.sales.sales_payment_method": "Zahlungsmethode",
|
|
90
|
-
"search.entityType.sales.sales_quote": "Angebot",
|
|
91
|
-
"search.entityType.sales.sales_quote_adjustment": "Angebotsanpassung",
|
|
92
|
-
"search.entityType.sales.sales_quote_line": "Angebotsposition",
|
|
93
|
-
"search.entityType.sales.sales_shipment": "Sendung",
|
|
94
|
-
"search.entityType.sales.sales_shipment_item": "Sendungsposition",
|
|
95
|
-
"search.entityType.sales.sales_shipping_method": "Versandart",
|
|
96
|
-
"search.entityType.sales.sales_tax_rate": "Steuersatz",
|
|
97
|
-
"search.entityType.staff.staff_team": "Team",
|
|
98
|
-
"search.entityType.staff.staff_team_member": "Teammitglied",
|
|
99
|
-
"search.entityType.staff.staff_team_role": "Teamrolle",
|
|
100
53
|
"search.messages.missingConfig": "Die Suche erfordert die Konfiguration eines Embedding-Anbieters für die semantische Suche.",
|
|
101
54
|
"search.nav.hybridSearch": "Suche",
|
|
102
55
|
"search.scopeHint.currentOrg": "Bereich: aktuelle Organisation",
|
|
@@ -214,8 +167,6 @@
|
|
|
214
167
|
"search.settings.vector.sectionTitle": "Vektorsuche",
|
|
215
168
|
"search.settings.vector.setEnvVar": "Umgebungsvariable setzen",
|
|
216
169
|
"search.settings.vector.store": "Vektorspeicher",
|
|
217
|
-
"search.settings.vector.storeUnavailable": "Vektorspeicher ist nicht verfügbar",
|
|
218
|
-
"search.settings.vector.storeUnavailableHint": "Vektorindizierung und semantische Suche werden übersprungen, bis der Speicher erreichbar ist. Installieren Sie die pgvector-Erweiterung auf Ihrem PostgreSQL-Server; der Status wird etwa einmal pro Minute neu geprüft.",
|
|
219
170
|
"search.settings.vector.usingTenantConfig": "Dieser Mandant verwendet eigene Embedding-Einstellungen.",
|
|
220
171
|
"search.settings.vectorDocumentsLabel": "Vektordokumente",
|
|
221
172
|
"search.settings.vectorNotConfigured": "Vektorsuche ist nicht konfiguriert.",
|
|
@@ -50,53 +50,6 @@
|
|
|
50
50
|
"search.dialog.strategies.toggle": "Search options",
|
|
51
51
|
"search.dialog.title": "Global Search",
|
|
52
52
|
"search.dialog.warnings.configureLink": "Configure search settings",
|
|
53
|
-
"search.entityType.catalog.catalog_offer": "Offer",
|
|
54
|
-
"search.entityType.catalog.catalog_option_schema_template": "Option Template",
|
|
55
|
-
"search.entityType.catalog.catalog_price_kind": "Price Type",
|
|
56
|
-
"search.entityType.catalog.catalog_product": "Product",
|
|
57
|
-
"search.entityType.catalog.catalog_product_category": "Category",
|
|
58
|
-
"search.entityType.catalog.catalog_product_tag": "Tag",
|
|
59
|
-
"search.entityType.catalog.catalog_product_unit_conversion": "Unit Conversion",
|
|
60
|
-
"search.entityType.catalog.catalog_product_variant": "Variant",
|
|
61
|
-
"search.entityType.customer_accounts.customer_role": "Customer Role",
|
|
62
|
-
"search.entityType.customer_accounts.customer_user": "Customer User",
|
|
63
|
-
"search.entityType.customers.customer_activity": "Activity",
|
|
64
|
-
"search.entityType.customers.customer_comment": "Comment",
|
|
65
|
-
"search.entityType.customers.customer_company_profile": "Company",
|
|
66
|
-
"search.entityType.customers.customer_deal": "Deal",
|
|
67
|
-
"search.entityType.customers.customer_entity": "Customer",
|
|
68
|
-
"search.entityType.customers.customer_person_profile": "Person",
|
|
69
|
-
"search.entityType.customers.customer_todo_link": "Task",
|
|
70
|
-
"search.entityType.inbox_ops.inbox_proposal": "Inbox Proposal",
|
|
71
|
-
"search.entityType.messages.message": "Message",
|
|
72
|
-
"search.entityType.planner.planner_availability_rule_set": "Availability Rules",
|
|
73
|
-
"search.entityType.resources.resources_resource": "Resource",
|
|
74
|
-
"search.entityType.resources.resources_resource_type": "Resource Type",
|
|
75
|
-
"search.entityType.sales.sales_channel": "Channel",
|
|
76
|
-
"search.entityType.sales.sales_credit_memo": "Credit Memo",
|
|
77
|
-
"search.entityType.sales.sales_credit_memo_line": "Credit Memo Line",
|
|
78
|
-
"search.entityType.sales.sales_delivery_window": "Delivery Window",
|
|
79
|
-
"search.entityType.sales.sales_document_address": "Document Address",
|
|
80
|
-
"search.entityType.sales.sales_document_tag": "Document Tag",
|
|
81
|
-
"search.entityType.sales.sales_invoice": "Invoice",
|
|
82
|
-
"search.entityType.sales.sales_invoice_line": "Invoice Line",
|
|
83
|
-
"search.entityType.sales.sales_note": "Note",
|
|
84
|
-
"search.entityType.sales.sales_order": "Order",
|
|
85
|
-
"search.entityType.sales.sales_order_adjustment": "Order Adjustment",
|
|
86
|
-
"search.entityType.sales.sales_order_line": "Order Line",
|
|
87
|
-
"search.entityType.sales.sales_payment": "Payment",
|
|
88
|
-
"search.entityType.sales.sales_payment_allocation": "Payment Allocation",
|
|
89
|
-
"search.entityType.sales.sales_payment_method": "Payment Method",
|
|
90
|
-
"search.entityType.sales.sales_quote": "Quote",
|
|
91
|
-
"search.entityType.sales.sales_quote_adjustment": "Quote Adjustment",
|
|
92
|
-
"search.entityType.sales.sales_quote_line": "Quote Line",
|
|
93
|
-
"search.entityType.sales.sales_shipment": "Shipment",
|
|
94
|
-
"search.entityType.sales.sales_shipment_item": "Shipment Item",
|
|
95
|
-
"search.entityType.sales.sales_shipping_method": "Shipping Method",
|
|
96
|
-
"search.entityType.sales.sales_tax_rate": "Tax Rate",
|
|
97
|
-
"search.entityType.staff.staff_team": "Team",
|
|
98
|
-
"search.entityType.staff.staff_team_member": "Team Member",
|
|
99
|
-
"search.entityType.staff.staff_team_role": "Team Role",
|
|
100
53
|
"search.messages.missingConfig": "Search requires configuring an embedding provider for semantic search.",
|
|
101
54
|
"search.nav.hybridSearch": "Search",
|
|
102
55
|
"search.scopeHint.currentOrg": "Scoped to current organization",
|
|
@@ -214,8 +167,6 @@
|
|
|
214
167
|
"search.settings.vector.sectionTitle": "Vector Search",
|
|
215
168
|
"search.settings.vector.setEnvVar": "Set environment variable",
|
|
216
169
|
"search.settings.vector.store": "Vector store",
|
|
217
|
-
"search.settings.vector.storeUnavailable": "Vector store is not available",
|
|
218
|
-
"search.settings.vector.storeUnavailableHint": "Vector indexing and semantic search are skipped until the store is reachable. Install the pgvector extension on your PostgreSQL server; the status is rechecked about once a minute.",
|
|
219
170
|
"search.settings.vector.usingTenantConfig": "This tenant is using its own embedding settings.",
|
|
220
171
|
"search.settings.vectorDocumentsLabel": "Vector documents",
|
|
221
172
|
"search.settings.vectorNotConfigured": "Vector search is not configured.",
|
|
@@ -50,53 +50,6 @@
|
|
|
50
50
|
"search.dialog.strategies.toggle": "Opciones de búsqueda",
|
|
51
51
|
"search.dialog.title": "Búsqueda Global",
|
|
52
52
|
"search.dialog.warnings.configureLink": "Configurar búsqueda",
|
|
53
|
-
"search.entityType.catalog.catalog_offer": "Oferta",
|
|
54
|
-
"search.entityType.catalog.catalog_option_schema_template": "Plantilla de opciones",
|
|
55
|
-
"search.entityType.catalog.catalog_price_kind": "Tipo de precio",
|
|
56
|
-
"search.entityType.catalog.catalog_product": "Producto",
|
|
57
|
-
"search.entityType.catalog.catalog_product_category": "Categoría",
|
|
58
|
-
"search.entityType.catalog.catalog_product_tag": "Etiqueta",
|
|
59
|
-
"search.entityType.catalog.catalog_product_unit_conversion": "Conversión de unidades",
|
|
60
|
-
"search.entityType.catalog.catalog_product_variant": "Variante",
|
|
61
|
-
"search.entityType.customer_accounts.customer_role": "Rol de cliente",
|
|
62
|
-
"search.entityType.customer_accounts.customer_user": "Usuario de cliente",
|
|
63
|
-
"search.entityType.customers.customer_activity": "Actividad",
|
|
64
|
-
"search.entityType.customers.customer_comment": "Comentario",
|
|
65
|
-
"search.entityType.customers.customer_company_profile": "Empresa",
|
|
66
|
-
"search.entityType.customers.customer_deal": "Oportunidad",
|
|
67
|
-
"search.entityType.customers.customer_entity": "Cliente",
|
|
68
|
-
"search.entityType.customers.customer_person_profile": "Persona",
|
|
69
|
-
"search.entityType.customers.customer_todo_link": "Tarea",
|
|
70
|
-
"search.entityType.inbox_ops.inbox_proposal": "Propuesta de bandeja",
|
|
71
|
-
"search.entityType.messages.message": "Mensaje",
|
|
72
|
-
"search.entityType.planner.planner_availability_rule_set": "Reglas de disponibilidad",
|
|
73
|
-
"search.entityType.resources.resources_resource": "Recurso",
|
|
74
|
-
"search.entityType.resources.resources_resource_type": "Tipo de recurso",
|
|
75
|
-
"search.entityType.sales.sales_channel": "Canal",
|
|
76
|
-
"search.entityType.sales.sales_credit_memo": "Nota de crédito",
|
|
77
|
-
"search.entityType.sales.sales_credit_memo_line": "Línea de nota de crédito",
|
|
78
|
-
"search.entityType.sales.sales_delivery_window": "Ventana de entrega",
|
|
79
|
-
"search.entityType.sales.sales_document_address": "Dirección del documento",
|
|
80
|
-
"search.entityType.sales.sales_document_tag": "Etiqueta de documento",
|
|
81
|
-
"search.entityType.sales.sales_invoice": "Factura",
|
|
82
|
-
"search.entityType.sales.sales_invoice_line": "Línea de factura",
|
|
83
|
-
"search.entityType.sales.sales_note": "Nota",
|
|
84
|
-
"search.entityType.sales.sales_order": "Pedido",
|
|
85
|
-
"search.entityType.sales.sales_order_adjustment": "Ajuste de pedido",
|
|
86
|
-
"search.entityType.sales.sales_order_line": "Línea de pedido",
|
|
87
|
-
"search.entityType.sales.sales_payment": "Pago",
|
|
88
|
-
"search.entityType.sales.sales_payment_allocation": "Asignación de pago",
|
|
89
|
-
"search.entityType.sales.sales_payment_method": "Método de pago",
|
|
90
|
-
"search.entityType.sales.sales_quote": "Presupuesto",
|
|
91
|
-
"search.entityType.sales.sales_quote_adjustment": "Ajuste de presupuesto",
|
|
92
|
-
"search.entityType.sales.sales_quote_line": "Línea de presupuesto",
|
|
93
|
-
"search.entityType.sales.sales_shipment": "Envío",
|
|
94
|
-
"search.entityType.sales.sales_shipment_item": "Artículo de envío",
|
|
95
|
-
"search.entityType.sales.sales_shipping_method": "Método de envío",
|
|
96
|
-
"search.entityType.sales.sales_tax_rate": "Tasa de impuesto",
|
|
97
|
-
"search.entityType.staff.staff_team": "Equipo",
|
|
98
|
-
"search.entityType.staff.staff_team_member": "Miembro del equipo",
|
|
99
|
-
"search.entityType.staff.staff_team_role": "Rol del equipo",
|
|
100
53
|
"search.messages.missingConfig": "La búsqueda requiere configurar un proveedor de embeddings para la búsqueda semántica.",
|
|
101
54
|
"search.nav.hybridSearch": "Búsqueda",
|
|
102
55
|
"search.scopeHint.currentOrg": "Alcance: organización actual",
|
|
@@ -214,8 +167,6 @@
|
|
|
214
167
|
"search.settings.vector.sectionTitle": "Búsqueda vectorial",
|
|
215
168
|
"search.settings.vector.setEnvVar": "Configurar variable de entorno",
|
|
216
169
|
"search.settings.vector.store": "Almacén vectorial",
|
|
217
|
-
"search.settings.vector.storeUnavailable": "El almacén vectorial no está disponible",
|
|
218
|
-
"search.settings.vector.storeUnavailableHint": "La indexación vectorial y la búsqueda semántica se omiten hasta que el almacén esté disponible. Instala la extensión pgvector en tu servidor PostgreSQL; el estado se vuelve a comprobar aproximadamente cada minuto.",
|
|
219
170
|
"search.settings.vector.usingTenantConfig": "Este inquilino usa su propia configuración de incrustaciones.",
|
|
220
171
|
"search.settings.vectorDocumentsLabel": "Documentos vectoriales",
|
|
221
172
|
"search.settings.vectorNotConfigured": "La búsqueda vectorial no está configurada.",
|
|
@@ -50,53 +50,6 @@
|
|
|
50
50
|
"search.dialog.strategies.toggle": "Opcje wyszukiwania",
|
|
51
51
|
"search.dialog.title": "Globalne Wyszukiwanie",
|
|
52
52
|
"search.dialog.warnings.configureLink": "Skonfiguruj wyszukiwanie",
|
|
53
|
-
"search.entityType.catalog.catalog_offer": "Oferta",
|
|
54
|
-
"search.entityType.catalog.catalog_option_schema_template": "Szablon opcji",
|
|
55
|
-
"search.entityType.catalog.catalog_price_kind": "Typ ceny",
|
|
56
|
-
"search.entityType.catalog.catalog_product": "Produkt",
|
|
57
|
-
"search.entityType.catalog.catalog_product_category": "Kategoria",
|
|
58
|
-
"search.entityType.catalog.catalog_product_tag": "Tag",
|
|
59
|
-
"search.entityType.catalog.catalog_product_unit_conversion": "Przelicznik jednostek",
|
|
60
|
-
"search.entityType.catalog.catalog_product_variant": "Wariant",
|
|
61
|
-
"search.entityType.customer_accounts.customer_role": "Rola klienta",
|
|
62
|
-
"search.entityType.customer_accounts.customer_user": "Użytkownik klienta",
|
|
63
|
-
"search.entityType.customers.customer_activity": "Aktywność",
|
|
64
|
-
"search.entityType.customers.customer_comment": "Komentarz",
|
|
65
|
-
"search.entityType.customers.customer_company_profile": "Firma",
|
|
66
|
-
"search.entityType.customers.customer_deal": "Szansa sprzedaży",
|
|
67
|
-
"search.entityType.customers.customer_entity": "Klient",
|
|
68
|
-
"search.entityType.customers.customer_person_profile": "Osoba",
|
|
69
|
-
"search.entityType.customers.customer_todo_link": "Zadanie",
|
|
70
|
-
"search.entityType.inbox_ops.inbox_proposal": "Propozycja skrzynki",
|
|
71
|
-
"search.entityType.messages.message": "Wiadomość",
|
|
72
|
-
"search.entityType.planner.planner_availability_rule_set": "Reguły dostępności",
|
|
73
|
-
"search.entityType.resources.resources_resource": "Zasób",
|
|
74
|
-
"search.entityType.resources.resources_resource_type": "Typ zasobu",
|
|
75
|
-
"search.entityType.sales.sales_channel": "Kanał",
|
|
76
|
-
"search.entityType.sales.sales_credit_memo": "Nota kredytowa",
|
|
77
|
-
"search.entityType.sales.sales_credit_memo_line": "Pozycja noty kredytowej",
|
|
78
|
-
"search.entityType.sales.sales_delivery_window": "Okno dostawy",
|
|
79
|
-
"search.entityType.sales.sales_document_address": "Adres dokumentu",
|
|
80
|
-
"search.entityType.sales.sales_document_tag": "Tag dokumentu",
|
|
81
|
-
"search.entityType.sales.sales_invoice": "Faktura",
|
|
82
|
-
"search.entityType.sales.sales_invoice_line": "Pozycja faktury",
|
|
83
|
-
"search.entityType.sales.sales_note": "Notatka",
|
|
84
|
-
"search.entityType.sales.sales_order": "Zamówienie",
|
|
85
|
-
"search.entityType.sales.sales_order_adjustment": "Korekta zamówienia",
|
|
86
|
-
"search.entityType.sales.sales_order_line": "Pozycja zamówienia",
|
|
87
|
-
"search.entityType.sales.sales_payment": "Płatność",
|
|
88
|
-
"search.entityType.sales.sales_payment_allocation": "Przypisanie płatności",
|
|
89
|
-
"search.entityType.sales.sales_payment_method": "Metoda płatności",
|
|
90
|
-
"search.entityType.sales.sales_quote": "Oferta",
|
|
91
|
-
"search.entityType.sales.sales_quote_adjustment": "Korekta oferty",
|
|
92
|
-
"search.entityType.sales.sales_quote_line": "Pozycja oferty",
|
|
93
|
-
"search.entityType.sales.sales_shipment": "Wysyłka",
|
|
94
|
-
"search.entityType.sales.sales_shipment_item": "Pozycja wysyłki",
|
|
95
|
-
"search.entityType.sales.sales_shipping_method": "Metoda wysyłki",
|
|
96
|
-
"search.entityType.sales.sales_tax_rate": "Stawka podatku",
|
|
97
|
-
"search.entityType.staff.staff_team": "Zespół",
|
|
98
|
-
"search.entityType.staff.staff_team_member": "Członek zespołu",
|
|
99
|
-
"search.entityType.staff.staff_team_role": "Rola w zespole",
|
|
100
53
|
"search.messages.missingConfig": "Wyszukiwanie wymaga skonfigurowania dostawcy embeddingów dla wyszukiwania semantycznego.",
|
|
101
54
|
"search.nav.hybridSearch": "Wyszukiwanie",
|
|
102
55
|
"search.scopeHint.currentOrg": "Zakres: bieżąca organizacja",
|
|
@@ -214,8 +167,6 @@
|
|
|
214
167
|
"search.settings.vector.sectionTitle": "Wyszukiwanie wektorowe",
|
|
215
168
|
"search.settings.vector.setEnvVar": "Ustaw zmienną środowiskową",
|
|
216
169
|
"search.settings.vector.store": "Magazyn wektorów",
|
|
217
|
-
"search.settings.vector.storeUnavailable": "Magazyn wektorów jest niedostępny",
|
|
218
|
-
"search.settings.vector.storeUnavailableHint": "Indeksowanie wektorowe i wyszukiwanie semantyczne są pomijane, dopóki magazyn nie będzie dostępny. Zainstaluj rozszerzenie pgvector na serwerze PostgreSQL; status jest sprawdzany ponownie mniej więcej co minutę.",
|
|
219
170
|
"search.settings.vector.usingTenantConfig": "Ten najemca używa własnych ustawień osadzania.",
|
|
220
171
|
"search.settings.vectorDocumentsLabel": "Dokumenty wektorowe",
|
|
221
172
|
"search.settings.vectorNotConfigured": "Wyszukiwanie wektorowe nie jest skonfigurowane.",
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { ConfigScope, ModuleConfigService } from '@open-mercato/core/modules/configs/lib/module-config-service'
|
|
2
|
-
import {
|
|
3
|
-
envDisablesAutoIndexing,
|
|
4
|
-
SEARCH_AUTO_INDEX_CONFIG_KEY,
|
|
5
|
-
SEARCH_AUTO_INDEX_CONFIG_MODULE,
|
|
6
|
-
} from '@open-mercato/shared/lib/search/auto-indexing'
|
|
2
|
+
import { parseBooleanToken } from '@open-mercato/shared/lib/boolean'
|
|
7
3
|
|
|
8
|
-
export
|
|
4
|
+
export const SEARCH_AUTO_INDEX_CONFIG_KEY = 'auto_index_enabled'
|
|
5
|
+
|
|
6
|
+
export function envDisablesAutoIndexing(): boolean {
|
|
7
|
+
const raw =
|
|
8
|
+
process.env.OM_DISABLE_VECTOR_SEARCH_AUTOINDEXING ??
|
|
9
|
+
process.env.DISABLE_VECTOR_SEARCH_AUTOINDEXING
|
|
10
|
+
if (!raw) return false
|
|
11
|
+
return parseBooleanToken(raw) === true
|
|
12
|
+
}
|
|
9
13
|
|
|
10
14
|
type Resolver = {
|
|
11
15
|
resolve: <T = unknown>(name: string) => T
|
|
@@ -24,7 +28,8 @@ export async function resolveAutoIndexingEnabled(
|
|
|
24
28
|
return fallback
|
|
25
29
|
}
|
|
26
30
|
try {
|
|
27
|
-
|
|
31
|
+
// Still use 'vector' module key for backwards compatibility
|
|
32
|
+
const value = await service.getValue<boolean>('vector', SEARCH_AUTO_INDEX_CONFIG_KEY, {
|
|
28
33
|
defaultValue: fallback,
|
|
29
34
|
scope: options?.scope,
|
|
30
35
|
})
|
package/src/service.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
} from './types'
|
|
11
11
|
import { mergeAndRankResults } from './lib/merger'
|
|
12
12
|
import { searchError } from './lib/debug'
|
|
13
|
+
import { needsSearchResultEnrichment } from './lib/search-result-enrichment'
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Default merge configuration.
|
|
@@ -162,8 +163,8 @@ export class SearchService {
|
|
|
162
163
|
}
|
|
163
164
|
|
|
164
165
|
/**
|
|
165
|
-
*
|
|
166
|
-
*
|
|
166
|
+
* Enrich results that are missing presenter data using the configured enricher.
|
|
167
|
+
* This ensures token-only results get proper titles/subtitles for display.
|
|
167
168
|
*/
|
|
168
169
|
private async enrichResultsWithPresenter(
|
|
169
170
|
results: SearchResult[],
|
|
@@ -173,6 +174,10 @@ export class SearchService {
|
|
|
173
174
|
// If no enricher configured, return as-is
|
|
174
175
|
if (!this.presenterEnricher) return results
|
|
175
176
|
|
|
177
|
+
const hasMissing = results.some(needsSearchResultEnrichment)
|
|
178
|
+
if (!hasMissing) return results
|
|
179
|
+
|
|
180
|
+
// Use the configured presenter enricher
|
|
176
181
|
try {
|
|
177
182
|
return await this.presenterEnricher(results, tenantId, organizationId)
|
|
178
183
|
} catch {
|
|
@@ -59,13 +59,7 @@ export class VectorSearchStrategy implements SearchStrategy {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
async isAvailable(): Promise<boolean> {
|
|
62
|
-
|
|
63
|
-
// A configured embedding provider says nothing about the vector store. When the
|
|
64
|
-
// store cannot serve writes (pgvector extension missing), reporting availability
|
|
65
|
-
// here makes SearchService call ensureReady() for every record and fail the whole
|
|
66
|
-
// index/delete operation. Drivers without a probe keep the previous behavior.
|
|
67
|
-
if (!this.vectorDriver.isHealthy) return true
|
|
68
|
-
return this.vectorDriver.isHealthy()
|
|
62
|
+
return this.embeddingService.available
|
|
69
63
|
}
|
|
70
64
|
|
|
71
65
|
async ensureReady(): Promise<void> {
|