@synth-coder/memhub 0.2.2 → 0.2.3
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/.eslintrc.cjs +45 -45
- package/.factory/commands/opsx-apply.md +150 -0
- package/.factory/commands/opsx-archive.md +155 -0
- package/.factory/commands/opsx-explore.md +171 -0
- package/.factory/commands/opsx-propose.md +104 -0
- package/.factory/skills/openspec-apply-change/SKILL.md +156 -0
- package/.factory/skills/openspec-archive-change/SKILL.md +114 -0
- package/.factory/skills/openspec-explore/SKILL.md +288 -0
- package/.factory/skills/openspec-propose/SKILL.md +110 -0
- package/.github/workflows/ci.yml +74 -74
- package/.iflow/commands/opsx-apply.md +152 -152
- package/.iflow/commands/opsx-archive.md +157 -157
- package/.iflow/commands/opsx-explore.md +173 -173
- package/.iflow/commands/opsx-propose.md +106 -106
- package/.iflow/skills/openspec-apply-change/SKILL.md +156 -156
- package/.iflow/skills/openspec-archive-change/SKILL.md +114 -114
- package/.iflow/skills/openspec-explore/SKILL.md +288 -288
- package/.iflow/skills/openspec-propose/SKILL.md +110 -110
- package/.prettierrc +11 -11
- package/AGENTS.md +169 -26
- package/README.md +195 -195
- package/README.zh-CN.md +193 -193
- package/dist/src/contracts/mcp.js +34 -34
- package/dist/src/server/mcp-server.d.ts +8 -0
- package/dist/src/server/mcp-server.d.ts.map +1 -1
- package/dist/src/server/mcp-server.js +23 -2
- package/dist/src/server/mcp-server.js.map +1 -1
- package/dist/src/services/memory-service.d.ts +1 -0
- package/dist/src/services/memory-service.d.ts.map +1 -1
- package/dist/src/services/memory-service.js +125 -82
- package/dist/src/services/memory-service.js.map +1 -1
- package/docs/architecture-diagrams.md +368 -0
- package/docs/architecture.md +381 -349
- package/docs/contracts.md +190 -119
- package/docs/prompt-template.md +33 -79
- package/docs/proposals/mcp-typescript-sdk-refactor.md +568 -568
- package/docs/proposals/proposal-close-gates.md +58 -58
- package/docs/tool-calling-policy.md +101 -107
- package/docs/vector-search.md +306 -0
- package/package.json +59 -58
- package/src/contracts/index.ts +12 -12
- package/src/contracts/mcp.ts +222 -222
- package/src/contracts/schemas.ts +307 -307
- package/src/contracts/types.ts +410 -410
- package/src/index.ts +8 -8
- package/src/server/index.ts +5 -5
- package/src/server/mcp-server.ts +185 -161
- package/src/services/embedding-service.ts +114 -114
- package/src/services/index.ts +5 -5
- package/src/services/memory-service.ts +663 -621
- package/src/storage/frontmatter-parser.ts +243 -243
- package/src/storage/index.ts +6 -6
- package/src/storage/markdown-storage.ts +236 -236
- package/src/storage/vector-index.ts +160 -160
- package/src/utils/index.ts +5 -5
- package/src/utils/slugify.ts +63 -63
- package/test/contracts/schemas.test.ts +313 -313
- package/test/contracts/types.test.ts +21 -21
- package/test/frontmatter-parser-more.test.ts +94 -94
- package/test/server/mcp-server.test.ts +210 -169
- package/test/services/memory-service-edge.test.ts +248 -248
- package/test/services/memory-service.test.ts +278 -278
- package/test/storage/frontmatter-parser.test.ts +222 -222
- package/test/storage/markdown-storage.test.ts +216 -216
- package/test/storage/storage-edge.test.ts +238 -238
- package/test/storage/vector-index.test.ts +153 -153
- package/test/utils/slugify-edge.test.ts +94 -94
- package/test/utils/slugify.test.ts +68 -68
- package/tsconfig.json +25 -25
- package/tsconfig.test.json +8 -8
- package/vitest.config.ts +29 -29
package/docs/contracts.md
CHANGED
|
@@ -1,119 +1,190 @@
|
|
|
1
|
-
# MemHub 契约文档(
|
|
2
|
-
|
|
3
|
-
当前对外 MCP
|
|
4
|
-
|
|
5
|
-
1. `memory_load
|
|
6
|
-
2. `memory_update
|
|
7
|
-
|
|
8
|
-
目标是形成稳定闭环:**先读 STM,再回写 STM**。
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
1
|
+
# MemHub 契约文档(v0.2.0)
|
|
2
|
+
|
|
3
|
+
当前对外 MCP 工具采用简化的 2-tool 接口:
|
|
4
|
+
|
|
5
|
+
1. `memory_load`(首轮):统一记忆加载接口
|
|
6
|
+
2. `memory_update`(末轮):统一记忆回写接口
|
|
7
|
+
|
|
8
|
+
目标是形成稳定闭环:**先读 STM,再回写 STM**。
|
|
9
|
+
|
|
10
|
+
## 核心特性
|
|
11
|
+
|
|
12
|
+
- **向量语义搜索**: 支持基于 query 的语义相似度搜索
|
|
13
|
+
- **元数据过滤**: 支持按 tags、category、date 过滤
|
|
14
|
+
- **混合搜索**: 可组合向量搜索和元数据过滤
|
|
15
|
+
- **并发安全**: 按 session_uuid 分目录存储,支持多 CLI 并发
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 1) memory_load
|
|
20
|
+
|
|
21
|
+
用于用户输入后第一轮主动加载短期记忆。支持向量语义搜索和元数据过滤。
|
|
22
|
+
|
|
23
|
+
### 输入
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
interface MemoryLoadInput {
|
|
27
|
+
id?: string; // 指定单条记忆 ID(优先级最高)
|
|
28
|
+
query?: string; // 语义搜索查询(启用向量搜索)
|
|
29
|
+
category?: string; // 分类过滤
|
|
30
|
+
tags?: string[]; // 标签过滤
|
|
31
|
+
limit?: number; // 返回数量限制,默认 20
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 行为说明
|
|
36
|
+
|
|
37
|
+
1. **向量搜索** (当提供 `query` 时):
|
|
38
|
+
- 使用 ONNX 模型将 query 转换为 384 维向量
|
|
39
|
+
- 在 LanceDB 中搜索最相似的向量
|
|
40
|
+
- 返回按相似度排序的结果
|
|
41
|
+
|
|
42
|
+
2. **元数据过滤** (当提供 `tags`、`category`、`date` 时):
|
|
43
|
+
- 在文件系统中扫描匹配的 Markdown 文件
|
|
44
|
+
- 解析 YAML Front Matter 进行过滤
|
|
45
|
+
- 支持多条件组合
|
|
46
|
+
|
|
47
|
+
3. **混合模式**:
|
|
48
|
+
- 先进行向量搜索获取候选集
|
|
49
|
+
- 再按元数据条件过滤
|
|
50
|
+
- 结合相似度得分和匹配度排序
|
|
51
|
+
|
|
52
|
+
4. **降级处理**:
|
|
53
|
+
- 向量搜索失败时自动降级为文本搜索
|
|
54
|
+
- 保证基本功能可用
|
|
55
|
+
|
|
56
|
+
### 输出
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
interface MemoryLoadOutput {
|
|
60
|
+
items: Memory[];
|
|
61
|
+
total: number;
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 2) memory_update
|
|
68
|
+
|
|
69
|
+
用于本轮结束前主动回写记忆。自动维护 Markdown 文件和向量索引。
|
|
70
|
+
|
|
71
|
+
### 输入
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
type EntryType = 'preference' | 'decision' | 'context' | 'fact';
|
|
75
|
+
|
|
76
|
+
interface MemoryUpdateInput {
|
|
77
|
+
id?: string; // 有则更新;无则创建新记录
|
|
78
|
+
sessionId?: string; // 无则服务端自动生成并返回
|
|
79
|
+
mode?: 'append' | 'upsert'; // 默认 append
|
|
80
|
+
entryType?: EntryType; // 记忆类型
|
|
81
|
+
title?: string; // 标题(Markdown H1)
|
|
82
|
+
content: string; // 内容(必填,Markdown 格式)
|
|
83
|
+
tags?: string[]; // 标签数组
|
|
84
|
+
category?: string; // 分类
|
|
85
|
+
importance?: number; // 重要性 1-5,默认 3
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 行为说明
|
|
90
|
+
|
|
91
|
+
1. **Markdown 写入** (同步):
|
|
92
|
+
- 生成或更新 Markdown 文件
|
|
93
|
+
- 路径格式: `YYYY-MM-DD/session_uuid/timestamp-title-slug.md`
|
|
94
|
+
- 写入 YAML Front Matter 和 Markdown 正文
|
|
95
|
+
|
|
96
|
+
2. **向量索引更新** (异步):
|
|
97
|
+
- 使用 Embedding 服务生成 384 维向量
|
|
98
|
+
- 在 LanceDB 中 upsert 向量记录
|
|
99
|
+
- 包含元数据字段用于过滤
|
|
100
|
+
|
|
101
|
+
3. **并发安全**:
|
|
102
|
+
- 按 `session_uuid` 分目录,避免多 CLI 冲突
|
|
103
|
+
- 文件名包含时间戳,保证唯一性
|
|
104
|
+
|
|
105
|
+
4. **容错处理**:
|
|
106
|
+
- 向量索引失败不影响 Markdown 写入
|
|
107
|
+
- 记录错误日志,不中断主流程
|
|
108
|
+
|
|
109
|
+
### 输出
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
interface MemoryUpdateOutput {
|
|
113
|
+
id: string;
|
|
114
|
+
sessionId: string;
|
|
115
|
+
filePath: string;
|
|
116
|
+
created: boolean;
|
|
117
|
+
updated: boolean;
|
|
118
|
+
memory: Memory;
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Memory 数据模型
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
type EntryType = 'preference' | 'decision' | 'context' | 'fact';
|
|
128
|
+
|
|
129
|
+
interface Memory {
|
|
130
|
+
id: string; // UUID v4
|
|
131
|
+
createdAt: string; // ISO 8601
|
|
132
|
+
updatedAt: string; // ISO 8601
|
|
133
|
+
sessionId?: string; // 会话 UUID
|
|
134
|
+
entryType?: EntryType; // 记忆类型
|
|
135
|
+
tags: string[]; // 标签数组
|
|
136
|
+
category: string; // 分类
|
|
137
|
+
importance: number; // 1-5
|
|
138
|
+
title: string; // Markdown H1 标题
|
|
139
|
+
content: string; // Markdown 正文
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### EntryType 说明
|
|
144
|
+
|
|
145
|
+
- **preference**: 用户偏好和习惯
|
|
146
|
+
- **decision**: 技术决策及其理由
|
|
147
|
+
- **context**: 项目和环境信息
|
|
148
|
+
- **fact**: 客观知识和事实
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 存储路径契约(并发安全)
|
|
153
|
+
|
|
154
|
+
为避免多个 CLI 同日写入冲突,采用分层目录:
|
|
155
|
+
|
|
156
|
+
```text
|
|
157
|
+
{storageRoot}/YYYY-MM-DD/{session_uuid}/{timestamp}-{slug}.md
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
例如:
|
|
161
|
+
|
|
162
|
+
```text
|
|
163
|
+
memories/2026-03-03/550e8400-e29b-41d4-a716-446655440111/2026-03-03T16-40-12-123Z-task-summary.md
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 向量索引存储
|
|
167
|
+
|
|
168
|
+
向量数据存储在独立的 LanceDB 目录中:
|
|
169
|
+
|
|
170
|
+
```text
|
|
171
|
+
{storageRoot}/.lancedb/
|
|
172
|
+
├── versions/
|
|
173
|
+
├── manifest.json
|
|
174
|
+
└── ...
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**重要特性**:
|
|
178
|
+
|
|
179
|
+
- Markdown 文件是唯一数据源
|
|
180
|
+
- 向量索引可随时从 Markdown 重建
|
|
181
|
+
- 删除 `.lancedb/` 目录不影响数据完整性
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## 调用策略契约(强建议)
|
|
186
|
+
|
|
187
|
+
- 用户输入后第一轮:调用 `memory_load`
|
|
188
|
+
- 最终输出前最后一轮:调用 `memory_update`
|
|
189
|
+
|
|
190
|
+
详细策略见:`docs/tool-calling-policy.md`
|
package/docs/prompt-template.md
CHANGED
|
@@ -1,79 +1,33 @@
|
|
|
1
|
-
# Prompt Template for Coding Agents (MemHub
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
###
|
|
23
|
-
|
|
24
|
-
Call
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
If task is date-scoped, add `date: "YYYY-MM-DD"`.
|
|
35
|
-
If task is keyword-driven, add `query`.
|
|
36
|
-
|
|
37
|
-
### On final round (`memory_update`)
|
|
38
|
-
|
|
39
|
-
Write only high-value context likely reused in next 3 turns:
|
|
40
|
-
|
|
41
|
-
- decisions
|
|
42
|
-
- preference changes
|
|
43
|
-
- constraints
|
|
44
|
-
- task state changes
|
|
45
|
-
- reusable conclusions
|
|
46
|
-
|
|
47
|
-
Example:
|
|
48
|
-
|
|
49
|
-
```json
|
|
50
|
-
{
|
|
51
|
-
"sessionId": "<session-uuid-if-known>",
|
|
52
|
-
"mode": "append",
|
|
53
|
-
"entryType": "decision",
|
|
54
|
-
"title": "Storage architecture decision",
|
|
55
|
-
"content": "Use date/session_uuid nested markdown storage to avoid multi-CLI collision.",
|
|
56
|
-
"tags": ["architecture", "storage", "stm"],
|
|
57
|
-
"category": "engineering",
|
|
58
|
-
"importance": 4
|
|
59
|
-
}
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## Minimal execution checklist
|
|
65
|
-
|
|
66
|
-
- [ ] First tool call is `memory_load`
|
|
67
|
-
- [ ] Final tool call is `memory_update`
|
|
68
|
-
- [ ] `memory_update` content is concise and reusable
|
|
69
|
-
- [ ] No sensitive secrets in memory payload
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## Failure fallback
|
|
74
|
-
|
|
75
|
-
If tool call fails:
|
|
76
|
-
|
|
77
|
-
1. continue task execution
|
|
78
|
-
2. mention memory tool failure briefly in internal reasoning/logs
|
|
79
|
-
3. still provide final user answer
|
|
1
|
+
# Prompt Template for Coding Agents (MemHub)
|
|
2
|
+
|
|
3
|
+
## Why Memory Matters
|
|
4
|
+
|
|
5
|
+
You have access to persistent memory across conversations. Use it wisely:
|
|
6
|
+
|
|
7
|
+
- **Remember preferences** — Learn what the user likes and avoid repeating mistakes
|
|
8
|
+
- **Recall decisions** — Build on past reasoning instead of starting from scratch
|
|
9
|
+
- **Store context** — Project knowledge that survives session boundaries
|
|
10
|
+
|
|
11
|
+
## When to Use
|
|
12
|
+
|
|
13
|
+
### `memory_load`
|
|
14
|
+
|
|
15
|
+
Call when you need context from past conversations:
|
|
16
|
+
- User references something from before
|
|
17
|
+
- You're unsure about user preferences
|
|
18
|
+
- A decision needs historical context
|
|
19
|
+
|
|
20
|
+
Don't call for simple, self-contained tasks.
|
|
21
|
+
|
|
22
|
+
### `memory_update`
|
|
23
|
+
|
|
24
|
+
Call when you discover something worth remembering:
|
|
25
|
+
- User expresses a preference
|
|
26
|
+
- You made a significant decision with reasoning
|
|
27
|
+
- Project context changed
|
|
28
|
+
|
|
29
|
+
Don't call for temporary or one-time information.
|
|
30
|
+
|
|
31
|
+
## Principle
|
|
32
|
+
|
|
33
|
+
Memory should feel natural — triggered by context, not by schedule. When in doubt, ask: "Would future me benefit from knowing this?"
|