@yottameta/yotta-memory 0.8.5 → 0.9.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/CHANGELOG.md +23 -2
- package/README.md +61 -7
- package/README.zh-CN.md +62 -8
- package/SKILL.md +17 -6
- package/USER_GUIDE.md +13 -6
- package/bin/yotta-memory.js +225 -16
- package/package.json +4 -3
- package/references/faq.md +33 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,29 @@
|
|
|
1
|
+
## v0.9.0 (2026-09-01)
|
|
2
|
+
|
|
3
|
+
召回质量与上下文选择升级。
|
|
4
|
+
|
|
5
|
+
- **两阶段召回**:词法候选 + 可选本地 embedding 插件候选,统一按语义分与效用分融合排序。
|
|
6
|
+
- **可选 embedding 插件**:`--embedding <command>` 或 `config set embedding_cmd <command>`;本地子进程、`stdin/stdout` JSON 协议、超时默认 3000ms、失败自动降级为词法召回。
|
|
7
|
+
- **任务感知上下文**:`context --focus <关键词>` 新增任务相关记忆段,按身份 / 边界 / 承诺 / 画像 / 任务记忆 / 近期记忆优先级组装。
|
|
8
|
+
- **选择解释**:`context --explain` 输出 included / dropped 与原因;`recall --explain` 继续显示命中理由并补充 embedding 分。
|
|
9
|
+
- **MCP 同步**:`recall` / `search` 新增 `embedding` / `embeddingTimeout` / `explain` 参数;新增 `context` 工具。
|
|
10
|
+
- **版本四件对齐**:package.json / SKILL.md / CHANGELOG.md / 引擎 VERSION = 0.9.0。
|
|
11
|
+
|
|
12
|
+
## v0.8.7 (2026-09-01)
|
|
13
|
+
|
|
14
|
+
评测反馈优化(文档 + 错误提示,功能不变)。
|
|
15
|
+
|
|
16
|
+
- 新增 `references/faq.md`:10 条常见问题 / 避坑(类型选错、私密区加密、多智能体权限、记忆找不到、忘记主口令、局域网连接、MCP 加载、记忆库位置、跨会话恢复、备份迁移)。
|
|
17
|
+
- 错误提示友好化:顶层错误附「修复建议」人话(检查 memory_home、主口令与恢复钥匙等)。
|
|
18
|
+
- README 中英:新增「命令输出样例」(init / remember / recall / context 屏幕输出示意)+「常见问题 FAQ 速查」。
|
|
19
|
+
- SKILL.md:新增「常见问题 FAQ(速查)」小节,指向 references/faq.md。
|
|
20
|
+
- 版本四件对齐 0.8.7(package.json / SKILL.md / CHANGELOG / 引擎 VERSION)。
|
|
21
|
+
|
|
1
22
|
# 更新日志
|
|
2
23
|
|
|
3
24
|
## v0.8.5 (2026-08-29)
|
|
4
25
|
|
|
5
|
-
|
|
26
|
+
安全修复(安全扫描发现高危,修复后三源同步升版):
|
|
6
27
|
|
|
7
28
|
- **MCP 命令执行入口封死**:MCP `distill` 不再接受 `--model`(`callTool` 在工具边界直接拒绝),远端智能体无法再借 MCP 在引擎主机执行任意命令。
|
|
8
29
|
- **MCP 任意路径读写封死**:MCP `export` / `import` 的 `out` / `src` 必须落在记忆库根内(新增 `resolveWithinRoot` 校验,防 `..` 穿越),库外路径直接拒绝,与「远程只能读写记忆」承诺对齐。
|
|
@@ -19,7 +40,7 @@
|
|
|
19
40
|
|
|
20
41
|
## v0.8.3 (2026-08-28)
|
|
21
42
|
|
|
22
|
-
中英双语 README
|
|
43
|
+
中英双语 README 对齐(确定「英文门面 + 中文全档」):
|
|
23
44
|
|
|
24
45
|
- **README.md 改为英文**:作为 GitHub / npm / ClawHub 首页的英文门面(翻译 + 精简,覆盖定位 / 核心价值 / 四类型 / 权限隔离 / 身份 / 语义检索 / 生命周期 / 对比 / 安装(CLI+技能双装)/ 升级 / CLI 用法 / 局域网共享 / 开发校验全流程)。
|
|
25
46
|
- **新增 README.zh-CN.md**:原中文完整主文档整体平移,顶部加语言切换链接。
|
package/README.md
CHANGED
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
|
|
24
24
|
> 📖 The user-facing operations manual lives in [USER_GUIDE.md](USER_GUIDE.md).
|
|
25
25
|
|
|
26
|
+
> 🆕 **v0.9.0**: recall quality + context selection — optional local embedding plugin, `context --focus`, and `--explain` selection trace.
|
|
27
|
+
|
|
26
28
|
> 🆕 **v0.8.5**: security hardening — MCP `distill` no longer accepts `--model`; MCP `export` / `import` paths are restricted to the memory root; CLI `distill --model` no longer shells out (allowlist-based).
|
|
27
29
|
|
|
28
30
|
## Core value
|
|
@@ -71,18 +73,19 @@ Each agent has a globally unique agent ID: it is the ownership key for private m
|
|
|
71
73
|
- **No token locally**: local CLI / stdio direct connection bypasses the network and does not validate tokens; identity is declared via the agent's MCP `env.YOTTA_AGENT_ID`.
|
|
72
74
|
- **Private memory requires an owner**: writing PREF / BOUND / COMMIT without declaring identity is rejected (public FACT is unaffected), mechanically preventing ID spoofing.
|
|
73
75
|
|
|
74
|
-
### Profile & start-of-work context (v0.6.0)
|
|
76
|
+
### Profile & start-of-work context (v0.6.0 + v0.9.0)
|
|
75
77
|
|
|
76
78
|
- **profile**: aggregates `private/<owner>/` PREF / BOUND / COMMIT verbatim, grouped by type + subject + tags, written to `profile.md`; the engine infers nothing — profile conclusions are formed internally by the AI per the "memory discipline", never pasted as labels.
|
|
77
|
-
- **context**: one-shot start-of-work package — multi-agent integration rules + identity + user profile digest + recent memory (importance-sorted) + boundary reminders + commitments/anchors; supports `--budget` character budget
|
|
79
|
+
- **context**: one-shot start-of-work package — multi-agent integration rules + identity + user profile digest + optional task-focused memory (`--focus`) + recent memory (importance-sorted) + boundary reminders + commitments/anchors; supports `--budget` character budget and `--explain` selection trace.
|
|
78
80
|
- **Memory discipline**: SKILL.md embeds a rule layer (type red lines / proactive trigger capture / know-the-user three stages / psychological grounding & alignment / bottom lines / host isolation / anti-patterns).
|
|
79
81
|
|
|
80
|
-
### Retrieval: semantic search (v0.8.0
|
|
82
|
+
### Retrieval: semantic search (v0.8.0 + v0.9.0 embedding)
|
|
81
83
|
|
|
82
84
|
- `remember` auto-builds the `index.json` index (version 4 since v0.8.1 with field weighting and pinyin tokens; public indexes over 5000 entries shard by year `index-<year>.json`; old indexes rebuild on first recall); recall defaults to semantic search — exact (field weighting: subject×3 / tags×2 / statement×1) + synonyms (built-in wordlist, extensible) + pinyin (full / initials, built-in 3755 common characters) + fuzzy (edit distance ≤ 2) + substring fallback, blended with utility score (0.65 × semantic + 0.35 × utility), zero-dependency.
|
|
83
85
|
- `recall --explain`: shows each hit's reason (exact / synonym / pinyin / fuzzy + field) and utility components.
|
|
84
86
|
- **Candidate pre-filtering (v0.8.1)**: before semantic scoring, index tokens coarsely filter the candidate set (exact / synonym / pinyin / substring / fuzzy length gate) — hit set identical to v0.8.0; the `view` platform paginates by offset, fetching only the current page.
|
|
85
|
-
- Optional embedding plugin
|
|
87
|
+
- **Optional embedding plugin (v0.9.0)**: `recall --embedding <command>` or `config set embedding_cmd <command>` runs a local subprocess that accepts JSON on stdin and returns vectors on stdout; results are blended into the same ranking. Failures, timeouts, or malformed output automatically fall back to zero-dependency lexical recall.
|
|
88
|
+
- **Embedding cache**: vectors are cached under each memory root at `.embed/cache.json`, keyed by `sha256(command + text)`; only vectors are stored, not plaintext.
|
|
86
89
|
- The `tokens` field of `index.json` is a Chinese-tokenization term-frequency table (for TF scoring), **not** an access credential; auth tokens live at `.server/tokens.json`.
|
|
87
90
|
- Supports keywords, `--type` filter, `--limit` truncation, project-level priority.
|
|
88
91
|
- **Root de-duplication (v0.6.5)**: when project and user roots point at the same directory, recall / context uniquify roots so a file shows once.
|
|
@@ -100,6 +103,21 @@ Each agent has a globally unique agent ID: it is the ownership key for private m
|
|
|
100
103
|
- `export` / `import`: export the whole store to JSON / import from JSON; an intermediate format for migration and backup.
|
|
101
104
|
- git: the whole store can be version-controlled — rollback / audit / team sync.
|
|
102
105
|
|
|
106
|
+
## FAQ (quick reference)
|
|
107
|
+
|
|
108
|
+
| Question | Answer (see references/faq.md) |
|
|
109
|
+
|---|---|
|
|
110
|
+
| Wrong memory type? | Hint only; forget and rewrite; --no-hint to disable |
|
|
111
|
+
| Private encryption? | init encrypts by default (master password + recovery key); migrate to encrypt a plaintext store |
|
|
112
|
+
| Multi-agent isolation? | FACT public; PREF/BOUND/COMMIT per-owner, grant via key authorize / view |
|
|
113
|
+
| Memory not found? | config get -> reindex -> recall/search |
|
|
114
|
+
| Lost master password? | reset-password with recovery key |
|
|
115
|
+
| LAN connect? | lan enable + token new; client url+token |
|
|
116
|
+
| MCP not loaded? | Check mcpServers + restart; use CLI directly |
|
|
117
|
+
| Where is the store? | config get; project-level .yottamemory |
|
|
118
|
+
| Cross-session resume? | Run context + recall at session start |
|
|
119
|
+
| Backup / migrate? | export / import |
|
|
120
|
+
|
|
103
121
|
## Comparison with other approaches
|
|
104
122
|
|
|
105
123
|
> Compared by solution type, not product names. Criteria: data sovereignty, deployment cost, permission boundaries, auditability, cross-agent ability.
|
|
@@ -151,6 +169,42 @@ bash install.sh --list # list agents -> default directories
|
|
|
151
169
|
```
|
|
152
170
|
|
|
153
171
|
> Method 1 uses the npm registry (npmmirror / npmjs) and does not depend on GitHub; Methods 2/3 use GitHub and may fail without a proxy in China.
|
|
172
|
+
## Example outputs
|
|
173
|
+
|
|
174
|
+
> Illustrative (actual output may vary by version) so you know what to expect on screen.
|
|
175
|
+
|
|
176
|
+
**init**:
|
|
177
|
+
|
|
178
|
+
```text
|
|
179
|
+
Memory store initialized: D:/.yottamemory
|
|
180
|
+
Master password set; recovery key: xxxx-xxxx-xxxx-xxxx (keep it safe)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**remember** (with verify):
|
|
184
|
+
|
|
185
|
+
```text
|
|
186
|
+
Recorded: D:/.yottamemory/facts/2026-09-01-0001.md
|
|
187
|
+
[verify] read-back OK: facts/2026-09-01-0001.md
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**recall**:
|
|
191
|
+
|
|
192
|
+
```text
|
|
193
|
+
3 memories (top 3):
|
|
194
|
+
[FACT] subject: statement... (D:/.yottamemory/facts/xxx.md)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**context**:
|
|
198
|
+
|
|
199
|
+
```text
|
|
200
|
+
# Start-of-work context (yotta-memory context)
|
|
201
|
+
## 1. Identity
|
|
202
|
+
## 2. User profile summary
|
|
203
|
+
## 3. Recent memories (top 10 by activity)
|
|
204
|
+
## 4. Boundaries (BOUND)
|
|
205
|
+
## 5. Commitments / anchors (COMMIT)
|
|
206
|
+
```
|
|
207
|
+
|
|
154
208
|
## Upgrade
|
|
155
209
|
|
|
156
210
|
Two upgrade paths match the two install paths:
|
|
@@ -170,9 +224,9 @@ npm i -g @yottameta/yotta-memory
|
|
|
170
224
|
|---|---|
|
|
171
225
|
| `yotta-memory init [--project] [--dir <dir>]` | Initialize the store (default user-level `~/.yottamemory/`; --dir sets an explicit location) |
|
|
172
226
|
| `yotta-memory remember <type> <subject> <statement> [--owner <id>] [--source <src>] [--weight <0..>] [--verify] [--no-hint]` | Write a memory (same subject+statement auto-updates; --owner marks ownership; --source records origin; --weight importance, dedup takes max; --verify read-back; --no-hint disables type hints) |
|
|
173
|
-
| `yotta-memory recall [keywords] [--type T] [--limit N] [--agent <id>] [--owner <id>] [--all] [--unsafe]` | Search memory (
|
|
227
|
+
| `yotta-memory recall [keywords] [--type T] [--limit N] [--agent <id>] [--owner <id>] [--all] [--unsafe] [--explain] [--semantic] [--embedding <cmd>] [--embedding-timeout N]` | Search memory (semantic + utility ranking; optional local embedding plugin; partitioned reads; cross-reading other agents' private is denied by default, needs grant / identity=user / `--unsafe`; project-level priority) |
|
|
174
228
|
| `yotta-memory profile [--owner <id>]` | Generate a user profile (aggregates `private/<owner>` verbatim, zero inference, writes `profile.md`; cross-owner denied by default) |
|
|
175
|
-
| `yotta-memory context [--limit N] [--owner <id>] [--budget N]` | Generate the start-of-work package (identity + multi-agent rules + profile + recent memory + boundaries + commitments; --budget
|
|
229
|
+
| `yotta-memory context [--limit N] [--owner <id>] [--budget N] [--focus <text>] [--explain] [--embedding <cmd>]` | Generate the start-of-work package (identity + multi-agent rules + profile + task-focused memory + recent memory + boundaries + commitments; --budget caps chars, --focus adds task relevance, --explain shows included/dropped) |
|
|
176
230
|
| `yotta-memory forget <file>` | Delete a memory (by type-dir path or file name) |
|
|
177
231
|
| `yotta-memory archive [--days 180] [--threshold 0.4]` | Archive old memory (final score + age; immutable excluded) |
|
|
178
232
|
| `yotta-memory reindex` | Rebuild the index (after manually editing .md) |
|
|
@@ -250,7 +304,7 @@ Register the connection in the agent's MCP config (`url` + two headers):
|
|
|
250
304
|
}
|
|
251
305
|
```
|
|
252
306
|
|
|
253
|
-
Once connected, MCP tools (remember / recall / search / forget / archive / reindex / export / import / agent_info) read/write memory and confirm identity; management actions (init / config / token / lan / serve) are not exposed via MCP, and token management is never exposed remotely. MCP `export` / `import` paths are restricted inside the memory root,
|
|
307
|
+
Once connected, MCP tools (remember / recall / search / context / forget / archive / reindex / export / import / agent_info) read/write memory and confirm identity; management actions (init / config / token / lan / serve) are not exposed via MCP, and token management is never exposed remotely. MCP `export` / `import` paths are restricted inside the memory root, MCP `distill` does not support `--model`, and MCP never accepts a raw embedding command from remote callers — the local embedding plugin must be configured on the engine host with `config set embedding_cmd`. `X-Agent-Id` must match the token's registered agent; read-partition rules are the same as the CLI (FACT public-readable, PREF / BOUND / COMMIT private).
|
|
254
308
|
|
|
255
309
|
### Location persistence
|
|
256
310
|
|
package/README.zh-CN.md
CHANGED
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
|
|
24
24
|
> 📖 面向用户的操作手册见 [USER_GUIDE.md](USER_GUIDE.md)。
|
|
25
25
|
|
|
26
|
+
> 🆕 **v0.9.0**:召回质量与上下文选择——可选本地 embedding 插件、`context --focus`、`--explain` 选择解释。
|
|
27
|
+
|
|
26
28
|
> 🆕 **v0.8.5**:安全加固——MCP `distill` 不再接受 `--model`;MCP `export` / `import` 路径限记忆库内;CLI `distill --model` 不再走 shell(改为允许清单)。
|
|
27
29
|
|
|
28
30
|
> 🆕 **v0.8.2**:发布元数据修复——三次源重发带 `--name 元忆 yotta-memory`,修复 ClawHub 展示名缺失中文(原为裸 `yotta-memory`);无功能变更。
|
|
@@ -98,18 +100,19 @@
|
|
|
98
100
|
- **本机免 token**:本机 CLI / stdio 直连不经网络、不校验 token;身份经该智能体 MCP 配置的 `env.YOTTA_AGENT_ID` 声明。本机多个智能体各自声明唯一 ID,互不撞。
|
|
99
101
|
- **私密记忆必须有 owner**:写 PREF / BOUND / COMMIT 时未声明身份会被拒绝(公共 FACT 不受影响),从机制上防止「抄别人的 ID」。
|
|
100
102
|
|
|
101
|
-
### 画像与开工上下文(v0.6.0)
|
|
103
|
+
### 画像与开工上下文(v0.6.0 + v0.9.0)
|
|
102
104
|
|
|
103
105
|
- **profile**:聚合 `private/<owner>/` 下 PREF / BOUND / COMMIT 原文,按 type + subject + tags 归组,写 `profile.md`;引擎零推断,画像结论由 AI 依据「记忆守则」内部形成,不当面贴标签。
|
|
104
|
-
- **context**:一键生成开工上下文包——多智能体接入铁律 + 身份 + 用户画像摘要 + 近期记忆(按 importance 排序)+ 边界提醒 + 承诺 / 锚点;支持 `--budget`
|
|
106
|
+
- **context**:一键生成开工上下文包——多智能体接入铁律 + 身份 + 用户画像摘要 + 任务相关记忆(`--focus`,v0.9.0)+ 近期记忆(按 importance 排序)+ 边界提醒 + 承诺 / 锚点;支持 `--budget` 字符预算与 `--explain` 选择解释。
|
|
105
107
|
- **记忆守则**:SKILL.md 内置规则层(类型红线 / 主动捕获触发信号 / 了解用户三阶段四手法 / 心理学底座与对齐 / 底线与边界 / 宿主隔离 / 反模式),让 AI「越用越懂」有章法。
|
|
106
108
|
|
|
107
|
-
### 检索:语义检索(v0.8.0
|
|
109
|
+
### 检索:语义检索(v0.8.0 + v0.9.0 embedding)
|
|
108
110
|
|
|
109
111
|
- `remember` 时自动构建 `index.json` 索引(v0.8.1 起 version=4,含字段加权与拼音 token;公共索引超过 5000 条按年份分片 `index-<year>.json`;旧索引首次 recall 自动重建);recall 默认语义检索——精确(字段加权:subject×3 / tags×2 / statement×1)+ 同义词(内置词表,可扩展)+ 拼音(全拼 / 首字母,内置 3755 常用字表)+ 模糊(编辑距离 ≤ 2)+ 子串兜底,并与效用分融合排序(0.65 × 语义 + 0.35 × 效用),零依赖。
|
|
110
112
|
- `recall --explain`:展示每条命中理由(精确 / 同义 / 拼音 / 模糊 + 字段)与效用分项。
|
|
111
113
|
- **recall 候选预过滤(v0.8.1)**:语义打分前先用索引 token 粗筛候选集(精确 / 同义 / 拼音 / 子串 / 模糊长度门槛),命中集与 v0.8.0 完全一致;`view` 查看平台按偏移分页返回,一次只取当前页。
|
|
112
|
-
-
|
|
114
|
+
- **可选 embedding 插件(v0.9.0)**:`recall --embedding <命令>` 或 `config set embedding_cmd <命令>`,本地子进程通过 stdin/stdout JSON 协议返回向量;结果并入同一套排序。插件失败、超时或输出非法时自动降级为零依赖词法检索。
|
|
115
|
+
- **向量缓存**:向量缓存在各记忆根下 `.embed/cache.json`,键为 `sha256(命令 + 文本)`;只存向量,不存明文。
|
|
113
116
|
- `index.json` 的 `tokens` 字段是中文分词的词频表(TF 打分用),**不是**访问凭证;鉴权令牌在记忆目录下 `.server/tokens.json`。
|
|
114
117
|
- 支持关键词、`--type` 过滤、`--limit` 截断、项目级优先。
|
|
115
118
|
- **根位置去重(v0.6.5)**:当项目级与用户级记忆库指向同一目录(如 cwd = home 或其父)时,`recall` / `context` 自动唯一化根,同一文件只展示一次。
|
|
@@ -139,6 +142,21 @@
|
|
|
139
142
|
- **安全边界**:管理动作(init / config / token / lan / serve)不进 MCP,token 不远程暴露;远程智能体只能读写记忆,且路径限记忆库内(export/import 的 out/src 必须落在库内)、distill 不支持 `--model`(仅本地 CLI),不能改配置、不能管 token。
|
|
140
143
|
- 完整操作步骤见上文「局域网多机共享」章节与 [USER_GUIDE.md](USER_GUIDE.md)。
|
|
141
144
|
|
|
145
|
+
## 常见问题 FAQ(速查)
|
|
146
|
+
|
|
147
|
+
| 问题 | 答案(详见 references/faq.md) |
|
|
148
|
+
|---|---|
|
|
149
|
+
| 类型选错? | 只提示不阻止;forget 后重写;--no-hint 关提示 |
|
|
150
|
+
| 私密区加密? | init 默认加密(主口令+恢复钥匙);明文库 migrate 升级 |
|
|
151
|
+
| 多智能体权限? | FACT 公共;PREF/BOUND/COMMIT 按 owner 隔离,需 key authorize / view 授权 |
|
|
152
|
+
| 记忆找不到? | config get 查位置 → reindex 重建索引 → recall/search |
|
|
153
|
+
| 忘记主口令? | 用恢复钥匙 reset-password(无私密区锁定的预期行为) |
|
|
154
|
+
| 局域网怎么连? | 引擎 lan enable + token new;客户端配 url+token |
|
|
155
|
+
| MCP 没加载? | 检查 mcpServers + 重启会话;本机直连用 CLI |
|
|
156
|
+
| 记忆库在哪? | config get;项目级 .yottamemory |
|
|
157
|
+
| 跨会话恢复? | 开工跑 context + recall |
|
|
158
|
+
| 备份迁移? | export / import |
|
|
159
|
+
|
|
142
160
|
## 与其他方案对比
|
|
143
161
|
|
|
144
162
|
> 以下按方案类型对比,不涉及具体产品名称。判断标准:数据主权、部署成本、权限边界、可审计性、跨智能体能力。
|
|
@@ -190,6 +208,42 @@ bash install.sh --list # 列出智能体 -> 默认目录
|
|
|
190
208
|
```
|
|
191
209
|
|
|
192
210
|
> 方式一走 npm 源(npmmirror / npmjs),不依赖 GitHub;方式二 / 三走 GitHub,国内无代理可能失败。
|
|
211
|
+
## 命令输出样例
|
|
212
|
+
|
|
213
|
+
> 以下为示意输出(以实际版本为准),让你知道执行命令后屏幕上会出现什么。
|
|
214
|
+
|
|
215
|
+
**init(初始化记忆库)**:
|
|
216
|
+
|
|
217
|
+
```text
|
|
218
|
+
初始化记忆库成功:D:\.yottamemory
|
|
219
|
+
主口令已设置;恢复钥匙:xxxx-xxxx-xxxx-xxxx(请妥善保存)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**remember(写入记忆,带 verify 回读)**:
|
|
223
|
+
|
|
224
|
+
```text
|
|
225
|
+
已记录: D:\.yottamemory\facts\2026-09-01-0001.md
|
|
226
|
+
[verify] 已写回读 OK: facts/2026-09-01-0001.md
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**recall(检索)**:
|
|
230
|
+
|
|
231
|
+
```text
|
|
232
|
+
共 3 条记忆(前 3 条):
|
|
233
|
+
[FACT] 项目名: 描述……(D:\.yottamemory\facts\xxx.md)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**context(开工上下文包)**:
|
|
237
|
+
|
|
238
|
+
```text
|
|
239
|
+
# 开工上下文包(yotta-memory context)
|
|
240
|
+
## 1. 身份
|
|
241
|
+
## 2. 用户画像摘要
|
|
242
|
+
## 3. 近期记忆(按活跃度前 10 条)
|
|
243
|
+
## 4. 边界提醒(BOUND)
|
|
244
|
+
## 5. 承诺 / 锚点(COMMIT)
|
|
245
|
+
```
|
|
246
|
+
|
|
193
247
|
## 升级
|
|
194
248
|
|
|
195
249
|
两种升级方式对应两种安装方式:
|
|
@@ -210,9 +264,9 @@ npm i -g @yottameta/yotta-memory
|
|
|
210
264
|
|---|---|
|
|
211
265
|
| `yotta-memory init [--project] [--dir <目录>]` | 初始化记忆库(默认用户级 `~/.yottamemory/`;--dir 显式指定位置)|
|
|
212
266
|
| `yotta-memory remember <type> <subject> <statement> [--owner <id>] [--source <来源>] [--weight <0..>] [--verify] [--no-hint]` | 写入记忆(同 subject+statement 自动更新;--owner 标注归属;--source 记录来源;--weight 重要性权重、去重取 max;--verify 写后回读;--no-hint 关闭类型提示)|
|
|
213
|
-
| `yotta-memory recall [关键词] [--type T] [--limit N] [--agent <id>] [--owner <id>] [--all] [--unsafe]` |
|
|
267
|
+
| `yotta-memory recall [关键词] [--type T] [--limit N] [--agent <id>] [--owner <id>] [--all] [--unsafe] [--explain] [--semantic] [--embedding <命令>] [--embedding-timeout N]` | 检索记忆(语义+效用分排序;可选本地 embedding 插件;读取分区过滤;越界读其它智能体私密默认拒绝,需 grant / identity=user / `--unsafe`;`--agent <其它>` 仅作身份声明、不授予跨读;项目级优先)|
|
|
214
268
|
| `yotta-memory profile [--owner <id>]` | 生成用户画像(聚合 `private/<owner>/` 原文,零推断,写 `profile.md`;跨 owner 默认拒绝)|
|
|
215
|
-
| `yotta-memory context [--limit N] [--owner <id>] [--budget N]` | 生成开工上下文包(身份 + 多智能体铁律 + 画像 + 近期记忆 + 边界 + 承诺;--budget
|
|
269
|
+
| `yotta-memory context [--limit N] [--owner <id>] [--budget N] [--focus <关键词>] [--explain] [--embedding <命令>]` | 生成开工上下文包(身份 + 多智能体铁律 + 画像 + 任务相关记忆 + 近期记忆 + 边界 + 承诺;--budget 字符预算;--focus 任务聚焦;--explain 输出 included/dropped 选择解释)|
|
|
216
270
|
| `yotta-memory forget <文件>` | 删除一条记忆(按类型目录路径或文件名)|
|
|
217
271
|
| `yotta-memory archive [--days 180] [--threshold 0.4]` | 归档旧记忆(盖棺分+年龄,immutable 除外)|
|
|
218
272
|
| `yotta-memory reindex` | 重建索引(手动改 .md 后校正)|
|
|
@@ -290,7 +344,7 @@ yotta-memory recall --type FACT --limit 10
|
|
|
290
344
|
}
|
|
291
345
|
```
|
|
292
346
|
|
|
293
|
-
连接后可通过 MCP tools(remember / recall / search / forget / archive / reindex / export / import / agent_info)读写记忆与确认身份;管理动作(init / config / token / lan / serve)不进 MCP,token 管理不远程暴露;MCP export/import 路径限记忆库内、distill 不支持 `--model
|
|
347
|
+
连接后可通过 MCP tools(remember / recall / search / context / forget / archive / reindex / export / import / agent_info)读写记忆与确认身份;管理动作(init / config / token / lan / serve)不进 MCP,token 管理不远程暴露;MCP export/import 路径限记忆库内、distill 不支持 `--model`,MCP 也不接受远端传入 embedding 命令——embedding 插件只能由引擎主机本地 `config set embedding_cmd` 配置。`X-Agent-Id` 必须与 token 登记的智能体一致;读取分区规则与 CLI 相同(FACT 公共可读,PREF / BOUND / COMMIT 私密隔离)。
|
|
294
348
|
|
|
295
349
|
### 位置持久化
|
|
296
350
|
|
|
@@ -309,4 +363,4 @@ yotta-memory config get
|
|
|
309
363
|
|
|
310
364
|
## 许可证
|
|
311
365
|
|
|
312
|
-
MIT © YottaMeta —— 详见 [LICENSE](./LICENSE)。
|
|
366
|
+
MIT © YottaMeta —— 详见 [LICENSE](./LICENSE)。
|
package/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yotta-memory
|
|
3
|
-
description: "元忆 —— 有权限边界的文件式智能体记忆。文件式、零依赖、可 diff
|
|
4
|
-
version: 0.
|
|
3
|
+
description: "元忆 —— 有权限边界的文件式智能体记忆。文件式、零依赖、可 diff/可回滚:让任何 AI 智能体活过会话,开工 recall 恢复上下文、重要信息 remember 落盘、收工归档。类型体系 FACT(公共共享)/ PREF / BOUND / COMMIT(私密隔离)。触发:记住、别忘了、记一笔、记忆、remember、recall、跨会话、上次说到、续测、交接、归档、记忆盘、共享记忆、局域网记忆、画像、开工上下文、记忆守则、profile、context、越用越懂、语义检索、反馈、维护、蒸馏、feedback、maintain、distill、explain、自我学习、自我进化、自我提升、查看平台分页、recall 候选预过滤、任务相关记忆、--focus、--embedding"
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
license: MIT
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -18,6 +18,7 @@ license: MIT
|
|
|
18
18
|
- **双级存储**:用户级 `~/.yottamemory/`(跨项目)+ 项目级 `.yottamemory/`(随项目共享)。
|
|
19
19
|
- **越用越懂**:`profile` 聚合用户画像(引擎零推断,只归组原文)+ `context` 一键生成开工上下文包(身份 + 画像 + 近期记忆 + 边界 + 承诺)+ SKILL「记忆守则」规则层;只注入规则与机制,不注入人格数据(出厂零数据)。
|
|
20
20
|
- **自我学习 / 自我进化 / 自我提升(v0.8.0)**:`recall` 语义检索(同义词 / 拼音 / 字段加权 / 模糊匹配,零依赖);`feedback` 显式使用反馈闭环(useful / useless → weight / confidence / feedback_net 演化,越用越懂);`maintain` 规则层自组织(统一效用分 + 年龄自动归档 / 遗忘候选 / 去重,默认 dry-run,immutable / BOUND 豁免);`distill` 心理日志蒸馏(统计摘要 / 主题画像 / 知识地图,可选 `--model` 外部模型增强);`explain` 查看单条记忆效用分项。
|
|
21
|
+
- **召回质量与上下文选择(v0.9.0)**:`recall` 支持可选本地 embedding 插件(`--embedding <command>` / `config set embedding_cmd <command>`);`context --focus <关键词>` 生成任务感知上下文;`--explain` 输出选择 trace,无插件时自动降级为词法检索。
|
|
21
22
|
|
|
22
23
|
## 何时使用(触发)
|
|
23
24
|
|
|
@@ -28,7 +29,7 @@ license: MIT
|
|
|
28
29
|
|
|
29
30
|
## 核心流程
|
|
30
31
|
|
|
31
|
-
1. **开工定向**:先按「开工第一步:确认记忆位置 + 智能体身份」检测记忆库与身份,再运行 `yotta-memory context`(主注入:身份 + 用户画像 + 近期记忆 + 边界 + 承诺)恢复上下文,需要细节再 `yotta-memory recall
|
|
32
|
+
1. **开工定向**:先按「开工第一步:确认记忆位置 + 智能体身份」检测记忆库与身份,再运行 `yotta-memory context`(主注入:身份 + 用户画像 + 近期记忆 + 边界 + 承诺)恢复上下文,需要细节再 `yotta-memory recall <关键词>`;若有明确任务关键词,用 `context --focus <关键词>` 获得任务相关记忆;项目级记忆优先,其次用户级。
|
|
32
33
|
2. **进行中落盘**:重要信息立即 `yotta-memory remember <type> <subject> <statement>`,不攒到收工。
|
|
33
34
|
3. **收工归档**:写会话小结(COMMIT / 笔记),旧记录定期 `yotta-memory archive`。
|
|
34
35
|
4. **多智能体纪律**:FACT 写入公共区,PREF / BOUND / COMMIT 只写本智能体私密区;不读取其他智能体私密区。**一切读写一律走 `yotta-memory` CLI / MCP 工具**——禁止用 shell(`Get-ChildItem` / `Get-Content` / `cat` / `ls` / `type` 等)直接读或改记忆库目录下的 `.md` / `index.json` / `tokens.json` / `agents.json` / `grants.json` 等文件,否则会绕过权限边界、读到别的智能体私密内容。
|
|
@@ -73,7 +74,7 @@ license: MIT
|
|
|
73
74
|
- 三角建模:情绪(措辞 / 标点 / 长度)→ 认知(归因 / 信念 / 控制感)→ 行为(作息 / 应对 / 执行);三者冲突时优先行为与认知。
|
|
74
75
|
- 共情至少到第 3 阶段:识别 → 理解 → 回应 → 验证。
|
|
75
76
|
- 诚实声明:AI 是模式匹配非真感受,不伪装、不编造伪情感记忆。
|
|
76
|
-
-
|
|
77
|
+
- 危机识别:不评判、持续在场、温和引导现实支持;不擅自越界联系外部。
|
|
77
78
|
- 对齐:回应时让积累的理解自然影响语气与措辞(让用户感到「被记得、被懂」),而非机械引用记忆条目。
|
|
78
79
|
- 情感外包双刃剑:做增益真实生活的陪伴,不替代真实关系。
|
|
79
80
|
|
|
@@ -161,9 +162,9 @@ license: MIT
|
|
|
161
162
|
| `yotta-memory reset-password [--password <当前> | --recovery-key <钥匙>] [--new-password <新>]` | 重设主口令(忘口令用恢复钥匙)|
|
|
162
163
|
| `yotta-memory key list / authorize <id> / revoke <id>` | 管理 AI 私密读取授权缓存(authorize 需主口令;revoke 立即吊销该 AI 解密能力)|
|
|
163
164
|
| `yotta-memory remember <type> <subject> <statement> [--owner <id>] [--source <来源>] [--weight <0..>] [--verify] [--no-hint]` | 写入(同 subject+statement 自动更新;--owner 标注归属;--source 记录来源;--weight 重要性权重默认 1.0、去重取 max;--verify 写后回读校验;--no-hint 关闭类型启发式提示)|
|
|
164
|
-
| `yotta-memory recall [关键词] [--type T] [--limit N] [--agent <id>] [--owner <id>] [--all] [--unsafe] [--explain] [--semantic]` | 检索(v0.8.0 默认语义检索:同义词 / 拼音全拼+首字母 / 字段加权 / 模糊匹配 +
|
|
165
|
+
| `yotta-memory recall [关键词] [--type T] [--limit N] [--agent <id>] [--owner <id>] [--all] [--unsafe] [--explain] [--semantic] [--embedding <command>] [--embedding-timeout N]` | 检索(v0.8.0 默认语义检索:同义词 / 拼音全拼+首字母 / 字段加权 / 模糊匹配 + 效用分融合排序;v0.9.0 支持可选本地 embedding 插件,失败自动降级;`--explain` 显示命中理由与效用分项;`--semantic` 显式开启;读取分区过滤;越界读其它智能体私密默认拒绝,需 grant / identity=user / `--unsafe`;`--agent <其它>` 只作身份声明/展示,不授予跨读——读他人私密同样要授权;项目级优先)|
|
|
165
166
|
| `yotta-memory profile [--owner <id>]` | 生成用户画像(聚合 `private/<owner>/` 原文,零推断,写 `profile.md`;跨 owner 默认拒绝)|
|
|
166
|
-
| `yotta-memory context [--limit N] [--owner <id>] [--budget N]` | 生成开工上下文包(身份 + 多智能体铁律 + 画像 + 近期记忆 + 边界 + 承诺;--budget
|
|
167
|
+
| `yotta-memory context [--limit N] [--owner <id>] [--budget N] [--focus <关键词>] [--explain] [--embedding <command>]` | 生成开工上下文包(身份 + 多智能体铁律 + 画像 + 任务相关记忆 + 近期记忆 + 边界 + 承诺;--budget 字符预算,0=不限;--explain 输出 included / dropped 选择 trace)|
|
|
167
168
|
| `yotta-memory forget <文件>` | 删除(按类型目录路径或文件名)|
|
|
168
169
|
| `yotta-memory archive [--days 180] [--threshold 0.35]` | 归档旧记忆(v0.8.0 统一效用分+年龄,immutable 除外;阈值默认读 config `maintain_archived_utility`)|
|
|
169
170
|
| `yotta-memory reindex` | 重建索引(手动改 .md 后校正)|
|
|
@@ -323,6 +324,16 @@ license: MIT
|
|
|
323
324
|
### 4.10 复用
|
|
324
325
|
- 成功后优先复用现有连接;失败(token 吊销等)再回 4.3。
|
|
325
326
|
|
|
327
|
+
## 常见问题 FAQ(速查)
|
|
328
|
+
|
|
329
|
+
常见问题与避坑见 `references/faq.md`:
|
|
330
|
+
- 类型选错 → 只提示不阻止;`forget` 后按正确类型重写;
|
|
331
|
+
- 私密区加密 → `init` 默认加密(主口令+恢复钥匙),明文库 `migrate` 升级,`view` 平台口令解锁;
|
|
332
|
+
- 多智能体权限 → FACT 公共、私密按 owner 隔离,需 `key authorize` / `view` 授权;
|
|
333
|
+
- 记忆找不到 → `config get` 查位置 → `reindex` → `recall` / `search`;
|
|
334
|
+
- 忘记主口令 → 用恢复钥匙 `reset-password`;
|
|
335
|
+
- 局域网 → 引擎 `lan enable` + `token new`,客户端配 url+token。
|
|
336
|
+
|
|
326
337
|
## 渐进披露
|
|
327
338
|
|
|
328
339
|
- 协议细节、目录结构与类型规则见 `references/protocol.md`,需要时读取,不要每次全读。
|
package/USER_GUIDE.md
CHANGED
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
|
|
26
26
|
**典型使用场景:**
|
|
27
27
|
|
|
28
|
-
- **跨会话续接**:AI 开工 `recall`
|
|
28
|
+
- **跨会话续接**:AI 开工 `recall` 恢复上次上下文,不丢记忆;v0.9.0 起可用 `context --focus <关键词>` 生成任务感知上下文。
|
|
29
29
|
- **多智能体共享**:FACT 进公共区共享,PREF / BOUND / COMMIT 各自私密隔离。
|
|
30
30
|
- **交接与团队协作**:项目级 `.yottamemory` 随仓库走,交接即恢复。
|
|
31
31
|
- **便携记忆盘**:记忆装在固定主机上,本机与局域网其它主机共享同一份记忆(见第 4 / 5 篇)。
|
|
32
32
|
- **越用越懂(v0.6.0)**:AI 按「记忆守则」主动捕获信号,`profile` 聚合画像、`context` 开工注入——用得越久越懂你。
|
|
33
|
-
- **自我学习 / 自我进化 / 自我提升(v0.8.0)**:`recall` 语义检索(同义词 / 拼音 / 字段加权 /
|
|
33
|
+
- **自我学习 / 自我进化 / 自我提升(v0.8.0 + v0.9.0)**:`recall` 语义检索(同义词 / 拼音 / 字段加权 / 模糊,v0.9.0 可选本地 embedding 插件)+ `feedback` 使用反馈闭环 + `maintain` 规则层自组织 + `distill` 心理日志蒸馏——记忆系统会自己整理、提炼、演化。
|
|
34
34
|
|
|
35
35
|
## 2. 安装(CLI + 技能)
|
|
36
36
|
|
|
@@ -77,7 +77,7 @@ yotta-memory config get # 查看记忆库位置
|
|
|
77
77
|
```bash
|
|
78
78
|
yotta-memory profile # 生成用户画像(写 private/<owner>/profile.md)
|
|
79
79
|
yotta-memory context --limit 10 --budget 1800 # 生成开工上下文包(身份+铁律+画像+近期记忆+边界+承诺,预算控 token)
|
|
80
|
-
yotta-memory iam <id> --name 元忆 --user
|
|
80
|
+
yotta-memory iam <id> --name 元忆 --user 用户 --relationship 伙伴 # 自我档案扩展显示名/用户/关系
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
- `profile` 引擎零推断:只按类型 / 主题 / 标签归组呈现原文,画像结论由 AI 内部形成,不当面贴标签。
|
|
@@ -142,9 +142,16 @@ statement: 本周完成发布
|
|
|
142
142
|
|
|
143
143
|
- `recall <关键词>` 默认语义检索:同义词(内置词表)、拼音(全拼 / 首字母,内置 3755 常用字表)、字段加权(subject 优先)、模糊匹配(编辑距离 ≤ 2)、子串兜底。
|
|
144
144
|
- 例:记过「越用越懂」,用 `recall yyyd`(首字母)或 `recall yueyong yuedong`(拼音)都能找回。
|
|
145
|
-
- `recall --explain
|
|
145
|
+
- `recall --explain`:显示每条命中理由与效用分项;配置 embedding 插件后还会显示向量相似度。
|
|
146
146
|
- 旧索引首次 recall 自动重建(version 4),无需手动 reindex。
|
|
147
147
|
|
|
148
|
+
**可选本地 embedding 插件(v0.9.0)**
|
|
149
|
+
|
|
150
|
+
- `recall <关键词> --embedding <命令>`:调用本地子进程,stdin 传 `{texts:[]}`,stdout 返回 `{vectors:[]}`;向量与词法得分共同参与排序。
|
|
151
|
+
- `config set embedding_cmd <命令>`:持久启用插件;`--embedding` 优先级更高。
|
|
152
|
+
- `--embedding-timeout N`:默认 3000ms;插件失败、超时或输出非法时自动降级为词法检索,不会中断命令。
|
|
153
|
+
- 向量缓存写入各记忆根下 `.embed/cache.json`,只存向量不存明文;同一命令与文本命中缓存时不再重复调用插件。
|
|
154
|
+
|
|
148
155
|
**使用反馈闭环(feedback)**
|
|
149
156
|
|
|
150
157
|
- `feedback <文件> --useful`:这条记忆有用 → weight ×1.2(上限 3.0)、confidence +0.05、feedback_net +1。
|
|
@@ -308,9 +315,9 @@ yotta-memory remember FACT 主题 内容 # 智能体落盘
|
|
|
308
315
|
|---|---|
|
|
309
316
|
| `yotta-memory init [--project] [--dir <目录>]` | 初始化记忆库 |
|
|
310
317
|
| `yotta-memory remember <类型> <主题> <内容> [--owner <id>] [--source <来源>] [--weight <0..>] [--verify] [--no-hint]` | 写入记忆(--source 来源;--weight 重要性权重;--verify 写后回读;--no-hint 关闭类型提示)|
|
|
311
|
-
| `yotta-memory recall [关键词] [--type T] [--limit N] [--agent <id>] [--owner <id>] [--all] [--unsafe] [--explain]
|
|
318
|
+
| `yotta-memory recall [关键词] [--type T] [--limit N] [--agent <id>] [--owner <id>] [--all] [--unsafe] [--explain] [--semantic] [--embedding <命令>] [--embedding-timeout N]` | 检索记忆(语义 + 效用分排序;可选本地 embedding 插件;读取分区过滤;越界读其它智能体私密默认拒绝,需 grant / identity=user / `--unsafe`)|
|
|
312
319
|
| `yotta-memory profile [--owner <id>]` | 生成用户画像(零推断,写 `profile.md`)|
|
|
313
|
-
| `yotta-memory context [--limit N] [--owner <id>] [--budget N]` |
|
|
320
|
+
| `yotta-memory context [--limit N] [--owner <id>] [--budget N] [--focus <关键词>] [--explain] [--embedding <命令>]` | 开工上下文包(身份+铁律+画像+任务相关记忆+近期记忆+边界+承诺;--focus 任务聚焦;--explain 输出 included/dropped 选择解释)|
|
|
314
321
|
| `yotta-memory forget <文件>` | 删除一条记忆 |
|
|
315
322
|
| `yotta-memory archive [--days 180] [--threshold 0.4]` | 归档旧记忆 |
|
|
316
323
|
| `yotta-memory reindex` | 重建索引 |
|
package/bin/yotta-memory.js
CHANGED
|
@@ -22,7 +22,7 @@ const crypto = require('crypto');
|
|
|
22
22
|
const http = require('http');
|
|
23
23
|
const child_process = require('child_process');
|
|
24
24
|
|
|
25
|
-
const VERSION = '0.
|
|
25
|
+
const VERSION = '0.9.0';
|
|
26
26
|
const TYPES = ['FACT', 'PREF', 'BOUND', 'COMMIT'];
|
|
27
27
|
const TYPE_DIRS = { FACT: 'facts', PREF: 'prefs', BOUND: 'bounds', COMMIT: 'commits' };
|
|
28
28
|
const PUBLIC_DIR = 'facts';
|
|
@@ -150,6 +150,103 @@ function runDistillModel(modelStr, payload) {
|
|
|
150
150
|
const r = child_process.spawnSync(argv[0], argv.slice(1), { input: payload, encoding: 'utf8', maxBuffer: 1024 * 1024, shell: false, windowsHide: true });
|
|
151
151
|
return r;
|
|
152
152
|
}
|
|
153
|
+
function cosineSimilarity(a, b) {
|
|
154
|
+
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return 0;
|
|
155
|
+
let dot = 0, na = 0, nb = 0;
|
|
156
|
+
for (let i = 0; i < a.length; i++) {
|
|
157
|
+
const x = Number(a[i]) || 0;
|
|
158
|
+
const y = Number(b[i]) || 0;
|
|
159
|
+
dot += x * y;
|
|
160
|
+
na += x * x;
|
|
161
|
+
nb += y * y;
|
|
162
|
+
}
|
|
163
|
+
if (!na || !nb) return 0;
|
|
164
|
+
return dot / (Math.sqrt(na) * Math.sqrt(nb));
|
|
165
|
+
}
|
|
166
|
+
function runEmbeddingPlugin(command, texts, timeoutMs) {
|
|
167
|
+
const argv = splitCommandArgv(String(command || ''));
|
|
168
|
+
if (!argv.length) throw new Error('embedding 命令为空');
|
|
169
|
+
const payload = JSON.stringify({ texts: (texts || []).map(String) });
|
|
170
|
+
const timeout = Math.max(1, parseInt(timeoutMs, 10) || 3000);
|
|
171
|
+
const r = child_process.spawnSync(argv[0], argv.slice(1), {
|
|
172
|
+
input: payload,
|
|
173
|
+
encoding: 'utf8',
|
|
174
|
+
maxBuffer: 1024 * 1024,
|
|
175
|
+
shell: false,
|
|
176
|
+
windowsHide: true,
|
|
177
|
+
timeout: timeout
|
|
178
|
+
});
|
|
179
|
+
if (r.error) throw r.error;
|
|
180
|
+
if (r.status !== 0) throw new Error('embedding 插件退出码 ' + r.status);
|
|
181
|
+
const parsed = JSON.parse(String(r.stdout || ''));
|
|
182
|
+
if (!parsed || !Array.isArray(parsed.vectors)) throw new Error('embedding 插件输出缺少 vectors 数组');
|
|
183
|
+
if (parsed.vectors.length !== texts.length) throw new Error('embedding 向量数量不匹配');
|
|
184
|
+
return parsed.vectors;
|
|
185
|
+
}
|
|
186
|
+
function embeddingCandidates(entries, query, opts) {
|
|
187
|
+
opts = opts || {};
|
|
188
|
+
const command = opts.embedding || '';
|
|
189
|
+
if (!command) return [];
|
|
190
|
+
const texts = [String(query || '')].concat((entries || []).map(function (e) {
|
|
191
|
+
return [e.subject || '', e.statement || '', (e.tags || []).join(' ')].join(' ');
|
|
192
|
+
}));
|
|
193
|
+
const root = opts.root ? String(opts.root) : '';
|
|
194
|
+
let cache = {};
|
|
195
|
+
let cachePath = '';
|
|
196
|
+
if (root) {
|
|
197
|
+
cachePath = path.join(root, '.embed', 'cache.json');
|
|
198
|
+
try {
|
|
199
|
+
fs.mkdirSync(path.dirname(cachePath), { recursive: true });
|
|
200
|
+
cache = JSON.parse(fs.readFileSync(cachePath, 'utf8'));
|
|
201
|
+
} catch (err) {
|
|
202
|
+
cache = {};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const keys = texts.map(function (text) {
|
|
206
|
+
return crypto.createHash('sha256').update(command + '\0' + text).digest('hex');
|
|
207
|
+
});
|
|
208
|
+
const missing = [];
|
|
209
|
+
const missingIndexes = [];
|
|
210
|
+
const vectors = new Array(texts.length);
|
|
211
|
+
for (let i = 0; i < texts.length; i++) {
|
|
212
|
+
if (cache[keys[i]]) {
|
|
213
|
+
vectors[i] = cache[keys[i]];
|
|
214
|
+
} else {
|
|
215
|
+
missing.push(texts[i]);
|
|
216
|
+
missingIndexes.push(i);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (missing.length) {
|
|
220
|
+
const missingVectors = runEmbeddingPlugin(command, missing, opts.embeddingTimeout);
|
|
221
|
+
for (let i = 0; i < missingVectors.length; i++) {
|
|
222
|
+
const idx = missingIndexes[i];
|
|
223
|
+
vectors[idx] = missingVectors[i];
|
|
224
|
+
cache[keys[idx]] = missingVectors[i];
|
|
225
|
+
}
|
|
226
|
+
if (cachePath) {
|
|
227
|
+
try { fs.writeFileSync(cachePath, JSON.stringify(cache, null, 2), 'utf8'); } catch (err) {}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const queryVec = vectors[0];
|
|
231
|
+
const out = [];
|
|
232
|
+
for (let i = 1; i < vectors.length; i++) {
|
|
233
|
+
const sim = cosineSimilarity(queryVec, vectors[i]);
|
|
234
|
+
if (sim > 0) out.push({ entry: entries[i - 1], score: sim, detail: ['embedding:' + round3(sim)] });
|
|
235
|
+
}
|
|
236
|
+
return out;
|
|
237
|
+
}
|
|
238
|
+
function effectiveEmbeddingCommand(opts) {
|
|
239
|
+
opts = opts || {};
|
|
240
|
+
if (opts.embedding) return String(opts.embedding);
|
|
241
|
+
const cfg = loadConfig();
|
|
242
|
+
return cfg && cfg.embedding_cmd ? String(cfg.embedding_cmd) : '';
|
|
243
|
+
}
|
|
244
|
+
function effectiveEmbeddingTimeout(opts) {
|
|
245
|
+
opts = opts || {};
|
|
246
|
+
if (opts.embeddingTimeout) return parseInt(opts.embeddingTimeout, 10) || 3000;
|
|
247
|
+
const cfg = loadConfig();
|
|
248
|
+
return cfg && cfg.embedding_timeout ? parseInt(cfg.embedding_timeout, 10) || 3000 : 3000;
|
|
249
|
+
}
|
|
153
250
|
function parseFrontmatter(text) {
|
|
154
251
|
const m = text.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
155
252
|
if (!m) return { meta: {}, body: text };
|
|
@@ -1154,6 +1251,28 @@ function recallCore(query, opts) {
|
|
|
1154
1251
|
const wantExplain = !!opts.explain;
|
|
1155
1252
|
const useSemantic = opts.semantic !== false;
|
|
1156
1253
|
const prefilter = (q && useSemantic) ? recallPrefilter(q) : null;
|
|
1254
|
+
const embeddingMap = new Map();
|
|
1255
|
+
const embeddingCommand = effectiveEmbeddingCommand(opts);
|
|
1256
|
+
const embeddingTimeout = effectiveEmbeddingTimeout(opts);
|
|
1257
|
+
if (q && embeddingCommand) {
|
|
1258
|
+
for (const root of roots) {
|
|
1259
|
+
const rootEntries = ensureIndex(root).filter(function (e) {
|
|
1260
|
+
return classifyRead(e, agent, ownerFilter, allSafe, selfAgent) !== 'denied';
|
|
1261
|
+
});
|
|
1262
|
+
try {
|
|
1263
|
+
const hits = embeddingCandidates(rootEntries, q, {
|
|
1264
|
+
embedding: embeddingCommand,
|
|
1265
|
+
embeddingTimeout: embeddingTimeout,
|
|
1266
|
+
root: root
|
|
1267
|
+
});
|
|
1268
|
+
for (const h of hits) {
|
|
1269
|
+
embeddingMap.set(root + '\0' + h.entry.file, h);
|
|
1270
|
+
}
|
|
1271
|
+
} catch (err) {
|
|
1272
|
+
// Plugin failure is not fatal; keep lexical-only recall.
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1157
1276
|
const hits = [];
|
|
1158
1277
|
let deniedCount = 0;
|
|
1159
1278
|
for (const root of roots) {
|
|
@@ -1164,12 +1283,19 @@ function recallCore(query, opts) {
|
|
|
1164
1283
|
if (r === 'denied') { deniedCount++; continue; }
|
|
1165
1284
|
let score = 0;
|
|
1166
1285
|
let detail = null;
|
|
1286
|
+
const embeddingHit = embeddingMap.get(root + '\0' + e.file) || null;
|
|
1167
1287
|
if (q) {
|
|
1168
1288
|
if (useSemantic) {
|
|
1169
|
-
if (prefilter && !prefilter(e)) continue; // v0.8.1
|
|
1289
|
+
if (prefilter && !prefilter(e) && !embeddingHit) continue; // v0.8.1 候选预过滤:粗筛后再语义打分;embedding 命中可越过词法预过滤
|
|
1170
1290
|
const m = semanticMatch(e, q, wantExplain);
|
|
1171
1291
|
score = m.score;
|
|
1172
1292
|
if (wantExplain && m.detail && m.detail.length) detail = m.detail;
|
|
1293
|
+
if (embeddingHit) {
|
|
1294
|
+
score = Math.max(score, embeddingHit.score);
|
|
1295
|
+
if (wantExplain && embeddingHit.detail) {
|
|
1296
|
+
detail = (detail || []).concat(embeddingHit.detail);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1173
1299
|
} else {
|
|
1174
1300
|
const qtoks = tokenize(q);
|
|
1175
1301
|
for (const tt of qtoks) { if (e.tokens && e.tokens[tt]) score += e.tokens[tt]; }
|
|
@@ -1245,7 +1371,21 @@ function recallCore(query, opts) {
|
|
|
1245
1371
|
if (deniedCount > 0 && explicitCross) {
|
|
1246
1372
|
lines.push('\n[警告] 本次检索共拒绝 ' + deniedCount + ' 条越界访问(其它智能体私密记忆,未授权不展示)。如需读取请加 --unsafe 或 --owner user。');
|
|
1247
1373
|
}
|
|
1248
|
-
return {
|
|
1374
|
+
return {
|
|
1375
|
+
error: false,
|
|
1376
|
+
exitCode: 0,
|
|
1377
|
+
text: lines.join('\n'),
|
|
1378
|
+
entries: shown.map(function (h) {
|
|
1379
|
+
return {
|
|
1380
|
+
root: h.root,
|
|
1381
|
+
file: h.entry.file,
|
|
1382
|
+
type: h.entry.type,
|
|
1383
|
+
subject: h.entry.subject,
|
|
1384
|
+
statement: h.entry.statement,
|
|
1385
|
+
score: h.finalScore === undefined ? h.score : h.finalScore
|
|
1386
|
+
};
|
|
1387
|
+
})
|
|
1388
|
+
};
|
|
1249
1389
|
}
|
|
1250
1390
|
function resolveMemoryFile(root, ref) {
|
|
1251
1391
|
const map = {};
|
|
@@ -2509,6 +2649,11 @@ function contextCore(opts) {
|
|
|
2509
2649
|
const owner = opts.owner || selfAgent;
|
|
2510
2650
|
const unsafe = !!opts.unsafe;
|
|
2511
2651
|
const budget = opts.budget ? parseInt(opts.budget, 10) : 0;
|
|
2652
|
+
const focus = opts.focus ? String(opts.focus) : '';
|
|
2653
|
+
const explain = !!opts.explain;
|
|
2654
|
+
const embeddingCommand = effectiveEmbeddingCommand(opts);
|
|
2655
|
+
const embeddingTimeout = effectiveEmbeddingTimeout(opts);
|
|
2656
|
+
const trace = [];
|
|
2512
2657
|
const lines = [];
|
|
2513
2658
|
const FENCE = String.fromCharCode(96, 96, 96);
|
|
2514
2659
|
function usedChars() { return lines.reduce(function (s, x) { return s + String(x).length + 1; }, 0); }
|
|
@@ -2561,6 +2706,32 @@ function contextCore(opts) {
|
|
|
2561
2706
|
lines.push('(未声明身份,跳过画像;先 iam 登记后可生成)');
|
|
2562
2707
|
}
|
|
2563
2708
|
lines.push('');
|
|
2709
|
+
|
|
2710
|
+
if (focus) {
|
|
2711
|
+
lines.push('## 2.5 任务相关记忆(--focus)');
|
|
2712
|
+
lines.push('');
|
|
2713
|
+
const focused = recallCore(focus, {
|
|
2714
|
+
limit: limit,
|
|
2715
|
+
owner: owner,
|
|
2716
|
+
unsafe: unsafe,
|
|
2717
|
+
selfAgent: selfAgent,
|
|
2718
|
+
embedding: embeddingCommand,
|
|
2719
|
+
embeddingTimeout: embeddingTimeout
|
|
2720
|
+
});
|
|
2721
|
+
const focusedEntries = focused.entries || [];
|
|
2722
|
+
if (!focusedEntries.length) lines.push('(无匹配记忆)');
|
|
2723
|
+
for (const e of focusedEntries) {
|
|
2724
|
+
const line = '- [' + e.type + '] ' + e.subject + ': ' + e.statement;
|
|
2725
|
+
if (budget > 0 && usedChars() + line.length > budget) {
|
|
2726
|
+
trace.push('[dropped] ' + e.file + ' reason: budget_exceeded');
|
|
2727
|
+
continue;
|
|
2728
|
+
}
|
|
2729
|
+
lines.push(line);
|
|
2730
|
+
trace.push('[included] ' + e.file + ' reason: focus_match score: ' + round3(e.score));
|
|
2731
|
+
}
|
|
2732
|
+
lines.push('');
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2564
2735
|
lines.push('## 3. 近期记忆(按活跃度前 ' + limit + ' 条)');
|
|
2565
2736
|
lines.push('');
|
|
2566
2737
|
const recent = [];
|
|
@@ -2576,8 +2747,12 @@ function contextCore(opts) {
|
|
|
2576
2747
|
if (!recentShown.length) lines.push('(暂无记忆)');
|
|
2577
2748
|
for (const h of recentShown) {
|
|
2578
2749
|
const line = '- [' + h.e.type + '] ' + h.e.subject + ': ' + h.e.statement;
|
|
2579
|
-
if (budget > 0 && usedChars() + line.length > budget)
|
|
2750
|
+
if (budget > 0 && usedChars() + line.length > budget) {
|
|
2751
|
+
trace.push('[dropped] ' + h.e.file + ' reason: budget_exceeded');
|
|
2752
|
+
break;
|
|
2753
|
+
}
|
|
2580
2754
|
lines.push(line);
|
|
2755
|
+
trace.push('[included] ' + h.e.file + ' reason: recent_match');
|
|
2581
2756
|
}
|
|
2582
2757
|
lines.push('');
|
|
2583
2758
|
lines.push('## 4. 边界提醒(BOUND)');
|
|
@@ -2620,6 +2795,13 @@ function contextCore(opts) {
|
|
|
2620
2795
|
}
|
|
2621
2796
|
const oldCount = allEntries.filter(function (e) { return e.created && daysBetween(e.created, today()) > 180 && classifyRead(e, owner, '', unsafe, selfAgent) !== 'denied'; }).length;
|
|
2622
2797
|
if (oldCount > 0) lines.push('- 归档提醒: ' + oldCount + ' 条超 180 天,建议 archive');
|
|
2798
|
+
if (explain) {
|
|
2799
|
+
lines.push('');
|
|
2800
|
+
lines.push('## 7. 选择解释(--explain)');
|
|
2801
|
+
lines.push('');
|
|
2802
|
+
if (!trace.length) lines.push('(无选择记录)');
|
|
2803
|
+
for (const t of trace) lines.push(t);
|
|
2804
|
+
}
|
|
2623
2805
|
return { error: false, exitCode: 0, text: lines.join('\n') };
|
|
2624
2806
|
}
|
|
2625
2807
|
function cmdContext(opts) {
|
|
@@ -2630,16 +2812,20 @@ function cmdContext(opts) {
|
|
|
2630
2812
|
|
|
2631
2813
|
// ---- config 命令 ----
|
|
2632
2814
|
function cmdConfigSet(key, value) {
|
|
2633
|
-
if (key !== 'memory_home') { console.error('未知配置项: ' + key + '(可用: memory_home)'); process.exit(2); }
|
|
2634
|
-
if (!value) { console.error('缺少值: config set
|
|
2815
|
+
if (key !== 'memory_home' && key !== 'embedding_cmd' && key !== 'embedding_timeout') { console.error('未知配置项: ' + key + '(可用: memory_home / embedding_cmd / embedding_timeout)'); process.exit(2); }
|
|
2816
|
+
if (!value) { console.error('缺少值: config set ' + key + ' <值>'); process.exit(2); }
|
|
2635
2817
|
const cfg = loadConfig();
|
|
2636
|
-
cfg.memory_home = value;
|
|
2818
|
+
if (key === 'memory_home') cfg.memory_home = value;
|
|
2819
|
+
else if (key === 'embedding_cmd') cfg.embedding_cmd = value;
|
|
2820
|
+
else if (key === 'embedding_timeout') cfg.embedding_timeout = parseInt(value, 10) || 3000;
|
|
2637
2821
|
saveConfig(cfg);
|
|
2638
|
-
console.log('
|
|
2822
|
+
console.log('已写入配置: ' + key + ' = ' + (key === 'embedding_timeout' ? (parseInt(value, 10) || 3000) : value));
|
|
2639
2823
|
}
|
|
2640
2824
|
function cmdConfigGet() {
|
|
2641
2825
|
const cfg = loadConfig();
|
|
2642
2826
|
console.log('memory_home: ' + (cfg.memory_home || '(未设置,默认 ~/.yottamemory)'));
|
|
2827
|
+
console.log('embedding_cmd: ' + (cfg.embedding_cmd || '(未设置)'));
|
|
2828
|
+
console.log('embedding_timeout: ' + (cfg.embedding_timeout || 3000));
|
|
2643
2829
|
console.log('当前生效用户级位置: ' + userRoot());
|
|
2644
2830
|
if (cfg.serve && Object.keys(cfg.serve).length) console.log('serve: ' + JSON.stringify(cfg.serve));
|
|
2645
2831
|
}
|
|
@@ -2648,8 +2834,9 @@ function cmdConfigGet() {
|
|
|
2648
2834
|
function mcpTools() {
|
|
2649
2835
|
return [
|
|
2650
2836
|
{ name: 'remember', description: '写入一条记忆。参数 type(FACT/PREF/BOUND/COMMIT)、subject、statement 必填;owner 可选,默认当前智能体', inputSchema: { type: 'object', properties: { type: { type: 'string', description: 'FACT/PREF/BOUND/COMMIT' }, subject: { type: 'string' }, statement: { type: 'string' }, owner: { type: 'string' } }, required: ['type', 'subject', 'statement'] } },
|
|
2651
|
-
{ name: 'recall', description: '检索记忆。query 可选;type 可选;limit 可选(默认 20
|
|
2652
|
-
{ name: 'search', description: '检索记忆(同 recall)。query 可选;type 可选;limit 可选(默认 20
|
|
2837
|
+
{ name: 'recall', description: '检索记忆。query 可选;type 可选;limit 可选(默认 20);explain 可选。只返回当前智能体可读记忆;embedding 插件只能由本机 config 配置,远端不可传命令', inputSchema: { type: 'object', properties: { query: { type: 'string' }, type: { type: 'string' }, limit: { type: 'number' }, embeddingTimeout: { type: 'number' }, explain: { type: 'boolean' } } } },
|
|
2838
|
+
{ name: 'search', description: '检索记忆(同 recall)。query 可选;type 可选;limit 可选(默认 20);explain 可选;embedding 插件只能由本机 config 配置,远端不可传命令', inputSchema: { type: 'object', properties: { query: { type: 'string' }, type: { type: 'string' }, limit: { type: 'number' }, embeddingTimeout: { type: 'number' }, explain: { type: 'boolean' } } } },
|
|
2839
|
+
{ name: 'context', description: '生成开工上下文包。focus 可选;limit 可选;budget 可选;explain 可选;embedding 插件只能由本机 config 配置,远端不可传命令', inputSchema: { type: 'object', properties: { focus: { type: 'string' }, limit: { type: 'number' }, budget: { type: 'number' }, explain: { type: 'boolean' }, embeddingTimeout: { type: 'number' } } } },
|
|
2653
2840
|
{ name: 'forget', description: '删除一条记忆。file 为记忆文件路径(如 facts/2026-08-24-0001.md 或文件名)', inputSchema: { type: 'object', properties: { file: { type: 'string' } }, required: ['file'] } },
|
|
2654
2841
|
{ name: 'archive', description: '归档旧记忆。days 默认 180;threshold 默认 0.4', inputSchema: { type: 'object', properties: { days: { type: 'number' }, threshold: { type: 'number' } } } },
|
|
2655
2842
|
{ name: 'reindex', description: '重建索引(手动改 .md 后校正;扫描 facts/prefs/bounds/commits 四目录)', inputSchema: { type: 'object', properties: {} } },
|
|
@@ -2673,7 +2860,24 @@ function callTool(name, args, ctx) {
|
|
|
2673
2860
|
return { text: r.text, error: r.error };
|
|
2674
2861
|
}
|
|
2675
2862
|
if (name === 'recall' || name === 'search') {
|
|
2676
|
-
const r = recallCore(args.query ? String(args.query) : null, {
|
|
2863
|
+
const r = recallCore(args.query ? String(args.query) : null, {
|
|
2864
|
+
limit: args.limit || 20,
|
|
2865
|
+
type: args.type ? String(args.type) : null,
|
|
2866
|
+
agent: agent,
|
|
2867
|
+
embeddingTimeout: args.embeddingTimeout || 3000,
|
|
2868
|
+
explain: !!args.explain
|
|
2869
|
+
});
|
|
2870
|
+
return { text: r.text, error: r.error };
|
|
2871
|
+
}
|
|
2872
|
+
if (name === 'context') {
|
|
2873
|
+
const r = contextCore({
|
|
2874
|
+
focus: args.focus ? String(args.focus) : '',
|
|
2875
|
+
limit: args.limit || 10,
|
|
2876
|
+
budget: args.budget || 0,
|
|
2877
|
+
explain: !!args.explain,
|
|
2878
|
+
embeddingTimeout: args.embeddingTimeout || 3000,
|
|
2879
|
+
selfAgent: agent
|
|
2880
|
+
});
|
|
2677
2881
|
return { text: r.text, error: r.error };
|
|
2678
2882
|
}
|
|
2679
2883
|
if (name === 'forget') {
|
|
@@ -3315,7 +3519,7 @@ function usage() {
|
|
|
3315
3519
|
['view', '启动用户查看平台(--port/--host;口令解锁浏览/授权/吊销 AI)'],
|
|
3316
3520
|
['reset-password', '重设主口令(忘口令用恢复钥匙)'],
|
|
3317
3521
|
['key', '管理 AI 私密读取授权缓存(list / authorize <id> / revoke <id>)'],
|
|
3318
|
-
['config', '
|
|
3522
|
+
['config', '查看/设置配置(get / set memory_home <目录> / set embedding_cmd <命令> / set embedding_timeout <毫秒>)']
|
|
3319
3523
|
]],
|
|
3320
3524
|
['平台与服务', [
|
|
3321
3525
|
['serve', '启动 MCP 记忆引擎(streamable HTTP;--stdio 本地零进程)'],
|
|
@@ -3343,7 +3547,7 @@ async function main() {
|
|
|
3343
3547
|
if (!args.length) { usage(); return; }
|
|
3344
3548
|
const opts = {};
|
|
3345
3549
|
const positional = [];
|
|
3346
|
-
const valueOpts = new Set(['--type', '--limit', '--days', '--out', '--owner', '--agent', '--threshold', '--scope', '--host', '--port', '--dir', '--name', '--user', '--relationship', '--source', '--weight', '--budget', '--password', '--new-password', '--recovery-key', '--reason', '--merge', '--model', '--subject']);
|
|
3550
|
+
const valueOpts = new Set(['--type', '--limit', '--days', '--out', '--owner', '--agent', '--threshold', '--scope', '--host', '--port', '--dir', '--name', '--user', '--relationship', '--source', '--weight', '--budget', '--password', '--new-password', '--recovery-key', '--reason', '--merge', '--model', '--subject', '--embedding', '--focus', '--embedding-timeout']);
|
|
3347
3551
|
for (let i = 0; i < args.length; i++) {
|
|
3348
3552
|
const a = args[i];
|
|
3349
3553
|
if (a === '--version' || a === '-v') { console.log(VERSION); return; }
|
|
@@ -3394,6 +3598,9 @@ async function main() {
|
|
|
3394
3598
|
else if (a === '--merge') opts.merge = v;
|
|
3395
3599
|
else if (a === '--model') opts.model = v;
|
|
3396
3600
|
else if (a === '--subject') opts.subject = v;
|
|
3601
|
+
else if (a === '--embedding') opts.embedding = v;
|
|
3602
|
+
else if (a === '--focus') opts.focus = v;
|
|
3603
|
+
else if (a === '--embedding-timeout') opts.embeddingTimeout = parseInt(v, 10) || 3000;
|
|
3397
3604
|
} else if (a.startsWith('--')) {
|
|
3398
3605
|
console.error('未知选项: ' + a);
|
|
3399
3606
|
process.exit(2);
|
|
@@ -3411,7 +3618,7 @@ async function main() {
|
|
|
3411
3618
|
const sub = rest[0];
|
|
3412
3619
|
if (sub === 'set') cmdConfigSet(rest[1], rest[2]);
|
|
3413
3620
|
else if (sub === 'get') cmdConfigGet();
|
|
3414
|
-
else { console.error('config 子命令: set memory_home <目录> / get'); process.exit(2); }
|
|
3621
|
+
else { console.error('config 子命令: set memory_home <目录> / set embedding_cmd <命令> / set embedding_timeout <毫秒> / get'); process.exit(2); }
|
|
3415
3622
|
break;
|
|
3416
3623
|
}
|
|
3417
3624
|
case 'remember': cmdRemember(rest[0], rest[1], rest[2], opts); break;
|
|
@@ -3464,7 +3671,7 @@ async function main() {
|
|
|
3464
3671
|
}
|
|
3465
3672
|
}
|
|
3466
3673
|
|
|
3467
|
-
if (require.main === module) { main().catch(function (e) { console.error('错误: ' + (e && e.message ? e.message : String(e))); process.exit(2); }); }
|
|
3674
|
+
if (require.main === module) { main().catch(function (e) { console.error('错误: ' + (e && e.message ? e.message : String(e))); console.error('修复建议: 若与记忆库/密钥/权限有关,请检查 memory_home 路径、主口令与恢复钥匙,或运行 yotta-memory config get 确认位置;仍无法解决请把上面的错误信息反馈给开发者。'); process.exit(2); }); }
|
|
3468
3675
|
module.exports = {
|
|
3469
3676
|
VERSION: VERSION,
|
|
3470
3677
|
userRoot: userRoot,
|
|
@@ -3536,6 +3743,9 @@ module.exports = {
|
|
|
3536
3743
|
utilityScore: utilityScore,
|
|
3537
3744
|
utilityBreakdown: utilityBreakdown,
|
|
3538
3745
|
semanticMatch: semanticMatch,
|
|
3746
|
+
runEmbeddingPlugin: runEmbeddingPlugin,
|
|
3747
|
+
cosineSimilarity: cosineSimilarity,
|
|
3748
|
+
embeddingCandidates: embeddingCandidates,
|
|
3539
3749
|
pinyinTokens: pinyinTokens,
|
|
3540
3750
|
isEncrypted: isEncrypted,
|
|
3541
3751
|
collectOwners: collectOwners,
|
|
@@ -3585,4 +3795,3 @@ module.exports = {
|
|
|
3585
3795
|
viewServerCore: viewServerCore,
|
|
3586
3796
|
|
|
3587
3797
|
};
|
|
3588
|
-
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yottameta/yotta-memory",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Yuanyi (元忆) — boundary-aware, file-based memory for AI agents. File-based, zero-dependency, diff/rollback-able; FACT/PREF/BOUND/COMMIT four types (public shared / private isolated), user-level + project-level storage; v0.8 semantic search
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "Yuanyi (元忆) — boundary-aware, file-based memory for AI agents. File-based, zero-dependency, diff/rollback-able; FACT/PREF/BOUND/COMMIT four types (public shared / private isolated), user-level + project-level storage; v0.9 recall quality, context focus, optional local embedding plugin, plus v0.8 semantic search, feedback loop, self-organization, and distillation.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"agent-skills",
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"bin",
|
|
24
24
|
"README.zh-CN.md",
|
|
25
25
|
"NOTICE",
|
|
26
|
-
"CHANGELOG.md"
|
|
26
|
+
"CHANGELOG.md",
|
|
27
|
+
"!scripts/test_*.py"
|
|
27
28
|
],
|
|
28
29
|
"repository": {
|
|
29
30
|
"type": "git",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# 元忆 FAQ / 避坑指南
|
|
2
|
+
|
|
3
|
+
> 常见问题速查:记忆找不到、权限/加密困惑、连不上时先看这里。
|
|
4
|
+
|
|
5
|
+
## 1. 记忆类型选错了怎么办?
|
|
6
|
+
类型只在写入时提示、不阻止(FACT=公共 / PREF、BOUND、COMMIT=私密)。写错不影响已写入内容;想改类型可 `forget` 后按正确类型重写。不需要提示可用 `--no-hint`。
|
|
7
|
+
|
|
8
|
+
## 2. 私密区加密怎么用?
|
|
9
|
+
`init` 默认初始化加密库(需主口令 + 恢复钥匙,请妥善保存);明文库可用 `migrate` 升级为加密。私密区文件为 `.md.enc`,可 git 版本化。查看/授权用 `yotta-memory view`(口令解锁,浏览/授权/吊销 AI)。
|
|
10
|
+
|
|
11
|
+
## 3. 多智能体权限怎么隔离?
|
|
12
|
+
公共 FACT 所有智能体可读;PREF / BOUND / COMMIT 按 owner 物理隔离,其他智能体需显式授权(`key authorize <id>` 或 `view` 平台授权)。不授权读不到,也不会被别的智能体读到。
|
|
13
|
+
|
|
14
|
+
## 4. 记忆找不到了?
|
|
15
|
+
先 `config get` 确认 `memory_home` 指向的库;再 `reindex` 重建索引(升级后索引版本变化会自动重建);最后 `recall <关键词>` / `search <词>` 语义检索。跨项目记忆在项目级 `.yottamemory`。
|
|
16
|
+
|
|
17
|
+
## 5. 忘记主口令了?
|
|
18
|
+
用初始化时保存的**恢复钥匙**:`yotta-memory reset-password`。没有恢复钥匙则私密区无法解锁(这是加密的预期行为),公共 FACT 不受影响。
|
|
19
|
+
|
|
20
|
+
## 6. 局域网(便携记忆盘)怎么连?
|
|
21
|
+
引擎主机 `lan enable` 注册开机自启(Windows 计划任务 / Linux systemd)→ `token new --agent <id>` 生成 token;客户端配 `url: http://<主机IP>:8787/mcp` + `Authorization: Bearer <token>` + `X-Agent-Id: <id>`。`lan status` 查状态。
|
|
22
|
+
|
|
23
|
+
## 7. MCP 工具没加载?
|
|
24
|
+
检查客户端 `mcpServers` 已配置 yotta-memory(url + token);改配置后重启/重载会话。本机直连可不配 MCP,直接用 CLI。
|
|
25
|
+
|
|
26
|
+
## 8. 记忆库在哪个目录?
|
|
27
|
+
`yotta-memory config get` 查看;`config set memory_home <目录>` 改位置。项目级记忆用 `init --project`(存 `.yottamemory/` 随项目共享)。
|
|
28
|
+
|
|
29
|
+
## 9. 跨会话恢复上下文?
|
|
30
|
+
开工运行 `yotta-memory context`(身份 + 画像 + 近期记忆 + 边界 + 承诺),需要细节再 `recall <关键词>`。
|
|
31
|
+
|
|
32
|
+
## 10. 备份与迁移?
|
|
33
|
+
`export --out 文件.json` 导出全部记忆;`import <文件.json>` 恢复。公共 FACT 是明文文件可直接 git 备份;私密区用 export(需解锁)。
|