@anuma/sdk 1.1.6 → 1.2.1

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.
@@ -1210,85 +1210,50 @@ async function getMessagesPageOp(ctx, convId, opts) {
1210
1210
  )
1211
1211
  );
1212
1212
  }
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
- );
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);
1254
- }
1255
- return indices;
1256
- }
1257
- async function decryptArtifactContent(skeletons, rows, artifactIndices, ctx) {
1258
- const address = ctx.walletAddress;
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);
1268
- }
1269
- }
1270
- await Promise.all(
1271
- artifactIndices.map(async (i) => {
1272
- skeletons[i].content = await decryptField(rows[i].content ?? "", address);
1273
- })
1274
- );
1275
- }
1276
1213
  async function getMessageSkeletonsOp(ctx, convId) {
1277
- const rows = await fetchThreadSkeletonRawPaged(ctx.messagesCollection, convId);
1214
+ const results = await ctx.messagesCollection.query(Q.where("conversation_id", convId), Q.sortBy("message_id", Q.asc)).fetch();
1278
1215
  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),
1216
+ for (const msg of results) {
1217
+ roleById.set(msg.id, msg.role);
1218
+ }
1219
+ const skeletons = results.map((msg) => ({
1220
+ uniqueId: msg.id,
1221
+ messageId: msg.messageId,
1222
+ conversationId: String(msg._getRaw("conversation_id")),
1223
+ role: msg.role,
1224
+ createdAt: msg.createdAt,
1286
1225
  // WatermelonDB surfaces unset text columns as null at runtime — normalize
1287
1226
  // to undefined so `parentMessageId ?? undefined` keying works everywhere.
1288
- parentMessageId: row.parent_message_id ?? void 0,
1289
- model: row.model ?? void 0
1227
+ parentMessageId: msg.parentMessageId ?? void 0,
1228
+ model: msg.model ?? void 0
1290
1229
  }));
1291
- await decryptArtifactContent(skeletons, rows, collectArtifactIndices(rows, roleById), ctx);
1230
+ const artifactIndices = [];
1231
+ for (let i = 0; i < results.length; i++) {
1232
+ const msg = results[i];
1233
+ if (msg.role !== "user" || !msg.parentMessageId) continue;
1234
+ if (roleById.get(msg.parentMessageId) === "user") {
1235
+ artifactIndices.push(i);
1236
+ }
1237
+ }
1238
+ const address = ctx.walletAddress;
1239
+ if (artifactIndices.length > 0 && address) {
1240
+ if (ctx.signMessage) {
1241
+ try {
1242
+ await requestEncryptionKey(address, ctx.signMessage, ctx.embeddedWalletSigner);
1243
+ } catch (error) {
1244
+ getLogger().warn("Failed to request encryption key for skeleton decryption:", error);
1245
+ }
1246
+ }
1247
+ await Promise.all(
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;
1255
+ }
1256
+ }
1292
1257
  return skeletons;
1293
1258
  }
1294
1259
  async function clearMessagesOp(ctx, convId) {
@@ -4715,7 +4680,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
4715
4680
  legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
4716
4681
  );
4717
4682
  }
4718
- const { recall: recall2 } = await import("./recall-EMFBX3WU.mjs");
4683
+ const { recall: recall2 } = await import("./recall-4JTNZBAW.mjs");
4719
4684
  const result = await recall2(
4720
4685
  query,
4721
4686
  { vaultCtx, embeddingOptions, vaultCache: cache },
@@ -2265,84 +2265,50 @@ async function getMessagesPageOp(ctx, convId, opts) {
2265
2265
  )
2266
2266
  );
2267
2267
  }
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
- );
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);
2308
- }
2309
- return indices;
2310
- }
2311
- async function decryptArtifactContent(skeletons, rows, artifactIndices, ctx) {
2312
- const address = ctx.walletAddress;
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);
2322
- }
2323
- }
2324
- await Promise.all(
2325
- artifactIndices.map(async (i) => {
2326
- skeletons[i].content = await decryptField(rows[i].content ?? "", address);
2327
- })
2328
- );
2329
- }
2330
2268
  async function getMessageSkeletonsOp(ctx, convId) {
2331
- const rows = await fetchThreadSkeletonRawPaged(ctx.messagesCollection, convId);
2269
+ const results = await ctx.messagesCollection.query(import_watermelondb.Q.where("conversation_id", convId), import_watermelondb.Q.sortBy("message_id", import_watermelondb.Q.asc)).fetch();
2332
2270
  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),
2271
+ for (const msg of results) {
2272
+ roleById.set(msg.id, msg.role);
2273
+ }
2274
+ const skeletons = results.map((msg) => ({
2275
+ uniqueId: msg.id,
2276
+ messageId: msg.messageId,
2277
+ conversationId: String(msg._getRaw("conversation_id")),
2278
+ role: msg.role,
2279
+ createdAt: msg.createdAt,
2340
2280
  // WatermelonDB surfaces unset text columns as null at runtime — normalize
2341
2281
  // to undefined so `parentMessageId ?? undefined` keying works everywhere.
2342
- parentMessageId: row.parent_message_id ?? void 0,
2343
- model: row.model ?? void 0
2282
+ parentMessageId: msg.parentMessageId ?? void 0,
2283
+ model: msg.model ?? void 0
2344
2284
  }));
2345
- await decryptArtifactContent(skeletons, rows, collectArtifactIndices(rows, roleById), ctx);
2285
+ const artifactIndices = [];
2286
+ for (let i = 0; i < results.length; i++) {
2287
+ const msg = results[i];
2288
+ if (msg.role !== "user" || !msg.parentMessageId) continue;
2289
+ if (roleById.get(msg.parentMessageId) === "user") {
2290
+ artifactIndices.push(i);
2291
+ }
2292
+ }
2293
+ const address = ctx.walletAddress;
2294
+ if (artifactIndices.length > 0 && address) {
2295
+ if (ctx.signMessage) {
2296
+ try {
2297
+ await requestEncryptionKey(address, ctx.signMessage, ctx.embeddedWalletSigner);
2298
+ } catch (error) {
2299
+ getLogger().warn("Failed to request encryption key for skeleton decryption:", error);
2300
+ }
2301
+ }
2302
+ await Promise.all(
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;
2310
+ }
2311
+ }
2346
2312
  return skeletons;
2347
2313
  }
2348
2314
  async function clearMessagesOp(ctx, convId) {
@@ -2680,7 +2646,7 @@ function makeSyntheticStoredConversation(opts, defaultTitle) {
2680
2646
  isDeleted: false
2681
2647
  };
2682
2648
  }
2683
- var import_watermelondb, import_uuid2, SKELETON_PAGE_SIZE;
2649
+ var import_watermelondb, import_uuid2;
2684
2650
  var init_operations = __esm({
2685
2651
  "src/lib/db/chat/operations.ts"() {
2686
2652
  "use strict";
@@ -2693,7 +2659,6 @@ var init_operations = __esm({
2693
2659
  init_conversationEncryption();
2694
2660
  init_encryption();
2695
2661
  init_types2();
2696
- SKELETON_PAGE_SIZE = 2e3;
2697
2662
  }
2698
2663
  });
2699
2664
 
@@ -16782,7 +16747,6 @@ var DatabaseManager = class {
16782
16747
  from: this.currentWalletAddress,
16783
16748
  to: walletAddress
16784
16749
  });
16785
- void this.disposeAdapter(this.database);
16786
16750
  this.database = null;
16787
16751
  }
16788
16752
  if (this.database) {
@@ -16812,37 +16776,11 @@ var DatabaseManager = class {
16812
16776
  async resetDatabase() {
16813
16777
  const db = this.database;
16814
16778
  if (db) {
16815
- this.database = null;
16816
- this.currentWalletAddress = void 0;
16817
16779
  await db.write(async () => {
16818
16780
  await db.unsafeResetDatabase();
16819
16781
  });
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
- });
16782
+ this.database = null;
16783
+ this.currentWalletAddress = void 0;
16846
16784
  }
16847
16785
  }
16848
16786
  /**
@@ -6568,21 +6568,6 @@ 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;
6586
6571
  /**
6587
6572
  * Check and handle schema migrations for a specific wallet.
6588
6573
  * Returns true if a destructive migration is in progress.
@@ -6568,21 +6568,6 @@ 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;
6586
6571
  /**
6587
6572
  * Check and handle schema migrations for a specific wallet.
6588
6573
  * Returns true if a destructive migration is in progress.
@@ -79,7 +79,7 @@ import {
79
79
  updateVaultMemoryOp,
80
80
  upsertMessageOp,
81
81
  useEncryption
82
- } from "./chunk-OZ357R4P.mjs";
82
+ } from "./chunk-IKPPX3GY.mjs";
83
83
  import {
84
84
  PII_PATTERNS,
85
85
  PiiRedactor,
@@ -10004,7 +10004,6 @@ var DatabaseManager = class {
10004
10004
  from: this.currentWalletAddress,
10005
10005
  to: walletAddress
10006
10006
  });
10007
- void this.disposeAdapter(this.database);
10008
10007
  this.database = null;
10009
10008
  }
10010
10009
  if (this.database) {
@@ -10034,37 +10033,11 @@ var DatabaseManager = class {
10034
10033
  async resetDatabase() {
10035
10034
  const db = this.database;
10036
10035
  if (db) {
10037
- this.database = null;
10038
- this.currentWalletAddress = void 0;
10039
10036
  await db.write(async () => {
10040
10037
  await db.unsafeResetDatabase();
10041
10038
  });
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
- });
10039
+ this.database = null;
10040
+ this.currentWalletAddress = void 0;
10068
10041
  }
10069
10042
  }
10070
10043
  /**
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-OZ357R4P.mjs";
3
+ } from "./chunk-IKPPX3GY.mjs";
4
4
  import "./chunk-DFVCS3QQ.mjs";
5
5
  import "./chunk-GYKJOWEO.mjs";
6
6
  export {
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,85 +1291,50 @@ async function getMessagesPageOp(ctx, convId, opts) {
1291
1291
  )
1292
1292
  );
1293
1293
  }
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
- );
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);
1335
- }
1336
- return indices;
1337
- }
1338
- async function decryptArtifactContent(skeletons, rows, artifactIndices, ctx) {
1339
- const address = ctx.walletAddress;
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);
1349
- }
1350
- }
1351
- await Promise.all(
1352
- artifactIndices.map(async (i) => {
1353
- skeletons[i].content = await decryptField(rows[i].content ?? "", address);
1354
- })
1355
- );
1356
- }
1357
1294
  async function getMessageSkeletonsOp(ctx, convId) {
1358
- const rows = await fetchThreadSkeletonRawPaged(ctx.messagesCollection, convId);
1295
+ const results = await ctx.messagesCollection.query(Q.where("conversation_id", convId), Q.sortBy("message_id", Q.asc)).fetch();
1359
1296
  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),
1297
+ for (const msg of results) {
1298
+ roleById.set(msg.id, msg.role);
1299
+ }
1300
+ const skeletons = results.map((msg) => ({
1301
+ uniqueId: msg.id,
1302
+ messageId: msg.messageId,
1303
+ conversationId: String(msg._getRaw("conversation_id")),
1304
+ role: msg.role,
1305
+ createdAt: msg.createdAt,
1367
1306
  // WatermelonDB surfaces unset text columns as null at runtime — normalize
1368
1307
  // to undefined so `parentMessageId ?? undefined` keying works everywhere.
1369
- parentMessageId: row.parent_message_id ?? void 0,
1370
- model: row.model ?? void 0
1308
+ parentMessageId: msg.parentMessageId ?? void 0,
1309
+ model: msg.model ?? void 0
1371
1310
  }));
1372
- await decryptArtifactContent(skeletons, rows, collectArtifactIndices(rows, roleById), ctx);
1311
+ const artifactIndices = [];
1312
+ for (let i = 0; i < results.length; i++) {
1313
+ const msg = results[i];
1314
+ if (msg.role !== "user" || !msg.parentMessageId) continue;
1315
+ if (roleById.get(msg.parentMessageId) === "user") {
1316
+ artifactIndices.push(i);
1317
+ }
1318
+ }
1319
+ const address = ctx.walletAddress;
1320
+ if (artifactIndices.length > 0 && address) {
1321
+ if (ctx.signMessage) {
1322
+ try {
1323
+ await requestEncryptionKey(address, ctx.signMessage, ctx.embeddedWalletSigner);
1324
+ } catch (error) {
1325
+ getLogger().warn("Failed to request encryption key for skeleton decryption:", error);
1326
+ }
1327
+ }
1328
+ await Promise.all(
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;
1336
+ }
1337
+ }
1373
1338
  return skeletons;
1374
1339
  }
1375
1340
  async function clearMessagesOp(ctx, convId) {
@@ -5046,7 +5011,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
5046
5011
  legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
5047
5012
  );
5048
5013
  }
5049
- const { recall: recall2 } = await import("./recall-RGKS2OIP.mjs");
5014
+ const { recall: recall2 } = await import("./recall-Z2HUBS2Y.mjs");
5050
5015
  const result = await recall2(
5051
5016
  query,
5052
5017
  { vaultCtx, embeddingOptions, vaultCache: cache },