@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.cjs
CHANGED
|
@@ -1566,6 +1566,7 @@ __export(index_exports, {
|
|
|
1566
1566
|
encryptDataBatch: () => encryptDataBatch,
|
|
1567
1567
|
encryptDataBytes: () => encryptDataBytes,
|
|
1568
1568
|
encryptDataWithKey: () => encryptDataWithKey,
|
|
1569
|
+
encryptToolCallEventsOp: () => encryptToolCallEventsOp,
|
|
1569
1570
|
ensureDefaultFoldersOp: () => ensureDefaultFoldersOp,
|
|
1570
1571
|
expandToolSetsAdditive: () => expandToolSetsAdditive,
|
|
1571
1572
|
exportElementToPdf: () => exportElementToPdf,
|
|
@@ -3584,6 +3585,35 @@ function decodeChunkVector(vector, onMalformed) {
|
|
|
3584
3585
|
}
|
|
3585
3586
|
}
|
|
3586
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
|
+
|
|
3587
3617
|
// src/lib/db/encryption-utils.ts
|
|
3588
3618
|
init_logger();
|
|
3589
3619
|
var ENCRYPTION_PREFIX = "enc:v3:";
|
|
@@ -3593,6 +3623,11 @@ function isEncrypted(value) {
|
|
|
3593
3623
|
const payload = value.slice(prefix.length);
|
|
3594
3624
|
return payload.length >= 56 && /^[0-9a-f]+$/i.test(payload);
|
|
3595
3625
|
}
|
|
3626
|
+
function hasEncryptedToolPayload(event) {
|
|
3627
|
+
return [event.arguments, event.output].some(
|
|
3628
|
+
(value) => typeof value === "string" && isEncrypted(value)
|
|
3629
|
+
);
|
|
3630
|
+
}
|
|
3596
3631
|
function detectEncryptionVersion(value) {
|
|
3597
3632
|
if (value.startsWith("enc:v3:")) {
|
|
3598
3633
|
return { version: "v3", encryptedData: value.slice("enc:v3:".length) };
|
|
@@ -3730,6 +3765,12 @@ async function encryptMessageFields(message, address, signMessage, embeddedWalle
|
|
|
3730
3765
|
const encryptedChunks = msg.chunks ? await encryptJsonField(msg.chunks, address, signMessage, embeddedWalletSigner, true) : void 0;
|
|
3731
3766
|
const encryptedSources = msg.sources ? await encryptJsonField(msg.sources, address, signMessage, embeddedWalletSigner, true) : void 0;
|
|
3732
3767
|
const encryptedThoughtProcess = msg.thoughtProcess ? await encryptJsonField(msg.thoughtProcess, address, signMessage, embeddedWalletSigner, true) : void 0;
|
|
3768
|
+
const encryptedToolCallEvents = Array.isArray(msg.toolCallEvents) ? await encryptToolCallEvents(
|
|
3769
|
+
msg.toolCallEvents,
|
|
3770
|
+
address,
|
|
3771
|
+
signMessage,
|
|
3772
|
+
embeddedWalletSigner
|
|
3773
|
+
) : void 0;
|
|
3733
3774
|
return {
|
|
3734
3775
|
...message,
|
|
3735
3776
|
...encryptedContent !== void 0 && { content: encryptedContent },
|
|
@@ -3737,13 +3778,31 @@ async function encryptMessageFields(message, address, signMessage, embeddedWalle
|
|
|
3737
3778
|
...encryptedVector !== void 0 && { vector: encryptedVector },
|
|
3738
3779
|
...encryptedChunks !== void 0 && { chunks: encryptedChunks },
|
|
3739
3780
|
...encryptedSources !== void 0 && { sources: encryptedSources },
|
|
3740
|
-
...encryptedThoughtProcess !== void 0 && { thoughtProcess: encryptedThoughtProcess }
|
|
3781
|
+
...encryptedThoughtProcess !== void 0 && { thoughtProcess: encryptedThoughtProcess },
|
|
3782
|
+
...encryptedToolCallEvents !== void 0 && { toolCallEvents: encryptedToolCallEvents }
|
|
3741
3783
|
};
|
|
3742
3784
|
} catch (error) {
|
|
3743
3785
|
getLogger().warn("Failed to encrypt message fields:", error);
|
|
3744
3786
|
throw error;
|
|
3745
3787
|
}
|
|
3746
3788
|
}
|
|
3789
|
+
function mapToolCallPayloads(events, transform) {
|
|
3790
|
+
return Promise.all(
|
|
3791
|
+
events.map(async (event) => {
|
|
3792
|
+
if (!event || typeof event !== "object") return event;
|
|
3793
|
+
const mapped = { ...event };
|
|
3794
|
+
if (typeof event.arguments === "string") mapped.arguments = await transform(event.arguments);
|
|
3795
|
+
if (typeof event.output === "string") mapped.output = await transform(event.output);
|
|
3796
|
+
return mapped;
|
|
3797
|
+
})
|
|
3798
|
+
);
|
|
3799
|
+
}
|
|
3800
|
+
function encryptToolCallEvents(events, address, signMessage, embeddedWalletSigner) {
|
|
3801
|
+
return mapToolCallPayloads(
|
|
3802
|
+
events,
|
|
3803
|
+
(value) => encryptField(value, address, signMessage, embeddedWalletSigner, true)
|
|
3804
|
+
);
|
|
3805
|
+
}
|
|
3747
3806
|
async function decryptMaybeJsonFieldDetailed(value, address) {
|
|
3748
3807
|
if (value === void 0) return { value: void 0, status: "plaintext" };
|
|
3749
3808
|
if (value === null) return { value, status: "plaintext" };
|
|
@@ -3829,6 +3888,10 @@ async function assembleDecryptedMessage(message, address) {
|
|
|
3829
3888
|
message.thoughtProcess,
|
|
3830
3889
|
address
|
|
3831
3890
|
);
|
|
3891
|
+
const toolCallEventsResult = await decryptMaybeJsonFieldDetailed(
|
|
3892
|
+
message.toolCallEvents,
|
|
3893
|
+
address
|
|
3894
|
+
);
|
|
3832
3895
|
let decryptionStatus;
|
|
3833
3896
|
let refreshProbe;
|
|
3834
3897
|
const consider = (status, probe) => {
|
|
@@ -3847,6 +3910,14 @@ async function assembleDecryptedMessage(message, address) {
|
|
|
3847
3910
|
if (thoughtProcessResult.probe) {
|
|
3848
3911
|
consider(thoughtProcessResult.status, thoughtProcessResult.probe);
|
|
3849
3912
|
}
|
|
3913
|
+
if (toolCallEventsResult.probe) {
|
|
3914
|
+
consider(toolCallEventsResult.status, toolCallEventsResult.probe);
|
|
3915
|
+
}
|
|
3916
|
+
const toolCallEvents = Array.isArray(toolCallEventsResult.value) ? await mapToolCallPayloads(toolCallEventsResult.value, async (value) => {
|
|
3917
|
+
const detailed = await decryptFieldDetailed(value, address);
|
|
3918
|
+
consider(detailed.status, isEncrypted(value) ? value : void 0);
|
|
3919
|
+
return detailed.value;
|
|
3920
|
+
}) : void 0;
|
|
3850
3921
|
const statusForConsumer = decryptionStatus === "ok" || decryptionStatus === "plaintext" || !decryptionStatus ? void 0 : decryptionStatus;
|
|
3851
3922
|
const result = {
|
|
3852
3923
|
...message,
|
|
@@ -3855,7 +3926,8 @@ async function assembleDecryptedMessage(message, address) {
|
|
|
3855
3926
|
vector: vectorResult.value,
|
|
3856
3927
|
chunks: chunksResult.value,
|
|
3857
3928
|
sources: sourcesResult.value,
|
|
3858
|
-
thoughtProcess: thoughtProcessResult.value
|
|
3929
|
+
thoughtProcess: thoughtProcessResult.value,
|
|
3930
|
+
toolCallEvents
|
|
3859
3931
|
};
|
|
3860
3932
|
if (statusForConsumer) {
|
|
3861
3933
|
result.decryptionStatus = statusForConsumer;
|
|
@@ -4649,7 +4721,7 @@ async function updateMessageChunksOp(ctx, uniqueId, chunks3, embeddingModel) {
|
|
|
4649
4721
|
});
|
|
4650
4722
|
return messageToStored(message, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
4651
4723
|
}
|
|
4652
|
-
var
|
|
4724
|
+
var RAW_REPAIR_PAGE_SIZE = 100;
|
|
4653
4725
|
function chunksWithoutText(raw) {
|
|
4654
4726
|
if (typeof raw !== "string") return null;
|
|
4655
4727
|
let parsed;
|
|
@@ -4672,8 +4744,8 @@ function chunksWithoutText(raw) {
|
|
|
4672
4744
|
async function stripLegacyChunkTextOp(ctx) {
|
|
4673
4745
|
const candidateIds = await ctx.messagesCollection.query(import_watermelondb2.Q.where("chunks", import_watermelondb2.Q.like(`%${import_watermelondb2.Q.sanitizeLikeString('"text":')}%`))).fetchIds();
|
|
4674
4746
|
let stripped = 0;
|
|
4675
|
-
for (let start = 0; start < candidateIds.length; start +=
|
|
4676
|
-
const pageIds = candidateIds.slice(start, start +
|
|
4747
|
+
for (let start = 0; start < candidateIds.length; start += RAW_REPAIR_PAGE_SIZE) {
|
|
4748
|
+
const pageIds = candidateIds.slice(start, start + RAW_REPAIR_PAGE_SIZE);
|
|
4677
4749
|
const rows = await ctx.messagesCollection.query(import_watermelondb2.Q.where("id", import_watermelondb2.Q.oneOf(pageIds))).unsafeFetchRaw();
|
|
4678
4750
|
const changedIds = rows.filter((row) => chunksWithoutText(row.chunks) !== null).map((row) => String(row.id));
|
|
4679
4751
|
if (changedIds.length === 0) continue;
|
|
@@ -4697,6 +4769,88 @@ async function stripLegacyChunkTextOp(ctx) {
|
|
|
4697
4769
|
}
|
|
4698
4770
|
return stripped;
|
|
4699
4771
|
}
|
|
4772
|
+
async function encryptedToolCallEventsColumn(raw, address, signMessage, embeddedWalletSigner) {
|
|
4773
|
+
if (typeof raw !== "string") return null;
|
|
4774
|
+
let parsed;
|
|
4775
|
+
try {
|
|
4776
|
+
parsed = JSON.parse(raw);
|
|
4777
|
+
} catch {
|
|
4778
|
+
return null;
|
|
4779
|
+
}
|
|
4780
|
+
if (!Array.isArray(parsed)) return null;
|
|
4781
|
+
const column = JSON.stringify(
|
|
4782
|
+
await encryptToolCallEvents(
|
|
4783
|
+
parsed,
|
|
4784
|
+
address,
|
|
4785
|
+
signMessage,
|
|
4786
|
+
embeddedWalletSigner
|
|
4787
|
+
)
|
|
4788
|
+
);
|
|
4789
|
+
return column === JSON.stringify(parsed) ? null : column;
|
|
4790
|
+
}
|
|
4791
|
+
async function encryptToolCallEventsOp(ctx) {
|
|
4792
|
+
const { walletAddress: address, signMessage, embeddedWalletSigner } = ctx;
|
|
4793
|
+
if (!address || !signMessage) return 0;
|
|
4794
|
+
if (!await requestEncryptionKey(address, signMessage, embeddedWalletSigner)) return 0;
|
|
4795
|
+
if (!hasEncryptionKey(address)) return 0;
|
|
4796
|
+
if (!await savedKeyOpensExistingData(ctx, address, signMessage, embeddedWalletSigner)) {
|
|
4797
|
+
return 0;
|
|
4798
|
+
}
|
|
4799
|
+
const candidateIds = await ctx.messagesCollection.query(
|
|
4800
|
+
import_watermelondb2.Q.where("tool_call_events", import_watermelondb2.Q.notEq(null)),
|
|
4801
|
+
import_watermelondb2.Q.where("tool_call_events", import_watermelondb2.Q.notIn(["", "[]"]))
|
|
4802
|
+
).fetchIds();
|
|
4803
|
+
let encrypted = 0;
|
|
4804
|
+
for (let start = 0; start < candidateIds.length; start += RAW_REPAIR_PAGE_SIZE) {
|
|
4805
|
+
const pageIds = candidateIds.slice(start, start + RAW_REPAIR_PAGE_SIZE);
|
|
4806
|
+
const rows = await ctx.messagesCollection.query(import_watermelondb2.Q.where("id", import_watermelondb2.Q.oneOf(pageIds))).unsafeFetchRaw();
|
|
4807
|
+
const repairs = /* @__PURE__ */ new Map();
|
|
4808
|
+
for (const row of rows) {
|
|
4809
|
+
const column = await encryptedToolCallEventsColumn(
|
|
4810
|
+
row.tool_call_events,
|
|
4811
|
+
address,
|
|
4812
|
+
signMessage,
|
|
4813
|
+
embeddedWalletSigner
|
|
4814
|
+
);
|
|
4815
|
+
if (column !== null) repairs.set(String(row.id), { raw: row.tool_call_events, column });
|
|
4816
|
+
}
|
|
4817
|
+
if (repairs.size === 0) continue;
|
|
4818
|
+
await ctx.database.write(async () => {
|
|
4819
|
+
const messages = (await ctx.messagesCollection.query(import_watermelondb2.Q.where("id", import_watermelondb2.Q.oneOf([...repairs.keys()]))).fetch()).filter(
|
|
4820
|
+
(message) => message._raw.tool_call_events === repairs.get(message.id)?.raw
|
|
4821
|
+
);
|
|
4822
|
+
if (messages.length === 0) return;
|
|
4823
|
+
const conversationIds = [...new Set(messages.map((message) => message.conversationId))];
|
|
4824
|
+
const conversations = await ctx.conversationsCollection.query(import_watermelondb2.Q.where("conversation_id", import_watermelondb2.Q.oneOf(conversationIds))).fetch();
|
|
4825
|
+
await ctx.database.batch(
|
|
4826
|
+
...messages.map(
|
|
4827
|
+
(message) => message.prepareUpdate((msg) => {
|
|
4828
|
+
msg._setRaw("tool_call_events", repairs.get(message.id).column);
|
|
4829
|
+
})
|
|
4830
|
+
),
|
|
4831
|
+
...conversations.map((conversation) => conversation.prepareUpdate(() => {
|
|
4832
|
+
}))
|
|
4833
|
+
);
|
|
4834
|
+
encrypted += messages.length;
|
|
4835
|
+
});
|
|
4836
|
+
}
|
|
4837
|
+
return encrypted;
|
|
4838
|
+
}
|
|
4839
|
+
async function savedKeyOpensExistingData(ctx, address, signMessage, embeddedWalletSigner) {
|
|
4840
|
+
const v3Probe = await findEncryptedContent(ctx, "enc:v3:%");
|
|
4841
|
+
if (v3Probe) {
|
|
4842
|
+
const { status } = await decryptFieldDetailed(v3Probe, address);
|
|
4843
|
+
if (status !== "auth_mismatch" && status !== "key_missing") return true;
|
|
4844
|
+
return refreshEncryptionKeyIfMatches(address, v3Probe, signMessage, embeddedWalletSigner);
|
|
4845
|
+
}
|
|
4846
|
+
const v2Probe = await findEncryptedContent(ctx, "enc:v2:%");
|
|
4847
|
+
if (!v2Probe) return true;
|
|
4848
|
+
return refreshEncryptionKeyIfMatches(address, v2Probe, signMessage, embeddedWalletSigner);
|
|
4849
|
+
}
|
|
4850
|
+
async function findEncryptedContent(ctx, pattern) {
|
|
4851
|
+
const [row] = await ctx.messagesCollection.query(import_watermelondb2.Q.where("content", import_watermelondb2.Q.like(pattern)), import_watermelondb2.Q.take(1)).unsafeFetchRaw();
|
|
4852
|
+
return row ? String(row.content) : null;
|
|
4853
|
+
}
|
|
4700
4854
|
async function updateMessageErrorOp(ctx, uniqueId, error) {
|
|
4701
4855
|
let message;
|
|
4702
4856
|
try {
|
|
@@ -4843,6 +4997,95 @@ async function searchMessagesOp(ctx, queryVector, options) {
|
|
|
4843
4997
|
})
|
|
4844
4998
|
);
|
|
4845
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
|
+
}
|
|
4846
5089
|
async function searchChunksOp(ctx, queryVector, options) {
|
|
4847
5090
|
const {
|
|
4848
5091
|
limit = 10,
|
|
@@ -4850,83 +5093,111 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
4850
5093
|
conversationId,
|
|
4851
5094
|
excludeConversationId,
|
|
4852
5095
|
embeddingModel,
|
|
4853
|
-
chunkCache
|
|
5096
|
+
chunkCache,
|
|
5097
|
+
onStats
|
|
4854
5098
|
} = options || {};
|
|
4855
|
-
const
|
|
4856
|
-
const
|
|
4857
|
-
activeConversations.map((c) => String(c._getRaw("conversation_id")))
|
|
4858
|
-
);
|
|
4859
|
-
const queryConditions = conversationId ? [import_watermelondb2.Q.where("conversation_id", conversationId)] : [];
|
|
4860
|
-
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);
|
|
4861
5101
|
const candidates = [];
|
|
4862
5102
|
let staleSkipped = 0;
|
|
4863
5103
|
let unreadableVectors = 0;
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
}
|
|
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;
|
|
4874
5113
|
}
|
|
4875
|
-
const
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
if (cached.chunks.length > 0) {
|
|
4879
|
-
for (let ci = 0; ci < cached.chunks.length; ci++) {
|
|
4880
|
-
const vec = cached.chunks[ci];
|
|
4881
|
-
if (vec.length === 0) continue;
|
|
4882
|
-
const similarity = cosineSimilarity(queryVector, vec);
|
|
4883
|
-
if (similarity >= minSimilarity) {
|
|
4884
|
-
candidates.push({
|
|
4885
|
-
message,
|
|
4886
|
-
similarity,
|
|
4887
|
-
chunkTextSource: { kind: "chunk-cached", chunkIndex: ci, version }
|
|
4888
|
-
});
|
|
4889
|
-
}
|
|
4890
|
-
}
|
|
4891
|
-
} else if (cached.fallback) {
|
|
4892
|
-
const similarity = cosineSimilarity(queryVector, cached.fallback);
|
|
4893
|
-
if (similarity >= minSimilarity) {
|
|
4894
|
-
candidates.push({ message, similarity, chunkTextSource: { kind: "message" } });
|
|
4895
|
-
}
|
|
4896
|
-
}
|
|
5114
|
+
const cached = chunkCache?.get(key.id);
|
|
5115
|
+
if (!cached || cached.version !== key.version) {
|
|
5116
|
+
missIds.push(key.id);
|
|
4897
5117
|
continue;
|
|
4898
5118
|
}
|
|
4899
|
-
|
|
4900
|
-
if (
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
unreadableVectors++;
|
|
4904
|
-
})
|
|
4905
|
-
);
|
|
4906
|
-
chunkCache?.set(message.id, { version, chunks: vectors });
|
|
4907
|
-
for (let ci = 0; ci < chunks3.length; ci++) {
|
|
4908
|
-
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];
|
|
4909
5123
|
if (vec.length === 0) continue;
|
|
4910
5124
|
const similarity = cosineSimilarity(queryVector, vec);
|
|
4911
5125
|
if (similarity >= minSimilarity) {
|
|
4912
5126
|
candidates.push({
|
|
4913
|
-
|
|
5127
|
+
id: key.id,
|
|
5128
|
+
version: key.version,
|
|
5129
|
+
order,
|
|
4914
5130
|
similarity,
|
|
4915
|
-
chunkTextSource: { kind: "chunk",
|
|
5131
|
+
chunkTextSource: { kind: "chunk-cached", chunkIndex: ci, version: key.version }
|
|
4916
5132
|
});
|
|
4917
5133
|
}
|
|
4918
5134
|
}
|
|
4919
|
-
} else {
|
|
4920
|
-
const
|
|
4921
|
-
if (!messageVector || messageVector.length === 0) continue;
|
|
4922
|
-
const fallback = Float32Array.from(messageVector);
|
|
4923
|
-
chunkCache?.set(message.id, { version, chunks: [], fallback });
|
|
4924
|
-
const similarity = cosineSimilarity(queryVector, fallback);
|
|
5135
|
+
} else if (cached.fallback) {
|
|
5136
|
+
const similarity = cosineSimilarity(queryVector, cached.fallback);
|
|
4925
5137
|
if (similarity >= minSimilarity) {
|
|
4926
|
-
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
|
+
}
|
|
4927
5197
|
}
|
|
4928
5198
|
}
|
|
4929
5199
|
}
|
|
5200
|
+
onStats?.({ rowsScanned: source.keys.length, rowsFetched, cacheHits });
|
|
4930
5201
|
if (staleSkipped > 0) {
|
|
4931
5202
|
getLogger().warn(
|
|
4932
5203
|
`searchChunksOp: skipped ${staleSkipped} messages whose embedding model differs from the current model (${embeddingModel}) \u2014 re-embed via chunkAndEmbedAllMessages`
|
|
@@ -4937,12 +5208,17 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
4937
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`
|
|
4938
5209
|
);
|
|
4939
5210
|
}
|
|
4940
|
-
const topK = candidates.sort((a, b) => b.similarity - a.similarity).slice(0, limit);
|
|
4941
|
-
const
|
|
4942
|
-
|
|
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
|
+
});
|
|
4943
5219
|
const storedById = new Map(
|
|
4944
5220
|
await Promise.all(
|
|
4945
|
-
Array.from(
|
|
5221
|
+
Array.from(rowById, async ([id, m]) => {
|
|
4946
5222
|
const stored2 = await messageRawToStored(
|
|
4947
5223
|
m,
|
|
4948
5224
|
ctx.walletAddress,
|
|
@@ -4955,24 +5231,24 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
4955
5231
|
);
|
|
4956
5232
|
const chunkStateByMsgId = /* @__PURE__ */ new Map();
|
|
4957
5233
|
const needsChunkText = /* @__PURE__ */ new Set();
|
|
4958
|
-
for (const c of
|
|
4959
|
-
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);
|
|
4960
5236
|
}
|
|
4961
5237
|
await Promise.all(
|
|
4962
5238
|
Array.from(needsChunkText, async (id) => {
|
|
4963
|
-
const m =
|
|
5239
|
+
const m = rowById.get(id);
|
|
4964
5240
|
const parsed = await readRawJsonField(m, "chunks", ctx.walletAddress);
|
|
4965
5241
|
const version = Number(m.updated_at) || 0;
|
|
4966
5242
|
if (parsed) chunkStateByMsgId.set(id, { version, chunks: parsed });
|
|
4967
5243
|
})
|
|
4968
5244
|
);
|
|
4969
|
-
return
|
|
4970
|
-
const stored2 = { ...storedById.get(
|
|
5245
|
+
return liveTopK.map(({ id, similarity, chunkTextSource }) => {
|
|
5246
|
+
const stored2 = { ...storedById.get(id) };
|
|
4971
5247
|
let chunkText2;
|
|
4972
5248
|
if (chunkTextSource.kind === "chunk") {
|
|
4973
5249
|
chunkText2 = resolveChunkText(stored2.content, chunkTextSource.chunk, chunkTextSource.siblings);
|
|
4974
5250
|
} else if (chunkTextSource.kind === "chunk-cached") {
|
|
4975
|
-
const state = chunkStateByMsgId.get(
|
|
5251
|
+
const state = chunkStateByMsgId.get(id);
|
|
4976
5252
|
const chunk = state && state.version === chunkTextSource.version ? state.chunks[chunkTextSource.chunkIndex] : void 0;
|
|
4977
5253
|
chunkText2 = resolveChunkText(stored2.content, chunk, state?.chunks);
|
|
4978
5254
|
} else {
|
|
@@ -6132,13 +6408,35 @@ async function generateEmbedding(text14, options) {
|
|
|
6132
6408
|
if (total === void 0) return embedOne(text14, options, void 0);
|
|
6133
6409
|
return withDeadline((signal) => embedOne(text14, options, signal), total, "embedding");
|
|
6134
6410
|
}
|
|
6411
|
+
var inFlightByCache = /* @__PURE__ */ new WeakMap();
|
|
6135
6412
|
async function embedOne(text14, options, outer) {
|
|
6136
|
-
const {
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
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
|
+
}
|
|
6141
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);
|
|
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;
|
|
6142
6440
|
const headers = {
|
|
6143
6441
|
...await resolveAuthHeaders(options, outer),
|
|
6144
6442
|
...taskTypeHeader(options.taskType)
|
|
@@ -6173,11 +6471,7 @@ async function embedOne(text14, options, outer) {
|
|
|
6173
6471
|
totalTokens: response.data.usage.total_tokens ?? 0
|
|
6174
6472
|
});
|
|
6175
6473
|
}
|
|
6176
|
-
|
|
6177
|
-
if (cache) {
|
|
6178
|
-
cache.set(text14, f32Embedding);
|
|
6179
|
-
}
|
|
6180
|
-
return Array.from(f32Embedding);
|
|
6474
|
+
return Float32Array.from(embedding2);
|
|
6181
6475
|
}
|
|
6182
6476
|
var DEFAULT_EMBEDDING_BATCH_SIZE = 100;
|
|
6183
6477
|
var DEFAULT_EMBEDDING_BATCH_CONCURRENCY = 3;
|
|
@@ -6575,7 +6869,8 @@ function extractReservationReceipts(toolCallEvents) {
|
|
|
6575
6869
|
for (const event of toolCallEvents ?? []) {
|
|
6576
6870
|
const action = ACTIONS.find((a) => event.name?.endsWith(a.tool));
|
|
6577
6871
|
const output = event.output ?? "";
|
|
6578
|
-
if (!action || !output || NOT_AN_ATTEMPT.test(output))
|
|
6872
|
+
if (!action || !output || hasEncryptedToolPayload(event) || NOT_AN_ATTEMPT.test(output))
|
|
6873
|
+
continue;
|
|
6579
6874
|
const kept = latest.get(action.kind)?.status;
|
|
6580
6875
|
if (kept === "made") continue;
|
|
6581
6876
|
const receipt = toReceipt(action, event.arguments ?? "", output);
|
|
@@ -17493,9 +17788,9 @@ function recencyMultiplier(updatedAt, opts = {}) {
|
|
|
17493
17788
|
const updatedMs = updatedAt.getTime();
|
|
17494
17789
|
if (!Number.isFinite(updatedMs)) return noDate;
|
|
17495
17790
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
17496
|
-
const
|
|
17497
|
-
if (!Number.isFinite(
|
|
17498
|
-
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);
|
|
17499
17794
|
const perYearDecay = opts.perYearDecay ?? DEFAULT_PER_YEAR_DECAY;
|
|
17500
17795
|
const floor = opts.floor ?? DEFAULT_FLOOR;
|
|
17501
17796
|
const decay = perYearDecay * (ageDays2 / 365);
|
|
@@ -18007,9 +18302,6 @@ function createVaultEmbeddingCache(maxSize = DEFAULT_VAULT_CACHE_SIZE) {
|
|
|
18007
18302
|
|
|
18008
18303
|
// src/lib/memoryVault/searchTool.ts
|
|
18009
18304
|
var DEFAULT_RERANK_TOP_N = 5;
|
|
18010
|
-
function nowMs() {
|
|
18011
|
-
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
18012
|
-
}
|
|
18013
18305
|
var warnedProgrammaticDecomposeIgnored = false;
|
|
18014
18306
|
function normalizeEventTimeKind(kind) {
|
|
18015
18307
|
return kind === "point" || kind === "range" || kind === "ongoing" ? kind : null;
|
|
@@ -20911,6 +21203,32 @@ function rankProfileCandidates(inputs, now = Date.now(), options = {}) {
|
|
|
20911
21203
|
return ranked;
|
|
20912
21204
|
}
|
|
20913
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
|
+
|
|
20914
21232
|
// src/lib/memory/recall.ts
|
|
20915
21233
|
init_logger();
|
|
20916
21234
|
|
|
@@ -21121,9 +21439,6 @@ function scoreEventTimeOverlap(memoryStart, memoryEnd, memoryKind, window2) {
|
|
|
21121
21439
|
var DEFAULT_LIMIT = 8;
|
|
21122
21440
|
var DEFAULT_BUDGET = "low";
|
|
21123
21441
|
var DEFAULT_FACT_MIN_SCORE = 0.1;
|
|
21124
|
-
function nowMs2() {
|
|
21125
|
-
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
21126
|
-
}
|
|
21127
21442
|
var DEFAULT_CHUNK_MIN_SCORE = 0.5;
|
|
21128
21443
|
var DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS = 8e3;
|
|
21129
21444
|
function flagsForBudget(budget) {
|
|
@@ -21161,12 +21476,19 @@ async function recall(query, ctx, options = {}) {
|
|
|
21161
21476
|
const subQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
21162
21477
|
const embeddingOptions = {
|
|
21163
21478
|
...ctx.embeddingOptions,
|
|
21164
|
-
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
|
+
}
|
|
21165
21486
|
};
|
|
21166
|
-
const t0 =
|
|
21487
|
+
const t0 = nowMs();
|
|
21167
21488
|
let prepMs = 0;
|
|
21168
21489
|
let factLaneMs = 0;
|
|
21169
21490
|
let chunkLaneMs = 0;
|
|
21491
|
+
let chunkStats;
|
|
21170
21492
|
let fuseMs = 0;
|
|
21171
21493
|
const factResults = [];
|
|
21172
21494
|
const chunkResults = [];
|
|
@@ -21221,6 +21543,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
21221
21543
|
...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
|
|
21222
21544
|
...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
|
|
21223
21545
|
...vaultRowsEmbedded !== void 0 && { vaultRowsEmbedded },
|
|
21546
|
+
...chunkStats && {
|
|
21547
|
+
chunkRowsScanned: chunkStats.rowsScanned,
|
|
21548
|
+
chunkRowsFetched: chunkStats.rowsFetched,
|
|
21549
|
+
chunkCacheHits: chunkStats.cacheHits
|
|
21550
|
+
},
|
|
21224
21551
|
factCount: factResults.length,
|
|
21225
21552
|
chunkCount: chunkResults.length,
|
|
21226
21553
|
admittedCount: admitted.length,
|
|
@@ -21232,7 +21559,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
21232
21559
|
temporalLaneCount,
|
|
21233
21560
|
emptyReason: emptyReasonFor(admitted.length, laneRan),
|
|
21234
21561
|
timings: {
|
|
21235
|
-
total:
|
|
21562
|
+
total: nowMs() - t0,
|
|
21236
21563
|
prep: prepMs,
|
|
21237
21564
|
factLane: factLaneMs,
|
|
21238
21565
|
rerank: rerankMs,
|
|
@@ -21254,14 +21581,14 @@ async function recall(query, ctx, options = {}) {
|
|
|
21254
21581
|
const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
|
|
21255
21582
|
const wantsTemporal = types.includes("fact") && (ctx.factSource || ctx.vaultCtx);
|
|
21256
21583
|
const queryEmbedTotalTimeoutMs = options.queryEmbedTotalTimeoutMs ?? DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS;
|
|
21257
|
-
const prepStart =
|
|
21584
|
+
const prepStart = nowMs();
|
|
21258
21585
|
let sharedEmbedMs = 0;
|
|
21259
21586
|
const [queryEmbedding, entityRanking, temporalRanking] = await Promise.all([
|
|
21260
21587
|
needsChunkEmbedding ? generateEmbedding(query, {
|
|
21261
21588
|
...embeddingOptions,
|
|
21262
21589
|
totalTimeoutMs: queryEmbedTotalTimeoutMs
|
|
21263
21590
|
}).finally(() => {
|
|
21264
|
-
sharedEmbedMs =
|
|
21591
|
+
sharedEmbedMs = nowMs() - prepStart;
|
|
21265
21592
|
}).then((vec) => {
|
|
21266
21593
|
if (vec.length === 0) {
|
|
21267
21594
|
getLogger().warn(
|
|
@@ -21294,11 +21621,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
21294
21621
|
() => ctx.factSource ? ctx.factSource.temporalRanking(query, options.now) : buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
|
|
21295
21622
|
) : Promise.resolve([])
|
|
21296
21623
|
]);
|
|
21297
|
-
prepMs =
|
|
21624
|
+
prepMs = nowMs() - prepStart;
|
|
21298
21625
|
graphLaneCount = entityRanking.length;
|
|
21299
21626
|
temporalLaneCount = temporalRanking.length;
|
|
21300
21627
|
if (types.includes("fact") && (ctx.factSource || ctx.vaultCtx && ctx.vaultCache)) {
|
|
21301
|
-
const factStart =
|
|
21628
|
+
const factStart = nowMs();
|
|
21302
21629
|
const vaultMinScore = options.minScore ?? DEFAULT_FACT_MIN_SCORE;
|
|
21303
21630
|
factFloor = vaultMinScore;
|
|
21304
21631
|
const {
|
|
@@ -21374,11 +21701,11 @@ async function recall(query, ctx, options = {}) {
|
|
|
21374
21701
|
factLaneRankedOnCosine = factRankedOnCosine;
|
|
21375
21702
|
decryptLastRan = factDecryptLast;
|
|
21376
21703
|
vaultRowsDecrypted = factRowsDecrypted;
|
|
21377
|
-
factLaneMs =
|
|
21704
|
+
factLaneMs = nowMs() - factStart;
|
|
21378
21705
|
}
|
|
21379
21706
|
if (chunkEmbedFailed && !factLaneRankedOnCosine) embeddingsUnavailable = true;
|
|
21380
21707
|
if (types.includes("chunk") && ctx.storageCtx && queryEmbedding) {
|
|
21381
|
-
const chunkStart =
|
|
21708
|
+
const chunkStart = nowMs();
|
|
21382
21709
|
const chunkMinScore = options.minScore ?? DEFAULT_CHUNK_MIN_SCORE;
|
|
21383
21710
|
chunkFloor = chunkMinScore;
|
|
21384
21711
|
const results = await searchChunksOp(ctx.storageCtx, queryEmbedding, {
|
|
@@ -21389,12 +21716,15 @@ async function recall(query, ctx, options = {}) {
|
|
|
21389
21716
|
...options.excludeConversationId && {
|
|
21390
21717
|
excludeConversationId: options.excludeConversationId
|
|
21391
21718
|
},
|
|
21392
|
-
...ctx.chunkCache && { chunkCache: ctx.chunkCache }
|
|
21719
|
+
...ctx.chunkCache && { chunkCache: ctx.chunkCache },
|
|
21720
|
+
onStats: (stats) => {
|
|
21721
|
+
chunkStats = stats;
|
|
21722
|
+
}
|
|
21393
21723
|
});
|
|
21394
21724
|
chunkResults.push(...dedupeBy(results, (r) => r.chunkText.trim()));
|
|
21395
|
-
chunkLaneMs =
|
|
21725
|
+
chunkLaneMs = nowMs() - chunkStart;
|
|
21396
21726
|
}
|
|
21397
|
-
const fuseStart =
|
|
21727
|
+
const fuseStart = nowMs();
|
|
21398
21728
|
if (types.length === 1 || factResults.length === 0 || chunkResults.length === 0) {
|
|
21399
21729
|
const memories2 = [
|
|
21400
21730
|
...factResults.map((r) => toFactMemory(r, options.now)),
|
|
@@ -21402,7 +21732,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
21402
21732
|
];
|
|
21403
21733
|
memories2.sort((a, b) => b.score - a.score);
|
|
21404
21734
|
const candidateCount = factResults.length + chunkResults.length;
|
|
21405
|
-
fuseMs =
|
|
21735
|
+
fuseMs = nowMs() - fuseStart;
|
|
21406
21736
|
const admitted = memories2.slice(0, limit);
|
|
21407
21737
|
hitLimit = memories2.length > limit;
|
|
21408
21738
|
emitDiagnostics(candidateCount, admitted);
|
|
@@ -21466,7 +21796,7 @@ async function recall(query, ctx, options = {}) {
|
|
|
21466
21796
|
memories = selection.out;
|
|
21467
21797
|
}
|
|
21468
21798
|
hitLimit = selection.cut;
|
|
21469
|
-
fuseMs =
|
|
21799
|
+
fuseMs = nowMs() - fuseStart;
|
|
21470
21800
|
emitDiagnostics(byId.size, memories);
|
|
21471
21801
|
return {
|
|
21472
21802
|
memories,
|
|
@@ -31486,28 +31816,6 @@ async function cleanupConversationSummary(database, conversationId) {
|
|
|
31486
31816
|
}
|
|
31487
31817
|
}
|
|
31488
31818
|
|
|
31489
|
-
// src/lib/db/chat/embeddingCache.ts
|
|
31490
|
-
var MaskScopedEmbeddingCache = class extends Map {
|
|
31491
|
-
constructor(inner, masked) {
|
|
31492
|
-
super();
|
|
31493
|
-
this.inner = inner;
|
|
31494
|
-
this.masked = masked;
|
|
31495
|
-
}
|
|
31496
|
-
key(text14) {
|
|
31497
|
-
return `${this.masked ? "m" : "r"}:${text14}`;
|
|
31498
|
-
}
|
|
31499
|
-
get(text14) {
|
|
31500
|
-
return this.inner.get(this.key(text14));
|
|
31501
|
-
}
|
|
31502
|
-
set(text14, value) {
|
|
31503
|
-
this.inner.set(this.key(text14), value);
|
|
31504
|
-
return this;
|
|
31505
|
-
}
|
|
31506
|
-
};
|
|
31507
|
-
function maskScopedEmbeddingCache(cache, masked) {
|
|
31508
|
-
return new MaskScopedEmbeddingCache(cache, masked);
|
|
31509
|
-
}
|
|
31510
|
-
|
|
31511
31819
|
// src/react/useChatStorage.ts
|
|
31512
31820
|
init_logger();
|
|
31513
31821
|
init_redactor();
|
|
@@ -32041,11 +32349,12 @@ async function storedToLlmapiMessage(stored2, encryptionKey, resolveMediaByIds)
|
|
|
32041
32349
|
textContent = textContent.replace(/\n{3,}/g, "\n\n").trim();
|
|
32042
32350
|
const content = [{ type: "text", text: textContent }, ...imageParts];
|
|
32043
32351
|
const messages = [];
|
|
32044
|
-
|
|
32352
|
+
const toolCallEvents = Array.isArray(stored2.toolCallEvents) ? stored2.toolCallEvents.filter((event) => !hasEncryptedToolPayload(event)) : [];
|
|
32353
|
+
if (stored2.role === "assistant" && toolCallEvents.length) {
|
|
32045
32354
|
messages.push({
|
|
32046
32355
|
role: stored2.role,
|
|
32047
32356
|
content: void 0,
|
|
32048
|
-
tool_calls:
|
|
32357
|
+
tool_calls: toolCallEvents.map((event) => ({
|
|
32049
32358
|
id: event.id,
|
|
32050
32359
|
type: "function",
|
|
32051
32360
|
function: {
|
|
@@ -32054,7 +32363,7 @@ async function storedToLlmapiMessage(stored2, encryptionKey, resolveMediaByIds)
|
|
|
32054
32363
|
}
|
|
32055
32364
|
}))
|
|
32056
32365
|
});
|
|
32057
|
-
for (const event of
|
|
32366
|
+
for (const event of toolCallEvents) {
|
|
32058
32367
|
if (event.id && event.output !== void 0 && event.output !== null) {
|
|
32059
32368
|
messages.push({
|
|
32060
32369
|
role: "tool",
|
|
@@ -37042,6 +37351,7 @@ function useWalletBinding(options = {}) {
|
|
|
37042
37351
|
encryptDataBatch,
|
|
37043
37352
|
encryptDataBytes,
|
|
37044
37353
|
encryptDataWithKey,
|
|
37354
|
+
encryptToolCallEventsOp,
|
|
37045
37355
|
ensureDefaultFoldersOp,
|
|
37046
37356
|
expandToolSetsAdditive,
|
|
37047
37357
|
exportElementToPdf,
|