scream-code 0.14.8 → 0.14.9
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/{app-CJCkJpo_.mjs → app-2Dd57a5d.mjs} +166 -14
- package/dist/{dispatch-usl5yQnT.mjs → dispatch-1ojfKMwf.mjs} +324 -116
- package/dist/{dispatch-DVJhr5Rj.mjs → dispatch-CJPpI4gm.mjs} +1 -1
- package/dist/main.mjs +1 -1
- package/dist/{src-DCp4eCi5.mjs → src-h6ZExh4A.mjs} +1 -1
- package/dist/{src-BH9W5k24.mjs → src-tDEINaMV.mjs} +196 -17
- package/dist/{text-input-dialog-B0yHChBj.mjs → text-input-dialog-BUXAKycx.mjs} +40 -14
- package/dist/{text-input-dialog-B9uwX1Uy.mjs → text-input-dialog-Dr42qLMU.mjs} +1 -1
- package/package.json +1 -1
|
@@ -3,5 +3,5 @@ import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
|
3
3
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
|
-
import { Kt as handleConnectCommand } from "./dispatch-
|
|
6
|
+
import { Kt as handleConnectCommand } from "./dispatch-1ojfKMwf.mjs";
|
|
7
7
|
export { handleConnectCommand };
|
package/dist/main.mjs
CHANGED
|
@@ -6,7 +6,7 @@ const __dirname = __cjsShimDirname(__filename);
|
|
|
6
6
|
import "./suppress-sqlite-warning-C2VB0doZ.mjs";
|
|
7
7
|
//#region src/main.ts
|
|
8
8
|
try {
|
|
9
|
-
(await import("./app-
|
|
9
|
+
(await import("./app-2Dd57a5d.mjs")).main();
|
|
10
10
|
} catch (error) {
|
|
11
11
|
process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
|
|
12
12
|
process.exit(1);
|
|
@@ -3,5 +3,5 @@ import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
|
3
3
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
|
-
import { n as multiSearchWithTrace } from "./src-
|
|
6
|
+
import { n as multiSearchWithTrace } from "./src-tDEINaMV.mjs";
|
|
7
7
|
export { multiSearchWithTrace };
|
|
@@ -3,6 +3,7 @@ import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
|
3
3
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
6
7
|
import { mkdir, readFile, readdir } from "node:fs/promises";
|
|
7
8
|
import { DatabaseSync } from "node:sqlite";
|
|
8
9
|
//#region ../../node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.mjs
|
|
@@ -203,6 +204,8 @@ function jsonToVector(json) {
|
|
|
203
204
|
function isEntityType(value) {
|
|
204
205
|
return ENTITY_TYPES$1.has(value);
|
|
205
206
|
}
|
|
207
|
+
/** Meta key recording which embedding model the stored vectors came from. */
|
|
208
|
+
const EMBEDDING_MODEL_META_KEY = "embedding_model";
|
|
206
209
|
var KnowledgeStore = class {
|
|
207
210
|
dbPath;
|
|
208
211
|
db;
|
|
@@ -288,6 +291,22 @@ var KnowledgeStore = class {
|
|
|
288
291
|
this.db.exec("ROLLBACK");
|
|
289
292
|
} catch {}
|
|
290
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* Read a metadata value (e.g. the embedding model identity the library was
|
|
296
|
+
* built with). Returns null when the key is absent.
|
|
297
|
+
*/
|
|
298
|
+
async getMeta(key) {
|
|
299
|
+
await this.init();
|
|
300
|
+
if (this.db === void 0) return null;
|
|
301
|
+
const row = this.db.prepare("SELECT value FROM knowledge_meta WHERE key = ?").get(key);
|
|
302
|
+
return row === void 0 ? null : asString(row["value"]);
|
|
303
|
+
}
|
|
304
|
+
/** Write a metadata value (upsert). */
|
|
305
|
+
async setMeta(key, value) {
|
|
306
|
+
await this.init();
|
|
307
|
+
if (this.db === void 0) throw new Error("knowledge store not initialized");
|
|
308
|
+
this.db.prepare("INSERT INTO knowledge_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(key, value);
|
|
309
|
+
}
|
|
291
310
|
createSchema() {
|
|
292
311
|
if (this.db === void 0) return;
|
|
293
312
|
this.db.exec(`
|
|
@@ -383,22 +402,39 @@ var KnowledgeStore = class {
|
|
|
383
402
|
CREATE VIRTUAL TABLE IF NOT EXISTS knowledge_entities_fts USING fts5(
|
|
384
403
|
name, description, content='knowledge_entities', content_rowid='rowid'
|
|
385
404
|
);
|
|
405
|
+
|
|
406
|
+
CREATE TABLE IF NOT EXISTS knowledge_meta (
|
|
407
|
+
key TEXT PRIMARY KEY,
|
|
408
|
+
value TEXT NOT NULL
|
|
409
|
+
);
|
|
386
410
|
`);
|
|
411
|
+
try {
|
|
412
|
+
this.db.exec("ALTER TABLE knowledge_sources ADD COLUMN content_hash TEXT");
|
|
413
|
+
} catch (error) {
|
|
414
|
+
if (!(error instanceof Error ? error.message : String(error)).includes("duplicate column")) throw error;
|
|
415
|
+
}
|
|
387
416
|
}
|
|
388
417
|
async createSource(params) {
|
|
389
418
|
await this.init();
|
|
390
419
|
if (this.db === void 0) throw new Error("knowledge store not initialized");
|
|
391
420
|
const id = generateId("src");
|
|
392
421
|
const createdAt = Date.now();
|
|
393
|
-
this.db.prepare("INSERT INTO knowledge_sources (id, name, file_path, description, created_at) VALUES (?, ?, ?, ?, ?)").run(id, params.name, params.filePath ?? null, params.description ?? null, createdAt);
|
|
422
|
+
this.db.prepare("INSERT INTO knowledge_sources (id, name, file_path, description, content_hash, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(id, params.name, params.filePath ?? null, params.description ?? null, params.contentHash ?? null, createdAt);
|
|
394
423
|
return {
|
|
395
424
|
id,
|
|
396
425
|
name: params.name,
|
|
397
426
|
filePath: params.filePath ?? null,
|
|
398
427
|
description: params.description ?? null,
|
|
428
|
+
contentHash: params.contentHash ?? null,
|
|
399
429
|
createdAt
|
|
400
430
|
};
|
|
401
431
|
}
|
|
432
|
+
/** Backfill or refresh a source's content fingerprint (legacy rows / replacements). */
|
|
433
|
+
async updateSourceContentHash(id, contentHash) {
|
|
434
|
+
await this.init();
|
|
435
|
+
if (this.db === void 0) throw new Error("knowledge store not initialized");
|
|
436
|
+
this.db.prepare("UPDATE knowledge_sources SET content_hash = ? WHERE id = ?").run(contentHash, id);
|
|
437
|
+
}
|
|
402
438
|
async findSourceByFilePath(filePath) {
|
|
403
439
|
await this.init();
|
|
404
440
|
if (this.db === void 0) return void 0;
|
|
@@ -766,6 +802,87 @@ var KnowledgeStore = class {
|
|
|
766
802
|
}
|
|
767
803
|
return out;
|
|
768
804
|
}
|
|
805
|
+
/**
|
|
806
|
+
* Recompute every embedding for one source from the already-stored texts
|
|
807
|
+
* (no LLM extraction). Repairs libraries whose vectors are missing
|
|
808
|
+
* (ingested while the embedding model was unavailable) or stale (produced
|
|
809
|
+
* by a different model). All texts are embedded up front — any batch
|
|
810
|
+
* failure aborts before the first write, so the library is never left
|
|
811
|
+
* half-updated. On success the embedding-model meta is stamped with the
|
|
812
|
+
* engine's identity, unblocking future ingests after a model change.
|
|
813
|
+
*/
|
|
814
|
+
async reembedSource(sourceId, engine) {
|
|
815
|
+
await this.init();
|
|
816
|
+
if (this.db === void 0) throw new Error("knowledge store not initialized");
|
|
817
|
+
if (!engine.available) throw new Error("embedding engine unavailable");
|
|
818
|
+
const chunkRows = this.db.prepare("SELECT id, heading, content FROM knowledge_chunks WHERE source_id = ? ORDER BY rank ASC").all(sourceId);
|
|
819
|
+
const chunkTexts = chunkRows.map((c) => c.heading !== null ? `${c.heading}\n${c.content}` : c.content);
|
|
820
|
+
const eventRows = this.db.prepare("SELECT id, title, content FROM knowledge_events WHERE source_id = ? ORDER BY rank ASC").all(sourceId);
|
|
821
|
+
const eventTitleTexts = eventRows.map((e) => e.title);
|
|
822
|
+
const eventContentTexts = eventRows.map((e) => `${e.title}\n\n${e.content}`);
|
|
823
|
+
const entityRows = this.db.prepare("SELECT id, name FROM knowledge_entities WHERE source_id = ?").all(sourceId);
|
|
824
|
+
const relationRows = this.db.prepare(`SELECT ee.id, ee.description, e.title, en.name
|
|
825
|
+
FROM knowledge_event_entities ee
|
|
826
|
+
JOIN knowledge_events e ON e.id = ee.event_id
|
|
827
|
+
JOIN knowledge_entities en ON en.id = ee.entity_id
|
|
828
|
+
WHERE e.source_id = ?`).all(sourceId);
|
|
829
|
+
const relationTexts = relationRows.map((r) => r.description !== null && r.description.length > 0 ? r.description : `${r.title} ${r.name}`);
|
|
830
|
+
const embedAll = async (texts) => {
|
|
831
|
+
if (texts.length === 0) return [];
|
|
832
|
+
const vectors = await engine.embedBatch(texts);
|
|
833
|
+
if (vectors === null || vectors.length !== texts.length) throw new Error("向量嵌入失败,已取消本次重新嵌入");
|
|
834
|
+
return vectors;
|
|
835
|
+
};
|
|
836
|
+
const chunkVecs = await embedAll(chunkTexts);
|
|
837
|
+
const eventTitleVecs = await embedAll(eventTitleTexts);
|
|
838
|
+
const eventContentVecs = await embedAll(eventContentTexts);
|
|
839
|
+
const entityVecs = await embedAll(entityRows.map((e) => e.name));
|
|
840
|
+
const relationVecs = await embedAll(relationTexts);
|
|
841
|
+
this.beginTransaction();
|
|
842
|
+
try {
|
|
843
|
+
const updChunk = this.db.prepare("UPDATE knowledge_chunks SET embedding_json = ? WHERE id = ?");
|
|
844
|
+
for (let i = 0; i < chunkRows.length; i++) updChunk.run(vectorToJson(chunkVecs[i] ?? null), chunkRows[i].id);
|
|
845
|
+
const updEvent = this.db.prepare("UPDATE knowledge_events SET title_embedding_json = ?, content_embedding_json = ? WHERE id = ?");
|
|
846
|
+
for (let i = 0; i < eventRows.length; i++) updEvent.run(vectorToJson(eventTitleVecs[i] ?? null), vectorToJson(eventContentVecs[i] ?? null), eventRows[i].id);
|
|
847
|
+
const updEntity = this.db.prepare("UPDATE knowledge_entities SET embedding_json = ? WHERE id = ?");
|
|
848
|
+
for (let i = 0; i < entityRows.length; i++) updEntity.run(vectorToJson(entityVecs[i] ?? null), entityRows[i].id);
|
|
849
|
+
const updRelation = this.db.prepare("UPDATE knowledge_event_entities SET embedding_json = ? WHERE id = ?");
|
|
850
|
+
for (let i = 0; i < relationRows.length; i++) updRelation.run(vectorToJson(relationVecs[i] ?? null), relationRows[i].id);
|
|
851
|
+
await this.setMeta(EMBEDDING_MODEL_META_KEY, engine.modelName);
|
|
852
|
+
this.commitTransaction();
|
|
853
|
+
} catch (error) {
|
|
854
|
+
this.rollbackTransaction();
|
|
855
|
+
throw error;
|
|
856
|
+
}
|
|
857
|
+
return {
|
|
858
|
+
chunks: chunkRows.length,
|
|
859
|
+
events: eventRows.length,
|
|
860
|
+
entities: entityRows.length,
|
|
861
|
+
relations: relationRows.length
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Chunk vector coverage — how many of the stored chunks carry an embedding.
|
|
866
|
+
* Used by the TUI to surface partial/skipped embedding after an ingest.
|
|
867
|
+
*/
|
|
868
|
+
async embeddingCoverage() {
|
|
869
|
+
await this.init();
|
|
870
|
+
if (this.db === void 0) return {
|
|
871
|
+
total: 0,
|
|
872
|
+
embedded: 0
|
|
873
|
+
};
|
|
874
|
+
const row = this.db.prepare(`SELECT COUNT(*) AS total,
|
|
875
|
+
SUM(CASE WHEN embedding_json IS NOT NULL THEN 1 ELSE 0 END) AS embedded
|
|
876
|
+
FROM knowledge_chunks`).get();
|
|
877
|
+
if (row === void 0) return {
|
|
878
|
+
total: 0,
|
|
879
|
+
embedded: 0
|
|
880
|
+
};
|
|
881
|
+
return {
|
|
882
|
+
total: Number(row["total"] ?? 0),
|
|
883
|
+
embedded: Number(row["embedded"] ?? 0)
|
|
884
|
+
};
|
|
885
|
+
}
|
|
769
886
|
async stats() {
|
|
770
887
|
await this.init();
|
|
771
888
|
if (this.db === void 0) return {
|
|
@@ -825,6 +942,7 @@ function rowToSource(row) {
|
|
|
825
942
|
name: asString(row["name"]),
|
|
826
943
|
filePath: asNullableString(row["file_path"]),
|
|
827
944
|
description: asNullableString(row["description"]),
|
|
945
|
+
contentHash: asNullableString(row["content_hash"]),
|
|
828
946
|
createdAt: Number(row["created_at"])
|
|
829
947
|
};
|
|
830
948
|
}
|
|
@@ -1487,6 +1605,22 @@ async function mapWithConcurrency(items, limit, fn, onProgress) {
|
|
|
1487
1605
|
return results;
|
|
1488
1606
|
}
|
|
1489
1607
|
/**
|
|
1608
|
+
* Stamp or verify the embedding-model identity recorded in the library.
|
|
1609
|
+
* A library written by a different model would mix vector spaces — block the
|
|
1610
|
+
* ingest with a clear message instead of silently storing incompatible
|
|
1611
|
+
* embeddings. A legacy library without the marker is stamped with the current
|
|
1612
|
+
* model (all existing data was written by it).
|
|
1613
|
+
*/
|
|
1614
|
+
async function ensureEmbeddingModelMatches(store, engine) {
|
|
1615
|
+
if (engine === void 0) return;
|
|
1616
|
+
const recorded = await store.getMeta(EMBEDDING_MODEL_META_KEY);
|
|
1617
|
+
if (recorded === null) {
|
|
1618
|
+
await store.setMeta(EMBEDDING_MODEL_META_KEY, engine.modelName);
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1621
|
+
if (recorded !== engine.modelName) throw new Error(`知识库由模型 ${recorded} 嵌入,当前模型为 ${engine.modelName},请先在 /knowledge 中重新嵌入知识库`);
|
|
1622
|
+
}
|
|
1623
|
+
/**
|
|
1490
1624
|
* Ingest a markdown file into the knowledge base.
|
|
1491
1625
|
*
|
|
1492
1626
|
* Steps:
|
|
@@ -1511,34 +1645,53 @@ async function ingestFile(store, llm, filePath, onProgress) {
|
|
|
1511
1645
|
stage: "embedding-check",
|
|
1512
1646
|
message: "向量模型未就绪,本次摄入跳过向量嵌入"
|
|
1513
1647
|
});
|
|
1514
|
-
|
|
1515
|
-
if (existing !== void 0) {
|
|
1516
|
-
onProgress?.({
|
|
1517
|
-
stage: "error",
|
|
1518
|
-
message: `文件已摄入:${existing.name}(source id=${existing.id})`
|
|
1519
|
-
});
|
|
1520
|
-
throw new Error(`文件已摄入过: ${filePath} (source ${existing.id})`);
|
|
1521
|
-
}
|
|
1648
|
+
await ensureEmbeddingModelMatches(store, engine);
|
|
1522
1649
|
onProgress?.({
|
|
1523
1650
|
stage: "chunking",
|
|
1524
1651
|
message: `读取并切分文件: ${basename(filePath)}`
|
|
1525
1652
|
});
|
|
1526
1653
|
const content = await readFileContent(filePath);
|
|
1527
|
-
const
|
|
1528
|
-
|
|
1654
|
+
const contentHash = createHash("sha256").update(content).digest("hex");
|
|
1655
|
+
const existing = await store.findSourceByFilePath(filePath);
|
|
1656
|
+
let replacedOldVersion = false;
|
|
1657
|
+
if (existing !== void 0) {
|
|
1658
|
+
if (existing.contentHash === contentHash || existing.contentHash === null) {
|
|
1659
|
+
if (existing.contentHash === null) await store.updateSourceContentHash(existing.id, contentHash);
|
|
1660
|
+
onProgress?.({
|
|
1661
|
+
stage: "completed",
|
|
1662
|
+
message: "内容未变化,已跳过"
|
|
1663
|
+
});
|
|
1664
|
+
return {
|
|
1665
|
+
documentId: null,
|
|
1666
|
+
chunkCount: 0,
|
|
1667
|
+
eventCount: 0,
|
|
1668
|
+
entityCount: 0,
|
|
1669
|
+
outcome: "unchanged"
|
|
1670
|
+
};
|
|
1671
|
+
}
|
|
1529
1672
|
onProgress?.({
|
|
1530
|
-
stage: "
|
|
1531
|
-
message:
|
|
1673
|
+
stage: "chunking",
|
|
1674
|
+
message: `检测到内容变更,替换旧版本: ${existing.name}`
|
|
1532
1675
|
});
|
|
1533
|
-
|
|
1676
|
+
await store.deleteSource(existing.id);
|
|
1677
|
+
replacedOldVersion = true;
|
|
1534
1678
|
}
|
|
1679
|
+
const sections = chunkContent(content, getFileExtension(filePath));
|
|
1535
1680
|
store.beginTransaction();
|
|
1536
1681
|
try {
|
|
1682
|
+
if (sections.length === 0) {
|
|
1683
|
+
onProgress?.({
|
|
1684
|
+
stage: "error",
|
|
1685
|
+
message: "文件无有效内容"
|
|
1686
|
+
});
|
|
1687
|
+
throw new Error("文件无有效内容可摄入");
|
|
1688
|
+
}
|
|
1537
1689
|
const fileName = basename(filePath);
|
|
1538
1690
|
const source = await store.createSource({
|
|
1539
1691
|
name: fileName,
|
|
1540
1692
|
filePath,
|
|
1541
|
-
description: null
|
|
1693
|
+
description: null,
|
|
1694
|
+
contentHash
|
|
1542
1695
|
});
|
|
1543
1696
|
const document = await store.createDocument({
|
|
1544
1697
|
sourceId: source.id,
|
|
@@ -1687,10 +1840,15 @@ async function ingestFile(store, llm, filePath, onProgress) {
|
|
|
1687
1840
|
documentId: document.id,
|
|
1688
1841
|
chunkCount: chunks.length,
|
|
1689
1842
|
eventCount: events.length,
|
|
1690
|
-
entityCount: uniqueEntities.length
|
|
1843
|
+
entityCount: uniqueEntities.length,
|
|
1844
|
+
outcome: replacedOldVersion ? "updated" : "created"
|
|
1691
1845
|
};
|
|
1692
1846
|
} catch (error) {
|
|
1693
1847
|
store.rollbackTransaction();
|
|
1848
|
+
if (replacedOldVersion) {
|
|
1849
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1850
|
+
throw new Error(`旧版本已删除、新版本摄入失败,请重新摄入该文件: ${filePath}(${message})`);
|
|
1851
|
+
}
|
|
1694
1852
|
throw error;
|
|
1695
1853
|
}
|
|
1696
1854
|
}
|
|
@@ -1709,6 +1867,9 @@ async function ingestDirectory(store, llm, dirPath, onProgress) {
|
|
|
1709
1867
|
if (files.length === 0) throw new Error(`目录下没有支持的文件 (.md, .markdown, .txt): ${dirPath}`);
|
|
1710
1868
|
const errors = [];
|
|
1711
1869
|
let succeeded = 0;
|
|
1870
|
+
let created = 0;
|
|
1871
|
+
let updated = 0;
|
|
1872
|
+
let unchanged = 0;
|
|
1712
1873
|
let totalChunks = 0;
|
|
1713
1874
|
let totalEvents = 0;
|
|
1714
1875
|
let totalEntities = 0;
|
|
@@ -1724,6 +1885,9 @@ async function ingestDirectory(store, llm, dirPath, onProgress) {
|
|
|
1724
1885
|
try {
|
|
1725
1886
|
const result = await ingestFile(store, llm, filePath, fileProgress);
|
|
1726
1887
|
succeeded += 1;
|
|
1888
|
+
if (result.outcome === "created") created += 1;
|
|
1889
|
+
else if (result.outcome === "updated") updated += 1;
|
|
1890
|
+
else unchanged += 1;
|
|
1727
1891
|
totalChunks += result.chunkCount;
|
|
1728
1892
|
totalEvents += result.eventCount;
|
|
1729
1893
|
totalEntities += result.entityCount;
|
|
@@ -1741,11 +1905,14 @@ async function ingestDirectory(store, llm, dirPath, onProgress) {
|
|
|
1741
1905
|
}
|
|
1742
1906
|
onProgress?.({
|
|
1743
1907
|
stage: "completed",
|
|
1744
|
-
message:
|
|
1908
|
+
message: `批量摄入完成:新增 ${created} · 更新 ${updated} · 未变化 ${unchanged} · 失败 ${errors.length}(${totalChunks} chunks, ${totalEvents} events, ${totalEntities} entities)`
|
|
1745
1909
|
});
|
|
1746
1910
|
return {
|
|
1747
1911
|
succeeded,
|
|
1748
1912
|
failed: errors.length,
|
|
1913
|
+
created,
|
|
1914
|
+
updated,
|
|
1915
|
+
unchanged,
|
|
1749
1916
|
totalChunks,
|
|
1750
1917
|
totalEvents,
|
|
1751
1918
|
totalEntities,
|
|
@@ -1820,6 +1987,18 @@ async function multiSearchWithTrace(store, llm, query, options = {}) {
|
|
|
1820
1987
|
}
|
|
1821
1988
|
};
|
|
1822
1989
|
}
|
|
1990
|
+
const recordedModel = await store.getMeta(EMBEDDING_MODEL_META_KEY);
|
|
1991
|
+
if (recordedModel !== null && recordedModel !== engine.modelName) {
|
|
1992
|
+
fallbackReason = `embedding model mismatch (library: ${recordedModel}, current: ${engine.modelName}); used FTS5 keyword fallback`;
|
|
1993
|
+
return {
|
|
1994
|
+
results: await ftsFallback(store, query, topK),
|
|
1995
|
+
trace: {
|
|
1996
|
+
steps,
|
|
1997
|
+
rerankedEventTitles,
|
|
1998
|
+
fallbackReason
|
|
1999
|
+
}
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
1823
2002
|
const queryEmbeddings = await timed(onStep, "queryEmbedding", "把用户问题转成向量,用于召回相关事件和切片。", async () => engine.embedBatch([query]));
|
|
1824
2003
|
if (queryEmbeddings === null || queryEmbeddings.length === 0) {
|
|
1825
2004
|
fallbackReason = "query embedding returned null; used FTS5 fallback";
|
|
@@ -302,6 +302,21 @@ const dictionaries = {
|
|
|
302
302
|
"knowledge.menu_title": "SAG知识库管理",
|
|
303
303
|
"knowledge.menu_hint": "选择操作(esc 退出)",
|
|
304
304
|
"knowledge.op_failed": "操作失败: {msg}",
|
|
305
|
+
"knowledge.loading_model": "加载向量模型中...",
|
|
306
|
+
"knowledge.model_missing": "尚未下载向量模型,请先在 /knowledge 菜单选择「下载向量模型」",
|
|
307
|
+
"knowledge.model_load_failed": "向量模型加载失败,本次未摄入任何内容",
|
|
308
|
+
"knowledge.vector_coverage": "向量嵌入: {embedded}/{total} chunks",
|
|
309
|
+
"knowledge.reembed": "重新嵌入",
|
|
310
|
+
"knowledge.reembed_desc": "对指定文档重算全部向量(不重新抽取,不消耗 LLM)",
|
|
311
|
+
"knowledge.reembed_pick": "选择要重新嵌入的知识",
|
|
312
|
+
"knowledge.reembed_confirm_name": "重新嵌入「{name}」?",
|
|
313
|
+
"knowledge.reembed_confirm_desc": "将重算该文档所有 chunks/events/entities 向量",
|
|
314
|
+
"knowledge.reembed_done": "重新嵌入完成",
|
|
315
|
+
"knowledge.reembed_summary": "chunks: {chunks}, events: {events}, entities: {entities}, relations: {relations}",
|
|
316
|
+
"knowledge.reembed_none": "知识库为空,无可重新嵌入的内容",
|
|
317
|
+
"knowledge.ingest_unchanged": "内容未变化,已跳过",
|
|
318
|
+
"knowledge.ingest_updated": "已替换旧版本,重新摄入完成",
|
|
319
|
+
"knowledge.sync_counts": "新增 {created} · 更新 {updated} · 未变化 {unchanged}",
|
|
305
320
|
"init.select_title": "选择 AGENTS.md 生成位置",
|
|
306
321
|
"init.select_hint": "当前目录:{currentDir} · 项目根目录:{projectRoot}",
|
|
307
322
|
"init.current_dir": "当前目录",
|
|
@@ -1018,12 +1033,6 @@ const dictionaries = {
|
|
|
1018
1033
|
"prompts.wire_openai_responses_desc": "OpenAI Responses API(推理模型)",
|
|
1019
1034
|
"prompts.wire_anthropic": "Anthropic 协议",
|
|
1020
1035
|
"prompts.wire_anthropic_desc": "Messages API 兼容的服务商",
|
|
1021
|
-
"prompts.thinking_off": "关闭思考",
|
|
1022
|
-
"prompts.thinking_low": "低强度思考",
|
|
1023
|
-
"prompts.thinking_medium": "中强度思考",
|
|
1024
|
-
"prompts.thinking_high": "高强度思考",
|
|
1025
|
-
"prompts.thinking_xhigh": "超高强度思考",
|
|
1026
|
-
"prompts.thinking_max": "最大强度思考",
|
|
1027
1036
|
"prompts.image_off": "关闭识图",
|
|
1028
1037
|
"prompts.image_off_desc": "模型不支持图片输入时请选择此项",
|
|
1029
1038
|
"prompts.image_on": "开启识图",
|
|
@@ -1199,7 +1208,11 @@ const dictionaries = {
|
|
|
1199
1208
|
"kw.embedding_ready": "向量模型已就绪",
|
|
1200
1209
|
"kw.embedding_not_downloaded": "向量模型未下载(选择「下载向量模型」手动下载)",
|
|
1201
1210
|
"kw.embedding_data_intact": " —— 你的知识数据仍然存在,下载模型后即可正常使用",
|
|
1202
|
-
"kw.embedding_already_installed": "向量模型已安装,无需重新下载"
|
|
1211
|
+
"kw.embedding_already_installed": "向量模型已安装,无需重新下载",
|
|
1212
|
+
"kw.setup_description": "检测到向量模型尚未下载。下载后 /knowledge 知识库与 /memory 记忆将启用语义检索(模型约 95 MB,只需下载一次)。",
|
|
1213
|
+
"kw.setup_download": "立即下载",
|
|
1214
|
+
"kw.setup_skip": "暂不下载",
|
|
1215
|
+
"kw.setup_hint": "↑↓ 选择 · Enter 确认 · Esc 跳过"
|
|
1203
1216
|
},
|
|
1204
1217
|
en: {
|
|
1205
1218
|
"status.not_set": "Not set",
|
|
@@ -1404,6 +1417,21 @@ const dictionaries = {
|
|
|
1404
1417
|
"knowledge.menu_title": "SAG Knowledge Base",
|
|
1405
1418
|
"knowledge.menu_hint": "Select an action (Esc to exit)",
|
|
1406
1419
|
"knowledge.op_failed": "Operation failed: {msg}",
|
|
1420
|
+
"knowledge.loading_model": "Loading vector model...",
|
|
1421
|
+
"knowledge.model_missing": "Vector model not downloaded yet. Select \"Download vector model\" in the /knowledge menu first.",
|
|
1422
|
+
"knowledge.model_load_failed": "Vector model failed to load. Nothing was ingested.",
|
|
1423
|
+
"knowledge.vector_coverage": "Vectors: {embedded}/{total} chunks embedded",
|
|
1424
|
+
"knowledge.reembed": "Re-embed",
|
|
1425
|
+
"knowledge.reembed_desc": "Recompute all vectors for one document (no re-extraction, no LLM cost)",
|
|
1426
|
+
"knowledge.reembed_pick": "Pick knowledge to re-embed",
|
|
1427
|
+
"knowledge.reembed_confirm_name": "Re-embed \"{name}\"?",
|
|
1428
|
+
"knowledge.reembed_confirm_desc": "All chunk/event/entity vectors of this document will be recomputed",
|
|
1429
|
+
"knowledge.reembed_done": "Re-embed completed",
|
|
1430
|
+
"knowledge.reembed_summary": "chunks: {chunks}, events: {events}, entities: {entities}, relations: {relations}",
|
|
1431
|
+
"knowledge.reembed_none": "Knowledge base is empty; nothing to re-embed",
|
|
1432
|
+
"knowledge.ingest_unchanged": "Content unchanged, skipped",
|
|
1433
|
+
"knowledge.ingest_updated": "Previous version replaced; re-ingestion completed",
|
|
1434
|
+
"knowledge.sync_counts": "new: {created} · updated: {updated} · unchanged: {unchanged}",
|
|
1407
1435
|
"init.select_title": "Select AGENTS.md location",
|
|
1408
1436
|
"init.select_hint": "Current: {currentDir} · Project root: {projectRoot}",
|
|
1409
1437
|
"init.current_dir": "Current directory",
|
|
@@ -2120,12 +2148,6 @@ const dictionaries = {
|
|
|
2120
2148
|
"prompts.wire_openai_responses_desc": "OpenAI Responses API (reasoning models)",
|
|
2121
2149
|
"prompts.wire_anthropic": "Anthropic protocol",
|
|
2122
2150
|
"prompts.wire_anthropic_desc": "Messages API compatible providers",
|
|
2123
|
-
"prompts.thinking_off": "Thinking off",
|
|
2124
|
-
"prompts.thinking_low": "Low thinking",
|
|
2125
|
-
"prompts.thinking_medium": "Medium thinking",
|
|
2126
|
-
"prompts.thinking_high": "High thinking",
|
|
2127
|
-
"prompts.thinking_xhigh": "Extra-high thinking",
|
|
2128
|
-
"prompts.thinking_max": "Max thinking",
|
|
2129
2151
|
"prompts.image_off": "Image off",
|
|
2130
2152
|
"prompts.image_off_desc": "Select this when the model does not support image input",
|
|
2131
2153
|
"prompts.image_on": "Image on",
|
|
@@ -2301,7 +2323,11 @@ const dictionaries = {
|
|
|
2301
2323
|
"kw.embedding_ready": "Vector model ready",
|
|
2302
2324
|
"kw.embedding_not_downloaded": "Vector model not downloaded (select Download vector model)",
|
|
2303
2325
|
"kw.embedding_data_intact": " — your knowledge data is still there; download the model to use it again",
|
|
2304
|
-
"kw.embedding_already_installed": "Vector model already installed, no need to re-download"
|
|
2326
|
+
"kw.embedding_already_installed": "Vector model already installed, no need to re-download",
|
|
2327
|
+
"kw.setup_description": "The vector model is not downloaded yet. Once downloaded, /knowledge and /memory gain semantic retrieval (about 95 MB, one-time download).",
|
|
2328
|
+
"kw.setup_download": "Download now",
|
|
2329
|
+
"kw.setup_skip": "Not now",
|
|
2330
|
+
"kw.setup_hint": "↑↓ select · Enter confirm · Esc skip"
|
|
2305
2331
|
}
|
|
2306
2332
|
};
|
|
2307
2333
|
function detectSystemLocale() {
|
|
@@ -3,5 +3,5 @@ import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
|
3
3
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
|
-
import { t as TextInputDialogComponent } from "./text-input-dialog-
|
|
6
|
+
import { t as TextInputDialogComponent } from "./text-input-dialog-BUXAKycx.mjs";
|
|
7
7
|
export { TextInputDialogComponent };
|