@almadar/llm 2.37.0 → 2.38.0
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/dist/vector/index.js +6 -1
- package/dist/vector/index.js.map +1 -1
- package/package.json +3 -3
- package/src/vector/store.ts +8 -1
package/dist/vector/index.js
CHANGED
|
@@ -258,12 +258,17 @@ function buildVectorStoreHandle(client, target) {
|
|
|
258
258
|
};
|
|
259
259
|
}
|
|
260
260
|
var vectorStoreCache = /* @__PURE__ */ new Map();
|
|
261
|
+
var emptyConfigSkipLogged = false;
|
|
261
262
|
function resetVectorStoreCache() {
|
|
262
263
|
vectorStoreCache.clear();
|
|
264
|
+
emptyConfigSkipLogged = false;
|
|
263
265
|
}
|
|
264
266
|
async function connectVectorStore(config) {
|
|
265
267
|
if (isEmptyConfig(config)) {
|
|
266
|
-
|
|
268
|
+
if (!emptyConfigSkipLogged) {
|
|
269
|
+
emptyConfigSkipLogged = true;
|
|
270
|
+
vectorLog.debug("store:skip", () => ({ reason: "config-empty" }));
|
|
271
|
+
}
|
|
267
272
|
return null;
|
|
268
273
|
}
|
|
269
274
|
const key = configCacheKey(config);
|
package/dist/vector/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/vector/env.ts","../../src/vector/store.ts","../../src/vector/shape.ts","../../src/vector/collection.ts"],"sourcesContent":["/**\n * Vector-store env resolution + host parsing — pure seams, no chromadb import.\n */\n\nexport interface VectorStoreConfig {\n host?: string;\n apiKey?: string;\n tenant?: string;\n database?: string;\n}\n\nfunction cleanEnvValue(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed : undefined;\n}\n\nexport function resolveVectorStoreEnv(): VectorStoreConfig {\n const env = process.env;\n return {\n host: cleanEnvValue(env.ALMADAR_CHROMA_HOST),\n apiKey: cleanEnvValue(env.ALMADAR_CHROMA_API_KEY),\n tenant: cleanEnvValue(env.ALMADAR_CHROMA_TENANT),\n database: cleanEnvValue(env.ALMADAR_CHROMA_DATABASE),\n };\n}\n\nexport interface VectorHostInit {\n host?: string;\n port?: number;\n ssl?: boolean;\n}\n\n/** Parse a bare host or full URL into chromadb client args: bare host ⇒ port 8000, https default 443. */\nexport function parseVectorHost(host: string): VectorHostInit {\n const init: VectorHostInit = {};\n try {\n const url = new URL(host.includes('://') ? host : `http://${host}`);\n init.host = url.hostname;\n init.port = url.port ? parseInt(url.port, 10) : url.protocol === 'https:' ? 443 : 8000;\n init.ssl = url.protocol === 'https:';\n } catch {\n init.host = host;\n }\n return init;\n}\n","/**\n * Vector-store connection + collection resolution: env → chromadb client\n * (cached per process, per distinct config), plus the space-mismatch policy\n * that guards a `collection()` call from silently ranking/writing under the\n * wrong index space.\n */\nimport type * as Chroma from 'chromadb';\nimport { createLogger } from '@almadar/logger';\nimport type { VectorStoreConfig } from './env.js';\nimport { parseVectorHost } from './env.js';\nimport { wrapVectorCollection, type VectorCollection } from './collection.js';\n\nconst vectorLog = createLogger('almadar:llm:vector');\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nexport type VectorSpace = 'cosine' | 'l2' | 'ip';\n\nexport interface VectorCollectionSpec {\n name: string;\n space?: VectorSpace;\n metadata?: Chroma.CollectionMetadata;\n /** 'recreate' drops + rebuilds a wrong-space collection (derived/rebuildable data only). Default 'reject' never auto-drops a consumer's data. */\n onSpaceMismatch?: 'recreate' | 'reject';\n}\n\nexport interface VectorStoreHandle {\n /** Human-readable connection target, for logs. */\n readonly target: string;\n collection(spec: VectorCollectionSpec): Promise<VectorCollection | null>;\n getCollection(name: string): Promise<VectorCollection | null>;\n deleteCollection(name: string): Promise<boolean>;\n heartbeat(): Promise<boolean>;\n}\n\nconst stubEmbeddingFunction: Chroma.EmbeddingFunction = {\n // Callers always supply pre-computed vectors; the stub stops chromadb from\n // instantiating its own DefaultEmbeddingFunction.\n generate: async () => [],\n};\n\nconst DEFAULT_ON_SPACE_MISMATCH = 'reject';\n\nfunction isEmptyConfig(config: VectorStoreConfig): boolean {\n return !config.host && !config.apiKey;\n}\n\nfunction configCacheKey(config: VectorStoreConfig): string {\n return JSON.stringify([config.host ?? null, config.apiKey ?? null, config.tenant ?? null, config.database ?? null]);\n}\n\nasync function loadChromaModule(): Promise<typeof import('chromadb') | null> {\n try {\n return await import('chromadb');\n } catch (err) {\n vectorLog.warn('store:module-missing', () => ({\n error: errorMessage(err),\n hint: 'add chromadb to dependencies and run pnpm install',\n }));\n return null;\n }\n}\n\nasync function resolveCollection(\n client: Chroma.ChromaClient,\n spec: VectorCollectionSpec,\n): Promise<VectorCollection | null> {\n const create = (): Promise<Chroma.Collection> =>\n client.getOrCreateCollection({\n name: spec.name,\n embeddingFunction: stubEmbeddingFunction,\n ...(spec.space ? { configuration: { hnsw: { space: spec.space } } } : {}),\n ...(spec.metadata ? { metadata: spec.metadata } : {}),\n });\n\n let raw: Chroma.Collection;\n try {\n raw = await create();\n } catch (err) {\n vectorLog.warn('collection:create-failed', () => ({ name: spec.name, error: errorMessage(err) }));\n return null;\n }\n\n // spec.space omitted ⇒ no verification, server default on create.\n if (!spec.space) return wrapVectorCollection(raw);\n\n const foundSpace = raw.configuration.hnsw?.space ?? null;\n if (foundSpace === spec.space) return wrapVectorCollection(raw);\n\n const policy = spec.onSpaceMismatch ?? DEFAULT_ON_SPACE_MISMATCH;\n if (policy === 'reject') {\n vectorLog.warn('collection:space-mismatch', () => ({\n name: spec.name,\n declaredSpace: spec.space,\n foundSpace,\n policy,\n }));\n return null;\n }\n\n vectorLog.warn('collection:space-heal', () => ({ name: spec.name, declaredSpace: spec.space, foundSpace }));\n await client.deleteCollection({ name: spec.name });\n try {\n raw = await create();\n } catch (err) {\n vectorLog.warn('collection:create-failed', () => ({ name: spec.name, error: errorMessage(err) }));\n return null;\n }\n return wrapVectorCollection(raw);\n}\n\nfunction buildVectorStoreHandle(client: Chroma.ChromaClient, target: string): VectorStoreHandle {\n return {\n target,\n collection(spec) {\n return resolveCollection(client, spec);\n },\n async getCollection(name) {\n try {\n const raw = await client.getCollection({ name, embeddingFunction: stubEmbeddingFunction });\n return wrapVectorCollection(raw);\n } catch (err) {\n vectorLog.debug('collection:get-missing', () => ({ name, error: errorMessage(err) }));\n return null;\n }\n },\n async deleteCollection(name) {\n try {\n await client.deleteCollection({ name });\n return true;\n } catch (err) {\n vectorLog.warn('collection:delete-failed', () => ({ name, error: errorMessage(err) }));\n return false;\n }\n },\n async heartbeat() {\n try {\n await client.heartbeat();\n return true;\n } catch {\n return false;\n }\n },\n };\n}\n\nconst vectorStoreCache = new Map<string, VectorStoreHandle>();\n\n/** Test-only reset — clears the per-process handle cache between cases. */\nexport function resetVectorStoreCache(): void {\n vectorStoreCache.clear();\n}\n\nexport async function connectVectorStore(config: VectorStoreConfig): Promise<VectorStoreHandle | null> {\n if (isEmptyConfig(config)) {\n vectorLog.debug('store:skip', () => ({ reason: 'config-empty' }));\n return null;\n }\n\n const key = configCacheKey(config);\n const cached = vectorStoreCache.get(key);\n if (cached) return cached;\n\n const mod = await loadChromaModule();\n if (!mod) return null;\n\n let client: Chroma.ChromaClient;\n let target: string;\n if (config.apiKey) {\n client = new mod.CloudClient({ apiKey: config.apiKey, tenant: config.tenant, database: config.database });\n target = `cloud(tenant=${config.tenant ?? 'default'}, db=${config.database ?? 'default'})`;\n } else if (config.host) {\n client = new mod.ChromaClient(parseVectorHost(config.host));\n target = config.host;\n } else {\n // unreachable: isEmptyConfig already guards host/apiKey both absent.\n return null;\n }\n\n try {\n await client.heartbeat();\n } catch (err) {\n vectorLog.warn('store:heartbeat-failed', () => ({ target, error: errorMessage(err) }));\n return null;\n }\n\n const handle = buildVectorStoreHandle(client, target);\n vectorStoreCache.set(key, handle);\n vectorLog.info('store:ready', () => ({ target }));\n return handle;\n}\n","/**\n * Query-result shaping — pure seams, no chromadb import (types only, erased).\n */\nimport type * as Chroma from 'chromadb';\n\nexport interface VectorHit {\n id: string;\n distance: number;\n score: number;\n metadata?: Chroma.Metadata;\n document?: string;\n}\n\nconst DEFAULT_QUERY_TOP_K = 10;\n\nexport function normalizeVectorTopK(topK: number | undefined): number {\n if (typeof topK !== 'number' || !Number.isFinite(topK) || topK <= 0) return DEFAULT_QUERY_TOP_K;\n return Math.floor(topK);\n}\n\nfunction clamp01(value: number): number {\n if (value < 0) return 0;\n if (value > 1) return 1;\n return value;\n}\n\n/** Structural subset of chromadb's `QueryResult` this module reads (pure-shaping seam). */\nexport interface VectorQueryResultLike {\n readonly ids: ReadonlyArray<ReadonlyArray<string>>;\n readonly distances: ReadonlyArray<ReadonlyArray<number | null>>;\n readonly metadatas?: ReadonlyArray<ReadonlyArray<Chroma.Metadata | null>>;\n readonly documents?: ReadonlyArray<ReadonlyArray<string | null>>;\n}\n\nexport function shapeVectorHits(result: VectorQueryResultLike): VectorHit[] {\n const ids = result.ids[0] ?? [];\n const distances = result.distances[0] ?? [];\n const metadatas = result.metadatas?.[0] ?? [];\n const documents = result.documents?.[0] ?? [];\n const hits: VectorHit[] = [];\n for (let i = 0; i < ids.length; i++) {\n const id = ids[i];\n if (typeof id !== 'string') continue;\n const rawDistance = distances[i];\n // a missing/null distance is the worst case (no similarity signal) — treat as 1, same as rabit's shapeChromaMatches.\n const distance = typeof rawDistance === 'number' ? rawDistance : 1;\n const score = clamp01(1 - distance);\n const metadata = metadatas[i];\n const document = documents[i];\n hits.push({\n id,\n distance,\n score,\n ...(metadata ? { metadata } : {}),\n ...(typeof document === 'string' ? { document } : {}),\n });\n }\n hits.sort((a, b) => b.score - a.score);\n return hits;\n}\n","/**\n * VectorCollection — thin wrapper over a live chromadb `Collection`: batched\n * writes, query shaping, and space/metadata read-through. Mechanics only —\n * callers own retry/best-effort policy, so failures propagate as rejections\n * here (unlike the connect/collection-resolution seams, which never throw).\n */\nimport type * as Chroma from 'chromadb';\nimport { normalizeVectorTopK, shapeVectorHits, type VectorHit } from './shape.js';\n\nexport interface VectorRecords {\n ids: readonly string[];\n embeddings: readonly (readonly number[])[];\n documents?: readonly string[];\n metadatas?: readonly Chroma.Metadata[];\n}\n\nexport interface VectorQueryOptions {\n embedding: readonly number[];\n topK?: number;\n where?: Chroma.Where;\n includeDocuments?: boolean;\n includeMetadatas?: boolean;\n}\n\nexport interface VectorDeleteTarget {\n ids?: readonly string[];\n where?: Chroma.Where;\n}\n\nexport interface VectorGetOptions {\n where?: Chroma.Where;\n /** Default true. */\n includeMetadatas?: boolean;\n /** Default false — privacy default: raw node text is never returned unless explicitly asked for. */\n includeDocuments?: boolean;\n limit?: number;\n}\n\nexport interface VectorRecord {\n id: string;\n metadata?: Chroma.Metadata | undefined;\n document?: string | undefined;\n}\n\nexport interface VectorCollection {\n upsert(records: VectorRecords): Promise<number>;\n add(records: VectorRecords): Promise<number>;\n query(opts: VectorQueryOptions): Promise<VectorHit[]>;\n /** Fetch records by metadata filter (no embedding / no similarity). Defaults to metadatas-only. */\n get(opts?: VectorGetOptions): Promise<VectorRecord[]>;\n delete(target: VectorDeleteTarget): Promise<void>;\n count(): Promise<number>;\n /** Every id in the collection (paged get, vectors not fetched) — backs mirror-sync reconciliation. */\n listIds(): Promise<string[]>;\n readonly metadata: Chroma.CollectionMetadata | undefined;\n readonly space: string | null;\n}\n\nconst WRITE_BATCH_SIZE = 500;\n\ninterface WriteBatch {\n ids: string[];\n embeddings: number[][];\n documents?: string[];\n metadatas?: Chroma.Metadata[];\n}\n\nasync function writeInBatches(\n write: (batch: WriteBatch) => Promise<void>,\n records: VectorRecords,\n): Promise<number> {\n const { ids, embeddings, documents, metadatas } = records;\n let written = 0;\n for (let start = 0; start < ids.length; start += WRITE_BATCH_SIZE) {\n const end = Math.min(start + WRITE_BATCH_SIZE, ids.length);\n await write({\n ids: ids.slice(start, end),\n embeddings: embeddings.slice(start, end).map((vec) => [...vec]),\n ...(documents ? { documents: documents.slice(start, end) } : {}),\n ...(metadatas ? { metadatas: metadatas.slice(start, end) } : {}),\n });\n written += end - start;\n }\n return written;\n}\n\nexport function wrapVectorCollection(raw: Chroma.Collection): VectorCollection {\n return {\n upsert(records) {\n return writeInBatches((batch) => raw.upsert(batch), records);\n },\n add(records) {\n return writeInBatches((batch) => raw.add(batch), records);\n },\n async query(opts) {\n const include: Array<'distances' | 'metadatas' | 'documents'> = ['distances'];\n if (opts.includeMetadatas) include.push('metadatas');\n if (opts.includeDocuments) include.push('documents');\n const result = await raw.query({\n queryEmbeddings: [[...opts.embedding]],\n nResults: normalizeVectorTopK(opts.topK),\n where: opts.where,\n include,\n });\n return shapeVectorHits(result);\n },\n async delete(target) {\n await raw.delete({\n ...(target.ids ? { ids: [...target.ids] } : {}),\n ...(target.where ? { where: target.where } : {}),\n });\n },\n async get(opts = {}) {\n const include: Array<'metadatas' | 'documents'> = [];\n if (opts.includeMetadatas !== false) include.push('metadatas');\n if (opts.includeDocuments) include.push('documents');\n const records: VectorRecord[] = [];\n const PAGE = 10_000;\n const hardLimit = opts.limit ?? Number.MAX_SAFE_INTEGER;\n for (let offset = 0; offset < hardLimit; offset += PAGE) {\n const pageLimit = Math.min(PAGE, hardLimit - offset);\n const page = await raw.get({\n ...(opts.where ? { where: opts.where } : {}),\n include,\n limit: pageLimit,\n offset,\n });\n const wantMeta = include.includes('metadatas');\n const wantDoc = include.includes('documents');\n for (let i = 0; i < page.ids.length; i++) {\n records.push({\n id: page.ids[i],\n ...(wantMeta ? { metadata: page.metadatas?.[i] ?? undefined } : {}),\n ...(wantDoc ? { document: page.documents?.[i] ?? undefined } : {}),\n });\n }\n if (page.ids.length < pageLimit) break;\n }\n return records;\n },\n count() {\n return raw.count();\n },\n async listIds() {\n const ids: string[] = [];\n const PAGE = 10_000;\n for (let offset = 0; ; offset += PAGE) {\n const page = await raw.get({ include: [], limit: PAGE, offset });\n ids.push(...page.ids);\n if (page.ids.length < PAGE) break;\n }\n return ids;\n },\n get metadata() {\n return raw.metadata;\n },\n get space() {\n return raw.configuration.hnsw?.space ?? null;\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/vector/env.ts","../../src/vector/store.ts","../../src/vector/shape.ts","../../src/vector/collection.ts"],"sourcesContent":["/**\n * Vector-store env resolution + host parsing — pure seams, no chromadb import.\n */\n\nexport interface VectorStoreConfig {\n host?: string;\n apiKey?: string;\n tenant?: string;\n database?: string;\n}\n\nfunction cleanEnvValue(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed : undefined;\n}\n\nexport function resolveVectorStoreEnv(): VectorStoreConfig {\n const env = process.env;\n return {\n host: cleanEnvValue(env.ALMADAR_CHROMA_HOST),\n apiKey: cleanEnvValue(env.ALMADAR_CHROMA_API_KEY),\n tenant: cleanEnvValue(env.ALMADAR_CHROMA_TENANT),\n database: cleanEnvValue(env.ALMADAR_CHROMA_DATABASE),\n };\n}\n\nexport interface VectorHostInit {\n host?: string;\n port?: number;\n ssl?: boolean;\n}\n\n/** Parse a bare host or full URL into chromadb client args: bare host ⇒ port 8000, https default 443. */\nexport function parseVectorHost(host: string): VectorHostInit {\n const init: VectorHostInit = {};\n try {\n const url = new URL(host.includes('://') ? host : `http://${host}`);\n init.host = url.hostname;\n init.port = url.port ? parseInt(url.port, 10) : url.protocol === 'https:' ? 443 : 8000;\n init.ssl = url.protocol === 'https:';\n } catch {\n init.host = host;\n }\n return init;\n}\n","/**\n * Vector-store connection + collection resolution: env → chromadb client\n * (cached per process, per distinct config), plus the space-mismatch policy\n * that guards a `collection()` call from silently ranking/writing under the\n * wrong index space.\n */\nimport type * as Chroma from 'chromadb';\nimport { createLogger } from '@almadar/logger';\nimport type { VectorStoreConfig } from './env.js';\nimport { parseVectorHost } from './env.js';\nimport { wrapVectorCollection, type VectorCollection } from './collection.js';\n\nconst vectorLog = createLogger('almadar:llm:vector');\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nexport type VectorSpace = 'cosine' | 'l2' | 'ip';\n\nexport interface VectorCollectionSpec {\n name: string;\n space?: VectorSpace;\n metadata?: Chroma.CollectionMetadata;\n /** 'recreate' drops + rebuilds a wrong-space collection (derived/rebuildable data only). Default 'reject' never auto-drops a consumer's data. */\n onSpaceMismatch?: 'recreate' | 'reject';\n}\n\nexport interface VectorStoreHandle {\n /** Human-readable connection target, for logs. */\n readonly target: string;\n collection(spec: VectorCollectionSpec): Promise<VectorCollection | null>;\n getCollection(name: string): Promise<VectorCollection | null>;\n deleteCollection(name: string): Promise<boolean>;\n heartbeat(): Promise<boolean>;\n}\n\nconst stubEmbeddingFunction: Chroma.EmbeddingFunction = {\n // Callers always supply pre-computed vectors; the stub stops chromadb from\n // instantiating its own DefaultEmbeddingFunction.\n generate: async () => [],\n};\n\nconst DEFAULT_ON_SPACE_MISMATCH = 'reject';\n\nfunction isEmptyConfig(config: VectorStoreConfig): boolean {\n return !config.host && !config.apiKey;\n}\n\nfunction configCacheKey(config: VectorStoreConfig): string {\n return JSON.stringify([config.host ?? null, config.apiKey ?? null, config.tenant ?? null, config.database ?? null]);\n}\n\nasync function loadChromaModule(): Promise<typeof import('chromadb') | null> {\n try {\n return await import('chromadb');\n } catch (err) {\n vectorLog.warn('store:module-missing', () => ({\n error: errorMessage(err),\n hint: 'add chromadb to dependencies and run pnpm install',\n }));\n return null;\n }\n}\n\nasync function resolveCollection(\n client: Chroma.ChromaClient,\n spec: VectorCollectionSpec,\n): Promise<VectorCollection | null> {\n const create = (): Promise<Chroma.Collection> =>\n client.getOrCreateCollection({\n name: spec.name,\n embeddingFunction: stubEmbeddingFunction,\n ...(spec.space ? { configuration: { hnsw: { space: spec.space } } } : {}),\n ...(spec.metadata ? { metadata: spec.metadata } : {}),\n });\n\n let raw: Chroma.Collection;\n try {\n raw = await create();\n } catch (err) {\n vectorLog.warn('collection:create-failed', () => ({ name: spec.name, error: errorMessage(err) }));\n return null;\n }\n\n // spec.space omitted ⇒ no verification, server default on create.\n if (!spec.space) return wrapVectorCollection(raw);\n\n const foundSpace = raw.configuration.hnsw?.space ?? null;\n if (foundSpace === spec.space) return wrapVectorCollection(raw);\n\n const policy = spec.onSpaceMismatch ?? DEFAULT_ON_SPACE_MISMATCH;\n if (policy === 'reject') {\n vectorLog.warn('collection:space-mismatch', () => ({\n name: spec.name,\n declaredSpace: spec.space,\n foundSpace,\n policy,\n }));\n return null;\n }\n\n vectorLog.warn('collection:space-heal', () => ({ name: spec.name, declaredSpace: spec.space, foundSpace }));\n await client.deleteCollection({ name: spec.name });\n try {\n raw = await create();\n } catch (err) {\n vectorLog.warn('collection:create-failed', () => ({ name: spec.name, error: errorMessage(err) }));\n return null;\n }\n return wrapVectorCollection(raw);\n}\n\nfunction buildVectorStoreHandle(client: Chroma.ChromaClient, target: string): VectorStoreHandle {\n return {\n target,\n collection(spec) {\n return resolveCollection(client, spec);\n },\n async getCollection(name) {\n try {\n const raw = await client.getCollection({ name, embeddingFunction: stubEmbeddingFunction });\n return wrapVectorCollection(raw);\n } catch (err) {\n vectorLog.debug('collection:get-missing', () => ({ name, error: errorMessage(err) }));\n return null;\n }\n },\n async deleteCollection(name) {\n try {\n await client.deleteCollection({ name });\n return true;\n } catch (err) {\n vectorLog.warn('collection:delete-failed', () => ({ name, error: errorMessage(err) }));\n return false;\n }\n },\n async heartbeat() {\n try {\n await client.heartbeat();\n return true;\n } catch {\n return false;\n }\n },\n };\n}\n\nconst vectorStoreCache = new Map<string, VectorStoreHandle>();\n\n/** The empty-config skip is a per-process fact — log it once, not per retrieval. */\nlet emptyConfigSkipLogged = false;\n\n/** Test-only reset — clears the per-process handle cache between cases. */\nexport function resetVectorStoreCache(): void {\n vectorStoreCache.clear();\n emptyConfigSkipLogged = false;\n}\n\nexport async function connectVectorStore(config: VectorStoreConfig): Promise<VectorStoreHandle | null> {\n if (isEmptyConfig(config)) {\n if (!emptyConfigSkipLogged) {\n emptyConfigSkipLogged = true;\n vectorLog.debug('store:skip', () => ({ reason: 'config-empty' }));\n }\n return null;\n }\n\n const key = configCacheKey(config);\n const cached = vectorStoreCache.get(key);\n if (cached) return cached;\n\n const mod = await loadChromaModule();\n if (!mod) return null;\n\n let client: Chroma.ChromaClient;\n let target: string;\n if (config.apiKey) {\n client = new mod.CloudClient({ apiKey: config.apiKey, tenant: config.tenant, database: config.database });\n target = `cloud(tenant=${config.tenant ?? 'default'}, db=${config.database ?? 'default'})`;\n } else if (config.host) {\n client = new mod.ChromaClient(parseVectorHost(config.host));\n target = config.host;\n } else {\n // unreachable: isEmptyConfig already guards host/apiKey both absent.\n return null;\n }\n\n try {\n await client.heartbeat();\n } catch (err) {\n vectorLog.warn('store:heartbeat-failed', () => ({ target, error: errorMessage(err) }));\n return null;\n }\n\n const handle = buildVectorStoreHandle(client, target);\n vectorStoreCache.set(key, handle);\n vectorLog.info('store:ready', () => ({ target }));\n return handle;\n}\n","/**\n * Query-result shaping — pure seams, no chromadb import (types only, erased).\n */\nimport type * as Chroma from 'chromadb';\n\nexport interface VectorHit {\n id: string;\n distance: number;\n score: number;\n metadata?: Chroma.Metadata;\n document?: string;\n}\n\nconst DEFAULT_QUERY_TOP_K = 10;\n\nexport function normalizeVectorTopK(topK: number | undefined): number {\n if (typeof topK !== 'number' || !Number.isFinite(topK) || topK <= 0) return DEFAULT_QUERY_TOP_K;\n return Math.floor(topK);\n}\n\nfunction clamp01(value: number): number {\n if (value < 0) return 0;\n if (value > 1) return 1;\n return value;\n}\n\n/** Structural subset of chromadb's `QueryResult` this module reads (pure-shaping seam). */\nexport interface VectorQueryResultLike {\n readonly ids: ReadonlyArray<ReadonlyArray<string>>;\n readonly distances: ReadonlyArray<ReadonlyArray<number | null>>;\n readonly metadatas?: ReadonlyArray<ReadonlyArray<Chroma.Metadata | null>>;\n readonly documents?: ReadonlyArray<ReadonlyArray<string | null>>;\n}\n\nexport function shapeVectorHits(result: VectorQueryResultLike): VectorHit[] {\n const ids = result.ids[0] ?? [];\n const distances = result.distances[0] ?? [];\n const metadatas = result.metadatas?.[0] ?? [];\n const documents = result.documents?.[0] ?? [];\n const hits: VectorHit[] = [];\n for (let i = 0; i < ids.length; i++) {\n const id = ids[i];\n if (typeof id !== 'string') continue;\n const rawDistance = distances[i];\n // a missing/null distance is the worst case (no similarity signal) — treat as 1, same as rabit's shapeChromaMatches.\n const distance = typeof rawDistance === 'number' ? rawDistance : 1;\n const score = clamp01(1 - distance);\n const metadata = metadatas[i];\n const document = documents[i];\n hits.push({\n id,\n distance,\n score,\n ...(metadata ? { metadata } : {}),\n ...(typeof document === 'string' ? { document } : {}),\n });\n }\n hits.sort((a, b) => b.score - a.score);\n return hits;\n}\n","/**\n * VectorCollection — thin wrapper over a live chromadb `Collection`: batched\n * writes, query shaping, and space/metadata read-through. Mechanics only —\n * callers own retry/best-effort policy, so failures propagate as rejections\n * here (unlike the connect/collection-resolution seams, which never throw).\n */\nimport type * as Chroma from 'chromadb';\nimport { normalizeVectorTopK, shapeVectorHits, type VectorHit } from './shape.js';\n\nexport interface VectorRecords {\n ids: readonly string[];\n embeddings: readonly (readonly number[])[];\n documents?: readonly string[];\n metadatas?: readonly Chroma.Metadata[];\n}\n\nexport interface VectorQueryOptions {\n embedding: readonly number[];\n topK?: number;\n where?: Chroma.Where;\n includeDocuments?: boolean;\n includeMetadatas?: boolean;\n}\n\nexport interface VectorDeleteTarget {\n ids?: readonly string[];\n where?: Chroma.Where;\n}\n\nexport interface VectorGetOptions {\n where?: Chroma.Where;\n /** Default true. */\n includeMetadatas?: boolean;\n /** Default false — privacy default: raw node text is never returned unless explicitly asked for. */\n includeDocuments?: boolean;\n limit?: number;\n}\n\nexport interface VectorRecord {\n id: string;\n metadata?: Chroma.Metadata | undefined;\n document?: string | undefined;\n}\n\nexport interface VectorCollection {\n upsert(records: VectorRecords): Promise<number>;\n add(records: VectorRecords): Promise<number>;\n query(opts: VectorQueryOptions): Promise<VectorHit[]>;\n /** Fetch records by metadata filter (no embedding / no similarity). Defaults to metadatas-only. */\n get(opts?: VectorGetOptions): Promise<VectorRecord[]>;\n delete(target: VectorDeleteTarget): Promise<void>;\n count(): Promise<number>;\n /** Every id in the collection (paged get, vectors not fetched) — backs mirror-sync reconciliation. */\n listIds(): Promise<string[]>;\n readonly metadata: Chroma.CollectionMetadata | undefined;\n readonly space: string | null;\n}\n\nconst WRITE_BATCH_SIZE = 500;\n\ninterface WriteBatch {\n ids: string[];\n embeddings: number[][];\n documents?: string[];\n metadatas?: Chroma.Metadata[];\n}\n\nasync function writeInBatches(\n write: (batch: WriteBatch) => Promise<void>,\n records: VectorRecords,\n): Promise<number> {\n const { ids, embeddings, documents, metadatas } = records;\n let written = 0;\n for (let start = 0; start < ids.length; start += WRITE_BATCH_SIZE) {\n const end = Math.min(start + WRITE_BATCH_SIZE, ids.length);\n await write({\n ids: ids.slice(start, end),\n embeddings: embeddings.slice(start, end).map((vec) => [...vec]),\n ...(documents ? { documents: documents.slice(start, end) } : {}),\n ...(metadatas ? { metadatas: metadatas.slice(start, end) } : {}),\n });\n written += end - start;\n }\n return written;\n}\n\nexport function wrapVectorCollection(raw: Chroma.Collection): VectorCollection {\n return {\n upsert(records) {\n return writeInBatches((batch) => raw.upsert(batch), records);\n },\n add(records) {\n return writeInBatches((batch) => raw.add(batch), records);\n },\n async query(opts) {\n const include: Array<'distances' | 'metadatas' | 'documents'> = ['distances'];\n if (opts.includeMetadatas) include.push('metadatas');\n if (opts.includeDocuments) include.push('documents');\n const result = await raw.query({\n queryEmbeddings: [[...opts.embedding]],\n nResults: normalizeVectorTopK(opts.topK),\n where: opts.where,\n include,\n });\n return shapeVectorHits(result);\n },\n async delete(target) {\n await raw.delete({\n ...(target.ids ? { ids: [...target.ids] } : {}),\n ...(target.where ? { where: target.where } : {}),\n });\n },\n async get(opts = {}) {\n const include: Array<'metadatas' | 'documents'> = [];\n if (opts.includeMetadatas !== false) include.push('metadatas');\n if (opts.includeDocuments) include.push('documents');\n const records: VectorRecord[] = [];\n const PAGE = 10_000;\n const hardLimit = opts.limit ?? Number.MAX_SAFE_INTEGER;\n for (let offset = 0; offset < hardLimit; offset += PAGE) {\n const pageLimit = Math.min(PAGE, hardLimit - offset);\n const page = await raw.get({\n ...(opts.where ? { where: opts.where } : {}),\n include,\n limit: pageLimit,\n offset,\n });\n const wantMeta = include.includes('metadatas');\n const wantDoc = include.includes('documents');\n for (let i = 0; i < page.ids.length; i++) {\n records.push({\n id: page.ids[i],\n ...(wantMeta ? { metadata: page.metadatas?.[i] ?? undefined } : {}),\n ...(wantDoc ? { document: page.documents?.[i] ?? undefined } : {}),\n });\n }\n if (page.ids.length < pageLimit) break;\n }\n return records;\n },\n count() {\n return raw.count();\n },\n async listIds() {\n const ids: string[] = [];\n const PAGE = 10_000;\n for (let offset = 0; ; offset += PAGE) {\n const page = await raw.get({ include: [], limit: PAGE, offset });\n ids.push(...page.ids);\n if (page.ids.length < PAGE) break;\n }\n return ids;\n },\n get metadata() {\n return raw.metadata;\n },\n get space() {\n return raw.configuration.hnsw?.space ?? null;\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@almadar/llm",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.38.0",
|
|
4
4
|
"description": "Multi-provider LLM client with rate limiting, token tracking, structured outputs, and continuation handling",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -46,10 +46,10 @@
|
|
|
46
46
|
"@almadar/logger": "^1.10.0"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"@almadar/core": "^10.
|
|
49
|
+
"@almadar/core": "^10.40.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@almadar/core": "^10.
|
|
52
|
+
"@almadar/core": "^10.40.0",
|
|
53
53
|
"@almadar/eslint-plugin": "^2.15.0",
|
|
54
54
|
"@types/node": "^22.0.0",
|
|
55
55
|
"@typescript-eslint/parser": "8.56.0",
|
package/src/vector/store.ts
CHANGED
|
@@ -148,14 +148,21 @@ function buildVectorStoreHandle(client: Chroma.ChromaClient, target: string): Ve
|
|
|
148
148
|
|
|
149
149
|
const vectorStoreCache = new Map<string, VectorStoreHandle>();
|
|
150
150
|
|
|
151
|
+
/** The empty-config skip is a per-process fact — log it once, not per retrieval. */
|
|
152
|
+
let emptyConfigSkipLogged = false;
|
|
153
|
+
|
|
151
154
|
/** Test-only reset — clears the per-process handle cache between cases. */
|
|
152
155
|
export function resetVectorStoreCache(): void {
|
|
153
156
|
vectorStoreCache.clear();
|
|
157
|
+
emptyConfigSkipLogged = false;
|
|
154
158
|
}
|
|
155
159
|
|
|
156
160
|
export async function connectVectorStore(config: VectorStoreConfig): Promise<VectorStoreHandle | null> {
|
|
157
161
|
if (isEmptyConfig(config)) {
|
|
158
|
-
|
|
162
|
+
if (!emptyConfigSkipLogged) {
|
|
163
|
+
emptyConfigSkipLogged = true;
|
|
164
|
+
vectorLog.debug('store:skip', () => ({ reason: 'config-empty' }));
|
|
165
|
+
}
|
|
159
166
|
return null;
|
|
160
167
|
}
|
|
161
168
|
|