@morningljn/mnemo 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +2 -0
- package/dist/config.js +28 -0
- package/dist/config.js.map +1 -0
- package/dist/dream-engine.d.ts +17 -0
- package/dist/dream-engine.js +144 -0
- package/dist/dream-engine.js.map +1 -0
- package/dist/dream.d.ts +2 -0
- package/dist/dream.js +20 -0
- package/dist/dream.js.map +1 -0
- package/dist/init.js +4 -24
- package/dist/init.js.map +1 -1
- package/dist/llm-client.d.ts +10 -0
- package/dist/llm-client.js +55 -0
- package/dist/llm-client.js.map +1 -0
- package/dist/resources.d.ts +22 -8
- package/dist/resources.js +66 -20
- package/dist/resources.js.map +1 -1
- package/dist/retriever.js +12 -5
- package/dist/retriever.js.map +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +2 -2
- package/dist/server.js +40 -6
- package/dist/server.js.map +1 -1
- package/dist/store.d.ts +23 -1
- package/dist/store.js +169 -4
- package/dist/store.js.map +1 -1
- package/dist/types.d.ts +41 -1
- package/docs/superpowers/plans/2026-05-16-llm-dream.md +973 -0
- package/docs/superpowers/plans/2026-05-16-memory-dreaming.md +626 -0
- package/openspec/changes/archive/2026-05-16-memory-dreaming/.openspec.yaml +2 -0
- package/openspec/changes/archive/2026-05-16-memory-dreaming/design.md +71 -0
- package/openspec/changes/archive/2026-05-16-memory-dreaming/proposal.md +32 -0
- package/openspec/changes/archive/2026-05-16-memory-dreaming/specs/compact-search/spec.md +16 -0
- package/openspec/changes/archive/2026-05-16-memory-dreaming/specs/dream-cycle/spec.md +38 -0
- package/openspec/changes/archive/2026-05-16-memory-dreaming/tasks.md +27 -0
- package/openspec/changes/llm-dream/.openspec.yaml +2 -0
- package/openspec/changes/llm-dream/design.md +84 -0
- package/openspec/changes/llm-dream/proposal.md +36 -0
- package/openspec/changes/llm-dream/specs/dream-cycle/spec.md +42 -0
- package/openspec/changes/llm-dream/specs/llm-client/spec.md +57 -0
- package/openspec/changes/llm-dream/specs/llm-dream-engine/spec.md +72 -0
- package/openspec/changes/llm-dream/tasks.md +32 -0
- package/openspec/specs/compact-search/spec.md +16 -0
- package/openspec/specs/dream-cycle/spec.md +38 -0
- package/package.json +3 -2
- package/src/config.ts +29 -0
- package/src/dream-engine.ts +162 -0
- package/src/dream.ts +20 -0
- package/src/init.ts +4 -24
- package/src/llm-client.ts +59 -0
- package/src/resources.ts +77 -21
- package/src/retriever.ts +9 -5
- package/src/schema.ts +2 -2
- package/src/server.ts +46 -7
- package/src/store.ts +198 -5
- package/src/types.ts +41 -1
- package/tests/dream-engine.test.ts +163 -0
- package/tests/llm-client.test.ts +105 -0
- package/tests/resource.test.ts +25 -23
- package/tests/store.test.ts +130 -2
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
const DEFAULT_CONFIG = {
|
|
5
|
+
baseUrl: 'http://localhost:11434/v1',
|
|
6
|
+
model: 'qwen3:8b',
|
|
7
|
+
temperature: 0.1,
|
|
8
|
+
};
|
|
9
|
+
export function loadConfig() {
|
|
10
|
+
const configPath = join(homedir(), '.mnemo', 'config.json');
|
|
11
|
+
if (!existsSync(configPath))
|
|
12
|
+
return { ...DEFAULT_CONFIG };
|
|
13
|
+
try {
|
|
14
|
+
const raw = readFileSync(configPath, 'utf-8');
|
|
15
|
+
const parsed = JSON.parse(raw);
|
|
16
|
+
const llm = parsed.llm ?? {};
|
|
17
|
+
return {
|
|
18
|
+
baseUrl: llm.baseUrl ?? DEFAULT_CONFIG.baseUrl,
|
|
19
|
+
model: llm.model ?? DEFAULT_CONFIG.model,
|
|
20
|
+
apiKey: llm.apiKey,
|
|
21
|
+
temperature: llm.temperature ?? DEFAULT_CONFIG.temperature,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return { ...DEFAULT_CONFIG };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAGjC,MAAM,cAAc,GAAc;IAChC,OAAO,EAAE,2BAA2B;IACpC,KAAK,EAAE,UAAU;IACjB,WAAW,EAAE,GAAG;CACjB,CAAA;AAED,MAAM,UAAU,UAAU;IACxB,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAA;IAC3D,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,EAAE,GAAG,cAAc,EAAE,CAAA;IAEzD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC9B,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAA;QAC5B,OAAO;YACL,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,cAAc,CAAC,OAAO;YAC9C,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,cAAc,CAAC,KAAK;YACxC,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,cAAc,CAAC,WAAW;SAC3D,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,GAAG,cAAc,EAAE,CAAA;IAC9B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { LLMClient } from './llm-client.js';
|
|
2
|
+
import type { MemoryStore } from './store.js';
|
|
3
|
+
export declare class DreamEngine {
|
|
4
|
+
private llm;
|
|
5
|
+
private store;
|
|
6
|
+
constructor(llm: LLMClient, store: MemoryStore);
|
|
7
|
+
semanticMerge(): Promise<{
|
|
8
|
+
merged: number;
|
|
9
|
+
details: Array<{
|
|
10
|
+
kept: number;
|
|
11
|
+
removed: number;
|
|
12
|
+
reason: string;
|
|
13
|
+
}>;
|
|
14
|
+
}>;
|
|
15
|
+
smartCompress(): Promise<number>;
|
|
16
|
+
smartReclassify(): Promise<number>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
const BATCH_SIZE = 20;
|
|
2
|
+
const MAX_DELETE_RATIO = 0.1;
|
|
3
|
+
const TRUST_DELETE_LIMIT = 0.8;
|
|
4
|
+
const RETRIEVAL_DELETE_LIMIT = 100;
|
|
5
|
+
export class DreamEngine {
|
|
6
|
+
llm;
|
|
7
|
+
store;
|
|
8
|
+
constructor(llm, store) {
|
|
9
|
+
this.llm = llm;
|
|
10
|
+
this.store = store;
|
|
11
|
+
}
|
|
12
|
+
async semanticMerge() {
|
|
13
|
+
const categories = ['identity', 'coding_style', 'tool_pref', 'workflow', 'general'];
|
|
14
|
+
let merged = 0;
|
|
15
|
+
const details = [];
|
|
16
|
+
const totalFacts = this.store.getTotalCount();
|
|
17
|
+
const maxDeletes = Math.max(1, Math.floor(totalFacts * MAX_DELETE_RATIO));
|
|
18
|
+
for (const cat of categories) {
|
|
19
|
+
const facts = this.store.listFacts(cat, 0, 200);
|
|
20
|
+
if (facts.length < 2)
|
|
21
|
+
continue;
|
|
22
|
+
for (let i = 0; i < facts.length; i += BATCH_SIZE) {
|
|
23
|
+
const batch = facts.slice(i, i + BATCH_SIZE);
|
|
24
|
+
const factList = batch.map(f => `[${f.factId}] ${f.content}`).join('\n');
|
|
25
|
+
const messages = [
|
|
26
|
+
{
|
|
27
|
+
role: 'system',
|
|
28
|
+
content: `你是一个记忆整理助手。分析以下同一分类(${cat})的记忆条目,找出语义重复的条目对。
|
|
29
|
+
只输出JSON,格式:{"merges": [{"kept": 保留的fact_id, "removed": 删除的fact_id, "reason": "原因"}]}
|
|
30
|
+
如果没有语义重复的条目,输出:{"merges": []}
|
|
31
|
+
规则:
|
|
32
|
+
- 保留内容更完整、信息量更大的条目
|
|
33
|
+
- 用词不同但意思相同的条目应合并(如"喜欢VS Code"和"偏好Visual Studio Code")
|
|
34
|
+
- 不要合并只是主题相关但内容不同的条目`,
|
|
35
|
+
},
|
|
36
|
+
{ role: 'user', content: factList },
|
|
37
|
+
];
|
|
38
|
+
try {
|
|
39
|
+
const result = await this.llm.chatJSON(messages);
|
|
40
|
+
if (!result?.merges || !Array.isArray(result.merges))
|
|
41
|
+
continue;
|
|
42
|
+
for (const merge of result.merges) {
|
|
43
|
+
if (merged >= maxDeletes)
|
|
44
|
+
break;
|
|
45
|
+
if (!merge.kept || !merge.removed)
|
|
46
|
+
continue;
|
|
47
|
+
const toRemove = this.store.listFacts(cat, 0, 200).find(f => f.factId === merge.removed);
|
|
48
|
+
if (!toRemove)
|
|
49
|
+
continue;
|
|
50
|
+
if (toRemove.trustScore > TRUST_DELETE_LIMIT)
|
|
51
|
+
continue;
|
|
52
|
+
if (toRemove.retrievalCount > RETRIEVAL_DELETE_LIMIT)
|
|
53
|
+
continue;
|
|
54
|
+
const toKeep = this.store.listFacts(cat, 0, 200).find(f => f.factId === merge.kept);
|
|
55
|
+
if (!toKeep)
|
|
56
|
+
continue;
|
|
57
|
+
this.store.removeFact(merge.removed);
|
|
58
|
+
details.push({ kept: merge.kept, removed: merge.removed, reason: merge.reason });
|
|
59
|
+
merged++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return { merged, details };
|
|
68
|
+
}
|
|
69
|
+
async smartCompress() {
|
|
70
|
+
const rows = this.store.connection.prepare("SELECT fact_id, content FROM facts WHERE length(content) > 200 AND (summary IS NULL OR summary = '')").all();
|
|
71
|
+
if (rows.length === 0)
|
|
72
|
+
return 0;
|
|
73
|
+
let compressed = 0;
|
|
74
|
+
for (let i = 0; i < rows.length; i += BATCH_SIZE) {
|
|
75
|
+
const batch = rows.slice(i, i + BATCH_SIZE);
|
|
76
|
+
const factList = batch.map(f => `[${f.fact_id}] ${f.content}`).join('\n\n---\n\n');
|
|
77
|
+
const messages = [
|
|
78
|
+
{
|
|
79
|
+
role: 'system',
|
|
80
|
+
content: `你是一个记忆摘要助手。为每条记忆生成简洁的摘要(≤150字)。
|
|
81
|
+
摘要应保留核心信息:谁/什么/关键决策/关键数据。去除示例、过程描述、冗余细节。
|
|
82
|
+
输出JSON:{"summaries": [{"fact_id": 数字, "summary": "摘要内容"}]}`,
|
|
83
|
+
},
|
|
84
|
+
{ role: 'user', content: factList },
|
|
85
|
+
];
|
|
86
|
+
try {
|
|
87
|
+
const result = await this.llm.chatJSON(messages);
|
|
88
|
+
if (!result?.summaries || !Array.isArray(result.summaries))
|
|
89
|
+
continue;
|
|
90
|
+
for (const item of result.summaries) {
|
|
91
|
+
if (!item.fact_id || !item.summary)
|
|
92
|
+
continue;
|
|
93
|
+
const truncated = item.summary.length > 150 ? item.summary.slice(0, 147) + '...' : item.summary;
|
|
94
|
+
this.store.connection.prepare('UPDATE facts SET summary = ? WHERE fact_id = ?').run(truncated, item.fact_id);
|
|
95
|
+
compressed++;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return compressed;
|
|
103
|
+
}
|
|
104
|
+
async smartReclassify() {
|
|
105
|
+
const rows = this.store.connection.prepare("SELECT fact_id, content FROM facts WHERE category = 'general'").all();
|
|
106
|
+
if (rows.length === 0)
|
|
107
|
+
return 0;
|
|
108
|
+
const validCategories = ['identity', 'coding_style', 'tool_pref', 'workflow'];
|
|
109
|
+
let reclassified = 0;
|
|
110
|
+
for (let i = 0; i < rows.length; i += BATCH_SIZE) {
|
|
111
|
+
const batch = rows.slice(i, i + BATCH_SIZE);
|
|
112
|
+
const factList = batch.map(f => `[${f.fact_id}] ${f.content}`).join('\n');
|
|
113
|
+
const messages = [
|
|
114
|
+
{
|
|
115
|
+
role: 'system',
|
|
116
|
+
content: `你是一个记忆分类助手。分析以下记忆条目,判断它们应该属于哪个分类。
|
|
117
|
+
可选分类:identity(身份/角色)、coding_style(编码规范)、tool_pref(工具偏好)、workflow(工作流)
|
|
118
|
+
如果记忆不属于以上任何分类,保持 general。
|
|
119
|
+
输出JSON:{"reclassify": [{"fact_id": 数字, "to": "分类名"}]}
|
|
120
|
+
不需要重新分类的条目不要输出。`,
|
|
121
|
+
},
|
|
122
|
+
{ role: 'user', content: factList },
|
|
123
|
+
];
|
|
124
|
+
try {
|
|
125
|
+
const result = await this.llm.chatJSON(messages);
|
|
126
|
+
if (!result?.reclassify || !Array.isArray(result.reclassify))
|
|
127
|
+
continue;
|
|
128
|
+
for (const item of result.reclassify) {
|
|
129
|
+
if (!item.fact_id || !item.to)
|
|
130
|
+
continue;
|
|
131
|
+
if (!validCategories.includes(item.to))
|
|
132
|
+
continue;
|
|
133
|
+
this.store.connection.prepare("UPDATE facts SET category = ?, updated_at = datetime('now', 'localtime') WHERE fact_id = ?").run(item.to, item.fact_id);
|
|
134
|
+
reclassified++;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return reclassified;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=dream-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dream-engine.js","sourceRoot":"","sources":["../src/dream-engine.ts"],"names":[],"mappings":"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"}
|
package/dist/dream.d.ts
ADDED
package/dist/dream.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { MemoryStore } from './store.js';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
const dbPath = join(homedir(), '.mnemo', 'facts.db');
|
|
6
|
+
const store = new MemoryStore(dbPath);
|
|
7
|
+
try {
|
|
8
|
+
console.log('[mnemo dream] 开始整理记忆库...\n');
|
|
9
|
+
const report = await store.runDream();
|
|
10
|
+
console.log(JSON.stringify(report, null, 2));
|
|
11
|
+
console.log(`\n[mnemo dream] 完成: merged=${report.merged} compressed=${report.compressed} reclassified=${report.reclassified} deleted=${report.deleted}`);
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
console.error('[mnemo dream] error:', err);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
store.close();
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=dream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dream.js","sourceRoot":"","sources":["../src/dream.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEjC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAA;AACpD,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAA;AAErC,IAAI,CAAC;IACH,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAA;IACzC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE,CAAA;IACrC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;IAC5C,OAAO,CAAC,GAAG,CAAC,8BAA8B,MAAM,CAAC,MAAM,eAAe,MAAM,CAAC,UAAU,iBAAiB,MAAM,CAAC,YAAY,YAAY,MAAM,CAAC,OAAO,EAAE,CAAC,CAAA;AAC1J,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACb,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAA;IAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC;QAAS,CAAC;IACT,KAAK,CAAC,KAAK,EAAE,CAAA;AACf,CAAC"}
|
package/dist/init.js
CHANGED
|
@@ -15,32 +15,12 @@ const CLAUDE_DIR = join(homedir(), '.claude');
|
|
|
15
15
|
const CLAUDE_MD_PATH = join(CLAUDE_DIR, 'CLAUDE.md');
|
|
16
16
|
const SETTINGS_PATH = join(CLAUDE_DIR, 'settings.json');
|
|
17
17
|
const MEMORY_RULES = `
|
|
18
|
-
# 记忆系统使用规则
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
# mnemo 记忆系统
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
## 规则 2:按需补充查询
|
|
27
|
-
仅在以下情况调用 \`fact_store(action="search")\`:
|
|
28
|
-
- 用户消息涉及个人偏好/习惯/工具选择且预热中未覆盖
|
|
29
|
-
- 用户明确查询记忆("我之前说过什么""按我的习惯")
|
|
30
|
-
- 技术选型时需要确认用户偏好
|
|
31
|
-
|
|
32
|
-
不触发查询的情况:
|
|
33
|
-
- 纯操作指令("运行测试""git commit")
|
|
34
|
-
- 通用技术问题("Promise 怎么用")
|
|
35
|
-
- 代码审查/解释请求
|
|
36
|
-
|
|
37
|
-
## 规则 3:写入记忆
|
|
38
|
-
用户说"记住"、"记下来"时,调用 \`fact_store(action="add", content="...", category="...")\`。
|
|
39
|
-
- 先 search 检查是否已有相似事实,有则 update
|
|
40
|
-
- category:identity / coding_style / tool_pref / workflow / general
|
|
41
|
-
|
|
42
|
-
## 规则 4:反馈强化
|
|
43
|
-
成功使用某条记忆时,调用 \`fact_feedback(action="helpful", fact_id=...)\`。
|
|
21
|
+
- 身份问题("你是谁"等)→ 先 fact_store(search, query="角色设定"),按设定回答
|
|
22
|
+
- 用户说"记住"→ fact_store(add),先 search 去重
|
|
23
|
+
- 成功使用记忆 → fact_feedback(helpful, fact_id)
|
|
44
24
|
`;
|
|
45
25
|
const MCP_TOOLS = [
|
|
46
26
|
'mcp__mnemo__fact_store',
|
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,10 @@
|
|
|
1
|
+
import type { LLMConfig, LLMMessage } from './types.js';
|
|
2
|
+
export declare class LLMClient {
|
|
3
|
+
private config;
|
|
4
|
+
constructor(config: LLMConfig);
|
|
5
|
+
chat(messages: LLMMessage[], options?: {
|
|
6
|
+
temperature?: number;
|
|
7
|
+
}): Promise<string>;
|
|
8
|
+
chatJSON<T = unknown>(messages: LLMMessage[]): Promise<T>;
|
|
9
|
+
isAvailable(): Promise<boolean>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export class LLMClient {
|
|
2
|
+
config;
|
|
3
|
+
constructor(config) {
|
|
4
|
+
this.config = config;
|
|
5
|
+
}
|
|
6
|
+
async chat(messages, options) {
|
|
7
|
+
const url = `${this.config.baseUrl}/chat/completions`;
|
|
8
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
9
|
+
if (this.config.apiKey) {
|
|
10
|
+
headers['Authorization'] = `Bearer ${this.config.apiKey}`;
|
|
11
|
+
}
|
|
12
|
+
const resp = await fetch(url, {
|
|
13
|
+
method: 'POST',
|
|
14
|
+
headers,
|
|
15
|
+
body: JSON.stringify({
|
|
16
|
+
model: this.config.model,
|
|
17
|
+
messages,
|
|
18
|
+
temperature: options?.temperature ?? this.config.temperature,
|
|
19
|
+
stream: false,
|
|
20
|
+
}),
|
|
21
|
+
});
|
|
22
|
+
if (!resp.ok) {
|
|
23
|
+
throw new Error(`LLM request failed: ${resp.status} ${await resp.text()}`);
|
|
24
|
+
}
|
|
25
|
+
const data = (await resp.json());
|
|
26
|
+
return data.choices[0]?.message?.content ?? '';
|
|
27
|
+
}
|
|
28
|
+
async chatJSON(messages) {
|
|
29
|
+
const text = await this.chat(messages);
|
|
30
|
+
try {
|
|
31
|
+
return JSON.parse(text);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
const match = text.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
|
|
35
|
+
if (match) {
|
|
36
|
+
return JSON.parse(match[1].trim());
|
|
37
|
+
}
|
|
38
|
+
throw new Error(`LLM response is not valid JSON: ${text.slice(0, 200)}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async isAvailable() {
|
|
42
|
+
try {
|
|
43
|
+
const url = `${this.config.baseUrl}/models`;
|
|
44
|
+
const resp = await fetch(url, {
|
|
45
|
+
method: 'GET',
|
|
46
|
+
signal: AbortSignal.timeout(3000),
|
|
47
|
+
});
|
|
48
|
+
return resp.ok;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=llm-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-client.js","sourceRoot":"","sources":["../src/llm-client.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,SAAS;IACA;IAApB,YAAoB,MAAiB;QAAjB,WAAM,GAAN,MAAM,CAAW;IAAG,CAAC;IAEzC,KAAK,CAAC,IAAI,CAAC,QAAsB,EAAE,OAAkC;QACnE,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,mBAAmB,CAAA;QACrD,MAAM,OAAO,GAA2B,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAA;QAC9E,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACvB,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAA;QAC3D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC5B,MAAM,EAAE,MAAM;YACd,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;gBACxB,QAAQ;gBACR,WAAW,EAAE,OAAO,EAAE,WAAW,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW;gBAC5D,MAAM,EAAE,KAAK;aACd,CAAC;SACH,CAAC,CAAA;QAEF,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,CAAC,MAAM,IAAI,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;QAC5E,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAE9B,CAAA;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,CAAA;IAChD,CAAC;IAED,KAAK,CAAC,QAAQ,CAAc,QAAsB;QAChD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACtC,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAA;YAC9D,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;YACpC,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,mCAAmC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;QAC1E,CAAC;IACH,CAAC;IAED,KAAK,CAAC,WAAW;QACf,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,SAAS,CAAA;YAC3C,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAC5B,MAAM,EAAE,KAAK;gBACb,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;aAClC,CAAC,CAAA;YACF,OAAO,IAAI,CAAC,EAAE,CAAA;QAChB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;CACF"}
|
package/dist/resources.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP Resource manager for mnemo-mcp.
|
|
3
|
-
* Exposes per-category memory
|
|
3
|
+
* Exposes per-category memory as MCP Resources for session warmup injection.
|
|
4
|
+
*
|
|
5
|
+
* identity → 指令格式(Claude 应遵循的行为设定)
|
|
6
|
+
* 其他 → 参考格式(供 Claude 查阅的用户偏好)
|
|
4
7
|
*/
|
|
5
8
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
9
|
import type { MemoryStore } from './store.js';
|
|
@@ -14,14 +17,25 @@ export declare class ResourceManager {
|
|
|
14
17
|
private store;
|
|
15
18
|
private cache;
|
|
16
19
|
constructor(store: MemoryStore);
|
|
17
|
-
/** Register all category resources with the MCP server */
|
|
18
20
|
registerResources(server: McpServer): void;
|
|
19
|
-
/** Read handler for a specific category */
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
/** Read handler for a specific category (public for server instructions) */
|
|
22
|
+
readCategory(category: FactCategory): {
|
|
23
|
+
contents: Array<{
|
|
24
|
+
uri: string;
|
|
25
|
+
mimeType: string;
|
|
26
|
+
text: string;
|
|
27
|
+
}>;
|
|
28
|
+
};
|
|
29
|
+
private getFormattedFacts;
|
|
30
|
+
/**
|
|
31
|
+
* identity 类事实格式化为指令——Claude 应直接遵循这些设定。
|
|
32
|
+
* 角色设定排在最前面,用祈使句。
|
|
33
|
+
*/
|
|
34
|
+
private formatAsInstructions;
|
|
35
|
+
/**
|
|
36
|
+
* 非 identity 类事实格式化为参考——供 Claude 查阅但不强制遵循。
|
|
37
|
+
*/
|
|
38
|
+
private formatAsReference;
|
|
24
39
|
invalidate(): void;
|
|
25
|
-
/** Get cache entry count for debugging */
|
|
26
40
|
cacheSize(): number;
|
|
27
41
|
}
|
package/dist/resources.js
CHANGED
|
@@ -1,54 +1,100 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP Resource manager for mnemo-mcp.
|
|
3
|
-
* Exposes per-category memory
|
|
3
|
+
* Exposes per-category memory as MCP Resources for session warmup injection.
|
|
4
|
+
*
|
|
5
|
+
* identity → 指令格式(Claude 应遵循的行为设定)
|
|
6
|
+
* 其他 → 参考格式(供 Claude 查阅的用户偏好)
|
|
4
7
|
*/
|
|
5
8
|
const CATEGORIES = ['identity', 'coding_style', 'tool_pref', 'workflow', 'general'];
|
|
6
|
-
const RESOURCE_LIMIT =
|
|
9
|
+
const RESOURCE_LIMIT = 15;
|
|
7
10
|
export class ResourceManager {
|
|
8
11
|
store;
|
|
9
12
|
cache = new Map();
|
|
10
13
|
constructor(store) {
|
|
11
14
|
this.store = store;
|
|
12
15
|
}
|
|
13
|
-
/** Register all category resources with the MCP server */
|
|
14
16
|
registerResources(server) {
|
|
15
17
|
for (const category of CATEGORIES) {
|
|
16
18
|
const uri = `mnemo://global/${category}`;
|
|
17
19
|
server.registerResource(`mnemo-global-${category}`, uri, {
|
|
18
20
|
description: `${category} category global facts (top ${RESOURCE_LIMIT} by trust)`,
|
|
19
|
-
mimeType: '
|
|
21
|
+
mimeType: 'text/markdown',
|
|
20
22
|
}, async () => this.readCategory(category));
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
|
-
/** Read handler for a specific category */
|
|
25
|
+
/** Read handler for a specific category (public for server instructions) */
|
|
24
26
|
readCategory(category) {
|
|
25
|
-
const
|
|
27
|
+
const text = this.getFormattedFacts(category);
|
|
26
28
|
return {
|
|
27
29
|
contents: [{
|
|
28
30
|
uri: `mnemo://global/${category}`,
|
|
29
|
-
mimeType: '
|
|
30
|
-
text
|
|
31
|
+
mimeType: 'text/markdown',
|
|
32
|
+
text,
|
|
31
33
|
}],
|
|
32
34
|
};
|
|
33
35
|
}
|
|
34
|
-
|
|
35
|
-
getFacts(category) {
|
|
36
|
+
getFormattedFacts(category) {
|
|
36
37
|
const cached = this.cache.get(category);
|
|
37
38
|
if (cached)
|
|
38
39
|
return cached;
|
|
39
|
-
const facts = this.store.listFacts(category, 0.0, RESOURCE_LIMIT)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
const facts = this.store.listFacts(category, 0.0, RESOURCE_LIMIT);
|
|
41
|
+
const text = category === 'identity'
|
|
42
|
+
? this.formatAsInstructions(facts)
|
|
43
|
+
: this.formatAsReference(facts, category);
|
|
44
|
+
this.cache.set(category, text);
|
|
45
|
+
return text;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* identity 类事实格式化为指令——Claude 应直接遵循这些设定。
|
|
49
|
+
* 角色设定排在最前面,用祈使句。
|
|
50
|
+
*/
|
|
51
|
+
formatAsInstructions(facts) {
|
|
52
|
+
const lines = ['# 身份与行为设定', '', '以下是你的身份设定和用户偏好,请直接遵循:', ''];
|
|
53
|
+
// 角色/身份相关的 fact 排在最前面
|
|
54
|
+
const roleFacts = facts.filter(f => f.content.includes('角色设定') ||
|
|
55
|
+
f.content.includes('你是') ||
|
|
56
|
+
f.content.includes('身份是') ||
|
|
57
|
+
f.content.includes('你扮演'));
|
|
58
|
+
const otherFacts = facts.filter(f => !roleFacts.includes(f));
|
|
59
|
+
if (roleFacts.length > 0) {
|
|
60
|
+
lines.push('## 你的身份');
|
|
61
|
+
for (const f of roleFacts) {
|
|
62
|
+
// 把描述性语句转为指令
|
|
63
|
+
const content = f.content
|
|
64
|
+
.replace(/^AI角色设定[::]/, '')
|
|
65
|
+
.replace(/^你是/, '')
|
|
66
|
+
.trim();
|
|
67
|
+
lines.push(`- ${content}`);
|
|
68
|
+
}
|
|
69
|
+
lines.push('');
|
|
70
|
+
}
|
|
71
|
+
if (otherFacts.length > 0) {
|
|
72
|
+
lines.push('## 用户信息');
|
|
73
|
+
for (const f of otherFacts) {
|
|
74
|
+
lines.push(`- ${f.content}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return lines.join('\n');
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 非 identity 类事实格式化为参考——供 Claude 查阅但不强制遵循。
|
|
81
|
+
*/
|
|
82
|
+
formatAsReference(facts, category) {
|
|
83
|
+
const title = {
|
|
84
|
+
coding_style: '编码风格偏好',
|
|
85
|
+
tool_pref: '工具偏好',
|
|
86
|
+
workflow: '工作流偏好',
|
|
87
|
+
general: '通用知识',
|
|
88
|
+
};
|
|
89
|
+
const lines = [`# ${title[category] ?? category}`, ''];
|
|
90
|
+
for (const f of facts) {
|
|
91
|
+
lines.push(`- ${f.content}`);
|
|
92
|
+
}
|
|
93
|
+
return lines.join('\n');
|
|
94
|
+
}
|
|
48
95
|
invalidate() {
|
|
49
96
|
this.cache.clear();
|
|
50
97
|
}
|
|
51
|
-
/** Get cache entry count for debugging */
|
|
52
98
|
cacheSize() {
|
|
53
99
|
return this.cache.size;
|
|
54
100
|
}
|
package/dist/resources.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"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"}
|
package/dist/retriever.js
CHANGED
|
@@ -360,16 +360,23 @@ export class FactRetriever {
|
|
|
360
360
|
const parts = query.split(/\s+/).filter(w => w.length > 0);
|
|
361
361
|
const ftsParts = [];
|
|
362
362
|
for (const word of parts) {
|
|
363
|
-
|
|
364
|
-
// 对中文部分追加 bigram
|
|
365
|
-
const cnChars = word.match(/[\u4e00-\u9fff]+/g);
|
|
363
|
+
const cnChars = word.match(/[一-鿿]+/g);
|
|
366
364
|
if (cnChars) {
|
|
365
|
+
// 中文部分:trigram tokenizer 需要至少 3 字符
|
|
367
366
|
for (const seg of cnChars) {
|
|
368
|
-
|
|
369
|
-
ftsParts.push(seg
|
|
367
|
+
if (seg.length >= 3)
|
|
368
|
+
ftsParts.push(seg);
|
|
369
|
+
// 提取 trigram(3 字符子串)
|
|
370
|
+
for (let i = 0; i <= seg.length - 3; i++) {
|
|
371
|
+
ftsParts.push(seg.slice(i, i + 3));
|
|
370
372
|
}
|
|
371
373
|
}
|
|
372
374
|
}
|
|
375
|
+
else {
|
|
376
|
+
// 非中文部分:用引号包裹(短语匹配),至少 1 字符
|
|
377
|
+
if (word.length >= 1)
|
|
378
|
+
ftsParts.push(`"${word}"`);
|
|
379
|
+
}
|
|
373
380
|
}
|
|
374
381
|
const ftsQuery = ftsParts.join(' OR ');
|
|
375
382
|
if (!ftsQuery)
|