@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.
- package/CHANGELOG.md +22 -0
- package/dist/cli/messenger/conversation-answers.d.ts +1 -0
- package/dist/cli/messenger/conversations-command.js +11 -3
- package/dist/cli/messenger/message-answers.d.ts +1 -0
- package/dist/cli/messenger/message-writes.d.ts +2 -0
- package/dist/cli/messenger/messages-search-command.js +11 -1
- package/dist/cli/messenger/search-answers.js +13 -0
- package/dist/cli/steps.js +6 -0
- package/dist/cli/upgrade-command.js +1 -1
- package/dist/entities/conversation-preparation.d.ts +10 -0
- package/dist/entities/conversation-preparation.js +2 -0
- package/dist/entities/conversation-results.d.ts +10 -0
- package/dist/entities/evidence.d.ts +8 -0
- package/dist/entities/index.d.ts +45 -0
- package/dist/entities/listener.d.ts +4 -0
- package/dist/entities/message-context.d.ts +3 -0
- package/dist/entities/message-transfer.d.ts +8 -0
- package/dist/entities/message-write.d.ts +4 -0
- package/dist/entities/message.d.ts +2 -0
- package/dist/entities/message.js +2 -0
- package/dist/entities/store-records.d.ts +5 -0
- package/dist/models/anthropic.js +2 -4
- package/dist/services/embeddings-maintenance.js +71 -2
- package/dist/services/embeddings-search.js +3 -1
- package/dist/services/embeddings.d.ts +7 -0
- package/dist/services/messages-archive-search.d.ts +2 -1
- package/dist/services/messages-archive-search.js +4 -4
- package/dist/services/messages-discovery.d.ts +24 -1
- package/dist/services/messages-discovery.js +61 -4
- package/dist/services/messages-meaning.d.ts +7 -0
- package/dist/services/messages-meaning.js +53 -0
- package/dist/services/messages-search.d.ts +5 -0
- package/dist/services/messages.d.ts +5 -0
- package/dist/services/messages.js +2 -1
- package/dist/services/search-catchup.js +1 -0
- package/dist/store/drivers/node-sqlite.js +1 -0
- package/dist/store/sqlite/drizzle/bun.js +58 -14
- package/dist/store/sqlite/drizzle/bun.js.map +3 -3
- package/dist/store/sqlite/drizzle/core.js +173 -7
- package/dist/store/sqlite/drizzle/core.js.map +4 -4
- package/dist/store/sqlite/drizzle/node.js +57 -13
- package/dist/store/sqlite/drizzle/node.js.map +3 -3
- package/dist/store/sqlite/drizzle/shared-55XJMTPA.js +6514 -0
- package/dist/store/sqlite/drizzle/shared-55XJMTPA.js.map +7 -0
- package/dist/store/sqlite/message-chunks.d.ts +44 -0
- package/dist/store/sqlite/message-chunks.js +76 -0
- package/dist/store/sqlite/open.js +1 -0
- package/dist/store/sqlite/schema/canonical-tags.d.ts +1 -0
- package/dist/store/sqlite/schema/document-index-pending.d.ts +1 -0
- package/dist/store/sqlite/schema/document-transfers.d.ts +1 -0
- package/dist/store/sqlite/schema/tag-consolidations.d.ts +2 -0
- package/dist/store/sqlite/schema.d.ts +97 -0
- package/dist/store/sqlite/vectors.js +4 -1
- package/dist/store/vectors.d.ts +36 -0
- package/dist/store/vectors.js +54 -0
- package/package.json +23 -24
- package/dist/store/sqlite/drizzle/shared-HKXF6HKX.js +0 -4846
- 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
|
+
};
|
|
@@ -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
|
}>;
|