@anuma/sdk 1.1.5 → 1.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/{chunk-IKPPX3GY.mjs → chunk-OZ357R4P.mjs} +75 -40
- package/dist/expo/index.cjs +104 -42
- package/dist/expo/index.d.mts +15 -0
- package/dist/expo/index.d.ts +15 -0
- package/dist/expo/index.mjs +30 -3
- package/dist/expo/{recall-4JTNZBAW.mjs → recall-EMFBX3WU.mjs} +1 -1
- package/dist/index.cjs +1 -0
- package/dist/index.mjs +1 -0
- package/dist/react/{chunk-KQZ4KVYY.mjs → chunk-DC6J5RX5.mjs} +75 -40
- package/dist/react/index.cjs +104 -42
- package/dist/react/index.d.mts +15 -0
- package/dist/react/index.d.ts +15 -0
- package/dist/react/index.mjs +30 -3
- package/dist/react/{recall-Z2HUBS2Y.mjs → recall-RGKS2OIP.mjs} +1 -1
- package/dist/server/{chunk-KLJBJWWI.mjs → chunk-MKRSHU4S.mjs} +1 -1
- package/dist/server/index.cjs +30 -2
- package/dist/server/index.d.mts +15 -0
- package/dist/server/index.d.ts +15 -0
- package/dist/server/index.mjs +31 -3
- package/dist/server/{recall-IF2HX7ZA.mjs → recall-V4763HKS.mjs} +1 -1
- package/dist/tools/index.cjs +412 -58
- package/dist/tools/index.d.mts +14 -3
- package/dist/tools/index.d.ts +14 -3
- package/dist/tools/index.mjs +412 -58
- package/package.json +1 -1
|
@@ -1210,50 +1210,85 @@ async function getMessagesPageOp(ctx, convId, opts) {
|
|
|
1210
1210
|
)
|
|
1211
1211
|
);
|
|
1212
1212
|
}
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1213
|
+
var SKELETON_PAGE_SIZE = 2e3;
|
|
1214
|
+
function narrowSkeletonRow(raw) {
|
|
1215
|
+
return {
|
|
1216
|
+
id: raw.id,
|
|
1217
|
+
message_id: raw.message_id,
|
|
1218
|
+
conversation_id: raw.conversation_id,
|
|
1219
|
+
role: raw.role,
|
|
1220
|
+
created_at: raw.created_at,
|
|
1221
|
+
parent_message_id: raw.parent_message_id ?? null,
|
|
1222
|
+
model: raw.model ?? null,
|
|
1223
|
+
content: raw.content ?? null
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
async function fetchThreadSkeletonRawPaged(collection, convId, pageSize = SKELETON_PAGE_SIZE) {
|
|
1227
|
+
const all = [];
|
|
1228
|
+
let cursor;
|
|
1229
|
+
for (; ; ) {
|
|
1230
|
+
const clauses = [Q.where("conversation_id", convId)];
|
|
1231
|
+
if (cursor) {
|
|
1232
|
+
clauses.push(
|
|
1233
|
+
Q.or(
|
|
1234
|
+
Q.where("message_id", Q.gt(cursor.messageId)),
|
|
1235
|
+
Q.and(Q.where("message_id", cursor.messageId), Q.where("id", Q.gt(cursor.id)))
|
|
1236
|
+
)
|
|
1237
|
+
);
|
|
1236
1238
|
}
|
|
1239
|
+
const page = await collection.query(...clauses, Q.sortBy("message_id", Q.asc), Q.sortBy("id", Q.asc), Q.take(pageSize)).unsafeFetchRaw();
|
|
1240
|
+
if (page.length === 0) break;
|
|
1241
|
+
for (const raw of page) all.push(narrowSkeletonRow(raw));
|
|
1242
|
+
if (page.length < pageSize) break;
|
|
1243
|
+
const last = all[all.length - 1];
|
|
1244
|
+
cursor = { messageId: last.message_id, id: last.id };
|
|
1245
|
+
}
|
|
1246
|
+
return all;
|
|
1247
|
+
}
|
|
1248
|
+
function collectArtifactIndices(rows, roleById) {
|
|
1249
|
+
const indices = [];
|
|
1250
|
+
for (let i = 0; i < rows.length; i++) {
|
|
1251
|
+
const row = rows[i];
|
|
1252
|
+
if (row.role !== "user" || !row.parent_message_id) continue;
|
|
1253
|
+
if (roleById.get(row.parent_message_id) === "user") indices.push(i);
|
|
1237
1254
|
}
|
|
1255
|
+
return indices;
|
|
1256
|
+
}
|
|
1257
|
+
async function decryptArtifactContent(skeletons, rows, artifactIndices, ctx) {
|
|
1238
1258
|
const address = ctx.walletAddress;
|
|
1239
|
-
if (artifactIndices.length
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
}
|
|
1247
|
-
|
|
1248
|
-
artifactIndices.map(async (i) => {
|
|
1249
|
-
skeletons[i].content = await decryptField(results[i].content, address);
|
|
1250
|
-
})
|
|
1251
|
-
);
|
|
1252
|
-
} else {
|
|
1253
|
-
for (const i of artifactIndices) {
|
|
1254
|
-
skeletons[i].content = results[i].content;
|
|
1259
|
+
if (artifactIndices.length === 0 || !address) {
|
|
1260
|
+
for (const i of artifactIndices) skeletons[i].content = rows[i].content ?? void 0;
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
if (ctx.signMessage) {
|
|
1264
|
+
try {
|
|
1265
|
+
await requestEncryptionKey(address, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
1266
|
+
} catch (error) {
|
|
1267
|
+
getLogger().warn("Failed to request encryption key for skeleton decryption:", error);
|
|
1255
1268
|
}
|
|
1256
1269
|
}
|
|
1270
|
+
await Promise.all(
|
|
1271
|
+
artifactIndices.map(async (i) => {
|
|
1272
|
+
skeletons[i].content = await decryptField(rows[i].content ?? "", address);
|
|
1273
|
+
})
|
|
1274
|
+
);
|
|
1275
|
+
}
|
|
1276
|
+
async function getMessageSkeletonsOp(ctx, convId) {
|
|
1277
|
+
const rows = await fetchThreadSkeletonRawPaged(ctx.messagesCollection, convId);
|
|
1278
|
+
const roleById = /* @__PURE__ */ new Map();
|
|
1279
|
+
for (const row of rows) roleById.set(row.id, row.role);
|
|
1280
|
+
const skeletons = rows.map((row) => ({
|
|
1281
|
+
uniqueId: row.id,
|
|
1282
|
+
messageId: row.message_id,
|
|
1283
|
+
conversationId: String(row.conversation_id),
|
|
1284
|
+
role: row.role,
|
|
1285
|
+
createdAt: new Date(row.created_at),
|
|
1286
|
+
// WatermelonDB surfaces unset text columns as null at runtime — normalize
|
|
1287
|
+
// to undefined so `parentMessageId ?? undefined` keying works everywhere.
|
|
1288
|
+
parentMessageId: row.parent_message_id ?? void 0,
|
|
1289
|
+
model: row.model ?? void 0
|
|
1290
|
+
}));
|
|
1291
|
+
await decryptArtifactContent(skeletons, rows, collectArtifactIndices(rows, roleById), ctx);
|
|
1257
1292
|
return skeletons;
|
|
1258
1293
|
}
|
|
1259
1294
|
async function clearMessagesOp(ctx, convId) {
|
|
@@ -4680,7 +4715,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
4680
4715
|
legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
|
|
4681
4716
|
);
|
|
4682
4717
|
}
|
|
4683
|
-
const { recall: recall2 } = await import("./recall-
|
|
4718
|
+
const { recall: recall2 } = await import("./recall-EMFBX3WU.mjs");
|
|
4684
4719
|
const result = await recall2(
|
|
4685
4720
|
query,
|
|
4686
4721
|
{ vaultCtx, embeddingOptions, vaultCache: cache },
|
package/dist/expo/index.cjs
CHANGED
|
@@ -2265,50 +2265,84 @@ async function getMessagesPageOp(ctx, convId, opts) {
|
|
|
2265
2265
|
)
|
|
2266
2266
|
);
|
|
2267
2267
|
}
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2268
|
+
function narrowSkeletonRow(raw) {
|
|
2269
|
+
return {
|
|
2270
|
+
id: raw.id,
|
|
2271
|
+
message_id: raw.message_id,
|
|
2272
|
+
conversation_id: raw.conversation_id,
|
|
2273
|
+
role: raw.role,
|
|
2274
|
+
created_at: raw.created_at,
|
|
2275
|
+
parent_message_id: raw.parent_message_id ?? null,
|
|
2276
|
+
model: raw.model ?? null,
|
|
2277
|
+
content: raw.content ?? null
|
|
2278
|
+
};
|
|
2279
|
+
}
|
|
2280
|
+
async function fetchThreadSkeletonRawPaged(collection, convId, pageSize = SKELETON_PAGE_SIZE) {
|
|
2281
|
+
const all = [];
|
|
2282
|
+
let cursor;
|
|
2283
|
+
for (; ; ) {
|
|
2284
|
+
const clauses = [import_watermelondb.Q.where("conversation_id", convId)];
|
|
2285
|
+
if (cursor) {
|
|
2286
|
+
clauses.push(
|
|
2287
|
+
import_watermelondb.Q.or(
|
|
2288
|
+
import_watermelondb.Q.where("message_id", import_watermelondb.Q.gt(cursor.messageId)),
|
|
2289
|
+
import_watermelondb.Q.and(import_watermelondb.Q.where("message_id", cursor.messageId), import_watermelondb.Q.where("id", import_watermelondb.Q.gt(cursor.id)))
|
|
2290
|
+
)
|
|
2291
|
+
);
|
|
2291
2292
|
}
|
|
2293
|
+
const page = await collection.query(...clauses, import_watermelondb.Q.sortBy("message_id", import_watermelondb.Q.asc), import_watermelondb.Q.sortBy("id", import_watermelondb.Q.asc), import_watermelondb.Q.take(pageSize)).unsafeFetchRaw();
|
|
2294
|
+
if (page.length === 0) break;
|
|
2295
|
+
for (const raw of page) all.push(narrowSkeletonRow(raw));
|
|
2296
|
+
if (page.length < pageSize) break;
|
|
2297
|
+
const last = all[all.length - 1];
|
|
2298
|
+
cursor = { messageId: last.message_id, id: last.id };
|
|
2299
|
+
}
|
|
2300
|
+
return all;
|
|
2301
|
+
}
|
|
2302
|
+
function collectArtifactIndices(rows, roleById) {
|
|
2303
|
+
const indices = [];
|
|
2304
|
+
for (let i = 0; i < rows.length; i++) {
|
|
2305
|
+
const row = rows[i];
|
|
2306
|
+
if (row.role !== "user" || !row.parent_message_id) continue;
|
|
2307
|
+
if (roleById.get(row.parent_message_id) === "user") indices.push(i);
|
|
2292
2308
|
}
|
|
2309
|
+
return indices;
|
|
2310
|
+
}
|
|
2311
|
+
async function decryptArtifactContent(skeletons, rows, artifactIndices, ctx) {
|
|
2293
2312
|
const address = ctx.walletAddress;
|
|
2294
|
-
if (artifactIndices.length
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
}
|
|
2302
|
-
|
|
2303
|
-
artifactIndices.map(async (i) => {
|
|
2304
|
-
skeletons[i].content = await decryptField(results[i].content, address);
|
|
2305
|
-
})
|
|
2306
|
-
);
|
|
2307
|
-
} else {
|
|
2308
|
-
for (const i of artifactIndices) {
|
|
2309
|
-
skeletons[i].content = results[i].content;
|
|
2313
|
+
if (artifactIndices.length === 0 || !address) {
|
|
2314
|
+
for (const i of artifactIndices) skeletons[i].content = rows[i].content ?? void 0;
|
|
2315
|
+
return;
|
|
2316
|
+
}
|
|
2317
|
+
if (ctx.signMessage) {
|
|
2318
|
+
try {
|
|
2319
|
+
await requestEncryptionKey(address, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
2320
|
+
} catch (error) {
|
|
2321
|
+
getLogger().warn("Failed to request encryption key for skeleton decryption:", error);
|
|
2310
2322
|
}
|
|
2311
2323
|
}
|
|
2324
|
+
await Promise.all(
|
|
2325
|
+
artifactIndices.map(async (i) => {
|
|
2326
|
+
skeletons[i].content = await decryptField(rows[i].content ?? "", address);
|
|
2327
|
+
})
|
|
2328
|
+
);
|
|
2329
|
+
}
|
|
2330
|
+
async function getMessageSkeletonsOp(ctx, convId) {
|
|
2331
|
+
const rows = await fetchThreadSkeletonRawPaged(ctx.messagesCollection, convId);
|
|
2332
|
+
const roleById = /* @__PURE__ */ new Map();
|
|
2333
|
+
for (const row of rows) roleById.set(row.id, row.role);
|
|
2334
|
+
const skeletons = rows.map((row) => ({
|
|
2335
|
+
uniqueId: row.id,
|
|
2336
|
+
messageId: row.message_id,
|
|
2337
|
+
conversationId: String(row.conversation_id),
|
|
2338
|
+
role: row.role,
|
|
2339
|
+
createdAt: new Date(row.created_at),
|
|
2340
|
+
// WatermelonDB surfaces unset text columns as null at runtime — normalize
|
|
2341
|
+
// to undefined so `parentMessageId ?? undefined` keying works everywhere.
|
|
2342
|
+
parentMessageId: row.parent_message_id ?? void 0,
|
|
2343
|
+
model: row.model ?? void 0
|
|
2344
|
+
}));
|
|
2345
|
+
await decryptArtifactContent(skeletons, rows, collectArtifactIndices(rows, roleById), ctx);
|
|
2312
2346
|
return skeletons;
|
|
2313
2347
|
}
|
|
2314
2348
|
async function clearMessagesOp(ctx, convId) {
|
|
@@ -2646,7 +2680,7 @@ function makeSyntheticStoredConversation(opts, defaultTitle) {
|
|
|
2646
2680
|
isDeleted: false
|
|
2647
2681
|
};
|
|
2648
2682
|
}
|
|
2649
|
-
var import_watermelondb, import_uuid2;
|
|
2683
|
+
var import_watermelondb, import_uuid2, SKELETON_PAGE_SIZE;
|
|
2650
2684
|
var init_operations = __esm({
|
|
2651
2685
|
"src/lib/db/chat/operations.ts"() {
|
|
2652
2686
|
"use strict";
|
|
@@ -2659,6 +2693,7 @@ var init_operations = __esm({
|
|
|
2659
2693
|
init_conversationEncryption();
|
|
2660
2694
|
init_encryption();
|
|
2661
2695
|
init_types2();
|
|
2696
|
+
SKELETON_PAGE_SIZE = 2e3;
|
|
2662
2697
|
}
|
|
2663
2698
|
});
|
|
2664
2699
|
|
|
@@ -16747,6 +16782,7 @@ var DatabaseManager = class {
|
|
|
16747
16782
|
from: this.currentWalletAddress,
|
|
16748
16783
|
to: walletAddress
|
|
16749
16784
|
});
|
|
16785
|
+
void this.disposeAdapter(this.database);
|
|
16750
16786
|
this.database = null;
|
|
16751
16787
|
}
|
|
16752
16788
|
if (this.database) {
|
|
@@ -16776,11 +16812,37 @@ var DatabaseManager = class {
|
|
|
16776
16812
|
async resetDatabase() {
|
|
16777
16813
|
const db = this.database;
|
|
16778
16814
|
if (db) {
|
|
16815
|
+
this.database = null;
|
|
16816
|
+
this.currentWalletAddress = void 0;
|
|
16779
16817
|
await db.write(async () => {
|
|
16780
16818
|
await db.unsafeResetDatabase();
|
|
16781
16819
|
});
|
|
16782
|
-
this.
|
|
16783
|
-
|
|
16820
|
+
await this.disposeAdapter(db);
|
|
16821
|
+
}
|
|
16822
|
+
}
|
|
16823
|
+
/**
|
|
16824
|
+
* Best-effort dispose of the adapter backing a Database, if it exposes one.
|
|
16825
|
+
*
|
|
16826
|
+
* OPFS/SQLite adapters use this to terminate their dedicated worker and release
|
|
16827
|
+
* the exclusive SAHPool (+ WASM heap) they hold. The SDK only sees a generic
|
|
16828
|
+
* `DatabaseAdapter`, so we probe `adapter.underlyingAdapter.dispose` rather than
|
|
16829
|
+
* type it. Client-side implementations are refcounted + idempotent, so calling
|
|
16830
|
+
* this is safe even when the adapter factory also disposes.
|
|
16831
|
+
*
|
|
16832
|
+
* Awaitable and never rejects: a sync throw or async rejection from `dispose`
|
|
16833
|
+
* is caught + logged. Awaited on the async `resetDatabase` path so teardown
|
|
16834
|
+
* completes before the caller reopens; fire-and-forget on the synchronous
|
|
16835
|
+
* `getDatabase` path (which cannot block).
|
|
16836
|
+
*/
|
|
16837
|
+
async disposeAdapter(db) {
|
|
16838
|
+
try {
|
|
16839
|
+
const underlying = db.adapter?.underlyingAdapter;
|
|
16840
|
+
await underlying?.dispose?.();
|
|
16841
|
+
} catch (error) {
|
|
16842
|
+
this.logger.warn?.("Adapter dispose failed", {
|
|
16843
|
+
component: "DatabaseManager",
|
|
16844
|
+
error
|
|
16845
|
+
});
|
|
16784
16846
|
}
|
|
16785
16847
|
}
|
|
16786
16848
|
/**
|
package/dist/expo/index.d.mts
CHANGED
|
@@ -6568,6 +6568,21 @@ declare class DatabaseManager {
|
|
|
6568
6568
|
* Reset the current database (useful for logout or testing).
|
|
6569
6569
|
*/
|
|
6570
6570
|
resetDatabase(): Promise<void>;
|
|
6571
|
+
/**
|
|
6572
|
+
* Best-effort dispose of the adapter backing a Database, if it exposes one.
|
|
6573
|
+
*
|
|
6574
|
+
* OPFS/SQLite adapters use this to terminate their dedicated worker and release
|
|
6575
|
+
* the exclusive SAHPool (+ WASM heap) they hold. The SDK only sees a generic
|
|
6576
|
+
* `DatabaseAdapter`, so we probe `adapter.underlyingAdapter.dispose` rather than
|
|
6577
|
+
* type it. Client-side implementations are refcounted + idempotent, so calling
|
|
6578
|
+
* this is safe even when the adapter factory also disposes.
|
|
6579
|
+
*
|
|
6580
|
+
* Awaitable and never rejects: a sync throw or async rejection from `dispose`
|
|
6581
|
+
* is caught + logged. Awaited on the async `resetDatabase` path so teardown
|
|
6582
|
+
* completes before the caller reopens; fire-and-forget on the synchronous
|
|
6583
|
+
* `getDatabase` path (which cannot block).
|
|
6584
|
+
*/
|
|
6585
|
+
private disposeAdapter;
|
|
6571
6586
|
/**
|
|
6572
6587
|
* Check and handle schema migrations for a specific wallet.
|
|
6573
6588
|
* Returns true if a destructive migration is in progress.
|
package/dist/expo/index.d.ts
CHANGED
|
@@ -6568,6 +6568,21 @@ declare class DatabaseManager {
|
|
|
6568
6568
|
* Reset the current database (useful for logout or testing).
|
|
6569
6569
|
*/
|
|
6570
6570
|
resetDatabase(): Promise<void>;
|
|
6571
|
+
/**
|
|
6572
|
+
* Best-effort dispose of the adapter backing a Database, if it exposes one.
|
|
6573
|
+
*
|
|
6574
|
+
* OPFS/SQLite adapters use this to terminate their dedicated worker and release
|
|
6575
|
+
* the exclusive SAHPool (+ WASM heap) they hold. The SDK only sees a generic
|
|
6576
|
+
* `DatabaseAdapter`, so we probe `adapter.underlyingAdapter.dispose` rather than
|
|
6577
|
+
* type it. Client-side implementations are refcounted + idempotent, so calling
|
|
6578
|
+
* this is safe even when the adapter factory also disposes.
|
|
6579
|
+
*
|
|
6580
|
+
* Awaitable and never rejects: a sync throw or async rejection from `dispose`
|
|
6581
|
+
* is caught + logged. Awaited on the async `resetDatabase` path so teardown
|
|
6582
|
+
* completes before the caller reopens; fire-and-forget on the synchronous
|
|
6583
|
+
* `getDatabase` path (which cannot block).
|
|
6584
|
+
*/
|
|
6585
|
+
private disposeAdapter;
|
|
6571
6586
|
/**
|
|
6572
6587
|
* Check and handle schema migrations for a specific wallet.
|
|
6573
6588
|
* Returns true if a destructive migration is in progress.
|
package/dist/expo/index.mjs
CHANGED
|
@@ -79,7 +79,7 @@ import {
|
|
|
79
79
|
updateVaultMemoryOp,
|
|
80
80
|
upsertMessageOp,
|
|
81
81
|
useEncryption
|
|
82
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-OZ357R4P.mjs";
|
|
83
83
|
import {
|
|
84
84
|
PII_PATTERNS,
|
|
85
85
|
PiiRedactor,
|
|
@@ -10004,6 +10004,7 @@ var DatabaseManager = class {
|
|
|
10004
10004
|
from: this.currentWalletAddress,
|
|
10005
10005
|
to: walletAddress
|
|
10006
10006
|
});
|
|
10007
|
+
void this.disposeAdapter(this.database);
|
|
10007
10008
|
this.database = null;
|
|
10008
10009
|
}
|
|
10009
10010
|
if (this.database) {
|
|
@@ -10033,11 +10034,37 @@ var DatabaseManager = class {
|
|
|
10033
10034
|
async resetDatabase() {
|
|
10034
10035
|
const db = this.database;
|
|
10035
10036
|
if (db) {
|
|
10037
|
+
this.database = null;
|
|
10038
|
+
this.currentWalletAddress = void 0;
|
|
10036
10039
|
await db.write(async () => {
|
|
10037
10040
|
await db.unsafeResetDatabase();
|
|
10038
10041
|
});
|
|
10039
|
-
this.
|
|
10040
|
-
|
|
10042
|
+
await this.disposeAdapter(db);
|
|
10043
|
+
}
|
|
10044
|
+
}
|
|
10045
|
+
/**
|
|
10046
|
+
* Best-effort dispose of the adapter backing a Database, if it exposes one.
|
|
10047
|
+
*
|
|
10048
|
+
* OPFS/SQLite adapters use this to terminate their dedicated worker and release
|
|
10049
|
+
* the exclusive SAHPool (+ WASM heap) they hold. The SDK only sees a generic
|
|
10050
|
+
* `DatabaseAdapter`, so we probe `adapter.underlyingAdapter.dispose` rather than
|
|
10051
|
+
* type it. Client-side implementations are refcounted + idempotent, so calling
|
|
10052
|
+
* this is safe even when the adapter factory also disposes.
|
|
10053
|
+
*
|
|
10054
|
+
* Awaitable and never rejects: a sync throw or async rejection from `dispose`
|
|
10055
|
+
* is caught + logged. Awaited on the async `resetDatabase` path so teardown
|
|
10056
|
+
* completes before the caller reopens; fire-and-forget on the synchronous
|
|
10057
|
+
* `getDatabase` path (which cannot block).
|
|
10058
|
+
*/
|
|
10059
|
+
async disposeAdapter(db) {
|
|
10060
|
+
try {
|
|
10061
|
+
const underlying = db.adapter?.underlyingAdapter;
|
|
10062
|
+
await underlying?.dispose?.();
|
|
10063
|
+
} catch (error) {
|
|
10064
|
+
this.logger.warn?.("Adapter dispose failed", {
|
|
10065
|
+
component: "DatabaseManager",
|
|
10066
|
+
error
|
|
10067
|
+
});
|
|
10041
10068
|
}
|
|
10042
10069
|
}
|
|
10043
10070
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -2942,6 +2942,7 @@ var TOOL_CATALOG = {
|
|
|
2942
2942
|
// Slack (src/tools/slack.ts)
|
|
2943
2943
|
slack_get_me: { label: "Get my Slack profile", provider: "slack", connector: "Slack" },
|
|
2944
2944
|
slack_list_channels: { label: "List channels", provider: "slack", connector: "Slack" },
|
|
2945
|
+
slack_list_dms: { label: "List direct messages", provider: "slack", connector: "Slack" },
|
|
2945
2946
|
slack_search_messages: { label: "Search messages", provider: "slack", connector: "Slack" },
|
|
2946
2947
|
slack_list_users: { label: "List members", provider: "slack", connector: "Slack" },
|
|
2947
2948
|
slack_get_channel_history: {
|
package/dist/index.mjs
CHANGED
|
@@ -2751,6 +2751,7 @@ var TOOL_CATALOG = {
|
|
|
2751
2751
|
// Slack (src/tools/slack.ts)
|
|
2752
2752
|
slack_get_me: { label: "Get my Slack profile", provider: "slack", connector: "Slack" },
|
|
2753
2753
|
slack_list_channels: { label: "List channels", provider: "slack", connector: "Slack" },
|
|
2754
|
+
slack_list_dms: { label: "List direct messages", provider: "slack", connector: "Slack" },
|
|
2754
2755
|
slack_search_messages: { label: "Search messages", provider: "slack", connector: "Slack" },
|
|
2755
2756
|
slack_list_users: { label: "List members", provider: "slack", connector: "Slack" },
|
|
2756
2757
|
slack_get_channel_history: {
|
|
@@ -1291,50 +1291,85 @@ async function getMessagesPageOp(ctx, convId, opts) {
|
|
|
1291
1291
|
)
|
|
1292
1292
|
);
|
|
1293
1293
|
}
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1294
|
+
var SKELETON_PAGE_SIZE = 2e3;
|
|
1295
|
+
function narrowSkeletonRow(raw) {
|
|
1296
|
+
return {
|
|
1297
|
+
id: raw.id,
|
|
1298
|
+
message_id: raw.message_id,
|
|
1299
|
+
conversation_id: raw.conversation_id,
|
|
1300
|
+
role: raw.role,
|
|
1301
|
+
created_at: raw.created_at,
|
|
1302
|
+
parent_message_id: raw.parent_message_id ?? null,
|
|
1303
|
+
model: raw.model ?? null,
|
|
1304
|
+
content: raw.content ?? null
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
async function fetchThreadSkeletonRawPaged(collection, convId, pageSize = SKELETON_PAGE_SIZE) {
|
|
1308
|
+
const all = [];
|
|
1309
|
+
let cursor;
|
|
1310
|
+
for (; ; ) {
|
|
1311
|
+
const clauses = [Q.where("conversation_id", convId)];
|
|
1312
|
+
if (cursor) {
|
|
1313
|
+
clauses.push(
|
|
1314
|
+
Q.or(
|
|
1315
|
+
Q.where("message_id", Q.gt(cursor.messageId)),
|
|
1316
|
+
Q.and(Q.where("message_id", cursor.messageId), Q.where("id", Q.gt(cursor.id)))
|
|
1317
|
+
)
|
|
1318
|
+
);
|
|
1317
1319
|
}
|
|
1320
|
+
const page = await collection.query(...clauses, Q.sortBy("message_id", Q.asc), Q.sortBy("id", Q.asc), Q.take(pageSize)).unsafeFetchRaw();
|
|
1321
|
+
if (page.length === 0) break;
|
|
1322
|
+
for (const raw of page) all.push(narrowSkeletonRow(raw));
|
|
1323
|
+
if (page.length < pageSize) break;
|
|
1324
|
+
const last = all[all.length - 1];
|
|
1325
|
+
cursor = { messageId: last.message_id, id: last.id };
|
|
1326
|
+
}
|
|
1327
|
+
return all;
|
|
1328
|
+
}
|
|
1329
|
+
function collectArtifactIndices(rows, roleById) {
|
|
1330
|
+
const indices = [];
|
|
1331
|
+
for (let i = 0; i < rows.length; i++) {
|
|
1332
|
+
const row = rows[i];
|
|
1333
|
+
if (row.role !== "user" || !row.parent_message_id) continue;
|
|
1334
|
+
if (roleById.get(row.parent_message_id) === "user") indices.push(i);
|
|
1318
1335
|
}
|
|
1336
|
+
return indices;
|
|
1337
|
+
}
|
|
1338
|
+
async function decryptArtifactContent(skeletons, rows, artifactIndices, ctx) {
|
|
1319
1339
|
const address = ctx.walletAddress;
|
|
1320
|
-
if (artifactIndices.length
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
artifactIndices.map(async (i) => {
|
|
1330
|
-
skeletons[i].content = await decryptField(results[i].content, address);
|
|
1331
|
-
})
|
|
1332
|
-
);
|
|
1333
|
-
} else {
|
|
1334
|
-
for (const i of artifactIndices) {
|
|
1335
|
-
skeletons[i].content = results[i].content;
|
|
1340
|
+
if (artifactIndices.length === 0 || !address) {
|
|
1341
|
+
for (const i of artifactIndices) skeletons[i].content = rows[i].content ?? void 0;
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1344
|
+
if (ctx.signMessage) {
|
|
1345
|
+
try {
|
|
1346
|
+
await requestEncryptionKey(address, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
1347
|
+
} catch (error) {
|
|
1348
|
+
getLogger().warn("Failed to request encryption key for skeleton decryption:", error);
|
|
1336
1349
|
}
|
|
1337
1350
|
}
|
|
1351
|
+
await Promise.all(
|
|
1352
|
+
artifactIndices.map(async (i) => {
|
|
1353
|
+
skeletons[i].content = await decryptField(rows[i].content ?? "", address);
|
|
1354
|
+
})
|
|
1355
|
+
);
|
|
1356
|
+
}
|
|
1357
|
+
async function getMessageSkeletonsOp(ctx, convId) {
|
|
1358
|
+
const rows = await fetchThreadSkeletonRawPaged(ctx.messagesCollection, convId);
|
|
1359
|
+
const roleById = /* @__PURE__ */ new Map();
|
|
1360
|
+
for (const row of rows) roleById.set(row.id, row.role);
|
|
1361
|
+
const skeletons = rows.map((row) => ({
|
|
1362
|
+
uniqueId: row.id,
|
|
1363
|
+
messageId: row.message_id,
|
|
1364
|
+
conversationId: String(row.conversation_id),
|
|
1365
|
+
role: row.role,
|
|
1366
|
+
createdAt: new Date(row.created_at),
|
|
1367
|
+
// WatermelonDB surfaces unset text columns as null at runtime — normalize
|
|
1368
|
+
// to undefined so `parentMessageId ?? undefined` keying works everywhere.
|
|
1369
|
+
parentMessageId: row.parent_message_id ?? void 0,
|
|
1370
|
+
model: row.model ?? void 0
|
|
1371
|
+
}));
|
|
1372
|
+
await decryptArtifactContent(skeletons, rows, collectArtifactIndices(rows, roleById), ctx);
|
|
1338
1373
|
return skeletons;
|
|
1339
1374
|
}
|
|
1340
1375
|
async function clearMessagesOp(ctx, convId) {
|
|
@@ -5011,7 +5046,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
5011
5046
|
legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
|
|
5012
5047
|
);
|
|
5013
5048
|
}
|
|
5014
|
-
const { recall: recall2 } = await import("./recall-
|
|
5049
|
+
const { recall: recall2 } = await import("./recall-RGKS2OIP.mjs");
|
|
5015
5050
|
const result = await recall2(
|
|
5016
5051
|
query,
|
|
5017
5052
|
{ vaultCtx, embeddingOptions, vaultCache: cache },
|