@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/react/index.cjs
CHANGED
|
@@ -6791,9 +6791,9 @@ function recencyMultiplier(updatedAt, opts = {}) {
|
|
|
6791
6791
|
const updatedMs = updatedAt.getTime();
|
|
6792
6792
|
if (!Number.isFinite(updatedMs)) return noDate;
|
|
6793
6793
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
6794
|
-
const
|
|
6795
|
-
if (!Number.isFinite(
|
|
6796
|
-
const ageDays2 = Math.max(0, (
|
|
6794
|
+
const nowMs3 = now.getTime();
|
|
6795
|
+
if (!Number.isFinite(nowMs3)) return noDate;
|
|
6796
|
+
const ageDays2 = Math.max(0, (nowMs3 - updatedMs) / DAY_MS2);
|
|
6797
6797
|
const perYearDecay = opts.perYearDecay ?? DEFAULT_PER_YEAR_DECAY;
|
|
6798
6798
|
const floor = opts.floor ?? DEFAULT_FLOOR;
|
|
6799
6799
|
const decay = perYearDecay * (ageDays2 / 365);
|
|
@@ -7148,6 +7148,9 @@ async function decomposeQuery(query, options) {
|
|
|
7148
7148
|
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
7149
7149
|
model: options.model ?? DEFAULT_MODEL2,
|
|
7150
7150
|
systemPrompt: SYSTEM_PROMPT2,
|
|
7151
|
+
// The query itself rides the user turn below, so SYSTEM_PROMPT is the whole
|
|
7152
|
+
// fixed instruction — which is what lets the portal own it outright.
|
|
7153
|
+
taskType: "memory_decompose",
|
|
7151
7154
|
// Wrap the bare query in a task framing so the model treats it as
|
|
7152
7155
|
// input to classify, not as a question to answer conversationally.
|
|
7153
7156
|
// Bare-query inputs caused Anthropic models to respond with prose
|
|
@@ -7491,24 +7494,19 @@ function createLlmNeighborRefiner(options) {
|
|
|
7491
7494
|
async refine(query, candidates, limit) {
|
|
7492
7495
|
if (candidates.length === 0) return [];
|
|
7493
7496
|
const numbered = candidates.map((name, i) => `[${i + 1}] ${name}`).join("\n");
|
|
7494
|
-
const systemPrompt = `You help a memory-retrieval system decide which related topics to explore.
|
|
7495
|
-
|
|
7496
|
-
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.
|
|
7497
|
-
|
|
7498
|
-
Output strict JSON, no prose: { "expand": [<entity names to expand, verbatim from the list>] }`;
|
|
7499
7497
|
const parsed = await callPortalJsonCompletion({
|
|
7500
7498
|
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
7501
7499
|
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
7502
7500
|
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
7503
7501
|
taskType: "memory_graph",
|
|
7504
7502
|
model: options.model ?? DEFAULT_REFINER_MODEL,
|
|
7505
|
-
systemPrompt,
|
|
7503
|
+
systemPrompt: REFINER_SYSTEM_PROMPT,
|
|
7506
7504
|
userMessage: `Question: ${query}
|
|
7507
7505
|
|
|
7508
7506
|
Candidate topics:
|
|
7509
7507
|
${numbered}
|
|
7510
7508
|
|
|
7511
|
-
Which should be expanded
|
|
7509
|
+
Which should be expanded? Choose at most ${limit}.`,
|
|
7512
7510
|
tag: "memory/graph-refine",
|
|
7513
7511
|
maxAttempts: options.maxAttempts ?? DEFAULT_REFINER_ATTEMPTS,
|
|
7514
7512
|
totalTimeoutMs: options.totalTimeoutMs ?? DEFAULT_REFINER_TOTAL_TIMEOUT_MS,
|
|
@@ -7529,7 +7527,7 @@ Which should be expanded?`,
|
|
|
7529
7527
|
}
|
|
7530
7528
|
};
|
|
7531
7529
|
}
|
|
7532
|
-
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;
|
|
7530
|
+
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;
|
|
7533
7531
|
var init_graphTraversal = __esm({
|
|
7534
7532
|
"src/lib/memory/graphTraversal.ts"() {
|
|
7535
7533
|
"use strict";
|
|
@@ -7548,6 +7546,11 @@ var init_graphTraversal = __esm({
|
|
|
7548
7546
|
DEFAULT_REFINER_MODEL = "inclusionai/ling-2.6-flash";
|
|
7549
7547
|
DEFAULT_REFINER_ATTEMPTS = 1;
|
|
7550
7548
|
DEFAULT_REFINER_TOTAL_TIMEOUT_MS = 8e3;
|
|
7549
|
+
REFINER_SYSTEM_PROMPT = `You help a memory-retrieval system decide which related topics to explore.
|
|
7550
|
+
|
|
7551
|
+
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.
|
|
7552
|
+
|
|
7553
|
+
Output strict JSON, no prose: { "expand": [<entity names to expand, verbatim from the list>] }`;
|
|
7551
7554
|
}
|
|
7552
7555
|
});
|
|
7553
7556
|
|
|
@@ -7847,6 +7850,9 @@ async function recall(query, ctx, options = {}) {
|
|
|
7847
7850
|
const chunkResults = [];
|
|
7848
7851
|
let vaultSize;
|
|
7849
7852
|
let didRerank = false;
|
|
7853
|
+
let rerankMs = 0;
|
|
7854
|
+
let queryEmbedMs = 0;
|
|
7855
|
+
let vaultRowsEmbedded;
|
|
7850
7856
|
let hadV2Head = false;
|
|
7851
7857
|
let embeddingsUnavailable = false;
|
|
7852
7858
|
let chunkEmbedFailed = false;
|
|
@@ -7871,12 +7877,15 @@ async function recall(query, ctx, options = {}) {
|
|
|
7871
7877
|
...vaultSize !== void 0 && { vaultSize },
|
|
7872
7878
|
...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
|
|
7873
7879
|
...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
|
|
7880
|
+
...vaultRowsEmbedded !== void 0 && { vaultRowsEmbedded },
|
|
7874
7881
|
factCount: factResults.length,
|
|
7875
7882
|
chunkCount: chunkResults.length,
|
|
7876
7883
|
timings: {
|
|
7877
7884
|
total: nowMs() - t0,
|
|
7878
7885
|
prep: prepMs,
|
|
7879
7886
|
factLane: factLaneMs,
|
|
7887
|
+
rerank: rerankMs,
|
|
7888
|
+
queryEmbed: queryEmbedMs,
|
|
7880
7889
|
chunkLane: chunkLaneMs,
|
|
7881
7890
|
fuse: fuseMs
|
|
7882
7891
|
},
|
|
@@ -7940,6 +7949,9 @@ async function recall(query, ctx, options = {}) {
|
|
|
7940
7949
|
results,
|
|
7941
7950
|
vaultSize: size,
|
|
7942
7951
|
reranked,
|
|
7952
|
+
rerankMs: factRerankMs,
|
|
7953
|
+
queryEmbedMs: factQueryEmbedMs,
|
|
7954
|
+
rowsEmbedded: factRowsEmbedded,
|
|
7943
7955
|
hadV2Head: v2Head,
|
|
7944
7956
|
embeddingsUnavailable: factEmbeddingsUnavailable,
|
|
7945
7957
|
rankedOnCosine: factRankedOnCosine,
|
|
@@ -7998,6 +8010,9 @@ async function recall(query, ctx, options = {}) {
|
|
|
7998
8010
|
);
|
|
7999
8011
|
vaultSize = size;
|
|
8000
8012
|
didRerank = reranked;
|
|
8013
|
+
rerankMs = factRerankMs;
|
|
8014
|
+
queryEmbedMs = factQueryEmbedMs;
|
|
8015
|
+
vaultRowsEmbedded = factRowsEmbedded;
|
|
8001
8016
|
hadV2Head = v2Head;
|
|
8002
8017
|
if (factEmbeddingsUnavailable) embeddingsUnavailable = true;
|
|
8003
8018
|
factLaneRankedOnCosine = factRankedOnCosine;
|
|
@@ -8462,6 +8477,7 @@ async function rankFusedVaultMemoriesAsync(query, queryEmbedding, items, options
|
|
|
8462
8477
|
const rerankTopN = options.rerankTopN ?? 30;
|
|
8463
8478
|
const ceWeight = options.ceWeight ?? 0.1;
|
|
8464
8479
|
const headSlice = v2Ranked.slice(0, rerankTopN);
|
|
8480
|
+
const ceStart = nowMs2();
|
|
8465
8481
|
try {
|
|
8466
8482
|
const reranked = await rerankPairs(
|
|
8467
8483
|
query,
|
|
@@ -8489,6 +8505,8 @@ async function rankFusedVaultMemoriesAsync(query, queryEmbedding, items, options
|
|
|
8489
8505
|
getLogger().warn("[memory/search] cross-encoder rerank failed; using V2 ranking", err);
|
|
8490
8506
|
}
|
|
8491
8507
|
combined = v2Ranked;
|
|
8508
|
+
} finally {
|
|
8509
|
+
if (options.rerankStats) options.rerankStats.ms += nowMs2() - ceStart;
|
|
8492
8510
|
}
|
|
8493
8511
|
} else {
|
|
8494
8512
|
combined = v2Ranked;
|
|
@@ -8655,6 +8673,7 @@ async function rankComposite(originalQuery, originalQueryEmbedding, subQueries,
|
|
|
8655
8673
|
const ceWeight = options.ceWeight ?? 0.1;
|
|
8656
8674
|
const headSlice = combined.slice(0, rerankTopN);
|
|
8657
8675
|
const tailSlice = combined.slice(rerankTopN);
|
|
8676
|
+
const ceStart = nowMs2();
|
|
8658
8677
|
try {
|
|
8659
8678
|
const reranked = await rerankPairs(
|
|
8660
8679
|
originalQuery,
|
|
@@ -8682,6 +8701,8 @@ async function rankComposite(originalQuery, originalQueryEmbedding, subQueries,
|
|
|
8682
8701
|
err
|
|
8683
8702
|
);
|
|
8684
8703
|
}
|
|
8704
|
+
} finally {
|
|
8705
|
+
if (options.rerankStats) options.rerankStats.ms += nowMs2() - ceStart;
|
|
8685
8706
|
}
|
|
8686
8707
|
}
|
|
8687
8708
|
if (options?.mmr) {
|
|
@@ -8808,11 +8829,13 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
|
|
|
8808
8829
|
rowsDecrypted: 0
|
|
8809
8830
|
};
|
|
8810
8831
|
}
|
|
8832
|
+
const queryEmbedStart = nowMs2();
|
|
8811
8833
|
const queryEmbedding = await embedQueryOrDegrade(
|
|
8812
8834
|
query,
|
|
8813
8835
|
embeddingOptions,
|
|
8814
8836
|
opts.onEmbeddingDegraded
|
|
8815
8837
|
);
|
|
8838
|
+
if (opts.embedStats) opts.embedStats.queryMs += nowMs2() - queryEmbedStart;
|
|
8816
8839
|
const embeddingsDegraded = queryEmbedding.length === 0;
|
|
8817
8840
|
const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
8818
8841
|
const vectored = [];
|
|
@@ -8865,6 +8888,7 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
|
|
|
8865
8888
|
const laneRows = laneFetched.filter((m) => !isEncrypted(m.content));
|
|
8866
8889
|
if (laneRows.length > 0) {
|
|
8867
8890
|
let laneVecs;
|
|
8891
|
+
if (opts.embedStats) opts.embedStats.rowsEmbedded += laneRows.length;
|
|
8868
8892
|
try {
|
|
8869
8893
|
laneVecs = await generateEmbeddings(
|
|
8870
8894
|
laneRows.map((m) => m.content),
|
|
@@ -8943,6 +8967,10 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
|
|
|
8943
8967
|
async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
|
|
8944
8968
|
if (!query || typeof query !== "string") {
|
|
8945
8969
|
return {
|
|
8970
|
+
// Nothing was read and nothing was embedded — the short-circuit fires
|
|
8971
|
+
// before either.
|
|
8972
|
+
queryEmbedMs: 0,
|
|
8973
|
+
rowsEmbedded: 0,
|
|
8946
8974
|
memories: [],
|
|
8947
8975
|
embeddedItems: [],
|
|
8948
8976
|
queryEmbedding: [],
|
|
@@ -8975,6 +9003,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
8975
9003
|
embeddingsUnavailable = true;
|
|
8976
9004
|
embeddingFailure = true;
|
|
8977
9005
|
};
|
|
9006
|
+
const embedStats = { queryMs: 0, rowsEmbedded: 0 };
|
|
8978
9007
|
if (searchOptions?.decryptLast) {
|
|
8979
9008
|
const forceIncludeIds = [
|
|
8980
9009
|
...searchOptions.entityRanking ?? [],
|
|
@@ -8986,7 +9015,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
8986
9015
|
admitFloor: ADMIT_FLOOR,
|
|
8987
9016
|
unembeddedCap: UNEMBEDDED_CAP,
|
|
8988
9017
|
...forceIncludeIds.length > 0 && { forceIncludeIds },
|
|
8989
|
-
onEmbeddingDegraded
|
|
9018
|
+
onEmbeddingDegraded,
|
|
9019
|
+
embedStats
|
|
8990
9020
|
});
|
|
8991
9021
|
if (corpus.vaultSize === 0) {
|
|
8992
9022
|
return {
|
|
@@ -8997,7 +9027,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
8997
9027
|
embeddingsUnavailable: false,
|
|
8998
9028
|
embeddingFailure: false,
|
|
8999
9029
|
decryptLast: true,
|
|
9000
|
-
rowsDecrypted: corpus.rowsDecrypted
|
|
9030
|
+
rowsDecrypted: corpus.rowsDecrypted,
|
|
9031
|
+
queryEmbedMs: embedStats.queryMs,
|
|
9032
|
+
rowsEmbedded: embedStats.rowsEmbedded
|
|
9001
9033
|
};
|
|
9002
9034
|
}
|
|
9003
9035
|
({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
|
|
@@ -9014,7 +9046,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
9014
9046
|
decryptLast: true,
|
|
9015
9047
|
// Rows WERE decrypt-attempted even though none came back readable — that
|
|
9016
9048
|
// is the whole point of reporting attempts rather than successes.
|
|
9017
|
-
rowsDecrypted: corpus.rowsDecrypted
|
|
9049
|
+
rowsDecrypted: corpus.rowsDecrypted,
|
|
9050
|
+
queryEmbedMs: embedStats.queryMs,
|
|
9051
|
+
rowsEmbedded: embedStats.rowsEmbedded
|
|
9018
9052
|
};
|
|
9019
9053
|
}
|
|
9020
9054
|
} else {
|
|
@@ -9039,10 +9073,14 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
9039
9073
|
embeddingsUnavailable: false,
|
|
9040
9074
|
embeddingFailure: false,
|
|
9041
9075
|
decryptLast: false,
|
|
9042
|
-
rowsDecrypted: loaded.length
|
|
9076
|
+
rowsDecrypted: loaded.length,
|
|
9077
|
+
queryEmbedMs: embedStats.queryMs,
|
|
9078
|
+
rowsEmbedded: embedStats.rowsEmbedded
|
|
9043
9079
|
};
|
|
9044
9080
|
}
|
|
9081
|
+
const legacyEmbedStart = nowMs2();
|
|
9045
9082
|
queryEmbedding = await embedQueryOrDegrade(query, embeddingOptions, onEmbeddingDegraded);
|
|
9083
|
+
embedStats.queryMs += nowMs2() - legacyEmbedStart;
|
|
9046
9084
|
const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
|
|
9047
9085
|
const uncachedTexts = [];
|
|
9048
9086
|
const uncachedIndices = [];
|
|
@@ -9076,6 +9114,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
9076
9114
|
}
|
|
9077
9115
|
if (uncachedTexts.length > 0) {
|
|
9078
9116
|
let newEmbeddings;
|
|
9117
|
+
embedStats.rowsEmbedded += uncachedTexts.length;
|
|
9079
9118
|
try {
|
|
9080
9119
|
newEmbeddings = await generateEmbeddings(uncachedTexts, embeddingOptions);
|
|
9081
9120
|
} catch (err) {
|
|
@@ -9119,6 +9158,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
|
|
|
9119
9158
|
embeddingsUnavailable = true;
|
|
9120
9159
|
}
|
|
9121
9160
|
return {
|
|
9161
|
+
queryEmbedMs: embedStats.queryMs,
|
|
9162
|
+
rowsEmbedded: embedStats.rowsEmbedded,
|
|
9122
9163
|
memories,
|
|
9123
9164
|
embeddedItems,
|
|
9124
9165
|
queryEmbedding,
|
|
@@ -9169,11 +9210,15 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
|
|
|
9169
9210
|
results: results2,
|
|
9170
9211
|
vaultSize: out.vaultSize,
|
|
9171
9212
|
reranked: out.reranked ?? false,
|
|
9213
|
+
// Read straight off the shared stats object rather than being passed in at
|
|
9214
|
+
// each call site: every return in this function funnels through here, so a
|
|
9215
|
+
// path added later reports the CE bill without having to remember to.
|
|
9216
|
+
rerankMs: rerankStats.ms,
|
|
9172
9217
|
hadV2Head: out.hadV2Head ?? false,
|
|
9173
9218
|
embeddingsUnavailable
|
|
9174
9219
|
};
|
|
9175
9220
|
};
|
|
9176
|
-
const rerankStats = { applied: false };
|
|
9221
|
+
const rerankStats = { applied: false, ms: 0 };
|
|
9177
9222
|
const useFusion = searchOptions?.useFusion ?? true;
|
|
9178
9223
|
const tuning = {
|
|
9179
9224
|
...searchOptions?.recencyAlpha !== void 0 && { recencyAlpha: searchOptions.recencyAlpha },
|
|
@@ -9292,13 +9337,16 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
|
|
|
9292
9337
|
results: [],
|
|
9293
9338
|
vaultSize: 0,
|
|
9294
9339
|
reranked: false,
|
|
9340
|
+
rerankMs: 0,
|
|
9295
9341
|
hadV2Head: false,
|
|
9296
9342
|
embeddingsUnavailable: false,
|
|
9297
9343
|
rankedOnCosine: false,
|
|
9298
9344
|
// No storage read happened, so nothing was decrypted; report the path the
|
|
9299
9345
|
// caller asked for so this turn is still attributable.
|
|
9300
9346
|
decryptLast: !!searchOptions?.decryptLast,
|
|
9301
|
-
rowsDecrypted: 0
|
|
9347
|
+
rowsDecrypted: 0,
|
|
9348
|
+
queryEmbedMs: 0,
|
|
9349
|
+
rowsEmbedded: 0
|
|
9302
9350
|
};
|
|
9303
9351
|
}
|
|
9304
9352
|
if (searchOptions?.decompose === "llm" && normalizeSubQueries(searchOptions.subQueries).length < 2 && !warnedProgrammaticDecomposeIgnored) {
|
|
@@ -9319,11 +9367,14 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
|
|
|
9319
9367
|
results: [],
|
|
9320
9368
|
vaultSize: 0,
|
|
9321
9369
|
reranked: false,
|
|
9370
|
+
rerankMs: 0,
|
|
9322
9371
|
hadV2Head: false,
|
|
9323
9372
|
embeddingsUnavailable: prepared.embeddingsUnavailable,
|
|
9324
9373
|
rankedOnCosine: false,
|
|
9325
9374
|
decryptLast: prepared.decryptLast,
|
|
9326
|
-
rowsDecrypted: prepared.rowsDecrypted
|
|
9375
|
+
rowsDecrypted: prepared.rowsDecrypted,
|
|
9376
|
+
queryEmbedMs: prepared.queryEmbedMs,
|
|
9377
|
+
rowsEmbedded: prepared.rowsEmbedded
|
|
9327
9378
|
};
|
|
9328
9379
|
}
|
|
9329
9380
|
if (prepared.memories.length === 0) {
|
|
@@ -9331,11 +9382,14 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
|
|
|
9331
9382
|
results: [],
|
|
9332
9383
|
vaultSize: prepared.vaultSize,
|
|
9333
9384
|
reranked: false,
|
|
9385
|
+
rerankMs: 0,
|
|
9334
9386
|
hadV2Head: false,
|
|
9335
9387
|
embeddingsUnavailable: prepared.embeddingsUnavailable,
|
|
9336
9388
|
rankedOnCosine: false,
|
|
9337
9389
|
decryptLast: prepared.decryptLast,
|
|
9338
|
-
rowsDecrypted: prepared.rowsDecrypted
|
|
9390
|
+
rowsDecrypted: prepared.rowsDecrypted,
|
|
9391
|
+
queryEmbedMs: prepared.queryEmbedMs,
|
|
9392
|
+
rowsEmbedded: prepared.rowsEmbedded
|
|
9339
9393
|
};
|
|
9340
9394
|
}
|
|
9341
9395
|
const ranked = await rankPreparedVaultCandidates(
|
|
@@ -9348,7 +9402,9 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
|
|
|
9348
9402
|
...ranked,
|
|
9349
9403
|
rankedOnCosine: !ranked.embeddingsUnavailable,
|
|
9350
9404
|
decryptLast: prepared.decryptLast,
|
|
9351
|
-
rowsDecrypted: prepared.rowsDecrypted
|
|
9405
|
+
rowsDecrypted: prepared.rowsDecrypted,
|
|
9406
|
+
queryEmbedMs: prepared.queryEmbedMs,
|
|
9407
|
+
rowsEmbedded: prepared.rowsEmbedded
|
|
9352
9408
|
};
|
|
9353
9409
|
}
|
|
9354
9410
|
async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
|
|
@@ -9498,7 +9554,7 @@ ${formatted}`;
|
|
|
9498
9554
|
}
|
|
9499
9555
|
};
|
|
9500
9556
|
}
|
|
9501
|
-
var warnedProgrammaticDecomposeIgnored, SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW, EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL;
|
|
9557
|
+
var nowMs2, warnedProgrammaticDecomposeIgnored, SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW, EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL;
|
|
9502
9558
|
var init_searchTool = __esm({
|
|
9503
9559
|
"src/lib/memoryVault/searchTool.ts"() {
|
|
9504
9560
|
"use strict";
|
|
@@ -9516,6 +9572,7 @@ var init_searchTool = __esm({
|
|
|
9516
9572
|
init_bm25();
|
|
9517
9573
|
init_decomposeQuery();
|
|
9518
9574
|
init_lruCache();
|
|
9575
|
+
nowMs2 = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
9519
9576
|
warnedProgrammaticDecomposeIgnored = false;
|
|
9520
9577
|
SUPERSESSION_SIMILARITY_THRESHOLD = 0.7;
|
|
9521
9578
|
SUPERSESSION_MIN_AGE_GAP_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -18984,6 +19041,7 @@ ${TRUNCATION_NOTICE}` : formatted;
|
|
|
18984
19041
|
// src/lib/memory/reflect.ts
|
|
18985
19042
|
init_clientConfig();
|
|
18986
19043
|
init_logger();
|
|
19044
|
+
init_taskType();
|
|
18987
19045
|
init_portalLlm();
|
|
18988
19046
|
init_recall();
|
|
18989
19047
|
var DEFAULT_BASE_URL2 = BASE_URL;
|
|
@@ -19029,11 +19087,13 @@ Respond with ONLY a single JSON object conforming to this JSON Schema, with no p
|
|
|
19029
19087
|
${JSON.stringify(
|
|
19030
19088
|
options.responseSchema
|
|
19031
19089
|
)}` : basePrompt;
|
|
19032
|
-
const userMessage =
|
|
19033
|
-
|
|
19034
|
-
|
|
19035
|
-
|
|
19036
|
-
|
|
19090
|
+
const userMessage = [
|
|
19091
|
+
`Question:
|
|
19092
|
+
${trimmed}`,
|
|
19093
|
+
...options.userInstructions ? [options.userInstructions] : [],
|
|
19094
|
+
`Memories (use only these as evidence):
|
|
19095
|
+
${evidence}`
|
|
19096
|
+
].join("\n\n");
|
|
19037
19097
|
const maxTokens = options.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
19038
19098
|
const fetchImpl = options.fetchFn ?? fetch;
|
|
19039
19099
|
const log = getLogger();
|
|
@@ -19047,7 +19107,13 @@ ${evidence}`;
|
|
|
19047
19107
|
try {
|
|
19048
19108
|
response = await fetchImpl(`${baseUrl}/api/v1/chat/completions`, {
|
|
19049
19109
|
method: "POST",
|
|
19050
|
-
|
|
19110
|
+
// No task type unless the caller named one — an undeclared task adds no
|
|
19111
|
+
// header at all, which is what keeps user-facing reflect() unlabelled.
|
|
19112
|
+
headers: {
|
|
19113
|
+
...authHeaders,
|
|
19114
|
+
...taskTypeHeader(options.taskType),
|
|
19115
|
+
"Content-Type": "application/json"
|
|
19116
|
+
},
|
|
19051
19117
|
body: JSON.stringify({
|
|
19052
19118
|
model,
|
|
19053
19119
|
// Modern OpenAI field; the portal reads only `max_completion_tokens`
|
|
@@ -19499,10 +19565,15 @@ async function synthesizeFacet(facet, ctx, options, prior) {
|
|
|
19499
19565
|
limit,
|
|
19500
19566
|
types: ["fact"],
|
|
19501
19567
|
maxTokens: DEFAULT_FACET_MAX_TOKENS,
|
|
19502
|
-
// Profile-facet synthesis is a background op, so it marks its own prompt
|
|
19503
|
-
// reflect() itself must
|
|
19504
|
-
// and that traffic is chat, not an internal flow. See
|
|
19505
|
-
|
|
19568
|
+
// Profile-facet synthesis is a background op, so it marks its own prompt AND
|
|
19569
|
+
// names its own task. reflect() itself must do neither — it also serves the
|
|
19570
|
+
// user's own questions, and that traffic is chat, not an internal flow. See
|
|
19571
|
+
// ../internalFlowMarker and ReflectOptions.taskType.
|
|
19572
|
+
taskType: "memory_profile_synth",
|
|
19573
|
+
systemPrompt: withInternalFlowMarker(FACET_SYSTEM_PROMPT),
|
|
19574
|
+
// The facet's label/guidance/response-fields, on the user turn — what keeps
|
|
19575
|
+
// the system half fixed and therefore server-ownable.
|
|
19576
|
+
userInstructions: buildFacetUserInstructions(facet),
|
|
19506
19577
|
responseSchema: facetResponseSchema(facet.key),
|
|
19507
19578
|
memories
|
|
19508
19579
|
});
|
|
@@ -19560,19 +19631,22 @@ function fallbackSection(facet, prior) {
|
|
|
19560
19631
|
stale: true
|
|
19561
19632
|
};
|
|
19562
19633
|
}
|
|
19563
|
-
|
|
19564
|
-
const structuredField = FACET_STRUCTURED_RESPONSE_HINT[facet.key] ?? "";
|
|
19565
|
-
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.
|
|
19566
|
-
|
|
19567
|
-
Task for this section:
|
|
19568
|
-
${facet.guidance}
|
|
19634
|
+
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.
|
|
19569
19635
|
|
|
19570
19636
|
Rules:
|
|
19571
19637
|
- Ground every claim in the supplied memories \u2014 never invent, infer beyond, or embellish what they support.
|
|
19572
19638
|
- If the memories don't cover this section, return an empty summary with hasEvidence=false. Do not pad or guess.
|
|
19573
19639
|
- Write in third person about the person, in a natural voice suitable for a public profile (no "I"/"you", no name repetition).
|
|
19574
19640
|
- Be concise and specific; no preamble, hedging, or meta-commentary.
|
|
19575
|
-
- Respond as JSON
|
|
19641
|
+
- Respond as JSON in exactly the shape the user turn states, with no extra fields.`;
|
|
19642
|
+
function buildFacetUserInstructions(facet) {
|
|
19643
|
+
const structuredField = FACET_STRUCTURED_RESPONSE_HINT[facet.key] ?? "";
|
|
19644
|
+
return `Section: "${facet.label}"
|
|
19645
|
+
|
|
19646
|
+
Task for this section:
|
|
19647
|
+
${facet.guidance}
|
|
19648
|
+
|
|
19649
|
+
Respond as JSON: { "summary": <the section text, or "">, "hasEvidence": <true|false>${structuredField} }.`;
|
|
19576
19650
|
}
|
|
19577
19651
|
function extractFacetText(structured) {
|
|
19578
19652
|
if (structured && typeof structured === "object") {
|
package/dist/react/index.d.mts
CHANGED
|
@@ -6140,6 +6140,51 @@ declare function getMemoriesByEntityNamesOp(ctx: EntityOperationsContext, entity
|
|
|
6140
6140
|
*/
|
|
6141
6141
|
declare function getEntitiesByMemoryIdsOp(ctx: EntityOperationsContext, memoryIds: readonly string[]): Promise<Map<string, Set<string>>>;
|
|
6142
6142
|
|
|
6143
|
+
/**
|
|
6144
|
+
* Class-B task types — the vocabulary of the `X-Anuma-Task-Type` header.
|
|
6145
|
+
*
|
|
6146
|
+
* A Class-B flow has ONE fixed purpose and no conversation: extract memories
|
|
6147
|
+
* from a snippet, pick a topic, consolidate duplicates, classify a query. Today
|
|
6148
|
+
* each of those builds its own system prompt on the client and sends it as a
|
|
6149
|
+
* `role:system` message, which makes the prompt a suggestion rather than a
|
|
6150
|
+
* contract — a caller can reword it into "you are a general assistant" and get
|
|
6151
|
+
* general chat at internal-endpoint prices.
|
|
6152
|
+
*
|
|
6153
|
+
* The fix is that the SERVER owns the text and the client only names the task.
|
|
6154
|
+
* This header is the name. The portal allowlists it against its own copy of this
|
|
6155
|
+
* enum (ai-portal `internal/systemprompt/tasks.go`) and DROPS anything it does
|
|
6156
|
+
* not recognise, so an unknown value degrades to "no task declared" rather than
|
|
6157
|
+
* failing the request.
|
|
6158
|
+
*
|
|
6159
|
+
* ⚠ These string values are a wire contract with ai-portal. Adding one here
|
|
6160
|
+
* before the portal knows it is harmless (it is dropped); renaming or removing
|
|
6161
|
+
* one silently stops that flow being counted. Keep them in step with
|
|
6162
|
+
* `AllTaskTypes` on the portal side, and see ai-portal
|
|
6163
|
+
* `docs/BACKEND_OWNED_TASK_PROMPTS.md` for the rollout.
|
|
6164
|
+
*
|
|
6165
|
+
* ⚠ RELEASE ORDER. This union is a PUBLIC type, so a split is breaking in both
|
|
6166
|
+
* directions and has to be sequenced:
|
|
6167
|
+
*
|
|
6168
|
+
* 1. merge + publish this package;
|
|
6169
|
+
* 2. bump `@anuma/sdk` in the consumer and switch its call sites to the new
|
|
6170
|
+
* names in the same commit.
|
|
6171
|
+
*
|
|
6172
|
+
* A consumer on the OLD version cannot compile the new names, and a consumer on
|
|
6173
|
+
* the NEW version cannot compile the retired ones (`app_inspiration` is gone
|
|
6174
|
+
* here, replaced by the three `app_inspiration_*` names). Both halves of that
|
|
6175
|
+
* are type-only — the wire itself always degrades safely, because the portal
|
|
6176
|
+
* drops any value it does not recognise. Concretely: ai-memoryless-client#5782
|
|
6177
|
+
* is blocked on this publish for exactly that reason.
|
|
6178
|
+
*
|
|
6179
|
+
* Deliberately ABSENT: agent personas, `reflect()` when it answers the user, and
|
|
6180
|
+
* the app-idea chat. Those carry an open conversation with the user, so a fixed
|
|
6181
|
+
* server-owned prompt would be wrong rather than merely premature — the same
|
|
6182
|
+
* boundary {@link INTERNAL_FLOW_MARKER} draws.
|
|
6183
|
+
*
|
|
6184
|
+
* @public
|
|
6185
|
+
*/
|
|
6186
|
+
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";
|
|
6187
|
+
|
|
6143
6188
|
/**
|
|
6144
6189
|
* Shared portal LLM call for the memory pipeline.
|
|
6145
6190
|
*
|
|
@@ -6992,6 +7037,17 @@ interface RecallDiagnostics {
|
|
|
6992
7037
|
* never the cost.
|
|
6993
7038
|
*/
|
|
6994
7039
|
vaultRowsDecrypted?: number;
|
|
7040
|
+
/**
|
|
7041
|
+
* Rows the fact lane had to re-embed through the portal because their stored
|
|
7042
|
+
* vector was unusable — stale `embedding_model`, wrong dimension, or
|
|
7043
|
+
* unparseable. Absent when the fact lane didn't run.
|
|
7044
|
+
*
|
|
7045
|
+
* Expected to be 0 on a healthy vault: rows are embedded at write time and the
|
|
7046
|
+
* re-embed writes the current model back, so a persistently non-zero value
|
|
7047
|
+
* means the writeback is not sticking and every turn is paying for it. On the
|
|
7048
|
+
* LEGACY read path this batch is uncapped, so it can be the whole vault.
|
|
7049
|
+
*/
|
|
7050
|
+
vaultRowsEmbedded?: number;
|
|
6995
7051
|
/** Facts the fact lane returned (post-dedupe, pre-fusion). */
|
|
6996
7052
|
factCount: number;
|
|
6997
7053
|
/** Chunks the chunk lane returned (post-dedupe, pre-fusion). */
|
|
@@ -7004,6 +7060,37 @@ interface RecallDiagnostics {
|
|
|
7004
7060
|
prep: number;
|
|
7005
7061
|
/** Vault fact-lane search (`searchVaultMemoriesWithSize`). */
|
|
7006
7062
|
factLane: number;
|
|
7063
|
+
/**
|
|
7064
|
+
* The cross-encoder's share of {@link factLane} — wall-clock spent inside
|
|
7065
|
+
* `rerankPairs`. Billed even when the CE threw partway through, because a
|
|
7066
|
+
* rerank that burned three seconds and then failed still cost them.
|
|
7067
|
+
*
|
|
7068
|
+
* A SUBSET of `factLane`, not a sibling: read `factLane - rerank` for
|
|
7069
|
+
* everything else the lane did (query embed, vault read, fused ranking).
|
|
7070
|
+
* 0 when the CE did not run; `reranked` is what distinguishes that from a
|
|
7071
|
+
* rerank that cost nothing.
|
|
7072
|
+
*
|
|
7073
|
+
* Exists because #845 spent three rounds arguing about which stage inside
|
|
7074
|
+
* the fact lane dominated — whole-vault read, then admission window, then
|
|
7075
|
+
* the CE — with one aggregate number for all of them. Every hypothesis was
|
|
7076
|
+
* an inference; this makes the question a query.
|
|
7077
|
+
*/
|
|
7078
|
+
rerank: number;
|
|
7079
|
+
/**
|
|
7080
|
+
* The query embed's share of {@link factLane} — one portal round trip.
|
|
7081
|
+
*
|
|
7082
|
+
* Also a SUBSET of `factLane`. Together with `rerank` this makes the lane
|
|
7083
|
+
* decomposable: `factLane - queryEmbed - rerank` is the local work (vault
|
|
7084
|
+
* read, decrypt, BM25/cosine fusion), and each of the three implies a
|
|
7085
|
+
* completely different fix.
|
|
7086
|
+
*
|
|
7087
|
+
* 0 when the lane returned before embedding, which includes every empty
|
|
7088
|
+
* vault — `prepareVaultCandidates` short-circuits first. That is why the
|
|
7089
|
+
* fast `vault_size = 0` population never established a baseline for this
|
|
7090
|
+
* cost, and why the ~850ms floor on the smallest NON-empty vaults had no
|
|
7091
|
+
* attributable owner.
|
|
7092
|
+
*/
|
|
7093
|
+
queryEmbed: number;
|
|
7007
7094
|
/** Chunk-lane search (`searchChunksOp`). */
|
|
7008
7095
|
chunkLane: number;
|
|
7009
7096
|
/** Cross-lane RRF fusion + provenance dedup after both lanes. */
|
|
@@ -9348,6 +9435,28 @@ interface ReflectOptions extends RecallOptions, PortalLlmAuth {
|
|
|
9348
9435
|
maxTokens?: number;
|
|
9349
9436
|
/** Override the grounding system prompt. */
|
|
9350
9437
|
systemPrompt?: string;
|
|
9438
|
+
/**
|
|
9439
|
+
* Extra caller instruction to carry on the USER turn, between the question and
|
|
9440
|
+
* the evidence block (see the `userMessage` assembly below). This is the slot a
|
|
9441
|
+
* background caller uses to keep its per-request data OUT of the system message
|
|
9442
|
+
* without colliding with the numbered evidence list — profile-facet synthesis
|
|
9443
|
+
* puts its section label, guidance and response-field hint here so its system
|
|
9444
|
+
* half can stay fixed and server-ownable.
|
|
9445
|
+
*/
|
|
9446
|
+
userInstructions?: string;
|
|
9447
|
+
/**
|
|
9448
|
+
* Class-B task name for the `X-Anuma-Task-Type` header, or nothing.
|
|
9449
|
+
*
|
|
9450
|
+
* Deliberately OPTIONAL and unset by default. reflect() also answers the user's
|
|
9451
|
+
* OWN question, and that traffic is chat, not an internal flow — declaring a
|
|
9452
|
+
* task type unconditionally here would put an internal-flow name on real
|
|
9453
|
+
* conversation, which is the same boundary `INTERNAL_FLOW_MARKER` draws
|
|
9454
|
+
* (reflect is deliberately unmarked; its background caller marks its own
|
|
9455
|
+
* prompt — see ../internalFlowMarker.ts). So the name is per call: only a
|
|
9456
|
+
* caller with ONE fixed purpose passes
|
|
9457
|
+
* one, and today that is profile-facet synthesis (`memory_profile_synth`).
|
|
9458
|
+
*/
|
|
9459
|
+
taskType?: TaskType;
|
|
9351
9460
|
/** Endpoint for the answer LLM. */
|
|
9352
9461
|
baseUrl?: string;
|
|
9353
9462
|
/** Override fetch (for tests). */
|