@anuma/sdk 6.10.0 → 6.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/expo/{chunk-4M56MKBV.mjs → chunk-732ZLOLA.mjs} +89 -32
- package/dist/expo/index.cjs +112 -38
- package/dist/expo/index.d.mts +109 -0
- package/dist/expo/index.d.ts +109 -0
- package/dist/expo/index.mjs +34 -18
- package/dist/expo/{recall-WIB7RQQZ.mjs → recall-PIATJ336.mjs} +1 -1
- package/dist/index.d.mts +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/react/{chunk-EJ65X4GI.mjs → chunk-6IBFFWCE.mjs} +89 -32
- package/dist/react/index.cjs +112 -38
- package/dist/react/index.d.mts +109 -0
- package/dist/react/index.d.ts +109 -0
- package/dist/react/index.mjs +34 -18
- package/dist/react/{recall-FWILZSFH.mjs → recall-QUWN7DJ7.mjs} +1 -1
- package/dist/server/{chunk-I56324FR.mjs → chunk-7YTEE6JT.mjs} +89 -32
- package/dist/server/index.cjs +112 -38
- package/dist/server/index.d.mts +109 -0
- package/dist/server/index.d.ts +109 -0
- package/dist/server/index.mjs +34 -18
- package/dist/server/{recall-T7CNXTQ3.mjs → recall-HOVWMT4Q.mjs} +1 -1
- package/package.json +1 -1
package/dist/expo/index.cjs
CHANGED
|
@@ -6507,9 +6507,9 @@ function recencyMultiplier(updatedAt, opts = {}) {
|
|
|
6507
6507
|
const updatedMs = updatedAt.getTime();
|
|
6508
6508
|
if (!Number.isFinite(updatedMs)) return noDate;
|
|
6509
6509
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
6510
|
-
const
|
|
6511
|
-
if (!Number.isFinite(
|
|
6512
|
-
const ageDays2 = Math.max(0, (
|
|
6510
|
+
const nowMs3 = now.getTime();
|
|
6511
|
+
if (!Number.isFinite(nowMs3)) return noDate;
|
|
6512
|
+
const ageDays2 = Math.max(0, (nowMs3 - updatedMs) / DAY_MS2);
|
|
6513
6513
|
const perYearDecay = opts.perYearDecay ?? DEFAULT_PER_YEAR_DECAY;
|
|
6514
6514
|
const floor = opts.floor ?? DEFAULT_FLOOR;
|
|
6515
6515
|
const decay = perYearDecay * (ageDays2 / 365);
|
|
@@ -6864,6 +6864,9 @@ async function decomposeQuery(query, options) {
|
|
|
6864
6864
|
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
6865
6865
|
model: options.model ?? DEFAULT_MODEL2,
|
|
6866
6866
|
systemPrompt: SYSTEM_PROMPT2,
|
|
6867
|
+
// The query itself rides the user turn below, so SYSTEM_PROMPT is the whole
|
|
6868
|
+
// fixed instruction — which is what lets the portal own it outright.
|
|
6869
|
+
taskType: "memory_decompose",
|
|
6867
6870
|
// Wrap the bare query in a task framing so the model treats it as
|
|
6868
6871
|
// input to classify, not as a question to answer conversationally.
|
|
6869
6872
|
// Bare-query inputs caused Anthropic models to respond with prose
|
|
@@ -7207,24 +7210,19 @@ function createLlmNeighborRefiner(options) {
|
|
|
7207
7210
|
async refine(query, candidates, limit) {
|
|
7208
7211
|
if (candidates.length === 0) return [];
|
|
7209
7212
|
const numbered = candidates.map((name, i) => `[${i + 1}] ${name}`).join("\n");
|
|
7210
|
-
const systemPrompt = `You help a memory-retrieval system decide which related topics to explore.
|
|
7211
|
-
|
|
7212
|
-
Given a user's question and a numbered list of candidate topics/entities linked to memories found so far, pick the ones most likely to lead to memories that help ANSWER the question. Choose at most ${limit}. Prefer topics semantically related to the question; ignore incidental ones.
|
|
7213
|
-
|
|
7214
|
-
Output strict JSON, no prose: { "expand": [<entity names to expand, verbatim from the list>] }`;
|
|
7215
7213
|
const parsed = await callPortalJsonCompletion({
|
|
7216
7214
|
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
7217
7215
|
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
7218
7216
|
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
7219
7217
|
taskType: "memory_graph",
|
|
7220
7218
|
model: options.model ?? DEFAULT_REFINER_MODEL,
|
|
7221
|
-
systemPrompt,
|
|
7219
|
+
systemPrompt: REFINER_SYSTEM_PROMPT,
|
|
7222
7220
|
userMessage: `Question: ${query}
|
|
7223
7221
|
|
|
7224
7222
|
Candidate topics:
|
|
7225
7223
|
${numbered}
|
|
7226
7224
|
|
|
7227
|
-
Which should be expanded
|
|
7225
|
+
Which should be expanded? Choose at most ${limit}.`,
|
|
7228
7226
|
tag: "memory/graph-refine",
|
|
7229
7227
|
maxAttempts: options.maxAttempts ?? DEFAULT_REFINER_ATTEMPTS,
|
|
7230
7228
|
totalTimeoutMs: options.totalTimeoutMs ?? DEFAULT_REFINER_TOTAL_TIMEOUT_MS,
|
|
@@ -7245,7 +7243,7 @@ Which should be expanded?`,
|
|
|
7245
7243
|
}
|
|
7246
7244
|
};
|
|
7247
7245
|
}
|
|
7248
|
-
var MAX_HOPS, ENTITY_FANOUT, MIN_REFINER_CANDIDATES, MAX_REFINER_CANDIDATES, NODE_BUDGET, VAULT_SIZE_HOP_CAP, DEFAULT_REFINER_MODEL, DEFAULT_REFINER_ATTEMPTS, DEFAULT_REFINER_TOTAL_TIMEOUT_MS;
|
|
7246
|
+
var MAX_HOPS, ENTITY_FANOUT, MIN_REFINER_CANDIDATES, MAX_REFINER_CANDIDATES, NODE_BUDGET, VAULT_SIZE_HOP_CAP, DEFAULT_REFINER_MODEL, DEFAULT_REFINER_ATTEMPTS, DEFAULT_REFINER_TOTAL_TIMEOUT_MS, REFINER_SYSTEM_PROMPT;
|
|
7249
7247
|
var init_graphTraversal = __esm({
|
|
7250
7248
|
"src/lib/memory/graphTraversal.ts"() {
|
|
7251
7249
|
"use strict";
|
|
@@ -7264,6 +7262,11 @@ var init_graphTraversal = __esm({
|
|
|
7264
7262
|
DEFAULT_REFINER_MODEL = "inclusionai/ling-2.6-flash";
|
|
7265
7263
|
DEFAULT_REFINER_ATTEMPTS = 1;
|
|
7266
7264
|
DEFAULT_REFINER_TOTAL_TIMEOUT_MS = 8e3;
|
|
7265
|
+
REFINER_SYSTEM_PROMPT = `You help a memory-retrieval system decide which related topics to explore.
|
|
7266
|
+
|
|
7267
|
+
Given a user's question and a numbered list of candidate topics/entities linked to memories found so far, pick the ones most likely to lead to memories that help ANSWER the question. Never return more than the maximum the user turn asks for. Prefer topics semantically related to the question; ignore incidental ones.
|
|
7268
|
+
|
|
7269
|
+
Output strict JSON, no prose: { "expand": [<entity names to expand, verbatim from the list>] }`;
|
|
7267
7270
|
}
|
|
7268
7271
|
});
|
|
7269
7272
|
|
|
@@ -7563,6 +7566,9 @@ async function recall(query, ctx, options = {}) {
|
|
|
7563
7566
|
const chunkResults = [];
|
|
7564
7567
|
let vaultSize;
|
|
7565
7568
|
let didRerank = false;
|
|
7569
|
+
let rerankMs = 0;
|
|
7570
|
+
let queryEmbedMs = 0;
|
|
7571
|
+
let vaultRowsEmbedded;
|
|
7566
7572
|
let hadV2Head = false;
|
|
7567
7573
|
let embeddingsUnavailable = false;
|
|
7568
7574
|
let chunkEmbedFailed = false;
|
|
@@ -7587,12 +7593,15 @@ async function recall(query, ctx, options = {}) {
|
|
|
7587
7593
|
...vaultSize !== void 0 && { vaultSize },
|
|
7588
7594
|
...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
|
|
7589
7595
|
...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
|
|
7596
|
+
...vaultRowsEmbedded !== void 0 && { vaultRowsEmbedded },
|
|
7590
7597
|
factCount: factResults.length,
|
|
7591
7598
|
chunkCount: chunkResults.length,
|
|
7592
7599
|
timings: {
|
|
7593
7600
|
total: nowMs() - t0,
|
|
7594
7601
|
prep: prepMs,
|
|
7595
7602
|
factLane: factLaneMs,
|
|
7603
|
+
rerank: rerankMs,
|
|
7604
|
+
queryEmbed: queryEmbedMs,
|
|
7596
7605
|
chunkLane: chunkLaneMs,
|
|
7597
7606
|
fuse: fuseMs
|
|
7598
7607
|
},
|
|
@@ -7656,6 +7665,9 @@ async function recall(query, ctx, options = {}) {
|
|
|
7656
7665
|
results,
|
|
7657
7666
|
vaultSize: size,
|
|
7658
7667
|
reranked,
|
|
7668
|
+
rerankMs: factRerankMs,
|
|
7669
|
+
queryEmbedMs: factQueryEmbedMs,
|
|
7670
|
+
rowsEmbedded: factRowsEmbedded,
|
|
7659
7671
|
hadV2Head: v2Head,
|
|
7660
7672
|
embeddingsUnavailable: factEmbeddingsUnavailable,
|
|
7661
7673
|
rankedOnCosine: factRankedOnCosine,
|
|
@@ -7714,6 +7726,9 @@ async function recall(query, ctx, options = {}) {
|
|
|
7714
7726
|
);
|
|
7715
7727
|
vaultSize = size;
|
|
7716
7728
|
didRerank = reranked;
|
|
7729
|
+
rerankMs = factRerankMs;
|
|
7730
|
+
queryEmbedMs = factQueryEmbedMs;
|
|
7731
|
+
vaultRowsEmbedded = factRowsEmbedded;
|
|
7717
7732
|
hadV2Head = v2Head;
|
|
7718
7733
|
if (factEmbeddingsUnavailable) embeddingsUnavailable = true;
|
|
7719
7734
|
factLaneRankedOnCosine = factRankedOnCosine;
|
|
@@ -8178,6 +8193,7 @@ async function rankFusedVaultMemoriesAsync(query, queryEmbedding, items, options
|
|
|
8178
8193
|
const rerankTopN = options.rerankTopN ?? 30;
|
|
8179
8194
|
const ceWeight = options.ceWeight ?? 0.1;
|
|
8180
8195
|
const headSlice = v2Ranked.slice(0, rerankTopN);
|
|
8196
|
+
const ceStart = nowMs2();
|
|
8181
8197
|
try {
|
|
8182
8198
|
const reranked = await rerankPairs(
|
|
8183
8199
|
query,
|
|
@@ -8205,6 +8221,8 @@ async function rankFusedVaultMemoriesAsync(query, queryEmbedding, items, options
|
|
|
8205
8221
|
getLogger().warn("[memory/search] cross-encoder rerank failed; using V2 ranking", err);
|
|
8206
8222
|
}
|
|
8207
8223
|
combined = v2Ranked;
|
|
8224
|
+
} finally {
|
|
8225
|
+
if (options.rerankStats) options.rerankStats.ms += nowMs2() - ceStart;
|
|
8208
8226
|
}
|
|
8209
8227
|
} else {
|
|
8210
8228
|
combined = v2Ranked;
|
|
@@ -8371,6 +8389,7 @@ async function rankComposite(originalQuery, originalQueryEmbedding, subQueries,
|
|
|
8371
8389
|
const ceWeight = options.ceWeight ?? 0.1;
|
|
8372
8390
|
const headSlice = combined.slice(0, rerankTopN);
|
|
8373
8391
|
const tailSlice = combined.slice(rerankTopN);
|
|
8392
|
+
const ceStart = nowMs2();
|
|
8374
8393
|
try {
|
|
8375
8394
|
const reranked = await rerankPairs(
|
|
8376
8395
|
originalQuery,
|
|
@@ -8398,6 +8417,8 @@ async function rankComposite(originalQuery, originalQueryEmbedding, subQueries,
|
|
|
8398
8417
|
err
|
|
8399
8418
|
);
|
|
8400
8419
|
}
|
|
8420
|
+
} finally {
|
|
8421
|
+
if (options.rerankStats) options.rerankStats.ms += nowMs2() - ceStart;
|
|
8401
8422
|
}
|
|
8402
8423
|
}
|
|
8403
8424
|
if (options?.mmr) {
|
|
@@ -8524,11 +8545,13 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
|
|
|
8524
8545
|
rowsDecrypted: 0
|
|
8525
8546
|
};
|
|
8526
8547
|
}
|
|
8548
|
+
const queryEmbedStart = nowMs2();
|
|
8527
8549
|
const queryEmbedding = await embedQueryOrDegrade(
|
|
8528
8550
|
query,
|
|
8529
8551
|
embeddingOptions,
|
|
8530
8552
|
opts.onEmbeddingDegraded
|
|
8531
8553
|
);
|
|
8554
|
+
if (opts.embedStats) opts.embedStats.queryMs += nowMs2() - queryEmbedStart;
|
|
8532
8555
|
const embeddingsDegraded = queryEmbedding.length === 0;
|
|
8533
8556
|
const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
8534
8557
|
const vectored = [];
|
|
@@ -8581,6 +8604,7 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
|
|
|
8581
8604
|
const laneRows = laneFetched.filter((m) => !isEncrypted(m.content));
|
|
8582
8605
|
if (laneRows.length > 0) {
|
|
8583
8606
|
let laneVecs;
|
|
8607
|
+
if (opts.embedStats) opts.embedStats.rowsEmbedded += laneRows.length;
|
|
8584
8608
|
try {
|
|
8585
8609
|
laneVecs = await generateEmbeddings(
|
|
8586
8610
|
laneRows.map((m) => m.content),
|
|
@@ -8659,6 +8683,10 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
|
|
|
8659
8683
|
async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
|
|
8660
8684
|
if (!query || typeof query !== "string") {
|
|
8661
8685
|
return {
|
|
8686
|
+
// Nothing was read and nothing was embedded — the short-circuit fires
|
|
8687
|
+
// before either.
|
|
8688
|
+
queryEmbedMs: 0,
|
|
8689
|
+
rowsEmbedded: 0,
|
|
8662
8690
|
memories: [],
|
|
8663
8691
|
embeddedItems: [],
|
|
8664
8692
|
queryEmbedding: [],
|
|
@@ -8691,6 +8719,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
8691
8719
|
embeddingsUnavailable = true;
|
|
8692
8720
|
embeddingFailure = true;
|
|
8693
8721
|
};
|
|
8722
|
+
const embedStats = { queryMs: 0, rowsEmbedded: 0 };
|
|
8694
8723
|
if (searchOptions?.decryptLast) {
|
|
8695
8724
|
const forceIncludeIds = [
|
|
8696
8725
|
...searchOptions.entityRanking ?? [],
|
|
@@ -8702,7 +8731,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
8702
8731
|
admitFloor: ADMIT_FLOOR,
|
|
8703
8732
|
unembeddedCap: UNEMBEDDED_CAP,
|
|
8704
8733
|
...forceIncludeIds.length > 0 && { forceIncludeIds },
|
|
8705
|
-
onEmbeddingDegraded
|
|
8734
|
+
onEmbeddingDegraded,
|
|
8735
|
+
embedStats
|
|
8706
8736
|
});
|
|
8707
8737
|
if (corpus.vaultSize === 0) {
|
|
8708
8738
|
return {
|
|
@@ -8713,7 +8743,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
8713
8743
|
embeddingsUnavailable: false,
|
|
8714
8744
|
embeddingFailure: false,
|
|
8715
8745
|
decryptLast: true,
|
|
8716
|
-
rowsDecrypted: corpus.rowsDecrypted
|
|
8746
|
+
rowsDecrypted: corpus.rowsDecrypted,
|
|
8747
|
+
queryEmbedMs: embedStats.queryMs,
|
|
8748
|
+
rowsEmbedded: embedStats.rowsEmbedded
|
|
8717
8749
|
};
|
|
8718
8750
|
}
|
|
8719
8751
|
({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
|
|
@@ -8730,7 +8762,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
8730
8762
|
decryptLast: true,
|
|
8731
8763
|
// Rows WERE decrypt-attempted even though none came back readable — that
|
|
8732
8764
|
// is the whole point of reporting attempts rather than successes.
|
|
8733
|
-
rowsDecrypted: corpus.rowsDecrypted
|
|
8765
|
+
rowsDecrypted: corpus.rowsDecrypted,
|
|
8766
|
+
queryEmbedMs: embedStats.queryMs,
|
|
8767
|
+
rowsEmbedded: embedStats.rowsEmbedded
|
|
8734
8768
|
};
|
|
8735
8769
|
}
|
|
8736
8770
|
} else {
|
|
@@ -8755,10 +8789,14 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
8755
8789
|
embeddingsUnavailable: false,
|
|
8756
8790
|
embeddingFailure: false,
|
|
8757
8791
|
decryptLast: false,
|
|
8758
|
-
rowsDecrypted: loaded.length
|
|
8792
|
+
rowsDecrypted: loaded.length,
|
|
8793
|
+
queryEmbedMs: embedStats.queryMs,
|
|
8794
|
+
rowsEmbedded: embedStats.rowsEmbedded
|
|
8759
8795
|
};
|
|
8760
8796
|
}
|
|
8797
|
+
const legacyEmbedStart = nowMs2();
|
|
8761
8798
|
queryEmbedding = await embedQueryOrDegrade(query, embeddingOptions, onEmbeddingDegraded);
|
|
8799
|
+
embedStats.queryMs += nowMs2() - legacyEmbedStart;
|
|
8762
8800
|
const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
8763
8801
|
const uncachedTexts = [];
|
|
8764
8802
|
const uncachedIndices = [];
|
|
@@ -8792,6 +8830,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
8792
8830
|
}
|
|
8793
8831
|
if (uncachedTexts.length > 0) {
|
|
8794
8832
|
let newEmbeddings;
|
|
8833
|
+
embedStats.rowsEmbedded += uncachedTexts.length;
|
|
8795
8834
|
try {
|
|
8796
8835
|
newEmbeddings = await generateEmbeddings(uncachedTexts, embeddingOptions);
|
|
8797
8836
|
} catch (err) {
|
|
@@ -8835,6 +8874,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
8835
8874
|
embeddingsUnavailable = true;
|
|
8836
8875
|
}
|
|
8837
8876
|
return {
|
|
8877
|
+
queryEmbedMs: embedStats.queryMs,
|
|
8878
|
+
rowsEmbedded: embedStats.rowsEmbedded,
|
|
8838
8879
|
memories,
|
|
8839
8880
|
embeddedItems,
|
|
8840
8881
|
queryEmbedding,
|
|
@@ -8885,11 +8926,15 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
|
|
|
8885
8926
|
results: results2,
|
|
8886
8927
|
vaultSize: out.vaultSize,
|
|
8887
8928
|
reranked: out.reranked ?? false,
|
|
8929
|
+
// Read straight off the shared stats object rather than being passed in at
|
|
8930
|
+
// each call site: every return in this function funnels through here, so a
|
|
8931
|
+
// path added later reports the CE bill without having to remember to.
|
|
8932
|
+
rerankMs: rerankStats.ms,
|
|
8888
8933
|
hadV2Head: out.hadV2Head ?? false,
|
|
8889
8934
|
embeddingsUnavailable
|
|
8890
8935
|
};
|
|
8891
8936
|
};
|
|
8892
|
-
const rerankStats = { applied: false };
|
|
8937
|
+
const rerankStats = { applied: false, ms: 0 };
|
|
8893
8938
|
const useFusion = searchOptions?.useFusion ?? true;
|
|
8894
8939
|
const tuning = {
|
|
8895
8940
|
...searchOptions?.recencyAlpha !== void 0 && { recencyAlpha: searchOptions.recencyAlpha },
|
|
@@ -9008,13 +9053,16 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
|
|
|
9008
9053
|
results: [],
|
|
9009
9054
|
vaultSize: 0,
|
|
9010
9055
|
reranked: false,
|
|
9056
|
+
rerankMs: 0,
|
|
9011
9057
|
hadV2Head: false,
|
|
9012
9058
|
embeddingsUnavailable: false,
|
|
9013
9059
|
rankedOnCosine: false,
|
|
9014
9060
|
// No storage read happened, so nothing was decrypted; report the path the
|
|
9015
9061
|
// caller asked for so this turn is still attributable.
|
|
9016
9062
|
decryptLast: !!searchOptions?.decryptLast,
|
|
9017
|
-
rowsDecrypted: 0
|
|
9063
|
+
rowsDecrypted: 0,
|
|
9064
|
+
queryEmbedMs: 0,
|
|
9065
|
+
rowsEmbedded: 0
|
|
9018
9066
|
};
|
|
9019
9067
|
}
|
|
9020
9068
|
if (searchOptions?.decompose === "llm" && normalizeSubQueries(searchOptions.subQueries).length < 2 && !warnedProgrammaticDecomposeIgnored) {
|
|
@@ -9035,11 +9083,14 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
|
|
|
9035
9083
|
results: [],
|
|
9036
9084
|
vaultSize: 0,
|
|
9037
9085
|
reranked: false,
|
|
9086
|
+
rerankMs: 0,
|
|
9038
9087
|
hadV2Head: false,
|
|
9039
9088
|
embeddingsUnavailable: prepared.embeddingsUnavailable,
|
|
9040
9089
|
rankedOnCosine: false,
|
|
9041
9090
|
decryptLast: prepared.decryptLast,
|
|
9042
|
-
rowsDecrypted: prepared.rowsDecrypted
|
|
9091
|
+
rowsDecrypted: prepared.rowsDecrypted,
|
|
9092
|
+
queryEmbedMs: prepared.queryEmbedMs,
|
|
9093
|
+
rowsEmbedded: prepared.rowsEmbedded
|
|
9043
9094
|
};
|
|
9044
9095
|
}
|
|
9045
9096
|
if (prepared.memories.length === 0) {
|
|
@@ -9047,11 +9098,14 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
|
|
|
9047
9098
|
results: [],
|
|
9048
9099
|
vaultSize: prepared.vaultSize,
|
|
9049
9100
|
reranked: false,
|
|
9101
|
+
rerankMs: 0,
|
|
9050
9102
|
hadV2Head: false,
|
|
9051
9103
|
embeddingsUnavailable: prepared.embeddingsUnavailable,
|
|
9052
9104
|
rankedOnCosine: false,
|
|
9053
9105
|
decryptLast: prepared.decryptLast,
|
|
9054
|
-
rowsDecrypted: prepared.rowsDecrypted
|
|
9106
|
+
rowsDecrypted: prepared.rowsDecrypted,
|
|
9107
|
+
queryEmbedMs: prepared.queryEmbedMs,
|
|
9108
|
+
rowsEmbedded: prepared.rowsEmbedded
|
|
9055
9109
|
};
|
|
9056
9110
|
}
|
|
9057
9111
|
const ranked = await rankPreparedVaultCandidates(
|
|
@@ -9064,7 +9118,9 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
|
|
|
9064
9118
|
...ranked,
|
|
9065
9119
|
rankedOnCosine: !ranked.embeddingsUnavailable,
|
|
9066
9120
|
decryptLast: prepared.decryptLast,
|
|
9067
|
-
rowsDecrypted: prepared.rowsDecrypted
|
|
9121
|
+
rowsDecrypted: prepared.rowsDecrypted,
|
|
9122
|
+
queryEmbedMs: prepared.queryEmbedMs,
|
|
9123
|
+
rowsEmbedded: prepared.rowsEmbedded
|
|
9068
9124
|
};
|
|
9069
9125
|
}
|
|
9070
9126
|
async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
|
|
@@ -9214,7 +9270,7 @@ ${formatted}`;
|
|
|
9214
9270
|
}
|
|
9215
9271
|
};
|
|
9216
9272
|
}
|
|
9217
|
-
var warnedProgrammaticDecomposeIgnored, SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW, EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL;
|
|
9273
|
+
var nowMs2, warnedProgrammaticDecomposeIgnored, SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW, EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL;
|
|
9218
9274
|
var init_searchTool = __esm({
|
|
9219
9275
|
"src/lib/memoryVault/searchTool.ts"() {
|
|
9220
9276
|
"use strict";
|
|
@@ -9232,6 +9288,7 @@ var init_searchTool = __esm({
|
|
|
9232
9288
|
init_bm25();
|
|
9233
9289
|
init_decomposeQuery();
|
|
9234
9290
|
init_lruCache();
|
|
9291
|
+
nowMs2 = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
9235
9292
|
warnedProgrammaticDecomposeIgnored = false;
|
|
9236
9293
|
SUPERSESSION_SIMILARITY_THRESHOLD = 0.7;
|
|
9237
9294
|
SUPERSESSION_MIN_AGE_GAP_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -17686,6 +17743,7 @@ ${TRUNCATION_NOTICE}` : formatted;
|
|
|
17686
17743
|
// src/lib/memory/reflect.ts
|
|
17687
17744
|
init_clientConfig();
|
|
17688
17745
|
init_logger();
|
|
17746
|
+
init_taskType();
|
|
17689
17747
|
init_portalLlm();
|
|
17690
17748
|
init_recall();
|
|
17691
17749
|
var DEFAULT_BASE_URL2 = BASE_URL;
|
|
@@ -17731,11 +17789,13 @@ Respond with ONLY a single JSON object conforming to this JSON Schema, with no p
|
|
|
17731
17789
|
${JSON.stringify(
|
|
17732
17790
|
options.responseSchema
|
|
17733
17791
|
)}` : basePrompt;
|
|
17734
|
-
const userMessage =
|
|
17735
|
-
|
|
17736
|
-
|
|
17737
|
-
|
|
17738
|
-
|
|
17792
|
+
const userMessage = [
|
|
17793
|
+
`Question:
|
|
17794
|
+
${trimmed}`,
|
|
17795
|
+
...options.userInstructions ? [options.userInstructions] : [],
|
|
17796
|
+
`Memories (use only these as evidence):
|
|
17797
|
+
${evidence}`
|
|
17798
|
+
].join("\n\n");
|
|
17739
17799
|
const maxTokens = options.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
17740
17800
|
const fetchImpl = options.fetchFn ?? fetch;
|
|
17741
17801
|
const log = getLogger();
|
|
@@ -17749,7 +17809,13 @@ ${evidence}`;
|
|
|
17749
17809
|
try {
|
|
17750
17810
|
response = await fetchImpl(`${baseUrl}/api/v1/chat/completions`, {
|
|
17751
17811
|
method: "POST",
|
|
17752
|
-
|
|
17812
|
+
// No task type unless the caller named one — an undeclared task adds no
|
|
17813
|
+
// header at all, which is what keeps user-facing reflect() unlabelled.
|
|
17814
|
+
headers: {
|
|
17815
|
+
...authHeaders,
|
|
17816
|
+
...taskTypeHeader(options.taskType),
|
|
17817
|
+
"Content-Type": "application/json"
|
|
17818
|
+
},
|
|
17753
17819
|
body: JSON.stringify({
|
|
17754
17820
|
model,
|
|
17755
17821
|
// Modern OpenAI field; the portal reads only `max_completion_tokens`
|
|
@@ -18201,10 +18267,15 @@ async function synthesizeFacet(facet, ctx, options, prior) {
|
|
|
18201
18267
|
limit,
|
|
18202
18268
|
types: ["fact"],
|
|
18203
18269
|
maxTokens: DEFAULT_FACET_MAX_TOKENS,
|
|
18204
|
-
// Profile-facet synthesis is a background op, so it marks its own prompt
|
|
18205
|
-
// reflect() itself must
|
|
18206
|
-
// and that traffic is chat, not an internal flow. See
|
|
18207
|
-
|
|
18270
|
+
// Profile-facet synthesis is a background op, so it marks its own prompt AND
|
|
18271
|
+
// names its own task. reflect() itself must do neither — it also serves the
|
|
18272
|
+
// user's own questions, and that traffic is chat, not an internal flow. See
|
|
18273
|
+
// ../internalFlowMarker and ReflectOptions.taskType.
|
|
18274
|
+
taskType: "memory_profile_synth",
|
|
18275
|
+
systemPrompt: withInternalFlowMarker(FACET_SYSTEM_PROMPT),
|
|
18276
|
+
// The facet's label/guidance/response-fields, on the user turn — what keeps
|
|
18277
|
+
// the system half fixed and therefore server-ownable.
|
|
18278
|
+
userInstructions: buildFacetUserInstructions(facet),
|
|
18208
18279
|
responseSchema: facetResponseSchema(facet.key),
|
|
18209
18280
|
memories
|
|
18210
18281
|
});
|
|
@@ -18262,19 +18333,22 @@ function fallbackSection(facet, prior) {
|
|
|
18262
18333
|
stale: true
|
|
18263
18334
|
};
|
|
18264
18335
|
}
|
|
18265
|
-
|
|
18266
|
-
const structuredField = FACET_STRUCTURED_RESPONSE_HINT[facet.key] ?? "";
|
|
18267
|
-
return `You are writing the "${facet.label}" section of a person's shareable profile, using their private memories (supplied as evidence) as the only source of truth.
|
|
18268
|
-
|
|
18269
|
-
Task for this section:
|
|
18270
|
-
${facet.guidance}
|
|
18336
|
+
var FACET_SYSTEM_PROMPT = `You are writing one section of a person's shareable profile, using their private memories (supplied as evidence) as the only source of truth. The user turn names the section, states the task for it, and gives the exact JSON shape to respond in.
|
|
18271
18337
|
|
|
18272
18338
|
Rules:
|
|
18273
18339
|
- Ground every claim in the supplied memories \u2014 never invent, infer beyond, or embellish what they support.
|
|
18274
18340
|
- If the memories don't cover this section, return an empty summary with hasEvidence=false. Do not pad or guess.
|
|
18275
18341
|
- Write in third person about the person, in a natural voice suitable for a public profile (no "I"/"you", no name repetition).
|
|
18276
18342
|
- Be concise and specific; no preamble, hedging, or meta-commentary.
|
|
18277
|
-
- Respond as JSON
|
|
18343
|
+
- Respond as JSON in exactly the shape the user turn states, with no extra fields.`;
|
|
18344
|
+
function buildFacetUserInstructions(facet) {
|
|
18345
|
+
const structuredField = FACET_STRUCTURED_RESPONSE_HINT[facet.key] ?? "";
|
|
18346
|
+
return `Section: "${facet.label}"
|
|
18347
|
+
|
|
18348
|
+
Task for this section:
|
|
18349
|
+
${facet.guidance}
|
|
18350
|
+
|
|
18351
|
+
Respond as JSON: { "summary": <the section text, or "">, "hasEvidence": <true|false>${structuredField} }.`;
|
|
18278
18352
|
}
|
|
18279
18353
|
function extractFacetText(structured) {
|
|
18280
18354
|
if (structured && typeof structured === "object") {
|
package/dist/expo/index.d.mts
CHANGED
|
@@ -4880,6 +4880,51 @@ interface EntityOperationsContext {
|
|
|
4880
4880
|
allowUnscopedRows?: boolean;
|
|
4881
4881
|
}
|
|
4882
4882
|
|
|
4883
|
+
/**
|
|
4884
|
+
* Class-B task types — the vocabulary of the `X-Anuma-Task-Type` header.
|
|
4885
|
+
*
|
|
4886
|
+
* A Class-B flow has ONE fixed purpose and no conversation: extract memories
|
|
4887
|
+
* from a snippet, pick a topic, consolidate duplicates, classify a query. Today
|
|
4888
|
+
* each of those builds its own system prompt on the client and sends it as a
|
|
4889
|
+
* `role:system` message, which makes the prompt a suggestion rather than a
|
|
4890
|
+
* contract — a caller can reword it into "you are a general assistant" and get
|
|
4891
|
+
* general chat at internal-endpoint prices.
|
|
4892
|
+
*
|
|
4893
|
+
* The fix is that the SERVER owns the text and the client only names the task.
|
|
4894
|
+
* This header is the name. The portal allowlists it against its own copy of this
|
|
4895
|
+
* enum (ai-portal `internal/systemprompt/tasks.go`) and DROPS anything it does
|
|
4896
|
+
* not recognise, so an unknown value degrades to "no task declared" rather than
|
|
4897
|
+
* failing the request.
|
|
4898
|
+
*
|
|
4899
|
+
* ⚠ These string values are a wire contract with ai-portal. Adding one here
|
|
4900
|
+
* before the portal knows it is harmless (it is dropped); renaming or removing
|
|
4901
|
+
* one silently stops that flow being counted. Keep them in step with
|
|
4902
|
+
* `AllTaskTypes` on the portal side, and see ai-portal
|
|
4903
|
+
* `docs/BACKEND_OWNED_TASK_PROMPTS.md` for the rollout.
|
|
4904
|
+
*
|
|
4905
|
+
* ⚠ RELEASE ORDER. This union is a PUBLIC type, so a split is breaking in both
|
|
4906
|
+
* directions and has to be sequenced:
|
|
4907
|
+
*
|
|
4908
|
+
* 1. merge + publish this package;
|
|
4909
|
+
* 2. bump `@anuma/sdk` in the consumer and switch its call sites to the new
|
|
4910
|
+
* names in the same commit.
|
|
4911
|
+
*
|
|
4912
|
+
* A consumer on the OLD version cannot compile the new names, and a consumer on
|
|
4913
|
+
* the NEW version cannot compile the retired ones (`app_inspiration` is gone
|
|
4914
|
+
* here, replaced by the three `app_inspiration_*` names). Both halves of that
|
|
4915
|
+
* are type-only — the wire itself always degrades safely, because the portal
|
|
4916
|
+
* drops any value it does not recognise. Concretely: ai-memoryless-client#5782
|
|
4917
|
+
* is blocked on this publish for exactly that reason.
|
|
4918
|
+
*
|
|
4919
|
+
* Deliberately ABSENT: agent personas, `reflect()` when it answers the user, and
|
|
4920
|
+
* the app-idea chat. Those carry an open conversation with the user, so a fixed
|
|
4921
|
+
* server-owned prompt would be wrong rather than merely premature — the same
|
|
4922
|
+
* boundary {@link INTERNAL_FLOW_MARKER} draws.
|
|
4923
|
+
*
|
|
4924
|
+
* @public
|
|
4925
|
+
*/
|
|
4926
|
+
type TaskType = "title" | "commit_message" | "memory_extract" | "memory_dedup" | "memory_decay" | "memory_injection_check" | "memory_verify_support" | "memory_autosort" | "memory_topic" | "memory_consolidate" | "memory_decompose" | "memory_profile_synth" | "memory_graph" | "folder_context" | "selection_memory" | "summarize" | "style_analysis" | "classify_search" | "app_inspiration_generate" | "app_inspiration_trends" | "app_inspiration_remix" | "spotlight_image" | "slide_image" | "slide_video" | "slide_music" | "slide_sfx" | "media_video" | "media_audio" | "media_bg_removal" | "media_image_preset" | "tool_app_builder" | "tool_document_builder" | "tool_slides" | "tool_slides_image_gen" | "connector_guidance" | "cf_task" | "xbot_intent" | "xbot_council" | "scheduled_task";
|
|
4927
|
+
|
|
4883
4928
|
/**
|
|
4884
4929
|
* Shared portal LLM call for the memory pipeline.
|
|
4885
4930
|
*
|
|
@@ -5732,6 +5777,17 @@ interface RecallDiagnostics {
|
|
|
5732
5777
|
* never the cost.
|
|
5733
5778
|
*/
|
|
5734
5779
|
vaultRowsDecrypted?: number;
|
|
5780
|
+
/**
|
|
5781
|
+
* Rows the fact lane had to re-embed through the portal because their stored
|
|
5782
|
+
* vector was unusable — stale `embedding_model`, wrong dimension, or
|
|
5783
|
+
* unparseable. Absent when the fact lane didn't run.
|
|
5784
|
+
*
|
|
5785
|
+
* Expected to be 0 on a healthy vault: rows are embedded at write time and the
|
|
5786
|
+
* re-embed writes the current model back, so a persistently non-zero value
|
|
5787
|
+
* means the writeback is not sticking and every turn is paying for it. On the
|
|
5788
|
+
* LEGACY read path this batch is uncapped, so it can be the whole vault.
|
|
5789
|
+
*/
|
|
5790
|
+
vaultRowsEmbedded?: number;
|
|
5735
5791
|
/** Facts the fact lane returned (post-dedupe, pre-fusion). */
|
|
5736
5792
|
factCount: number;
|
|
5737
5793
|
/** Chunks the chunk lane returned (post-dedupe, pre-fusion). */
|
|
@@ -5744,6 +5800,37 @@ interface RecallDiagnostics {
|
|
|
5744
5800
|
prep: number;
|
|
5745
5801
|
/** Vault fact-lane search (`searchVaultMemoriesWithSize`). */
|
|
5746
5802
|
factLane: number;
|
|
5803
|
+
/**
|
|
5804
|
+
* The cross-encoder's share of {@link factLane} — wall-clock spent inside
|
|
5805
|
+
* `rerankPairs`. Billed even when the CE threw partway through, because a
|
|
5806
|
+
* rerank that burned three seconds and then failed still cost them.
|
|
5807
|
+
*
|
|
5808
|
+
* A SUBSET of `factLane`, not a sibling: read `factLane - rerank` for
|
|
5809
|
+
* everything else the lane did (query embed, vault read, fused ranking).
|
|
5810
|
+
* 0 when the CE did not run; `reranked` is what distinguishes that from a
|
|
5811
|
+
* rerank that cost nothing.
|
|
5812
|
+
*
|
|
5813
|
+
* Exists because #845 spent three rounds arguing about which stage inside
|
|
5814
|
+
* the fact lane dominated — whole-vault read, then admission window, then
|
|
5815
|
+
* the CE — with one aggregate number for all of them. Every hypothesis was
|
|
5816
|
+
* an inference; this makes the question a query.
|
|
5817
|
+
*/
|
|
5818
|
+
rerank: number;
|
|
5819
|
+
/**
|
|
5820
|
+
* The query embed's share of {@link factLane} — one portal round trip.
|
|
5821
|
+
*
|
|
5822
|
+
* Also a SUBSET of `factLane`. Together with `rerank` this makes the lane
|
|
5823
|
+
* decomposable: `factLane - queryEmbed - rerank` is the local work (vault
|
|
5824
|
+
* read, decrypt, BM25/cosine fusion), and each of the three implies a
|
|
5825
|
+
* completely different fix.
|
|
5826
|
+
*
|
|
5827
|
+
* 0 when the lane returned before embedding, which includes every empty
|
|
5828
|
+
* vault — `prepareVaultCandidates` short-circuits first. That is why the
|
|
5829
|
+
* fast `vault_size = 0` population never established a baseline for this
|
|
5830
|
+
* cost, and why the ~850ms floor on the smallest NON-empty vaults had no
|
|
5831
|
+
* attributable owner.
|
|
5832
|
+
*/
|
|
5833
|
+
queryEmbed: number;
|
|
5747
5834
|
/** Chunk-lane search (`searchChunksOp`). */
|
|
5748
5835
|
chunkLane: number;
|
|
5749
5836
|
/** Cross-lane RRF fusion + provenance dedup after both lanes. */
|
|
@@ -8180,6 +8267,28 @@ interface ReflectOptions extends RecallOptions, PortalLlmAuth {
|
|
|
8180
8267
|
maxTokens?: number;
|
|
8181
8268
|
/** Override the grounding system prompt. */
|
|
8182
8269
|
systemPrompt?: string;
|
|
8270
|
+
/**
|
|
8271
|
+
* Extra caller instruction to carry on the USER turn, between the question and
|
|
8272
|
+
* the evidence block (see the `userMessage` assembly below). This is the slot a
|
|
8273
|
+
* background caller uses to keep its per-request data OUT of the system message
|
|
8274
|
+
* without colliding with the numbered evidence list — profile-facet synthesis
|
|
8275
|
+
* puts its section label, guidance and response-field hint here so its system
|
|
8276
|
+
* half can stay fixed and server-ownable.
|
|
8277
|
+
*/
|
|
8278
|
+
userInstructions?: string;
|
|
8279
|
+
/**
|
|
8280
|
+
* Class-B task name for the `X-Anuma-Task-Type` header, or nothing.
|
|
8281
|
+
*
|
|
8282
|
+
* Deliberately OPTIONAL and unset by default. reflect() also answers the user's
|
|
8283
|
+
* OWN question, and that traffic is chat, not an internal flow — declaring a
|
|
8284
|
+
* task type unconditionally here would put an internal-flow name on real
|
|
8285
|
+
* conversation, which is the same boundary `INTERNAL_FLOW_MARKER` draws
|
|
8286
|
+
* (reflect is deliberately unmarked; its background caller marks its own
|
|
8287
|
+
* prompt — see ../internalFlowMarker.ts). So the name is per call: only a
|
|
8288
|
+
* caller with ONE fixed purpose passes
|
|
8289
|
+
* one, and today that is profile-facet synthesis (`memory_profile_synth`).
|
|
8290
|
+
*/
|
|
8291
|
+
taskType?: TaskType;
|
|
8183
8292
|
/** Endpoint for the answer LLM. */
|
|
8184
8293
|
baseUrl?: string;
|
|
8185
8294
|
/** Override fetch (for tests). */
|