stable-harness 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +10 -0
  2. package/docs/0.1.0-p0-runtime-control-plane-plan.zh.md +171 -0
  3. package/docs/0.1.0-retry-policy.zh.md +87 -0
  4. package/docs/0.1.0-stable-runtime-development-roadmap.zh.md +393 -0
  5. package/docs/0.1.0-tool-guard-benchmark.zh.md +42 -0
  6. package/docs/adapter-contract.md +199 -0
  7. package/docs/architecture/backend-comparison.md +41 -0
  8. package/docs/architecture/runtime-events.md +263 -0
  9. package/docs/architecture/runtime-events.zh.md +248 -0
  10. package/docs/architecture/system-architecture.zh.md +435 -0
  11. package/docs/compatibility-matrix.md +139 -0
  12. package/docs/engineering-rules.md +111 -0
  13. package/docs/evaluation/0.1.0-bfcl-targeted-model-matrix.zh.md +1632 -0
  14. package/docs/evaluation/0.1.0-bfcl-targeted-review-matrix.zh.md +1952 -0
  15. package/docs/evaluation/0.1.0-bfcl-tool-guard.zh.md +1427 -0
  16. package/docs/granite-tool-calling-comparison.zh.md +206 -0
  17. package/docs/guides/getting-started.md +126 -0
  18. package/docs/guides/index.md +40 -0
  19. package/docs/guides/integration-guide.md +126 -0
  20. package/docs/guides/operator-runbook.md +153 -0
  21. package/docs/guides/workspace-authoring.md +212 -0
  22. package/docs/implementation-blueprint.md +233 -0
  23. package/docs/memory/0.1.0-memory-design.zh.md +719 -0
  24. package/docs/memory/0.1.0-step-09-deepagents-native-memory.zh.md +146 -0
  25. package/docs/memory/0.1.0-step-09-langmem-shaped-provider.zh.md +169 -0
  26. package/docs/memory/0.1.0-step-09-memory-adapter-projection.zh.md +123 -0
  27. package/docs/memory/0.1.0-step-09-memory-contract.zh.md +169 -0
  28. package/docs/memory/0.1.0-step-09-memory-governance-approval.zh.md +143 -0
  29. package/docs/memory/0.1.0-step-09-memory-lifecycle-hooks.zh.md +150 -0
  30. package/docs/memory/0.1.0-step-09-memory-maintenance-boundary.zh.md +118 -0
  31. package/docs/memory/0.1.0-step-09-memory-persistence-boundary.zh.md +118 -0
  32. package/docs/product/adoption-playbook.md +145 -0
  33. package/docs/product/market-positioning.md +137 -0
  34. package/docs/product-boundary.md +258 -0
  35. package/docs/protocols/http-runtime.md +37 -0
  36. package/docs/protocols/langgraph-compatible.md +107 -0
  37. package/docs/protocols/openai-compatible.md +121 -0
  38. package/docs/tooling/0.1.0-bettercall-tool-quality.zh.md +231 -0
  39. package/package.json +3 -1
@@ -0,0 +1,719 @@
1
+ # 0.1.0 Memory 设计说明
2
+
3
+ ## 目标
4
+
5
+ `stable-harness` 的 memory 设计目标是让 agent workspace 拥有可控、可插拔、可长期测试的长期记忆能力,同时不重写 DeepAgents 的执行语义。
6
+
7
+ 当前设计同时支持两类 memory:
8
+
9
+ 1. `LangMem`:`stable-harness` 主路径。由 runtime 在 run 前召回、run 后抽取,交给 LangMem-style service 持久化到 SQLite 和 vector index。
10
+ 2. `deepagentsMem`:DeepAgents 原生 memory passthrough。通过 DeepAgents 的 `memory` 参数暴露 `/memories/<id>.md`,由 DeepAgents 自己读取或写入 memory 文件。
11
+
12
+ 这两类 memory 使用同一组 workspace Memory YAML 定义,但通过四个 boolean flag 独立控制读写。
13
+
14
+ ## 非目标
15
+
16
+ - 不把 memory 做成领域路由规则。
17
+ - 不在 core runtime 中 hardcode EasyNet、股票、Kubernetes、release 等 downstream 逻辑。
18
+ - 不把 vector store 当成唯一事实源。
19
+ - 不让 DeepAgents native memory 和 LangMem structured memory 互相依赖。
20
+ - 不依赖 system prompt 作为唯一治理手段。
21
+ - 不在 adapter 中重写 DeepAgents 的 planning、delegation、filesystem、memory 执行语义。
22
+
23
+ ## 核心概念
24
+
25
+ | 概念 | 说明 |
26
+ |---|---|
27
+ | `Memory` YAML | 声明一个 memory profile,例如 `workspace`、`user`、`agent`、`session`。 |
28
+ | `profile` | 决定 namespace 和抽取边界。常见值为 `workspace`、`user`。 |
29
+ | `LangMem` | 后台抽取、去重、持久化、vector recall 的主 memory path。 |
30
+ | `deepagentsMem` | DeepAgents 原生 file memory passthrough。 |
31
+ | `memory_records` | SQLite 中的结构化 memory 事实表。 |
32
+ | `memory_vectors` | SQLite 中的 embedding JSON 表,用于 vector search。 |
33
+ | `metadata.memoryWrite=false` | 单次 request 只 recall,不写回 memory。 |
34
+
35
+ ## 四个 Boolean Flag
36
+
37
+ runtime 配置面保持简单,只暴露四个 boolean:
38
+
39
+ ```yaml
40
+ memory:
41
+ deepagentsMem:
42
+ read: true
43
+ write: true
44
+ LangMem:
45
+ read: true
46
+ write: true
47
+ maintenance:
48
+ enabled: true
49
+ schedule: periodic
50
+ prompt: durable preferences, workspace facts, reusable procedures, prior corrections, stale duplicates, and contradicted memories
51
+ ```
52
+
53
+ | Flag | 默认建议 | 作用 |
54
+ |---|---:|---|
55
+ | `memory.deepagentsMem.read` | `true` | 是否把 enabled Memory YAML 映射成 DeepAgents 原生 `memory: ["/memories/<id>.md"]`。 |
56
+ | `memory.deepagentsMem.write` | `true` | 是否允许 DeepAgents 写 `/memories/**`。为 `false` 时 adapter 增加 write deny permission。 |
57
+ | `memory.LangMem.read` | `true` | 是否在 run 前从 LangMem provider 搜索并召回相关 memory records。 |
58
+ | `memory.LangMem.write` | `true` | 是否在 run 后把 `User input + Agent output` 发给 LangMem provider 抽取并写入。 |
59
+
60
+ 单个 memory profile 的开关仍然在 Memory YAML 内:
61
+
62
+ ```yaml
63
+ apiVersion: stable-harness.dev/v1
64
+ kind: Memory
65
+ metadata:
66
+ name: workspace
67
+ spec:
68
+ provider: langmem
69
+ profile: workspace
70
+ enabled: true
71
+ ```
72
+
73
+ ## 推荐默认值
74
+
75
+ 生产默认推荐:
76
+
77
+ ```yaml
78
+ memory:
79
+ deepagentsMem:
80
+ read: true
81
+ write: true
82
+ LangMem:
83
+ read: true
84
+ write: true
85
+ maintenance:
86
+ enabled: true
87
+ schedule: periodic
88
+ prompt: durable preferences, workspace facts, reusable procedures, prior corrections, stale duplicates, and contradicted memories
89
+ ```
90
+
91
+ 含义:
92
+
93
+ - 默认双写:DeepAgents 原生 file memory 和 LangMem structured memory 都写入。
94
+ - 默认双读:DeepAgents 可以读取 native memory files,LangMem 也会在 run 前做 top-k recall。
95
+ - 两个 memory 的后台整理使用同一个 maintenance prompt 和 schedule,但 target 独立运行,互不依赖。
96
+ - 需要关闭某一路时,只关对应 `read` 或 `write` boolean。
97
+
98
+ ## Memory YAML
99
+
100
+ Memory YAML 是可扩展定义,类似 resources/tools/skills 的 runtime inventory。
101
+
102
+ 示例:
103
+
104
+ ```yaml
105
+ apiVersion: stable-harness.dev/v1
106
+ kind: Memory
107
+ metadata:
108
+ name: workspace
109
+ description: Workspace memory for durable project facts and reusable operating evidence.
110
+ spec:
111
+ provider: langmem
112
+ profile: workspace
113
+ enabled: true
114
+ mode: background
115
+ prompts:
116
+ semantic: |-
117
+ Remember durable workspace facts, repository structure, runtime defaults,
118
+ validation commands, model names, URLs, and sentinel tokens.
119
+ episodic: |-
120
+ Remember important workspace events, validation runs, incidents, migrations,
121
+ release checks, and fixes that are likely to matter later.
122
+ procedural: |-
123
+ Remember reusable operating procedures, recovery steps, release gates,
124
+ full-matrix test commands, and project-specific engineering constraints.
125
+ ```
126
+
127
+ 每个 Memory profile 都可以有自己的 prompt,但输入上下文来自同一次 run:
128
+
129
+ ```text
130
+ User input
131
+ Agent output
132
+ runtime metadata
133
+ profile prompts
134
+ ```
135
+
136
+ 这样可以让 `workspace` 和 `user` 使用同一段上下文,但分别抽取不同的 memory。
137
+
138
+ ## LangMem 主路径
139
+
140
+ LangMem 主路径由 `stable-harness` 控制 lifecycle。
141
+
142
+ ### 写入来源
143
+
144
+ `memory_records.content` 不是 client 直接写入,也不是 DeepAgents 自动写入。
145
+
146
+ 写入流程是:
147
+
148
+ 1. client 或 agent run 产生 `User input` 和 `Agent output`。
149
+ 2. `stable-harness` memory layer 把 run context、profile、prompts、namespace 发给 provider。
150
+ 3. LangMem service 调 LLM 抽取 durable memory。
151
+ 4. SQLite store 做过滤、合并、去重、embedding。
152
+ 5. 最终写入 `memory_records` 和 `memory_vectors`。
153
+
154
+ ### LangMem 写入 Sequence
155
+
156
+ ```mermaid
157
+ sequenceDiagram
158
+ participant Client as Client
159
+ participant Runtime as stable-harness Runtime
160
+ participant Adapter as Backend Adapter
161
+ participant Agent as DeepAgents
162
+ participant MemLayer as Memory Plugin Layer
163
+ participant Service as LangMem Service
164
+ participant LLM as Memory Extraction LLM
165
+ participant Store as SQLite + Vector Store
166
+
167
+ Client->>Runtime: request(input, metadata)
168
+ Runtime->>Adapter: run(adapterContext)
169
+ Adapter->>Agent: invoke(user message)
170
+ Agent-->>Adapter: agent output
171
+ Adapter-->>Runtime: RuntimeOutput
172
+ Runtime->>MemLayer: write-after-run hook
173
+ MemLayer->>Service: propose(namespace, User input + Agent output, prompts)
174
+ Service->>LLM: extract semantic/episodic/procedural memories
175
+ LLM-->>Service: memory candidates
176
+ Service->>Store: upsert + dedupe + embed
177
+ Store-->>Service: MemoryRecord
178
+ Service-->>MemLayer: candidates accepted
179
+ MemLayer-->>Runtime: runtime.memory.plugin.completed event
180
+ Runtime-->>Client: response
181
+ ```
182
+
183
+ ### LangMem 召回 Sequence
184
+
185
+ ```mermaid
186
+ sequenceDiagram
187
+ participant Client as Client
188
+ participant Runtime as stable-harness Runtime
189
+ participant MemLayer as Memory Plugin Layer
190
+ participant Service as LangMem Service
191
+ participant Store as SQLite + Vector Store
192
+ participant Adapter as DeepAgents Adapter
193
+ participant Agent as DeepAgents
194
+
195
+ Client->>Runtime: request(input)
196
+ Runtime->>MemLayer: read-before-run hook
197
+ MemLayer->>Service: search(namespace, input)
198
+ Service->>Store: embed query + vector search
199
+ Store-->>Service: relevant MemoryRecords
200
+ Service-->>MemLayer: records
201
+ MemLayer-->>Runtime: pluginMemories context
202
+ Runtime->>Adapter: run(context includes pluginMemories)
203
+ Adapter->>Agent: "Relevant long-term memory" + User request
204
+ Agent-->>Adapter: output using recalled facts
205
+ Adapter-->>Runtime: RuntimeOutput
206
+ Runtime-->>Client: response
207
+ ```
208
+
209
+ ## DeepAgents 原生 Memory
210
+
211
+ DeepAgents 原生 memory 是上游框架自己的 memory primitive。
212
+
213
+ 当 `memory.deepagentsMem.read=true` 且 agent 没有显式配置 DeepAgents memory 时,adapter 会把 enabled Memory YAML 映射成:
214
+
215
+ ```text
216
+ memory:
217
+ - /memories/workspace.md
218
+ - /memories/user.md
219
+ ```
220
+
221
+ 这表示 DeepAgents 可以读取这些 memory file。它和 LangMem SQLite/vector 不是同一个存储系统。
222
+
223
+ ### DeepAgents 原生 Read Sequence
224
+
225
+ ```mermaid
226
+ sequenceDiagram
227
+ participant Runtime as stable-harness Runtime
228
+ participant Adapter as DeepAgents Adapter
229
+ participant DA as DeepAgents
230
+ participant FS as DeepAgents Memory Backend
231
+
232
+ Runtime->>Adapter: run(adapterContext)
233
+ Adapter->>Adapter: read memory.deepagentsMem.read
234
+ alt deepagentsMem.read is true
235
+ Adapter->>DA: createDeepAgent(memory=["/memories/workspace.md"])
236
+ DA->>FS: read /memories/workspace.md
237
+ FS-->>DA: markdown memory content
238
+ else deepagentsMem.read is false
239
+ Adapter->>DA: createDeepAgent(memory omitted)
240
+ end
241
+ DA-->>Adapter: output
242
+ ```
243
+
244
+ ### DeepAgents 原生 Write Sequence
245
+
246
+ ```mermaid
247
+ sequenceDiagram
248
+ participant DA as DeepAgents
249
+ participant Adapter as DeepAgents Adapter
250
+ participant Policy as Permissions / Middleware
251
+ participant FS as DeepAgents Memory Backend
252
+
253
+ DA->>Adapter: edit_file(/memories/workspace.md)
254
+ Adapter->>Policy: check memory.deepagentsMem.write
255
+ alt deepagentsMem.write is true
256
+ Policy-->>Adapter: allow
257
+ Adapter->>FS: write memory file
258
+ FS-->>DA: write ok
259
+ else deepagentsMem.write is false
260
+ Policy-->>Adapter: deny write /memories/**
261
+ Adapter-->>DA: tool error
262
+ end
263
+ ```
264
+
265
+ ## Prompt 控制和 Governance 控制
266
+
267
+ DeepAgents native memory 有两层控制:
268
+
269
+ | 控制层 | 类型 | 能控制什么 | 局限 |
270
+ |---|---|---|---|
271
+ | system prompt | 软控制 | 告诉 agent 什么时候写、写什么格式、不要写什么 | 模型可能忘记、误解或被 prompt injection 影响 |
272
+ | permission / middleware | 硬控制 | 是否允许写 `/memories/**`、是否需要 approval、是否允许某个 path | 只能控制能不能写,不负责判断内容是否高质量 |
273
+
274
+ LangMem 主路径的控制点不同:
275
+
276
+ | 控制层 | 类型 | 能控制什么 |
277
+ |---|---|---|
278
+ | Memory YAML prompts | 抽取边界 | semantic/episodic/procedural 各存什么 |
279
+ | profile namespace | 隔离边界 | workspace/user/agent/session 分开 |
280
+ | service filtering | 内容过滤 | 过滤低价值 run instruction,例如 “Reply exactly” |
281
+ | store dedupe | 记录治理 | canonical token、相似度、跨 kind 合并 |
282
+ | runtime flag | 生命周期 | 读写开关、单次 request read-only |
283
+
284
+ ## Side-by-side 对比
285
+
286
+ | 维度 | `deepagentsMem` | `LangMem` |
287
+ |---|---|---|
288
+ | 归属 | DeepAgents 上游能力 | stable-harness runtime capability |
289
+ | 存储形态 | memory files / markdown | SQLite `memory_records` + `memory_vectors` |
290
+ | 写入者 | agent 通过 file edit 写 | LangMem service 从 run context 抽取 |
291
+ | 读入方式 | DeepAgents 读取 `/memories/*.md` | runtime 先 vector search,再注入相关 records |
292
+ | 是否动态学习 | 是,agent 自己决定是否写文件 | 是,runtime run 后后台抽取 |
293
+ | 内容质量控制 | prompt + permissions | prompts + filter + dedupe + namespace |
294
+ | 去重 | 需要 agent 自觉或额外 middleware | store 层合并 |
295
+ | 审计 | 文件 diff | record metadata + sourceRef + runtime events |
296
+ | 生产默认 | 开启读写 | 开启读写 |
297
+ | 适合用途 | 轻量 notebook、上游能力测试 | 生产长期记忆主路径 |
298
+
299
+ ## 四个 Flag 的行为矩阵
300
+
301
+ | `deepagentsMem.read` | `deepagentsMem.write` | `LangMem.read` | `LangMem.write` | 行为 |
302
+ |---:|---:|---:|---:|---|
303
+ | true | true | true | true | 推荐默认。DeepAgents native memory 和 LangMem 都读写;后台整理保持同 prompt、同 schedule、独立 target。 |
304
+ | false | false | true | true | LangMem-only 模式。DeepAgents 不读写 native memory;LangMem 负责召回和写入。 |
305
+ | true | false | true | true | 额外让 DeepAgents 读 memory files,但不允许写;LangMem 仍是主路径。 |
306
+ | false | false | true | false | 只读 LangMem,用于回归或只想使用已有 memory。 |
307
+ | false | false | false | true | 只写 LangMem,不召回;适合离线采集或影子写入测试。 |
308
+ | false | false | false | false | memory 完全关闭。 |
309
+
310
+ ## 单次 Request 只读
311
+
312
+ 如果某次请求只是测试 recall,不希望把这次回答再次写回 memory,可传:
313
+
314
+ ```json
315
+ {
316
+ "metadata": {
317
+ "memoryWrite": false
318
+ }
319
+ }
320
+ ```
321
+
322
+ Sequence:
323
+
324
+ ```mermaid
325
+ sequenceDiagram
326
+ participant Runtime as Runtime
327
+ participant Service as LangMem Service
328
+ participant Agent as Agent
329
+
330
+ Runtime->>Service: search(namespace, input)
331
+ Service-->>Runtime: recalled records
332
+ Runtime->>Agent: prompt with memory
333
+ Agent-->>Runtime: answer
334
+ alt metadata.memoryWrite is false
335
+ Runtime-->>Service: no propose call
336
+ else default
337
+ Runtime->>Service: propose(run context)
338
+ end
339
+ ```
340
+
341
+ ## 后台整理 Daemon
342
+
343
+ 后台整理是 `stable-harness` runtime capability,不属于 DeepAgents 执行语义。它只负责调度和审计,具体整理逻辑由各 memory target 自己实现。
344
+
345
+ 原则:
346
+
347
+ - `LangMem` 和 `deepagentsMem` 是两个独立 target。
348
+ - 两个 target 使用同一个 `memory.maintenance.prompt`。
349
+ - 两个 target 使用同一个 schedule。
350
+ - 一个 target 失败不阻塞另一个 target。
351
+ - LangMem target 调 provider `search -> consolidate`。
352
+ - DeepAgents target 通过独立 maintainer 处理 native memory file,不依赖 LangMem records。
353
+ - Skill Candidate Miner target 从长期稳定 memory pattern 中生成候选 Skill,但不直接启用。
354
+
355
+ Sequence:
356
+
357
+ ```mermaid
358
+ sequenceDiagram
359
+ participant Daemon as Memory Maintenance Daemon
360
+ participant LangMem as LangMem Target
361
+ participant DeepMem as DeepAgentsMem Target
362
+ participant Provider as LangMem Provider
363
+ participant Store as DeepAgents StoreBackend
364
+
365
+ Daemon->>Daemon: load shared schedule and prompt
366
+ par LangMem maintenance
367
+ Daemon->>LangMem: run(prompt)
368
+ LangMem->>Provider: search(namespace, prompt)
369
+ Provider-->>LangMem: records
370
+ LangMem->>Provider: consolidate(records)
371
+ Provider-->>LangMem: operations
372
+ and DeepAgents native maintenance
373
+ Daemon->>DeepMem: run(prompt)
374
+ DeepMem->>Store: read /memories/*.md
375
+ DeepMem->>Store: compact / dedupe / rewrite files
376
+ Store-->>DeepMem: saved
377
+ and Skill candidate mining
378
+ Daemon->>Daemon: scan stable repeated memory evidence
379
+ Daemon->>Daemon: upsert skill_candidates
380
+ Daemon->>Daemon: create skill_candidate approval
381
+ end
382
+ Daemon->>Daemon: emit maintenance events
383
+ ```
384
+
385
+ ## Skill Candidate
386
+
387
+ `SkillCandidate` 是 control-plane 对象,不是普通 memory record。它表示系统从长期稳定、可靠、可验证的 memory evidence 中发现了一个可能值得沉淀成 Skill 的流程。
388
+
389
+ 默认规则:
390
+
391
+ - 不写入 `memory_records`。
392
+ - 不自动写入 `resources/skills/**/SKILL.md`。
393
+ - 不自动启用。
394
+ - 只生成 `review_required` candidate。
395
+ - 同时创建 `skill_candidate` approval。
396
+
397
+ 推荐存储在 control-plane SQLite:
398
+
399
+ ```text
400
+ .stable-harness/control-plane/stable.sqlite
401
+ skill_candidates
402
+ skill_candidate_evidence
403
+ ```
404
+
405
+ 真实 E2E 使用:
406
+
407
+ ```text
408
+ npm run test:skill-mining:e2e
409
+ ```
410
+
411
+ 测试会启动真实 Python LangMem service,通过远端 `qwen3.5:4b` 在多个 session 中写入长期 memory evidence,再由 maintenance daemon 生成 `review_required` SkillCandidate。
412
+
413
+ ## Namespace 规则
414
+
415
+ namespace 由 `workspaceId`、profile、request metadata 决定:
416
+
417
+ | Profile | Namespace 形态 |
418
+ |---|---|
419
+ | `workspace` | `<workspaceId>:workspace:<memoryId>` |
420
+ | `user` | `<workspaceId>:user:<userId>:<memoryId>` |
421
+ | `agent` | `<workspaceId>:agent:<agentId>:<memoryId>` |
422
+ | `session` | `<workspaceId>:session:<sessionId>:<memoryId>` |
423
+
424
+ EasyNet 示例:
425
+
426
+ ```text
427
+ easynet:workspace:workspace
428
+ easynet:user:e2e-user:user
429
+ ```
430
+
431
+ ## 存储目录
432
+
433
+ 配置和生成数据分开。
434
+
435
+ `stable-harness`:
436
+
437
+ ```text
438
+ config/memory/ # Memory YAML
439
+ .stable-harness/memory/langmem/ # generated LangMem data
440
+ .stable-harness/memory/langmem/e2e/ # disposable E2E SQLite
441
+ ```
442
+
443
+ EasyNet:
444
+
445
+ ```text
446
+ config/memory/ # Memory YAML
447
+ .botbotgo/memory/langmem/ # generated LangMem data
448
+ .botbotgo/memory/langmem/e2e/ # disposable E2E SQLite
449
+ .botbotgo/runtime/ # runtime run records
450
+ .botbotgo/knowledge/ # existing native knowledge DBs
451
+ ```
452
+
453
+ 生成数据不提交到 git。
454
+
455
+ ## SQLite Schema
456
+
457
+ LangMem SQLite service 当前维护两张表:
458
+
459
+ ```text
460
+ memory_records
461
+ ├─ id
462
+ ├─ namespace
463
+ ├─ kind
464
+ ├─ scope
465
+ ├─ status
466
+ ├─ content
467
+ ├─ summary
468
+ ├─ confidence
469
+ ├─ tags_json
470
+ ├─ sensitivity
471
+ ├─ metadata_json
472
+ └─ created_at
473
+
474
+ memory_vectors
475
+ ├─ record_id
476
+ ├─ namespace
477
+ ├─ dimensions
478
+ └─ embedding_json
479
+ ```
480
+
481
+ `memory_records` 是事实源,`memory_vectors` 是召回索引。
482
+
483
+ ## 去重策略
484
+
485
+ 重复来源主要有两类:
486
+
487
+ 1. 读取 memory 的回答又被写回,形成派生 memory。
488
+ 2. LLM 对同一事实生成中英文、semantic/procedural/episodic 多种表述。
489
+
490
+ 当前处理:
491
+
492
+ - 支持 `metadata.memoryWrite=false`,只召回不写回。
493
+ - 过滤低价值内容,例如 `Reply exactly`、`memory stored`、`asked to remember`。
494
+ - 同 namespace 内跨 kind 查找相似 memory。
495
+ - 对 `npm run ...`、`EASYNET_*` 等 canonical token 做强匹配。
496
+ - 相似内容合并到已有 record,而不是新增行。
497
+
498
+ 去重 Sequence:
499
+
500
+ ```mermaid
501
+ sequenceDiagram
502
+ participant Service as LangMem Service
503
+ participant LLM as Extraction LLM
504
+ participant Store as SQLite Store
505
+ participant Vec as Vector Store
506
+
507
+ Service->>LLM: extract memories
508
+ LLM-->>Service: candidates
509
+ loop each candidate
510
+ Service->>Service: filter low-value run instructions
511
+ Service->>Store: find active records in namespace
512
+ Store-->>Service: existing records
513
+ Service->>Service: compare text similarity + canonical tokens
514
+ alt duplicate found
515
+ Service->>Store: merge into existing memory_record
516
+ Service->>Vec: replace embedding
517
+ else new fact
518
+ Service->>Store: insert memory_record
519
+ Service->>Vec: insert embedding
520
+ end
521
+ end
522
+ ```
523
+
524
+ ## 长期测试
525
+
526
+ 长期测试目标是验证多轮重复写入不会让 memory records 无限制增长,并确认后续 run 能使用已经生成的 memory。
527
+
528
+ `stable-harness`:
529
+
530
+ ```text
531
+ LANGMEM_E2E_ITERATIONS=3 npm run test:langmem:sqlite:e2e
532
+ ```
533
+
534
+ 期望:
535
+
536
+ ```text
537
+ memoryRecords: 1
538
+ secondOutput includes npm run check:rules
539
+ ```
540
+
541
+ EasyNet:
542
+
543
+ ```text
544
+ EASYNET_LANGMEM_E2E_ITERATIONS=3 npm run test:langmem:sqlite:e2e
545
+ ```
546
+
547
+ 期望:
548
+
549
+ ```text
550
+ workspaceRecords: 1
551
+ userRecords: 2
552
+ secondOutput includes npm run test:botbotgo:full
553
+ secondOutput includes EASYNET_USER_MEMORY_9137
554
+ ```
555
+
556
+ 长期测试 Sequence:
557
+
558
+ ```mermaid
559
+ sequenceDiagram
560
+ participant Test as E2E Script
561
+ participant Runtime as Runtime
562
+ participant Service as LangMem Service
563
+ participant Store as SQLite Store
564
+ participant Agent as Agent
565
+
566
+ Test->>Service: start with clean E2E SQLite
567
+ loop N iterations
568
+ Test->>Runtime: write request
569
+ Runtime->>Service: propose(run context)
570
+ Service->>Store: upsert/dedupe
571
+ Test->>Runtime: read request with memoryWrite=false
572
+ Runtime->>Service: search(query)
573
+ Service-->>Runtime: stable records
574
+ Runtime->>Agent: recalled memory
575
+ Agent-->>Runtime: exact remembered answer
576
+ end
577
+ Test->>Store: count records
578
+ Store-->>Test: bounded record count
579
+ ```
580
+
581
+ ## 配置示例
582
+
583
+ ### 推荐生产默认
584
+
585
+ ```yaml
586
+ memory:
587
+ enabled: true
588
+ deepagentsMem:
589
+ read: true
590
+ write: true
591
+ LangMem:
592
+ read: true
593
+ write: true
594
+ maintenance:
595
+ enabled: true
596
+ schedule: periodic
597
+ prompt: durable preferences, workspace facts, reusable procedures, prior corrections, stale duplicates, and contradicted memories
598
+ refs:
599
+ - workspace
600
+ - user
601
+ ```
602
+
603
+ ### LangMem-only 对比测试
604
+
605
+ ```yaml
606
+ memory:
607
+ enabled: true
608
+ deepagentsMem:
609
+ read: false
610
+ write: false
611
+ LangMem:
612
+ read: true
613
+ write: true
614
+ refs:
615
+ - workspace
616
+ - user
617
+ ```
618
+
619
+ ### DeepAgents native read-only 对比测试
620
+
621
+ ```yaml
622
+ memory:
623
+ enabled: true
624
+ deepagentsMem:
625
+ read: true
626
+ write: false
627
+ LangMem:
628
+ read: true
629
+ write: true
630
+ refs:
631
+ - workspace
632
+ - user
633
+ ```
634
+
635
+ ### 只读 LangMem
636
+
637
+ ```yaml
638
+ memory:
639
+ enabled: true
640
+ deepagentsMem:
641
+ read: false
642
+ write: false
643
+ LangMem:
644
+ read: true
645
+ write: false
646
+ refs:
647
+ - workspace
648
+ - user
649
+ ```
650
+
651
+ ## 端到端总览
652
+
653
+ ```mermaid
654
+ sequenceDiagram
655
+ participant User as User
656
+ participant Runtime as stable-harness Runtime
657
+ participant LangMem as LangMem Provider
658
+ participant SQLite as SQLite + Vector
659
+ participant Adapter as DeepAgents Adapter
660
+ participant DeepAgents as DeepAgents
661
+ participant Native as DeepAgents Native Memory
662
+
663
+ User->>Runtime: request(input, metadata)
664
+
665
+ alt LangMem.read is true
666
+ Runtime->>LangMem: search(namespace, input)
667
+ LangMem->>SQLite: vector search
668
+ SQLite-->>LangMem: MemoryRecords
669
+ LangMem-->>Runtime: recalled context
670
+ end
671
+
672
+ Runtime->>Adapter: run(pluginMemories)
673
+
674
+ alt deepagentsMem.read is true
675
+ Adapter->>DeepAgents: memory=["/memories/workspace.md", "/memories/user.md"]
676
+ DeepAgents->>Native: read memory files
677
+ Native-->>DeepAgents: markdown memory
678
+ else deepagentsMem.read is false
679
+ Adapter->>DeepAgents: no native memory paths
680
+ end
681
+
682
+ Adapter->>DeepAgents: user request + recalled LangMem context
683
+ DeepAgents-->>Adapter: output
684
+ Adapter-->>Runtime: RuntimeOutput
685
+
686
+ alt deepagentsMem.write is true
687
+ DeepAgents->>Native: may edit /memories/**
688
+ else deepagentsMem.write is false
689
+ Adapter-->>DeepAgents: deny writes to /memories/**
690
+ end
691
+
692
+ alt LangMem.write is true and memoryWrite is not false
693
+ Runtime->>LangMem: propose(User input + Agent output)
694
+ LangMem->>SQLite: upsert/dedupe/vectorize
695
+ else LangMem.write is false or memoryWrite=false
696
+ Runtime-->>LangMem: no write
697
+ end
698
+
699
+ Runtime-->>User: response
700
+ ```
701
+
702
+ ## 最终建议
703
+
704
+ 短期默认:
705
+
706
+ ```yaml
707
+ deepagentsMem.read: true
708
+ deepagentsMem.write: true
709
+ LangMem.read: true
710
+ LangMem.write: true
711
+ maintenance.enabled: true
712
+ ```
713
+
714
+ 长期评估:
715
+
716
+ - 默认双读双写,长期观察重复、污染、文件 diff、profile 边界。
717
+ - 两个 memory 的整理使用同一个 prompt 和 schedule,但 target 独立。
718
+ - 如果 DeepAgents native memory 污染明显,可只关闭 `deepagentsMem.write`。
719
+ - 如果 LangMem recall 成本过高,可只关闭 `LangMem.read`,保留 `LangMem.write` 做后台积累。