@anuma/sdk 6.25.1 → 6.25.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/expo/index.cjs +348 -148
- package/dist/expo/index.d.mts +34 -9
- package/dist/expo/index.d.ts +34 -9
- package/dist/expo/index.mjs +348 -148
- package/dist/react/index.cjs +348 -148
- package/dist/react/index.d.mts +34 -9
- package/dist/react/index.d.ts +34 -9
- package/dist/react/index.mjs +348 -148
- package/dist/server/index.cjs +348 -148
- package/dist/server/index.d.mts +34 -9
- package/dist/server/index.d.ts +34 -9
- package/dist/server/index.mjs +348 -148
- package/package.json +1 -1
package/dist/expo/index.mjs
CHANGED
|
@@ -9809,8 +9809,42 @@ async function vaultMemoryToStored(memory, walletAddress, signMessage, embeddedW
|
|
|
9809
9809
|
}
|
|
9810
9810
|
return raw;
|
|
9811
9811
|
}
|
|
9812
|
+
function populateNewVaultMemory(record, ctx, opts, encryptedContent) {
|
|
9813
|
+
record._setRaw("content", encryptedContent);
|
|
9814
|
+
record._setRaw("scope", opts.scope ?? "private");
|
|
9815
|
+
record._setRaw("folder_id", opts.folderId ?? null);
|
|
9816
|
+
record._setRaw("user_id", ctx.userId ?? null);
|
|
9817
|
+
record._setRaw("is_deleted", false);
|
|
9818
|
+
if (opts.embedding !== void 0) {
|
|
9819
|
+
record._setRaw("embedding", opts.embedding);
|
|
9820
|
+
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
9821
|
+
}
|
|
9822
|
+
if (opts.sourceChunkIds !== void 0) {
|
|
9823
|
+
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
9824
|
+
}
|
|
9825
|
+
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
9826
|
+
record._setRaw("source", opts.source ?? "manual");
|
|
9827
|
+
if (opts.eventTime) {
|
|
9828
|
+
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
9829
|
+
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
9830
|
+
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
9831
|
+
}
|
|
9832
|
+
if (opts.factType !== void 0) {
|
|
9833
|
+
record._setRaw("fact_type", opts.factType);
|
|
9834
|
+
}
|
|
9835
|
+
if (opts.trustTier !== void 0) {
|
|
9836
|
+
record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
9837
|
+
}
|
|
9838
|
+
record._setRaw("visibility", opts.visibility ?? "private");
|
|
9839
|
+
record._setRaw(
|
|
9840
|
+
"published_at",
|
|
9841
|
+
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
9842
|
+
);
|
|
9843
|
+
if (opts.geohash !== void 0) {
|
|
9844
|
+
record._setRaw("geohash", opts.geohash);
|
|
9845
|
+
}
|
|
9846
|
+
}
|
|
9812
9847
|
async function createVaultMemoryOp(ctx, opts) {
|
|
9813
|
-
const scope = opts.scope ?? "private";
|
|
9814
9848
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
9815
9849
|
opts.content,
|
|
9816
9850
|
ctx.walletAddress,
|
|
@@ -9820,47 +9854,14 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
9820
9854
|
const created = await ctx.database.write(async () => {
|
|
9821
9855
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
9822
9856
|
throw new Error("Memory source is no longer eligible");
|
|
9823
|
-
return ctx.vaultMemoryCollection.create(
|
|
9824
|
-
record
|
|
9825
|
-
|
|
9826
|
-
record._setRaw("folder_id", opts.folderId ?? null);
|
|
9827
|
-
record._setRaw("user_id", ctx.userId ?? null);
|
|
9828
|
-
record._setRaw("is_deleted", false);
|
|
9829
|
-
if (opts.embedding !== void 0) {
|
|
9830
|
-
record._setRaw("embedding", opts.embedding);
|
|
9831
|
-
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
9832
|
-
}
|
|
9833
|
-
if (opts.sourceChunkIds !== void 0) {
|
|
9834
|
-
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
9835
|
-
}
|
|
9836
|
-
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
9837
|
-
record._setRaw("source", opts.source ?? "manual");
|
|
9838
|
-
if (opts.eventTime) {
|
|
9839
|
-
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
9840
|
-
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
9841
|
-
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
9842
|
-
}
|
|
9843
|
-
if (opts.factType !== void 0) {
|
|
9844
|
-
record._setRaw("fact_type", opts.factType);
|
|
9845
|
-
}
|
|
9846
|
-
if (opts.trustTier !== void 0) {
|
|
9847
|
-
record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
9848
|
-
}
|
|
9849
|
-
record._setRaw("visibility", opts.visibility ?? "private");
|
|
9850
|
-
record._setRaw(
|
|
9851
|
-
"published_at",
|
|
9852
|
-
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
9853
|
-
);
|
|
9854
|
-
if (opts.geohash !== void 0) {
|
|
9855
|
-
record._setRaw("geohash", opts.geohash);
|
|
9856
|
-
}
|
|
9857
|
-
});
|
|
9857
|
+
return ctx.vaultMemoryCollection.create(
|
|
9858
|
+
(record) => populateNewVaultMemory(record, ctx, opts, encryptedContent)
|
|
9859
|
+
);
|
|
9858
9860
|
});
|
|
9859
9861
|
return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
9860
9862
|
}
|
|
9861
9863
|
async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
9862
9864
|
if (!targetId) return { created: null, retired: false };
|
|
9863
|
-
const scope = opts.scope ?? "private";
|
|
9864
9865
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
9865
9866
|
opts.content,
|
|
9866
9867
|
ctx.walletAddress,
|
|
@@ -9878,27 +9879,9 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
|
9878
9879
|
return;
|
|
9879
9880
|
}
|
|
9880
9881
|
if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target)) return;
|
|
9881
|
-
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
9882
|
-
record
|
|
9883
|
-
|
|
9884
|
-
record._setRaw("folder_id", opts.folderId ?? null);
|
|
9885
|
-
record._setRaw("user_id", ctx.userId ?? null);
|
|
9886
|
-
record._setRaw("is_deleted", false);
|
|
9887
|
-
if (opts.embedding !== void 0) {
|
|
9888
|
-
record._setRaw("embedding", opts.embedding);
|
|
9889
|
-
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
9890
|
-
}
|
|
9891
|
-
if (opts.sourceChunkIds !== void 0) {
|
|
9892
|
-
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
9893
|
-
}
|
|
9894
|
-
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
9895
|
-
record._setRaw("source", opts.source ?? "manual");
|
|
9896
|
-
if (opts.eventTime) {
|
|
9897
|
-
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
9898
|
-
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
9899
|
-
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
9900
|
-
}
|
|
9901
|
-
});
|
|
9882
|
+
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
9883
|
+
(record) => populateNewVaultMemory(record, ctx, opts, encryptedContent)
|
|
9884
|
+
);
|
|
9902
9885
|
await target.update((r) => {
|
|
9903
9886
|
r._setRaw("superseded_by", createdRecord.id);
|
|
9904
9887
|
r._setRaw("superseded_at", Date.now());
|
|
@@ -9978,41 +9961,9 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
9978
9961
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
9979
9962
|
throw new Error("Memory source is no longer eligible");
|
|
9980
9963
|
const prepared = optionsArray.map(
|
|
9981
|
-
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
9982
|
-
record
|
|
9983
|
-
|
|
9984
|
-
record._setRaw("folder_id", opts.folderId ?? null);
|
|
9985
|
-
record._setRaw("user_id", ctx.userId ?? null);
|
|
9986
|
-
record._setRaw("is_deleted", false);
|
|
9987
|
-
if (optionsArray[i].embedding !== void 0) {
|
|
9988
|
-
record._setRaw("embedding", optionsArray[i].embedding);
|
|
9989
|
-
record._setRaw("embedding_model", optionsArray[i].embeddingModel ?? null);
|
|
9990
|
-
}
|
|
9991
|
-
if (opts.sourceChunkIds !== void 0) {
|
|
9992
|
-
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
9993
|
-
}
|
|
9994
|
-
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
9995
|
-
record._setRaw("source", opts.source ?? "manual");
|
|
9996
|
-
if (opts.eventTime) {
|
|
9997
|
-
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
9998
|
-
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
9999
|
-
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
10000
|
-
}
|
|
10001
|
-
if (opts.factType !== void 0) {
|
|
10002
|
-
record._setRaw("fact_type", opts.factType);
|
|
10003
|
-
}
|
|
10004
|
-
if (opts.trustTier !== void 0) {
|
|
10005
|
-
record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
10006
|
-
}
|
|
10007
|
-
record._setRaw("visibility", opts.visibility ?? "private");
|
|
10008
|
-
record._setRaw(
|
|
10009
|
-
"published_at",
|
|
10010
|
-
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
10011
|
-
);
|
|
10012
|
-
if (opts.geohash !== void 0) {
|
|
10013
|
-
record._setRaw("geohash", opts.geohash);
|
|
10014
|
-
}
|
|
10015
|
-
})
|
|
9964
|
+
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
9965
|
+
(record) => populateNewVaultMemory(record, ctx, opts, encryptedContents[i])
|
|
9966
|
+
)
|
|
10016
9967
|
);
|
|
10017
9968
|
await ctx.database.batch(...prepared);
|
|
10018
9969
|
return prepared;
|
|
@@ -10833,21 +10784,73 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
|
10833
10784
|
return false;
|
|
10834
10785
|
}
|
|
10835
10786
|
}
|
|
10836
|
-
async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel) {
|
|
10787
|
+
async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel, expected) {
|
|
10837
10788
|
try {
|
|
10838
10789
|
const record = await ctx.vaultMemoryCollection.find(id);
|
|
10839
10790
|
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
|
|
10791
|
+
const readUpdatedAt = record.updatedAt.getTime();
|
|
10792
|
+
const readStoredContent = record._getRaw("content");
|
|
10793
|
+
if (expected?.updatedAt !== void 0 && expected.updatedAt !== readUpdatedAt) return false;
|
|
10794
|
+
if (expected?.content !== void 0) {
|
|
10795
|
+
const current = await vaultMemoryToStored(
|
|
10796
|
+
record,
|
|
10797
|
+
ctx.walletAddress,
|
|
10798
|
+
ctx.signMessage,
|
|
10799
|
+
ctx.embeddedWalletSigner
|
|
10800
|
+
);
|
|
10801
|
+
if (current.content !== expected.content) return false;
|
|
10802
|
+
}
|
|
10803
|
+
let written = false;
|
|
10840
10804
|
await ctx.database.write(async () => {
|
|
10805
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return;
|
|
10806
|
+
const originalUpdatedAt = record.updatedAt.getTime();
|
|
10807
|
+
if (originalUpdatedAt !== readUpdatedAt || record._getRaw("content") !== readStoredContent)
|
|
10808
|
+
return;
|
|
10841
10809
|
await record.update((r) => {
|
|
10842
10810
|
r._setRaw("embedding", embedding);
|
|
10843
10811
|
r._setRaw("embedding_model", embeddingModel);
|
|
10812
|
+
r._setRaw("updated_at", originalUpdatedAt);
|
|
10844
10813
|
});
|
|
10814
|
+
written = true;
|
|
10845
10815
|
});
|
|
10846
|
-
return
|
|
10816
|
+
return written;
|
|
10847
10817
|
} catch {
|
|
10848
10818
|
return false;
|
|
10849
10819
|
}
|
|
10850
10820
|
}
|
|
10821
|
+
function normalizeForDedupe(content) {
|
|
10822
|
+
return content.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
|
|
10823
|
+
}
|
|
10824
|
+
async function findQuarantinedDuplicateOp(ctx, content, sourceIds, where) {
|
|
10825
|
+
const wanted = [...new Set(sourceIds)].sort().join("\0");
|
|
10826
|
+
const target = normalizeForDedupe(content);
|
|
10827
|
+
const rows = await ctx.vaultMemoryCollection.query(
|
|
10828
|
+
Q5.where("trust_tier", "quarantined"),
|
|
10829
|
+
Q5.where("is_deleted", false),
|
|
10830
|
+
Q5.where("scope", where.scope),
|
|
10831
|
+
Q5.where("folder_id", where.folderId),
|
|
10832
|
+
...ctx.userId !== void 0 ? [Q5.where("user_id", ctx.userId)] : []
|
|
10833
|
+
).unsafeFetchRaw();
|
|
10834
|
+
for (const raw of rows) {
|
|
10835
|
+
let ids;
|
|
10836
|
+
try {
|
|
10837
|
+
ids = JSON.parse(raw.source_chunk_ids ?? "[]");
|
|
10838
|
+
} catch {
|
|
10839
|
+
continue;
|
|
10840
|
+
}
|
|
10841
|
+
if (!Array.isArray(ids)) continue;
|
|
10842
|
+
const key = [...new Set(ids.filter((id) => typeof id === "string"))].sort().join("\0");
|
|
10843
|
+
if (key !== wanted) continue;
|
|
10844
|
+
const stored = await vaultMemoryRawToStored(
|
|
10845
|
+
raw,
|
|
10846
|
+
ctx.walletAddress,
|
|
10847
|
+
ctx.signMessage,
|
|
10848
|
+
ctx.embeddedWalletSigner
|
|
10849
|
+
);
|
|
10850
|
+
if (normalizeForDedupe(stored.content) === target) return stored.uniqueId;
|
|
10851
|
+
}
|
|
10852
|
+
return null;
|
|
10853
|
+
}
|
|
10851
10854
|
|
|
10852
10855
|
// src/lib/memory/decay.ts
|
|
10853
10856
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -10871,6 +10874,10 @@ var DEFAULT_DECAY_POLICY = {
|
|
|
10871
10874
|
hardDeleteWindowMs: HARD_DELETE_WINDOW_MS,
|
|
10872
10875
|
pastEventGraceMs: PAST_EVENT_GRACE_MS
|
|
10873
10876
|
};
|
|
10877
|
+
function lastActivityAt(m) {
|
|
10878
|
+
const observedAt = Number.isFinite(m.lastObservedAt) ? m.lastObservedAt : m.updatedAt;
|
|
10879
|
+
return Math.max(m.updatedAt, observedAt);
|
|
10880
|
+
}
|
|
10874
10881
|
function resolvePolicy(policy) {
|
|
10875
10882
|
if (!policy) return DEFAULT_DECAY_POLICY;
|
|
10876
10883
|
return {
|
|
@@ -10910,8 +10917,7 @@ function classifyDecay(m, now, policy) {
|
|
|
10910
10917
|
if (m.eventTimeEnd < now - resolved.pastEventGraceMs) return "archive";
|
|
10911
10918
|
if (m.eventTimeEnd >= now) return "keep";
|
|
10912
10919
|
}
|
|
10913
|
-
|
|
10914
|
-
if (now - Math.max(m.updatedAt, observedAt) > ttlForType(m.factType, resolved)) return "archive";
|
|
10920
|
+
if (now - lastActivityAt(m) > ttlForType(m.factType, resolved)) return "archive";
|
|
10915
10921
|
return "keep";
|
|
10916
10922
|
}
|
|
10917
10923
|
|
|
@@ -14251,6 +14257,24 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
14251
14257
|
const tRetain = Date.now();
|
|
14252
14258
|
for (const { candidate, isQuarantined, reason, signature } of toRetain) {
|
|
14253
14259
|
try {
|
|
14260
|
+
if (isQuarantined) {
|
|
14261
|
+
const existingId = await findQuarantinedDuplicateOp(
|
|
14262
|
+
retainCtx.vaultCtx,
|
|
14263
|
+
candidate.content,
|
|
14264
|
+
candidate.sourceMessageIds,
|
|
14265
|
+
// The same defaults retain() writes the row with.
|
|
14266
|
+
{ scope: options.scope ?? "private", folderId: options.folderId ?? null }
|
|
14267
|
+
).catch(() => null);
|
|
14268
|
+
if (existingId) {
|
|
14269
|
+
quarantinedInfo.push({
|
|
14270
|
+
candidate,
|
|
14271
|
+
memoryId: existingId,
|
|
14272
|
+
reason,
|
|
14273
|
+
signature
|
|
14274
|
+
});
|
|
14275
|
+
continue;
|
|
14276
|
+
}
|
|
14277
|
+
}
|
|
14254
14278
|
const result = await retain(candidate.content, retainCtx, {
|
|
14255
14279
|
source: "auto-extracted",
|
|
14256
14280
|
sourceChunkIds: candidate.sourceMessageIds,
|
|
@@ -14696,7 +14720,7 @@ function createLlmDecayClassifier(options) {
|
|
|
14696
14720
|
if (!content || content.trim().length === 0) return ruleVerdict;
|
|
14697
14721
|
const trimmed = content.trim().slice(0, MAX_CONTENT_CHARS);
|
|
14698
14722
|
const safe = redactor ? (await redactor.redactTextAsync(trimmed)).text : trimmed;
|
|
14699
|
-
const meta = `factType: ${input.factType ?? "none"}; ageDays: ${ageDays(input
|
|
14723
|
+
const meta = `factType: ${input.factType ?? "none"}; ageDays: ${ageDays(lastActivityAt(input), now)}`;
|
|
14700
14724
|
let parsed;
|
|
14701
14725
|
try {
|
|
14702
14726
|
parsed = await callPortalJsonCompletion({
|
|
@@ -14729,9 +14753,9 @@ Should this be kept or archived?`,
|
|
|
14729
14753
|
}
|
|
14730
14754
|
};
|
|
14731
14755
|
}
|
|
14732
|
-
function ageDays(
|
|
14733
|
-
if (!Number.isFinite(
|
|
14734
|
-
return Math.max(0, Math.floor((now -
|
|
14756
|
+
function ageDays(activityAt, now) {
|
|
14757
|
+
if (!Number.isFinite(activityAt) || !Number.isFinite(now)) return 0;
|
|
14758
|
+
return Math.max(0, Math.floor((now - activityAt) / (24 * 60 * 60 * 1e3)));
|
|
14735
14759
|
}
|
|
14736
14760
|
function parseVerdict(parsed) {
|
|
14737
14761
|
if (typeof parsed !== "object" || parsed === null) return null;
|
|
@@ -14784,7 +14808,7 @@ function createDecaySweeper(options) {
|
|
|
14784
14808
|
if (!classifier || !isBorderline(input)) return ruleVerdict;
|
|
14785
14809
|
if (input.id) {
|
|
14786
14810
|
const cached = classifierCache.get(input.id);
|
|
14787
|
-
if (cached && cached.
|
|
14811
|
+
if (cached && cached.activityAt === lastActivityAt(input)) return cached.verdict;
|
|
14788
14812
|
}
|
|
14789
14813
|
if (sweep.classifierCalls >= maxClassifierCalls) {
|
|
14790
14814
|
if (!sweep.ceilingLogged) {
|
|
@@ -14798,7 +14822,7 @@ function createDecaySweeper(options) {
|
|
|
14798
14822
|
sweep.classifierCalls++;
|
|
14799
14823
|
try {
|
|
14800
14824
|
const verdict = await classifier.classify(input, ruleVerdict, now);
|
|
14801
|
-
if (input.id) classifierCache.set(input.id, {
|
|
14825
|
+
if (input.id) classifierCache.set(input.id, { activityAt: lastActivityAt(input), verdict });
|
|
14802
14826
|
return verdict;
|
|
14803
14827
|
} catch (err) {
|
|
14804
14828
|
getLogger().warn(
|
|
@@ -16525,7 +16549,10 @@ function reviewedMemoryIdsSignature(ids) {
|
|
|
16525
16549
|
return [...new Set(ids)].sort().join("\n");
|
|
16526
16550
|
}
|
|
16527
16551
|
function facetsSignature(facets) {
|
|
16528
|
-
return
|
|
16552
|
+
return [
|
|
16553
|
+
JSON.stringify(FACET_SYSTEM_PROMPT),
|
|
16554
|
+
...facets.map((f) => JSON.stringify([f.key, f.label, f.query, f.guidance, facetResponseSchema(f.key)])).sort()
|
|
16555
|
+
].join("\n");
|
|
16529
16556
|
}
|
|
16530
16557
|
function trendsEqual(a, b) {
|
|
16531
16558
|
if (!a) return false;
|
|
@@ -16747,7 +16774,7 @@ var FACET_SYSTEM_PROMPT = `You are writing one section of a person's shareable p
|
|
|
16747
16774
|
Rules:
|
|
16748
16775
|
- Ground every claim in the supplied memories \u2014 never invent, infer beyond, or embellish what they support.
|
|
16749
16776
|
- If the memories don't cover this section, return an empty summary with hasEvidence=false. Do not pad or guess.
|
|
16750
|
-
- Write in
|
|
16777
|
+
- 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.
|
|
16751
16778
|
- Be concise and specific; no preamble, hedging, or meta-commentary.
|
|
16752
16779
|
- Respond as JSON in exactly the shape the user turn states, with no extra fields.`;
|
|
16753
16780
|
function buildFacetUserInstructions(facet) {
|
|
@@ -17416,6 +17443,37 @@ async function assembleMemoryContext(options) {
|
|
|
17416
17443
|
import { Q as Q7 } from "@nozbe/watermelondb";
|
|
17417
17444
|
var MAX_JOBS_PER_PASS = 3;
|
|
17418
17445
|
var MAX_ATTEMPTS = 3;
|
|
17446
|
+
var MAX_FAILED_SESSIONS = 3;
|
|
17447
|
+
var MIN_FAILED_SESSION_GAP_MS = 60 * 60 * 1e3;
|
|
17448
|
+
var REQUEST_REJECTED_STATUSES = /* @__PURE__ */ new Set([400, 404, 413, 422]);
|
|
17449
|
+
var CONTENT_FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
17450
|
+
"empty-content",
|
|
17451
|
+
"invalid-json",
|
|
17452
|
+
"null-completion",
|
|
17453
|
+
"body-parse-failed"
|
|
17454
|
+
]);
|
|
17455
|
+
var BACKOFF_ALLOWANCE_MS = 2100;
|
|
17456
|
+
var RETAIN_BUDGET_MS = 12e4;
|
|
17457
|
+
function defaultBatchTimeoutMs(extract) {
|
|
17458
|
+
const attempts = Math.max(1, extract.maxAttempts ?? 3);
|
|
17459
|
+
const calls = (extract.timeoutMs ?? 6e4) * attempts + BACKOFF_ALLOWANCE_MS * (attempts - 1);
|
|
17460
|
+
const extraction = extract.totalTimeoutMs !== void 0 ? Math.min(extract.totalTimeoutMs, calls) : calls;
|
|
17461
|
+
return extraction + RETAIN_BUDGET_MS;
|
|
17462
|
+
}
|
|
17463
|
+
var BatchFailureError = class extends Error {
|
|
17464
|
+
constructor(message, terminal) {
|
|
17465
|
+
super(message);
|
|
17466
|
+
this.terminal = terminal;
|
|
17467
|
+
}
|
|
17468
|
+
};
|
|
17469
|
+
var AccountFailureError = class extends Error {
|
|
17470
|
+
};
|
|
17471
|
+
var LockedSourcesError = class extends Error {
|
|
17472
|
+
constructor(persistentIds) {
|
|
17473
|
+
super("Source messages are locked; retained for retry");
|
|
17474
|
+
this.persistentIds = persistentIds;
|
|
17475
|
+
}
|
|
17476
|
+
};
|
|
17419
17477
|
function idsOf(job) {
|
|
17420
17478
|
return JSON.parse(String(job._getRaw("message_ids")));
|
|
17421
17479
|
}
|
|
@@ -17423,6 +17481,16 @@ function seqOf(job) {
|
|
|
17423
17481
|
const raw = job._getRaw("watermark_seq");
|
|
17424
17482
|
return typeof raw === "number" && raw > 0 ? raw : void 0;
|
|
17425
17483
|
}
|
|
17484
|
+
function failedSessionsOf(job, head) {
|
|
17485
|
+
if (job._getRaw("failed_head") !== head) return 0;
|
|
17486
|
+
const raw = job._getRaw("failed_sessions");
|
|
17487
|
+
return typeof raw === "number" && raw > 0 ? raw : 0;
|
|
17488
|
+
}
|
|
17489
|
+
function failedAtOf(job, head) {
|
|
17490
|
+
if (job._getRaw("failed_head") !== head) return void 0;
|
|
17491
|
+
const raw = job._getRaw("failed_at");
|
|
17492
|
+
return typeof raw === "number" ? raw : void 0;
|
|
17493
|
+
}
|
|
17426
17494
|
function createDurableAutoExtractor(options) {
|
|
17427
17495
|
const vault = options.retainCtx.vaultCtx;
|
|
17428
17496
|
const database = vault.database;
|
|
@@ -17445,6 +17513,9 @@ function createDurableAutoExtractor(options) {
|
|
|
17445
17513
|
let writes = Promise.resolve();
|
|
17446
17514
|
let storeFailures = 0;
|
|
17447
17515
|
const attempts = /* @__PURE__ */ new Map();
|
|
17516
|
+
const sessionFailures = /* @__PURE__ */ new Map();
|
|
17517
|
+
const skippedThisSession = /* @__PURE__ */ new Set();
|
|
17518
|
+
const clock = options.now ?? Date.now;
|
|
17448
17519
|
const reportError = (error, conversationId) => {
|
|
17449
17520
|
try {
|
|
17450
17521
|
options.onError?.(error instanceof Error ? error : new Error(String(error)), conversationId);
|
|
@@ -17473,6 +17544,7 @@ function createDurableAutoExtractor(options) {
|
|
|
17473
17544
|
}
|
|
17474
17545
|
async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
|
|
17475
17546
|
let watchdog;
|
|
17547
|
+
let cancelled = false;
|
|
17476
17548
|
const model = options.modelForScope?.(jobScope) ?? options.extract.model;
|
|
17477
17549
|
try {
|
|
17478
17550
|
return await Promise.race([
|
|
@@ -17483,7 +17555,7 @@ function createDurableAutoExtractor(options) {
|
|
|
17483
17555
|
...options.retainCtx,
|
|
17484
17556
|
vaultCtx: {
|
|
17485
17557
|
...vault,
|
|
17486
|
-
canWrite: async () => !disposed && await storage.conversationsCollection.query(Q7.where("conversation_id", conversationId), Q7.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(Q7.where("conversation_id", conversationId), Q7.where("id", Q7.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed
|
|
17558
|
+
canWrite: async () => !disposed && !cancelled && await storage.conversationsCollection.query(Q7.where("conversation_id", conversationId), Q7.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(Q7.where("conversation_id", conversationId), Q7.where("id", Q7.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed && !cancelled
|
|
17487
17559
|
}
|
|
17488
17560
|
},
|
|
17489
17561
|
// The model follows the job's scope, not the mode alive at drain time.
|
|
@@ -17503,14 +17575,116 @@ function createDurableAutoExtractor(options) {
|
|
|
17503
17575
|
new Promise((_resolve, reject) => {
|
|
17504
17576
|
watchdog = setTimeout(
|
|
17505
17577
|
() => reject(new Error("Extraction did not settle in time; retained for retry")),
|
|
17506
|
-
options.batchTimeoutMs ??
|
|
17578
|
+
options.batchTimeoutMs ?? defaultBatchTimeoutMs(options.extract)
|
|
17507
17579
|
);
|
|
17508
17580
|
})
|
|
17509
17581
|
]);
|
|
17510
17582
|
} finally {
|
|
17583
|
+
cancelled = true;
|
|
17511
17584
|
if (watchdog !== void 0) clearTimeout(watchdog);
|
|
17512
17585
|
}
|
|
17513
17586
|
}
|
|
17587
|
+
async function acknowledge(job, ids, loaded, abandoned) {
|
|
17588
|
+
attempts.delete(job.id);
|
|
17589
|
+
sessionFailures.delete(job.id);
|
|
17590
|
+
skippedThisSession.delete(job.id);
|
|
17591
|
+
const sequences = /* @__PURE__ */ new Map();
|
|
17592
|
+
for (const message of loaded)
|
|
17593
|
+
if (message && message.messageId > 0) sequences.set(message.uniqueId, message.messageId);
|
|
17594
|
+
await database.write(async () => {
|
|
17595
|
+
const current = idsOf(job);
|
|
17596
|
+
const acknowledged = ids.filter((id) => current.includes(id));
|
|
17597
|
+
if (!acknowledged.length) return;
|
|
17598
|
+
const done = new Set(acknowledged);
|
|
17599
|
+
const remaining = current.filter((id) => !done.has(id));
|
|
17600
|
+
await job.update((r) => {
|
|
17601
|
+
r._setRaw(
|
|
17602
|
+
"message_ids",
|
|
17603
|
+
JSON.stringify(
|
|
17604
|
+
remaining.length ? [...abandoned ? [] : acknowledged.slice(-2), ...remaining] : []
|
|
17605
|
+
)
|
|
17606
|
+
);
|
|
17607
|
+
const newest = acknowledged[acknowledged.length - 1];
|
|
17608
|
+
r._setRaw("watermark", newest);
|
|
17609
|
+
const sequence = sequences.get(newest);
|
|
17610
|
+
if (sequence !== void 0) {
|
|
17611
|
+
const prior = seqOf(job);
|
|
17612
|
+
r._setRaw("watermark_seq", prior === void 0 ? sequence : Math.max(prior, sequence));
|
|
17613
|
+
}
|
|
17614
|
+
r._setRaw("failed_sessions", abandoned ? MAX_FAILED_SESSIONS : null);
|
|
17615
|
+
r._setRaw("failed_head", abandoned ? newest : null);
|
|
17616
|
+
r._setRaw("failed_at", null);
|
|
17617
|
+
});
|
|
17618
|
+
});
|
|
17619
|
+
}
|
|
17620
|
+
async function recordFailure(job, ids, loaded, error, conversationId) {
|
|
17621
|
+
const head = ids[0];
|
|
17622
|
+
if (!head || !loaded.some(Boolean)) return false;
|
|
17623
|
+
if (error instanceof AccountFailureError) {
|
|
17624
|
+
skippedThisSession.add(job.id);
|
|
17625
|
+
return false;
|
|
17626
|
+
}
|
|
17627
|
+
const counted = error instanceof BatchFailureError || error instanceof LockedSourcesError && error.persistentIds.length > 0;
|
|
17628
|
+
if (!counted) return false;
|
|
17629
|
+
const prior = sessionFailures.get(job.id);
|
|
17630
|
+
const count = prior?.head === head ? prior.count + 1 : 1;
|
|
17631
|
+
sessionFailures.set(job.id, { head, count });
|
|
17632
|
+
const terminal = error instanceof BatchFailureError && error.terminal;
|
|
17633
|
+
if (!terminal && count < MAX_ATTEMPTS) return false;
|
|
17634
|
+
skippedThisSession.add(job.id);
|
|
17635
|
+
const now = clock();
|
|
17636
|
+
const lastCounted = failedAtOf(job, head);
|
|
17637
|
+
if (lastCounted !== void 0 && now - lastCounted < MIN_FAILED_SESSION_GAP_MS) return false;
|
|
17638
|
+
const failures = failedSessionsOf(job, head) + 1;
|
|
17639
|
+
if (failures < MAX_FAILED_SESSIONS) {
|
|
17640
|
+
await database.write(
|
|
17641
|
+
() => job.update((r) => {
|
|
17642
|
+
r._setRaw("failed_sessions", failures);
|
|
17643
|
+
r._setRaw("failed_head", head);
|
|
17644
|
+
r._setRaw("failed_at", now);
|
|
17645
|
+
})
|
|
17646
|
+
);
|
|
17647
|
+
return false;
|
|
17648
|
+
}
|
|
17649
|
+
if (error instanceof LockedSourcesError) {
|
|
17650
|
+
const dropped = new Set(error.persistentIds);
|
|
17651
|
+
let newest;
|
|
17652
|
+
for (const message of loaded)
|
|
17653
|
+
if (message && dropped.has(message.uniqueId) && message.messageId > (newest?.seq ?? 0))
|
|
17654
|
+
newest = { id: message.uniqueId, seq: message.messageId };
|
|
17655
|
+
const advance = newest !== void 0 && newest.seq > (seqOf(job) ?? 0) ? newest : void 0;
|
|
17656
|
+
await database.write(
|
|
17657
|
+
() => job.update((r) => {
|
|
17658
|
+
r._setRaw("message_ids", JSON.stringify(idsOf(job).filter((id) => !dropped.has(id))));
|
|
17659
|
+
if (advance) {
|
|
17660
|
+
r._setRaw("watermark", advance.id);
|
|
17661
|
+
r._setRaw("watermark_seq", advance.seq);
|
|
17662
|
+
}
|
|
17663
|
+
r._setRaw("failed_sessions", advance ? MAX_FAILED_SESSIONS : null);
|
|
17664
|
+
r._setRaw("failed_head", advance ? advance.id : null);
|
|
17665
|
+
r._setRaw("failed_at", null);
|
|
17666
|
+
})
|
|
17667
|
+
);
|
|
17668
|
+
attempts.delete(job.id);
|
|
17669
|
+
sessionFailures.delete(job.id);
|
|
17670
|
+
skippedThisSession.delete(job.id);
|
|
17671
|
+
reportError(
|
|
17672
|
+
new Error(
|
|
17673
|
+
`Dropped ${dropped.size} source id(s) that stayed locked for ${failures} sessions to unblock extraction`
|
|
17674
|
+
),
|
|
17675
|
+
conversationId
|
|
17676
|
+
);
|
|
17677
|
+
return true;
|
|
17678
|
+
}
|
|
17679
|
+
await acknowledge(job, ids, loaded, true);
|
|
17680
|
+
reportError(
|
|
17681
|
+
new Error(
|
|
17682
|
+
`Abandoned an extraction batch of ${ids.length} source id(s) after it failed in ${failures} sessions`
|
|
17683
|
+
),
|
|
17684
|
+
conversationId
|
|
17685
|
+
);
|
|
17686
|
+
return true;
|
|
17687
|
+
}
|
|
17514
17688
|
async function drain() {
|
|
17515
17689
|
if (disposed || running) return;
|
|
17516
17690
|
running = true;
|
|
@@ -17525,21 +17699,23 @@ function createDurableAutoExtractor(options) {
|
|
|
17525
17699
|
for (const job of pending) {
|
|
17526
17700
|
if (disposed) break;
|
|
17527
17701
|
const attempted = attempts.get(job.id) ?? 0;
|
|
17528
|
-
if (attempted >= MAX_ATTEMPTS) continue;
|
|
17702
|
+
if (attempted >= MAX_ATTEMPTS || skippedThisSession.has(job.id)) continue;
|
|
17529
17703
|
if (processed >= MAX_JOBS_PER_PASS) {
|
|
17530
17704
|
scheduleAfterSuccess = true;
|
|
17531
17705
|
break;
|
|
17532
17706
|
}
|
|
17533
17707
|
processed++;
|
|
17534
17708
|
const conversationId = String(job._getRaw("conversation_id"));
|
|
17709
|
+
let ids = [];
|
|
17710
|
+
let loaded = [];
|
|
17535
17711
|
try {
|
|
17536
17712
|
const conversations = await storage.conversationsCollection.query(Q7.where("conversation_id", conversationId), Q7.where("is_deleted", false)).fetchCount();
|
|
17537
17713
|
if (!conversations) {
|
|
17538
17714
|
await database.write(() => job.destroyPermanently());
|
|
17539
17715
|
continue;
|
|
17540
17716
|
}
|
|
17541
|
-
|
|
17542
|
-
|
|
17717
|
+
ids = idsOf(job).slice(0, 20);
|
|
17718
|
+
loaded = await Promise.all(ids.map((id) => getMessageOp(storage, id)));
|
|
17543
17719
|
const missing = ids.filter((_id, index) => loaded[index] === null);
|
|
17544
17720
|
if (missing.length) {
|
|
17545
17721
|
if (attempted < MAX_ATTEMPTS - 1)
|
|
@@ -17563,17 +17739,21 @@ function createDurableAutoExtractor(options) {
|
|
|
17563
17739
|
);
|
|
17564
17740
|
continue;
|
|
17565
17741
|
}
|
|
17566
|
-
|
|
17567
|
-
|
|
17568
|
-
|
|
17569
|
-
|
|
17742
|
+
const locked = loaded.filter((message) => message && isEncrypted(message.content));
|
|
17743
|
+
if (locked.length) {
|
|
17744
|
+
throw new LockedSourcesError(
|
|
17745
|
+
locked.flatMap(
|
|
17746
|
+
(message) => message.decryptionStatus === "auth_mismatch" || message.decryptionStatus === "invalid_payload" ? [message.uniqueId] : []
|
|
17747
|
+
)
|
|
17748
|
+
);
|
|
17570
17749
|
}
|
|
17571
17750
|
const messages = loaded.flatMap(
|
|
17572
17751
|
(m) => m && m.conversationId === conversationId && (m.role === "user" || m.role === "assistant") ? [{ id: m.uniqueId, role: m.role, content: m.content }] : []
|
|
17573
17752
|
);
|
|
17574
17753
|
let success = messages.length === 0;
|
|
17754
|
+
let result;
|
|
17575
17755
|
if (messages.length) {
|
|
17576
|
-
|
|
17756
|
+
result = await extractBatch(
|
|
17577
17757
|
messages,
|
|
17578
17758
|
conversationId,
|
|
17579
17759
|
ids,
|
|
@@ -17583,41 +17763,35 @@ function createDurableAutoExtractor(options) {
|
|
|
17583
17763
|
success = result.failedCount === 0 && result.outcome !== "empty-after-retry";
|
|
17584
17764
|
options.onTurnComplete?.(result);
|
|
17585
17765
|
}
|
|
17586
|
-
if (!success)
|
|
17587
|
-
|
|
17588
|
-
|
|
17589
|
-
|
|
17590
|
-
|
|
17591
|
-
|
|
17592
|
-
|
|
17593
|
-
|
|
17594
|
-
const acknowledged = ids.filter((id) => current.includes(id));
|
|
17595
|
-
if (!acknowledged.length) return;
|
|
17596
|
-
const done = new Set(acknowledged);
|
|
17597
|
-
const remaining = current.filter((id) => !done.has(id));
|
|
17598
|
-
if (remaining.length) {
|
|
17599
|
-
await job.update(
|
|
17600
|
-
(r) => r._setRaw("message_ids", JSON.stringify([...acknowledged.slice(-2), ...remaining]))
|
|
17601
|
-
);
|
|
17602
|
-
} else await job.update((r) => r._setRaw("message_ids", "[]"));
|
|
17603
|
-
const newest = acknowledged[acknowledged.length - 1];
|
|
17604
|
-
await job.update((r) => {
|
|
17605
|
-
r._setRaw("watermark", newest);
|
|
17606
|
-
const sequence = sequences.get(newest);
|
|
17607
|
-
if (sequence !== void 0) {
|
|
17608
|
-
const prior = seqOf(job);
|
|
17609
|
-
r._setRaw(
|
|
17610
|
-
"watermark_seq",
|
|
17611
|
-
prior === void 0 ? sequence : Math.max(prior, sequence)
|
|
17766
|
+
if (!success) {
|
|
17767
|
+
const failure = result?.failure;
|
|
17768
|
+
if (failure?.reason === "http-terminal") {
|
|
17769
|
+
const status = failure.httpStatus;
|
|
17770
|
+
if (status !== void 0 && REQUEST_REJECTED_STATUSES.has(status))
|
|
17771
|
+
throw new BatchFailureError(
|
|
17772
|
+
`Extraction rejected the batch (HTTP ${status}); not retried this session`,
|
|
17773
|
+
true
|
|
17612
17774
|
);
|
|
17613
|
-
|
|
17614
|
-
|
|
17615
|
-
|
|
17775
|
+
throw new AccountFailureError(
|
|
17776
|
+
`Extraction refused for the account (HTTP ${status ?? "unknown"}); retried next session`
|
|
17777
|
+
);
|
|
17778
|
+
}
|
|
17779
|
+
if ((result?.failedCount ?? 0) > 0 || failure !== void 0 && CONTENT_FAILURE_REASONS.has(failure.reason))
|
|
17780
|
+
throw new BatchFailureError("Extraction batch incomplete; retained for retry", false);
|
|
17781
|
+
throw new Error("Extraction batch incomplete; retained for retry");
|
|
17782
|
+
}
|
|
17783
|
+
await acknowledge(job, ids, loaded, false);
|
|
17616
17784
|
scheduleAfterSuccess = true;
|
|
17617
17785
|
} catch (error) {
|
|
17618
17786
|
attempts.set(job.id, attempted + 1);
|
|
17619
17787
|
retry = true;
|
|
17620
17788
|
reportError(error, conversationId);
|
|
17789
|
+
try {
|
|
17790
|
+
if (await recordFailure(job, ids, loaded, error, conversationId))
|
|
17791
|
+
scheduleAfterSuccess = true;
|
|
17792
|
+
} catch (recordError) {
|
|
17793
|
+
reportError(recordError, conversationId);
|
|
17794
|
+
}
|
|
17621
17795
|
}
|
|
17622
17796
|
}
|
|
17623
17797
|
} catch (error) {
|
|
@@ -17687,7 +17861,7 @@ function createDurableAutoExtractor(options) {
|
|
|
17687
17861
|
const start = boundary >= 0 ? boundary + 1 : Math.max(0, ids.length - Math.max(1, options.windowSize ?? 6));
|
|
17688
17862
|
if (start >= ids.length) return;
|
|
17689
17863
|
const ownWatermark = job?._getRaw("watermark");
|
|
17690
|
-
const atOwnWatermark = !!job && boundary >= 0 && (ids[boundary] === ownWatermark || sequences.get(ids[boundary]) !== void 0 && sequences.get(ids[boundary]) === seqOf(job));
|
|
17864
|
+
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));
|
|
17691
17865
|
const overlapStart = atOwnWatermark ? Math.max(0, boundary - 1) : start;
|
|
17692
17866
|
const fresh = ids.slice(overlapStart).filter((id) => !foreignSources.has(id));
|
|
17693
17867
|
if (!fresh.length) return;
|
|
@@ -18134,6 +18308,9 @@ var MANUAL_FACT_TYPES = [
|
|
|
18134
18308
|
function normalizeManualFactType(value) {
|
|
18135
18309
|
return typeof value === "string" && MANUAL_FACT_TYPES.includes(value) ? value : void 0;
|
|
18136
18310
|
}
|
|
18311
|
+
function isSharedScope(scope) {
|
|
18312
|
+
return scope === "shared";
|
|
18313
|
+
}
|
|
18137
18314
|
async function notifyWritten(options, input, outcome) {
|
|
18138
18315
|
try {
|
|
18139
18316
|
await options?.onWritten?.({ input, outcome });
|
|
@@ -18202,14 +18379,17 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
|
|
|
18202
18379
|
try {
|
|
18203
18380
|
const isUpdate = !!id;
|
|
18204
18381
|
let previousContent;
|
|
18382
|
+
const scope = options?.scope ?? "private";
|
|
18205
18383
|
if (isUpdate) {
|
|
18206
18384
|
const existing = await getVaultMemoryOp(vaultCtx, id);
|
|
18207
18385
|
if (!existing) {
|
|
18208
18386
|
return `Error: Memory with ID "${id}" not found. Creating a new memory instead would require a separate call without an ID.`;
|
|
18209
18387
|
}
|
|
18388
|
+
if (isSharedScope(existing.scope) !== isSharedScope(scope)) {
|
|
18389
|
+
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.`;
|
|
18390
|
+
}
|
|
18210
18391
|
previousContent = existing.content;
|
|
18211
18392
|
}
|
|
18212
|
-
const scope = options?.scope ?? "private";
|
|
18213
18393
|
const operation = {
|
|
18214
18394
|
action: isUpdate ? "update" : "add",
|
|
18215
18395
|
content,
|
|
@@ -21269,7 +21449,7 @@ __decorateClass([
|
|
|
21269
21449
|
], VaultFolder.prototype, "context", 2);
|
|
21270
21450
|
|
|
21271
21451
|
// src/lib/db/schema.ts
|
|
21272
|
-
var SDK_SCHEMA_VERSION =
|
|
21452
|
+
var SDK_SCHEMA_VERSION = 47;
|
|
21273
21453
|
var sdkSchema = appSchema2({
|
|
21274
21454
|
version: SDK_SCHEMA_VERSION,
|
|
21275
21455
|
tables: [
|
|
@@ -21285,7 +21465,11 @@ var sdkSchema = appSchema2({
|
|
|
21285
21465
|
// source. `watermark` alone is an id, and deleting that message erased
|
|
21286
21466
|
// the anchor — see the column note in extractionJobs/models.ts.
|
|
21287
21467
|
{ name: "watermark_seq", type: "number", isOptional: true },
|
|
21288
|
-
{ name: "folder_id", type: "string", isOptional: true }
|
|
21468
|
+
{ name: "folder_id", type: "string", isOptional: true },
|
|
21469
|
+
// Poison accounting for the head batch; see extractionJobs/models.ts.
|
|
21470
|
+
{ name: "failed_sessions", type: "number", isOptional: true },
|
|
21471
|
+
{ name: "failed_head", type: "string", isOptional: true },
|
|
21472
|
+
{ name: "failed_at", type: "number", isOptional: true }
|
|
21289
21473
|
]
|
|
21290
21474
|
}),
|
|
21291
21475
|
// Chat storage tables
|
|
@@ -22309,6 +22493,22 @@ var sdkMigrations = schemaMigrations2({
|
|
|
22309
22493
|
]
|
|
22310
22494
|
})
|
|
22311
22495
|
]
|
|
22496
|
+
},
|
|
22497
|
+
// v46 -> v47: persisted poison count (and when it was last counted) for a
|
|
22498
|
+
// durable-extraction job's head batch. NULL = never failed, which is right
|
|
22499
|
+
// for every existing row.
|
|
22500
|
+
{
|
|
22501
|
+
toVersion: 47,
|
|
22502
|
+
steps: [
|
|
22503
|
+
addColumns2({
|
|
22504
|
+
table: "memory_extraction_jobs",
|
|
22505
|
+
columns: [
|
|
22506
|
+
{ name: "failed_sessions", type: "number", isOptional: true },
|
|
22507
|
+
{ name: "failed_head", type: "string", isOptional: true },
|
|
22508
|
+
{ name: "failed_at", type: "number", isOptional: true }
|
|
22509
|
+
]
|
|
22510
|
+
})
|
|
22511
|
+
]
|
|
22312
22512
|
}
|
|
22313
22513
|
]
|
|
22314
22514
|
});
|