@anuma/sdk 7.0.0 → 7.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/expo/index.cjs +421 -111
- package/dist/expo/index.d.mts +25 -24
- package/dist/expo/index.d.ts +25 -24
- package/dist/expo/index.mjs +420 -111
- package/dist/index.cjs +216 -192
- package/dist/index.mjs +216 -192
- package/dist/memory/context.d.mts +8 -0
- package/dist/memory/context.d.ts +8 -0
- package/dist/react/index.cjs +442 -132
- package/dist/react/index.d.mts +30 -44
- package/dist/react/index.d.ts +30 -44
- package/dist/react/index.mjs +441 -132
- package/dist/server/index.cjs +431 -106
- package/dist/server/index.d.mts +30 -21
- package/dist/server/index.d.ts +30 -21
- package/dist/server/index.mjs +430 -106
- package/dist/telemetry/index.d.mts +6 -0
- package/dist/telemetry/index.d.ts +6 -0
- package/dist/tools/selection/index.cjs +28 -10
- package/dist/tools/selection/index.mjs +28 -10
- package/package.json +1 -1
package/dist/react/index.mjs
CHANGED
|
@@ -1813,6 +1813,35 @@ function decodeChunkVector(vector, onMalformed) {
|
|
|
1813
1813
|
}
|
|
1814
1814
|
}
|
|
1815
1815
|
|
|
1816
|
+
// src/lib/scheduling.ts
|
|
1817
|
+
function nowMs() {
|
|
1818
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
1819
|
+
}
|
|
1820
|
+
function yieldToEventLoop() {
|
|
1821
|
+
const scheduler = globalThis.scheduler;
|
|
1822
|
+
if (typeof scheduler?.yield === "function") return scheduler.yield();
|
|
1823
|
+
if (typeof MessageChannel === "function") {
|
|
1824
|
+
return new Promise((resolve) => {
|
|
1825
|
+
const channel = new MessageChannel();
|
|
1826
|
+
channel.port1.onmessage = () => {
|
|
1827
|
+
channel.port1.close();
|
|
1828
|
+
channel.port2.close();
|
|
1829
|
+
resolve();
|
|
1830
|
+
};
|
|
1831
|
+
channel.port2.postMessage(null);
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1834
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
1835
|
+
}
|
|
1836
|
+
function createTimeSliceYielder(budgetMs) {
|
|
1837
|
+
let sliceStart = nowMs();
|
|
1838
|
+
return async () => {
|
|
1839
|
+
if (nowMs() - sliceStart < budgetMs) return;
|
|
1840
|
+
await yieldToEventLoop();
|
|
1841
|
+
sliceStart = nowMs();
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1816
1845
|
// src/lib/db/encryption-utils.ts
|
|
1817
1846
|
var ENCRYPTION_PREFIX = "enc:v3:";
|
|
1818
1847
|
function isEncrypted(value) {
|
|
@@ -1821,6 +1850,11 @@ function isEncrypted(value) {
|
|
|
1821
1850
|
const payload = value.slice(prefix.length);
|
|
1822
1851
|
return payload.length >= 56 && /^[0-9a-f]+$/i.test(payload);
|
|
1823
1852
|
}
|
|
1853
|
+
function hasEncryptedToolPayload(event) {
|
|
1854
|
+
return [event.arguments, event.output].some(
|
|
1855
|
+
(value) => typeof value === "string" && isEncrypted(value)
|
|
1856
|
+
);
|
|
1857
|
+
}
|
|
1824
1858
|
function detectEncryptionVersion(value) {
|
|
1825
1859
|
if (value.startsWith("enc:v3:")) {
|
|
1826
1860
|
return { version: "v3", encryptedData: value.slice("enc:v3:".length) };
|
|
@@ -1956,6 +1990,12 @@ async function encryptMessageFields(message, address, signMessage, embeddedWalle
|
|
|
1956
1990
|
const encryptedChunks = msg.chunks ? await encryptJsonField(msg.chunks, address, signMessage, embeddedWalletSigner, true) : void 0;
|
|
1957
1991
|
const encryptedSources = msg.sources ? await encryptJsonField(msg.sources, address, signMessage, embeddedWalletSigner, true) : void 0;
|
|
1958
1992
|
const encryptedThoughtProcess = msg.thoughtProcess ? await encryptJsonField(msg.thoughtProcess, address, signMessage, embeddedWalletSigner, true) : void 0;
|
|
1993
|
+
const encryptedToolCallEvents = Array.isArray(msg.toolCallEvents) ? await encryptToolCallEvents(
|
|
1994
|
+
msg.toolCallEvents,
|
|
1995
|
+
address,
|
|
1996
|
+
signMessage,
|
|
1997
|
+
embeddedWalletSigner
|
|
1998
|
+
) : void 0;
|
|
1959
1999
|
return {
|
|
1960
2000
|
...message,
|
|
1961
2001
|
...encryptedContent !== void 0 && { content: encryptedContent },
|
|
@@ -1963,13 +2003,31 @@ async function encryptMessageFields(message, address, signMessage, embeddedWalle
|
|
|
1963
2003
|
...encryptedVector !== void 0 && { vector: encryptedVector },
|
|
1964
2004
|
...encryptedChunks !== void 0 && { chunks: encryptedChunks },
|
|
1965
2005
|
...encryptedSources !== void 0 && { sources: encryptedSources },
|
|
1966
|
-
...encryptedThoughtProcess !== void 0 && { thoughtProcess: encryptedThoughtProcess }
|
|
2006
|
+
...encryptedThoughtProcess !== void 0 && { thoughtProcess: encryptedThoughtProcess },
|
|
2007
|
+
...encryptedToolCallEvents !== void 0 && { toolCallEvents: encryptedToolCallEvents }
|
|
1967
2008
|
};
|
|
1968
2009
|
} catch (error) {
|
|
1969
2010
|
getLogger().warn("Failed to encrypt message fields:", error);
|
|
1970
2011
|
throw error;
|
|
1971
2012
|
}
|
|
1972
2013
|
}
|
|
2014
|
+
function mapToolCallPayloads(events, transform) {
|
|
2015
|
+
return Promise.all(
|
|
2016
|
+
events.map(async (event) => {
|
|
2017
|
+
if (!event || typeof event !== "object") return event;
|
|
2018
|
+
const mapped = { ...event };
|
|
2019
|
+
if (typeof event.arguments === "string") mapped.arguments = await transform(event.arguments);
|
|
2020
|
+
if (typeof event.output === "string") mapped.output = await transform(event.output);
|
|
2021
|
+
return mapped;
|
|
2022
|
+
})
|
|
2023
|
+
);
|
|
2024
|
+
}
|
|
2025
|
+
function encryptToolCallEvents(events, address, signMessage, embeddedWalletSigner) {
|
|
2026
|
+
return mapToolCallPayloads(
|
|
2027
|
+
events,
|
|
2028
|
+
(value) => encryptField(value, address, signMessage, embeddedWalletSigner, true)
|
|
2029
|
+
);
|
|
2030
|
+
}
|
|
1973
2031
|
async function decryptMaybeJsonFieldDetailed(value, address) {
|
|
1974
2032
|
if (value === void 0) return { value: void 0, status: "plaintext" };
|
|
1975
2033
|
if (value === null) return { value, status: "plaintext" };
|
|
@@ -2055,6 +2113,10 @@ async function assembleDecryptedMessage(message, address) {
|
|
|
2055
2113
|
message.thoughtProcess,
|
|
2056
2114
|
address
|
|
2057
2115
|
);
|
|
2116
|
+
const toolCallEventsResult = await decryptMaybeJsonFieldDetailed(
|
|
2117
|
+
message.toolCallEvents,
|
|
2118
|
+
address
|
|
2119
|
+
);
|
|
2058
2120
|
let decryptionStatus;
|
|
2059
2121
|
let refreshProbe;
|
|
2060
2122
|
const consider = (status, probe) => {
|
|
@@ -2073,6 +2135,14 @@ async function assembleDecryptedMessage(message, address) {
|
|
|
2073
2135
|
if (thoughtProcessResult.probe) {
|
|
2074
2136
|
consider(thoughtProcessResult.status, thoughtProcessResult.probe);
|
|
2075
2137
|
}
|
|
2138
|
+
if (toolCallEventsResult.probe) {
|
|
2139
|
+
consider(toolCallEventsResult.status, toolCallEventsResult.probe);
|
|
2140
|
+
}
|
|
2141
|
+
const toolCallEvents = Array.isArray(toolCallEventsResult.value) ? await mapToolCallPayloads(toolCallEventsResult.value, async (value) => {
|
|
2142
|
+
const detailed = await decryptFieldDetailed(value, address);
|
|
2143
|
+
consider(detailed.status, isEncrypted(value) ? value : void 0);
|
|
2144
|
+
return detailed.value;
|
|
2145
|
+
}) : void 0;
|
|
2076
2146
|
const statusForConsumer = decryptionStatus === "ok" || decryptionStatus === "plaintext" || !decryptionStatus ? void 0 : decryptionStatus;
|
|
2077
2147
|
const result = {
|
|
2078
2148
|
...message,
|
|
@@ -2081,7 +2151,8 @@ async function assembleDecryptedMessage(message, address) {
|
|
|
2081
2151
|
vector: vectorResult.value,
|
|
2082
2152
|
chunks: chunksResult.value,
|
|
2083
2153
|
sources: sourcesResult.value,
|
|
2084
|
-
thoughtProcess: thoughtProcessResult.value
|
|
2154
|
+
thoughtProcess: thoughtProcessResult.value,
|
|
2155
|
+
toolCallEvents
|
|
2085
2156
|
};
|
|
2086
2157
|
if (statusForConsumer) {
|
|
2087
2158
|
result.decryptionStatus = statusForConsumer;
|
|
@@ -2875,7 +2946,7 @@ async function updateMessageChunksOp(ctx, uniqueId, chunks3, embeddingModel) {
|
|
|
2875
2946
|
});
|
|
2876
2947
|
return messageToStored(message, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
2877
2948
|
}
|
|
2878
|
-
var
|
|
2949
|
+
var RAW_REPAIR_PAGE_SIZE = 100;
|
|
2879
2950
|
function chunksWithoutText(raw) {
|
|
2880
2951
|
if (typeof raw !== "string") return null;
|
|
2881
2952
|
let parsed;
|
|
@@ -2898,8 +2969,8 @@ function chunksWithoutText(raw) {
|
|
|
2898
2969
|
async function stripLegacyChunkTextOp(ctx) {
|
|
2899
2970
|
const candidateIds = await ctx.messagesCollection.query(Q.where("chunks", Q.like(`%${Q.sanitizeLikeString('"text":')}%`))).fetchIds();
|
|
2900
2971
|
let stripped = 0;
|
|
2901
|
-
for (let start = 0; start < candidateIds.length; start +=
|
|
2902
|
-
const pageIds = candidateIds.slice(start, start +
|
|
2972
|
+
for (let start = 0; start < candidateIds.length; start += RAW_REPAIR_PAGE_SIZE) {
|
|
2973
|
+
const pageIds = candidateIds.slice(start, start + RAW_REPAIR_PAGE_SIZE);
|
|
2903
2974
|
const rows = await ctx.messagesCollection.query(Q.where("id", Q.oneOf(pageIds))).unsafeFetchRaw();
|
|
2904
2975
|
const changedIds = rows.filter((row) => chunksWithoutText(row.chunks) !== null).map((row) => String(row.id));
|
|
2905
2976
|
if (changedIds.length === 0) continue;
|
|
@@ -2923,6 +2994,88 @@ async function stripLegacyChunkTextOp(ctx) {
|
|
|
2923
2994
|
}
|
|
2924
2995
|
return stripped;
|
|
2925
2996
|
}
|
|
2997
|
+
async function encryptedToolCallEventsColumn(raw, address, signMessage, embeddedWalletSigner) {
|
|
2998
|
+
if (typeof raw !== "string") return null;
|
|
2999
|
+
let parsed;
|
|
3000
|
+
try {
|
|
3001
|
+
parsed = JSON.parse(raw);
|
|
3002
|
+
} catch {
|
|
3003
|
+
return null;
|
|
3004
|
+
}
|
|
3005
|
+
if (!Array.isArray(parsed)) return null;
|
|
3006
|
+
const column = JSON.stringify(
|
|
3007
|
+
await encryptToolCallEvents(
|
|
3008
|
+
parsed,
|
|
3009
|
+
address,
|
|
3010
|
+
signMessage,
|
|
3011
|
+
embeddedWalletSigner
|
|
3012
|
+
)
|
|
3013
|
+
);
|
|
3014
|
+
return column === JSON.stringify(parsed) ? null : column;
|
|
3015
|
+
}
|
|
3016
|
+
async function encryptToolCallEventsOp(ctx) {
|
|
3017
|
+
const { walletAddress: address, signMessage, embeddedWalletSigner } = ctx;
|
|
3018
|
+
if (!address || !signMessage) return 0;
|
|
3019
|
+
if (!await requestEncryptionKey(address, signMessage, embeddedWalletSigner)) return 0;
|
|
3020
|
+
if (!hasEncryptionKey(address)) return 0;
|
|
3021
|
+
if (!await savedKeyOpensExistingData(ctx, address, signMessage, embeddedWalletSigner)) {
|
|
3022
|
+
return 0;
|
|
3023
|
+
}
|
|
3024
|
+
const candidateIds = await ctx.messagesCollection.query(
|
|
3025
|
+
Q.where("tool_call_events", Q.notEq(null)),
|
|
3026
|
+
Q.where("tool_call_events", Q.notIn(["", "[]"]))
|
|
3027
|
+
).fetchIds();
|
|
3028
|
+
let encrypted = 0;
|
|
3029
|
+
for (let start = 0; start < candidateIds.length; start += RAW_REPAIR_PAGE_SIZE) {
|
|
3030
|
+
const pageIds = candidateIds.slice(start, start + RAW_REPAIR_PAGE_SIZE);
|
|
3031
|
+
const rows = await ctx.messagesCollection.query(Q.where("id", Q.oneOf(pageIds))).unsafeFetchRaw();
|
|
3032
|
+
const repairs = /* @__PURE__ */ new Map();
|
|
3033
|
+
for (const row of rows) {
|
|
3034
|
+
const column = await encryptedToolCallEventsColumn(
|
|
3035
|
+
row.tool_call_events,
|
|
3036
|
+
address,
|
|
3037
|
+
signMessage,
|
|
3038
|
+
embeddedWalletSigner
|
|
3039
|
+
);
|
|
3040
|
+
if (column !== null) repairs.set(String(row.id), { raw: row.tool_call_events, column });
|
|
3041
|
+
}
|
|
3042
|
+
if (repairs.size === 0) continue;
|
|
3043
|
+
await ctx.database.write(async () => {
|
|
3044
|
+
const messages = (await ctx.messagesCollection.query(Q.where("id", Q.oneOf([...repairs.keys()]))).fetch()).filter(
|
|
3045
|
+
(message) => message._raw.tool_call_events === repairs.get(message.id)?.raw
|
|
3046
|
+
);
|
|
3047
|
+
if (messages.length === 0) return;
|
|
3048
|
+
const conversationIds = [...new Set(messages.map((message) => message.conversationId))];
|
|
3049
|
+
const conversations = await ctx.conversationsCollection.query(Q.where("conversation_id", Q.oneOf(conversationIds))).fetch();
|
|
3050
|
+
await ctx.database.batch(
|
|
3051
|
+
...messages.map(
|
|
3052
|
+
(message) => message.prepareUpdate((msg) => {
|
|
3053
|
+
msg._setRaw("tool_call_events", repairs.get(message.id).column);
|
|
3054
|
+
})
|
|
3055
|
+
),
|
|
3056
|
+
...conversations.map((conversation) => conversation.prepareUpdate(() => {
|
|
3057
|
+
}))
|
|
3058
|
+
);
|
|
3059
|
+
encrypted += messages.length;
|
|
3060
|
+
});
|
|
3061
|
+
}
|
|
3062
|
+
return encrypted;
|
|
3063
|
+
}
|
|
3064
|
+
async function savedKeyOpensExistingData(ctx, address, signMessage, embeddedWalletSigner) {
|
|
3065
|
+
const v3Probe = await findEncryptedContent(ctx, "enc:v3:%");
|
|
3066
|
+
if (v3Probe) {
|
|
3067
|
+
const { status } = await decryptFieldDetailed(v3Probe, address);
|
|
3068
|
+
if (status !== "auth_mismatch" && status !== "key_missing") return true;
|
|
3069
|
+
return refreshEncryptionKeyIfMatches(address, v3Probe, signMessage, embeddedWalletSigner);
|
|
3070
|
+
}
|
|
3071
|
+
const v2Probe = await findEncryptedContent(ctx, "enc:v2:%");
|
|
3072
|
+
if (!v2Probe) return true;
|
|
3073
|
+
return refreshEncryptionKeyIfMatches(address, v2Probe, signMessage, embeddedWalletSigner);
|
|
3074
|
+
}
|
|
3075
|
+
async function findEncryptedContent(ctx, pattern) {
|
|
3076
|
+
const [row] = await ctx.messagesCollection.query(Q.where("content", Q.like(pattern)), Q.take(1)).unsafeFetchRaw();
|
|
3077
|
+
return row ? String(row.content) : null;
|
|
3078
|
+
}
|
|
2926
3079
|
async function updateMessageErrorOp(ctx, uniqueId, error) {
|
|
2927
3080
|
let message;
|
|
2928
3081
|
try {
|
|
@@ -3069,6 +3222,95 @@ async function searchMessagesOp(ctx, queryVector, options) {
|
|
|
3069
3222
|
})
|
|
3070
3223
|
);
|
|
3071
3224
|
}
|
|
3225
|
+
var CHUNK_VECTOR_BATCH_SIZE = 50;
|
|
3226
|
+
var CHUNK_SCAN_YIELD_BUDGET_MS = 12;
|
|
3227
|
+
var hasEmbeddingSql = `(coalesce("chunks", '') != '' or coalesce("vector", '') != '')`;
|
|
3228
|
+
function toChunkCandidateKey(raw) {
|
|
3229
|
+
return {
|
|
3230
|
+
id: raw.id,
|
|
3231
|
+
conversationId: String(raw.conversation_id),
|
|
3232
|
+
version: Number(raw.updated_at) || 0,
|
|
3233
|
+
embeddingModel: raw.embedding_model ?? null
|
|
3234
|
+
};
|
|
3235
|
+
}
|
|
3236
|
+
async function fetchRowsByIds(ctx, ids) {
|
|
3237
|
+
if (ids.length === 0) return [];
|
|
3238
|
+
return await ctx.messagesCollection.query(Q.where("id", Q.oneOf(ids))).unsafeFetchRaw();
|
|
3239
|
+
}
|
|
3240
|
+
async function projectedChunkRowSource(ctx, filter) {
|
|
3241
|
+
const clauses = [
|
|
3242
|
+
`"history"."_status" is not 'deleted'`,
|
|
3243
|
+
hasEmbeddingSql,
|
|
3244
|
+
`exists (select 1 from "conversations" where "conversations"."conversation_id" = "history"."conversation_id" and "conversations"."is_deleted" = 0 and "conversations"."_status" is not 'deleted')`
|
|
3245
|
+
];
|
|
3246
|
+
const args = [];
|
|
3247
|
+
if (filter.conversationId !== void 0) {
|
|
3248
|
+
clauses.push(`"history"."conversation_id" = ?`);
|
|
3249
|
+
args.push(filter.conversationId);
|
|
3250
|
+
}
|
|
3251
|
+
if (filter.excludeConversationId !== void 0) {
|
|
3252
|
+
clauses.push(`"history"."conversation_id" != ?`);
|
|
3253
|
+
args.push(filter.excludeConversationId);
|
|
3254
|
+
}
|
|
3255
|
+
const keyRows = await ctx.messagesCollection.query(
|
|
3256
|
+
Q.unsafeSqlQuery(
|
|
3257
|
+
`select "id", "conversation_id", "updated_at", "embedding_model" from "history" where ${clauses.join(" and ")}`,
|
|
3258
|
+
args
|
|
3259
|
+
)
|
|
3260
|
+
).unsafeFetchRaw();
|
|
3261
|
+
return {
|
|
3262
|
+
keys: keyRows.map(toChunkCandidateKey),
|
|
3263
|
+
loadVectorRows: async (ids) => {
|
|
3264
|
+
if (ids.length === 0) return [];
|
|
3265
|
+
return await ctx.messagesCollection.query(
|
|
3266
|
+
Q.unsafeSqlQuery(
|
|
3267
|
+
`select "id", "updated_at", "chunks", "vector" from "history" where "_status" is not 'deleted' and "id" in (${ids.map(() => "?").join(",")})`,
|
|
3268
|
+
ids
|
|
3269
|
+
)
|
|
3270
|
+
).unsafeFetchRaw();
|
|
3271
|
+
},
|
|
3272
|
+
loadFullRows: (ids) => fetchRowsByIds(ctx, ids)
|
|
3273
|
+
};
|
|
3274
|
+
}
|
|
3275
|
+
async function fullScanChunkRowSource(ctx, filter) {
|
|
3276
|
+
const activeConversations = await ctx.conversationsCollection.query(Q.where("is_deleted", false)).fetch();
|
|
3277
|
+
const activeConversationIds = new Set(
|
|
3278
|
+
activeConversations.map((c) => String(c._getRaw("conversation_id")))
|
|
3279
|
+
);
|
|
3280
|
+
const queryConditions = filter.conversationId !== void 0 ? [Q.where("conversation_id", filter.conversationId)] : [];
|
|
3281
|
+
const rows = await ctx.messagesCollection.query(...queryConditions).unsafeFetchRaw();
|
|
3282
|
+
const rowsById = /* @__PURE__ */ new Map();
|
|
3283
|
+
for (const row of rows) {
|
|
3284
|
+
const conversationId = String(row.conversation_id);
|
|
3285
|
+
if (!activeConversationIds.has(conversationId)) continue;
|
|
3286
|
+
if (filter.excludeConversationId !== void 0 && conversationId === filter.excludeConversationId) {
|
|
3287
|
+
continue;
|
|
3288
|
+
}
|
|
3289
|
+
if (!row.chunks && !row.vector) continue;
|
|
3290
|
+
rowsById.set(row.id, row);
|
|
3291
|
+
}
|
|
3292
|
+
const pick = (ids) => Promise.resolve(
|
|
3293
|
+
ids.flatMap((id) => {
|
|
3294
|
+
const row = rowsById.get(id);
|
|
3295
|
+
return row ? [row] : [];
|
|
3296
|
+
})
|
|
3297
|
+
);
|
|
3298
|
+
return {
|
|
3299
|
+
keys: Array.from(rowsById.values(), toChunkCandidateKey),
|
|
3300
|
+
loadVectorRows: pick,
|
|
3301
|
+
loadFullRows: pick
|
|
3302
|
+
};
|
|
3303
|
+
}
|
|
3304
|
+
async function chunkRowSource(ctx, filter) {
|
|
3305
|
+
try {
|
|
3306
|
+
return await projectedChunkRowSource(ctx, filter);
|
|
3307
|
+
} catch (err) {
|
|
3308
|
+
getLogger().debug(
|
|
3309
|
+
"searchChunksOp: projected SQL unavailable, using full-load fallback: " + (err instanceof Error ? err.message : String(err))
|
|
3310
|
+
);
|
|
3311
|
+
return fullScanChunkRowSource(ctx, filter);
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3072
3314
|
async function searchChunksOp(ctx, queryVector, options) {
|
|
3073
3315
|
const {
|
|
3074
3316
|
limit = 10,
|
|
@@ -3076,83 +3318,111 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
3076
3318
|
conversationId,
|
|
3077
3319
|
excludeConversationId,
|
|
3078
3320
|
embeddingModel,
|
|
3079
|
-
chunkCache
|
|
3321
|
+
chunkCache,
|
|
3322
|
+
onStats
|
|
3080
3323
|
} = options || {};
|
|
3081
|
-
const
|
|
3082
|
-
const
|
|
3083
|
-
activeConversations.map((c) => String(c._getRaw("conversation_id")))
|
|
3084
|
-
);
|
|
3085
|
-
const queryConditions = conversationId ? [Q.where("conversation_id", conversationId)] : [];
|
|
3086
|
-
const messages = await ctx.messagesCollection.query(...queryConditions).unsafeFetchRaw();
|
|
3324
|
+
const source = await chunkRowSource(ctx, { conversationId, excludeConversationId });
|
|
3325
|
+
const yieldIfDue = createTimeSliceYielder(CHUNK_SCAN_YIELD_BUDGET_MS);
|
|
3087
3326
|
const candidates = [];
|
|
3088
3327
|
let staleSkipped = 0;
|
|
3089
3328
|
let unreadableVectors = 0;
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
}
|
|
3329
|
+
let cacheHits = 0;
|
|
3330
|
+
const missIds = [];
|
|
3331
|
+
const orderById = /* @__PURE__ */ new Map();
|
|
3332
|
+
for (const [order, key] of source.keys.entries()) {
|
|
3333
|
+
await yieldIfDue();
|
|
3334
|
+
orderById.set(key.id, order);
|
|
3335
|
+
if (embeddingModel && key.embeddingModel !== null && key.embeddingModel !== embeddingModel) {
|
|
3336
|
+
staleSkipped++;
|
|
3337
|
+
continue;
|
|
3100
3338
|
}
|
|
3101
|
-
const
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
if (cached.chunks.length > 0) {
|
|
3105
|
-
for (let ci = 0; ci < cached.chunks.length; ci++) {
|
|
3106
|
-
const vec = cached.chunks[ci];
|
|
3107
|
-
if (vec.length === 0) continue;
|
|
3108
|
-
const similarity = cosineSimilarity(queryVector, vec);
|
|
3109
|
-
if (similarity >= minSimilarity) {
|
|
3110
|
-
candidates.push({
|
|
3111
|
-
message,
|
|
3112
|
-
similarity,
|
|
3113
|
-
chunkTextSource: { kind: "chunk-cached", chunkIndex: ci, version }
|
|
3114
|
-
});
|
|
3115
|
-
}
|
|
3116
|
-
}
|
|
3117
|
-
} else if (cached.fallback) {
|
|
3118
|
-
const similarity = cosineSimilarity(queryVector, cached.fallback);
|
|
3119
|
-
if (similarity >= minSimilarity) {
|
|
3120
|
-
candidates.push({ message, similarity, chunkTextSource: { kind: "message" } });
|
|
3121
|
-
}
|
|
3122
|
-
}
|
|
3339
|
+
const cached = chunkCache?.get(key.id);
|
|
3340
|
+
if (!cached || cached.version !== key.version) {
|
|
3341
|
+
missIds.push(key.id);
|
|
3123
3342
|
continue;
|
|
3124
3343
|
}
|
|
3125
|
-
|
|
3126
|
-
if (
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
unreadableVectors++;
|
|
3130
|
-
})
|
|
3131
|
-
);
|
|
3132
|
-
chunkCache?.set(message.id, { version, chunks: vectors });
|
|
3133
|
-
for (let ci = 0; ci < chunks3.length; ci++) {
|
|
3134
|
-
const vec = vectors[ci];
|
|
3344
|
+
cacheHits++;
|
|
3345
|
+
if (cached.chunks.length > 0) {
|
|
3346
|
+
for (let ci = 0; ci < cached.chunks.length; ci++) {
|
|
3347
|
+
const vec = cached.chunks[ci];
|
|
3135
3348
|
if (vec.length === 0) continue;
|
|
3136
3349
|
const similarity = cosineSimilarity(queryVector, vec);
|
|
3137
3350
|
if (similarity >= minSimilarity) {
|
|
3138
3351
|
candidates.push({
|
|
3139
|
-
|
|
3352
|
+
id: key.id,
|
|
3353
|
+
version: key.version,
|
|
3354
|
+
order,
|
|
3140
3355
|
similarity,
|
|
3141
|
-
chunkTextSource: { kind: "chunk",
|
|
3356
|
+
chunkTextSource: { kind: "chunk-cached", chunkIndex: ci, version: key.version }
|
|
3142
3357
|
});
|
|
3143
3358
|
}
|
|
3144
3359
|
}
|
|
3145
|
-
} else {
|
|
3146
|
-
const
|
|
3147
|
-
if (!messageVector || messageVector.length === 0) continue;
|
|
3148
|
-
const fallback = Float32Array.from(messageVector);
|
|
3149
|
-
chunkCache?.set(message.id, { version, chunks: [], fallback });
|
|
3150
|
-
const similarity = cosineSimilarity(queryVector, fallback);
|
|
3360
|
+
} else if (cached.fallback) {
|
|
3361
|
+
const similarity = cosineSimilarity(queryVector, cached.fallback);
|
|
3151
3362
|
if (similarity >= minSimilarity) {
|
|
3152
|
-
candidates.push({
|
|
3363
|
+
candidates.push({
|
|
3364
|
+
id: key.id,
|
|
3365
|
+
version: key.version,
|
|
3366
|
+
order,
|
|
3367
|
+
similarity,
|
|
3368
|
+
chunkTextSource: { kind: "message" }
|
|
3369
|
+
});
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
let rowsFetched = 0;
|
|
3374
|
+
for (let offset = 0; offset < missIds.length; offset += CHUNK_VECTOR_BATCH_SIZE) {
|
|
3375
|
+
const rows = await source.loadVectorRows(
|
|
3376
|
+
missIds.slice(offset, offset + CHUNK_VECTOR_BATCH_SIZE)
|
|
3377
|
+
);
|
|
3378
|
+
rowsFetched += rows.length;
|
|
3379
|
+
for (const row of rows) {
|
|
3380
|
+
await yieldIfDue();
|
|
3381
|
+
const id = row.id;
|
|
3382
|
+
const version = Number(row.updated_at) || 0;
|
|
3383
|
+
const order = orderById.get(id) ?? Number.MAX_SAFE_INTEGER;
|
|
3384
|
+
const chunks3 = await readRawJsonField(row, "chunks", ctx.walletAddress);
|
|
3385
|
+
if (chunks3 && chunks3.length > 0) {
|
|
3386
|
+
const vectors = chunks3.map(
|
|
3387
|
+
(chunk) => decodeChunkVector(chunk.vector, () => {
|
|
3388
|
+
unreadableVectors++;
|
|
3389
|
+
})
|
|
3390
|
+
);
|
|
3391
|
+
chunkCache?.set(id, { version, chunks: vectors });
|
|
3392
|
+
for (let ci = 0; ci < chunks3.length; ci++) {
|
|
3393
|
+
const vec = vectors[ci];
|
|
3394
|
+
if (vec.length === 0) continue;
|
|
3395
|
+
const similarity = cosineSimilarity(queryVector, vec);
|
|
3396
|
+
if (similarity >= minSimilarity) {
|
|
3397
|
+
candidates.push({
|
|
3398
|
+
id,
|
|
3399
|
+
version,
|
|
3400
|
+
order,
|
|
3401
|
+
similarity,
|
|
3402
|
+
chunkTextSource: { kind: "chunk", chunk: chunks3[ci], siblings: chunks3 }
|
|
3403
|
+
});
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
} else {
|
|
3407
|
+
const messageVector = await readRawJsonField(row, "vector", ctx.walletAddress);
|
|
3408
|
+
if (messageVector && messageVector.length > 0) {
|
|
3409
|
+
const fallback = Float32Array.from(messageVector);
|
|
3410
|
+
chunkCache?.set(id, { version, chunks: [], fallback });
|
|
3411
|
+
const similarity = cosineSimilarity(queryVector, fallback);
|
|
3412
|
+
if (similarity >= minSimilarity) {
|
|
3413
|
+
candidates.push({
|
|
3414
|
+
id,
|
|
3415
|
+
version,
|
|
3416
|
+
order,
|
|
3417
|
+
similarity,
|
|
3418
|
+
chunkTextSource: { kind: "message" }
|
|
3419
|
+
});
|
|
3420
|
+
}
|
|
3421
|
+
}
|
|
3153
3422
|
}
|
|
3154
3423
|
}
|
|
3155
3424
|
}
|
|
3425
|
+
onStats?.({ rowsScanned: source.keys.length, rowsFetched, cacheHits });
|
|
3156
3426
|
if (staleSkipped > 0) {
|
|
3157
3427
|
getLogger().warn(
|
|
3158
3428
|
`searchChunksOp: skipped ${staleSkipped} messages whose embedding model differs from the current model (${embeddingModel}) \u2014 re-embed via chunkAndEmbedAllMessages`
|
|
@@ -3163,12 +3433,17 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
3163
3433
|
`searchChunksOp: could not read ${unreadableVectors} chunk vectors and left them out of ranking \u2014 the stored value is corrupt, so those chunks stay unsearchable until the message is re-embedded via chunkAndEmbedAllMessages`
|
|
3164
3434
|
);
|
|
3165
3435
|
}
|
|
3166
|
-
const topK = candidates.sort((a, b) => b.similarity - a.similarity).slice(0, limit);
|
|
3167
|
-
const
|
|
3168
|
-
|
|
3436
|
+
const topK = candidates.sort((a, b) => b.similarity - a.similarity || a.order - b.order).slice(0, limit);
|
|
3437
|
+
const topIds = Array.from(new Set(topK.map((c) => c.id)));
|
|
3438
|
+
const fullRows = await source.loadFullRows(topIds);
|
|
3439
|
+
const rowById = new Map(fullRows.map((row) => [row.id, row]));
|
|
3440
|
+
const liveTopK = topK.filter((c) => {
|
|
3441
|
+
const row = rowById.get(c.id);
|
|
3442
|
+
return row !== void 0 && (Number(row.updated_at) || 0) === c.version;
|
|
3443
|
+
});
|
|
3169
3444
|
const storedById = new Map(
|
|
3170
3445
|
await Promise.all(
|
|
3171
|
-
Array.from(
|
|
3446
|
+
Array.from(rowById, async ([id, m]) => {
|
|
3172
3447
|
const stored2 = await messageRawToStored(
|
|
3173
3448
|
m,
|
|
3174
3449
|
ctx.walletAddress,
|
|
@@ -3181,24 +3456,24 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
3181
3456
|
);
|
|
3182
3457
|
const chunkStateByMsgId = /* @__PURE__ */ new Map();
|
|
3183
3458
|
const needsChunkText = /* @__PURE__ */ new Set();
|
|
3184
|
-
for (const c of
|
|
3185
|
-
if (c.chunkTextSource.kind === "chunk-cached") needsChunkText.add(c.
|
|
3459
|
+
for (const c of liveTopK) {
|
|
3460
|
+
if (c.chunkTextSource.kind === "chunk-cached") needsChunkText.add(c.id);
|
|
3186
3461
|
}
|
|
3187
3462
|
await Promise.all(
|
|
3188
3463
|
Array.from(needsChunkText, async (id) => {
|
|
3189
|
-
const m =
|
|
3464
|
+
const m = rowById.get(id);
|
|
3190
3465
|
const parsed = await readRawJsonField(m, "chunks", ctx.walletAddress);
|
|
3191
3466
|
const version = Number(m.updated_at) || 0;
|
|
3192
3467
|
if (parsed) chunkStateByMsgId.set(id, { version, chunks: parsed });
|
|
3193
3468
|
})
|
|
3194
3469
|
);
|
|
3195
|
-
return
|
|
3196
|
-
const stored2 = { ...storedById.get(
|
|
3470
|
+
return liveTopK.map(({ id, similarity, chunkTextSource }) => {
|
|
3471
|
+
const stored2 = { ...storedById.get(id) };
|
|
3197
3472
|
let chunkText2;
|
|
3198
3473
|
if (chunkTextSource.kind === "chunk") {
|
|
3199
3474
|
chunkText2 = resolveChunkText(stored2.content, chunkTextSource.chunk, chunkTextSource.siblings);
|
|
3200
3475
|
} else if (chunkTextSource.kind === "chunk-cached") {
|
|
3201
|
-
const state = chunkStateByMsgId.get(
|
|
3476
|
+
const state = chunkStateByMsgId.get(id);
|
|
3202
3477
|
const chunk = state && state.version === chunkTextSource.version ? state.chunks[chunkTextSource.chunkIndex] : void 0;
|
|
3203
3478
|
chunkText2 = resolveChunkText(stored2.content, chunk, state?.chunks);
|
|
3204
3479
|
} else {
|
|
@@ -4352,13 +4627,35 @@ async function generateEmbedding(text14, options) {
|
|
|
4352
4627
|
if (total === void 0) return embedOne(text14, options, void 0);
|
|
4353
4628
|
return withDeadline((signal) => embedOne(text14, options, signal), total, "embedding");
|
|
4354
4629
|
}
|
|
4630
|
+
var inFlightByCache = /* @__PURE__ */ new WeakMap();
|
|
4355
4631
|
async function embedOne(text14, options, outer) {
|
|
4356
|
-
const {
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4632
|
+
const { cache } = options;
|
|
4633
|
+
if (!cache) return Array.from(await requestEmbedding(text14, options, outer));
|
|
4634
|
+
const cached = cache.get(text14);
|
|
4635
|
+
if (cached) return Array.from(cached);
|
|
4636
|
+
const inFlight = inFlightByCache.get(cache) ?? /* @__PURE__ */ new Map();
|
|
4637
|
+
inFlightByCache.set(cache, inFlight);
|
|
4638
|
+
const pending = inFlight.get(text14);
|
|
4639
|
+
if (pending) {
|
|
4640
|
+
try {
|
|
4641
|
+
return Array.from(await pending);
|
|
4642
|
+
} catch (err) {
|
|
4643
|
+
if (outer?.aborted) throw err;
|
|
4644
|
+
}
|
|
4361
4645
|
}
|
|
4646
|
+
const request = requestEmbedding(text14, options, outer);
|
|
4647
|
+
inFlight.set(text14, request);
|
|
4648
|
+
try {
|
|
4649
|
+
const embedding2 = await request;
|
|
4650
|
+
cache.set(text14, embedding2);
|
|
4651
|
+
return Array.from(embedding2);
|
|
4652
|
+
} finally {
|
|
4653
|
+
if (inFlight.get(text14) === request) inFlight.delete(text14);
|
|
4654
|
+
}
|
|
4655
|
+
}
|
|
4656
|
+
async function requestEmbedding(text14, options, outer) {
|
|
4657
|
+
const { baseUrl = BASE_URL, model } = options;
|
|
4658
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_EMBEDDING_REQUEST_TIMEOUT_MS;
|
|
4362
4659
|
const headers = {
|
|
4363
4660
|
...await resolveAuthHeaders(options, outer),
|
|
4364
4661
|
...taskTypeHeader(options.taskType)
|
|
@@ -4393,11 +4690,7 @@ async function embedOne(text14, options, outer) {
|
|
|
4393
4690
|
totalTokens: response.data.usage.total_tokens ?? 0
|
|
4394
4691
|
});
|
|
4395
4692
|
}
|
|
4396
|
-
|
|
4397
|
-
if (cache) {
|
|
4398
|
-
cache.set(text14, f32Embedding);
|
|
4399
|
-
}
|
|
4400
|
-
return Array.from(f32Embedding);
|
|
4693
|
+
return Float32Array.from(embedding2);
|
|
4401
4694
|
}
|
|
4402
4695
|
var DEFAULT_EMBEDDING_BATCH_SIZE = 100;
|
|
4403
4696
|
var DEFAULT_EMBEDDING_BATCH_CONCURRENCY = 3;
|
|
@@ -4795,7 +5088,8 @@ function extractReservationReceipts(toolCallEvents) {
|
|
|
4795
5088
|
for (const event of toolCallEvents ?? []) {
|
|
4796
5089
|
const action = ACTIONS.find((a) => event.name?.endsWith(a.tool));
|
|
4797
5090
|
const output = event.output ?? "";
|
|
4798
|
-
if (!action || !output || NOT_AN_ATTEMPT.test(output))
|
|
5091
|
+
if (!action || !output || hasEncryptedToolPayload(event) || NOT_AN_ATTEMPT.test(output))
|
|
5092
|
+
continue;
|
|
4799
5093
|
const kept = latest.get(action.kind)?.status;
|
|
4800
5094
|
if (kept === "made") continue;
|
|
4801
5095
|
const receipt = toReceipt(action, event.arguments ?? "", output);
|
|
@@ -15676,9 +15970,9 @@ function recencyMultiplier(updatedAt, opts = {}) {
|
|
|
15676
15970
|
const updatedMs = updatedAt.getTime();
|
|
15677
15971
|
if (!Number.isFinite(updatedMs)) return noDate;
|
|
15678
15972
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
15679
|
-
const
|
|
15680
|
-
if (!Number.isFinite(
|
|
15681
|
-
const ageDays2 = Math.max(0, (
|
|
15973
|
+
const nowMs2 = now.getTime();
|
|
15974
|
+
if (!Number.isFinite(nowMs2)) return noDate;
|
|
15975
|
+
const ageDays2 = Math.max(0, (nowMs2 - updatedMs) / DAY_MS2);
|
|
15682
15976
|
const perYearDecay = opts.perYearDecay ?? DEFAULT_PER_YEAR_DECAY;
|
|
15683
15977
|
const floor = opts.floor ?? DEFAULT_FLOOR;
|
|
15684
15978
|
const decay = perYearDecay * (ageDays2 / 365);
|
|
@@ -16187,9 +16481,6 @@ function createVaultEmbeddingCache(maxSize = DEFAULT_VAULT_CACHE_SIZE) {
|
|
|
16187
16481
|
|
|
16188
16482
|
// src/lib/memoryVault/searchTool.ts
|
|
16189
16483
|
var DEFAULT_RERANK_TOP_N = 5;
|
|
16190
|
-
function nowMs() {
|
|
16191
|
-
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
16192
|
-
}
|
|
16193
16484
|
var warnedProgrammaticDecomposeIgnored = false;
|
|
16194
16485
|
function normalizeEventTimeKind(kind) {
|
|
16195
16486
|
return kind === "point" || kind === "range" || kind === "ongoing" ? kind : null;
|
|
@@ -19080,6 +19371,32 @@ function rankProfileCandidates(inputs, now = Date.now(), options = {}) {
|
|
|
19080
19371
|
return ranked;
|
|
19081
19372
|
}
|
|
19082
19373
|
|
|
19374
|
+
// src/lib/db/chat/embeddingCache.ts
|
|
19375
|
+
var MaskScopedEmbeddingCache = class extends Map {
|
|
19376
|
+
constructor(inner, masked) {
|
|
19377
|
+
super();
|
|
19378
|
+
this.inner = inner;
|
|
19379
|
+
this.masked = masked;
|
|
19380
|
+
}
|
|
19381
|
+
key(text14) {
|
|
19382
|
+
return `${this.masked ? "m" : "r"}:${text14}`;
|
|
19383
|
+
}
|
|
19384
|
+
get(text14) {
|
|
19385
|
+
return this.inner.get(this.key(text14));
|
|
19386
|
+
}
|
|
19387
|
+
set(text14, value) {
|
|
19388
|
+
this.inner.set(this.key(text14), value);
|
|
19389
|
+
return this;
|
|
19390
|
+
}
|
|
19391
|
+
};
|
|
19392
|
+
var scopedViews = /* @__PURE__ */ new WeakMap();
|
|
19393
|
+
function maskScopedEmbeddingCache(cache, masked) {
|
|
19394
|
+
const views = scopedViews.get(cache) ?? {};
|
|
19395
|
+
scopedViews.set(cache, views);
|
|
19396
|
+
const slot = masked ? "masked" : "raw";
|
|
19397
|
+
return views[slot] ?? (views[slot] = new MaskScopedEmbeddingCache(cache, masked));
|
|
19398
|
+
}
|
|
19399
|
+
|
|
19083
19400
|
// src/lib/memory/queryTemporal.ts
|
|
19084
19401
|
var RELATIVE_DAY_ENTRIES = [
|
|
19085
19402
|
[/\btoday\b/, "today", 0],
|
|
@@ -19287,9 +19604,6 @@ function scoreEventTimeOverlap(memoryStart, memoryEnd, memoryKind, window2) {
|
|
|
19287
19604
|
var DEFAULT_LIMIT = 8;
|
|
19288
19605
|
var DEFAULT_BUDGET = "low";
|
|
19289
19606
|
var DEFAULT_FACT_MIN_SCORE = 0.1;
|
|
19290
|
-
function nowMs2() {
|
|
19291
|
-
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
19292
|
-
}
|
|
19293
19607
|
var DEFAULT_CHUNK_MIN_SCORE = 0.5;
|
|
19294
19608
|
var DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS = 8e3;
|
|
19295
19609
|
function flagsForBudget(budget) {
|
|
@@ -19327,12 +19641,19 @@ async function recall(query, ctx, options = {}) {
|
|
|
19327
19641
|
const subQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
19328
19642
|
const embeddingOptions = {
|
|
19329
19643
|
...ctx.embeddingOptions,
|
|
19330
|
-
taskType: "memory_recall_embed"
|
|
19644
|
+
taskType: "memory_recall_embed",
|
|
19645
|
+
...options.embeddingCache && !ctx.embeddingOptions.cache && {
|
|
19646
|
+
cache: maskScopedEmbeddingCache(
|
|
19647
|
+
options.embeddingCache,
|
|
19648
|
+
Boolean(ctx.embeddingOptions.maskInput)
|
|
19649
|
+
)
|
|
19650
|
+
}
|
|
19331
19651
|
};
|
|
19332
|
-
const t0 =
|
|
19652
|
+
const t0 = nowMs();
|
|
19333
19653
|
let prepMs = 0;
|
|
19334
19654
|
let factLaneMs = 0;
|
|
19335
19655
|
let chunkLaneMs = 0;
|
|
19656
|
+
let chunkStats;
|
|
19336
19657
|
let fuseMs = 0;
|
|
19337
19658
|
const factResults = [];
|
|
19338
19659
|
const chunkResults = [];
|
|
@@ -19387,6 +19708,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
19387
19708
|
...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
|
|
19388
19709
|
...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
|
|
19389
19710
|
...vaultRowsEmbedded !== void 0 && { vaultRowsEmbedded },
|
|
19711
|
+
...chunkStats && {
|
|
19712
|
+
chunkRowsScanned: chunkStats.rowsScanned,
|
|
19713
|
+
chunkRowsFetched: chunkStats.rowsFetched,
|
|
19714
|
+
chunkCacheHits: chunkStats.cacheHits
|
|
19715
|
+
},
|
|
19390
19716
|
factCount: factResults.length,
|
|
19391
19717
|
chunkCount: chunkResults.length,
|
|
19392
19718
|
admittedCount: admitted.length,
|
|
@@ -19398,7 +19724,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
19398
19724
|
temporalLaneCount,
|
|
19399
19725
|
emptyReason: emptyReasonFor(admitted.length, laneRan),
|
|
19400
19726
|
timings: {
|
|
19401
|
-
total:
|
|
19727
|
+
total: nowMs() - t0,
|
|
19402
19728
|
prep: prepMs,
|
|
19403
19729
|
factLane: factLaneMs,
|
|
19404
19730
|
rerank: rerankMs,
|
|
@@ -19420,14 +19746,14 @@ async function recall(query, ctx, options = {}) {
|
|
|
19420
19746
|
const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
|
|
19421
19747
|
const wantsTemporal = types.includes("fact") && (ctx.factSource || ctx.vaultCtx);
|
|
19422
19748
|
const queryEmbedTotalTimeoutMs = options.queryEmbedTotalTimeoutMs ?? DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS;
|
|
19423
|
-
const prepStart =
|
|
19749
|
+
const prepStart = nowMs();
|
|
19424
19750
|
let sharedEmbedMs = 0;
|
|
19425
19751
|
const [queryEmbedding, entityRanking, temporalRanking] = await Promise.all([
|
|
19426
19752
|
needsChunkEmbedding ? generateEmbedding(query, {
|
|
19427
19753
|
...embeddingOptions,
|
|
19428
19754
|
totalTimeoutMs: queryEmbedTotalTimeoutMs
|
|
19429
19755
|
}).finally(() => {
|
|
19430
|
-
sharedEmbedMs =
|
|
19756
|
+
sharedEmbedMs = nowMs() - prepStart;
|
|
19431
19757
|
}).then((vec) => {
|
|
19432
19758
|
if (vec.length === 0) {
|
|
19433
19759
|
getLogger().warn(
|
|
@@ -19460,11 +19786,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
19460
19786
|
() => ctx.factSource ? ctx.factSource.temporalRanking(query, options.now) : buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
|
|
19461
19787
|
) : Promise.resolve([])
|
|
19462
19788
|
]);
|
|
19463
|
-
prepMs =
|
|
19789
|
+
prepMs = nowMs() - prepStart;
|
|
19464
19790
|
graphLaneCount = entityRanking.length;
|
|
19465
19791
|
temporalLaneCount = temporalRanking.length;
|
|
19466
19792
|
if (types.includes("fact") && (ctx.factSource || ctx.vaultCtx && ctx.vaultCache)) {
|
|
19467
|
-
const factStart =
|
|
19793
|
+
const factStart = nowMs();
|
|
19468
19794
|
const vaultMinScore = options.minScore ?? DEFAULT_FACT_MIN_SCORE;
|
|
19469
19795
|
factFloor = vaultMinScore;
|
|
19470
19796
|
const {
|
|
@@ -19540,11 +19866,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
19540
19866
|
factLaneRankedOnCosine = factRankedOnCosine;
|
|
19541
19867
|
decryptLastRan = factDecryptLast;
|
|
19542
19868
|
vaultRowsDecrypted = factRowsDecrypted;
|
|
19543
|
-
factLaneMs =
|
|
19869
|
+
factLaneMs = nowMs() - factStart;
|
|
19544
19870
|
}
|
|
19545
19871
|
if (chunkEmbedFailed && !factLaneRankedOnCosine) embeddingsUnavailable = true;
|
|
19546
19872
|
if (types.includes("chunk") && ctx.storageCtx && queryEmbedding) {
|
|
19547
|
-
const chunkStart =
|
|
19873
|
+
const chunkStart = nowMs();
|
|
19548
19874
|
const chunkMinScore = options.minScore ?? DEFAULT_CHUNK_MIN_SCORE;
|
|
19549
19875
|
chunkFloor = chunkMinScore;
|
|
19550
19876
|
const results = await searchChunksOp(ctx.storageCtx, queryEmbedding, {
|
|
@@ -19555,12 +19881,15 @@ async function recall(query, ctx, options = {}) {
|
|
|
19555
19881
|
...options.excludeConversationId && {
|
|
19556
19882
|
excludeConversationId: options.excludeConversationId
|
|
19557
19883
|
},
|
|
19558
|
-
...ctx.chunkCache && { chunkCache: ctx.chunkCache }
|
|
19884
|
+
...ctx.chunkCache && { chunkCache: ctx.chunkCache },
|
|
19885
|
+
onStats: (stats) => {
|
|
19886
|
+
chunkStats = stats;
|
|
19887
|
+
}
|
|
19559
19888
|
});
|
|
19560
19889
|
chunkResults.push(...dedupeBy(results, (r) => r.chunkText.trim()));
|
|
19561
|
-
chunkLaneMs =
|
|
19890
|
+
chunkLaneMs = nowMs() - chunkStart;
|
|
19562
19891
|
}
|
|
19563
|
-
const fuseStart =
|
|
19892
|
+
const fuseStart = nowMs();
|
|
19564
19893
|
if (types.length === 1 || factResults.length === 0 || chunkResults.length === 0) {
|
|
19565
19894
|
const memories2 = [
|
|
19566
19895
|
...factResults.map((r) => toFactMemory(r, options.now)),
|
|
@@ -19568,7 +19897,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
19568
19897
|
];
|
|
19569
19898
|
memories2.sort((a, b) => b.score - a.score);
|
|
19570
19899
|
const candidateCount = factResults.length + chunkResults.length;
|
|
19571
|
-
fuseMs =
|
|
19900
|
+
fuseMs = nowMs() - fuseStart;
|
|
19572
19901
|
const admitted = memories2.slice(0, limit);
|
|
19573
19902
|
hitLimit = memories2.length > limit;
|
|
19574
19903
|
emitDiagnostics(candidateCount, admitted);
|
|
@@ -19632,7 +19961,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
19632
19961
|
memories = selection.out;
|
|
19633
19962
|
}
|
|
19634
19963
|
hitLimit = selection.cut;
|
|
19635
|
-
fuseMs =
|
|
19964
|
+
fuseMs = nowMs() - fuseStart;
|
|
19636
19965
|
emitDiagnostics(byId.size, memories);
|
|
19637
19966
|
return {
|
|
19638
19967
|
memories,
|
|
@@ -29635,28 +29964,6 @@ async function cleanupConversationSummary(database, conversationId) {
|
|
|
29635
29964
|
}
|
|
29636
29965
|
}
|
|
29637
29966
|
|
|
29638
|
-
// src/lib/db/chat/embeddingCache.ts
|
|
29639
|
-
var MaskScopedEmbeddingCache = class extends Map {
|
|
29640
|
-
constructor(inner, masked) {
|
|
29641
|
-
super();
|
|
29642
|
-
this.inner = inner;
|
|
29643
|
-
this.masked = masked;
|
|
29644
|
-
}
|
|
29645
|
-
key(text14) {
|
|
29646
|
-
return `${this.masked ? "m" : "r"}:${text14}`;
|
|
29647
|
-
}
|
|
29648
|
-
get(text14) {
|
|
29649
|
-
return this.inner.get(this.key(text14));
|
|
29650
|
-
}
|
|
29651
|
-
set(text14, value) {
|
|
29652
|
-
this.inner.set(this.key(text14), value);
|
|
29653
|
-
return this;
|
|
29654
|
-
}
|
|
29655
|
-
};
|
|
29656
|
-
function maskScopedEmbeddingCache(cache, masked) {
|
|
29657
|
-
return new MaskScopedEmbeddingCache(cache, masked);
|
|
29658
|
-
}
|
|
29659
|
-
|
|
29660
29967
|
// src/lib/tools/selection/activeToolSets.ts
|
|
29661
29968
|
function mergeActiveToolSets(current, derived) {
|
|
29662
29969
|
if (derived.length === 0) return current;
|
|
@@ -30185,11 +30492,12 @@ async function storedToLlmapiMessage(stored2, encryptionKey, resolveMediaByIds)
|
|
|
30185
30492
|
textContent = textContent.replace(/\n{3,}/g, "\n\n").trim();
|
|
30186
30493
|
const content = [{ type: "text", text: textContent }, ...imageParts];
|
|
30187
30494
|
const messages = [];
|
|
30188
|
-
|
|
30495
|
+
const toolCallEvents = Array.isArray(stored2.toolCallEvents) ? stored2.toolCallEvents.filter((event) => !hasEncryptedToolPayload(event)) : [];
|
|
30496
|
+
if (stored2.role === "assistant" && toolCallEvents.length) {
|
|
30189
30497
|
messages.push({
|
|
30190
30498
|
role: stored2.role,
|
|
30191
30499
|
content: void 0,
|
|
30192
|
-
tool_calls:
|
|
30500
|
+
tool_calls: toolCallEvents.map((event) => ({
|
|
30193
30501
|
id: event.id,
|
|
30194
30502
|
type: "function",
|
|
30195
30503
|
function: {
|
|
@@ -30198,7 +30506,7 @@ async function storedToLlmapiMessage(stored2, encryptionKey, resolveMediaByIds)
|
|
|
30198
30506
|
}
|
|
30199
30507
|
}))
|
|
30200
30508
|
});
|
|
30201
|
-
for (const event of
|
|
30509
|
+
for (const event of toolCallEvents) {
|
|
30202
30510
|
if (event.id && event.output !== void 0 && event.output !== null) {
|
|
30203
30511
|
messages.push({
|
|
30204
30512
|
role: "tool",
|
|
@@ -35190,6 +35498,7 @@ export {
|
|
|
35190
35498
|
encryptDataBatch,
|
|
35191
35499
|
encryptDataBytes,
|
|
35192
35500
|
encryptDataWithKey,
|
|
35501
|
+
encryptToolCallEventsOp,
|
|
35193
35502
|
ensureDefaultFoldersOp,
|
|
35194
35503
|
expandToolSetsAdditive,
|
|
35195
35504
|
exportElementToPdf,
|