@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.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(
|
|
@@ -19481,7 +19505,10 @@ function reviewedMemoryIdsSignature(ids) {
|
|
|
19481
19505
|
return [...new Set(ids)].sort().join("\n");
|
|
19482
19506
|
}
|
|
19483
19507
|
function facetsSignature(facets) {
|
|
19484
|
-
return
|
|
19508
|
+
return [
|
|
19509
|
+
JSON.stringify(FACET_SYSTEM_PROMPT),
|
|
19510
|
+
...facets.map((f) => JSON.stringify([f.key, f.label, f.query, f.guidance, facetResponseSchema(f.key)])).sort()
|
|
19511
|
+
].join("\n");
|
|
19485
19512
|
}
|
|
19486
19513
|
function trendsEqual(a, b) {
|
|
19487
19514
|
if (!a) return false;
|
|
@@ -19703,7 +19730,7 @@ var FACET_SYSTEM_PROMPT = `You are writing one section of a person's shareable p
|
|
|
19703
19730
|
Rules:
|
|
19704
19731
|
- Ground every claim in the supplied memories \u2014 never invent, infer beyond, or embellish what they support.
|
|
19705
19732
|
- If the memories don't cover this section, return an empty summary with hasEvidence=false. Do not pad or guess.
|
|
19706
|
-
- Write in
|
|
19733
|
+
- 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.
|
|
19707
19734
|
- Be concise and specific; no preamble, hedging, or meta-commentary.
|
|
19708
19735
|
- Respond as JSON in exactly the shape the user turn states, with no extra fields.`;
|
|
19709
19736
|
function buildFacetUserInstructions(facet) {
|
|
@@ -20378,6 +20405,37 @@ async function assembleMemoryContext(options) {
|
|
|
20378
20405
|
var import_watermelondb13 = require("@nozbe/watermelondb");
|
|
20379
20406
|
var MAX_JOBS_PER_PASS = 3;
|
|
20380
20407
|
var MAX_ATTEMPTS = 3;
|
|
20408
|
+
var MAX_FAILED_SESSIONS = 3;
|
|
20409
|
+
var MIN_FAILED_SESSION_GAP_MS = 60 * 60 * 1e3;
|
|
20410
|
+
var REQUEST_REJECTED_STATUSES = /* @__PURE__ */ new Set([400, 404, 413, 422]);
|
|
20411
|
+
var CONTENT_FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
20412
|
+
"empty-content",
|
|
20413
|
+
"invalid-json",
|
|
20414
|
+
"null-completion",
|
|
20415
|
+
"body-parse-failed"
|
|
20416
|
+
]);
|
|
20417
|
+
var BACKOFF_ALLOWANCE_MS = 2100;
|
|
20418
|
+
var RETAIN_BUDGET_MS = 12e4;
|
|
20419
|
+
function defaultBatchTimeoutMs(extract) {
|
|
20420
|
+
const attempts = Math.max(1, extract.maxAttempts ?? 3);
|
|
20421
|
+
const calls = (extract.timeoutMs ?? 6e4) * attempts + BACKOFF_ALLOWANCE_MS * (attempts - 1);
|
|
20422
|
+
const extraction = extract.totalTimeoutMs !== void 0 ? Math.min(extract.totalTimeoutMs, calls) : calls;
|
|
20423
|
+
return extraction + RETAIN_BUDGET_MS;
|
|
20424
|
+
}
|
|
20425
|
+
var BatchFailureError = class extends Error {
|
|
20426
|
+
constructor(message, terminal) {
|
|
20427
|
+
super(message);
|
|
20428
|
+
this.terminal = terminal;
|
|
20429
|
+
}
|
|
20430
|
+
};
|
|
20431
|
+
var AccountFailureError = class extends Error {
|
|
20432
|
+
};
|
|
20433
|
+
var LockedSourcesError = class extends Error {
|
|
20434
|
+
constructor(persistentIds) {
|
|
20435
|
+
super("Source messages are locked; retained for retry");
|
|
20436
|
+
this.persistentIds = persistentIds;
|
|
20437
|
+
}
|
|
20438
|
+
};
|
|
20381
20439
|
function idsOf(job) {
|
|
20382
20440
|
return JSON.parse(String(job._getRaw("message_ids")));
|
|
20383
20441
|
}
|
|
@@ -20385,6 +20443,16 @@ function seqOf(job) {
|
|
|
20385
20443
|
const raw = job._getRaw("watermark_seq");
|
|
20386
20444
|
return typeof raw === "number" && raw > 0 ? raw : void 0;
|
|
20387
20445
|
}
|
|
20446
|
+
function failedSessionsOf(job, head) {
|
|
20447
|
+
if (job._getRaw("failed_head") !== head) return 0;
|
|
20448
|
+
const raw = job._getRaw("failed_sessions");
|
|
20449
|
+
return typeof raw === "number" && raw > 0 ? raw : 0;
|
|
20450
|
+
}
|
|
20451
|
+
function failedAtOf(job, head) {
|
|
20452
|
+
if (job._getRaw("failed_head") !== head) return void 0;
|
|
20453
|
+
const raw = job._getRaw("failed_at");
|
|
20454
|
+
return typeof raw === "number" ? raw : void 0;
|
|
20455
|
+
}
|
|
20388
20456
|
function createDurableAutoExtractor(options) {
|
|
20389
20457
|
const vault = options.retainCtx.vaultCtx;
|
|
20390
20458
|
const database = vault.database;
|
|
@@ -20407,6 +20475,9 @@ function createDurableAutoExtractor(options) {
|
|
|
20407
20475
|
let writes = Promise.resolve();
|
|
20408
20476
|
let storeFailures = 0;
|
|
20409
20477
|
const attempts = /* @__PURE__ */ new Map();
|
|
20478
|
+
const sessionFailures = /* @__PURE__ */ new Map();
|
|
20479
|
+
const skippedThisSession = /* @__PURE__ */ new Set();
|
|
20480
|
+
const clock = options.now ?? Date.now;
|
|
20410
20481
|
const reportError = (error, conversationId) => {
|
|
20411
20482
|
try {
|
|
20412
20483
|
options.onError?.(error instanceof Error ? error : new Error(String(error)), conversationId);
|
|
@@ -20435,6 +20506,7 @@ function createDurableAutoExtractor(options) {
|
|
|
20435
20506
|
}
|
|
20436
20507
|
async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
|
|
20437
20508
|
let watchdog;
|
|
20509
|
+
let cancelled = false;
|
|
20438
20510
|
const model = options.modelForScope?.(jobScope) ?? options.extract.model;
|
|
20439
20511
|
try {
|
|
20440
20512
|
return await Promise.race([
|
|
@@ -20445,7 +20517,7 @@ function createDurableAutoExtractor(options) {
|
|
|
20445
20517
|
...options.retainCtx,
|
|
20446
20518
|
vaultCtx: {
|
|
20447
20519
|
...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
|
|
20520
|
+
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
20521
|
}
|
|
20450
20522
|
},
|
|
20451
20523
|
// The model follows the job's scope, not the mode alive at drain time.
|
|
@@ -20465,14 +20537,116 @@ function createDurableAutoExtractor(options) {
|
|
|
20465
20537
|
new Promise((_resolve, reject) => {
|
|
20466
20538
|
watchdog = setTimeout(
|
|
20467
20539
|
() => reject(new Error("Extraction did not settle in time; retained for retry")),
|
|
20468
|
-
options.batchTimeoutMs ??
|
|
20540
|
+
options.batchTimeoutMs ?? defaultBatchTimeoutMs(options.extract)
|
|
20469
20541
|
);
|
|
20470
20542
|
})
|
|
20471
20543
|
]);
|
|
20472
20544
|
} finally {
|
|
20545
|
+
cancelled = true;
|
|
20473
20546
|
if (watchdog !== void 0) clearTimeout(watchdog);
|
|
20474
20547
|
}
|
|
20475
20548
|
}
|
|
20549
|
+
async function acknowledge(job, ids, loaded, abandoned) {
|
|
20550
|
+
attempts.delete(job.id);
|
|
20551
|
+
sessionFailures.delete(job.id);
|
|
20552
|
+
skippedThisSession.delete(job.id);
|
|
20553
|
+
const sequences = /* @__PURE__ */ new Map();
|
|
20554
|
+
for (const message of loaded)
|
|
20555
|
+
if (message && message.messageId > 0) sequences.set(message.uniqueId, message.messageId);
|
|
20556
|
+
await database.write(async () => {
|
|
20557
|
+
const current = idsOf(job);
|
|
20558
|
+
const acknowledged = ids.filter((id) => current.includes(id));
|
|
20559
|
+
if (!acknowledged.length) return;
|
|
20560
|
+
const done = new Set(acknowledged);
|
|
20561
|
+
const remaining = current.filter((id) => !done.has(id));
|
|
20562
|
+
await job.update((r) => {
|
|
20563
|
+
r._setRaw(
|
|
20564
|
+
"message_ids",
|
|
20565
|
+
JSON.stringify(
|
|
20566
|
+
remaining.length ? [...abandoned ? [] : acknowledged.slice(-2), ...remaining] : []
|
|
20567
|
+
)
|
|
20568
|
+
);
|
|
20569
|
+
const newest = acknowledged[acknowledged.length - 1];
|
|
20570
|
+
r._setRaw("watermark", newest);
|
|
20571
|
+
const sequence = sequences.get(newest);
|
|
20572
|
+
if (sequence !== void 0) {
|
|
20573
|
+
const prior = seqOf(job);
|
|
20574
|
+
r._setRaw("watermark_seq", prior === void 0 ? sequence : Math.max(prior, sequence));
|
|
20575
|
+
}
|
|
20576
|
+
r._setRaw("failed_sessions", abandoned ? MAX_FAILED_SESSIONS : null);
|
|
20577
|
+
r._setRaw("failed_head", abandoned ? newest : null);
|
|
20578
|
+
r._setRaw("failed_at", null);
|
|
20579
|
+
});
|
|
20580
|
+
});
|
|
20581
|
+
}
|
|
20582
|
+
async function recordFailure(job, ids, loaded, error, conversationId) {
|
|
20583
|
+
const head = ids[0];
|
|
20584
|
+
if (!head || !loaded.some(Boolean)) return false;
|
|
20585
|
+
if (error instanceof AccountFailureError) {
|
|
20586
|
+
skippedThisSession.add(job.id);
|
|
20587
|
+
return false;
|
|
20588
|
+
}
|
|
20589
|
+
const counted = error instanceof BatchFailureError || error instanceof LockedSourcesError && error.persistentIds.length > 0;
|
|
20590
|
+
if (!counted) return false;
|
|
20591
|
+
const prior = sessionFailures.get(job.id);
|
|
20592
|
+
const count = prior?.head === head ? prior.count + 1 : 1;
|
|
20593
|
+
sessionFailures.set(job.id, { head, count });
|
|
20594
|
+
const terminal = error instanceof BatchFailureError && error.terminal;
|
|
20595
|
+
if (!terminal && count < MAX_ATTEMPTS) return false;
|
|
20596
|
+
skippedThisSession.add(job.id);
|
|
20597
|
+
const now = clock();
|
|
20598
|
+
const lastCounted = failedAtOf(job, head);
|
|
20599
|
+
if (lastCounted !== void 0 && now - lastCounted < MIN_FAILED_SESSION_GAP_MS) return false;
|
|
20600
|
+
const failures = failedSessionsOf(job, head) + 1;
|
|
20601
|
+
if (failures < MAX_FAILED_SESSIONS) {
|
|
20602
|
+
await database.write(
|
|
20603
|
+
() => job.update((r) => {
|
|
20604
|
+
r._setRaw("failed_sessions", failures);
|
|
20605
|
+
r._setRaw("failed_head", head);
|
|
20606
|
+
r._setRaw("failed_at", now);
|
|
20607
|
+
})
|
|
20608
|
+
);
|
|
20609
|
+
return false;
|
|
20610
|
+
}
|
|
20611
|
+
if (error instanceof LockedSourcesError) {
|
|
20612
|
+
const dropped = new Set(error.persistentIds);
|
|
20613
|
+
let newest;
|
|
20614
|
+
for (const message of loaded)
|
|
20615
|
+
if (message && dropped.has(message.uniqueId) && message.messageId > (newest?.seq ?? 0))
|
|
20616
|
+
newest = { id: message.uniqueId, seq: message.messageId };
|
|
20617
|
+
const advance = newest !== void 0 && newest.seq > (seqOf(job) ?? 0) ? newest : void 0;
|
|
20618
|
+
await database.write(
|
|
20619
|
+
() => job.update((r) => {
|
|
20620
|
+
r._setRaw("message_ids", JSON.stringify(idsOf(job).filter((id) => !dropped.has(id))));
|
|
20621
|
+
if (advance) {
|
|
20622
|
+
r._setRaw("watermark", advance.id);
|
|
20623
|
+
r._setRaw("watermark_seq", advance.seq);
|
|
20624
|
+
}
|
|
20625
|
+
r._setRaw("failed_sessions", advance ? MAX_FAILED_SESSIONS : null);
|
|
20626
|
+
r._setRaw("failed_head", advance ? advance.id : null);
|
|
20627
|
+
r._setRaw("failed_at", null);
|
|
20628
|
+
})
|
|
20629
|
+
);
|
|
20630
|
+
attempts.delete(job.id);
|
|
20631
|
+
sessionFailures.delete(job.id);
|
|
20632
|
+
skippedThisSession.delete(job.id);
|
|
20633
|
+
reportError(
|
|
20634
|
+
new Error(
|
|
20635
|
+
`Dropped ${dropped.size} source id(s) that stayed locked for ${failures} sessions to unblock extraction`
|
|
20636
|
+
),
|
|
20637
|
+
conversationId
|
|
20638
|
+
);
|
|
20639
|
+
return true;
|
|
20640
|
+
}
|
|
20641
|
+
await acknowledge(job, ids, loaded, true);
|
|
20642
|
+
reportError(
|
|
20643
|
+
new Error(
|
|
20644
|
+
`Abandoned an extraction batch of ${ids.length} source id(s) after it failed in ${failures} sessions`
|
|
20645
|
+
),
|
|
20646
|
+
conversationId
|
|
20647
|
+
);
|
|
20648
|
+
return true;
|
|
20649
|
+
}
|
|
20476
20650
|
async function drain() {
|
|
20477
20651
|
if (disposed || running) return;
|
|
20478
20652
|
running = true;
|
|
@@ -20487,21 +20661,23 @@ function createDurableAutoExtractor(options) {
|
|
|
20487
20661
|
for (const job of pending) {
|
|
20488
20662
|
if (disposed) break;
|
|
20489
20663
|
const attempted = attempts.get(job.id) ?? 0;
|
|
20490
|
-
if (attempted >= MAX_ATTEMPTS) continue;
|
|
20664
|
+
if (attempted >= MAX_ATTEMPTS || skippedThisSession.has(job.id)) continue;
|
|
20491
20665
|
if (processed >= MAX_JOBS_PER_PASS) {
|
|
20492
20666
|
scheduleAfterSuccess = true;
|
|
20493
20667
|
break;
|
|
20494
20668
|
}
|
|
20495
20669
|
processed++;
|
|
20496
20670
|
const conversationId = String(job._getRaw("conversation_id"));
|
|
20671
|
+
let ids = [];
|
|
20672
|
+
let loaded = [];
|
|
20497
20673
|
try {
|
|
20498
20674
|
const conversations = await storage.conversationsCollection.query(import_watermelondb13.Q.where("conversation_id", conversationId), import_watermelondb13.Q.where("is_deleted", false)).fetchCount();
|
|
20499
20675
|
if (!conversations) {
|
|
20500
20676
|
await database.write(() => job.destroyPermanently());
|
|
20501
20677
|
continue;
|
|
20502
20678
|
}
|
|
20503
|
-
|
|
20504
|
-
|
|
20679
|
+
ids = idsOf(job).slice(0, 20);
|
|
20680
|
+
loaded = await Promise.all(ids.map((id) => getMessageOp(storage, id)));
|
|
20505
20681
|
const missing = ids.filter((_id, index) => loaded[index] === null);
|
|
20506
20682
|
if (missing.length) {
|
|
20507
20683
|
if (attempted < MAX_ATTEMPTS - 1)
|
|
@@ -20525,17 +20701,21 @@ function createDurableAutoExtractor(options) {
|
|
|
20525
20701
|
);
|
|
20526
20702
|
continue;
|
|
20527
20703
|
}
|
|
20528
|
-
|
|
20529
|
-
|
|
20530
|
-
|
|
20531
|
-
|
|
20704
|
+
const locked = loaded.filter((message) => message && isEncrypted(message.content));
|
|
20705
|
+
if (locked.length) {
|
|
20706
|
+
throw new LockedSourcesError(
|
|
20707
|
+
locked.flatMap(
|
|
20708
|
+
(message) => message.decryptionStatus === "auth_mismatch" || message.decryptionStatus === "invalid_payload" ? [message.uniqueId] : []
|
|
20709
|
+
)
|
|
20710
|
+
);
|
|
20532
20711
|
}
|
|
20533
20712
|
const messages = loaded.flatMap(
|
|
20534
20713
|
(m) => m && m.conversationId === conversationId && (m.role === "user" || m.role === "assistant") ? [{ id: m.uniqueId, role: m.role, content: m.content }] : []
|
|
20535
20714
|
);
|
|
20536
20715
|
let success = messages.length === 0;
|
|
20716
|
+
let result;
|
|
20537
20717
|
if (messages.length) {
|
|
20538
|
-
|
|
20718
|
+
result = await extractBatch(
|
|
20539
20719
|
messages,
|
|
20540
20720
|
conversationId,
|
|
20541
20721
|
ids,
|
|
@@ -20545,41 +20725,35 @@ function createDurableAutoExtractor(options) {
|
|
|
20545
20725
|
success = result.failedCount === 0 && result.outcome !== "empty-after-retry";
|
|
20546
20726
|
options.onTurnComplete?.(result);
|
|
20547
20727
|
}
|
|
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)
|
|
20728
|
+
if (!success) {
|
|
20729
|
+
const failure = result?.failure;
|
|
20730
|
+
if (failure?.reason === "http-terminal") {
|
|
20731
|
+
const status = failure.httpStatus;
|
|
20732
|
+
if (status !== void 0 && REQUEST_REJECTED_STATUSES.has(status))
|
|
20733
|
+
throw new BatchFailureError(
|
|
20734
|
+
`Extraction rejected the batch (HTTP ${status}); not retried this session`,
|
|
20735
|
+
true
|
|
20574
20736
|
);
|
|
20575
|
-
|
|
20576
|
-
|
|
20577
|
-
|
|
20737
|
+
throw new AccountFailureError(
|
|
20738
|
+
`Extraction refused for the account (HTTP ${status ?? "unknown"}); retried next session`
|
|
20739
|
+
);
|
|
20740
|
+
}
|
|
20741
|
+
if ((result?.failedCount ?? 0) > 0 || failure !== void 0 && CONTENT_FAILURE_REASONS.has(failure.reason))
|
|
20742
|
+
throw new BatchFailureError("Extraction batch incomplete; retained for retry", false);
|
|
20743
|
+
throw new Error("Extraction batch incomplete; retained for retry");
|
|
20744
|
+
}
|
|
20745
|
+
await acknowledge(job, ids, loaded, false);
|
|
20578
20746
|
scheduleAfterSuccess = true;
|
|
20579
20747
|
} catch (error) {
|
|
20580
20748
|
attempts.set(job.id, attempted + 1);
|
|
20581
20749
|
retry = true;
|
|
20582
20750
|
reportError(error, conversationId);
|
|
20751
|
+
try {
|
|
20752
|
+
if (await recordFailure(job, ids, loaded, error, conversationId))
|
|
20753
|
+
scheduleAfterSuccess = true;
|
|
20754
|
+
} catch (recordError) {
|
|
20755
|
+
reportError(recordError, conversationId);
|
|
20756
|
+
}
|
|
20583
20757
|
}
|
|
20584
20758
|
}
|
|
20585
20759
|
} catch (error) {
|
|
@@ -20649,7 +20823,7 @@ function createDurableAutoExtractor(options) {
|
|
|
20649
20823
|
const start = boundary >= 0 ? boundary + 1 : Math.max(0, ids.length - Math.max(1, options.windowSize ?? 6));
|
|
20650
20824
|
if (start >= ids.length) return;
|
|
20651
20825
|
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));
|
|
20826
|
+
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
20827
|
const overlapStart = atOwnWatermark ? Math.max(0, boundary - 1) : start;
|
|
20654
20828
|
const fresh = ids.slice(overlapStart).filter((id) => !foreignSources.has(id));
|
|
20655
20829
|
if (!fresh.length) return;
|
|
@@ -21096,6 +21270,9 @@ var MANUAL_FACT_TYPES = [
|
|
|
21096
21270
|
function normalizeManualFactType(value) {
|
|
21097
21271
|
return typeof value === "string" && MANUAL_FACT_TYPES.includes(value) ? value : void 0;
|
|
21098
21272
|
}
|
|
21273
|
+
function isSharedScope(scope) {
|
|
21274
|
+
return scope === "shared";
|
|
21275
|
+
}
|
|
21099
21276
|
async function notifyWritten(options, input, outcome) {
|
|
21100
21277
|
try {
|
|
21101
21278
|
await options?.onWritten?.({ input, outcome });
|
|
@@ -21164,14 +21341,17 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
|
|
|
21164
21341
|
try {
|
|
21165
21342
|
const isUpdate = !!id;
|
|
21166
21343
|
let previousContent;
|
|
21344
|
+
const scope = options?.scope ?? "private";
|
|
21167
21345
|
if (isUpdate) {
|
|
21168
21346
|
const existing = await getVaultMemoryOp(vaultCtx, id);
|
|
21169
21347
|
if (!existing) {
|
|
21170
21348
|
return `Error: Memory with ID "${id}" not found. Creating a new memory instead would require a separate call without an ID.`;
|
|
21171
21349
|
}
|
|
21350
|
+
if (isSharedScope(existing.scope) !== isSharedScope(scope)) {
|
|
21351
|
+
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.`;
|
|
21352
|
+
}
|
|
21172
21353
|
previousContent = existing.content;
|
|
21173
21354
|
}
|
|
21174
|
-
const scope = options?.scope ?? "private";
|
|
21175
21355
|
const operation = {
|
|
21176
21356
|
action: isUpdate ? "update" : "add",
|
|
21177
21357
|
content,
|
|
@@ -25418,7 +25598,7 @@ __decorateClass([
|
|
|
25418
25598
|
], VaultFolder.prototype, "context", 2);
|
|
25419
25599
|
|
|
25420
25600
|
// src/lib/db/schema.ts
|
|
25421
|
-
var SDK_SCHEMA_VERSION =
|
|
25601
|
+
var SDK_SCHEMA_VERSION = 47;
|
|
25422
25602
|
var sdkSchema = (0, import_watermelondb22.appSchema)({
|
|
25423
25603
|
version: SDK_SCHEMA_VERSION,
|
|
25424
25604
|
tables: [
|
|
@@ -25434,7 +25614,11 @@ var sdkSchema = (0, import_watermelondb22.appSchema)({
|
|
|
25434
25614
|
// source. `watermark` alone is an id, and deleting that message erased
|
|
25435
25615
|
// the anchor — see the column note in extractionJobs/models.ts.
|
|
25436
25616
|
{ name: "watermark_seq", type: "number", isOptional: true },
|
|
25437
|
-
{ name: "folder_id", type: "string", isOptional: true }
|
|
25617
|
+
{ name: "folder_id", type: "string", isOptional: true },
|
|
25618
|
+
// Poison accounting for the head batch; see extractionJobs/models.ts.
|
|
25619
|
+
{ name: "failed_sessions", type: "number", isOptional: true },
|
|
25620
|
+
{ name: "failed_head", type: "string", isOptional: true },
|
|
25621
|
+
{ name: "failed_at", type: "number", isOptional: true }
|
|
25438
25622
|
]
|
|
25439
25623
|
}),
|
|
25440
25624
|
// Chat storage tables
|
|
@@ -26458,6 +26642,22 @@ var sdkMigrations = (0, import_migrations2.schemaMigrations)({
|
|
|
26458
26642
|
]
|
|
26459
26643
|
})
|
|
26460
26644
|
]
|
|
26645
|
+
},
|
|
26646
|
+
// v46 -> v47: persisted poison count (and when it was last counted) for a
|
|
26647
|
+
// durable-extraction job's head batch. NULL = never failed, which is right
|
|
26648
|
+
// for every existing row.
|
|
26649
|
+
{
|
|
26650
|
+
toVersion: 47,
|
|
26651
|
+
steps: [
|
|
26652
|
+
(0, import_migrations2.addColumns)({
|
|
26653
|
+
table: "memory_extraction_jobs",
|
|
26654
|
+
columns: [
|
|
26655
|
+
{ name: "failed_sessions", type: "number", isOptional: true },
|
|
26656
|
+
{ name: "failed_head", type: "string", isOptional: true },
|
|
26657
|
+
{ name: "failed_at", type: "number", isOptional: true }
|
|
26658
|
+
]
|
|
26659
|
+
})
|
|
26660
|
+
]
|
|
26461
26661
|
}
|
|
26462
26662
|
]
|
|
26463
26663
|
});
|