@anuma/sdk 4.2.1 → 5.0.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-3CDSIN22.mjs → chunk-SIMGZQ4P.mjs} +177 -148
- package/dist/expo/index.cjs +164 -73
- package/dist/expo/index.d.mts +75 -20
- package/dist/expo/index.d.ts +75 -20
- package/dist/expo/index.mjs +70 -8
- package/dist/expo/{recall-NARBDQAK.mjs → recall-PIDYDFIQ.mjs} +1 -1
- package/dist/react/{chunk-CUJDSH55.mjs → chunk-KTBOHRRE.mjs} +177 -148
- package/dist/react/index.cjs +164 -73
- package/dist/react/index.d.mts +75 -20
- package/dist/react/index.d.ts +75 -20
- package/dist/react/index.mjs +70 -8
- package/dist/react/{recall-FPPCKYYH.mjs → recall-DVX4W2UD.mjs} +1 -1
- package/dist/server/{chunk-UQDYBQVF.mjs → chunk-FKVYUOSD.mjs} +177 -148
- package/dist/server/index.cjs +164 -73
- package/dist/server/index.d.mts +75 -20
- package/dist/server/index.d.ts +75 -20
- package/dist/server/index.mjs +70 -8
- package/dist/server/{recall-ZHEPQNEU.mjs → recall-74L75BJ3.mjs} +1 -1
- package/package.json +1 -1
package/dist/server/index.cjs
CHANGED
|
@@ -20612,11 +20612,11 @@ async function decomposeQuery(query, options) {
|
|
|
20612
20612
|
userMessage: `Classify the following memory query and decompose if composite. Respond with JSON only \u2014 do not answer the question, do not ask for clarification.
|
|
20613
20613
|
|
|
20614
20614
|
Query: ${trimmed}`,
|
|
20615
|
-
// Decompose runs
|
|
20615
|
+
// Decompose runs ahead of recall in the tool layer — tighter than the
|
|
20616
20616
|
// portalLlm default (consolidate/extract can wait longer).
|
|
20617
20617
|
timeoutMs: 2e4,
|
|
20618
20618
|
// No internal retry: a failure degrades to the safe `{specific,[query]}`
|
|
20619
|
-
// fallback below
|
|
20619
|
+
// fallback below. The agent/tool loop is the retry surface (719/B4).
|
|
20620
20620
|
maxAttempts: 1,
|
|
20621
20621
|
tag: "memory/decompose",
|
|
20622
20622
|
...options.fetchFn && { fetchFn: options.fetchFn }
|
|
@@ -20628,12 +20628,28 @@ Query: ${trimmed}`,
|
|
|
20628
20628
|
if (parsed === null) return fallback;
|
|
20629
20629
|
return validate(parsed, trimmed) ?? fallback;
|
|
20630
20630
|
}
|
|
20631
|
+
function normalizeSubQueries(raw) {
|
|
20632
|
+
if (!raw || raw.length === 0) return [];
|
|
20633
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20634
|
+
const out = [];
|
|
20635
|
+
for (const s of raw) {
|
|
20636
|
+
if (typeof s !== "string") continue;
|
|
20637
|
+
const t = s.trim();
|
|
20638
|
+
if (t.length === 0) continue;
|
|
20639
|
+
const key = t.toLowerCase();
|
|
20640
|
+
if (seen.has(key)) continue;
|
|
20641
|
+
seen.add(key);
|
|
20642
|
+
out.push(t);
|
|
20643
|
+
if (out.length >= MAX_SUB_QUERIES) break;
|
|
20644
|
+
}
|
|
20645
|
+
return out;
|
|
20646
|
+
}
|
|
20631
20647
|
function validate(parsed, originalQuery) {
|
|
20632
20648
|
if (typeof parsed !== "object" || parsed === null) return null;
|
|
20633
20649
|
const obj = parsed;
|
|
20634
20650
|
const mode = obj.mode === "composite" ? "composite" : "specific";
|
|
20635
20651
|
if (!Array.isArray(obj.subQueries)) return null;
|
|
20636
|
-
const subQueries = obj.subQueries
|
|
20652
|
+
const subQueries = normalizeSubQueries(obj.subQueries);
|
|
20637
20653
|
if (subQueries.length === 0) return null;
|
|
20638
20654
|
if (mode === "specific") {
|
|
20639
20655
|
return { mode: "specific", subQueries: [originalQuery] };
|
|
@@ -21212,12 +21228,12 @@ __export(recall_exports, {
|
|
|
21212
21228
|
function flagsForBudget(budget) {
|
|
21213
21229
|
switch (budget) {
|
|
21214
21230
|
case "high":
|
|
21215
|
-
return { rerank: true,
|
|
21231
|
+
return { rerank: true, traverse: true };
|
|
21216
21232
|
case "mid":
|
|
21217
|
-
return { rerank: true,
|
|
21233
|
+
return { rerank: true, traverse: false };
|
|
21218
21234
|
case "low":
|
|
21219
21235
|
default:
|
|
21220
|
-
return { rerank: false,
|
|
21236
|
+
return { rerank: false, traverse: false };
|
|
21221
21237
|
}
|
|
21222
21238
|
}
|
|
21223
21239
|
function dedupeBy(items, ...keys) {
|
|
@@ -21236,10 +21252,10 @@ function dedupeBy(items, ...keys) {
|
|
|
21236
21252
|
async function recall(query, ctx, options = {}) {
|
|
21237
21253
|
const types = options.types ?? ["fact"];
|
|
21238
21254
|
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
21239
|
-
const
|
|
21240
|
-
const flags = flagsForBudget(
|
|
21241
|
-
const
|
|
21242
|
-
const
|
|
21255
|
+
const usedBudget = options.budget ?? DEFAULT_BUDGET;
|
|
21256
|
+
const flags = flagsForBudget(usedBudget);
|
|
21257
|
+
const normalizedFacets = normalizeSubQueries(options.subQueries);
|
|
21258
|
+
const subQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
21243
21259
|
const t0 = nowMs();
|
|
21244
21260
|
let prepMs = 0;
|
|
21245
21261
|
let factLaneMs = 0;
|
|
@@ -21260,7 +21276,9 @@ async function recall(query, ctx, options = {}) {
|
|
|
21260
21276
|
if (flags.rerank && factResults.length > 0 && hadV2Head && !didRerank) {
|
|
21261
21277
|
degraded.push("rerank-unavailable");
|
|
21262
21278
|
}
|
|
21263
|
-
if (
|
|
21279
|
+
if (usedBudget === "high" && options.decomposeOptions && !subQueries && !options.graphRefine) {
|
|
21280
|
+
degraded.push("decompose-moved");
|
|
21281
|
+
}
|
|
21264
21282
|
if (embeddingsUnavailable) degraded.push("embeddings-unavailable");
|
|
21265
21283
|
const diagnostics = {
|
|
21266
21284
|
usedBudget,
|
|
@@ -21373,10 +21391,8 @@ async function recall(query, ctx, options = {}) {
|
|
|
21373
21391
|
},
|
|
21374
21392
|
...options.rrfK !== void 0 && { rrfK: options.rrfK },
|
|
21375
21393
|
...options.decryptLast !== void 0 && { decryptLast: options.decryptLast },
|
|
21376
|
-
|
|
21377
|
-
|
|
21378
|
-
decomposeOptions: options.decomposeOptions
|
|
21379
|
-
},
|
|
21394
|
+
// 719/B4 — composite facets arrive pre-built; no LLM call here.
|
|
21395
|
+
...subQueries && { subQueries },
|
|
21380
21396
|
...options.scopes && { scopes: options.scopes },
|
|
21381
21397
|
...options.folderId !== void 0 && { folderId: options.folderId },
|
|
21382
21398
|
...options.factTypes?.length && { factTypes: options.factTypes },
|
|
@@ -21613,6 +21629,7 @@ var init_recall = __esm({
|
|
|
21613
21629
|
init_logger();
|
|
21614
21630
|
init_constants();
|
|
21615
21631
|
init_embeddings();
|
|
21632
|
+
init_decomposeQuery();
|
|
21616
21633
|
init_searchTool();
|
|
21617
21634
|
init_graphTraversal();
|
|
21618
21635
|
init_observationTrend();
|
|
@@ -22558,52 +22575,51 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
|
|
|
22558
22575
|
...searchOptions?.rrfK !== void 0 && { rrfK: searchOptions.rrfK },
|
|
22559
22576
|
...searchOptions?.factTypeWeights && { factTypeWeights: searchOptions.factTypeWeights }
|
|
22560
22577
|
};
|
|
22561
|
-
|
|
22562
|
-
|
|
22563
|
-
|
|
22564
|
-
|
|
22565
|
-
|
|
22566
|
-
|
|
22567
|
-
|
|
22568
|
-
|
|
22569
|
-
|
|
22570
|
-
|
|
22571
|
-
|
|
22572
|
-
|
|
22573
|
-
|
|
22574
|
-
|
|
22575
|
-
|
|
22576
|
-
|
|
22577
|
-
|
|
22578
|
-
|
|
22579
|
-
|
|
22580
|
-
|
|
22581
|
-
|
|
22582
|
-
|
|
22583
|
-
|
|
22584
|
-
|
|
22585
|
-
|
|
22586
|
-
|
|
22587
|
-
|
|
22588
|
-
|
|
22589
|
-
|
|
22590
|
-
|
|
22591
|
-
|
|
22592
|
-
|
|
22593
|
-
|
|
22594
|
-
|
|
22595
|
-
|
|
22596
|
-
|
|
22597
|
-
|
|
22598
|
-
|
|
22599
|
-
|
|
22600
|
-
|
|
22601
|
-
|
|
22602
|
-
|
|
22603
|
-
|
|
22604
|
-
|
|
22605
|
-
|
|
22606
|
-
}
|
|
22578
|
+
const normalizedFacets = normalizeSubQueries(searchOptions?.subQueries);
|
|
22579
|
+
const facetQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
22580
|
+
if (useFusion && !embeddingsUnavailable && facetQueries) {
|
|
22581
|
+
let subEmbeddings;
|
|
22582
|
+
try {
|
|
22583
|
+
subEmbeddings = await generateEmbeddings(facetQueries, embeddingOptions);
|
|
22584
|
+
} catch (err) {
|
|
22585
|
+
getLogger().warn(
|
|
22586
|
+
"memoryVault: sub-query embedding failed \u2014 falling back to single-query ranking: " + (err instanceof Error ? err.message : String(err))
|
|
22587
|
+
);
|
|
22588
|
+
subEmbeddings = [];
|
|
22589
|
+
}
|
|
22590
|
+
const subEmbeddingsUsable = facetQueries.length > 0 && subEmbeddings.length === facetQueries.length && subEmbeddings.every((v) => v.length > 0 && v.length === queryEmbedding.length);
|
|
22591
|
+
if (subEmbeddings.length > 0 && !subEmbeddingsUsable) {
|
|
22592
|
+
getLogger().warn(
|
|
22593
|
+
`memoryVault: sub-query embedding returned ${subEmbeddings.length} vectors (dims ${subEmbeddings.map((v) => v.length).join(",")}) for ${facetQueries.length} sub-queries against a ${queryEmbedding.length}-dim query \u2014 falling back to single-query ranking`
|
|
22594
|
+
);
|
|
22595
|
+
}
|
|
22596
|
+
if (subEmbeddingsUsable) {
|
|
22597
|
+
const subQueries = facetQueries.map((sq, i) => ({
|
|
22598
|
+
query: sq,
|
|
22599
|
+
embedding: subEmbeddings[i]
|
|
22600
|
+
}));
|
|
22601
|
+
const v2HeadStats = { hadResults: false };
|
|
22602
|
+
const composite = await rankComposite(query, queryEmbedding, subQueries, embeddedItems, {
|
|
22603
|
+
limit,
|
|
22604
|
+
minSimilarity,
|
|
22605
|
+
rerank: !!searchOptions?.rerank,
|
|
22606
|
+
...searchOptions?.rerankTopN !== void 0 && {
|
|
22607
|
+
rerankTopN: searchOptions.rerankTopN
|
|
22608
|
+
},
|
|
22609
|
+
...searchOptions?.ceWeight !== void 0 && { ceWeight: searchOptions.ceWeight },
|
|
22610
|
+
...searchOptions?.mmr !== void 0 && { mmr: searchOptions.mmr },
|
|
22611
|
+
...tuning,
|
|
22612
|
+
...searchOptions?.entityRanking && { entityRanking: searchOptions.entityRanking },
|
|
22613
|
+
...searchOptions?.temporalRanking && { temporalRanking: searchOptions.temporalRanking },
|
|
22614
|
+
rerankStats,
|
|
22615
|
+
v2HeadStats
|
|
22616
|
+
});
|
|
22617
|
+
return stampTimestamps({
|
|
22618
|
+
results: composite,
|
|
22619
|
+
vaultSize,
|
|
22620
|
+
reranked: rerankStats.applied,
|
|
22621
|
+
hadV2Head: v2HeadStats.hadResults
|
|
22622
|
+
});
|
|
22607
22623
|
}
|
|
22608
22624
|
}
|
|
22609
22625
|
if (useFusion && searchOptions?.rerank) {
|
|
@@ -22663,6 +22679,12 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
|
|
|
22663
22679
|
rankedOnCosine: false
|
|
22664
22680
|
};
|
|
22665
22681
|
}
|
|
22682
|
+
if (searchOptions?.decompose === "llm" && normalizeSubQueries(searchOptions.subQueries).length < 2 && !warnedProgrammaticDecomposeIgnored) {
|
|
22683
|
+
warnedProgrammaticDecomposeIgnored = true;
|
|
22684
|
+
getLogger().warn(
|
|
22685
|
+
'memoryVault: decompose:"llm" is ignored by searchVaultMemories \u2014 pass subQueries or use createMemoryVaultSearchTool / createRecallTool (719/B4)'
|
|
22686
|
+
);
|
|
22687
|
+
}
|
|
22666
22688
|
const prepared = await prepareVaultCandidates(
|
|
22667
22689
|
query,
|
|
22668
22690
|
vaultCtx,
|
|
@@ -22767,7 +22789,8 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
22767
22789
|
return "Error: A search query is required.";
|
|
22768
22790
|
}
|
|
22769
22791
|
try {
|
|
22770
|
-
const
|
|
22792
|
+
const wantsDecompose = searchOptions?.decompose === "llm" && !!searchOptions.decomposeOptions;
|
|
22793
|
+
const budget = wantsDecompose ? "high" : searchOptions?.rerank ? "mid" : "low";
|
|
22771
22794
|
const folderId = searchOptions?.folderId ?? argFolderId;
|
|
22772
22795
|
if (searchOptions?.useFusion === false) {
|
|
22773
22796
|
const { results: legacy, embeddingsUnavailable } = await searchVaultMemoriesWithSize(
|
|
@@ -22791,6 +22814,13 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
22791
22814
|
legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
|
|
22792
22815
|
);
|
|
22793
22816
|
}
|
|
22817
|
+
let subQueries;
|
|
22818
|
+
if (wantsDecompose && searchOptions?.decomposeOptions) {
|
|
22819
|
+
const decomp = await decomposeQuery(query, searchOptions.decomposeOptions);
|
|
22820
|
+
if (decomp.mode === "composite" && decomp.subQueries.length >= 2) {
|
|
22821
|
+
subQueries = decomp.subQueries;
|
|
22822
|
+
}
|
|
22823
|
+
}
|
|
22794
22824
|
const { recall: recall2 } = await Promise.resolve().then(() => (init_recall(), recall_exports));
|
|
22795
22825
|
let recallDegraded = [];
|
|
22796
22826
|
const result = await recall2(
|
|
@@ -22807,9 +22837,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
22807
22837
|
...tuningForward,
|
|
22808
22838
|
...folderId !== void 0 && { folderId },
|
|
22809
22839
|
...searchOptions?.scopes && { scopes: searchOptions.scopes },
|
|
22810
|
-
...
|
|
22811
|
-
decomposeOptions: searchOptions.decomposeOptions
|
|
22812
|
-
}
|
|
22840
|
+
...subQueries && { subQueries }
|
|
22813
22841
|
}
|
|
22814
22842
|
);
|
|
22815
22843
|
if (result.vaultSize === 0) {
|
|
@@ -22839,7 +22867,7 @@ ${formatted}`;
|
|
|
22839
22867
|
}
|
|
22840
22868
|
};
|
|
22841
22869
|
}
|
|
22842
|
-
var SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW, EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL;
|
|
22870
|
+
var warnedProgrammaticDecomposeIgnored, SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW, EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL;
|
|
22843
22871
|
var init_searchTool = __esm({
|
|
22844
22872
|
"src/lib/memoryVault/searchTool.ts"() {
|
|
22845
22873
|
"use strict";
|
|
@@ -22857,6 +22885,7 @@ var init_searchTool = __esm({
|
|
|
22857
22885
|
init_bm25();
|
|
22858
22886
|
init_decomposeQuery();
|
|
22859
22887
|
init_lruCache();
|
|
22888
|
+
warnedProgrammaticDecomposeIgnored = false;
|
|
22860
22889
|
SUPERSESSION_SIMILARITY_THRESHOLD = 0.7;
|
|
22861
22890
|
SUPERSESSION_MIN_AGE_GAP_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
22862
22891
|
SUPERSESSION_BOOST_FACTOR = 0.8;
|
|
@@ -24496,7 +24525,7 @@ __decorateClass([
|
|
|
24496
24525
|
], VaultFolder.prototype, "context", 2);
|
|
24497
24526
|
|
|
24498
24527
|
// src/lib/db/schema.ts
|
|
24499
|
-
var SDK_SCHEMA_VERSION =
|
|
24528
|
+
var SDK_SCHEMA_VERSION = 43;
|
|
24500
24529
|
var sdkSchema = (0, import_watermelondb12.appSchema)({
|
|
24501
24530
|
version: SDK_SCHEMA_VERSION,
|
|
24502
24531
|
tables: [
|
|
@@ -24544,7 +24573,16 @@ var sdkSchema = (0, import_watermelondb12.appSchema)({
|
|
|
24544
24573
|
{ name: "conversation_id", type: "string", isIndexed: true },
|
|
24545
24574
|
{ name: "title", type: "string" },
|
|
24546
24575
|
{ name: "project_id", type: "string", isOptional: true, isIndexed: true },
|
|
24547
|
-
|
|
24576
|
+
// Indexed to match every other list-sorted created_at in this schema.
|
|
24577
|
+
// Note this single-column index is NOT what makes the conversation list
|
|
24578
|
+
// reads fast on native SQLite — they all filter is_deleted as well, and
|
|
24579
|
+
// SQLite will not combine the two indexes, so the composite created by
|
|
24580
|
+
// the v42 migration is what its planner actually uses. This declaration
|
|
24581
|
+
// still earns its keep on the other two adapters: LokiJS builds its
|
|
24582
|
+
// binary indices from `isIndexed` (and ignores `sql` migration steps
|
|
24583
|
+
// outright), and Postgres gathers statistics via autovacuum, so its
|
|
24584
|
+
// planner can use a single-column index the SQLite planner skips.
|
|
24585
|
+
{ name: "created_at", type: "number", isIndexed: true },
|
|
24548
24586
|
{ name: "updated_at", type: "number" },
|
|
24549
24587
|
{ name: "is_deleted", type: "boolean", isIndexed: true },
|
|
24550
24588
|
{ name: "pinned_at", type: "number", isOptional: true }
|
|
@@ -25411,6 +25449,49 @@ var sdkMigrations = (0, import_migrations.schemaMigrations)({
|
|
|
25411
25449
|
]
|
|
25412
25450
|
})
|
|
25413
25451
|
]
|
|
25452
|
+
},
|
|
25453
|
+
// v42 -> v43: Give the conversation list reads an index they can actually
|
|
25454
|
+
// sort on. All five of them (getConversationsOp, getConversationsLazyOp,
|
|
25455
|
+
// getConversationsByProjectOp, getConversationsByProjectLazyOp and the
|
|
25456
|
+
// keyset getConversationsPageOp) emit `where is_deleted is 0 ... order by
|
|
25457
|
+
// created_at desc`, so before this they resolved is_deleted through its
|
|
25458
|
+
// index and then built a temp B-tree over every live row just to return
|
|
25459
|
+
// the newest page.
|
|
25460
|
+
//
|
|
25461
|
+
// The index is COMPOSITE, and that is the whole point — a bare index on
|
|
25462
|
+
// created_at does not fix this. SQLite will not combine two single-column
|
|
25463
|
+
// indexes here, so with `is_deleted` indexed and `created_at` indexed
|
|
25464
|
+
// separately it still picks conversations_is_deleted and still temp-sorts.
|
|
25465
|
+
// It only prefers a lone created_at index once ANALYZE has populated
|
|
25466
|
+
// sqlite_stat1, and nothing ever runs ANALYZE: not WatermelonDB, not its
|
|
25467
|
+
// native SQLite bindings, not this SDK. Every device is permanently in the
|
|
25468
|
+
// no-statistics state, so the index has to satisfy the filter and the sort
|
|
25469
|
+
// in one structure. `(is_deleted, created_at)` does: equality on the
|
|
25470
|
+
// leading column, ordered scan on the second, and the keyset boundary
|
|
25471
|
+
// becomes a range seek on the same index.
|
|
25472
|
+
//
|
|
25473
|
+
// unsafeExecuteSql, not addColumns: both columns already exist and
|
|
25474
|
+
// WatermelonDB has no add-index migration step, so raw SQL is the only way
|
|
25475
|
+
// to build one in place (same shape as the v19 -> v20 memory_vault
|
|
25476
|
+
// migration). IF NOT EXISTS keeps the step idempotent.
|
|
25477
|
+
//
|
|
25478
|
+
// Two limits worth knowing before someone re-measures this and finds it
|
|
25479
|
+
// missing. First, the LokiJS (web) adapter discards `sql` steps entirely,
|
|
25480
|
+
// so existing browser databases gain nothing — web's only lever is the
|
|
25481
|
+
// `isIndexed` flag on the column itself. Second, this index reaches
|
|
25482
|
+
// MIGRATED databases only: WatermelonDB builds a fresh database purely from
|
|
25483
|
+
// the encoded schema, and its schema format cannot express a composite
|
|
25484
|
+
// index. The one hook that could (`unsafeSql` on the table) is a function,
|
|
25485
|
+
// and the LokiJS adapter posts the schema to its worker, so attaching it
|
|
25486
|
+
// makes the whole schema fail structuredClone and takes the database down
|
|
25487
|
+
// at setup for anyone on `useWebWorker: true`. Not worth it for an index.
|
|
25488
|
+
{
|
|
25489
|
+
toVersion: 43,
|
|
25490
|
+
steps: [
|
|
25491
|
+
(0, import_migrations.unsafeExecuteSql)(
|
|
25492
|
+
"CREATE INDEX IF NOT EXISTS conversations_is_deleted_created_at ON conversations (is_deleted, created_at);"
|
|
25493
|
+
)
|
|
25494
|
+
]
|
|
25414
25495
|
}
|
|
25415
25496
|
]
|
|
25416
25497
|
});
|
|
@@ -29733,6 +29814,7 @@ function rankProfileCandidates(inputs, now = Date.now(), options = {}) {
|
|
|
29733
29814
|
init_recall();
|
|
29734
29815
|
|
|
29735
29816
|
// src/lib/memory/recallTool.ts
|
|
29817
|
+
init_decomposeQuery();
|
|
29736
29818
|
init_recall();
|
|
29737
29819
|
init_recallConstants();
|
|
29738
29820
|
var DEFAULT_LIMIT2 = 8;
|
|
@@ -29830,7 +29912,7 @@ function createRecallTool(ctx, toolOptions, callbacks) {
|
|
|
29830
29912
|
type: "function",
|
|
29831
29913
|
function: {
|
|
29832
29914
|
name: RECALL_TOOL_NAME,
|
|
29833
|
-
description:
|
|
29915
|
+
description: `Search the user's memory across stored facts/preferences and past conversation excerpts. Returns a unified ranked list \u2014 facts carry an \`id\` you can reference; conversation excerpts carry a date and role. Use this whenever the user's question may relate to anything previously discussed or saved (preferences, prior decisions, past topics). Phrase the query naturally. For multi-faceted / overview questions ("tell me about the user", "what's my tech stack"), prefer several targeted searches \u2014 one facet each (e.g. name, work, hobbies) \u2014 over a single broad query; fuse the results yourself.`,
|
|
29834
29916
|
arguments: {
|
|
29835
29917
|
type: "object",
|
|
29836
29918
|
properties: {
|
|
@@ -29885,6 +29967,13 @@ function createRecallTool(ctx, toolOptions, callbacks) {
|
|
|
29885
29967
|
let surfaced = 0;
|
|
29886
29968
|
try {
|
|
29887
29969
|
let recallDegraded = [];
|
|
29970
|
+
let subQueries;
|
|
29971
|
+
if (defaultBudget === "high" && toolOptions?.decomposeOptions) {
|
|
29972
|
+
const decomp = await decomposeQuery(query, toolOptions.decomposeOptions);
|
|
29973
|
+
if (decomp.mode === "composite" && decomp.subQueries.length >= 2) {
|
|
29974
|
+
subQueries = decomp.subQueries;
|
|
29975
|
+
}
|
|
29976
|
+
}
|
|
29888
29977
|
const recallOpts = {
|
|
29889
29978
|
onDiagnostics: (d) => {
|
|
29890
29979
|
recallDegraded = d.degraded;
|
|
@@ -29898,10 +29987,12 @@ function createRecallTool(ctx, toolOptions, callbacks) {
|
|
|
29898
29987
|
...toolOptions?.excludeConversationId && {
|
|
29899
29988
|
excludeConversationId: toolOptions.excludeConversationId
|
|
29900
29989
|
},
|
|
29901
|
-
|
|
29902
|
-
|
|
29903
|
-
|
|
29904
|
-
|
|
29990
|
+
// Do NOT forward decomposeOptions into recall() — rewrite already
|
|
29991
|
+
// ran above, and forwarding would falsely trip `decompose-moved`
|
|
29992
|
+
// on every specific-mode high-budget call. graphRefine auth can
|
|
29993
|
+
// be threaded later when the tool opts into that path.
|
|
29994
|
+
...toolOptions?.now !== void 0 && { now: toolOptions.now },
|
|
29995
|
+
...subQueries && { subQueries }
|
|
29905
29996
|
};
|
|
29906
29997
|
const result = await recall(query, ctx, recallOpts);
|
|
29907
29998
|
if (callbacks?.onChunksRetrieved) {
|
package/dist/server/index.d.mts
CHANGED
|
@@ -87,8 +87,12 @@ import { ResultCallback } from '@nozbe/watermelondb/utils/fp/Result';
|
|
|
87
87
|
* `topics_updated_at` is a SECOND timestamp because every topic writer pins
|
|
88
88
|
* `updated_at` on purpose (recall's recency multiplier) and both sync paths
|
|
89
89
|
* key on `updated_at`, so a topic-only change would neither upload nor merge
|
|
90
|
+
* - v43: Added a (is_deleted, created_at) index to conversations. Every
|
|
91
|
+
* conversation list read filters is_deleted and orders by created_at DESC,
|
|
92
|
+
* which previously meant a temp B-tree sort of the whole live set on every
|
|
93
|
+
* read. Structural only — no column added, no data rewritten
|
|
90
94
|
*/
|
|
91
|
-
declare const SDK_SCHEMA_VERSION =
|
|
95
|
+
declare const SDK_SCHEMA_VERSION = 43;
|
|
92
96
|
/**
|
|
93
97
|
* Combined WatermelonDB schema for all SDK storage modules.
|
|
94
98
|
*
|
|
@@ -175,6 +179,7 @@ declare const sdkSchema: Readonly<{
|
|
|
175
179
|
* - v39 → v40: Added `fact_type`, `archived_at`, `trust_tier` columns to memory_vault for typed memory + decay + Tier-0 security (all nullable + plaintext, NULL backfill)
|
|
176
180
|
* - v40 → v41: Added `visibility`, `twin_opt_in`, `published_at`, `geohash` columns to memory_vault for the People Nearby cross-user visibility axis (two-tier `private | public`; null/unknown grandfathered as 'private')
|
|
177
181
|
* - v41 → v42: Added `topics` + `topics_updated_at` columns to memory_vault, making a memory's topics the durable synced record and `entity`/`memory_entity` a device-local index over it (null `topics` = pre-v42, backfilled from the row's current links by the sweep)
|
|
182
|
+
* - v42 → v43: Added a composite `(is_deleted, created_at)` index to conversations so the list reads stop temp-sorting (structural only, no data rewritten)
|
|
178
183
|
*/
|
|
179
184
|
declare const sdkMigrations: Readonly<{
|
|
180
185
|
validated: true;
|
|
@@ -4945,15 +4950,26 @@ interface MemoryVaultSearchOptions {
|
|
|
4945
4950
|
/** RRF smoothing constant for lane fusion. Default 60. */
|
|
4946
4951
|
rrfK?: number;
|
|
4947
4952
|
/**
|
|
4948
|
-
*
|
|
4949
|
-
*
|
|
4950
|
-
*
|
|
4951
|
-
*
|
|
4953
|
+
* Pre-decomposed facet queries for the composite ranker (719/B4). When
|
|
4954
|
+
* ≥2 are supplied (and embeddings are available), runs {@link rankComposite}
|
|
4955
|
+
* over them — no LLM call inside the search path. Callers that want LLM
|
|
4956
|
+
* rewrite (e.g. `createRecallTool`) call `decomposeQuery` first and pass
|
|
4957
|
+
* the facets here.
|
|
4958
|
+
*/
|
|
4959
|
+
subQueries?: string[];
|
|
4960
|
+
/**
|
|
4961
|
+
* @deprecated 719/B4 — ignored by {@link searchVaultMemories} /
|
|
4962
|
+
* {@link searchVaultMemoriesWithSize}. Pass {@link MemoryVaultSearchOptions.subQueries}
|
|
4963
|
+
* (or use `createRecallTool`). The legacy {@link createMemoryVaultSearchTool}
|
|
4964
|
+
* executor still honors `decompose: "llm"` + `decomposeOptions` for eval
|
|
4965
|
+
* parity, then forwards facets into the LLM-free search path.
|
|
4952
4966
|
*/
|
|
4953
4967
|
decompose?: "off" | "llm";
|
|
4954
|
-
/**
|
|
4955
|
-
*
|
|
4956
|
-
*
|
|
4968
|
+
/**
|
|
4969
|
+
* @deprecated 719/B4 — see `decompose`. Ignored on the programmatic search
|
|
4970
|
+
* path; tool-layer rewrite still reads this from the search-tool options.
|
|
4971
|
+
* Prefer `RecallToolOptions.decomposeOptions` with `createRecallTool`.
|
|
4972
|
+
*/
|
|
4957
4973
|
decomposeOptions?: PortalLlmAuth & {
|
|
4958
4974
|
baseUrl?: string;
|
|
4959
4975
|
model?: string;
|
|
@@ -5118,9 +5134,11 @@ type MemoryKind = "fact" | "chunk";
|
|
|
5118
5134
|
* Budget controls retrieval depth/cost. Higher budgets enable more
|
|
5119
5135
|
* candidate sources and the cross-encoder reranker.
|
|
5120
5136
|
*
|
|
5121
|
-
* - `low`: cosine + BM25
|
|
5122
|
-
* - `mid`: +
|
|
5123
|
-
* - `high`: +
|
|
5137
|
+
* - `low`: cosine + BM25 + recency. No reranker. Mobile default.
|
|
5138
|
+
* - `mid`: + cross-encoder rerank.
|
|
5139
|
+
* - `high`: + multi-hop graph traversal. LLM-free — query decomposition
|
|
5140
|
+
* (when wanted) lives in the tool/agent layer ({@link createRecallTool}),
|
|
5141
|
+
* not inside `recall()` itself (719/B4).
|
|
5124
5142
|
*/
|
|
5125
5143
|
type Budget = "low" | "mid" | "high";
|
|
5126
5144
|
interface ScoreBreakdown {
|
|
@@ -5220,10 +5238,28 @@ interface RecallOptions {
|
|
|
5220
5238
|
/** Drop results below this score. Default: 0.1 for facts, 0.5 for chunks (mirrors today's defaults). */
|
|
5221
5239
|
minScore?: number;
|
|
5222
5240
|
/**
|
|
5223
|
-
*
|
|
5224
|
-
*
|
|
5225
|
-
*
|
|
5226
|
-
*
|
|
5241
|
+
* Pre-decomposed facet queries for the composite ranker. When ≥2 are
|
|
5242
|
+
* supplied, the vault lane runs `rankComposite` over them (no LLM call
|
|
5243
|
+
* inside `recall()` — 719/B4). Callers that still want LLM rewrite
|
|
5244
|
+
* (e.g. {@link createRecallTool} at `budget: 'high'`) call
|
|
5245
|
+
* `decomposeQuery` themselves and pass the result here. A single entry
|
|
5246
|
+
* (or omitting this) keeps the single-query path.
|
|
5247
|
+
*/
|
|
5248
|
+
subQueries?: string[];
|
|
5249
|
+
/**
|
|
5250
|
+
* Auth + endpoint for optional LLM helpers that reuse portal auth —
|
|
5251
|
+
* currently {@link RecallOptions.graphRefine} neighbor selection.
|
|
5252
|
+
* Query decomposition is **not** driven by this field inside `recall()`
|
|
5253
|
+
* (719/B4); {@link createRecallTool} reads the same shape from
|
|
5254
|
+
* `RecallToolOptions.decomposeOptions` for tool-layer rewrite.
|
|
5255
|
+
*
|
|
5256
|
+
* Callers that still pass `{ budget: 'high', decomposeOptions }` without
|
|
5257
|
+
* {@link RecallOptions.subQueries} keep compiling but no longer rewrite —
|
|
5258
|
+
* `recall()` emits `decompose-moved` on {@link RecallDiagnostics.degraded}
|
|
5259
|
+
* so upgrades without a changelog read still leave a telemetry breadcrumb.
|
|
5260
|
+
*
|
|
5261
|
+
* Auth is the dual pattern — one of `apiKey` / `getToken` is required;
|
|
5262
|
+
* see {@link PortalLlmAuth}.
|
|
5227
5263
|
*/
|
|
5228
5264
|
decomposeOptions?: PortalLlmAuth & {
|
|
5229
5265
|
baseUrl?: string;
|
|
@@ -5327,9 +5363,22 @@ type RecallDegradation =
|
|
|
5327
5363
|
/** Rerank was requested (budget mid/high) but the cross-encoder didn't run
|
|
5328
5364
|
* this call — unavailable (e.g. React Native) or a transient failure. */
|
|
5329
5365
|
"rerank-unavailable"
|
|
5330
|
-
/**
|
|
5331
|
-
*
|
|
5366
|
+
/**
|
|
5367
|
+
* @deprecated 719/B4 moved query decomposition out of `recall()`. Budget
|
|
5368
|
+
* `high` no longer requires `decomposeOptions` and this signal is never
|
|
5369
|
+
* emitted. Prefer `"decompose-moved"` for the upgrade breadcrumb. Kept in
|
|
5370
|
+
* the union so existing telemetry consumers stay typed.
|
|
5371
|
+
*/
|
|
5332
5372
|
| "decompose-unavailable"
|
|
5373
|
+
/**
|
|
5374
|
+
* `budget: 'high'` with `decomposeOptions` set but no usable
|
|
5375
|
+
* {@link RecallOptions.subQueries}. Pre-B4 this call shape triggered LLM
|
|
5376
|
+
* rewrite inside `recall()`; post-B4 it stays on the single-query high
|
|
5377
|
+
* path (rerank + graph) and callers must pass facets (or use
|
|
5378
|
+
* {@link createRecallTool}). Surfaced so silent quality regressions show
|
|
5379
|
+
* up in diagnostics instead of looking healthier than before.
|
|
5380
|
+
*/
|
|
5381
|
+
| "decompose-moved"
|
|
5333
5382
|
/** There was no usable cosine lane, so results were ranked on BM25 (lexical)
|
|
5334
5383
|
* alone: either the query embedding failed (or came back empty), or no
|
|
5335
5384
|
* candidate had a vector to score against it because the row (re)embed failed.
|
|
@@ -8103,9 +8152,14 @@ declare function rankProfileCandidates(inputs: readonly ProfileSalienceInput[],
|
|
|
8103
8152
|
* Unified Recall API — single retrieval surface above vault + engine.
|
|
8104
8153
|
*
|
|
8105
8154
|
* Budget maps to pipeline depth (mirrors Hindsight's tiered defaults):
|
|
8106
|
-
* - `low` → V2 cosine + BM25 + recency (no rerank
|
|
8155
|
+
* - `low` → V2 cosine + BM25 + recency (no rerank)
|
|
8107
8156
|
* - `mid` → V2 + cross-encoder rerank
|
|
8108
|
-
* - `high` → V2 + rerank +
|
|
8157
|
+
* - `high` → V2 + rerank + multi-hop graph traversal
|
|
8158
|
+
*
|
|
8159
|
+
* LLM-free by design (719/B4): query decomposition for composite asks
|
|
8160
|
+
* lives in the tool/agent layer (`createRecallTool`), which may pass
|
|
8161
|
+
* pre-built `subQueries` into this API. `recall()` itself never pays an
|
|
8162
|
+
* LLM RTT.
|
|
8109
8163
|
*
|
|
8110
8164
|
* Fact + chunk lanes are fused with RRF (k=60). The previous naive
|
|
8111
8165
|
* "sort the union by raw score" path is gone — score scales differ
|
|
@@ -8160,7 +8214,8 @@ interface RecallToolOptions {
|
|
|
8160
8214
|
folderId?: string | null;
|
|
8161
8215
|
/** Exclude one conversation from chunk results (typically the active one). */
|
|
8162
8216
|
excludeConversationId?: string;
|
|
8163
|
-
/** LLM-decompose options; only used at budget="high".
|
|
8217
|
+
/** LLM-decompose options; only used at budget="high". Runs in THIS tool
|
|
8218
|
+
* executor (719/B4) — `recall()` itself is LLM-free. Auth follows the
|
|
8164
8219
|
* dual pattern: apiKey (server/CLI) or getToken (browser identity
|
|
8165
8220
|
* tokens) — at least one required. */
|
|
8166
8221
|
decomposeOptions?: PortalLlmAuth & {
|