@morningljn/mnemo 0.1.2 → 0.1.4
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/README.md +44 -15
- package/README_zh.md +1 -1
- package/dist/cache.d.ts +23 -0
- package/dist/cache.js +44 -0
- package/dist/cache.js.map +1 -0
- package/dist/init.js +16 -8
- package/dist/init.js.map +1 -1
- package/dist/metrics.d.ts +31 -0
- package/dist/metrics.js +57 -0
- package/dist/metrics.js.map +1 -0
- package/dist/refine.d.ts +14 -0
- package/dist/refine.js +115 -0
- package/dist/refine.js.map +1 -0
- package/dist/resources.d.ts +27 -0
- package/dist/resources.js +56 -0
- package/dist/resources.js.map +1 -0
- package/dist/retriever.d.ts +14 -2
- package/dist/retriever.js +126 -36
- package/dist/retriever.js.map +1 -1
- package/dist/server.js +40 -16
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/docs/superpowers/plans/2026-05-15-mnemo-mcp.md +1154 -0
- package/docs/superpowers/plans/2026-05-16-mnemo-query-cache.md +613 -0
- package/docs/superpowers/plans/2026-05-16-retrieval-and-injection-optimization.md +770 -0
- package/openspec/changes/archive/2026-05-15-mnemo-mcp/.openspec.yaml +2 -0
- package/openspec/changes/archive/2026-05-15-mnemo-mcp/design.md +83 -0
- package/openspec/changes/archive/2026-05-15-mnemo-mcp/proposal.md +32 -0
- package/openspec/changes/archive/2026-05-15-mnemo-mcp/specs/fact-retrieval/spec.md +75 -0
- package/openspec/changes/archive/2026-05-15-mnemo-mcp/specs/fact-store/spec.md +83 -0
- package/openspec/changes/archive/2026-05-15-mnemo-mcp/specs/mcp-server/spec.md +34 -0
- package/openspec/changes/archive/2026-05-15-mnemo-mcp/specs/security/spec.md +37 -0
- package/openspec/changes/archive/2026-05-15-mnemo-mcp/tasks.md +44 -0
- package/openspec/changes/archive/2026-05-16-mnemo-query-cache/.openspec.yaml +2 -0
- package/openspec/changes/archive/2026-05-16-mnemo-query-cache/design.md +96 -0
- package/openspec/changes/archive/2026-05-16-mnemo-query-cache/proposal.md +29 -0
- package/openspec/changes/archive/2026-05-16-mnemo-query-cache/specs/batch-operations/spec.md +42 -0
- package/openspec/changes/archive/2026-05-16-mnemo-query-cache/specs/perf-metrics/spec.md +55 -0
- package/openspec/changes/archive/2026-05-16-mnemo-query-cache/specs/query-cache/spec.md +65 -0
- package/openspec/changes/archive/2026-05-16-mnemo-query-cache/tasks.md +45 -0
- package/openspec/changes/retrieval-and-injection-optimization/.openspec.yaml +2 -0
- package/openspec/changes/retrieval-and-injection-optimization/design.md +117 -0
- package/openspec/changes/retrieval-and-injection-optimization/proposal.md +30 -0
- package/openspec/changes/retrieval-and-injection-optimization/specs/adaptive-scoring/spec.md +43 -0
- package/openspec/changes/retrieval-and-injection-optimization/specs/injection-protocol/spec.md +48 -0
- package/openspec/changes/retrieval-and-injection-optimization/specs/mcp-resources/spec.md +39 -0
- package/openspec/changes/retrieval-and-injection-optimization/specs/query-refinement/spec.md +39 -0
- package/openspec/changes/retrieval-and-injection-optimization/tasks.md +33 -0
- package/openspec/config.yaml +20 -0
- package/package.json +1 -1
- package/src/cache.ts +65 -0
- package/src/init.ts +17 -9
- package/src/metrics.ts +81 -0
- package/src/refine.ts +127 -0
- package/src/resources.ts +78 -0
- package/src/retriever.ts +141 -34
- package/src/server.ts +42 -17
- package/src/types.ts +2 -2
- package/tests/refine.test.ts +52 -0
- package/tests/resource.test.ts +62 -0
package/README.md
CHANGED
|
@@ -15,6 +15,8 @@ AI coding assistants forget everything between sessions. `CLAUDE.md` stores stat
|
|
|
15
15
|
mnemo gives your AI assistant a **searchable, structured memory layer** that persists across sessions:
|
|
16
16
|
|
|
17
17
|
- **Search by meaning** — FTS5 full-text search + Jaccard reranking + bilingual expansion
|
|
18
|
+
- **Session warmup** — MCP Resources auto-inject top facts at session start, zero tool calls
|
|
19
|
+
- **Query refinement** — strips action words and noise tokens before memory search
|
|
18
20
|
- **Trust scoring** — facts gain or lose trust over time based on feedback and decay
|
|
19
21
|
- **Entity graph** — automatic entity extraction with multi-hop relationship queries
|
|
20
22
|
- **Contradiction detection** — finds conflicting facts and demotes the older one
|
|
@@ -24,7 +26,7 @@ mnemo gives your AI assistant a **searchable, structured memory layer** that per
|
|
|
24
26
|
|
|
25
27
|
```bash
|
|
26
28
|
# Install
|
|
27
|
-
npm install -g @
|
|
29
|
+
npm install -g @morningljn/mnemo
|
|
28
30
|
|
|
29
31
|
# One-command setup (register MCP + write rules + set permissions)
|
|
30
32
|
mnemo-init
|
|
@@ -49,15 +51,26 @@ claude mcp add mnemo -- mnemo
|
|
|
49
51
|
|
|
50
52
|
You have mnemo memory tools (fact_store / fact_feedback). Rules:
|
|
51
53
|
|
|
52
|
-
## Rule 1:
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
## Rule 1: Session warmup (automatic)
|
|
55
|
+
mnemo MCP Resources auto-inject global memory into system context at session start.
|
|
56
|
+
You do NOT need to call fact_store(search) for high-frequency memories.
|
|
55
57
|
|
|
56
|
-
## Rule 2:
|
|
58
|
+
## Rule 2: On-demand search
|
|
59
|
+
Only call fact_store(action="search") when:
|
|
60
|
+
- User message involves personal preferences/habits/tool choices not covered by warmup
|
|
61
|
+
- User explicitly queries memory ("what did I say before", "per my habits")
|
|
62
|
+
- Technical decisions need user preference confirmation
|
|
63
|
+
|
|
64
|
+
Do NOT trigger search for:
|
|
65
|
+
- Pure operations ("run tests", "git commit")
|
|
66
|
+
- General tech questions ("how to use Promise")
|
|
67
|
+
- Code review/explanation requests
|
|
68
|
+
|
|
69
|
+
## Rule 3: Write on request
|
|
57
70
|
When user says "remember", call `fact_store(action="add", content="...", category="...")`.
|
|
58
71
|
Search first to avoid duplicates. Categories: identity / coding_style / tool_pref / workflow / general.
|
|
59
72
|
|
|
60
|
-
## Rule
|
|
73
|
+
## Rule 4: Feedback
|
|
61
74
|
When a memory was useful, call `fact_feedback(action="helpful", fact_id=...)`.
|
|
62
75
|
```
|
|
63
76
|
|
|
@@ -115,21 +128,37 @@ Rate a fact after use. Good facts rise, bad facts decay.
|
|
|
115
128
|
| `helpful` | +0.05 trust |
|
|
116
129
|
| `unhelpful` | -0.10 trust |
|
|
117
130
|
|
|
131
|
+
## MCP Resources
|
|
132
|
+
|
|
133
|
+
mnemo exposes 5 global category resources for **zero-cost session warmup**:
|
|
134
|
+
|
|
135
|
+
| Resource URI | Description |
|
|
136
|
+
|-------------|-------------|
|
|
137
|
+
| `mnemo://global/identity` | Identity facts (top 10 by trust) |
|
|
138
|
+
| `mnemo://global/coding_style` | Coding style preferences |
|
|
139
|
+
| `mnemo://global/tool_pref` | Tool preferences |
|
|
140
|
+
| `mnemo://global/workflow` | Workflow preferences |
|
|
141
|
+
| `mnemo://global/general` | General facts |
|
|
142
|
+
|
|
143
|
+
MCP clients (Claude Code, Codex) automatically fetch these resources at session start, injecting memory into system context without any tool calls. This eliminates the need for "search every message" patterns.
|
|
144
|
+
|
|
118
145
|
## Architecture
|
|
119
146
|
|
|
120
147
|
```
|
|
121
148
|
┌───────────────────┐ stdio ┌────────────┐ SQLite ┌─────────────────────┐
|
|
122
149
|
│ MCP Client │◄─────────►│ mnemo │◄───────────►│ ~/.mnemo/facts.db │
|
|
123
150
|
│ (Claude / Codex) │ JSON │ server │ │ │
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
151
|
+
│ │ └─────┬──────┘ │ Tables: │
|
|
152
|
+
│ Auto-fetch: │ │ │ facts │
|
|
153
|
+
│ mnemo://global/* │ ┌──────────┼──────────┐ │ entities │
|
|
154
|
+
│ (session warmup) │ │ │ │ │ fact_entities │
|
|
155
|
+
└───────────────────┘ │ │ │ │ Indexes: │
|
|
156
|
+
│ │ │ │ facts_fts (FTS5) │
|
|
157
|
+
Resources Retriever Security │ idx_facts_trust │
|
|
158
|
+
(warmup, (search, (PII scan, │ idx_facts_category│
|
|
159
|
+
cache) probe, injection └─────────────────────┘
|
|
160
|
+
reason) detection)
|
|
161
|
+
└──────────────────┘
|
|
133
162
|
```
|
|
134
163
|
|
|
135
164
|
## Categories
|
package/README_zh.md
CHANGED
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query result cache for mnemo-mcp.
|
|
3
|
+
* Process-local Map with TTL. Cleared on write operations.
|
|
4
|
+
*/
|
|
5
|
+
import type { ScoredFact } from './types.js';
|
|
6
|
+
export declare class QueryCache {
|
|
7
|
+
private cache;
|
|
8
|
+
private ttlMs;
|
|
9
|
+
constructor(ttlMs?: number);
|
|
10
|
+
makeKey(params: {
|
|
11
|
+
action: string;
|
|
12
|
+
query?: string;
|
|
13
|
+
entity?: string;
|
|
14
|
+
entities?: string[];
|
|
15
|
+
category?: string;
|
|
16
|
+
minTrust?: number;
|
|
17
|
+
limit?: number;
|
|
18
|
+
}): string;
|
|
19
|
+
get(key: string): ScoredFact[] | null;
|
|
20
|
+
set(key: string, results: ScoredFact[]): void;
|
|
21
|
+
clear(): void;
|
|
22
|
+
size(): number;
|
|
23
|
+
}
|
package/dist/cache.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query result cache for mnemo-mcp.
|
|
3
|
+
* Process-local Map with TTL. Cleared on write operations.
|
|
4
|
+
*/
|
|
5
|
+
const DEFAULT_TTL_MS = 60_000;
|
|
6
|
+
export class QueryCache {
|
|
7
|
+
cache = new Map();
|
|
8
|
+
ttlMs;
|
|
9
|
+
constructor(ttlMs = DEFAULT_TTL_MS) {
|
|
10
|
+
this.ttlMs = ttlMs;
|
|
11
|
+
}
|
|
12
|
+
makeKey(params) {
|
|
13
|
+
const parts = [
|
|
14
|
+
params.action,
|
|
15
|
+
params.query ?? '',
|
|
16
|
+
params.entity ?? '',
|
|
17
|
+
params.entities?.join(',') ?? '',
|
|
18
|
+
params.category ?? '',
|
|
19
|
+
String(params.minTrust ?? ''),
|
|
20
|
+
String(params.limit ?? ''),
|
|
21
|
+
];
|
|
22
|
+
return parts.join('|');
|
|
23
|
+
}
|
|
24
|
+
get(key) {
|
|
25
|
+
const entry = this.cache.get(key);
|
|
26
|
+
if (!entry)
|
|
27
|
+
return null;
|
|
28
|
+
if (Date.now() - entry.timestamp > this.ttlMs) {
|
|
29
|
+
this.cache.delete(key);
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return entry.results;
|
|
33
|
+
}
|
|
34
|
+
set(key, results) {
|
|
35
|
+
this.cache.set(key, { results, timestamp: Date.now() });
|
|
36
|
+
}
|
|
37
|
+
clear() {
|
|
38
|
+
this.cache.clear();
|
|
39
|
+
}
|
|
40
|
+
size() {
|
|
41
|
+
return this.cache.size;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,MAAM,cAAc,GAAG,MAAM,CAAA;AAE7B,MAAM,OAAO,UAAU;IACb,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAA;IACrC,KAAK,CAAQ;IAErB,YAAY,KAAK,GAAG,cAAc;QAChC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IACpB,CAAC;IAED,OAAO,CAAC,MAQP;QACC,MAAM,KAAK,GAAG;YACZ,MAAM,CAAC,MAAM;YACb,MAAM,CAAC,KAAK,IAAI,EAAE;YAClB,MAAM,CAAC,MAAM,IAAI,EAAE;YACnB,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;YAChC,MAAM,CAAC,QAAQ,IAAI,EAAE;YACrB,MAAM,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;YAC7B,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;SAC3B,CAAA;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACxB,CAAC;IAED,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACjC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA;QACvB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACtB,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,KAAK,CAAC,OAAO,CAAA;IACtB,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,OAAqB;QACpC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;IACzD,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;IACpB,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAA;IACxB,CAAC;CACF"}
|
package/dist/init.js
CHANGED
|
@@ -19,19 +19,27 @@ const MEMORY_RULES = `
|
|
|
19
19
|
|
|
20
20
|
你有 mnemo 记忆工具(fact_store / fact_feedback),必须按以下规则使用:
|
|
21
21
|
|
|
22
|
-
## 规则 1
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
- 用户说"我叫什么" → query="姓名 名字 叫什么"
|
|
26
|
-
- 用户说"我喜欢什么语言" → query="编程语言 偏好 喜欢"
|
|
27
|
-
搜索后根据结果自然回复,不要说"根据记忆"。
|
|
22
|
+
## 规则 1:会话预热(自动)
|
|
23
|
+
会话启动时,mnemo-mcp 的 MCP Resource 会自动注入全局记忆到 system context。
|
|
24
|
+
你不需要主动调用 fact_store(search) 来获取高频记忆。
|
|
28
25
|
|
|
29
|
-
## 规则 2
|
|
26
|
+
## 规则 2:按需补充查询
|
|
27
|
+
仅在以下情况调用 \`fact_store(action="search")\`:
|
|
28
|
+
- 用户消息涉及个人偏好/习惯/工具选择且预热中未覆盖
|
|
29
|
+
- 用户明确查询记忆("我之前说过什么""按我的习惯")
|
|
30
|
+
- 技术选型时需要确认用户偏好
|
|
31
|
+
|
|
32
|
+
不触发查询的情况:
|
|
33
|
+
- 纯操作指令("运行测试""git commit")
|
|
34
|
+
- 通用技术问题("Promise 怎么用")
|
|
35
|
+
- 代码审查/解释请求
|
|
36
|
+
|
|
37
|
+
## 规则 3:写入记忆
|
|
30
38
|
用户说"记住"、"记下来"时,调用 \`fact_store(action="add", content="...", category="...")\`。
|
|
31
39
|
- 先 search 检查是否已有相似事实,有则 update
|
|
32
40
|
- category:identity / coding_style / tool_pref / workflow / general
|
|
33
41
|
|
|
34
|
-
## 规则
|
|
42
|
+
## 规则 4:反馈强化
|
|
35
43
|
成功使用某条记忆时,调用 \`fact_feedback(action="helpful", fact_id=...)\`。
|
|
36
44
|
`;
|
|
37
45
|
const MCP_TOOLS = [
|
package/dist/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEjC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAA;AAC7C,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAA;AACpD,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAA;AAEvD,MAAM,YAAY,GAAG
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance metrics for mnemo-mcp.
|
|
3
|
+
* Tracks query timing, cache hit/miss, and retrieval paths.
|
|
4
|
+
* Only active when MNEMO_DEBUG=1.
|
|
5
|
+
*/
|
|
6
|
+
export interface QueryMetrics {
|
|
7
|
+
action: string;
|
|
8
|
+
durationMs: number;
|
|
9
|
+
resultCount: number;
|
|
10
|
+
cacheHit: boolean;
|
|
11
|
+
retrievalPath?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class PerfMetrics {
|
|
14
|
+
private enabled;
|
|
15
|
+
private totalQueries;
|
|
16
|
+
private cacheHits;
|
|
17
|
+
private cacheMisses;
|
|
18
|
+
private totalMissTimeMs;
|
|
19
|
+
constructor();
|
|
20
|
+
isEnabled(): boolean;
|
|
21
|
+
record(metrics: QueryMetrics): void;
|
|
22
|
+
getStats(): {
|
|
23
|
+
totalQueries: number;
|
|
24
|
+
cacheHits: number;
|
|
25
|
+
cacheMisses: number;
|
|
26
|
+
hitRatio: number;
|
|
27
|
+
avgQueryTime: number;
|
|
28
|
+
totalTimeSaved: number;
|
|
29
|
+
};
|
|
30
|
+
logStats(): void;
|
|
31
|
+
}
|
package/dist/metrics.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance metrics for mnemo-mcp.
|
|
3
|
+
* Tracks query timing, cache hit/miss, and retrieval paths.
|
|
4
|
+
* Only active when MNEMO_DEBUG=1.
|
|
5
|
+
*/
|
|
6
|
+
export class PerfMetrics {
|
|
7
|
+
enabled;
|
|
8
|
+
totalQueries = 0;
|
|
9
|
+
cacheHits = 0;
|
|
10
|
+
cacheMisses = 0;
|
|
11
|
+
totalMissTimeMs = 0;
|
|
12
|
+
constructor() {
|
|
13
|
+
this.enabled = process.env.MNEMO_DEBUG === '1';
|
|
14
|
+
}
|
|
15
|
+
isEnabled() {
|
|
16
|
+
return this.enabled;
|
|
17
|
+
}
|
|
18
|
+
record(metrics) {
|
|
19
|
+
if (!this.enabled)
|
|
20
|
+
return;
|
|
21
|
+
this.totalQueries++;
|
|
22
|
+
if (metrics.cacheHit) {
|
|
23
|
+
this.cacheHits++;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
this.cacheMisses++;
|
|
27
|
+
this.totalMissTimeMs += metrics.durationMs;
|
|
28
|
+
}
|
|
29
|
+
const hitRatio = this.totalQueries > 0 ? (this.cacheHits / this.totalQueries * 100).toFixed(1) : '0.0';
|
|
30
|
+
const path = metrics.retrievalPath ? ` [${metrics.retrievalPath}]` : '';
|
|
31
|
+
console.error(`[mnemo:debug] ${metrics.action} | ${metrics.cacheHit ? 'HIT' : 'MISS'} | ` +
|
|
32
|
+
`${metrics.durationMs.toFixed(2)}ms | ${metrics.resultCount} results | ` +
|
|
33
|
+
`hit_ratio=${hitRatio}%${path}`);
|
|
34
|
+
}
|
|
35
|
+
getStats() {
|
|
36
|
+
const hitRatio = this.totalQueries > 0 ? this.cacheHits / this.totalQueries : 0;
|
|
37
|
+
const avgQueryTime = this.cacheMisses > 0 ? this.totalMissTimeMs / this.cacheMisses : 0;
|
|
38
|
+
const totalTimeSaved = this.cacheHits * avgQueryTime;
|
|
39
|
+
return {
|
|
40
|
+
totalQueries: this.totalQueries,
|
|
41
|
+
cacheHits: this.cacheHits,
|
|
42
|
+
cacheMisses: this.cacheMisses,
|
|
43
|
+
hitRatio,
|
|
44
|
+
avgQueryTime,
|
|
45
|
+
totalTimeSaved,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
logStats() {
|
|
49
|
+
if (!this.enabled)
|
|
50
|
+
return;
|
|
51
|
+
const stats = this.getStats();
|
|
52
|
+
console.error(`[mnemo:debug] stats | total=${stats.totalQueries} hits=${stats.cacheHits} ` +
|
|
53
|
+
`misses=${stats.cacheMisses} hit_ratio=${(stats.hitRatio * 100).toFixed(1)}% ` +
|
|
54
|
+
`avg_time=${stats.avgQueryTime.toFixed(2)}ms saved=${stats.totalTimeSaved.toFixed(2)}ms`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,MAAM,OAAO,WAAW;IACd,OAAO,CAAS;IAChB,YAAY,GAAG,CAAC,CAAA;IAChB,SAAS,GAAG,CAAC,CAAA;IACb,WAAW,GAAG,CAAC,CAAA;IACf,eAAe,GAAG,CAAC,CAAA;IAE3B;QACE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,GAAG,CAAA;IAChD,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAED,MAAM,CAAC,OAAqB;QAC1B,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAM;QAEzB,IAAI,CAAC,YAAY,EAAE,CAAA;QACnB,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,IAAI,CAAC,SAAS,EAAE,CAAA;QAClB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,WAAW,EAAE,CAAA;YAClB,IAAI,CAAC,eAAe,IAAI,OAAO,CAAC,UAAU,CAAA;QAC5C,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;QACtG,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;QACvE,OAAO,CAAC,KAAK,CACX,iBAAiB,OAAO,CAAC,MAAM,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,KAAK;YAC3E,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,OAAO,CAAC,WAAW,aAAa;YACxE,aAAa,QAAQ,IAAI,IAAI,EAAE,CAChC,CAAA;IACH,CAAC;IAED,QAAQ;QAQN,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;QAC/E,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;QACvF,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,GAAG,YAAY,CAAA;QAEpD,OAAO;YACL,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,QAAQ;YACR,YAAY;YACZ,cAAc;SACf,CAAA;IACH,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAM;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAA;QAC7B,OAAO,CAAC,KAAK,CACX,+BAA+B,KAAK,CAAC,YAAY,SAAS,KAAK,CAAC,SAAS,GAAG;YAC5E,UAAU,KAAK,CAAC,WAAW,cAAc,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;YAC9E,YAAY,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CACzF,CAAA;IACH,CAAC;CACF"}
|
package/dist/refine.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query refinement: strip noise tokens from user messages before memory search.
|
|
3
|
+
* Pure function — no side effects, no DB access.
|
|
4
|
+
*/
|
|
5
|
+
export interface RefineResult {
|
|
6
|
+
query: string | null;
|
|
7
|
+
tokens: string[];
|
|
8
|
+
entityTokens: string[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Refine a raw user message into memory-searchable keywords.
|
|
12
|
+
* Returns null if the message is a pure operation command with no memory relevance.
|
|
13
|
+
*/
|
|
14
|
+
export declare function refineQuery(raw: string): RefineResult | null;
|
package/dist/refine.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query refinement: strip noise tokens from user messages before memory search.
|
|
3
|
+
* Pure function — no side effects, no DB access.
|
|
4
|
+
*/
|
|
5
|
+
// Action words / helper phrases to strip (Chinese)
|
|
6
|
+
const ACTION_WORDS = [
|
|
7
|
+
'帮我看看', '能不能帮我', '给我看看',
|
|
8
|
+
'帮我', '看看', '看一下', '做一下', '能不能', '为什么', '怎么',
|
|
9
|
+
'是什么', '如何', '请', '麻烦', '可以', '给我',
|
|
10
|
+
'给我做', '给我写', '给我查', '给我找', '给我说', '给我讲',
|
|
11
|
+
'告诉我', '跟我说', '跟我讲', '给我解释', '给我说明', '给我介绍',
|
|
12
|
+
'运行', '执行', '启动', '停止', '创建', '删除', '修改', '更新', '查看',
|
|
13
|
+
'检查', '测试', '提交', '推送', '拉取', '合并', '切换', '重置', '重构',
|
|
14
|
+
'运行测试', '创建文件',
|
|
15
|
+
];
|
|
16
|
+
// Common CLI commands / low-signal English tokens to filter
|
|
17
|
+
const NOISE_WORDS = new Set([
|
|
18
|
+
'git', 'npm', 'npx', 'yarn', 'pnpm', 'status', 'log', 'diff', 'add',
|
|
19
|
+
'commit', 'push', 'pull', 'merge', 'checkout', 'branch', 'stash',
|
|
20
|
+
'install', 'build', 'run', 'start', 'stop', 'test', 'lint', 'format',
|
|
21
|
+
]);
|
|
22
|
+
// Sort by length descending so longer phrases match first during replacement
|
|
23
|
+
const ACTION_WORDS_SORTED = [...ACTION_WORDS].sort((a, b) => b.length - a.length);
|
|
24
|
+
const ACTION_WORDS_SET = new Set(ACTION_WORDS);
|
|
25
|
+
// Reuse existing stop words from retriever
|
|
26
|
+
const CN_STOP_WORDS = new Set([
|
|
27
|
+
'的', '了', '是', '在', '有', '和', '就', '不', '人', '都',
|
|
28
|
+
'一', '个', '上', '也', '很', '到', '说', '要', '去', '你',
|
|
29
|
+
'会', '着', '没', '看', '好', '自', '这', '他', '她', '它',
|
|
30
|
+
'那', '些', '用', '对', '下', '为', '从', '被', '把', '能',
|
|
31
|
+
'可', '以', '所', '而', '又', '与', '但', '或', '等', '中',
|
|
32
|
+
'大', '小', '多', '少', '其', '之', '做', '让', '给', '已',
|
|
33
|
+
'还', '来', '地', '得', '过', '时', '里', '后', '前', '当',
|
|
34
|
+
]);
|
|
35
|
+
/**
|
|
36
|
+
* Refine a raw user message into memory-searchable keywords.
|
|
37
|
+
* Returns null if the message is a pure operation command with no memory relevance.
|
|
38
|
+
*/
|
|
39
|
+
export function refineQuery(raw) {
|
|
40
|
+
const trimmed = raw.trim();
|
|
41
|
+
if (!trimmed)
|
|
42
|
+
return null;
|
|
43
|
+
// Extract high-signal tokens first: quoted content, book titles, capitalized phrases
|
|
44
|
+
const entityTokens = [];
|
|
45
|
+
// Chinese quotes: 「深色主题」 or "深色主题" or '深色主题'
|
|
46
|
+
for (const m of trimmed.matchAll(/[「""'']([^「""''」]{2,20})[」""'']/g)) {
|
|
47
|
+
entityTokens.push(m[1]);
|
|
48
|
+
}
|
|
49
|
+
// Book titles: 《记忆系统》
|
|
50
|
+
for (const m of trimmed.matchAll(/《([^》]+)》/g)) {
|
|
51
|
+
entityTokens.push(m[1]);
|
|
52
|
+
}
|
|
53
|
+
// Capitalized English phrases: "TypeScript", "Visual Studio Code"
|
|
54
|
+
for (const m of trimmed.matchAll(/\b([A-Z][a-zA-Z]*(?:\s+[A-Z][a-zA-Z]*)+)\b/g)) {
|
|
55
|
+
entityTokens.push(m[1]);
|
|
56
|
+
}
|
|
57
|
+
// Tokenize: split by spaces and Chinese character boundaries
|
|
58
|
+
const tokens = [];
|
|
59
|
+
const parts = trimmed.split(/\s+/);
|
|
60
|
+
for (const part of parts) {
|
|
61
|
+
// English words
|
|
62
|
+
for (const word of part.match(/[a-zA-Z0-9_\-.]+/g) ?? []) {
|
|
63
|
+
if (word.length >= 2)
|
|
64
|
+
tokens.push(word);
|
|
65
|
+
}
|
|
66
|
+
// For Chinese: strip action words first, then extract remaining chars
|
|
67
|
+
let cnText = part.replace(/[\u4e00-\u9fff]+/g, (seg) => {
|
|
68
|
+
let result = seg;
|
|
69
|
+
for (const aw of ACTION_WORDS_SORTED) {
|
|
70
|
+
result = result.replaceAll(aw, '');
|
|
71
|
+
}
|
|
72
|
+
return result;
|
|
73
|
+
});
|
|
74
|
+
const cnChars = cnText.match(/[\u4e00-\u9fff]/g) ?? [];
|
|
75
|
+
for (const c of cnChars) {
|
|
76
|
+
if (!CN_STOP_WORDS.has(c))
|
|
77
|
+
tokens.push(c);
|
|
78
|
+
}
|
|
79
|
+
// Chinese 2-grams for better matching
|
|
80
|
+
for (let i = 0; i < cnChars.length - 1; i++) {
|
|
81
|
+
const bigram = cnChars[i] + cnChars[i + 1];
|
|
82
|
+
tokens.push(bigram);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Filter stop words, noise, and short tokens
|
|
86
|
+
const filtered = tokens.filter(t => {
|
|
87
|
+
if (ACTION_WORDS_SET.has(t))
|
|
88
|
+
return false;
|
|
89
|
+
if (CN_STOP_WORDS.has(t))
|
|
90
|
+
return false;
|
|
91
|
+
if (NOISE_WORDS.has(t.toLowerCase()))
|
|
92
|
+
return false;
|
|
93
|
+
if (t.length < 2)
|
|
94
|
+
return false;
|
|
95
|
+
return true;
|
|
96
|
+
});
|
|
97
|
+
// Deduplicate while preserving order
|
|
98
|
+
const seen = new Set();
|
|
99
|
+
const deduped = [];
|
|
100
|
+
for (const t of filtered) {
|
|
101
|
+
if (!seen.has(t)) {
|
|
102
|
+
seen.add(t);
|
|
103
|
+
deduped.push(t);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// If nothing left after filtering, check if we have entity tokens
|
|
107
|
+
if (deduped.length === 0 && entityTokens.length === 0) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
// Combine: entity tokens first (higher signal), then deduped tokens
|
|
111
|
+
const allTokens = [...entityTokens, ...deduped.filter(t => !entityTokens.includes(t))];
|
|
112
|
+
const query = allTokens.join(' ');
|
|
113
|
+
return { query, tokens: deduped, entityTokens };
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=refine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refine.js","sourceRoot":"","sources":["../src/refine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Resource manager for mnemo-mcp.
|
|
3
|
+
* Exposes per-category memory summaries as MCP Resources for session warmup injection.
|
|
4
|
+
*/
|
|
5
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
|
+
import type { MemoryStore } from './store.js';
|
|
7
|
+
import type { FactCategory } from './types.js';
|
|
8
|
+
export interface ResourceFact {
|
|
9
|
+
fact_id: number;
|
|
10
|
+
content: string;
|
|
11
|
+
trust_score: number;
|
|
12
|
+
}
|
|
13
|
+
export declare class ResourceManager {
|
|
14
|
+
private store;
|
|
15
|
+
private cache;
|
|
16
|
+
constructor(store: MemoryStore);
|
|
17
|
+
/** Register all category resources with the MCP server */
|
|
18
|
+
registerResources(server: McpServer): void;
|
|
19
|
+
/** Read handler for a specific category */
|
|
20
|
+
private readCategory;
|
|
21
|
+
/** Get facts for a category — with caching */
|
|
22
|
+
getFacts(category: FactCategory): ResourceFact[];
|
|
23
|
+
/** Invalidate all caches — call after any write operation */
|
|
24
|
+
invalidate(): void;
|
|
25
|
+
/** Get cache entry count for debugging */
|
|
26
|
+
cacheSize(): number;
|
|
27
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Resource manager for mnemo-mcp.
|
|
3
|
+
* Exposes per-category memory summaries as MCP Resources for session warmup injection.
|
|
4
|
+
*/
|
|
5
|
+
const CATEGORIES = ['identity', 'coding_style', 'tool_pref', 'workflow', 'general'];
|
|
6
|
+
const RESOURCE_LIMIT = 10;
|
|
7
|
+
export class ResourceManager {
|
|
8
|
+
store;
|
|
9
|
+
cache = new Map();
|
|
10
|
+
constructor(store) {
|
|
11
|
+
this.store = store;
|
|
12
|
+
}
|
|
13
|
+
/** Register all category resources with the MCP server */
|
|
14
|
+
registerResources(server) {
|
|
15
|
+
for (const category of CATEGORIES) {
|
|
16
|
+
const uri = `mnemo://global/${category}`;
|
|
17
|
+
server.registerResource(`mnemo-global-${category}`, uri, {
|
|
18
|
+
description: `${category} category global facts (top ${RESOURCE_LIMIT} by trust)`,
|
|
19
|
+
mimeType: 'application/json',
|
|
20
|
+
}, async () => this.readCategory(category));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/** Read handler for a specific category */
|
|
24
|
+
readCategory(category) {
|
|
25
|
+
const facts = this.getFacts(category);
|
|
26
|
+
return {
|
|
27
|
+
contents: [{
|
|
28
|
+
uri: `mnemo://global/${category}`,
|
|
29
|
+
mimeType: 'application/json',
|
|
30
|
+
text: JSON.stringify(facts, null, 2),
|
|
31
|
+
}],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** Get facts for a category — with caching */
|
|
35
|
+
getFacts(category) {
|
|
36
|
+
const cached = this.cache.get(category);
|
|
37
|
+
if (cached)
|
|
38
|
+
return cached;
|
|
39
|
+
const facts = this.store.listFacts(category, 0.0, RESOURCE_LIMIT).map(f => ({
|
|
40
|
+
fact_id: f.factId,
|
|
41
|
+
content: f.content,
|
|
42
|
+
trust_score: f.trustScore,
|
|
43
|
+
}));
|
|
44
|
+
this.cache.set(category, facts);
|
|
45
|
+
return facts;
|
|
46
|
+
}
|
|
47
|
+
/** Invalidate all caches — call after any write operation */
|
|
48
|
+
invalidate() {
|
|
49
|
+
this.cache.clear();
|
|
50
|
+
}
|
|
51
|
+
/** Get cache entry count for debugging */
|
|
52
|
+
cacheSize() {
|
|
53
|
+
return this.cache.size;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,UAAU,GAAmB,CAAC,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,CAAC,CAAA;AACnG,MAAM,cAAc,GAAG,EAAE,CAAA;AAQzB,MAAM,OAAO,eAAe;IAIhB;IAHF,KAAK,GAAG,IAAI,GAAG,EAAgC,CAAA;IAEvD,YACU,KAAkB;QAAlB,UAAK,GAAL,KAAK,CAAa;IACzB,CAAC;IAEJ,0DAA0D;IAC1D,iBAAiB,CAAC,MAAiB;QACjC,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;YAClC,MAAM,GAAG,GAAG,kBAAkB,QAAQ,EAAE,CAAA;YACxC,MAAM,CAAC,gBAAgB,CACrB,gBAAgB,QAAQ,EAAE,EAC1B,GAAG,EACH;gBACE,WAAW,EAAE,GAAG,QAAQ,+BAA+B,cAAc,YAAY;gBACjF,QAAQ,EAAE,kBAAkB;aAC7B,EACD,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CACxC,CAAA;QACH,CAAC;IACH,CAAC;IAED,2CAA2C;IACnC,YAAY,CAAC,QAAsB;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;QACrC,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,kBAAkB,QAAQ,EAAE;oBACjC,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;iBACrC,CAAC;SACH,CAAA;IACH,CAAC;IAED,8CAA8C;IAC9C,QAAQ,CAAC,QAAsB;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACvC,IAAI,MAAM;YAAE,OAAO,MAAM,CAAA;QAEzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC1E,OAAO,EAAE,CAAC,CAAC,MAAM;YACjB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,WAAW,EAAE,CAAC,CAAC,UAAU;SAC1B,CAAC,CAAC,CAAA;QAEH,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;QAC/B,OAAO,KAAK,CAAA;IACd,CAAC;IAED,6DAA6D;IAC7D,UAAU;QACR,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;IACpB,CAAC;IAED,0CAA0C;IAC1C,SAAS;QACP,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAA;IACxB,CAAC;CACF"}
|
package/dist/retriever.d.ts
CHANGED
|
@@ -8,26 +8,38 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { ScoredFact, Contradiction, SearchOptions, ContradictOptions, RetrieverOptions } from './types.js';
|
|
10
10
|
import { MemoryStore } from './store.js';
|
|
11
|
+
import { QueryCache } from './cache.js';
|
|
12
|
+
import { PerfMetrics } from './metrics.js';
|
|
11
13
|
export declare class FactRetriever {
|
|
12
14
|
private store;
|
|
13
15
|
private db;
|
|
14
16
|
private ftsWeight;
|
|
15
17
|
private jaccardWeight;
|
|
16
18
|
private halfLifeDays;
|
|
19
|
+
/** 查询缓存(60s TTL,进程内 Map) */
|
|
20
|
+
private cache;
|
|
21
|
+
/** 性能指标(MNEMO_DEBUG=1 时生效) */
|
|
22
|
+
private metrics;
|
|
17
23
|
/** category → 高频 tag 集合(从事实库自动学习,惰性初始化) */
|
|
18
24
|
private _categoryTagMap;
|
|
19
25
|
/** 中英术语对列表(从事实库自动学习,惰性初始化) */
|
|
20
26
|
private _cnEnPairs;
|
|
21
27
|
constructor(store: MemoryStore, options?: RetrieverOptions);
|
|
28
|
+
/** 获取缓存实例(供 server.ts 写操作时调用 cache.clear()) */
|
|
29
|
+
getCache(): QueryCache;
|
|
30
|
+
/** 获取性能指标实例(供调试接口使用) */
|
|
31
|
+
getMetrics(): PerfMetrics;
|
|
22
32
|
/** 主搜索:FTS5 → LIKE → 字符交叉 → 分类推断 → Jaccard → 信任评分 → 时间衰减 */
|
|
23
|
-
search(query: string, options?: SearchOptions
|
|
33
|
+
search(query: string, options?: SearchOptions & {
|
|
34
|
+
skipRefine?: boolean;
|
|
35
|
+
}): ScoredFact[];
|
|
24
36
|
/** 实体探测:查询某实体关联的所有事实 */
|
|
25
37
|
probe(entity: string, options?: SearchOptions): ScoredFact[];
|
|
26
38
|
/** 实体关联:查找与某实体共享上下文的其他事实 */
|
|
27
39
|
related(entity: string, options?: SearchOptions): ScoredFact[];
|
|
28
40
|
/** 多实体推理:查找同时关联多个实体的事实 */
|
|
29
41
|
reason(entities: string[], options?: SearchOptions): ScoredFact[];
|
|
30
|
-
/** 矛盾检测:实体重叠 +
|
|
42
|
+
/** 矛盾检测:实体重叠 + 内容差异(仅指标,不缓存 — 返回类型不同) */
|
|
31
43
|
contradict(options?: ContradictOptions): Contradiction[];
|
|
32
44
|
/** Stage 1: FTS5 候选集 */
|
|
33
45
|
private ftsCandidates;
|