@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/server/index.cjs
CHANGED
|
@@ -17129,7 +17129,7 @@ __decorateClass([
|
|
|
17129
17129
|
], VaultFolder.prototype, "context", 2);
|
|
17130
17130
|
|
|
17131
17131
|
// src/lib/db/schema.ts
|
|
17132
|
-
var SDK_SCHEMA_VERSION =
|
|
17132
|
+
var SDK_SCHEMA_VERSION = 47;
|
|
17133
17133
|
var sdkSchema = (0, import_watermelondb13.appSchema)({
|
|
17134
17134
|
version: SDK_SCHEMA_VERSION,
|
|
17135
17135
|
tables: [
|
|
@@ -17145,7 +17145,11 @@ var sdkSchema = (0, import_watermelondb13.appSchema)({
|
|
|
17145
17145
|
// source. `watermark` alone is an id, and deleting that message erased
|
|
17146
17146
|
// the anchor — see the column note in extractionJobs/models.ts.
|
|
17147
17147
|
{ name: "watermark_seq", type: "number", isOptional: true },
|
|
17148
|
-
{ name: "folder_id", type: "string", isOptional: true }
|
|
17148
|
+
{ name: "folder_id", type: "string", isOptional: true },
|
|
17149
|
+
// Poison accounting for the head batch; see extractionJobs/models.ts.
|
|
17150
|
+
{ name: "failed_sessions", type: "number", isOptional: true },
|
|
17151
|
+
{ name: "failed_head", type: "string", isOptional: true },
|
|
17152
|
+
{ name: "failed_at", type: "number", isOptional: true }
|
|
17149
17153
|
]
|
|
17150
17154
|
}),
|
|
17151
17155
|
// Chat storage tables
|
|
@@ -18169,6 +18173,22 @@ var sdkMigrations = (0, import_migrations.schemaMigrations)({
|
|
|
18169
18173
|
]
|
|
18170
18174
|
})
|
|
18171
18175
|
]
|
|
18176
|
+
},
|
|
18177
|
+
// v46 -> v47: persisted poison count (and when it was last counted) for a
|
|
18178
|
+
// durable-extraction job's head batch. NULL = never failed, which is right
|
|
18179
|
+
// for every existing row.
|
|
18180
|
+
{
|
|
18181
|
+
toVersion: 47,
|
|
18182
|
+
steps: [
|
|
18183
|
+
(0, import_migrations.addColumns)({
|
|
18184
|
+
table: "memory_extraction_jobs",
|
|
18185
|
+
columns: [
|
|
18186
|
+
{ name: "failed_sessions", type: "number", isOptional: true },
|
|
18187
|
+
{ name: "failed_head", type: "string", isOptional: true },
|
|
18188
|
+
{ name: "failed_at", type: "number", isOptional: true }
|
|
18189
|
+
]
|
|
18190
|
+
})
|
|
18191
|
+
]
|
|
18172
18192
|
}
|
|
18173
18193
|
]
|
|
18174
18194
|
});
|
|
@@ -22065,8 +22085,42 @@ async function vaultMemoryToStored(memory, walletAddress, signMessage, embeddedW
|
|
|
22065
22085
|
}
|
|
22066
22086
|
return raw;
|
|
22067
22087
|
}
|
|
22088
|
+
function populateNewVaultMemory(record, ctx, opts, encryptedContent) {
|
|
22089
|
+
record._setRaw("content", encryptedContent);
|
|
22090
|
+
record._setRaw("scope", opts.scope ?? "private");
|
|
22091
|
+
record._setRaw("folder_id", opts.folderId ?? null);
|
|
22092
|
+
record._setRaw("user_id", ctx.userId ?? null);
|
|
22093
|
+
record._setRaw("is_deleted", false);
|
|
22094
|
+
if (opts.embedding !== void 0) {
|
|
22095
|
+
record._setRaw("embedding", opts.embedding);
|
|
22096
|
+
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
22097
|
+
}
|
|
22098
|
+
if (opts.sourceChunkIds !== void 0) {
|
|
22099
|
+
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
22100
|
+
}
|
|
22101
|
+
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
22102
|
+
record._setRaw("source", opts.source ?? "manual");
|
|
22103
|
+
if (opts.eventTime) {
|
|
22104
|
+
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
22105
|
+
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
22106
|
+
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
22107
|
+
}
|
|
22108
|
+
if (opts.factType !== void 0) {
|
|
22109
|
+
record._setRaw("fact_type", opts.factType);
|
|
22110
|
+
}
|
|
22111
|
+
if (opts.trustTier !== void 0) {
|
|
22112
|
+
record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
22113
|
+
}
|
|
22114
|
+
record._setRaw("visibility", opts.visibility ?? "private");
|
|
22115
|
+
record._setRaw(
|
|
22116
|
+
"published_at",
|
|
22117
|
+
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
22118
|
+
);
|
|
22119
|
+
if (opts.geohash !== void 0) {
|
|
22120
|
+
record._setRaw("geohash", opts.geohash);
|
|
22121
|
+
}
|
|
22122
|
+
}
|
|
22068
22123
|
async function createVaultMemoryOp(ctx, opts) {
|
|
22069
|
-
const scope = opts.scope ?? "private";
|
|
22070
22124
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
22071
22125
|
opts.content,
|
|
22072
22126
|
ctx.walletAddress,
|
|
@@ -22076,47 +22130,14 @@ async function createVaultMemoryOp(ctx, opts) {
|
|
|
22076
22130
|
const created = await ctx.database.write(async () => {
|
|
22077
22131
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
22078
22132
|
throw new Error("Memory source is no longer eligible");
|
|
22079
|
-
return ctx.vaultMemoryCollection.create(
|
|
22080
|
-
record
|
|
22081
|
-
|
|
22082
|
-
record._setRaw("folder_id", opts.folderId ?? null);
|
|
22083
|
-
record._setRaw("user_id", ctx.userId ?? null);
|
|
22084
|
-
record._setRaw("is_deleted", false);
|
|
22085
|
-
if (opts.embedding !== void 0) {
|
|
22086
|
-
record._setRaw("embedding", opts.embedding);
|
|
22087
|
-
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
22088
|
-
}
|
|
22089
|
-
if (opts.sourceChunkIds !== void 0) {
|
|
22090
|
-
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
22091
|
-
}
|
|
22092
|
-
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
22093
|
-
record._setRaw("source", opts.source ?? "manual");
|
|
22094
|
-
if (opts.eventTime) {
|
|
22095
|
-
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
22096
|
-
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
22097
|
-
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
22098
|
-
}
|
|
22099
|
-
if (opts.factType !== void 0) {
|
|
22100
|
-
record._setRaw("fact_type", opts.factType);
|
|
22101
|
-
}
|
|
22102
|
-
if (opts.trustTier !== void 0) {
|
|
22103
|
-
record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
22104
|
-
}
|
|
22105
|
-
record._setRaw("visibility", opts.visibility ?? "private");
|
|
22106
|
-
record._setRaw(
|
|
22107
|
-
"published_at",
|
|
22108
|
-
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
22109
|
-
);
|
|
22110
|
-
if (opts.geohash !== void 0) {
|
|
22111
|
-
record._setRaw("geohash", opts.geohash);
|
|
22112
|
-
}
|
|
22113
|
-
});
|
|
22133
|
+
return ctx.vaultMemoryCollection.create(
|
|
22134
|
+
(record) => populateNewVaultMemory(record, ctx, opts, encryptedContent)
|
|
22135
|
+
);
|
|
22114
22136
|
});
|
|
22115
22137
|
return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
22116
22138
|
}
|
|
22117
22139
|
async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
22118
22140
|
if (!targetId) return { created: null, retired: false };
|
|
22119
|
-
const scope = opts.scope ?? "private";
|
|
22120
22141
|
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
22121
22142
|
opts.content,
|
|
22122
22143
|
ctx.walletAddress,
|
|
@@ -22134,27 +22155,9 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
|
|
|
22134
22155
|
return;
|
|
22135
22156
|
}
|
|
22136
22157
|
if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target)) return;
|
|
22137
|
-
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
22138
|
-
record
|
|
22139
|
-
|
|
22140
|
-
record._setRaw("folder_id", opts.folderId ?? null);
|
|
22141
|
-
record._setRaw("user_id", ctx.userId ?? null);
|
|
22142
|
-
record._setRaw("is_deleted", false);
|
|
22143
|
-
if (opts.embedding !== void 0) {
|
|
22144
|
-
record._setRaw("embedding", opts.embedding);
|
|
22145
|
-
record._setRaw("embedding_model", opts.embeddingModel ?? null);
|
|
22146
|
-
}
|
|
22147
|
-
if (opts.sourceChunkIds !== void 0) {
|
|
22148
|
-
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
22149
|
-
}
|
|
22150
|
-
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
22151
|
-
record._setRaw("source", opts.source ?? "manual");
|
|
22152
|
-
if (opts.eventTime) {
|
|
22153
|
-
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
22154
|
-
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
22155
|
-
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
22156
|
-
}
|
|
22157
|
-
});
|
|
22158
|
+
createdRecord = await ctx.vaultMemoryCollection.create(
|
|
22159
|
+
(record) => populateNewVaultMemory(record, ctx, opts, encryptedContent)
|
|
22160
|
+
);
|
|
22158
22161
|
await target.update((r) => {
|
|
22159
22162
|
r._setRaw("superseded_by", createdRecord.id);
|
|
22160
22163
|
r._setRaw("superseded_at", Date.now());
|
|
@@ -22234,41 +22237,9 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
|
|
|
22234
22237
|
if (ctx.canWrite && !await ctx.canWrite())
|
|
22235
22238
|
throw new Error("Memory source is no longer eligible");
|
|
22236
22239
|
const prepared = optionsArray.map(
|
|
22237
|
-
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
22238
|
-
record
|
|
22239
|
-
|
|
22240
|
-
record._setRaw("folder_id", opts.folderId ?? null);
|
|
22241
|
-
record._setRaw("user_id", ctx.userId ?? null);
|
|
22242
|
-
record._setRaw("is_deleted", false);
|
|
22243
|
-
if (optionsArray[i].embedding !== void 0) {
|
|
22244
|
-
record._setRaw("embedding", optionsArray[i].embedding);
|
|
22245
|
-
record._setRaw("embedding_model", optionsArray[i].embeddingModel ?? null);
|
|
22246
|
-
}
|
|
22247
|
-
if (opts.sourceChunkIds !== void 0) {
|
|
22248
|
-
record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
|
|
22249
|
-
}
|
|
22250
|
-
record._setRaw("proof_count", opts.proofCount ?? 1);
|
|
22251
|
-
record._setRaw("source", opts.source ?? "manual");
|
|
22252
|
-
if (opts.eventTime) {
|
|
22253
|
-
record._setRaw("event_time_start", opts.eventTime.start ?? null);
|
|
22254
|
-
record._setRaw("event_time_end", opts.eventTime.end ?? null);
|
|
22255
|
-
record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
|
|
22256
|
-
}
|
|
22257
|
-
if (opts.factType !== void 0) {
|
|
22258
|
-
record._setRaw("fact_type", opts.factType);
|
|
22259
|
-
}
|
|
22260
|
-
if (opts.trustTier !== void 0) {
|
|
22261
|
-
record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
|
|
22262
|
-
}
|
|
22263
|
-
record._setRaw("visibility", opts.visibility ?? "private");
|
|
22264
|
-
record._setRaw(
|
|
22265
|
-
"published_at",
|
|
22266
|
-
opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
|
|
22267
|
-
);
|
|
22268
|
-
if (opts.geohash !== void 0) {
|
|
22269
|
-
record._setRaw("geohash", opts.geohash);
|
|
22270
|
-
}
|
|
22271
|
-
})
|
|
22240
|
+
(opts, i) => ctx.vaultMemoryCollection.prepareCreate(
|
|
22241
|
+
(record) => populateNewVaultMemory(record, ctx, opts, encryptedContents[i])
|
|
22242
|
+
)
|
|
22272
22243
|
);
|
|
22273
22244
|
await ctx.database.batch(...prepared);
|
|
22274
22245
|
return prepared;
|
|
@@ -23062,21 +23033,73 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
|
|
|
23062
23033
|
return false;
|
|
23063
23034
|
}
|
|
23064
23035
|
}
|
|
23065
|
-
async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel) {
|
|
23036
|
+
async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel, expected) {
|
|
23066
23037
|
try {
|
|
23067
23038
|
const record = await ctx.vaultMemoryCollection.find(id);
|
|
23068
23039
|
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
|
|
23040
|
+
const readUpdatedAt = record.updatedAt.getTime();
|
|
23041
|
+
const readStoredContent = record._getRaw("content");
|
|
23042
|
+
if (expected?.updatedAt !== void 0 && expected.updatedAt !== readUpdatedAt) return false;
|
|
23043
|
+
if (expected?.content !== void 0) {
|
|
23044
|
+
const current = await vaultMemoryToStored(
|
|
23045
|
+
record,
|
|
23046
|
+
ctx.walletAddress,
|
|
23047
|
+
ctx.signMessage,
|
|
23048
|
+
ctx.embeddedWalletSigner
|
|
23049
|
+
);
|
|
23050
|
+
if (current.content !== expected.content) return false;
|
|
23051
|
+
}
|
|
23052
|
+
let written = false;
|
|
23069
23053
|
await ctx.database.write(async () => {
|
|
23054
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return;
|
|
23055
|
+
const originalUpdatedAt = record.updatedAt.getTime();
|
|
23056
|
+
if (originalUpdatedAt !== readUpdatedAt || record._getRaw("content") !== readStoredContent)
|
|
23057
|
+
return;
|
|
23070
23058
|
await record.update((r) => {
|
|
23071
23059
|
r._setRaw("embedding", embedding);
|
|
23072
23060
|
r._setRaw("embedding_model", embeddingModel);
|
|
23061
|
+
r._setRaw("updated_at", originalUpdatedAt);
|
|
23073
23062
|
});
|
|
23063
|
+
written = true;
|
|
23074
23064
|
});
|
|
23075
|
-
return
|
|
23065
|
+
return written;
|
|
23076
23066
|
} catch {
|
|
23077
23067
|
return false;
|
|
23078
23068
|
}
|
|
23079
23069
|
}
|
|
23070
|
+
function normalizeForDedupe(content) {
|
|
23071
|
+
return content.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
|
|
23072
|
+
}
|
|
23073
|
+
async function findQuarantinedDuplicateOp(ctx, content, sourceIds, where) {
|
|
23074
|
+
const wanted = [...new Set(sourceIds)].sort().join("\0");
|
|
23075
|
+
const target = normalizeForDedupe(content);
|
|
23076
|
+
const rows = await ctx.vaultMemoryCollection.query(
|
|
23077
|
+
import_watermelondb18.Q.where("trust_tier", "quarantined"),
|
|
23078
|
+
import_watermelondb18.Q.where("is_deleted", false),
|
|
23079
|
+
import_watermelondb18.Q.where("scope", where.scope),
|
|
23080
|
+
import_watermelondb18.Q.where("folder_id", where.folderId),
|
|
23081
|
+
...ctx.userId !== void 0 ? [import_watermelondb18.Q.where("user_id", ctx.userId)] : []
|
|
23082
|
+
).unsafeFetchRaw();
|
|
23083
|
+
for (const raw of rows) {
|
|
23084
|
+
let ids;
|
|
23085
|
+
try {
|
|
23086
|
+
ids = JSON.parse(raw.source_chunk_ids ?? "[]");
|
|
23087
|
+
} catch {
|
|
23088
|
+
continue;
|
|
23089
|
+
}
|
|
23090
|
+
if (!Array.isArray(ids)) continue;
|
|
23091
|
+
const key = [...new Set(ids.filter((id) => typeof id === "string"))].sort().join("\0");
|
|
23092
|
+
if (key !== wanted) continue;
|
|
23093
|
+
const stored = await vaultMemoryRawToStored(
|
|
23094
|
+
raw,
|
|
23095
|
+
ctx.walletAddress,
|
|
23096
|
+
ctx.signMessage,
|
|
23097
|
+
ctx.embeddedWalletSigner
|
|
23098
|
+
);
|
|
23099
|
+
if (normalizeForDedupe(stored.content) === target) return stored.uniqueId;
|
|
23100
|
+
}
|
|
23101
|
+
return null;
|
|
23102
|
+
}
|
|
23080
23103
|
|
|
23081
23104
|
// src/lib/memory/decay.ts
|
|
23082
23105
|
init_logger();
|
|
@@ -23101,6 +23124,10 @@ var DEFAULT_DECAY_POLICY = {
|
|
|
23101
23124
|
hardDeleteWindowMs: HARD_DELETE_WINDOW_MS,
|
|
23102
23125
|
pastEventGraceMs: PAST_EVENT_GRACE_MS
|
|
23103
23126
|
};
|
|
23127
|
+
function lastActivityAt(m) {
|
|
23128
|
+
const observedAt = Number.isFinite(m.lastObservedAt) ? m.lastObservedAt : m.updatedAt;
|
|
23129
|
+
return Math.max(m.updatedAt, observedAt);
|
|
23130
|
+
}
|
|
23104
23131
|
function resolvePolicy(policy) {
|
|
23105
23132
|
if (!policy) return DEFAULT_DECAY_POLICY;
|
|
23106
23133
|
return {
|
|
@@ -23140,8 +23167,7 @@ function classifyDecay(m, now, policy) {
|
|
|
23140
23167
|
if (m.eventTimeEnd < now - resolved.pastEventGraceMs) return "archive";
|
|
23141
23168
|
if (m.eventTimeEnd >= now) return "keep";
|
|
23142
23169
|
}
|
|
23143
|
-
|
|
23144
|
-
if (now - Math.max(m.updatedAt, observedAt) > ttlForType(m.factType, resolved)) return "archive";
|
|
23170
|
+
if (now - lastActivityAt(m) > ttlForType(m.factType, resolved)) return "archive";
|
|
23145
23171
|
return "keep";
|
|
23146
23172
|
}
|
|
23147
23173
|
|
|
@@ -28701,6 +28727,9 @@ var MANUAL_FACT_TYPES = [
|
|
|
28701
28727
|
function normalizeManualFactType(value) {
|
|
28702
28728
|
return typeof value === "string" && MANUAL_FACT_TYPES.includes(value) ? value : void 0;
|
|
28703
28729
|
}
|
|
28730
|
+
function isSharedScope(scope) {
|
|
28731
|
+
return scope === "shared";
|
|
28732
|
+
}
|
|
28704
28733
|
async function notifyWritten(options, input, outcome) {
|
|
28705
28734
|
try {
|
|
28706
28735
|
await options?.onWritten?.({ input, outcome });
|
|
@@ -28769,14 +28798,17 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
|
|
|
28769
28798
|
try {
|
|
28770
28799
|
const isUpdate = !!id;
|
|
28771
28800
|
let previousContent;
|
|
28801
|
+
const scope = options?.scope ?? "private";
|
|
28772
28802
|
if (isUpdate) {
|
|
28773
28803
|
const existing = await getVaultMemoryOp(vaultCtx, id);
|
|
28774
28804
|
if (!existing) {
|
|
28775
28805
|
return `Error: Memory with ID "${id}" not found. Creating a new memory instead would require a separate call without an ID.`;
|
|
28776
28806
|
}
|
|
28807
|
+
if (isSharedScope(existing.scope) !== isSharedScope(scope)) {
|
|
28808
|
+
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.`;
|
|
28809
|
+
}
|
|
28777
28810
|
previousContent = existing.content;
|
|
28778
28811
|
}
|
|
28779
|
-
const scope = options?.scope ?? "private";
|
|
28780
28812
|
const operation = {
|
|
28781
28813
|
action: isUpdate ? "update" : "add",
|
|
28782
28814
|
content,
|
|
@@ -29986,6 +30018,24 @@ async function extractAndRetain(messages, retainCtx, options) {
|
|
|
29986
30018
|
const tRetain = Date.now();
|
|
29987
30019
|
for (const { candidate, isQuarantined, reason, signature } of toRetain) {
|
|
29988
30020
|
try {
|
|
30021
|
+
if (isQuarantined) {
|
|
30022
|
+
const existingId = await findQuarantinedDuplicateOp(
|
|
30023
|
+
retainCtx.vaultCtx,
|
|
30024
|
+
candidate.content,
|
|
30025
|
+
candidate.sourceMessageIds,
|
|
30026
|
+
// The same defaults retain() writes the row with.
|
|
30027
|
+
{ scope: options.scope ?? "private", folderId: options.folderId ?? null }
|
|
30028
|
+
).catch(() => null);
|
|
30029
|
+
if (existingId) {
|
|
30030
|
+
quarantinedInfo.push({
|
|
30031
|
+
candidate,
|
|
30032
|
+
memoryId: existingId,
|
|
30033
|
+
reason,
|
|
30034
|
+
signature
|
|
30035
|
+
});
|
|
30036
|
+
continue;
|
|
30037
|
+
}
|
|
30038
|
+
}
|
|
29989
30039
|
const result = await retain(candidate.content, retainCtx, {
|
|
29990
30040
|
source: "auto-extracted",
|
|
29991
30041
|
sourceChunkIds: candidate.sourceMessageIds,
|
|
@@ -30436,7 +30486,7 @@ function createLlmDecayClassifier(options) {
|
|
|
30436
30486
|
if (!content || content.trim().length === 0) return ruleVerdict;
|
|
30437
30487
|
const trimmed = content.trim().slice(0, MAX_CONTENT_CHARS);
|
|
30438
30488
|
const safe = redactor ? (await redactor.redactTextAsync(trimmed)).text : trimmed;
|
|
30439
|
-
const meta = `factType: ${input.factType ?? "none"}; ageDays: ${ageDays(input
|
|
30489
|
+
const meta = `factType: ${input.factType ?? "none"}; ageDays: ${ageDays(lastActivityAt(input), now)}`;
|
|
30440
30490
|
let parsed;
|
|
30441
30491
|
try {
|
|
30442
30492
|
parsed = await callPortalJsonCompletion({
|
|
@@ -30469,9 +30519,9 @@ Should this be kept or archived?`,
|
|
|
30469
30519
|
}
|
|
30470
30520
|
};
|
|
30471
30521
|
}
|
|
30472
|
-
function ageDays(
|
|
30473
|
-
if (!Number.isFinite(
|
|
30474
|
-
return Math.max(0, Math.floor((now -
|
|
30522
|
+
function ageDays(activityAt, now) {
|
|
30523
|
+
if (!Number.isFinite(activityAt) || !Number.isFinite(now)) return 0;
|
|
30524
|
+
return Math.max(0, Math.floor((now - activityAt) / (24 * 60 * 60 * 1e3)));
|
|
30475
30525
|
}
|
|
30476
30526
|
function parseVerdict(parsed) {
|
|
30477
30527
|
if (typeof parsed !== "object" || parsed === null) return null;
|
|
@@ -30525,7 +30575,7 @@ function createDecaySweeper(options) {
|
|
|
30525
30575
|
if (!classifier || !isBorderline(input)) return ruleVerdict;
|
|
30526
30576
|
if (input.id) {
|
|
30527
30577
|
const cached = classifierCache.get(input.id);
|
|
30528
|
-
if (cached && cached.
|
|
30578
|
+
if (cached && cached.activityAt === lastActivityAt(input)) return cached.verdict;
|
|
30529
30579
|
}
|
|
30530
30580
|
if (sweep.classifierCalls >= maxClassifierCalls) {
|
|
30531
30581
|
if (!sweep.ceilingLogged) {
|
|
@@ -30539,7 +30589,7 @@ function createDecaySweeper(options) {
|
|
|
30539
30589
|
sweep.classifierCalls++;
|
|
30540
30590
|
try {
|
|
30541
30591
|
const verdict = await classifier.classify(input, ruleVerdict, now);
|
|
30542
|
-
if (input.id) classifierCache.set(input.id, {
|
|
30592
|
+
if (input.id) classifierCache.set(input.id, { activityAt: lastActivityAt(input), verdict });
|
|
30543
30593
|
return verdict;
|
|
30544
30594
|
} catch (err) {
|
|
30545
30595
|
getLogger().warn(
|
|
@@ -32184,6 +32234,37 @@ async function assembleMemoryContext(options) {
|
|
|
32184
32234
|
var import_watermelondb24 = __toESM(require_watermelondb());
|
|
32185
32235
|
var MAX_JOBS_PER_PASS = 3;
|
|
32186
32236
|
var MAX_ATTEMPTS = 3;
|
|
32237
|
+
var MAX_FAILED_SESSIONS = 3;
|
|
32238
|
+
var MIN_FAILED_SESSION_GAP_MS = 60 * 60 * 1e3;
|
|
32239
|
+
var REQUEST_REJECTED_STATUSES = /* @__PURE__ */ new Set([400, 404, 413, 422]);
|
|
32240
|
+
var CONTENT_FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
32241
|
+
"empty-content",
|
|
32242
|
+
"invalid-json",
|
|
32243
|
+
"null-completion",
|
|
32244
|
+
"body-parse-failed"
|
|
32245
|
+
]);
|
|
32246
|
+
var BACKOFF_ALLOWANCE_MS = 2100;
|
|
32247
|
+
var RETAIN_BUDGET_MS = 12e4;
|
|
32248
|
+
function defaultBatchTimeoutMs(extract) {
|
|
32249
|
+
const attempts = Math.max(1, extract.maxAttempts ?? 3);
|
|
32250
|
+
const calls = (extract.timeoutMs ?? 6e4) * attempts + BACKOFF_ALLOWANCE_MS * (attempts - 1);
|
|
32251
|
+
const extraction = extract.totalTimeoutMs !== void 0 ? Math.min(extract.totalTimeoutMs, calls) : calls;
|
|
32252
|
+
return extraction + RETAIN_BUDGET_MS;
|
|
32253
|
+
}
|
|
32254
|
+
var BatchFailureError = class extends Error {
|
|
32255
|
+
constructor(message, terminal) {
|
|
32256
|
+
super(message);
|
|
32257
|
+
this.terminal = terminal;
|
|
32258
|
+
}
|
|
32259
|
+
};
|
|
32260
|
+
var AccountFailureError = class extends Error {
|
|
32261
|
+
};
|
|
32262
|
+
var LockedSourcesError = class extends Error {
|
|
32263
|
+
constructor(persistentIds) {
|
|
32264
|
+
super("Source messages are locked; retained for retry");
|
|
32265
|
+
this.persistentIds = persistentIds;
|
|
32266
|
+
}
|
|
32267
|
+
};
|
|
32187
32268
|
function idsOf(job) {
|
|
32188
32269
|
return JSON.parse(String(job._getRaw("message_ids")));
|
|
32189
32270
|
}
|
|
@@ -32191,6 +32272,16 @@ function seqOf(job) {
|
|
|
32191
32272
|
const raw = job._getRaw("watermark_seq");
|
|
32192
32273
|
return typeof raw === "number" && raw > 0 ? raw : void 0;
|
|
32193
32274
|
}
|
|
32275
|
+
function failedSessionsOf(job, head) {
|
|
32276
|
+
if (job._getRaw("failed_head") !== head) return 0;
|
|
32277
|
+
const raw = job._getRaw("failed_sessions");
|
|
32278
|
+
return typeof raw === "number" && raw > 0 ? raw : 0;
|
|
32279
|
+
}
|
|
32280
|
+
function failedAtOf(job, head) {
|
|
32281
|
+
if (job._getRaw("failed_head") !== head) return void 0;
|
|
32282
|
+
const raw = job._getRaw("failed_at");
|
|
32283
|
+
return typeof raw === "number" ? raw : void 0;
|
|
32284
|
+
}
|
|
32194
32285
|
function createDurableAutoExtractor(options) {
|
|
32195
32286
|
const vault = options.retainCtx.vaultCtx;
|
|
32196
32287
|
const database = vault.database;
|
|
@@ -32213,6 +32304,9 @@ function createDurableAutoExtractor(options) {
|
|
|
32213
32304
|
let writes = Promise.resolve();
|
|
32214
32305
|
let storeFailures = 0;
|
|
32215
32306
|
const attempts = /* @__PURE__ */ new Map();
|
|
32307
|
+
const sessionFailures = /* @__PURE__ */ new Map();
|
|
32308
|
+
const skippedThisSession = /* @__PURE__ */ new Set();
|
|
32309
|
+
const clock = options.now ?? Date.now;
|
|
32216
32310
|
const reportError = (error, conversationId) => {
|
|
32217
32311
|
try {
|
|
32218
32312
|
options.onError?.(error instanceof Error ? error : new Error(String(error)), conversationId);
|
|
@@ -32241,6 +32335,7 @@ function createDurableAutoExtractor(options) {
|
|
|
32241
32335
|
}
|
|
32242
32336
|
async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
|
|
32243
32337
|
let watchdog;
|
|
32338
|
+
let cancelled = false;
|
|
32244
32339
|
const model = options.modelForScope?.(jobScope) ?? options.extract.model;
|
|
32245
32340
|
try {
|
|
32246
32341
|
return await Promise.race([
|
|
@@ -32251,7 +32346,7 @@ function createDurableAutoExtractor(options) {
|
|
|
32251
32346
|
...options.retainCtx,
|
|
32252
32347
|
vaultCtx: {
|
|
32253
32348
|
...vault,
|
|
32254
|
-
canWrite: async () => !disposed && await storage.conversationsCollection.query(import_watermelondb24.Q.where("conversation_id", conversationId), import_watermelondb24.Q.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(import_watermelondb24.Q.where("conversation_id", conversationId), import_watermelondb24.Q.where("id", import_watermelondb24.Q.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed
|
|
32349
|
+
canWrite: async () => !disposed && !cancelled && await storage.conversationsCollection.query(import_watermelondb24.Q.where("conversation_id", conversationId), import_watermelondb24.Q.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(import_watermelondb24.Q.where("conversation_id", conversationId), import_watermelondb24.Q.where("id", import_watermelondb24.Q.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed && !cancelled
|
|
32255
32350
|
}
|
|
32256
32351
|
},
|
|
32257
32352
|
// The model follows the job's scope, not the mode alive at drain time.
|
|
@@ -32271,14 +32366,116 @@ function createDurableAutoExtractor(options) {
|
|
|
32271
32366
|
new Promise((_resolve, reject) => {
|
|
32272
32367
|
watchdog = setTimeout(
|
|
32273
32368
|
() => reject(new Error("Extraction did not settle in time; retained for retry")),
|
|
32274
|
-
options.batchTimeoutMs ??
|
|
32369
|
+
options.batchTimeoutMs ?? defaultBatchTimeoutMs(options.extract)
|
|
32275
32370
|
);
|
|
32276
32371
|
})
|
|
32277
32372
|
]);
|
|
32278
32373
|
} finally {
|
|
32374
|
+
cancelled = true;
|
|
32279
32375
|
if (watchdog !== void 0) clearTimeout(watchdog);
|
|
32280
32376
|
}
|
|
32281
32377
|
}
|
|
32378
|
+
async function acknowledge(job, ids, loaded, abandoned) {
|
|
32379
|
+
attempts.delete(job.id);
|
|
32380
|
+
sessionFailures.delete(job.id);
|
|
32381
|
+
skippedThisSession.delete(job.id);
|
|
32382
|
+
const sequences = /* @__PURE__ */ new Map();
|
|
32383
|
+
for (const message of loaded)
|
|
32384
|
+
if (message && message.messageId > 0) sequences.set(message.uniqueId, message.messageId);
|
|
32385
|
+
await database.write(async () => {
|
|
32386
|
+
const current = idsOf(job);
|
|
32387
|
+
const acknowledged = ids.filter((id) => current.includes(id));
|
|
32388
|
+
if (!acknowledged.length) return;
|
|
32389
|
+
const done = new Set(acknowledged);
|
|
32390
|
+
const remaining = current.filter((id) => !done.has(id));
|
|
32391
|
+
await job.update((r) => {
|
|
32392
|
+
r._setRaw(
|
|
32393
|
+
"message_ids",
|
|
32394
|
+
JSON.stringify(
|
|
32395
|
+
remaining.length ? [...abandoned ? [] : acknowledged.slice(-2), ...remaining] : []
|
|
32396
|
+
)
|
|
32397
|
+
);
|
|
32398
|
+
const newest = acknowledged[acknowledged.length - 1];
|
|
32399
|
+
r._setRaw("watermark", newest);
|
|
32400
|
+
const sequence = sequences.get(newest);
|
|
32401
|
+
if (sequence !== void 0) {
|
|
32402
|
+
const prior = seqOf(job);
|
|
32403
|
+
r._setRaw("watermark_seq", prior === void 0 ? sequence : Math.max(prior, sequence));
|
|
32404
|
+
}
|
|
32405
|
+
r._setRaw("failed_sessions", abandoned ? MAX_FAILED_SESSIONS : null);
|
|
32406
|
+
r._setRaw("failed_head", abandoned ? newest : null);
|
|
32407
|
+
r._setRaw("failed_at", null);
|
|
32408
|
+
});
|
|
32409
|
+
});
|
|
32410
|
+
}
|
|
32411
|
+
async function recordFailure(job, ids, loaded, error, conversationId) {
|
|
32412
|
+
const head = ids[0];
|
|
32413
|
+
if (!head || !loaded.some(Boolean)) return false;
|
|
32414
|
+
if (error instanceof AccountFailureError) {
|
|
32415
|
+
skippedThisSession.add(job.id);
|
|
32416
|
+
return false;
|
|
32417
|
+
}
|
|
32418
|
+
const counted = error instanceof BatchFailureError || error instanceof LockedSourcesError && error.persistentIds.length > 0;
|
|
32419
|
+
if (!counted) return false;
|
|
32420
|
+
const prior = sessionFailures.get(job.id);
|
|
32421
|
+
const count = prior?.head === head ? prior.count + 1 : 1;
|
|
32422
|
+
sessionFailures.set(job.id, { head, count });
|
|
32423
|
+
const terminal = error instanceof BatchFailureError && error.terminal;
|
|
32424
|
+
if (!terminal && count < MAX_ATTEMPTS) return false;
|
|
32425
|
+
skippedThisSession.add(job.id);
|
|
32426
|
+
const now = clock();
|
|
32427
|
+
const lastCounted = failedAtOf(job, head);
|
|
32428
|
+
if (lastCounted !== void 0 && now - lastCounted < MIN_FAILED_SESSION_GAP_MS) return false;
|
|
32429
|
+
const failures = failedSessionsOf(job, head) + 1;
|
|
32430
|
+
if (failures < MAX_FAILED_SESSIONS) {
|
|
32431
|
+
await database.write(
|
|
32432
|
+
() => job.update((r) => {
|
|
32433
|
+
r._setRaw("failed_sessions", failures);
|
|
32434
|
+
r._setRaw("failed_head", head);
|
|
32435
|
+
r._setRaw("failed_at", now);
|
|
32436
|
+
})
|
|
32437
|
+
);
|
|
32438
|
+
return false;
|
|
32439
|
+
}
|
|
32440
|
+
if (error instanceof LockedSourcesError) {
|
|
32441
|
+
const dropped = new Set(error.persistentIds);
|
|
32442
|
+
let newest;
|
|
32443
|
+
for (const message of loaded)
|
|
32444
|
+
if (message && dropped.has(message.uniqueId) && message.messageId > (newest?.seq ?? 0))
|
|
32445
|
+
newest = { id: message.uniqueId, seq: message.messageId };
|
|
32446
|
+
const advance = newest !== void 0 && newest.seq > (seqOf(job) ?? 0) ? newest : void 0;
|
|
32447
|
+
await database.write(
|
|
32448
|
+
() => job.update((r) => {
|
|
32449
|
+
r._setRaw("message_ids", JSON.stringify(idsOf(job).filter((id) => !dropped.has(id))));
|
|
32450
|
+
if (advance) {
|
|
32451
|
+
r._setRaw("watermark", advance.id);
|
|
32452
|
+
r._setRaw("watermark_seq", advance.seq);
|
|
32453
|
+
}
|
|
32454
|
+
r._setRaw("failed_sessions", advance ? MAX_FAILED_SESSIONS : null);
|
|
32455
|
+
r._setRaw("failed_head", advance ? advance.id : null);
|
|
32456
|
+
r._setRaw("failed_at", null);
|
|
32457
|
+
})
|
|
32458
|
+
);
|
|
32459
|
+
attempts.delete(job.id);
|
|
32460
|
+
sessionFailures.delete(job.id);
|
|
32461
|
+
skippedThisSession.delete(job.id);
|
|
32462
|
+
reportError(
|
|
32463
|
+
new Error(
|
|
32464
|
+
`Dropped ${dropped.size} source id(s) that stayed locked for ${failures} sessions to unblock extraction`
|
|
32465
|
+
),
|
|
32466
|
+
conversationId
|
|
32467
|
+
);
|
|
32468
|
+
return true;
|
|
32469
|
+
}
|
|
32470
|
+
await acknowledge(job, ids, loaded, true);
|
|
32471
|
+
reportError(
|
|
32472
|
+
new Error(
|
|
32473
|
+
`Abandoned an extraction batch of ${ids.length} source id(s) after it failed in ${failures} sessions`
|
|
32474
|
+
),
|
|
32475
|
+
conversationId
|
|
32476
|
+
);
|
|
32477
|
+
return true;
|
|
32478
|
+
}
|
|
32282
32479
|
async function drain() {
|
|
32283
32480
|
if (disposed || running) return;
|
|
32284
32481
|
running = true;
|
|
@@ -32293,21 +32490,23 @@ function createDurableAutoExtractor(options) {
|
|
|
32293
32490
|
for (const job of pending) {
|
|
32294
32491
|
if (disposed) break;
|
|
32295
32492
|
const attempted = attempts.get(job.id) ?? 0;
|
|
32296
|
-
if (attempted >= MAX_ATTEMPTS) continue;
|
|
32493
|
+
if (attempted >= MAX_ATTEMPTS || skippedThisSession.has(job.id)) continue;
|
|
32297
32494
|
if (processed >= MAX_JOBS_PER_PASS) {
|
|
32298
32495
|
scheduleAfterSuccess = true;
|
|
32299
32496
|
break;
|
|
32300
32497
|
}
|
|
32301
32498
|
processed++;
|
|
32302
32499
|
const conversationId = String(job._getRaw("conversation_id"));
|
|
32500
|
+
let ids = [];
|
|
32501
|
+
let loaded = [];
|
|
32303
32502
|
try {
|
|
32304
32503
|
const conversations = await storage.conversationsCollection.query(import_watermelondb24.Q.where("conversation_id", conversationId), import_watermelondb24.Q.where("is_deleted", false)).fetchCount();
|
|
32305
32504
|
if (!conversations) {
|
|
32306
32505
|
await database.write(() => job.destroyPermanently());
|
|
32307
32506
|
continue;
|
|
32308
32507
|
}
|
|
32309
|
-
|
|
32310
|
-
|
|
32508
|
+
ids = idsOf(job).slice(0, 20);
|
|
32509
|
+
loaded = await Promise.all(ids.map((id) => getMessageOp(storage, id)));
|
|
32311
32510
|
const missing = ids.filter((_id, index) => loaded[index] === null);
|
|
32312
32511
|
if (missing.length) {
|
|
32313
32512
|
if (attempted < MAX_ATTEMPTS - 1)
|
|
@@ -32331,17 +32530,21 @@ function createDurableAutoExtractor(options) {
|
|
|
32331
32530
|
);
|
|
32332
32531
|
continue;
|
|
32333
32532
|
}
|
|
32334
|
-
|
|
32335
|
-
|
|
32336
|
-
|
|
32337
|
-
|
|
32533
|
+
const locked = loaded.filter((message) => message && isEncrypted(message.content));
|
|
32534
|
+
if (locked.length) {
|
|
32535
|
+
throw new LockedSourcesError(
|
|
32536
|
+
locked.flatMap(
|
|
32537
|
+
(message) => message.decryptionStatus === "auth_mismatch" || message.decryptionStatus === "invalid_payload" ? [message.uniqueId] : []
|
|
32538
|
+
)
|
|
32539
|
+
);
|
|
32338
32540
|
}
|
|
32339
32541
|
const messages = loaded.flatMap(
|
|
32340
32542
|
(m) => m && m.conversationId === conversationId && (m.role === "user" || m.role === "assistant") ? [{ id: m.uniqueId, role: m.role, content: m.content }] : []
|
|
32341
32543
|
);
|
|
32342
32544
|
let success = messages.length === 0;
|
|
32545
|
+
let result;
|
|
32343
32546
|
if (messages.length) {
|
|
32344
|
-
|
|
32547
|
+
result = await extractBatch(
|
|
32345
32548
|
messages,
|
|
32346
32549
|
conversationId,
|
|
32347
32550
|
ids,
|
|
@@ -32351,41 +32554,35 @@ function createDurableAutoExtractor(options) {
|
|
|
32351
32554
|
success = result.failedCount === 0 && result.outcome !== "empty-after-retry";
|
|
32352
32555
|
options.onTurnComplete?.(result);
|
|
32353
32556
|
}
|
|
32354
|
-
if (!success)
|
|
32355
|
-
|
|
32356
|
-
|
|
32357
|
-
|
|
32358
|
-
|
|
32359
|
-
|
|
32360
|
-
|
|
32361
|
-
|
|
32362
|
-
const acknowledged = ids.filter((id) => current.includes(id));
|
|
32363
|
-
if (!acknowledged.length) return;
|
|
32364
|
-
const done = new Set(acknowledged);
|
|
32365
|
-
const remaining = current.filter((id) => !done.has(id));
|
|
32366
|
-
if (remaining.length) {
|
|
32367
|
-
await job.update(
|
|
32368
|
-
(r) => r._setRaw("message_ids", JSON.stringify([...acknowledged.slice(-2), ...remaining]))
|
|
32369
|
-
);
|
|
32370
|
-
} else await job.update((r) => r._setRaw("message_ids", "[]"));
|
|
32371
|
-
const newest = acknowledged[acknowledged.length - 1];
|
|
32372
|
-
await job.update((r) => {
|
|
32373
|
-
r._setRaw("watermark", newest);
|
|
32374
|
-
const sequence = sequences.get(newest);
|
|
32375
|
-
if (sequence !== void 0) {
|
|
32376
|
-
const prior = seqOf(job);
|
|
32377
|
-
r._setRaw(
|
|
32378
|
-
"watermark_seq",
|
|
32379
|
-
prior === void 0 ? sequence : Math.max(prior, sequence)
|
|
32557
|
+
if (!success) {
|
|
32558
|
+
const failure = result?.failure;
|
|
32559
|
+
if (failure?.reason === "http-terminal") {
|
|
32560
|
+
const status = failure.httpStatus;
|
|
32561
|
+
if (status !== void 0 && REQUEST_REJECTED_STATUSES.has(status))
|
|
32562
|
+
throw new BatchFailureError(
|
|
32563
|
+
`Extraction rejected the batch (HTTP ${status}); not retried this session`,
|
|
32564
|
+
true
|
|
32380
32565
|
);
|
|
32381
|
-
|
|
32382
|
-
|
|
32383
|
-
|
|
32566
|
+
throw new AccountFailureError(
|
|
32567
|
+
`Extraction refused for the account (HTTP ${status ?? "unknown"}); retried next session`
|
|
32568
|
+
);
|
|
32569
|
+
}
|
|
32570
|
+
if ((result?.failedCount ?? 0) > 0 || failure !== void 0 && CONTENT_FAILURE_REASONS.has(failure.reason))
|
|
32571
|
+
throw new BatchFailureError("Extraction batch incomplete; retained for retry", false);
|
|
32572
|
+
throw new Error("Extraction batch incomplete; retained for retry");
|
|
32573
|
+
}
|
|
32574
|
+
await acknowledge(job, ids, loaded, false);
|
|
32384
32575
|
scheduleAfterSuccess = true;
|
|
32385
32576
|
} catch (error) {
|
|
32386
32577
|
attempts.set(job.id, attempted + 1);
|
|
32387
32578
|
retry = true;
|
|
32388
32579
|
reportError(error, conversationId);
|
|
32580
|
+
try {
|
|
32581
|
+
if (await recordFailure(job, ids, loaded, error, conversationId))
|
|
32582
|
+
scheduleAfterSuccess = true;
|
|
32583
|
+
} catch (recordError) {
|
|
32584
|
+
reportError(recordError, conversationId);
|
|
32585
|
+
}
|
|
32389
32586
|
}
|
|
32390
32587
|
}
|
|
32391
32588
|
} catch (error) {
|
|
@@ -32455,7 +32652,7 @@ function createDurableAutoExtractor(options) {
|
|
|
32455
32652
|
const start = boundary >= 0 ? boundary + 1 : Math.max(0, ids.length - Math.max(1, options.windowSize ?? 6));
|
|
32456
32653
|
if (start >= ids.length) return;
|
|
32457
32654
|
const ownWatermark = job?._getRaw("watermark");
|
|
32458
|
-
const atOwnWatermark = !!job && boundary >= 0 && (ids[boundary] === ownWatermark || sequences.get(ids[boundary]) !== void 0 && sequences.get(ids[boundary]) === seqOf(job));
|
|
32655
|
+
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));
|
|
32459
32656
|
const overlapStart = atOwnWatermark ? Math.max(0, boundary - 1) : start;
|
|
32460
32657
|
const fresh = ids.slice(overlapStart).filter((id) => !foreignSources.has(id));
|
|
32461
32658
|
if (!fresh.length) return;
|