@anuma/sdk 10.1.0 → 10.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/expo/index.cjs +612 -524
- package/dist/expo/index.d.mts +3706 -3698
- package/dist/expo/index.d.ts +3706 -3698
- package/dist/expo/index.mjs +612 -525
- package/dist/react/index.cjs +611 -523
- package/dist/react/index.d.mts +4114 -4106
- package/dist/react/index.d.ts +4114 -4106
- package/dist/react/index.mjs +611 -524
- package/dist/server/index.cjs +50 -13
- package/dist/server/index.d.mts +2 -2
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.mjs +49 -13
- package/package.json +1 -1
package/dist/expo/index.mjs
CHANGED
|
@@ -9780,17 +9780,18 @@ var xhrTransport = (options) => {
|
|
|
9780
9780
|
|
|
9781
9781
|
// src/lib/db/chat/summaryOperations.ts
|
|
9782
9782
|
import { Q as Q3 } from "@nozbe/watermelondb";
|
|
9783
|
-
function createSummaryContext(database) {
|
|
9783
|
+
function createSummaryContext(database, encryption = {}) {
|
|
9784
9784
|
return {
|
|
9785
|
+
...encryption,
|
|
9785
9786
|
database,
|
|
9786
9787
|
summariesCollection: database.get("conversation_summaries")
|
|
9787
9788
|
};
|
|
9788
9789
|
}
|
|
9789
|
-
function modelToStored(record2) {
|
|
9790
|
+
function modelToStored(record2, summary) {
|
|
9790
9791
|
return {
|
|
9791
9792
|
uniqueId: record2.id,
|
|
9792
9793
|
conversationId: record2.conversationId,
|
|
9793
|
-
summary
|
|
9794
|
+
summary,
|
|
9794
9795
|
summarizedUpTo: record2.summarizedUpTo,
|
|
9795
9796
|
tokenCount: record2.tokenCount,
|
|
9796
9797
|
createdAt: record2.createdAt,
|
|
@@ -9800,28 +9801,62 @@ function modelToStored(record2) {
|
|
|
9800
9801
|
async function getConversationSummaryOp(ctx, conversationId) {
|
|
9801
9802
|
const results = await ctx.summariesCollection.query(Q3.where("conversation_id", conversationId)).fetch();
|
|
9802
9803
|
if (results.length === 0) return null;
|
|
9803
|
-
|
|
9804
|
+
const record2 = results[0];
|
|
9805
|
+
const stored2 = modelToStored(record2, record2.summary);
|
|
9806
|
+
if (ctx.walletAddress && isEncrypted(stored2.summary)) {
|
|
9807
|
+
if (ctx.signMessage) {
|
|
9808
|
+
try {
|
|
9809
|
+
await requestEncryptionKey(ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
9810
|
+
} catch (error) {
|
|
9811
|
+
getLogger().warn("Failed to request the encryption key for the summary:", error);
|
|
9812
|
+
}
|
|
9813
|
+
}
|
|
9814
|
+
stored2.summary = await decryptField(stored2.summary, ctx.walletAddress);
|
|
9815
|
+
} else if (ctx.walletAddress && ctx.signMessage && stored2.summary) {
|
|
9816
|
+
try {
|
|
9817
|
+
const encryptedSummary = await encryptField(
|
|
9818
|
+
stored2.summary,
|
|
9819
|
+
ctx.walletAddress,
|
|
9820
|
+
ctx.signMessage,
|
|
9821
|
+
ctx.embeddedWalletSigner
|
|
9822
|
+
);
|
|
9823
|
+
await ctx.database.write(async () => {
|
|
9824
|
+
const current = await ctx.summariesCollection.query(Q3.where("id", record2.id)).fetch();
|
|
9825
|
+
if (current[0]?.summary === stored2.summary) {
|
|
9826
|
+
await current[0].update((rec) => {
|
|
9827
|
+
rec.summary = encryptedSummary;
|
|
9828
|
+
});
|
|
9829
|
+
}
|
|
9830
|
+
});
|
|
9831
|
+
} catch (error) {
|
|
9832
|
+
getLogger().warn("Failed to encrypt the legacy summary:", error);
|
|
9833
|
+
}
|
|
9834
|
+
}
|
|
9835
|
+
return stored2;
|
|
9804
9836
|
}
|
|
9805
9837
|
async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
|
|
9838
|
+
const revision2 = getConversationRevision(ctx.database, conversationId);
|
|
9806
9839
|
let record2;
|
|
9840
|
+
const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
|
|
9807
9841
|
await ctx.database.write(async () => {
|
|
9842
|
+
assertConversationRevision(ctx.database, conversationId, revision2);
|
|
9808
9843
|
const existing = await ctx.summariesCollection.query(Q3.where("conversation_id", conversationId)).fetch();
|
|
9809
9844
|
if (existing.length > 0) {
|
|
9810
9845
|
record2 = await existing[0].update((rec) => {
|
|
9811
|
-
rec.summary =
|
|
9846
|
+
rec.summary = encryptedSummary;
|
|
9812
9847
|
rec.summarizedUpTo = summarizedUpTo;
|
|
9813
9848
|
rec.tokenCount = tokenCount;
|
|
9814
9849
|
});
|
|
9815
9850
|
} else {
|
|
9816
9851
|
record2 = await ctx.summariesCollection.create((rec) => {
|
|
9817
9852
|
rec.conversationId = conversationId;
|
|
9818
|
-
rec.summary =
|
|
9853
|
+
rec.summary = encryptedSummary;
|
|
9819
9854
|
rec.summarizedUpTo = summarizedUpTo;
|
|
9820
9855
|
rec.tokenCount = tokenCount;
|
|
9821
9856
|
});
|
|
9822
9857
|
}
|
|
9823
9858
|
});
|
|
9824
|
-
return modelToStored(record2);
|
|
9859
|
+
return modelToStored(record2, summary);
|
|
9825
9860
|
}
|
|
9826
9861
|
async function deleteConversationSummaryOp(ctx, conversationId) {
|
|
9827
9862
|
await ctx.database.write(async () => {
|
|
@@ -9943,95 +9978,364 @@ async function clearConversationMemoriesOp(ctx, conversationId) {
|
|
|
9943
9978
|
});
|
|
9944
9979
|
}
|
|
9945
9980
|
|
|
9946
|
-
// src/lib/
|
|
9947
|
-
var
|
|
9948
|
-
|
|
9949
|
-
|
|
9950
|
-
|
|
9951
|
-
|
|
9952
|
-
|
|
9953
|
-
|
|
9954
|
-
|
|
9955
|
-
|
|
9956
|
-
|
|
9957
|
-
function normalizeEntityName(name) {
|
|
9958
|
-
return name.trim().toLowerCase();
|
|
9981
|
+
// src/lib/chatStore/vaultRecords.ts
|
|
9982
|
+
var PINNED_SORT_BASE = 2 ** 51;
|
|
9983
|
+
var recordBudgetBytes = 104e4;
|
|
9984
|
+
var storedDims = 1536;
|
|
9985
|
+
var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
|
|
9986
|
+
var maxChunks = 16;
|
|
9987
|
+
var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
|
|
9988
|
+
var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
|
|
9989
|
+
var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
|
|
9990
|
+
function plain(value) {
|
|
9991
|
+
return JSON.parse(JSON.stringify(value ?? {}));
|
|
9959
9992
|
}
|
|
9960
|
-
|
|
9961
|
-
|
|
9962
|
-
return topic2.source === "user" ? 1 : topic2.weight ?? 1;
|
|
9993
|
+
function text4(value) {
|
|
9994
|
+
return typeof value === "string" ? value : void 0;
|
|
9963
9995
|
}
|
|
9964
|
-
function
|
|
9965
|
-
|
|
9966
|
-
|
|
9967
|
-
|
|
9996
|
+
function number(value) {
|
|
9997
|
+
return typeof value === "number" ? value : void 0;
|
|
9998
|
+
}
|
|
9999
|
+
function conversationSortKey(data, createdAt) {
|
|
10000
|
+
const pinnedAt = number(data.pinnedAt);
|
|
10001
|
+
if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
|
|
10002
|
+
return number(data.lastActivityAt) ?? createdAt;
|
|
10003
|
+
}
|
|
10004
|
+
function toConversation(record2) {
|
|
10005
|
+
const pinnedAt = number(record2.data.pinnedAt);
|
|
10006
|
+
const projectId = text4(record2.data.projectId);
|
|
10007
|
+
return {
|
|
10008
|
+
uniqueId: record2.id,
|
|
10009
|
+
conversationId: record2.id,
|
|
10010
|
+
title: text4(record2.data.title) ?? "",
|
|
10011
|
+
...projectId ? { projectId } : {},
|
|
10012
|
+
createdAt: new Date(record2.createdAt),
|
|
10013
|
+
updatedAt: new Date(record2.updatedAt),
|
|
10014
|
+
isDeleted: record2.isDeleted,
|
|
10015
|
+
pinnedAt: pinnedAt ? new Date(pinnedAt) : null
|
|
10016
|
+
};
|
|
10017
|
+
}
|
|
10018
|
+
function messageData(options) {
|
|
10019
|
+
return plain(
|
|
10020
|
+
Object.fromEntries(
|
|
10021
|
+
Object.entries(options).filter(
|
|
10022
|
+
([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
|
|
10023
|
+
)
|
|
10024
|
+
)
|
|
10025
|
+
);
|
|
10026
|
+
}
|
|
10027
|
+
function toMessage(record2) {
|
|
10028
|
+
const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
|
|
10029
|
+
return {
|
|
10030
|
+
...fields,
|
|
10031
|
+
uniqueId: record2.id,
|
|
10032
|
+
messageId: record2.sortKey,
|
|
10033
|
+
conversationId: record2.conversationId,
|
|
10034
|
+
createdAt: new Date(record2.createdAt),
|
|
10035
|
+
updatedAt: new Date(record2.updatedAt)
|
|
10036
|
+
};
|
|
10037
|
+
}
|
|
10038
|
+
function chunkOffsets(record2) {
|
|
10039
|
+
const offsets = record2.data.chunkOffsets;
|
|
10040
|
+
return Array.isArray(offsets) ? offsets : void 0;
|
|
10041
|
+
}
|
|
10042
|
+
function toSkeletons(records) {
|
|
10043
|
+
const roleById = new Map(records.map((r) => [r.id, text4(r.data.role)]));
|
|
10044
|
+
return records.map((r) => {
|
|
10045
|
+
const parentMessageId = text4(r.data.parentMessageId);
|
|
10046
|
+
const model = text4(r.data.model);
|
|
10047
|
+
const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
|
|
10048
|
+
return {
|
|
10049
|
+
uniqueId: r.id,
|
|
10050
|
+
messageId: r.sortKey,
|
|
10051
|
+
conversationId: r.conversationId,
|
|
10052
|
+
role: text4(r.data.role) ?? "",
|
|
10053
|
+
createdAt: new Date(r.createdAt),
|
|
10054
|
+
...parentMessageId ? { parentMessageId } : {},
|
|
10055
|
+
...model ? { model } : {},
|
|
10056
|
+
...artifact ? { content: text4(r.data.content) ?? "" } : {}
|
|
10057
|
+
};
|
|
10058
|
+
});
|
|
10059
|
+
}
|
|
10060
|
+
function toSummary(record2) {
|
|
10061
|
+
return {
|
|
10062
|
+
uniqueId: record2.id,
|
|
10063
|
+
conversationId: record2.id,
|
|
10064
|
+
summary: text4(record2.data.summary) ?? "",
|
|
10065
|
+
summarizedUpTo: text4(record2.data.summarizedUpTo) ?? "",
|
|
10066
|
+
tokenCount: number(record2.data.tokenCount) ?? 0,
|
|
10067
|
+
createdAt: new Date(record2.createdAt),
|
|
10068
|
+
updatedAt: new Date(record2.updatedAt)
|
|
10069
|
+
};
|
|
10070
|
+
}
|
|
10071
|
+
function links(data) {
|
|
10072
|
+
return Array.isArray(data.links) ? data.links : [];
|
|
10073
|
+
}
|
|
10074
|
+
function applyLinkOps(data, ops) {
|
|
10075
|
+
let current = links(data);
|
|
10076
|
+
for (const op of ops) {
|
|
10077
|
+
if ("clear" in op) {
|
|
10078
|
+
current = [];
|
|
10079
|
+
continue;
|
|
10080
|
+
}
|
|
10081
|
+
const byId = new Map(current.map((l) => [l.memoryId, l]));
|
|
10082
|
+
const turn = /* @__PURE__ */ new Set();
|
|
10083
|
+
op.add.forEach((item, i) => {
|
|
10084
|
+
if (!item.memoryId || turn.has(item.memoryId)) return;
|
|
10085
|
+
turn.add(item.memoryId);
|
|
10086
|
+
const known = byId.get(item.memoryId);
|
|
10087
|
+
if (known && known.createdAt >= op.at + i) return;
|
|
10088
|
+
byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
|
|
10089
|
+
});
|
|
10090
|
+
current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
|
|
9968
10091
|
}
|
|
9969
|
-
return
|
|
10092
|
+
return plain({ links: current });
|
|
9970
10093
|
}
|
|
9971
|
-
function
|
|
9972
|
-
return
|
|
10094
|
+
function toLinks(record2) {
|
|
10095
|
+
return links(record2.data).map((l) => ({
|
|
10096
|
+
uniqueId: `${record2.id}:${l.memoryId}`,
|
|
10097
|
+
conversationId: record2.id,
|
|
10098
|
+
memoryId: l.memoryId,
|
|
10099
|
+
score: l.score,
|
|
10100
|
+
createdAt: new Date(l.createdAt)
|
|
10101
|
+
}));
|
|
9973
10102
|
}
|
|
9974
|
-
function
|
|
9975
|
-
return JSON.stringify(
|
|
10103
|
+
function bytes(value) {
|
|
10104
|
+
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
9976
10105
|
}
|
|
9977
|
-
function
|
|
9978
|
-
if (
|
|
9979
|
-
|
|
9980
|
-
|
|
9981
|
-
|
|
9982
|
-
|
|
9983
|
-
|
|
10106
|
+
function fitRecord(record2) {
|
|
10107
|
+
if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
|
|
10108
|
+
const data = { ...record2.data };
|
|
10109
|
+
const truncated = [];
|
|
10110
|
+
for (const field10 of droppable) {
|
|
10111
|
+
if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
|
|
10112
|
+
if (data[field10] === void 0) continue;
|
|
10113
|
+
delete data[field10];
|
|
10114
|
+
truncated.push(field10);
|
|
9984
10115
|
}
|
|
9985
|
-
|
|
10116
|
+
const content = text4(data.content) ?? "";
|
|
10117
|
+
const over = bytes({ ...record2, data }) - recordBudgetBytes;
|
|
10118
|
+
if (over > 0) {
|
|
10119
|
+
const encoded = new TextEncoder().encode(content);
|
|
10120
|
+
data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
|
|
10121
|
+
truncated.push("content");
|
|
10122
|
+
}
|
|
10123
|
+
return { ...record2, data: { ...data, truncated } };
|
|
10124
|
+
}
|
|
10125
|
+
function acceptedVector(vector2) {
|
|
10126
|
+
if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
|
|
10127
|
+
if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims).some((x) => x !== 0))
|
|
10128
|
+
return void 0;
|
|
10129
|
+
return [...vector2];
|
|
10130
|
+
}
|
|
10131
|
+
function normalized(vector2) {
|
|
10132
|
+
const norm = Math.hypot(...vector2) || 1;
|
|
10133
|
+
return vector2.map((x) => x / norm);
|
|
10134
|
+
}
|
|
10135
|
+
function fitChunks(chunks3) {
|
|
10136
|
+
const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
|
|
10137
|
+
if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
|
|
10138
|
+
if (usable.length <= maxChunks) return usable;
|
|
9986
10139
|
const out = [];
|
|
9987
|
-
for (
|
|
9988
|
-
|
|
9989
|
-
|
|
9990
|
-
|
|
9991
|
-
|
|
10140
|
+
for (let g = 0; g < maxChunks; g++) {
|
|
10141
|
+
const group = usable.slice(
|
|
10142
|
+
Math.floor(g * usable.length / maxChunks),
|
|
10143
|
+
Math.floor((g + 1) * usable.length / maxChunks)
|
|
10144
|
+
);
|
|
10145
|
+
const dims = group[0].vector.length;
|
|
10146
|
+
const mean = new Array(dims).fill(0);
|
|
10147
|
+
for (const c of group) {
|
|
10148
|
+
const unit = normalized(c.vector);
|
|
10149
|
+
for (let d = 0; d < dims; d++) mean[d] += unit[d];
|
|
10150
|
+
}
|
|
9992
10151
|
out.push({
|
|
9993
|
-
|
|
9994
|
-
|
|
9995
|
-
|
|
9996
|
-
...parsedWeight !== void 0 ? { weight: parsedWeight } : {}
|
|
10152
|
+
vector: normalized(mean),
|
|
10153
|
+
startOffset: group[0].startOffset,
|
|
10154
|
+
endOffset: group[group.length - 1].endOffset
|
|
9997
10155
|
});
|
|
9998
10156
|
}
|
|
9999
10157
|
return out;
|
|
10000
10158
|
}
|
|
10001
10159
|
|
|
10002
|
-
// src/lib/
|
|
10003
|
-
|
|
10004
|
-
|
|
10005
|
-
|
|
10006
|
-
|
|
10007
|
-
|
|
10160
|
+
// src/lib/chatStore/chatImports.ts
|
|
10161
|
+
var importBatch = 100;
|
|
10162
|
+
var importChunks = 200;
|
|
10163
|
+
var importPlaintextBytes = 39e5;
|
|
10164
|
+
function ms(date10, fallback = 1) {
|
|
10165
|
+
const value = date10?.getTime();
|
|
10166
|
+
return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
|
|
10008
10167
|
}
|
|
10009
|
-
function
|
|
10168
|
+
function bytes2(value) {
|
|
10169
|
+
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
10170
|
+
}
|
|
10171
|
+
function conversationRecord(conversation, messages) {
|
|
10172
|
+
const createdAt = ms(conversation.createdAt);
|
|
10173
|
+
const data = plain({
|
|
10174
|
+
title: conversation.title,
|
|
10175
|
+
projectId: conversation.projectId || void 0,
|
|
10176
|
+
pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
|
|
10177
|
+
lastActivityAt: Math.max(
|
|
10178
|
+
ms(conversation.updatedAt, createdAt),
|
|
10179
|
+
...messages.map((m) => ms(m.createdAt))
|
|
10180
|
+
)
|
|
10181
|
+
});
|
|
10010
10182
|
return {
|
|
10011
|
-
|
|
10012
|
-
|
|
10013
|
-
|
|
10014
|
-
|
|
10015
|
-
|
|
10016
|
-
|
|
10017
|
-
|
|
10018
|
-
|
|
10019
|
-
|
|
10020
|
-
|
|
10021
|
-
|
|
10022
|
-
|
|
10023
|
-
|
|
10024
|
-
|
|
10025
|
-
|
|
10026
|
-
|
|
10027
|
-
|
|
10028
|
-
|
|
10029
|
-
|
|
10030
|
-
|
|
10031
|
-
|
|
10032
|
-
|
|
10033
|
-
|
|
10034
|
-
|
|
10183
|
+
record: {
|
|
10184
|
+
kind: "conversation",
|
|
10185
|
+
id: conversation.conversationId,
|
|
10186
|
+
conversationId: "",
|
|
10187
|
+
sortKey: conversationSortKey(data, createdAt),
|
|
10188
|
+
createdAt,
|
|
10189
|
+
updatedAt: ms(conversation.updatedAt, createdAt),
|
|
10190
|
+
isDeleted: false,
|
|
10191
|
+
data
|
|
10192
|
+
}
|
|
10193
|
+
};
|
|
10194
|
+
}
|
|
10195
|
+
function messageRecord(message) {
|
|
10196
|
+
const {
|
|
10197
|
+
uniqueId: _uniqueId,
|
|
10198
|
+
messageId: _messageId,
|
|
10199
|
+
createdAt: _createdAt,
|
|
10200
|
+
updatedAt: _updatedAt,
|
|
10201
|
+
decryptionStatus: _status,
|
|
10202
|
+
chunks: chunks3,
|
|
10203
|
+
vector: vector2,
|
|
10204
|
+
...fields
|
|
10205
|
+
} = message;
|
|
10206
|
+
const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
|
|
10207
|
+
const single = fitted ? void 0 : acceptedVector(vector2);
|
|
10208
|
+
const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
|
|
10209
|
+
const record2 = fitRecord({
|
|
10210
|
+
kind: "message",
|
|
10211
|
+
id: message.uniqueId,
|
|
10212
|
+
conversationId: message.conversationId,
|
|
10213
|
+
sortKey: message.messageId,
|
|
10214
|
+
createdAt: ms(message.createdAt),
|
|
10215
|
+
updatedAt: ms(message.updatedAt, ms(message.createdAt)),
|
|
10216
|
+
isDeleted: false,
|
|
10217
|
+
data: {
|
|
10218
|
+
...messageData(fields),
|
|
10219
|
+
...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
|
|
10220
|
+
}
|
|
10221
|
+
});
|
|
10222
|
+
return {
|
|
10223
|
+
record: record2,
|
|
10224
|
+
...embeddings2 ? { embeddings: embeddings2 } : {},
|
|
10225
|
+
...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
|
|
10226
|
+
};
|
|
10227
|
+
}
|
|
10228
|
+
function batches(records) {
|
|
10229
|
+
const out = [];
|
|
10230
|
+
let batch = [];
|
|
10231
|
+
let chunks3 = 0;
|
|
10232
|
+
let size = 0;
|
|
10233
|
+
for (const item of records) {
|
|
10234
|
+
const vectors = item.embeddings?.length ?? 0;
|
|
10235
|
+
const itemSize = bytes2(item.record);
|
|
10236
|
+
if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
|
|
10237
|
+
out.push(batch);
|
|
10238
|
+
batch = [];
|
|
10239
|
+
chunks3 = 0;
|
|
10240
|
+
size = 0;
|
|
10241
|
+
}
|
|
10242
|
+
batch.push(item);
|
|
10243
|
+
chunks3 += vectors;
|
|
10244
|
+
size += itemSize;
|
|
10245
|
+
}
|
|
10246
|
+
if (batch.length) out.push(batch);
|
|
10247
|
+
return out;
|
|
10248
|
+
}
|
|
10249
|
+
|
|
10250
|
+
// src/lib/db/entities/types.ts
|
|
10251
|
+
var ENTITY_KINDS = [
|
|
10252
|
+
"person",
|
|
10253
|
+
"organization",
|
|
10254
|
+
"place",
|
|
10255
|
+
"event",
|
|
10256
|
+
"product",
|
|
10257
|
+
"thing",
|
|
10258
|
+
"concept",
|
|
10259
|
+
"other"
|
|
10260
|
+
];
|
|
10261
|
+
function normalizeEntityName(name) {
|
|
10262
|
+
return name.trim().toLowerCase();
|
|
10263
|
+
}
|
|
10264
|
+
var TOPIC_SALIENCE_WEIGHTS = { primary: 1, secondary: 0.6, mention: 0.3 };
|
|
10265
|
+
function topicWeight(topic2) {
|
|
10266
|
+
return topic2.source === "user" ? 1 : topic2.weight ?? 1;
|
|
10267
|
+
}
|
|
10268
|
+
function primaryTopic(topics) {
|
|
10269
|
+
let best = null;
|
|
10270
|
+
for (const topic2 of topics ?? []) {
|
|
10271
|
+
if (best === null || topicWeight(topic2) > topicWeight(best)) best = topic2;
|
|
10272
|
+
}
|
|
10273
|
+
return best;
|
|
10274
|
+
}
|
|
10275
|
+
function parseTopicWeight(value) {
|
|
10276
|
+
return typeof value === "number" && value > 0 && value <= 1 ? value : void 0;
|
|
10277
|
+
}
|
|
10278
|
+
function serializeTopics(topics) {
|
|
10279
|
+
return JSON.stringify(topics);
|
|
10280
|
+
}
|
|
10281
|
+
function parseTopics(value) {
|
|
10282
|
+
if (typeof value !== "string" || value.length === 0) return null;
|
|
10283
|
+
let parsed;
|
|
10284
|
+
try {
|
|
10285
|
+
parsed = JSON.parse(value);
|
|
10286
|
+
} catch {
|
|
10287
|
+
return null;
|
|
10288
|
+
}
|
|
10289
|
+
if (!Array.isArray(parsed)) return null;
|
|
10290
|
+
const out = [];
|
|
10291
|
+
for (const raw of parsed) {
|
|
10292
|
+
if (typeof raw !== "object" || raw === null) continue;
|
|
10293
|
+
const { name, kind, source, weight } = raw;
|
|
10294
|
+
if (typeof name !== "string" || name.trim().length === 0) continue;
|
|
10295
|
+
const parsedWeight = parseTopicWeight(weight);
|
|
10296
|
+
out.push({
|
|
10297
|
+
name,
|
|
10298
|
+
...typeof kind === "string" && kind.length > 0 ? { kind } : {},
|
|
10299
|
+
source: source === "user" ? "user" : "auto",
|
|
10300
|
+
...parsedWeight !== void 0 ? { weight: parsedWeight } : {}
|
|
10301
|
+
});
|
|
10302
|
+
}
|
|
10303
|
+
return out;
|
|
10304
|
+
}
|
|
10305
|
+
|
|
10306
|
+
// src/lib/memory/store/remoteTopics.ts
|
|
10307
|
+
function topic(value) {
|
|
10308
|
+
const t = value;
|
|
10309
|
+
if (!t || typeof t.name !== "string" || !t.name || !Number.isSafeInteger(t.version) || t.version < 1 || typeof t.is_deleted !== "boolean" || typeof t.server_updated_at !== "string" || t.kind !== void 0 && typeof t.kind !== "string")
|
|
10310
|
+
throw new Error("Invalid nearby topic");
|
|
10311
|
+
return t;
|
|
10312
|
+
}
|
|
10313
|
+
function createRemoteTopicPersistence(request) {
|
|
10314
|
+
return {
|
|
10315
|
+
topics: async () => {
|
|
10316
|
+
const out = [];
|
|
10317
|
+
let cursor;
|
|
10318
|
+
do {
|
|
10319
|
+
const page = await request(
|
|
10320
|
+
"/topics?limit=200" + (cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""),
|
|
10321
|
+
{}
|
|
10322
|
+
);
|
|
10323
|
+
if (!Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string")
|
|
10324
|
+
throw new Error("Invalid nearby topic page");
|
|
10325
|
+
out.push(...page.items.map(topic));
|
|
10326
|
+
cursor = page.next_cursor;
|
|
10327
|
+
} while (cursor);
|
|
10328
|
+
return out;
|
|
10329
|
+
},
|
|
10330
|
+
putTopic: async (value, expectedVersion) => {
|
|
10331
|
+
if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
|
|
10332
|
+
throw new Error("Expected topic version must be a nonnegative integer");
|
|
10333
|
+
return topic(
|
|
10334
|
+
await request("/topics", {
|
|
10335
|
+
method: "PUT",
|
|
10336
|
+
body: JSON.stringify({ topic: value, expected_version: expectedVersion })
|
|
10337
|
+
})
|
|
10338
|
+
);
|
|
10035
10339
|
},
|
|
10036
10340
|
importTopics: async (topics, signal) => {
|
|
10037
10341
|
for (let i = 0; i < topics.length; i += 50) {
|
|
@@ -10681,7 +10985,7 @@ var ChatStoreError = class extends Error {
|
|
|
10681
10985
|
var kinds = /* @__PURE__ */ new Set(["conversation", "message", "summary", "project", "memory_links"]);
|
|
10682
10986
|
var cipherPattern = /^enc:v\d+:(?:[0-9a-f]{2}){28,}$/i;
|
|
10683
10987
|
var maxPayload = 2 * 1024 * 1024;
|
|
10684
|
-
var
|
|
10988
|
+
var storedDims2 = 1536;
|
|
10685
10989
|
var maxRequestCiphertext = 8 * 1024 * 1024;
|
|
10686
10990
|
var maxGetRefs = 50;
|
|
10687
10991
|
var maxImportRecords = 100;
|
|
@@ -10749,24 +11053,24 @@ function vector(v) {
|
|
|
10749
11053
|
for (let i = 0; i < v.length; i++) {
|
|
10750
11054
|
const x = v[i];
|
|
10751
11055
|
if (typeof x !== "number" || !Number.isFinite(x)) return false;
|
|
10752
|
-
if (i <
|
|
11056
|
+
if (i < storedDims2 && x !== 0) nonZero = true;
|
|
10753
11057
|
}
|
|
10754
11058
|
return nonZero;
|
|
10755
11059
|
}
|
|
10756
11060
|
function vectorFields(write) {
|
|
10757
11061
|
return {
|
|
10758
|
-
...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0,
|
|
11062
|
+
...write.embeddings !== void 0 ? { embeddings: write.embeddings.map((v) => v.slice(0, storedDims2)) } : {},
|
|
10759
11063
|
...write.embeddingModel !== void 0 ? { embedding_model: write.embeddingModel } : {}
|
|
10760
11064
|
};
|
|
10761
11065
|
}
|
|
10762
|
-
function
|
|
11066
|
+
function text5(value) {
|
|
10763
11067
|
return typeof value === "string";
|
|
10764
11068
|
}
|
|
10765
11069
|
function timestamp(value) {
|
|
10766
11070
|
return typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
10767
11071
|
}
|
|
10768
11072
|
function presigned(value) {
|
|
10769
|
-
if (!object(value) || !
|
|
11073
|
+
if (!object(value) || !text5(value.url) || !/^https:\/\//.test(value.url) || !text5(value.method) || !object(value.headers) || !Object.values(value.headers).every(text5) || !timestamp(value.expires_at))
|
|
10770
11074
|
invalid();
|
|
10771
11075
|
return {
|
|
10772
11076
|
url: value.url,
|
|
@@ -10776,7 +11080,7 @@ function presigned(value) {
|
|
|
10776
11080
|
};
|
|
10777
11081
|
}
|
|
10778
11082
|
function attachment(value) {
|
|
10779
|
-
if (!object(value) || !
|
|
11083
|
+
if (!object(value) || !text5(value.attachment_id) || !attachmentIdPattern.test(value.attachment_id) || !integer(value.size_bytes, 1) || value.state !== "pending" && value.state !== "committed" || value.owner_kind !== void 0 && value.owner_kind !== "message" && value.owner_kind !== "summary" || value.owner_id !== void 0 && !id(value.owner_id) || !timestamp(value.created_at) || value.committed_at !== void 0 && !timestamp(value.committed_at))
|
|
10780
11084
|
invalid();
|
|
10781
11085
|
return {
|
|
10782
11086
|
id: value.attachment_id,
|
|
@@ -10789,7 +11093,7 @@ function attachment(value) {
|
|
|
10789
11093
|
};
|
|
10790
11094
|
}
|
|
10791
11095
|
function ref(value) {
|
|
10792
|
-
if (!object(value) || !
|
|
11096
|
+
if (!object(value) || !text5(value.kind) || !kinds.has(value.kind) || !id(value.id)) invalid();
|
|
10793
11097
|
return { kind: value.kind, id: value.id };
|
|
10794
11098
|
}
|
|
10795
11099
|
function sameMetadata(a, b) {
|
|
@@ -11012,7 +11316,7 @@ async function createRemoteChatStore(options) {
|
|
|
11012
11316
|
},
|
|
11013
11317
|
async account(signal) {
|
|
11014
11318
|
const value = await request("/account", {}, signal);
|
|
11015
|
-
if (!object(value) || value.account_id !== accountId || !
|
|
11319
|
+
if (!object(value) || value.account_id !== accountId || !text5(value.key_id) || value.state !== "none" && value.state !== "migrating" && value.state !== "active" || !integer(value.record_count) || !integer(value.storage_bytes) || !integer(value.vector_count) || value.changes_cursor !== void 0 && (!text5(value.changes_cursor) || value.changes_cursor.length > 2048))
|
|
11016
11320
|
invalid();
|
|
11017
11321
|
if (value.key_id && value.key_id !== keyId)
|
|
11018
11322
|
throw new ChatStoreError("Canonical chat key does not match", 409, "key_mismatch");
|
|
@@ -11056,364 +11360,178 @@ async function createRemoteChatStore(options) {
|
|
|
11056
11360
|
asked.add(`${checked.kind}/${checked.id}`);
|
|
11057
11361
|
return {
|
|
11058
11362
|
kind: checked.kind,
|
|
11059
|
-
id: checked.id,
|
|
11060
|
-
updated_at: r.updatedAt,
|
|
11061
|
-
is_deleted: r.isDeleted
|
|
11062
|
-
};
|
|
11063
|
-
});
|
|
11064
|
-
if (wireRevisions.length === 0) return [];
|
|
11065
|
-
const value = await request(
|
|
11066
|
-
"/verify",
|
|
11067
|
-
{
|
|
11068
|
-
method: "POST",
|
|
11069
|
-
body: JSON.stringify({ account_id: accountId, revisions: wireRevisions })
|
|
11070
|
-
},
|
|
11071
|
-
signal
|
|
11072
|
-
);
|
|
11073
|
-
if (!object(value) || !Array.isArray(value.missing)) invalid();
|
|
11074
|
-
const missing2 = value.missing.map(ref);
|
|
11075
|
-
if (missing2.some((r) => !asked.has(`${r.kind}/${r.id}`))) invalid();
|
|
11076
|
-
return missing2;
|
|
11077
|
-
},
|
|
11078
|
-
async activate(signal) {
|
|
11079
|
-
const value = await request(
|
|
11080
|
-
"/account",
|
|
11081
|
-
{ method: "PUT", body: JSON.stringify({ account_id: accountId, state: "active" }) },
|
|
11082
|
-
signal
|
|
11083
|
-
);
|
|
11084
|
-
if (!object(value) || value.state !== "active" || typeof value.transitioned !== "boolean")
|
|
11085
|
-
invalid();
|
|
11086
|
-
return value.transitioned;
|
|
11087
|
-
},
|
|
11088
|
-
async changes(cursor, options2) {
|
|
11089
|
-
const limit = options2?.limit ?? 100;
|
|
11090
|
-
if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!
|
|
11091
|
-
invalid();
|
|
11092
|
-
const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
|
|
11093
|
-
if (cursor) params.set("cursor", cursor);
|
|
11094
|
-
const value = await request(`/changes?${params}`, {}, options2?.signal);
|
|
11095
|
-
if (!object(value) || !Array.isArray(value.items) || value.items.length > limit || value.next_cursor !== void 0 && !
|
|
11096
|
-
invalid();
|
|
11097
|
-
const items = [];
|
|
11098
|
-
for (const item of value.items) items.push(await decode(item));
|
|
11099
|
-
options2?.signal?.throwIfAborted();
|
|
11100
|
-
return {
|
|
11101
|
-
items,
|
|
11102
|
-
...value.next_cursor ? { nextCursor: value.next_cursor } : {},
|
|
11103
|
-
changesCursor: value.changes_cursor ?? cursor ?? ""
|
|
11104
|
-
};
|
|
11105
|
-
},
|
|
11106
|
-
async search(embedding2, options2) {
|
|
11107
|
-
const limit = options2?.limit ?? 20;
|
|
11108
|
-
const kindsFilter = options2?.kinds;
|
|
11109
|
-
if (!Array.isArray(embedding2) || !embeddings({
|
|
11110
|
-
record: { ...emptyMessage, isDeleted: false },
|
|
11111
|
-
embeddings: [embedding2]
|
|
11112
|
-
}) || !integer(limit, 1) || limit > 50 || kindsFilter !== void 0 && (!Array.isArray(kindsFilter) || kindsFilter.length === 0 || kindsFilter.some((k) => k !== "message" && k !== "summary")) || options2?.conversationId !== void 0 && !id(options2.conversationId) || options2?.excludeConversationId !== void 0 && !id(options2.excludeConversationId) || options2?.embeddingModel !== void 0 && (!
|
|
11113
|
-
invalid();
|
|
11114
|
-
const value = await request(
|
|
11115
|
-
"/search",
|
|
11116
|
-
{
|
|
11117
|
-
method: "POST",
|
|
11118
|
-
body: JSON.stringify({
|
|
11119
|
-
account_id: accountId,
|
|
11120
|
-
embedding: embedding2.slice(0,
|
|
11121
|
-
limit,
|
|
11122
|
-
...kindsFilter ? { kinds: kindsFilter } : {},
|
|
11123
|
-
...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
|
|
11124
|
-
...options2?.excludeConversationId ? { exclude_conversation_id: options2.excludeConversationId } : {},
|
|
11125
|
-
...options2?.embeddingModel ? { embedding_model: options2.embeddingModel } : {}
|
|
11126
|
-
})
|
|
11127
|
-
},
|
|
11128
|
-
options2?.signal
|
|
11129
|
-
);
|
|
11130
|
-
if (!object(value) || !Array.isArray(value.items) || value.items.length > limit) invalid();
|
|
11131
|
-
const hits = [];
|
|
11132
|
-
for (const item of value.items) {
|
|
11133
|
-
if (!object(item) || !integer(item.chunk) || typeof item.score !== "number" || !Number.isFinite(item.score))
|
|
11134
|
-
invalid();
|
|
11135
|
-
const snapshot = await decode(item);
|
|
11136
|
-
if (snapshot.record.isDeleted || kindsFilter !== void 0 && !kindsFilter.includes(snapshot.record.kind) || snapshot.record.kind !== "message" && snapshot.record.kind !== "summary" || options2?.conversationId !== void 0 && snapshot.record.conversationId !== options2.conversationId || snapshot.record.conversationId === options2?.excludeConversationId)
|
|
11137
|
-
invalid();
|
|
11138
|
-
hits.push({ ...snapshot, chunk: item.chunk, score: item.score });
|
|
11139
|
-
}
|
|
11140
|
-
options2?.signal?.throwIfAborted();
|
|
11141
|
-
return hits;
|
|
11142
|
-
},
|
|
11143
|
-
async deleteAll(signal) {
|
|
11144
|
-
const value = await request(`/records?account_id=${accountId}`, { method: "DELETE" }, signal);
|
|
11145
|
-
if (!object(value) || !integer(value.deleted)) invalid();
|
|
11146
|
-
return value.deleted;
|
|
11147
|
-
},
|
|
11148
|
-
attachments: {
|
|
11149
|
-
async create(sizeBytes, signal) {
|
|
11150
|
-
if (!integer(sizeBytes, 1) || sizeBytes > maxAttachmentBytes) invalid();
|
|
11151
|
-
const value = await request(
|
|
11152
|
-
"/attachments",
|
|
11153
|
-
{
|
|
11154
|
-
method: "POST",
|
|
11155
|
-
body: JSON.stringify({ account_id: accountId, size_bytes: sizeBytes })
|
|
11156
|
-
},
|
|
11157
|
-
signal
|
|
11158
|
-
);
|
|
11159
|
-
if (!object(value)) invalid();
|
|
11160
|
-
const created = attachment(value.attachment);
|
|
11161
|
-
if (created.sizeBytes !== sizeBytes || created.state !== "pending") invalid();
|
|
11162
|
-
return { attachment: created, upload: presigned(value.upload) };
|
|
11163
|
-
},
|
|
11164
|
-
async commit(attachmentId, owner, signal) {
|
|
11165
|
-
if (!attachmentIdPattern.test(attachmentId) || !object(owner) || owner.kind !== "message" && owner.kind !== "summary" || !id(owner.id))
|
|
11166
|
-
invalid();
|
|
11167
|
-
const value = await request(
|
|
11168
|
-
`/attachments/${attachmentId}/commit`,
|
|
11169
|
-
{
|
|
11170
|
-
method: "POST",
|
|
11171
|
-
body: JSON.stringify({
|
|
11172
|
-
account_id: accountId,
|
|
11173
|
-
owner_kind: owner.kind,
|
|
11174
|
-
owner_id: owner.id
|
|
11175
|
-
})
|
|
11176
|
-
},
|
|
11177
|
-
signal
|
|
11178
|
-
);
|
|
11179
|
-
if (!object(value)) invalid();
|
|
11180
|
-
const committed = attachment(value.attachment);
|
|
11181
|
-
if (committed.id !== attachmentId || committed.state !== "committed" || committed.ownerKind !== owner.kind || committed.ownerId !== owner.id)
|
|
11182
|
-
invalid();
|
|
11183
|
-
return committed;
|
|
11184
|
-
},
|
|
11185
|
-
async get(attachmentId, signal) {
|
|
11186
|
-
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
11187
|
-
let value;
|
|
11188
|
-
try {
|
|
11189
|
-
value = await request(`/attachments/${attachmentId}?account_id=${accountId}`, {}, signal);
|
|
11190
|
-
} catch (error) {
|
|
11191
|
-
if (error instanceof ChatStoreError && error.status === 404) return null;
|
|
11192
|
-
throw error;
|
|
11193
|
-
}
|
|
11194
|
-
if (!object(value)) invalid();
|
|
11195
|
-
const found = attachment(value.attachment);
|
|
11196
|
-
if (found.id !== attachmentId) invalid();
|
|
11197
|
-
return {
|
|
11198
|
-
attachment: found,
|
|
11199
|
-
...value.download !== void 0 ? { download: presigned(value.download) } : {}
|
|
11200
|
-
};
|
|
11201
|
-
},
|
|
11202
|
-
async delete(attachmentId, signal) {
|
|
11203
|
-
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
11204
|
-
await request(
|
|
11205
|
-
`/attachments/${attachmentId}?account_id=${accountId}`,
|
|
11206
|
-
{ method: "DELETE" },
|
|
11207
|
-
signal
|
|
11208
|
-
);
|
|
11209
|
-
}
|
|
11210
|
-
}
|
|
11211
|
-
};
|
|
11212
|
-
}
|
|
11213
|
-
var emptyMessage = {
|
|
11214
|
-
kind: "message",
|
|
11215
|
-
id: "query",
|
|
11216
|
-
conversationId: "query",
|
|
11217
|
-
sortKey: 0,
|
|
11218
|
-
createdAt: 1,
|
|
11219
|
-
updatedAt: 1,
|
|
11220
|
-
isDeleted: false,
|
|
11221
|
-
data: {}
|
|
11222
|
-
};
|
|
11223
|
-
|
|
11224
|
-
// src/lib/chatStore/vaultRecords.ts
|
|
11225
|
-
var PINNED_SORT_BASE = 2 ** 51;
|
|
11226
|
-
var recordBudgetBytes = 104e4;
|
|
11227
|
-
var storedDims2 = 1536;
|
|
11228
|
-
var acceptedDims = /* @__PURE__ */ new Set([1536, 4096]);
|
|
11229
|
-
var maxChunks = 16;
|
|
11230
|
-
var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
|
|
11231
|
-
var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
|
|
11232
|
-
var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
|
|
11233
|
-
function plain(value) {
|
|
11234
|
-
return JSON.parse(JSON.stringify(value ?? {}));
|
|
11235
|
-
}
|
|
11236
|
-
function text5(value) {
|
|
11237
|
-
return typeof value === "string" ? value : void 0;
|
|
11238
|
-
}
|
|
11239
|
-
function number(value) {
|
|
11240
|
-
return typeof value === "number" ? value : void 0;
|
|
11241
|
-
}
|
|
11242
|
-
function conversationSortKey(data, createdAt) {
|
|
11243
|
-
const pinnedAt = number(data.pinnedAt);
|
|
11244
|
-
if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
|
|
11245
|
-
return number(data.lastActivityAt) ?? createdAt;
|
|
11246
|
-
}
|
|
11247
|
-
function toConversation(record2) {
|
|
11248
|
-
const pinnedAt = number(record2.data.pinnedAt);
|
|
11249
|
-
const projectId = text5(record2.data.projectId);
|
|
11250
|
-
return {
|
|
11251
|
-
uniqueId: record2.id,
|
|
11252
|
-
conversationId: record2.id,
|
|
11253
|
-
title: text5(record2.data.title) ?? "",
|
|
11254
|
-
...projectId ? { projectId } : {},
|
|
11255
|
-
createdAt: new Date(record2.createdAt),
|
|
11256
|
-
updatedAt: new Date(record2.updatedAt),
|
|
11257
|
-
isDeleted: record2.isDeleted,
|
|
11258
|
-
pinnedAt: pinnedAt ? new Date(pinnedAt) : null
|
|
11259
|
-
};
|
|
11260
|
-
}
|
|
11261
|
-
function messageData(options) {
|
|
11262
|
-
return plain(
|
|
11263
|
-
Object.fromEntries(
|
|
11264
|
-
Object.entries(options).filter(
|
|
11265
|
-
([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
|
|
11266
|
-
)
|
|
11267
|
-
)
|
|
11268
|
-
);
|
|
11269
|
-
}
|
|
11270
|
-
function toMessage(record2) {
|
|
11271
|
-
const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
|
|
11272
|
-
return {
|
|
11273
|
-
...fields,
|
|
11274
|
-
uniqueId: record2.id,
|
|
11275
|
-
messageId: record2.sortKey,
|
|
11276
|
-
conversationId: record2.conversationId,
|
|
11277
|
-
createdAt: new Date(record2.createdAt),
|
|
11278
|
-
updatedAt: new Date(record2.updatedAt)
|
|
11279
|
-
};
|
|
11280
|
-
}
|
|
11281
|
-
function chunkOffsets(record2) {
|
|
11282
|
-
const offsets = record2.data.chunkOffsets;
|
|
11283
|
-
return Array.isArray(offsets) ? offsets : void 0;
|
|
11284
|
-
}
|
|
11285
|
-
function toSkeletons(records) {
|
|
11286
|
-
const roleById = new Map(records.map((r) => [r.id, text5(r.data.role)]));
|
|
11287
|
-
return records.map((r) => {
|
|
11288
|
-
const parentMessageId = text5(r.data.parentMessageId);
|
|
11289
|
-
const model = text5(r.data.model);
|
|
11290
|
-
const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
|
|
11291
|
-
return {
|
|
11292
|
-
uniqueId: r.id,
|
|
11293
|
-
messageId: r.sortKey,
|
|
11294
|
-
conversationId: r.conversationId,
|
|
11295
|
-
role: text5(r.data.role) ?? "",
|
|
11296
|
-
createdAt: new Date(r.createdAt),
|
|
11297
|
-
...parentMessageId ? { parentMessageId } : {},
|
|
11298
|
-
...model ? { model } : {},
|
|
11299
|
-
...artifact ? { content: text5(r.data.content) ?? "" } : {}
|
|
11300
|
-
};
|
|
11301
|
-
});
|
|
11302
|
-
}
|
|
11303
|
-
function toSummary(record2) {
|
|
11304
|
-
return {
|
|
11305
|
-
uniqueId: record2.id,
|
|
11306
|
-
conversationId: record2.id,
|
|
11307
|
-
summary: text5(record2.data.summary) ?? "",
|
|
11308
|
-
summarizedUpTo: text5(record2.data.summarizedUpTo) ?? "",
|
|
11309
|
-
tokenCount: number(record2.data.tokenCount) ?? 0,
|
|
11310
|
-
createdAt: new Date(record2.createdAt),
|
|
11311
|
-
updatedAt: new Date(record2.updatedAt)
|
|
11312
|
-
};
|
|
11313
|
-
}
|
|
11314
|
-
function links(data) {
|
|
11315
|
-
return Array.isArray(data.links) ? data.links : [];
|
|
11316
|
-
}
|
|
11317
|
-
function applyLinkOps(data, ops) {
|
|
11318
|
-
let current = links(data);
|
|
11319
|
-
for (const op of ops) {
|
|
11320
|
-
if ("clear" in op) {
|
|
11321
|
-
current = [];
|
|
11322
|
-
continue;
|
|
11323
|
-
}
|
|
11324
|
-
const byId = new Map(current.map((l) => [l.memoryId, l]));
|
|
11325
|
-
const turn = /* @__PURE__ */ new Set();
|
|
11326
|
-
op.add.forEach((item, i) => {
|
|
11327
|
-
if (!item.memoryId || turn.has(item.memoryId)) return;
|
|
11328
|
-
turn.add(item.memoryId);
|
|
11329
|
-
const known = byId.get(item.memoryId);
|
|
11330
|
-
if (known && known.createdAt >= op.at + i) return;
|
|
11331
|
-
byId.set(item.memoryId, { memoryId: item.memoryId, score: item.score, createdAt: op.at + i });
|
|
11332
|
-
});
|
|
11333
|
-
current = [...byId.values()].sort((a, b) => a.createdAt - b.createdAt).slice(-MAX_PER_CONVERSATION);
|
|
11334
|
-
}
|
|
11335
|
-
return plain({ links: current });
|
|
11336
|
-
}
|
|
11337
|
-
function toLinks(record2) {
|
|
11338
|
-
return links(record2.data).map((l) => ({
|
|
11339
|
-
uniqueId: `${record2.id}:${l.memoryId}`,
|
|
11340
|
-
conversationId: record2.id,
|
|
11341
|
-
memoryId: l.memoryId,
|
|
11342
|
-
score: l.score,
|
|
11343
|
-
createdAt: new Date(l.createdAt)
|
|
11344
|
-
}));
|
|
11345
|
-
}
|
|
11346
|
-
function bytes(value) {
|
|
11347
|
-
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
11348
|
-
}
|
|
11349
|
-
function fitRecord(record2) {
|
|
11350
|
-
if (record2.kind !== "message" || bytes(record2) <= recordBudgetBytes) return record2;
|
|
11351
|
-
const data = { ...record2.data };
|
|
11352
|
-
const truncated = [];
|
|
11353
|
-
for (const field10 of droppable) {
|
|
11354
|
-
if (bytes({ ...record2, data }) <= recordBudgetBytes) break;
|
|
11355
|
-
if (data[field10] === void 0) continue;
|
|
11356
|
-
delete data[field10];
|
|
11357
|
-
truncated.push(field10);
|
|
11358
|
-
}
|
|
11359
|
-
const content = text5(data.content) ?? "";
|
|
11360
|
-
const over = bytes({ ...record2, data }) - recordBudgetBytes;
|
|
11361
|
-
if (over > 0) {
|
|
11362
|
-
const encoded = new TextEncoder().encode(content);
|
|
11363
|
-
data.content = new TextDecoder().decode(encoded.slice(0, Math.max(0, encoded.length - over - 64))).replace(/�$/, "");
|
|
11364
|
-
truncated.push("content");
|
|
11365
|
-
}
|
|
11366
|
-
return { ...record2, data: { ...data, truncated } };
|
|
11367
|
-
}
|
|
11368
|
-
function acceptedVector(vector2) {
|
|
11369
|
-
if (!vector2 || !acceptedDims.has(vector2.length)) return void 0;
|
|
11370
|
-
if (!vector2.every(Number.isFinite) || !vector2.slice(0, storedDims2).some((x) => x !== 0))
|
|
11371
|
-
return void 0;
|
|
11372
|
-
return [...vector2];
|
|
11373
|
-
}
|
|
11374
|
-
function normalized(vector2) {
|
|
11375
|
-
const norm = Math.hypot(...vector2) || 1;
|
|
11376
|
-
return vector2.map((x) => x / norm);
|
|
11377
|
-
}
|
|
11378
|
-
function fitChunks(chunks3) {
|
|
11379
|
-
const usable = chunks3.map((c) => ({ ...c, vector: acceptedVector(c.vector) }));
|
|
11380
|
-
if (usable.length === 0 || usable.some((c) => !c.vector)) return void 0;
|
|
11381
|
-
if (usable.length <= maxChunks) return usable;
|
|
11382
|
-
const out = [];
|
|
11383
|
-
for (let g = 0; g < maxChunks; g++) {
|
|
11384
|
-
const group = usable.slice(
|
|
11385
|
-
Math.floor(g * usable.length / maxChunks),
|
|
11386
|
-
Math.floor((g + 1) * usable.length / maxChunks)
|
|
11387
|
-
);
|
|
11388
|
-
const dims = group[0].vector.length;
|
|
11389
|
-
const mean = new Array(dims).fill(0);
|
|
11390
|
-
for (const c of group) {
|
|
11391
|
-
const unit = normalized(c.vector);
|
|
11392
|
-
for (let d = 0; d < dims; d++) mean[d] += unit[d];
|
|
11363
|
+
id: checked.id,
|
|
11364
|
+
updated_at: r.updatedAt,
|
|
11365
|
+
is_deleted: r.isDeleted
|
|
11366
|
+
};
|
|
11367
|
+
});
|
|
11368
|
+
if (wireRevisions.length === 0) return [];
|
|
11369
|
+
const value = await request(
|
|
11370
|
+
"/verify",
|
|
11371
|
+
{
|
|
11372
|
+
method: "POST",
|
|
11373
|
+
body: JSON.stringify({ account_id: accountId, revisions: wireRevisions })
|
|
11374
|
+
},
|
|
11375
|
+
signal
|
|
11376
|
+
);
|
|
11377
|
+
if (!object(value) || !Array.isArray(value.missing)) invalid();
|
|
11378
|
+
const missing2 = value.missing.map(ref);
|
|
11379
|
+
if (missing2.some((r) => !asked.has(`${r.kind}/${r.id}`))) invalid();
|
|
11380
|
+
return missing2;
|
|
11381
|
+
},
|
|
11382
|
+
async activate(signal) {
|
|
11383
|
+
const value = await request(
|
|
11384
|
+
"/account",
|
|
11385
|
+
{ method: "PUT", body: JSON.stringify({ account_id: accountId, state: "active" }) },
|
|
11386
|
+
signal
|
|
11387
|
+
);
|
|
11388
|
+
if (!object(value) || value.state !== "active" || typeof value.transitioned !== "boolean")
|
|
11389
|
+
invalid();
|
|
11390
|
+
return value.transitioned;
|
|
11391
|
+
},
|
|
11392
|
+
async changes(cursor, options2) {
|
|
11393
|
+
const limit = options2?.limit ?? 100;
|
|
11394
|
+
if (!integer(limit, 1) || limit > 200 || cursor !== void 0 && (!text5(cursor) || cursor.length > 2048))
|
|
11395
|
+
invalid();
|
|
11396
|
+
const params = new URLSearchParams({ account_id: String(accountId), limit: String(limit) });
|
|
11397
|
+
if (cursor) params.set("cursor", cursor);
|
|
11398
|
+
const value = await request(`/changes?${params}`, {}, options2?.signal);
|
|
11399
|
+
if (!object(value) || !Array.isArray(value.items) || value.items.length > limit || value.next_cursor !== void 0 && !text5(value.next_cursor) || value.changes_cursor !== void 0 && !text5(value.changes_cursor))
|
|
11400
|
+
invalid();
|
|
11401
|
+
const items = [];
|
|
11402
|
+
for (const item of value.items) items.push(await decode(item));
|
|
11403
|
+
options2?.signal?.throwIfAborted();
|
|
11404
|
+
return {
|
|
11405
|
+
items,
|
|
11406
|
+
...value.next_cursor ? { nextCursor: value.next_cursor } : {},
|
|
11407
|
+
changesCursor: value.changes_cursor ?? cursor ?? ""
|
|
11408
|
+
};
|
|
11409
|
+
},
|
|
11410
|
+
async search(embedding2, options2) {
|
|
11411
|
+
const limit = options2?.limit ?? 20;
|
|
11412
|
+
const kindsFilter = options2?.kinds;
|
|
11413
|
+
if (!Array.isArray(embedding2) || !embeddings({
|
|
11414
|
+
record: { ...emptyMessage, isDeleted: false },
|
|
11415
|
+
embeddings: [embedding2]
|
|
11416
|
+
}) || !integer(limit, 1) || limit > 50 || kindsFilter !== void 0 && (!Array.isArray(kindsFilter) || kindsFilter.length === 0 || kindsFilter.some((k) => k !== "message" && k !== "summary")) || options2?.conversationId !== void 0 && !id(options2.conversationId) || options2?.excludeConversationId !== void 0 && !id(options2.excludeConversationId) || options2?.embeddingModel !== void 0 && (!text5(options2.embeddingModel) || options2.embeddingModel.length > 256))
|
|
11417
|
+
invalid();
|
|
11418
|
+
const value = await request(
|
|
11419
|
+
"/search",
|
|
11420
|
+
{
|
|
11421
|
+
method: "POST",
|
|
11422
|
+
body: JSON.stringify({
|
|
11423
|
+
account_id: accountId,
|
|
11424
|
+
embedding: embedding2.slice(0, storedDims2),
|
|
11425
|
+
limit,
|
|
11426
|
+
...kindsFilter ? { kinds: kindsFilter } : {},
|
|
11427
|
+
...options2?.conversationId ? { conversation_id: options2.conversationId } : {},
|
|
11428
|
+
...options2?.excludeConversationId ? { exclude_conversation_id: options2.excludeConversationId } : {},
|
|
11429
|
+
...options2?.embeddingModel ? { embedding_model: options2.embeddingModel } : {}
|
|
11430
|
+
})
|
|
11431
|
+
},
|
|
11432
|
+
options2?.signal
|
|
11433
|
+
);
|
|
11434
|
+
if (!object(value) || !Array.isArray(value.items) || value.items.length > limit) invalid();
|
|
11435
|
+
const hits = [];
|
|
11436
|
+
for (const item of value.items) {
|
|
11437
|
+
if (!object(item) || !integer(item.chunk) || typeof item.score !== "number" || !Number.isFinite(item.score))
|
|
11438
|
+
invalid();
|
|
11439
|
+
const snapshot = await decode(item);
|
|
11440
|
+
if (snapshot.record.isDeleted || kindsFilter !== void 0 && !kindsFilter.includes(snapshot.record.kind) || snapshot.record.kind !== "message" && snapshot.record.kind !== "summary" || options2?.conversationId !== void 0 && snapshot.record.conversationId !== options2.conversationId || snapshot.record.conversationId === options2?.excludeConversationId)
|
|
11441
|
+
invalid();
|
|
11442
|
+
hits.push({ ...snapshot, chunk: item.chunk, score: item.score });
|
|
11443
|
+
}
|
|
11444
|
+
options2?.signal?.throwIfAborted();
|
|
11445
|
+
return hits;
|
|
11446
|
+
},
|
|
11447
|
+
async deleteAll(signal) {
|
|
11448
|
+
const value = await request(`/records?account_id=${accountId}`, { method: "DELETE" }, signal);
|
|
11449
|
+
if (!object(value) || !integer(value.deleted)) invalid();
|
|
11450
|
+
return value.deleted;
|
|
11451
|
+
},
|
|
11452
|
+
attachments: {
|
|
11453
|
+
async create(sizeBytes, signal) {
|
|
11454
|
+
if (!integer(sizeBytes, 1) || sizeBytes > maxAttachmentBytes) invalid();
|
|
11455
|
+
const value = await request(
|
|
11456
|
+
"/attachments",
|
|
11457
|
+
{
|
|
11458
|
+
method: "POST",
|
|
11459
|
+
body: JSON.stringify({ account_id: accountId, size_bytes: sizeBytes })
|
|
11460
|
+
},
|
|
11461
|
+
signal
|
|
11462
|
+
);
|
|
11463
|
+
if (!object(value)) invalid();
|
|
11464
|
+
const created = attachment(value.attachment);
|
|
11465
|
+
if (created.sizeBytes !== sizeBytes || created.state !== "pending") invalid();
|
|
11466
|
+
return { attachment: created, upload: presigned(value.upload) };
|
|
11467
|
+
},
|
|
11468
|
+
async commit(attachmentId, owner, signal) {
|
|
11469
|
+
if (!attachmentIdPattern.test(attachmentId) || !object(owner) || owner.kind !== "message" && owner.kind !== "summary" || !id(owner.id))
|
|
11470
|
+
invalid();
|
|
11471
|
+
const value = await request(
|
|
11472
|
+
`/attachments/${attachmentId}/commit`,
|
|
11473
|
+
{
|
|
11474
|
+
method: "POST",
|
|
11475
|
+
body: JSON.stringify({
|
|
11476
|
+
account_id: accountId,
|
|
11477
|
+
owner_kind: owner.kind,
|
|
11478
|
+
owner_id: owner.id
|
|
11479
|
+
})
|
|
11480
|
+
},
|
|
11481
|
+
signal
|
|
11482
|
+
);
|
|
11483
|
+
if (!object(value)) invalid();
|
|
11484
|
+
const committed = attachment(value.attachment);
|
|
11485
|
+
if (committed.id !== attachmentId || committed.state !== "committed" || committed.ownerKind !== owner.kind || committed.ownerId !== owner.id)
|
|
11486
|
+
invalid();
|
|
11487
|
+
return committed;
|
|
11488
|
+
},
|
|
11489
|
+
async get(attachmentId, signal) {
|
|
11490
|
+
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
11491
|
+
let value;
|
|
11492
|
+
try {
|
|
11493
|
+
value = await request(`/attachments/${attachmentId}?account_id=${accountId}`, {}, signal);
|
|
11494
|
+
} catch (error) {
|
|
11495
|
+
if (error instanceof ChatStoreError && error.status === 404) return null;
|
|
11496
|
+
throw error;
|
|
11497
|
+
}
|
|
11498
|
+
if (!object(value)) invalid();
|
|
11499
|
+
const found = attachment(value.attachment);
|
|
11500
|
+
if (found.id !== attachmentId) invalid();
|
|
11501
|
+
return {
|
|
11502
|
+
attachment: found,
|
|
11503
|
+
...value.download !== void 0 ? { download: presigned(value.download) } : {}
|
|
11504
|
+
};
|
|
11505
|
+
},
|
|
11506
|
+
async delete(attachmentId, signal) {
|
|
11507
|
+
if (!attachmentIdPattern.test(attachmentId)) invalid();
|
|
11508
|
+
await request(
|
|
11509
|
+
`/attachments/${attachmentId}?account_id=${accountId}`,
|
|
11510
|
+
{ method: "DELETE" },
|
|
11511
|
+
signal
|
|
11512
|
+
);
|
|
11513
|
+
}
|
|
11393
11514
|
}
|
|
11394
|
-
|
|
11395
|
-
vector: normalized(mean),
|
|
11396
|
-
startOffset: group[0].startOffset,
|
|
11397
|
-
endOffset: group[group.length - 1].endOffset
|
|
11398
|
-
});
|
|
11399
|
-
}
|
|
11400
|
-
return out;
|
|
11515
|
+
};
|
|
11401
11516
|
}
|
|
11517
|
+
var emptyMessage = {
|
|
11518
|
+
kind: "message",
|
|
11519
|
+
id: "query",
|
|
11520
|
+
conversationId: "query",
|
|
11521
|
+
sortKey: 0,
|
|
11522
|
+
createdAt: 1,
|
|
11523
|
+
updatedAt: 1,
|
|
11524
|
+
isDeleted: false,
|
|
11525
|
+
data: {}
|
|
11526
|
+
};
|
|
11402
11527
|
|
|
11403
11528
|
// src/lib/chatStore/migrateChats.ts
|
|
11404
11529
|
var maxPasses = 5;
|
|
11405
11530
|
var verifyBatch = 1e3;
|
|
11406
|
-
var importBatch = 100;
|
|
11407
|
-
var importChunks = 200;
|
|
11408
|
-
var importPlaintextBytes = 39e5;
|
|
11409
11531
|
var writeBatch = 25;
|
|
11410
11532
|
function key(record2) {
|
|
11411
11533
|
return `${record2.kind}/${record2.id}`;
|
|
11412
11534
|
}
|
|
11413
|
-
function ms(date10, fallback = 1) {
|
|
11414
|
-
const value = date10?.getTime();
|
|
11415
|
-
return value && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : fallback;
|
|
11416
|
-
}
|
|
11417
11535
|
function sealed(value) {
|
|
11418
11536
|
if (typeof value === "string") return isEncrypted(value);
|
|
11419
11537
|
if (Array.isArray(value)) return typeof value[0] !== "number" && value.some(sealed);
|
|
@@ -11421,42 +11539,6 @@ function sealed(value) {
|
|
|
11421
11539
|
return Object.values(value).some(sealed);
|
|
11422
11540
|
return false;
|
|
11423
11541
|
}
|
|
11424
|
-
function bytes2(value) {
|
|
11425
|
-
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
11426
|
-
}
|
|
11427
|
-
function messageRecord(message) {
|
|
11428
|
-
const {
|
|
11429
|
-
uniqueId: _uniqueId,
|
|
11430
|
-
messageId: _messageId,
|
|
11431
|
-
createdAt: _createdAt,
|
|
11432
|
-
updatedAt: _updatedAt,
|
|
11433
|
-
decryptionStatus: _status,
|
|
11434
|
-
chunks: chunks3,
|
|
11435
|
-
vector: vector2,
|
|
11436
|
-
...fields
|
|
11437
|
-
} = message;
|
|
11438
|
-
const fitted = chunks3?.length ? fitChunks(chunks3) : void 0;
|
|
11439
|
-
const single = fitted ? void 0 : acceptedVector(vector2);
|
|
11440
|
-
const embeddings2 = fitted?.map((c) => c.vector) ?? (single ? [single] : void 0);
|
|
11441
|
-
const record2 = fitRecord({
|
|
11442
|
-
kind: "message",
|
|
11443
|
-
id: message.uniqueId,
|
|
11444
|
-
conversationId: message.conversationId,
|
|
11445
|
-
sortKey: message.messageId,
|
|
11446
|
-
createdAt: ms(message.createdAt),
|
|
11447
|
-
updatedAt: ms(message.updatedAt, ms(message.createdAt)),
|
|
11448
|
-
isDeleted: false,
|
|
11449
|
-
data: {
|
|
11450
|
-
...messageData(fields),
|
|
11451
|
-
...fitted ? { chunkOffsets: fitted.map((c) => [c.startOffset, c.endOffset]) } : {}
|
|
11452
|
-
}
|
|
11453
|
-
});
|
|
11454
|
-
return {
|
|
11455
|
-
record: record2,
|
|
11456
|
-
...embeddings2 ? { embeddings: embeddings2 } : {},
|
|
11457
|
-
...embeddings2 && message.embeddingModel ? { embeddingModel: message.embeddingModel } : {}
|
|
11458
|
-
};
|
|
11459
|
-
}
|
|
11460
11542
|
async function readLocal(options) {
|
|
11461
11543
|
const { database } = options;
|
|
11462
11544
|
const ctx = {
|
|
@@ -11467,7 +11549,7 @@ async function readLocal(options) {
|
|
|
11467
11549
|
signMessage: options.signMessage,
|
|
11468
11550
|
embeddedWalletSigner: options.embeddedWalletSigner
|
|
11469
11551
|
};
|
|
11470
|
-
const summaries = createSummaryContext(database);
|
|
11552
|
+
const summaries = createSummaryContext(database, ctx);
|
|
11471
11553
|
const memory = {
|
|
11472
11554
|
database,
|
|
11473
11555
|
conversationMemoryCollection: database.get(ConversationMemory.table)
|
|
@@ -11510,29 +11592,10 @@ async function readLocal(options) {
|
|
|
11510
11592
|
const messages = await getMessagesOp(ctx, conversationId);
|
|
11511
11593
|
const unreadableTitle = isEncrypted(conversation.title);
|
|
11512
11594
|
if (unreadableTitle) out.untitled++;
|
|
11513
|
-
const createdAt = ms(conversation.createdAt);
|
|
11514
|
-
const data = plain({
|
|
11515
|
-
title: unreadableTitle ? "" : conversation.title,
|
|
11516
|
-
projectId: conversation.projectId || void 0,
|
|
11517
|
-
pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
|
|
11518
|
-
lastActivityAt: Math.max(
|
|
11519
|
-
ms(conversation.updatedAt, createdAt),
|
|
11520
|
-
...messages.map((m) => ms(m.createdAt))
|
|
11521
|
-
)
|
|
11522
|
-
});
|
|
11523
11595
|
out.conversations++;
|
|
11524
|
-
out.records.push(
|
|
11525
|
-
|
|
11526
|
-
|
|
11527
|
-
id: conversationId,
|
|
11528
|
-
conversationId: "",
|
|
11529
|
-
sortKey: conversationSortKey(data, createdAt),
|
|
11530
|
-
createdAt,
|
|
11531
|
-
updatedAt: ms(conversation.updatedAt, createdAt),
|
|
11532
|
-
isDeleted: false,
|
|
11533
|
-
data
|
|
11534
|
-
}
|
|
11535
|
-
});
|
|
11596
|
+
out.records.push(
|
|
11597
|
+
conversationRecord(unreadableTitle ? { ...conversation, title: "" } : conversation, messages)
|
|
11598
|
+
);
|
|
11536
11599
|
for (const message of messages) {
|
|
11537
11600
|
if (message.decryptionStatus || sealed(message)) {
|
|
11538
11601
|
skip("message", message.uniqueId, "unreadable");
|
|
@@ -11548,7 +11611,9 @@ async function readLocal(options) {
|
|
|
11548
11611
|
out.records.push(prepared);
|
|
11549
11612
|
}
|
|
11550
11613
|
const summary = await getConversationSummaryOp(summaries, conversationId);
|
|
11551
|
-
if (summary)
|
|
11614
|
+
if (summary && isEncrypted(summary.summary)) {
|
|
11615
|
+
skip("summary", conversationId, "unreadable");
|
|
11616
|
+
} else if (summary)
|
|
11552
11617
|
out.records.push({
|
|
11553
11618
|
record: {
|
|
11554
11619
|
kind: "summary",
|
|
@@ -11651,27 +11716,6 @@ async function deletedSinceUpload(store, journal, local, signal) {
|
|
|
11651
11716
|
};
|
|
11652
11717
|
});
|
|
11653
11718
|
}
|
|
11654
|
-
function batches(records) {
|
|
11655
|
-
const out = [];
|
|
11656
|
-
let batch = [];
|
|
11657
|
-
let chunks3 = 0;
|
|
11658
|
-
let size = 0;
|
|
11659
|
-
for (const item of records) {
|
|
11660
|
-
const vectors = item.embeddings?.length ?? 0;
|
|
11661
|
-
const itemSize = bytes2(item.record);
|
|
11662
|
-
if (batch.length > 0 && (batch.length >= importBatch || chunks3 + vectors > importChunks || size + itemSize > importPlaintextBytes)) {
|
|
11663
|
-
out.push(batch);
|
|
11664
|
-
batch = [];
|
|
11665
|
-
chunks3 = 0;
|
|
11666
|
-
size = 0;
|
|
11667
|
-
}
|
|
11668
|
-
batch.push(item);
|
|
11669
|
-
chunks3 += vectors;
|
|
11670
|
-
size += itemSize;
|
|
11671
|
-
}
|
|
11672
|
-
if (batch.length) out.push(batch);
|
|
11673
|
-
return out;
|
|
11674
|
-
}
|
|
11675
11719
|
function fitVectors(records, available2, unembedded) {
|
|
11676
11720
|
let total = records.reduce((sum, r) => sum + (r.embeddings?.length ?? 0), 0);
|
|
11677
11721
|
if (total <= available2) return records;
|
|
@@ -12752,6 +12796,45 @@ function createVaultChatBackend(options) {
|
|
|
12752
12796
|
},
|
|
12753
12797
|
flush,
|
|
12754
12798
|
poll,
|
|
12799
|
+
async importChats(chats) {
|
|
12800
|
+
await ready();
|
|
12801
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12802
|
+
const unique = (items) => items.filter(({ record: record2 }) => {
|
|
12803
|
+
const k = key2(record2.kind, record2.id);
|
|
12804
|
+
if (seen.has(k)) return false;
|
|
12805
|
+
seen.add(k);
|
|
12806
|
+
return true;
|
|
12807
|
+
});
|
|
12808
|
+
const valid = chats.filter((c) => validChatId(c.conversation.conversationId));
|
|
12809
|
+
const conversations = unique(
|
|
12810
|
+
valid.map((c) => conversationRecord(c.conversation, c.messages))
|
|
12811
|
+
);
|
|
12812
|
+
const messages = unique(
|
|
12813
|
+
valid.flatMap(
|
|
12814
|
+
(c) => c.messages.filter(
|
|
12815
|
+
(m) => m.conversationId === c.conversation.conversationId && validChatId(m.uniqueId) && Number.isSafeInteger(m.messageId)
|
|
12816
|
+
).map((m) => messageRecord({ ...m, vector: void 0, chunks: void 0 }))
|
|
12817
|
+
)
|
|
12818
|
+
);
|
|
12819
|
+
let conversationCount = 0;
|
|
12820
|
+
let messageCount = 0;
|
|
12821
|
+
try {
|
|
12822
|
+
for (const batch of batches(conversations))
|
|
12823
|
+
conversationCount += await store.importRecords(batch);
|
|
12824
|
+
for (const batch of batches(messages)) messageCount += await store.importRecords(batch);
|
|
12825
|
+
} finally {
|
|
12826
|
+
for (const { record: record2 } of messages) checked.delete(key2("message", record2.id));
|
|
12827
|
+
await refresh(conversations.map(({ record: record2 }) => key2("conversation", record2.id))).catch(
|
|
12828
|
+
() => void 0
|
|
12829
|
+
);
|
|
12830
|
+
for (const { record: record2 } of conversations) threads.delete(record2.id);
|
|
12831
|
+
channel?.postMessage("changed");
|
|
12832
|
+
emit({ type: "conversations", origin: "local" });
|
|
12833
|
+
for (const { record: record2 } of conversations)
|
|
12834
|
+
emit({ type: "messages", conversationId: record2.id, origin: "local" });
|
|
12835
|
+
}
|
|
12836
|
+
return { conversations: conversationCount, messages: messageCount };
|
|
12837
|
+
},
|
|
12755
12838
|
status: () => ({ pending: pending.size + inflight.size, ...stopped ? { stopped } : {} }),
|
|
12756
12839
|
close() {
|
|
12757
12840
|
closed = true;
|
|
@@ -27274,11 +27357,14 @@ var WatermelonChatStorageAdapter = class {
|
|
|
27274
27357
|
return searchChunksOp(this.ctx, queryVector, options);
|
|
27275
27358
|
}
|
|
27276
27359
|
getSummary(conversationId) {
|
|
27277
|
-
return getConversationSummaryOp(
|
|
27360
|
+
return getConversationSummaryOp(
|
|
27361
|
+
createSummaryContext(this.ctx.database, this.ctx),
|
|
27362
|
+
conversationId
|
|
27363
|
+
);
|
|
27278
27364
|
}
|
|
27279
27365
|
upsertSummary(conversationId, summary, summarizedUpTo, tokenCount) {
|
|
27280
27366
|
return upsertConversationSummaryOp(
|
|
27281
|
-
createSummaryContext(this.ctx.database),
|
|
27367
|
+
createSummaryContext(this.ctx.database, this.ctx),
|
|
27282
27368
|
conversationId,
|
|
27283
27369
|
summary,
|
|
27284
27370
|
summarizedUpTo,
|
|
@@ -29413,7 +29499,7 @@ async function summarizeHistoryAtRevision(options, revision2) {
|
|
|
29413
29499
|
const cachedSummary = await summaryStore(options).getSummary(conversationId);
|
|
29414
29500
|
return {
|
|
29415
29501
|
messagesToConvert: messages,
|
|
29416
|
-
summarySystemMessage: cachedSummary?.summary ? summaryToSystemMessage(cachedSummary.summary) : null
|
|
29502
|
+
summarySystemMessage: cachedSummary?.summary && !isEncrypted(cachedSummary.summary) ? summaryToSystemMessage(cachedSummary.summary) : null
|
|
29417
29503
|
};
|
|
29418
29504
|
} catch {
|
|
29419
29505
|
return { messagesToConvert: messages, summarySystemMessage: null };
|
|
@@ -29468,14 +29554,15 @@ async function doSummarizeHistory(options, revision2) {
|
|
|
29468
29554
|
} = options;
|
|
29469
29555
|
try {
|
|
29470
29556
|
const summaries = summaryStore(options);
|
|
29471
|
-
const persistSummary = (summary, summarizedUpTo, tokenCount) =>
|
|
29557
|
+
const persistSummary = (summary, summarizedUpTo, tokenCount) => {
|
|
29472
29558
|
assertConversationRevision(database, conversationId, revision2);
|
|
29473
|
-
|
|
29474
|
-
|
|
29475
|
-
);
|
|
29476
|
-
});
|
|
29559
|
+
return summaries.upsertSummary(conversationId, summary, summarizedUpTo, tokenCount);
|
|
29560
|
+
};
|
|
29477
29561
|
let cachedSummary = await summaries.getSummary(conversationId);
|
|
29478
29562
|
assertConversationRevision(database, conversationId, revision2);
|
|
29563
|
+
if (cachedSummary && isEncrypted(cachedSummary.summary)) {
|
|
29564
|
+
throw new Error("The cached summary could not be decrypted");
|
|
29565
|
+
}
|
|
29479
29566
|
const lastCompacted = lastCompactionTime.get(conversationId) ?? 0;
|
|
29480
29567
|
const compactionCooledDown = Date.now() - lastCompacted > COMPACTION_COOLDOWN_MS;
|
|
29481
29568
|
if (cachedSummary && cachedSummary.tokenCount > summaryTokenThreshold * MAX_SUMMARY_TOKEN_RATIO && compactionCooledDown) {
|