@anuma/sdk 6.8.2 → 6.9.0
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/{chunk-LUGYCFVI.mjs → chunk-4M56MKBV.mjs} +66 -44
- package/dist/expo/index.cjs +71 -45
- package/dist/expo/index.d.mts +24 -0
- package/dist/expo/index.d.ts +24 -0
- package/dist/expo/index.mjs +7 -3
- package/dist/expo/{recall-77QK4RT6.mjs → recall-WIB7RQQZ.mjs} +1 -1
- package/dist/react/{chunk-NPJSO5ES.mjs → chunk-EJ65X4GI.mjs} +74 -46
- package/dist/react/index.cjs +79 -47
- package/dist/react/index.d.mts +24 -0
- package/dist/react/index.d.ts +24 -0
- package/dist/react/index.mjs +7 -3
- package/dist/react/{recall-3I5GDJZE.mjs → recall-FWILZSFH.mjs} +1 -1
- package/dist/server/{chunk-IP6PGI7H.mjs → chunk-I56324FR.mjs} +66 -44
- package/dist/server/index.cjs +71 -45
- package/dist/server/index.d.mts +24 -0
- package/dist/server/index.d.ts +24 -0
- package/dist/server/index.mjs +7 -3
- package/dist/server/{recall-RTW7T7KR.mjs → recall-T7CNXTQ3.mjs} +1 -1
- package/package.json +1 -1
|
@@ -2175,13 +2175,13 @@ async function upsertEntitiesInWrite(ctx, entities) {
|
|
|
2175
2175
|
}
|
|
2176
2176
|
const unique = Array.from(kindByName.keys());
|
|
2177
2177
|
const out = /* @__PURE__ */ new Map();
|
|
2178
|
-
if (unique.length === 0) return { entities: out, operations: [] };
|
|
2178
|
+
if (unique.length === 0) return { entities: out, operations: [], kindBackfills: [] };
|
|
2179
2179
|
const existing = await ctx.entityCollection.query(Q2.where("canonical_name", Q2.oneOf(unique))).fetch();
|
|
2180
2180
|
const existingNames = new Set(existing.map((e) => e.canonicalName));
|
|
2181
|
-
const
|
|
2181
|
+
const kindBackfills = existing.filter((e) => {
|
|
2182
2182
|
const incoming = kindByName.get(e.canonicalName);
|
|
2183
2183
|
return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
|
|
2184
|
-
});
|
|
2184
|
+
}).map((record) => ({ record, kind: kindByName.get(record.canonicalName) }));
|
|
2185
2185
|
const missing = unique.filter((n) => !existingNames.has(n));
|
|
2186
2186
|
const created = missing.map(
|
|
2187
2187
|
(name) => ctx.entityCollection.prepareCreate((record) => {
|
|
@@ -2190,14 +2190,19 @@ async function upsertEntitiesInWrite(ctx, entities) {
|
|
|
2190
2190
|
if (kind !== void 0) record._setRaw("kind", kind);
|
|
2191
2191
|
})
|
|
2192
2192
|
);
|
|
2193
|
-
const updated = updates.map(
|
|
2194
|
-
(e) => e.prepareUpdate((record) => {
|
|
2195
|
-
record._setRaw("kind", kindByName.get(e.canonicalName));
|
|
2196
|
-
})
|
|
2197
|
-
);
|
|
2198
2193
|
for (const e of existing) out.set(e.canonicalName, entityToStored(e));
|
|
2199
2194
|
for (const record of created) out.set(record.canonicalName, entityToStored(record));
|
|
2200
|
-
|
|
2195
|
+
for (const { record, kind } of kindBackfills) {
|
|
2196
|
+
out.set(record.canonicalName, { ...entityToStored(record), kind });
|
|
2197
|
+
}
|
|
2198
|
+
return { entities: out, operations: created, kindBackfills };
|
|
2199
|
+
}
|
|
2200
|
+
function prepareKindBackfills(backfills) {
|
|
2201
|
+
return backfills.map(
|
|
2202
|
+
({ record, kind }) => record.prepareUpdate((r) => {
|
|
2203
|
+
r._setRaw("kind", kind);
|
|
2204
|
+
})
|
|
2205
|
+
);
|
|
2201
2206
|
}
|
|
2202
2207
|
async function findVaultRowInWrite(ctx, memoryId) {
|
|
2203
2208
|
try {
|
|
@@ -2247,10 +2252,12 @@ function topicsForEntities(entities, displayNames, source) {
|
|
|
2247
2252
|
function toEntityObjects(entityInputs) {
|
|
2248
2253
|
return entityInputs.map((e) => typeof e === "string" ? { name: e } : e);
|
|
2249
2254
|
}
|
|
2250
|
-
async function
|
|
2255
|
+
async function resolveMemoryTopicsWrite(ctx, memoryId, linked, inputs, source) {
|
|
2251
2256
|
const row = await findVaultRowInWrite(ctx, memoryId);
|
|
2252
|
-
|
|
2253
|
-
|
|
2257
|
+
return resolveTopicsWrite(row, linked, displayNamesOf(toEntityObjects(inputs)), source);
|
|
2258
|
+
}
|
|
2259
|
+
function prepareMemoryTopicsUpdate(write) {
|
|
2260
|
+
return prepareTopicsUpdate(write.row, write.topics, Date.now());
|
|
2254
2261
|
}
|
|
2255
2262
|
async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
2256
2263
|
if (entityInputs.length === 0) return [];
|
|
@@ -2259,15 +2266,16 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
2259
2266
|
let skipped = false;
|
|
2260
2267
|
let entities = [];
|
|
2261
2268
|
await ctx.database.write(async () => {
|
|
2262
|
-
const {
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2269
|
+
const {
|
|
2270
|
+
entities: byName,
|
|
2271
|
+
operations: entityOps,
|
|
2272
|
+
kindBackfills
|
|
2273
|
+
} = await upsertEntitiesInWrite(ctx, normalized);
|
|
2266
2274
|
entities = Array.from(byName.values());
|
|
2267
2275
|
const vaultRow = await findVaultRowInWrite(ctx, memoryId);
|
|
2268
2276
|
if (options?.unlessTopicsUserManaged && autoLinkBlocked(vaultRow)) {
|
|
2269
|
-
if (entityOps.length > 0) {
|
|
2270
|
-
await ctx.database.batch(...entityOps);
|
|
2277
|
+
if (entityOps.length > 0 || kindBackfills.length > 0) {
|
|
2278
|
+
await ctx.database.batch(...entityOps, ...prepareKindBackfills(kindBackfills));
|
|
2271
2279
|
}
|
|
2272
2280
|
skipped = true;
|
|
2273
2281
|
return;
|
|
@@ -2287,7 +2295,9 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
2287
2295
|
displayNamesOf(normalized),
|
|
2288
2296
|
options?.topicsSource ?? "auto"
|
|
2289
2297
|
);
|
|
2290
|
-
if (entityOps.length === 0 && toCreate.length === 0 && topicsWrite === null)
|
|
2298
|
+
if (entityOps.length === 0 && kindBackfills.length === 0 && toCreate.length === 0 && topicsWrite === null) {
|
|
2299
|
+
return;
|
|
2300
|
+
}
|
|
2291
2301
|
const linkOps = toCreate.map(
|
|
2292
2302
|
(e) => ctx.memoryEntityCollection.prepareCreate((record) => {
|
|
2293
2303
|
record._setRaw("memory_id", memoryId);
|
|
@@ -2297,6 +2307,7 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
2297
2307
|
);
|
|
2298
2308
|
await ctx.database.batch(
|
|
2299
2309
|
...entityOps,
|
|
2310
|
+
...prepareKindBackfills(kindBackfills),
|
|
2300
2311
|
...linkOps,
|
|
2301
2312
|
...topicsWrite ? [prepareTopicsUpdate(topicsWrite.row, topicsWrite.topics, Date.now())] : []
|
|
2302
2313
|
);
|
|
@@ -2334,10 +2345,11 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
2334
2345
|
skipped = true;
|
|
2335
2346
|
return;
|
|
2336
2347
|
}
|
|
2337
|
-
const {
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2348
|
+
const {
|
|
2349
|
+
entities: byName,
|
|
2350
|
+
operations: entityOps,
|
|
2351
|
+
kindBackfills
|
|
2352
|
+
} = await upsertEntitiesInWrite(ctx, normalized);
|
|
2341
2353
|
entities = Array.from(byName.values());
|
|
2342
2354
|
const existingLinks = await ctx.memoryEntityCollection.query(Q2.where("memory_id", memoryId)).fetch();
|
|
2343
2355
|
const keep = new Set(entities.map((e) => e.uniqueId));
|
|
@@ -2350,12 +2362,13 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
2350
2362
|
displayNamesOf(normalized),
|
|
2351
2363
|
options.topicsSource
|
|
2352
2364
|
);
|
|
2353
|
-
if (entityOps.length === 0 && toCreate.length === 0 && toDestroy.length === 0 && topicsWrite === null) {
|
|
2365
|
+
if (entityOps.length === 0 && kindBackfills.length === 0 && toCreate.length === 0 && toDestroy.length === 0 && topicsWrite === null) {
|
|
2354
2366
|
return;
|
|
2355
2367
|
}
|
|
2356
2368
|
const orphans = await findOrphanedEntities(ctx, memoryId, toDestroy);
|
|
2357
2369
|
await ctx.database.batch(
|
|
2358
2370
|
...entityOps,
|
|
2371
|
+
...prepareKindBackfills(kindBackfills),
|
|
2359
2372
|
...toCreate.map(
|
|
2360
2373
|
(e) => ctx.memoryEntityCollection.prepareCreate((record) => {
|
|
2361
2374
|
record._setRaw("memory_id", memoryId);
|
|
@@ -3429,27 +3442,36 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
|
|
|
3429
3442
|
if (!entityCtx) {
|
|
3430
3443
|
throw new Error("backfillMemoryTopicsOp requires ctx.entityCtx");
|
|
3431
3444
|
}
|
|
3445
|
+
const uniqueIds = Array.from(new Set(memoryIds));
|
|
3446
|
+
if (uniqueIds.length === 0) return [];
|
|
3432
3447
|
const filled = [];
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
record = await ctx.vaultMemoryCollection.find(id);
|
|
3437
|
-
} catch {
|
|
3438
|
-
continue;
|
|
3439
|
-
}
|
|
3440
|
-
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) continue;
|
|
3441
|
-
if (parseTopics(record.topics) !== null) continue;
|
|
3442
|
-
const links = await entityCtx.memoryEntityCollection.query(Q3.where("memory_id", id)).unsafeFetchRaw();
|
|
3443
|
-
const entityIds = links.map((l) => String(l.entity_id));
|
|
3444
|
-
if (entityIds.length === 0) continue;
|
|
3445
|
-
const entities = await entityCtx.entityCollection.query(Q3.where("id", Q3.oneOf(entityIds))).fetch();
|
|
3446
|
-
if (entities.length === 0) continue;
|
|
3447
|
-
const source = record.topicsUserManaged ? "user" : "auto";
|
|
3448
|
+
const CHUNK = 500;
|
|
3449
|
+
for (let i = 0; i < uniqueIds.length; i += CHUNK) {
|
|
3450
|
+
const chunkIds = uniqueIds.slice(i, i + CHUNK);
|
|
3448
3451
|
await ctx.database.write(async () => {
|
|
3449
|
-
const
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3452
|
+
const writes = [];
|
|
3453
|
+
for (const id of chunkIds) {
|
|
3454
|
+
let record;
|
|
3455
|
+
try {
|
|
3456
|
+
record = await ctx.vaultMemoryCollection.find(id);
|
|
3457
|
+
} catch {
|
|
3458
|
+
continue;
|
|
3459
|
+
}
|
|
3460
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) continue;
|
|
3461
|
+
if (parseTopics(record.topics) !== null) continue;
|
|
3462
|
+
const links = await entityCtx.memoryEntityCollection.query(Q3.where("memory_id", id)).unsafeFetchRaw();
|
|
3463
|
+
const entityIds = links.map((l) => String(l.entity_id));
|
|
3464
|
+
if (entityIds.length === 0) continue;
|
|
3465
|
+
const entities = await entityCtx.entityCollection.query(Q3.where("id", Q3.oneOf(entityIds))).fetch();
|
|
3466
|
+
if (entities.length === 0) continue;
|
|
3467
|
+
const source = record.topicsUserManaged ? "user" : "auto";
|
|
3468
|
+
const write = await resolveMemoryTopicsWrite(entityCtx, id, entities, [], source);
|
|
3469
|
+
if (write) writes.push(write);
|
|
3470
|
+
}
|
|
3471
|
+
if (writes.length === 0) return;
|
|
3472
|
+
const prepared = writes.map(prepareMemoryTopicsUpdate);
|
|
3473
|
+
await ctx.database.batch(...prepared);
|
|
3474
|
+
for (const write of writes) filled.push(write.row.id);
|
|
3453
3475
|
});
|
|
3454
3476
|
}
|
|
3455
3477
|
return filled;
|
|
@@ -6818,7 +6840,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
6818
6840
|
subQueries = decomp.subQueries;
|
|
6819
6841
|
}
|
|
6820
6842
|
}
|
|
6821
|
-
const { recall: recall2 } = await import("./recall-
|
|
6843
|
+
const { recall: recall2 } = await import("./recall-WIB7RQQZ.mjs");
|
|
6822
6844
|
let recallDegraded = [];
|
|
6823
6845
|
const result = await recall2(
|
|
6824
6846
|
query,
|
package/dist/expo/index.cjs
CHANGED
|
@@ -4671,13 +4671,13 @@ async function upsertEntitiesInWrite(ctx, entities) {
|
|
|
4671
4671
|
}
|
|
4672
4672
|
const unique = Array.from(kindByName.keys());
|
|
4673
4673
|
const out = /* @__PURE__ */ new Map();
|
|
4674
|
-
if (unique.length === 0) return { entities: out, operations: [] };
|
|
4674
|
+
if (unique.length === 0) return { entities: out, operations: [], kindBackfills: [] };
|
|
4675
4675
|
const existing = await ctx.entityCollection.query(import_watermelondb8.Q.where("canonical_name", import_watermelondb8.Q.oneOf(unique))).fetch();
|
|
4676
4676
|
const existingNames = new Set(existing.map((e) => e.canonicalName));
|
|
4677
|
-
const
|
|
4677
|
+
const kindBackfills = existing.filter((e) => {
|
|
4678
4678
|
const incoming = kindByName.get(e.canonicalName);
|
|
4679
4679
|
return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
|
|
4680
|
-
});
|
|
4680
|
+
}).map((record) => ({ record, kind: kindByName.get(record.canonicalName) }));
|
|
4681
4681
|
const missing = unique.filter((n) => !existingNames.has(n));
|
|
4682
4682
|
const created = missing.map(
|
|
4683
4683
|
(name) => ctx.entityCollection.prepareCreate((record) => {
|
|
@@ -4686,14 +4686,19 @@ async function upsertEntitiesInWrite(ctx, entities) {
|
|
|
4686
4686
|
if (kind !== void 0) record._setRaw("kind", kind);
|
|
4687
4687
|
})
|
|
4688
4688
|
);
|
|
4689
|
-
const updated = updates.map(
|
|
4690
|
-
(e) => e.prepareUpdate((record) => {
|
|
4691
|
-
record._setRaw("kind", kindByName.get(e.canonicalName));
|
|
4692
|
-
})
|
|
4693
|
-
);
|
|
4694
4689
|
for (const e of existing) out.set(e.canonicalName, entityToStored(e));
|
|
4695
4690
|
for (const record of created) out.set(record.canonicalName, entityToStored(record));
|
|
4696
|
-
|
|
4691
|
+
for (const { record, kind } of kindBackfills) {
|
|
4692
|
+
out.set(record.canonicalName, { ...entityToStored(record), kind });
|
|
4693
|
+
}
|
|
4694
|
+
return { entities: out, operations: created, kindBackfills };
|
|
4695
|
+
}
|
|
4696
|
+
function prepareKindBackfills(backfills) {
|
|
4697
|
+
return backfills.map(
|
|
4698
|
+
({ record, kind }) => record.prepareUpdate((r) => {
|
|
4699
|
+
r._setRaw("kind", kind);
|
|
4700
|
+
})
|
|
4701
|
+
);
|
|
4697
4702
|
}
|
|
4698
4703
|
async function findVaultRowInWrite(ctx, memoryId) {
|
|
4699
4704
|
try {
|
|
@@ -4743,10 +4748,12 @@ function topicsForEntities(entities, displayNames, source) {
|
|
|
4743
4748
|
function toEntityObjects(entityInputs) {
|
|
4744
4749
|
return entityInputs.map((e) => typeof e === "string" ? { name: e } : e);
|
|
4745
4750
|
}
|
|
4746
|
-
async function
|
|
4751
|
+
async function resolveMemoryTopicsWrite(ctx, memoryId, linked, inputs, source) {
|
|
4747
4752
|
const row = await findVaultRowInWrite(ctx, memoryId);
|
|
4748
|
-
|
|
4749
|
-
|
|
4753
|
+
return resolveTopicsWrite(row, linked, displayNamesOf(toEntityObjects(inputs)), source);
|
|
4754
|
+
}
|
|
4755
|
+
function prepareMemoryTopicsUpdate(write) {
|
|
4756
|
+
return prepareTopicsUpdate(write.row, write.topics, Date.now());
|
|
4750
4757
|
}
|
|
4751
4758
|
async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
4752
4759
|
if (entityInputs.length === 0) return [];
|
|
@@ -4755,15 +4762,16 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
4755
4762
|
let skipped = false;
|
|
4756
4763
|
let entities = [];
|
|
4757
4764
|
await ctx.database.write(async () => {
|
|
4758
|
-
const {
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4765
|
+
const {
|
|
4766
|
+
entities: byName,
|
|
4767
|
+
operations: entityOps,
|
|
4768
|
+
kindBackfills
|
|
4769
|
+
} = await upsertEntitiesInWrite(ctx, normalized);
|
|
4762
4770
|
entities = Array.from(byName.values());
|
|
4763
4771
|
const vaultRow = await findVaultRowInWrite(ctx, memoryId);
|
|
4764
4772
|
if (options?.unlessTopicsUserManaged && autoLinkBlocked(vaultRow)) {
|
|
4765
|
-
if (entityOps.length > 0) {
|
|
4766
|
-
await ctx.database.batch(...entityOps);
|
|
4773
|
+
if (entityOps.length > 0 || kindBackfills.length > 0) {
|
|
4774
|
+
await ctx.database.batch(...entityOps, ...prepareKindBackfills(kindBackfills));
|
|
4767
4775
|
}
|
|
4768
4776
|
skipped = true;
|
|
4769
4777
|
return;
|
|
@@ -4783,7 +4791,9 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
4783
4791
|
displayNamesOf(normalized),
|
|
4784
4792
|
options?.topicsSource ?? "auto"
|
|
4785
4793
|
);
|
|
4786
|
-
if (entityOps.length === 0 && toCreate.length === 0 && topicsWrite === null)
|
|
4794
|
+
if (entityOps.length === 0 && kindBackfills.length === 0 && toCreate.length === 0 && topicsWrite === null) {
|
|
4795
|
+
return;
|
|
4796
|
+
}
|
|
4787
4797
|
const linkOps = toCreate.map(
|
|
4788
4798
|
(e) => ctx.memoryEntityCollection.prepareCreate((record) => {
|
|
4789
4799
|
record._setRaw("memory_id", memoryId);
|
|
@@ -4793,6 +4803,7 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
4793
4803
|
);
|
|
4794
4804
|
await ctx.database.batch(
|
|
4795
4805
|
...entityOps,
|
|
4806
|
+
...prepareKindBackfills(kindBackfills),
|
|
4796
4807
|
...linkOps,
|
|
4797
4808
|
...topicsWrite ? [prepareTopicsUpdate(topicsWrite.row, topicsWrite.topics, Date.now())] : []
|
|
4798
4809
|
);
|
|
@@ -4830,10 +4841,11 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
4830
4841
|
skipped = true;
|
|
4831
4842
|
return;
|
|
4832
4843
|
}
|
|
4833
|
-
const {
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4844
|
+
const {
|
|
4845
|
+
entities: byName,
|
|
4846
|
+
operations: entityOps,
|
|
4847
|
+
kindBackfills
|
|
4848
|
+
} = await upsertEntitiesInWrite(ctx, normalized);
|
|
4837
4849
|
entities = Array.from(byName.values());
|
|
4838
4850
|
const existingLinks = await ctx.memoryEntityCollection.query(import_watermelondb8.Q.where("memory_id", memoryId)).fetch();
|
|
4839
4851
|
const keep = new Set(entities.map((e) => e.uniqueId));
|
|
@@ -4846,12 +4858,13 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
4846
4858
|
displayNamesOf(normalized),
|
|
4847
4859
|
options.topicsSource
|
|
4848
4860
|
);
|
|
4849
|
-
if (entityOps.length === 0 && toCreate.length === 0 && toDestroy.length === 0 && topicsWrite === null) {
|
|
4861
|
+
if (entityOps.length === 0 && kindBackfills.length === 0 && toCreate.length === 0 && toDestroy.length === 0 && topicsWrite === null) {
|
|
4850
4862
|
return;
|
|
4851
4863
|
}
|
|
4852
4864
|
const orphans = await findOrphanedEntities(ctx, memoryId, toDestroy);
|
|
4853
4865
|
await ctx.database.batch(
|
|
4854
4866
|
...entityOps,
|
|
4867
|
+
...prepareKindBackfills(kindBackfills),
|
|
4855
4868
|
...toCreate.map(
|
|
4856
4869
|
(e) => ctx.memoryEntityCollection.prepareCreate((record) => {
|
|
4857
4870
|
record._setRaw("memory_id", memoryId);
|
|
@@ -5940,27 +5953,36 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
|
|
|
5940
5953
|
if (!entityCtx) {
|
|
5941
5954
|
throw new Error("backfillMemoryTopicsOp requires ctx.entityCtx");
|
|
5942
5955
|
}
|
|
5956
|
+
const uniqueIds = Array.from(new Set(memoryIds));
|
|
5957
|
+
if (uniqueIds.length === 0) return [];
|
|
5943
5958
|
const filled = [];
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
record = await ctx.vaultMemoryCollection.find(id);
|
|
5948
|
-
} catch {
|
|
5949
|
-
continue;
|
|
5950
|
-
}
|
|
5951
|
-
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) continue;
|
|
5952
|
-
if (parseTopics(record.topics) !== null) continue;
|
|
5953
|
-
const links = await entityCtx.memoryEntityCollection.query(import_watermelondb9.Q.where("memory_id", id)).unsafeFetchRaw();
|
|
5954
|
-
const entityIds = links.map((l) => String(l.entity_id));
|
|
5955
|
-
if (entityIds.length === 0) continue;
|
|
5956
|
-
const entities = await entityCtx.entityCollection.query(import_watermelondb9.Q.where("id", import_watermelondb9.Q.oneOf(entityIds))).fetch();
|
|
5957
|
-
if (entities.length === 0) continue;
|
|
5958
|
-
const source = record.topicsUserManaged ? "user" : "auto";
|
|
5959
|
+
const CHUNK = 500;
|
|
5960
|
+
for (let i = 0; i < uniqueIds.length; i += CHUNK) {
|
|
5961
|
+
const chunkIds = uniqueIds.slice(i, i + CHUNK);
|
|
5959
5962
|
await ctx.database.write(async () => {
|
|
5960
|
-
const
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5963
|
+
const writes = [];
|
|
5964
|
+
for (const id of chunkIds) {
|
|
5965
|
+
let record;
|
|
5966
|
+
try {
|
|
5967
|
+
record = await ctx.vaultMemoryCollection.find(id);
|
|
5968
|
+
} catch {
|
|
5969
|
+
continue;
|
|
5970
|
+
}
|
|
5971
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) continue;
|
|
5972
|
+
if (parseTopics(record.topics) !== null) continue;
|
|
5973
|
+
const links = await entityCtx.memoryEntityCollection.query(import_watermelondb9.Q.where("memory_id", id)).unsafeFetchRaw();
|
|
5974
|
+
const entityIds = links.map((l) => String(l.entity_id));
|
|
5975
|
+
if (entityIds.length === 0) continue;
|
|
5976
|
+
const entities = await entityCtx.entityCollection.query(import_watermelondb9.Q.where("id", import_watermelondb9.Q.oneOf(entityIds))).fetch();
|
|
5977
|
+
if (entities.length === 0) continue;
|
|
5978
|
+
const source = record.topicsUserManaged ? "user" : "auto";
|
|
5979
|
+
const write = await resolveMemoryTopicsWrite(entityCtx, id, entities, [], source);
|
|
5980
|
+
if (write) writes.push(write);
|
|
5981
|
+
}
|
|
5982
|
+
if (writes.length === 0) return;
|
|
5983
|
+
const prepared = writes.map(prepareMemoryTopicsUpdate);
|
|
5984
|
+
await ctx.database.batch(...prepared);
|
|
5985
|
+
for (const write of writes) filled.push(write.row.id);
|
|
5964
5986
|
});
|
|
5965
5987
|
}
|
|
5966
5988
|
return filled;
|
|
@@ -17095,7 +17117,7 @@ function createAutoExtractor(options) {
|
|
|
17095
17117
|
const t0 = Date.now();
|
|
17096
17118
|
void (async () => {
|
|
17097
17119
|
try {
|
|
17098
|
-
const { candidates, results, failedCount, outcome } = await extractAndRetain(
|
|
17120
|
+
const { candidates, results, failedCount, outcome, failure } = await extractAndRetain(
|
|
17099
17121
|
window2,
|
|
17100
17122
|
retainCtx,
|
|
17101
17123
|
{
|
|
@@ -17135,7 +17157,11 @@ function createAutoExtractor(options) {
|
|
|
17135
17157
|
failedCount,
|
|
17136
17158
|
durationMs: Date.now() - t0,
|
|
17137
17159
|
conversationId,
|
|
17138
|
-
outcome
|
|
17160
|
+
outcome,
|
|
17161
|
+
// Only set alongside `outcome: "empty-after-retry"`. Spread so the key
|
|
17162
|
+
// is absent rather than explicitly undefined on a healthy turn —
|
|
17163
|
+
// analytics backends store an explicit undefined as a real value.
|
|
17164
|
+
...failure !== void 0 && { failure }
|
|
17139
17165
|
});
|
|
17140
17166
|
} catch (err) {
|
|
17141
17167
|
options.onError?.(err instanceof Error ? err : new Error(String(err)), conversationId);
|
package/dist/expo/index.d.mts
CHANGED
|
@@ -6768,6 +6768,14 @@ declare function relinkMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryI
|
|
|
6768
6768
|
* row has: a curated memory's topics are recorded as `user`, everything else as
|
|
6769
6769
|
* `auto`. Skips deleted, foreign-user, unlinked rows, and rows that already have
|
|
6770
6770
|
* a record. Returns the ids filled.
|
|
6771
|
+
*
|
|
6772
|
+
* Runs as ONE writer over the whole (caller-bounded) list, in two phases:
|
|
6773
|
+
* resolve every row's write — all the awaits — and only then prepare and batch,
|
|
6774
|
+
* synchronously. Resolving and preparing per row inside its own writer is what
|
|
6775
|
+
* fired WatermelonDB's "wasn't sent to batch() synchronously" diagnostic once
|
|
6776
|
+
* per memory (~107 on a single dev launch, sdk#891); it also cost N writes.
|
|
6777
|
+
* Same treatment as {@link stampTopicsExtractedAtOp}, including its
|
|
6778
|
+
* transpilation hazard — the prepare pass MUST stay a `.map()`.
|
|
6771
6779
|
*/
|
|
6772
6780
|
declare function backfillMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryIds: readonly string[]): Promise<string[]>;
|
|
6773
6781
|
declare function deleteAllVaultMemoriesForUserOp(ctx: VaultMemoryOperationsContext, userId: string): Promise<number>;
|
|
@@ -7230,6 +7238,22 @@ interface TurnCompleteEvent {
|
|
|
7230
7238
|
* previously indistinguishable (both surfaced as zero candidates).
|
|
7231
7239
|
*/
|
|
7232
7240
|
outcome: ExtractOutcome;
|
|
7241
|
+
/**
|
|
7242
|
+
* Present only alongside `outcome: "empty-after-retry"` — WHICH failure ended
|
|
7243
|
+
* the turn (#888).
|
|
7244
|
+
*
|
|
7245
|
+
* `outcome` says extraction gave up; this says why, from a stable enum. The
|
|
7246
|
+
* distinction is the whole point: a 2026-08-11 audit measured ~63% of
|
|
7247
|
+
* production extraction turns ending in `empty-after-retry` and could not tell
|
|
7248
|
+
* from telemetry whether the cause was the freeloader 403 everyone assumed or
|
|
7249
|
+
* something else. It took a Prometheus cross-check to find the real one — the
|
|
7250
|
+
* portal returning HTTP 200 with an empty body, which it counts as a success.
|
|
7251
|
+
*
|
|
7252
|
+
* Forward `failure.reason` into your extraction analytics event; all three
|
|
7253
|
+
* fields are bounded (an enum, an HTTP status, a small attempt count) and none
|
|
7254
|
+
* carries content.
|
|
7255
|
+
*/
|
|
7256
|
+
failure?: PortalLlmFailure;
|
|
7233
7257
|
}
|
|
7234
7258
|
/** @public */
|
|
7235
7259
|
/**
|
package/dist/expo/index.d.ts
CHANGED
|
@@ -6768,6 +6768,14 @@ declare function relinkMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryI
|
|
|
6768
6768
|
* row has: a curated memory's topics are recorded as `user`, everything else as
|
|
6769
6769
|
* `auto`. Skips deleted, foreign-user, unlinked rows, and rows that already have
|
|
6770
6770
|
* a record. Returns the ids filled.
|
|
6771
|
+
*
|
|
6772
|
+
* Runs as ONE writer over the whole (caller-bounded) list, in two phases:
|
|
6773
|
+
* resolve every row's write — all the awaits — and only then prepare and batch,
|
|
6774
|
+
* synchronously. Resolving and preparing per row inside its own writer is what
|
|
6775
|
+
* fired WatermelonDB's "wasn't sent to batch() synchronously" diagnostic once
|
|
6776
|
+
* per memory (~107 on a single dev launch, sdk#891); it also cost N writes.
|
|
6777
|
+
* Same treatment as {@link stampTopicsExtractedAtOp}, including its
|
|
6778
|
+
* transpilation hazard — the prepare pass MUST stay a `.map()`.
|
|
6771
6779
|
*/
|
|
6772
6780
|
declare function backfillMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryIds: readonly string[]): Promise<string[]>;
|
|
6773
6781
|
declare function deleteAllVaultMemoriesForUserOp(ctx: VaultMemoryOperationsContext, userId: string): Promise<number>;
|
|
@@ -7230,6 +7238,22 @@ interface TurnCompleteEvent {
|
|
|
7230
7238
|
* previously indistinguishable (both surfaced as zero candidates).
|
|
7231
7239
|
*/
|
|
7232
7240
|
outcome: ExtractOutcome;
|
|
7241
|
+
/**
|
|
7242
|
+
* Present only alongside `outcome: "empty-after-retry"` — WHICH failure ended
|
|
7243
|
+
* the turn (#888).
|
|
7244
|
+
*
|
|
7245
|
+
* `outcome` says extraction gave up; this says why, from a stable enum. The
|
|
7246
|
+
* distinction is the whole point: a 2026-08-11 audit measured ~63% of
|
|
7247
|
+
* production extraction turns ending in `empty-after-retry` and could not tell
|
|
7248
|
+
* from telemetry whether the cause was the freeloader 403 everyone assumed or
|
|
7249
|
+
* something else. It took a Prometheus cross-check to find the real one — the
|
|
7250
|
+
* portal returning HTTP 200 with an empty body, which it counts as a success.
|
|
7251
|
+
*
|
|
7252
|
+
* Forward `failure.reason` into your extraction analytics event; all three
|
|
7253
|
+
* fields are bounded (an enum, an HTTP status, a small attempt count) and none
|
|
7254
|
+
* carries content.
|
|
7255
|
+
*/
|
|
7256
|
+
failure?: PortalLlmFailure;
|
|
7233
7257
|
}
|
|
7234
7258
|
/** @public */
|
|
7235
7259
|
/**
|
package/dist/expo/index.mjs
CHANGED
|
@@ -132,7 +132,7 @@ import {
|
|
|
132
132
|
upsertMessageOp,
|
|
133
133
|
useEncryption,
|
|
134
134
|
vaultMemoryToStored
|
|
135
|
-
} from "./chunk-
|
|
135
|
+
} from "./chunk-4M56MKBV.mjs";
|
|
136
136
|
import {
|
|
137
137
|
PII_PATTERNS,
|
|
138
138
|
PiiRedactor,
|
|
@@ -7539,7 +7539,7 @@ function createAutoExtractor(options) {
|
|
|
7539
7539
|
const t0 = Date.now();
|
|
7540
7540
|
void (async () => {
|
|
7541
7541
|
try {
|
|
7542
|
-
const { candidates, results, failedCount, outcome } = await extractAndRetain(
|
|
7542
|
+
const { candidates, results, failedCount, outcome, failure } = await extractAndRetain(
|
|
7543
7543
|
window,
|
|
7544
7544
|
retainCtx,
|
|
7545
7545
|
{
|
|
@@ -7579,7 +7579,11 @@ function createAutoExtractor(options) {
|
|
|
7579
7579
|
failedCount,
|
|
7580
7580
|
durationMs: Date.now() - t0,
|
|
7581
7581
|
conversationId,
|
|
7582
|
-
outcome
|
|
7582
|
+
outcome,
|
|
7583
|
+
// Only set alongside `outcome: "empty-after-retry"`. Spread so the key
|
|
7584
|
+
// is absent rather than explicitly undefined on a healthy turn —
|
|
7585
|
+
// analytics backends store an explicit undefined as a real value.
|
|
7586
|
+
...failure !== void 0 && { failure }
|
|
7583
7587
|
});
|
|
7584
7588
|
} catch (err) {
|
|
7585
7589
|
options.onError?.(err instanceof Error ? err : new Error(String(err)), conversationId);
|