@hy-sde-org/dsh-memory-extraction 0.1.2-rc.1
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/LICENSE +21 -0
- package/README.i18n.yaml +6 -0
- package/README.md +148 -0
- package/README.zh.md +134 -0
- package/dist/control.d.ts +42 -0
- package/dist/control.d.ts.map +1 -0
- package/dist/control.js +125 -0
- package/dist/control.js.map +1 -0
- package/dist/engine.d.ts +78 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +411 -0
- package/dist/engine.js.map +1 -0
- package/dist/events.d.ts +19 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +76 -0
- package/dist/events.js.map +1 -0
- package/dist/evidence.d.ts +66 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +221 -0
- package/dist/evidence.js.map +1 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/memory-adapter.d.ts +44 -0
- package/dist/memory-adapter.d.ts.map +1 -0
- package/dist/memory-adapter.js +69 -0
- package/dist/memory-adapter.js.map +1 -0
- package/dist/proposal.d.ts +63 -0
- package/dist/proposal.d.ts.map +1 -0
- package/dist/proposal.js +309 -0
- package/dist/proposal.js.map +1 -0
- package/dist/runtime.d.ts +56 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +172 -0
- package/dist/runtime.js.map +1 -0
- package/dist/types.d.ts +196 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 hy-sde
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/memory/memory-extraction/README.md
|
|
5
|
+
README.md: 25234ba6ae648ede9e26988d72271e257596e5eb
|
|
6
|
+
README.zh.md: c7b48d15b06fe6381c66ad5bfd3824ba6e54a258
|
package/README.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Automatic long-term-memory extraction at compaction checkpoints: evidence projection, proposal/canonicalization pipeline, gated ctx.memory commit, and durable cursors/receipts/failure ledger (Maka port, slice No. 2)."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @hy-sde-org/dsh-memory-extraction
|
|
7
|
+
|
|
8
|
+
English | [中文](README.zh.md)
|
|
9
|
+
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
`dsh-memory-extraction` is the DSH port of Maka's automatic memory-extraction
|
|
13
|
+
trigger: after every `compaction/summary` event (a checkpoint boundary), a
|
|
14
|
+
bounded, fail-open pipeline projects the **user-authored** text of the
|
|
15
|
+
checkpointed range, proposes and canonicalizes durable facts with auxiliary
|
|
16
|
+
model calls, and commits admitted facts into the same project memory bank
|
|
17
|
+
`retain`/`learn` write. It is strictly **additive** to DSH's explicit memory
|
|
18
|
+
surface: the `retain`/`learn`/`memory_edit` tools stay the model-facing path
|
|
19
|
+
and the port intentionally reserves (does not port) Maka's
|
|
20
|
+
`memory_remember`/`memory_extract` verbs.
|
|
21
|
+
|
|
22
|
+
The package is a **host-plane** Cordis plugin (`inject: ['memory', 'llm']`,
|
|
23
|
+
publishes nothing): one process opens the `memory_extraction` control unit once
|
|
24
|
+
and observes every session's events through an unscoped `ctx.on('session/event')`
|
|
25
|
+
listener (the scope filter admits unscoped listeners globally). Runs are
|
|
26
|
+
per-session serialized and never block the compaction listener.
|
|
27
|
+
|
|
28
|
+
### Load-bearing rules (ported from Maka)
|
|
29
|
+
|
|
30
|
+
1. **Evidence is user-authored text only** — project `user/message` events whose
|
|
31
|
+
`source.kind === 'user'`; assistant text is interpretation-only; tool
|
|
32
|
+
calls/results, reasoning, and plugin checkpoints are opaque. Evidence is
|
|
33
|
+
bounded (12 000 chars JSON / 4 000 chars per record / 64 records) and
|
|
34
|
+
**fail-closed** on overflow.
|
|
35
|
+
2. **Admission is verified** — proposal → admission (verbatim quote check
|
|
36
|
+
against the bounded evidence + secret rejection) → canonicalization →
|
|
37
|
+
re-admission, at most **3 auxiliary model calls** per range with a 60 s
|
|
38
|
+
timeout; failures are contained (fail-open at the runtime boundary).
|
|
39
|
+
3. **The cursor only moves to a committed boundary** — empty ranges still
|
|
40
|
+
advance (a no-op receipt, no model call); a failed range becomes one pending
|
|
41
|
+
record retried by the next trigger and then discarded. Write order is
|
|
42
|
+
items → cursor → receipt, so a crash between cursor and receipt can never
|
|
43
|
+
double-process.
|
|
44
|
+
4. **Idempotency is deterministic** — operation id = `memory_` + sha256 of
|
|
45
|
+
`{sessionId, trigger, boundarySeq}`; receipts make replays no-ops and the
|
|
46
|
+
commit-side dedupe probe heals a crash between items and receipt.
|
|
47
|
+
5. **Subagents are excluded** — the gate re-checks after every model call and
|
|
48
|
+
rejects child sessions by default (`excludeSubagents: true`).
|
|
49
|
+
|
|
50
|
+
## Table of Contents
|
|
51
|
+
|
|
52
|
+
- [Use this package](#use-this-package)
|
|
53
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
54
|
+
- [Further Exploration](#further-exploration)
|
|
55
|
+
- [Model Experience](#model-experience)
|
|
56
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
57
|
+
|
|
58
|
+
## Use this package
|
|
59
|
+
|
|
60
|
+
The row belongs in the **host composition** — it injects host services
|
|
61
|
+
(`memory`, `llm`), opens the control unit once per process, and must observe
|
|
62
|
+
every session's events. There is no agent-preset contribution and no tool.
|
|
63
|
+
|
|
64
|
+
```yaml
|
|
65
|
+
# host composition (loaded before any session)
|
|
66
|
+
- id: memory-extraction
|
|
67
|
+
name: '@hy-sde-org/dsh-memory-extraction'
|
|
68
|
+
config:
|
|
69
|
+
backend: sqlite # storage backend hosting the control unit (default sqlite)
|
|
70
|
+
enabled: true # master switch (default true)
|
|
71
|
+
excludeSubagents: true # child-agent compactions never extract (default true)
|
|
72
|
+
# provider: <cheap provider id> # optional; unset uses the session's routed model config
|
|
73
|
+
# model: <cheap model id> # optional; unset uses the session's routed model config
|
|
74
|
+
importance: 0.5 # bank importance for auto-extracted facts (default 0.5)
|
|
75
|
+
dedupe: true # probe the bank before committing duplicates (default true)
|
|
76
|
+
timeoutMs: 60000 # auxiliary call timeout (default 60000)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Its storage backend must expose a `kv` facet (the shipped `sqlite` backend
|
|
80
|
+
does; `storage-json` does not) — see the
|
|
81
|
+
[example patch](../../../apps/cli/config/examples/memory-extraction/cordis.yml).
|
|
82
|
+
The engine itself is pure and testable without cordis:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { MemoryExtractionEngine } from '@hy-sde-org/dsh-memory-extraction'
|
|
86
|
+
|
|
87
|
+
const engine = new MemoryExtractionEngine(ports) // readGate/readEvents/read+write cursor+receipt+failure/commitItems/generate
|
|
88
|
+
const result = await engine.execute(snapshot) // never throws; idempotent by operation id
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Wiring
|
|
92
|
+
|
|
93
|
+
The plugin boots asynchronously: an effect opens the control unit via
|
|
94
|
+
`storage.backend.<backend>.kv.open(MemoryExtractionControlStore.descriptor)`
|
|
95
|
+
(`memory_extraction`, version 1, tables `cursors`/`receipts`/`failures`) and
|
|
96
|
+
registers the `session/event` listener. A missing backend logs and leaves the
|
|
97
|
+
plugin inert instead of failing composition.
|
|
98
|
+
|
|
99
|
+
## Understand the implementation
|
|
100
|
+
|
|
101
|
+
- `src/evidence.ts` — bounded evidence projection, coverage planning
|
|
102
|
+
(binary-search shrink, fail-closed overflow), the same-session localization
|
|
103
|
+
search, and quote verification.
|
|
104
|
+
- `src/proposal.ts` — strict hand-rolled JSON parsers (complete /
|
|
105
|
+
`search_required` / `cannot_resolve` / canonicalization), prompt builders that
|
|
106
|
+
frame evidence as **untrusted data**, admission (verbatim quotes, min 4 chars,
|
|
107
|
+
secret rejection, NFC + injection neutralization, 2 000-char content cap).
|
|
108
|
+
- `src/control.ts` — the durable cursor/receipt/failure store over one
|
|
109
|
+
`KvUnit` (single write chain; heal-on-open; write ordering documented).
|
|
110
|
+
- `src/engine.ts` — the state machine: idempotency receipt, gate, empty-range
|
|
111
|
+
advance, one-retry-then-discard, 3-call budget, commit ordering.
|
|
112
|
+
- `src/events.ts` — the lossy DSH event projection (user/assistant text only,
|
|
113
|
+
turn tracking for localization grouping).
|
|
114
|
+
- `src/memory-adapter.ts` — the commit surface over `ctx.memory`: a dedupe probe,
|
|
115
|
+
then `save` with `source: 'memory_extract'`, plus the gate factory.
|
|
116
|
+
- `src/runtime.ts` — host wiring: per-session sequential queue, generate adapter
|
|
117
|
+
(`BlockAssembler`, `AbortSignal.timeout`, routed provider/model override),
|
|
118
|
+
sync/async port implementations over live services.
|
|
119
|
+
|
|
120
|
+
## Further Exploration
|
|
121
|
+
|
|
122
|
+
- The Maka source this was ported from: `packages/runtime/src/memory-extraction.ts`
|
|
123
|
+
in the Maka repository.
|
|
124
|
+
- The compaction lifecycle that emits the boundary events:
|
|
125
|
+
`@deepseek-ai/dsh-compaction`.
|
|
126
|
+
|
|
127
|
+
## Model Experience
|
|
128
|
+
|
|
129
|
+
The pipeline adds up to 3 auxiliary model calls per checkpointed range with
|
|
130
|
+
user-authored text (proposal, optional localization, canonicalization), each
|
|
131
|
+
bounded by `timeoutMs`. Configuring `provider`/`model` to a cheap auxiliary
|
|
132
|
+
model is recommended for large deployments; when unset the session's routed
|
|
133
|
+
request header is used. The model never sees raw logs or tool results — only
|
|
134
|
+
the bounded, user-authored evidence plus a short localization context.
|
|
135
|
+
|
|
136
|
+
## Known Limitations and Deferred Work
|
|
137
|
+
|
|
138
|
+
- **One pending failure per session** (retry once, then discard) — Maka keeps
|
|
139
|
+
richer failure states (e.g. evidence-growth retry), ported as a single later
|
|
140
|
+
retry.
|
|
141
|
+
- **No persistent re-extraction** on evidence growth: a checkpoint that failed
|
|
142
|
+
is retried once and then dropped.
|
|
143
|
+
- **Maka facets are not ported** (kind/temporal/scope/tags); every extracted
|
|
144
|
+
fact lands with `source: 'memory_extract'` and the configured importance.
|
|
145
|
+
- **No per-verb tools**: `memory_remember`/`memory_extract` are reserved names;
|
|
146
|
+
the explicit DSH memory tools remain the model-facing path.
|
|
147
|
+
- The dedupe probe relies on the local memory bank's `search` seeing previously
|
|
148
|
+
committed rows (same-process semantics).
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "在压缩检查点自动提取长期记忆:证据投影、提案/规范化流水线、受门控的 ctx.memory 提交,以及持久化的游标/回执/失败账本(Maka 移植,切片 No. 2)。"
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @hy-sde-org/dsh-memory-extraction
|
|
7
|
+
|
|
8
|
+
[English](README.md) | 中文
|
|
9
|
+
|
|
10
|
+
## 摘要
|
|
11
|
+
|
|
12
|
+
`dsh-memory-extraction` 是 Maka 自动记忆提取触发器的 DSH 移植:每次
|
|
13
|
+
`compaction/summary` 事件(检查点边界)之后,一个有界、失败开放的流水线投影
|
|
14
|
+
检查点范围内**用户撰写**的文本,用辅助模型调用提出并规范化持久事实,并把通过
|
|
15
|
+
的事实提交到 `retain`/`learn` 使用的同一项目记忆库。它严格**叠加**在 DSH 显式
|
|
16
|
+
记忆能力之上:`retain`/`learn`/`memory_edit` 工具仍是面向模型的路径,移植
|
|
17
|
+
有意保留(不移植)Maka 的 `memory_remember`/`memory_extract` 动词。
|
|
18
|
+
|
|
19
|
+
本包是**主机平面**的 Cordis 插件(`inject: ['memory', 'llm']`,不发布服务):
|
|
20
|
+
每进程只打开一次 `memory_extraction` 控制单元,通过无作用域的
|
|
21
|
+
`ctx.on('session/event')` 监听器观察所有会话的事件(作用域过滤器全局接纳无
|
|
22
|
+
作用域监听器)。运行按会话串行,绝不阻塞压缩监听器。
|
|
23
|
+
|
|
24
|
+
### 承重规则(移植自 Maka)
|
|
25
|
+
|
|
26
|
+
1. **证据仅限用户撰写文本** —— 投影 `source.kind === 'user'` 的
|
|
27
|
+
`user/message` 事件;助手文本仅作解读上下文;工具调用/结果、推理块和插件
|
|
28
|
+
检查点保持不透明。证据有界(12 000 字符 JSON / 单条 4 000 字符 / 64 条)且
|
|
29
|
+
**失败关闭**(溢出则跳过)。
|
|
30
|
+
2. **准入经核验** —— 提案 → 准入(对有界证据逐字核验引文 + 密钥拒绝)→
|
|
31
|
+
规范化 → 再准入,每个范围最多 **3 次辅助模型调用**、60 秒超时;失败被包含
|
|
32
|
+
(在运行时边界失败开放)。
|
|
33
|
+
3. **游标只推进到已提交边界** —— 空范围仍然推进(记无操作回执,不调用模型);
|
|
34
|
+
失败范围成为一条待处理记录,由下一次触发重试一次后丢弃。写入顺序为
|
|
35
|
+
条目 → 游标 → 回执,因此游标与回执之间崩溃永远不会重复处理。
|
|
36
|
+
4. **幂等是确定性的** —— 操作 id = `memory_` + sha256(`{sessionId, trigger,
|
|
37
|
+
boundarySeq}`);回执使重放成为空操作,提交侧去重探测修复条目与回执之间的
|
|
38
|
+
崩溃。
|
|
39
|
+
5. **排除子代理** —— 门控在每次模型调用后重新检查,默认拒绝子会话
|
|
40
|
+
(`excludeSubagents: true`)。
|
|
41
|
+
|
|
42
|
+
## 目录
|
|
43
|
+
|
|
44
|
+
- [使用本包](#use-this-package)
|
|
45
|
+
- [理解实现](#understand-the-implementation)
|
|
46
|
+
- [进一步探索](#further-exploration)
|
|
47
|
+
- [模型体验](#model-experience)
|
|
48
|
+
- [已知局限与延后工作](#known-limitations-and-deferred-work)
|
|
49
|
+
|
|
50
|
+
<a id="use-this-package"></a>
|
|
51
|
+
## 使用本包
|
|
52
|
+
|
|
53
|
+
该行属于**主机组合** —— 它注入主机服务(`memory`、`llm`),每进程打开一次
|
|
54
|
+
控制单元,且必须观察所有会话的事件。没有代理预设贡献,也没有工具。
|
|
55
|
+
|
|
56
|
+
```yaml
|
|
57
|
+
# host composition (loaded before any session)
|
|
58
|
+
- id: memory-extraction
|
|
59
|
+
name: '@hy-sde-org/dsh-memory-extraction'
|
|
60
|
+
config:
|
|
61
|
+
backend: sqlite # storage backend hosting the control unit (default sqlite)
|
|
62
|
+
enabled: true # master switch (default true)
|
|
63
|
+
excludeSubagents: true # child-agent compactions never extract (default true)
|
|
64
|
+
# provider: <cheap provider id> # optional; unset uses the session's routed model config
|
|
65
|
+
# model: <cheap model id> # optional; unset uses the session's routed model config
|
|
66
|
+
importance: 0.5 # bank importance for auto-extracted facts (default 0.5)
|
|
67
|
+
dedupe: true # probe the bank before committing duplicates (default true)
|
|
68
|
+
timeoutMs: 60000 # auxiliary call timeout (default 60000)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
其存储后端必须暴露 `kv` 面(shipped 的 `sqlite` 后端可以;`storage-json`
|
|
72
|
+
不可以)—— 参见
|
|
73
|
+
[示例补丁](../../../apps/cli/config/examples/memory-extraction/cordis.yml)。
|
|
74
|
+
引擎本身是纯的,可在无 cordis 下测试:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import { MemoryExtractionEngine } from '@hy-sde-org/dsh-memory-extraction'
|
|
78
|
+
|
|
79
|
+
const engine = new MemoryExtractionEngine(ports) // readGate/readEvents/read+write cursor+receipt+failure/commitItems/generate
|
|
80
|
+
const result = await engine.execute(snapshot) // never throws; idempotent by operation id
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 接线
|
|
84
|
+
|
|
85
|
+
插件异步启动:一个 effect 通过
|
|
86
|
+
`storage.backend.<backend>.kv.open(MemoryExtractionControlStore.descriptor)`
|
|
87
|
+
打开控制单元(`memory_extraction`,版本 1,表 `cursors`/`receipts`/`failures`)
|
|
88
|
+
并注册 `session/event` 监听器。后端缺失时记录日志并保持惰性,而不是让组合失败。
|
|
89
|
+
|
|
90
|
+
<a id="understand-the-implementation"></a>
|
|
91
|
+
## 理解实现
|
|
92
|
+
|
|
93
|
+
- `src/evidence.ts` —— 有界证据投影、覆盖规划(二分收缩、溢出失败关闭)、
|
|
94
|
+
同会话本地化搜索、引文核验。
|
|
95
|
+
- `src/proposal.ts` —— 严格手写 JSON 解析(complete/`search_required`/
|
|
96
|
+
`cannot_resolve`/规范化)、把证据标示为**不可信数据**的提示词构建、准入
|
|
97
|
+
(逐字引文、最少 4 字符、密钥拒绝、NFC + 注入中和、内容上限 2 000 字符)。
|
|
98
|
+
- `src/control.ts` —— 单个 `KvUnit` 上的持久化游标/回执/失败存储(单一写入
|
|
99
|
+
链;打开时自愈;写入顺序有文档说明)。
|
|
100
|
+
- `src/engine.ts` —— 状态机:幂等回执、门控、空范围推进、一次重试后丢弃、
|
|
101
|
+
3 次调用预算、提交顺序。
|
|
102
|
+
- `src/events.ts` —— 有损的 DSH 事件投影(仅用户/助手文本,为本地化分组跟踪
|
|
103
|
+
轮次)。
|
|
104
|
+
- `src/memory-adapter.ts` —— 基于 `ctx.memory` 的提交面(去重探测 +
|
|
105
|
+
`save`,来源 `'memory_extract'`)与门控工厂。
|
|
106
|
+
- `src/runtime.ts` —— 主机接线:按会话的顺序队列、generate 适配器
|
|
107
|
+
(`BlockAssembler`、`AbortSignal.timeout`、路由 provider/model 覆盖)、
|
|
108
|
+
基于真实服务的同步/异步端口实现。
|
|
109
|
+
|
|
110
|
+
<a id="further-exploration"></a>
|
|
111
|
+
## 进一步探索
|
|
112
|
+
|
|
113
|
+
- 移植来源:Maka 仓库 `packages/runtime/src/memory-extraction.ts`。
|
|
114
|
+
- 产生边界事件的压缩生命周期:`@deepseek-ai/dsh-compaction`。
|
|
115
|
+
|
|
116
|
+
<a id="model-experience"></a>
|
|
117
|
+
## 模型体验
|
|
118
|
+
|
|
119
|
+
流水线对每个含用户文本的检查点范围最多增加 3 次辅助模型调用(提案、可选
|
|
120
|
+
本地化、规范化),每次受 `timeoutMs` 约束。大型部署建议把 `provider`/`model`
|
|
121
|
+
配置为廉价辅助模型;未配置时使用会话路由的请求头。模型从不接触原始日志或
|
|
122
|
+
工具结果 —— 只有有界的用户证据和一小段本地化上下文。
|
|
123
|
+
|
|
124
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
125
|
+
## 已知局限与延后工作
|
|
126
|
+
|
|
127
|
+
- **每会话仅一条待处理失败**(重试一次后丢弃)—— Maka 保有更丰富的失败
|
|
128
|
+
状态(如证据增长重试),此处移植为单次延后重试。
|
|
129
|
+
- **证据增长不重提取**:失败的检查点只重试一次即丢弃。
|
|
130
|
+
- **Maka 侧面未移植**(kind/temporal/scope/tags);每条提取事实以
|
|
131
|
+
`source: 'memory_extract'` 与配置的重要性落库。
|
|
132
|
+
- **无逐动词工具**:`memory_remember`/`memory_extract` 为保留名;显式 DSH
|
|
133
|
+
记忆工具仍是面向模型的路径。
|
|
134
|
+
- 去重探测依赖本地记忆库的 `search` 能看到先前提交的行(同进程语义)。
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The memory-extraction control store: durable per-session cursor, idempotency
|
|
3
|
+
* receipts, and the single pending-failure record, over one {@link KvUnit}
|
|
4
|
+
* (`memory_extraction`). Same pattern as `dsh-graph-control`: single write
|
|
5
|
+
* chain, heal-on-open, no SQL transactions (the storage contract already
|
|
6
|
+
* forbids concurrent writers on one unit).
|
|
7
|
+
*
|
|
8
|
+
* Write ordering is load-bearing: the CURSOR is written before the receipt so
|
|
9
|
+
* a crash between the two can never double-process a range (the next trigger's
|
|
10
|
+
* range starts at the new cursor), and a pending failure is written before any
|
|
11
|
+
* retry settles so a crash mid-retry keeps the pending row.
|
|
12
|
+
* @module @hy-sde-org/dsh-memory-extraction/control
|
|
13
|
+
*/
|
|
14
|
+
import type { KvUnit } from '@deepseek-ai/dsh-storage';
|
|
15
|
+
import type { MemoryExtractionCursor, MemoryExtractionReceipt, PendingMemoryExtractionFailure } from './types.ts';
|
|
16
|
+
export declare const MEMORY_EXTRACTION_CONTROL_UNIT_NAME = "memory_extraction";
|
|
17
|
+
export declare const MEMORY_EXTRACTION_CONTROL_UNIT_VERSION = 1;
|
|
18
|
+
export declare class MemoryExtractionControlStore {
|
|
19
|
+
private readonly kv;
|
|
20
|
+
/** The unit descriptor callers open with `storage.backend.<name>.kv.open(descriptor)`. */
|
|
21
|
+
static readonly descriptor: {
|
|
22
|
+
name: string;
|
|
23
|
+
version: number;
|
|
24
|
+
tables: ("cursors" | "receipts" | "failures")[];
|
|
25
|
+
hasGlobal: boolean;
|
|
26
|
+
};
|
|
27
|
+
private constructor();
|
|
28
|
+
/** Open the store over an already-opened unit. */
|
|
29
|
+
static open(kv: KvUnit): MemoryExtractionControlStore;
|
|
30
|
+
/** Serialize one read-modify-write over the unit (the single write chain). */
|
|
31
|
+
private withChain;
|
|
32
|
+
private tail;
|
|
33
|
+
readCursor(sessionId: string): Promise<MemoryExtractionCursor | undefined>;
|
|
34
|
+
/** Advance the watermark. Written before the receipt on every commit path. */
|
|
35
|
+
writeCursor(cursor: MemoryExtractionCursor): Promise<void>;
|
|
36
|
+
readReceipt(operationId: string): Promise<MemoryExtractionReceipt | undefined>;
|
|
37
|
+
writeReceipt(receipt: MemoryExtractionReceipt): Promise<void>;
|
|
38
|
+
readFailure(sessionId: string): Promise<PendingMemoryExtractionFailure | undefined>;
|
|
39
|
+
writeFailure(failure: PendingMemoryExtractionFailure): Promise<void>;
|
|
40
|
+
deleteFailure(sessionId: string): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=control.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control.d.ts","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAA;AACtD,OAAO,KAAK,EACV,sBAAsB,EACtB,uBAAuB,EACvB,8BAA8B,EAC/B,MAAM,YAAY,CAAA;AAEnB,eAAO,MAAM,mCAAmC,sBAAsB,CAAA;AACtE,eAAO,MAAM,sCAAsC,IAAI,CAAA;AAQvD,qBAAa,4BAA4B;IASnB,OAAO,CAAC,QAAQ,CAAC,EAAE;IARvC,0FAA0F;IAC1F,MAAM,CAAC,QAAQ,CAAC,UAAU;;;;;MAKzB;IAED,OAAO;IAEP,kDAAkD;IAClD,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,4BAA4B;IAIrD,8EAA8E;IAC9E,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,IAAI,CAAsC;IAI5C,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC;IAUhF,8EAA8E;IAC9E,WAAW,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpD,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,GAAG,SAAS,CAAC;IAqBpF,YAAY,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvD,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,8BAA8B,GAAG,SAAS,CAAC;IA8BzF,YAAY,CAAC,OAAO,EAAE,8BAA8B,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpE,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGhD"}
|
package/dist/control.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The memory-extraction control store: durable per-session cursor, idempotency
|
|
3
|
+
* receipts, and the single pending-failure record, over one {@link KvUnit}
|
|
4
|
+
* (`memory_extraction`). Same pattern as `dsh-graph-control`: single write
|
|
5
|
+
* chain, heal-on-open, no SQL transactions (the storage contract already
|
|
6
|
+
* forbids concurrent writers on one unit).
|
|
7
|
+
*
|
|
8
|
+
* Write ordering is load-bearing: the CURSOR is written before the receipt so
|
|
9
|
+
* a crash between the two can never double-process a range (the next trigger's
|
|
10
|
+
* range starts at the new cursor), and a pending failure is written before any
|
|
11
|
+
* retry settles so a crash mid-retry keeps the pending row.
|
|
12
|
+
* @module @hy-sde-org/dsh-memory-extraction/control
|
|
13
|
+
*/
|
|
14
|
+
export const MEMORY_EXTRACTION_CONTROL_UNIT_NAME = 'memory_extraction';
|
|
15
|
+
export const MEMORY_EXTRACTION_CONTROL_UNIT_VERSION = 1;
|
|
16
|
+
const UNIT_TABLES = ['cursors', 'receipts', 'failures'];
|
|
17
|
+
function isRecord(value) {
|
|
18
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
19
|
+
}
|
|
20
|
+
export class MemoryExtractionControlStore {
|
|
21
|
+
kv;
|
|
22
|
+
/** The unit descriptor callers open with `storage.backend.<name>.kv.open(descriptor)`. */
|
|
23
|
+
static descriptor = {
|
|
24
|
+
name: MEMORY_EXTRACTION_CONTROL_UNIT_NAME,
|
|
25
|
+
version: MEMORY_EXTRACTION_CONTROL_UNIT_VERSION,
|
|
26
|
+
tables: [...UNIT_TABLES],
|
|
27
|
+
hasGlobal: false,
|
|
28
|
+
};
|
|
29
|
+
constructor(kv) {
|
|
30
|
+
this.kv = kv;
|
|
31
|
+
}
|
|
32
|
+
/** Open the store over an already-opened unit. */
|
|
33
|
+
static open(kv) {
|
|
34
|
+
return new MemoryExtractionControlStore(kv);
|
|
35
|
+
}
|
|
36
|
+
/** Serialize one read-modify-write over the unit (the single write chain). */
|
|
37
|
+
withChain(run) {
|
|
38
|
+
const tail = this.tail;
|
|
39
|
+
const next = tail.then(run, run);
|
|
40
|
+
const guarded = next.then(() => { if (this.tail === guarded)
|
|
41
|
+
this.tail = Promise.resolve(); }, () => { if (this.tail === guarded)
|
|
42
|
+
this.tail = Promise.resolve(); });
|
|
43
|
+
this.tail = guarded;
|
|
44
|
+
return next;
|
|
45
|
+
}
|
|
46
|
+
tail = Promise.resolve();
|
|
47
|
+
/* ── cursor ──────────────────────────────────────────────────────────── */
|
|
48
|
+
async readCursor(sessionId) {
|
|
49
|
+
const { tables } = await this.kv.loadAll();
|
|
50
|
+
const row = tables['cursors']?.[sessionId];
|
|
51
|
+
if (!isRecord(row))
|
|
52
|
+
return undefined;
|
|
53
|
+
const processedSeq = row['processedSeq'];
|
|
54
|
+
const updatedAt = row['updatedAt'];
|
|
55
|
+
if (typeof processedSeq !== 'number' || typeof updatedAt !== 'number')
|
|
56
|
+
return undefined;
|
|
57
|
+
return { sessionId, processedSeq, updatedAt };
|
|
58
|
+
}
|
|
59
|
+
/** Advance the watermark. Written before the receipt on every commit path. */
|
|
60
|
+
writeCursor(cursor) {
|
|
61
|
+
return this.withChain(() => this.kv.putRecord('cursors', cursor.sessionId, { ...cursor }));
|
|
62
|
+
}
|
|
63
|
+
/* ── receipts (idempotency) ──────────────────────────────────────────── */
|
|
64
|
+
async readReceipt(operationId) {
|
|
65
|
+
const { tables } = await this.kv.loadAll();
|
|
66
|
+
const row = tables['receipts']?.[operationId];
|
|
67
|
+
if (!isRecord(row))
|
|
68
|
+
return undefined;
|
|
69
|
+
const sessionId = row['sessionId'];
|
|
70
|
+
const status = row['status'];
|
|
71
|
+
const items = row['items'];
|
|
72
|
+
const committedAt = row['committedAt'];
|
|
73
|
+
if (typeof sessionId !== 'string' || typeof status !== 'string' || typeof committedAt !== 'number') {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
if (!Array.isArray(items) || items.some(item => typeof item !== 'string'))
|
|
77
|
+
return undefined;
|
|
78
|
+
return {
|
|
79
|
+
operationId,
|
|
80
|
+
sessionId,
|
|
81
|
+
status: status,
|
|
82
|
+
items: items,
|
|
83
|
+
committedAt,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
writeReceipt(receipt) {
|
|
87
|
+
return this.withChain(() => this.kv.putRecord('receipts', receipt.operationId, { ...receipt }));
|
|
88
|
+
}
|
|
89
|
+
/* ── pending failure ─────────────────────────────────────────────────── */
|
|
90
|
+
async readFailure(sessionId) {
|
|
91
|
+
const { tables } = await this.kv.loadAll();
|
|
92
|
+
const row = tables['failures']?.[sessionId];
|
|
93
|
+
if (!isRecord(row))
|
|
94
|
+
return undefined;
|
|
95
|
+
const throughSeq = row['throughSeq'];
|
|
96
|
+
const coverageHash = row['coverageHash'];
|
|
97
|
+
const operationId = row['operationId'];
|
|
98
|
+
const attempts = row['attempts'];
|
|
99
|
+
const failureClass = row['failureClass'];
|
|
100
|
+
const failedAt = row['failedAt'];
|
|
101
|
+
if (typeof throughSeq !== 'number' || typeof coverageHash !== 'string'
|
|
102
|
+
|| typeof operationId !== 'string' || typeof attempts !== 'number'
|
|
103
|
+
|| typeof failureClass !== 'string' || typeof failedAt !== 'number') {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
const fromSeq = row['fromSeq'];
|
|
107
|
+
return {
|
|
108
|
+
sessionId,
|
|
109
|
+
fromSeq: typeof fromSeq === 'number' ? fromSeq : throughSeq,
|
|
110
|
+
throughSeq,
|
|
111
|
+
coverageHash,
|
|
112
|
+
operationId,
|
|
113
|
+
attempts,
|
|
114
|
+
failureClass: failureClass,
|
|
115
|
+
failedAt,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
writeFailure(failure) {
|
|
119
|
+
return this.withChain(() => this.kv.putRecord('failures', failure.sessionId, { ...failure }));
|
|
120
|
+
}
|
|
121
|
+
deleteFailure(sessionId) {
|
|
122
|
+
return this.withChain(() => this.kv.deleteRecord('failures', sessionId));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=control.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control.js","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The memory-extraction engine: a bounded, fail-open pipeline over frozen
|
|
3
|
+
* evidence. Ported from Maka `memory-extraction.ts` with the compaction-only
|
|
4
|
+
* surface (no `remember`/`extract` tools, no per-checkpoint policy denials,
|
|
5
|
+
* no range-splitting) and the same load-bearing rules:
|
|
6
|
+
*
|
|
7
|
+
* - evidence is user-authored text only, bounded and fail-closed on overflow;
|
|
8
|
+
* - proposal → admission → canonicalization → re-admission, with verbatim
|
|
9
|
+
* quote verification and deterministic secret rejection;
|
|
10
|
+
* - the per-session cursor only moves to a committed boundary; empty ranges
|
|
11
|
+
* still advance; a failed range becomes one pending record retried by the
|
|
12
|
+
* next trigger and then discarded;
|
|
13
|
+
* - every run is idempotent by deterministic operation id.
|
|
14
|
+
*
|
|
15
|
+
* The engine is pure (ports only, no cordis, no live session) so the whole
|
|
16
|
+
* state machine is unit-testable with fakes.
|
|
17
|
+
* @module @hy-sde-org/dsh-memory-extraction/engine
|
|
18
|
+
*/
|
|
19
|
+
import type { AdmittedMemoryItem, MemoryExtractionCursor, MemoryExtractionEventEntry, MemoryExtractionGate, MemoryExtractionReceipt, MemoryExtractionRunResult, MemoryExtractionSourceSnapshot, PendingMemoryExtractionFailure } from './types.ts';
|
|
20
|
+
export type MemoryExtractionStage = 'proposal' | 'localized' | 'canonicalize';
|
|
21
|
+
export type MemoryGenerateResult = {
|
|
22
|
+
readonly ok: true;
|
|
23
|
+
readonly text: string;
|
|
24
|
+
} | {
|
|
25
|
+
readonly ok: false;
|
|
26
|
+
readonly errorClass: 'aborted' | 'timeout' | 'configuration' | 'provider' | 'persistence' | 'unknown';
|
|
27
|
+
};
|
|
28
|
+
/** The ports the engine drives. One implementation: the host runtime over real services. */
|
|
29
|
+
export interface MemoryExtractionPorts {
|
|
30
|
+
readGate(snapshot: MemoryExtractionSourceSnapshot): MemoryExtractionGate | Promise<MemoryExtractionGate>;
|
|
31
|
+
/** Read the session log window `(fromSeq, throughSeq]` as portable text events. */
|
|
32
|
+
readEvents(sessionId: string, fromSeq: number, throughSeq: number): readonly MemoryExtractionEventEntry[] | Promise<readonly MemoryExtractionEventEntry[]>;
|
|
33
|
+
readCursor(sessionId: string): MemoryExtractionCursor | undefined | Promise<MemoryExtractionCursor | undefined>;
|
|
34
|
+
readReceipt(operationId: string): MemoryExtractionReceipt | undefined | Promise<MemoryExtractionReceipt | undefined>;
|
|
35
|
+
readFailure(sessionId: string): PendingMemoryExtractionFailure | undefined | Promise<PendingMemoryExtractionFailure | undefined>;
|
|
36
|
+
writeCursor(cursor: MemoryExtractionCursor): void | Promise<void>;
|
|
37
|
+
writeReceipt(receipt: MemoryExtractionReceipt): void | Promise<void>;
|
|
38
|
+
writeFailure(failure: PendingMemoryExtractionFailure): void | Promise<void>;
|
|
39
|
+
deleteFailure(sessionId: string): void | Promise<void>;
|
|
40
|
+
/** Commit admitted items into the project memory store; returns what was actually stored. */
|
|
41
|
+
commitItems(input: {
|
|
42
|
+
readonly sessionId: string;
|
|
43
|
+
readonly workspaceKey?: string;
|
|
44
|
+
readonly trigger: MemoryExtractionSourceSnapshot['trigger'];
|
|
45
|
+
readonly boundarySeq: number;
|
|
46
|
+
readonly items: readonly AdmittedMemoryItem[];
|
|
47
|
+
}): {
|
|
48
|
+
readonly committed: readonly string[];
|
|
49
|
+
} | Promise<{
|
|
50
|
+
readonly committed: readonly string[];
|
|
51
|
+
}>;
|
|
52
|
+
/** One bounded auxiliary model call. Implementations own the timeout signal. */
|
|
53
|
+
generate(input: {
|
|
54
|
+
readonly snapshot: MemoryExtractionSourceSnapshot;
|
|
55
|
+
readonly prompt: string;
|
|
56
|
+
readonly stage: MemoryExtractionStage;
|
|
57
|
+
}): MemoryGenerateResult | Promise<MemoryGenerateResult>;
|
|
58
|
+
now?(): number;
|
|
59
|
+
}
|
|
60
|
+
/** Max auxiliary model calls per range (Maka: 3). */
|
|
61
|
+
export declare const MAX_MEMORY_EXTRACTION_MODEL_CALLS = 3;
|
|
62
|
+
/** One later retry after a settled failure, then discard (Maka keeps more states). */
|
|
63
|
+
export declare const MAX_FAILURE_ATTEMPTS = 2;
|
|
64
|
+
export declare class MemoryExtractionEngine {
|
|
65
|
+
private readonly ports;
|
|
66
|
+
constructor(ports: MemoryExtractionPorts);
|
|
67
|
+
execute(snapshot: MemoryExtractionSourceSnapshot): Promise<MemoryExtractionRunResult>;
|
|
68
|
+
private processRange;
|
|
69
|
+
private processCoverage;
|
|
70
|
+
private commitEmpty;
|
|
71
|
+
private settleCountedFailure;
|
|
72
|
+
private callModel;
|
|
73
|
+
private allowed;
|
|
74
|
+
private now;
|
|
75
|
+
}
|
|
76
|
+
export declare function memoryExtractionOperationId(snapshot: MemoryExtractionSourceSnapshot): string;
|
|
77
|
+
export declare function memoryCoverageHash(entries: readonly MemoryExtractionEventEntry[], fromSeq: number, throughSeq: number): string;
|
|
78
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|