Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@
# VECTOR_WEIGHT=0.6 # Hybrid search weight for vector leg
# AGENTMEMORY_GRAPH_WEIGHT=0.2 # Graph traversal bonus on smart-search ranking
# TOKEN_BUDGET=2000 # Max tokens injected via mem::context per session
# Recall context now uses ~/.agentmemory/config.toml for structured budgets.
# Environment overrides still win over config.toml:
# AGENTMEMORY_RECALL_MAX_CONTEXT_TOKENS=800
# AGENTMEMORY_RECALL_RESERVED_BOOTSTRAP_TOKENS=200
# AGENTMEMORY_RECALL_MAX_SEMANTIC_TOKENS=600
# AGENTMEMORY_RECALL_UNKNOWN_AUTO_INJECTION=false
# AGENTMEMORY_RECALL_UNKNOWN_EXPLICIT_SEARCH=true
# AGENTMEMORY_RECALL_ALLOWED_ROOTS=~/work;~/src # Semicolon-separated trusted roots for cwd-based repo identity on Windows; defaults to the worker cwd

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Find how AGENTMEMORY_RECALL_ALLOWED_ROOTS is parsed in config.ts
rg -n -C5 'AGENTMEMORY_RECALL_ALLOWED_ROOTS|allowedRoots|ALLOWED_ROOTS' --type=ts src/

Repository: rohitg00/agentmemory

Length of output: 3480


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## .env.example around line 107\n'
sed -n '100,112p' .env.example

printf '\n## Search for docs mentioning AGENTMEMORY_RECALL_ALLOWED_ROOTS or delimiter wording\n'
rg -n -C2 'AGENTMEMORY_RECALL_ALLOWED_ROOTS|semicolon|delimiter|path.delimiter|trusted roots' --glob '!**/node_modules/**' .

Repository: rohitg00/agentmemory

Length of output: 4363


Use the platform path separator here. src/recall/identity.ts splits AGENTMEMORY_RECALL_ALLOWED_ROOTS with path.delimiter, so this example should say : on Unix and ; on Windows (or just refer to the platform delimiter) instead of only mentioning Windows.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.env.example at line 107, Update the AGENTMEMORY_RECALL_ALLOWED_ROOTS
example comment to describe the platform-specific path delimiter used by
src/recall/identity.ts: colon on Unix-like systems and semicolon on Windows,
rather than documenting only the Windows separator.

# AGENTMEMORY_RECALL_TRACE_MAX_DROPPED_ITEMS_PER_REASON=20
# MAX_OBS_PER_SESSION=500 # Per-session observation cap before consolidation kicks in
# SUMMARIZE_CHUNK_SIZE=400 # When mem::summarize sees a session larger than this, it chunks observations and map-reduces (chunk-summarize → reduce-merge) to stay within the LLM's context window. Default 400 ≈ 50k tokens per chunk at ~110 tok/obs. Native sessions are capped by MAX_OBS_PER_SESSION; chunking primarily matters for bulk-imported jsonl sessions, which bypass that cap.
# SUMMARIZE_CHUNK_CONCURRENCY=6 # Parallel chunk LLM calls during chunked summarize. Default 6 fits ~100-chunk sessions under iii's 180s function-invocation timeout at typical ~8s/call. High-throughput providers (Novita, DeepInfra, DeepSeek) commonly allow 100+ concurrent — bump this for very large imported sessions.
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ agentmemory-debug/

# Lock files — never commit (see feedback_no_lockfiles memory)
package-lock.json
eval/recall/fixtures/local.json
pnpm-lock.yaml
yarn.lock
integrations/hermes/__pycache__/
Expand Down
36 changes: 30 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,30 @@ case "memory_your_tool": {
}
```

### Recall Pattern

Recall is centralized through `RecallCore` (`src/recall/core.ts`). All search paths (`context`, `enrich`, `prompt-submit`, `pre-compact`, MCP `memory_recall`, `memory_smart_search`) route through it instead of calling `hybridSearch` or `kv.list` directly. This ensures every recall produces a traceable `RecallTrace` with selected/dropped items and reasons.

```typescript
const recallCore = new RecallCore(kv, config.recall, hybridSearch.searchWithTrace);
// context generation
registerContextFunction(sdk, kv, config.tokenBudget, recallCore);
// enrichment (PreToolUse)
registerEnrichFunction(sdk, kv, recallCore);
// MCP tools: memory_recall + memory_smart_search with outputMode=structured/context
// route through mem::context which delegates to recallCore
```

**When adding new search/recal paths, you MUST:**
1. Route through `RecallCore` — never bypass it with direct `hybridSearch` or `kv.list`
2. Wire recall trace persistence via `persistRecallTrace()` in `src/recall/trace-store.ts`
3. Register new debug endpoints in `src/triggers/api.ts` (`api::recall-debug` / `api::recall-debug-by-id`)
4. Add corresponding skill docs if the recall path is user-facing

**When adding new KV scopes for recall traces:**
1. `src/state/schema.ts` — add to the KV object (e.g. `recallTraces: { kv: "memory" }`)
2. `src/types.ts` — add the corresponding interface (`RecallTrace`, `RecallItemTrace`, etc.)

### Hook Scripts
Hook scripts in `src/hooks/` are standalone Node.js scripts (no iii-sdk import). They read JSON from stdin, make HTTP calls to the REST API, and exit. There are two patterns depending on whether Claude Code consumes the script's stdout:

Expand All @@ -114,11 +138,11 @@ Hook scripts in `src/hooks/` are standalone Node.js scripts (no iii-sdk import).
- Test files go in `test/` with `.test.ts` extension
- Follow existing patterns in `test/crystallize.test.ts` for function tests

## Current Stats (v0.9.16)
## Current Stats (v0.9.27)

- 53 MCP tools (8 visible by default, `AGENTMEMORY_TOOLS=all` for all)
- 128 REST endpoints
- 53 MCP tools (core: memory_recall, memory_save, memory_compress_file, memory_file_history, memory_patterns, memory_sessions, memory_smart_search, memory_timeline, memory_profile, memory_export, memory_relations; `AGENTMEMORY_TOOLS=all` for 53)
- 137 REST endpoints
- 6 MCP resources, 3 MCP prompts
- 12 hooks, 15 skills
- 50+ iii functions
- 950+ tests
- 12 hooks, 17 skills (10 invocable + 7 reference)
- 296 registered functions (148 mem::, 137 api::, 6 mcp::, 5 event::)
- 184 source files · ~42,400 LOC · 1,500+ tests · 58 KV scopes
63 changes: 63 additions & 0 deletions CODERABBIT_REVIEW_TRIAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# CodeRabbit Review Triage — PR #1050

日期:2026-07-13
当前复核基线:`52f7200` (`p2-recall-observability-final`)
CodeRabbit 原 review 范围:`93ae9bc` → `2245597`

本报告按当前 HEAD 复核旧评论;旧评论没有被直接当作当前代码事实。此次工作不 push、不写远端 issue、不修改 Scheduled Task,也不移动 tag。

## 当前仍有效且本次修复

| 评论 | 当前分类 | 当前证据与处理 |
|---|---|---|
| `mem::context` 丢弃 `limit` | `still-valid` → fixed | `src/functions/context.ts` 未转发调用方 limit,且 Recall Core 用 `limit || 20`;新增 context/Core 回归测试,转发并保留 `limit=0`。 |
| `resolveRecallIdentity` 接受任意 cwd 并同步执行 git | `still-valid` → fixed | 当前路径使用同步 git 且未做可信根约束;改为异步、500ms 超时、显式允许根、realpath/目录/UNC/越界/symlink escape 校验,并对失败降级 unknown。 |
| Git remote 归一化不一致 | `still-valid` → fixed | HTTPS、SSH URL、SCP 旧实现产生不同 fingerprint;统一 hostname、用户信息、默认端口、URL decoding、`.git` 和尾斜杠处理,并覆盖不同 host/owner/repo 不碰撞。 |
| Recall stats 非原子 get/set | `still-valid` → fixed | 选中数、分数总和和 scope mismatch 改用 `state::update` 原子 increment;平均分由缩放整数累加器物化;memory 内容/version/updatedAt 不参与写入。 |
| Viewer dropped count 未完整转义 | `still-valid` → fixed | dropped reason/label/value 的同一路径统一经 `esc(String(...))` 后进入 `innerHTML`,并加入 payload XSS 回归测试。 |

## 其他评论的当前分类

| 评论 | 当前分类 | 说明 |
|---|---|---|
| README 测试数 `1,423` vs `1,500+` | `defer-with-issue` | 当前 README 仍有旧 badge/开发段落数字;不影响运行时,建议文档清理阶段统一从实际测试清单生成。 |
| README endpoint 数 `136` vs 生成 reference `125` | `defer-with-issue` | 评论中的两个数字已过时;当前 README 为 137,生成 reference 为 126,说明仍有计数漂移,但不阻塞本次 P2 代码合并。 |
| `recall_budget.maxSessionSummaries` 错误标签 | `defer-with-issue` | 当前仍可见,影响配置错误诊断一致性,不改变 recall 结果;建议配置/schema 一致性阶段修复。 |
| archive import session ID 一致性 | `defer-with-issue` | 当前 archive import 仍未把解析到的 session ID 贯穿导入路径;建议 archive/replay 一致性阶段修复。 |
| observe rollback image reference decrement | `defer-with-issue` | 当前 rollback 仍有直接删除 image 的路径;可能造成引用计数不一致,但与本次五项 P2 合并阻塞无直接依赖。 |
| pre-compact epoch 错误隔离 | `defer-with-issue` | 当前 epoch 与 context 仍在同一失败边界;建议 hook 可用性/降级阶段修复。 |
| MCP `outputMode` schema | `defer-with-issue` | 当前 registry schema 仍为宽泛 string,server 运行时有校验;建议 MCP schema 收紧阶段修复。 |
| 共享类型整理 | `defer-with-issue` | 当前 `InjectionLedgerEntry` 等类型仍存在模块内定义;属于可维护性整理,不阻塞行为验收。 |
| 重复 checkoutId spread | `defer-with-issue` | 当前 API payload 构造仍有重复 spread;结果通常相同但增加维护风险,建议 API 清理阶段修复。 |
| stale comment / unknown wildcard 说明 | `defer-with-issue` | `remember` 附近注释与当前 scope gate 语义不完全一致;建议 scope 文档/注释阶段修复。 |
| fake timer cleanup | `defer-with-issue` | 当前测试仍手动恢复 timer;建议测试卫生阶段统一 afterEach。 |
| 重复 enum | `defer-with-issue` | 当前 eval schema 与生产类型仍有重复候选枚举;建议 shared-type 阶段整理。 |
| CJK token range | `defer-with-issue` | 当前 token 快路径仍使用有限 Unicode range;建议 tokenizer 正确性阶段扩展并补基准。 |
| trace retention 全量扫描 | `defer-with-issue` | 当前 retention 仍扫描完整 trace 列表;建议存储/索引优化阶段处理。 |
| hydration 串行 KV 读取 | `defer-with-issue` | 当前 hydration 仍按顺序读取;建议启动性能阶段并行化及限流。 |

本次没有发现可安全标为 `already-fixed-after-2245597` 或 `not-applicable` 的上述重点评论;数字评论的具体旧数字虽然已经过时,但其文档漂移问题仍存在,因此按 `defer-with-issue` 记录。

## 非当前合并阻塞问题清单

| 问题 | 影响 | 建议阶段 | 建议 issue 标题 | 是否阻塞当前合并 |
|---|---|---|---|---|
| README 测试数/endpoint 数漂移 | 用户看到的项目规模与生成事实不一致 | docs hygiene | `docs: reconcile README test and endpoint counts` | 否 |
| 配置错误标签 camelCase | 错误路径与 TOML 配置名不一致,降低排障效率 | config consistency | `fix: align recall budget error labels with config keys` | 否 |
| archive import session ID 一致性 | 导入记录可能失去原始 session 关联 | archive/replay | `fix: preserve archive import session identity` | 否 |
| observe rollback image ref decrement | 多引用图片的回滚计数可能不准 | media lifecycle | `fix: decrement image refs during observe rollback` | 否 |
| pre-compact epoch 错误隔离 | epoch 失败可能连带跳过 context | hook resilience | `fix: isolate pre-compact epoch failures` | 否 |
| MCP outputMode schema | 客户端无法从 schema 获得枚举约束 | MCP contract | `fix: constrain memory recall outputMode schema` | 否 |
| duplicate checkoutId spread | API payload 维护风险 | API cleanup | `refactor: remove duplicate checkout identity spread` | 否 |
| stale scope wildcard comment | 注释误导 scope 行为理解 | scope docs | `docs: correct legacy scope wildcard comment` | 否 |
| fake timer cleanup | 测试隔离依赖手动清理 | test hygiene | `test: centralize fake timer cleanup` | 否 |
| duplicate enum/shared types | 类型漂移风险 | type consolidation | `refactor: consolidate recall shared types` | 否 |
| CJK token range | 少数 Unicode CJK 字符估算可能偏差 | tokenizer correctness | `fix: expand CJK token detection coverage` | 否 |
| trace retention full scan | 大规模 trace store 的 sweep 成本 | storage performance | `perf: bound trace retention candidate scan` | 否 |
| serial hydration | 启动/恢复延迟随记录数线性叠加 | startup performance | `perf: parallelize bounded hydration reads` | 否 |

## 本次修复验证范围

新增/更新回归测试覆盖 limit 传播与 `limit=0`、search 与 context budget 分离、prompt hard budget、remote normalization、cwd 安全与异步 git、100 次并发 stats、memory 不变、Viewer XSS payload。benchmark runner 的 in-memory KV stub 也补齐了与生产 `state::update` 对齐的原子操作语义。

不创建远端 issue。tag 建议以最终远端查询结果为准:远端未发现 `p2-recall-observability-final*` 时,建议用户确认后重建本地未 push tag;若旧 tag 已 push,保留旧 tag 并新建 `p2-recall-observability-final.1`。
20 changes: 19 additions & 1 deletion INSTALL_FOR_AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,25 @@ If you cannot tell which agent you are, default to `claude-code`. After wiring,

Expect: the agent now lists agentmemory's tools. With the server running you should see the full set of 53 tools (for example `memory_save`, `memory_smart_search`, `memory_sessions`). If you see only 7 tools, the MCP shim could not reach a server, see Troubleshooting.

## 6. Install native skills
## 6. Enable Codex archive ingestion on native Windows

Codex writes completed sessions to `~/.codex/archived_sessions` but does not expose an Archive hook. After installing the stable `agentmemory` CLI, choose one explicit history policy:

```powershell
agentmemory archive-watcher install --dry-run
agentmemory archive-watcher install --yes # process existing + future archives
agentmemory archive-watcher install --new-only # future archives only
```

The installer is idempotent and registers a user-scoped Scheduled Task that invokes `agentmemory archive-watcher run --mode background`. It does not delete state, the archive ledger, the canonical store, or memory data. Remove only the task with:

```powershell
agentmemory archive-watcher uninstall
```

The watcher performs one health check per scan, waits for two stable observations before posting a file, and uses bounded retry backoff while the server is unavailable.

## 7. Install native skills

```bash
npx skills add rohitg00/agentmemory -y
Expand Down
71 changes: 71 additions & 0 deletions P2_FINAL_ACCEPTANCE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# P2 Recall Observability — Final Acceptance

日期:2026-07-13
原验收 commit:`52f7200`
原验收 tag:`p2-recall-observability-final`(本地指向 `52f7200`)
CodeRabbit review 复核范围:PR #1050 的旧范围 `93ae9bc` → `2245597`;本次以当前 HEAD 为准。

## 本次结论

CodeRabbit 五项重点评论在当前 HEAD 仍存在,均已先补回归测试再修复:

1. `mem::context` 现在保留并转发 `limit`,`limit=0` 不会被默认值覆盖;ranked results 的 limit 不再被 context token budget 错误截断。
2. recall identity 改为异步 git 探测,cwd 受 `AGENTMEMORY_RECALL_ALLOWED_ROOTS`/默认工作根约束,并拒绝越界、不存在、文件、UNC、symlink escape;git 探测有 500ms 超时,失败安全降级 unknown。
3. HTTPS、SSH URL、SCP remote 统一 hostname/用户/default port/URL encoding/`.git`/尾斜杠后计算稳定 repoId;不同 host/owner/repo 不碰撞。
4. recall stats 使用底层 `state::update` 的原子 increment 保存 count、scaled score total、scope mismatch;平均分在读取时物化,不写 Memory 内容、version 或 updatedAt。
5. Viewer dropped reason/label/value 同一路径全部转义后才进入 `innerHTML`。

逐条分类和非阻塞事项见 [CODERABBIT_REVIEW_TRIAGE.md](CODERABBIT_REVIEW_TRIAGE.md)。其他评论(archive import session ID、observe rollback image ref、trace retention、hydration、pre-compact、MCP schema、README 数字、配置标签、checkoutId、stale comment、重复 enum、fake timer、CJK token、共享类型)未混入本次修复,均列为 `defer-with-issue`。

## 修改清单

- `src/functions/context.ts`、`src/recall/core.ts`、`src/triggers/api.ts`:贯通并校验 limit,保留零值。
- `src/recall/identity.ts`:异步、受信根、realpath、symlink/UNC/越界检查、超时和 remote canonicalization。
- `src/state/kv.ts`、`src/recall/trace-store.ts`、`src/types.ts`:原子 stats 更新和 scaled aggregate。
- `src/viewer/index.html`:完整转义 dropped 动态值。
- `eval/recall/runner.ts`:benchmark KV stub 补齐 `state::update` 原子操作语义。
- `.env.example` 与生成的 config reference:记录允许 identity roots 配置。
- 新增/更新五组 focused regression tests;新增本报告与 CodeRabbit triage 报告。

## 实际测试与 benchmark

已通过:

```text
npx vitest run test/recall-core.test.ts test/recall-context-limit.test.ts test/recall-identity.test.ts test/recall-trace-store.test.ts test/viewer-recall-xss.test.ts --reporter=verbose
5 files / 17 tests passed

npx vitest run test/cross-project-isolation.test.ts test/agent-isolation-search.test.ts test/enrich-project-isolation.test.ts test/recall-core.test.ts test/recall-config.test.ts test/circuit-breaker.test.ts test/vector-retrieval-health.test.ts test/recall-context-limit.test.ts test/recall-identity.test.ts test/recall-trace-store.test.ts test/viewer-recall-xss.test.ts --reporter=verbose
11 files / 50 tests passed

npx vitest run test/hybrid-search.test.ts test/vector-retrieval-health.test.ts test/recall-core.test.ts --reporter=verbose
3 files / 17 tests passed

npm run skills:check
17 skills checked; passed

npm run build
exit code 0; passed
```

Benchmark command:`npm run bench:recall -- --json`。结果:hit rate `1.0000`、precision `0.8421`、cross-project contamination `0`、budget violation `0`、duplicate injection `0`、stale/superseded injection `0`、average injected tokens `57.07`。首次运行发现并修复 benchmark stub 缺少 `update` 的验收阻断,修复后结果恢复并达到 gate。

Scope smoke 的可执行覆盖来自 benchmark fixture 和 focused suites:project 正向命中、cross-project contamination `0`、user scope 跨项目、unknown 不自动注入、explicit recall 可返回 unknown。Vector degraded/BM25 fallback 由 `hybrid-search` 与 `vector-retrieval-health` 定向 smoke 通过。

## Runtime / build-info

原有 runtime 在 3111 上保持运行,未停止任何身份不明进程;原实例已验证 `/agentmemory/livez` 200、`/agentmemory/health` 200、`GET /agentmemory/build-info` 200。该实例的旧 build-info 是 `52f7200`,因此不把它冒充为本次修复后的 runtime 验证。

最终 runtime 重启使用本地构建的 acceptance HEAD,接入既有 iii bridge(49134);未停止 Scheduled Task。`/agentmemory/livez`、`/agentmemory/health`、`GET /agentmemory/build-info` 均 HTTP 200,viewer live smoke HTTP 200(端口因 3113 被占用而安全 fallback 到 3116)。build-info 实测 `sourceCommit` 与验收时 HEAD 一致、`sourceDirty=false`、`builtAt` 为 ISO 时间、`artifactHash=f19c526f7bb86c290bad8a95769d8515f1bda393ae6e8544bde4bbc4e4eb45b3`;按 `scripts/build-runtime-assets.mjs` 的 Windows 路径规则重算一致。REST recall context/debug/debug-by-id 均 HTTP 200,最新 trace=`rtr_mrix53u6_f2b4a2bde895`,并验证 `limit=0`。实例只用于验收;停止/重启的进程均为已识别 AgentMemory/iii runtime 进程,不修改 Scheduled Task。

## 全量测试分类

本次 `npm test -- --reporter=dot` 实际为 `1,422 passed / 40 failed`(新增 11 个回归测试,故通过数较原 `1,411` 基线增加 11;失败数保持 40)。40 项逐项豁免保持原分类:connector-environment 15(connect-new-agents 11、copilot-plugin 1、cli-remove 3);windows-path 14(obsidian-export 8、hook-project 6);symlink-capability 5(compress-file 5);env-isolation 5(embedding-provider 3、slots-flag-gate 2);known-preexisting 1(integration-plaintext-http 1)。

最终验收必须确认:`P2-related failures = 0`、`new regressions = 0`,任何超出上述 40 项的失败都必须单独调查,不能归入 baseline。另执行 `git diff --check`,结果必须无 whitespace error。

## 提交与 tag 建议

最终验证代码 commit:`e0c6ce9`(完整 hash `e0c6ce9817a8e6b41e83d469435942385cb91cb4`)。本 acceptance record 的后续 docs-only commit 如产生,需在最终输出中另行记录;工作树最终必须 clean。

本次不创建、删除、移动或 push tag。远端查询未返回 `p2-recall-observability-final*`,所以若最终确认本地 tag 尚未 push,建议用户确认后将本地 tag 从原 `52f7200` 重建到新的最终验收 commit;若发现旧 tag 已 push,则保留旧 tag,建议新建 `p2-recall-observability-final.1`。本次只给建议,不执行 tag 操作。
Loading