@anuma/sdk 6.25.1 → 6.25.3
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 +348 -148
- package/dist/expo/index.d.mts +34 -9
- package/dist/expo/index.d.ts +34 -9
- package/dist/expo/index.mjs +348 -148
- package/dist/react/index.cjs +348 -148
- package/dist/react/index.d.mts +34 -9
- package/dist/react/index.d.ts +34 -9
- package/dist/react/index.mjs +348 -148
- package/dist/server/index.cjs +348 -148
- package/dist/server/index.d.mts +34 -9
- package/dist/server/index.d.ts +34 -9
- package/dist/server/index.mjs +348 -148
- 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(
|
|
@@ -18178,7 +18202,10 @@ function reviewedMemoryIdsSignature(ids) {
|
|
|
18178
18202
|
return [...new Set(ids)].sort().join("\n");
|
|
18179
18203
|
}
|
|
18180
18204
|
function facetsSignature(facets) {
|
|
18181
|
-
return
|
|
18205
|
+
return [
|
|
18206
|
+
JSON.stringify(FACET_SYSTEM_PROMPT),
|
|
18207
|
+
...facets.map((f) => JSON.stringify([f.key, f.label, f.query, f.guidance, facetResponseSchema(f.key)])).sort()
|
|
18208
|
+
].join("\n");
|
|
18182
18209
|
}
|
|
18183
18210
|
function trendsEqual(a, b) {
|
|
18184
18211
|
if (!a) return false;
|
|
@@ -18400,7 +18427,7 @@ var FACET_SYSTEM_PROMPT = `You are writing one section of a person's shareable p
|
|
|
18400
18427
|
Rules:
|
|
18401
18428
|
- Ground every claim in the supplied memories \u2014 never invent, infer beyond, or embellish what they support.
|
|
18402
18429
|
- If the memories don't cover this section, return an empty summary with hasEvidence=false. Do not pad or guess.
|
|
18403
|
-
- Write in
|
|
18430
|
+
- Write in a pronoun-free profile voice: lead with the descriptor or the verb ("Thoughtful, detail-oriented builder. Values clear communication."). Never use "they"/"he"/"she", "I", "you", or the person's name \u2014 the person publishes this as their own profile, and strangers read it there.
|
|
18404
18431
|
- Be concise and specific; no preamble, hedging, or meta-commentary.
|
|
18405
18432
|
- Respond as JSON in exactly the shape the user turn states, with no extra fields.`;
|
|
18406
18433
|
function buildFacetUserInstructions(facet) {
|
|
@@ -19075,6 +19102,37 @@ async function assembleMemoryContext(options) {
|
|
|
19075
19102
|
var import_watermelondb12 = require("@nozbe/watermelondb");
|
|
19076
19103
|
var MAX_JOBS_PER_PASS = 3;
|
|
19077
19104
|
var MAX_ATTEMPTS = 3;
|
|
19105
|
+
var MAX_FAILED_SESSIONS = 3;
|
|
19106
|
+
var MIN_FAILED_SESSION_GAP_MS = 60 * 60 * 1e3;
|
|
19107
|
+
var REQUEST_REJECTED_STATUSES = /* @__PURE__ */ new Set([400, 404, 413, 422]);
|
|
19108
|
+
var CONTENT_FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
19109
|
+
"empty-content",
|
|
19110
|
+
"invalid-json",
|
|
19111
|
+
"null-completion",
|
|
19112
|
+
"body-parse-failed"
|
|
19113
|
+
]);
|
|
19114
|
+
var BACKOFF_ALLOWANCE_MS = 2100;
|
|
19115
|
+
var RETAIN_BUDGET_MS = 12e4;
|
|
19116
|
+
function defaultBatchTimeoutMs(extract) {
|
|
19117
|
+
const attempts = Math.max(1, extract.maxAttempts ?? 3);
|
|
19118
|
+
const calls = (extract.timeoutMs ?? 6e4) * attempts + BACKOFF_ALLOWANCE_MS * (attempts - 1);
|
|
19119
|
+
const extraction = extract.totalTimeoutMs !== void 0 ? Math.min(extract.totalTimeoutMs, calls) : calls;
|
|
19120
|
+
return extraction + RETAIN_BUDGET_MS;
|
|
19121
|
+
}
|
|
19122
|
+
var BatchFailureError = class extends Error {
|
|
19123
|
+
constructor(message, terminal) {
|
|
19124
|
+
super(message);
|
|
19125
|
+
this.terminal = terminal;
|
|
19126
|
+
}
|
|
19127
|
+
};
|
|
19128
|
+
var AccountFailureError = class extends Error {
|
|
19129
|
+
};
|
|
19130
|
+
var LockedSourcesError = class extends Error {
|
|
19131
|
+
constructor(persistentIds) {
|
|
19132
|
+
super("Source messages are locked; retained for retry");
|
|
19133
|
+
this.persistentIds = persistentIds;
|
|
19134
|
+
}
|
|
19135
|
+
};
|
|
19078
19136
|
function idsOf(job) {
|
|
19079
19137
|
return JSON.parse(String(job._getRaw("message_ids")));
|
|
19080
19138
|
}
|
|
@@ -19082,6 +19140,16 @@ function seqOf(job) {
|
|
|
19082
19140
|
const raw = job._getRaw("watermark_seq");
|
|
19083
19141
|
return typeof raw === "number" && raw > 0 ? raw : void 0;
|
|
19084
19142
|
}
|
|
19143
|
+
function failedSessionsOf(job, head) {
|
|
19144
|
+
if (job._getRaw("failed_head") !== head) return 0;
|
|
19145
|
+
const raw = job._getRaw("failed_sessions");
|
|
19146
|
+
return typeof raw === "number" && raw > 0 ? raw : 0;
|
|
19147
|
+
}
|
|
19148
|
+
function failedAtOf(job, head) {
|
|
19149
|
+
if (job._getRaw("failed_head") !== head) return void 0;
|
|
19150
|
+
const raw = job._getRaw("failed_at");
|
|
19151
|
+
return typeof raw === "number" ? raw : void 0;
|
|
19152
|
+
}
|
|
19085
19153
|
function createDurableAutoExtractor(options) {
|
|
19086
19154
|
const vault = options.retainCtx.vaultCtx;
|
|
19087
19155
|
const database = vault.database;
|
|
@@ -19104,6 +19172,9 @@ function createDurableAutoExtractor(options) {
|
|
|
19104
19172
|
let writes = Promise.resolve();
|
|
19105
19173
|
let storeFailures = 0;
|
|
19106
19174
|
const attempts = /* @__PURE__ */ new Map();
|
|
19175
|
+
const sessionFailures = /* @__PURE__ */ new Map();
|
|
19176
|
+
const skippedThisSession = /* @__PURE__ */ new Set();
|
|
19177
|
+
const clock = options.now ?? Date.now;
|
|
19107
19178
|
const reportError = (error, conversationId) => {
|
|
19108
19179
|
try {
|
|
19109
19180
|
options.onError?.(error instanceof Error ? error : new Error(String(error)), conversationId);
|
|
@@ -19132,6 +19203,7 @@ function createDurableAutoExtractor(options) {
|
|
|
19132
19203
|
}
|
|
19133
19204
|
async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
|
|
19134
19205
|
let watchdog;
|
|
19206
|
+
let cancelled = false;
|
|
19135
19207
|
const model = options.modelForScope?.(jobScope) ?? options.extract.model;
|
|
19136
19208
|
try {
|
|
19137
19209
|
return await Promise.race([
|
|
@@ -19142,7 +19214,7 @@ function createDurableAutoExtractor(options) {
|
|
|
19142
19214
|
...options.retainCtx,
|
|
19143
19215
|
vaultCtx: {
|
|
19144
19216
|
...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
|
|
19217
|
+
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
19218
|
}
|
|
19147
19219
|
},
|
|
19148
19220
|
// The model follows the job's scope, not the mode alive at drain time.
|
|
@@ -19162,14 +19234,116 @@ function createDurableAutoExtractor(options) {
|
|
|
19162
19234
|
new Promise((_resolve, reject) => {
|
|
19163
19235
|
watchdog = setTimeout(
|
|
19164
19236
|
() => reject(new Error("Extraction did not settle in time; retained for retry")),
|
|
19165
|
-
options.batchTimeoutMs ??
|
|
19237
|
+
options.batchTimeoutMs ?? defaultBatchTimeoutMs(options.extract)
|
|
19166
19238
|
);
|
|
19167
19239
|
})
|
|
19168
19240
|
]);
|
|
19169
19241
|
} finally {
|
|
19242
|
+
cancelled = true;
|
|
19170
19243
|
if (watchdog !== void 0) clearTimeout(watchdog);
|
|
19171
19244
|
}
|
|
19172
19245
|
}
|
|
19246
|
+
async function acknowledge(job, ids, loaded, abandoned) {
|
|
19247
|
+
attempts.delete(job.id);
|
|
19248
|
+
sessionFailures.delete(job.id);
|
|
19249
|
+
skippedThisSession.delete(job.id);
|
|
19250
|
+
const sequences = /* @__PURE__ */ new Map();
|
|
19251
|
+
for (const message of loaded)
|
|
19252
|
+
if (message && message.messageId > 0) sequences.set(message.uniqueId, message.messageId);
|
|
19253
|
+
await database.write(async () => {
|
|
19254
|
+
const current = idsOf(job);
|
|
19255
|
+
const acknowledged = ids.filter((id) => current.includes(id));
|
|
19256
|
+
if (!acknowledged.length) return;
|
|
19257
|
+
const done = new Set(acknowledged);
|
|
19258
|
+
const remaining = current.filter((id) => !done.has(id));
|
|
19259
|
+
await job.update((r) => {
|
|
19260
|
+
r._setRaw(
|
|
19261
|
+
"message_ids",
|
|
19262
|
+
JSON.stringify(
|
|
19263
|
+
remaining.length ? [...abandoned ? [] : acknowledged.slice(-2), ...remaining] : []
|
|
19264
|
+
)
|
|
19265
|
+
);
|
|
19266
|
+
const newest = acknowledged[acknowledged.length - 1];
|
|
19267
|
+
r._setRaw("watermark", newest);
|
|
19268
|
+
const sequence = sequences.get(newest);
|
|
19269
|
+
if (sequence !== void 0) {
|
|
19270
|
+
const prior = seqOf(job);
|
|
19271
|
+
r._setRaw("watermark_seq", prior === void 0 ? sequence : Math.max(prior, sequence));
|
|
19272
|
+
}
|
|
19273
|
+
r._setRaw("failed_sessions", abandoned ? MAX_FAILED_SESSIONS : null);
|
|
19274
|
+
r._setRaw("failed_head", abandoned ? newest : null);
|
|
19275
|
+
r._setRaw("failed_at", null);
|
|
19276
|
+
});
|
|
19277
|
+
});
|
|
19278
|
+
}
|
|
19279
|
+
async function recordFailure(job, ids, loaded, error, conversationId) {
|
|
19280
|
+
const head = ids[0];
|
|
19281
|
+
if (!head || !loaded.some(Boolean)) return false;
|
|
19282
|
+
if (error instanceof AccountFailureError) {
|
|
19283
|
+
skippedThisSession.add(job.id);
|
|
19284
|
+
return false;
|
|
19285
|
+
}
|
|
19286
|
+
const counted = error instanceof BatchFailureError || error instanceof LockedSourcesError && error.persistentIds.length > 0;
|
|
19287
|
+
if (!counted) return false;
|
|
19288
|
+
const prior = sessionFailures.get(job.id);
|
|
19289
|
+
const count = prior?.head === head ? prior.count + 1 : 1;
|
|
19290
|
+
sessionFailures.set(job.id, { head, count });
|
|
19291
|
+
const terminal = error instanceof BatchFailureError && error.terminal;
|
|
19292
|
+
if (!terminal && count < MAX_ATTEMPTS) return false;
|
|
19293
|
+
skippedThisSession.add(job.id);
|
|
19294
|
+
const now = clock();
|
|
19295
|
+
const lastCounted = failedAtOf(job, head);
|
|
19296
|
+
if (lastCounted !== void 0 && now - lastCounted < MIN_FAILED_SESSION_GAP_MS) return false;
|
|
19297
|
+
const failures = failedSessionsOf(job, head) + 1;
|
|
19298
|
+
if (failures < MAX_FAILED_SESSIONS) {
|
|
19299
|
+
await database.write(
|
|
19300
|
+
() => job.update((r) => {
|
|
19301
|
+
r._setRaw("failed_sessions", failures);
|
|
19302
|
+
r._setRaw("failed_head", head);
|
|
19303
|
+
r._setRaw("failed_at", now);
|
|
19304
|
+
})
|
|
19305
|
+
);
|
|
19306
|
+
return false;
|
|
19307
|
+
}
|
|
19308
|
+
if (error instanceof LockedSourcesError) {
|
|
19309
|
+
const dropped = new Set(error.persistentIds);
|
|
19310
|
+
let newest;
|
|
19311
|
+
for (const message of loaded)
|
|
19312
|
+
if (message && dropped.has(message.uniqueId) && message.messageId > (newest?.seq ?? 0))
|
|
19313
|
+
newest = { id: message.uniqueId, seq: message.messageId };
|
|
19314
|
+
const advance = newest !== void 0 && newest.seq > (seqOf(job) ?? 0) ? newest : void 0;
|
|
19315
|
+
await database.write(
|
|
19316
|
+
() => job.update((r) => {
|
|
19317
|
+
r._setRaw("message_ids", JSON.stringify(idsOf(job).filter((id) => !dropped.has(id))));
|
|
19318
|
+
if (advance) {
|
|
19319
|
+
r._setRaw("watermark", advance.id);
|
|
19320
|
+
r._setRaw("watermark_seq", advance.seq);
|
|
19321
|
+
}
|
|
19322
|
+
r._setRaw("failed_sessions", advance ? MAX_FAILED_SESSIONS : null);
|
|
19323
|
+
r._setRaw("failed_head", advance ? advance.id : null);
|
|
19324
|
+
r._setRaw("failed_at", null);
|
|
19325
|
+
})
|
|
19326
|
+
);
|
|
19327
|
+
attempts.delete(job.id);
|
|
19328
|
+
sessionFailures.delete(job.id);
|
|
19329
|
+
skippedThisSession.delete(job.id);
|
|
19330
|
+
reportError(
|
|
19331
|
+
new Error(
|
|
19332
|
+
`Dropped ${dropped.size} source id(s) that stayed locked for ${failures} sessions to unblock extraction`
|
|
19333
|
+
),
|
|
19334
|
+
conversationId
|
|
19335
|
+
);
|
|
19336
|
+
return true;
|
|
19337
|
+
}
|
|
19338
|
+
await acknowledge(job, ids, loaded, true);
|
|
19339
|
+
reportError(
|
|
19340
|
+
new Error(
|
|
19341
|
+
`Abandoned an extraction batch of ${ids.length} source id(s) after it failed in ${failures} sessions`
|
|
19342
|
+
),
|
|
19343
|
+
conversationId
|
|
19344
|
+
);
|
|
19345
|
+
return true;
|
|
19346
|
+
}
|
|
19173
19347
|
async function drain() {
|
|
19174
19348
|
if (disposed || running) return;
|
|
19175
19349
|
running = true;
|
|
@@ -19184,21 +19358,23 @@ function createDurableAutoExtractor(options) {
|
|
|
19184
19358
|
for (const job of pending) {
|
|
19185
19359
|
if (disposed) break;
|
|
19186
19360
|
const attempted = attempts.get(job.id) ?? 0;
|
|
19187
|
-
if (attempted >= MAX_ATTEMPTS) continue;
|
|
19361
|
+
if (attempted >= MAX_ATTEMPTS || skippedThisSession.has(job.id)) continue;
|
|
19188
19362
|
if (processed >= MAX_JOBS_PER_PASS) {
|
|
19189
19363
|
scheduleAfterSuccess = true;
|
|
19190
19364
|
break;
|
|
19191
19365
|
}
|
|
19192
19366
|
processed++;
|
|
19193
19367
|
const conversationId = String(job._getRaw("conversation_id"));
|
|
19368
|
+
let ids = [];
|
|
19369
|
+
let loaded = [];
|
|
19194
19370
|
try {
|
|
19195
19371
|
const conversations = await storage.conversationsCollection.query(import_watermelondb12.Q.where("conversation_id", conversationId), import_watermelondb12.Q.where("is_deleted", false)).fetchCount();
|
|
19196
19372
|
if (!conversations) {
|
|
19197
19373
|
await database.write(() => job.destroyPermanently());
|
|
19198
19374
|
continue;
|
|
19199
19375
|
}
|
|
19200
|
-
|
|
19201
|
-
|
|
19376
|
+
ids = idsOf(job).slice(0, 20);
|
|
19377
|
+
loaded = await Promise.all(ids.map((id) => getMessageOp(storage, id)));
|
|
19202
19378
|
const missing = ids.filter((_id, index) => loaded[index] === null);
|
|
19203
19379
|
if (missing.length) {
|
|
19204
19380
|
if (attempted < MAX_ATTEMPTS - 1)
|
|
@@ -19222,17 +19398,21 @@ function createDurableAutoExtractor(options) {
|
|
|
19222
19398
|
);
|
|
19223
19399
|
continue;
|
|
19224
19400
|
}
|
|
19225
|
-
|
|
19226
|
-
|
|
19227
|
-
|
|
19228
|
-
|
|
19401
|
+
const locked = loaded.filter((message) => message && isEncrypted(message.content));
|
|
19402
|
+
if (locked.length) {
|
|
19403
|
+
throw new LockedSourcesError(
|
|
19404
|
+
locked.flatMap(
|
|
19405
|
+
(message) => message.decryptionStatus === "auth_mismatch" || message.decryptionStatus === "invalid_payload" ? [message.uniqueId] : []
|
|
19406
|
+
)
|
|
19407
|
+
);
|
|
19229
19408
|
}
|
|
19230
19409
|
const messages = loaded.flatMap(
|
|
19231
19410
|
(m) => m && m.conversationId === conversationId && (m.role === "user" || m.role === "assistant") ? [{ id: m.uniqueId, role: m.role, content: m.content }] : []
|
|
19232
19411
|
);
|
|
19233
19412
|
let success = messages.length === 0;
|
|
19413
|
+
let result;
|
|
19234
19414
|
if (messages.length) {
|
|
19235
|
-
|
|
19415
|
+
result = await extractBatch(
|
|
19236
19416
|
messages,
|
|
19237
19417
|
conversationId,
|
|
19238
19418
|
ids,
|
|
@@ -19242,41 +19422,35 @@ function createDurableAutoExtractor(options) {
|
|
|
19242
19422
|
success = result.failedCount === 0 && result.outcome !== "empty-after-retry";
|
|
19243
19423
|
options.onTurnComplete?.(result);
|
|
19244
19424
|
}
|
|
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)
|
|
19425
|
+
if (!success) {
|
|
19426
|
+
const failure = result?.failure;
|
|
19427
|
+
if (failure?.reason === "http-terminal") {
|
|
19428
|
+
const status = failure.httpStatus;
|
|
19429
|
+
if (status !== void 0 && REQUEST_REJECTED_STATUSES.has(status))
|
|
19430
|
+
throw new BatchFailureError(
|
|
19431
|
+
`Extraction rejected the batch (HTTP ${status}); not retried this session`,
|
|
19432
|
+
true
|
|
19271
19433
|
);
|
|
19272
|
-
|
|
19273
|
-
|
|
19274
|
-
|
|
19434
|
+
throw new AccountFailureError(
|
|
19435
|
+
`Extraction refused for the account (HTTP ${status ?? "unknown"}); retried next session`
|
|
19436
|
+
);
|
|
19437
|
+
}
|
|
19438
|
+
if ((result?.failedCount ?? 0) > 0 || failure !== void 0 && CONTENT_FAILURE_REASONS.has(failure.reason))
|
|
19439
|
+
throw new BatchFailureError("Extraction batch incomplete; retained for retry", false);
|
|
19440
|
+
throw new Error("Extraction batch incomplete; retained for retry");
|
|
19441
|
+
}
|
|
19442
|
+
await acknowledge(job, ids, loaded, false);
|
|
19275
19443
|
scheduleAfterSuccess = true;
|
|
19276
19444
|
} catch (error) {
|
|
19277
19445
|
attempts.set(job.id, attempted + 1);
|
|
19278
19446
|
retry = true;
|
|
19279
19447
|
reportError(error, conversationId);
|
|
19448
|
+
try {
|
|
19449
|
+
if (await recordFailure(job, ids, loaded, error, conversationId))
|
|
19450
|
+
scheduleAfterSuccess = true;
|
|
19451
|
+
} catch (recordError) {
|
|
19452
|
+
reportError(recordError, conversationId);
|
|
19453
|
+
}
|
|
19280
19454
|
}
|
|
19281
19455
|
}
|
|
19282
19456
|
} catch (error) {
|
|
@@ -19346,7 +19520,7 @@ function createDurableAutoExtractor(options) {
|
|
|
19346
19520
|
const start = boundary >= 0 ? boundary + 1 : Math.max(0, ids.length - Math.max(1, options.windowSize ?? 6));
|
|
19347
19521
|
if (start >= ids.length) return;
|
|
19348
19522
|
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));
|
|
19523
|
+
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
19524
|
const overlapStart = atOwnWatermark ? Math.max(0, boundary - 1) : start;
|
|
19351
19525
|
const fresh = ids.slice(overlapStart).filter((id) => !foreignSources.has(id));
|
|
19352
19526
|
if (!fresh.length) return;
|
|
@@ -19793,6 +19967,9 @@ var MANUAL_FACT_TYPES = [
|
|
|
19793
19967
|
function normalizeManualFactType(value) {
|
|
19794
19968
|
return typeof value === "string" && MANUAL_FACT_TYPES.includes(value) ? value : void 0;
|
|
19795
19969
|
}
|
|
19970
|
+
function isSharedScope(scope) {
|
|
19971
|
+
return scope === "shared";
|
|
19972
|
+
}
|
|
19796
19973
|
async function notifyWritten(options, input, outcome) {
|
|
19797
19974
|
try {
|
|
19798
19975
|
await options?.onWritten?.({ input, outcome });
|
|
@@ -19861,14 +20038,17 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
|
|
|
19861
20038
|
try {
|
|
19862
20039
|
const isUpdate = !!id;
|
|
19863
20040
|
let previousContent;
|
|
20041
|
+
const scope = options?.scope ?? "private";
|
|
19864
20042
|
if (isUpdate) {
|
|
19865
20043
|
const existing = await getVaultMemoryOp(vaultCtx, id);
|
|
19866
20044
|
if (!existing) {
|
|
19867
20045
|
return `Error: Memory with ID "${id}" not found. Creating a new memory instead would require a separate call without an ID.`;
|
|
19868
20046
|
}
|
|
20047
|
+
if (isSharedScope(existing.scope) !== isSharedScope(scope)) {
|
|
20048
|
+
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.`;
|
|
20049
|
+
}
|
|
19869
20050
|
previousContent = existing.content;
|
|
19870
20051
|
}
|
|
19871
|
-
const scope = options?.scope ?? "private";
|
|
19872
20052
|
const operation = {
|
|
19873
20053
|
action: isUpdate ? "update" : "add",
|
|
19874
20054
|
content,
|
|
@@ -22931,7 +23111,7 @@ __decorateClass([
|
|
|
22931
23111
|
], VaultFolder.prototype, "context", 2);
|
|
22932
23112
|
|
|
22933
23113
|
// src/lib/db/schema.ts
|
|
22934
|
-
var SDK_SCHEMA_VERSION =
|
|
23114
|
+
var SDK_SCHEMA_VERSION = 47;
|
|
22935
23115
|
var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
22936
23116
|
version: SDK_SCHEMA_VERSION,
|
|
22937
23117
|
tables: [
|
|
@@ -22947,7 +23127,11 @@ var sdkSchema = (0, import_watermelondb21.appSchema)({
|
|
|
22947
23127
|
// source. `watermark` alone is an id, and deleting that message erased
|
|
22948
23128
|
// the anchor — see the column note in extractionJobs/models.ts.
|
|
22949
23129
|
{ name: "watermark_seq", type: "number", isOptional: true },
|
|
22950
|
-
{ name: "folder_id", type: "string", isOptional: true }
|
|
23130
|
+
{ name: "folder_id", type: "string", isOptional: true },
|
|
23131
|
+
// Poison accounting for the head batch; see extractionJobs/models.ts.
|
|
23132
|
+
{ name: "failed_sessions", type: "number", isOptional: true },
|
|
23133
|
+
{ name: "failed_head", type: "string", isOptional: true },
|
|
23134
|
+
{ name: "failed_at", type: "number", isOptional: true }
|
|
22951
23135
|
]
|
|
22952
23136
|
}),
|
|
22953
23137
|
// Chat storage tables
|
|
@@ -23971,6 +24155,22 @@ var sdkMigrations = (0, import_migrations2.schemaMigrations)({
|
|
|
23971
24155
|
]
|
|
23972
24156
|
})
|
|
23973
24157
|
]
|
|
24158
|
+
},
|
|
24159
|
+
// v46 -> v47: persisted poison count (and when it was last counted) for a
|
|
24160
|
+
// durable-extraction job's head batch. NULL = never failed, which is right
|
|
24161
|
+
// for every existing row.
|
|
24162
|
+
{
|
|
24163
|
+
toVersion: 47,
|
|
24164
|
+
steps: [
|
|
24165
|
+
(0, import_migrations2.addColumns)({
|
|
24166
|
+
table: "memory_extraction_jobs",
|
|
24167
|
+
columns: [
|
|
24168
|
+
{ name: "failed_sessions", type: "number", isOptional: true },
|
|
24169
|
+
{ name: "failed_head", type: "string", isOptional: true },
|
|
24170
|
+
{ name: "failed_at", type: "number", isOptional: true }
|
|
24171
|
+
]
|
|
24172
|
+
})
|
|
24173
|
+
]
|
|
23974
24174
|
}
|
|
23975
24175
|
]
|
|
23976
24176
|
});
|