@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/react/index.cjs
CHANGED
|
@@ -13014,8 +13014,42 @@ async function vaultMemoryToStored(memory, walletAddress, signMessage, embeddedW
|
|
|
13014
13014
|
}
|
|
13015
13015
|
return raw;
|
|
13016
13016
|
}
|
|
13017
|
+
function populateNewVaultMemory(record, ctx, opts, encryptedContent) {
|
|
13018
|
+
record._setRaw("content", encryptedContent);
|
|
13019
|
+
record._setRaw("scope", opts.scope ?? "private");
|
|
13020
|
+
record._setRaw("folder_id", opts.folderId ?? null);
|
|
13021
|
+
record._setRaw("user_id", ctx.userId ?? null);
|
|
13022
|
+
record._setRaw("is_deleted", false);
|
|
13023
|
+
if (opts.embedding !== void 0) {
|
|
13024
|
+
record._setRaw("embedding", opts.embedding);
|
|
13025
|
+
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
13026
|
+
}
|
|
13027
|
+
if (opts.sourceChunkIds !== void 0) {
|
|
13028
|
+
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
13029
|
+
}
|
|
13030
|
+
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
13031
|
+
record._setRaw("source", opts.source ?? "manual");
|
|
13032
|
+
if (opts.eventTime) {
|
|
13033
|
+
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
13034
|
+
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
13035
|
+
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
13036
|
+
}
|
|
13037
|
+
if (opts.factType !== void 0) {
|
|
13038
|
+
record._setRaw("fact_type", opts.factType);
|
|
13039
|
+
}
|
|
13040
|
+
if (opts.trustTier !== void 0) {
|
|
13041
|
+
record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
13042
|
+
}
|
|
13043
|
+
record._setRaw("visibility", opts.visibility ?? "private");
|
|
13044
|
+
record._setRaw(
|
|
13045
|
+
"published_at",
|
|
13046
|
+
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
13047
|
+
);
|
|
13048
|
+
if (opts.geohash !== void 0) {
|
|
13049
|
+
record._setRaw("geohash", opts.geohash);
|
|
13050
|
+
}
|
|
13051
|
+
}
|
|
13017
13052
|
async function createVaultMemoryOp(ctx, opts) {
|
|
13018
|
-
const scope = opts.scope ?? "private";
|
|
13019
13053
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
13020
13054
|
opts.content,
|
|
13021
13055
|
ctx.walletAddress,
|
|
@@ -13025,47 +13059,14 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
13025
13059
|
const created = await ctx.database.write(async () => {
|
|
13026
13060
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
13027
13061
|
throw new Error("Memory source is no longer eligible");
|
|
13028
|
-
return ctx.vaultMemoryCollection.create(
|
|
13029
|
-
record
|
|
13030
|
-
|
|
13031
|
-
record._setRaw("folder_id", opts.folderId ?? null);
|
|
13032
|
-
record._setRaw("user_id", ctx.userId ?? null);
|
|
13033
|
-
record._setRaw("is_deleted", false);
|
|
13034
|
-
if (opts.embedding !== void 0) {
|
|
13035
|
-
record._setRaw("embedding", opts.embedding);
|
|
13036
|
-
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
13037
|
-
}
|
|
13038
|
-
if (opts.sourceChunkIds !== void 0) {
|
|
13039
|
-
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
13040
|
-
}
|
|
13041
|
-
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
13042
|
-
record._setRaw("source", opts.source ?? "manual");
|
|
13043
|
-
if (opts.eventTime) {
|
|
13044
|
-
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
13045
|
-
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
13046
|
-
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
13047
|
-
}
|
|
13048
|
-
if (opts.factType !== void 0) {
|
|
13049
|
-
record._setRaw("fact_type", opts.factType);
|
|
13050
|
-
}
|
|
13051
|
-
if (opts.trustTier !== void 0) {
|
|
13052
|
-
record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
13053
|
-
}
|
|
13054
|
-
record._setRaw("visibility", opts.visibility ?? "private");
|
|
13055
|
-
record._setRaw(
|
|
13056
|
-
"published_at",
|
|
13057
|
-
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
13058
|
-
);
|
|
13059
|
-
if (opts.geohash !== void 0) {
|
|
13060
|
-
record._setRaw("geohash", opts.geohash);
|
|
13061
|
-
}
|
|
13062
|
-
});
|
|
13062
|
+
return ctx.vaultMemoryCollection.create(
|
|
13063
|
+
(record) => populateNewVaultMemory(record, ctx, opts, encryptedContent)
|
|
13064
|
+
);
|
|
13063
13065
|
});
|
|
13064
13066
|
return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
13065
13067
|
}
|
|
13066
13068
|
async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
13067
13069
|
if (!targetId) return { created: null, retired: false };
|
|
13068
|
-
const scope = opts.scope ?? "private";
|
|
13069
13070
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
13070
13071
|
opts.content,
|
|
13071
13072
|
ctx.walletAddress,
|
|
@@ -13083,27 +13084,9 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
|
13083
13084
|
return;
|
|
13084
13085
|
}
|
|
13085
13086
|
if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target)) return;
|
|
13086
|
-
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
13087
|
-
record
|
|
13088
|
-
|
|
13089
|
-
record._setRaw("folder_id", opts.folderId ?? null);
|
|
13090
|
-
record._setRaw("user_id", ctx.userId ?? null);
|
|
13091
|
-
record._setRaw("is_deleted", false);
|
|
13092
|
-
if (opts.embedding !== void 0) {
|
|
13093
|
-
record._setRaw("embedding", opts.embedding);
|
|
13094
|
-
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
13095
|
-
}
|
|
13096
|
-
if (opts.sourceChunkIds !== void 0) {
|
|
13097
|
-
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
13098
|
-
}
|
|
13099
|
-
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
13100
|
-
record._setRaw("source", opts.source ?? "manual");
|
|
13101
|
-
if (opts.eventTime) {
|
|
13102
|
-
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
13103
|
-
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
13104
|
-
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
13105
|
-
}
|
|
13106
|
-
});
|
|
13087
|
+
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
13088
|
+
(record) => populateNewVaultMemory(record, ctx, opts, encryptedContent)
|
|
13089
|
+
);
|
|
13107
13090
|
await target.update((r) => {
|
|
13108
13091
|
r._setRaw("superseded_by", createdRecord.id);
|
|
13109
13092
|
r._setRaw("superseded_at", Date.now());
|
|
@@ -13183,41 +13166,9 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
13183
13166
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
13184
13167
|
throw new Error("Memory source is no longer eligible");
|
|
13185
13168
|
const prepared = optionsArray.map(
|
|
13186
|
-
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
13187
|
-
record
|
|
13188
|
-
|
|
13189
|
-
record._setRaw("folder_id", opts.folderId ?? null);
|
|
13190
|
-
record._setRaw("user_id", ctx.userId ?? null);
|
|
13191
|
-
record._setRaw("is_deleted", false);
|
|
13192
|
-
if (optionsArray[i].embedding !== void 0) {
|
|
13193
|
-
record._setRaw("embedding", optionsArray[i].embedding);
|
|
13194
|
-
record._setRaw("embedding_model", optionsArray[i].embeddingModel ?? null);
|
|
13195
|
-
}
|
|
13196
|
-
if (opts.sourceChunkIds !== void 0) {
|
|
13197
|
-
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
13198
|
-
}
|
|
13199
|
-
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
13200
|
-
record._setRaw("source", opts.source ?? "manual");
|
|
13201
|
-
if (opts.eventTime) {
|
|
13202
|
-
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
13203
|
-
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
13204
|
-
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
13205
|
-
}
|
|
13206
|
-
if (opts.factType !== void 0) {
|
|
13207
|
-
record._setRaw("fact_type", opts.factType);
|
|
13208
|
-
}
|
|
13209
|
-
if (opts.trustTier !== void 0) {
|
|
13210
|
-
record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
13211
|
-
}
|
|
13212
|
-
record._setRaw("visibility", opts.visibility ?? "private");
|
|
13213
|
-
record._setRaw(
|
|
13214
|
-
"published_at",
|
|
13215
|
-
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
13216
|
-
);
|
|
13217
|
-
if (opts.geohash !== void 0) {
|
|
13218
|
-
record._setRaw("geohash", opts.geohash);
|
|
13219
|
-
}
|
|
13220
|
-
})
|
|
13169
|
+
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
13170
|
+
(record) => populateNewVaultMemory(record, ctx, opts, encryptedContents[i])
|
|
13171
|
+
)
|
|
13221
13172
|
);
|
|
13222
13173
|
await ctx.database.batch(...prepared);
|
|
13223
13174
|
return prepared;
|
|
@@ -14083,21 +14034,73 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
|
14083
14034
|
return false;
|
|
14084
14035
|
}
|
|
14085
14036
|
}
|
|
14086
|
-
async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel) {
|
|
14037
|
+
async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel, expected) {
|
|
14087
14038
|
try {
|
|
14088
14039
|
const record = await ctx.vaultMemoryCollection.find(id);
|
|
14089
14040
|
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
|
|
14041
|
+
const readUpdatedAt = record.updatedAt.getTime();
|
|
14042
|
+
const readStoredContent = record._getRaw("content");
|
|
14043
|
+
if (expected?.updatedAt !== void 0 && expected.updatedAt !== readUpdatedAt) return false;
|
|
14044
|
+
if (expected?.content !== void 0) {
|
|
14045
|
+
const current = await vaultMemoryToStored(
|
|
14046
|
+
record,
|
|
14047
|
+
ctx.walletAddress,
|
|
14048
|
+
ctx.signMessage,
|
|
14049
|
+
ctx.embeddedWalletSigner
|
|
14050
|
+
);
|
|
14051
|
+
if (current.content !== expected.content) return false;
|
|
14052
|
+
}
|
|
14053
|
+
let written = false;
|
|
14090
14054
|
await ctx.database.write(async () => {
|
|
14055
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return;
|
|
14056
|
+
const originalUpdatedAt = record.updatedAt.getTime();
|
|
14057
|
+
if (originalUpdatedAt !== readUpdatedAt || record._getRaw("content") !== readStoredContent)
|
|
14058
|
+
return;
|
|
14091
14059
|
await record.update((r) => {
|
|
14092
14060
|
r._setRaw("embedding", embedding);
|
|
14093
14061
|
r._setRaw("embedding_model", embeddingModel);
|
|
14062
|
+
r._setRaw("updated_at", originalUpdatedAt);
|
|
14094
14063
|
});
|
|
14064
|
+
written = true;
|
|
14095
14065
|
});
|
|
14096
|
-
return
|
|
14066
|
+
return written;
|
|
14097
14067
|
} catch {
|
|
14098
14068
|
return false;
|
|
14099
14069
|
}
|
|
14100
14070
|
}
|
|
14071
|
+
function normalizeForDedupe(content) {
|
|
14072
|
+
return content.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
|
|
14073
|
+
}
|
|
14074
|
+
async function findQuarantinedDuplicateOp(ctx, content, sourceIds, where) {
|
|
14075
|
+
const wanted = [...new Set(sourceIds)].sort().join("\0");
|
|
14076
|
+
const target = normalizeForDedupe(content);
|
|
14077
|
+
const rows = await ctx.vaultMemoryCollection.query(
|
|
14078
|
+
import_watermelondb11.Q.where("trust_tier", "quarantined"),
|
|
14079
|
+
import_watermelondb11.Q.where("is_deleted", false),
|
|
14080
|
+
import_watermelondb11.Q.where("scope", where.scope),
|
|
14081
|
+
import_watermelondb11.Q.where("folder_id", where.folderId),
|
|
14082
|
+
...ctx.userId !== void 0 ? [import_watermelondb11.Q.where("user_id", ctx.userId)] : []
|
|
14083
|
+
).unsafeFetchRaw();
|
|
14084
|
+
for (const raw of rows) {
|
|
14085
|
+
let ids;
|
|
14086
|
+
try {
|
|
14087
|
+
ids = JSON.parse(raw.source_chunk_ids ?? "[]");
|
|
14088
|
+
} catch {
|
|
14089
|
+
continue;
|
|
14090
|
+
}
|
|
14091
|
+
if (!Array.isArray(ids)) continue;
|
|
14092
|
+
const key = [...new Set(ids.filter((id) => typeof id === "string"))].sort().join("\0");
|
|
14093
|
+
if (key !== wanted) continue;
|
|
14094
|
+
const stored = await vaultMemoryRawToStored(
|
|
14095
|
+
raw,
|
|
14096
|
+
ctx.walletAddress,
|
|
14097
|
+
ctx.signMessage,
|
|
14098
|
+
ctx.embeddedWalletSigner
|
|
14099
|
+
);
|
|
14100
|
+
if (normalizeForDedupe(stored.content) === target) return stored.uniqueId;
|
|
14101
|
+
}
|
|
14102
|
+
return null;
|
|
14103
|
+
}
|
|
14101
14104
|
|
|
14102
14105
|
// src/lib/memory/decay.ts
|
|
14103
14106
|
init_logger();
|
|
@@ -14122,6 +14125,10 @@ var DEFAULT_DECAY_POLICY = {
|
|
|
14122
14125
|
hardDeleteWindowMs: HARD_DELETE_WINDOW_MS,
|
|
14123
14126
|
pastEventGraceMs: PAST_EVENT_GRACE_MS
|
|
14124
14127
|
};
|
|
14128
|
+
function lastActivityAt(m) {
|
|
14129
|
+
const observedAt = Number.isFinite(m.lastObservedAt) ? m.lastObservedAt : m.updatedAt;
|
|
14130
|
+
return Math.max(m.updatedAt, observedAt);
|
|
14131
|
+
}
|
|
14125
14132
|
function resolvePolicy(policy) {
|
|
14126
14133
|
if (!policy) return DEFAULT_DECAY_POLICY;
|
|
14127
14134
|
return {
|
|
@@ -14161,8 +14168,7 @@ function classifyDecay(m, now, policy) {
|
|
|
14161
14168
|
if (m.eventTimeEnd < now - resolved.pastEventGraceMs) return "archive";
|
|
14162
14169
|
if (m.eventTimeEnd >= now) return "keep";
|
|
14163
14170
|
}
|
|
14164
|
-
|
|
14165
|
-
if (now - Math.max(m.updatedAt, observedAt) > ttlForType(m.factType, resolved)) return "archive";
|
|
14171
|
+
if (now - lastActivityAt(m) > ttlForType(m.factType, resolved)) return "archive";
|
|
14166
14172
|
return "keep";
|
|
14167
14173
|
}
|
|
14168
14174
|
|
|
@@ -17188,6 +17194,24 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
17188
17194
|
const tRetain = Date.now();
|
|
17189
17195
|
for (const { candidate, isQuarantined, reason, signature } of toRetain) {
|
|
17190
17196
|
try {
|
|
17197
|
+
if (isQuarantined) {
|
|
17198
|
+
const existingId = await findQuarantinedDuplicateOp(
|
|
17199
|
+
retainCtx.vaultCtx,
|
|
17200
|
+
candidate.content,
|
|
17201
|
+
candidate.sourceMessageIds,
|
|
17202
|
+
// The same defaults retain() writes the row with.
|
|
17203
|
+
{ scope: options.scope ?? "private", folderId: options.folderId ?? null }
|
|
17204
|
+
).catch(() => null);
|
|
17205
|
+
if (existingId) {
|
|
17206
|
+
quarantinedInfo.push({
|
|
17207
|
+
candidate,
|
|
17208
|
+
memoryId: existingId,
|
|
17209
|
+
reason,
|
|
17210
|
+
signature
|
|
17211
|
+
});
|
|
17212
|
+
continue;
|
|
17213
|
+
}
|
|
17214
|
+
}
|
|
17191
17215
|
const result = await retain(candidate.content, retainCtx, {
|
|
17192
17216
|
source: "auto-extracted",
|
|
17193
17217
|
sourceChunkIds: candidate.sourceMessageIds,
|
|
@@ -17638,7 +17662,7 @@ function createLlmDecayClassifier(options) {
|
|
|
17638
17662
|
if (!content || content.trim().length === 0) return ruleVerdict;
|
|
17639
17663
|
const trimmed = content.trim().slice(0, MAX_CONTENT_CHARS);
|
|
17640
17664
|
const safe = redactor ? (await redactor.redactTextAsync(trimmed)).text : trimmed;
|
|
17641
|
-
const meta = `factType: ${input.factType ?? "none"}; ageDays: ${ageDays(input
|
|
17665
|
+
const meta = `factType: ${input.factType ?? "none"}; ageDays: ${ageDays(lastActivityAt(input), now)}`;
|
|
17642
17666
|
let parsed;
|
|
17643
17667
|
try {
|
|
17644
17668
|
parsed = await callPortalJsonCompletion({
|
|
@@ -17671,9 +17695,9 @@ Should this be kept or archived?`,
|
|
|
17671
17695
|
}
|
|
17672
17696
|
};
|
|
17673
17697
|
}
|
|
17674
|
-
function ageDays(
|
|
17675
|
-
if (!Number.isFinite(
|
|
17676
|
-
return Math.max(0, Math.floor((now -
|
|
17698
|
+
function ageDays(activityAt, now) {
|
|
17699
|
+
if (!Number.isFinite(activityAt) || !Number.isFinite(now)) return 0;
|
|
17700
|
+
return Math.max(0, Math.floor((now - activityAt) / (24 * 60 * 60 * 1e3)));
|
|
17677
17701
|
}
|
|
17678
17702
|
function parseVerdict(parsed) {
|
|
17679
17703
|
if (typeof parsed !== "object" || parsed === null) return null;
|
|
@@ -17727,7 +17751,7 @@ function createDecaySweeper(options) {
|
|
|
17727
17751
|
if (!classifier || !isBorderline(input)) return ruleVerdict;
|
|
17728
17752
|
if (input.id) {
|
|
17729
17753
|
const cached = classifierCache.get(input.id);
|
|
17730
|
-
if (cached && cached.
|
|
17754
|
+
if (cached && cached.activityAt === lastActivityAt(input)) return cached.verdict;
|
|
17731
17755
|
}
|
|
17732
17756
|
if (sweep.classifierCalls >= maxClassifierCalls) {
|
|
17733
17757
|
if (!sweep.ceilingLogged) {
|
|
@@ -17741,7 +17765,7 @@ function createDecaySweeper(options) {
|
|
|
17741
17765
|
sweep.classifierCalls++;
|
|
17742
17766
|
try {
|
|
17743
17767
|
const verdict = await classifier.classify(input, ruleVerdict, now);
|
|
17744
|
-
if (input.id) classifierCache.set(input.id, {
|
|
17768
|
+
if (input.id) classifierCache.set(input.id, { activityAt: lastActivityAt(input), verdict });
|
|
17745
17769
|
return verdict;
|
|
17746
17770
|
} catch (err) {
|
|
17747
17771
|
getLogger().warn(
|
|
@@ -20378,6 +20402,37 @@ async function assembleMemoryContext(options) {
|
|
|
20378
20402
|
var import_watermelondb13 = require("@nozbe/watermelondb");
|
|
20379
20403
|
var MAX_JOBS_PER_PASS = 3;
|
|
20380
20404
|
var MAX_ATTEMPTS = 3;
|
|
20405
|
+
var MAX_FAILED_SESSIONS = 3;
|
|
20406
|
+
var MIN_FAILED_SESSION_GAP_MS = 60 * 60 * 1e3;
|
|
20407
|
+
var REQUEST_REJECTED_STATUSES = /* @__PURE__ */ new Set([400, 404, 413, 422]);
|
|
20408
|
+
var CONTENT_FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
20409
|
+
"empty-content",
|
|
20410
|
+
"invalid-json",
|
|
20411
|
+
"null-completion",
|
|
20412
|
+
"body-parse-failed"
|
|
20413
|
+
]);
|
|
20414
|
+
var BACKOFF_ALLOWANCE_MS = 2100;
|
|
20415
|
+
var RETAIN_BUDGET_MS = 12e4;
|
|
20416
|
+
function defaultBatchTimeoutMs(extract) {
|
|
20417
|
+
const attempts = Math.max(1, extract.maxAttempts ?? 3);
|
|
20418
|
+
const calls = (extract.timeoutMs ?? 6e4) * attempts + BACKOFF_ALLOWANCE_MS * (attempts - 1);
|
|
20419
|
+
const extraction = extract.totalTimeoutMs !== void 0 ? Math.min(extract.totalTimeoutMs, calls) : calls;
|
|
20420
|
+
return extraction + RETAIN_BUDGET_MS;
|
|
20421
|
+
}
|
|
20422
|
+
var BatchFailureError = class extends Error {
|
|
20423
|
+
constructor(message, terminal) {
|
|
20424
|
+
super(message);
|
|
20425
|
+
this.terminal = terminal;
|
|
20426
|
+
}
|
|
20427
|
+
};
|
|
20428
|
+
var AccountFailureError = class extends Error {
|
|
20429
|
+
};
|
|
20430
|
+
var LockedSourcesError = class extends Error {
|
|
20431
|
+
constructor(persistentIds) {
|
|
20432
|
+
super("Source messages are locked; retained for retry");
|
|
20433
|
+
this.persistentIds = persistentIds;
|
|
20434
|
+
}
|
|
20435
|
+
};
|
|
20381
20436
|
function idsOf(job) {
|
|
20382
20437
|
return JSON.parse(String(job._getRaw("message_ids")));
|
|
20383
20438
|
}
|
|
@@ -20385,6 +20440,16 @@ function seqOf(job) {
|
|
|
20385
20440
|
const raw = job._getRaw("watermark_seq");
|
|
20386
20441
|
return typeof raw === "number" && raw > 0 ? raw : void 0;
|
|
20387
20442
|
}
|
|
20443
|
+
function failedSessionsOf(job, head) {
|
|
20444
|
+
if (job._getRaw("failed_head") !== head) return 0;
|
|
20445
|
+
const raw = job._getRaw("failed_sessions");
|
|
20446
|
+
return typeof raw === "number" && raw > 0 ? raw : 0;
|
|
20447
|
+
}
|
|
20448
|
+
function failedAtOf(job, head) {
|
|
20449
|
+
if (job._getRaw("failed_head") !== head) return void 0;
|
|
20450
|
+
const raw = job._getRaw("failed_at");
|
|
20451
|
+
return typeof raw === "number" ? raw : void 0;
|
|
20452
|
+
}
|
|
20388
20453
|
function createDurableAutoExtractor(options) {
|
|
20389
20454
|
const vault = options.retainCtx.vaultCtx;
|
|
20390
20455
|
const database = vault.database;
|
|
@@ -20407,6 +20472,9 @@ function createDurableAutoExtractor(options) {
|
|
|
20407
20472
|
let writes = Promise.resolve();
|
|
20408
20473
|
let storeFailures = 0;
|
|
20409
20474
|
const attempts = /* @__PURE__ */ new Map();
|
|
20475
|
+
const sessionFailures = /* @__PURE__ */ new Map();
|
|
20476
|
+
const skippedThisSession = /* @__PURE__ */ new Set();
|
|
20477
|
+
const clock = options.now ?? Date.now;
|
|
20410
20478
|
const reportError = (error, conversationId) => {
|
|
20411
20479
|
try {
|
|
20412
20480
|
options.onError?.(error instanceof Error ? error : new Error(String(error)), conversationId);
|
|
@@ -20435,6 +20503,7 @@ function createDurableAutoExtractor(options) {
|
|
|
20435
20503
|
}
|
|
20436
20504
|
async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
|
|
20437
20505
|
let watchdog;
|
|
20506
|
+
let cancelled = false;
|
|
20438
20507
|
const model = options.modelForScope?.(jobScope) ?? options.extract.model;
|
|
20439
20508
|
try {
|
|
20440
20509
|
return await Promise.race([
|
|
@@ -20445,7 +20514,7 @@ function createDurableAutoExtractor(options) {
|
|
|
20445
20514
|
...options.retainCtx,
|
|
20446
20515
|
vaultCtx: {
|
|
20447
20516
|
...vault,
|
|
20448
|
-
canWrite: async () => !disposed && await storage.conversationsCollection.query(import_watermelondb13.Q.where("conversation_id", conversationId), import_watermelondb13.Q.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(import_watermelondb13.Q.where("conversation_id", conversationId), import_watermelondb13.Q.where("id", import_watermelondb13.Q.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed
|
|
20517
|
+
canWrite: async () => !disposed && !cancelled && await storage.conversationsCollection.query(import_watermelondb13.Q.where("conversation_id", conversationId), import_watermelondb13.Q.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(import_watermelondb13.Q.where("conversation_id", conversationId), import_watermelondb13.Q.where("id", import_watermelondb13.Q.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed && !cancelled
|
|
20449
20518
|
}
|
|
20450
20519
|
},
|
|
20451
20520
|
// The model follows the job's scope, not the mode alive at drain time.
|
|
@@ -20465,14 +20534,116 @@ function createDurableAutoExtractor(options) {
|
|
|
20465
20534
|
new Promise((_resolve, reject) => {
|
|
20466
20535
|
watchdog = setTimeout(
|
|
20467
20536
|
() => reject(new Error("Extraction did not settle in time; retained for retry")),
|
|
20468
|
-
options.batchTimeoutMs ??
|
|
20537
|
+
options.batchTimeoutMs ?? defaultBatchTimeoutMs(options.extract)
|
|
20469
20538
|
);
|
|
20470
20539
|
})
|
|
20471
20540
|
]);
|
|
20472
20541
|
} finally {
|
|
20542
|
+
cancelled = true;
|
|
20473
20543
|
if (watchdog !== void 0) clearTimeout(watchdog);
|
|
20474
20544
|
}
|
|
20475
20545
|
}
|
|
20546
|
+
async function acknowledge(job, ids, loaded, abandoned) {
|
|
20547
|
+
attempts.delete(job.id);
|
|
20548
|
+
sessionFailures.delete(job.id);
|
|
20549
|
+
skippedThisSession.delete(job.id);
|
|
20550
|
+
const sequences = /* @__PURE__ */ new Map();
|
|
20551
|
+
for (const message of loaded)
|
|
20552
|
+
if (message && message.messageId > 0) sequences.set(message.uniqueId, message.messageId);
|
|
20553
|
+
await database.write(async () => {
|
|
20554
|
+
const current = idsOf(job);
|
|
20555
|
+
const acknowledged = ids.filter((id) => current.includes(id));
|
|
20556
|
+
if (!acknowledged.length) return;
|
|
20557
|
+
const done = new Set(acknowledged);
|
|
20558
|
+
const remaining = current.filter((id) => !done.has(id));
|
|
20559
|
+
await job.update((r) => {
|
|
20560
|
+
r._setRaw(
|
|
20561
|
+
"message_ids",
|
|
20562
|
+
JSON.stringify(
|
|
20563
|
+
remaining.length ? [...abandoned ? [] : acknowledged.slice(-2), ...remaining] : []
|
|
20564
|
+
)
|
|
20565
|
+
);
|
|
20566
|
+
const newest = acknowledged[acknowledged.length - 1];
|
|
20567
|
+
r._setRaw("watermark", newest);
|
|
20568
|
+
const sequence = sequences.get(newest);
|
|
20569
|
+
if (sequence !== void 0) {
|
|
20570
|
+
const prior = seqOf(job);
|
|
20571
|
+
r._setRaw("watermark_seq", prior === void 0 ? sequence : Math.max(prior, sequence));
|
|
20572
|
+
}
|
|
20573
|
+
r._setRaw("failed_sessions", abandoned ? MAX_FAILED_SESSIONS : null);
|
|
20574
|
+
r._setRaw("failed_head", abandoned ? newest : null);
|
|
20575
|
+
r._setRaw("failed_at", null);
|
|
20576
|
+
});
|
|
20577
|
+
});
|
|
20578
|
+
}
|
|
20579
|
+
async function recordFailure(job, ids, loaded, error, conversationId) {
|
|
20580
|
+
const head = ids[0];
|
|
20581
|
+
if (!head || !loaded.some(Boolean)) return false;
|
|
20582
|
+
if (error instanceof AccountFailureError) {
|
|
20583
|
+
skippedThisSession.add(job.id);
|
|
20584
|
+
return false;
|
|
20585
|
+
}
|
|
20586
|
+
const counted = error instanceof BatchFailureError || error instanceof LockedSourcesError && error.persistentIds.length > 0;
|
|
20587
|
+
if (!counted) return false;
|
|
20588
|
+
const prior = sessionFailures.get(job.id);
|
|
20589
|
+
const count = prior?.head === head ? prior.count + 1 : 1;
|
|
20590
|
+
sessionFailures.set(job.id, { head, count });
|
|
20591
|
+
const terminal = error instanceof BatchFailureError && error.terminal;
|
|
20592
|
+
if (!terminal && count < MAX_ATTEMPTS) return false;
|
|
20593
|
+
skippedThisSession.add(job.id);
|
|
20594
|
+
const now = clock();
|
|
20595
|
+
const lastCounted = failedAtOf(job, head);
|
|
20596
|
+
if (lastCounted !== void 0 && now - lastCounted < MIN_FAILED_SESSION_GAP_MS) return false;
|
|
20597
|
+
const failures = failedSessionsOf(job, head) + 1;
|
|
20598
|
+
if (failures < MAX_FAILED_SESSIONS) {
|
|
20599
|
+
await database.write(
|
|
20600
|
+
() => job.update((r) => {
|
|
20601
|
+
r._setRaw("failed_sessions", failures);
|
|
20602
|
+
r._setRaw("failed_head", head);
|
|
20603
|
+
r._setRaw("failed_at", now);
|
|
20604
|
+
})
|
|
20605
|
+
);
|
|
20606
|
+
return false;
|
|
20607
|
+
}
|
|
20608
|
+
if (error instanceof LockedSourcesError) {
|
|
20609
|
+
const dropped = new Set(error.persistentIds);
|
|
20610
|
+
let newest;
|
|
20611
|
+
for (const message of loaded)
|
|
20612
|
+
if (message && dropped.has(message.uniqueId) && message.messageId > (newest?.seq ?? 0))
|
|
20613
|
+
newest = { id: message.uniqueId, seq: message.messageId };
|
|
20614
|
+
const advance = newest !== void 0 && newest.seq > (seqOf(job) ?? 0) ? newest : void 0;
|
|
20615
|
+
await database.write(
|
|
20616
|
+
() => job.update((r) => {
|
|
20617
|
+
r._setRaw("message_ids", JSON.stringify(idsOf(job).filter((id) => !dropped.has(id))));
|
|
20618
|
+
if (advance) {
|
|
20619
|
+
r._setRaw("watermark", advance.id);
|
|
20620
|
+
r._setRaw("watermark_seq", advance.seq);
|
|
20621
|
+
}
|
|
20622
|
+
r._setRaw("failed_sessions", advance ? MAX_FAILED_SESSIONS : null);
|
|
20623
|
+
r._setRaw("failed_head", advance ? advance.id : null);
|
|
20624
|
+
r._setRaw("failed_at", null);
|
|
20625
|
+
})
|
|
20626
|
+
);
|
|
20627
|
+
attempts.delete(job.id);
|
|
20628
|
+
sessionFailures.delete(job.id);
|
|
20629
|
+
skippedThisSession.delete(job.id);
|
|
20630
|
+
reportError(
|
|
20631
|
+
new Error(
|
|
20632
|
+
`Dropped ${dropped.size} source id(s) that stayed locked for ${failures} sessions to unblock extraction`
|
|
20633
|
+
),
|
|
20634
|
+
conversationId
|
|
20635
|
+
);
|
|
20636
|
+
return true;
|
|
20637
|
+
}
|
|
20638
|
+
await acknowledge(job, ids, loaded, true);
|
|
20639
|
+
reportError(
|
|
20640
|
+
new Error(
|
|
20641
|
+
`Abandoned an extraction batch of ${ids.length} source id(s) after it failed in ${failures} sessions`
|
|
20642
|
+
),
|
|
20643
|
+
conversationId
|
|
20644
|
+
);
|
|
20645
|
+
return true;
|
|
20646
|
+
}
|
|
20476
20647
|
async function drain() {
|
|
20477
20648
|
if (disposed || running) return;
|
|
20478
20649
|
running = true;
|
|
@@ -20487,21 +20658,23 @@ function createDurableAutoExtractor(options) {
|
|
|
20487
20658
|
for (const job of pending) {
|
|
20488
20659
|
if (disposed) break;
|
|
20489
20660
|
const attempted = attempts.get(job.id) ?? 0;
|
|
20490
|
-
if (attempted >= MAX_ATTEMPTS) continue;
|
|
20661
|
+
if (attempted >= MAX_ATTEMPTS || skippedThisSession.has(job.id)) continue;
|
|
20491
20662
|
if (processed >= MAX_JOBS_PER_PASS) {
|
|
20492
20663
|
scheduleAfterSuccess = true;
|
|
20493
20664
|
break;
|
|
20494
20665
|
}
|
|
20495
20666
|
processed++;
|
|
20496
20667
|
const conversationId = String(job._getRaw("conversation_id"));
|
|
20668
|
+
let ids = [];
|
|
20669
|
+
let loaded = [];
|
|
20497
20670
|
try {
|
|
20498
20671
|
const conversations = await storage.conversationsCollection.query(import_watermelondb13.Q.where("conversation_id", conversationId), import_watermelondb13.Q.where("is_deleted", false)).fetchCount();
|
|
20499
20672
|
if (!conversations) {
|
|
20500
20673
|
await database.write(() => job.destroyPermanently());
|
|
20501
20674
|
continue;
|
|
20502
20675
|
}
|
|
20503
|
-
|
|
20504
|
-
|
|
20676
|
+
ids = idsOf(job).slice(0, 20);
|
|
20677
|
+
loaded = await Promise.all(ids.map((id) => getMessageOp(storage, id)));
|
|
20505
20678
|
const missing = ids.filter((_id, index) => loaded[index] === null);
|
|
20506
20679
|
if (missing.length) {
|
|
20507
20680
|
if (attempted < MAX_ATTEMPTS - 1)
|
|
@@ -20525,17 +20698,21 @@ function createDurableAutoExtractor(options) {
|
|
|
20525
20698
|
);
|
|
20526
20699
|
continue;
|
|
20527
20700
|
}
|
|
20528
|
-
|
|
20529
|
-
|
|
20530
|
-
|
|
20531
|
-
|
|
20701
|
+
const locked = loaded.filter((message) => message && isEncrypted(message.content));
|
|
20702
|
+
if (locked.length) {
|
|
20703
|
+
throw new LockedSourcesError(
|
|
20704
|
+
locked.flatMap(
|
|
20705
|
+
(message) => message.decryptionStatus === "auth_mismatch" || message.decryptionStatus === "invalid_payload" ? [message.uniqueId] : []
|
|
20706
|
+
)
|
|
20707
|
+
);
|
|
20532
20708
|
}
|
|
20533
20709
|
const messages = loaded.flatMap(
|
|
20534
20710
|
(m) => m && m.conversationId === conversationId && (m.role === "user" || m.role === "assistant") ? [{ id: m.uniqueId, role: m.role, content: m.content }] : []
|
|
20535
20711
|
);
|
|
20536
20712
|
let success = messages.length === 0;
|
|
20713
|
+
let result;
|
|
20537
20714
|
if (messages.length) {
|
|
20538
|
-
|
|
20715
|
+
result = await extractBatch(
|
|
20539
20716
|
messages,
|
|
20540
20717
|
conversationId,
|
|
20541
20718
|
ids,
|
|
@@ -20545,41 +20722,35 @@ function createDurableAutoExtractor(options) {
|
|
|
20545
20722
|
success = result.failedCount === 0 && result.outcome !== "empty-after-retry";
|
|
20546
20723
|
options.onTurnComplete?.(result);
|
|
20547
20724
|
}
|
|
20548
|
-
if (!success)
|
|
20549
|
-
|
|
20550
|
-
|
|
20551
|
-
|
|
20552
|
-
|
|
20553
|
-
|
|
20554
|
-
|
|
20555
|
-
|
|
20556
|
-
const acknowledged = ids.filter((id) => current.includes(id));
|
|
20557
|
-
if (!acknowledged.length) return;
|
|
20558
|
-
const done = new Set(acknowledged);
|
|
20559
|
-
const remaining = current.filter((id) => !done.has(id));
|
|
20560
|
-
if (remaining.length) {
|
|
20561
|
-
await job.update(
|
|
20562
|
-
(r) => r._setRaw("message_ids", JSON.stringify([...acknowledged.slice(-2), ...remaining]))
|
|
20563
|
-
);
|
|
20564
|
-
} else await job.update((r) => r._setRaw("message_ids", "[]"));
|
|
20565
|
-
const newest = acknowledged[acknowledged.length - 1];
|
|
20566
|
-
await job.update((r) => {
|
|
20567
|
-
r._setRaw("watermark", newest);
|
|
20568
|
-
const sequence = sequences.get(newest);
|
|
20569
|
-
if (sequence !== void 0) {
|
|
20570
|
-
const prior = seqOf(job);
|
|
20571
|
-
r._setRaw(
|
|
20572
|
-
"watermark_seq",
|
|
20573
|
-
prior === void 0 ? sequence : Math.max(prior, sequence)
|
|
20725
|
+
if (!success) {
|
|
20726
|
+
const failure = result?.failure;
|
|
20727
|
+
if (failure?.reason === "http-terminal") {
|
|
20728
|
+
const status = failure.httpStatus;
|
|
20729
|
+
if (status !== void 0 && REQUEST_REJECTED_STATUSES.has(status))
|
|
20730
|
+
throw new BatchFailureError(
|
|
20731
|
+
`Extraction rejected the batch (HTTP ${status}); not retried this session`,
|
|
20732
|
+
true
|
|
20574
20733
|
);
|
|
20575
|
-
|
|
20576
|
-
|
|
20577
|
-
|
|
20734
|
+
throw new AccountFailureError(
|
|
20735
|
+
`Extraction refused for the account (HTTP ${status ?? "unknown"}); retried next session`
|
|
20736
|
+
);
|
|
20737
|
+
}
|
|
20738
|
+
if ((result?.failedCount ?? 0) > 0 || failure !== void 0 && CONTENT_FAILURE_REASONS.has(failure.reason))
|
|
20739
|
+
throw new BatchFailureError("Extraction batch incomplete; retained for retry", false);
|
|
20740
|
+
throw new Error("Extraction batch incomplete; retained for retry");
|
|
20741
|
+
}
|
|
20742
|
+
await acknowledge(job, ids, loaded, false);
|
|
20578
20743
|
scheduleAfterSuccess = true;
|
|
20579
20744
|
} catch (error) {
|
|
20580
20745
|
attempts.set(job.id, attempted + 1);
|
|
20581
20746
|
retry = true;
|
|
20582
20747
|
reportError(error, conversationId);
|
|
20748
|
+
try {
|
|
20749
|
+
if (await recordFailure(job, ids, loaded, error, conversationId))
|
|
20750
|
+
scheduleAfterSuccess = true;
|
|
20751
|
+
} catch (recordError) {
|
|
20752
|
+
reportError(recordError, conversationId);
|
|
20753
|
+
}
|
|
20583
20754
|
}
|
|
20584
20755
|
}
|
|
20585
20756
|
} catch (error) {
|
|
@@ -20649,7 +20820,7 @@ function createDurableAutoExtractor(options) {
|
|
|
20649
20820
|
const start = boundary >= 0 ? boundary + 1 : Math.max(0, ids.length - Math.max(1, options.windowSize ?? 6));
|
|
20650
20821
|
if (start >= ids.length) return;
|
|
20651
20822
|
const ownWatermark = job?._getRaw("watermark");
|
|
20652
|
-
const atOwnWatermark = !!job && boundary >= 0 && (ids[boundary] === ownWatermark || sequences.get(ids[boundary]) !== void 0 && sequences.get(ids[boundary]) === seqOf(job));
|
|
20823
|
+
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));
|
|
20653
20824
|
const overlapStart = atOwnWatermark ? Math.max(0, boundary - 1) : start;
|
|
20654
20825
|
const fresh = ids.slice(overlapStart).filter((id) => !foreignSources.has(id));
|
|
20655
20826
|
if (!fresh.length) return;
|
|
@@ -21096,6 +21267,9 @@ var MANUAL_FACT_TYPES = [
|
|
|
21096
21267
|
function normalizeManualFactType(value) {
|
|
21097
21268
|
return typeof value === "string" && MANUAL_FACT_TYPES.includes(value) ? value : void 0;
|
|
21098
21269
|
}
|
|
21270
|
+
function isSharedScope(scope) {
|
|
21271
|
+
return scope === "shared";
|
|
21272
|
+
}
|
|
21099
21273
|
async function notifyWritten(options, input, outcome) {
|
|
21100
21274
|
try {
|
|
21101
21275
|
await options?.onWritten?.({ input, outcome });
|
|
@@ -21164,14 +21338,17 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
|
|
|
21164
21338
|
try {
|
|
21165
21339
|
const isUpdate = !!id;
|
|
21166
21340
|
let previousContent;
|
|
21341
|
+
const scope = options?.scope ?? "private";
|
|
21167
21342
|
if (isUpdate) {
|
|
21168
21343
|
const existing = await getVaultMemoryOp(vaultCtx, id);
|
|
21169
21344
|
if (!existing) {
|
|
21170
21345
|
return `Error: Memory with ID "${id}" not found. Creating a new memory instead would require a separate call without an ID.`;
|
|
21171
21346
|
}
|
|
21347
|
+
if (isSharedScope(existing.scope) !== isSharedScope(scope)) {
|
|
21348
|
+
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.`;
|
|
21349
|
+
}
|
|
21172
21350
|
previousContent = existing.content;
|
|
21173
21351
|
}
|
|
21174
|
-
const scope = options?.scope ?? "private";
|
|
21175
21352
|
const operation = {
|
|
21176
21353
|
action: isUpdate ? "update" : "add",
|
|
21177
21354
|
content,
|
|
@@ -25418,7 +25595,7 @@ __decorateClass([
|
|
|
25418
25595
|
], VaultFolder.prototype, "context", 2);
|
|
25419
25596
|
|
|
25420
25597
|
// src/lib/db/schema.ts
|
|
25421
|
-
var SDK_SCHEMA_VERSION =
|
|
25598
|
+
var SDK_SCHEMA_VERSION = 47;
|
|
25422
25599
|
var sdkSchema = (0, import_watermelondb22.appSchema)({
|
|
25423
25600
|
version: SDK_SCHEMA_VERSION,
|
|
25424
25601
|
tables: [
|
|
@@ -25434,7 +25611,11 @@ var sdkSchema = (0, import_watermelondb22.appSchema)({
|
|
|
25434
25611
|
// source. `watermark` alone is an id, and deleting that message erased
|
|
25435
25612
|
// the anchor — see the column note in extractionJobs/models.ts.
|
|
25436
25613
|
{ name: "watermark_seq", type: "number", isOptional: true },
|
|
25437
|
-
{ name: "folder_id", type: "string", isOptional: true }
|
|
25614
|
+
{ name: "folder_id", type: "string", isOptional: true },
|
|
25615
|
+
// Poison accounting for the head batch; see extractionJobs/models.ts.
|
|
25616
|
+
{ name: "failed_sessions", type: "number", isOptional: true },
|
|
25617
|
+
{ name: "failed_head", type: "string", isOptional: true },
|
|
25618
|
+
{ name: "failed_at", type: "number", isOptional: true }
|
|
25438
25619
|
]
|
|
25439
25620
|
}),
|
|
25440
25621
|
// Chat storage tables
|
|
@@ -26458,6 +26639,22 @@ var sdkMigrations = (0, import_migrations2.schemaMigrations)({
|
|
|
26458
26639
|
]
|
|
26459
26640
|
})
|
|
26460
26641
|
]
|
|
26642
|
+
},
|
|
26643
|
+
// v46 -> v47: persisted poison count (and when it was last counted) for a
|
|
26644
|
+
// durable-extraction job's head batch. NULL = never failed, which is right
|
|
26645
|
+
// for every existing row.
|
|
26646
|
+
{
|
|
26647
|
+
toVersion: 47,
|
|
26648
|
+
steps: [
|
|
26649
|
+
(0, import_migrations2.addColumns)({
|
|
26650
|
+
table: "memory_extraction_jobs",
|
|
26651
|
+
columns: [
|
|
26652
|
+
{ name: "failed_sessions", type: "number", isOptional: true },
|
|
26653
|
+
{ name: "failed_head", type: "string", isOptional: true },
|
|
26654
|
+
{ name: "failed_at", type: "number", isOptional: true }
|
|
26655
|
+
]
|
|
26656
|
+
})
|
|
26657
|
+
]
|
|
26461
26658
|
}
|
|
26462
26659
|
]
|
|
26463
26660
|
});
|