@anuma/sdk 6.41.0 → 6.42.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/index.cjs +37 -16
- package/dist/expo/index.d.mts +12 -0
- package/dist/expo/index.d.ts +12 -0
- package/dist/expo/index.mjs +37 -16
- package/dist/react/index.cjs +37 -16
- package/dist/react/index.d.mts +12 -0
- package/dist/react/index.d.ts +12 -0
- package/dist/react/index.mjs +37 -16
- package/dist/server/index.cjs +37 -16
- package/dist/server/index.d.mts +12 -0
- package/dist/server/index.d.ts +12 -0
- package/dist/server/index.mjs +37 -16
- package/package.json +1 -1
package/dist/expo/index.cjs
CHANGED
|
@@ -21843,12 +21843,19 @@ var FACET_STRUCTURED_RESPONSE_HINT = {
|
|
|
21843
21843
|
interests: `, "interests": <the same interests as an array of at most ${NEARBY_MAX_INTERESTS} strings of at most ${NEARBY_MAX_INTEREST_CODEPOINTS} characters each, e.g. ["trail running", "film photography"], or []>`
|
|
21844
21844
|
};
|
|
21845
21845
|
async function synthesizeProfile(ctx, options = {}) {
|
|
21846
|
-
|
|
21847
|
-
|
|
21846
|
+
const { store } = options;
|
|
21847
|
+
const vaultCtx = ctx.vaultCtx;
|
|
21848
|
+
if (!store && !vaultCtx) {
|
|
21849
|
+
throw new Error(
|
|
21850
|
+
"synthesizeProfile requires options.store or ctx.vaultCtx (vault-backed facts)."
|
|
21851
|
+
);
|
|
21848
21852
|
}
|
|
21849
|
-
if (!ctx.vaultCache) {
|
|
21850
|
-
throw new Error(
|
|
21853
|
+
if (!store && !ctx.vaultCache) {
|
|
21854
|
+
throw new Error(
|
|
21855
|
+
"synthesizeProfile requires options.store or ctx.vaultCache (semantic fact recall)."
|
|
21856
|
+
);
|
|
21851
21857
|
}
|
|
21858
|
+
const recallCtx = store ? { embeddingOptions: ctx.embeddingOptions, factSource: store.factSource } : ctx;
|
|
21852
21859
|
const facets = options.facets ?? DEFAULT_PROFILE_FACETS;
|
|
21853
21860
|
const scopes = options.scopes ?? DEFAULT_SCOPES;
|
|
21854
21861
|
const config = {
|
|
@@ -21859,11 +21866,8 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
21859
21866
|
reviewedMemoryIdsSignature: reviewedMemoryIdsSignature(options.reviewedMemoryIds)
|
|
21860
21867
|
};
|
|
21861
21868
|
const previous = options.previous && options.previous.version === PROFILE_DOC_VERSION && configMatches(options.previous.config, config) ? options.previous : void 0;
|
|
21862
|
-
const
|
|
21863
|
-
|
|
21864
|
-
includeDeleted: true,
|
|
21865
|
-
includeSuperseded: true
|
|
21866
|
-
});
|
|
21869
|
+
const listOptions = { scopes, includeDeleted: true, includeSuperseded: true };
|
|
21870
|
+
const [memories, projections] = store ? await Promise.all([store.list(listOptions), store.listProjections(listOptions)]) : [await getAllVaultMemoriesOp(vaultCtx, listOptions), []];
|
|
21867
21871
|
const watermark = computeVaultWatermark(memories);
|
|
21868
21872
|
const observationTrends = summarizeObservationTrends(
|
|
21869
21873
|
memories.filter((m) => !m.isDeleted && m.supersededBy === null).map((m) => ({
|
|
@@ -21873,11 +21877,14 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
21873
21877
|
}))
|
|
21874
21878
|
);
|
|
21875
21879
|
const presentIds = new Set(memories.map((m) => m.uniqueId));
|
|
21880
|
+
const unreadableMemoryIds = projections.map((p) => p.uniqueId).filter((id) => !presentIds.has(id)).sort();
|
|
21881
|
+
const previousUnreadable = new Set(previous?.unreadableMemoryIds ?? []);
|
|
21882
|
+
const sameUnreadable = unreadableMemoryIds.length === previousUnreadable.size && unreadableMemoryIds.every((id) => previousUnreadable.has(id));
|
|
21876
21883
|
const hasStaleSections = previous?.sections.some((s) => s.stale);
|
|
21877
21884
|
const citesMissingFact = previous?.sections.some(
|
|
21878
21885
|
(s) => s.sourceMemoryIds.some((id) => !presentIds.has(id))
|
|
21879
21886
|
);
|
|
21880
|
-
if (previous && previous.vaultWatermark === watermark && !hasStaleSections && !citesMissingFact) {
|
|
21887
|
+
if (previous && previous.vaultWatermark === watermark && !hasStaleSections && !citesMissingFact && sameUnreadable) {
|
|
21881
21888
|
const sameOrder = previous.sections.length === facets.length && facets.every((f, i) => previous.sections[i]?.key === f.key);
|
|
21882
21889
|
if (sameOrder) {
|
|
21883
21890
|
if (trendsEqual(previous.observationTrends, observationTrends)) return previous;
|
|
@@ -21890,12 +21897,13 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
21890
21897
|
};
|
|
21891
21898
|
}
|
|
21892
21899
|
const staleKeys = await computeStaleFacetKeys(
|
|
21893
|
-
|
|
21900
|
+
recallCtx,
|
|
21894
21901
|
memories,
|
|
21895
21902
|
facets,
|
|
21896
21903
|
previous,
|
|
21897
21904
|
watermark,
|
|
21898
|
-
options.reviewedMemoryIds
|
|
21905
|
+
options.reviewedMemoryIds,
|
|
21906
|
+
previousUnreadable
|
|
21899
21907
|
);
|
|
21900
21908
|
const memoriesById = new Map(memories.map((memory) => [memory.uniqueId, memory]));
|
|
21901
21909
|
const fallbackPriors = /* @__PURE__ */ new Map();
|
|
@@ -21915,7 +21923,7 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
21915
21923
|
if (prior && !staleKeys.has(facet.key)) {
|
|
21916
21924
|
return prior;
|
|
21917
21925
|
}
|
|
21918
|
-
return synthesizeFacet(facet,
|
|
21926
|
+
return synthesizeFacet(facet, recallCtx, options, fallbackPriors.get(facet.key));
|
|
21919
21927
|
})
|
|
21920
21928
|
);
|
|
21921
21929
|
const sections = settled.map((r, i) => {
|
|
@@ -21930,12 +21938,18 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
21930
21938
|
);
|
|
21931
21939
|
return fallbackSection(facet, fallbackPriors.get(facet.key));
|
|
21932
21940
|
});
|
|
21941
|
+
if (!sameUnreadable && unreadableMemoryIds.length > 0) {
|
|
21942
|
+
getLogger().warn("[memory/synthesizeProfile] some memories could not be read", {
|
|
21943
|
+
unreadable: unreadableMemoryIds.length
|
|
21944
|
+
});
|
|
21945
|
+
}
|
|
21933
21946
|
return {
|
|
21934
21947
|
version: PROFILE_DOC_VERSION,
|
|
21935
21948
|
sections,
|
|
21936
21949
|
vaultWatermark: watermark,
|
|
21937
21950
|
config,
|
|
21938
21951
|
observationTrends,
|
|
21952
|
+
...unreadableMemoryIds.length > 0 && { unreadableMemoryIds },
|
|
21939
21953
|
generatedAt: Date.now()
|
|
21940
21954
|
};
|
|
21941
21955
|
}
|
|
@@ -21969,11 +21983,13 @@ function computeVaultWatermark(memories) {
|
|
|
21969
21983
|
}
|
|
21970
21984
|
return max;
|
|
21971
21985
|
}
|
|
21972
|
-
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds) {
|
|
21986
|
+
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds, previouslyUnreadable) {
|
|
21973
21987
|
const allKeys = new Set(facets.map((f) => f.key));
|
|
21974
21988
|
if (previous && watermark < previous.vaultWatermark) return allKeys;
|
|
21975
21989
|
if (!previous) return allKeys;
|
|
21976
|
-
const changed = memories.filter(
|
|
21990
|
+
const changed = memories.filter(
|
|
21991
|
+
(m) => changeTime(m) > previous.vaultWatermark || previouslyUnreadable.has(m.uniqueId)
|
|
21992
|
+
);
|
|
21977
21993
|
const changedIds = new Set(changed.map((m) => m.uniqueId));
|
|
21978
21994
|
const presentIds = new Set(memories.map((m) => m.uniqueId));
|
|
21979
21995
|
const stale = /* @__PURE__ */ new Set();
|
|
@@ -22047,7 +22063,12 @@ async function attributeFacts(ctx, candidates, facets) {
|
|
|
22047
22063
|
for (const fv of factVectors) {
|
|
22048
22064
|
let matchedAny = false;
|
|
22049
22065
|
for (let i = 0; i < facets.length; i++) {
|
|
22050
|
-
|
|
22066
|
+
const query = queryVectors[i];
|
|
22067
|
+
const similarity = cosineSimilarity(
|
|
22068
|
+
fv,
|
|
22069
|
+
fv.length < query.length ? query.slice(0, fv.length) : query
|
|
22070
|
+
);
|
|
22071
|
+
if (similarity >= NEW_FACT_ATTRIBUTION_MIN_SCORE) {
|
|
22051
22072
|
keys.add(facets[i].key);
|
|
22052
22073
|
matchedAny = true;
|
|
22053
22074
|
}
|
package/dist/expo/index.d.mts
CHANGED
|
@@ -9821,6 +9821,12 @@ interface ProfileDoc {
|
|
|
9821
9821
|
* without another LLM pass. Recomputed every synthesis (not delta-cached).
|
|
9822
9822
|
*/
|
|
9823
9823
|
observationTrends: Record<ObservationTrend, number>;
|
|
9824
|
+
/**
|
|
9825
|
+
* Sorted ids the store listed but could not decrypt at synthesis time.
|
|
9826
|
+
* Absent when every memory was readable. A later call regenerates only when
|
|
9827
|
+
* this set changes, and attributes a memory once it becomes readable.
|
|
9828
|
+
*/
|
|
9829
|
+
unreadableMemoryIds?: string[];
|
|
9824
9830
|
/** Unix ms this doc was produced. */
|
|
9825
9831
|
generatedAt: number;
|
|
9826
9832
|
}
|
|
@@ -9874,6 +9880,12 @@ interface SynthesizeProfileOptions extends PortalLlmAuth {
|
|
|
9874
9880
|
* never accidentally disable the gate by finding it empty.
|
|
9875
9881
|
*/
|
|
9876
9882
|
reviewedMemoryIds?: readonly string[];
|
|
9883
|
+
/**
|
|
9884
|
+
* Read facts and recall through this store instead of `ctx.vaultCtx` and
|
|
9885
|
+
* `ctx.vaultCache`, so a remote store works. Only `ctx.embeddingOptions` is
|
|
9886
|
+
* then read from `ctx`.
|
|
9887
|
+
*/
|
|
9888
|
+
store?: Pick<MemoryStore, "list" | "listProjections" | "factSource">;
|
|
9877
9889
|
}
|
|
9878
9890
|
/**
|
|
9879
9891
|
* Synthesize a shareable {@link ProfileDoc} from the user's vault, on-device.
|
package/dist/expo/index.d.ts
CHANGED
|
@@ -9821,6 +9821,12 @@ interface ProfileDoc {
|
|
|
9821
9821
|
* without another LLM pass. Recomputed every synthesis (not delta-cached).
|
|
9822
9822
|
*/
|
|
9823
9823
|
observationTrends: Record<ObservationTrend, number>;
|
|
9824
|
+
/**
|
|
9825
|
+
* Sorted ids the store listed but could not decrypt at synthesis time.
|
|
9826
|
+
* Absent when every memory was readable. A later call regenerates only when
|
|
9827
|
+
* this set changes, and attributes a memory once it becomes readable.
|
|
9828
|
+
*/
|
|
9829
|
+
unreadableMemoryIds?: string[];
|
|
9824
9830
|
/** Unix ms this doc was produced. */
|
|
9825
9831
|
generatedAt: number;
|
|
9826
9832
|
}
|
|
@@ -9874,6 +9880,12 @@ interface SynthesizeProfileOptions extends PortalLlmAuth {
|
|
|
9874
9880
|
* never accidentally disable the gate by finding it empty.
|
|
9875
9881
|
*/
|
|
9876
9882
|
reviewedMemoryIds?: readonly string[];
|
|
9883
|
+
/**
|
|
9884
|
+
* Read facts and recall through this store instead of `ctx.vaultCtx` and
|
|
9885
|
+
* `ctx.vaultCache`, so a remote store works. Only `ctx.embeddingOptions` is
|
|
9886
|
+
* then read from `ctx`.
|
|
9887
|
+
*/
|
|
9888
|
+
store?: Pick<MemoryStore, "list" | "listProjections" | "factSource">;
|
|
9877
9889
|
}
|
|
9878
9890
|
/**
|
|
9879
9891
|
* Synthesize a shareable {@link ProfileDoc} from the user's vault, on-device.
|
package/dist/expo/index.mjs
CHANGED
|
@@ -20206,12 +20206,19 @@ var FACET_STRUCTURED_RESPONSE_HINT = {
|
|
|
20206
20206
|
interests: `, "interests": <the same interests as an array of at most ${NEARBY_MAX_INTERESTS} strings of at most ${NEARBY_MAX_INTEREST_CODEPOINTS} characters each, e.g. ["trail running", "film photography"], or []>`
|
|
20207
20207
|
};
|
|
20208
20208
|
async function synthesizeProfile(ctx, options = {}) {
|
|
20209
|
-
|
|
20210
|
-
|
|
20209
|
+
const { store } = options;
|
|
20210
|
+
const vaultCtx = ctx.vaultCtx;
|
|
20211
|
+
if (!store && !vaultCtx) {
|
|
20212
|
+
throw new Error(
|
|
20213
|
+
"synthesizeProfile requires options.store or ctx.vaultCtx (vault-backed facts)."
|
|
20214
|
+
);
|
|
20211
20215
|
}
|
|
20212
|
-
if (!ctx.vaultCache) {
|
|
20213
|
-
throw new Error(
|
|
20216
|
+
if (!store && !ctx.vaultCache) {
|
|
20217
|
+
throw new Error(
|
|
20218
|
+
"synthesizeProfile requires options.store or ctx.vaultCache (semantic fact recall)."
|
|
20219
|
+
);
|
|
20214
20220
|
}
|
|
20221
|
+
const recallCtx = store ? { embeddingOptions: ctx.embeddingOptions, factSource: store.factSource } : ctx;
|
|
20215
20222
|
const facets = options.facets ?? DEFAULT_PROFILE_FACETS;
|
|
20216
20223
|
const scopes = options.scopes ?? DEFAULT_SCOPES;
|
|
20217
20224
|
const config = {
|
|
@@ -20222,11 +20229,8 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
20222
20229
|
reviewedMemoryIdsSignature: reviewedMemoryIdsSignature(options.reviewedMemoryIds)
|
|
20223
20230
|
};
|
|
20224
20231
|
const previous = options.previous && options.previous.version === PROFILE_DOC_VERSION && configMatches(options.previous.config, config) ? options.previous : void 0;
|
|
20225
|
-
const
|
|
20226
|
-
|
|
20227
|
-
includeDeleted: true,
|
|
20228
|
-
includeSuperseded: true
|
|
20229
|
-
});
|
|
20232
|
+
const listOptions = { scopes, includeDeleted: true, includeSuperseded: true };
|
|
20233
|
+
const [memories, projections] = store ? await Promise.all([store.list(listOptions), store.listProjections(listOptions)]) : [await getAllVaultMemoriesOp(vaultCtx, listOptions), []];
|
|
20230
20234
|
const watermark = computeVaultWatermark(memories);
|
|
20231
20235
|
const observationTrends = summarizeObservationTrends(
|
|
20232
20236
|
memories.filter((m) => !m.isDeleted && m.supersededBy === null).map((m) => ({
|
|
@@ -20236,11 +20240,14 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
20236
20240
|
}))
|
|
20237
20241
|
);
|
|
20238
20242
|
const presentIds = new Set(memories.map((m) => m.uniqueId));
|
|
20243
|
+
const unreadableMemoryIds = projections.map((p) => p.uniqueId).filter((id) => !presentIds.has(id)).sort();
|
|
20244
|
+
const previousUnreadable = new Set(previous?.unreadableMemoryIds ?? []);
|
|
20245
|
+
const sameUnreadable = unreadableMemoryIds.length === previousUnreadable.size && unreadableMemoryIds.every((id) => previousUnreadable.has(id));
|
|
20239
20246
|
const hasStaleSections = previous?.sections.some((s) => s.stale);
|
|
20240
20247
|
const citesMissingFact = previous?.sections.some(
|
|
20241
20248
|
(s) => s.sourceMemoryIds.some((id) => !presentIds.has(id))
|
|
20242
20249
|
);
|
|
20243
|
-
if (previous && previous.vaultWatermark === watermark && !hasStaleSections && !citesMissingFact) {
|
|
20250
|
+
if (previous && previous.vaultWatermark === watermark && !hasStaleSections && !citesMissingFact && sameUnreadable) {
|
|
20244
20251
|
const sameOrder = previous.sections.length === facets.length && facets.every((f, i) => previous.sections[i]?.key === f.key);
|
|
20245
20252
|
if (sameOrder) {
|
|
20246
20253
|
if (trendsEqual(previous.observationTrends, observationTrends)) return previous;
|
|
@@ -20253,12 +20260,13 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
20253
20260
|
};
|
|
20254
20261
|
}
|
|
20255
20262
|
const staleKeys = await computeStaleFacetKeys(
|
|
20256
|
-
|
|
20263
|
+
recallCtx,
|
|
20257
20264
|
memories,
|
|
20258
20265
|
facets,
|
|
20259
20266
|
previous,
|
|
20260
20267
|
watermark,
|
|
20261
|
-
options.reviewedMemoryIds
|
|
20268
|
+
options.reviewedMemoryIds,
|
|
20269
|
+
previousUnreadable
|
|
20262
20270
|
);
|
|
20263
20271
|
const memoriesById = new Map(memories.map((memory) => [memory.uniqueId, memory]));
|
|
20264
20272
|
const fallbackPriors = /* @__PURE__ */ new Map();
|
|
@@ -20278,7 +20286,7 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
20278
20286
|
if (prior && !staleKeys.has(facet.key)) {
|
|
20279
20287
|
return prior;
|
|
20280
20288
|
}
|
|
20281
|
-
return synthesizeFacet(facet,
|
|
20289
|
+
return synthesizeFacet(facet, recallCtx, options, fallbackPriors.get(facet.key));
|
|
20282
20290
|
})
|
|
20283
20291
|
);
|
|
20284
20292
|
const sections = settled.map((r, i) => {
|
|
@@ -20293,12 +20301,18 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
20293
20301
|
);
|
|
20294
20302
|
return fallbackSection(facet, fallbackPriors.get(facet.key));
|
|
20295
20303
|
});
|
|
20304
|
+
if (!sameUnreadable && unreadableMemoryIds.length > 0) {
|
|
20305
|
+
getLogger().warn("[memory/synthesizeProfile] some memories could not be read", {
|
|
20306
|
+
unreadable: unreadableMemoryIds.length
|
|
20307
|
+
});
|
|
20308
|
+
}
|
|
20296
20309
|
return {
|
|
20297
20310
|
version: PROFILE_DOC_VERSION,
|
|
20298
20311
|
sections,
|
|
20299
20312
|
vaultWatermark: watermark,
|
|
20300
20313
|
config,
|
|
20301
20314
|
observationTrends,
|
|
20315
|
+
...unreadableMemoryIds.length > 0 && { unreadableMemoryIds },
|
|
20302
20316
|
generatedAt: Date.now()
|
|
20303
20317
|
};
|
|
20304
20318
|
}
|
|
@@ -20332,11 +20346,13 @@ function computeVaultWatermark(memories) {
|
|
|
20332
20346
|
}
|
|
20333
20347
|
return max;
|
|
20334
20348
|
}
|
|
20335
|
-
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds) {
|
|
20349
|
+
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds, previouslyUnreadable) {
|
|
20336
20350
|
const allKeys = new Set(facets.map((f) => f.key));
|
|
20337
20351
|
if (previous && watermark < previous.vaultWatermark) return allKeys;
|
|
20338
20352
|
if (!previous) return allKeys;
|
|
20339
|
-
const changed = memories.filter(
|
|
20353
|
+
const changed = memories.filter(
|
|
20354
|
+
(m) => changeTime(m) > previous.vaultWatermark || previouslyUnreadable.has(m.uniqueId)
|
|
20355
|
+
);
|
|
20340
20356
|
const changedIds = new Set(changed.map((m) => m.uniqueId));
|
|
20341
20357
|
const presentIds = new Set(memories.map((m) => m.uniqueId));
|
|
20342
20358
|
const stale = /* @__PURE__ */ new Set();
|
|
@@ -20410,7 +20426,12 @@ async function attributeFacts(ctx, candidates, facets) {
|
|
|
20410
20426
|
for (const fv of factVectors) {
|
|
20411
20427
|
let matchedAny = false;
|
|
20412
20428
|
for (let i = 0; i < facets.length; i++) {
|
|
20413
|
-
|
|
20429
|
+
const query = queryVectors[i];
|
|
20430
|
+
const similarity = cosineSimilarity(
|
|
20431
|
+
fv,
|
|
20432
|
+
fv.length < query.length ? query.slice(0, fv.length) : query
|
|
20433
|
+
);
|
|
20434
|
+
if (similarity >= NEW_FACT_ATTRIBUTION_MIN_SCORE) {
|
|
20414
20435
|
keys.add(facets[i].key);
|
|
20415
20436
|
matchedAny = true;
|
|
20416
20437
|
}
|
package/dist/react/index.cjs
CHANGED
|
@@ -25216,12 +25216,19 @@ var FACET_STRUCTURED_RESPONSE_HINT = {
|
|
|
25216
25216
|
interests: `, "interests": <the same interests as an array of at most ${NEARBY_MAX_INTERESTS} strings of at most ${NEARBY_MAX_INTEREST_CODEPOINTS} characters each, e.g. ["trail running", "film photography"], or []>`
|
|
25217
25217
|
};
|
|
25218
25218
|
async function synthesizeProfile(ctx, options = {}) {
|
|
25219
|
-
|
|
25220
|
-
|
|
25219
|
+
const { store } = options;
|
|
25220
|
+
const vaultCtx = ctx.vaultCtx;
|
|
25221
|
+
if (!store && !vaultCtx) {
|
|
25222
|
+
throw new Error(
|
|
25223
|
+
"synthesizeProfile requires options.store or ctx.vaultCtx (vault-backed facts)."
|
|
25224
|
+
);
|
|
25221
25225
|
}
|
|
25222
|
-
if (!ctx.vaultCache) {
|
|
25223
|
-
throw new Error(
|
|
25226
|
+
if (!store && !ctx.vaultCache) {
|
|
25227
|
+
throw new Error(
|
|
25228
|
+
"synthesizeProfile requires options.store or ctx.vaultCache (semantic fact recall)."
|
|
25229
|
+
);
|
|
25224
25230
|
}
|
|
25231
|
+
const recallCtx = store ? { embeddingOptions: ctx.embeddingOptions, factSource: store.factSource } : ctx;
|
|
25225
25232
|
const facets = options.facets ?? DEFAULT_PROFILE_FACETS;
|
|
25226
25233
|
const scopes = options.scopes ?? DEFAULT_SCOPES;
|
|
25227
25234
|
const config = {
|
|
@@ -25232,11 +25239,8 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
25232
25239
|
reviewedMemoryIdsSignature: reviewedMemoryIdsSignature(options.reviewedMemoryIds)
|
|
25233
25240
|
};
|
|
25234
25241
|
const previous = options.previous && options.previous.version === PROFILE_DOC_VERSION && configMatches(options.previous.config, config) ? options.previous : void 0;
|
|
25235
|
-
const
|
|
25236
|
-
|
|
25237
|
-
includeDeleted: true,
|
|
25238
|
-
includeSuperseded: true
|
|
25239
|
-
});
|
|
25242
|
+
const listOptions = { scopes, includeDeleted: true, includeSuperseded: true };
|
|
25243
|
+
const [memories, projections] = store ? await Promise.all([store.list(listOptions), store.listProjections(listOptions)]) : [await getAllVaultMemoriesOp(vaultCtx, listOptions), []];
|
|
25240
25244
|
const watermark = computeVaultWatermark(memories);
|
|
25241
25245
|
const observationTrends = summarizeObservationTrends(
|
|
25242
25246
|
memories.filter((m) => !m.isDeleted && m.supersededBy === null).map((m) => ({
|
|
@@ -25246,11 +25250,14 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
25246
25250
|
}))
|
|
25247
25251
|
);
|
|
25248
25252
|
const presentIds = new Set(memories.map((m) => m.uniqueId));
|
|
25253
|
+
const unreadableMemoryIds = projections.map((p) => p.uniqueId).filter((id) => !presentIds.has(id)).sort();
|
|
25254
|
+
const previousUnreadable = new Set(previous?.unreadableMemoryIds ?? []);
|
|
25255
|
+
const sameUnreadable = unreadableMemoryIds.length === previousUnreadable.size && unreadableMemoryIds.every((id) => previousUnreadable.has(id));
|
|
25249
25256
|
const hasStaleSections = previous?.sections.some((s) => s.stale);
|
|
25250
25257
|
const citesMissingFact = previous?.sections.some(
|
|
25251
25258
|
(s) => s.sourceMemoryIds.some((id) => !presentIds.has(id))
|
|
25252
25259
|
);
|
|
25253
|
-
if (previous && previous.vaultWatermark === watermark && !hasStaleSections && !citesMissingFact) {
|
|
25260
|
+
if (previous && previous.vaultWatermark === watermark && !hasStaleSections && !citesMissingFact && sameUnreadable) {
|
|
25254
25261
|
const sameOrder = previous.sections.length === facets.length && facets.every((f, i) => previous.sections[i]?.key === f.key);
|
|
25255
25262
|
if (sameOrder) {
|
|
25256
25263
|
if (trendsEqual(previous.observationTrends, observationTrends)) return previous;
|
|
@@ -25263,12 +25270,13 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
25263
25270
|
};
|
|
25264
25271
|
}
|
|
25265
25272
|
const staleKeys = await computeStaleFacetKeys(
|
|
25266
|
-
|
|
25273
|
+
recallCtx,
|
|
25267
25274
|
memories,
|
|
25268
25275
|
facets,
|
|
25269
25276
|
previous,
|
|
25270
25277
|
watermark,
|
|
25271
|
-
options.reviewedMemoryIds
|
|
25278
|
+
options.reviewedMemoryIds,
|
|
25279
|
+
previousUnreadable
|
|
25272
25280
|
);
|
|
25273
25281
|
const memoriesById = new Map(memories.map((memory) => [memory.uniqueId, memory]));
|
|
25274
25282
|
const fallbackPriors = /* @__PURE__ */ new Map();
|
|
@@ -25288,7 +25296,7 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
25288
25296
|
if (prior && !staleKeys.has(facet.key)) {
|
|
25289
25297
|
return prior;
|
|
25290
25298
|
}
|
|
25291
|
-
return synthesizeFacet(facet,
|
|
25299
|
+
return synthesizeFacet(facet, recallCtx, options, fallbackPriors.get(facet.key));
|
|
25292
25300
|
})
|
|
25293
25301
|
);
|
|
25294
25302
|
const sections = settled.map((r, i) => {
|
|
@@ -25303,12 +25311,18 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
25303
25311
|
);
|
|
25304
25312
|
return fallbackSection(facet, fallbackPriors.get(facet.key));
|
|
25305
25313
|
});
|
|
25314
|
+
if (!sameUnreadable && unreadableMemoryIds.length > 0) {
|
|
25315
|
+
getLogger().warn("[memory/synthesizeProfile] some memories could not be read", {
|
|
25316
|
+
unreadable: unreadableMemoryIds.length
|
|
25317
|
+
});
|
|
25318
|
+
}
|
|
25306
25319
|
return {
|
|
25307
25320
|
version: PROFILE_DOC_VERSION,
|
|
25308
25321
|
sections,
|
|
25309
25322
|
vaultWatermark: watermark,
|
|
25310
25323
|
config,
|
|
25311
25324
|
observationTrends,
|
|
25325
|
+
...unreadableMemoryIds.length > 0 && { unreadableMemoryIds },
|
|
25312
25326
|
generatedAt: Date.now()
|
|
25313
25327
|
};
|
|
25314
25328
|
}
|
|
@@ -25342,11 +25356,13 @@ function computeVaultWatermark(memories) {
|
|
|
25342
25356
|
}
|
|
25343
25357
|
return max;
|
|
25344
25358
|
}
|
|
25345
|
-
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds) {
|
|
25359
|
+
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds, previouslyUnreadable) {
|
|
25346
25360
|
const allKeys = new Set(facets.map((f) => f.key));
|
|
25347
25361
|
if (previous && watermark < previous.vaultWatermark) return allKeys;
|
|
25348
25362
|
if (!previous) return allKeys;
|
|
25349
|
-
const changed = memories.filter(
|
|
25363
|
+
const changed = memories.filter(
|
|
25364
|
+
(m) => changeTime(m) > previous.vaultWatermark || previouslyUnreadable.has(m.uniqueId)
|
|
25365
|
+
);
|
|
25350
25366
|
const changedIds = new Set(changed.map((m) => m.uniqueId));
|
|
25351
25367
|
const presentIds = new Set(memories.map((m) => m.uniqueId));
|
|
25352
25368
|
const stale = /* @__PURE__ */ new Set();
|
|
@@ -25420,7 +25436,12 @@ async function attributeFacts(ctx, candidates, facets) {
|
|
|
25420
25436
|
for (const fv of factVectors) {
|
|
25421
25437
|
let matchedAny = false;
|
|
25422
25438
|
for (let i = 0; i < facets.length; i++) {
|
|
25423
|
-
|
|
25439
|
+
const query = queryVectors[i];
|
|
25440
|
+
const similarity = cosineSimilarity(
|
|
25441
|
+
fv,
|
|
25442
|
+
fv.length < query.length ? query.slice(0, fv.length) : query
|
|
25443
|
+
);
|
|
25444
|
+
if (similarity >= NEW_FACT_ATTRIBUTION_MIN_SCORE) {
|
|
25424
25445
|
keys.add(facets[i].key);
|
|
25425
25446
|
matchedAny = true;
|
|
25426
25447
|
}
|
package/dist/react/index.d.mts
CHANGED
|
@@ -12057,6 +12057,12 @@ interface ProfileDoc {
|
|
|
12057
12057
|
* without another LLM pass. Recomputed every synthesis (not delta-cached).
|
|
12058
12058
|
*/
|
|
12059
12059
|
observationTrends: Record<ObservationTrend, number>;
|
|
12060
|
+
/**
|
|
12061
|
+
* Sorted ids the store listed but could not decrypt at synthesis time.
|
|
12062
|
+
* Absent when every memory was readable. A later call regenerates only when
|
|
12063
|
+
* this set changes, and attributes a memory once it becomes readable.
|
|
12064
|
+
*/
|
|
12065
|
+
unreadableMemoryIds?: string[];
|
|
12060
12066
|
/** Unix ms this doc was produced. */
|
|
12061
12067
|
generatedAt: number;
|
|
12062
12068
|
}
|
|
@@ -12110,6 +12116,12 @@ interface SynthesizeProfileOptions extends PortalLlmAuth {
|
|
|
12110
12116
|
* never accidentally disable the gate by finding it empty.
|
|
12111
12117
|
*/
|
|
12112
12118
|
reviewedMemoryIds?: readonly string[];
|
|
12119
|
+
/**
|
|
12120
|
+
* Read facts and recall through this store instead of `ctx.vaultCtx` and
|
|
12121
|
+
* `ctx.vaultCache`, so a remote store works. Only `ctx.embeddingOptions` is
|
|
12122
|
+
* then read from `ctx`.
|
|
12123
|
+
*/
|
|
12124
|
+
store?: Pick<MemoryStore, "list" | "listProjections" | "factSource">;
|
|
12113
12125
|
}
|
|
12114
12126
|
/**
|
|
12115
12127
|
* Synthesize a shareable {@link ProfileDoc} from the user's vault, on-device.
|
package/dist/react/index.d.ts
CHANGED
|
@@ -12057,6 +12057,12 @@ interface ProfileDoc {
|
|
|
12057
12057
|
* without another LLM pass. Recomputed every synthesis (not delta-cached).
|
|
12058
12058
|
*/
|
|
12059
12059
|
observationTrends: Record<ObservationTrend, number>;
|
|
12060
|
+
/**
|
|
12061
|
+
* Sorted ids the store listed but could not decrypt at synthesis time.
|
|
12062
|
+
* Absent when every memory was readable. A later call regenerates only when
|
|
12063
|
+
* this set changes, and attributes a memory once it becomes readable.
|
|
12064
|
+
*/
|
|
12065
|
+
unreadableMemoryIds?: string[];
|
|
12060
12066
|
/** Unix ms this doc was produced. */
|
|
12061
12067
|
generatedAt: number;
|
|
12062
12068
|
}
|
|
@@ -12110,6 +12116,12 @@ interface SynthesizeProfileOptions extends PortalLlmAuth {
|
|
|
12110
12116
|
* never accidentally disable the gate by finding it empty.
|
|
12111
12117
|
*/
|
|
12112
12118
|
reviewedMemoryIds?: readonly string[];
|
|
12119
|
+
/**
|
|
12120
|
+
* Read facts and recall through this store instead of `ctx.vaultCtx` and
|
|
12121
|
+
* `ctx.vaultCache`, so a remote store works. Only `ctx.embeddingOptions` is
|
|
12122
|
+
* then read from `ctx`.
|
|
12123
|
+
*/
|
|
12124
|
+
store?: Pick<MemoryStore, "list" | "listProjections" | "factSource">;
|
|
12113
12125
|
}
|
|
12114
12126
|
/**
|
|
12115
12127
|
* Synthesize a shareable {@link ProfileDoc} from the user's vault, on-device.
|
package/dist/react/index.mjs
CHANGED
|
@@ -23308,12 +23308,19 @@ var FACET_STRUCTURED_RESPONSE_HINT = {
|
|
|
23308
23308
|
interests: `, "interests": <the same interests as an array of at most ${NEARBY_MAX_INTERESTS} strings of at most ${NEARBY_MAX_INTEREST_CODEPOINTS} characters each, e.g. ["trail running", "film photography"], or []>`
|
|
23309
23309
|
};
|
|
23310
23310
|
async function synthesizeProfile(ctx, options = {}) {
|
|
23311
|
-
|
|
23312
|
-
|
|
23311
|
+
const { store } = options;
|
|
23312
|
+
const vaultCtx = ctx.vaultCtx;
|
|
23313
|
+
if (!store && !vaultCtx) {
|
|
23314
|
+
throw new Error(
|
|
23315
|
+
"synthesizeProfile requires options.store or ctx.vaultCtx (vault-backed facts)."
|
|
23316
|
+
);
|
|
23313
23317
|
}
|
|
23314
|
-
if (!ctx.vaultCache) {
|
|
23315
|
-
throw new Error(
|
|
23318
|
+
if (!store && !ctx.vaultCache) {
|
|
23319
|
+
throw new Error(
|
|
23320
|
+
"synthesizeProfile requires options.store or ctx.vaultCache (semantic fact recall)."
|
|
23321
|
+
);
|
|
23316
23322
|
}
|
|
23323
|
+
const recallCtx = store ? { embeddingOptions: ctx.embeddingOptions, factSource: store.factSource } : ctx;
|
|
23317
23324
|
const facets = options.facets ?? DEFAULT_PROFILE_FACETS;
|
|
23318
23325
|
const scopes = options.scopes ?? DEFAULT_SCOPES;
|
|
23319
23326
|
const config = {
|
|
@@ -23324,11 +23331,8 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
23324
23331
|
reviewedMemoryIdsSignature: reviewedMemoryIdsSignature(options.reviewedMemoryIds)
|
|
23325
23332
|
};
|
|
23326
23333
|
const previous = options.previous && options.previous.version === PROFILE_DOC_VERSION && configMatches(options.previous.config, config) ? options.previous : void 0;
|
|
23327
|
-
const
|
|
23328
|
-
|
|
23329
|
-
includeDeleted: true,
|
|
23330
|
-
includeSuperseded: true
|
|
23331
|
-
});
|
|
23334
|
+
const listOptions = { scopes, includeDeleted: true, includeSuperseded: true };
|
|
23335
|
+
const [memories, projections] = store ? await Promise.all([store.list(listOptions), store.listProjections(listOptions)]) : [await getAllVaultMemoriesOp(vaultCtx, listOptions), []];
|
|
23332
23336
|
const watermark = computeVaultWatermark(memories);
|
|
23333
23337
|
const observationTrends = summarizeObservationTrends(
|
|
23334
23338
|
memories.filter((m) => !m.isDeleted && m.supersededBy === null).map((m) => ({
|
|
@@ -23338,11 +23342,14 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
23338
23342
|
}))
|
|
23339
23343
|
);
|
|
23340
23344
|
const presentIds = new Set(memories.map((m) => m.uniqueId));
|
|
23345
|
+
const unreadableMemoryIds = projections.map((p) => p.uniqueId).filter((id) => !presentIds.has(id)).sort();
|
|
23346
|
+
const previousUnreadable = new Set(previous?.unreadableMemoryIds ?? []);
|
|
23347
|
+
const sameUnreadable = unreadableMemoryIds.length === previousUnreadable.size && unreadableMemoryIds.every((id) => previousUnreadable.has(id));
|
|
23341
23348
|
const hasStaleSections = previous?.sections.some((s) => s.stale);
|
|
23342
23349
|
const citesMissingFact = previous?.sections.some(
|
|
23343
23350
|
(s) => s.sourceMemoryIds.some((id) => !presentIds.has(id))
|
|
23344
23351
|
);
|
|
23345
|
-
if (previous && previous.vaultWatermark === watermark && !hasStaleSections && !citesMissingFact) {
|
|
23352
|
+
if (previous && previous.vaultWatermark === watermark && !hasStaleSections && !citesMissingFact && sameUnreadable) {
|
|
23346
23353
|
const sameOrder = previous.sections.length === facets.length && facets.every((f, i) => previous.sections[i]?.key === f.key);
|
|
23347
23354
|
if (sameOrder) {
|
|
23348
23355
|
if (trendsEqual(previous.observationTrends, observationTrends)) return previous;
|
|
@@ -23355,12 +23362,13 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
23355
23362
|
};
|
|
23356
23363
|
}
|
|
23357
23364
|
const staleKeys = await computeStaleFacetKeys(
|
|
23358
|
-
|
|
23365
|
+
recallCtx,
|
|
23359
23366
|
memories,
|
|
23360
23367
|
facets,
|
|
23361
23368
|
previous,
|
|
23362
23369
|
watermark,
|
|
23363
|
-
options.reviewedMemoryIds
|
|
23370
|
+
options.reviewedMemoryIds,
|
|
23371
|
+
previousUnreadable
|
|
23364
23372
|
);
|
|
23365
23373
|
const memoriesById = new Map(memories.map((memory) => [memory.uniqueId, memory]));
|
|
23366
23374
|
const fallbackPriors = /* @__PURE__ */ new Map();
|
|
@@ -23380,7 +23388,7 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
23380
23388
|
if (prior && !staleKeys.has(facet.key)) {
|
|
23381
23389
|
return prior;
|
|
23382
23390
|
}
|
|
23383
|
-
return synthesizeFacet(facet,
|
|
23391
|
+
return synthesizeFacet(facet, recallCtx, options, fallbackPriors.get(facet.key));
|
|
23384
23392
|
})
|
|
23385
23393
|
);
|
|
23386
23394
|
const sections = settled.map((r, i) => {
|
|
@@ -23395,12 +23403,18 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
23395
23403
|
);
|
|
23396
23404
|
return fallbackSection(facet, fallbackPriors.get(facet.key));
|
|
23397
23405
|
});
|
|
23406
|
+
if (!sameUnreadable && unreadableMemoryIds.length > 0) {
|
|
23407
|
+
getLogger().warn("[memory/synthesizeProfile] some memories could not be read", {
|
|
23408
|
+
unreadable: unreadableMemoryIds.length
|
|
23409
|
+
});
|
|
23410
|
+
}
|
|
23398
23411
|
return {
|
|
23399
23412
|
version: PROFILE_DOC_VERSION,
|
|
23400
23413
|
sections,
|
|
23401
23414
|
vaultWatermark: watermark,
|
|
23402
23415
|
config,
|
|
23403
23416
|
observationTrends,
|
|
23417
|
+
...unreadableMemoryIds.length > 0 && { unreadableMemoryIds },
|
|
23404
23418
|
generatedAt: Date.now()
|
|
23405
23419
|
};
|
|
23406
23420
|
}
|
|
@@ -23434,11 +23448,13 @@ function computeVaultWatermark(memories) {
|
|
|
23434
23448
|
}
|
|
23435
23449
|
return max;
|
|
23436
23450
|
}
|
|
23437
|
-
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds) {
|
|
23451
|
+
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds, previouslyUnreadable) {
|
|
23438
23452
|
const allKeys = new Set(facets.map((f) => f.key));
|
|
23439
23453
|
if (previous && watermark < previous.vaultWatermark) return allKeys;
|
|
23440
23454
|
if (!previous) return allKeys;
|
|
23441
|
-
const changed = memories.filter(
|
|
23455
|
+
const changed = memories.filter(
|
|
23456
|
+
(m) => changeTime(m) > previous.vaultWatermark || previouslyUnreadable.has(m.uniqueId)
|
|
23457
|
+
);
|
|
23442
23458
|
const changedIds = new Set(changed.map((m) => m.uniqueId));
|
|
23443
23459
|
const presentIds = new Set(memories.map((m) => m.uniqueId));
|
|
23444
23460
|
const stale = /* @__PURE__ */ new Set();
|
|
@@ -23512,7 +23528,12 @@ async function attributeFacts(ctx, candidates, facets) {
|
|
|
23512
23528
|
for (const fv of factVectors) {
|
|
23513
23529
|
let matchedAny = false;
|
|
23514
23530
|
for (let i = 0; i < facets.length; i++) {
|
|
23515
|
-
|
|
23531
|
+
const query = queryVectors[i];
|
|
23532
|
+
const similarity = cosineSimilarity(
|
|
23533
|
+
fv,
|
|
23534
|
+
fv.length < query.length ? query.slice(0, fv.length) : query
|
|
23535
|
+
);
|
|
23536
|
+
if (similarity >= NEW_FACT_ATTRIBUTION_MIN_SCORE) {
|
|
23516
23537
|
keys.add(facets[i].key);
|
|
23517
23538
|
matchedAny = true;
|
|
23518
23539
|
}
|
package/dist/server/index.cjs
CHANGED
|
@@ -35411,12 +35411,19 @@ var FACET_STRUCTURED_RESPONSE_HINT = {
|
|
|
35411
35411
|
interests: `, "interests": <the same interests as an array of at most ${NEARBY_MAX_INTERESTS} strings of at most ${NEARBY_MAX_INTEREST_CODEPOINTS} characters each, e.g. ["trail running", "film photography"], or []>`
|
|
35412
35412
|
};
|
|
35413
35413
|
async function synthesizeProfile(ctx, options = {}) {
|
|
35414
|
-
|
|
35415
|
-
|
|
35414
|
+
const { store } = options;
|
|
35415
|
+
const vaultCtx = ctx.vaultCtx;
|
|
35416
|
+
if (!store && !vaultCtx) {
|
|
35417
|
+
throw new Error(
|
|
35418
|
+
"synthesizeProfile requires options.store or ctx.vaultCtx (vault-backed facts)."
|
|
35419
|
+
);
|
|
35416
35420
|
}
|
|
35417
|
-
if (!ctx.vaultCache) {
|
|
35418
|
-
throw new Error(
|
|
35421
|
+
if (!store && !ctx.vaultCache) {
|
|
35422
|
+
throw new Error(
|
|
35423
|
+
"synthesizeProfile requires options.store or ctx.vaultCache (semantic fact recall)."
|
|
35424
|
+
);
|
|
35419
35425
|
}
|
|
35426
|
+
const recallCtx = store ? { embeddingOptions: ctx.embeddingOptions, factSource: store.factSource } : ctx;
|
|
35420
35427
|
const facets = options.facets ?? DEFAULT_PROFILE_FACETS;
|
|
35421
35428
|
const scopes = options.scopes ?? DEFAULT_SCOPES;
|
|
35422
35429
|
const config = {
|
|
@@ -35427,11 +35434,8 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
35427
35434
|
reviewedMemoryIdsSignature: reviewedMemoryIdsSignature(options.reviewedMemoryIds)
|
|
35428
35435
|
};
|
|
35429
35436
|
const previous = options.previous && options.previous.version === PROFILE_DOC_VERSION && configMatches(options.previous.config, config) ? options.previous : void 0;
|
|
35430
|
-
const
|
|
35431
|
-
|
|
35432
|
-
includeDeleted: true,
|
|
35433
|
-
includeSuperseded: true
|
|
35434
|
-
});
|
|
35437
|
+
const listOptions = { scopes, includeDeleted: true, includeSuperseded: true };
|
|
35438
|
+
const [memories, projections] = store ? await Promise.all([store.list(listOptions), store.listProjections(listOptions)]) : [await getAllVaultMemoriesOp(vaultCtx, listOptions), []];
|
|
35435
35439
|
const watermark = computeVaultWatermark(memories);
|
|
35436
35440
|
const observationTrends = summarizeObservationTrends(
|
|
35437
35441
|
memories.filter((m) => !m.isDeleted && m.supersededBy === null).map((m) => ({
|
|
@@ -35441,11 +35445,14 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
35441
35445
|
}))
|
|
35442
35446
|
);
|
|
35443
35447
|
const presentIds = new Set(memories.map((m) => m.uniqueId));
|
|
35448
|
+
const unreadableMemoryIds = projections.map((p) => p.uniqueId).filter((id) => !presentIds.has(id)).sort();
|
|
35449
|
+
const previousUnreadable = new Set(previous?.unreadableMemoryIds ?? []);
|
|
35450
|
+
const sameUnreadable = unreadableMemoryIds.length === previousUnreadable.size && unreadableMemoryIds.every((id) => previousUnreadable.has(id));
|
|
35444
35451
|
const hasStaleSections = previous?.sections.some((s) => s.stale);
|
|
35445
35452
|
const citesMissingFact = previous?.sections.some(
|
|
35446
35453
|
(s) => s.sourceMemoryIds.some((id) => !presentIds.has(id))
|
|
35447
35454
|
);
|
|
35448
|
-
if (previous && previous.vaultWatermark === watermark && !hasStaleSections && !citesMissingFact) {
|
|
35455
|
+
if (previous && previous.vaultWatermark === watermark && !hasStaleSections && !citesMissingFact && sameUnreadable) {
|
|
35449
35456
|
const sameOrder = previous.sections.length === facets.length && facets.every((f, i) => previous.sections[i]?.key === f.key);
|
|
35450
35457
|
if (sameOrder) {
|
|
35451
35458
|
if (trendsEqual(previous.observationTrends, observationTrends)) return previous;
|
|
@@ -35458,12 +35465,13 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
35458
35465
|
};
|
|
35459
35466
|
}
|
|
35460
35467
|
const staleKeys = await computeStaleFacetKeys(
|
|
35461
|
-
|
|
35468
|
+
recallCtx,
|
|
35462
35469
|
memories,
|
|
35463
35470
|
facets,
|
|
35464
35471
|
previous,
|
|
35465
35472
|
watermark,
|
|
35466
|
-
options.reviewedMemoryIds
|
|
35473
|
+
options.reviewedMemoryIds,
|
|
35474
|
+
previousUnreadable
|
|
35467
35475
|
);
|
|
35468
35476
|
const memoriesById = new Map(memories.map((memory) => [memory.uniqueId, memory]));
|
|
35469
35477
|
const fallbackPriors = /* @__PURE__ */ new Map();
|
|
@@ -35483,7 +35491,7 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
35483
35491
|
if (prior && !staleKeys.has(facet.key)) {
|
|
35484
35492
|
return prior;
|
|
35485
35493
|
}
|
|
35486
|
-
return synthesizeFacet(facet,
|
|
35494
|
+
return synthesizeFacet(facet, recallCtx, options, fallbackPriors.get(facet.key));
|
|
35487
35495
|
})
|
|
35488
35496
|
);
|
|
35489
35497
|
const sections = settled.map((r, i) => {
|
|
@@ -35498,12 +35506,18 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
35498
35506
|
);
|
|
35499
35507
|
return fallbackSection(facet, fallbackPriors.get(facet.key));
|
|
35500
35508
|
});
|
|
35509
|
+
if (!sameUnreadable && unreadableMemoryIds.length > 0) {
|
|
35510
|
+
getLogger().warn("[memory/synthesizeProfile] some memories could not be read", {
|
|
35511
|
+
unreadable: unreadableMemoryIds.length
|
|
35512
|
+
});
|
|
35513
|
+
}
|
|
35501
35514
|
return {
|
|
35502
35515
|
version: PROFILE_DOC_VERSION,
|
|
35503
35516
|
sections,
|
|
35504
35517
|
vaultWatermark: watermark,
|
|
35505
35518
|
config,
|
|
35506
35519
|
observationTrends,
|
|
35520
|
+
...unreadableMemoryIds.length > 0 && { unreadableMemoryIds },
|
|
35507
35521
|
generatedAt: Date.now()
|
|
35508
35522
|
};
|
|
35509
35523
|
}
|
|
@@ -35537,11 +35551,13 @@ function computeVaultWatermark(memories) {
|
|
|
35537
35551
|
}
|
|
35538
35552
|
return max;
|
|
35539
35553
|
}
|
|
35540
|
-
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds) {
|
|
35554
|
+
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds, previouslyUnreadable) {
|
|
35541
35555
|
const allKeys = new Set(facets.map((f) => f.key));
|
|
35542
35556
|
if (previous && watermark < previous.vaultWatermark) return allKeys;
|
|
35543
35557
|
if (!previous) return allKeys;
|
|
35544
|
-
const changed = memories.filter(
|
|
35558
|
+
const changed = memories.filter(
|
|
35559
|
+
(m) => changeTime(m) > previous.vaultWatermark || previouslyUnreadable.has(m.uniqueId)
|
|
35560
|
+
);
|
|
35545
35561
|
const changedIds = new Set(changed.map((m) => m.uniqueId));
|
|
35546
35562
|
const presentIds = new Set(memories.map((m) => m.uniqueId));
|
|
35547
35563
|
const stale = /* @__PURE__ */ new Set();
|
|
@@ -35615,7 +35631,12 @@ async function attributeFacts(ctx, candidates, facets) {
|
|
|
35615
35631
|
for (const fv of factVectors) {
|
|
35616
35632
|
let matchedAny = false;
|
|
35617
35633
|
for (let i = 0; i < facets.length; i++) {
|
|
35618
|
-
|
|
35634
|
+
const query = queryVectors[i];
|
|
35635
|
+
const similarity = cosineSimilarity(
|
|
35636
|
+
fv,
|
|
35637
|
+
fv.length < query.length ? query.slice(0, fv.length) : query
|
|
35638
|
+
);
|
|
35639
|
+
if (similarity >= NEW_FACT_ATTRIBUTION_MIN_SCORE) {
|
|
35619
35640
|
keys.add(facets[i].key);
|
|
35620
35641
|
matchedAny = true;
|
|
35621
35642
|
}
|
package/dist/server/index.d.mts
CHANGED
|
@@ -9766,6 +9766,12 @@ interface ProfileDoc {
|
|
|
9766
9766
|
* without another LLM pass. Recomputed every synthesis (not delta-cached).
|
|
9767
9767
|
*/
|
|
9768
9768
|
observationTrends: Record<ObservationTrend, number>;
|
|
9769
|
+
/**
|
|
9770
|
+
* Sorted ids the store listed but could not decrypt at synthesis time.
|
|
9771
|
+
* Absent when every memory was readable. A later call regenerates only when
|
|
9772
|
+
* this set changes, and attributes a memory once it becomes readable.
|
|
9773
|
+
*/
|
|
9774
|
+
unreadableMemoryIds?: string[];
|
|
9769
9775
|
/** Unix ms this doc was produced. */
|
|
9770
9776
|
generatedAt: number;
|
|
9771
9777
|
}
|
|
@@ -9819,6 +9825,12 @@ interface SynthesizeProfileOptions extends PortalLlmAuth {
|
|
|
9819
9825
|
* never accidentally disable the gate by finding it empty.
|
|
9820
9826
|
*/
|
|
9821
9827
|
reviewedMemoryIds?: readonly string[];
|
|
9828
|
+
/**
|
|
9829
|
+
* Read facts and recall through this store instead of `ctx.vaultCtx` and
|
|
9830
|
+
* `ctx.vaultCache`, so a remote store works. Only `ctx.embeddingOptions` is
|
|
9831
|
+
* then read from `ctx`.
|
|
9832
|
+
*/
|
|
9833
|
+
store?: Pick<MemoryStore, "list" | "listProjections" | "factSource">;
|
|
9822
9834
|
}
|
|
9823
9835
|
/**
|
|
9824
9836
|
* Synthesize a shareable {@link ProfileDoc} from the user's vault, on-device.
|
package/dist/server/index.d.ts
CHANGED
|
@@ -9766,6 +9766,12 @@ interface ProfileDoc {
|
|
|
9766
9766
|
* without another LLM pass. Recomputed every synthesis (not delta-cached).
|
|
9767
9767
|
*/
|
|
9768
9768
|
observationTrends: Record<ObservationTrend, number>;
|
|
9769
|
+
/**
|
|
9770
|
+
* Sorted ids the store listed but could not decrypt at synthesis time.
|
|
9771
|
+
* Absent when every memory was readable. A later call regenerates only when
|
|
9772
|
+
* this set changes, and attributes a memory once it becomes readable.
|
|
9773
|
+
*/
|
|
9774
|
+
unreadableMemoryIds?: string[];
|
|
9769
9775
|
/** Unix ms this doc was produced. */
|
|
9770
9776
|
generatedAt: number;
|
|
9771
9777
|
}
|
|
@@ -9819,6 +9825,12 @@ interface SynthesizeProfileOptions extends PortalLlmAuth {
|
|
|
9819
9825
|
* never accidentally disable the gate by finding it empty.
|
|
9820
9826
|
*/
|
|
9821
9827
|
reviewedMemoryIds?: readonly string[];
|
|
9828
|
+
/**
|
|
9829
|
+
* Read facts and recall through this store instead of `ctx.vaultCtx` and
|
|
9830
|
+
* `ctx.vaultCache`, so a remote store works. Only `ctx.embeddingOptions` is
|
|
9831
|
+
* then read from `ctx`.
|
|
9832
|
+
*/
|
|
9833
|
+
store?: Pick<MemoryStore, "list" | "listProjections" | "factSource">;
|
|
9822
9834
|
}
|
|
9823
9835
|
/**
|
|
9824
9836
|
* Synthesize a shareable {@link ProfileDoc} from the user's vault, on-device.
|
package/dist/server/index.mjs
CHANGED
|
@@ -33686,12 +33686,19 @@ var FACET_STRUCTURED_RESPONSE_HINT = {
|
|
|
33686
33686
|
interests: `, "interests": <the same interests as an array of at most ${NEARBY_MAX_INTERESTS} strings of at most ${NEARBY_MAX_INTEREST_CODEPOINTS} characters each, e.g. ["trail running", "film photography"], or []>`
|
|
33687
33687
|
};
|
|
33688
33688
|
async function synthesizeProfile(ctx, options = {}) {
|
|
33689
|
-
|
|
33690
|
-
|
|
33689
|
+
const { store } = options;
|
|
33690
|
+
const vaultCtx = ctx.vaultCtx;
|
|
33691
|
+
if (!store && !vaultCtx) {
|
|
33692
|
+
throw new Error(
|
|
33693
|
+
"synthesizeProfile requires options.store or ctx.vaultCtx (vault-backed facts)."
|
|
33694
|
+
);
|
|
33691
33695
|
}
|
|
33692
|
-
if (!ctx.vaultCache) {
|
|
33693
|
-
throw new Error(
|
|
33696
|
+
if (!store && !ctx.vaultCache) {
|
|
33697
|
+
throw new Error(
|
|
33698
|
+
"synthesizeProfile requires options.store or ctx.vaultCache (semantic fact recall)."
|
|
33699
|
+
);
|
|
33694
33700
|
}
|
|
33701
|
+
const recallCtx = store ? { embeddingOptions: ctx.embeddingOptions, factSource: store.factSource } : ctx;
|
|
33695
33702
|
const facets = options.facets ?? DEFAULT_PROFILE_FACETS;
|
|
33696
33703
|
const scopes = options.scopes ?? DEFAULT_SCOPES;
|
|
33697
33704
|
const config = {
|
|
@@ -33702,11 +33709,8 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
33702
33709
|
reviewedMemoryIdsSignature: reviewedMemoryIdsSignature(options.reviewedMemoryIds)
|
|
33703
33710
|
};
|
|
33704
33711
|
const previous = options.previous && options.previous.version === PROFILE_DOC_VERSION && configMatches(options.previous.config, config) ? options.previous : void 0;
|
|
33705
|
-
const
|
|
33706
|
-
|
|
33707
|
-
includeDeleted: true,
|
|
33708
|
-
includeSuperseded: true
|
|
33709
|
-
});
|
|
33712
|
+
const listOptions = { scopes, includeDeleted: true, includeSuperseded: true };
|
|
33713
|
+
const [memories, projections] = store ? await Promise.all([store.list(listOptions), store.listProjections(listOptions)]) : [await getAllVaultMemoriesOp(vaultCtx, listOptions), []];
|
|
33710
33714
|
const watermark = computeVaultWatermark(memories);
|
|
33711
33715
|
const observationTrends = summarizeObservationTrends(
|
|
33712
33716
|
memories.filter((m) => !m.isDeleted && m.supersededBy === null).map((m) => ({
|
|
@@ -33716,11 +33720,14 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
33716
33720
|
}))
|
|
33717
33721
|
);
|
|
33718
33722
|
const presentIds = new Set(memories.map((m) => m.uniqueId));
|
|
33723
|
+
const unreadableMemoryIds = projections.map((p) => p.uniqueId).filter((id) => !presentIds.has(id)).sort();
|
|
33724
|
+
const previousUnreadable = new Set(previous?.unreadableMemoryIds ?? []);
|
|
33725
|
+
const sameUnreadable = unreadableMemoryIds.length === previousUnreadable.size && unreadableMemoryIds.every((id) => previousUnreadable.has(id));
|
|
33719
33726
|
const hasStaleSections = previous?.sections.some((s) => s.stale);
|
|
33720
33727
|
const citesMissingFact = previous?.sections.some(
|
|
33721
33728
|
(s) => s.sourceMemoryIds.some((id) => !presentIds.has(id))
|
|
33722
33729
|
);
|
|
33723
|
-
if (previous && previous.vaultWatermark === watermark && !hasStaleSections && !citesMissingFact) {
|
|
33730
|
+
if (previous && previous.vaultWatermark === watermark && !hasStaleSections && !citesMissingFact && sameUnreadable) {
|
|
33724
33731
|
const sameOrder = previous.sections.length === facets.length && facets.every((f, i) => previous.sections[i]?.key === f.key);
|
|
33725
33732
|
if (sameOrder) {
|
|
33726
33733
|
if (trendsEqual(previous.observationTrends, observationTrends)) return previous;
|
|
@@ -33733,12 +33740,13 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
33733
33740
|
};
|
|
33734
33741
|
}
|
|
33735
33742
|
const staleKeys = await computeStaleFacetKeys(
|
|
33736
|
-
|
|
33743
|
+
recallCtx,
|
|
33737
33744
|
memories,
|
|
33738
33745
|
facets,
|
|
33739
33746
|
previous,
|
|
33740
33747
|
watermark,
|
|
33741
|
-
options.reviewedMemoryIds
|
|
33748
|
+
options.reviewedMemoryIds,
|
|
33749
|
+
previousUnreadable
|
|
33742
33750
|
);
|
|
33743
33751
|
const memoriesById = new Map(memories.map((memory) => [memory.uniqueId, memory]));
|
|
33744
33752
|
const fallbackPriors = /* @__PURE__ */ new Map();
|
|
@@ -33758,7 +33766,7 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
33758
33766
|
if (prior && !staleKeys.has(facet.key)) {
|
|
33759
33767
|
return prior;
|
|
33760
33768
|
}
|
|
33761
|
-
return synthesizeFacet(facet,
|
|
33769
|
+
return synthesizeFacet(facet, recallCtx, options, fallbackPriors.get(facet.key));
|
|
33762
33770
|
})
|
|
33763
33771
|
);
|
|
33764
33772
|
const sections = settled.map((r, i) => {
|
|
@@ -33773,12 +33781,18 @@ async function synthesizeProfile(ctx, options = {}) {
|
|
|
33773
33781
|
);
|
|
33774
33782
|
return fallbackSection(facet, fallbackPriors.get(facet.key));
|
|
33775
33783
|
});
|
|
33784
|
+
if (!sameUnreadable && unreadableMemoryIds.length > 0) {
|
|
33785
|
+
getLogger().warn("[memory/synthesizeProfile] some memories could not be read", {
|
|
33786
|
+
unreadable: unreadableMemoryIds.length
|
|
33787
|
+
});
|
|
33788
|
+
}
|
|
33776
33789
|
return {
|
|
33777
33790
|
version: PROFILE_DOC_VERSION,
|
|
33778
33791
|
sections,
|
|
33779
33792
|
vaultWatermark: watermark,
|
|
33780
33793
|
config,
|
|
33781
33794
|
observationTrends,
|
|
33795
|
+
...unreadableMemoryIds.length > 0 && { unreadableMemoryIds },
|
|
33782
33796
|
generatedAt: Date.now()
|
|
33783
33797
|
};
|
|
33784
33798
|
}
|
|
@@ -33812,11 +33826,13 @@ function computeVaultWatermark(memories) {
|
|
|
33812
33826
|
}
|
|
33813
33827
|
return max;
|
|
33814
33828
|
}
|
|
33815
|
-
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds) {
|
|
33829
|
+
async function computeStaleFacetKeys(ctx, memories, facets, previous, watermark, reviewedMemoryIds, previouslyUnreadable) {
|
|
33816
33830
|
const allKeys = new Set(facets.map((f) => f.key));
|
|
33817
33831
|
if (previous && watermark < previous.vaultWatermark) return allKeys;
|
|
33818
33832
|
if (!previous) return allKeys;
|
|
33819
|
-
const changed = memories.filter(
|
|
33833
|
+
const changed = memories.filter(
|
|
33834
|
+
(m) => changeTime(m) > previous.vaultWatermark || previouslyUnreadable.has(m.uniqueId)
|
|
33835
|
+
);
|
|
33820
33836
|
const changedIds = new Set(changed.map((m) => m.uniqueId));
|
|
33821
33837
|
const presentIds = new Set(memories.map((m) => m.uniqueId));
|
|
33822
33838
|
const stale = /* @__PURE__ */ new Set();
|
|
@@ -33890,7 +33906,12 @@ async function attributeFacts(ctx, candidates, facets) {
|
|
|
33890
33906
|
for (const fv of factVectors) {
|
|
33891
33907
|
let matchedAny = false;
|
|
33892
33908
|
for (let i = 0; i < facets.length; i++) {
|
|
33893
|
-
|
|
33909
|
+
const query = queryVectors[i];
|
|
33910
|
+
const similarity = cosineSimilarity(
|
|
33911
|
+
fv,
|
|
33912
|
+
fv.length < query.length ? query.slice(0, fv.length) : query
|
|
33913
|
+
);
|
|
33914
|
+
if (similarity >= NEW_FACT_ATTRIBUTION_MIN_SCORE) {
|
|
33894
33915
|
keys.add(facets[i].key);
|
|
33895
33916
|
matchedAny = true;
|
|
33896
33917
|
}
|