memorylake-openclaw 0.0.3 → 0.0.5-beta.1

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.

Potentially problematic release.


This version of memorylake-openclaw might be problematic. Click here for more details.

@@ -0,0 +1,22 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "WebFetch(domain:10.71.10.71)",
5
+ "Bash(find /Users/henry/work/github/memorylake-openclaw -maxdepth 2 \\\\\\( -name \".env*\" -o -name \"*.config.*\" -o -name \"openclaw.json\" \\\\\\) 2>/dev/null | grep -v node_modules)",
6
+ "Bash(jq '.env' /Users/henry/.openclaw/openclaw.json)",
7
+ "Bash(wc -l /Users/henry/.openclaw/agents/main/sessions/*.jsonl)",
8
+ "Bash(curl -s http://10.71.10.71:8001/v3/api-docs/open-api 2>&1 | head -5000)",
9
+ "Bash(cat /Users/henry/.claude/projects/-Users-henry-work-github-memorylake-openclaw/667ef3f7-2edf-4030-b7cf-239a4d916489/tool-results/bf9jm64sc.txt | python3 -c \"\nimport json, sys\ndata = json.load\\(sys.stdin\\)\n# Extract the memories endpoint\npaths = data.get\\('paths', {}\\)\nfor path, methods in paths.items\\(\\):\n if 'memories' in path:\n print\\(f'\\\\\\\\n=== {path} ==='\\)\n for method, spec in methods.items\\(\\):\n print\\(f'\\\\\\\\n--- {method.upper\\(\\)} ---'\\)\n print\\(json.dumps\\(spec, indent=2\\)\\)\n\n# Also print relevant schemas\nschemas = data.get\\('components', {}\\).get\\('schemas', {}\\)\nfor name, schema in schemas.items\\(\\):\n if 'memory' in name.lower\\(\\) or 'Memory' in name or 'Message' in name:\n print\\(f'\\\\\\\\n=== Schema: {name} ==='\\)\n print\\(json.dumps\\(schema, indent=2\\)\\)\n\")",
10
+ "Bash(cat /Users/henry/.openclaw/openclaw.json | python3 -c \"\nimport json, sys\ndata = json.load\\(sys.stdin\\)\n# Look for plugin-related config\nfor key in data:\n if 'plugin' in key.lower\\(\\) or 'memory' in key.lower\\(\\) or 'memorylake' in key.lower\\(\\) or 'extension' in key.lower\\(\\):\n print\\(f'=== {key} ==='\\)\n print\\(json.dumps\\(data[key], indent=2\\)[:3000]\\)\n# Also print top-level keys\nprint\\('\\\\\\\\n=== Top-level keys ==='\\)\nprint\\(list\\(data.keys\\(\\)\\)\\)\n\")",
11
+ "Bash(cat /Users/henry/.openclaw/agents/main/sessions/sessions.json | python3 -c \"\nimport json, sys\ndata = json.load\\(sys.stdin\\)\nfor key, val in data.items\\(\\):\n print\\(f'Key: {key}'\\)\n print\\(f' sessionId: {val.get\\(\\\\\"sessionId\\\\\"\\)}'\\)\n print\\(f' chatType: {val.get\\(\\\\\"chatType\\\\\"\\)}'\\)\n print\\(f' channel: {val.get\\(\\\\\"channel\\\\\"\\)}'\\)\n print\\(f' displayName: {val.get\\(\\\\\"displayName\\\\\"\\)}'\\)\n print\\(f' subject: {val.get\\(\\\\\"subject\\\\\"\\)}'\\)\n print\\(f' sessionFile: {val.get\\(\\\\\"sessionFile\\\\\"\\)}'\\)\n print\\(\\)\n\")",
12
+ "Bash(head -20 /Users/henry/.openclaw/agents/main/sessions/8cc2bff3-a3af-4725-b071-43caffb36771.jsonl | python3 -c \"\nimport json, sys\nfor line in sys.stdin:\n line = line.strip\\(\\)\n if not line:\n continue\n obj = json.loads\\(line\\)\n t = obj.get\\('type'\\)\n if t == 'message':\n msg = obj.get\\('message', {}\\)\n role = msg.get\\('role'\\)\n content = msg.get\\('content', []\\)\n # Truncate content for display\n content_str = str\\(content\\)[:200]\n print\\(f'Type: {t}, Role: {role}, Content: {content_str}...'\\)\n else:\n print\\(f'Type: {t}, Keys: {list\\(obj.keys\\(\\)\\)}'\\)\n\")",
13
+ "Bash(ls ~/.openclaw/agents/main/sessions/*.jsonl 2>/dev/null | head -3)",
14
+ "Bash(cat ~/.openclaw/agents/main/sessions/sessions.json 2>/dev/null | python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); print\\(json.dumps\\(dict\\(list\\(d.items\\(\\)\\)[:2]\\), indent=2\\)\\)\" 2>/dev/null || echo \"No sessions.json or parse error\")",
15
+ "Bash(head -5 ~/.openclaw/agents/main/sessions/372112f5-ea26-4440-995f-aa756c707858.jsonl 2>/dev/null | python3 -c \"\nimport json, sys\nfor line in sys.stdin:\n line = line.strip\\(\\)\n if not line: continue\n d = json.loads\\(line\\)\n print\\(json.dumps\\({k: d[k] for k in list\\(d.keys\\(\\)\\)[:3]}, indent=2, ensure_ascii=False\\)\\)\n if d.get\\('type'\\) == 'message':\n msg = d.get\\('message', {}\\)\n role = msg.get\\('role'\\)\n content = msg.get\\('content'\\)\n if isinstance\\(content, list\\):\n types = [c.get\\('type'\\) for c in content]\n print\\(f' role={role}, content_types={types}'\\)\n else:\n print\\(f' role={role}, content type={type\\(content\\).__name__}'\\)\n\")",
16
+ "Bash(python3 -c \"\nimport json\nwith open\\('/Users/henry/.openclaw/agents/main/sessions/372112f5-ea26-4440-995f-aa756c707858.jsonl'\\) as f:\n for line in f:\n line = line.strip\\(\\)\n if not line: continue\n d = json.loads\\(line\\)\n if d.get\\('type'\\) != 'message': continue\n msg = d.get\\('message', {}\\)\n role = msg.get\\('role'\\)\n content = msg.get\\('content'\\)\n if isinstance\\(content, list\\):\n types = [c.get\\('type'\\) for c in content]\n print\\(f'role={role}, content_types={types}'\\)\n elif isinstance\\(content, str\\):\n print\\(f'role={role}, content=str[{len\\(content\\)}]'\\)\n else:\n print\\(f'role={role}, content={type\\(content\\).__name__}'\\)\n\" | head -20)",
17
+ "Bash(python3 << 'PYEOF'\nimport json\nwith open\\(\"/Users/henry/.openclaw/agents/main/sessions/372112f5-ea26-4440-995f-aa756c707858.jsonl\"\\) as f:\n for line in f:\n line = line.strip\\(\\)\n if not line:\n continue\n d = json.loads\\(line\\)\n if d.get\\(\"type\"\\) != \"message\":\n continue\n msg = d.get\\(\"message\", {}\\)\n role = msg.get\\(\"role\"\\)\n content = msg.get\\(\"content\"\\)\n if isinstance\\(content, list\\):\n types = [c.get\\(\"type\"\\) for c in content]\n print\\(f\"role={role}, content_types={types}\"\\)\n elif isinstance\\(content, str\\):\n print\\(f\"role={role}, content=str[{len\\(content\\)}]\"\\)\n else:\n print\\(f\"role={role}, content={type\\(content\\).__name__}\"\\)\nPYEOF)",
18
+ "Bash(python3 << 'PYEOF'\nimport json\nwith open\\(\"/Users/henry/.openclaw/openclaw.json\"\\) as f:\n config = json.load\\(f\\)\n# Show agents structure\nagents = config.get\\(\"agents\", {}\\)\nprint\\(json.dumps\\({\n \"defaults\": agents.get\\(\"defaults\", {}\\),\n \"list_keys\": [list\\(a.keys\\(\\)\\) for a in agents.get\\(\"list\", []\\)][:3],\n \"list_sample\": agents.get\\(\"list\", []\\)[:2]\n}, indent=2, default=str\\)\\)\nPYEOF)",
19
+ "Bash(chmod +x /Users/henry/work/github/memorylake-openclaw/skills/migrate-memories-to-memorylake/migrate.mjs)"
20
+ ]
21
+ }
22
+ }
@@ -0,0 +1,79 @@
1
+ ## PR #2 Review:Add advanced web search tool with plugin-level constraints
2
+
3
+ > 之前那条简短英文评论格式不太好,这条为主,请以本评论为准。
4
+
5
+ ### 总体评价
6
+ - **整体设计合理**:`advanced_web_search` 作为可选工具(`optional: true`),需要在 OpenClaw 侧显式允许,和现有工具体系一致。
7
+ - **配置与文档同步到位**:新增的 `webSearch*` 配置在 README、OpenClaw 文档以及 `openclaw.plugin.json` 里都有说明,label/placeholder/help 也比较清晰。
8
+ - **错误处理风格统一**:工具实现中的 try/catch、返回 `content` + `details` 的方式,与现有 `document_search` 等工具保持一致。
9
+
10
+ ### 需要在合并前确认/修复的点(Blocking)
11
+ 1. **Web Search API 路径**
12
+
13
+ ```ts
14
+ this.webSearchPath = "api/v1/search"; //TODO: update to the new web search API `openapi/memorylake/api/v1/search`
15
+ ```
16
+
17
+ - 目前这里用的是 `api/v1/search`,但其它路径(memories/doc search)都是走 `openapi/memorylake/...`。
18
+ - TODO 里也写了目标路径可能是 `openapi/memorylake/api/v1/search`。
19
+ - **建议**:跟后端或 API 文档确认最终路径,二选一:
20
+ - 若最终是 `openapi/memorylake/api/v1/search`,这里改成该路径并删除 TODO;
21
+ - 若确实是 `api/v1/search`,则保留该值、删掉 TODO,并补一行注释说明这是 web search 的独立 endpoint。
22
+
23
+ 2. **统一搜索 API 的响应结构**
24
+
25
+ - 目前 `searchWeb` 是:
26
+
27
+ ```ts
28
+ const resp = await this.http
29
+ .post(this.webSearchPath, { json: body })
30
+ .json<WebSearchResponse>();
31
+ return normalizeWebSearchResponse(resp);
32
+ ```
33
+
34
+ - 但其它接口(memories/doc search)是走统一 `ApiResponse` 包装:先检查 `success`,再从 `data` 里取结果。
35
+ - 如果 unified web search API 实际返回的是 `{ success, data: { results, total_results } }` 这一套,那么这里会少了解包,`normalizeWebSearchResponse` 的入参就不对齐。
36
+ - **建议**:确认该接口真实响应:
37
+ - 若也是 `ApiResponse` 风格,就改成先解析 `ApiResponse`(含 `success` 判断),再对 `data` 做 `normalizeWebSearchResponse`,与其它接口保持一致;
38
+ - 若这个接口是裸的 `WebSearchResponse`(没有 `success/data` 包装),当前写法就 OK,可以在注释里说明这是一个特例。
39
+
40
+ ### 非阻塞的改进建议(Nice to have)
41
+ 1. **空数组语义**
42
+
43
+ - 现在发送请求前的判断是:
44
+
45
+ ```ts
46
+ if (options.include_domains?.length) body.include_domains = options.include_domains;
47
+ if (options.exclude_domains?.length) body.exclude_domains = options.exclude_domains;
48
+ ```
49
+
50
+ - 这意味着:当配置为 `[]` 时字段不会发送,仅当长度 > 0 才会发。
51
+ - 如果产品上不需要区分:“未配置” vs “显式设为空数组”,当前实现是合理的;
52
+ - 如果未来希望支持“显式禁用所有域名”之类的语义,可能需要改成 `options.include_domains !== undefined` 决定是否传字段。
53
+
54
+ 2. **normalizeWebSearchResponse 的稳健性**
55
+
56
+ - 当前只对顶层 `results`/`total_results` 做了类型兜底:
57
+
58
+ ```ts
59
+ return {
60
+ results: Array.isArray(raw?.results) ? raw.results : [],
61
+ total_results: typeof raw?.total_results === "number" ? raw.total_results : 0,
62
+ };
63
+ ```
64
+
65
+ - 如果后端在单条 result 的字段上(`url`/`title` 等)有可能返回 `null` 或非字符串,将来可以考虑在这里顺便做一层浅 normalize,减少下游使用时的防御性代码。不是必须,看 API 稳定性。
66
+
67
+ 3. **配置解析的测试**
68
+
69
+ - 新增的 `parseOptionalStringArray` / `parseOptionalString` 实现本身比较简单,但关系到配置体验。
70
+ - 如果项目中已有 config 相关的测试套件,可以考虑加一小组用例(合法/非法类型,`null`、`[]` 等),防止以后改动时出现回归。
71
+
72
+ ### 结论
73
+
74
+ - **总体 LGTM**:设计、类型、文档和插件配置都比较完整。
75
+ - 真正阻塞合并的主要是:
76
+ - 确认并固定 `webSearchPath` 路径;
77
+ - 确认统一搜索 API 的响应是否包在 `ApiResponse` 里,并根据结果决定是否需要像其它接口那样做一层解包。
78
+ - 这两个点确认/修完之后,就可以放心合并了。
79
+
@@ -0,0 +1,83 @@
1
+ ---
2
+ name: gh-pr-description-gen
3
+ description: Use when creating a GitHub PR with gh CLI and needing to generate title and description from git diff and optional issue context
4
+ ---
5
+
6
+ # gh PR Create with Generated Description
7
+
8
+ ## Overview
9
+
10
+ Create a GitHub pull request using `gh pr create`, with title and body generated by the agent from the git diff. No external model calls—the agent generates the content directly.
11
+
12
+ ## When to Use
13
+
14
+ - User wants to create a PR with `gh` and needs title/description written
15
+ - User has uncommitted or committed changes and wants a PR created
16
+ - User may reference related issues (e.g. "fixes #123") to include in context
17
+
18
+ ## Core Workflow
19
+
20
+ 1. **Gather context**
21
+ - Current branch: `git branch --show-current`
22
+ - Base branch: `git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's#.*/##'` or fallback to `main`/`master`
23
+ - Git diff: `git diff origin/{base}...HEAD` (or `git diff origin/{base}` if no merge base)
24
+ - Truncate diff to ~15000 chars if large
25
+ - Optional: if user provides issue numbers, run `gh issue view {number}` for each to get title and description
26
+
27
+ 2. **Generate title and body**
28
+ - Use the diff (and optionally issue context) to write a clear title and description
29
+ - Title: concise, descriptive, no "to #X:" prefix
30
+ - Body format:
31
+
32
+ ```
33
+ ### Motivation
34
+
35
+ (Describe the motivation of this PR)
36
+
37
+ ### Modifications
38
+
39
+ * (Modification 1)
40
+ * (Modification 2)
41
+ * ...
42
+ ```
43
+
44
+ - Use fluent, simple-yet-elegant English
45
+ - Keep meanings clear, sentences short, lines under ~150 characters
46
+ - If related to issues, add "Fixes #123" or "Closes #123" in body to auto-link
47
+
48
+ 3. **Create PR**
49
+ - `gh pr create --title "..." --body "..."` (or `--body-file -` with stdin)
50
+ - Add `--base` if base branch differs from default
51
+ - Add `--draft` if user wants a draft PR
52
+
53
+ ## Quick Reference
54
+
55
+ | Step | Command |
56
+ |------|---------|
57
+ | Current branch | `git branch --show-current` |
58
+ | Default base | `git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null \| sed 's#.*/##'` or `main` |
59
+ | Diff | `git diff origin/{base}...HEAD` |
60
+ | Issue view | `gh issue view {number} --json title,body` |
61
+ | Create PR | `gh pr create -t "Title" -b "Body"` |
62
+
63
+ ## Body Template
64
+
65
+ Use this structure when generating the description:
66
+
67
+ ```markdown
68
+ ### Motivation
69
+
70
+ (Describe what problem this PR solves or why it matters)
71
+
72
+ ### Modifications
73
+
74
+ * (First change)
75
+ * (Second change)
76
+ * ...
77
+ ```
78
+
79
+ ## Common Mistakes
80
+
81
+ - **Forgetting to push**: Ensure branch is pushed before `gh pr create`; `gh` will prompt if not
82
+ - **Long body**: Use `--body-file -` with heredoc when body is large or contains special chars
83
+ - **Wrong base**: Use `--base branch` when base differs from default
@@ -0,0 +1,97 @@
1
+ ---
2
+ name: git-create-branch
3
+ description: 标准化流程:先从远端获取最新 main,再创建 feature/bugfix 分支用于功能开发或 bug 修复。当你准备开始一项新开发任务并需要新分支时使用。
4
+ ---
5
+
6
+ # Git 新建分支流程(基于 main)
7
+
8
+ ## 前置约定
9
+
10
+ - **默认远端名**:`origin`(如果项目不是用 `origin`,请将下面命令中的 `origin` 换成实际远端名)
11
+ - **主干分支名**:`main`(如果项目主干是 `master` 或其他名字,同理替换)
12
+ - **前提条件**:在运行本流程前,工作区应当是干净的(没有未提交更改,或明确知道自己在做什么)
13
+
14
+ ## 一、检查当前工作区状态
15
+
16
+ 1. 查看当前分支与工作区:
17
+
18
+ ```bash
19
+ git status
20
+ ```
21
+
22
+ 2. 如果有未提交的更改:
23
+ - 需要的话先提交:`git commit -am "your message"`
24
+ - 或者暂存:`git stash push -m "temp before new branch"`
25
+ - 或者放弃本地修改:`git restore .`(谨慎使用,会丢弃修改)
26
+
27
+ 目标:在继续之前,`git status` 应尽量是干净状态。
28
+
29
+ ## 二、从远端获取最新 main
30
+
31
+ 1. 抓取远端最新记录(包括 main):
32
+
33
+ ```bash
34
+ git fetch origin main
35
+ ```
36
+
37
+ 2. 切换到本地 `main` 分支(如果当前还不在):
38
+
39
+ ```bash
40
+ git checkout main
41
+ ```
42
+
43
+ 3. 将本地 `main` 更新到与远端一致,避免产生多余 merge 提交:
44
+
45
+ ```bash
46
+ git pull --ff-only origin main
47
+ ```
48
+
49
+ 如果 `--ff-only` 报错,说明本地 `main` 有额外提交,需要先确认是否应该保留;通常建议保持本地 `main` 与远端完全一致,没有额外提交。
50
+
51
+ ## 三、从最新 main 创建开发分支
52
+
53
+ 1. 根据需求选择分支前缀:
54
+ - 功能开发:`feature/xxx-简短描述`
55
+ - Bug 修复:`bugfix/xxx-简短描述`
56
+
57
+ 示例:
58
+ - `feature/1234-add-knowledge-search`
59
+ - `bugfix/5678-fix-memory-sync`
60
+
61
+ 2. 从最新 `main` 创建并切换到新分支(将 `<new-branch-name>` 替换为你的实际分支名):
62
+
63
+ ```bash
64
+ git checkout -b <new-branch-name> main
65
+ ```
66
+
67
+ 3. 确认当前分支确实是新建分支:
68
+
69
+ ```bash
70
+ git branch --show-current
71
+ git status
72
+ ```
73
+
74
+ ## 四、(可选)立即将新分支推送到远端
75
+
76
+ 如果你希望尽早在远端创建对应分支(方便备份或协作):
77
+
78
+ ```bash
79
+ git push -u origin <new-branch-name>
80
+ ```
81
+
82
+ - `-u` 会设置默认上游分支,之后只需要 `git push` / `git pull` 即可。
83
+
84
+ ## 五、后续使用建议
85
+
86
+ - **开始开发**:在新分支上进行所有与本任务相关的修改与提交。
87
+ - **保持同步 main**:在开发周期较长时,周期性地从 `main` 合并或 rebase,避免与主干差异过大,例如:
88
+
89
+ ```bash
90
+ git checkout main
91
+ git pull --ff-only origin main
92
+ git checkout <new-branch-name>
93
+ git rebase main # 或 git merge main,根据团队习惯
94
+ ```
95
+
96
+ - **完成开发后**:通过 PR / Merge Request 将该分支合入主干,然后根据团队流程删除本地与远端分支。
97
+
package/README.md CHANGED
@@ -10,7 +10,7 @@ Your agent forgets everything between sessions. This plugin fixes that. It watch
10
10
  <img src="../docs/images/openclaw-architecture.png" alt="Architecture" width="800" />
11
11
  </p> -->
12
12
 
13
- **Auto-Recall** — Before the agent responds, the plugin searches MemoryLake for memories that match the current message and injects them into context.
13
+ **Auto-Recall** — Before the agent responds, the plugin searches MemoryLake for memories and relevant document excerpts that match the current message and injects them into context.
14
14
 
15
15
  **Auto-Capture** — After the agent responds, the plugin sends the exchange to MemoryLake. MemoryLake decides what's worth keeping — new facts get stored, stale ones updated, duplicates merged.
16
16
 
@@ -29,16 +29,15 @@ Get an API key from [app.memorylake.ai](https://app.memorylake.ai), then add to
29
29
  "memorylake-openclaw": {
30
30
  "enabled": true,
31
31
  "config": {
32
- "apiKey": "${MEMORYLAKE_API_KEY}",
33
- "projectId": "proj-...",
34
- "userId": "your-user-id"
32
+ "apiKey": "sk-...",
33
+ "projectId": "proj-..."
35
34
  }
36
35
  }
37
36
  ```
38
37
 
39
38
  ## Agent tools
40
39
 
41
- The agent gets five tools it can call during conversations:
40
+ The agent gets six tools it can call during conversations:
42
41
 
43
42
  | Tool | Description |
44
43
  |------|-------------|
@@ -47,6 +46,7 @@ The agent gets five tools it can call during conversations:
47
46
  | `memory_store` | Explicitly save a fact |
48
47
  | `memory_get` | Retrieve a memory by ID |
49
48
  | `memory_forget` | Delete a memory by ID |
49
+ | `document_search` | Search project documents for relevant paragraphs, tables, and figures |
50
50
 
51
51
  ## CLI
52
52
 
@@ -65,7 +65,6 @@ openclaw memorylake stats
65
65
  | `apiKey` | `string` | — | **Required.** MemoryLake API key (supports `${MEMORYLAKE_API_KEY}`) |
66
66
  | `projectId` | `string` | — | **Required.** MemoryLake project ID |
67
67
  | `host` | `string` | `https://app.memorylake.ai` | MemoryLake server endpoint URL |
68
- | `userId` | `string` | `"default"` | Scope memories per user |
69
68
  | `autoRecall` | `boolean` | `true` | Inject memories before each turn |
70
69
  | `autoCapture` | `boolean` | `true` | Store facts after each turn |
71
70
  | `topK` | `number` | `5` | Max memories per recall |
package/docs/openclaw.mdx CHANGED
@@ -11,9 +11,9 @@ Add long-term memory to [OpenClaw](https://github.com/openclaw/openclaw) agents
11
11
  </Frame>*/}
12
12
 
13
13
  The plugin provides:
14
- 1. **Auto-Recall** — Before the agent responds, memories matching the current message are injected into context
14
+ 1. **Auto-Recall** — Before the agent responds, memories and relevant document excerpts matching the current message are injected into context
15
15
  2. **Auto-Capture** — After the agent responds, the exchange is sent to MemoryLake which decides what's worth keeping
16
- 3. **Agent Tools** — Five tools for explicit memory operations during conversations
16
+ 3. **Agent Tools** — Six tools for memory and document operations during conversations
17
17
 
18
18
  Both auto-recall and auto-capture run silently with no manual configuration required.
19
19
 
@@ -34,16 +34,15 @@ Add to your `openclaw.json`:
34
34
  "memorylake-openclaw": {
35
35
  "enabled": true,
36
36
  "config": {
37
- "apiKey": "${MEMORYLAKE_API_KEY}",
38
- "projectId": "proj-...",
39
- "userId": "your-user-id"
37
+ "apiKey": "sk-...",
38
+ "projectId": "proj-..."
40
39
  }
41
40
  }
42
41
  ```
43
42
 
44
43
  ## Agent Tools
45
44
 
46
- The agent gets five tools it can call during conversations:
45
+ The agent gets six tools it can call during conversations:
47
46
 
48
47
  | Tool | Description |
49
48
  |------|-------------|
@@ -52,6 +51,7 @@ The agent gets five tools it can call during conversations:
52
51
  | `memory_store` | Explicitly save a fact |
53
52
  | `memory_get` | Retrieve a memory by ID |
54
53
  | `memory_forget` | Delete a memory by ID |
54
+ | `document_search` | Search project documents for relevant paragraphs, tables, and figures |
55
55
 
56
56
  ## CLI Commands
57
57
 
@@ -70,7 +70,6 @@ openclaw memorylake stats
70
70
  | `apiKey` | `string` | — | **Required.** MemoryLake API key (supports `${MEMORYLAKE_API_KEY}`) |
71
71
  | `projectId` | `string` | — | **Required.** MemoryLake project ID |
72
72
  | `host` | `string` | `https://app.memorylake.ai` | MemoryLake server endpoint URL |
73
- | `userId` | `string` | `"default"` | Scope memories per user |
74
73
  | `autoRecall` | `boolean` | `true` | Inject memories before each turn |
75
74
  | `autoCapture` | `boolean` | `true` | Store facts after each turn |
76
75
  | `topK` | `number` | `5` | Max memories per recall |
@@ -82,7 +81,7 @@ openclaw memorylake stats
82
81
  1. **Zero Configuration** — Auto-recall and auto-capture work out of the box with no prompting required
83
82
  2. **Async Processing** — Memory extraction runs asynchronously via MemoryLake's API
84
83
  3. **Session Tracking** — Conversations are tagged with `chat_session_id` for traceability
85
- 4. **Rich Tool Suite** — Five agent tools for explicit memory operations when needed
84
+ 4. **Rich Tool Suite** — Six agent tools for memory and document operations when needed
86
85
 
87
86
  ## Conclusion
88
87
 
@@ -0,0 +1,96 @@
1
+ ---
2
+ title: OpenClaw(中文)
3
+ ---
4
+
5
+ 通过 `memorylake-openclaw` 插件为 [OpenClaw](https://github.com/openclaw/openclaw) 代理添加长期记忆。你的代理在不同会话之间会忘记一切——这个插件会自动“观察”对话、提取重要信息,并在相关时把它们带回上下文,从而解决遗忘问题。
6
+
7
+ ## 概览
8
+
9
+ {/*<Frame>
10
+ <img src="/images/openclaw-architecture.png" alt="OpenClaw MemoryLake Architecture" />
11
+ </Frame>*/}
12
+
13
+ 该插件提供:
14
+ 1. **自动召回(Auto-Recall)** — 在代理回复前,将与当前消息匹配的记忆注入到上下文中
15
+ 2. **自动捕获(Auto-Capture)** — 在代理回复后,将本轮对话发送到 MemoryLake,由其判断哪些内容值得长期保存
16
+ 3. **代理工具(Agent Tools)** — 提供 5 个工具,便于在对话中显式进行记忆操作
17
+
18
+ 自动召回与自动捕获默认静默运行,无需手动配置即可生效。
19
+
20
+ ## 安装
21
+
22
+ ```bash
23
+ openclaw plugins install memorylake-openclaw
24
+ ```
25
+
26
+ ## 设置与配置
27
+
28
+ <Note>请从 [app.memorylake.ai](https://app.memorylake.ai) 获取 API key 和 project ID。</Note>
29
+
30
+ 在你的 `openclaw.json` 中添加:
31
+
32
+ ```json5
33
+ // plugins.entries
34
+ "memorylake-openclaw": {
35
+ "enabled": true,
36
+ "config": {
37
+ "apiKey": "${MEMORYLAKE_API_KEY}",
38
+ "projectId": "proj-..."
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## 代理工具
44
+
45
+ 代理在对话中可调用以下 5 个工具:
46
+
47
+ | 工具 | 说明 |
48
+ |------|------|
49
+ | `memory_search` | 用自然语言搜索记忆 |
50
+ | `memory_list` | 列出某个用户已存储的全部记忆 |
51
+ | `memory_store` | 显式保存一条事实 |
52
+ | `memory_get` | 通过 ID 读取一条记忆 |
53
+ | `memory_forget` | 通过 ID 删除一条记忆 |
54
+
55
+ ## CLI 命令
56
+
57
+ ```bash
58
+ # 搜索记忆
59
+ openclaw memorylake search "what languages does the user know"
60
+
61
+ # 查看统计信息
62
+ openclaw memorylake stats
63
+ ```
64
+
65
+ ## 配置项
66
+
67
+ | Key | 类型 | 默认值 | 说明 |
68
+ |-----|------|--------|------|
69
+ | `apiKey` | `string` | — | **必填。** MemoryLake API key(支持 `${MEMORYLAKE_API_KEY}`) |
70
+ | `projectId` | `string` | — | **必填。** MemoryLake project ID |
71
+ | `host` | `string` | `https://app.memorylake.ai` | MemoryLake 服务端点 URL |
72
+ | `autoRecall` | `boolean` | `true` | 每轮对话前注入记忆 |
73
+ | `autoCapture` | `boolean` | `true` | 每轮对话后存储事实 |
74
+ | `topK` | `number` | `5` | 每次召回最多注入的记忆条数 |
75
+ | `searchThreshold` | `number` | `0.3` | 最小相似度阈值(0–1) |
76
+ | `rerank` | `boolean` | `true` | 对搜索结果重排以提升相关性 |
77
+
78
+ ## 关键特性
79
+
80
+ 1. **零配置** — 自动召回与自动捕获开箱即用,无需额外提示词或手动开关
81
+ 2. **异步处理** — 记忆提取通过 MemoryLake API 异步执行
82
+ 3. **会话追踪** — 对话会附带 `chat_session_id`,便于追溯与排查
83
+ 4. **工具完备** — 需要时可使用 5 个代理工具显式管理记忆
84
+
85
+ ## 总结
86
+
87
+ `memorylake-openclaw` 插件让 OpenClaw 代理以极低成本获得持久记忆能力。你的代理可以跨会话自动记住用户偏好、事实与上下文,从而更稳定地连续协作。
88
+
89
+ {/*<CardGroup cols={2}>
90
+ <Card title="MemoryLake" icon="brain" href="https://app.memorylake.ai">
91
+ MemoryLake platform
92
+ </Card>
93
+ <Card title="OpenClaw" icon="robot" href="https://github.com/openclaw/openclaw">
94
+ OpenClaw agent framework
95
+ </Card>
96
+ </CardGroup>*/}