@utaba/deep-memory 0.14.0 → 0.16.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/{StorageProvider-BfdyQgiI.d.cts → StorageProvider-BGtKZZt4.d.cts} +1 -1
- package/dist/{StorageProvider-jpzVIKXs.d.ts → StorageProvider-D_o2Hksf.d.ts} +1 -1
- package/dist/index.cjs +180 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +67 -8
- package/dist/index.d.ts +67 -8
- package/dist/index.js +179 -70
- package/dist/index.js.map +1 -1
- package/dist/{portability-DWpZbxNn.d.cts → portability-P1hL-bOa.d.cts} +11 -0
- package/dist/{portability-DWpZbxNn.d.ts → portability-P1hL-bOa.d.ts} +11 -0
- package/dist/providers/index.d.cts +3 -3
- package/dist/providers/index.d.ts +3 -3
- package/dist/testing/conformance.d.cts +2 -2
- package/dist/testing/conformance.d.ts +2 -2
- package/dist/{traversal-COr0AJBc.d.ts → traversal-B_84kGaO.d.ts} +1 -1
- package/dist/{traversal-37JAiha-.d.cts → traversal-CBE5h5ob.d.cts} +1 -1
- package/dist/types/index.d.cts +13 -4
- package/dist/types/index.d.ts +13 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -165,6 +165,18 @@ var OperationCancelledError = class extends DeepMemoryError {
|
|
|
165
165
|
this.reason = reason;
|
|
166
166
|
}
|
|
167
167
|
};
|
|
168
|
+
var OperationAbortedError = class extends DeepMemoryError {
|
|
169
|
+
operation;
|
|
170
|
+
constructor(operation) {
|
|
171
|
+
super(
|
|
172
|
+
"OPERATION_ABORTED",
|
|
173
|
+
`${operation} aborted by caller`,
|
|
174
|
+
`The caller's AbortSignal was triggered. Partial state from completed batches has been retained.`
|
|
175
|
+
);
|
|
176
|
+
this.name = "OperationAbortedError";
|
|
177
|
+
this.operation = operation;
|
|
178
|
+
}
|
|
179
|
+
};
|
|
168
180
|
var EmbeddingProviderRequiredError = class extends DeepMemoryError {
|
|
169
181
|
constructor() {
|
|
170
182
|
super(
|
|
@@ -821,10 +833,15 @@ var EntityManager = class {
|
|
|
821
833
|
attempt++;
|
|
822
834
|
if (attempt > maxRetries) {
|
|
823
835
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
836
|
+
const failureMessage = `embedBatch failed after ${maxRetries} retries: ${errorMsg}`;
|
|
837
|
+
const failed = entries.map(([id]) => ({ entityId: id, error: failureMessage }));
|
|
838
|
+
for (const { entityId, error } of failed) {
|
|
839
|
+
await options?.onItemFailed?.(entityId, error);
|
|
840
|
+
}
|
|
824
841
|
return {
|
|
825
842
|
processed: 0,
|
|
826
843
|
failed: entries.length,
|
|
827
|
-
errors:
|
|
844
|
+
errors: failed,
|
|
828
845
|
modelId: this.embedding.modelId(),
|
|
829
846
|
dimensions: this.embedding.dimensions()
|
|
830
847
|
};
|
|
@@ -847,7 +864,9 @@ var EntityManager = class {
|
|
|
847
864
|
});
|
|
848
865
|
processed++;
|
|
849
866
|
} catch (err) {
|
|
850
|
-
|
|
867
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
868
|
+
errors.push({ entityId: id, error: errorMessage });
|
|
869
|
+
await options?.onItemFailed?.(id, errorMessage);
|
|
851
870
|
}
|
|
852
871
|
}
|
|
853
872
|
return {
|
|
@@ -872,6 +891,7 @@ var EntityManager = class {
|
|
|
872
891
|
}
|
|
873
892
|
const batchSize = options?.batchSize ?? 50;
|
|
874
893
|
const errorThreshold = options?.errorThresholdToAbort;
|
|
894
|
+
const signal = options?.signal;
|
|
875
895
|
const firstPage = await this.storage.findEntities(this.repositoryId, { limit: 1, offset: 0 });
|
|
876
896
|
const total = firstPage.total;
|
|
877
897
|
let totalProcessed = 0;
|
|
@@ -879,6 +899,9 @@ var EntityManager = class {
|
|
|
879
899
|
const allErrors = [];
|
|
880
900
|
let offset = 0;
|
|
881
901
|
while (offset < total) {
|
|
902
|
+
if (signal?.aborted) {
|
|
903
|
+
throw new OperationAbortedError("reembedAll");
|
|
904
|
+
}
|
|
882
905
|
const page = await this.storage.findEntities(this.repositoryId, {
|
|
883
906
|
limit: batchSize,
|
|
884
907
|
offset
|
|
@@ -886,17 +909,21 @@ var EntityManager = class {
|
|
|
886
909
|
if (page.items.length === 0) break;
|
|
887
910
|
const ids = page.items.map((e) => e.id);
|
|
888
911
|
const result = await this.reembedEntities(ids, {
|
|
889
|
-
maxRetries: options?.maxRetries
|
|
912
|
+
maxRetries: options?.maxRetries,
|
|
913
|
+
onItemFailed: options?.onItemFailed
|
|
890
914
|
});
|
|
891
915
|
totalProcessed += result.processed;
|
|
892
916
|
totalFailed += result.failed;
|
|
893
917
|
allErrors.push(...result.errors);
|
|
894
|
-
options?.onProgress?.(totalProcessed, total, totalFailed);
|
|
918
|
+
await options?.onProgress?.(totalProcessed, total, totalFailed);
|
|
895
919
|
if (errorThreshold !== void 0 && totalFailed >= errorThreshold) {
|
|
896
920
|
allErrors.push({ entityId: "", error: `Aborted: error threshold of ${errorThreshold} reached (${totalFailed} failures)` });
|
|
897
921
|
break;
|
|
898
922
|
}
|
|
899
923
|
offset += page.items.length;
|
|
924
|
+
if (signal?.aborted) {
|
|
925
|
+
throw new OperationAbortedError("reembedAll");
|
|
926
|
+
}
|
|
900
927
|
const delayMs = options?.delayBetweenBatchesMs ?? 0;
|
|
901
928
|
if (delayMs > 0 && offset < total) {
|
|
902
929
|
await new Promise((resolve) => {
|
|
@@ -2263,7 +2290,13 @@ var MemoryRepository = class {
|
|
|
2263
2290
|
* the repository's embedding configuration is updated to the new values before
|
|
2264
2291
|
* re-embedding, so all subsequent entity writes use the new model/dimensionality.
|
|
2265
2292
|
*
|
|
2266
|
-
* Processes in batches with optional rate limiting.
|
|
2293
|
+
* Processes in batches with optional rate limiting.
|
|
2294
|
+
*
|
|
2295
|
+
* Progress is delivered via the optional `onProgress` callback. Most callers
|
|
2296
|
+
* should use {@link DeepMemory.reembedAll} instead, which wires this callback
|
|
2297
|
+
* to the global event bus so `reembed:*` events are reachable via
|
|
2298
|
+
* `DeepMemory.on()`.
|
|
2299
|
+
*
|
|
2267
2300
|
* Updates repository metadata with the new model ID and dimensions on completion.
|
|
2268
2301
|
*/
|
|
2269
2302
|
async reembedAll(options) {
|
|
@@ -2298,46 +2331,26 @@ var MemoryRepository = class {
|
|
|
2298
2331
|
}
|
|
2299
2332
|
});
|
|
2300
2333
|
}
|
|
2301
|
-
const
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2334
|
+
const result = await this.entityManager.reembedAll({
|
|
2335
|
+
batchSize: options?.batchSize,
|
|
2336
|
+
maxRetries: options?.maxRetries,
|
|
2337
|
+
errorThresholdToAbort: options?.errorThresholdToAbort,
|
|
2338
|
+
delayBetweenBatchesMs: options?.delayBetweenBatchesMs,
|
|
2339
|
+
signal: options?.signal,
|
|
2340
|
+
onProgress: async (processed, total, failed) => {
|
|
2341
|
+
await options?.onProgress?.({ processed, totalEntities: total, failed });
|
|
2342
|
+
},
|
|
2343
|
+
onItemFailed: async (entityId, error) => {
|
|
2344
|
+
await options?.onItemFailed?.({ entityId, error });
|
|
2345
|
+
}
|
|
2305
2346
|
});
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
await this.eventBus.emit("reembed:progress", {
|
|
2314
|
-
repositoryId: this.repositoryId,
|
|
2315
|
-
processed,
|
|
2316
|
-
totalEntities: total,
|
|
2317
|
-
failed
|
|
2318
|
-
});
|
|
2319
|
-
}
|
|
2320
|
-
});
|
|
2321
|
-
await this.storage.updateRepository(this.repositoryId, {
|
|
2322
|
-
metadata: {
|
|
2323
|
-
embeddingModelId: result.modelId,
|
|
2324
|
-
embeddingDimensions: result.dimensions
|
|
2325
|
-
}
|
|
2326
|
-
});
|
|
2327
|
-
await this.eventBus.emit("reembed:completed", {
|
|
2328
|
-
repositoryId: this.repositoryId,
|
|
2329
|
-
processed: result.processed,
|
|
2330
|
-
failed: result.failed,
|
|
2331
|
-
modelId: result.modelId
|
|
2332
|
-
});
|
|
2333
|
-
return result;
|
|
2334
|
-
} catch (err) {
|
|
2335
|
-
await this.eventBus.emit("reembed:failed", {
|
|
2336
|
-
repositoryId: this.repositoryId,
|
|
2337
|
-
error: err instanceof Error ? err.message : String(err)
|
|
2338
|
-
});
|
|
2339
|
-
throw err;
|
|
2340
|
-
}
|
|
2347
|
+
await this.storage.updateRepository(this.repositoryId, {
|
|
2348
|
+
metadata: {
|
|
2349
|
+
embeddingModelId: result.modelId,
|
|
2350
|
+
embeddingDimensions: result.dimensions
|
|
2351
|
+
}
|
|
2352
|
+
});
|
|
2353
|
+
return result;
|
|
2341
2354
|
}
|
|
2342
2355
|
// ─── Relationships ─────────────────────────────────────────────────
|
|
2343
2356
|
async createRelationships(inputs) {
|
|
@@ -3451,7 +3464,7 @@ var EventBus = class {
|
|
|
3451
3464
|
};
|
|
3452
3465
|
|
|
3453
3466
|
// src/portability/RepositoryExporter.ts
|
|
3454
|
-
var LIBRARY_VERSION = true ? "0.
|
|
3467
|
+
var LIBRARY_VERSION = true ? "0.16.0" : "0.1.0";
|
|
3455
3468
|
var RepositoryExporter = class {
|
|
3456
3469
|
storage;
|
|
3457
3470
|
provenance;
|
|
@@ -3805,11 +3818,20 @@ var RepositoryImporter = class {
|
|
|
3805
3818
|
storage;
|
|
3806
3819
|
actorId;
|
|
3807
3820
|
onProgress;
|
|
3821
|
+
onItemFailed;
|
|
3822
|
+
signal;
|
|
3808
3823
|
migrationEngine = new MigrationEngine();
|
|
3809
3824
|
constructor(config) {
|
|
3810
3825
|
this.storage = config.storage;
|
|
3811
3826
|
this.actorId = config.actorId;
|
|
3812
3827
|
this.onProgress = config.onProgress;
|
|
3828
|
+
this.onItemFailed = config.onItemFailed;
|
|
3829
|
+
this.signal = config.signal;
|
|
3830
|
+
}
|
|
3831
|
+
throwIfAborted() {
|
|
3832
|
+
if (this.signal?.aborted) {
|
|
3833
|
+
throw new OperationAbortedError("import");
|
|
3834
|
+
}
|
|
3813
3835
|
}
|
|
3814
3836
|
/**
|
|
3815
3837
|
* Import an export archive according to the provided options.
|
|
@@ -3885,6 +3907,7 @@ var RepositoryImporter = class {
|
|
|
3885
3907
|
let chunksCompleted = 0;
|
|
3886
3908
|
const adaptiveConcurrencyHandle = options.bulk?.adaptiveConcurrencyHandle ?? {};
|
|
3887
3909
|
for await (const chunk of chunks) {
|
|
3910
|
+
this.throwIfAborted();
|
|
3888
3911
|
const bulkResult = await this.storage.importBulk(target.repositoryId, [chunk], {
|
|
3889
3912
|
...options.bulk,
|
|
3890
3913
|
skipExistenceCheck: true,
|
|
@@ -3899,6 +3922,8 @@ var RepositoryImporter = class {
|
|
|
3899
3922
|
message: `Failed to import ${e.item}: ${e.error}`,
|
|
3900
3923
|
id: e.item
|
|
3901
3924
|
});
|
|
3925
|
+
const itemType = chunk.entities?.some((x) => x.id === e.item) ? "entity" : chunk.relationships?.some((x) => x.id === e.item) ? "relationship" : "entity";
|
|
3926
|
+
await this.onItemFailed?.({ itemId: e.item, itemType, error: e.error });
|
|
3902
3927
|
}
|
|
3903
3928
|
await this.onProgress?.({
|
|
3904
3929
|
repositoryId: target.repositoryId,
|
|
@@ -3966,6 +3991,7 @@ var RepositoryImporter = class {
|
|
|
3966
3991
|
let relationshipsSkipped = 0;
|
|
3967
3992
|
let chunksCompleted = 0;
|
|
3968
3993
|
for await (const chunk of chunks) {
|
|
3994
|
+
this.throwIfAborted();
|
|
3969
3995
|
if (chunk.entities) {
|
|
3970
3996
|
for (const entity of chunk.entities) {
|
|
3971
3997
|
let existing = await this.storage.getEntity(repositoryId, entity.id);
|
|
@@ -4034,11 +4060,13 @@ var RepositoryImporter = class {
|
|
|
4034
4060
|
const targetExists = await this.storage.getEntity(repositoryId, rel.targetEntityId);
|
|
4035
4061
|
if (!sourceExists || !targetExists) {
|
|
4036
4062
|
relationshipsSkipped++;
|
|
4063
|
+
const errorMsg = `source or target entity missing`;
|
|
4037
4064
|
warnings.push({
|
|
4038
4065
|
code: "relationship_orphaned",
|
|
4039
|
-
message: `Relationship "${rel.id}" skipped \u2014
|
|
4066
|
+
message: `Relationship "${rel.id}" skipped \u2014 ${errorMsg}`,
|
|
4040
4067
|
relationshipId: rel.id
|
|
4041
4068
|
});
|
|
4069
|
+
await this.onItemFailed?.({ itemId: rel.id, itemType: "relationship", error: errorMsg });
|
|
4042
4070
|
} else {
|
|
4043
4071
|
try {
|
|
4044
4072
|
await this.storage.createRelationship(repositoryId, rel);
|
|
@@ -4384,22 +4412,37 @@ var DeepMemory = class {
|
|
|
4384
4412
|
const importer = new RepositoryImporter({
|
|
4385
4413
|
storage: this.storage,
|
|
4386
4414
|
actorId: this.provenance.getContext().actorId,
|
|
4387
|
-
onProgress: (progress) => this.globalEventBus.emit("import:progress", progress)
|
|
4415
|
+
onProgress: (progress) => this.globalEventBus.emit("import:progress", progress),
|
|
4416
|
+
onItemFailed: (failure) => this.globalEventBus.emit("import:item-failed", {
|
|
4417
|
+
repositoryId: options.target.repositoryId,
|
|
4418
|
+
itemId: failure.itemId,
|
|
4419
|
+
itemType: failure.itemType,
|
|
4420
|
+
error: failure.error
|
|
4421
|
+
}),
|
|
4422
|
+
signal: options.signal
|
|
4388
4423
|
});
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4424
|
+
try {
|
|
4425
|
+
const result = await importer.import(archive, options);
|
|
4426
|
+
if (result.success) {
|
|
4427
|
+
await this.globalEventBus.emit("import:completed", {
|
|
4428
|
+
repositoryId: result.repositoryId,
|
|
4429
|
+
entitiesImported: result.statistics.entitiesImported,
|
|
4430
|
+
relationshipsImported: result.statistics.relationshipsImported
|
|
4431
|
+
});
|
|
4432
|
+
} else {
|
|
4433
|
+
await this.globalEventBus.emit("import:failed", {
|
|
4434
|
+
repositoryId: result.repositoryId,
|
|
4435
|
+
error: result.warnings.map((w) => w.message).join("; ")
|
|
4436
|
+
});
|
|
4437
|
+
}
|
|
4438
|
+
return result;
|
|
4439
|
+
} catch (err) {
|
|
4397
4440
|
await this.globalEventBus.emit("import:failed", {
|
|
4398
|
-
repositoryId:
|
|
4399
|
-
error:
|
|
4441
|
+
repositoryId: options.target.repositoryId,
|
|
4442
|
+
error: err instanceof Error ? err.message : String(err)
|
|
4400
4443
|
});
|
|
4444
|
+
throw err;
|
|
4401
4445
|
}
|
|
4402
|
-
return result;
|
|
4403
4446
|
}
|
|
4404
4447
|
/**
|
|
4405
4448
|
* Stream a repository export as an async generator.
|
|
@@ -4468,23 +4511,88 @@ var DeepMemory = class {
|
|
|
4468
4511
|
const importer = new RepositoryImporter({
|
|
4469
4512
|
storage: this.storage,
|
|
4470
4513
|
actorId: this.provenance.getContext().actorId,
|
|
4471
|
-
onProgress: (progress) => this.globalEventBus.emit("import:progress", progress)
|
|
4514
|
+
onProgress: (progress) => this.globalEventBus.emit("import:progress", progress),
|
|
4515
|
+
onItemFailed: (failure) => this.globalEventBus.emit("import:item-failed", {
|
|
4516
|
+
repositoryId: options.target.repositoryId,
|
|
4517
|
+
itemId: failure.itemId,
|
|
4518
|
+
itemType: failure.itemType,
|
|
4519
|
+
error: failure.error
|
|
4520
|
+
}),
|
|
4521
|
+
signal: options.signal
|
|
4472
4522
|
});
|
|
4473
4523
|
await this.globalEventBus.emit("import:started", { repositoryId: options.target.repositoryId });
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4524
|
+
try {
|
|
4525
|
+
const result = await importer.importStream(header, chunks, options);
|
|
4526
|
+
if (result.success) {
|
|
4527
|
+
await this.globalEventBus.emit("import:completed", {
|
|
4528
|
+
repositoryId: result.repositoryId,
|
|
4529
|
+
entitiesImported: result.statistics.entitiesImported,
|
|
4530
|
+
relationshipsImported: result.statistics.relationshipsImported
|
|
4531
|
+
});
|
|
4532
|
+
} else {
|
|
4533
|
+
await this.globalEventBus.emit("import:failed", {
|
|
4534
|
+
repositoryId: result.repositoryId,
|
|
4535
|
+
error: result.warnings.map((w) => w.message).join("; ")
|
|
4536
|
+
});
|
|
4537
|
+
}
|
|
4538
|
+
return result;
|
|
4539
|
+
} catch (err) {
|
|
4482
4540
|
await this.globalEventBus.emit("import:failed", {
|
|
4483
|
-
repositoryId:
|
|
4484
|
-
error:
|
|
4541
|
+
repositoryId: options.target.repositoryId,
|
|
4542
|
+
error: err instanceof Error ? err.message : String(err)
|
|
4485
4543
|
});
|
|
4544
|
+
throw err;
|
|
4545
|
+
}
|
|
4546
|
+
}
|
|
4547
|
+
/**
|
|
4548
|
+
* Re-embed all entities in a repository, emitting `reembed:*` events on the
|
|
4549
|
+
* global event bus (reachable via {@link DeepMemory.on}).
|
|
4550
|
+
*
|
|
4551
|
+
* Mirrors the lifecycle of {@link importRepositoryStream}: emits
|
|
4552
|
+
* `reembed:started` up front, `reembed:progress` after every batch,
|
|
4553
|
+
* and either `reembed:completed` or `reembed:failed` at the end.
|
|
4554
|
+
*
|
|
4555
|
+
* `options.signal` is honoured at batch boundaries — any vectors already
|
|
4556
|
+
* written by completed batches are retained, and `reembed:failed` is emitted
|
|
4557
|
+
* with the abort error message.
|
|
4558
|
+
*/
|
|
4559
|
+
async reembedAll(repositoryId, options) {
|
|
4560
|
+
await this.ensureInitialized();
|
|
4561
|
+
const repo = await this.openRepository(repositoryId);
|
|
4562
|
+
const stats = await repo.getStats();
|
|
4563
|
+
await this.globalEventBus.emit("reembed:started", {
|
|
4564
|
+
repositoryId,
|
|
4565
|
+
totalEntities: stats.entityCount
|
|
4566
|
+
});
|
|
4567
|
+
try {
|
|
4568
|
+
const result = await repo.reembedAll({
|
|
4569
|
+
...options,
|
|
4570
|
+
onProgress: (progress) => this.globalEventBus.emit("reembed:progress", {
|
|
4571
|
+
repositoryId,
|
|
4572
|
+
processed: progress.processed,
|
|
4573
|
+
totalEntities: progress.totalEntities,
|
|
4574
|
+
failed: progress.failed
|
|
4575
|
+
}),
|
|
4576
|
+
onItemFailed: (failure) => this.globalEventBus.emit("reembed:item-failed", {
|
|
4577
|
+
repositoryId,
|
|
4578
|
+
entityId: failure.entityId,
|
|
4579
|
+
error: failure.error
|
|
4580
|
+
})
|
|
4581
|
+
});
|
|
4582
|
+
await this.globalEventBus.emit("reembed:completed", {
|
|
4583
|
+
repositoryId,
|
|
4584
|
+
processed: result.processed,
|
|
4585
|
+
failed: result.failed,
|
|
4586
|
+
modelId: result.modelId
|
|
4587
|
+
});
|
|
4588
|
+
return result;
|
|
4589
|
+
} catch (err) {
|
|
4590
|
+
await this.globalEventBus.emit("reembed:failed", {
|
|
4591
|
+
repositoryId,
|
|
4592
|
+
error: err instanceof Error ? err.message : String(err)
|
|
4593
|
+
});
|
|
4594
|
+
throw err;
|
|
4486
4595
|
}
|
|
4487
|
-
return result;
|
|
4488
4596
|
}
|
|
4489
4597
|
/** Subscribe to global events */
|
|
4490
4598
|
on(event, handler) {
|
|
@@ -5585,6 +5693,7 @@ export {
|
|
|
5585
5693
|
InvalidInputError,
|
|
5586
5694
|
MemoryRepository,
|
|
5587
5695
|
NoOpEmbeddingProvider,
|
|
5696
|
+
OperationAbortedError,
|
|
5588
5697
|
OperationCancelledError,
|
|
5589
5698
|
ProviderError,
|
|
5590
5699
|
RelationshipConstraintError,
|