@wirecat/cli-core 0.431.0 → 0.433.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.
Files changed (58) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/cli/messenger/conversation-answers.d.ts +1 -0
  3. package/dist/cli/messenger/conversations-command.js +11 -3
  4. package/dist/cli/messenger/message-answers.d.ts +1 -0
  5. package/dist/cli/messenger/message-writes.d.ts +2 -0
  6. package/dist/cli/messenger/messages-search-command.js +11 -1
  7. package/dist/cli/messenger/search-answers.js +13 -0
  8. package/dist/cli/steps.js +6 -0
  9. package/dist/cli/upgrade-command.js +1 -1
  10. package/dist/entities/conversation-preparation.d.ts +10 -0
  11. package/dist/entities/conversation-preparation.js +2 -0
  12. package/dist/entities/conversation-results.d.ts +10 -0
  13. package/dist/entities/evidence.d.ts +8 -0
  14. package/dist/entities/index.d.ts +45 -0
  15. package/dist/entities/listener.d.ts +4 -0
  16. package/dist/entities/message-context.d.ts +3 -0
  17. package/dist/entities/message-transfer.d.ts +8 -0
  18. package/dist/entities/message-write.d.ts +4 -0
  19. package/dist/entities/message.d.ts +2 -0
  20. package/dist/entities/message.js +2 -0
  21. package/dist/entities/store-records.d.ts +5 -0
  22. package/dist/models/anthropic.js +2 -4
  23. package/dist/services/embeddings-maintenance.js +71 -2
  24. package/dist/services/embeddings-search.js +3 -1
  25. package/dist/services/embeddings.d.ts +7 -0
  26. package/dist/services/messages-archive-search.d.ts +2 -1
  27. package/dist/services/messages-archive-search.js +4 -4
  28. package/dist/services/messages-discovery.d.ts +24 -1
  29. package/dist/services/messages-discovery.js +61 -4
  30. package/dist/services/messages-meaning.d.ts +7 -0
  31. package/dist/services/messages-meaning.js +53 -0
  32. package/dist/services/messages-search.d.ts +5 -0
  33. package/dist/services/messages.d.ts +5 -0
  34. package/dist/services/messages.js +2 -1
  35. package/dist/services/search-catchup.js +1 -0
  36. package/dist/store/drivers/node-sqlite.js +1 -0
  37. package/dist/store/sqlite/drizzle/bun.js +58 -14
  38. package/dist/store/sqlite/drizzle/bun.js.map +3 -3
  39. package/dist/store/sqlite/drizzle/core.js +173 -7
  40. package/dist/store/sqlite/drizzle/core.js.map +4 -4
  41. package/dist/store/sqlite/drizzle/node.js +57 -13
  42. package/dist/store/sqlite/drizzle/node.js.map +3 -3
  43. package/dist/store/sqlite/drizzle/shared-55XJMTPA.js +6514 -0
  44. package/dist/store/sqlite/drizzle/shared-55XJMTPA.js.map +7 -0
  45. package/dist/store/sqlite/message-chunks.d.ts +44 -0
  46. package/dist/store/sqlite/message-chunks.js +76 -0
  47. package/dist/store/sqlite/open.js +1 -0
  48. package/dist/store/sqlite/schema/canonical-tags.d.ts +1 -0
  49. package/dist/store/sqlite/schema/document-index-pending.d.ts +1 -0
  50. package/dist/store/sqlite/schema/document-transfers.d.ts +1 -0
  51. package/dist/store/sqlite/schema/tag-consolidations.d.ts +2 -0
  52. package/dist/store/sqlite/schema.d.ts +97 -0
  53. package/dist/store/sqlite/vectors.js +4 -1
  54. package/dist/store/vectors.d.ts +36 -0
  55. package/dist/store/vectors.js +54 -0
  56. package/package.json +23 -24
  57. package/dist/store/sqlite/drizzle/shared-HKXF6HKX.js +0 -4846
  58. package/dist/store/sqlite/drizzle/shared-HKXF6HKX.js.map +0 -7
@@ -0,0 +1,44 @@
1
+ import type { StoreContext } from "./open.js";
2
+ /** A live message with text, and the chunk and vector it already has, if any. */
3
+ export interface MessageToEmbed {
4
+ messagePk: number;
5
+ text: string;
6
+ sentAt: number;
7
+ hash: string | null;
8
+ embedded: boolean;
9
+ }
10
+ /** Live messages with text of the account, by pk after `after`; the caller compares hashes. */
11
+ export declare const messagesToEmbed: ({ orm }: StoreContext, accountPk: number, { chatKey, model, after, limit }: {
12
+ chatKey?: number;
13
+ model: string;
14
+ after: number;
15
+ limit: number;
16
+ }) => MessageToEmbed[];
17
+ /** Makes each hash its message's chunk; the vectors are saved apart, by `saveVectors`. */
18
+ export declare const saveMessageChunks: (context: StoreContext, accountPk: number, chunks: {
19
+ messagePk: number;
20
+ hash: string;
21
+ length: number;
22
+ occurredAt: number;
23
+ }[]) => void;
24
+ /**
25
+ * Drops the chunks of the account's messages that are gone, deleted or emptied, with the vectors nothing else
26
+ * uses: no trigger does it for messages, and a deleted message keeps no trace of its text.
27
+ */
28
+ export declare const dropGoneMessageChunks: (context: StoreContext, accountPk: number) => number;
29
+ /** Whether any message of the account has a vector of `model`. */
30
+ export declare const hasMessageVectors: ({ orm }: StoreContext, accountPk: number, model: string) => boolean;
31
+ export interface NearestMessage {
32
+ chatId: string;
33
+ messageId: string;
34
+ score: number;
35
+ }
36
+ /** The account's live messages nearest to `query` by their vector of `model`, best first: a scan of every vector. */
37
+ export declare const nearestMessages: ({ orm }: StoreContext, accountPk: number, { chatKey, model, since, before, limit, query, }: {
38
+ chatKey?: number;
39
+ model: string;
40
+ since?: number;
41
+ before?: number;
42
+ limit: number;
43
+ query: Float32Array;
44
+ }) => NearestMessage[];
@@ -0,0 +1,76 @@
1
+ import { sql } from "./drizzle/core.js";
2
+ import { dot } from "./vectors.js";
3
+ /** Live messages with text of the account, by pk after `after`; the caller compares hashes. */
4
+ export const messagesToEmbed = ({ orm }, accountPk, { chatKey, model, after, limit }) => orm
5
+ .all(sql `SELECT m.id AS messagePk, m.text, m.sent_at AS sentAt, k.content_hash AS hash,
6
+ EXISTS (SELECT 1 FROM embeddings v WHERE v.model = ${model} AND v.content_hash = k.content_hash) AS embedded
7
+ FROM messages m
8
+ LEFT JOIN chunks k ON k.chunkable_type = 'message' AND k.chunkable_id = m.id AND k.position = 0
9
+ WHERE m.account_id = ${accountPk} AND m.deleted_at IS NULL AND trim(m.text) <> '' AND m.id > ${after}
10
+ ${chatKey === undefined ? sql `` : sql `AND m.chat_id = ${chatKey}`}
11
+ ORDER BY m.id LIMIT ${limit}`)
12
+ .map((row) => ({ ...row, embedded: row.embedded === 1 }));
13
+ const dropUnshared = ({ orm }, hashes) => {
14
+ for (const hash of hashes)
15
+ orm.run(sql `DELETE FROM embeddings WHERE content_hash = ${hash}
16
+ AND NOT EXISTS (SELECT 1 FROM chunks WHERE content_hash = ${hash})`);
17
+ };
18
+ /** Makes each hash its message's chunk; the vectors are saved apart, by `saveVectors`. */
19
+ export const saveMessageChunks = (context, accountPk, chunks) => {
20
+ const { orm, now } = context;
21
+ const at = now();
22
+ const scope = orm.get(sql `SELECT scope FROM accounts WHERE id = ${accountPk}`)?.scope ?? null;
23
+ const old = new Set();
24
+ for (const { messagePk, hash, length, occurredAt } of chunks) {
25
+ const held = orm.get(sql `SELECT content_hash AS hash FROM chunks
26
+ WHERE chunkable_type = 'message' AND chunkable_id = ${messagePk} AND position = 0`);
27
+ if (held?.hash === hash)
28
+ continue;
29
+ if (held)
30
+ old.add(held.hash);
31
+ orm.run(sql `DELETE FROM chunks WHERE chunkable_type = 'message' AND chunkable_id = ${messagePk} AND position = 0`);
32
+ orm.run(sql `INSERT INTO chunks (chunkable_type, chunkable_id, position, start_offset, end_offset, content_hash, scope,
33
+ account_id, occurred_at, created_at, updated_at)
34
+ VALUES ('message', ${messagePk}, 0, 0, ${length}, ${hash}, ${scope}, ${accountPk}, ${occurredAt}, ${at}, ${at})`);
35
+ }
36
+ dropUnshared(context, old);
37
+ };
38
+ /**
39
+ * Drops the chunks of the account's messages that are gone, deleted or emptied, with the vectors nothing else
40
+ * uses: no trigger does it for messages, and a deleted message keeps no trace of its text.
41
+ */
42
+ export const dropGoneMessageChunks = (context, accountPk) => {
43
+ const gone = sql `chunkable_type = 'message' AND account_id = ${accountPk} AND NOT EXISTS (SELECT 1 FROM messages m
44
+ WHERE m.id = chunkable_id AND m.deleted_at IS NULL AND trim(m.text) <> '')`;
45
+ const dropped = context.orm.all(sql `SELECT content_hash AS hash FROM chunks WHERE ${gone}`);
46
+ context.orm.run(sql `DELETE FROM chunks WHERE ${gone}`);
47
+ dropUnshared(context, dropped.map(({ hash }) => hash));
48
+ return dropped.length;
49
+ };
50
+ /** Whether any message of the account has a vector of `model`. */
51
+ export const hasMessageVectors = ({ orm }, accountPk, model) => orm.get(sql `SELECT 1 FROM chunks k JOIN embeddings v ON v.model = ${model} AND v.content_hash = k.content_hash
52
+ WHERE k.chunkable_type = 'message' AND k.account_id = ${accountPk} LIMIT 1`) !== undefined;
53
+ const SCAN_PAGE = 5_000;
54
+ /** The account's live messages nearest to `query` by their vector of `model`, best first: a scan of every vector. */
55
+ export const nearestMessages = ({ orm }, accountPk, { chatKey, model, since, before, limit, query, }) => {
56
+ const found = [];
57
+ let after = 0;
58
+ for (;;) {
59
+ const rows = orm.all(sql `SELECT k.id, ch.external_id AS chatId, m.external_id AS messageId, v.vector
60
+ FROM chunks k CROSS JOIN messages m ON m.id = k.chunkable_id AND m.deleted_at IS NULL
61
+ JOIN chats ch ON ch.id = m.chat_id
62
+ JOIN embeddings v ON v.model = ${model} AND v.content_hash = k.content_hash
63
+ WHERE k.chunkable_type = 'message' AND k.position = 0 AND k.account_id = ${accountPk} AND k.id > ${after}
64
+ ${chatKey === undefined ? sql `AND ch.searchable = 1` : sql `AND m.chat_id = ${chatKey}`}
65
+ ${since === undefined ? sql `` : sql `AND m.sent_at >= ${since}`}
66
+ ${before === undefined ? sql `` : sql `AND m.sent_at < ${before}`}
67
+ ORDER BY k.id LIMIT ${SCAN_PAGE}`);
68
+ for (const row of rows)
69
+ found.push({ chatId: row.chatId, messageId: row.messageId, score: dot(query, row.vector) });
70
+ const last = rows.at(-1);
71
+ if (!last || rows.length < SCAN_PAGE)
72
+ break;
73
+ after = last.id;
74
+ }
75
+ return found.sort((a, b) => b.score - a.score).slice(0, limit);
76
+ };
@@ -1,3 +1,4 @@
1
+ // biome-ignore-all lint/plugin/no-sqlite-driver: cli-core owns the store, so it opens the driver itself
1
2
  import { PRAGMAS } from "../driver.js";
2
3
  import { quietSqliteWarning } from "../sqlite-warning.js";
3
4
  /**
@@ -84,4 +84,5 @@ export declare const canonicalTags: import("drizzle-orm/sqlite-core").SQLiteTabl
84
84
  }, {}>;
85
85
  };
86
86
  dialect: 'sqlite';
87
+ isAlias: false;
87
88
  }>;
@@ -36,4 +36,5 @@ export declare const documentIndexPending: import("drizzle-orm/sqlite-core").SQL
36
36
  }, {}>;
37
37
  };
38
38
  dialect: 'sqlite';
39
+ isAlias: false;
39
40
  }>;
@@ -100,4 +100,5 @@ export declare const documentAnnotationTransfers: import("drizzle-orm/sqlite-cor
100
100
  }, {}>;
101
101
  };
102
102
  dialect: 'sqlite';
103
+ isAlias: false;
103
104
  }>;
@@ -52,6 +52,7 @@ export declare const tagRedirects: import("drizzle-orm/sqlite-core").SQLiteTable
52
52
  }, {}>;
53
53
  };
54
54
  dialect: 'sqlite';
55
+ isAlias: false;
55
56
  }>;
56
57
  export declare const tagConsolidations: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
57
58
  name: "tag_consolidations";
@@ -267,4 +268,5 @@ export declare const tagConsolidations: import("drizzle-orm/sqlite-core").SQLite
267
268
  }, {}>;
268
269
  };
269
270
  dialect: 'sqlite';
271
+ isAlias: false;
270
272
  }>;