@opengeni/documents 0.2.7 → 0.2.9
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/index.js +200 -120
- package/dist/index.js.map +1 -1
- package/package.json +16 -16
- package/src/index.ts +541 -303
package/dist/index.js
CHANGED
|
@@ -56,8 +56,6 @@ var RecursiveTextChunker = class {
|
|
|
56
56
|
throw new Error("document chunk overlap must be smaller than chunk size");
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
maxChars;
|
|
60
|
-
overlapChars;
|
|
61
59
|
chunk(parsed, file) {
|
|
62
60
|
return chunkText(parsed.text, this.maxChars, this.overlapChars).map((text, index) => ({
|
|
63
61
|
text,
|
|
@@ -127,8 +125,6 @@ var DeterministicEmbeddingProvider = class {
|
|
|
127
125
|
this.dimensions = dimensions;
|
|
128
126
|
this.model = model;
|
|
129
127
|
}
|
|
130
|
-
dimensions;
|
|
131
|
-
model;
|
|
132
128
|
async embedMany(texts) {
|
|
133
129
|
return texts.map((text) => deterministicEmbedding(text, this.dimensions));
|
|
134
130
|
}
|
|
@@ -190,16 +186,20 @@ function azureOpenAIDefaultQuery(settings, baseURL) {
|
|
|
190
186
|
return { "api-version": settings.azureOpenaiApiVersion };
|
|
191
187
|
}
|
|
192
188
|
async function createDocumentBase(db, input) {
|
|
193
|
-
return await withRlsContext(
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
189
|
+
return await withRlsContext(
|
|
190
|
+
db,
|
|
191
|
+
{ accountId: input.accountId, workspaceId: input.workspaceId },
|
|
192
|
+
async (scopedDb) => {
|
|
193
|
+
const [row] = await scopedDb.insert(schema.documentBases).values({
|
|
194
|
+
accountId: input.accountId,
|
|
195
|
+
workspaceId: input.workspaceId,
|
|
196
|
+
name: input.name.trim(),
|
|
197
|
+
description: input.description?.trim() || null
|
|
198
|
+
}).returning();
|
|
199
|
+
if (!row) throw new Error("Failed to create document base");
|
|
200
|
+
return mapDocumentBase(row);
|
|
201
|
+
}
|
|
202
|
+
);
|
|
203
203
|
}
|
|
204
204
|
async function listDocumentBases(db, workspaceId) {
|
|
205
205
|
return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
|
|
@@ -209,77 +209,112 @@ async function listDocumentBases(db, workspaceId) {
|
|
|
209
209
|
}
|
|
210
210
|
async function getDocumentBase(db, workspaceId, baseId) {
|
|
211
211
|
return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
|
|
212
|
-
const [row] = await scopedDb.select().from(schema.documentBases).where(
|
|
212
|
+
const [row] = await scopedDb.select().from(schema.documentBases).where(
|
|
213
|
+
and(eq(schema.documentBases.workspaceId, workspaceId), eq(schema.documentBases.id, baseId))
|
|
214
|
+
).limit(1);
|
|
213
215
|
return row ? mapDocumentBase(row) : null;
|
|
214
216
|
});
|
|
215
217
|
}
|
|
216
218
|
async function addDocumentToBase(db, input) {
|
|
217
|
-
return await withRlsContext(
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
219
|
+
return await withRlsContext(
|
|
220
|
+
db,
|
|
221
|
+
{ accountId: input.accountId, workspaceId: input.workspaceId },
|
|
222
|
+
async (scopedDb) => {
|
|
223
|
+
const base = await getDocumentBase(scopedDb, input.workspaceId, input.baseId);
|
|
224
|
+
if (!base) throw new Error(`Document base not found: ${input.baseId}`);
|
|
225
|
+
const file = await requireReadyFile(scopedDb, input.workspaceId, input.fileId);
|
|
226
|
+
const now = /* @__PURE__ */ new Date();
|
|
227
|
+
const [existing] = await scopedDb.select().from(schema.documents).where(
|
|
228
|
+
and(
|
|
229
|
+
eq(schema.documents.workspaceId, input.workspaceId),
|
|
230
|
+
eq(schema.documents.baseId, input.baseId),
|
|
231
|
+
eq(schema.documents.fileId, input.fileId)
|
|
232
|
+
)
|
|
233
|
+
).limit(1);
|
|
234
|
+
if (existing) {
|
|
235
|
+
const [updated] = await scopedDb.update(schema.documents).set({
|
|
236
|
+
title: cleanString(input.title) ?? cleanString(input.sourceTitle) ?? existing.title,
|
|
237
|
+
...input.sourceKind !== void 0 ? { sourceKind: input.sourceKind } : {},
|
|
238
|
+
sourceUri: cleanString(input.sourceUri) ?? existing.sourceUri,
|
|
239
|
+
sourceExternalId: cleanString(input.sourceExternalId) ?? existing.sourceExternalId,
|
|
240
|
+
sourceTitle: cleanString(input.sourceTitle) ?? existing.sourceTitle,
|
|
241
|
+
sourceAuthor: cleanString(input.sourceAuthor) ?? existing.sourceAuthor,
|
|
242
|
+
sourceCreatedAt: parseOptionalDate(input.sourceCreatedAt) ?? existing.sourceCreatedAt,
|
|
243
|
+
sourceUpdatedAt: parseOptionalDate(input.sourceUpdatedAt) ?? existing.sourceUpdatedAt,
|
|
244
|
+
sourceVersion: cleanString(input.sourceVersion) ?? existing.sourceVersion,
|
|
245
|
+
...input.aclTags !== void 0 ? { aclTags: cleanStringArray(input.aclTags) } : {},
|
|
246
|
+
updatedAt: now
|
|
247
|
+
}).where(
|
|
248
|
+
and(
|
|
249
|
+
eq(schema.documents.workspaceId, input.workspaceId),
|
|
250
|
+
eq(schema.documents.id, existing.id)
|
|
251
|
+
)
|
|
252
|
+
).returning();
|
|
253
|
+
return mapDocument(updated ?? existing);
|
|
254
|
+
}
|
|
255
|
+
const [row] = await scopedDb.insert(schema.documents).values({
|
|
256
|
+
accountId: input.accountId,
|
|
257
|
+
workspaceId: input.workspaceId,
|
|
258
|
+
baseId: input.baseId,
|
|
259
|
+
fileId: input.fileId,
|
|
260
|
+
status: "queued",
|
|
261
|
+
title: cleanString(input.title) ?? cleanString(input.sourceTitle) ?? file.filename,
|
|
262
|
+
parser: DEFAULT_DOCUMENT_PARSER,
|
|
263
|
+
sourceKind: input.sourceKind ?? "manual_upload",
|
|
264
|
+
sourceUri: cleanString(input.sourceUri) ?? null,
|
|
265
|
+
sourceExternalId: cleanString(input.sourceExternalId) ?? null,
|
|
266
|
+
sourceTitle: cleanString(input.sourceTitle) ?? null,
|
|
267
|
+
sourceAuthor: cleanString(input.sourceAuthor) ?? null,
|
|
268
|
+
sourceCreatedAt: parseOptionalDate(input.sourceCreatedAt),
|
|
269
|
+
sourceUpdatedAt: parseOptionalDate(input.sourceUpdatedAt),
|
|
270
|
+
sourceVersion: cleanString(input.sourceVersion) ?? null,
|
|
271
|
+
aclTags: cleanStringArray(input.aclTags),
|
|
235
272
|
updatedAt: now
|
|
236
|
-
}).
|
|
237
|
-
|
|
273
|
+
}).returning();
|
|
274
|
+
if (!row) throw new Error("Failed to create document");
|
|
275
|
+
return mapDocument(row);
|
|
238
276
|
}
|
|
239
|
-
|
|
240
|
-
accountId: input.accountId,
|
|
241
|
-
workspaceId: input.workspaceId,
|
|
242
|
-
baseId: input.baseId,
|
|
243
|
-
fileId: input.fileId,
|
|
244
|
-
status: "queued",
|
|
245
|
-
title: cleanString(input.title) ?? cleanString(input.sourceTitle) ?? file.filename,
|
|
246
|
-
parser: DEFAULT_DOCUMENT_PARSER,
|
|
247
|
-
sourceKind: input.sourceKind ?? "manual_upload",
|
|
248
|
-
sourceUri: cleanString(input.sourceUri) ?? null,
|
|
249
|
-
sourceExternalId: cleanString(input.sourceExternalId) ?? null,
|
|
250
|
-
sourceTitle: cleanString(input.sourceTitle) ?? null,
|
|
251
|
-
sourceAuthor: cleanString(input.sourceAuthor) ?? null,
|
|
252
|
-
sourceCreatedAt: parseOptionalDate(input.sourceCreatedAt),
|
|
253
|
-
sourceUpdatedAt: parseOptionalDate(input.sourceUpdatedAt),
|
|
254
|
-
sourceVersion: cleanString(input.sourceVersion) ?? null,
|
|
255
|
-
aclTags: cleanStringArray(input.aclTags),
|
|
256
|
-
updatedAt: now
|
|
257
|
-
}).returning();
|
|
258
|
-
if (!row) throw new Error("Failed to create document");
|
|
259
|
-
return mapDocument(row);
|
|
260
|
-
});
|
|
277
|
+
);
|
|
261
278
|
}
|
|
262
279
|
async function deleteDocumentFromBase(db, input) {
|
|
263
|
-
await withRlsContext(
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
280
|
+
await withRlsContext(
|
|
281
|
+
db,
|
|
282
|
+
{ accountId: input.accountId, workspaceId: input.workspaceId },
|
|
283
|
+
async (scopedDb) => {
|
|
284
|
+
const [document] = await scopedDb.select().from(schema.documents).where(
|
|
285
|
+
and(
|
|
286
|
+
eq(schema.documents.workspaceId, input.workspaceId),
|
|
287
|
+
eq(schema.documents.id, input.documentId)
|
|
288
|
+
)
|
|
289
|
+
).limit(1);
|
|
290
|
+
if (!document) {
|
|
291
|
+
throw new Error(`Document not found: ${input.documentId}`);
|
|
292
|
+
}
|
|
293
|
+
if (document.baseId !== input.baseId) {
|
|
294
|
+
throw new Error(`Document not found: ${input.documentId}`);
|
|
295
|
+
}
|
|
296
|
+
await scopedDb.delete(schema.documents).where(
|
|
297
|
+
and(
|
|
298
|
+
eq(schema.documents.workspaceId, input.workspaceId),
|
|
299
|
+
eq(schema.documents.id, input.documentId)
|
|
300
|
+
)
|
|
301
|
+
);
|
|
270
302
|
}
|
|
271
|
-
|
|
272
|
-
});
|
|
303
|
+
);
|
|
273
304
|
}
|
|
274
305
|
async function listDocuments(db, workspaceId, baseId) {
|
|
275
306
|
return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
|
|
276
|
-
const rows = await scopedDb.select().from(schema.documents).where(
|
|
307
|
+
const rows = await scopedDb.select().from(schema.documents).where(
|
|
308
|
+
and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.baseId, baseId))
|
|
309
|
+
).orderBy(asc(schema.documents.createdAt));
|
|
277
310
|
return rows.map(mapDocument);
|
|
278
311
|
});
|
|
279
312
|
}
|
|
280
313
|
async function getDocument(db, workspaceId, documentId) {
|
|
281
314
|
return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
|
|
282
|
-
const [row] = await scopedDb.select().from(schema.documents).where(
|
|
315
|
+
const [row] = await scopedDb.select().from(schema.documents).where(
|
|
316
|
+
and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId))
|
|
317
|
+
).limit(1);
|
|
283
318
|
return row ? mapDocument(row) : null;
|
|
284
319
|
});
|
|
285
320
|
}
|
|
@@ -289,7 +324,9 @@ async function queueDocumentForReindex(db, workspaceId, documentId) {
|
|
|
289
324
|
status: "queued",
|
|
290
325
|
error: null,
|
|
291
326
|
updatedAt: /* @__PURE__ */ new Date()
|
|
292
|
-
}).where(
|
|
327
|
+
}).where(
|
|
328
|
+
and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId))
|
|
329
|
+
).returning();
|
|
293
330
|
if (!row) throw new Error(`Document not found: ${documentId}`);
|
|
294
331
|
return mapDocument(row);
|
|
295
332
|
});
|
|
@@ -298,7 +335,9 @@ async function indexDocumentNow(db, objectStorage, workspaceId, documentId, serv
|
|
|
298
335
|
const [document] = await withWorkspaceRls(
|
|
299
336
|
db,
|
|
300
337
|
workspaceId,
|
|
301
|
-
async (scopedDb) => await scopedDb.select().from(schema.documents).where(
|
|
338
|
+
async (scopedDb) => await scopedDb.select().from(schema.documents).where(
|
|
339
|
+
and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId))
|
|
340
|
+
).limit(1)
|
|
302
341
|
);
|
|
303
342
|
if (!document) throw new Error(`Document not found: ${documentId}`);
|
|
304
343
|
const file = await requireReadyFile(db, workspaceId, document.fileId);
|
|
@@ -308,7 +347,9 @@ async function indexDocumentNow(db, objectStorage, workspaceId, documentId, serv
|
|
|
308
347
|
parser: services.parser.name,
|
|
309
348
|
error: null,
|
|
310
349
|
updatedAt: /* @__PURE__ */ new Date()
|
|
311
|
-
}).where(
|
|
350
|
+
}).where(
|
|
351
|
+
and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId))
|
|
352
|
+
);
|
|
312
353
|
});
|
|
313
354
|
try {
|
|
314
355
|
const bytes = await objectStorage.getFileBytes(file);
|
|
@@ -322,44 +363,66 @@ async function indexDocumentNow(db, objectStorage, workspaceId, documentId, serv
|
|
|
322
363
|
});
|
|
323
364
|
const embeddings = await services.embedder.embedMany(chunks.map((chunk) => chunk.text));
|
|
324
365
|
if (embeddings.length !== chunks.length) {
|
|
325
|
-
throw new Error(
|
|
366
|
+
throw new Error(
|
|
367
|
+
`Embedding provider returned ${embeddings.length} embeddings for ${chunks.length} chunks`
|
|
368
|
+
);
|
|
326
369
|
}
|
|
327
|
-
await withWorkspaceRls(
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
370
|
+
await withWorkspaceRls(
|
|
371
|
+
db,
|
|
372
|
+
workspaceId,
|
|
373
|
+
async (scopedDb) => await scopedDb.transaction(async (tx) => {
|
|
374
|
+
await tx.delete(schema.documentChunks).where(
|
|
375
|
+
and(
|
|
376
|
+
eq(schema.documentChunks.workspaceId, workspaceId),
|
|
377
|
+
eq(schema.documentChunks.documentId, documentId)
|
|
378
|
+
)
|
|
379
|
+
);
|
|
380
|
+
if (chunks.length > 0) {
|
|
381
|
+
await tx.insert(schema.documentChunks).values(
|
|
382
|
+
chunks.map((chunk, index) => ({
|
|
383
|
+
accountId: document.accountId,
|
|
384
|
+
workspaceId: document.workspaceId,
|
|
385
|
+
documentId,
|
|
386
|
+
baseId: document.baseId,
|
|
387
|
+
fileId: file.id,
|
|
388
|
+
chunkIndex: index,
|
|
389
|
+
text: chunk.text,
|
|
390
|
+
metadata: {
|
|
391
|
+
...chunk.metadata,
|
|
392
|
+
documentTitle: document.title,
|
|
393
|
+
sourceKind: document.sourceKind,
|
|
394
|
+
sourceUri: document.sourceUri,
|
|
395
|
+
sourceExternalId: document.sourceExternalId,
|
|
396
|
+
sourceTitle: document.sourceTitle,
|
|
397
|
+
sourceAuthor: document.sourceAuthor,
|
|
398
|
+
sourceCreatedAt: document.sourceCreatedAt?.toISOString() ?? null,
|
|
399
|
+
sourceUpdatedAt: document.sourceUpdatedAt?.toISOString() ?? null,
|
|
400
|
+
sourceVersion: document.sourceVersion,
|
|
401
|
+
aclTags: document.aclTags
|
|
402
|
+
},
|
|
403
|
+
embedding: validateEmbedding(
|
|
404
|
+
embeddings[index] ?? [],
|
|
405
|
+
services.embedder.dimensions,
|
|
406
|
+
services.embedder.model
|
|
407
|
+
),
|
|
408
|
+
embeddingModel: services.embedder.model
|
|
409
|
+
}))
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
await tx.update(schema.documents).set({
|
|
413
|
+
status: "ready",
|
|
414
|
+
parser: services.parser.name,
|
|
415
|
+
chunkCount: chunks.length,
|
|
416
|
+
error: null,
|
|
417
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
418
|
+
}).where(
|
|
419
|
+
and(
|
|
420
|
+
eq(schema.documents.workspaceId, workspaceId),
|
|
421
|
+
eq(schema.documents.id, documentId)
|
|
422
|
+
)
|
|
423
|
+
);
|
|
424
|
+
})
|
|
425
|
+
);
|
|
363
426
|
} catch (error) {
|
|
364
427
|
const [failed] = await withWorkspaceRls(
|
|
365
428
|
db,
|
|
@@ -368,7 +431,9 @@ async function indexDocumentNow(db, objectStorage, workspaceId, documentId, serv
|
|
|
368
431
|
status: "failed",
|
|
369
432
|
error: error instanceof Error ? error.message : String(error),
|
|
370
433
|
updatedAt: /* @__PURE__ */ new Date()
|
|
371
|
-
}).where(
|
|
434
|
+
}).where(
|
|
435
|
+
and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId))
|
|
436
|
+
).returning()
|
|
372
437
|
);
|
|
373
438
|
if (!failed) throw error;
|
|
374
439
|
return mapDocument(failed);
|
|
@@ -389,10 +454,13 @@ async function searchDocuments(db, input, services = createDocumentServices()) {
|
|
|
389
454
|
if (mode === "vector") {
|
|
390
455
|
throw error;
|
|
391
456
|
}
|
|
392
|
-
console.warn(
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
457
|
+
console.warn(
|
|
458
|
+
"document hybrid search vector component failed; falling back to keyword search",
|
|
459
|
+
{
|
|
460
|
+
workspaceId: input.workspaceId,
|
|
461
|
+
error: error instanceof Error ? error.message : String(error)
|
|
462
|
+
}
|
|
463
|
+
);
|
|
396
464
|
}
|
|
397
465
|
}
|
|
398
466
|
if (mode === "keyword" || mode === "hybrid") {
|
|
@@ -458,10 +526,12 @@ async function keywordSearchDocuments(db, input, limit) {
|
|
|
458
526
|
sourceVersion: schema.documents.sourceVersion,
|
|
459
527
|
aclTags: schema.documents.aclTags,
|
|
460
528
|
rank
|
|
461
|
-
}).from(schema.documentChunks).innerJoin(schema.documents, eq(schema.documentChunks.documentId, schema.documents.id)).where(
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
529
|
+
}).from(schema.documentChunks).innerJoin(schema.documents, eq(schema.documentChunks.documentId, schema.documents.id)).where(
|
|
530
|
+
and(
|
|
531
|
+
...documentSearchConditions(input),
|
|
532
|
+
sql`to_tsvector('simple', ${schema.documentChunks.text}) @@ plainto_tsquery('simple', ${input.query})`
|
|
533
|
+
)
|
|
534
|
+
).orderBy(desc(rank)).limit(limit)
|
|
465
535
|
);
|
|
466
536
|
return rows.map((row) => ({
|
|
467
537
|
...mapSearchRowBase(row, input.workspaceId),
|
|
@@ -491,7 +561,13 @@ async function getDocumentChunk(db, workspaceId, chunkId) {
|
|
|
491
561
|
sourceUpdatedAt: schema.documents.sourceUpdatedAt,
|
|
492
562
|
sourceVersion: schema.documents.sourceVersion,
|
|
493
563
|
aclTags: schema.documents.aclTags
|
|
494
|
-
}).from(schema.documentChunks).innerJoin(schema.documents, eq(schema.documentChunks.documentId, schema.documents.id)).where(
|
|
564
|
+
}).from(schema.documentChunks).innerJoin(schema.documents, eq(schema.documentChunks.documentId, schema.documents.id)).where(
|
|
565
|
+
and(
|
|
566
|
+
eq(schema.documentChunks.workspaceId, workspaceId),
|
|
567
|
+
eq(schema.documentChunks.id, chunkId),
|
|
568
|
+
eq(schema.documents.status, "ready")
|
|
569
|
+
)
|
|
570
|
+
).limit(1)
|
|
495
571
|
);
|
|
496
572
|
if (!row) return null;
|
|
497
573
|
return {
|
|
@@ -576,7 +652,9 @@ function combinedSearchScore(mode, vectorScore, keywordScore, matchType) {
|
|
|
576
652
|
const keyword = keywordScore ?? 0;
|
|
577
653
|
if (mode === "vector") return roundScore(vector);
|
|
578
654
|
if (mode === "keyword") return roundScore(keyword);
|
|
579
|
-
return roundScore(
|
|
655
|
+
return roundScore(
|
|
656
|
+
Math.min(1, 0.65 * vector + 0.35 * keyword + (matchType === "hybrid" ? 0.1 : 0))
|
|
657
|
+
);
|
|
580
658
|
}
|
|
581
659
|
function normalizeKeywordScore(rank) {
|
|
582
660
|
if (!Number.isFinite(rank) || rank <= 0) {
|
|
@@ -637,7 +715,9 @@ async function requireReadyFile(db, workspaceId, fileId) {
|
|
|
637
715
|
}
|
|
638
716
|
function validateEmbedding(values, dimensions, model) {
|
|
639
717
|
if (values.length !== dimensions) {
|
|
640
|
-
throw new Error(
|
|
718
|
+
throw new Error(
|
|
719
|
+
`Embedding model ${model} returned ${values.length} dimensions; expected ${dimensions}`
|
|
720
|
+
);
|
|
641
721
|
}
|
|
642
722
|
if (values.some((value) => !Number.isFinite(value))) {
|
|
643
723
|
throw new Error(`Embedding model ${model} returned non-finite values`);
|