@anuma/sdk 3.8.2 → 3.8.4
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-IFZZQPRO.mjs → chunk-42Y42CAZ.mjs} +60 -40
- package/dist/expo/index.cjs +223 -43
- package/dist/expo/index.d.mts +1 -1
- package/dist/expo/index.d.ts +1 -1
- package/dist/expo/index.mjs +165 -5
- package/dist/expo/{recall-MUFOZB6P.mjs → recall-JFZ3Z6EX.mjs} +1 -1
- package/dist/react/{chunk-35BHTCK4.mjs → chunk-NLVSQAYH.mjs} +60 -40
- package/dist/react/index.cjs +223 -43
- package/dist/react/index.d.mts +9 -4
- package/dist/react/index.d.ts +9 -4
- package/dist/react/index.mjs +165 -5
- package/dist/react/{recall-JUERXQA7.mjs → recall-BCEH7U2Z.mjs} +1 -1
- package/dist/server/{chunk-GKN5NJKZ.mjs → chunk-FS56IDOW.mjs} +60 -40
- package/dist/server/index.cjs +223 -43
- package/dist/server/index.d.mts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.mjs +165 -5
- package/dist/server/{recall-XZ6WLFPJ.mjs → recall-VDMDNQNB.mjs} +1 -1
- package/package.json +1 -1
|
@@ -1801,7 +1801,7 @@ function entityToStored(e) {
|
|
|
1801
1801
|
updatedAt: e.updatedAt
|
|
1802
1802
|
};
|
|
1803
1803
|
}
|
|
1804
|
-
async function
|
|
1804
|
+
async function upsertEntitiesInWrite(ctx, entities) {
|
|
1805
1805
|
const kindByName = /* @__PURE__ */ new Map();
|
|
1806
1806
|
for (const e of entities) {
|
|
1807
1807
|
const name = normalizeEntityName(e.name);
|
|
@@ -1815,60 +1815,62 @@ async function upsertEntitiesOp(ctx, entities) {
|
|
|
1815
1815
|
}
|
|
1816
1816
|
const unique = Array.from(kindByName.keys());
|
|
1817
1817
|
const out = /* @__PURE__ */ new Map();
|
|
1818
|
-
if (unique.length === 0) return out;
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
const
|
|
1823
|
-
|
|
1824
|
-
return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
|
|
1825
|
-
});
|
|
1826
|
-
const missing = unique.filter((n) => !existingNames.has(n));
|
|
1827
|
-
const created = missing.map(
|
|
1828
|
-
(name) => ctx.entityCollection.prepareCreate((record) => {
|
|
1829
|
-
record._setRaw("canonical_name", name);
|
|
1830
|
-
const kind = kindByName.get(name);
|
|
1831
|
-
if (kind !== void 0) record._setRaw("kind", kind);
|
|
1832
|
-
})
|
|
1833
|
-
);
|
|
1834
|
-
const updated = updates.map(
|
|
1835
|
-
(e) => e.prepareUpdate((record) => {
|
|
1836
|
-
record._setRaw("kind", kindByName.get(e.canonicalName));
|
|
1837
|
-
})
|
|
1838
|
-
);
|
|
1839
|
-
if (created.length > 0 || updated.length > 0) {
|
|
1840
|
-
await ctx.database.batch(...created, ...updated);
|
|
1841
|
-
}
|
|
1842
|
-
for (const e of existing) out.set(e.canonicalName, entityToStored(e));
|
|
1843
|
-
for (const record of created) out.set(record.canonicalName, entityToStored(record));
|
|
1844
|
-
return out;
|
|
1818
|
+
if (unique.length === 0) return { entities: out, operations: [] };
|
|
1819
|
+
const existing = await ctx.entityCollection.query(Q2.where("canonical_name", Q2.oneOf(unique))).fetch();
|
|
1820
|
+
const existingNames = new Set(existing.map((e) => e.canonicalName));
|
|
1821
|
+
const updates = existing.filter((e) => {
|
|
1822
|
+
const incoming = kindByName.get(e.canonicalName);
|
|
1823
|
+
return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
|
|
1845
1824
|
});
|
|
1825
|
+
const missing = unique.filter((n) => !existingNames.has(n));
|
|
1826
|
+
const created = missing.map(
|
|
1827
|
+
(name) => ctx.entityCollection.prepareCreate((record) => {
|
|
1828
|
+
record._setRaw("canonical_name", name);
|
|
1829
|
+
const kind = kindByName.get(name);
|
|
1830
|
+
if (kind !== void 0) record._setRaw("kind", kind);
|
|
1831
|
+
})
|
|
1832
|
+
);
|
|
1833
|
+
const updated = updates.map(
|
|
1834
|
+
(e) => e.prepareUpdate((record) => {
|
|
1835
|
+
record._setRaw("kind", kindByName.get(e.canonicalName));
|
|
1836
|
+
})
|
|
1837
|
+
);
|
|
1838
|
+
for (const e of existing) out.set(e.canonicalName, entityToStored(e));
|
|
1839
|
+
for (const record of created) out.set(record.canonicalName, entityToStored(record));
|
|
1840
|
+
return { entities: out, operations: [...created, ...updated] };
|
|
1846
1841
|
}
|
|
1847
1842
|
async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
1848
1843
|
if (entityInputs.length === 0) return [];
|
|
1849
1844
|
const normalized = entityInputs.map((e) => typeof e === "string" ? { name: e } : e);
|
|
1850
|
-
const byName = await upsertEntitiesOp(ctx, normalized);
|
|
1851
|
-
const entities = Array.from(byName.values());
|
|
1852
|
-
if (entities.length === 0) return [];
|
|
1853
1845
|
const userId = ctx.userId;
|
|
1854
1846
|
let skipped = false;
|
|
1847
|
+
let entities = [];
|
|
1855
1848
|
await ctx.database.write(async () => {
|
|
1849
|
+
const { entities: byName, operations: entityOps } = await upsertEntitiesInWrite(
|
|
1850
|
+
ctx,
|
|
1851
|
+
normalized
|
|
1852
|
+
);
|
|
1853
|
+
entities = Array.from(byName.values());
|
|
1856
1854
|
if (options?.unlessTopicsUserManaged && await autoLinkBlocked(ctx, memoryId)) {
|
|
1855
|
+
if (entityOps.length > 0) {
|
|
1856
|
+
await ctx.database.batch(...entityOps);
|
|
1857
|
+
}
|
|
1857
1858
|
skipped = true;
|
|
1858
1859
|
return;
|
|
1859
1860
|
}
|
|
1861
|
+
if (entities.length === 0) return;
|
|
1860
1862
|
const existingLinks = await ctx.memoryEntityCollection.query(Q2.where("memory_id", memoryId)).fetch();
|
|
1861
1863
|
const existingEntityIds = new Set(existingLinks.map((l) => String(l.entityId)));
|
|
1862
1864
|
const toCreate = entities.filter((e) => !existingEntityIds.has(e.uniqueId));
|
|
1863
|
-
if (toCreate.length === 0) return;
|
|
1864
|
-
const
|
|
1865
|
+
if (entityOps.length === 0 && toCreate.length === 0) return;
|
|
1866
|
+
const linkOps = toCreate.map(
|
|
1865
1867
|
(e) => ctx.memoryEntityCollection.prepareCreate((record) => {
|
|
1866
1868
|
record._setRaw("memory_id", memoryId);
|
|
1867
1869
|
record._setRaw("entity_id", e.uniqueId);
|
|
1868
1870
|
if (userId !== void 0) record._setRaw("user_id", userId);
|
|
1869
1871
|
})
|
|
1870
1872
|
);
|
|
1871
|
-
await ctx.database.batch(...
|
|
1873
|
+
await ctx.database.batch(...entityOps, ...linkOps);
|
|
1872
1874
|
});
|
|
1873
1875
|
return skipped ? [] : entities;
|
|
1874
1876
|
}
|
|
@@ -1883,22 +1885,28 @@ async function autoLinkBlocked(ctx, memoryId) {
|
|
|
1883
1885
|
}
|
|
1884
1886
|
async function replaceMemoryEntitiesGuardedOp(ctx, memoryId, entityInputs) {
|
|
1885
1887
|
const normalized = entityInputs.map((e) => typeof e === "string" ? { name: e } : e);
|
|
1886
|
-
const byName = await upsertEntitiesOp(ctx, normalized);
|
|
1887
|
-
const entities = Array.from(byName.values());
|
|
1888
1888
|
const userId = ctx.userId;
|
|
1889
1889
|
let skipped = false;
|
|
1890
|
+
let entities = [];
|
|
1890
1891
|
await ctx.database.write(async () => {
|
|
1891
1892
|
if (await autoLinkBlocked(ctx, memoryId)) {
|
|
1892
1893
|
skipped = true;
|
|
1893
1894
|
return;
|
|
1894
1895
|
}
|
|
1896
|
+
const { entities: byName, operations: entityOps } = await upsertEntitiesInWrite(
|
|
1897
|
+
ctx,
|
|
1898
|
+
normalized
|
|
1899
|
+
);
|
|
1900
|
+
entities = Array.from(byName.values());
|
|
1895
1901
|
const existingLinks = await ctx.memoryEntityCollection.query(Q2.where("memory_id", memoryId)).fetch();
|
|
1896
1902
|
const keep = new Set(entities.map((e) => e.uniqueId));
|
|
1897
1903
|
const existingEntityIds = new Set(existingLinks.map((l) => String(l.entityId)));
|
|
1898
1904
|
const toCreate = entities.filter((e) => !existingEntityIds.has(e.uniqueId));
|
|
1899
1905
|
const toDestroy = existingLinks.filter((l) => !keep.has(String(l.entityId)));
|
|
1900
|
-
if (toCreate.length === 0 && toDestroy.length === 0) return;
|
|
1906
|
+
if (entityOps.length === 0 && toCreate.length === 0 && toDestroy.length === 0) return;
|
|
1907
|
+
const orphans = await findOrphanedEntities(ctx, memoryId, toDestroy);
|
|
1901
1908
|
await ctx.database.batch(
|
|
1909
|
+
...entityOps,
|
|
1902
1910
|
...toCreate.map(
|
|
1903
1911
|
(e) => ctx.memoryEntityCollection.prepareCreate((record) => {
|
|
1904
1912
|
record._setRaw("memory_id", memoryId);
|
|
@@ -1906,11 +1914,23 @@ async function replaceMemoryEntitiesGuardedOp(ctx, memoryId, entityInputs) {
|
|
|
1906
1914
|
if (userId !== void 0) record._setRaw("user_id", userId);
|
|
1907
1915
|
})
|
|
1908
1916
|
),
|
|
1909
|
-
...toDestroy.map((l) => l.prepareDestroyPermanently())
|
|
1917
|
+
...toDestroy.map((l) => l.prepareDestroyPermanently()),
|
|
1918
|
+
...orphans.map((e) => e.prepareDestroyPermanently())
|
|
1910
1919
|
);
|
|
1911
1920
|
});
|
|
1912
1921
|
return skipped ? null : entities;
|
|
1913
1922
|
}
|
|
1923
|
+
async function findOrphanedEntities(ctx, memoryId, toDestroy) {
|
|
1924
|
+
const candidateIds = [...new Set(toDestroy.map((l) => String(l.entityId)))];
|
|
1925
|
+
if (candidateIds.length === 0) return [];
|
|
1926
|
+
const links = await ctx.memoryEntityCollection.query(Q2.where("entity_id", Q2.oneOf(candidateIds))).fetch();
|
|
1927
|
+
const stillLinked = new Set(
|
|
1928
|
+
links.filter((l) => String(l.memoryId) !== memoryId).map((l) => String(l.entityId))
|
|
1929
|
+
);
|
|
1930
|
+
const orphanIds = candidateIds.filter((id) => !stillLinked.has(id));
|
|
1931
|
+
if (orphanIds.length === 0) return [];
|
|
1932
|
+
return await ctx.entityCollection.query(Q2.where("id", Q2.oneOf(orphanIds))).fetch();
|
|
1933
|
+
}
|
|
1914
1934
|
async function unlinkMemoryEntitiesOp(ctx, memoryIds) {
|
|
1915
1935
|
if (memoryIds.length === 0) return;
|
|
1916
1936
|
const links = await ctx.memoryEntityCollection.query(Q2.where("memory_id", Q2.oneOf(Array.from(memoryIds)))).fetch();
|
|
@@ -2531,7 +2551,7 @@ async function getUnfiledVaultMemoriesOp(ctx) {
|
|
|
2531
2551
|
(record) => vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
2532
2552
|
);
|
|
2533
2553
|
}
|
|
2534
|
-
var TOPICS_EXTRACTION_VERSION =
|
|
2554
|
+
var TOPICS_EXTRACTION_VERSION = 3;
|
|
2535
2555
|
async function getMemoriesNeedingTopicExtractionOp(ctx, options) {
|
|
2536
2556
|
const entityCtx = ctx.entityCtx;
|
|
2537
2557
|
if (!entityCtx) {
|
|
@@ -5363,7 +5383,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
5363
5383
|
legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
|
|
5364
5384
|
);
|
|
5365
5385
|
}
|
|
5366
|
-
const { recall: recall2 } = await import("./recall-
|
|
5386
|
+
const { recall: recall2 } = await import("./recall-JFZ3Z6EX.mjs");
|
|
5367
5387
|
const result = await recall2(
|
|
5368
5388
|
query,
|
|
5369
5389
|
{ vaultCtx, embeddingOptions, vaultCache: cache },
|
package/dist/expo/index.cjs
CHANGED
|
@@ -4030,7 +4030,7 @@ function entityToStored(e) {
|
|
|
4030
4030
|
updatedAt: e.updatedAt
|
|
4031
4031
|
};
|
|
4032
4032
|
}
|
|
4033
|
-
async function
|
|
4033
|
+
async function upsertEntitiesInWrite(ctx, entities) {
|
|
4034
4034
|
const kindByName = /* @__PURE__ */ new Map();
|
|
4035
4035
|
for (const e of entities) {
|
|
4036
4036
|
const name = normalizeEntityName(e.name);
|
|
@@ -4044,60 +4044,62 @@ async function upsertEntitiesOp(ctx, entities) {
|
|
|
4044
4044
|
}
|
|
4045
4045
|
const unique = Array.from(kindByName.keys());
|
|
4046
4046
|
const out = /* @__PURE__ */ new Map();
|
|
4047
|
-
if (unique.length === 0) return out;
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
const
|
|
4052
|
-
|
|
4053
|
-
return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
|
|
4054
|
-
});
|
|
4055
|
-
const missing = unique.filter((n) => !existingNames.has(n));
|
|
4056
|
-
const created = missing.map(
|
|
4057
|
-
(name) => ctx.entityCollection.prepareCreate((record) => {
|
|
4058
|
-
record._setRaw("canonical_name", name);
|
|
4059
|
-
const kind = kindByName.get(name);
|
|
4060
|
-
if (kind !== void 0) record._setRaw("kind", kind);
|
|
4061
|
-
})
|
|
4062
|
-
);
|
|
4063
|
-
const updated = updates.map(
|
|
4064
|
-
(e) => e.prepareUpdate((record) => {
|
|
4065
|
-
record._setRaw("kind", kindByName.get(e.canonicalName));
|
|
4066
|
-
})
|
|
4067
|
-
);
|
|
4068
|
-
if (created.length > 0 || updated.length > 0) {
|
|
4069
|
-
await ctx.database.batch(...created, ...updated);
|
|
4070
|
-
}
|
|
4071
|
-
for (const e of existing) out.set(e.canonicalName, entityToStored(e));
|
|
4072
|
-
for (const record of created) out.set(record.canonicalName, entityToStored(record));
|
|
4073
|
-
return out;
|
|
4047
|
+
if (unique.length === 0) return { entities: out, operations: [] };
|
|
4048
|
+
const existing = await ctx.entityCollection.query(import_watermelondb8.Q.where("canonical_name", import_watermelondb8.Q.oneOf(unique))).fetch();
|
|
4049
|
+
const existingNames = new Set(existing.map((e) => e.canonicalName));
|
|
4050
|
+
const updates = existing.filter((e) => {
|
|
4051
|
+
const incoming = kindByName.get(e.canonicalName);
|
|
4052
|
+
return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
|
|
4074
4053
|
});
|
|
4054
|
+
const missing = unique.filter((n) => !existingNames.has(n));
|
|
4055
|
+
const created = missing.map(
|
|
4056
|
+
(name) => ctx.entityCollection.prepareCreate((record) => {
|
|
4057
|
+
record._setRaw("canonical_name", name);
|
|
4058
|
+
const kind = kindByName.get(name);
|
|
4059
|
+
if (kind !== void 0) record._setRaw("kind", kind);
|
|
4060
|
+
})
|
|
4061
|
+
);
|
|
4062
|
+
const updated = updates.map(
|
|
4063
|
+
(e) => e.prepareUpdate((record) => {
|
|
4064
|
+
record._setRaw("kind", kindByName.get(e.canonicalName));
|
|
4065
|
+
})
|
|
4066
|
+
);
|
|
4067
|
+
for (const e of existing) out.set(e.canonicalName, entityToStored(e));
|
|
4068
|
+
for (const record of created) out.set(record.canonicalName, entityToStored(record));
|
|
4069
|
+
return { entities: out, operations: [...created, ...updated] };
|
|
4075
4070
|
}
|
|
4076
4071
|
async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
4077
4072
|
if (entityInputs.length === 0) return [];
|
|
4078
4073
|
const normalized = entityInputs.map((e) => typeof e === "string" ? { name: e } : e);
|
|
4079
|
-
const byName = await upsertEntitiesOp(ctx, normalized);
|
|
4080
|
-
const entities = Array.from(byName.values());
|
|
4081
|
-
if (entities.length === 0) return [];
|
|
4082
4074
|
const userId = ctx.userId;
|
|
4083
4075
|
let skipped = false;
|
|
4076
|
+
let entities = [];
|
|
4084
4077
|
await ctx.database.write(async () => {
|
|
4078
|
+
const { entities: byName, operations: entityOps } = await upsertEntitiesInWrite(
|
|
4079
|
+
ctx,
|
|
4080
|
+
normalized
|
|
4081
|
+
);
|
|
4082
|
+
entities = Array.from(byName.values());
|
|
4085
4083
|
if (options?.unlessTopicsUserManaged && await autoLinkBlocked(ctx, memoryId)) {
|
|
4084
|
+
if (entityOps.length > 0) {
|
|
4085
|
+
await ctx.database.batch(...entityOps);
|
|
4086
|
+
}
|
|
4086
4087
|
skipped = true;
|
|
4087
4088
|
return;
|
|
4088
4089
|
}
|
|
4090
|
+
if (entities.length === 0) return;
|
|
4089
4091
|
const existingLinks = await ctx.memoryEntityCollection.query(import_watermelondb8.Q.where("memory_id", memoryId)).fetch();
|
|
4090
4092
|
const existingEntityIds = new Set(existingLinks.map((l) => String(l.entityId)));
|
|
4091
4093
|
const toCreate = entities.filter((e) => !existingEntityIds.has(e.uniqueId));
|
|
4092
|
-
if (toCreate.length === 0) return;
|
|
4093
|
-
const
|
|
4094
|
+
if (entityOps.length === 0 && toCreate.length === 0) return;
|
|
4095
|
+
const linkOps = toCreate.map(
|
|
4094
4096
|
(e) => ctx.memoryEntityCollection.prepareCreate((record) => {
|
|
4095
4097
|
record._setRaw("memory_id", memoryId);
|
|
4096
4098
|
record._setRaw("entity_id", e.uniqueId);
|
|
4097
4099
|
if (userId !== void 0) record._setRaw("user_id", userId);
|
|
4098
4100
|
})
|
|
4099
4101
|
);
|
|
4100
|
-
await ctx.database.batch(...
|
|
4102
|
+
await ctx.database.batch(...entityOps, ...linkOps);
|
|
4101
4103
|
});
|
|
4102
4104
|
return skipped ? [] : entities;
|
|
4103
4105
|
}
|
|
@@ -4112,22 +4114,28 @@ async function autoLinkBlocked(ctx, memoryId) {
|
|
|
4112
4114
|
}
|
|
4113
4115
|
async function replaceMemoryEntitiesGuardedOp(ctx, memoryId, entityInputs) {
|
|
4114
4116
|
const normalized = entityInputs.map((e) => typeof e === "string" ? { name: e } : e);
|
|
4115
|
-
const byName = await upsertEntitiesOp(ctx, normalized);
|
|
4116
|
-
const entities = Array.from(byName.values());
|
|
4117
4117
|
const userId = ctx.userId;
|
|
4118
4118
|
let skipped = false;
|
|
4119
|
+
let entities = [];
|
|
4119
4120
|
await ctx.database.write(async () => {
|
|
4120
4121
|
if (await autoLinkBlocked(ctx, memoryId)) {
|
|
4121
4122
|
skipped = true;
|
|
4122
4123
|
return;
|
|
4123
4124
|
}
|
|
4125
|
+
const { entities: byName, operations: entityOps } = await upsertEntitiesInWrite(
|
|
4126
|
+
ctx,
|
|
4127
|
+
normalized
|
|
4128
|
+
);
|
|
4129
|
+
entities = Array.from(byName.values());
|
|
4124
4130
|
const existingLinks = await ctx.memoryEntityCollection.query(import_watermelondb8.Q.where("memory_id", memoryId)).fetch();
|
|
4125
4131
|
const keep = new Set(entities.map((e) => e.uniqueId));
|
|
4126
4132
|
const existingEntityIds = new Set(existingLinks.map((l) => String(l.entityId)));
|
|
4127
4133
|
const toCreate = entities.filter((e) => !existingEntityIds.has(e.uniqueId));
|
|
4128
4134
|
const toDestroy = existingLinks.filter((l) => !keep.has(String(l.entityId)));
|
|
4129
|
-
if (toCreate.length === 0 && toDestroy.length === 0) return;
|
|
4135
|
+
if (entityOps.length === 0 && toCreate.length === 0 && toDestroy.length === 0) return;
|
|
4136
|
+
const orphans = await findOrphanedEntities(ctx, memoryId, toDestroy);
|
|
4130
4137
|
await ctx.database.batch(
|
|
4138
|
+
...entityOps,
|
|
4131
4139
|
...toCreate.map(
|
|
4132
4140
|
(e) => ctx.memoryEntityCollection.prepareCreate((record) => {
|
|
4133
4141
|
record._setRaw("memory_id", memoryId);
|
|
@@ -4135,11 +4143,23 @@ async function replaceMemoryEntitiesGuardedOp(ctx, memoryId, entityInputs) {
|
|
|
4135
4143
|
if (userId !== void 0) record._setRaw("user_id", userId);
|
|
4136
4144
|
})
|
|
4137
4145
|
),
|
|
4138
|
-
...toDestroy.map((l) => l.prepareDestroyPermanently())
|
|
4146
|
+
...toDestroy.map((l) => l.prepareDestroyPermanently()),
|
|
4147
|
+
...orphans.map((e) => e.prepareDestroyPermanently())
|
|
4139
4148
|
);
|
|
4140
4149
|
});
|
|
4141
4150
|
return skipped ? null : entities;
|
|
4142
4151
|
}
|
|
4152
|
+
async function findOrphanedEntities(ctx, memoryId, toDestroy) {
|
|
4153
|
+
const candidateIds = [...new Set(toDestroy.map((l) => String(l.entityId)))];
|
|
4154
|
+
if (candidateIds.length === 0) return [];
|
|
4155
|
+
const links = await ctx.memoryEntityCollection.query(import_watermelondb8.Q.where("entity_id", import_watermelondb8.Q.oneOf(candidateIds))).fetch();
|
|
4156
|
+
const stillLinked = new Set(
|
|
4157
|
+
links.filter((l) => String(l.memoryId) !== memoryId).map((l) => String(l.entityId))
|
|
4158
|
+
);
|
|
4159
|
+
const orphanIds = candidateIds.filter((id) => !stillLinked.has(id));
|
|
4160
|
+
if (orphanIds.length === 0) return [];
|
|
4161
|
+
return await ctx.entityCollection.query(import_watermelondb8.Q.where("id", import_watermelondb8.Q.oneOf(orphanIds))).fetch();
|
|
4162
|
+
}
|
|
4143
4163
|
async function unlinkMemoryEntitiesOp(ctx, memoryIds) {
|
|
4144
4164
|
if (memoryIds.length === 0) return;
|
|
4145
4165
|
const links = await ctx.memoryEntityCollection.query(import_watermelondb8.Q.where("memory_id", import_watermelondb8.Q.oneOf(Array.from(memoryIds)))).fetch();
|
|
@@ -4997,7 +5017,7 @@ var init_operations3 = __esm({
|
|
|
4997
5017
|
init_operations2();
|
|
4998
5018
|
init_encryption2();
|
|
4999
5019
|
KNOWN_TRUST_TIERS = /* @__PURE__ */ new Set(["quarantined", "trusted"]);
|
|
5000
|
-
TOPICS_EXTRACTION_VERSION =
|
|
5020
|
+
TOPICS_EXTRACTION_VERSION = 3;
|
|
5001
5021
|
}
|
|
5002
5022
|
});
|
|
5003
5023
|
|
|
@@ -13744,6 +13764,162 @@ init_types3();
|
|
|
13744
13764
|
init_logger();
|
|
13745
13765
|
init_redactor();
|
|
13746
13766
|
|
|
13767
|
+
// src/lib/memory/entitySalience.ts
|
|
13768
|
+
var GENERIC_ENTITY_NAMES = /* @__PURE__ */ new Set([
|
|
13769
|
+
// Relative and absolute time
|
|
13770
|
+
"today",
|
|
13771
|
+
"tomorrow",
|
|
13772
|
+
"yesterday",
|
|
13773
|
+
"tonight",
|
|
13774
|
+
"morning",
|
|
13775
|
+
"afternoon",
|
|
13776
|
+
"evening",
|
|
13777
|
+
"night",
|
|
13778
|
+
"day",
|
|
13779
|
+
"date",
|
|
13780
|
+
"time",
|
|
13781
|
+
"week",
|
|
13782
|
+
"weekend",
|
|
13783
|
+
"weekday",
|
|
13784
|
+
"month",
|
|
13785
|
+
"year",
|
|
13786
|
+
"monday",
|
|
13787
|
+
"tuesday",
|
|
13788
|
+
"wednesday",
|
|
13789
|
+
"thursday",
|
|
13790
|
+
"friday",
|
|
13791
|
+
"saturday",
|
|
13792
|
+
"sunday",
|
|
13793
|
+
"january",
|
|
13794
|
+
"february",
|
|
13795
|
+
"march",
|
|
13796
|
+
"april",
|
|
13797
|
+
"may",
|
|
13798
|
+
"june",
|
|
13799
|
+
"july",
|
|
13800
|
+
"august",
|
|
13801
|
+
"september",
|
|
13802
|
+
"october",
|
|
13803
|
+
"november",
|
|
13804
|
+
"december",
|
|
13805
|
+
// Generic containers and venues — the named ones ("Blue Bottle on Valencia",
|
|
13806
|
+
// "Stanford") are unaffected because they are not bare tokens.
|
|
13807
|
+
"home",
|
|
13808
|
+
"house",
|
|
13809
|
+
"apartment",
|
|
13810
|
+
"room",
|
|
13811
|
+
"office",
|
|
13812
|
+
"work",
|
|
13813
|
+
"workplace",
|
|
13814
|
+
"school",
|
|
13815
|
+
"gym",
|
|
13816
|
+
"store",
|
|
13817
|
+
"shop",
|
|
13818
|
+
"hospital",
|
|
13819
|
+
"airport",
|
|
13820
|
+
"hotel",
|
|
13821
|
+
"city",
|
|
13822
|
+
"town",
|
|
13823
|
+
"country",
|
|
13824
|
+
"place",
|
|
13825
|
+
// Generic calendar entries — "Chicago Marathon" survives, "meeting" doesn't.
|
|
13826
|
+
"meeting",
|
|
13827
|
+
"call",
|
|
13828
|
+
"appointment",
|
|
13829
|
+
"reminder",
|
|
13830
|
+
"event",
|
|
13831
|
+
"birthday",
|
|
13832
|
+
"breakfast",
|
|
13833
|
+
"lunch",
|
|
13834
|
+
"dinner",
|
|
13835
|
+
"brunch",
|
|
13836
|
+
"vacation",
|
|
13837
|
+
"holiday",
|
|
13838
|
+
"trip",
|
|
13839
|
+
// Plurals are listed explicitly rather than stemmed: naive `s`-stripping
|
|
13840
|
+
// would fold real titles into generics ("The Times" → "time"). Only plurals
|
|
13841
|
+
// that are junk as topics in their own right belong here — note the absence
|
|
13842
|
+
// of "times", "places", and anything else that reads as a name.
|
|
13843
|
+
"days",
|
|
13844
|
+
"weeks",
|
|
13845
|
+
"weekends",
|
|
13846
|
+
"months",
|
|
13847
|
+
"years",
|
|
13848
|
+
"rooms",
|
|
13849
|
+
"offices",
|
|
13850
|
+
"houses",
|
|
13851
|
+
"apartments",
|
|
13852
|
+
"stores",
|
|
13853
|
+
"shops",
|
|
13854
|
+
"hotels",
|
|
13855
|
+
"meetings",
|
|
13856
|
+
"calls",
|
|
13857
|
+
"appointments",
|
|
13858
|
+
"reminders",
|
|
13859
|
+
"events",
|
|
13860
|
+
"birthdays",
|
|
13861
|
+
"trips",
|
|
13862
|
+
"vacations",
|
|
13863
|
+
"holidays",
|
|
13864
|
+
// Meta / filler the models occasionally echo back as an entity
|
|
13865
|
+
"user",
|
|
13866
|
+
"assistant",
|
|
13867
|
+
"memory",
|
|
13868
|
+
"memories",
|
|
13869
|
+
"note",
|
|
13870
|
+
"notes",
|
|
13871
|
+
"thing",
|
|
13872
|
+
"things",
|
|
13873
|
+
"stuff",
|
|
13874
|
+
"something",
|
|
13875
|
+
"someone",
|
|
13876
|
+
"anything",
|
|
13877
|
+
"everything",
|
|
13878
|
+
"none",
|
|
13879
|
+
"other",
|
|
13880
|
+
"misc",
|
|
13881
|
+
"general",
|
|
13882
|
+
"unknown"
|
|
13883
|
+
]);
|
|
13884
|
+
function isGenericEntityName(name) {
|
|
13885
|
+
const tokens = name.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((token) => token.length > 0);
|
|
13886
|
+
if (tokens.length === 0) return true;
|
|
13887
|
+
const distinctive = tokens.filter(
|
|
13888
|
+
(token) => !GENERIC_ENTITY_NAMES.has(token) && !ARTICLES.has(token) && !WEAK_MODIFIERS.has(token)
|
|
13889
|
+
);
|
|
13890
|
+
if (distinctive.length > 0) return false;
|
|
13891
|
+
const generic = tokens.filter((token) => GENERIC_ENTITY_NAMES.has(token));
|
|
13892
|
+
if (generic.length === 0) return true;
|
|
13893
|
+
const titleShaped = generic.length === 1 && tokens.some((token) => ARTICLES.has(token)) && !tokens.some((token) => WEAK_MODIFIERS.has(token));
|
|
13894
|
+
return !titleShaped;
|
|
13895
|
+
}
|
|
13896
|
+
var ARTICLES = /* @__PURE__ */ new Set(["the", "a", "an"]);
|
|
13897
|
+
var WEAK_MODIFIERS = /* @__PURE__ */ new Set([
|
|
13898
|
+
"my",
|
|
13899
|
+
"our",
|
|
13900
|
+
"their",
|
|
13901
|
+
"his",
|
|
13902
|
+
"her",
|
|
13903
|
+
"its",
|
|
13904
|
+
"this",
|
|
13905
|
+
"that",
|
|
13906
|
+
"next",
|
|
13907
|
+
"last",
|
|
13908
|
+
"upcoming",
|
|
13909
|
+
"every",
|
|
13910
|
+
"at",
|
|
13911
|
+
"in",
|
|
13912
|
+
"on",
|
|
13913
|
+
"of",
|
|
13914
|
+
"for",
|
|
13915
|
+
"with",
|
|
13916
|
+
"from",
|
|
13917
|
+
"to",
|
|
13918
|
+
"by",
|
|
13919
|
+
"and",
|
|
13920
|
+
"or"
|
|
13921
|
+
]);
|
|
13922
|
+
|
|
13747
13923
|
// src/lib/memory/injectionClassifier.ts
|
|
13748
13924
|
init_logger();
|
|
13749
13925
|
init_redactor();
|
|
@@ -14684,13 +14860,13 @@ function parseEntities(raw) {
|
|
|
14684
14860
|
for (const e of raw) {
|
|
14685
14861
|
if (typeof e === "string") {
|
|
14686
14862
|
const name2 = e.trim();
|
|
14687
|
-
if (name2.length > 0) out.push({ name: name2 });
|
|
14863
|
+
if (name2.length > 0 && !isGenericEntityName(name2)) out.push({ name: name2 });
|
|
14688
14864
|
continue;
|
|
14689
14865
|
}
|
|
14690
14866
|
if (typeof e !== "object" || e === null) continue;
|
|
14691
14867
|
const obj = e;
|
|
14692
14868
|
const name = typeof obj.name === "string" ? obj.name.trim() : "";
|
|
14693
|
-
if (name.length === 0) continue;
|
|
14869
|
+
if (name.length === 0 || isGenericEntityName(name)) continue;
|
|
14694
14870
|
const kind = typeof obj.kind === "string" && ENTITY_KINDS.includes(obj.kind) ? obj.kind : void 0;
|
|
14695
14871
|
out.push(kind !== void 0 ? { name, kind } : { name });
|
|
14696
14872
|
}
|
|
@@ -16032,7 +16208,11 @@ var SYSTEM_PROMPT6 = `You assign topics to saved memories for a personal memory
|
|
|
16032
16208
|
|
|
16033
16209
|
Each memory is a short statement about the user. For each memory, list the NAMED entities it mentions \u2014 these become the memory's topics, used to connect related memories in a knowledge graph.
|
|
16034
16210
|
|
|
16035
|
-
Include only NAMED entities, skip generic/common nouns.
|
|
16211
|
+
Include only NAMED entities, skip generic/common nouns. A topic must identify a specific thing the user could recognize by name; if it would be equally true of thousands of unrelated memories, leave it out:
|
|
16212
|
+
- SKIP bare generic nouns even when the memory capitalizes them or a calendar entry is titled that way \u2014 "Home", "Work", "Meeting", "Lunch", "Birthday", "Appointment", "Trip", "Today", "Friday", "March" are NOT topics.
|
|
16213
|
+
- KEEP the specific thing instead, when the memory names one: "Blue Bottle on Valencia" over "cafe", "Chicago Marathon" over "event", "Hollowpoint Labs" over "work".
|
|
16214
|
+
- Prefer 0 entities over a weak one. A memory whose only candidate is a generic noun has NO entities.
|
|
16215
|
+
${ENTITY_KIND_GUIDELINES}
|
|
16036
16216
|
|
|
16037
16217
|
Each memory below is written as "<id>: <text>". Output strict JSON: {"memories": [{"id": string, "entities": [{"name": string, "kind": string}]}]}
|
|
16038
16218
|
- exactly one element per input memory; copy its id EXACTLY as written (the token before the first ": "), with no brackets, quotes, or extra characters
|
|
@@ -16044,7 +16224,7 @@ async function extractEntitiesForMemories(memories, options) {
|
|
|
16044
16224
|
const redactor = resolvePiiRedactor(options.piiRedaction);
|
|
16045
16225
|
const vocabulary = (options.existingEntityNames ?? []).filter((n) => n.trim().length > 0).slice(0, MAX_VOCABULARY_NAMES).map((n) => redactor ? redactor.redactText(n).text : n);
|
|
16046
16226
|
const vocabularyNote = vocabulary.length > 0 ? `The user's existing topics: ${vocabulary.join(", ")}.
|
|
16047
|
-
When a memory refers to one of these, reuse the EXACT existing name (same spelling and
|
|
16227
|
+
When a memory refers to one of these, reuse the EXACT existing name (same spelling, casing, spacing and punctuation) instead of a variant \u2014 if "Foo.ai" is listed, never emit "Foo ai" or "Foo AI", and if "Jane Roe" is listed, emit that rather than a bare "Jane".
|
|
16048
16228
|
|
|
16049
16229
|
` : "";
|
|
16050
16230
|
for (let i = 0; i < memories.length; i += TOPIC_EXTRACTION_BATCH_SIZE) {
|
package/dist/expo/index.d.mts
CHANGED
|
@@ -5879,7 +5879,7 @@ declare function getUnfiledVaultMemoriesOp(ctx: VaultMemoryOperationsContext): P
|
|
|
5879
5879
|
* by the next sweep, so topic-quality improvements propagate across the existing
|
|
5880
5880
|
* vault. The worker's `limit` drains that re-extraction across sweeps.
|
|
5881
5881
|
*/
|
|
5882
|
-
declare const TOPICS_EXTRACTION_VERSION =
|
|
5882
|
+
declare const TOPICS_EXTRACTION_VERSION = 3;
|
|
5883
5883
|
/**
|
|
5884
5884
|
* Result of {@link getMemoriesNeedingTopicExtractionOp}: which memories the
|
|
5885
5885
|
* background topic worker should run LLM entity extraction on, and which it
|
package/dist/expo/index.d.ts
CHANGED
|
@@ -5879,7 +5879,7 @@ declare function getUnfiledVaultMemoriesOp(ctx: VaultMemoryOperationsContext): P
|
|
|
5879
5879
|
* by the next sweep, so topic-quality improvements propagate across the existing
|
|
5880
5880
|
* vault. The worker's `limit` drains that re-extraction across sweeps.
|
|
5881
5881
|
*/
|
|
5882
|
-
declare const TOPICS_EXTRACTION_VERSION =
|
|
5882
|
+
declare const TOPICS_EXTRACTION_VERSION = 3;
|
|
5883
5883
|
/**
|
|
5884
5884
|
* Result of {@link getMemoriesNeedingTopicExtractionOp}: which memories the
|
|
5885
5885
|
* background topic worker should run LLM entity extraction on, and which it
|