@anuma/sdk 6.25.1 → 6.25.2
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/expo/index.cjs +343 -146
- package/dist/expo/index.d.mts +34 -9
- package/dist/expo/index.d.ts +34 -9
- package/dist/expo/index.mjs +343 -146
- package/dist/react/index.cjs +343 -146
- package/dist/react/index.d.mts +34 -9
- package/dist/react/index.d.ts +34 -9
- package/dist/react/index.mjs +343 -146
- package/dist/server/index.cjs +343 -146
- package/dist/server/index.d.mts +34 -9
- package/dist/server/index.d.ts +34 -9
- package/dist/server/index.mjs +343 -146
- package/package.json +1 -1
package/dist/expo/index.cjs
CHANGED
|
@@ -11419,8 +11419,42 @@ async function vaultMemoryToStored(memory, walletAddress, signMessage, embeddedW
|
|
|
11419
11419
|
}
|
|
11420
11420
|
return raw;
|
|
11421
11421
|
}
|
|
11422
|
+
function populateNewVaultMemory(record, ctx, opts, encryptedContent) {
|
|
11423
|
+
record._setRaw("content", encryptedContent);
|
|
11424
|
+
record._setRaw("scope", opts.scope ?? "private");
|
|
11425
|
+
record._setRaw("folder_id", opts.folderId ?? null);
|
|
11426
|
+
record._setRaw("user_id", ctx.userId ?? null);
|
|
11427
|
+
record._setRaw("is_deleted", false);
|
|
11428
|
+
if (opts.embedding !== void 0) {
|
|
11429
|
+
record._setRaw("embedding", opts.embedding);
|
|
11430
|
+
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
11431
|
+
}
|
|
11432
|
+
if (opts.sourceChunkIds !== void 0) {
|
|
11433
|
+
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
11434
|
+
}
|
|
11435
|
+
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
11436
|
+
record._setRaw("source", opts.source ?? "manual");
|
|
11437
|
+
if (opts.eventTime) {
|
|
11438
|
+
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
11439
|
+
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
11440
|
+
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
11441
|
+
}
|
|
11442
|
+
if (opts.factType !== void 0) {
|
|
11443
|
+
record._setRaw("fact_type", opts.factType);
|
|
11444
|
+
}
|
|
11445
|
+
if (opts.trustTier !== void 0) {
|
|
11446
|
+
record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
11447
|
+
}
|
|
11448
|
+
record._setRaw("visibility", opts.visibility ?? "private");
|
|
11449
|
+
record._setRaw(
|
|
11450
|
+
"published_at",
|
|
11451
|
+
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
11452
|
+
);
|
|
11453
|
+
if (opts.geohash !== void 0) {
|
|
11454
|
+
record._setRaw("geohash", opts.geohash);
|
|
11455
|
+
}
|
|
11456
|
+
}
|
|
11422
11457
|
async function createVaultMemoryOp(ctx, opts) {
|
|
11423
|
-
const scope = opts.scope ?? "private";
|
|
11424
11458
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
11425
11459
|
opts.content,
|
|
11426
11460
|
ctx.walletAddress,
|
|
@@ -11430,47 +11464,14 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
11430
11464
|
const created = await ctx.database.write(async () => {
|
|
11431
11465
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
11432
11466
|
throw new Error("Memory source is no longer eligible");
|
|
11433
|
-
return ctx.vaultMemoryCollection.create(
|
|
11434
|
-
record
|
|
11435
|
-
|
|
11436
|
-
record._setRaw("folder_id", opts.folderId ?? null);
|
|
11437
|
-
record._setRaw("user_id", ctx.userId ?? null);
|
|
11438
|
-
record._setRaw("is_deleted", false);
|
|
11439
|
-
if (opts.embedding !== void 0) {
|
|
11440
|
-
record._setRaw("embedding", opts.embedding);
|
|
11441
|
-
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
11442
|
-
}
|
|
11443
|
-
if (opts.sourceChunkIds !== void 0) {
|
|
11444
|
-
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
11445
|
-
}
|
|
11446
|
-
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
11447
|
-
record._setRaw("source", opts.source ?? "manual");
|
|
11448
|
-
if (opts.eventTime) {
|
|
11449
|
-
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
11450
|
-
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
11451
|
-
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
11452
|
-
}
|
|
11453
|
-
if (opts.factType !== void 0) {
|
|
11454
|
-
record._setRaw("fact_type", opts.factType);
|
|
11455
|
-
}
|
|
11456
|
-
if (opts.trustTier !== void 0) {
|
|
11457
|
-
record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
11458
|
-
}
|
|
11459
|
-
record._setRaw("visibility", opts.visibility ?? "private");
|
|
11460
|
-
record._setRaw(
|
|
11461
|
-
"published_at",
|
|
11462
|
-
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
11463
|
-
);
|
|
11464
|
-
if (opts.geohash !== void 0) {
|
|
11465
|
-
record._setRaw("geohash", opts.geohash);
|
|
11466
|
-
}
|
|
11467
|
-
});
|
|
11467
|
+
return ctx.vaultMemoryCollection.create(
|
|
11468
|
+
(record) => populateNewVaultMemory(record, ctx, opts, encryptedContent)
|
|
11469
|
+
);
|
|
11468
11470
|
});
|
|
11469
11471
|
return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
11470
11472
|
}
|
|
11471
11473
|
async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
11472
11474
|
if (!targetId) return { created: null, retired: false };
|
|
11473
|
-
const scope = opts.scope ?? "private";
|
|
11474
11475
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
11475
11476
|
opts.content,
|
|
11476
11477
|
ctx.walletAddress,
|
|
@@ -11488,27 +11489,9 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
|
11488
11489
|
return;
|
|
11489
11490
|
}
|
|
11490
11491
|
if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target)) return;
|
|
11491
|
-
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
11492
|
-
record
|
|
11493
|
-
|
|
11494
|
-
record._setRaw("folder_id", opts.folderId ?? null);
|
|
11495
|
-
record._setRaw("user_id", ctx.userId ?? null);
|
|
11496
|
-
record._setRaw("is_deleted", false);
|
|
11497
|
-
if (opts.embedding !== void 0) {
|
|
11498
|
-
record._setRaw("embedding", opts.embedding);
|
|
11499
|
-
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
11500
|
-
}
|
|
11501
|
-
if (opts.sourceChunkIds !== void 0) {
|
|
11502
|
-
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
11503
|
-
}
|
|
11504
|
-
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
11505
|
-
record._setRaw("source", opts.source ?? "manual");
|
|
11506
|
-
if (opts.eventTime) {
|
|
11507
|
-
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
11508
|
-
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
11509
|
-
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
11510
|
-
}
|
|
11511
|
-
});
|
|
11492
|
+
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
11493
|
+
(record) => populateNewVaultMemory(record, ctx, opts, encryptedContent)
|
|
11494
|
+
);
|
|
11512
11495
|
await target.update((r) => {
|
|
11513
11496
|
r._setRaw("superseded_by", createdRecord.id);
|
|
11514
11497
|
r._setRaw("superseded_at", Date.now());
|
|
@@ -11588,41 +11571,9 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
11588
11571
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
11589
11572
|
throw new Error("Memory source is no longer eligible");
|
|
11590
11573
|
const prepared = optionsArray.map(
|
|
11591
|
-
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
11592
|
-
record
|
|
11593
|
-
|
|
11594
|
-
record._setRaw("folder_id", opts.folderId ?? null);
|
|
11595
|
-
record._setRaw("user_id", ctx.userId ?? null);
|
|
11596
|
-
record._setRaw("is_deleted", false);
|
|
11597
|
-
if (optionsArray[i].embedding !== void 0) {
|
|
11598
|
-
record._setRaw("embedding", optionsArray[i].embedding);
|
|
11599
|
-
record._setRaw("embedding_model", optionsArray[i].embeddingModel ?? null);
|
|
11600
|
-
}
|
|
11601
|
-
if (opts.sourceChunkIds !== void 0) {
|
|
11602
|
-
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
11603
|
-
}
|
|
11604
|
-
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
11605
|
-
record._setRaw("source", opts.source ?? "manual");
|
|
11606
|
-
if (opts.eventTime) {
|
|
11607
|
-
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
11608
|
-
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
11609
|
-
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
11610
|
-
}
|
|
11611
|
-
if (opts.factType !== void 0) {
|
|
11612
|
-
record._setRaw("fact_type", opts.factType);
|
|
11613
|
-
}
|
|
11614
|
-
if (opts.trustTier !== void 0) {
|
|
11615
|
-
record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
11616
|
-
}
|
|
11617
|
-
record._setRaw("visibility", opts.visibility ?? "private");
|
|
11618
|
-
record._setRaw(
|
|
11619
|
-
"published_at",
|
|
11620
|
-
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
11621
|
-
);
|
|
11622
|
-
if (opts.geohash !== void 0) {
|
|
11623
|
-
record._setRaw("geohash", opts.geohash);
|
|
11624
|
-
}
|
|
11625
|
-
})
|
|
11574
|
+
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
11575
|
+
(record) => populateNewVaultMemory(record, ctx, opts, encryptedContents[i])
|
|
11576
|
+
)
|
|
11626
11577
|
);
|
|
11627
11578
|
await ctx.database.batch(...prepared);
|
|
11628
11579
|
return prepared;
|
|
@@ -12443,21 +12394,73 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
|
12443
12394
|
return false;
|
|
12444
12395
|
}
|
|
12445
12396
|
}
|
|
12446
|
-
async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel) {
|
|
12397
|
+
async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel, expected) {
|
|
12447
12398
|
try {
|
|
12448
12399
|
const record = await ctx.vaultMemoryCollection.find(id);
|
|
12449
12400
|
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
|
|
12401
|
+
const readUpdatedAt = record.updatedAt.getTime();
|
|
12402
|
+
const readStoredContent = record._getRaw("content");
|
|
12403
|
+
if (expected?.updatedAt !== void 0 && expected.updatedAt !== readUpdatedAt) return false;
|
|
12404
|
+
if (expected?.content !== void 0) {
|
|
12405
|
+
const current = await vaultMemoryToStored(
|
|
12406
|
+
record,
|
|
12407
|
+
ctx.walletAddress,
|
|
12408
|
+
ctx.signMessage,
|
|
12409
|
+
ctx.embeddedWalletSigner
|
|
12410
|
+
);
|
|
12411
|
+
if (current.content !== expected.content) return false;
|
|
12412
|
+
}
|
|
12413
|
+
let written = false;
|
|
12450
12414
|
await ctx.database.write(async () => {
|
|
12415
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return;
|
|
12416
|
+
const originalUpdatedAt = record.updatedAt.getTime();
|
|
12417
|
+
if (originalUpdatedAt !== readUpdatedAt || record._getRaw("content") !== readStoredContent)
|
|
12418
|
+
return;
|
|
12451
12419
|
await record.update((r) => {
|
|
12452
12420
|
r._setRaw("embedding", embedding);
|
|
12453
12421
|
r._setRaw("embedding_model", embeddingModel);
|
|
12422
|
+
r._setRaw("updated_at", originalUpdatedAt);
|
|
12454
12423
|
});
|
|
12424
|
+
written = true;
|
|
12455
12425
|
});
|
|
12456
|
-
return
|
|
12426
|
+
return written;
|
|
12457
12427
|
} catch {
|
|
12458
12428
|
return false;
|
|
12459
12429
|
}
|
|
12460
12430
|
}
|
|
12431
|
+
function normalizeForDedupe(content) {
|
|
12432
|
+
return content.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
|
|
12433
|
+
}
|
|
12434
|
+
async function findQuarantinedDuplicateOp(ctx, content, sourceIds, where) {
|
|
12435
|
+
const wanted = [...new Set(sourceIds)].sort().join("\0");
|
|
12436
|
+
const target = normalizeForDedupe(content);
|
|
12437
|
+
const rows = await ctx.vaultMemoryCollection.query(
|
|
12438
|
+
import_watermelondb10.Q.where("trust_tier", "quarantined"),
|
|
12439
|
+
import_watermelondb10.Q.where("is_deleted", false),
|
|
12440
|
+
import_watermelondb10.Q.where("scope", where.scope),
|
|
12441
|
+
import_watermelondb10.Q.where("folder_id", where.folderId),
|
|
12442
|
+
...ctx.userId !== void 0 ? [import_watermelondb10.Q.where("user_id", ctx.userId)] : []
|
|
12443
|
+
).unsafeFetchRaw();
|
|
12444
|
+
for (const raw of rows) {
|
|
12445
|
+
let ids;
|
|
12446
|
+
try {
|
|
12447
|
+
ids = JSON.parse(raw.source_chunk_ids ?? "[]");
|
|
12448
|
+
} catch {
|
|
12449
|
+
continue;
|
|
12450
|
+
}
|
|
12451
|
+
if (!Array.isArray(ids)) continue;
|
|
12452
|
+
const key = [...new Set(ids.filter((id) => typeof id === "string"))].sort().join("\0");
|
|
12453
|
+
if (key !== wanted) continue;
|
|
12454
|
+
const stored = await vaultMemoryRawToStored(
|
|
12455
|
+
raw,
|
|
12456
|
+
ctx.walletAddress,
|
|
12457
|
+
ctx.signMessage,
|
|
12458
|
+
ctx.embeddedWalletSigner
|
|
12459
|
+
);
|
|
12460
|
+
if (normalizeForDedupe(stored.content) === target) return stored.uniqueId;
|
|
12461
|
+
}
|
|
12462
|
+
return null;
|
|
12463
|
+
}
|
|
12461
12464
|
|
|
12462
12465
|
// src/lib/memory/decay.ts
|
|
12463
12466
|
init_logger();
|
|
@@ -12482,6 +12485,10 @@ var DEFAULT_DECAY_POLICY = {
|
|
|
12482
12485
|
hardDeleteWindowMs: HARD_DELETE_WINDOW_MS,
|
|
12483
12486
|
pastEventGraceMs: PAST_EVENT_GRACE_MS
|
|
12484
12487
|
};
|
|
12488
|
+
function lastActivityAt(m) {
|
|
12489
|
+
const observedAt = Number.isFinite(m.lastObservedAt) ? m.lastObservedAt : m.updatedAt;
|
|
12490
|
+
return Math.max(m.updatedAt, observedAt);
|
|
12491
|
+
}
|
|
12485
12492
|
function resolvePolicy(policy) {
|
|
12486
12493
|
if (!policy) return DEFAULT_DECAY_POLICY;
|
|
12487
12494
|
return {
|
|
@@ -12521,8 +12528,7 @@ function classifyDecay(m, now, policy) {
|
|
|
12521
12528
|
if (m.eventTimeEnd < now - resolved.pastEventGraceMs) return "archive";
|
|
12522
12529
|
if (m.eventTimeEnd >= now) return "keep";
|
|
12523
12530
|
}
|
|
12524
|
-
|
|
12525
|
-
if (now - Math.max(m.updatedAt, observedAt) > ttlForType(m.factType, resolved)) return "archive";
|
|
12531
|
+
if (now - lastActivityAt(m) > ttlForType(m.factType, resolved)) return "archive";
|
|
12526
12532
|
return "keep";
|
|
12527
12533
|
}
|
|
12528
12534
|
|
|
@@ -15885,6 +15891,24 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
15885
15891
|
const tRetain = Date.now();
|
|
15886
15892
|
for (const { candidate, isQuarantined, reason, signature } of toRetain) {
|
|
15887
15893
|
try {
|
|
15894
|
+
if (isQuarantined) {
|
|
15895
|
+
const existingId = await findQuarantinedDuplicateOp(
|
|
15896
|
+
retainCtx.vaultCtx,
|
|
15897
|
+
candidate.content,
|
|
15898
|
+
candidate.sourceMessageIds,
|
|
15899
|
+
// The same defaults retain() writes the row with.
|
|
15900
|
+
{ scope: options.scope ?? "private", folderId: options.folderId ?? null }
|
|
15901
|
+
).catch(() => null);
|
|
15902
|
+
if (existingId) {
|
|
15903
|
+
quarantinedInfo.push({
|
|
15904
|
+
candidate,
|
|
15905
|
+
memoryId: existingId,
|
|
15906
|
+
reason,
|
|
15907
|
+
signature
|
|
15908
|
+
});
|
|
15909
|
+
continue;
|
|
15910
|
+
}
|
|
15911
|
+
}
|
|
15888
15912
|
const result = await retain(candidate.content, retainCtx, {
|
|
15889
15913
|
source: "auto-extracted",
|
|
15890
15914
|
sourceChunkIds: candidate.sourceMessageIds,
|
|
@@ -16335,7 +16359,7 @@ function createLlmDecayClassifier(options) {
|
|
|
16335
16359
|
if (!content || content.trim().length === 0) return ruleVerdict;
|
|
16336
16360
|
const trimmed = content.trim().slice(0, MAX_CONTENT_CHARS);
|
|
16337
16361
|
const safe = redactor ? (await redactor.redactTextAsync(trimmed)).text : trimmed;
|
|
16338
|
-
const meta = `factType: ${input.factType ?? "none"}; ageDays: ${ageDays(input
|
|
16362
|
+
const meta = `factType: ${input.factType ?? "none"}; ageDays: ${ageDays(lastActivityAt(input), now)}`;
|
|
16339
16363
|
let parsed;
|
|
16340
16364
|
try {
|
|
16341
16365
|
parsed = await callPortalJsonCompletion({
|
|
@@ -16368,9 +16392,9 @@ Should this be kept or archived?`,
|
|
|
16368
16392
|
}
|
|
16369
16393
|
};
|
|
16370
16394
|
}
|
|
16371
|
-
function ageDays(
|
|
16372
|
-
if (!Number.isFinite(
|
|
16373
|
-
return Math.max(0, Math.floor((now -
|
|
16395
|
+
function ageDays(activityAt, now) {
|
|
16396
|
+
if (!Number.isFinite(activityAt) || !Number.isFinite(now)) return 0;
|
|
16397
|
+
return Math.max(0, Math.floor((now - activityAt) / (24 * 60 * 60 * 1e3)));
|
|
16374
16398
|
}
|
|
16375
16399
|
function parseVerdict(parsed) {
|
|
16376
16400
|
if (typeof parsed !== "object" || parsed === null) return null;
|
|
@@ -16424,7 +16448,7 @@ function createDecaySweeper(options) {
|
|
|
16424
16448
|
if (!classifier || !isBorderline(input)) return ruleVerdict;
|
|
16425
16449
|
if (input.id) {
|
|
16426
16450
|
const cached = classifierCache.get(input.id);
|
|
16427
|
-
if (cached && cached.
|
|
16451
|
+
if (cached && cached.activityAt === lastActivityAt(input)) return cached.verdict;
|
|
16428
16452
|
}
|
|
16429
16453
|
if (sweep.classifierCalls >= maxClassifierCalls) {
|
|
16430
16454
|
if (!sweep.ceilingLogged) {
|
|
@@ -16438,7 +16462,7 @@ function createDecaySweeper(options) {
|
|
|
16438
16462
|
sweep.classifierCalls++;
|
|
16439
16463
|
try {
|
|
16440
16464
|
const verdict = await classifier.classify(input, ruleVerdict, now);
|
|
16441
|
-
if (input.id) classifierCache.set(input.id, {
|
|
16465
|
+
if (input.id) classifierCache.set(input.id, { activityAt: lastActivityAt(input), verdict });
|
|
16442
16466
|
return verdict;
|
|
16443
16467
|
} catch (err) {
|
|
16444
16468
|
getLogger().warn(
|
|
@@ -19075,6 +19099,37 @@ async function assembleMemoryContext(options) {
|
|
|
19075
19099
|
var import_watermelondb12 = require("@nozbe/watermelondb");
|
|
19076
19100
|
var MAX_JOBS_PER_PASS = 3;
|
|
19077
19101
|
var MAX_ATTEMPTS = 3;
|
|
19102
|
+
var MAX_FAILED_SESSIONS = 3;
|
|
19103
|
+
var MIN_FAILED_SESSION_GAP_MS = 60 * 60 * 1e3;
|
|
19104
|
+
var REQUEST_REJECTED_STATUSES = /* @__PURE__ */ new Set([400, 404, 413, 422]);
|
|
19105
|
+
var CONTENT_FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
19106
|
+
"empty-content",
|
|
19107
|
+
"invalid-json",
|
|
19108
|
+
"null-completion",
|
|
19109
|
+
"body-parse-failed"
|
|
19110
|
+
]);
|
|
19111
|
+
var BACKOFF_ALLOWANCE_MS = 2100;
|
|
19112
|
+
var RETAIN_BUDGET_MS = 12e4;
|
|
19113
|
+
function defaultBatchTimeoutMs(extract) {
|
|
19114
|
+
const attempts = Math.max(1, extract.maxAttempts ?? 3);
|
|
19115
|
+
const calls = (extract.timeoutMs ?? 6e4) * attempts + BACKOFF_ALLOWANCE_MS * (attempts - 1);
|
|
19116
|
+
const extraction = extract.totalTimeoutMs !== void 0 ? Math.min(extract.totalTimeoutMs, calls) : calls;
|
|
19117
|
+
return extraction + RETAIN_BUDGET_MS;
|
|
19118
|
+
}
|
|
19119
|
+
var BatchFailureError = class extends Error {
|
|
19120
|
+
constructor(message, terminal) {
|
|
19121
|
+
super(message);
|
|
19122
|
+
this.terminal = terminal;
|
|
19123
|
+
}
|
|
19124
|
+
};
|
|
19125
|
+
var AccountFailureError = class extends Error {
|
|
19126
|
+
};
|
|
19127
|
+
var LockedSourcesError = class extends Error {
|
|
19128
|
+
constructor(persistentIds) {
|
|
19129
|
+
super("Source messages are locked; retained for retry");
|
|
19130
|
+
this.persistentIds = persistentIds;
|
|
19131
|
+
}
|
|
19132
|
+
};
|
|
19078
19133
|
function idsOf(job) {
|
|
19079
19134
|
return JSON.parse(String(job._getRaw("message_ids")));
|
|
19080
19135
|
}
|
|
@@ -19082,6 +19137,16 @@ function seqOf(job) {
|
|
|
19082
19137
|
const raw = job._getRaw("watermark_seq");
|
|
19083
19138
|
return typeof raw === "number" && raw > 0 ? raw : void 0;
|
|
19084
19139
|
}
|
|
19140
|
+
function failedSessionsOf(job, head) {
|
|
19141
|
+
if (job._getRaw("failed_head") !== head) return 0;
|
|
19142
|
+
const raw = job._getRaw("failed_sessions");
|
|
19143
|
+
return typeof raw === "number" && raw > 0 ? raw : 0;
|
|
19144
|
+
}
|
|
19145
|
+
function failedAtOf(job, head) {
|
|
19146
|
+
if (job._getRaw("failed_head") !== head) return void 0;
|
|
19147
|
+
const raw = job._getRaw("failed_at");
|
|
19148
|
+
return typeof raw === "number" ? raw : void 0;
|
|
19149
|
+
}
|
|
19085
19150
|
function createDurableAutoExtractor(options) {
|
|
19086
19151
|
const vault = options.retainCtx.vaultCtx;
|
|
19087
19152
|
const database = vault.database;
|
|
@@ -19104,6 +19169,9 @@ function createDurableAutoExtractor(options) {
|
|
|
19104
19169
|
let writes = Promise.resolve();
|
|
19105
19170
|
let storeFailures = 0;
|
|
19106
19171
|
const attempts = /* @__PURE__ */ new Map();
|
|
19172
|
+
const sessionFailures = /* @__PURE__ */ new Map();
|
|
19173
|
+
const skippedThisSession = /* @__PURE__ */ new Set();
|
|
19174
|
+
const clock = options.now ?? Date.now;
|
|
19107
19175
|
const reportError = (error, conversationId) => {
|
|
19108
19176
|
try {
|
|
19109
19177
|
options.onError?.(error instanceof Error ? error : new Error(String(error)), conversationId);
|
|
@@ -19132,6 +19200,7 @@ function createDurableAutoExtractor(options) {
|
|
|
19132
19200
|
}
|
|
19133
19201
|
async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
|
|
19134
19202
|
let watchdog;
|
|
19203
|
+
let cancelled = false;
|
|
19135
19204
|
const model = options.modelForScope?.(jobScope) ?? options.extract.model;
|
|
19136
19205
|
try {
|
|
19137
19206
|
return await Promise.race([
|
|
@@ -19142,7 +19211,7 @@ function createDurableAutoExtractor(options) {
|
|
|
19142
19211
|
...options.retainCtx,
|
|
19143
19212
|
vaultCtx: {
|
|
19144
19213
|
...vault,
|
|
19145
|
-
canWrite: async () => !disposed && await storage.conversationsCollection.query(import_watermelondb12.Q.where("conversation_id", conversationId), import_watermelondb12.Q.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(import_watermelondb12.Q.where("conversation_id", conversationId), import_watermelondb12.Q.where("id", import_watermelondb12.Q.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed
|
|
19214
|
+
canWrite: async () => !disposed && !cancelled && await storage.conversationsCollection.query(import_watermelondb12.Q.where("conversation_id", conversationId), import_watermelondb12.Q.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(import_watermelondb12.Q.where("conversation_id", conversationId), import_watermelondb12.Q.where("id", import_watermelondb12.Q.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed && !cancelled
|
|
19146
19215
|
}
|
|
19147
19216
|
},
|
|
19148
19217
|
// The model follows the job's scope, not the mode alive at drain time.
|
|
@@ -19162,14 +19231,116 @@ function createDurableAutoExtractor(options) {
|
|
|
19162
19231
|
new Promise((_resolve, reject) => {
|
|
19163
19232
|
watchdog = setTimeout(
|
|
19164
19233
|
() => reject(new Error("Extraction did not settle in time; retained for retry")),
|
|
19165
|
-
options.batchTimeoutMs ??
|
|
19234
|
+
options.batchTimeoutMs ?? defaultBatchTimeoutMs(options.extract)
|
|
19166
19235
|
);
|
|
19167
19236
|
})
|
|
19168
19237
|
]);
|
|
19169
19238
|
} finally {
|
|
19239
|
+
cancelled = true;
|
|
19170
19240
|
if (watchdog !== void 0) clearTimeout(watchdog);
|
|
19171
19241
|
}
|
|
19172
19242
|
}
|
|
19243
|
+
async function acknowledge(job, ids, loaded, abandoned) {
|
|
19244
|
+
attempts.delete(job.id);
|
|
19245
|
+
sessionFailures.delete(job.id);
|
|
19246
|
+
skippedThisSession.delete(job.id);
|
|
19247
|
+
const sequences = /* @__PURE__ */ new Map();
|
|
19248
|
+
for (const message of loaded)
|
|
19249
|
+
if (message && message.messageId > 0) sequences.set(message.uniqueId, message.messageId);
|
|
19250
|
+
await database.write(async () => {
|
|
19251
|
+
const current = idsOf(job);
|
|
19252
|
+
const acknowledged = ids.filter((id) => current.includes(id));
|
|
19253
|
+
if (!acknowledged.length) return;
|
|
19254
|
+
const done = new Set(acknowledged);
|
|
19255
|
+
const remaining = current.filter((id) => !done.has(id));
|
|
19256
|
+
await job.update((r) => {
|
|
19257
|
+
r._setRaw(
|
|
19258
|
+
"message_ids",
|
|
19259
|
+
JSON.stringify(
|
|
19260
|
+
remaining.length ? [...abandoned ? [] : acknowledged.slice(-2), ...remaining] : []
|
|
19261
|
+
)
|
|
19262
|
+
);
|
|
19263
|
+
const newest = acknowledged[acknowledged.length - 1];
|
|
19264
|
+
r._setRaw("watermark", newest);
|
|
19265
|
+
const sequence = sequences.get(newest);
|
|
19266
|
+
if (sequence !== void 0) {
|
|
19267
|
+
const prior = seqOf(job);
|
|
19268
|
+
r._setRaw("watermark_seq", prior === void 0 ? sequence : Math.max(prior, sequence));
|
|
19269
|
+
}
|
|
19270
|
+
r._setRaw("failed_sessions", abandoned ? MAX_FAILED_SESSIONS : null);
|
|
19271
|
+
r._setRaw("failed_head", abandoned ? newest : null);
|
|
19272
|
+
r._setRaw("failed_at", null);
|
|
19273
|
+
});
|
|
19274
|
+
});
|
|
19275
|
+
}
|
|
19276
|
+
async function recordFailure(job, ids, loaded, error, conversationId) {
|
|
19277
|
+
const head = ids[0];
|
|
19278
|
+
if (!head || !loaded.some(Boolean)) return false;
|
|
19279
|
+
if (error instanceof AccountFailureError) {
|
|
19280
|
+
skippedThisSession.add(job.id);
|
|
19281
|
+
return false;
|
|
19282
|
+
}
|
|
19283
|
+
const counted = error instanceof BatchFailureError || error instanceof LockedSourcesError && error.persistentIds.length > 0;
|
|
19284
|
+
if (!counted) return false;
|
|
19285
|
+
const prior = sessionFailures.get(job.id);
|
|
19286
|
+
const count = prior?.head === head ? prior.count + 1 : 1;
|
|
19287
|
+
sessionFailures.set(job.id, { head, count });
|
|
19288
|
+
const terminal = error instanceof BatchFailureError && error.terminal;
|
|
19289
|
+
if (!terminal && count < MAX_ATTEMPTS) return false;
|
|
19290
|
+
skippedThisSession.add(job.id);
|
|
19291
|
+
const now = clock();
|
|
19292
|
+
const lastCounted = failedAtOf(job, head);
|
|
19293
|
+
if (lastCounted !== void 0 && now - lastCounted < MIN_FAILED_SESSION_GAP_MS) return false;
|
|
19294
|
+
const failures = failedSessionsOf(job, head) + 1;
|
|
19295
|
+
if (failures < MAX_FAILED_SESSIONS) {
|
|
19296
|
+
await database.write(
|
|
19297
|
+
() => job.update((r) => {
|
|
19298
|
+
r._setRaw("failed_sessions", failures);
|
|
19299
|
+
r._setRaw("failed_head", head);
|
|
19300
|
+
r._setRaw("failed_at", now);
|
|
19301
|
+
})
|
|
19302
|
+
);
|
|
19303
|
+
return false;
|
|
19304
|
+
}
|
|
19305
|
+
if (error instanceof LockedSourcesError) {
|
|
19306
|
+
const dropped = new Set(error.persistentIds);
|
|
19307
|
+
let newest;
|
|
19308
|
+
for (const message of loaded)
|
|
19309
|
+
if (message && dropped.has(message.uniqueId) && message.messageId > (newest?.seq ?? 0))
|
|
19310
|
+
newest = { id: message.uniqueId, seq: message.messageId };
|
|
19311
|
+
const advance = newest !== void 0 && newest.seq > (seqOf(job) ?? 0) ? newest : void 0;
|
|
19312
|
+
await database.write(
|
|
19313
|
+
() => job.update((r) => {
|
|
19314
|
+
r._setRaw("message_ids", JSON.stringify(idsOf(job).filter((id) => !dropped.has(id))));
|
|
19315
|
+
if (advance) {
|
|
19316
|
+
r._setRaw("watermark", advance.id);
|
|
19317
|
+
r._setRaw("watermark_seq", advance.seq);
|
|
19318
|
+
}
|
|
19319
|
+
r._setRaw("failed_sessions", advance ? MAX_FAILED_SESSIONS : null);
|
|
19320
|
+
r._setRaw("failed_head", advance ? advance.id : null);
|
|
19321
|
+
r._setRaw("failed_at", null);
|
|
19322
|
+
})
|
|
19323
|
+
);
|
|
19324
|
+
attempts.delete(job.id);
|
|
19325
|
+
sessionFailures.delete(job.id);
|
|
19326
|
+
skippedThisSession.delete(job.id);
|
|
19327
|
+
reportError(
|
|
19328
|
+
new Error(
|
|
19329
|
+
`Dropped ${dropped.size} source id(s) that stayed locked for ${failures} sessions to unblock extraction`
|
|
19330
|
+
),
|
|
19331
|
+
conversationId
|
|
19332
|
+
);
|
|
19333
|
+
return true;
|
|
19334
|
+
}
|
|
19335
|
+
await acknowledge(job, ids, loaded, true);
|
|
19336
|
+
reportError(
|
|
19337
|
+
new Error(
|
|
19338
|
+
`Abandoned an extraction batch of ${ids.length} source id(s) after it failed in ${failures} sessions`
|
|
19339
|
+
),
|
|
19340
|
+
conversationId
|
|
19341
|
+
);
|
|
19342
|
+
return true;
|
|
19343
|
+
}
|
|
19173
19344
|
async function drain() {
|
|
19174
19345
|
if (disposed || running) return;
|
|
19175
19346
|
running = true;
|
|
@@ -19184,21 +19355,23 @@ function createDurableAutoExtractor(options) {
|
|
|
19184
19355
|
for (const job of pending) {
|
|
19185
19356
|
if (disposed) break;
|
|
19186
19357
|
const attempted = attempts.get(job.id) ?? 0;
|
|
19187
|
-
if (attempted >= MAX_ATTEMPTS) continue;
|
|
19358
|
+
if (attempted >= MAX_ATTEMPTS || skippedThisSession.has(job.id)) continue;
|
|
19188
19359
|
if (processed >= MAX_JOBS_PER_PASS) {
|
|
19189
19360
|
scheduleAfterSuccess = true;
|
|
19190
19361
|
break;
|
|
19191
19362
|
}
|
|
19192
19363
|
processed++;
|
|
19193
19364
|
const conversationId = String(job._getRaw("conversation_id"));
|
|
19365
|
+
let ids = [];
|
|
19366
|
+
let loaded = [];
|
|
19194
19367
|
try {
|
|
19195
19368
|
const conversations = await storage.conversationsCollection.query(import_watermelondb12.Q.where("conversation_id", conversationId), import_watermelondb12.Q.where("is_deleted", false)).fetchCount();
|
|
19196
19369
|
if (!conversations) {
|
|
19197
19370
|
await database.write(() => job.destroyPermanently());
|
|
19198
19371
|
continue;
|
|
19199
19372
|
}
|
|
19200
|
-
|
|
19201
|
-
|
|
19373
|
+
ids = idsOf(job).slice(0, 20);
|
|
19374
|
+
loaded = await Promise.all(ids.map((id) => getMessageOp(storage, id)));
|
|
19202
19375
|
const missing = ids.filter((_id, index) => loaded[index] === null);
|
|
19203
19376
|
if (missing.length) {
|
|
19204
19377
|
if (attempted < MAX_ATTEMPTS - 1)
|
|
@@ -19222,17 +19395,21 @@ function createDurableAutoExtractor(options) {
|
|
|
19222
19395
|
);
|
|
19223
19396
|
continue;
|
|
19224
19397
|
}
|
|
19225
|
-
|
|
19226
|
-
|
|
19227
|
-
|
|
19228
|
-
|
|
19398
|
+
const locked = loaded.filter((message) => message && isEncrypted(message.content));
|
|
19399
|
+
if (locked.length) {
|
|
19400
|
+
throw new LockedSourcesError(
|
|
19401
|
+
locked.flatMap(
|
|
19402
|
+
(message) => message.decryptionStatus === "auth_mismatch" || message.decryptionStatus === "invalid_payload" ? [message.uniqueId] : []
|
|
19403
|
+
)
|
|
19404
|
+
);
|
|
19229
19405
|
}
|
|
19230
19406
|
const messages = loaded.flatMap(
|
|
19231
19407
|
(m) => m && m.conversationId === conversationId && (m.role === "user" || m.role === "assistant") ? [{ id: m.uniqueId, role: m.role, content: m.content }] : []
|
|
19232
19408
|
);
|
|
19233
19409
|
let success = messages.length === 0;
|
|
19410
|
+
let result;
|
|
19234
19411
|
if (messages.length) {
|
|
19235
|
-
|
|
19412
|
+
result = await extractBatch(
|
|
19236
19413
|
messages,
|
|
19237
19414
|
conversationId,
|
|
19238
19415
|
ids,
|
|
@@ -19242,41 +19419,35 @@ function createDurableAutoExtractor(options) {
|
|
|
19242
19419
|
success = result.failedCount === 0 && result.outcome !== "empty-after-retry";
|
|
19243
19420
|
options.onTurnComplete?.(result);
|
|
19244
19421
|
}
|
|
19245
|
-
if (!success)
|
|
19246
|
-
|
|
19247
|
-
|
|
19248
|
-
|
|
19249
|
-
|
|
19250
|
-
|
|
19251
|
-
|
|
19252
|
-
|
|
19253
|
-
const acknowledged = ids.filter((id) => current.includes(id));
|
|
19254
|
-
if (!acknowledged.length) return;
|
|
19255
|
-
const done = new Set(acknowledged);
|
|
19256
|
-
const remaining = current.filter((id) => !done.has(id));
|
|
19257
|
-
if (remaining.length) {
|
|
19258
|
-
await job.update(
|
|
19259
|
-
(r) => r._setRaw("message_ids", JSON.stringify([...acknowledged.slice(-2), ...remaining]))
|
|
19260
|
-
);
|
|
19261
|
-
} else await job.update((r) => r._setRaw("message_ids", "[]"));
|
|
19262
|
-
const newest = acknowledged[acknowledged.length - 1];
|
|
19263
|
-
await job.update((r) => {
|
|
19264
|
-
r._setRaw("watermark", newest);
|
|
19265
|
-
const sequence = sequences.get(newest);
|
|
19266
|
-
if (sequence !== void 0) {
|
|
19267
|
-
const prior = seqOf(job);
|
|
19268
|
-
r._setRaw(
|
|
19269
|
-
"watermark_seq",
|
|
19270
|
-
prior === void 0 ? sequence : Math.max(prior, sequence)
|
|
19422
|
+
if (!success) {
|
|
19423
|
+
const failure = result?.failure;
|
|
19424
|
+
if (failure?.reason === "http-terminal") {
|
|
19425
|
+
const status = failure.httpStatus;
|
|
19426
|
+
if (status !== void 0 && REQUEST_REJECTED_STATUSES.has(status))
|
|
19427
|
+
throw new BatchFailureError(
|
|
19428
|
+
`Extraction rejected the batch (HTTP ${status}); not retried this session`,
|
|
19429
|
+
true
|
|
19271
19430
|
);
|
|
19272
|
-
|
|
19273
|
-
|
|
19274
|
-
|
|
19431
|
+
throw new AccountFailureError(
|
|
19432
|
+
`Extraction refused for the account (HTTP ${status ?? "unknown"}); retried next session`
|
|
19433
|
+
);
|
|
19434
|
+
}
|
|
19435
|
+
if ((result?.failedCount ?? 0) > 0 || failure !== void 0 && CONTENT_FAILURE_REASONS.has(failure.reason))
|
|
19436
|
+
throw new BatchFailureError("Extraction batch incomplete; retained for retry", false);
|
|
19437
|
+
throw new Error("Extraction batch incomplete; retained for retry");
|
|
19438
|
+
}
|
|
19439
|
+
await acknowledge(job, ids, loaded, false);
|
|
19275
19440
|
scheduleAfterSuccess = true;
|
|
19276
19441
|
} catch (error) {
|
|
19277
19442
|
attempts.set(job.id, attempted + 1);
|
|
19278
19443
|
retry = true;
|
|
19279
19444
|
reportError(error, conversationId);
|
|
19445
|
+
try {
|
|
19446
|
+
if (await recordFailure(job, ids, loaded, error, conversationId))
|
|
19447
|
+
scheduleAfterSuccess = true;
|
|
19448
|
+
} catch (recordError) {
|
|
19449
|
+
reportError(recordError, conversationId);
|
|
19450
|
+
}
|
|
19280
19451
|
}
|
|
19281
19452
|
}
|
|
19282
19453
|
} catch (error) {
|
|
@@ -19346,7 +19517,7 @@ function createDurableAutoExtractor(options) {
|
|
|
19346
19517
|
const start = boundary >= 0 ? boundary + 1 : Math.max(0, ids.length - Math.max(1, options.windowSize ?? 6));
|
|
19347
19518
|
if (start >= ids.length) return;
|
|
19348
19519
|
const ownWatermark = job?._getRaw("watermark");
|
|
19349
|
-
const atOwnWatermark = !!job && boundary >= 0 && (ids[boundary] === ownWatermark || sequences.get(ids[boundary]) !== void 0 && sequences.get(ids[boundary]) === seqOf(job));
|
|
19520
|
+
const atOwnWatermark = !!job && boundary >= 0 && failedSessionsOf(job, String(ownWatermark)) < MAX_FAILED_SESSIONS && (ids[boundary] === ownWatermark || sequences.get(ids[boundary]) !== void 0 && sequences.get(ids[boundary]) === seqOf(job));
|
|
19350
19521
|
const overlapStart = atOwnWatermark ? Math.max(0, boundary - 1) : start;
|
|
19351
19522
|
const fresh = ids.slice(overlapStart).filter((id) => !foreignSources.has(id));
|
|
19352
19523
|
if (!fresh.length) return;
|
|
@@ -19793,6 +19964,9 @@ var MANUAL_FACT_TYPES = [
|
|
|
19793
19964
|
function normalizeManualFactType(value) {
|
|
19794
19965
|
return typeof value === "string" && MANUAL_FACT_TYPES.includes(value) ? value : void 0;
|
|
19795
19966
|
}
|
|
19967
|
+
function isSharedScope(scope) {
|
|
19968
|
+
return scope === "shared";
|
|
19969
|
+
}
|
|
19796
19970
|
async function notifyWritten(options, input, outcome) {
|
|
19797
19971
|
try {
|
|
19798
19972
|
await options?.onWritten?.({ input, outcome });
|
|
@@ -19861,14 +20035,17 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
|
|
|
19861
20035
|
try {
|
|
19862
20036
|
const isUpdate = !!id;
|
|
19863
20037
|
let previousContent;
|
|
20038
|
+
const scope = options?.scope ?? "private";
|
|
19864
20039
|
if (isUpdate) {
|
|
19865
20040
|
const existing = await getVaultMemoryOp(vaultCtx, id);
|
|
19866
20041
|
if (!existing) {
|
|
19867
20042
|
return `Error: Memory with ID "${id}" not found. Creating a new memory instead would require a separate call without an ID.`;
|
|
19868
20043
|
}
|
|
20044
|
+
if (isSharedScope(existing.scope) !== isSharedScope(scope)) {
|
|
20045
|
+
return `Error: Memory "${id}" belongs to a different scope than this conversation and cannot be updated from here. It was not modified. To record this fact, save it as a new memory without an ID.`;
|
|
20046
|
+
}
|
|
19869
20047
|
previousContent = existing.content;
|
|
19870
20048
|
}
|
|
19871
|
-
const scope = options?.scope ?? "private";
|
|
19872
20049
|
const operation = {
|
|
19873
20050
|
action: isUpdate ? "update" : "add",
|
|
19874
20051
|
content,
|
|
@@ -22931,7 +23108,7 @@ __decorateClass([
|
|
|
22931
23108
|
], VaultFolder.prototype, "context", 2);
|
|
22932
23109
|
|
|
22933
23110
|
// src/lib/db/schema.ts
|
|
22934
|
-
var SDK_SCHEMA_VERSION =
|
|
23111
|
+
var SDK_SCHEMA_VERSION = 47;
|
|
22935
23112
|
var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
22936
23113
|
version: SDK_SCHEMA_VERSION,
|
|
22937
23114
|
tables: [
|
|
@@ -22947,7 +23124,11 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
22947
23124
|
// source. `watermark` alone is an id, and deleting that message erased
|
|
22948
23125
|
// the anchor — see the column note in extractionJobs/models.ts.
|
|
22949
23126
|
{ name: "watermark_seq", type: "number", isOptional: true },
|
|
22950
|
-
{ name: "folder_id", type: "string", isOptional: true }
|
|
23127
|
+
{ name: "folder_id", type: "string", isOptional: true },
|
|
23128
|
+
// Poison accounting for the head batch; see extractionJobs/models.ts.
|
|
23129
|
+
{ name: "failed_sessions", type: "number", isOptional: true },
|
|
23130
|
+
{ name: "failed_head", type: "string", isOptional: true },
|
|
23131
|
+
{ name: "failed_at", type: "number", isOptional: true }
|
|
22951
23132
|
]
|
|
22952
23133
|
}),
|
|
22953
23134
|
// Chat storage tables
|
|
@@ -23971,6 +24152,22 @@ var sdkMigrations = (0, import_migrations2.schemaMigrations)({
|
|
|
23971
24152
|
]
|
|
23972
24153
|
})
|
|
23973
24154
|
]
|
|
24155
|
+
},
|
|
24156
|
+
// v46 -> v47: persisted poison count (and when it was last counted) for a
|
|
24157
|
+
// durable-extraction job's head batch. NULL = never failed, which is right
|
|
24158
|
+
// for every existing row.
|
|
24159
|
+
{
|
|
24160
|
+
toVersion: 47,
|
|
24161
|
+
steps: [
|
|
24162
|
+
(0, import_migrations2.addColumns)({
|
|
24163
|
+
table: "memory_extraction_jobs",
|
|
24164
|
+
columns: [
|
|
24165
|
+
{ name: "failed_sessions", type: "number", isOptional: true },
|
|
24166
|
+
{ name: "failed_head", type: "string", isOptional: true },
|
|
24167
|
+
{ name: "failed_at", type: "number", isOptional: true }
|
|
24168
|
+
]
|
|
24169
|
+
})
|
|
24170
|
+
]
|
|
23974
24171
|
}
|
|
23975
24172
|
]
|
|
23976
24173
|
});
|