@anuma/sdk 7.0.1 → 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 +284 -102
- package/dist/expo/index.d.mts +18 -24
- package/dist/expo/index.d.ts +18 -24
- package/dist/expo/index.mjs +284 -102
- package/dist/index.cjs +28 -10
- package/dist/index.mjs +28 -10
- package/dist/memory/context.d.mts +8 -0
- package/dist/memory/context.d.ts +8 -0
- package/dist/react/index.cjs +305 -123
- package/dist/react/index.d.mts +23 -44
- package/dist/react/index.d.ts +23 -44
- package/dist/react/index.mjs +305 -123
- package/dist/server/index.cjs +305 -101
- package/dist/server/index.d.mts +23 -21
- package/dist/server/index.d.ts +23 -21
- package/dist/server/index.mjs +305 -101
- 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.cjs
CHANGED
|
@@ -3585,6 +3585,35 @@ function decodeChunkVector(vector, onMalformed) {
|
|
|
3585
3585
|
}
|
|
3586
3586
|
}
|
|
3587
3587
|
|
|
3588
|
+
// src/lib/scheduling.ts
|
|
3589
|
+
function nowMs() {
|
|
3590
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
3591
|
+
}
|
|
3592
|
+
function yieldToEventLoop() {
|
|
3593
|
+
const scheduler = globalThis.scheduler;
|
|
3594
|
+
if (typeof scheduler?.yield === "function") return scheduler.yield();
|
|
3595
|
+
if (typeof MessageChannel === "function") {
|
|
3596
|
+
return new Promise((resolve) => {
|
|
3597
|
+
const channel = new MessageChannel();
|
|
3598
|
+
channel.port1.onmessage = () => {
|
|
3599
|
+
channel.port1.close();
|
|
3600
|
+
channel.port2.close();
|
|
3601
|
+
resolve();
|
|
3602
|
+
};
|
|
3603
|
+
channel.port2.postMessage(null);
|
|
3604
|
+
});
|
|
3605
|
+
}
|
|
3606
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
3607
|
+
}
|
|
3608
|
+
function createTimeSliceYielder(budgetMs) {
|
|
3609
|
+
let sliceStart = nowMs();
|
|
3610
|
+
return async () => {
|
|
3611
|
+
if (nowMs() - sliceStart < budgetMs) return;
|
|
3612
|
+
await yieldToEventLoop();
|
|
3613
|
+
sliceStart = nowMs();
|
|
3614
|
+
};
|
|
3615
|
+
}
|
|
3616
|
+
|
|
3588
3617
|
// src/lib/db/encryption-utils.ts
|
|
3589
3618
|
init_logger();
|
|
3590
3619
|
var ENCRYPTION_PREFIX = "enc:v3:";
|
|
@@ -4968,6 +4997,95 @@ async function searchMessagesOp(ctx, queryVector, options) {
|
|
|
4968
4997
|
})
|
|
4969
4998
|
);
|
|
4970
4999
|
}
|
|
5000
|
+
var CHUNK_VECTOR_BATCH_SIZE = 50;
|
|
5001
|
+
var CHUNK_SCAN_YIELD_BUDGET_MS = 12;
|
|
5002
|
+
var hasEmbeddingSql = `(coalesce("chunks", '') != '' or coalesce("vector", '') != '')`;
|
|
5003
|
+
function toChunkCandidateKey(raw) {
|
|
5004
|
+
return {
|
|
5005
|
+
id: raw.id,
|
|
5006
|
+
conversationId: String(raw.conversation_id),
|
|
5007
|
+
version: Number(raw.updated_at) || 0,
|
|
5008
|
+
embeddingModel: raw.embedding_model ?? null
|
|
5009
|
+
};
|
|
5010
|
+
}
|
|
5011
|
+
async function fetchRowsByIds(ctx, ids) {
|
|
5012
|
+
if (ids.length === 0) return [];
|
|
5013
|
+
return await ctx.messagesCollection.query(import_watermelondb2.Q.where("id", import_watermelondb2.Q.oneOf(ids))).unsafeFetchRaw();
|
|
5014
|
+
}
|
|
5015
|
+
async function projectedChunkRowSource(ctx, filter) {
|
|
5016
|
+
const clauses = [
|
|
5017
|
+
`"history"."_status" is not 'deleted'`,
|
|
5018
|
+
hasEmbeddingSql,
|
|
5019
|
+
`exists (select 1 from "conversations" where "conversations"."conversation_id" = "history"."conversation_id" and "conversations"."is_deleted" = 0 and "conversations"."_status" is not 'deleted')`
|
|
5020
|
+
];
|
|
5021
|
+
const args = [];
|
|
5022
|
+
if (filter.conversationId !== void 0) {
|
|
5023
|
+
clauses.push(`"history"."conversation_id" = ?`);
|
|
5024
|
+
args.push(filter.conversationId);
|
|
5025
|
+
}
|
|
5026
|
+
if (filter.excludeConversationId !== void 0) {
|
|
5027
|
+
clauses.push(`"history"."conversation_id" != ?`);
|
|
5028
|
+
args.push(filter.excludeConversationId);
|
|
5029
|
+
}
|
|
5030
|
+
const keyRows = await ctx.messagesCollection.query(
|
|
5031
|
+
import_watermelondb2.Q.unsafeSqlQuery(
|
|
5032
|
+
`select "id", "conversation_id", "updated_at", "embedding_model" from "history" where ${clauses.join(" and ")}`,
|
|
5033
|
+
args
|
|
5034
|
+
)
|
|
5035
|
+
).unsafeFetchRaw();
|
|
5036
|
+
return {
|
|
5037
|
+
keys: keyRows.map(toChunkCandidateKey),
|
|
5038
|
+
loadVectorRows: async (ids) => {
|
|
5039
|
+
if (ids.length === 0) return [];
|
|
5040
|
+
return await ctx.messagesCollection.query(
|
|
5041
|
+
import_watermelondb2.Q.unsafeSqlQuery(
|
|
5042
|
+
`select "id", "updated_at", "chunks", "vector" from "history" where "_status" is not 'deleted' and "id" in (${ids.map(() => "?").join(",")})`,
|
|
5043
|
+
ids
|
|
5044
|
+
)
|
|
5045
|
+
).unsafeFetchRaw();
|
|
5046
|
+
},
|
|
5047
|
+
loadFullRows: (ids) => fetchRowsByIds(ctx, ids)
|
|
5048
|
+
};
|
|
5049
|
+
}
|
|
5050
|
+
async function fullScanChunkRowSource(ctx, filter) {
|
|
5051
|
+
const activeConversations = await ctx.conversationsCollection.query(import_watermelondb2.Q.where("is_deleted", false)).fetch();
|
|
5052
|
+
const activeConversationIds = new Set(
|
|
5053
|
+
activeConversations.map((c) => String(c._getRaw("conversation_id")))
|
|
5054
|
+
);
|
|
5055
|
+
const queryConditions = filter.conversationId !== void 0 ? [import_watermelondb2.Q.where("conversation_id", filter.conversationId)] : [];
|
|
5056
|
+
const rows = await ctx.messagesCollection.query(...queryConditions).unsafeFetchRaw();
|
|
5057
|
+
const rowsById = /* @__PURE__ */ new Map();
|
|
5058
|
+
for (const row of rows) {
|
|
5059
|
+
const conversationId = String(row.conversation_id);
|
|
5060
|
+
if (!activeConversationIds.has(conversationId)) continue;
|
|
5061
|
+
if (filter.excludeConversationId !== void 0 && conversationId === filter.excludeConversationId) {
|
|
5062
|
+
continue;
|
|
5063
|
+
}
|
|
5064
|
+
if (!row.chunks && !row.vector) continue;
|
|
5065
|
+
rowsById.set(row.id, row);
|
|
5066
|
+
}
|
|
5067
|
+
const pick = (ids) => Promise.resolve(
|
|
5068
|
+
ids.flatMap((id) => {
|
|
5069
|
+
const row = rowsById.get(id);
|
|
5070
|
+
return row ? [row] : [];
|
|
5071
|
+
})
|
|
5072
|
+
);
|
|
5073
|
+
return {
|
|
5074
|
+
keys: Array.from(rowsById.values(), toChunkCandidateKey),
|
|
5075
|
+
loadVectorRows: pick,
|
|
5076
|
+
loadFullRows: pick
|
|
5077
|
+
};
|
|
5078
|
+
}
|
|
5079
|
+
async function chunkRowSource(ctx, filter) {
|
|
5080
|
+
try {
|
|
5081
|
+
return await projectedChunkRowSource(ctx, filter);
|
|
5082
|
+
} catch (err) {
|
|
5083
|
+
getLogger().debug(
|
|
5084
|
+
"searchChunksOp: projected SQL unavailable, using full-load fallback: " + (err instanceof Error ? err.message : String(err))
|
|
5085
|
+
);
|
|
5086
|
+
return fullScanChunkRowSource(ctx, filter);
|
|
5087
|
+
}
|
|
5088
|
+
}
|
|
4971
5089
|
async function searchChunksOp(ctx, queryVector, options) {
|
|
4972
5090
|
const {
|
|
4973
5091
|
limit = 10,
|
|
@@ -4975,83 +5093,111 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
4975
5093
|
conversationId,
|
|
4976
5094
|
excludeConversationId,
|
|
4977
5095
|
embeddingModel,
|
|
4978
|
-
chunkCache
|
|
5096
|
+
chunkCache,
|
|
5097
|
+
onStats
|
|
4979
5098
|
} = options || {};
|
|
4980
|
-
const
|
|
4981
|
-
const
|
|
4982
|
-
activeConversations.map((c) => String(c._getRaw("conversation_id")))
|
|
4983
|
-
);
|
|
4984
|
-
const queryConditions = conversationId ? [import_watermelondb2.Q.where("conversation_id", conversationId)] : [];
|
|
4985
|
-
const messages = await ctx.messagesCollection.query(...queryConditions).unsafeFetchRaw();
|
|
5099
|
+
const source = await chunkRowSource(ctx, { conversationId, excludeConversationId });
|
|
5100
|
+
const yieldIfDue = createTimeSliceYielder(CHUNK_SCAN_YIELD_BUDGET_MS);
|
|
4986
5101
|
const candidates = [];
|
|
4987
5102
|
let staleSkipped = 0;
|
|
4988
5103
|
let unreadableVectors = 0;
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
}
|
|
5104
|
+
let cacheHits = 0;
|
|
5105
|
+
const missIds = [];
|
|
5106
|
+
const orderById = /* @__PURE__ */ new Map();
|
|
5107
|
+
for (const [order, key] of source.keys.entries()) {
|
|
5108
|
+
await yieldIfDue();
|
|
5109
|
+
orderById.set(key.id, order);
|
|
5110
|
+
if (embeddingModel && key.embeddingModel !== null && key.embeddingModel !== embeddingModel) {
|
|
5111
|
+
staleSkipped++;
|
|
5112
|
+
continue;
|
|
4999
5113
|
}
|
|
5000
|
-
const
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
if (cached.chunks.length > 0) {
|
|
5004
|
-
for (let ci = 0; ci < cached.chunks.length; ci++) {
|
|
5005
|
-
const vec = cached.chunks[ci];
|
|
5006
|
-
if (vec.length === 0) continue;
|
|
5007
|
-
const similarity = cosineSimilarity(queryVector, vec);
|
|
5008
|
-
if (similarity >= minSimilarity) {
|
|
5009
|
-
candidates.push({
|
|
5010
|
-
message,
|
|
5011
|
-
similarity,
|
|
5012
|
-
chunkTextSource: { kind: "chunk-cached", chunkIndex: ci, version }
|
|
5013
|
-
});
|
|
5014
|
-
}
|
|
5015
|
-
}
|
|
5016
|
-
} else if (cached.fallback) {
|
|
5017
|
-
const similarity = cosineSimilarity(queryVector, cached.fallback);
|
|
5018
|
-
if (similarity >= minSimilarity) {
|
|
5019
|
-
candidates.push({ message, similarity, chunkTextSource: { kind: "message" } });
|
|
5020
|
-
}
|
|
5021
|
-
}
|
|
5114
|
+
const cached = chunkCache?.get(key.id);
|
|
5115
|
+
if (!cached || cached.version !== key.version) {
|
|
5116
|
+
missIds.push(key.id);
|
|
5022
5117
|
continue;
|
|
5023
5118
|
}
|
|
5024
|
-
|
|
5025
|
-
if (
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
unreadableVectors++;
|
|
5029
|
-
})
|
|
5030
|
-
);
|
|
5031
|
-
chunkCache?.set(message.id, { version, chunks: vectors });
|
|
5032
|
-
for (let ci = 0; ci < chunks3.length; ci++) {
|
|
5033
|
-
const vec = vectors[ci];
|
|
5119
|
+
cacheHits++;
|
|
5120
|
+
if (cached.chunks.length > 0) {
|
|
5121
|
+
for (let ci = 0; ci < cached.chunks.length; ci++) {
|
|
5122
|
+
const vec = cached.chunks[ci];
|
|
5034
5123
|
if (vec.length === 0) continue;
|
|
5035
5124
|
const similarity = cosineSimilarity(queryVector, vec);
|
|
5036
5125
|
if (similarity >= minSimilarity) {
|
|
5037
5126
|
candidates.push({
|
|
5038
|
-
|
|
5127
|
+
id: key.id,
|
|
5128
|
+
version: key.version,
|
|
5129
|
+
order,
|
|
5039
5130
|
similarity,
|
|
5040
|
-
chunkTextSource: { kind: "chunk",
|
|
5131
|
+
chunkTextSource: { kind: "chunk-cached", chunkIndex: ci, version: key.version }
|
|
5041
5132
|
});
|
|
5042
5133
|
}
|
|
5043
5134
|
}
|
|
5044
|
-
} else {
|
|
5045
|
-
const
|
|
5046
|
-
if (!messageVector || messageVector.length === 0) continue;
|
|
5047
|
-
const fallback = Float32Array.from(messageVector);
|
|
5048
|
-
chunkCache?.set(message.id, { version, chunks: [], fallback });
|
|
5049
|
-
const similarity = cosineSimilarity(queryVector, fallback);
|
|
5135
|
+
} else if (cached.fallback) {
|
|
5136
|
+
const similarity = cosineSimilarity(queryVector, cached.fallback);
|
|
5050
5137
|
if (similarity >= minSimilarity) {
|
|
5051
|
-
candidates.push({
|
|
5138
|
+
candidates.push({
|
|
5139
|
+
id: key.id,
|
|
5140
|
+
version: key.version,
|
|
5141
|
+
order,
|
|
5142
|
+
similarity,
|
|
5143
|
+
chunkTextSource: { kind: "message" }
|
|
5144
|
+
});
|
|
5145
|
+
}
|
|
5146
|
+
}
|
|
5147
|
+
}
|
|
5148
|
+
let rowsFetched = 0;
|
|
5149
|
+
for (let offset = 0; offset < missIds.length; offset += CHUNK_VECTOR_BATCH_SIZE) {
|
|
5150
|
+
const rows = await source.loadVectorRows(
|
|
5151
|
+
missIds.slice(offset, offset + CHUNK_VECTOR_BATCH_SIZE)
|
|
5152
|
+
);
|
|
5153
|
+
rowsFetched += rows.length;
|
|
5154
|
+
for (const row of rows) {
|
|
5155
|
+
await yieldIfDue();
|
|
5156
|
+
const id = row.id;
|
|
5157
|
+
const version = Number(row.updated_at) || 0;
|
|
5158
|
+
const order = orderById.get(id) ?? Number.MAX_SAFE_INTEGER;
|
|
5159
|
+
const chunks3 = await readRawJsonField(row, "chunks", ctx.walletAddress);
|
|
5160
|
+
if (chunks3 && chunks3.length > 0) {
|
|
5161
|
+
const vectors = chunks3.map(
|
|
5162
|
+
(chunk) => decodeChunkVector(chunk.vector, () => {
|
|
5163
|
+
unreadableVectors++;
|
|
5164
|
+
})
|
|
5165
|
+
);
|
|
5166
|
+
chunkCache?.set(id, { version, chunks: vectors });
|
|
5167
|
+
for (let ci = 0; ci < chunks3.length; ci++) {
|
|
5168
|
+
const vec = vectors[ci];
|
|
5169
|
+
if (vec.length === 0) continue;
|
|
5170
|
+
const similarity = cosineSimilarity(queryVector, vec);
|
|
5171
|
+
if (similarity >= minSimilarity) {
|
|
5172
|
+
candidates.push({
|
|
5173
|
+
id,
|
|
5174
|
+
version,
|
|
5175
|
+
order,
|
|
5176
|
+
similarity,
|
|
5177
|
+
chunkTextSource: { kind: "chunk", chunk: chunks3[ci], siblings: chunks3 }
|
|
5178
|
+
});
|
|
5179
|
+
}
|
|
5180
|
+
}
|
|
5181
|
+
} else {
|
|
5182
|
+
const messageVector = await readRawJsonField(row, "vector", ctx.walletAddress);
|
|
5183
|
+
if (messageVector && messageVector.length > 0) {
|
|
5184
|
+
const fallback = Float32Array.from(messageVector);
|
|
5185
|
+
chunkCache?.set(id, { version, chunks: [], fallback });
|
|
5186
|
+
const similarity = cosineSimilarity(queryVector, fallback);
|
|
5187
|
+
if (similarity >= minSimilarity) {
|
|
5188
|
+
candidates.push({
|
|
5189
|
+
id,
|
|
5190
|
+
version,
|
|
5191
|
+
order,
|
|
5192
|
+
similarity,
|
|
5193
|
+
chunkTextSource: { kind: "message" }
|
|
5194
|
+
});
|
|
5195
|
+
}
|
|
5196
|
+
}
|
|
5052
5197
|
}
|
|
5053
5198
|
}
|
|
5054
5199
|
}
|
|
5200
|
+
onStats?.({ rowsScanned: source.keys.length, rowsFetched, cacheHits });
|
|
5055
5201
|
if (staleSkipped > 0) {
|
|
5056
5202
|
getLogger().warn(
|
|
5057
5203
|
`searchChunksOp: skipped ${staleSkipped} messages whose embedding model differs from the current model (${embeddingModel}) \u2014 re-embed via chunkAndEmbedAllMessages`
|
|
@@ -5062,12 +5208,17 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
5062
5208
|
`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`
|
|
5063
5209
|
);
|
|
5064
5210
|
}
|
|
5065
|
-
const topK = candidates.sort((a, b) => b.similarity - a.similarity).slice(0, limit);
|
|
5066
|
-
const
|
|
5067
|
-
|
|
5211
|
+
const topK = candidates.sort((a, b) => b.similarity - a.similarity || a.order - b.order).slice(0, limit);
|
|
5212
|
+
const topIds = Array.from(new Set(topK.map((c) => c.id)));
|
|
5213
|
+
const fullRows = await source.loadFullRows(topIds);
|
|
5214
|
+
const rowById = new Map(fullRows.map((row) => [row.id, row]));
|
|
5215
|
+
const liveTopK = topK.filter((c) => {
|
|
5216
|
+
const row = rowById.get(c.id);
|
|
5217
|
+
return row !== void 0 && (Number(row.updated_at) || 0) === c.version;
|
|
5218
|
+
});
|
|
5068
5219
|
const storedById = new Map(
|
|
5069
5220
|
await Promise.all(
|
|
5070
|
-
Array.from(
|
|
5221
|
+
Array.from(rowById, async ([id, m]) => {
|
|
5071
5222
|
const stored2 = await messageRawToStored(
|
|
5072
5223
|
m,
|
|
5073
5224
|
ctx.walletAddress,
|
|
@@ -5080,24 +5231,24 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
5080
5231
|
);
|
|
5081
5232
|
const chunkStateByMsgId = /* @__PURE__ */ new Map();
|
|
5082
5233
|
const needsChunkText = /* @__PURE__ */ new Set();
|
|
5083
|
-
for (const c of
|
|
5084
|
-
if (c.chunkTextSource.kind === "chunk-cached") needsChunkText.add(c.
|
|
5234
|
+
for (const c of liveTopK) {
|
|
5235
|
+
if (c.chunkTextSource.kind === "chunk-cached") needsChunkText.add(c.id);
|
|
5085
5236
|
}
|
|
5086
5237
|
await Promise.all(
|
|
5087
5238
|
Array.from(needsChunkText, async (id) => {
|
|
5088
|
-
const m =
|
|
5239
|
+
const m = rowById.get(id);
|
|
5089
5240
|
const parsed = await readRawJsonField(m, "chunks", ctx.walletAddress);
|
|
5090
5241
|
const version = Number(m.updated_at) || 0;
|
|
5091
5242
|
if (parsed) chunkStateByMsgId.set(id, { version, chunks: parsed });
|
|
5092
5243
|
})
|
|
5093
5244
|
);
|
|
5094
|
-
return
|
|
5095
|
-
const stored2 = { ...storedById.get(
|
|
5245
|
+
return liveTopK.map(({ id, similarity, chunkTextSource }) => {
|
|
5246
|
+
const stored2 = { ...storedById.get(id) };
|
|
5096
5247
|
let chunkText2;
|
|
5097
5248
|
if (chunkTextSource.kind === "chunk") {
|
|
5098
5249
|
chunkText2 = resolveChunkText(stored2.content, chunkTextSource.chunk, chunkTextSource.siblings);
|
|
5099
5250
|
} else if (chunkTextSource.kind === "chunk-cached") {
|
|
5100
|
-
const state = chunkStateByMsgId.get(
|
|
5251
|
+
const state = chunkStateByMsgId.get(id);
|
|
5101
5252
|
const chunk = state && state.version === chunkTextSource.version ? state.chunks[chunkTextSource.chunkIndex] : void 0;
|
|
5102
5253
|
chunkText2 = resolveChunkText(stored2.content, chunk, state?.chunks);
|
|
5103
5254
|
} else {
|
|
@@ -6257,13 +6408,35 @@ async function generateEmbedding(text14, options) {
|
|
|
6257
6408
|
if (total === void 0) return embedOne(text14, options, void 0);
|
|
6258
6409
|
return withDeadline((signal) => embedOne(text14, options, signal), total, "embedding");
|
|
6259
6410
|
}
|
|
6411
|
+
var inFlightByCache = /* @__PURE__ */ new WeakMap();
|
|
6260
6412
|
async function embedOne(text14, options, outer) {
|
|
6261
|
-
const {
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6413
|
+
const { cache } = options;
|
|
6414
|
+
if (!cache) return Array.from(await requestEmbedding(text14, options, outer));
|
|
6415
|
+
const cached = cache.get(text14);
|
|
6416
|
+
if (cached) return Array.from(cached);
|
|
6417
|
+
const inFlight = inFlightByCache.get(cache) ?? /* @__PURE__ */ new Map();
|
|
6418
|
+
inFlightByCache.set(cache, inFlight);
|
|
6419
|
+
const pending = inFlight.get(text14);
|
|
6420
|
+
if (pending) {
|
|
6421
|
+
try {
|
|
6422
|
+
return Array.from(await pending);
|
|
6423
|
+
} catch (err) {
|
|
6424
|
+
if (outer?.aborted) throw err;
|
|
6425
|
+
}
|
|
6426
|
+
}
|
|
6427
|
+
const request = requestEmbedding(text14, options, outer);
|
|
6428
|
+
inFlight.set(text14, request);
|
|
6429
|
+
try {
|
|
6430
|
+
const embedding2 = await request;
|
|
6431
|
+
cache.set(text14, embedding2);
|
|
6432
|
+
return Array.from(embedding2);
|
|
6433
|
+
} finally {
|
|
6434
|
+
if (inFlight.get(text14) === request) inFlight.delete(text14);
|
|
6266
6435
|
}
|
|
6436
|
+
}
|
|
6437
|
+
async function requestEmbedding(text14, options, outer) {
|
|
6438
|
+
const { baseUrl = BASE_URL, model } = options;
|
|
6439
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_EMBEDDING_REQUEST_TIMEOUT_MS;
|
|
6267
6440
|
const headers = {
|
|
6268
6441
|
...await resolveAuthHeaders(options, outer),
|
|
6269
6442
|
...taskTypeHeader(options.taskType)
|
|
@@ -6298,11 +6471,7 @@ async function embedOne(text14, options, outer) {
|
|
|
6298
6471
|
totalTokens: response.data.usage.total_tokens ?? 0
|
|
6299
6472
|
});
|
|
6300
6473
|
}
|
|
6301
|
-
|
|
6302
|
-
if (cache) {
|
|
6303
|
-
cache.set(text14, f32Embedding);
|
|
6304
|
-
}
|
|
6305
|
-
return Array.from(f32Embedding);
|
|
6474
|
+
return Float32Array.from(embedding2);
|
|
6306
6475
|
}
|
|
6307
6476
|
var DEFAULT_EMBEDDING_BATCH_SIZE = 100;
|
|
6308
6477
|
var DEFAULT_EMBEDDING_BATCH_CONCURRENCY = 3;
|
|
@@ -17619,9 +17788,9 @@ function recencyMultiplier(updatedAt, opts = {}) {
|
|
|
17619
17788
|
const updatedMs = updatedAt.getTime();
|
|
17620
17789
|
if (!Number.isFinite(updatedMs)) return noDate;
|
|
17621
17790
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
17622
|
-
const
|
|
17623
|
-
if (!Number.isFinite(
|
|
17624
|
-
const ageDays2 = Math.max(0, (
|
|
17791
|
+
const nowMs2 = now.getTime();
|
|
17792
|
+
if (!Number.isFinite(nowMs2)) return noDate;
|
|
17793
|
+
const ageDays2 = Math.max(0, (nowMs2 - updatedMs) / DAY_MS2);
|
|
17625
17794
|
const perYearDecay = opts.perYearDecay ?? DEFAULT_PER_YEAR_DECAY;
|
|
17626
17795
|
const floor = opts.floor ?? DEFAULT_FLOOR;
|
|
17627
17796
|
const decay = perYearDecay * (ageDays2 / 365);
|
|
@@ -18133,9 +18302,6 @@ function createVaultEmbeddingCache(maxSize = DEFAULT_VAULT_CACHE_SIZE) {
|
|
|
18133
18302
|
|
|
18134
18303
|
// src/lib/memoryVault/searchTool.ts
|
|
18135
18304
|
var DEFAULT_RERANK_TOP_N = 5;
|
|
18136
|
-
function nowMs() {
|
|
18137
|
-
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
18138
|
-
}
|
|
18139
18305
|
var warnedProgrammaticDecomposeIgnored = false;
|
|
18140
18306
|
function normalizeEventTimeKind(kind) {
|
|
18141
18307
|
return kind === "point" || kind === "range" || kind === "ongoing" ? kind : null;
|
|
@@ -21037,6 +21203,32 @@ function rankProfileCandidates(inputs, now = Date.now(), options = {}) {
|
|
|
21037
21203
|
return ranked;
|
|
21038
21204
|
}
|
|
21039
21205
|
|
|
21206
|
+
// src/lib/db/chat/embeddingCache.ts
|
|
21207
|
+
var MaskScopedEmbeddingCache = class extends Map {
|
|
21208
|
+
constructor(inner, masked) {
|
|
21209
|
+
super();
|
|
21210
|
+
this.inner = inner;
|
|
21211
|
+
this.masked = masked;
|
|
21212
|
+
}
|
|
21213
|
+
key(text14) {
|
|
21214
|
+
return `${this.masked ? "m" : "r"}:${text14}`;
|
|
21215
|
+
}
|
|
21216
|
+
get(text14) {
|
|
21217
|
+
return this.inner.get(this.key(text14));
|
|
21218
|
+
}
|
|
21219
|
+
set(text14, value) {
|
|
21220
|
+
this.inner.set(this.key(text14), value);
|
|
21221
|
+
return this;
|
|
21222
|
+
}
|
|
21223
|
+
};
|
|
21224
|
+
var scopedViews = /* @__PURE__ */ new WeakMap();
|
|
21225
|
+
function maskScopedEmbeddingCache(cache, masked) {
|
|
21226
|
+
const views = scopedViews.get(cache) ?? {};
|
|
21227
|
+
scopedViews.set(cache, views);
|
|
21228
|
+
const slot = masked ? "masked" : "raw";
|
|
21229
|
+
return views[slot] ?? (views[slot] = new MaskScopedEmbeddingCache(cache, masked));
|
|
21230
|
+
}
|
|
21231
|
+
|
|
21040
21232
|
// src/lib/memory/recall.ts
|
|
21041
21233
|
init_logger();
|
|
21042
21234
|
|
|
@@ -21247,9 +21439,6 @@ function scoreEventTimeOverlap(memoryStart, memoryEnd, memoryKind, window2) {
|
|
|
21247
21439
|
var DEFAULT_LIMIT = 8;
|
|
21248
21440
|
var DEFAULT_BUDGET = "low";
|
|
21249
21441
|
var DEFAULT_FACT_MIN_SCORE = 0.1;
|
|
21250
|
-
function nowMs2() {
|
|
21251
|
-
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
21252
|
-
}
|
|
21253
21442
|
var DEFAULT_CHUNK_MIN_SCORE = 0.5;
|
|
21254
21443
|
var DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS = 8e3;
|
|
21255
21444
|
function flagsForBudget(budget) {
|
|
@@ -21287,12 +21476,19 @@ async function recall(query, ctx, options = {}) {
|
|
|
21287
21476
|
const subQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
21288
21477
|
const embeddingOptions = {
|
|
21289
21478
|
...ctx.embeddingOptions,
|
|
21290
|
-
taskType: "memory_recall_embed"
|
|
21479
|
+
taskType: "memory_recall_embed",
|
|
21480
|
+
...options.embeddingCache && !ctx.embeddingOptions.cache && {
|
|
21481
|
+
cache: maskScopedEmbeddingCache(
|
|
21482
|
+
options.embeddingCache,
|
|
21483
|
+
Boolean(ctx.embeddingOptions.maskInput)
|
|
21484
|
+
)
|
|
21485
|
+
}
|
|
21291
21486
|
};
|
|
21292
|
-
const t0 =
|
|
21487
|
+
const t0 = nowMs();
|
|
21293
21488
|
let prepMs = 0;
|
|
21294
21489
|
let factLaneMs = 0;
|
|
21295
21490
|
let chunkLaneMs = 0;
|
|
21491
|
+
let chunkStats;
|
|
21296
21492
|
let fuseMs = 0;
|
|
21297
21493
|
const factResults = [];
|
|
21298
21494
|
const chunkResults = [];
|
|
@@ -21347,6 +21543,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
21347
21543
|
...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
|
|
21348
21544
|
...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
|
|
21349
21545
|
...vaultRowsEmbedded !== void 0 && { vaultRowsEmbedded },
|
|
21546
|
+
...chunkStats && {
|
|
21547
|
+
chunkRowsScanned: chunkStats.rowsScanned,
|
|
21548
|
+
chunkRowsFetched: chunkStats.rowsFetched,
|
|
21549
|
+
chunkCacheHits: chunkStats.cacheHits
|
|
21550
|
+
},
|
|
21350
21551
|
factCount: factResults.length,
|
|
21351
21552
|
chunkCount: chunkResults.length,
|
|
21352
21553
|
admittedCount: admitted.length,
|
|
@@ -21358,7 +21559,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
21358
21559
|
temporalLaneCount,
|
|
21359
21560
|
emptyReason: emptyReasonFor(admitted.length, laneRan),
|
|
21360
21561
|
timings: {
|
|
21361
|
-
total:
|
|
21562
|
+
total: nowMs() - t0,
|
|
21362
21563
|
prep: prepMs,
|
|
21363
21564
|
factLane: factLaneMs,
|
|
21364
21565
|
rerank: rerankMs,
|
|
@@ -21380,14 +21581,14 @@ async function recall(query, ctx, options = {}) {
|
|
|
21380
21581
|
const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
|
|
21381
21582
|
const wantsTemporal = types.includes("fact") && (ctx.factSource || ctx.vaultCtx);
|
|
21382
21583
|
const queryEmbedTotalTimeoutMs = options.queryEmbedTotalTimeoutMs ?? DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS;
|
|
21383
|
-
const prepStart =
|
|
21584
|
+
const prepStart = nowMs();
|
|
21384
21585
|
let sharedEmbedMs = 0;
|
|
21385
21586
|
const [queryEmbedding, entityRanking, temporalRanking] = await Promise.all([
|
|
21386
21587
|
needsChunkEmbedding ? generateEmbedding(query, {
|
|
21387
21588
|
...embeddingOptions,
|
|
21388
21589
|
totalTimeoutMs: queryEmbedTotalTimeoutMs
|
|
21389
21590
|
}).finally(() => {
|
|
21390
|
-
sharedEmbedMs =
|
|
21591
|
+
sharedEmbedMs = nowMs() - prepStart;
|
|
21391
21592
|
}).then((vec) => {
|
|
21392
21593
|
if (vec.length === 0) {
|
|
21393
21594
|
getLogger().warn(
|
|
@@ -21420,11 +21621,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
21420
21621
|
() => ctx.factSource ? ctx.factSource.temporalRanking(query, options.now) : buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
|
|
21421
21622
|
) : Promise.resolve([])
|
|
21422
21623
|
]);
|
|
21423
|
-
prepMs =
|
|
21624
|
+
prepMs = nowMs() - prepStart;
|
|
21424
21625
|
graphLaneCount = entityRanking.length;
|
|
21425
21626
|
temporalLaneCount = temporalRanking.length;
|
|
21426
21627
|
if (types.includes("fact") && (ctx.factSource || ctx.vaultCtx && ctx.vaultCache)) {
|
|
21427
|
-
const factStart =
|
|
21628
|
+
const factStart = nowMs();
|
|
21428
21629
|
const vaultMinScore = options.minScore ?? DEFAULT_FACT_MIN_SCORE;
|
|
21429
21630
|
factFloor = vaultMinScore;
|
|
21430
21631
|
const {
|
|
@@ -21500,11 +21701,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
21500
21701
|
factLaneRankedOnCosine = factRankedOnCosine;
|
|
21501
21702
|
decryptLastRan = factDecryptLast;
|
|
21502
21703
|
vaultRowsDecrypted = factRowsDecrypted;
|
|
21503
|
-
factLaneMs =
|
|
21704
|
+
factLaneMs = nowMs() - factStart;
|
|
21504
21705
|
}
|
|
21505
21706
|
if (chunkEmbedFailed && !factLaneRankedOnCosine) embeddingsUnavailable = true;
|
|
21506
21707
|
if (types.includes("chunk") && ctx.storageCtx && queryEmbedding) {
|
|
21507
|
-
const chunkStart =
|
|
21708
|
+
const chunkStart = nowMs();
|
|
21508
21709
|
const chunkMinScore = options.minScore ?? DEFAULT_CHUNK_MIN_SCORE;
|
|
21509
21710
|
chunkFloor = chunkMinScore;
|
|
21510
21711
|
const results = await searchChunksOp(ctx.storageCtx, queryEmbedding, {
|
|
@@ -21515,12 +21716,15 @@ async function recall(query, ctx, options = {}) {
|
|
|
21515
21716
|
...options.excludeConversationId && {
|
|
21516
21717
|
excludeConversationId: options.excludeConversationId
|
|
21517
21718
|
},
|
|
21518
|
-
...ctx.chunkCache && { chunkCache: ctx.chunkCache }
|
|
21719
|
+
...ctx.chunkCache && { chunkCache: ctx.chunkCache },
|
|
21720
|
+
onStats: (stats) => {
|
|
21721
|
+
chunkStats = stats;
|
|
21722
|
+
}
|
|
21519
21723
|
});
|
|
21520
21724
|
chunkResults.push(...dedupeBy(results, (r) => r.chunkText.trim()));
|
|
21521
|
-
chunkLaneMs =
|
|
21725
|
+
chunkLaneMs = nowMs() - chunkStart;
|
|
21522
21726
|
}
|
|
21523
|
-
const fuseStart =
|
|
21727
|
+
const fuseStart = nowMs();
|
|
21524
21728
|
if (types.length === 1 || factResults.length === 0 || chunkResults.length === 0) {
|
|
21525
21729
|
const memories2 = [
|
|
21526
21730
|
...factResults.map((r) => toFactMemory(r, options.now)),
|
|
@@ -21528,7 +21732,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
21528
21732
|
];
|
|
21529
21733
|
memories2.sort((a, b) => b.score - a.score);
|
|
21530
21734
|
const candidateCount = factResults.length + chunkResults.length;
|
|
21531
|
-
fuseMs =
|
|
21735
|
+
fuseMs = nowMs() - fuseStart;
|
|
21532
21736
|
const admitted = memories2.slice(0, limit);
|
|
21533
21737
|
hitLimit = memories2.length > limit;
|
|
21534
21738
|
emitDiagnostics(candidateCount, admitted);
|
|
@@ -21592,7 +21796,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
21592
21796
|
memories = selection.out;
|
|
21593
21797
|
}
|
|
21594
21798
|
hitLimit = selection.cut;
|
|
21595
|
-
fuseMs =
|
|
21799
|
+
fuseMs = nowMs() - fuseStart;
|
|
21596
21800
|
emitDiagnostics(byId.size, memories);
|
|
21597
21801
|
return {
|
|
21598
21802
|
memories,
|
|
@@ -31612,28 +31816,6 @@ async function cleanupConversationSummary(database, conversationId) {
|
|
|
31612
31816
|
}
|
|
31613
31817
|
}
|
|
31614
31818
|
|
|
31615
|
-
// src/lib/db/chat/embeddingCache.ts
|
|
31616
|
-
var MaskScopedEmbeddingCache = class extends Map {
|
|
31617
|
-
constructor(inner, masked) {
|
|
31618
|
-
super();
|
|
31619
|
-
this.inner = inner;
|
|
31620
|
-
this.masked = masked;
|
|
31621
|
-
}
|
|
31622
|
-
key(text14) {
|
|
31623
|
-
return `${this.masked ? "m" : "r"}:${text14}`;
|
|
31624
|
-
}
|
|
31625
|
-
get(text14) {
|
|
31626
|
-
return this.inner.get(this.key(text14));
|
|
31627
|
-
}
|
|
31628
|
-
set(text14, value) {
|
|
31629
|
-
this.inner.set(this.key(text14), value);
|
|
31630
|
-
return this;
|
|
31631
|
-
}
|
|
31632
|
-
};
|
|
31633
|
-
function maskScopedEmbeddingCache(cache, masked) {
|
|
31634
|
-
return new MaskScopedEmbeddingCache(cache, masked);
|
|
31635
|
-
}
|
|
31636
|
-
|
|
31637
31819
|
// src/react/useChatStorage.ts
|
|
31638
31820
|
init_logger();
|
|
31639
31821
|
init_redactor();
|