@co-engram/core 0.1.5 → 0.1.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/dist/dreaming/decay.d.ts.map +1 -1
- package/dist/dreaming/decay.js +1 -1
- package/dist/dreaming/decay.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +29 -4
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts +24 -5
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +29 -2
- package/dist/i18n/zh.js.map +1 -1
- package/dist/importance/vector.d.ts +4 -4
- package/dist/importance/vector.d.ts.map +1 -1
- package/dist/importance/vector.js +7 -12
- package/dist/importance/vector.js.map +1 -1
- package/dist/lifecycle/freshness.d.ts +25 -6
- package/dist/lifecycle/freshness.d.ts.map +1 -1
- package/dist/lifecycle/freshness.js +37 -21
- package/dist/lifecycle/freshness.js.map +1 -1
- package/dist/merge-driver.cjs +1 -1
- package/dist/observability/proposal-engine.d.ts +2 -1
- package/dist/observability/proposal-engine.d.ts.map +1 -1
- package/dist/observability/proposal-engine.js +6 -3
- package/dist/observability/proposal-engine.js.map +1 -1
- package/dist/prompt-builder/builder.d.ts +3 -0
- package/dist/prompt-builder/builder.d.ts.map +1 -1
- package/dist/prompt-builder/builder.js +45 -3
- package/dist/prompt-builder/builder.js.map +1 -1
- package/dist/prompt-builder/index.d.ts +1 -0
- package/dist/prompt-builder/index.d.ts.map +1 -1
- package/dist/prompt-builder/index.js +1 -0
- package/dist/prompt-builder/index.js.map +1 -1
- package/dist/prompt-builder/path-overview.d.ts +35 -0
- package/dist/prompt-builder/path-overview.d.ts.map +1 -0
- package/dist/prompt-builder/path-overview.js +44 -0
- package/dist/prompt-builder/path-overview.js.map +1 -0
- package/dist/prompt-builder/types.d.ts +11 -0
- package/dist/prompt-builder/types.d.ts.map +1 -1
- package/dist/retrieval/index.d.ts +2 -0
- package/dist/retrieval/index.d.ts.map +1 -1
- package/dist/retrieval/index.js +2 -0
- package/dist/retrieval/index.js.map +1 -1
- package/dist/retrieval/scoring.d.ts +7 -4
- package/dist/retrieval/scoring.d.ts.map +1 -1
- package/dist/retrieval/scoring.js +9 -16
- package/dist/retrieval/scoring.js.map +1 -1
- package/dist/retrieval/search-engine.d.ts +58 -0
- package/dist/retrieval/search-engine.d.ts.map +1 -0
- package/dist/retrieval/search-engine.js +53 -0
- package/dist/retrieval/search-engine.js.map +1 -0
- package/dist/retrieval/sqlite-orchestrator.d.ts +68 -0
- package/dist/retrieval/sqlite-orchestrator.d.ts.map +1 -0
- package/dist/retrieval/sqlite-orchestrator.js +148 -0
- package/dist/retrieval/sqlite-orchestrator.js.map +1 -0
- package/dist/storage/bootstrap.d.ts +31 -0
- package/dist/storage/bootstrap.d.ts.map +1 -0
- package/dist/storage/bootstrap.js +89 -0
- package/dist/storage/bootstrap.js.map +1 -0
- package/dist/storage/index-db-cursor.d.ts +27 -0
- package/dist/storage/index-db-cursor.d.ts.map +1 -0
- package/dist/storage/index-db-cursor.js +59 -0
- package/dist/storage/index-db-cursor.js.map +1 -0
- package/dist/storage/index-db.d.ts +112 -0
- package/dist/storage/index-db.d.ts.map +1 -0
- package/dist/storage/index-db.js +183 -0
- package/dist/storage/index-db.js.map +1 -0
- package/dist/storage/index.d.ts +3 -0
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +5 -0
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/repository.d.ts +30 -2
- package/dist/storage/repository.d.ts.map +1 -1
- package/dist/storage/repository.js +73 -2
- package/dist/storage/repository.js.map +1 -1
- package/dist/tools/audit-query-tool.d.ts +2 -2
- package/dist/tools/engram-tools.d.ts.map +1 -1
- package/dist/tools/engram-tools.js +2 -2
- package/dist/tools/engram-tools.js.map +1 -1
- package/dist/tools/proposal-tools.d.ts.map +1 -1
- package/dist/tools/proposal-tools.js +1 -0
- package/dist/tools/proposal-tools.js.map +1 -1
- package/dist/tools/schemas.d.ts +78 -70
- package/dist/tools/schemas.d.ts.map +1 -1
- package/dist/tools/schemas.js +6 -0
- package/dist/tools/schemas.js.map +1 -1
- package/dist/tools/tool.d.ts +1 -1
- package/dist/tools/tool.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompt-builder/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompt-builder/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 仓库目录概览(host-agnostic 工具)
|
|
3
|
+
*
|
|
4
|
+
* 用于 system prompt 的"目录深度渐进式披露":常驻注入 depth=1 顶级目录,
|
|
5
|
+
* 让 LLM 在 search 前看到仓库结构。
|
|
6
|
+
*
|
|
7
|
+
* 设计判断(详见对话样本 2026-07-04):
|
|
8
|
+
* - 目录是**结构信息**(静态、廉价),不是统计信息(动态、需算频次)
|
|
9
|
+
* - 因此走常驻 system prompt,不走 prompt-signals 自进化路径
|
|
10
|
+
* - 深度梯度靠 maxDepth 参数:system prompt=1、engram_list_paths 工具按需调用
|
|
11
|
+
*
|
|
12
|
+
* @module @co-engram/core/prompt-builder
|
|
13
|
+
*/
|
|
14
|
+
import type { Language } from "../i18n/index.js";
|
|
15
|
+
import type { PathTreeNode } from "../types/repository-types.js";
|
|
16
|
+
/** 单条目录概览项(扁平,无树结构) */
|
|
17
|
+
export interface PathOverviewItem {
|
|
18
|
+
/** 相对 dataRoot 的目录路径(如 "co-engram"、"设计原则/co-engram") */
|
|
19
|
+
readonly path: string;
|
|
20
|
+
/** 该目录及其所有子目录的累积 engram 数 */
|
|
21
|
+
readonly engramCount: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 从完整 PathTreeNode 截断到指定深度,返回扁平概览列表。
|
|
25
|
+
*
|
|
26
|
+
* @param maxDepth - 1=顶级目录(项目级),2=加孙目录(领域级),以此类推
|
|
27
|
+
*/
|
|
28
|
+
export declare function pathOverviewFromTree(tree: PathTreeNode, maxDepth?: number): readonly PathOverviewItem[];
|
|
29
|
+
/**
|
|
30
|
+
* 格式化目录概览为可注入 system prompt 的 i18n 文本。
|
|
31
|
+
*
|
|
32
|
+
* 空列表返回空字符串(调用方决定是否注入)。
|
|
33
|
+
*/
|
|
34
|
+
export declare function formatPathOverview(items: readonly PathOverviewItem[], language: Language): string;
|
|
35
|
+
//# sourceMappingURL=path-overview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-overview.d.ts","sourceRoot":"","sources":["../../src/prompt-builder/path-overview.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,uBAAuB;AACvB,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6BAA6B;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,YAAY,EAClB,QAAQ,SAAI,GACX,SAAS,gBAAgB,EAAE,CAW7B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,gBAAgB,EAAE,EAClC,QAAQ,EAAE,QAAQ,GACjB,MAAM,CAIR"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 仓库目录概览(host-agnostic 工具)
|
|
3
|
+
*
|
|
4
|
+
* 用于 system prompt 的"目录深度渐进式披露":常驻注入 depth=1 顶级目录,
|
|
5
|
+
* 让 LLM 在 search 前看到仓库结构。
|
|
6
|
+
*
|
|
7
|
+
* 设计判断(详见对话样本 2026-07-04):
|
|
8
|
+
* - 目录是**结构信息**(静态、廉价),不是统计信息(动态、需算频次)
|
|
9
|
+
* - 因此走常驻 system prompt,不走 prompt-signals 自进化路径
|
|
10
|
+
* - 深度梯度靠 maxDepth 参数:system prompt=1、engram_list_paths 工具按需调用
|
|
11
|
+
*
|
|
12
|
+
* @module @co-engram/core/prompt-builder
|
|
13
|
+
*/
|
|
14
|
+
import { translatePrompt } from "../i18n/index.js";
|
|
15
|
+
/**
|
|
16
|
+
* 从完整 PathTreeNode 截断到指定深度,返回扁平概览列表。
|
|
17
|
+
*
|
|
18
|
+
* @param maxDepth - 1=顶级目录(项目级),2=加孙目录(领域级),以此类推
|
|
19
|
+
*/
|
|
20
|
+
export function pathOverviewFromTree(tree, maxDepth = 1) {
|
|
21
|
+
const out = [];
|
|
22
|
+
const walk = (node, depth) => {
|
|
23
|
+
if (depth > maxDepth)
|
|
24
|
+
return;
|
|
25
|
+
for (const child of node.children) {
|
|
26
|
+
out.push({ path: child.path, engramCount: child.engramCount });
|
|
27
|
+
walk(child, depth + 1);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
walk(tree, 1);
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 格式化目录概览为可注入 system prompt 的 i18n 文本。
|
|
35
|
+
*
|
|
36
|
+
* 空列表返回空字符串(调用方决定是否注入)。
|
|
37
|
+
*/
|
|
38
|
+
export function formatPathOverview(items, language) {
|
|
39
|
+
if (items.length === 0)
|
|
40
|
+
return "";
|
|
41
|
+
const tree = items.map((i) => `- ${i.path} (${i.engramCount})`).join("\n");
|
|
42
|
+
return translatePrompt(language, "prompt.memory.repo_overview", { tree });
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=path-overview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-overview.js","sourceRoot":"","sources":["../../src/prompt-builder/path-overview.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAWnD;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAkB,EAClB,QAAQ,GAAG,CAAC;IAEZ,MAAM,GAAG,GAAuB,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,CAAC,IAAkB,EAAE,KAAa,EAAQ,EAAE;QACvD,IAAI,KAAK,GAAG,QAAQ;YAAE,OAAO;QAC7B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;YAC/D,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACzB,CAAC;IACH,CAAC,CAAC;IACF,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACd,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAkC,EAClC,QAAkB;IAElB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3E,OAAO,eAAe,CAAC,QAAQ,EAAE,6BAA6B,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;AAC5E,CAAC"}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { Language } from "../i18n/index.js";
|
|
10
10
|
import type { PromptSignalSnapshot } from "../prompt-signals/types.js";
|
|
11
|
+
import type { PathOverviewItem } from "./path-overview.js";
|
|
11
12
|
/**
|
|
12
13
|
* 自进化信号(从 PromptSignalSnapshot 派生)
|
|
13
14
|
*
|
|
@@ -34,6 +35,16 @@ export interface BuildPromptInput {
|
|
|
34
35
|
readonly signals?: PromptSignals;
|
|
35
36
|
/** 待处理 proposal 数量;0 时不注入 proposal 提醒 */
|
|
36
37
|
readonly proposalCount?: number;
|
|
38
|
+
/**
|
|
39
|
+
* 仓库目录概览(常驻 system prompt 注入,depth=1)。
|
|
40
|
+
*
|
|
41
|
+
* undefined / 空数组时跳过。提供时由 host adapter 从
|
|
42
|
+
* `repository.listPathTree()` 截断后传入。
|
|
43
|
+
*
|
|
44
|
+
* 与 signals 不同:目录是**结构信息**(静态、廉价),不走自进化路径。
|
|
45
|
+
* 设计判断详见 `path-overview.ts` 模块注释。
|
|
46
|
+
*/
|
|
47
|
+
readonly pathOverview?: readonly PathOverviewItem[];
|
|
37
48
|
}
|
|
38
49
|
/**
|
|
39
50
|
* Prompt builder 函数签名
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/prompt-builder/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/prompt-builder/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,oBAAoB,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6BAA6B;IAC7B,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7C,wBAAwB;IACxB,QAAQ,CAAC,aAAa,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;IACpD,oCAAoC;IACpC,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAC7B,oCAAoC;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;IACjC,yCAAyC;IACzC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;;;;OAQG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,SAAS,MAAM,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/retrieval/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/retrieval/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC"}
|
package/dist/retrieval/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/retrieval/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/retrieval/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC"}
|
|
@@ -59,11 +59,14 @@ export declare function effectiveImportance(importance: number, reinforcementSco
|
|
|
59
59
|
/**
|
|
60
60
|
* 从 DigestLine + relevance 计算三因子得分
|
|
61
61
|
*
|
|
62
|
+
* recency 维度的衰退计时起点 = `lastEffectiveAt ?? line.lastEffectiveAt ?? line.createdAt`:
|
|
63
|
+
* 未生效 engram 用 createdAt 兜底,新记忆从编码完成起开始衰退(艾宾浩斯模型)。
|
|
64
|
+
*
|
|
62
65
|
* @param relevance - 归一化相关度 [0,1]
|
|
63
|
-
* @param line - DigestLine
|
|
64
|
-
* @param lastEffectiveAt -
|
|
65
|
-
* @param now -
|
|
66
|
-
* @param weights -
|
|
66
|
+
* @param line - DigestLine(含 recency/importance 数据,需有 createdAt)
|
|
67
|
+
* @param lastEffectiveAt - 最后有效检索时间(可选,省略则用 line.lastEffectiveAt)
|
|
68
|
+
* @param now - 当前时间(可选,便于测试;省略则 new Date())
|
|
69
|
+
* @param weights - 权重配置(可选,省略用默认)
|
|
67
70
|
*/
|
|
68
71
|
export declare function computeThreeFactorScore(relevance: number, line: DigestLine, options?: {
|
|
69
72
|
lastEffectiveAt?: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scoring.d.ts","sourceRoot":"","sources":["../../src/retrieval/scoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"scoring.d.ts","sourceRoot":"","sources":["../../src/retrieval/scoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpD,cAAc;AACd,MAAM,WAAW,kBAAkB;IACjC,6BAA6B;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yBAAyB;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wBAAwB;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,yCAAyC;AACzC,eAAO,MAAM,eAAe,EAAE,kBAI7B,CAAC;AAEF;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAY3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,iBAAiB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC3C,MAAM,CAIR;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAOR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE;IACP,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,OAAO,CAAC,EAAE,kBAAkB,CAAC;CACzB,GACL,MAAM,CAmBR;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,EACzE,OAAO,GAAE;IACP,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,OAAO,CAAC,EAAE,kBAAkB,CAAC;CACzB,GACL,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAK9C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,EACjD,CAAC,SAAK,GACL,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAoB9C"}
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
*
|
|
20
20
|
* @module @co-engram/core/retrieval
|
|
21
21
|
*/
|
|
22
|
+
import { effectiveAge } from "../lifecycle/freshness.js";
|
|
22
23
|
/** 默认权重(spec 3.7:α=0.5, β=0.3, γ=0.2) */
|
|
23
24
|
export const DEFAULT_WEIGHTS = {
|
|
24
25
|
alpha: 0.5,
|
|
@@ -76,18 +77,21 @@ export function effectiveImportance(importance, reinforcementScore) {
|
|
|
76
77
|
/**
|
|
77
78
|
* 从 DigestLine + relevance 计算三因子得分
|
|
78
79
|
*
|
|
80
|
+
* recency 维度的衰退计时起点 = `lastEffectiveAt ?? line.lastEffectiveAt ?? line.createdAt`:
|
|
81
|
+
* 未生效 engram 用 createdAt 兜底,新记忆从编码完成起开始衰退(艾宾浩斯模型)。
|
|
82
|
+
*
|
|
79
83
|
* @param relevance - 归一化相关度 [0,1]
|
|
80
|
-
* @param line - DigestLine
|
|
81
|
-
* @param lastEffectiveAt -
|
|
82
|
-
* @param now -
|
|
83
|
-
* @param weights -
|
|
84
|
+
* @param line - DigestLine(含 recency/importance 数据,需有 createdAt)
|
|
85
|
+
* @param lastEffectiveAt - 最后有效检索时间(可选,省略则用 line.lastEffectiveAt)
|
|
86
|
+
* @param now - 当前时间(可选,便于测试;省略则 new Date())
|
|
87
|
+
* @param weights - 权重配置(可选,省略用默认)
|
|
84
88
|
*/
|
|
85
89
|
export function computeThreeFactorScore(relevance, line, options = {}) {
|
|
86
90
|
const weights = options.weights ?? DEFAULT_WEIGHTS;
|
|
87
91
|
validateWeights(weights);
|
|
88
92
|
const now = options.now ?? new Date();
|
|
89
93
|
const lastEffective = options.lastEffectiveAt ?? line.lastEffectiveAt;
|
|
90
|
-
const ageDays =
|
|
94
|
+
const ageDays = effectiveAge(lastEffective, line.createdAt, now);
|
|
91
95
|
const recency = recencyDecay(ageDays, line.decayHalfLifeDays);
|
|
92
96
|
const importance = effectiveImportance(line.importance, line.reinforcementScore);
|
|
93
97
|
return (weights.alpha * clamp01(relevance) +
|
|
@@ -151,15 +155,4 @@ function clamp01(x) {
|
|
|
151
155
|
return 1;
|
|
152
156
|
return x;
|
|
153
157
|
}
|
|
154
|
-
function computeAgeDays(lastEffectiveAt, now) {
|
|
155
|
-
if (!lastEffectiveAt)
|
|
156
|
-
return Number.POSITIVE_INFINITY; // 从未有效 → age = ∞ → recency → 0
|
|
157
|
-
const ts = new Date(lastEffectiveAt).getTime();
|
|
158
|
-
if (Number.isNaN(ts))
|
|
159
|
-
return Number.POSITIVE_INFINITY;
|
|
160
|
-
const ageMs = now.getTime() - ts;
|
|
161
|
-
if (ageMs < 0)
|
|
162
|
-
return 0; // 时钟偏差/未来
|
|
163
|
-
return ageMs / (1000 * 60 * 60 * 24);
|
|
164
|
-
}
|
|
165
158
|
//# sourceMappingURL=scoring.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scoring.js","sourceRoot":"","sources":["../../src/retrieval/scoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;
|
|
1
|
+
{"version":3,"file":"scoring.js","sourceRoot":"","sources":["../../src/retrieval/scoring.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { IndexDb } from "../storage/index-db.js";
|
|
2
|
+
import type { DigestLine } from "../index/types.js";
|
|
3
|
+
import type { SearchFilter } from "../types/disclosure.js";
|
|
4
|
+
import { type SimpleSearchResult } from "./orchestrator.js";
|
|
5
|
+
import { SqliteSearchOrchestrator } from "./sqlite-orchestrator.js";
|
|
6
|
+
/** 引擎类型 */
|
|
7
|
+
export type SearchEngineType = "memory" | "sqlite";
|
|
8
|
+
/**
|
|
9
|
+
* 统一检索引擎接口 —— in-memory SearchOrchestrator 与 SQLite 适配器都满足。
|
|
10
|
+
*
|
|
11
|
+
* 只暴露工具调用方需要的两个方法:
|
|
12
|
+
* - search(query, filter?, limit?) —— 检索
|
|
13
|
+
* - build(lines) —— 索引重建(in-memory 必需;SQLite 模式 no-op,
|
|
14
|
+
* write-through 在 EngramRepository 写入路径已透明维护索引)
|
|
15
|
+
*
|
|
16
|
+
* SearchOrchestrator 自身的 setClock / setWeights / listByFilter /
|
|
17
|
+
* listByImportance 等方法不在此接口 —— 这些是 in-memory 引擎特有的
|
|
18
|
+
* 调优 hook,SQLite 端无对应概念(bm25 自带相关度,无需三因子融合调权)。
|
|
19
|
+
*/
|
|
20
|
+
export interface SearchEngine {
|
|
21
|
+
search(query: string, filter?: SearchFilter, limit?: number): SimpleSearchResult[];
|
|
22
|
+
build(lines: readonly DigestLine[]): void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* SQLite 引擎适配器 —— 把 SqliteSearchOrchestrator 包装成 SearchEngine。
|
|
26
|
+
*
|
|
27
|
+
* - search():把 3-arg signature 转成 SqliteSearchOrchestrator 的
|
|
28
|
+
* { filter, limit } opts signature,丢掉 nextCursor(search 工具不强制分页)。
|
|
29
|
+
* - build():no-op。SQLite 索引由 EngramRepository 的 write-through 持续
|
|
30
|
+
* 维护,不需要外部触发重建。保留方法仅为接口兼容。
|
|
31
|
+
*/
|
|
32
|
+
export declare class SqliteSearchEngineAdapter implements SearchEngine {
|
|
33
|
+
private readonly sqlite;
|
|
34
|
+
constructor(sqlite: SqliteSearchOrchestrator);
|
|
35
|
+
search(query: string, filter?: SearchFilter, limit?: number): SimpleSearchResult[];
|
|
36
|
+
build(_lines: readonly DigestLine[]): void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 工厂:按 type 创建 SearchEngine。
|
|
40
|
+
*
|
|
41
|
+
* sqlite 模式必须提供 indexDb(已 open())。memory 模式忽略 indexDb。
|
|
42
|
+
*
|
|
43
|
+
* @throws sqlite 模式未提供 indexDb 时抛错(fail-loud,避免运行时静默退化)
|
|
44
|
+
*/
|
|
45
|
+
export declare function createSearchEngine(opts: {
|
|
46
|
+
readonly type: SearchEngineType;
|
|
47
|
+
readonly indexDb?: IndexDb;
|
|
48
|
+
}): SearchEngine;
|
|
49
|
+
/**
|
|
50
|
+
* 从环境变量解析 engine flag。
|
|
51
|
+
*
|
|
52
|
+
* - CO_ENGRAM_SEARCH_ENGINE=sqlite → sqlite
|
|
53
|
+
* - 未设置 / 空 / 其他值 → memory(默认 + 灰度保守)
|
|
54
|
+
*
|
|
55
|
+
* 函数纯函数(可注入 env),便于测试。
|
|
56
|
+
*/
|
|
57
|
+
export declare function resolveSearchEngineType(env?: NodeJS.ProcessEnv): SearchEngineType;
|
|
58
|
+
//# sourceMappingURL=search-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-engine.d.ts","sourceRoot":"","sources":["../../src/retrieval/search-engine.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,WAAW;AACX,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEnD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAAC;IACnF,KAAK,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,IAAI,CAAC;CAC3C;AAED;;;;;;;GAOG;AACH,qBAAa,yBAA0B,YAAW,YAAY;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,wBAAwB;IAE7D,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,KAAK,SAAK,GAAG,kBAAkB,EAAE;IAI9E,KAAK,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,IAAI;CAK3C;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B,GAAG,YAAY,CAUf;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,gBAAgB,CAGlB"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { SearchOrchestrator } from "./orchestrator.js";
|
|
2
|
+
import { SqliteSearchOrchestrator } from "./sqlite-orchestrator.js";
|
|
3
|
+
/**
|
|
4
|
+
* SQLite 引擎适配器 —— 把 SqliteSearchOrchestrator 包装成 SearchEngine。
|
|
5
|
+
*
|
|
6
|
+
* - search():把 3-arg signature 转成 SqliteSearchOrchestrator 的
|
|
7
|
+
* { filter, limit } opts signature,丢掉 nextCursor(search 工具不强制分页)。
|
|
8
|
+
* - build():no-op。SQLite 索引由 EngramRepository 的 write-through 持续
|
|
9
|
+
* 维护,不需要外部触发重建。保留方法仅为接口兼容。
|
|
10
|
+
*/
|
|
11
|
+
export class SqliteSearchEngineAdapter {
|
|
12
|
+
sqlite;
|
|
13
|
+
constructor(sqlite) {
|
|
14
|
+
this.sqlite = sqlite;
|
|
15
|
+
}
|
|
16
|
+
search(query, filter, limit = 20) {
|
|
17
|
+
return this.sqlite.search(query, { filter, limit }).results;
|
|
18
|
+
}
|
|
19
|
+
build(_lines) {
|
|
20
|
+
// intentional no-op:write-through 已维护 SQLite 索引。
|
|
21
|
+
// 参数保留是为了与 SearchOrchestrator.build 签名对齐,允许调用方
|
|
22
|
+
// 不感知底层引擎而透明调用。
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 工厂:按 type 创建 SearchEngine。
|
|
27
|
+
*
|
|
28
|
+
* sqlite 模式必须提供 indexDb(已 open())。memory 模式忽略 indexDb。
|
|
29
|
+
*
|
|
30
|
+
* @throws sqlite 模式未提供 indexDb 时抛错(fail-loud,避免运行时静默退化)
|
|
31
|
+
*/
|
|
32
|
+
export function createSearchEngine(opts) {
|
|
33
|
+
if (opts.type === "sqlite") {
|
|
34
|
+
if (!opts.indexDb) {
|
|
35
|
+
throw new Error("createSearchEngine: sqlite 模式必须提供 indexDb(已 open)。若要 fallback 到 memory,显式传 type='memory'。");
|
|
36
|
+
}
|
|
37
|
+
return new SqliteSearchEngineAdapter(new SqliteSearchOrchestrator({ db: opts.indexDb }));
|
|
38
|
+
}
|
|
39
|
+
return new SearchOrchestrator();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 从环境变量解析 engine flag。
|
|
43
|
+
*
|
|
44
|
+
* - CO_ENGRAM_SEARCH_ENGINE=sqlite → sqlite
|
|
45
|
+
* - 未设置 / 空 / 其他值 → memory(默认 + 灰度保守)
|
|
46
|
+
*
|
|
47
|
+
* 函数纯函数(可注入 env),便于测试。
|
|
48
|
+
*/
|
|
49
|
+
export function resolveSearchEngineType(env = process.env) {
|
|
50
|
+
const v = (env.CO_ENGRAM_SEARCH_ENGINE ?? "memory").toString().toLowerCase().trim();
|
|
51
|
+
return v === "sqlite" ? "sqlite" : "memory";
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=search-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-engine.js","sourceRoot":"","sources":["../../src/retrieval/search-engine.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,kBAAkB,EAA2B,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAsBpE;;;;;;;GAOG;AACH,MAAM,OAAO,yBAAyB;IACP;IAA7B,YAA6B,MAAgC;QAAhC,WAAM,GAAN,MAAM,CAA0B;IAAG,CAAC;IAEjE,MAAM,CAAC,KAAa,EAAE,MAAqB,EAAE,KAAK,GAAG,EAAE;QACrD,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;IAC9D,CAAC;IAED,KAAK,CAAC,MAA6B;QACjC,iDAAiD;QACjD,+CAA+C;QAC/C,gBAAgB;IAClB,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAGlC;IACC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CACb,2FAA2F,CAC5F,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,yBAAyB,CAAC,IAAI,wBAAwB,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC3F,CAAC;IACD,OAAO,IAAI,kBAAkB,EAAE,CAAC;AAClC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CACrC,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,uBAAuB,IAAI,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IACpF,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { IndexDb } from "../storage/index-db.js";
|
|
2
|
+
import type { SearchFilter } from "../types/disclosure.js";
|
|
3
|
+
import type { SimpleSearchResult } from "./orchestrator.js";
|
|
4
|
+
/** SqliteSearchOrchestrator 构造参数 */
|
|
5
|
+
export interface SqliteSearchOptions {
|
|
6
|
+
readonly db: IndexDb;
|
|
7
|
+
/**
|
|
8
|
+
* 时钟注入(测试用);当前实现未依赖时间,但保留接口便于后续三因子融合。
|
|
9
|
+
*/
|
|
10
|
+
readonly nowFn?: () => Date;
|
|
11
|
+
}
|
|
12
|
+
/** search() 调用选项 */
|
|
13
|
+
export interface SearchQueryOptions {
|
|
14
|
+
readonly filter?: SearchFilter;
|
|
15
|
+
readonly limit?: number;
|
|
16
|
+
/**
|
|
17
|
+
* 游标分页(Phase 3 启用);当前实现忽略,只返回 nextCursor=null。
|
|
18
|
+
*/
|
|
19
|
+
readonly cursor?: string | null;
|
|
20
|
+
}
|
|
21
|
+
/** search() 返回结构 */
|
|
22
|
+
export interface SearchResponse {
|
|
23
|
+
readonly results: SimpleSearchResult[];
|
|
24
|
+
readonly nextCursor: string | null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* SQLite FTS5 召回编排器。
|
|
28
|
+
*
|
|
29
|
+
* 与 in-memory SearchOrchestrator 接口兼容(same query → SimpleSearchResult[]),
|
|
30
|
+
* 上层 engram_search 工具按 feature flag 切换引擎。
|
|
31
|
+
*/
|
|
32
|
+
export declare class SqliteSearchOrchestrator {
|
|
33
|
+
private readonly db;
|
|
34
|
+
constructor(opts: SqliteSearchOptions);
|
|
35
|
+
search(query: string, opts?: SearchQueryOptions): SearchResponse;
|
|
36
|
+
/** FTS5 trigram MATCH,bm25 排序(负值越优,ASC 即最相关在前) */
|
|
37
|
+
private searchByFts;
|
|
38
|
+
/**
|
|
39
|
+
* LIKE 兜底:1-2 字符 query(trigram 无法处理)或 FTS5 MATCH 无命中时降级。
|
|
40
|
+
*
|
|
41
|
+
* LIKE 覆盖四个文本维度:engrams.title + engram_fts.summary +
|
|
42
|
+
* engram_fts.content_tokens + engram_domains.domain。仅靠 title 召回过窄
|
|
43
|
+
* (中文 1-2 字 query 经常只在 summary / content / domainTags 中出现),
|
|
44
|
+
* 必须扫全部索引文本,与 in-memory FTS 的索引字段对齐。
|
|
45
|
+
*
|
|
46
|
+
* 排序:importance + updatedAt DESC(无相关度信号,用静态质量分代替)。
|
|
47
|
+
*/
|
|
48
|
+
private searchByLike;
|
|
49
|
+
/**
|
|
50
|
+
* 把用户 query 转成 FTS5 MATCH 表达式。
|
|
51
|
+
*
|
|
52
|
+
* 实现:整体作为 FTS5 string query(`"..."` 语法),FTS5 trigram tokenizer
|
|
53
|
+
* 自行切分。`"` 内的双引号 escape 为 `""`(FTS5 标准做法)。
|
|
54
|
+
*
|
|
55
|
+
* 不做手工 trigram 切分:trigram tokenizer 已在 SQL 层做,手工切分反而
|
|
56
|
+
* 会和 tokenizer 双重处理,导致短语匹配失效。
|
|
57
|
+
*/
|
|
58
|
+
private buildFtsQuery;
|
|
59
|
+
/**
|
|
60
|
+
* 后置过滤(SQL 端已做 limit,这里做 filter 收紧)。
|
|
61
|
+
*
|
|
62
|
+
* 当前实现只处理 domainTags;其余 SearchFilter 字段(kinds / status /
|
|
63
|
+
* freshness / contextTags / 时间窗 / minImportance)留待 Phase 3 在 SQL
|
|
64
|
+
* 端实现以避免 N+1 拉取。
|
|
65
|
+
*/
|
|
66
|
+
private applyPostFilter;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=sqlite-orchestrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-orchestrator.d.ts","sourceRoot":"","sources":["../../src/retrieval/sqlite-orchestrator.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAG3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,oCAAoC;AACpC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,oBAAoB;AACpB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,oBAAoB;AACpB,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,kBAAkB,EAAE,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAKD;;;;;GAKG;AACH,qBAAa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAU;gBAEjB,IAAI,EAAE,mBAAmB;IAIrC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB,GAAG,cAAc;IA0BpE,kDAAkD;IAClD,OAAO,CAAC,WAAW;IA4BnB;;;;;;;;;OASG;IACH,OAAO,CAAC,YAAY;IA4BpB;;;;;;;;OAQG;IACH,OAAO,CAAC,aAAa;IAKrB;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;CAmBxB"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/** trigram tokenizer 命中所需的最小 UTF-16 code unit 数 */
|
|
2
|
+
const LIKE_FALLBACK_MIN_CHARS = 3;
|
|
3
|
+
/**
|
|
4
|
+
* SQLite FTS5 召回编排器。
|
|
5
|
+
*
|
|
6
|
+
* 与 in-memory SearchOrchestrator 接口兼容(same query → SimpleSearchResult[]),
|
|
7
|
+
* 上层 engram_search 工具按 feature flag 切换引擎。
|
|
8
|
+
*/
|
|
9
|
+
export class SqliteSearchOrchestrator {
|
|
10
|
+
db;
|
|
11
|
+
constructor(opts) {
|
|
12
|
+
this.db = opts.db;
|
|
13
|
+
}
|
|
14
|
+
search(query, opts = {}) {
|
|
15
|
+
const limit = Math.min(Math.max(opts.limit ?? 20, 1), 500);
|
|
16
|
+
const q = query.trim();
|
|
17
|
+
if (!q)
|
|
18
|
+
return { results: [], nextCursor: null };
|
|
19
|
+
const useLike = q.length < LIKE_FALLBACK_MIN_CHARS;
|
|
20
|
+
const rows = useLike
|
|
21
|
+
? this.searchByLike(q, limit)
|
|
22
|
+
: this.searchByFts(q, limit);
|
|
23
|
+
const filtered = this.applyPostFilter(rows, opts.filter);
|
|
24
|
+
const results = filtered.map((r) => ({
|
|
25
|
+
id: r.id,
|
|
26
|
+
score: r.score,
|
|
27
|
+
entry: {
|
|
28
|
+
id: r.id,
|
|
29
|
+
title: r.title,
|
|
30
|
+
kind: r.kind,
|
|
31
|
+
domainTags: r.domainTags,
|
|
32
|
+
},
|
|
33
|
+
}));
|
|
34
|
+
return { results, nextCursor: null };
|
|
35
|
+
}
|
|
36
|
+
/** FTS5 trigram MATCH,bm25 排序(负值越优,ASC 即最相关在前) */
|
|
37
|
+
searchByFts(q, limit) {
|
|
38
|
+
const ftsQuery = this.buildFtsQuery(q);
|
|
39
|
+
if (!ftsQuery)
|
|
40
|
+
return [];
|
|
41
|
+
const stmt = this.db.prepare(`
|
|
42
|
+
SELECT e.id AS id, e.title AS title, e.kind AS kind, e.importance AS importance,
|
|
43
|
+
(SELECT group_concat(domain, ',') FROM engram_domains d WHERE d.engram_id = e.id) AS domain_tags,
|
|
44
|
+
bm25(engram_fts) AS fts_score
|
|
45
|
+
FROM engram_fts
|
|
46
|
+
JOIN engrams e ON e.id = engram_fts.id
|
|
47
|
+
WHERE engram_fts MATCH ?
|
|
48
|
+
ORDER BY fts_score ASC
|
|
49
|
+
LIMIT ?
|
|
50
|
+
`);
|
|
51
|
+
const rows = stmt.all(ftsQuery, limit);
|
|
52
|
+
return rows.map((r) => ({
|
|
53
|
+
id: r.id,
|
|
54
|
+
title: r.title,
|
|
55
|
+
kind: r.kind,
|
|
56
|
+
importance: r.importance,
|
|
57
|
+
domainTags: splitCsv(r.domain_tags),
|
|
58
|
+
// bm25 返回负值,反转成正数(score 越大越优,与 in-memory 一致)
|
|
59
|
+
score: -r.fts_score,
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* LIKE 兜底:1-2 字符 query(trigram 无法处理)或 FTS5 MATCH 无命中时降级。
|
|
64
|
+
*
|
|
65
|
+
* LIKE 覆盖四个文本维度:engrams.title + engram_fts.summary +
|
|
66
|
+
* engram_fts.content_tokens + engram_domains.domain。仅靠 title 召回过窄
|
|
67
|
+
* (中文 1-2 字 query 经常只在 summary / content / domainTags 中出现),
|
|
68
|
+
* 必须扫全部索引文本,与 in-memory FTS 的索引字段对齐。
|
|
69
|
+
*
|
|
70
|
+
* 排序:importance + updatedAt DESC(无相关度信号,用静态质量分代替)。
|
|
71
|
+
*/
|
|
72
|
+
searchByLike(q, limit) {
|
|
73
|
+
const stmt = this.db.prepare(`
|
|
74
|
+
SELECT e.id AS id, e.title AS title, e.kind AS kind, e.importance AS importance,
|
|
75
|
+
(SELECT group_concat(domain, ',') FROM engram_domains d WHERE d.engram_id = e.id) AS domain_tags
|
|
76
|
+
FROM engrams e
|
|
77
|
+
JOIN engram_fts f ON f.id = e.id
|
|
78
|
+
WHERE e.title LIKE ? ESCAPE '\\'
|
|
79
|
+
OR f.summary LIKE ? ESCAPE '\\'
|
|
80
|
+
OR f.content_tokens LIKE ? ESCAPE '\\'
|
|
81
|
+
OR EXISTS (
|
|
82
|
+
SELECT 1 FROM engram_domains d
|
|
83
|
+
WHERE d.engram_id = e.id AND d.domain LIKE ? ESCAPE '\\'
|
|
84
|
+
)
|
|
85
|
+
ORDER BY e.importance DESC, e.updated_at DESC
|
|
86
|
+
LIMIT ?
|
|
87
|
+
`);
|
|
88
|
+
const pattern = `%${escapeLike(q)}%`;
|
|
89
|
+
const rows = stmt.all(pattern, pattern, pattern, pattern, limit);
|
|
90
|
+
return rows.map((r) => ({
|
|
91
|
+
id: r.id,
|
|
92
|
+
title: r.title,
|
|
93
|
+
kind: r.kind,
|
|
94
|
+
importance: r.importance,
|
|
95
|
+
domainTags: splitCsv(r.domain_tags),
|
|
96
|
+
score: 0,
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* 把用户 query 转成 FTS5 MATCH 表达式。
|
|
101
|
+
*
|
|
102
|
+
* 实现:整体作为 FTS5 string query(`"..."` 语法),FTS5 trigram tokenizer
|
|
103
|
+
* 自行切分。`"` 内的双引号 escape 为 `""`(FTS5 标准做法)。
|
|
104
|
+
*
|
|
105
|
+
* 不做手工 trigram 切分:trigram tokenizer 已在 SQL 层做,手工切分反而
|
|
106
|
+
* 会和 tokenizer 双重处理,导致短语匹配失效。
|
|
107
|
+
*/
|
|
108
|
+
buildFtsQuery(query) {
|
|
109
|
+
if (!query)
|
|
110
|
+
return null;
|
|
111
|
+
return `"${query.replace(/"/g, '""')}"`;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 后置过滤(SQL 端已做 limit,这里做 filter 收紧)。
|
|
115
|
+
*
|
|
116
|
+
* 当前实现只处理 domainTags;其余 SearchFilter 字段(kinds / status /
|
|
117
|
+
* freshness / contextTags / 时间窗 / minImportance)留待 Phase 3 在 SQL
|
|
118
|
+
* 端实现以避免 N+1 拉取。
|
|
119
|
+
*/
|
|
120
|
+
applyPostFilter(rows, filter) {
|
|
121
|
+
if (!filter)
|
|
122
|
+
return rows;
|
|
123
|
+
if (filter.domainTags && filter.domainTags.length > 0) {
|
|
124
|
+
const want = new Set(filter.domainTags);
|
|
125
|
+
rows = rows.filter((r) => r.domainTags.some((t) => want.has(t)));
|
|
126
|
+
}
|
|
127
|
+
if (filter.kinds && filter.kinds.length > 0) {
|
|
128
|
+
const want = new Set(filter.kinds);
|
|
129
|
+
rows = rows.filter((r) => want.has(r.kind));
|
|
130
|
+
}
|
|
131
|
+
if (typeof filter.minImportance === "number") {
|
|
132
|
+
const floor = filter.minImportance;
|
|
133
|
+
rows = rows.filter((r) => r.importance >= floor);
|
|
134
|
+
}
|
|
135
|
+
return rows;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/** group_concat(domain, ',') 拆回数组(null / "" → []) */
|
|
139
|
+
function splitCsv(joined) {
|
|
140
|
+
if (!joined)
|
|
141
|
+
return [];
|
|
142
|
+
return joined.split(",").filter(Boolean);
|
|
143
|
+
}
|
|
144
|
+
/** LIKE escape:% _ \ 三个特殊字符转义,使用 ESCAPE '\' 子句 */
|
|
145
|
+
function escapeLike(s) {
|
|
146
|
+
return s.replace(/[\\%_]/g, (m) => `\\${m}`);
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=sqlite-orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-orchestrator.js","sourceRoot":"","sources":["../../src/retrieval/sqlite-orchestrator.ts"],"names":[],"mappings":"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"}
|