recallnest 2.5.4 → 2.6.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 +37 -0
- package/README.md +34 -9
- package/README_CN.md +37 -12
- package/package.json +4 -4
- package/src/__tests__/access-tracker-novelty.test.ts +66 -0
- package/src/__tests__/api-server-security.test.ts +102 -0
- package/src/__tests__/belief-history.test.ts +220 -0
- package/src/__tests__/capture-engine.test.ts +93 -3
- package/src/__tests__/category-min-scores.test.ts +83 -0
- package/src/__tests__/cluster-consolidation.test.ts +167 -4
- package/src/__tests__/conflict-store.test.ts +46 -2
- package/src/__tests__/consolidation-engine.test.ts +97 -0
- package/src/__tests__/contracts.test.ts +46 -0
- package/src/__tests__/decay-exemption.test.ts +45 -0
- package/src/__tests__/dream-pipeline.test.ts +464 -5
- package/src/__tests__/freshness.test.ts +186 -0
- package/src/__tests__/hotness-blend.test.ts +207 -0
- package/src/__tests__/llm-client-pivot.test.ts +628 -0
- package/src/__tests__/maintenance-locks.test.ts +15 -0
- package/src/__tests__/memory-boundaries.test.ts +32 -0
- package/src/__tests__/noise-prototype-bank.test.ts +280 -0
- package/src/__tests__/pii-redact.test.ts +19 -0
- package/src/__tests__/pivot-apply.test.ts +373 -0
- package/src/__tests__/pivot-distill-supervisor.test.ts +457 -0
- package/src/__tests__/pivot-distill.test.ts +1178 -0
- package/src/__tests__/preference-matcher.test.ts +54 -2
- package/src/__tests__/pull-from-macbook-sync-only.test.ts +679 -0
- package/src/__tests__/recall-gate.test.ts +266 -0
- package/src/__tests__/resolve-db-path.test.ts +130 -0
- package/src/__tests__/resolve-tier.test.ts +64 -0
- package/src/__tests__/retrieval-eval.test.ts +163 -0
- package/src/__tests__/retriever-lazy-init-dispatch.test.ts +123 -0
- package/src/__tests__/skill-promotion.test.ts +53 -0
- package/src/__tests__/stable-context-length-contract.test.ts +62 -0
- package/src/__tests__/store-read-consistency.test.ts +122 -0
- package/src/__tests__/store-schema-migration.test.ts +87 -0
- package/src/__tests__/store-upsert.test.ts +17 -0
- package/src/__tests__/term-registry-terminal-roster.test.ts +127 -0
- package/src/__tests__/ui-server-security.test.ts +93 -0
- package/src/access-tracker.ts +53 -3
- package/src/adaptive-retrieval.ts +11 -0
- package/src/api-server.ts +9 -2
- package/src/auto-recall.ts +61 -1
- package/src/belief-history.ts +164 -0
- package/src/capture-engine.ts +88 -11
- package/src/cli.ts +109 -14
- package/src/conflict-engine.ts +24 -3
- package/src/consolidation-engine.ts +146 -12
- package/src/context-composer-stable-selection.ts +7 -1
- package/src/data-checkup.ts +1 -1
- package/src/decay-engine.ts +59 -7
- package/src/doctor.ts +4 -2
- package/src/dream-pipeline.ts +359 -11
- package/src/env-config.ts +41 -0
- package/src/eval.ts +154 -11
- package/src/freshness.ts +192 -0
- package/src/http-request-policy.ts +148 -0
- package/src/ingest.ts +277 -2
- package/src/kg-extractor.ts +7 -1
- package/src/llm-client.ts +106 -11
- package/src/mcp-server.ts +2 -1
- package/src/mcp-tools-advanced.ts +13 -0
- package/src/mcp-tools-core.ts +5 -1
- package/src/memory-boundaries.ts +23 -2
- package/src/memory-health-rebalance.ts +4 -0
- package/src/memory-output.ts +16 -2
- package/src/memory-store-port.ts +3 -0
- package/src/noise-prototype-bank.ts +408 -0
- package/src/pii-detector.ts +52 -2
- package/src/pivot-apply.ts +399 -0
- package/src/preference-matcher.ts +37 -3
- package/src/recall-gate.ts +305 -0
- package/src/retrieval-profiles.ts +46 -4
- package/src/retriever.ts +95 -18
- package/src/retroactive-boost.ts +6 -2
- package/src/runtime-config.ts +70 -5
- package/src/skill-promotion.ts +58 -2
- package/src/store.ts +54 -19
- package/src/term-registry.ts +35 -0
- package/src/ui-server.ts +7 -0
- package/src/version.ts +19 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v2.6.0 — Cross-process consistency and reliable distribution (2026-08-13)
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Claude Code marketplace installation now registers the RecallNest MCP server and continuity skill instead of shipping metadata only. Jina credentials use sensitive plugin configuration; generated config and LanceDB data live under `${CLAUDE_PLUGIN_DATA}` and survive plugin updates.
|
|
8
|
+
- Kimi, AGY/Antigravity, and minis transcript sources are recognized across ingestion, memory-boundary policy, and term resolution.
|
|
9
|
+
- Retrieval audit logging is connected to the live retriever, and the opt-in layer-admission shadow/enforcement pipeline is available through `RECALLNEST_LAYER_ADMISSION=observe|on`.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- `package.json` is now the single version source for CLI output, MCP server metadata, HTTP health responses, npm metadata, and the Claude Code marketplace. All public surfaces report `2.6.0`.
|
|
14
|
+
- LanceDB uses strong cross-process read consistency by default. `RECALLNEST_READ_CONSISTENCY_INTERVAL=<seconds>` selects bounded staleness; `off` restores the legacy unchecked handle behavior.
|
|
15
|
+
- Belief changes preserve prior rows as `superseded`; procedural memories avoid time decay; cold-start scoring, length normalization, and short single-token queries have safer retrieval behavior.
|
|
16
|
+
- `dream` adds failure classification, wall-clock budgeting, vector refill before clustering, and output assertions so a successful status means useful work was produced.
|
|
17
|
+
- `@modelcontextprotocol/sdk` is updated to 1.30.0, with both npm and Bun lockfiles aligned.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Empty legacy LanceDB tables now receive schema migrations before their first new write.
|
|
22
|
+
- Long-lived retrievers now see writes committed by CLI ingest and other processes without a restart.
|
|
23
|
+
- Runtime and maintenance scripts resolve the configured database path consistently instead of silently opening a second database.
|
|
24
|
+
- Local HTTP access is constrained to the intended loopback boundary, and tracked credential scans cover release contents without printing secret values.
|
|
25
|
+
- Per-cluster LLM timeouts no longer abort an entire `dream` scope; failures are counted, single-scope runs emit the same metrics contract as automatic runs, and the launch wrapper no longer fails after successful work because of an undefined log-file variable.
|
|
26
|
+
|
|
27
|
+
### Upgrade notes
|
|
28
|
+
|
|
29
|
+
- v2.5.4 databases open in place; no export/import step is required. The schema migration also covers empty tables.
|
|
30
|
+
- Plugin users need Bun and will be prompted for a Jina API key on first install. Existing manual-clone installations keep their current configuration and data path.
|
|
31
|
+
- Retrievals now add audit rows. `audit.jsonl` has no automatic rotation; archive it when it approaches 50 MB.
|
|
32
|
+
- Layer admission remains off by default. Use `observe` before enabling enforcement on an existing memory corpus.
|
|
33
|
+
|
|
34
|
+
### Verification
|
|
35
|
+
|
|
36
|
+
- 2,152 tests pass across 152 files.
|
|
37
|
+
- A database written by the remote v2.5.4 release was opened, read, and extended by v2.6.0 in an isolated upgrade smoke test.
|
|
38
|
+
- An isolated Claude Code installation connected to the plugin MCP server with all 43 tools; packed npm installs reported `2.6.0` from both `recallnest` and the legacy `local-memory` alias.
|
|
39
|
+
|
|
3
40
|
## v2.5.4 — npm 发布边界修复 (2026-07-17)
|
|
4
41
|
|
|
5
42
|
- package.json 改为严格 files 白名单,只发布运行所需源码、示例配置、UI、集成脚本和必要文档。
|
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
# RecallNest
|
|
4
4
|
|
|
5
|
-
**Shared Memory Layer for Claude Code, Codex,
|
|
5
|
+
**Shared Memory Layer for Any MCP Client — Claude Code, Codex, Kimi, Antigravity, Gemini CLI**
|
|
6
6
|
|
|
7
|
-
*One memory.
|
|
7
|
+
*One memory. Every terminal. Context that survives across windows.*
|
|
8
8
|
|
|
9
9
|
A local-first memory system backed by LanceDB that turns scattered conversation history into reusable knowledge — shared across your coding agents, recalled automatically.
|
|
10
10
|
|
|
@@ -13,7 +13,7 @@ A local-first memory system backed by LanceDB that turns scattered conversation
|
|
|
13
13
|
[](https://bun.sh)
|
|
14
14
|
[](https://lancedb.com)
|
|
15
15
|
[](https://modelcontextprotocol.io)
|
|
16
|
-
[](https://github.com/AliceLJY/recallnest/actions/workflows/ci.yml)
|
|
17
17
|
[](https://github.com/AliceLJY/recallnest)
|
|
18
18
|
|
|
19
19
|
**English** | [简体中文](README_CN.md) | [Roadmap](ROADMAP.md)
|
|
@@ -24,7 +24,7 @@ A local-first memory system backed by LanceDB that turns scattered conversation
|
|
|
24
24
|
|
|
25
25
|
## Why RecallNest?
|
|
26
26
|
|
|
27
|
-
Coding agents forget everything between windows. Your context — project configs, debugging decisions, entity mappings — is scattered across Claude Code, Codex, and
|
|
27
|
+
Coding agents forget everything between windows. Your context — project configs, debugging decisions, entity mappings — is scattered across Claude Code, Codex, Kimi, Antigravity — and every other terminal you open — with no shared memory.
|
|
28
28
|
|
|
29
29
|
RecallNest solves this: **a single LanceDB-backed memory layer that your coding agents read and write**. Context stored in one window is auto-recalled in another. Sessions checkpoint on exit and resume on start. Memory decays, evolves, and self-organizes — not just raw log storage.
|
|
30
30
|
|
|
@@ -40,7 +40,11 @@ RecallNest solves this: **a single LanceDB-backed memory layer that your coding
|
|
|
40
40
|
|
|
41
41
|
RecallNest starts automatically with Claude Code. No manual MCP config needed.
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
Claude Code prompts for a Jina API key during installation. The key is stored through Claude Code's sensitive plugin configuration, while the generated config and LanceDB database live in the plugin's persistent data directory rather than the versioned plugin cache.
|
|
44
|
+
|
|
45
|
+
> The Claude Code plugin and npm package share one release version and are updated together.
|
|
46
|
+
>
|
|
47
|
+
> **Requires:** [Bun](https://bun.sh). Dependencies install on first start.
|
|
44
48
|
|
|
45
49
|
### Option B: npm install
|
|
46
50
|
|
|
@@ -139,7 +143,7 @@ bun run src/ui-server.ts
|
|
|
139
143
|
| Capability | Description |
|
|
140
144
|
|---|---|
|
|
141
145
|
| **CC Plugin** | Install in Claude Code with one command — no manual config |
|
|
142
|
-
| **Shared Index** | One LanceDB store
|
|
146
|
+
| **Shared Index** | One LanceDB store shared by every terminal that speaks MCP |
|
|
143
147
|
| **Dual Interface** | MCP (stdio) for CLI tools + HTTP API for custom agents |
|
|
144
148
|
| **One-Click Setup** | Integration scripts install MCP access and continuity rules |
|
|
145
149
|
|
|
@@ -192,6 +196,26 @@ bun run src/ui-server.ts
|
|
|
192
196
|
|
|
193
197
|
---
|
|
194
198
|
|
|
199
|
+
## New in v2.6: Reliable Cross-Process Memory and Distribution
|
|
200
|
+
|
|
201
|
+
v2.6 turns the development since v2.5.4 into a release-ready upgrade:
|
|
202
|
+
|
|
203
|
+
- **Cross-process visibility** — LanceDB now checks for external commits on every read by default, so resident MCP/API/UI processes see writes from CLI ingestion without a restart. Set `RECALLNEST_READ_CONSISTENCY_INTERVAL=<seconds>` for bounded staleness or `off` for the legacy unchecked behavior.
|
|
204
|
+
- **Safer memory evolution** — belief changes preserve the old row as `superseded`; procedural memories avoid time decay; cold-start and length-normalization behavior no longer suppress short entity queries or stable memories.
|
|
205
|
+
- **More reliable consolidation** — `dream` now distinguishes failure classes, honors wall-clock budgets, refills vectors before semantic clustering, and asserts that successful runs actually produced work.
|
|
206
|
+
- **Broader conversation coverage** — Kimi, AGY/Antigravity, and minis sources are recognized across ingestion, scope boundaries, and term resolution.
|
|
207
|
+
- **One public version** — npm metadata, CLI `--version`, MCP handshakes, HTTP health responses, and the Claude Code marketplace all follow the `2.6.0` release contract.
|
|
208
|
+
- **Installable Claude Code plugin** — installation now registers the 43-tool MCP server and continuity skill, asks for the Jina key through sensitive plugin configuration, and keeps config plus LanceDB data in Claude Code's persistent plugin data directory.
|
|
209
|
+
|
|
210
|
+
### Upgrading from v2.5.4
|
|
211
|
+
|
|
212
|
+
- Existing LanceDB data is opened in place. Legacy tables missing newer fields are migrated automatically, including empty tables.
|
|
213
|
+
- Plugin data survives plugin updates because it is stored outside the versioned cache. A manual clone continues to use its existing `config.json` and database path.
|
|
214
|
+
- Retrieval auditing now includes read operations. `audit.jsonl` has no automatic rotation yet; consider archiving it if it approaches 50 MB.
|
|
215
|
+
- `RECALLNEST_LAYER_ADMISSION` remains opt-in (`observe` or `on`); the default is `off`.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
195
219
|
## New in v2.1: Philosophy-Informed Memory
|
|
196
220
|
|
|
197
221
|
v2.0 built the operational memory platform; v2.1 added philosophy-informed memory behavior.
|
|
@@ -299,7 +323,7 @@ v2.2 hardened retrieval quality; v2.3 opens RecallNest to external data sources
|
|
|
299
323
|
|
|
300
324
|
RecallNest serves two interfaces:
|
|
301
325
|
|
|
302
|
-
- **MCP** — for Claude Code,
|
|
326
|
+
- **MCP** — for any MCP client: Claude Code, Codex, Kimi, Antigravity, Gemini CLI (native tool access)
|
|
303
327
|
- **HTTP API** — for custom agents, SDK-based apps, and any HTTP client
|
|
304
328
|
|
|
305
329
|
### Agent framework examples
|
|
@@ -352,6 +376,7 @@ Examples live in [`integrations/examples/`](integrations/examples/):
|
|
|
352
376
|
| `store_skill` | Store an executable skill with trigger conditions and verification |
|
|
353
377
|
| `retrieve_skill` | Retrieve matching executable skills by semantic similarity |
|
|
354
378
|
| `scan_skill_promotions` | Scan cases/patterns for promotion candidates to skills |
|
|
379
|
+
| `manage_alias` | Add, remove, list, or explain user query aliases for BM25 retrieval |
|
|
355
380
|
| `list_tools` | Discover available tools by tier (core/advanced/full) |
|
|
356
381
|
| `batch_store` | Store up to 20 memories in a single call with dedup |
|
|
357
382
|
| `distill_session` | Distill a conversation into structured knowledge via 3-layer pipeline |
|
|
@@ -474,7 +499,7 @@ RecallNest is actively maintained. All major architecture phases are complete
|
|
|
474
499
|
RecallNest started as a fork of [memory-lancedb-pro](https://github.com/CortexReach/memory-lancedb-pro) and shares its core ideas around hybrid retrieval, decay modeling, and memory-as-engineering-system. The key difference:
|
|
475
500
|
|
|
476
501
|
- **memory-lancedb-pro** is an OpenClaw plugin — it adds long-term memory to a single OpenClaw agent.
|
|
477
|
-
- **RecallNest** is a standalone memory layer — it serves Claude Code, Codex,
|
|
502
|
+
- **RecallNest** is a standalone memory layer — it serves any MCP client (Claude Code, Codex, Kimi, Antigravity, Gemini CLI) simultaneously through MCP + HTTP API, with session continuity, structured assets, and conflict management built in.
|
|
478
503
|
|
|
479
504
|
## Credit
|
|
480
505
|
|
|
@@ -494,7 +519,7 @@ Part of the **小试AI** open-source AI workflow:
|
|
|
494
519
|
| Project | Description |
|
|
495
520
|
|---------|-------------|
|
|
496
521
|
| [babel-memory](https://github.com/AliceLJY/babel-memory) | Multilingual preprocessing for BM25 — 27+ languages, zero deps |
|
|
497
|
-
|
|
|
522
|
+
| cc-empire *(private)* | Hooks/rules/methodology — the connective tissue of the whole ecosystem |
|
|
498
523
|
| [telegram-ai-bridge](https://github.com/AliceLJY/telegram-ai-bridge) | Telegram bots for Claude, Codex, and Gemini |
|
|
499
524
|
| [tg-bridge-channel](https://github.com/AliceLJY/tg-bridge-channel) | Sister Telegram bridge using Claude Agent View background sessions |
|
|
500
525
|
| [wechat-ai-bridge](https://github.com/AliceLJY/wechat-ai-bridge) | Run Claude Code / Codex / Gemini in WeChat with session management |
|
package/README_CN.md
CHANGED
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
# RecallNest
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**面向任意 MCP 客户端的共享记忆层 —— Claude Code、Codex、Kimi、Antigravity、Gemini CLI**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
*一套记忆,每个终端,上下文跨窗口延续。*
|
|
8
8
|
|
|
9
|
-
基于 LanceDB
|
|
9
|
+
基于 LanceDB 的本地优先记忆系统,把散落在各个终端的对话历史沉淀为可复用知识,跨终端共享,自动召回。
|
|
10
10
|
|
|
11
11
|
[](https://github.com/AliceLJY/recallnest)
|
|
12
12
|
[](LICENSE)
|
|
13
13
|
[](https://bun.sh)
|
|
14
14
|
[](https://lancedb.com)
|
|
15
15
|
[](https://modelcontextprotocol.io)
|
|
16
|
-
[](https://github.com/AliceLJY/recallnest/actions/workflows/ci.yml)
|
|
17
17
|
[](https://github.com/AliceLJY/recallnest)
|
|
18
18
|
|
|
19
19
|
[English](README.md) | **简体中文** | [Roadmap](ROADMAP.md)
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
## 为什么需要 RecallNest?
|
|
26
26
|
|
|
27
|
-
编程 Agent 每开一个窗口就失忆。项目配置、调试决策、实体映射——散落在 Claude Code、Codex、
|
|
27
|
+
编程 Agent 每开一个窗口就失忆。项目配置、调试决策、实体映射——散落在 Claude Code、Codex、Kimi、Antigravity 以及你打开的每一个终端里,互相不通。
|
|
28
28
|
|
|
29
29
|
RecallNest 的解法:**一个 LanceDB 驱动的记忆层,供你的编程 Agent 共读共写**。一个窗口存入的上下文,另一个窗口自动召回。会话退出时 checkpoint,启动时 resume。记忆会衰减、演化、自组织——不是简单的日志堆积。
|
|
30
30
|
|
|
@@ -40,7 +40,11 @@ RecallNest 的解法:**一个 LanceDB 驱动的记忆层,供你的编程 Age
|
|
|
40
40
|
|
|
41
41
|
RecallNest 随 Claude Code 自动启动,无需手动配置 MCP。
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
安装时 Claude Code 会提示填写 Jina API key。密钥由 Claude Code 的敏感插件配置保存;自动生成的配置和 LanceDB 数据库则放在插件持久数据目录,不会混进按版本更新的插件缓存。
|
|
44
|
+
|
|
45
|
+
> Claude Code 插件与 npm 包共用同一个发布版本,并随版本发布同步更新。
|
|
46
|
+
>
|
|
47
|
+
> **前置要求:** [Bun](https://bun.sh)。首次启动自动安装依赖。
|
|
44
48
|
|
|
45
49
|
### 方式 B:npm 安装
|
|
46
50
|
|
|
@@ -139,7 +143,7 @@ bun run src/ui-server.ts
|
|
|
139
143
|
| 能力 | 说明 |
|
|
140
144
|
|---|---|
|
|
141
145
|
| **CC Plugin** | 一行命令装入 Claude Code,无需手动配置 MCP |
|
|
142
|
-
| **共享索引** |
|
|
146
|
+
| **共享索引** | 所有支持 MCP 的终端共用同一个 LanceDB 存储 |
|
|
143
147
|
| **双通道接入** | MCP(stdio)给 CLI 工具 + HTTP API 给自定义 Agent |
|
|
144
148
|
| **一键接入** | 集成脚本同时安装 MCP 和 continuity 规则 |
|
|
145
149
|
|
|
@@ -192,6 +196,26 @@ bun run src/ui-server.ts
|
|
|
192
196
|
|
|
193
197
|
---
|
|
194
198
|
|
|
199
|
+
## v2.6 新增:跨进程一致性与可靠分发
|
|
200
|
+
|
|
201
|
+
v2.6 把 v2.5.4 以来的开发整理成一版可升级、可安装、版本口径一致的正式候选:
|
|
202
|
+
|
|
203
|
+
- **跨进程即时可见** —— LanceDB 默认每次读取都检查外部提交,常驻 MCP/API/UI 无需重启即可看见 CLI ingest 写入。可用 `RECALLNEST_READ_CONSISTENCY_INTERVAL=<秒>` 设置允许的延迟窗口,或设为 `off` 恢复旧版不检查行为。
|
|
204
|
+
- **更安全的记忆演化** —— 信念变化不再原地覆盖,旧记录保留为 `superseded`;程序性记忆免于时间衰减;冷启动和长度归一化不再压低短实体查询与稳定记忆。
|
|
205
|
+
- **更可靠的整合管线** —— `dream` 增加失败分型、总时长预算、聚类前向量回填,以及“成功必须真的产出结果”的断言。
|
|
206
|
+
- **更完整的对话来源** —— Kimi、AGY/Antigravity 和 minis 已同步纳入 ingest、scope 边界与术语识别。
|
|
207
|
+
- **一个公开版本号** —— npm 元数据、CLI `--version`、MCP 握手、HTTP 健康接口和 Claude Code marketplace 统一遵守 `2.6.0` 发布契约。
|
|
208
|
+
- **真正可安装的 Claude Code 插件** —— 安装后自动注册 43 个 MCP 工具与连续性 skill,通过敏感插件配置接收 Jina key,并把配置与 LanceDB 数据放进 Claude Code 的持久插件数据目录。
|
|
209
|
+
|
|
210
|
+
### 从 v2.5.4 升级
|
|
211
|
+
|
|
212
|
+
- 现有 LanceDB 数据原地打开;缺少新字段的旧表会自动迁移,空表也覆盖。
|
|
213
|
+
- 插件数据位于版本缓存之外,更新插件不会清空;手动 clone 仍沿用现有 `config.json` 与数据库路径。
|
|
214
|
+
- 检索操作现已写入审计日志。`audit.jsonl` 暂无自动轮转,接近 50 MB 时建议人工归档。
|
|
215
|
+
- `RECALLNEST_LAYER_ADMISSION` 仍是显式开启项(`observe` 或 `on`),默认 `off`。
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
195
219
|
## v2.1 新增:记忆哲学驱动的架构升级
|
|
196
220
|
|
|
197
221
|
v2.0 建立了完整的记忆操作平台;v2.1 加入了记忆哲学驱动的记忆行为。
|
|
@@ -253,7 +277,7 @@ v2.2 强化了检索质量;v2.3 通过标准 Connector 框架和运维健康
|
|
|
253
277
|
│ 集成层 │
|
|
254
278
|
│ ┌─────────────────────┐ ┌────────────────────────────┐ │
|
|
255
279
|
│ │ MCP Server │ │ HTTP API Server │ │
|
|
256
|
-
│ │
|
|
280
|
+
│ │ 43 个工具 │ │ 21 个端点 │ │
|
|
257
281
|
│ └─────────┬───────────┘ └──────────┬─────────────────┘ │
|
|
258
282
|
└────────────┼─────────────────────────┼───────────────────┘
|
|
259
283
|
└──────────┬──────────────┘
|
|
@@ -298,7 +322,7 @@ v2.2 强化了检索质量;v2.3 通过标准 Connector 框架和运维健康
|
|
|
298
322
|
|
|
299
323
|
RecallNest 提供两种接口:
|
|
300
324
|
|
|
301
|
-
- **MCP** ——
|
|
325
|
+
- **MCP** —— 给任意 MCP 客户端使用:Claude Code、Codex、Kimi、Antigravity、Gemini CLI(原生工具访问)
|
|
302
326
|
- **HTTP API** —— 给自定义 Agent、SDK 应用和任何 HTTP 客户端使用
|
|
303
327
|
|
|
304
328
|
### Agent 框架示例
|
|
@@ -314,7 +338,7 @@ RecallNest 提供两种接口:
|
|
|
314
338
|
---
|
|
315
339
|
|
|
316
340
|
<details>
|
|
317
|
-
<summary><strong>MCP 工具(
|
|
341
|
+
<summary><strong>MCP 工具(43 个)</strong></summary>
|
|
318
342
|
|
|
319
343
|
| 工具 | 说明 |
|
|
320
344
|
|------|------|
|
|
@@ -351,6 +375,7 @@ RecallNest 提供两种接口:
|
|
|
351
375
|
| `store_skill` | 存储可执行技能 |
|
|
352
376
|
| `retrieve_skill` | 按语义相似度检索技能 |
|
|
353
377
|
| `scan_skill_promotions` | 扫描可升级为技能的候选 |
|
|
378
|
+
| `manage_alias` | 新增、删除、列出或解释 BM25 用户查询别名 |
|
|
354
379
|
| `list_tools` | 按层级发现工具(core/advanced/full) |
|
|
355
380
|
| `batch_store` | 批量存储最多 20 条记忆 |
|
|
356
381
|
| `distill_session` | 三层管线蒸馏对话为结构化知识 |
|
|
@@ -473,7 +498,7 @@ RecallNest 持续维护中。所有主要架构阶段已完成——完整路线
|
|
|
473
498
|
RecallNest 起源于 [memory-lancedb-pro](https://github.com/CortexReach/memory-lancedb-pro) 的 fork,共享混合检索、衰减建模、记忆即系统的核心理念。关键区别:
|
|
474
499
|
|
|
475
500
|
- **memory-lancedb-pro** 是 OpenClaw 插件——为单个 OpenClaw Agent 添加长期记忆。
|
|
476
|
-
- **RecallNest** 是独立记忆层——通过 MCP + HTTP API
|
|
501
|
+
- **RecallNest** 是独立记忆层——通过 MCP + HTTP API 同时服务任意 MCP 客户端(Claude Code、Codex、Kimi、Antigravity、Gemini CLI),内建会话连续性、结构化资产和冲突管理。
|
|
477
502
|
|
|
478
503
|
## 致谢
|
|
479
504
|
|
|
@@ -504,7 +529,7 @@ RecallNest 起源于 [memory-lancedb-pro](https://github.com/CortexReach/memory-
|
|
|
504
529
|
| [claude-code-studio](https://github.com/AliceLJY/claude-code-studio) | Claude Code 多会话协作平台 |
|
|
505
530
|
| [cc-genius](https://github.com/AliceLJY/cc-genius) | Web 版 Claude 客户端(PWA)—— 自托管,iPad 可用 |
|
|
506
531
|
| [agent-nexus](https://github.com/AliceLJY/agent-nexus) | 一键安装:记忆 + 远程控制 |
|
|
507
|
-
|
|
|
532
|
+
| cc-empire *(private)* | Claude Code 完整工作流脚手架 |
|
|
508
533
|
|
|
509
534
|
</details>
|
|
510
535
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "recallnest",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "RecallNest
|
|
3
|
+
"version": "2.6.0",
|
|
4
|
+
"description": "RecallNest — MCP-native, local-first memory search and distillation for AI conversations",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -61,14 +61,14 @@
|
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@lancedb/lancedb": "^0.26.0",
|
|
64
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
64
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
65
65
|
"commander": "^12.0.0",
|
|
66
66
|
"openai": "^4.0.0",
|
|
67
67
|
"tsx": "^4.19.0",
|
|
68
68
|
"zod": "^3.25.76"
|
|
69
69
|
},
|
|
70
70
|
"optionalDependencies": {
|
|
71
|
-
"babel-memory": "
|
|
71
|
+
"babel-memory": "^2.1.1"
|
|
72
72
|
},
|
|
73
73
|
"repository": {
|
|
74
74
|
"type": "git",
|
|
@@ -236,3 +236,69 @@ describe("destroy cleans cooldown", () => {
|
|
|
236
236
|
expect(tracker.shouldReinforce("a", 0.40)).toBe(true);
|
|
237
237
|
});
|
|
238
238
|
});
|
|
239
|
+
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
// Distinct-reader bookkeeping (Artel read fan-out) + default-config semantics
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
|
|
244
|
+
describe("default config after 2026-07-23 production fix", () => {
|
|
245
|
+
it("novelty gate is OFF by default (high-similarity hits are reinforced)", () => {
|
|
246
|
+
const tracker = new AccessTracker(createMockStore([]) as any);
|
|
247
|
+
// 生产实测修复:真实相关命中 cosine >0.65 也必须打点
|
|
248
|
+
expect(tracker.shouldReinforce("a", 0.95)).toBe(true);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
describe("distinct-reader bookkeeping", () => {
|
|
253
|
+
it("writes readerIds and distinctReaderCount on flush", async () => {
|
|
254
|
+
const entries = [makeEntry("a")];
|
|
255
|
+
const store = createMockStore(entries);
|
|
256
|
+
const tracker = new AccessTracker(store as any, {
|
|
257
|
+
...DEFAULT_ACCESS_TRACKER_CONFIG,
|
|
258
|
+
flushIntervalMs: 1,
|
|
259
|
+
cooldownMs: 0,
|
|
260
|
+
});
|
|
261
|
+
tracker.recordAccess(["a"]);
|
|
262
|
+
await tracker.flush();
|
|
263
|
+
|
|
264
|
+
const meta = JSON.parse(store.data.get("a")!.metadata!) as Record<string, unknown>;
|
|
265
|
+
expect(meta.accessCount).toBe(1);
|
|
266
|
+
expect(meta.readerIds).toEqual([tracker.readerId]);
|
|
267
|
+
expect(meta.distinctReaderCount).toBe(1);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it("dedups same reader and unions different readers", async () => {
|
|
271
|
+
const entries = [makeEntry("a")];
|
|
272
|
+
const store = createMockStore(entries);
|
|
273
|
+
const t1 = new AccessTracker(store as any, { ...DEFAULT_ACCESS_TRACKER_CONFIG, flushIntervalMs: 1, cooldownMs: 0 });
|
|
274
|
+
t1.recordAccess(["a"]);
|
|
275
|
+
await t1.flush();
|
|
276
|
+
t1.recordAccess(["a"]);
|
|
277
|
+
await t1.flush(); // same reader twice → still 1 distinct
|
|
278
|
+
|
|
279
|
+
const t2 = new AccessTracker(store as any, { ...DEFAULT_ACCESS_TRACKER_CONFIG, flushIntervalMs: 1, cooldownMs: 0 });
|
|
280
|
+
t2.recordAccess(["a"]);
|
|
281
|
+
await t2.flush(); // second reader → 2 distinct
|
|
282
|
+
|
|
283
|
+
const meta = JSON.parse(store.data.get("a")!.metadata!) as Record<string, unknown>;
|
|
284
|
+
expect(meta.accessCount).toBe(3);
|
|
285
|
+
expect((meta.readerIds as string[]).sort()).toEqual([t1.readerId, t2.readerId].sort());
|
|
286
|
+
expect(meta.distinctReaderCount).toBe(2);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it("saturates readerIds at READER_ID_CAP without growing the array", async () => {
|
|
290
|
+
const capped = Array.from({ length: 8 }, (_, i) => `r-cap${i}`);
|
|
291
|
+
const entries = [makeEntry("a", {
|
|
292
|
+
metadata: JSON.stringify({ accessCount: 8, readerIds: capped, distinctReaderCount: 8 }),
|
|
293
|
+
})];
|
|
294
|
+
const store = createMockStore(entries);
|
|
295
|
+
const tracker = new AccessTracker(store as any, { ...DEFAULT_ACCESS_TRACKER_CONFIG, flushIntervalMs: 1, cooldownMs: 0 });
|
|
296
|
+
tracker.recordAccess(["a"]);
|
|
297
|
+
await tracker.flush();
|
|
298
|
+
|
|
299
|
+
const meta = JSON.parse(store.data.get("a")!.metadata!) as Record<string, unknown>;
|
|
300
|
+
expect((meta.readerIds as string[]).length).toBe(8); // no growth past cap
|
|
301
|
+
expect(meta.distinctReaderCount).toBe(8); // saturates, no overcount
|
|
302
|
+
expect(meta.accessCount).toBe(9); // access still counted
|
|
303
|
+
});
|
|
304
|
+
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
enforceLocalHttpRequestPolicy,
|
|
5
|
+
LOCAL_JSON_BODY_LIMIT_BYTES,
|
|
6
|
+
} from "../http-request-policy.js";
|
|
7
|
+
|
|
8
|
+
function apiRequest({
|
|
9
|
+
method = "GET",
|
|
10
|
+
host = "localhost:4318",
|
|
11
|
+
headers = {},
|
|
12
|
+
body,
|
|
13
|
+
}: {
|
|
14
|
+
method?: string;
|
|
15
|
+
host?: string;
|
|
16
|
+
headers?: Record<string, string>;
|
|
17
|
+
body?: string;
|
|
18
|
+
} = {}): Request {
|
|
19
|
+
return new Request("http://localhost:4318/v1/store", {
|
|
20
|
+
method,
|
|
21
|
+
headers: { host, ...headers },
|
|
22
|
+
body,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe("RecallNest API local HTTP policy", () => {
|
|
27
|
+
test("keeps local CLI JSON requests without Origin usable", async () => {
|
|
28
|
+
const result = await enforceLocalHttpRequestPolicy(apiRequest({
|
|
29
|
+
method: "POST",
|
|
30
|
+
headers: { "content-type": "application/json" },
|
|
31
|
+
body: JSON.stringify({ text: "local CLI", scope: "test:local" }),
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
expect(result).toEqual({ allowed: true });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("allows loopback GET requests without browser headers", async () => {
|
|
38
|
+
const result = await enforceLocalHttpRequestPolicy(apiRequest());
|
|
39
|
+
|
|
40
|
+
expect(result).toEqual({ allowed: true });
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("rejects malformed or non-local Host headers", async () => {
|
|
44
|
+
const malformed = await enforceLocalHttpRequestPolicy(apiRequest({ host: "localhost@attacker.example" }));
|
|
45
|
+
const nonLocal = await enforceLocalHttpRequestPolicy(apiRequest({ host: "192.168.1.10:4318" }));
|
|
46
|
+
|
|
47
|
+
expect(malformed).toEqual({ allowed: false, status: 403, message: "Host is not allowed." });
|
|
48
|
+
expect(nonLocal).toEqual({ allowed: false, status: 403, message: "Host is not allowed." });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("rejects opaque origins and same-site cross-origin requests", async () => {
|
|
52
|
+
const opaqueOrigin = await enforceLocalHttpRequestPolicy(apiRequest({
|
|
53
|
+
headers: { origin: "null" },
|
|
54
|
+
}));
|
|
55
|
+
const sameSite = await enforceLocalHttpRequestPolicy(apiRequest({
|
|
56
|
+
headers: { "sec-fetch-site": "same-site" },
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
expect(opaqueOrigin).toEqual({ allowed: false, status: 403, message: "Origin is not allowed." });
|
|
60
|
+
expect(sameSite).toEqual({ allowed: false, status: 403, message: "Cross-site requests are not allowed." });
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("requires application/json for API POST requests", async () => {
|
|
64
|
+
const missing = await enforceLocalHttpRequestPolicy(apiRequest({
|
|
65
|
+
method: "POST",
|
|
66
|
+
body: "{}",
|
|
67
|
+
}));
|
|
68
|
+
const form = await enforceLocalHttpRequestPolicy(apiRequest({
|
|
69
|
+
method: "POST",
|
|
70
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
71
|
+
body: "text=example",
|
|
72
|
+
}));
|
|
73
|
+
|
|
74
|
+
expect(missing).toEqual({
|
|
75
|
+
allowed: false,
|
|
76
|
+
status: 415,
|
|
77
|
+
message: "Content-Type must be application/json.",
|
|
78
|
+
});
|
|
79
|
+
expect(form).toEqual({
|
|
80
|
+
allowed: false,
|
|
81
|
+
status: 415,
|
|
82
|
+
message: "Content-Type must be application/json.",
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("rejects declared JSON bodies over the limit before route handling", async () => {
|
|
87
|
+
const result = await enforceLocalHttpRequestPolicy(apiRequest({
|
|
88
|
+
method: "POST",
|
|
89
|
+
headers: {
|
|
90
|
+
"content-type": "application/json",
|
|
91
|
+
"content-length": String(LOCAL_JSON_BODY_LIMIT_BYTES + 1),
|
|
92
|
+
},
|
|
93
|
+
body: "{}",
|
|
94
|
+
}));
|
|
95
|
+
|
|
96
|
+
expect(result).toEqual({
|
|
97
|
+
allowed: false,
|
|
98
|
+
status: 413,
|
|
99
|
+
message: `Request body exceeds ${LOCAL_JSON_BODY_LIMIT_BYTES} bytes.`,
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|