dsh-cortex-memory 0.1.0 → 0.2.0-rc.13

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 (56) hide show
  1. package/LICENSE +3 -3
  2. package/README.md +85 -146
  3. package/bench/ab-engine.mjs +60 -0
  4. package/bench/ann-bench.mjs +78 -0
  5. package/bench/hnsw-bench.mjs +79 -0
  6. package/bench/metrics.js +8 -0
  7. package/bench/migration-bench.mjs +69 -0
  8. package/bench/run.js +5 -2
  9. package/bench/synthetic.js +51 -7
  10. package/bench/vector-ab.mjs +76 -0
  11. package/bin/cortex.mjs +2 -3
  12. package/client.js +286 -4
  13. package/cordis.patch.yml +1 -1
  14. package/docs/install-windows.md +115 -27
  15. package/docs/models.md +165 -30
  16. package/docs/multimodal.md +112 -0
  17. package/docs/scopes.md +142 -0
  18. package/examples/README.md +72 -0
  19. package/examples/setup-cortex-bge.ps1 +66 -0
  20. package/examples/uninstall-cortex.ps1 +91 -0
  21. package/index.js +15 -1
  22. package/package.json +5 -12
  23. package/src/adapters/markdown-import.js +20 -1
  24. package/src/adapters/markdown.js +12 -2
  25. package/src/adapters/shiori.js +1 -1
  26. package/src/api/routes.js +148 -4
  27. package/src/api/validate.js +26 -0
  28. package/src/core/attachment-reader.js +31 -0
  29. package/src/core/attachments.js +39 -0
  30. package/src/core/config.js +36 -1
  31. package/src/core/model-config.js +3 -1
  32. package/src/core/profile.js +32 -0
  33. package/src/engines/develop.js +1 -1
  34. package/src/engines/encode.js +68 -30
  35. package/src/engines/extract.js +13 -8
  36. package/src/engines/growth.js +1 -1
  37. package/src/engines/reflect.js +1 -1
  38. package/src/engines/retrieve.js +44 -13
  39. package/src/host/runtime.js +1 -1
  40. package/src/memory/query.js +1 -1
  41. package/src/memory/tokenizer.js +19 -4
  42. package/src/security/scope-grants.js +73 -0
  43. package/src/self/appraisal.js +3 -3
  44. package/src/self/emotion.js +1 -1
  45. package/src/self/identity.js +1 -1
  46. package/src/self/relationship.js +2 -2
  47. package/src/service/cortex.js +191 -3
  48. package/src/store/database.js +33 -1
  49. package/src/store/repositories/edges.js +48 -4
  50. package/src/store/repositories/traces.js +23 -12
  51. package/src/store/schema.sql +1 -0
  52. package/src/tools/definitions.js +64 -5
  53. package/src/vector/external-ann.js +37 -0
  54. package/src/vector/hnsw.js +246 -0
  55. package/src/vector/index.js +85 -2
  56. package/docs/compatibility.md +0 -39
@@ -1,56 +1,144 @@
1
- # Windows install
1
+ # Windows 安装与回滚
2
2
 
3
- ## Requirements
3
+ > 目标:和本鲸一样的 Windows DSH 用户,能从 tgz 直接安装,不需要编译、不需要原生依赖。
4
+ > 前提:**Node >= 24**(`node:sqlite` 内置)、DSH `>=0.2.1-rc.2 <0.4.0`、Windows 10/11。
4
5
 
5
- - Windows 10/11
6
- - Node.js **>= 24** (DSH ships a compatible runtime on current builds)
7
- - DSH `>=0.2.1-rc.2 <0.4.0`
6
+ ## 1. 先备份
8
7
 
9
- ## Install from a release tgz
8
+ ```powershell
9
+ $stamp = Get-Date -Format 'yyyyMMdd-HHmm'
10
+ Copy-Item -Recurse "$env:USERPROFILE\.dsh\profiles\desktop" "$env:USERPROFILE\Desktop\dsh-profile-backup-$stamp"
11
+ ```
12
+
13
+ `dsh-cortex` 默认数据在 `~/.dsh/cortex`,**不读写 shiori 的 `D:\shiori-data`**。第一次安装没有旧数据,不需要迁移。
14
+
15
+ ## 2. 生成/取得 tgz
16
+
17
+ 在 `plugins/dsh-cortex`:
18
+
19
+ ```powershell
20
+ npm pack
21
+ # 产出 dsh-cortex-0.2.0-dev.1.tgz
22
+ ```
23
+
24
+ 如果用本鲸打好的包,直接用 `dist/dsh-cortex-0.2.0-dev.1.tgz`。包是纯 JS + SQL,无 `node_modules` 依赖。
25
+
26
+ ## 3. 安装到 desktop profile
10
27
 
11
28
  ```powershell
12
- dsh plugin --profile desktop add "C:\path\to\dsh-cortex-memory-0.1.0.tgz"
29
+ dsh plugin --profile desktop add "C:\完整路径\dsh-cortex-0.2.0-dev.1.tgz"
13
30
  ```
14
31
 
15
- If `dsh` is not on PATH, install through **DSH → Settings → Plugins → Install**
16
- and select the same tgz.
32
+ 路径必须是**绝对路径**。装完重启 DSH。不要用 `link:` 去指向一个会被清理的目录。
17
33
 
18
- ## Verify
34
+ ## 4. 验收
35
+
36
+ 重启后:
37
+
38
+ 1. 模型工具列表出现 21 个 `cortex_*`(至少 `cortex_write` / `cortex_search` / `cortex_as_of` / `cortex_playbook` / `cortex_consolidate`)。
39
+ 2. 侧栏/插件面板能看到 Cortex。
40
+ 3. 写一条测试记忆:
41
+
42
+ ```text
43
+ cortex_write({ text: "安装验收:主人喜欢白饭。", explicit: true })
44
+ cortex_search({ query: "白饭" })
45
+ cortex_self({})
46
+ cortex_guard({ action: "check" })
47
+ ```
48
+
49
+ 4. API(默认只回环):
19
50
 
20
51
  ```powershell
21
- dsh plugin --profile desktop list
52
+ curl.exe http://127.0.0.1:7430/api/cortex/health
22
53
  ```
23
54
 
24
- Expected: the `cortex` entry is enabled and active. Then open the Cortex panel
25
- and run **Guardian → check**.
55
+ 期望 `{"ok":true,...}` 且没有 shiori 数据被写。
26
56
 
27
- ## Data
57
+ ## 5. 可选:开 LLM 巩固
28
58
 
29
- Default data root:
59
+ 默认 `features.llm=false`,巩固会记录 `skipped` 且零改动。可以在面板「设置 → 权限」点按钮,确认后写入:
30
60
 
31
61
  ```text
32
- %USERPROFILE%\.dsh\cortex
62
+ <dataRoot>/feature-overrides.json
33
63
  ```
34
64
 
35
- It is separate from any other memory plugin's data. Do not point two memory
36
- plugins at the same SQLite file.
65
+ **重启 DSH 后生效**;同一页可以回滚上一次权限修改,审计记录在本地 `audit` 表。
66
+ 也可以用配置:
67
+
68
+ ```yaml
69
+ - id: cortex
70
+ name: dsh-cortex
71
+ config:
72
+ features:
73
+ llm: true
74
+ consolidateOnSleep: true
75
+ ```
37
76
 
38
- ## Upgrade
77
+ 开之前先确认当前 DSH 的模型路由可用。失败会跳过,不阻塞睡眠。
78
+
79
+ ## 6. 回滚
39
80
 
40
81
  ```powershell
41
- dsh plugin --profile desktop add "C:\path\to\dsh-cortex-memory-0.2.0.tgz"
82
+ dsh plugin --profile desktop remove dsh-cortex
42
83
  ```
43
84
 
44
- Back up the data root before major upgrades:
85
+ 重启。`~/.dsh/cortex` 不会被自动删除;确认不要后再手动处理。要恢复 profile,拷回第 1 步的备份。
86
+
87
+ ### 卸载后清理手写 patch
88
+
89
+ 如果你在 `cordis.patch.yml` 里手写过 cortex 配置,`dsh plugin remove` **不会删这段**。残留块通常不影响 `--dump-config`,但会让 diff 变脏,重装时也可能踩到“entry not found”。
90
+
91
+ 可以用脚本:
92
+
93
+ ```powershell
94
+ powershell -ExecutionPolicy Bypass -File .\examples\uninstall-cortex.ps1 `
95
+ -Dsh "D:\path\to\dsh.cmd" -Profile <profile>
96
+ ```
97
+
98
+ 脚本只删 `- id: cortex` 段,保留其他 patch,并跑一次 `--dump-config`;不删 dataRoot。已手动移除时也会跳过 remove、继续清 patch。
99
+
100
+ 卸载后检查:
45
101
 
46
102
  ```powershell
47
- Copy-Item "$env:USERPROFILE\.dsh\cortex" "$env:USERPROFILE\Desktop\cortex-backup" -Recurse
103
+ notepad "$HOME\.dsh\profiles\<profile>\cordis.patch.yml"
104
+ ```
105
+
106
+ 删除整段:
107
+
108
+ ```yaml
109
+ - id: cortex
110
+ name: dsh-cortex
111
+ config:
112
+ ...
48
113
  ```
49
114
 
50
- ## Rollback
115
+ 保留其他条目;如果文件只剩注释,写回:
116
+
117
+ ```yaml
118
+ []
119
+ ```
120
+
121
+ 然后再跑一次:
122
+
123
+ ```powershell
124
+ dsh --profile <profile> --dump-config > $null
125
+ ```
126
+
127
+ 不要为了清理 patch 去删整个 profile 目录;dataRoot 可能不在 profile 内。
128
+
129
+ ## 7. 常见问题
130
+
131
+ | 现象 | 原因 | 处理 |
132
+ |---|---|---|
133
+ | 装完没有工具 | 插件条目没 active / 重启没做 | 看 profile 的 bundles,重启 DSH |
134
+ | `node:sqlite` 报错 | Node < 24 或运行时不带 SQLite | 升级 DSH/Node 到 24+ |
135
+ | 工具名冲突 | 另一个插件也注册同名工具 | 先停用旧插件,或改名后再装 |
136
+ | 数据目录不对 | 改过 `dataRoot` | 用绝对路径,不要指向 profile 内部 |
137
+ | 面板 403 | 非回环 Host / 跨源 | 用 `127.0.0.1`,同源打开 |
51
138
 
52
- 1. Disable the `cortex` entry in the DSH plugin manager.
53
- 2. Re-enable the previous plugin entry if needed.
54
- 3. Restore the profile configuration and data backup.
139
+ ## 8. 兼容性说明
55
140
 
56
- The plugin never modifies another plugin's data.
141
+ - 这是 **bundle 插件**:`dsh.bundle.patch` 指向 `cordis.patch.yml`,装完自动注册 Host 行。
142
+ - 零运行时 npm 依赖;SQLite 用 Node 内置。
143
+ - Windows 路径手写 `C:\...` 即可;包内没有 shell 脚本。
144
+ - 不修改全局 patch,不覆盖系统提示,不碰 shiori。
package/docs/models.md CHANGED
@@ -1,48 +1,183 @@
1
- # Optional models
1
+ # 可选模型:embedder / rerank
2
2
 
3
- ## Default: hash
3
+ > 结论先说:**安装包不自动下载模型,也不默认联网。**
4
+ > 大模型动辄几百 MB,自动下载会把“装插件”变成“装模型”,还可能带来磁盘、网络、校验和更新问题。
5
+ > 本插件只提供可插拔接口;用户显式配置后才使用。
4
6
 
5
- No model, no network. Uses a local lexical hash embedder.
7
+ ## 0. 当前接线状态(2026-11-11)
6
8
 
7
- ## Local: Ollama bge-m3
9
+ - HTTP rerank:**已接到 QA**(`cortex_qa`),默认关,失败开放。
10
+ - HTTP embedder:**接口已实现**(`createOpenAIEmbedder`);**异步索引入口** `POST /vector/index` / `POST /vector/rebuild` 已可用,写不会被网络阻塞;**异步混合检索** `GET /search?async=true` 与 QA 已走 `searchAsync`(远程向量可参与);默认同步 `/search` 仍不等待网络。
11
+ - 安装包**不自动下载**任何模型。
8
12
 
9
- ```powershell
10
- ollama pull bge-m3
13
+ ## 1. 默认路径(零依赖)
14
+
15
+ - `features.vector = false`:不用向量,FTS5 + 图 + recent 融合。
16
+ - `features.vector = true`:使用内置 `hash-256` embedder(词法哈希,**不是语义模型**)。
17
+ - 不下载任何文件;不需要 `node_modules`;Windows 直接可用。
18
+
19
+ ## 2. 可选 HTTP embedder
20
+
21
+ 代码:`src/vector/providers.js` 的 `createOpenAIEmbedder`。
22
+
23
+ 接口是 OpenAI-compatible `/embeddings`:
24
+
25
+ ```http
26
+ POST {baseUrl}/embeddings
27
+ Authorization: Bearer <apiKey>
28
+ {"model":"bge-m3","input":["文本"]}
11
29
  ```
12
30
 
13
- Settings:
31
+ 返回:
14
32
 
15
- ```text
16
- mode: local
17
- baseUrl: http://127.0.0.1:11434/v1
18
- model: bge-m3
19
- dim: 1024
20
- key: (blank)
33
+ ```json
34
+ {"data":[{"embedding":[0.1,0.2]}]}
21
35
  ```
22
36
 
23
- `bge-m3` supports Chinese and multilingual text. A smaller fallback is
24
- `nomic-embed-text` (768 dimensions), but it is weaker on Chinese.
37
+ 它不会在安装时运行。要接本地服务(如 Xinference / Ollama 的 OpenAI 兼容层 / vLLM),由用户自己启动服务并提供 `baseUrl`。
38
+ **不要把 API key 写进仓库或安装包。**
39
+
40
+ ## 2.1 本地 bge 可选配置(默认关)
41
+
42
+ 本机实测用 Ollama 的 `bge-m3`(1024 维)通过 OpenAI 兼容 `/v1/embeddings` 接入。
25
43
 
26
- ## Remote: OpenAI-compatible `/embeddings`
44
+ ### profile 配置
45
+
46
+ ```yaml
47
+ - id: cortex
48
+ name: dsh-cortex
49
+ config:
50
+ features:
51
+ vector: true
52
+ # dataRoot / dbFile 按你的 profile 配
53
+ ```
54
+
55
+ ### 模型配置
56
+
57
+ 在 cortex 的 dataRoot 下放 `model-config.json`(可在面板模型设置里保存,效果相同):
58
+
59
+ ```json
60
+ {
61
+ "embedding": {
62
+ "mode": "local",
63
+ "baseUrl": "http://127.0.0.1:11434/v1",
64
+ "model": "bge-m3",
65
+ "dim": 1024,
66
+ "apiKey": ""
67
+ },
68
+ "rerank": {
69
+ "enabled": false,
70
+ "baseUrl": "",
71
+ "model": "",
72
+ "apiKey": ""
73
+ }
74
+ }
75
+ ```
76
+
77
+ - `mode: local` 表示本地 keyless 服务;不要把云端 key 写进仓库。
78
+ - 不配模型时,`features.vector=true` 只会用内置 `hash-256` 词法哈希,**不是语义模型**。
79
+ - 向量索引是暴力扫描,适合个人千条级记忆;不是十亿级 ANN。
80
+
81
+ ### 实测代价(2026-11-11,300 traces / 50 paraphrase queries)
27
82
 
28
83
  ```text
29
- mode: remote
30
- baseUrl: https://your-provider.example/v1
31
- model: your-embedding-model
32
- dim: provider dimension
33
- key: required
84
+ FTS: hit 0.96 / MRR 0.694 / nDCG 0.603 / p50 4.5-4.8ms
85
+ bge: hit 1.00 / MRR 0.960 / nDCG 0.883 / p50 51-63ms
86
+ ```
87
+
88
+ - 语义召回明显提升,但查询延迟约 10 倍。
89
+ - 这是合成 paraphrase,不是 LoCoMo;不能当公开 SOTA。
90
+ - 默认仍关闭;没有本地模型/服务就不要开。
91
+
92
+ ## 2.2 可选 ANN(默认关)
93
+
94
+ ```yaml
95
+ features:
96
+ vector: true
97
+ vectorAnn: true
98
+ vectorAnnMin: 20000
99
+ vectorAnnEngine: hnsw
100
+ ```
101
+
102
+ - 复用 `src/vector/ann.js` 的单层 NSW 索引;纯 JS,无原生依赖。
103
+ - 小于 `vectorAnnMin` 时仍走暴力精确扫描。
104
+ - ANN 命中不足 5 条时自动回退暴力扫描,避免 scope/过滤把结果卡空。
105
+ - 首次搜索从 embeddings 懒构建;写入/删除会同步索引。
106
+ - 默认 `vectorAnn: false`;不开启时行为不变。
107
+ - 当前验证是单元/小规模,不是 100k ANN 压测;大库收益和召回还需单独 benchmark。
108
+ - 5000 条 A/B 结论(dim 64):ANN ef=120 recall@10 0.29,ef=400 0.70(p50 0.99ms,暴力 1.11ms),ef=800 0.93(p50 2.73ms,暴力 1.16ms),ef=1600 0.998(p50 11ms)。**小库暴力反而更快**,所以默认阈值放在 20000,且 ANN 默认关。
109
+ - 20k / 100k 复验(ef=800/1600):20k recall 0.591(ANN p50 5.4ms,暴力 9.2ms);100k recall 0.413(ANN p50 10.9ms,暴力 38.9ms,构建约 101s)。
110
+ - HNSW 候选(`src/vector/hnsw.js`,二叉堆版)在 5k/20k 的质量:
111
+ - 5k:recall 0.997,build 5.5s,p50 2.24ms(暴力 1.15ms)
112
+ - 20k:recall 0.956,build 58.4s,p50 4.88ms(暴力 5.78ms)
113
+ - 所以 `vectorAnnEngine: hnsw` 已接到可选路径,但 **`vectorAnn` 仍默认关**;HNSW 冷构建慢,20k 以下没明显查询优势。
114
+ - 旧 NSW 保留为 `vectorAnnEngine: nsw` 的兼容选项,不再是默认引擎。
115
+ - 100k 构建/内存尚未验证;不建议在生产库直接开。
116
+
117
+ ### 外置 ANN(默认关)
118
+
119
+ ```yaml
120
+ features:
121
+ vector: true
122
+ vectorAnnExternal: true
123
+ vectorAnnEndpoint: 'http://127.0.0.1:8765/search'
124
+ vectorAnnTimeoutMs: 800
34
125
  ```
35
126
 
36
- The remote mode refuses to save without a key. The key is stored locally and
37
- redacted from API responses.
127
+ - 只接 `searchAsync` 异步路径;同步 `search` 继续精确扫描。
128
+ - 端点为空或请求失败 → 回退精确扫描,不丢召回。
129
+ - 客户端契约见 `docs/external-ann.md`。
130
+ - **需要你手动启动本地 ANN 服务**;当前没有常驻服务。
131
+ - 20k 端到端验证:recall@10 1.0,p50 20.3-20.8ms(HTTP 客户端 + HNSW 服务)。
132
+
133
+ ## 3. 可选 HTTP rerank(已接到 QA)
134
+
135
+ 代码:`createHttpReranker`,已在 `cortex_qa` 的检索结果上生效(失败开放,回退融合顺序)。
136
+
137
+ 配置:
138
+
139
+ ```yaml
140
+ - id: cortex
141
+ name: dsh-cortex
142
+ config:
143
+ rerankEnabled: true
144
+ rerankBaseUrl: "http://127.0.0.1:9000/v1"
145
+ rerankModel: "bge-reranker-base"
146
+ # rerankApiKey: "" # 本机服务通常不需要
147
+ ```
148
+
149
+ 接口:
150
+
151
+ ```http
152
+ POST {baseUrl}/rerank
153
+ {"model":"bge-reranker-base","query":"...","documents":["..."],"top_n":8}
154
+ ```
155
+
156
+ 返回 `results: [{index, relevance_score}]`。
157
+
158
+ 默认关;没有配置或请求失败时,QA 保持原来的 RRF 顺序,不阻塞回答。
159
+
160
+ ## 4. 本地 ONNX 模型(未内置)
161
+
162
+ 本鲸没有把 `onnxruntime-node` 或 `@huggingface/transformers` 放进运行时依赖,原因:
163
+
164
+ - 安装体积大(数百 MB);
165
+ - Windows 上原生二进制/驱动差异;
166
+ - 安装期下载模型不可审计。
167
+
168
+ 后续如果要内置,应该是**单独的 optional 包**,并满足:
38
169
 
39
- ## Rerank (optional)
170
+ 1. 用户显式点“下载模型”;
171
+ 2. 显示 URL、大小、SHA-256;
172
+ 3. 下载到 `~/.dsh/cortex/models/`,不写 profile;
173
+ 4. 失败开放,不影响 FTS;
174
+ 5. 可一键删除。
40
175
 
41
- Any OpenAI-compatible `/rerank` service can be configured. If it is disabled or
42
- fails, Cortex keeps the original fusion order.
176
+ ## 5. 安装包里有什么
43
177
 
44
- ## Security
178
+ - 没有模型文件;
179
+ - 没有原生 `.node`;
180
+ - 没有 `node_modules`;
181
+ - 只有纯 JS + SQL + 文档。
45
182
 
46
- - Do not paste keys into issues or chat logs.
47
- - Local mode is the safest for private data.
48
- - Remote mode sends memory text to the configured endpoint.
183
+ 所以 Windows 用户装完即可用;要用语义模型时再按上面的配置接服务。
@@ -0,0 +1,112 @@
1
+ # 多模态附件:只存引用,不存字节
2
+
3
+ > 当前实现是**元数据边界**,不是视觉/音频理解模型。
4
+
5
+ ## 1. 写入
6
+
7
+ `cortex_write` / `POST /api/cortex/write` 支持 `attachments`:
8
+
9
+ ```json
10
+ {
11
+ "text": "主人发来一张白饭照片。",
12
+ "explicit": true,
13
+ "attachments": [
14
+ {
15
+ "kind": "image",
16
+ "uri": "https://example.test/rice.png",
17
+ "name": "rice.png",
18
+ "mime": "image/png",
19
+ "bytes": 12345,
20
+ "sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
21
+ }
22
+ ]
23
+ }
24
+ ```
25
+
26
+ 约束:
27
+
28
+ - 最多 8 个
29
+ - `kind`: image / audio / video / file
30
+ - `uri` 必填,最长 2000
31
+ - `sha256` 必须是 64 位 hex
32
+ - `bytes` 0..1e9
33
+ - **不读取、不下载、不解析 URI**
34
+ - 不把二进制写进 SQLite
35
+
36
+ ## 2. 存储
37
+
38
+ 落在 `traces.metadata_json.attachments`:
39
+
40
+ ```json
41
+ {
42
+ "attachments": [
43
+ {"kind": "image", "uri": "https://example.test/rice.png", "mime": "image/png", "bytes": 12345}
44
+ ]
45
+ }
46
+ ```
47
+
48
+ 没有单独附件表,也没有内容寻址存储。旧库会通过 `ensureTraceColumns` 自动补 `metadata_json` 列,默认 `{}`。
49
+
50
+ ## 3. 当前能做什么
51
+
52
+ - 记录“这条记忆关联了哪些附件”的引用
53
+ - 在 trace 读取时返回 metadata
54
+ - 在写入结果里报告附件数量
55
+ - 为未来的视觉/音频模型留出入口
56
+
57
+ ## 4. 当前不能做什么
58
+
59
+ - 不能读取图片/音频内容
60
+ - 不能生成缩略图
61
+ - 不能做 OCR / 语音转写
62
+ - 不能校验 URI 指向的内容
63
+ - 不能防止恶意 URI(调用方自己负责)
64
+ - 不能自动下载模型
65
+
66
+ ## 5. 安全边界
67
+
68
+ - 附件只是引用,不是可信内容
69
+ - 不要把私密 URL、token、签名参数写进 uri
70
+ - 隐私删除 trace 时,metadata 随 trace 一起离开;外部 URI 上的文件不在 cortex 控制内
71
+ - 导出 Markdown 是否包含附件元数据,后续再定
72
+
73
+ ## 5.1 可选本地读取器(默认关)
74
+
75
+ ```yaml
76
+ features:
77
+ attachmentReader: true
78
+ ```
79
+
80
+ ```http
81
+ POST /api/cortex/attachments/inspect
82
+ {"uri":"file:///C:/path/rice.txt"}
83
+ ```
84
+
85
+ - **只接受 `file://`**
86
+ - 只返回 name/bytes/mtime/sha256
87
+ - 不返回文件内容
88
+ - 最大 50MB
89
+ - 默认关;未开启 403
90
+ - 写入 audit:`attachment.inspect`
91
+
92
+ 这不是 OCR/转写。它只做本地文件元数据与哈希校验,方便把附件引用和实际文件对上。
93
+
94
+ ## 5.2 提取器联动(可选)
95
+
96
+ 独立包 `dsh-cortex-extractors` 的 `cortex_extract_text` 支持显式 `traceId`:
97
+
98
+ ```json
99
+ {"uri":"file:///C:/tmp/frame.png","mode":"ocr","traceId":"trc_target"}
100
+ ```
101
+
102
+ - 主脑写入一条 **派生 trace**(不修改原 trace)
103
+ - metadata 保留 `derivedFrom`、URI、mode、engine
104
+ - 需要提取器与主脑同时启用
105
+ - 不传 `traceId` 时仍只返回文字,不写记忆
106
+
107
+ ## 6. 下一步
108
+
109
+ 1. 可选附件读取器接口(本地、显式开启)
110
+ 2. 图片缩略图/OCR 作为独立可选包
111
+ 3. 附件级删除/保留策略
112
+ 4. 与 bge 一样:默认关,失败开放,不自动下载模型
package/docs/scopes.md ADDED
@@ -0,0 +1,142 @@
1
+ # Scope 与只读共享
2
+
3
+ > 结论先说:`scope` 是**数据隔离边界**,`readOnlyScopes` 是**写保护**;
4
+ > 它们不是完整的身份认证/授权系统。能读 shared 的调用方仍然能读,只是不能改。
5
+
6
+ ## 0. 默认行为
7
+
8
+ - 默认 scope:`global`
9
+ - 默认 `readOnlyScopes: []`
10
+ - 默认 dataRoot:`desktop` profile 仍是历史 `~/.dsh/cortex`;其他 profile 未显式配置时派生到 `~/.dsh/cortex/profiles/<profile>`(避免干净 profile 读到 desktop 库)
11
+ - 显式 `dataRoot` / `dbFile` / `CORTEX_HOME` 优先级更高
12
+ - 不配置 `readOnlyScopes` 时,写权限行为和以前一样
13
+
14
+ ## 1. scope 怎么用
15
+
16
+ API 支持:
17
+
18
+ ```http
19
+ x-cortex-scope: agent-a
20
+ ```
21
+
22
+ 或查询参数:
23
+
24
+ ```text
25
+ ?scope=agent-a
26
+ ```
27
+
28
+ 工具大多只操作当前配置的默认 scope;按 id 的写工具会先查记录所属 scope。
29
+
30
+ ## 2. 只读共享示例
31
+
32
+ 主配置:
33
+
34
+ ```yaml
35
+ - id: cortex
36
+ name: dsh-cortex
37
+ config:
38
+ scope: agent-a
39
+ readOnlyScopes:
40
+ - shared
41
+ ```
42
+
43
+ 含义:
44
+
45
+ - `agent-a` 可写自己的 scope
46
+ - `shared` 只能读
47
+ - 写 `shared` 的记忆、工作项、目标、准则、候选边、日记、情绪都会拒绝
48
+ - `forget` / compress / retention / consolidate / vector rebuild 也不会动 `shared`
49
+
50
+ API 返回:
51
+
52
+ ```json
53
+ {"ok":false,"error":"scope-read-only","scopeId":"shared"}
54
+ ```
55
+
56
+ 状态码:**403**。
57
+
58
+ 工具返回:
59
+
60
+ ```text
61
+ 未执行:该记录属于只读共享 scope。
62
+ ```
63
+
64
+ ## 2.1 显式写授权(可选)
65
+
66
+ 默认只读 scope 谁都写不了。需要给某个 agent 开写时:
67
+
68
+ ```yaml
69
+ - id: cortex
70
+ name: dsh-cortex
71
+ config:
72
+ readOnlyScopes:
73
+ - shared
74
+ scopeWriteGrants:
75
+ - shared:agent-a
76
+ - grant: shared:agent-b
77
+ until: '2026-12-31T00:00:00Z'
78
+ ```
79
+
80
+ 字符串是永久授权;对象形式到期自动失效。调用时带:
81
+
82
+ ```http
83
+ x-cortex-agent: agent-a
84
+ ```
85
+
86
+ 未带 header / 未授权仍是 403。
87
+
88
+ ### 运行时撤销/新增(不重启)
89
+
90
+ ```text
91
+ GET /api/cortex/security/grants
92
+ POST /api/cortex/security/grants { "action": "add", "grant": "shared:agent-a" }
93
+ POST /api/cortex/security/grants { "action": "revoke", "grant": "shared:agent-a" }
94
+ ```
95
+
96
+ 覆盖保存在 `<dataRoot>/scope-grants.json`,重启后仍生效。
97
+ 撤销会写入 `revoked` 列表,优先于配置文件里的同名 grant。
98
+ 这些改动会进 audit:`scope.grant.add` / `scope.grant.revoke`。
99
+
100
+ 这不是登录或签名:header 是本地调用方自报的 agent id,只适合本机多 agent 协作。工具路径不带这个 header,因此工具仍按“默认 scope 只读”处理。
101
+
102
+ ## 3. 多 agent 的两种隔离
103
+
104
+ ### 同一 dataRoot,不同 scope
105
+
106
+ 适合“一个进程里多个 agent / 会话共享一份库”。
107
+
108
+ - 各自读写自己的 scope
109
+ - `shared` 设为只读
110
+ - 谁有 API 访问权,谁就能读 `shared`
111
+
112
+ ### 不同 dataRoot / profile
113
+
114
+ 适合“完全不同的 agent,不共享数据库”。
115
+
116
+ - 每个 profile 独立 `dataRoot`
117
+ - 不会互相看到 traces/facts/graph
118
+ - 需要共享时,走导出/导入或单独的共享库
119
+
120
+ ## 4. 这不是什么
121
+
122
+ - 不是多用户登录 / token 身份系统
123
+ - 不是按 agent 的细粒度 ACL
124
+ - 不会阻止能访问本地 API 的人读取 shared
125
+ - 不会自动把 desktop 数据迁到 shared
126
+ - 不会替调用方判断“这个 agent 该不该读”
127
+
128
+ ## 5. 已验证的边界
129
+
130
+ - 两个 scope 的 facts / as-of 互不可见
131
+ - 两个 scope 的候选边互不混
132
+ - 只读 scope 的 write / working / goal / playbook / candidate / life / emotion / compress / forget 都会拒绝
133
+ - 候选边仍然要人工 approve 才进图
134
+
135
+ ## 6. 还没做
136
+
137
+ - agent 身份与签名
138
+ - 显式 share grant / 到期时间
139
+ - 跨 agent 审计报表
140
+ - 多模态附件的共享边界
141
+
142
+ 在这些完成前,文档里不要把它写成“多 agent 安全模型”,只能写“scope 隔离 + 写保护”。