@anuma/sdk 3.12.2 → 3.13.1
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-ORVYPS3R.mjs → chunk-BOAKGY4R.mjs} +277 -46
- package/dist/expo/index.cjs +369 -66
- package/dist/expo/index.d.mts +133 -13
- package/dist/expo/index.d.ts +133 -13
- package/dist/expo/index.mjs +95 -22
- package/dist/expo/{recall-A4WZELH5.mjs → recall-O65PGPIQ.mjs} +1 -1
- package/dist/react/{chunk-QURYPMCE.mjs → chunk-XXCZVG4Z.mjs} +290 -49
- package/dist/react/index.cjs +401 -85
- package/dist/react/index.d.mts +146 -14
- package/dist/react/index.d.ts +146 -14
- package/dist/react/index.mjs +114 -38
- package/dist/react/{recall-NQNZDPNU.mjs → recall-KTJCUAXN.mjs} +1 -1
- package/dist/server/{chunk-FXGG7JA5.mjs → chunk-ME6ZQN52.mjs} +277 -46
- package/dist/server/index.cjs +330 -46
- package/dist/server/index.d.mts +133 -13
- package/dist/server/index.d.ts +133 -13
- package/dist/server/index.mjs +56 -2
- package/dist/server/{recall-SLMMIFHM.mjs → recall-RMCSM6L6.mjs} +1 -1
- package/package.json +3 -2
|
@@ -1918,6 +1918,31 @@ var ENTITY_KINDS = [
|
|
|
1918
1918
|
function normalizeEntityName(name) {
|
|
1919
1919
|
return name.trim().toLowerCase();
|
|
1920
1920
|
}
|
|
1921
|
+
function serializeTopics(topics) {
|
|
1922
|
+
return JSON.stringify(topics);
|
|
1923
|
+
}
|
|
1924
|
+
function parseTopics(value) {
|
|
1925
|
+
if (typeof value !== "string" || value.length === 0) return null;
|
|
1926
|
+
let parsed;
|
|
1927
|
+
try {
|
|
1928
|
+
parsed = JSON.parse(value);
|
|
1929
|
+
} catch {
|
|
1930
|
+
return null;
|
|
1931
|
+
}
|
|
1932
|
+
if (!Array.isArray(parsed)) return null;
|
|
1933
|
+
const out = [];
|
|
1934
|
+
for (const raw of parsed) {
|
|
1935
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
1936
|
+
const { name, kind, source } = raw;
|
|
1937
|
+
if (typeof name !== "string" || name.trim().length === 0) continue;
|
|
1938
|
+
out.push({
|
|
1939
|
+
name,
|
|
1940
|
+
...typeof kind === "string" && kind.length > 0 ? { kind } : {},
|
|
1941
|
+
source: source === "user" ? "user" : "auto"
|
|
1942
|
+
});
|
|
1943
|
+
}
|
|
1944
|
+
return out;
|
|
1945
|
+
}
|
|
1921
1946
|
|
|
1922
1947
|
// src/lib/db/entities/operations.ts
|
|
1923
1948
|
function entityToStored(e) {
|
|
@@ -1967,9 +1992,62 @@ async function upsertEntitiesInWrite(ctx, entities) {
|
|
|
1967
1992
|
for (const record of created) out.set(record.canonicalName, entityToStored(record));
|
|
1968
1993
|
return { entities: out, operations: [...created, ...updated] };
|
|
1969
1994
|
}
|
|
1995
|
+
async function findVaultRowInWrite(ctx, memoryId) {
|
|
1996
|
+
try {
|
|
1997
|
+
const rows = await ctx.database.get("memory_vault").query(Q2.where("id", memoryId)).fetch();
|
|
1998
|
+
return rows[0] ?? null;
|
|
1999
|
+
} catch {
|
|
2000
|
+
return null;
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
function prepareTopicsUpdate(row, topics, now) {
|
|
2004
|
+
const originalUpdatedAt = row.updatedAt.getTime();
|
|
2005
|
+
return row.prepareUpdate((r) => {
|
|
2006
|
+
r._setRaw("topics", serializeTopics(topics));
|
|
2007
|
+
r._setRaw("topics_updated_at", now);
|
|
2008
|
+
r._setRaw("updated_at", originalUpdatedAt);
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
2011
|
+
function displayNamesOf(entities) {
|
|
2012
|
+
const out = /* @__PURE__ */ new Map();
|
|
2013
|
+
for (const e of entities) {
|
|
2014
|
+
const name = e.name.trim();
|
|
2015
|
+
const normalized = normalizeEntityName(name);
|
|
2016
|
+
if (normalized.length === 0 || out.has(normalized)) continue;
|
|
2017
|
+
out.set(normalized, name);
|
|
2018
|
+
}
|
|
2019
|
+
return out;
|
|
2020
|
+
}
|
|
2021
|
+
function topicsEqual(stored, computed) {
|
|
2022
|
+
if (stored === null || stored.length !== computed.length) return false;
|
|
2023
|
+
const key = (t) => JSON.stringify([t.name, t.kind ?? null, t.source]);
|
|
2024
|
+
const storedKeys = stored.map(key).sort();
|
|
2025
|
+
const computedKeys = computed.map(key).sort();
|
|
2026
|
+
return storedKeys.every((k, i) => k === computedKeys[i]);
|
|
2027
|
+
}
|
|
2028
|
+
function resolveTopicsWrite(row, linked, displayNames, source) {
|
|
2029
|
+
if (row === null || source === null) return null;
|
|
2030
|
+
const topics = topicsForEntities(linked, displayNames, source);
|
|
2031
|
+
if (topicsEqual(parseTopics(row.topics), topics)) return null;
|
|
2032
|
+
return { row, topics };
|
|
2033
|
+
}
|
|
2034
|
+
function topicsForEntities(entities, displayNames, source) {
|
|
2035
|
+
return entities.map((e) => {
|
|
2036
|
+
const name = displayNames.get(e.canonicalName) ?? e.canonicalName;
|
|
2037
|
+
return { name, ...e.kind ? { kind: e.kind } : {}, source };
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2040
|
+
function toEntityObjects(entityInputs) {
|
|
2041
|
+
return entityInputs.map((e) => typeof e === "string" ? { name: e } : e);
|
|
2042
|
+
}
|
|
2043
|
+
async function prepareMemoryTopicsUpdate(ctx, memoryId, linked, inputs, source) {
|
|
2044
|
+
const row = await findVaultRowInWrite(ctx, memoryId);
|
|
2045
|
+
const write = resolveTopicsWrite(row, linked, displayNamesOf(toEntityObjects(inputs)), source);
|
|
2046
|
+
return write === null ? null : prepareTopicsUpdate(write.row, write.topics, Date.now());
|
|
2047
|
+
}
|
|
1970
2048
|
async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
1971
2049
|
if (entityInputs.length === 0) return [];
|
|
1972
|
-
const normalized = entityInputs
|
|
2050
|
+
const normalized = toEntityObjects(entityInputs);
|
|
1973
2051
|
const userId = ctx.userId;
|
|
1974
2052
|
let skipped = false;
|
|
1975
2053
|
let entities = [];
|
|
@@ -1979,7 +2057,8 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
1979
2057
|
normalized
|
|
1980
2058
|
);
|
|
1981
2059
|
entities = Array.from(byName.values());
|
|
1982
|
-
|
|
2060
|
+
const vaultRow = await findVaultRowInWrite(ctx, memoryId);
|
|
2061
|
+
if (options?.unlessTopicsUserManaged && autoLinkBlocked(vaultRow)) {
|
|
1983
2062
|
if (entityOps.length > 0) {
|
|
1984
2063
|
await ctx.database.batch(...entityOps);
|
|
1985
2064
|
}
|
|
@@ -1990,7 +2069,18 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
1990
2069
|
const existingLinks = await ctx.memoryEntityCollection.query(Q2.where("memory_id", memoryId)).fetch();
|
|
1991
2070
|
const existingEntityIds = new Set(existingLinks.map((l) => String(l.entityId)));
|
|
1992
2071
|
const toCreate = entities.filter((e) => !existingEntityIds.has(e.uniqueId));
|
|
1993
|
-
|
|
2072
|
+
const keptIds = entities.map((e) => e.uniqueId);
|
|
2073
|
+
const carriedOver = await resolveEntitiesByIds(
|
|
2074
|
+
ctx,
|
|
2075
|
+
[...existingEntityIds].filter((id) => !keptIds.includes(id))
|
|
2076
|
+
);
|
|
2077
|
+
const topicsWrite = resolveTopicsWrite(
|
|
2078
|
+
vaultRow,
|
|
2079
|
+
[...carriedOver, ...entities],
|
|
2080
|
+
displayNamesOf(normalized),
|
|
2081
|
+
options?.topicsSource ?? "auto"
|
|
2082
|
+
);
|
|
2083
|
+
if (entityOps.length === 0 && toCreate.length === 0 && topicsWrite === null) return;
|
|
1994
2084
|
const linkOps = toCreate.map(
|
|
1995
2085
|
(e) => ctx.memoryEntityCollection.prepareCreate((record) => {
|
|
1996
2086
|
record._setRaw("memory_id", memoryId);
|
|
@@ -1998,26 +2088,42 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
1998
2088
|
if (userId !== void 0) record._setRaw("user_id", userId);
|
|
1999
2089
|
})
|
|
2000
2090
|
);
|
|
2001
|
-
await ctx.database.batch(
|
|
2091
|
+
await ctx.database.batch(
|
|
2092
|
+
...entityOps,
|
|
2093
|
+
...linkOps,
|
|
2094
|
+
...topicsWrite ? [prepareTopicsUpdate(topicsWrite.row, topicsWrite.topics, Date.now())] : []
|
|
2095
|
+
);
|
|
2002
2096
|
});
|
|
2003
2097
|
return skipped ? [] : entities;
|
|
2004
2098
|
}
|
|
2005
|
-
async function
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
}
|
|
2099
|
+
async function resolveEntitiesByIds(ctx, entityIds) {
|
|
2100
|
+
if (entityIds.length === 0) return [];
|
|
2101
|
+
const rows = await ctx.entityCollection.query(Q2.where("id", Q2.oneOf(Array.from(entityIds)))).fetch();
|
|
2102
|
+
return rows.map(entityToStored);
|
|
2103
|
+
}
|
|
2104
|
+
function autoLinkBlocked(row) {
|
|
2105
|
+
return !row || !!row.isDeleted || !!row.topicsUserManaged;
|
|
2013
2106
|
}
|
|
2014
2107
|
async function replaceMemoryEntitiesGuardedOp(ctx, memoryId, entityInputs) {
|
|
2015
|
-
|
|
2108
|
+
return replaceMemoryEntities(ctx, memoryId, entityInputs, {
|
|
2109
|
+
guarded: true,
|
|
2110
|
+
topicsSource: "auto"
|
|
2111
|
+
});
|
|
2112
|
+
}
|
|
2113
|
+
async function relinkMemoryEntitiesFromTopicsOp(ctx, memoryId, topics) {
|
|
2114
|
+
return replaceMemoryEntities(ctx, memoryId, topics, {
|
|
2115
|
+
guarded: false,
|
|
2116
|
+
topicsSource: null
|
|
2117
|
+
});
|
|
2118
|
+
}
|
|
2119
|
+
async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
2120
|
+
const normalized = toEntityObjects(entityInputs);
|
|
2016
2121
|
const userId = ctx.userId;
|
|
2017
2122
|
let skipped = false;
|
|
2018
2123
|
let entities = [];
|
|
2019
2124
|
await ctx.database.write(async () => {
|
|
2020
|
-
|
|
2125
|
+
const vaultRow = await findVaultRowInWrite(ctx, memoryId);
|
|
2126
|
+
if (options.guarded && autoLinkBlocked(vaultRow)) {
|
|
2021
2127
|
skipped = true;
|
|
2022
2128
|
return;
|
|
2023
2129
|
}
|
|
@@ -2031,7 +2137,15 @@ async function replaceMemoryEntitiesGuardedOp(ctx, memoryId, entityInputs) {
|
|
|
2031
2137
|
const existingEntityIds = new Set(existingLinks.map((l) => String(l.entityId)));
|
|
2032
2138
|
const toCreate = entities.filter((e) => !existingEntityIds.has(e.uniqueId));
|
|
2033
2139
|
const toDestroy = existingLinks.filter((l) => !keep.has(String(l.entityId)));
|
|
2034
|
-
|
|
2140
|
+
const topicsWrite = resolveTopicsWrite(
|
|
2141
|
+
vaultRow,
|
|
2142
|
+
entities,
|
|
2143
|
+
displayNamesOf(normalized),
|
|
2144
|
+
options.topicsSource
|
|
2145
|
+
);
|
|
2146
|
+
if (entityOps.length === 0 && toCreate.length === 0 && toDestroy.length === 0 && topicsWrite === null) {
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2035
2149
|
const orphans = await findOrphanedEntities(ctx, memoryId, toDestroy);
|
|
2036
2150
|
await ctx.database.batch(
|
|
2037
2151
|
...entityOps,
|
|
@@ -2043,7 +2157,8 @@ async function replaceMemoryEntitiesGuardedOp(ctx, memoryId, entityInputs) {
|
|
|
2043
2157
|
})
|
|
2044
2158
|
),
|
|
2045
2159
|
...toDestroy.map((l) => l.prepareDestroyPermanently()),
|
|
2046
|
-
...orphans.map((e) => e.prepareDestroyPermanently())
|
|
2160
|
+
...orphans.map((e) => e.prepareDestroyPermanently()),
|
|
2161
|
+
...topicsWrite ? [prepareTopicsUpdate(topicsWrite.row, topicsWrite.topics, Date.now())] : []
|
|
2047
2162
|
);
|
|
2048
2163
|
});
|
|
2049
2164
|
return skipped ? null : entities;
|
|
@@ -2253,6 +2368,8 @@ function vaultMemoryToStoredRaw(memory) {
|
|
|
2253
2368
|
eventTimeEnd: memory.eventTimeEnd ?? null,
|
|
2254
2369
|
eventTimeKind: memory.eventTimeKind ?? null,
|
|
2255
2370
|
topicsUserManaged: memory.topicsUserManaged ?? false,
|
|
2371
|
+
topics: parseTopics(memory.topics),
|
|
2372
|
+
topicsUpdatedAt: memory.topicsUpdatedAt ?? null,
|
|
2256
2373
|
topicsExtractedAt: memory.topicsExtractedAt ?? null,
|
|
2257
2374
|
topicsExtractedVersion: memory.topicsExtractedVersion ?? null,
|
|
2258
2375
|
supersededBy: memory.supersededBy ?? null,
|
|
@@ -2529,6 +2646,8 @@ function vaultMemoryRawToStoredRaw(raw) {
|
|
|
2529
2646
|
eventTimeKind: raw.event_time_kind ?? null,
|
|
2530
2647
|
// SQLite stores booleans as 0/1, LokiJS as true/false — coerce both.
|
|
2531
2648
|
topicsUserManaged: raw.topics_user_managed === true || raw.topics_user_managed === 1,
|
|
2649
|
+
topics: parseTopics(raw.topics),
|
|
2650
|
+
topicsUpdatedAt: raw.topics_updated_at ?? null,
|
|
2532
2651
|
topicsExtractedAt: raw.topics_extracted_at ?? null,
|
|
2533
2652
|
topicsExtractedVersion: raw.topics_extracted_version ?? null,
|
|
2534
2653
|
supersededBy: raw.superseded_by ?? null,
|
|
@@ -2819,13 +2938,23 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
|
|
|
2819
2938
|
});
|
|
2820
2939
|
});
|
|
2821
2940
|
if (stale) return null;
|
|
2822
|
-
const linked = entities.length > 0 ? await linkMemoryEntitiesOp(entityCtx, memoryId, entities) : [];
|
|
2941
|
+
const linked = entities.length > 0 ? await linkMemoryEntitiesOp(entityCtx, memoryId, entities, { topicsSource: "user" }) : [];
|
|
2823
2942
|
const keep = new Set(linked.map((e) => e.uniqueId));
|
|
2824
2943
|
const existing = await entityCtx.memoryEntityCollection.query(Q3.where("memory_id", memoryId)).fetch();
|
|
2825
2944
|
const staleLinks = existing.filter((l) => !keep.has(String(l.entityId)));
|
|
2826
|
-
if (staleLinks.length > 0) {
|
|
2945
|
+
if (staleLinks.length > 0 || entities.length === 0) {
|
|
2827
2946
|
await ctx.database.write(async () => {
|
|
2828
|
-
|
|
2947
|
+
const topicsOp = await prepareMemoryTopicsUpdate(
|
|
2948
|
+
entityCtx,
|
|
2949
|
+
memoryId,
|
|
2950
|
+
linked,
|
|
2951
|
+
entities,
|
|
2952
|
+
"user"
|
|
2953
|
+
);
|
|
2954
|
+
await ctx.database.batch(
|
|
2955
|
+
...staleLinks.map((l) => l.prepareDestroyPermanently()),
|
|
2956
|
+
...topicsOp ? [topicsOp] : []
|
|
2957
|
+
);
|
|
2829
2958
|
});
|
|
2830
2959
|
}
|
|
2831
2960
|
return vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
@@ -2956,56 +3085,111 @@ async function getUnfiledVaultMemoriesOp(ctx) {
|
|
|
2956
3085
|
);
|
|
2957
3086
|
}
|
|
2958
3087
|
var TOPICS_EXTRACTION_VERSION = 3;
|
|
3088
|
+
async function linkedEntityNamesByMemory(entityCtx, memoryIds) {
|
|
3089
|
+
const CHUNK = 500;
|
|
3090
|
+
const entityIdByMemory = /* @__PURE__ */ new Map();
|
|
3091
|
+
const allEntityIds = /* @__PURE__ */ new Set();
|
|
3092
|
+
for (let i = 0; i < memoryIds.length; i += CHUNK) {
|
|
3093
|
+
const links = await entityCtx.memoryEntityCollection.query(Q3.where("memory_id", Q3.oneOf(memoryIds.slice(i, i + CHUNK)))).unsafeFetchRaw();
|
|
3094
|
+
for (const link of links) {
|
|
3095
|
+
const memoryId = String(link.memory_id);
|
|
3096
|
+
const entityId = String(link.entity_id);
|
|
3097
|
+
allEntityIds.add(entityId);
|
|
3098
|
+
let bucket = entityIdByMemory.get(memoryId);
|
|
3099
|
+
if (!bucket) {
|
|
3100
|
+
bucket = /* @__PURE__ */ new Set();
|
|
3101
|
+
entityIdByMemory.set(memoryId, bucket);
|
|
3102
|
+
}
|
|
3103
|
+
bucket.add(entityId);
|
|
3104
|
+
}
|
|
3105
|
+
}
|
|
3106
|
+
const entityIds = Array.from(allEntityIds);
|
|
3107
|
+
const nameById = /* @__PURE__ */ new Map();
|
|
3108
|
+
for (let i = 0; i < entityIds.length; i += CHUNK) {
|
|
3109
|
+
const entities = await entityCtx.entityCollection.query(Q3.where("id", Q3.oneOf(entityIds.slice(i, i + CHUNK)))).unsafeFetchRaw();
|
|
3110
|
+
for (const e of entities) {
|
|
3111
|
+
if (typeof e.canonical_name === "string") nameById.set(String(e.id), e.canonical_name);
|
|
3112
|
+
}
|
|
3113
|
+
}
|
|
3114
|
+
const out = /* @__PURE__ */ new Map();
|
|
3115
|
+
for (const [memoryId, ids] of entityIdByMemory) {
|
|
3116
|
+
const names = /* @__PURE__ */ new Set();
|
|
3117
|
+
for (const id of ids) {
|
|
3118
|
+
const name = nameById.get(id);
|
|
3119
|
+
if (name !== void 0) names.add(name);
|
|
3120
|
+
}
|
|
3121
|
+
if (names.size > 0) out.set(memoryId, names);
|
|
3122
|
+
}
|
|
3123
|
+
return out;
|
|
3124
|
+
}
|
|
3125
|
+
function linksDivergeFromTopics(topics, linked) {
|
|
3126
|
+
const wanted = new Set(
|
|
3127
|
+
topics.map((t) => normalizeEntityName(t.name)).filter((n) => n.length > 0)
|
|
3128
|
+
);
|
|
3129
|
+
if (wanted.size !== linked.size) return true;
|
|
3130
|
+
for (const name of wanted) if (!linked.has(name)) return true;
|
|
3131
|
+
return false;
|
|
3132
|
+
}
|
|
2959
3133
|
async function getMemoriesNeedingTopicExtractionOp(ctx, options) {
|
|
2960
3134
|
const entityCtx = ctx.entityCtx;
|
|
2961
3135
|
if (!entityCtx) {
|
|
2962
3136
|
throw new Error("getMemoriesNeedingTopicExtractionOp requires ctx.entityCtx");
|
|
2963
3137
|
}
|
|
2964
|
-
const conditions = [
|
|
2965
|
-
// Boolean optional column: null (legacy) and false both mean auto-managed.
|
|
2966
|
-
// Q.notEq(true) is a NULL trap on SQLite (NULL <> TRUE is NULL) — enumerate.
|
|
2967
|
-
Q3.or(Q3.where("topics_user_managed", null), Q3.where("topics_user_managed", false)),
|
|
2968
|
-
...baseVaultConditions(ctx),
|
|
2969
|
-
Q3.sortBy("created_at", Q3.desc)
|
|
2970
|
-
];
|
|
3138
|
+
const conditions = [...baseVaultConditions(ctx), Q3.sortBy("created_at", Q3.desc)];
|
|
2971
3139
|
const rows = await ctx.vaultMemoryCollection.query(...conditions).unsafeFetchRaw();
|
|
2972
|
-
const
|
|
2973
|
-
|
|
3140
|
+
const linkedNames = await linkedEntityNamesByMemory(
|
|
3141
|
+
entityCtx,
|
|
3142
|
+
rows.map((r) => r.id)
|
|
3143
|
+
);
|
|
3144
|
+
const pendingRaw = [];
|
|
3145
|
+
const stampedPendingRaw = [];
|
|
3146
|
+
const linkedUnstampedAll = [];
|
|
3147
|
+
const topicsToRelinkAll = [];
|
|
3148
|
+
const topicsBackfillAll = [];
|
|
2974
3149
|
for (const raw of rows) {
|
|
3150
|
+
const id = raw.id;
|
|
3151
|
+
const topics = parseTopics(raw.topics);
|
|
3152
|
+
const linked = linkedNames.get(id);
|
|
3153
|
+
if (topics !== null && topics.length > 0 && linksDivergeFromTopics(topics, linked ?? /* @__PURE__ */ new Set())) {
|
|
3154
|
+
topicsToRelinkAll.push(id);
|
|
3155
|
+
continue;
|
|
3156
|
+
}
|
|
3157
|
+
if (raw.topics_user_managed) {
|
|
3158
|
+
if (topics === null && linked !== void 0) topicsBackfillAll.push(id);
|
|
3159
|
+
continue;
|
|
3160
|
+
}
|
|
2975
3161
|
const stamp = raw.topics_extracted_at ?? null;
|
|
3162
|
+
let isPending = false;
|
|
2976
3163
|
if (stamp !== null) {
|
|
2977
3164
|
const version = raw.topics_extracted_version ?? 0;
|
|
2978
3165
|
if (raw.updated_at > stamp || version < TOPICS_EXTRACTION_VERSION) {
|
|
2979
|
-
|
|
3166
|
+
stampedPendingRaw.push(raw);
|
|
3167
|
+
isPending = true;
|
|
2980
3168
|
}
|
|
2981
|
-
} else {
|
|
2982
|
-
|
|
2983
|
-
}
|
|
2984
|
-
}
|
|
2985
|
-
const linkedIds = /* @__PURE__ */ new Set();
|
|
2986
|
-
const CHUNK = 500;
|
|
2987
|
-
for (let i = 0; i < unstamped.length; i += CHUNK) {
|
|
2988
|
-
const ids = unstamped.slice(i, i + CHUNK).map((r) => r.id);
|
|
2989
|
-
const links = await entityCtx.memoryEntityCollection.query(Q3.where("memory_id", Q3.oneOf(ids))).unsafeFetchRaw();
|
|
2990
|
-
for (const link of links) linkedIds.add(String(link.memory_id));
|
|
2991
|
-
}
|
|
2992
|
-
const linkedUnstampedAll = [];
|
|
2993
|
-
const pendingRaw = [...stampedPending];
|
|
2994
|
-
for (const raw of unstamped) {
|
|
2995
|
-
if (linkedIds.has(raw.id)) {
|
|
2996
|
-
linkedUnstampedAll.push(raw.id);
|
|
3169
|
+
} else if (linked !== void 0) {
|
|
3170
|
+
linkedUnstampedAll.push(id);
|
|
2997
3171
|
} else {
|
|
2998
3172
|
pendingRaw.push(raw);
|
|
3173
|
+
isPending = true;
|
|
3174
|
+
}
|
|
3175
|
+
if (!isPending && topics === null && linked !== void 0) {
|
|
3176
|
+
topicsBackfillAll.push(id);
|
|
2999
3177
|
}
|
|
3000
3178
|
}
|
|
3001
3179
|
const cap = options?.limit !== void 0 && options.limit > 0 ? options.limit : void 0;
|
|
3002
|
-
const
|
|
3003
|
-
const
|
|
3180
|
+
const orderedPendingRaw = [...stampedPendingRaw, ...pendingRaw];
|
|
3181
|
+
const limitedPendingRaw = cap !== void 0 ? orderedPendingRaw.slice(0, cap) : orderedPendingRaw;
|
|
3004
3182
|
const pending = await mapInBatches(
|
|
3005
3183
|
limitedPendingRaw,
|
|
3006
3184
|
(raw) => vaultMemoryRawToStored(raw, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
|
|
3007
3185
|
);
|
|
3008
|
-
|
|
3186
|
+
const applyCap = (ids) => cap !== void 0 ? ids.slice(0, cap) : ids;
|
|
3187
|
+
return {
|
|
3188
|
+
pending,
|
|
3189
|
+
linkedUnstamped: applyCap(linkedUnstampedAll),
|
|
3190
|
+
topicsToRelink: applyCap(topicsToRelinkAll),
|
|
3191
|
+
topicsBackfill: applyCap(topicsBackfillAll)
|
|
3192
|
+
};
|
|
3009
3193
|
}
|
|
3010
3194
|
async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = TOPICS_EXTRACTION_VERSION) {
|
|
3011
3195
|
if (memoryIds.length === 0) return [];
|
|
@@ -3039,6 +3223,61 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
|
|
|
3039
3223
|
}
|
|
3040
3224
|
return stamped;
|
|
3041
3225
|
}
|
|
3226
|
+
async function relinkMemoryTopicsOp(ctx, memoryIds) {
|
|
3227
|
+
const entityCtx = ctx.entityCtx;
|
|
3228
|
+
if (!entityCtx) {
|
|
3229
|
+
throw new Error("relinkMemoryTopicsOp requires ctx.entityCtx");
|
|
3230
|
+
}
|
|
3231
|
+
const relinked = [];
|
|
3232
|
+
for (const id of Array.from(new Set(memoryIds))) {
|
|
3233
|
+
let record;
|
|
3234
|
+
try {
|
|
3235
|
+
record = await ctx.vaultMemoryCollection.find(id);
|
|
3236
|
+
} catch {
|
|
3237
|
+
continue;
|
|
3238
|
+
}
|
|
3239
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) continue;
|
|
3240
|
+
const topics = parseTopics(record.topics);
|
|
3241
|
+
if (topics === null || topics.length === 0) continue;
|
|
3242
|
+
try {
|
|
3243
|
+
await relinkMemoryEntitiesFromTopicsOp(entityCtx, id, topics);
|
|
3244
|
+
relinked.push(id);
|
|
3245
|
+
} catch (err) {
|
|
3246
|
+
getLogger().warn("[memory/topics] relink failed", err);
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3249
|
+
return relinked;
|
|
3250
|
+
}
|
|
3251
|
+
async function backfillMemoryTopicsOp(ctx, memoryIds) {
|
|
3252
|
+
const entityCtx = ctx.entityCtx;
|
|
3253
|
+
if (!entityCtx) {
|
|
3254
|
+
throw new Error("backfillMemoryTopicsOp requires ctx.entityCtx");
|
|
3255
|
+
}
|
|
3256
|
+
const filled = [];
|
|
3257
|
+
for (const id of Array.from(new Set(memoryIds))) {
|
|
3258
|
+
let record;
|
|
3259
|
+
try {
|
|
3260
|
+
record = await ctx.vaultMemoryCollection.find(id);
|
|
3261
|
+
} catch {
|
|
3262
|
+
continue;
|
|
3263
|
+
}
|
|
3264
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) continue;
|
|
3265
|
+
if (parseTopics(record.topics) !== null) continue;
|
|
3266
|
+
const links = await entityCtx.memoryEntityCollection.query(Q3.where("memory_id", id)).unsafeFetchRaw();
|
|
3267
|
+
const entityIds = links.map((l) => String(l.entity_id));
|
|
3268
|
+
if (entityIds.length === 0) continue;
|
|
3269
|
+
const entities = await entityCtx.entityCollection.query(Q3.where("id", Q3.oneOf(entityIds))).fetch();
|
|
3270
|
+
if (entities.length === 0) continue;
|
|
3271
|
+
const source = record.topicsUserManaged ? "user" : "auto";
|
|
3272
|
+
await ctx.database.write(async () => {
|
|
3273
|
+
const topicsOp = await prepareMemoryTopicsUpdate(entityCtx, id, entities, [], source);
|
|
3274
|
+
if (!topicsOp) return;
|
|
3275
|
+
await ctx.database.batch(topicsOp);
|
|
3276
|
+
filled.push(id);
|
|
3277
|
+
});
|
|
3278
|
+
}
|
|
3279
|
+
return filled;
|
|
3280
|
+
}
|
|
3042
3281
|
async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
|
|
3043
3282
|
if (ctx.userId !== void 0 && ctx.userId !== userId) return 0;
|
|
3044
3283
|
const records = await ctx.vaultMemoryCollection.query(Q3.where("user_id", userId), Q3.where("is_deleted", false)).fetch();
|
|
@@ -6191,7 +6430,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
6191
6430
|
legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
|
|
6192
6431
|
);
|
|
6193
6432
|
}
|
|
6194
|
-
const { recall: recall2 } = await import("./recall-
|
|
6433
|
+
const { recall: recall2 } = await import("./recall-KTJCUAXN.mjs");
|
|
6195
6434
|
let recallDegraded = [];
|
|
6196
6435
|
const result = await recall2(
|
|
6197
6436
|
query,
|
|
@@ -7257,6 +7496,8 @@ export {
|
|
|
7257
7496
|
TOPICS_EXTRACTION_VERSION,
|
|
7258
7497
|
getMemoriesNeedingTopicExtractionOp,
|
|
7259
7498
|
stampTopicsExtractedAtOp,
|
|
7499
|
+
relinkMemoryTopicsOp,
|
|
7500
|
+
backfillMemoryTopicsOp,
|
|
7260
7501
|
deleteAllVaultMemoriesForUserOp,
|
|
7261
7502
|
assertVaultScopeForSweep,
|
|
7262
7503
|
getDecayCandidatesRawOp,
|