luckytri 1.0.4 → 1.0.6
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/LICENSE +21 -21
- package/README.en.md +2 -0
- package/README.md +2 -0
- package/docs/en/CHANGELOG.md +20 -13
- package/docs/en/guide.md +7 -5
- package/docs/en/her-life.md +2 -2
- package/docs/en/webui.md +1 -1
- package/docs/zh/CHANGELOG.md +20 -13
- package/docs/zh/guide.md +7 -5
- package/docs/zh/her-life.md +2 -2
- package/docs/zh/webui.md +1 -1
- package/package.json +2 -1
- package/public/app/assets/ChatsPage-CFMVozoG.css +1 -0
- package/public/app/assets/{ChatsPage-CshdtTzV.js → ChatsPage-DCYMkJ91.js} +2 -2
- package/public/app/assets/{Empty-C7yzOBzy.js → Empty-CLyZkxR5.js} +1 -1
- package/public/app/assets/{Empty-DmUB2-Bk.css → Empty-DIobYG3x.css} +1 -1
- package/public/app/assets/{Field-BjFv4Rfn.js → Field-BpaRwLI_.js} +1 -1
- package/public/app/assets/{HeartPage-eqo6ru16.js → HeartPage-BIOMTiwr.js} +1 -1
- package/public/app/assets/HeartPage-C-2jvgzF.css +1 -0
- package/public/app/assets/{LifePage-CN8GE5NK.js → LifePage-BCgM4JkR.js} +1 -1
- package/public/app/assets/LifePage-CG1OHbRK.css +1 -0
- package/public/app/assets/MemoryPage-C_Bu4rfb.css +1 -0
- package/public/app/assets/{MemoryPage-CCpMN4Wg.js → MemoryPage-vShvRqMt.js} +1 -1
- package/public/app/assets/NaturePage-CPZlImT0.css +1 -0
- package/public/app/assets/{NaturePage-C0JqdBTR.js → NaturePage-Cy9ptr4G.js} +2 -2
- package/public/app/assets/PeoplePage-3RRUITDz.css +1 -0
- package/public/app/assets/{PeoplePage-BXGBbO4u.js → PeoplePage-CUZekB2E.js} +1 -1
- package/public/app/assets/{PluginsPage-Dksp5AV5.js → PluginsPage-1RM4rmJP.js} +1 -1
- package/public/app/assets/{SystemPage-BenIyTvk.css → SystemPage-BI2CB5Ig.css} +1 -1
- package/public/app/assets/{SystemPage-Cd7aa8eE.js → SystemPage-BeT5TmIV.js} +1 -1
- package/public/app/assets/TimePage-C-guwPk2.css +1 -0
- package/public/app/assets/{TimePage-Bs_zImb4.js → TimePage-taTmPMM8.js} +2 -2
- package/public/app/assets/{index-BHZcHUMh.css → index-DY5AM0Hz.css} +1 -1
- package/public/app/assets/{index-CyRtYxP3.js → index-DdYwC5ZU.js} +3 -3
- package/public/app/assets/{knowledge-BJOIyuJo.js → knowledge-DJmfu2KN.js} +1 -1
- package/public/app/assets/{media-Bwtx8blz.js → media-BEtnE0Gv.js} +1 -1
- package/public/app/assets/{mind-DtTVrW6Z.js → mind-Dtiw0-QK.js} +1 -1
- package/public/app/index.html +6 -5
- package/public/guide.en.html +11 -3
- package/public/guide.html +6 -3
- package/public/tutorial.en.md +2 -0
- package/public/tutorial.md +2 -0
- package/scripts/import-data.js +128 -128
- package/scripts/proxy-config.js +167 -167
- package/scripts/service-supervisor.js +50 -0
- package/scripts/start-server.js +71 -16
- package/scripts/update-instance.js +201 -201
- package/server/channels/adapters.js +27 -27
- package/server/channels/onebot/adapter.js +288 -288
- package/server/channels/qqbot/adapter.js +253 -253
- package/server/channels/qqbot/api.js +199 -199
- package/server/channels/qqbot/credentials.js +11 -11
- package/server/channels/qqbot/gateway.js +274 -274
- package/server/channels/qqbot/index.js +389 -389
- package/server/channels/segments.js +40 -40
- package/server/channels/session-key.js +153 -153
- package/server/channels/state.js +42 -42
- package/server/core/api.js +564 -564
- package/server/core/context-builder.js +288 -288
- package/server/core/context-compactor.js +454 -454
- package/server/core/conversation-cues.js +325 -325
- package/server/core/conversation-manager.js +87 -87
- package/server/core/feedback.js +8 -8
- package/server/core/group-style.js +72 -72
- package/server/core/initiative-context.js +66 -66
- package/server/core/input-budget.js +32 -32
- package/server/core/local-demo.js +98 -98
- package/server/core/message-manager.js +118 -118
- package/server/core/message-scheduler.js +78 -78
- package/server/core/model-json.js +190 -190
- package/server/core/model-presets.js +900 -900
- package/server/core/name-call.js +29 -29
- package/server/core/network.js +157 -157
- package/server/core/person-name.js +22 -22
- package/server/core/persona-manager.js +2 -1
- package/server/core/reply-delivery.js +404 -403
- package/server/core/reply-target-resolver.js +50 -50
- package/server/core/response-generator.js +50 -50
- package/server/core/response-validator.js +14 -2
- package/server/core/retired-prompts.js +51 -51
- package/server/core/sessions.js +109 -109
- package/server/core/speaker-names.js +92 -92
- package/server/core/topic-tracker.js +65 -65
- package/server/http.js +18 -18
- package/server/i18n/decisions.js +209 -206
- package/server/i18n/errors.js +4 -0
- package/server/i18n/index.js +144 -144
- package/server/i18n/models.js +111 -111
- package/server/knowledge/api.js +342 -342
- package/server/knowledge/embedding-profile.js +114 -114
- package/server/knowledge/index.js +13 -13
- package/server/knowledge/retrieval.js +93 -93
- package/server/knowledge/schema.js +158 -158
- package/server/knowledge/vector-index.js +90 -90
- package/server/mind/affect.js +265 -265
- package/server/mind/attention.js +200 -200
- package/server/mind/bonds.js +565 -565
- package/server/mind/clock.js +83 -83
- package/server/mind/continuity.js +562 -562
- package/server/mind/conversation-origin.js +175 -175
- package/server/mind/days.js +210 -210
- package/server/mind/evidence-read.js +45 -45
- package/server/mind/faces.js +373 -373
- package/server/mind/guard.js +60 -60
- package/server/mind/initiative.js +338 -338
- package/server/mind/life/activities.js +21 -21
- package/server/mind/life/context.js +330 -323
- package/server/mind/life/diary.js +20 -0
- package/server/mind/life/growth.js +261 -254
- package/server/mind/life/index.js +10 -2
- package/server/mind/life/presence.js +305 -305
- package/server/mind/meetings.js +1069 -1069
- package/server/mind/memory-policy.js +48 -48
- package/server/mind/memory.js +888 -888
- package/server/mind/nature.js +358 -358
- package/server/mind/novelty.js +19 -19
- package/server/mind/periods.js +118 -118
- package/server/mind/reading.js +120 -120
- package/server/mind/relationship-context.js +71 -0
- package/server/mind/relationships.js +390 -279
- package/server/mind/salience.js +201 -201
- package/server/mind/schema.js +567 -567
- package/server/mind/self.js +484 -484
- package/server/mind/thoughts.js +274 -274
- package/server/mind/time/agenda.js +242 -242
- package/server/mind/time/api.js +200 -200
- package/server/mind/time/attention.js +34 -34
- package/server/mind/time/delivery-links.js +130 -130
- package/server/mind/time/model-material.js +77 -77
- package/server/mind/time/presentation.js +51 -51
- package/server/mind/time/schedule.js +83 -83
- package/server/mind/time/schema.js +84 -84
- package/server/mind/time/search.js +383 -383
- package/server/mind/time/sharing.js +472 -472
- package/server/mind/time/task-links.js +311 -311
- package/server/mind/time/works.js +432 -432
- package/server/mind/traits.js +191 -191
- package/server/mind/view.js +9 -1
- package/server/runtime/installation.js +116 -116
- package/server/runtime/update-execution.js +2 -1
- package/server/runtime/update-manager.js +140 -140
- package/server/storage/data-package.js +298 -298
- package/server/storage/data-transfer-api.js +50 -50
- package/server/storage/data-transfer-worker.js +18 -18
- package/server/storage/data-transfer.js +416 -416
- package/server/studio/display-names.js +139 -139
- package/server/studio/management.js +102 -102
- package/server/studio/updates.js +144 -144
- package/server/version.js +10 -10
- package/public/app/assets/ChatsPage-DfyPCS9N.css +0 -1
- package/public/app/assets/HeartPage-Bft9wZp5.css +0 -1
- package/public/app/assets/LifePage-BUi5euBF.css +0 -1
- package/public/app/assets/MemoryPage-cZvXfkXb.css +0 -1
- package/public/app/assets/NaturePage-CHkpb5NK.css +0 -1
- package/public/app/assets/PeoplePage-BTU0H1pM.css +0 -1
- package/public/app/assets/TimePage-BOms_n4I.css +0 -1
|
@@ -1,158 +1,158 @@
|
|
|
1
|
-
import { ftsTokens } from "./retrieval.js";
|
|
2
|
-
|
|
3
|
-
export function indexMemory(db, id, content) {
|
|
4
|
-
db.prepare("DELETE FROM core_memory_fts WHERE memory_id=?").run(id);
|
|
5
|
-
const tokens = ftsTokens(content);
|
|
6
|
-
if (tokens)
|
|
7
|
-
db.prepare(
|
|
8
|
-
"INSERT INTO core_memory_fts(memory_id, tokens) VALUES (?,?)",
|
|
9
|
-
).run(id, tokens);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function indexChunk(db, id, content) {
|
|
13
|
-
db.prepare("DELETE FROM core_chunk_fts WHERE chunk_id=?").run(id);
|
|
14
|
-
const tokens = ftsTokens(content);
|
|
15
|
-
if (tokens)
|
|
16
|
-
db.prepare("INSERT INTO core_chunk_fts(chunk_id, tokens) VALUES (?,?)").run(
|
|
17
|
-
id,
|
|
18
|
-
tokens,
|
|
19
|
-
);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function mergeLegacyMemories(db) {
|
|
23
|
-
if (db.prepare("SELECT id FROM core_config WHERE id='memory-merge-v1'").get())
|
|
24
|
-
return;
|
|
25
|
-
db.exec("BEGIN IMMEDIATE");
|
|
26
|
-
try {
|
|
27
|
-
for (const m of db.prepare("SELECT * FROM memories").all()) {
|
|
28
|
-
const sessionId =
|
|
29
|
-
m.scope === "shared"
|
|
30
|
-
? "__shared__"
|
|
31
|
-
: m.scope === "private"
|
|
32
|
-
? `__private__:${m.user_id}`
|
|
33
|
-
: m.scope;
|
|
34
|
-
const id = "legacy:" + m.id;
|
|
35
|
-
if (db.prepare("SELECT id FROM core_memories WHERE id=?").get(id))
|
|
36
|
-
continue;
|
|
37
|
-
db.prepare(
|
|
38
|
-
"INSERT INTO core_memories(id,session_id,subject,content,type,confidence,importance,status,locked,sources,created,updated) VALUES (?,?,?,?,'reviewed',1,1,'confirmed',1,'[]',?,?)",
|
|
39
|
-
).run(
|
|
40
|
-
id,
|
|
41
|
-
sessionId,
|
|
42
|
-
m.user_id,
|
|
43
|
-
m.content,
|
|
44
|
-
m.time || Date.now(),
|
|
45
|
-
Date.now(),
|
|
46
|
-
);
|
|
47
|
-
indexMemory(db, id, m.content);
|
|
48
|
-
}
|
|
49
|
-
db.prepare("INSERT INTO core_config(id,value) VALUES (?,?)").run(
|
|
50
|
-
"memory-merge-v1",
|
|
51
|
-
JSON.stringify({ time: Date.now() }),
|
|
52
|
-
);
|
|
53
|
-
db.exec("COMMIT");
|
|
54
|
-
} catch (e) {
|
|
55
|
-
db.exec("ROLLBACK");
|
|
56
|
-
throw e;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export const KNOWLEDGE_TRIGGERS = [
|
|
61
|
-
`CREATE TRIGGER IF NOT EXISTS core_vector_changed AFTER UPDATE OF embedding ON core_chunks BEGIN
|
|
62
|
-
DELETE FROM core_vector_buckets WHERE chunk_id=NEW.id;
|
|
63
|
-
UPDATE core_chunks SET vector_indexed=0 WHERE id=NEW.id;
|
|
64
|
-
END`,
|
|
65
|
-
`CREATE TRIGGER IF NOT EXISTS core_vector_deleted AFTER DELETE ON core_chunks BEGIN
|
|
66
|
-
DELETE FROM core_vector_buckets WHERE chunk_id=OLD.id;
|
|
67
|
-
END`,
|
|
68
|
-
];
|
|
69
|
-
|
|
70
|
-
export function migrateKnowledge(db) {
|
|
71
|
-
db.exec(`
|
|
72
|
-
CREATE TABLE IF NOT EXISTS core_collections (
|
|
73
|
-
id TEXT PRIMARY KEY,
|
|
74
|
-
name TEXT NOT NULL,
|
|
75
|
-
scope TEXT NOT NULL,
|
|
76
|
-
created INTEGER NOT NULL,
|
|
77
|
-
updated INTEGER NOT NULL
|
|
78
|
-
);
|
|
79
|
-
CREATE TABLE IF NOT EXISTS core_collection_sessions (
|
|
80
|
-
collection_id TEXT NOT NULL,
|
|
81
|
-
session_id TEXT NOT NULL,
|
|
82
|
-
PRIMARY KEY(collection_id, session_id)
|
|
83
|
-
);
|
|
84
|
-
CREATE TABLE IF NOT EXISTS core_documents (
|
|
85
|
-
id TEXT PRIMARY KEY,
|
|
86
|
-
collection_id TEXT NOT NULL,
|
|
87
|
-
title TEXT NOT NULL,
|
|
88
|
-
source TEXT,
|
|
89
|
-
path TEXT,
|
|
90
|
-
status TEXT NOT NULL,
|
|
91
|
-
error TEXT,
|
|
92
|
-
created INTEGER NOT NULL,
|
|
93
|
-
updated INTEGER NOT NULL,
|
|
94
|
-
bytes INTEGER,
|
|
95
|
-
hash TEXT
|
|
96
|
-
);
|
|
97
|
-
CREATE TABLE IF NOT EXISTS core_chunks (
|
|
98
|
-
id TEXT PRIMARY KEY,
|
|
99
|
-
document_id TEXT NOT NULL,
|
|
100
|
-
collection_id TEXT NOT NULL,
|
|
101
|
-
ordinal INTEGER NOT NULL,
|
|
102
|
-
heading TEXT,
|
|
103
|
-
text TEXT NOT NULL,
|
|
104
|
-
tokens TEXT,
|
|
105
|
-
embedding BLOB,
|
|
106
|
-
hash TEXT,
|
|
107
|
-
created INTEGER NOT NULL
|
|
108
|
-
);
|
|
109
|
-
`);
|
|
110
|
-
db.exec(
|
|
111
|
-
"CREATE VIRTUAL TABLE IF NOT EXISTS core_memory_fts USING fts5(memory_id UNINDEXED, tokens)",
|
|
112
|
-
);
|
|
113
|
-
db.exec(
|
|
114
|
-
"CREATE VIRTUAL TABLE IF NOT EXISTS core_chunk_fts USING fts5(chunk_id UNINDEXED, tokens)",
|
|
115
|
-
);
|
|
116
|
-
if (
|
|
117
|
-
!db
|
|
118
|
-
.prepare("PRAGMA table_info(core_chunks)")
|
|
119
|
-
.all()
|
|
120
|
-
.some((c) => c.name === "vector_indexed")
|
|
121
|
-
)
|
|
122
|
-
db.exec(
|
|
123
|
-
"ALTER TABLE core_chunks ADD COLUMN vector_indexed INTEGER NOT NULL DEFAULT 0",
|
|
124
|
-
);
|
|
125
|
-
if (
|
|
126
|
-
!db
|
|
127
|
-
.prepare("PRAGMA table_info(core_chunks)")
|
|
128
|
-
.all()
|
|
129
|
-
.some((c) => c.name === "embedding_profile")
|
|
130
|
-
)
|
|
131
|
-
db.exec(
|
|
132
|
-
"ALTER TABLE core_chunks ADD COLUMN embedding_profile TEXT NOT NULL DEFAULT ''",
|
|
133
|
-
);
|
|
134
|
-
db.exec(`CREATE INDEX IF NOT EXISTS core_chunks_collection ON core_chunks(collection_id, document_id);
|
|
135
|
-
CREATE INDEX IF NOT EXISTS core_chunks_unindexed ON core_chunks(vector_indexed) WHERE embedding IS NOT NULL;
|
|
136
|
-
CREATE TABLE IF NOT EXISTS core_vector_buckets(dimension INTEGER NOT NULL,band INTEGER NOT NULL,bucket INTEGER NOT NULL,chunk_id TEXT NOT NULL,PRIMARY KEY(dimension,band,bucket,chunk_id));
|
|
137
|
-
CREATE INDEX IF NOT EXISTS core_vector_buckets_chunk ON core_vector_buckets(chunk_id);`);
|
|
138
|
-
db.exec(KNOWLEDGE_TRIGGERS.join(";") + ";");
|
|
139
|
-
if (
|
|
140
|
-
!db
|
|
141
|
-
.prepare("SELECT id FROM core_collections WHERE id='shared-default'")
|
|
142
|
-
.get()
|
|
143
|
-
)
|
|
144
|
-
db.prepare(
|
|
145
|
-
"INSERT INTO core_collections(id,name,scope,created,updated) VALUES ('shared-default','共享知识库','shared',?,?)",
|
|
146
|
-
).run(Date.now(), Date.now());
|
|
147
|
-
mergeLegacyMemories(db);
|
|
148
|
-
if (
|
|
149
|
-
!db.prepare("SELECT id FROM core_config WHERE id='memory-fts-v1'").get()
|
|
150
|
-
) {
|
|
151
|
-
for (const m of db.prepare("SELECT id,content FROM core_memories").all())
|
|
152
|
-
indexMemory(db, m.id, m.content);
|
|
153
|
-
db.prepare("INSERT INTO core_config(id,value) VALUES (?,?)").run(
|
|
154
|
-
"memory-fts-v1",
|
|
155
|
-
JSON.stringify({ time: Date.now() }),
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
1
|
+
import { ftsTokens } from "./retrieval.js";
|
|
2
|
+
|
|
3
|
+
export function indexMemory(db, id, content) {
|
|
4
|
+
db.prepare("DELETE FROM core_memory_fts WHERE memory_id=?").run(id);
|
|
5
|
+
const tokens = ftsTokens(content);
|
|
6
|
+
if (tokens)
|
|
7
|
+
db.prepare(
|
|
8
|
+
"INSERT INTO core_memory_fts(memory_id, tokens) VALUES (?,?)",
|
|
9
|
+
).run(id, tokens);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function indexChunk(db, id, content) {
|
|
13
|
+
db.prepare("DELETE FROM core_chunk_fts WHERE chunk_id=?").run(id);
|
|
14
|
+
const tokens = ftsTokens(content);
|
|
15
|
+
if (tokens)
|
|
16
|
+
db.prepare("INSERT INTO core_chunk_fts(chunk_id, tokens) VALUES (?,?)").run(
|
|
17
|
+
id,
|
|
18
|
+
tokens,
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function mergeLegacyMemories(db) {
|
|
23
|
+
if (db.prepare("SELECT id FROM core_config WHERE id='memory-merge-v1'").get())
|
|
24
|
+
return;
|
|
25
|
+
db.exec("BEGIN IMMEDIATE");
|
|
26
|
+
try {
|
|
27
|
+
for (const m of db.prepare("SELECT * FROM memories").all()) {
|
|
28
|
+
const sessionId =
|
|
29
|
+
m.scope === "shared"
|
|
30
|
+
? "__shared__"
|
|
31
|
+
: m.scope === "private"
|
|
32
|
+
? `__private__:${m.user_id}`
|
|
33
|
+
: m.scope;
|
|
34
|
+
const id = "legacy:" + m.id;
|
|
35
|
+
if (db.prepare("SELECT id FROM core_memories WHERE id=?").get(id))
|
|
36
|
+
continue;
|
|
37
|
+
db.prepare(
|
|
38
|
+
"INSERT INTO core_memories(id,session_id,subject,content,type,confidence,importance,status,locked,sources,created,updated) VALUES (?,?,?,?,'reviewed',1,1,'confirmed',1,'[]',?,?)",
|
|
39
|
+
).run(
|
|
40
|
+
id,
|
|
41
|
+
sessionId,
|
|
42
|
+
m.user_id,
|
|
43
|
+
m.content,
|
|
44
|
+
m.time || Date.now(),
|
|
45
|
+
Date.now(),
|
|
46
|
+
);
|
|
47
|
+
indexMemory(db, id, m.content);
|
|
48
|
+
}
|
|
49
|
+
db.prepare("INSERT INTO core_config(id,value) VALUES (?,?)").run(
|
|
50
|
+
"memory-merge-v1",
|
|
51
|
+
JSON.stringify({ time: Date.now() }),
|
|
52
|
+
);
|
|
53
|
+
db.exec("COMMIT");
|
|
54
|
+
} catch (e) {
|
|
55
|
+
db.exec("ROLLBACK");
|
|
56
|
+
throw e;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const KNOWLEDGE_TRIGGERS = [
|
|
61
|
+
`CREATE TRIGGER IF NOT EXISTS core_vector_changed AFTER UPDATE OF embedding ON core_chunks BEGIN
|
|
62
|
+
DELETE FROM core_vector_buckets WHERE chunk_id=NEW.id;
|
|
63
|
+
UPDATE core_chunks SET vector_indexed=0 WHERE id=NEW.id;
|
|
64
|
+
END`,
|
|
65
|
+
`CREATE TRIGGER IF NOT EXISTS core_vector_deleted AFTER DELETE ON core_chunks BEGIN
|
|
66
|
+
DELETE FROM core_vector_buckets WHERE chunk_id=OLD.id;
|
|
67
|
+
END`,
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
export function migrateKnowledge(db) {
|
|
71
|
+
db.exec(`
|
|
72
|
+
CREATE TABLE IF NOT EXISTS core_collections (
|
|
73
|
+
id TEXT PRIMARY KEY,
|
|
74
|
+
name TEXT NOT NULL,
|
|
75
|
+
scope TEXT NOT NULL,
|
|
76
|
+
created INTEGER NOT NULL,
|
|
77
|
+
updated INTEGER NOT NULL
|
|
78
|
+
);
|
|
79
|
+
CREATE TABLE IF NOT EXISTS core_collection_sessions (
|
|
80
|
+
collection_id TEXT NOT NULL,
|
|
81
|
+
session_id TEXT NOT NULL,
|
|
82
|
+
PRIMARY KEY(collection_id, session_id)
|
|
83
|
+
);
|
|
84
|
+
CREATE TABLE IF NOT EXISTS core_documents (
|
|
85
|
+
id TEXT PRIMARY KEY,
|
|
86
|
+
collection_id TEXT NOT NULL,
|
|
87
|
+
title TEXT NOT NULL,
|
|
88
|
+
source TEXT,
|
|
89
|
+
path TEXT,
|
|
90
|
+
status TEXT NOT NULL,
|
|
91
|
+
error TEXT,
|
|
92
|
+
created INTEGER NOT NULL,
|
|
93
|
+
updated INTEGER NOT NULL,
|
|
94
|
+
bytes INTEGER,
|
|
95
|
+
hash TEXT
|
|
96
|
+
);
|
|
97
|
+
CREATE TABLE IF NOT EXISTS core_chunks (
|
|
98
|
+
id TEXT PRIMARY KEY,
|
|
99
|
+
document_id TEXT NOT NULL,
|
|
100
|
+
collection_id TEXT NOT NULL,
|
|
101
|
+
ordinal INTEGER NOT NULL,
|
|
102
|
+
heading TEXT,
|
|
103
|
+
text TEXT NOT NULL,
|
|
104
|
+
tokens TEXT,
|
|
105
|
+
embedding BLOB,
|
|
106
|
+
hash TEXT,
|
|
107
|
+
created INTEGER NOT NULL
|
|
108
|
+
);
|
|
109
|
+
`);
|
|
110
|
+
db.exec(
|
|
111
|
+
"CREATE VIRTUAL TABLE IF NOT EXISTS core_memory_fts USING fts5(memory_id UNINDEXED, tokens)",
|
|
112
|
+
);
|
|
113
|
+
db.exec(
|
|
114
|
+
"CREATE VIRTUAL TABLE IF NOT EXISTS core_chunk_fts USING fts5(chunk_id UNINDEXED, tokens)",
|
|
115
|
+
);
|
|
116
|
+
if (
|
|
117
|
+
!db
|
|
118
|
+
.prepare("PRAGMA table_info(core_chunks)")
|
|
119
|
+
.all()
|
|
120
|
+
.some((c) => c.name === "vector_indexed")
|
|
121
|
+
)
|
|
122
|
+
db.exec(
|
|
123
|
+
"ALTER TABLE core_chunks ADD COLUMN vector_indexed INTEGER NOT NULL DEFAULT 0",
|
|
124
|
+
);
|
|
125
|
+
if (
|
|
126
|
+
!db
|
|
127
|
+
.prepare("PRAGMA table_info(core_chunks)")
|
|
128
|
+
.all()
|
|
129
|
+
.some((c) => c.name === "embedding_profile")
|
|
130
|
+
)
|
|
131
|
+
db.exec(
|
|
132
|
+
"ALTER TABLE core_chunks ADD COLUMN embedding_profile TEXT NOT NULL DEFAULT ''",
|
|
133
|
+
);
|
|
134
|
+
db.exec(`CREATE INDEX IF NOT EXISTS core_chunks_collection ON core_chunks(collection_id, document_id);
|
|
135
|
+
CREATE INDEX IF NOT EXISTS core_chunks_unindexed ON core_chunks(vector_indexed) WHERE embedding IS NOT NULL;
|
|
136
|
+
CREATE TABLE IF NOT EXISTS core_vector_buckets(dimension INTEGER NOT NULL,band INTEGER NOT NULL,bucket INTEGER NOT NULL,chunk_id TEXT NOT NULL,PRIMARY KEY(dimension,band,bucket,chunk_id));
|
|
137
|
+
CREATE INDEX IF NOT EXISTS core_vector_buckets_chunk ON core_vector_buckets(chunk_id);`);
|
|
138
|
+
db.exec(KNOWLEDGE_TRIGGERS.join(";") + ";");
|
|
139
|
+
if (
|
|
140
|
+
!db
|
|
141
|
+
.prepare("SELECT id FROM core_collections WHERE id='shared-default'")
|
|
142
|
+
.get()
|
|
143
|
+
)
|
|
144
|
+
db.prepare(
|
|
145
|
+
"INSERT INTO core_collections(id,name,scope,created,updated) VALUES ('shared-default','共享知识库','shared',?,?)",
|
|
146
|
+
).run(Date.now(), Date.now());
|
|
147
|
+
mergeLegacyMemories(db);
|
|
148
|
+
if (
|
|
149
|
+
!db.prepare("SELECT id FROM core_config WHERE id='memory-fts-v1'").get()
|
|
150
|
+
) {
|
|
151
|
+
for (const m of db.prepare("SELECT id,content FROM core_memories").all())
|
|
152
|
+
indexMemory(db, m.id, m.content);
|
|
153
|
+
db.prepare("INSERT INTO core_config(id,value) VALUES (?,?)").run(
|
|
154
|
+
"memory-fts-v1",
|
|
155
|
+
JSON.stringify({ time: Date.now() }),
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -1,90 +1,90 @@
|
|
|
1
|
-
import { unpackVector } from "./retrieval.js";
|
|
2
|
-
|
|
3
|
-
const BANDS = 12,
|
|
4
|
-
BITS = 6;
|
|
5
|
-
export const VECTOR_CANDIDATES = 256;
|
|
6
|
-
|
|
7
|
-
// Deterministic random hyperplanes: index signatures remain valid across
|
|
8
|
-
// restarts and do not depend on the order documents were imported.
|
|
9
|
-
function signatures(vector) {
|
|
10
|
-
const result = [];
|
|
11
|
-
for (let band = 0; band < BANDS; band++) {
|
|
12
|
-
let bucket = 0;
|
|
13
|
-
for (let bit = 0; bit < BITS; bit++) {
|
|
14
|
-
let sum = 0;
|
|
15
|
-
for (let dimension = 0; dimension < vector.length; dimension++) {
|
|
16
|
-
let seed =
|
|
17
|
-
Math.imul(dimension + 1, 0x9e3779b1) ^
|
|
18
|
-
Math.imul(band * BITS + bit + 1, 0x85ebca6b);
|
|
19
|
-
seed = Math.imul(seed ^ (seed >>> 16), 0x7feb352d);
|
|
20
|
-
sum += vector[dimension] * (seed >>> 31 ? 1 : -1);
|
|
21
|
-
}
|
|
22
|
-
if (sum >= 0) bucket |= 1 << bit;
|
|
23
|
-
}
|
|
24
|
-
result.push({ band, bucket });
|
|
25
|
-
}
|
|
26
|
-
return result;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function ensureVectorIndex(db) {
|
|
30
|
-
const rows = db.prepare(
|
|
31
|
-
"SELECT id,embedding FROM core_chunks WHERE vector_indexed=0 AND embedding IS NOT NULL",
|
|
32
|
-
);
|
|
33
|
-
const insert = db.prepare(
|
|
34
|
-
"INSERT OR IGNORE INTO core_vector_buckets(dimension,band,bucket,chunk_id) VALUES (?,?,?,?)",
|
|
35
|
-
);
|
|
36
|
-
const mark = db.prepare("UPDATE core_chunks SET vector_indexed=1 WHERE id=?");
|
|
37
|
-
db.exec("SAVEPOINT vector_index");
|
|
38
|
-
try {
|
|
39
|
-
for (const row of rows.iterate()) {
|
|
40
|
-
const vector = unpackVector(row.embedding);
|
|
41
|
-
if (
|
|
42
|
-
vector?.length &&
|
|
43
|
-
vector.every(Number.isFinite) &&
|
|
44
|
-
vector.some((value) => value !== 0)
|
|
45
|
-
)
|
|
46
|
-
for (const { band, bucket } of signatures(vector))
|
|
47
|
-
insert.run(vector.length, band, bucket, row.id);
|
|
48
|
-
mark.run(row.id);
|
|
49
|
-
}
|
|
50
|
-
db.exec("RELEASE vector_index");
|
|
51
|
-
} catch (error) {
|
|
52
|
-
db.exec("ROLLBACK TO vector_index");
|
|
53
|
-
db.exec("RELEASE vector_index");
|
|
54
|
-
throw error;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export function vectorCandidates(
|
|
59
|
-
db,
|
|
60
|
-
vector,
|
|
61
|
-
collections,
|
|
62
|
-
cutoff,
|
|
63
|
-
{ signature = null, legacy = true } = {},
|
|
64
|
-
) {
|
|
65
|
-
if (!vector?.length || !vector.every(Number.isFinite)) return [];
|
|
66
|
-
const buckets = signatures(vector).flatMap(({ band, bucket }) =>
|
|
67
|
-
[
|
|
68
|
-
bucket,
|
|
69
|
-
...Array.from({ length: BITS }, (_, bit) => bucket ^ (1 << bit)),
|
|
70
|
-
].map((value) => ({ band, bucket: value })),
|
|
71
|
-
);
|
|
72
|
-
return db
|
|
73
|
-
.prepare(
|
|
74
|
-
`SELECT b.chunk_id FROM core_vector_buckets b
|
|
75
|
-
JOIN core_chunks c ON c.id=b.chunk_id JOIN core_documents d ON d.id=c.document_id
|
|
76
|
-
WHERE b.dimension=? AND (${buckets.map(() => "(b.band=? AND b.bucket=?)").join(" OR ")})
|
|
77
|
-
AND c.collection_id IN (${collections.map(() => "?").join(",")}) AND d.status='ready' AND d.created<=?
|
|
78
|
-
${signature ? "AND (c.embedding_profile=?" + (legacy ? " OR c.embedding_profile=''" : "") + ")" : ""}
|
|
79
|
-
GROUP BY b.chunk_id ORDER BY COUNT(*) DESC, c.created DESC, b.chunk_id LIMIT ?`,
|
|
80
|
-
)
|
|
81
|
-
.all(
|
|
82
|
-
vector.length,
|
|
83
|
-
...buckets.flatMap((item) => [item.band, item.bucket]),
|
|
84
|
-
...collections,
|
|
85
|
-
cutoff,
|
|
86
|
-
...(signature ? [signature] : []),
|
|
87
|
-
VECTOR_CANDIDATES,
|
|
88
|
-
)
|
|
89
|
-
.map((row) => row.chunk_id);
|
|
90
|
-
}
|
|
1
|
+
import { unpackVector } from "./retrieval.js";
|
|
2
|
+
|
|
3
|
+
const BANDS = 12,
|
|
4
|
+
BITS = 6;
|
|
5
|
+
export const VECTOR_CANDIDATES = 256;
|
|
6
|
+
|
|
7
|
+
// Deterministic random hyperplanes: index signatures remain valid across
|
|
8
|
+
// restarts and do not depend on the order documents were imported.
|
|
9
|
+
function signatures(vector) {
|
|
10
|
+
const result = [];
|
|
11
|
+
for (let band = 0; band < BANDS; band++) {
|
|
12
|
+
let bucket = 0;
|
|
13
|
+
for (let bit = 0; bit < BITS; bit++) {
|
|
14
|
+
let sum = 0;
|
|
15
|
+
for (let dimension = 0; dimension < vector.length; dimension++) {
|
|
16
|
+
let seed =
|
|
17
|
+
Math.imul(dimension + 1, 0x9e3779b1) ^
|
|
18
|
+
Math.imul(band * BITS + bit + 1, 0x85ebca6b);
|
|
19
|
+
seed = Math.imul(seed ^ (seed >>> 16), 0x7feb352d);
|
|
20
|
+
sum += vector[dimension] * (seed >>> 31 ? 1 : -1);
|
|
21
|
+
}
|
|
22
|
+
if (sum >= 0) bucket |= 1 << bit;
|
|
23
|
+
}
|
|
24
|
+
result.push({ band, bucket });
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function ensureVectorIndex(db) {
|
|
30
|
+
const rows = db.prepare(
|
|
31
|
+
"SELECT id,embedding FROM core_chunks WHERE vector_indexed=0 AND embedding IS NOT NULL",
|
|
32
|
+
);
|
|
33
|
+
const insert = db.prepare(
|
|
34
|
+
"INSERT OR IGNORE INTO core_vector_buckets(dimension,band,bucket,chunk_id) VALUES (?,?,?,?)",
|
|
35
|
+
);
|
|
36
|
+
const mark = db.prepare("UPDATE core_chunks SET vector_indexed=1 WHERE id=?");
|
|
37
|
+
db.exec("SAVEPOINT vector_index");
|
|
38
|
+
try {
|
|
39
|
+
for (const row of rows.iterate()) {
|
|
40
|
+
const vector = unpackVector(row.embedding);
|
|
41
|
+
if (
|
|
42
|
+
vector?.length &&
|
|
43
|
+
vector.every(Number.isFinite) &&
|
|
44
|
+
vector.some((value) => value !== 0)
|
|
45
|
+
)
|
|
46
|
+
for (const { band, bucket } of signatures(vector))
|
|
47
|
+
insert.run(vector.length, band, bucket, row.id);
|
|
48
|
+
mark.run(row.id);
|
|
49
|
+
}
|
|
50
|
+
db.exec("RELEASE vector_index");
|
|
51
|
+
} catch (error) {
|
|
52
|
+
db.exec("ROLLBACK TO vector_index");
|
|
53
|
+
db.exec("RELEASE vector_index");
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function vectorCandidates(
|
|
59
|
+
db,
|
|
60
|
+
vector,
|
|
61
|
+
collections,
|
|
62
|
+
cutoff,
|
|
63
|
+
{ signature = null, legacy = true } = {},
|
|
64
|
+
) {
|
|
65
|
+
if (!vector?.length || !vector.every(Number.isFinite)) return [];
|
|
66
|
+
const buckets = signatures(vector).flatMap(({ band, bucket }) =>
|
|
67
|
+
[
|
|
68
|
+
bucket,
|
|
69
|
+
...Array.from({ length: BITS }, (_, bit) => bucket ^ (1 << bit)),
|
|
70
|
+
].map((value) => ({ band, bucket: value })),
|
|
71
|
+
);
|
|
72
|
+
return db
|
|
73
|
+
.prepare(
|
|
74
|
+
`SELECT b.chunk_id FROM core_vector_buckets b
|
|
75
|
+
JOIN core_chunks c ON c.id=b.chunk_id JOIN core_documents d ON d.id=c.document_id
|
|
76
|
+
WHERE b.dimension=? AND (${buckets.map(() => "(b.band=? AND b.bucket=?)").join(" OR ")})
|
|
77
|
+
AND c.collection_id IN (${collections.map(() => "?").join(",")}) AND d.status='ready' AND d.created<=?
|
|
78
|
+
${signature ? "AND (c.embedding_profile=?" + (legacy ? " OR c.embedding_profile=''" : "") + ")" : ""}
|
|
79
|
+
GROUP BY b.chunk_id ORDER BY COUNT(*) DESC, c.created DESC, b.chunk_id LIMIT ?`,
|
|
80
|
+
)
|
|
81
|
+
.all(
|
|
82
|
+
vector.length,
|
|
83
|
+
...buckets.flatMap((item) => [item.band, item.bucket]),
|
|
84
|
+
...collections,
|
|
85
|
+
cutoff,
|
|
86
|
+
...(signature ? [signature] : []),
|
|
87
|
+
VECTOR_CANDIDATES,
|
|
88
|
+
)
|
|
89
|
+
.map((row) => row.chunk_id);
|
|
90
|
+
}
|