@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/react/index.mjs
CHANGED
|
@@ -11159,8 +11159,42 @@ async function vaultMemoryToStored(memory, walletAddress, signMessage, embeddedW
|
|
|
11159
11159
|
}
|
|
11160
11160
|
return raw;
|
|
11161
11161
|
}
|
|
11162
|
+
function populateNewVaultMemory(record, ctx, opts, encryptedContent) {
|
|
11163
|
+
record._setRaw("content", encryptedContent);
|
|
11164
|
+
record._setRaw("scope", opts.scope ?? "private");
|
|
11165
|
+
record._setRaw("folder_id", opts.folderId ?? null);
|
|
11166
|
+
record._setRaw("user_id", ctx.userId ?? null);
|
|
11167
|
+
record._setRaw("is_deleted", false);
|
|
11168
|
+
if (opts.embedding !== void 0) {
|
|
11169
|
+
record._setRaw("embedding", opts.embedding);
|
|
11170
|
+
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
11171
|
+
}
|
|
11172
|
+
if (opts.sourceChunkIds !== void 0) {
|
|
11173
|
+
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
11174
|
+
}
|
|
11175
|
+
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
11176
|
+
record._setRaw("source", opts.source ?? "manual");
|
|
11177
|
+
if (opts.eventTime) {
|
|
11178
|
+
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
11179
|
+
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
11180
|
+
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
11181
|
+
}
|
|
11182
|
+
if (opts.factType !== void 0) {
|
|
11183
|
+
record._setRaw("fact_type", opts.factType);
|
|
11184
|
+
}
|
|
11185
|
+
if (opts.trustTier !== void 0) {
|
|
11186
|
+
record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
11187
|
+
}
|
|
11188
|
+
record._setRaw("visibility", opts.visibility ?? "private");
|
|
11189
|
+
record._setRaw(
|
|
11190
|
+
"published_at",
|
|
11191
|
+
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
11192
|
+
);
|
|
11193
|
+
if (opts.geohash !== void 0) {
|
|
11194
|
+
record._setRaw("geohash", opts.geohash);
|
|
11195
|
+
}
|
|
11196
|
+
}
|
|
11162
11197
|
async function createVaultMemoryOp(ctx, opts) {
|
|
11163
|
-
const scope = opts.scope ?? "private";
|
|
11164
11198
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
11165
11199
|
opts.content,
|
|
11166
11200
|
ctx.walletAddress,
|
|
@@ -11170,47 +11204,14 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
11170
11204
|
const created = await ctx.database.write(async () => {
|
|
11171
11205
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
11172
11206
|
throw new Error("Memory source is no longer eligible");
|
|
11173
|
-
return ctx.vaultMemoryCollection.create(
|
|
11174
|
-
record
|
|
11175
|
-
|
|
11176
|
-
record._setRaw("folder_id", opts.folderId ?? null);
|
|
11177
|
-
record._setRaw("user_id", ctx.userId ?? null);
|
|
11178
|
-
record._setRaw("is_deleted", false);
|
|
11179
|
-
if (opts.embedding !== void 0) {
|
|
11180
|
-
record._setRaw("embedding", opts.embedding);
|
|
11181
|
-
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
11182
|
-
}
|
|
11183
|
-
if (opts.sourceChunkIds !== void 0) {
|
|
11184
|
-
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
11185
|
-
}
|
|
11186
|
-
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
11187
|
-
record._setRaw("source", opts.source ?? "manual");
|
|
11188
|
-
if (opts.eventTime) {
|
|
11189
|
-
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
11190
|
-
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
11191
|
-
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
11192
|
-
}
|
|
11193
|
-
if (opts.factType !== void 0) {
|
|
11194
|
-
record._setRaw("fact_type", opts.factType);
|
|
11195
|
-
}
|
|
11196
|
-
if (opts.trustTier !== void 0) {
|
|
11197
|
-
record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
11198
|
-
}
|
|
11199
|
-
record._setRaw("visibility", opts.visibility ?? "private");
|
|
11200
|
-
record._setRaw(
|
|
11201
|
-
"published_at",
|
|
11202
|
-
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
11203
|
-
);
|
|
11204
|
-
if (opts.geohash !== void 0) {
|
|
11205
|
-
record._setRaw("geohash", opts.geohash);
|
|
11206
|
-
}
|
|
11207
|
-
});
|
|
11207
|
+
return ctx.vaultMemoryCollection.create(
|
|
11208
|
+
(record) => populateNewVaultMemory(record, ctx, opts, encryptedContent)
|
|
11209
|
+
);
|
|
11208
11210
|
});
|
|
11209
11211
|
return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
11210
11212
|
}
|
|
11211
11213
|
async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
11212
11214
|
if (!targetId) return { created: null, retired: false };
|
|
11213
|
-
const scope = opts.scope ?? "private";
|
|
11214
11215
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
11215
11216
|
opts.content,
|
|
11216
11217
|
ctx.walletAddress,
|
|
@@ -11228,27 +11229,9 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
|
11228
11229
|
return;
|
|
11229
11230
|
}
|
|
11230
11231
|
if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target)) return;
|
|
11231
|
-
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
11232
|
-
record
|
|
11233
|
-
|
|
11234
|
-
record._setRaw("folder_id", opts.folderId ?? null);
|
|
11235
|
-
record._setRaw("user_id", ctx.userId ?? null);
|
|
11236
|
-
record._setRaw("is_deleted", false);
|
|
11237
|
-
if (opts.embedding !== void 0) {
|
|
11238
|
-
record._setRaw("embedding", opts.embedding);
|
|
11239
|
-
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
11240
|
-
}
|
|
11241
|
-
if (opts.sourceChunkIds !== void 0) {
|
|
11242
|
-
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
11243
|
-
}
|
|
11244
|
-
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
11245
|
-
record._setRaw("source", opts.source ?? "manual");
|
|
11246
|
-
if (opts.eventTime) {
|
|
11247
|
-
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
11248
|
-
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
11249
|
-
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
11250
|
-
}
|
|
11251
|
-
});
|
|
11232
|
+
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
11233
|
+
(record) => populateNewVaultMemory(record, ctx, opts, encryptedContent)
|
|
11234
|
+
);
|
|
11252
11235
|
await target.update((r) => {
|
|
11253
11236
|
r._setRaw("superseded_by", createdRecord.id);
|
|
11254
11237
|
r._setRaw("superseded_at", Date.now());
|
|
@@ -11328,41 +11311,9 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
11328
11311
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
11329
11312
|
throw new Error("Memory source is no longer eligible");
|
|
11330
11313
|
const prepared = optionsArray.map(
|
|
11331
|
-
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
11332
|
-
record
|
|
11333
|
-
|
|
11334
|
-
record._setRaw("folder_id", opts.folderId ?? null);
|
|
11335
|
-
record._setRaw("user_id", ctx.userId ?? null);
|
|
11336
|
-
record._setRaw("is_deleted", false);
|
|
11337
|
-
if (optionsArray[i].embedding !== void 0) {
|
|
11338
|
-
record._setRaw("embedding", optionsArray[i].embedding);
|
|
11339
|
-
record._setRaw("embedding_model", optionsArray[i].embeddingModel ?? null);
|
|
11340
|
-
}
|
|
11341
|
-
if (opts.sourceChunkIds !== void 0) {
|
|
11342
|
-
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
11343
|
-
}
|
|
11344
|
-
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
11345
|
-
record._setRaw("source", opts.source ?? "manual");
|
|
11346
|
-
if (opts.eventTime) {
|
|
11347
|
-
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
11348
|
-
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
11349
|
-
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
11350
|
-
}
|
|
11351
|
-
if (opts.factType !== void 0) {
|
|
11352
|
-
record._setRaw("fact_type", opts.factType);
|
|
11353
|
-
}
|
|
11354
|
-
if (opts.trustTier !== void 0) {
|
|
11355
|
-
record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
11356
|
-
}
|
|
11357
|
-
record._setRaw("visibility", opts.visibility ?? "private");
|
|
11358
|
-
record._setRaw(
|
|
11359
|
-
"published_at",
|
|
11360
|
-
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
11361
|
-
);
|
|
11362
|
-
if (opts.geohash !== void 0) {
|
|
11363
|
-
record._setRaw("geohash", opts.geohash);
|
|
11364
|
-
}
|
|
11365
|
-
})
|
|
11314
|
+
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
11315
|
+
(record) => populateNewVaultMemory(record, ctx, opts, encryptedContents[i])
|
|
11316
|
+
)
|
|
11366
11317
|
);
|
|
11367
11318
|
await ctx.database.batch(...prepared);
|
|
11368
11319
|
return prepared;
|
|
@@ -12228,21 +12179,73 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
|
12228
12179
|
return false;
|
|
12229
12180
|
}
|
|
12230
12181
|
}
|
|
12231
|
-
async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel) {
|
|
12182
|
+
async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel, expected) {
|
|
12232
12183
|
try {
|
|
12233
12184
|
const record = await ctx.vaultMemoryCollection.find(id);
|
|
12234
12185
|
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
|
|
12186
|
+
const readUpdatedAt = record.updatedAt.getTime();
|
|
12187
|
+
const readStoredContent = record._getRaw("content");
|
|
12188
|
+
if (expected?.updatedAt !== void 0 && expected.updatedAt !== readUpdatedAt) return false;
|
|
12189
|
+
if (expected?.content !== void 0) {
|
|
12190
|
+
const current = await vaultMemoryToStored(
|
|
12191
|
+
record,
|
|
12192
|
+
ctx.walletAddress,
|
|
12193
|
+
ctx.signMessage,
|
|
12194
|
+
ctx.embeddedWalletSigner
|
|
12195
|
+
);
|
|
12196
|
+
if (current.content !== expected.content) return false;
|
|
12197
|
+
}
|
|
12198
|
+
let written = false;
|
|
12235
12199
|
await ctx.database.write(async () => {
|
|
12200
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return;
|
|
12201
|
+
const originalUpdatedAt = record.updatedAt.getTime();
|
|
12202
|
+
if (originalUpdatedAt !== readUpdatedAt || record._getRaw("content") !== readStoredContent)
|
|
12203
|
+
return;
|
|
12236
12204
|
await record.update((r) => {
|
|
12237
12205
|
r._setRaw("embedding", embedding);
|
|
12238
12206
|
r._setRaw("embedding_model", embeddingModel);
|
|
12207
|
+
r._setRaw("updated_at", originalUpdatedAt);
|
|
12239
12208
|
});
|
|
12209
|
+
written = true;
|
|
12240
12210
|
});
|
|
12241
|
-
return
|
|
12211
|
+
return written;
|
|
12242
12212
|
} catch {
|
|
12243
12213
|
return false;
|
|
12244
12214
|
}
|
|
12245
12215
|
}
|
|
12216
|
+
function normalizeForDedupe(content) {
|
|
12217
|
+
return content.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
|
|
12218
|
+
}
|
|
12219
|
+
async function findQuarantinedDuplicateOp(ctx, content, sourceIds, where) {
|
|
12220
|
+
const wanted = [...new Set(sourceIds)].sort().join("\0");
|
|
12221
|
+
const target = normalizeForDedupe(content);
|
|
12222
|
+
const rows = await ctx.vaultMemoryCollection.query(
|
|
12223
|
+
Q6.where("trust_tier", "quarantined"),
|
|
12224
|
+
Q6.where("is_deleted", false),
|
|
12225
|
+
Q6.where("scope", where.scope),
|
|
12226
|
+
Q6.where("folder_id", where.folderId),
|
|
12227
|
+
...ctx.userId !== void 0 ? [Q6.where("user_id", ctx.userId)] : []
|
|
12228
|
+
).unsafeFetchRaw();
|
|
12229
|
+
for (const raw of rows) {
|
|
12230
|
+
let ids;
|
|
12231
|
+
try {
|
|
12232
|
+
ids = JSON.parse(raw.source_chunk_ids ?? "[]");
|
|
12233
|
+
} catch {
|
|
12234
|
+
continue;
|
|
12235
|
+
}
|
|
12236
|
+
if (!Array.isArray(ids)) continue;
|
|
12237
|
+
const key = [...new Set(ids.filter((id) => typeof id === "string"))].sort().join("\0");
|
|
12238
|
+
if (key !== wanted) continue;
|
|
12239
|
+
const stored = await vaultMemoryRawToStored(
|
|
12240
|
+
raw,
|
|
12241
|
+
ctx.walletAddress,
|
|
12242
|
+
ctx.signMessage,
|
|
12243
|
+
ctx.embeddedWalletSigner
|
|
12244
|
+
);
|
|
12245
|
+
if (normalizeForDedupe(stored.content) === target) return stored.uniqueId;
|
|
12246
|
+
}
|
|
12247
|
+
return null;
|
|
12248
|
+
}
|
|
12246
12249
|
|
|
12247
12250
|
// src/lib/memory/decay.ts
|
|
12248
12251
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -12266,6 +12269,10 @@ var DEFAULT_DECAY_POLICY = {
|
|
|
12266
12269
|
hardDeleteWindowMs: HARD_DELETE_WINDOW_MS,
|
|
12267
12270
|
pastEventGraceMs: PAST_EVENT_GRACE_MS
|
|
12268
12271
|
};
|
|
12272
|
+
function lastActivityAt(m) {
|
|
12273
|
+
const observedAt = Number.isFinite(m.lastObservedAt) ? m.lastObservedAt : m.updatedAt;
|
|
12274
|
+
return Math.max(m.updatedAt, observedAt);
|
|
12275
|
+
}
|
|
12269
12276
|
function resolvePolicy(policy) {
|
|
12270
12277
|
if (!policy) return DEFAULT_DECAY_POLICY;
|
|
12271
12278
|
return {
|
|
@@ -12305,8 +12312,7 @@ function classifyDecay(m, now, policy) {
|
|
|
12305
12312
|
if (m.eventTimeEnd < now - resolved.pastEventGraceMs) return "archive";
|
|
12306
12313
|
if (m.eventTimeEnd >= now) return "keep";
|
|
12307
12314
|
}
|
|
12308
|
-
|
|
12309
|
-
if (now - Math.max(m.updatedAt, observedAt) > ttlForType(m.factType, resolved)) return "archive";
|
|
12315
|
+
if (now - lastActivityAt(m) > ttlForType(m.factType, resolved)) return "archive";
|
|
12310
12316
|
return "keep";
|
|
12311
12317
|
}
|
|
12312
12318
|
|
|
@@ -15307,6 +15313,24 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
15307
15313
|
const tRetain = Date.now();
|
|
15308
15314
|
for (const { candidate, isQuarantined, reason, signature } of toRetain) {
|
|
15309
15315
|
try {
|
|
15316
|
+
if (isQuarantined) {
|
|
15317
|
+
const existingId = await findQuarantinedDuplicateOp(
|
|
15318
|
+
retainCtx.vaultCtx,
|
|
15319
|
+
candidate.content,
|
|
15320
|
+
candidate.sourceMessageIds,
|
|
15321
|
+
// The same defaults retain() writes the row with.
|
|
15322
|
+
{ scope: options.scope ?? "private", folderId: options.folderId ?? null }
|
|
15323
|
+
).catch(() => null);
|
|
15324
|
+
if (existingId) {
|
|
15325
|
+
quarantinedInfo.push({
|
|
15326
|
+
candidate,
|
|
15327
|
+
memoryId: existingId,
|
|
15328
|
+
reason,
|
|
15329
|
+
signature
|
|
15330
|
+
});
|
|
15331
|
+
continue;
|
|
15332
|
+
}
|
|
15333
|
+
}
|
|
15310
15334
|
const result = await retain(candidate.content, retainCtx, {
|
|
15311
15335
|
source: "auto-extracted",
|
|
15312
15336
|
sourceChunkIds: candidate.sourceMessageIds,
|
|
@@ -15752,7 +15776,7 @@ function createLlmDecayClassifier(options) {
|
|
|
15752
15776
|
if (!content || content.trim().length === 0) return ruleVerdict;
|
|
15753
15777
|
const trimmed = content.trim().slice(0, MAX_CONTENT_CHARS);
|
|
15754
15778
|
const safe = redactor ? (await redactor.redactTextAsync(trimmed)).text : trimmed;
|
|
15755
|
-
const meta = `factType: ${input.factType ?? "none"}; ageDays: ${ageDays(input
|
|
15779
|
+
const meta = `factType: ${input.factType ?? "none"}; ageDays: ${ageDays(lastActivityAt(input), now)}`;
|
|
15756
15780
|
let parsed;
|
|
15757
15781
|
try {
|
|
15758
15782
|
parsed = await callPortalJsonCompletion({
|
|
@@ -15785,9 +15809,9 @@ Should this be kept or archived?`,
|
|
|
15785
15809
|
}
|
|
15786
15810
|
};
|
|
15787
15811
|
}
|
|
15788
|
-
function ageDays(
|
|
15789
|
-
if (!Number.isFinite(
|
|
15790
|
-
return Math.max(0, Math.floor((now -
|
|
15812
|
+
function ageDays(activityAt, now) {
|
|
15813
|
+
if (!Number.isFinite(activityAt) || !Number.isFinite(now)) return 0;
|
|
15814
|
+
return Math.max(0, Math.floor((now - activityAt) / (24 * 60 * 60 * 1e3)));
|
|
15791
15815
|
}
|
|
15792
15816
|
function parseVerdict(parsed) {
|
|
15793
15817
|
if (typeof parsed !== "object" || parsed === null) return null;
|
|
@@ -15840,7 +15864,7 @@ function createDecaySweeper(options) {
|
|
|
15840
15864
|
if (!classifier || !isBorderline(input)) return ruleVerdict;
|
|
15841
15865
|
if (input.id) {
|
|
15842
15866
|
const cached = classifierCache.get(input.id);
|
|
15843
|
-
if (cached && cached.
|
|
15867
|
+
if (cached && cached.activityAt === lastActivityAt(input)) return cached.verdict;
|
|
15844
15868
|
}
|
|
15845
15869
|
if (sweep.classifierCalls >= maxClassifierCalls) {
|
|
15846
15870
|
if (!sweep.ceilingLogged) {
|
|
@@ -15854,7 +15878,7 @@ function createDecaySweeper(options) {
|
|
|
15854
15878
|
sweep.classifierCalls++;
|
|
15855
15879
|
try {
|
|
15856
15880
|
const verdict = await classifier.classify(input, ruleVerdict, now);
|
|
15857
|
-
if (input.id) classifierCache.set(input.id, {
|
|
15881
|
+
if (input.id) classifierCache.set(input.id, { activityAt: lastActivityAt(input), verdict });
|
|
15858
15882
|
return verdict;
|
|
15859
15883
|
} catch (err) {
|
|
15860
15884
|
getLogger().warn(
|
|
@@ -17581,7 +17605,10 @@ function reviewedMemoryIdsSignature(ids) {
|
|
|
17581
17605
|
return [...new Set(ids)].sort().join("\n");
|
|
17582
17606
|
}
|
|
17583
17607
|
function facetsSignature(facets) {
|
|
17584
|
-
return
|
|
17608
|
+
return [
|
|
17609
|
+
JSON.stringify(FACET_SYSTEM_PROMPT),
|
|
17610
|
+
...facets.map((f) => JSON.stringify([f.key, f.label, f.query, f.guidance, facetResponseSchema(f.key)])).sort()
|
|
17611
|
+
].join("\n");
|
|
17585
17612
|
}
|
|
17586
17613
|
function trendsEqual(a, b) {
|
|
17587
17614
|
if (!a) return false;
|
|
@@ -17803,7 +17830,7 @@ var FACET_SYSTEM_PROMPT = `You are writing one section of a person's shareable p
|
|
|
17803
17830
|
Rules:
|
|
17804
17831
|
- Ground every claim in the supplied memories \u2014 never invent, infer beyond, or embellish what they support.
|
|
17805
17832
|
- If the memories don't cover this section, return an empty summary with hasEvidence=false. Do not pad or guess.
|
|
17806
|
-
- Write in
|
|
17833
|
+
- 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.
|
|
17807
17834
|
- Be concise and specific; no preamble, hedging, or meta-commentary.
|
|
17808
17835
|
- Respond as JSON in exactly the shape the user turn states, with no extra fields.`;
|
|
17809
17836
|
function buildFacetUserInstructions(facet) {
|
|
@@ -18472,6 +18499,37 @@ async function assembleMemoryContext(options) {
|
|
|
18472
18499
|
import { Q as Q8 } from "@nozbe/watermelondb";
|
|
18473
18500
|
var MAX_JOBS_PER_PASS = 3;
|
|
18474
18501
|
var MAX_ATTEMPTS = 3;
|
|
18502
|
+
var MAX_FAILED_SESSIONS = 3;
|
|
18503
|
+
var MIN_FAILED_SESSION_GAP_MS = 60 * 60 * 1e3;
|
|
18504
|
+
var REQUEST_REJECTED_STATUSES = /* @__PURE__ */ new Set([400, 404, 413, 422]);
|
|
18505
|
+
var CONTENT_FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
18506
|
+
"empty-content",
|
|
18507
|
+
"invalid-json",
|
|
18508
|
+
"null-completion",
|
|
18509
|
+
"body-parse-failed"
|
|
18510
|
+
]);
|
|
18511
|
+
var BACKOFF_ALLOWANCE_MS = 2100;
|
|
18512
|
+
var RETAIN_BUDGET_MS = 12e4;
|
|
18513
|
+
function defaultBatchTimeoutMs(extract) {
|
|
18514
|
+
const attempts = Math.max(1, extract.maxAttempts ?? 3);
|
|
18515
|
+
const calls = (extract.timeoutMs ?? 6e4) * attempts + BACKOFF_ALLOWANCE_MS * (attempts - 1);
|
|
18516
|
+
const extraction = extract.totalTimeoutMs !== void 0 ? Math.min(extract.totalTimeoutMs, calls) : calls;
|
|
18517
|
+
return extraction + RETAIN_BUDGET_MS;
|
|
18518
|
+
}
|
|
18519
|
+
var BatchFailureError = class extends Error {
|
|
18520
|
+
constructor(message, terminal) {
|
|
18521
|
+
super(message);
|
|
18522
|
+
this.terminal = terminal;
|
|
18523
|
+
}
|
|
18524
|
+
};
|
|
18525
|
+
var AccountFailureError = class extends Error {
|
|
18526
|
+
};
|
|
18527
|
+
var LockedSourcesError = class extends Error {
|
|
18528
|
+
constructor(persistentIds) {
|
|
18529
|
+
super("Source messages are locked; retained for retry");
|
|
18530
|
+
this.persistentIds = persistentIds;
|
|
18531
|
+
}
|
|
18532
|
+
};
|
|
18475
18533
|
function idsOf(job) {
|
|
18476
18534
|
return JSON.parse(String(job._getRaw("message_ids")));
|
|
18477
18535
|
}
|
|
@@ -18479,6 +18537,16 @@ function seqOf(job) {
|
|
|
18479
18537
|
const raw = job._getRaw("watermark_seq");
|
|
18480
18538
|
return typeof raw === "number" && raw > 0 ? raw : void 0;
|
|
18481
18539
|
}
|
|
18540
|
+
function failedSessionsOf(job, head) {
|
|
18541
|
+
if (job._getRaw("failed_head") !== head) return 0;
|
|
18542
|
+
const raw = job._getRaw("failed_sessions");
|
|
18543
|
+
return typeof raw === "number" && raw > 0 ? raw : 0;
|
|
18544
|
+
}
|
|
18545
|
+
function failedAtOf(job, head) {
|
|
18546
|
+
if (job._getRaw("failed_head") !== head) return void 0;
|
|
18547
|
+
const raw = job._getRaw("failed_at");
|
|
18548
|
+
return typeof raw === "number" ? raw : void 0;
|
|
18549
|
+
}
|
|
18482
18550
|
function createDurableAutoExtractor(options) {
|
|
18483
18551
|
const vault = options.retainCtx.vaultCtx;
|
|
18484
18552
|
const database = vault.database;
|
|
@@ -18501,6 +18569,9 @@ function createDurableAutoExtractor(options) {
|
|
|
18501
18569
|
let writes = Promise.resolve();
|
|
18502
18570
|
let storeFailures = 0;
|
|
18503
18571
|
const attempts = /* @__PURE__ */ new Map();
|
|
18572
|
+
const sessionFailures = /* @__PURE__ */ new Map();
|
|
18573
|
+
const skippedThisSession = /* @__PURE__ */ new Set();
|
|
18574
|
+
const clock = options.now ?? Date.now;
|
|
18504
18575
|
const reportError = (error, conversationId) => {
|
|
18505
18576
|
try {
|
|
18506
18577
|
options.onError?.(error instanceof Error ? error : new Error(String(error)), conversationId);
|
|
@@ -18529,6 +18600,7 @@ function createDurableAutoExtractor(options) {
|
|
|
18529
18600
|
}
|
|
18530
18601
|
async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
|
|
18531
18602
|
let watchdog;
|
|
18603
|
+
let cancelled = false;
|
|
18532
18604
|
const model = options.modelForScope?.(jobScope) ?? options.extract.model;
|
|
18533
18605
|
try {
|
|
18534
18606
|
return await Promise.race([
|
|
@@ -18539,7 +18611,7 @@ function createDurableAutoExtractor(options) {
|
|
|
18539
18611
|
...options.retainCtx,
|
|
18540
18612
|
vaultCtx: {
|
|
18541
18613
|
...vault,
|
|
18542
|
-
canWrite: async () => !disposed && await storage.conversationsCollection.query(Q8.where("conversation_id", conversationId), Q8.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(Q8.where("conversation_id", conversationId), Q8.where("id", Q8.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed
|
|
18614
|
+
canWrite: async () => !disposed && !cancelled && await storage.conversationsCollection.query(Q8.where("conversation_id", conversationId), Q8.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(Q8.where("conversation_id", conversationId), Q8.where("id", Q8.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed && !cancelled
|
|
18543
18615
|
}
|
|
18544
18616
|
},
|
|
18545
18617
|
// The model follows the job's scope, not the mode alive at drain time.
|
|
@@ -18559,14 +18631,116 @@ function createDurableAutoExtractor(options) {
|
|
|
18559
18631
|
new Promise((_resolve, reject) => {
|
|
18560
18632
|
watchdog = setTimeout(
|
|
18561
18633
|
() => reject(new Error("Extraction did not settle in time; retained for retry")),
|
|
18562
|
-
options.batchTimeoutMs ??
|
|
18634
|
+
options.batchTimeoutMs ?? defaultBatchTimeoutMs(options.extract)
|
|
18563
18635
|
);
|
|
18564
18636
|
})
|
|
18565
18637
|
]);
|
|
18566
18638
|
} finally {
|
|
18639
|
+
cancelled = true;
|
|
18567
18640
|
if (watchdog !== void 0) clearTimeout(watchdog);
|
|
18568
18641
|
}
|
|
18569
18642
|
}
|
|
18643
|
+
async function acknowledge(job, ids, loaded, abandoned) {
|
|
18644
|
+
attempts.delete(job.id);
|
|
18645
|
+
sessionFailures.delete(job.id);
|
|
18646
|
+
skippedThisSession.delete(job.id);
|
|
18647
|
+
const sequences = /* @__PURE__ */ new Map();
|
|
18648
|
+
for (const message of loaded)
|
|
18649
|
+
if (message && message.messageId > 0) sequences.set(message.uniqueId, message.messageId);
|
|
18650
|
+
await database.write(async () => {
|
|
18651
|
+
const current = idsOf(job);
|
|
18652
|
+
const acknowledged = ids.filter((id) => current.includes(id));
|
|
18653
|
+
if (!acknowledged.length) return;
|
|
18654
|
+
const done = new Set(acknowledged);
|
|
18655
|
+
const remaining = current.filter((id) => !done.has(id));
|
|
18656
|
+
await job.update((r) => {
|
|
18657
|
+
r._setRaw(
|
|
18658
|
+
"message_ids",
|
|
18659
|
+
JSON.stringify(
|
|
18660
|
+
remaining.length ? [...abandoned ? [] : acknowledged.slice(-2), ...remaining] : []
|
|
18661
|
+
)
|
|
18662
|
+
);
|
|
18663
|
+
const newest = acknowledged[acknowledged.length - 1];
|
|
18664
|
+
r._setRaw("watermark", newest);
|
|
18665
|
+
const sequence = sequences.get(newest);
|
|
18666
|
+
if (sequence !== void 0) {
|
|
18667
|
+
const prior = seqOf(job);
|
|
18668
|
+
r._setRaw("watermark_seq", prior === void 0 ? sequence : Math.max(prior, sequence));
|
|
18669
|
+
}
|
|
18670
|
+
r._setRaw("failed_sessions", abandoned ? MAX_FAILED_SESSIONS : null);
|
|
18671
|
+
r._setRaw("failed_head", abandoned ? newest : null);
|
|
18672
|
+
r._setRaw("failed_at", null);
|
|
18673
|
+
});
|
|
18674
|
+
});
|
|
18675
|
+
}
|
|
18676
|
+
async function recordFailure(job, ids, loaded, error, conversationId) {
|
|
18677
|
+
const head = ids[0];
|
|
18678
|
+
if (!head || !loaded.some(Boolean)) return false;
|
|
18679
|
+
if (error instanceof AccountFailureError) {
|
|
18680
|
+
skippedThisSession.add(job.id);
|
|
18681
|
+
return false;
|
|
18682
|
+
}
|
|
18683
|
+
const counted = error instanceof BatchFailureError || error instanceof LockedSourcesError && error.persistentIds.length > 0;
|
|
18684
|
+
if (!counted) return false;
|
|
18685
|
+
const prior = sessionFailures.get(job.id);
|
|
18686
|
+
const count = prior?.head === head ? prior.count + 1 : 1;
|
|
18687
|
+
sessionFailures.set(job.id, { head, count });
|
|
18688
|
+
const terminal = error instanceof BatchFailureError && error.terminal;
|
|
18689
|
+
if (!terminal && count < MAX_ATTEMPTS) return false;
|
|
18690
|
+
skippedThisSession.add(job.id);
|
|
18691
|
+
const now = clock();
|
|
18692
|
+
const lastCounted = failedAtOf(job, head);
|
|
18693
|
+
if (lastCounted !== void 0 && now - lastCounted < MIN_FAILED_SESSION_GAP_MS) return false;
|
|
18694
|
+
const failures = failedSessionsOf(job, head) + 1;
|
|
18695
|
+
if (failures < MAX_FAILED_SESSIONS) {
|
|
18696
|
+
await database.write(
|
|
18697
|
+
() => job.update((r) => {
|
|
18698
|
+
r._setRaw("failed_sessions", failures);
|
|
18699
|
+
r._setRaw("failed_head", head);
|
|
18700
|
+
r._setRaw("failed_at", now);
|
|
18701
|
+
})
|
|
18702
|
+
);
|
|
18703
|
+
return false;
|
|
18704
|
+
}
|
|
18705
|
+
if (error instanceof LockedSourcesError) {
|
|
18706
|
+
const dropped = new Set(error.persistentIds);
|
|
18707
|
+
let newest;
|
|
18708
|
+
for (const message of loaded)
|
|
18709
|
+
if (message && dropped.has(message.uniqueId) && message.messageId > (newest?.seq ?? 0))
|
|
18710
|
+
newest = { id: message.uniqueId, seq: message.messageId };
|
|
18711
|
+
const advance = newest !== void 0 && newest.seq > (seqOf(job) ?? 0) ? newest : void 0;
|
|
18712
|
+
await database.write(
|
|
18713
|
+
() => job.update((r) => {
|
|
18714
|
+
r._setRaw("message_ids", JSON.stringify(idsOf(job).filter((id) => !dropped.has(id))));
|
|
18715
|
+
if (advance) {
|
|
18716
|
+
r._setRaw("watermark", advance.id);
|
|
18717
|
+
r._setRaw("watermark_seq", advance.seq);
|
|
18718
|
+
}
|
|
18719
|
+
r._setRaw("failed_sessions", advance ? MAX_FAILED_SESSIONS : null);
|
|
18720
|
+
r._setRaw("failed_head", advance ? advance.id : null);
|
|
18721
|
+
r._setRaw("failed_at", null);
|
|
18722
|
+
})
|
|
18723
|
+
);
|
|
18724
|
+
attempts.delete(job.id);
|
|
18725
|
+
sessionFailures.delete(job.id);
|
|
18726
|
+
skippedThisSession.delete(job.id);
|
|
18727
|
+
reportError(
|
|
18728
|
+
new Error(
|
|
18729
|
+
`Dropped ${dropped.size} source id(s) that stayed locked for ${failures} sessions to unblock extraction`
|
|
18730
|
+
),
|
|
18731
|
+
conversationId
|
|
18732
|
+
);
|
|
18733
|
+
return true;
|
|
18734
|
+
}
|
|
18735
|
+
await acknowledge(job, ids, loaded, true);
|
|
18736
|
+
reportError(
|
|
18737
|
+
new Error(
|
|
18738
|
+
`Abandoned an extraction batch of ${ids.length} source id(s) after it failed in ${failures} sessions`
|
|
18739
|
+
),
|
|
18740
|
+
conversationId
|
|
18741
|
+
);
|
|
18742
|
+
return true;
|
|
18743
|
+
}
|
|
18570
18744
|
async function drain() {
|
|
18571
18745
|
if (disposed || running) return;
|
|
18572
18746
|
running = true;
|
|
@@ -18581,21 +18755,23 @@ function createDurableAutoExtractor(options) {
|
|
|
18581
18755
|
for (const job of pending) {
|
|
18582
18756
|
if (disposed) break;
|
|
18583
18757
|
const attempted = attempts.get(job.id) ?? 0;
|
|
18584
|
-
if (attempted >= MAX_ATTEMPTS) continue;
|
|
18758
|
+
if (attempted >= MAX_ATTEMPTS || skippedThisSession.has(job.id)) continue;
|
|
18585
18759
|
if (processed >= MAX_JOBS_PER_PASS) {
|
|
18586
18760
|
scheduleAfterSuccess = true;
|
|
18587
18761
|
break;
|
|
18588
18762
|
}
|
|
18589
18763
|
processed++;
|
|
18590
18764
|
const conversationId = String(job._getRaw("conversation_id"));
|
|
18765
|
+
let ids = [];
|
|
18766
|
+
let loaded = [];
|
|
18591
18767
|
try {
|
|
18592
18768
|
const conversations = await storage.conversationsCollection.query(Q8.where("conversation_id", conversationId), Q8.where("is_deleted", false)).fetchCount();
|
|
18593
18769
|
if (!conversations) {
|
|
18594
18770
|
await database.write(() => job.destroyPermanently());
|
|
18595
18771
|
continue;
|
|
18596
18772
|
}
|
|
18597
|
-
|
|
18598
|
-
|
|
18773
|
+
ids = idsOf(job).slice(0, 20);
|
|
18774
|
+
loaded = await Promise.all(ids.map((id) => getMessageOp(storage, id)));
|
|
18599
18775
|
const missing = ids.filter((_id, index) => loaded[index] === null);
|
|
18600
18776
|
if (missing.length) {
|
|
18601
18777
|
if (attempted < MAX_ATTEMPTS - 1)
|
|
@@ -18619,17 +18795,21 @@ function createDurableAutoExtractor(options) {
|
|
|
18619
18795
|
);
|
|
18620
18796
|
continue;
|
|
18621
18797
|
}
|
|
18622
|
-
|
|
18623
|
-
|
|
18624
|
-
|
|
18625
|
-
|
|
18798
|
+
const locked = loaded.filter((message) => message && isEncrypted(message.content));
|
|
18799
|
+
if (locked.length) {
|
|
18800
|
+
throw new LockedSourcesError(
|
|
18801
|
+
locked.flatMap(
|
|
18802
|
+
(message) => message.decryptionStatus === "auth_mismatch" || message.decryptionStatus === "invalid_payload" ? [message.uniqueId] : []
|
|
18803
|
+
)
|
|
18804
|
+
);
|
|
18626
18805
|
}
|
|
18627
18806
|
const messages = loaded.flatMap(
|
|
18628
18807
|
(m) => m && m.conversationId === conversationId && (m.role === "user" || m.role === "assistant") ? [{ id: m.uniqueId, role: m.role, content: m.content }] : []
|
|
18629
18808
|
);
|
|
18630
18809
|
let success = messages.length === 0;
|
|
18810
|
+
let result;
|
|
18631
18811
|
if (messages.length) {
|
|
18632
|
-
|
|
18812
|
+
result = await extractBatch(
|
|
18633
18813
|
messages,
|
|
18634
18814
|
conversationId,
|
|
18635
18815
|
ids,
|
|
@@ -18639,41 +18819,35 @@ function createDurableAutoExtractor(options) {
|
|
|
18639
18819
|
success = result.failedCount === 0 && result.outcome !== "empty-after-retry";
|
|
18640
18820
|
options.onTurnComplete?.(result);
|
|
18641
18821
|
}
|
|
18642
|
-
if (!success)
|
|
18643
|
-
|
|
18644
|
-
|
|
18645
|
-
|
|
18646
|
-
|
|
18647
|
-
|
|
18648
|
-
|
|
18649
|
-
|
|
18650
|
-
const acknowledged = ids.filter((id) => current.includes(id));
|
|
18651
|
-
if (!acknowledged.length) return;
|
|
18652
|
-
const done = new Set(acknowledged);
|
|
18653
|
-
const remaining = current.filter((id) => !done.has(id));
|
|
18654
|
-
if (remaining.length) {
|
|
18655
|
-
await job.update(
|
|
18656
|
-
(r) => r._setRaw("message_ids", JSON.stringify([...acknowledged.slice(-2), ...remaining]))
|
|
18657
|
-
);
|
|
18658
|
-
} else await job.update((r) => r._setRaw("message_ids", "[]"));
|
|
18659
|
-
const newest = acknowledged[acknowledged.length - 1];
|
|
18660
|
-
await job.update((r) => {
|
|
18661
|
-
r._setRaw("watermark", newest);
|
|
18662
|
-
const sequence = sequences.get(newest);
|
|
18663
|
-
if (sequence !== void 0) {
|
|
18664
|
-
const prior = seqOf(job);
|
|
18665
|
-
r._setRaw(
|
|
18666
|
-
"watermark_seq",
|
|
18667
|
-
prior === void 0 ? sequence : Math.max(prior, sequence)
|
|
18822
|
+
if (!success) {
|
|
18823
|
+
const failure = result?.failure;
|
|
18824
|
+
if (failure?.reason === "http-terminal") {
|
|
18825
|
+
const status = failure.httpStatus;
|
|
18826
|
+
if (status !== void 0 && REQUEST_REJECTED_STATUSES.has(status))
|
|
18827
|
+
throw new BatchFailureError(
|
|
18828
|
+
`Extraction rejected the batch (HTTP ${status}); not retried this session`,
|
|
18829
|
+
true
|
|
18668
18830
|
);
|
|
18669
|
-
|
|
18670
|
-
|
|
18671
|
-
|
|
18831
|
+
throw new AccountFailureError(
|
|
18832
|
+
`Extraction refused for the account (HTTP ${status ?? "unknown"}); retried next session`
|
|
18833
|
+
);
|
|
18834
|
+
}
|
|
18835
|
+
if ((result?.failedCount ?? 0) > 0 || failure !== void 0 && CONTENT_FAILURE_REASONS.has(failure.reason))
|
|
18836
|
+
throw new BatchFailureError("Extraction batch incomplete; retained for retry", false);
|
|
18837
|
+
throw new Error("Extraction batch incomplete; retained for retry");
|
|
18838
|
+
}
|
|
18839
|
+
await acknowledge(job, ids, loaded, false);
|
|
18672
18840
|
scheduleAfterSuccess = true;
|
|
18673
18841
|
} catch (error) {
|
|
18674
18842
|
attempts.set(job.id, attempted + 1);
|
|
18675
18843
|
retry = true;
|
|
18676
18844
|
reportError(error, conversationId);
|
|
18845
|
+
try {
|
|
18846
|
+
if (await recordFailure(job, ids, loaded, error, conversationId))
|
|
18847
|
+
scheduleAfterSuccess = true;
|
|
18848
|
+
} catch (recordError) {
|
|
18849
|
+
reportError(recordError, conversationId);
|
|
18850
|
+
}
|
|
18677
18851
|
}
|
|
18678
18852
|
}
|
|
18679
18853
|
} catch (error) {
|
|
@@ -18743,7 +18917,7 @@ function createDurableAutoExtractor(options) {
|
|
|
18743
18917
|
const start = boundary >= 0 ? boundary + 1 : Math.max(0, ids.length - Math.max(1, options.windowSize ?? 6));
|
|
18744
18918
|
if (start >= ids.length) return;
|
|
18745
18919
|
const ownWatermark = job?._getRaw("watermark");
|
|
18746
|
-
const atOwnWatermark = !!job && boundary >= 0 && (ids[boundary] === ownWatermark || sequences.get(ids[boundary]) !== void 0 && sequences.get(ids[boundary]) === seqOf(job));
|
|
18920
|
+
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));
|
|
18747
18921
|
const overlapStart = atOwnWatermark ? Math.max(0, boundary - 1) : start;
|
|
18748
18922
|
const fresh = ids.slice(overlapStart).filter((id) => !foreignSources.has(id));
|
|
18749
18923
|
if (!fresh.length) return;
|
|
@@ -19190,6 +19364,9 @@ var MANUAL_FACT_TYPES = [
|
|
|
19190
19364
|
function normalizeManualFactType(value) {
|
|
19191
19365
|
return typeof value === "string" && MANUAL_FACT_TYPES.includes(value) ? value : void 0;
|
|
19192
19366
|
}
|
|
19367
|
+
function isSharedScope(scope) {
|
|
19368
|
+
return scope === "shared";
|
|
19369
|
+
}
|
|
19193
19370
|
async function notifyWritten(options, input, outcome) {
|
|
19194
19371
|
try {
|
|
19195
19372
|
await options?.onWritten?.({ input, outcome });
|
|
@@ -19258,14 +19435,17 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
|
|
|
19258
19435
|
try {
|
|
19259
19436
|
const isUpdate = !!id;
|
|
19260
19437
|
let previousContent;
|
|
19438
|
+
const scope = options?.scope ?? "private";
|
|
19261
19439
|
if (isUpdate) {
|
|
19262
19440
|
const existing = await getVaultMemoryOp(vaultCtx, id);
|
|
19263
19441
|
if (!existing) {
|
|
19264
19442
|
return `Error: Memory with ID "${id}" not found. Creating a new memory instead would require a separate call without an ID.`;
|
|
19265
19443
|
}
|
|
19444
|
+
if (isSharedScope(existing.scope) !== isSharedScope(scope)) {
|
|
19445
|
+
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.`;
|
|
19446
|
+
}
|
|
19266
19447
|
previousContent = existing.content;
|
|
19267
19448
|
}
|
|
19268
|
-
const scope = options?.scope ?? "private";
|
|
19269
19449
|
const operation = {
|
|
19270
19450
|
action: isUpdate ? "update" : "add",
|
|
19271
19451
|
content,
|
|
@@ -23504,7 +23684,7 @@ __decorateClass([
|
|
|
23504
23684
|
], VaultFolder.prototype, "context", 2);
|
|
23505
23685
|
|
|
23506
23686
|
// src/lib/db/schema.ts
|
|
23507
|
-
var SDK_SCHEMA_VERSION =
|
|
23687
|
+
var SDK_SCHEMA_VERSION = 47;
|
|
23508
23688
|
var sdkSchema = appSchema2({
|
|
23509
23689
|
version: SDK_SCHEMA_VERSION,
|
|
23510
23690
|
tables: [
|
|
@@ -23520,7 +23700,11 @@ var sdkSchema = appSchema2({
|
|
|
23520
23700
|
// source. `watermark` alone is an id, and deleting that message erased
|
|
23521
23701
|
// the anchor — see the column note in extractionJobs/models.ts.
|
|
23522
23702
|
{ name: "watermark_seq", type: "number", isOptional: true },
|
|
23523
|
-
{ name: "folder_id", type: "string", isOptional: true }
|
|
23703
|
+
{ name: "folder_id", type: "string", isOptional: true },
|
|
23704
|
+
// Poison accounting for the head batch; see extractionJobs/models.ts.
|
|
23705
|
+
{ name: "failed_sessions", type: "number", isOptional: true },
|
|
23706
|
+
{ name: "failed_head", type: "string", isOptional: true },
|
|
23707
|
+
{ name: "failed_at", type: "number", isOptional: true }
|
|
23524
23708
|
]
|
|
23525
23709
|
}),
|
|
23526
23710
|
// Chat storage tables
|
|
@@ -24544,6 +24728,22 @@ var sdkMigrations = schemaMigrations2({
|
|
|
24544
24728
|
]
|
|
24545
24729
|
})
|
|
24546
24730
|
]
|
|
24731
|
+
},
|
|
24732
|
+
// v46 -> v47: persisted poison count (and when it was last counted) for a
|
|
24733
|
+
// durable-extraction job's head batch. NULL = never failed, which is right
|
|
24734
|
+
// for every existing row.
|
|
24735
|
+
{
|
|
24736
|
+
toVersion: 47,
|
|
24737
|
+
steps: [
|
|
24738
|
+
addColumns2({
|
|
24739
|
+
table: "memory_extraction_jobs",
|
|
24740
|
+
columns: [
|
|
24741
|
+
{ name: "failed_sessions", type: "number", isOptional: true },
|
|
24742
|
+
{ name: "failed_head", type: "string", isOptional: true },
|
|
24743
|
+
{ name: "failed_at", type: "number", isOptional: true }
|
|
24744
|
+
]
|
|
24745
|
+
})
|
|
24746
|
+
]
|
|
24547
24747
|
}
|
|
24548
24748
|
]
|
|
24549
24749
|
});
|