pi-okf-memory 0.1.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/LICENSE +21 -0
- package/README.en.md +204 -0
- package/README.md +265 -0
- package/cordis.patch.yml +6 -0
- package/docs/graph-demo.png +0 -0
- package/lib/capture.js +53 -0
- package/lib/client.js +417 -0
- package/lib/client.js.map +1 -0
- package/lib/concept.js +264 -0
- package/lib/dedupe.js +149 -0
- package/lib/graph.js +95 -0
- package/lib/index.js +381 -0
- package/lib/learning.js +185 -0
- package/lib/memory.js +135 -0
- package/lib/recall.js +47 -0
- package/lib/store.js +217 -0
- package/package.json +89 -0
- package/src/client/index.tsx +232 -0
- package/src/pi/graph-html.ts +300 -0
- package/src/pi/index.ts +383 -0
- package/src/server/capture.ts +52 -0
- package/src/server/concept.ts +302 -0
- package/src/server/dedupe.ts +164 -0
- package/src/server/dsh-tools.d.ts +11 -0
- package/src/server/graph.ts +135 -0
- package/src/server/index.ts +376 -0
- package/src/server/learning.ts +219 -0
- package/src/server/memory.ts +157 -0
- package/src/server/recall.ts +58 -0
- package/src/server/store.ts +255 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dsh-okf-memory contributors
|
|
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.en.md
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# pi-okf-memory
|
|
2
|
+
|
|
3
|
+
[简体中文](README.md) | English
|
|
4
|
+
|
|
5
|
+
**Session memory → OKF knowledge. Make pi remember you across sessions.**
|
|
6
|
+
|
|
7
|
+
High-value content from your sessions is distilled into long-term memory as [OKF v0.1](https://github.com/open-knowledge-format) documents, and recalled automatically in later sessions. Every pick, skip and correction is a learning signal — recall gets sharper the longer you use it.
|
|
8
|
+
|
|
9
|
+
> **中文速览** —— `pi-okf-memory` 把 pi 会话中的高价值内容沉淀为持久的 [OKF v0.1](https://github.com/open-knowledge-format) Markdown 文件,
|
|
10
|
+
> 并在之后的会话中自动唤起。记忆完全属于你:纯文件,可读、可 `git`、可手改。权重随你的每次选择与跳过持续调整,召回越来越准。
|
|
11
|
+
> **安装:** `pi install npm:pi-okf-memory`(或 `pi install git:github.com/ZHI-QI/pi-okf-memory`)。
|
|
12
|
+
> 一个命令:`/okf`。六个工具:`okf_remember` / `okf_search` / `okf_read` / `okf_forget` / `okf_graph` / `okf_feedback`。
|
|
13
|
+
> [完整中文说明 →](README.md)
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Why
|
|
20
|
+
|
|
21
|
+
Every new pi session starts from zero, so you keep repeating yourself:
|
|
22
|
+
|
|
23
|
+
> "I use pnpm, not npm."
|
|
24
|
+
> "Revenue data comes from the Dezensaas MySQL — don't grep local files."
|
|
25
|
+
> "We settled on React 18 + Vite last quarter; stop asking about the frontend."
|
|
26
|
+
|
|
27
|
+
`pi-okf-memory` turns that into files. The memory is yours, not a black box:
|
|
28
|
+
|
|
29
|
+
- **Readable** — plain Markdown. Open it, `git` it, hand-edit it.
|
|
30
|
+
- **Portable** — one directory. Copy it and the whole memory moves with you.
|
|
31
|
+
- **Honest** — when nothing matches, it says "not in the memory library" instead of making something up.
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
pi install git:github.com/ZHI-QI/pi-okf-memory # from GitHub
|
|
37
|
+
pi install /path/to/pi-okf-memory # from a local checkout
|
|
38
|
+
pi -e /path/to/pi-okf-memory/src/pi/index.ts # try it without writing config
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Zero runtime dependencies and **no build step** — pi loads TypeScript directly via [jiti](https://github.com/unjs/jiti) and provides `typebox` / `@earendil-works/pi-*` through aliases.
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
### You don't need to learn any commands
|
|
46
|
+
|
|
47
|
+
Once installed, the plugin injects a "memory discipline" prompt and pi decides on its own what to store and what to look up:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
You: Remember — my three stores are Shaoshan/Xiangxiang/Tangxia, sharing a LAN folder
|
|
51
|
+
→ pi judges value, dedupes, writes the concept, updates the index
|
|
52
|
+
|
|
53
|
+
You: Where should revenue queries go?
|
|
54
|
+
→ pi runs okf_search first, then answers from memory instead of guessing
|
|
55
|
+
|
|
56
|
+
You: Search memory for anything about stores
|
|
57
|
+
→ explicit recall
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 6 tools (called by pi autonomously)
|
|
61
|
+
|
|
62
|
+
| Tool | Purpose |
|
|
63
|
+
|---|---|
|
|
64
|
+
| `okf_remember` | Write a concept (type validation → dedupe → section-level merge → persist) |
|
|
65
|
+
| `okf_search` | Recall ranked by relevance × weight × recency; `TechChoice` hits include the full options table |
|
|
66
|
+
| `okf_read` | Read a concept in full (with cross-links) and record one usage feedback |
|
|
67
|
+
| `okf_forget` | Withdraw a concept (file kept by default for traceability; optionally delete) |
|
|
68
|
+
| `okf_graph` | Export the graph JSON (nodes / edges / timeline) |
|
|
69
|
+
| `okf_feedback` | User selected `+1.0` / skipped `−0.5` — moves weights directly |
|
|
70
|
+
|
|
71
|
+
### Commands: just `/okf`
|
|
72
|
+
|
|
73
|
+
Only **one** command is registered; subcommands complete with Tab (type `/okf ` then Tab).
|
|
74
|
+
|
|
75
|
+
| Command | Purpose |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `/okf` | Library status: root, concept count, weight leaderboard |
|
|
78
|
+
| `/okf search <query>` | Search (short alias `/okf s`) |
|
|
79
|
+
| `/okf graph` | Export a **single self-contained** interactive HTML graph and open it (alias `/okf g`) |
|
|
80
|
+
| `/okf consolidate` | Run consolidation now, decay + archive (alias `/okf c`) |
|
|
81
|
+
| `/okf help` | List all subcommands |
|
|
82
|
+
|
|
83
|
+
### What gets remembered
|
|
84
|
+
|
|
85
|
+
| Worth storing ✅ | Not worth storing ❌ |
|
|
86
|
+
|---|---|
|
|
87
|
+
| New background facts, preferences, habits | Greetings, process chatter |
|
|
88
|
+
| Decisions **and their rationale** | One-off tasks |
|
|
89
|
+
| Reusable methods, processes, lessons | Restating what's already stored |
|
|
90
|
+
| **When you correct pi** (strongest signal) | Unverified guesses (goes to `Idea` until it matures) |
|
|
91
|
+
| Counter-intuitive findings you confirm | |
|
|
92
|
+
| Technology choices (frontend/backend/language/approach/config) | |
|
|
93
|
+
|
|
94
|
+
## How it works
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
capture ──→ conceptualize ──→ persist ──→ recall
|
|
98
|
+
│ │ │ │
|
|
99
|
+
│ │ │ └─ rank by relevance × weight × recency, write back feedback
|
|
100
|
+
│ │ └─ validate type → dedupe by title → section-level merge → update index/log
|
|
101
|
+
│ └─ 8-type vocabulary + OKF v0.1 frontmatter validation
|
|
102
|
+
└─ pi decides whether this turn produced knowledge worth keeping
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Weighted learning
|
|
106
|
+
|
|
107
|
+
Recall score is `relevance × weight × recency`, and weight follows your behaviour:
|
|
108
|
+
|
|
109
|
+
| Behaviour | Weight |
|
|
110
|
+
|---|---|
|
|
111
|
+
| User selects / confirms an option | **+1.0** |
|
|
112
|
+
| User skips / rejects | **−0.5** |
|
|
113
|
+
| Concept read and used | +0.1 |
|
|
114
|
+
| Untouched for 30 days | starts decaying (`0.9^(days over 30 / 30)`) |
|
|
115
|
+
| Weight < 0.3 | archived (`inactive` — **never deleted, revivable**) |
|
|
116
|
+
| Used again after archiving | restored to ≥ 0.6 |
|
|
117
|
+
|
|
118
|
+
Decay is **incremental**: if no time has passed, nothing is deducted. Running consolidation repeatedly gives exactly the same result as running it once.
|
|
119
|
+
|
|
120
|
+
### TechChoice three-tier rule (built-in protocol)
|
|
121
|
+
|
|
122
|
+
For frontend/backend/language/approach/config decisions:
|
|
123
|
+
|
|
124
|
+
1. **2+ candidates match** → present all of them and let you choose; never decide unilaterally
|
|
125
|
+
2. **1 candidate matches** → use it directly
|
|
126
|
+
3. You didn't name a technology but the message matches a dimension keyword (e.g. "frontend") → handle via that dimension's memory
|
|
127
|
+
4. You propose a new option / switch / config → **append** rather than overwrite (keeps the v1→vN trail)
|
|
128
|
+
|
|
129
|
+
## Memory library layout
|
|
130
|
+
|
|
131
|
+
Defaults to `~/.pi/agent/okf-memory/` (override with `OKF_MEMORY_ROOT`):
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
~/.pi/agent/okf-memory/
|
|
135
|
+
├── index.md ← progressive index (okf_version: "0.1")
|
|
136
|
+
├── log.md ← change history (## YYYY-MM-DD)
|
|
137
|
+
├── fact/ ← background facts
|
|
138
|
+
├── preference/ ← preferences
|
|
139
|
+
├── decision/ ← decisions (three-part: data / analysis / conclusion)
|
|
140
|
+
├── method/ ← methodologies
|
|
141
|
+
├── insight/ ← insights
|
|
142
|
+
├── idea/ ← unformed ideas
|
|
143
|
+
├── lesson/ ← lessons learned
|
|
144
|
+
├── techchoice/ ← technology choices (Options table + Active)
|
|
145
|
+
└── .meta/weights.json ← learning weights (dot dir, keeps OKF conformance clean)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
A concept ID *is* its relative path (e.g. `fact/store-layout`), and cross-links use in-bundle absolute paths: `[text](/fact/store-layout.md)`.
|
|
149
|
+
|
|
150
|
+
## Graph visualization
|
|
151
|
+
|
|
152
|
+
`/okf graph` produces a **single self-contained** HTML file (no CDN, no build artifacts) you can double-click or share:
|
|
153
|
+
|
|
154
|
+
- Node size = weight, colour = type, dashed outline = archived
|
|
155
|
+
- Hover for details, scroll to zoom, drag to pan, drag nodes to rearrange
|
|
156
|
+
- A search hit gets a white ring, a pulse, and `⚡hit`, then **BFS-propagates** along cross-links to light up related memories
|
|
157
|
+
|
|
158
|
+
## Configuration
|
|
159
|
+
|
|
160
|
+
| Item | How | Default |
|
|
161
|
+
|---|---|---|
|
|
162
|
+
| Memory root | `OKF_MEMORY_ROOT` env var | `~/.pi/agent/okf-memory/` |
|
|
163
|
+
| Learning parameters | `PARAMS` in `src/server/learning.ts` | see "Weighted learning" above |
|
|
164
|
+
|
|
165
|
+
Tuning knobs live in `PARAMS`: `SELECT_DELTA` / `SKIP_DELTA` / `HIT_DELTA` / `DECAY_DAYS` / `DECAY_FACTOR` / `ARCHIVE_THRESHOLD` / `ARCHIVE_RECOVER` / `CONSOLIDATE_INTERVAL_MS`.
|
|
166
|
+
|
|
167
|
+
## The same core also drives the dsh plugin
|
|
168
|
+
|
|
169
|
+
The runtime-agnostic core (`src/server/*`) has zero host coupling — its only imports are `node:fs` / `node:path` / `node:os`, and `src/server/index.ts` is the sole dsh adapter. So the dsh plugin `dsh-okf-memory` and the pi extension `pi-okf-memory` share one implementation:
|
|
170
|
+
|
|
171
|
+
| | pi (this repo's focus) | dsh |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| Adapter | `src/pi/index.ts` | `src/server/index.ts` |
|
|
174
|
+
| Default library | `~/.pi/agent/okf-memory/` | `~/.dsh/memory/` |
|
|
175
|
+
| Prompt injection | `pi.on("before_agent_start")` | `ctx.systemPrompt.section()` |
|
|
176
|
+
| Graph | `/okf graph` exports HTML | web conversation-view tab |
|
|
177
|
+
| Tools | 6 | 5 |
|
|
178
|
+
|
|
179
|
+
Both honour `OKF_MEMORY_ROOT` — point them at the same directory to share one memory library.
|
|
180
|
+
|
|
181
|
+
## Development & testing
|
|
182
|
+
|
|
183
|
+
```sh
|
|
184
|
+
pnpm install
|
|
185
|
+
pnpm test # typecheck + build + 6 suites, 250 assertions, offline & deterministic
|
|
186
|
+
pnpm test:e2e # real-model end-to-end (needs a token), 9 assertions
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
| Layer | Script | What it proves |
|
|
190
|
+
|---|---|---|
|
|
191
|
+
| Type check | `tsc -p tsconfig.typecheck.json` | Adapter usage matches pi's **real `.d.ts`** |
|
|
192
|
+
| Core | `scripts/smoke.js` | store / concept / dedupe / learning / recall / graph |
|
|
193
|
+
| dsh integration | `scripts/integration.js` | 5 tools end-to-end under a mocked dsh ctx |
|
|
194
|
+
| pi integration | `scripts/pi-integration.js` | 6 tools + 4 commands + schema validation under a mocked pi API |
|
|
195
|
+
| **pi real RPC** | `scripts/pi-rpc-commands.js` | Commands are recognised and executed by a **real pi process** |
|
|
196
|
+
| **Real-model E2E** | `scripts/pi-e2e-model.js` | The model really calls the tools, really persists, really recalls across sessions |
|
|
197
|
+
|
|
198
|
+
**Why the last two layers exist**: a hand-written mock only proves "the code matches my assumptions" — not that the assumptions are right. This project's first real bug slipped through exactly there: the model never knew to pass the `related` parameter, so in real use the graph was always a set of edgeless islands while every mock test stayed green.
|
|
199
|
+
|
|
200
|
+
**Note**: `tsdown` (rolldown) strips types without checking them, so a passing `pnpm build` does *not* mean the types are correct — `typecheck` is a separate layer.
|
|
201
|
+
|
|
202
|
+
## License
|
|
203
|
+
|
|
204
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# pi-okf-memory
|
|
2
|
+
|
|
3
|
+
[简体中文](README.md) | [English](README.en.md)
|
|
4
|
+
|
|
5
|
+
**会话记忆 → OKF 知识沉淀。让 pi 跨会话记住你。**
|
|
6
|
+
|
|
7
|
+
把会话里高价值的内容按 [OKF v0.1](https://github.com/open-knowledge-format) 规范自动沉淀成长期记忆,下次开新会话自动唤起。每次选择、跳过、纠正都是学习信号 —— 用得越久,召回越准。
|
|
8
|
+
|
|
9
|
+
> **English TL;DR** — `pi-okf-memory` distills high-value content from your pi sessions into
|
|
10
|
+
> durable [OKF v0.1](https://github.com/open-knowledge-format) Markdown files and recalls it in later sessions.
|
|
11
|
+
> The memory is yours: plain files you can read, `git`, and edit. Weighted recall sharpens with every pick and skip.
|
|
12
|
+
> **Install:** `pi install npm:pi-okf-memory` (or `pi install git:github.com/ZHI-QI/pi-okf-memory`).
|
|
13
|
+
> One command: `/okf`. Six tools: `okf_remember` / `okf_search` / `okf_read` / `okf_forget` / `okf_graph` / `okf_feedback`.
|
|
14
|
+
> [Full English README →](README.en.md)
|
|
15
|
+
|
|
16
|
+

|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 为什么需要它
|
|
21
|
+
|
|
22
|
+
pi 每次开新会话都从零开始。你反复交代同样的事:
|
|
23
|
+
|
|
24
|
+
> 「我用 pnpm 不用 npm」
|
|
25
|
+
> 「经营数据走鼎赞 SaaS 的 MySQL,别翻本地文件」
|
|
26
|
+
> 「上季度定了 React 18 + Vite,别再问我前端用什么」
|
|
27
|
+
|
|
28
|
+
`pi-okf-memory` 把这些**沉淀成文件**。它是你的,不是黑盒:
|
|
29
|
+
|
|
30
|
+
- **可读** —— 就是 Markdown,直接打开看、`git` 管、随时手改
|
|
31
|
+
- **可迁** —— 一个目录,拷走就是完整记忆
|
|
32
|
+
- **不编造** —— 检索不到会明确说「记忆库没有」,不会假装记得
|
|
33
|
+
|
|
34
|
+
## 安装
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
pi install git:github.com/ZHI-QI/pi-okf-memory # 从 GitHub
|
|
38
|
+
pi install /path/to/pi-okf-memory # 从本地 checkout
|
|
39
|
+
pi -e /path/to/pi-okf-memory/src/pi/index.ts # 试用,不写配置
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
零运行时依赖,无需构建步骤 —— pi 用 [jiti](https://github.com/unjs/jiti) 直接加载 TypeScript,并通过别名提供 `typebox` 与 `@earendil-works/pi-*`。
|
|
43
|
+
|
|
44
|
+
## 用法
|
|
45
|
+
|
|
46
|
+
### 你不需要学任何命令
|
|
47
|
+
|
|
48
|
+
装好后,插件会注入一段「记忆纪律」,pi 会**自己判断**该记什么、该查什么:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
你: 记住,我的三家门店是韶山/湘乡/塘厦,共用局域网共享文件夹
|
|
52
|
+
→ pi 自行判断价值、去重、写入、建索引
|
|
53
|
+
|
|
54
|
+
你: 查询经营数据走哪里?
|
|
55
|
+
→ pi 先 okf_search 召回,再基于记忆回答(而不是瞎猜或翻文件)
|
|
56
|
+
|
|
57
|
+
你: 查一下记忆里关于门店的
|
|
58
|
+
→ 显式触发检索
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 6 个工具(pi 自主调用)
|
|
62
|
+
|
|
63
|
+
| 工具 | 作用 |
|
|
64
|
+
|---|---|
|
|
65
|
+
| `okf_remember` | 写入一条记忆(自动类型校验 → 去重 → 小节级合并 → 落盘) |
|
|
66
|
+
| `okf_search` | 按 相关度 × 权重 × 近因 排序召回;命中 `TechChoice` 附候选表 |
|
|
67
|
+
| `okf_read` | 精读某条全文(含交叉链接),并记一次使用反馈 |
|
|
68
|
+
| `okf_forget` | 撤回一条(默认保留文件可追溯,可选删文件) |
|
|
69
|
+
| `okf_graph` | 导出图谱 JSON(nodes / edges / timeline) |
|
|
70
|
+
| `okf_feedback` | 用户选中 `+1.0` / 跳过 `−0.5`,直接调权重 |
|
|
71
|
+
|
|
72
|
+
### 命令:一个 `/okf` 就够
|
|
73
|
+
|
|
74
|
+
只注册**一个**命令,子命令可 Tab 补全(输入 `/okf ` 后按 Tab)。
|
|
75
|
+
|
|
76
|
+
| 命令 | 作用 |
|
|
77
|
+
|---|---|
|
|
78
|
+
| `/okf` | 记忆库状态:根目录 / 概念数 / 权重榜 |
|
|
79
|
+
| `/okf search <关键词>` | 检索(短别名 `/okf s`) |
|
|
80
|
+
| `/okf graph` | 导出**单文件自包含**交互式图谱 HTML 并打开(短别名 `/okf g`) |
|
|
81
|
+
| `/okf consolidate` | 立即跑一次巩固(衰减 + 归档)(短别名 `/okf c`) |
|
|
82
|
+
| `/okf help` | 列出全部子命令 |
|
|
83
|
+
|
|
84
|
+
### 什么值得记
|
|
85
|
+
|
|
86
|
+
| 记 ✅ | 不记 ❌ |
|
|
87
|
+
|---|---|
|
|
88
|
+
| 新背景事实 / 偏好 / 习惯 | 寒暄、过程性问答 |
|
|
89
|
+
| 拍板的决策**及理由** | 单轮临时任务 |
|
|
90
|
+
| 可复用方法论 / 流程 / 教训 | 已有记忆的重复表述 |
|
|
91
|
+
| **你纠正它的时候**(最强信号) | 未验证的猜测(可归入 `Idea` 等成熟) |
|
|
92
|
+
| 被确认的反直觉结论 | |
|
|
93
|
+
| 技术选型(前端/后端/语言/方案/配置) | |
|
|
94
|
+
|
|
95
|
+
## 工作原理
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
捕获 ──→ 概念化 ──→ 沉淀 ──→ 唤起
|
|
99
|
+
│ │ │ │
|
|
100
|
+
│ │ │ └─ 相关度 × 权重 × 近因 排序,写回使用反馈
|
|
101
|
+
│ │ └─ type 校验 → 标题去重 → 小节级合并 → index/log 更新
|
|
102
|
+
│ └─ 8 类型词表 + OKF v0.1 frontmatter 校验
|
|
103
|
+
└─ pi 依据「记忆纪律」判断本轮是否产生值得沉淀的新知识
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 权重学习
|
|
107
|
+
|
|
108
|
+
召回评分是 `relevance × weight × recency`。权重随你的行为变化:
|
|
109
|
+
|
|
110
|
+
| 行为 | 权重 |
|
|
111
|
+
|---|---|
|
|
112
|
+
| 用户选中 / 确认采用 | **+1.0** |
|
|
113
|
+
| 用户跳过 / 否定 | **−0.5** |
|
|
114
|
+
| 被精读使用 | +0.1 |
|
|
115
|
+
| 30 天未触碰 | 开始衰减(`0.9^超出天数/30`) |
|
|
116
|
+
| 权重 < 0.3 | 归档(`inactive`,**不删除,可复活**) |
|
|
117
|
+
| 归档后被重新使用 | 回到 ≥ 0.6 |
|
|
118
|
+
|
|
119
|
+
衰减是**增量式**的:时间没流逝就不会重复扣血 —— 反复调用巩固与只调用一次结果完全相同。
|
|
120
|
+
|
|
121
|
+
### 技术选型三档规则(内置协议)
|
|
122
|
+
|
|
123
|
+
针对前端/后端/语言/方案/配置这类选型:
|
|
124
|
+
|
|
125
|
+
1. 命中 **2+ 候选** → 全部展示给你选,绝不擅自决定
|
|
126
|
+
2. 命中 **1 个候选** → 直接使用
|
|
127
|
+
3. 你未指定技术但命中维度关键词(如「前端」)→ 按该维度记忆处理
|
|
128
|
+
4. 你提出新方案/切换/配置 → **追加式更新**,不覆盖旧候选(保留 v1→vN 轨迹)
|
|
129
|
+
|
|
130
|
+
## 记忆库结构
|
|
131
|
+
|
|
132
|
+
默认 `~/.pi/agent/okf-memory/`(环境变量 `OKF_MEMORY_ROOT` 可覆盖):
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
~/.pi/agent/okf-memory/
|
|
136
|
+
├── index.md ← 渐进式目录(okf_version: "0.1")
|
|
137
|
+
├── log.md ← 变更历史(## YYYY-MM-DD)
|
|
138
|
+
├── fact/ ← 背景事实
|
|
139
|
+
├── preference/ ← 偏好
|
|
140
|
+
├── decision/ ← 决策(三段式:数据/分析/结论)
|
|
141
|
+
├── method/ ← 方法论
|
|
142
|
+
├── insight/ ← 洞察
|
|
143
|
+
├── idea/ ← 未成型灵感
|
|
144
|
+
├── lesson/ ← 经验教训
|
|
145
|
+
├── techchoice/ ← 技术选型(Options 候选表 + Active)
|
|
146
|
+
└── .meta/weights.json ← 学习权重(点目录,不污染 OKF 符合性)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
概念 ID 就是相对路径(如 `fact/门店布局`),交叉链接用包内绝对路径 `[文字](/fact/门店布局.md)`。
|
|
150
|
+
|
|
151
|
+
## 可视化图谱
|
|
152
|
+
|
|
153
|
+
`/okf graph` 生成**单文件自包含** HTML(无 CDN、无构建产物),双击即可打开或分享:
|
|
154
|
+
|
|
155
|
+
- 节点大小 = 权重,颜色 = 类型,虚线描边 = 已归档
|
|
156
|
+
- 悬停看详情,滚轮缩放,拖拽平移,可拖动节点
|
|
157
|
+
- 搜索命中 → 白边 + 脉冲光环 + `⚡命中`,并沿交叉链接 **BFS 传导**点亮关联记忆
|
|
158
|
+
|
|
159
|
+
## 配置
|
|
160
|
+
|
|
161
|
+
| 项 | 方式 | 默认 |
|
|
162
|
+
|---|---|---|
|
|
163
|
+
| 记忆库根目录 | 环境变量 `OKF_MEMORY_ROOT` | `~/.pi/agent/okf-memory/` |
|
|
164
|
+
| 学习参数 | `src/server/learning.ts` 的 `PARAMS` | 见上「权重学习」 |
|
|
165
|
+
|
|
166
|
+
调参入口都集中在 `PARAMS`:`SELECT_DELTA` / `SKIP_DELTA` / `HIT_DELTA` / `DECAY_DAYS` / `DECAY_FACTOR` / `ARCHIVE_THRESHOLD` / `ARCHIVE_RECOVER` / `CONSOLIDATE_INTERVAL_MS`。
|
|
167
|
+
|
|
168
|
+
## 同一份核心也驱动 dsh 插件
|
|
169
|
+
|
|
170
|
+
运行时无关的核心(`src/server/*`)零宿主耦合 —— 外部依赖只有 `node:fs` / `node:path` / `node:os`,只有 `src/server/index.ts` 是 dsh 适配层。因此 dsh 插件 `dsh-okf-memory` 与 pi 扩展 `pi-okf-memory` 共享同一实现:
|
|
171
|
+
|
|
172
|
+
| | pi(本仓库主场) | dsh |
|
|
173
|
+
|---|---|---|
|
|
174
|
+
| 适配层 | `src/pi/index.ts` | `src/server/index.ts` |
|
|
175
|
+
| 默认记忆库 | `~/.pi/agent/okf-memory/` | `~/.dsh/memory/` |
|
|
176
|
+
| 提示注入 | `pi.on("before_agent_start")` | `ctx.systemPrompt.section()` |
|
|
177
|
+
| 图谱 | `/okf graph` 导出 HTML | web 对话视图标签 |
|
|
178
|
+
| 工具 | 6 | 5 |
|
|
179
|
+
|
|
180
|
+
`OKF_MEMORY_ROOT` 两个宿主都认 —— 指向同一目录即可共享记忆库。
|
|
181
|
+
|
|
182
|
+
## 开发与测试
|
|
183
|
+
|
|
184
|
+
```sh
|
|
185
|
+
pnpm install
|
|
186
|
+
pnpm test # typecheck + build + 6 套件,250 断言,离线确定性
|
|
187
|
+
pnpm test:e2e # 真实模型端到端(需 token),9 断言
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
| 层 | 脚本 | 证明什么 |
|
|
191
|
+
|---|---|---|
|
|
192
|
+
| 类型对账 | `tsc -p tsconfig.typecheck.json` | 适配层用法符合 **pi 真实 `.d.ts`** |
|
|
193
|
+
| 核心功能 | `scripts/smoke.js` | store / concept / dedupe / learning / recall / graph |
|
|
194
|
+
| dsh 集成 | `scripts/integration.js` | mock dsh ctx 下 5 工具全链路 |
|
|
195
|
+
| pi 集成 | `scripts/pi-integration.js` | mock pi API 下 6 工具 + 4 命令 + schema 校验 |
|
|
196
|
+
| **pi 真实 RPC** | `scripts/pi-rpc-commands.js` | 命令真的被**真实 pi 进程**识别并执行 |
|
|
197
|
+
| **真实模型 E2E** | `scripts/pi-e2e-model.js` | 模型真的调工具、真的落盘、真的跨会话召回 |
|
|
198
|
+
|
|
199
|
+
**为什么必须有最后两层**:自写 mock 只能证明「代码符合我的假设」,证明不了假设本身。本项目的第一个真实 bug 就是这样漏掉的 —— 模型从不知道要传 `related` 参数,导致真实使用下图谱恒为零边孤岛,而 mock 测试全绿。
|
|
200
|
+
|
|
201
|
+
**注意**:`tsdown`(rolldown)只剥离类型、不做类型检查,所以 `pnpm build` 通过 ≠ 类型正确,`typecheck` 是独立一层。
|
|
202
|
+
|
|
203
|
+
## 发布到 npm
|
|
204
|
+
|
|
205
|
+
发布由 `.github/workflows/npm-publish.yml` 负责,认证走 **Trusted Publishing(OIDC)—— 不需要任何 npm token**。
|
|
206
|
+
|
|
207
|
+
### 为什么不用 token
|
|
208
|
+
|
|
209
|
+
npm 在 2026 年收紧了 token 发布:
|
|
210
|
+
|
|
211
|
+
- 自 2025-11 起不再支持经典 access token,只认 granular token
|
|
212
|
+
- granular token 里「绕过 2FA」的那类,自 2026-07-31 起也**不能再直接发布**
|
|
213
|
+
(实测报 `403 You may not perform that action with these credentials`)
|
|
214
|
+
|
|
215
|
+
所以 CI 发布的正路是 OIDC:npm 用本次 workflow 的 OIDC 身份换一个短时 token,
|
|
216
|
+
无需存储任何长期凭据。workflow 里所需的全部权限就是 `id-token: write`。
|
|
217
|
+
|
|
218
|
+
### 首次使用前:在 npmjs.com 配一次 Trusted Publisher
|
|
219
|
+
|
|
220
|
+
打开 **https://www.npmjs.com/package/pi-okf-memory/access** → `Trusted Publisher` → 选 GitHub Actions,填:
|
|
221
|
+
|
|
222
|
+
| 字段 | 值 |
|
|
223
|
+
|---|---|
|
|
224
|
+
| Organization or user | `ZHI-QI` |
|
|
225
|
+
| Repository | `pi-okf-memory` |
|
|
226
|
+
| Workflow filename | `npm-publish.yml`(只填文件名,不带路径) |
|
|
227
|
+
| Environment name | 留空 |
|
|
228
|
+
| Allowed actions | 勾上 **`npm publish`** |
|
|
229
|
+
|
|
230
|
+
> 这个配置动作本身**需要 2FA**,所以只能人工在网页完成一次。
|
|
231
|
+
> 该端点对**尚未发布**的包名也可用 —— 也就是说可以先配好,再让 CI 发第一个版本。
|
|
232
|
+
|
|
233
|
+
### 之后两条发布路径
|
|
234
|
+
|
|
235
|
+
| 方式 | 行为 |
|
|
236
|
+
|---|---|
|
|
237
|
+
| 发一个 GitHub Release | 自动发布到 npm(打 `latest` 标签) |
|
|
238
|
+
| Actions → npm-publish → Run workflow | 默认 `dry_run = true` 只做校验;确认后把开关关掉再跑 |
|
|
239
|
+
|
|
240
|
+
workflow 会在发布前依次拦截:
|
|
241
|
+
|
|
242
|
+
- `pnpm test` 全绿(typecheck + 构建 + 266 断言;含需要真实 `pi` 进程的 RPC 测试层)
|
|
243
|
+
- npm 版本 < 11.5.1 → 拦(trusted publishing 的硬要求)
|
|
244
|
+
- Release tag 与 `package.json` 版本不一致 → 拦
|
|
245
|
+
- 该版本已存在于 npm → 拦(防重复发布)
|
|
246
|
+
- **包内容缺少 `src/` 或 `lib/` → 拦**
|
|
247
|
+
|
|
248
|
+
最后一条是关键守卫:`lib/` 在 `.gitignore` 里,CI 是干净 checkout。
|
|
249
|
+
`package.json` 的 `prepublishOnly` 会在 `npm publish` 时自动构建,避免发出残缺包。
|
|
250
|
+
|
|
251
|
+
### 本地发布
|
|
252
|
+
|
|
253
|
+
本地发布需要交互式 2FA,适合首次破壳或 token 路子完全走不通时:
|
|
254
|
+
|
|
255
|
+
```sh
|
|
256
|
+
npm login # 浏览器 / OTP 完成 2FA
|
|
257
|
+
npm publish --access public
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
已有一个 `node scripts/release.mjs` 脚本(bump 版本 → 构建 → dry-run → 发布),但它走 token 路子,
|
|
261
|
+
在当前的 npm 政策下**已不可用**,仅作参考保留。
|
|
262
|
+
|
|
263
|
+
## License
|
|
264
|
+
|
|
265
|
+
MIT
|
package/cordis.patch.yml
ADDED
|
Binary file
|
package/lib/capture.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//#region src/server/capture.ts
|
|
2
|
+
/**
|
|
3
|
+
* capture.ts — 记忆纪律(系统提示片段)与捕获评估。
|
|
4
|
+
* 神经自我学习驱动:捕获由"预测误差"驱动 —— 用户纠正、首次披露、反直觉结论
|
|
5
|
+
* 都是模型预测失败的信号,内在动机触发写入;取代固定规则表。
|
|
6
|
+
*/
|
|
7
|
+
/** 注入系统提示的"记忆纪律"片段(Agent 自主决定何时调用 okf_remember) */
|
|
8
|
+
const MEMORY_DISCIPLINE = `
|
|
9
|
+
# 记忆纪律(okf-memory)
|
|
10
|
+
|
|
11
|
+
你有一个 OKF 长期记忆库。记忆不靠自动记录,而靠你判断"本轮是否产生了值得沉淀的新知识"。
|
|
12
|
+
|
|
13
|
+
## 值得记忆(高价值信号,写!)
|
|
14
|
+
- 用户给出新背景事实 / 偏好 / 习惯(首次披露)
|
|
15
|
+
- 达成的决策及理由(尤其用户明确拍板的事项)
|
|
16
|
+
- 可复用方法论 / 流程 / 经验教训
|
|
17
|
+
- 用户纠正了你的理解(这是最强的"预测误差"信号)
|
|
18
|
+
- 反直觉但被用户确认的结论
|
|
19
|
+
- 技术选型:用户提到前端/后端/语言/方案/配置的选择、切换、配置细节
|
|
20
|
+
|
|
21
|
+
## 不值得记忆(不写)
|
|
22
|
+
- 寒暄、过程性问答、单轮临时任务
|
|
23
|
+
- 已记忆内容的重复表述(先搜再写,命中则跳过)
|
|
24
|
+
- 未验证的猜测、尚未落地的设想(可归入 Idea 类型等待成熟)
|
|
25
|
+
|
|
26
|
+
## 写入纪律
|
|
27
|
+
1. 写入前必先 okf_search:命中同标题 → 不新建,更新或跳过;命中相近 → 互补合并或互建交叉链接
|
|
28
|
+
2. 每篇必须:type 非空、title 简洁、description 一句话摘要(检索全靠它)、正文结构化(标题/列表/表格)
|
|
29
|
+
3. type 词表:Fact 背景事实 / Preference 偏好 / Decision 决策 / Method 方法论 / Insight 洞察 / Idea 灵感 / Lesson 教训 / TechChoice 技术选型
|
|
30
|
+
4. 正文模板:Decision/Insight 用 # 数据 → # 分析 → # 结论 三段式;TechChoice 用 # Options 候选表 + # Active 当前使用;其余自由结构化
|
|
31
|
+
5. **交叉链接必须显式传 related 参数**:新建概念时,把 okf_search 命中的相关概念 ID 填进
|
|
32
|
+
related(如 related: ["fact/门店布局"])。工具会自动双向建立「## 相关」链接。
|
|
33
|
+
- 正文里手写路径 **不会** 生成图谱边 —— 图谱的边只来自 related 写入的链接。
|
|
34
|
+
- 一次会话里新建多条互相相关的概念时,后建的必须把先建的 ID 放进 related。
|
|
35
|
+
- 若 okf_remember 返回 status="linked",说明命中相近概念,用返回的 similarTo 作 related 重新提交(不要重复写正文)。
|
|
36
|
+
|
|
37
|
+
## 技术选型三档规则(用户既定协议,硬性执行)
|
|
38
|
+
1. 命中 2+ 候选 → 全部展示给用户选择(带说明/配置/状态),绝不擅自决定
|
|
39
|
+
2. 命中 1 个候选 → 直接使用
|
|
40
|
+
3. 用户未指定技术,但消息命中维度关键词(如"前端")→ 按该维度记忆处理
|
|
41
|
+
4. 用户说出新技术/切换/配置 → okf_remember 追加式更新,不覆盖旧候选
|
|
42
|
+
5. 用户拍板后,记录选择反馈(权重自动更新,下次排序靠前)
|
|
43
|
+
|
|
44
|
+
## 唤起纪律
|
|
45
|
+
- 会话开场先 okf_search 预取相关记忆,再开始干活
|
|
46
|
+
- 检索不到 → 明确告知"记忆库没有",不要编造
|
|
47
|
+
`.trim();
|
|
48
|
+
/** 预取提示:会话启动时建议先搜什么(低优先级,供摘要注入用) */
|
|
49
|
+
const RECALL_GUIDE = `
|
|
50
|
+
记忆库概念清单见本片段顶部(okf-memory index)。需要细节时用 okf_read <concept_id>。
|
|
51
|
+
`.trim();
|
|
52
|
+
//#endregion
|
|
53
|
+
export { MEMORY_DISCIPLINE, RECALL_GUIDE };
|