{"id":43429578,"url":"https://github.com/voocel/openclaw-mini","last_synced_at":"2026-02-08T00:00:22.759Z","repository":{"id":335969299,"uuid":"1147148934","full_name":"voocel/openclaw-mini","owner":"voocel","description":"🦞 OpenClaw 核心架构的极简复现，涵盖 sessionKey 会话域、队列串行、工具化记忆检索、按需上下文加载、可扩展技能与主动心跳唤醒机制","archived":false,"fork":false,"pushed_at":"2026-02-05T13:06:40.000Z","size":132,"stargazers_count":297,"open_issues_count":1,"forks_count":16,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-02-07T07:47:29.071Z","etag":null,"topics":["agent","ai","clawdbot","openclaw"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/voocel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-01T09:24:33.000Z","updated_at":"2026-02-07T07:42:58.000Z","dependencies_parsed_at":"2026-02-05T22:00:40.935Z","dependency_job_id":null,"html_url":"https://github.com/voocel/openclaw-mini","commit_stats":null,"previous_names":["voocel/openclaw-mini"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/voocel/openclaw-mini","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voocel%2Fopenclaw-mini","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voocel%2Fopenclaw-mini/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voocel%2Fopenclaw-mini/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voocel%2Fopenclaw-mini/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/voocel","download_url":"https://codeload.github.com/voocel/openclaw-mini/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voocel%2Fopenclaw-mini/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29213439,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-07T23:58:20.073Z","status":"ssl_error","status_checked_at":"2026-02-07T23:58:07.729Z","response_time":63,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent","ai","clawdbot","openclaw"],"created_at":"2026-02-02T19:15:52.177Z","updated_at":"2026-02-08T00:00:22.657Z","avatar_url":"https://github.com/voocel.png","language":"TypeScript","funding_links":[],"categories":["Skills \u0026 Plugins"],"sub_categories":["Third-Party Platforms"],"readme":"# OpenClaw Mini\n\n**OpenClaw 核心架构的极简复现，用于学习 AI Agent 的系统级设计。**\n\n\u003e \"没有记忆的 AI 只是函数映射，有记忆 + 主动唤醒的 AI，才是会演化的'生命系统'\"\n\n## 为什么做这个项目\n\n网上大多数 Agent 教程只讲 Agent Loop：\n\n```python\nwhile tool_calls:\n    response = llm.generate(messages)\n    for tool in tools:\n        result = tool.execute()\n        messages.append(result)\n```\n\n**这不是真正的 Agent 架构。** 一个生产级 Agent 需要的是\"系统级最佳实践\"。\n\nOpenClaw 是一个 5 万行的生产级 Agent 系统，本项目从中提炼出 **~800 行核心代码**，帮助你理解：\n\n- 为什么需要长期记忆？\n- 如何实现按需上下文加载？\n- 技能系统怎么设计才能扩展？\n- 主动唤醒机制的真实实现是什么？\n\n## 架构对照\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│                       OpenClaw Mini                               │\n│                      (本项目 ~800 行)                             │\n├──────────────────────────────────────────────────────────────────┤\n│                                                                   │\n│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────────┐   │\n│  │   Context   │  │   Skills    │  │       Heartbeat         │   │\n│  │   Loader    │  │   Manager   │  │       Manager           │   │\n│  │             │  │             │  │  ┌─────────────────┐    │   │\n│  │ AGENTS.md   │  │ SKILL.md    │  │  │ HeartbeatWake   │    │   │\n│  │ SOUL.md     │  │ 触发词匹配  │  │  │ (请求合并层)    │    │   │\n│  │ TOOLS.md... │  │ 内置+自定义 │  │  └────────┬────────┘    │   │\n│  └──────┬──────┘  └──────┬──────┘  │           │             │   │\n│         │                │         │  ┌────────▼────────┐    │   │\n│         │                │         │  │ HeartbeatRunner │    │   │\n│         │                │         │  │ (调度层)        │    │   │\n│         │                │         │  └────────┬────────┘    │   │\n│         │                │         └───────────┼─────────────┘   │\n│         │                │                     │                  │\n│         ▼                ▼                     ▼                  │\n│  ┌────────────────────────────────────────────────────────────┐  │\n│  │                      Agent Loop                             │  │\n│  │                                                             │  │\n│  │   while (tool_calls) {                                      │  │\n│  │     response = llm.generate(system_prompt + messages)       │  │\n│  │     for (tool of tools) { result = tool.execute() }         │  │\n│  │     messages.push(result)                                   │  │\n│  │   }                                                         │  │\n│  │                                                             │  │\n│  └────────────────────────────────────────────────────────────┘  │\n│         │                                          │              │\n│         ▼                                          ▼              │\n│  ┌─────────────┐                          ┌─────────────┐        │\n│  │   Session   │                          │   Memory    │        │\n│  │   Manager   │                          │   Manager   │        │\n│  │  (JSONL)    │                          │ (关键词检索) │        │\n│  └─────────────┘                          └─────────────┘        │\n│                                                                   │\n└──────────────────────────────────────────────────────────────────┘\n```\n\n## 5 大核心子系统\n\n| 子系统 | 本项目 | OpenClaw 源码 | 核心职责 |\n|--------|--------|---------------|----------|\n| **Session** | `session.ts` | `src/agents/session-manager.ts` | 会话持久化 (JSONL)、历史管理 |\n| **Memory** | `memory.ts` | `src/memory/manager.ts` (76KB) | 长期记忆、语义检索 |\n| **Context** | `context/loader.ts` | `src/agents/bootstrap-files.ts` | 按需加载 AGENTS/SOUL/TOOLS/IDENTITY/USER/HEARTBEAT/BOOTSTRAP/MEMORY |\n| **Skills** | `skills.ts` | `src/agents/skills/` | 可扩展技能、触发词匹配 |\n| **Heartbeat** | `heartbeat.ts` | `src/infra/heartbeat-runner.ts`\u003cbr\u003e`src/infra/heartbeat-wake.ts` | 主动唤醒、事件驱动调度 |\n\n---\n\n## 深入解析\n\n### 1. Session Manager - 会话持久化\n\n**问题**：Agent 重启后如何恢复对话上下文？\n\n**OpenClaw 方案**：\n- JSONL 格式存储（每行一条消息，追加写入）\n- 分布式锁防止并发写入\n- 自动 compaction 压缩历史\n\n**本项目实现** (`session.ts:45-62`)：\n```typescript\nasync append(sessionId: string, message: Message): Promise\u003cvoid\u003e {\n  const filePath = this.getFilePath(sessionId);\n  await fs.mkdir(path.dirname(filePath), { recursive: true });\n  await fs.appendFile(filePath, JSON.stringify(message) + \"\\n\");\n}\n```\n\n### 2. Memory Manager - 长期记忆\n\n**问题**：如何让 Agent \"记住\"跨会话的信息？\n\n**OpenClaw 方案** (`src/memory/manager.ts`)：\n- SQLite-vec 向量数据库做语义搜索\n- BM25 做关键词搜索\n- 混合排序 (Hybrid Search)\n\n**本项目简化** (`memory.ts:85-118`)：\n```typescript\nasync search(query: string, limit = 5): Promise\u003cMemorySearchResult[]\u003e {\n  const queryTerms = query.toLowerCase().split(/\\s+/);\n\n  for (const entry of this.entries) {\n    let score = 0;\n    // 关键词匹配得分\n    for (const term of queryTerms) {\n      if (text.includes(term)) score += 1;\n      if (entry.tags.some(t =\u003e t.includes(term))) score += 0.5;\n    }\n    // 时间衰减：越新的记忆分数越高\n    const recencyBoost = Math.max(0, 1 - ageHours / (24 * 30));\n    score += recencyBoost * 0.3;\n  }\n}\n```\n\n### 3. Context Loader - 按需上下文\n\n**问题**：如何注入项目级规范而不污染每次对话？\n\n**OpenClaw 方案** (`src/agents/bootstrap-files.ts`)：\n- `AGENTS.md / SOUL.md / TOOLS.md / IDENTITY.md / USER.md / HEARTBEAT.md / BOOTSTRAP.md`\n- `MEMORY.md`（或 `memory.md`）作为记忆补充\n- 子代理仅允许 `AGENTS.md` + `TOOLS.md` 进入上下文\n- 超长文件按 head+tail 截断并加标记\n\n**本项目实现** (`context/loader.ts`)：\n```typescript\nasync buildContextPrompt(params?: { sessionKey?: string }): Promise\u003cstring\u003e {\n  const files = await this.loadBootstrapFiles(params);\n  const contextFiles = buildBootstrapContextFiles(files, { maxChars: this.maxChars });\n  // Project Context 输出（含 SOUL.md 特殊提示）\n}\n```\n\n### 3.1 Context Pruning/Compaction - 上下文压缩\n\n**OpenClaw 方案**：\n- `src/agents/pi-extensions/context-pruning/*`：裁剪工具结果、保留最近上下文\n- `src/agents/compaction.ts`：超长历史摘要压缩\n\n**本项目实现**：\n- `context/pruning.ts`：软裁剪 tool_result + 保留最近 assistant\n- `context/compaction.ts`：触发阈值后生成“历史摘要”并注入\n\n### 4. Skills Manager - 可扩展技能\n\n**问题**：如何让用户自定义 Agent 能力？\n\n**OpenClaw 方案** (`src/agents/skills/types.ts`)：\n- SKILL.md frontmatter 定义元数据\n- 支持触发条件、安装脚本、参数校验\n- 运行时动态加载\n\n**本项目实现** (`skills.ts:125-170`)：\n```typescript\n// SKILL.md 格式\n// ---\n// id: deploy\n// name: 部署助手\n// triggers: [\"/deploy\", \"部署\"]\n// ---\n// Prompt 内容...\n\nasync match(input: string): Promise\u003cSkillMatch | null\u003e {\n  for (const skill of this.skills.values()) {\n    for (const trigger of skill.triggers) {\n      if (input.startsWith(trigger)) {\n        return { skill, matchedTrigger: trigger };\n      }\n    }\n  }\n}\n```\n\n### 5. Heartbeat Manager - 主动唤醒\n\n**问题**：Agent 如何\"主动\"工作，而不只是被动响应？\n\n**OpenClaw 方案** (`src/infra/heartbeat-runner.ts`, `src/infra/heartbeat-wake.ts`)：\n\n这是最复杂的子系统，包含两层架构：\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│                     HeartbeatWake (请求合并层)               │\n├─────────────────────────────────────────────────────────────┤\n│                                                              │\n│  多来源触发:                                                 │\n│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐    │\n│  │ interval │  │   cron   │  │   exec   │  │ requested│    │\n│  │ (定时器) │  │ (任务完成)│  │ (命令完成)│  │ (手动)   │    │\n│  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘    │\n│       │             │             │             │           │\n│       └─────────────┴──────┬──────┴─────────────┘           │\n│                            ▼                                 │\n│                    request({ reason })                       │\n│                            │                                 │\n│                    ┌───────▼───────┐                        │\n│                    │ 原因优先级合并 │                        │\n│                    │ exec \u003e cron   │                        │\n│                    │ \u003e interval    │                        │\n│                    └───────┬───────┘                        │\n│                            │                                 │\n│                    ┌───────▼───────┐                        │\n│                    │ schedule(250ms)│ ◄── 合并窗口          │\n│                    └───────┬───────┘                        │\n│                            │                                 │\n│              ┌─────────────┼─────────────┐                  │\n│              │ if running: │ else:       │                  │\n│              │ scheduled=  │ setTimeout  │                  │\n│              │ true (排队) │ execute()   │                  │\n│              └─────────────┴─────────────┘                  │\n│                                                              │\n└─────────────────────────────────────────────────────────────┘\n                            │\n                            ▼\n┌─────────────────────────────────────────────────────────────┐\n│                   HeartbeatRunner (调度层)                   │\n├─────────────────────────────────────────────────────────────┤\n│                                                              │\n│  runOnce(request):                                          │\n│                                                              │\n│  1. isWithinActiveHours()  ─── 活跃时间窗口检查             │\n│     │                          (08:00-22:00, 支持时区)      │\n│     ▼                                                        │\n│  2. parseTasks()           ─── HEARTBEAT.md 解析            │\n│     │                                                        │\n│     ▼                                                        │\n│  3. 空内容检测             ─── 无任务时跳过 API 调用        │\n│     │                          (exec 事件除外)              │\n│     ▼                                                        │\n│  4. 执行回调               ─── Agent 处理任务               │\n│     │                                                        │\n│     ▼                                                        │\n│  5. isDuplicateMessage()   ─── 24h 内重复消息抑制           │\n│     │                                                        │\n│     ▼                                                        │\n│  6. scheduleNext()         ─── setTimeout 精确调度          │\n│                                (lastRunAt + intervalMs)     │\n│                                                              │\n└─────────────────────────────────────────────────────────────┘\n```\n\n**关键设计决策**：\n\n| 设计点 | 为什么这样做 |\n|--------|-------------|\n| setTimeout 而非 setInterval | 精确计算下次运行时间，避免漂移 |\n| 250ms 合并窗口 | 防止多个事件同时触发导致的\"呼吸急促\" |\n| 双重缓冲 | 运行中收到新请求不丢失，完成后立即处理 |\n| 空内容检测 | 无任务时跳过 LLM 调用，节省成本 |\n| 重复抑制 | 24h 内相同消息不重复发送，防止\"纠缠\" |\n| 活跃时间窗口 | 避免半夜打扰用户 |\n\n**本项目实现** (`heartbeat.ts:147-160`)：\n```typescript\nprivate schedule(delayMs: number): void {\n  // 如果已在运行，标记为已排队（双重缓冲）\n  if (this.state.running) {\n    this.state.scheduled = true;\n    return;\n  }\n  // 如果已有定时器，不重复设置（合并）\n  if (this.state.timer) {\n    return;\n  }\n  this.state.timer = setTimeout(() =\u003e this.execute(), delayMs);\n}\n```\n\n---\n\n## 源码映射表\n\n| 本项目文件 | 行数 | OpenClaw 对应文件 | 原始规模 |\n|-----------|------|-------------------|---------|\n| `agent.ts` | ~320 | `src/agents/pi-embedded-runner/run.ts` | ~700 行 |\n| `session.ts` | ~110 | `src/agents/session-manager.ts` | ~500 行 |\n| `memory.ts` | ~170 | `src/memory/manager.ts` | 76KB |\n| `context/loader.ts` | ~150 | `src/agents/bootstrap-files.ts` | ~300 行 |\n| `context/pruning.ts` | ~220 | `src/agents/pi-extensions/context-pruning/pruner.ts` | ~450 行 |\n| `context/compaction.ts` | ~260 | `src/agents/compaction.ts` | ~380 行 |\n| `skills.ts` | ~230 | `src/agents/skills/` | ~2000 行 |\n| `heartbeat.ts` | ~400 | `src/infra/heartbeat-runner.ts`\u003cbr\u003e`src/infra/heartbeat-wake.ts` | ~1500 行 |\n| `tools/*.ts` | ~210 | `src/tools/` | 50+ 工具 |\n| **总计** | **~800** | | **~50,000** |\n\n---\n\n## 快速开始\n\n```bash\n# 进入目录\ncd examples/openclaw-mini\n\n# 安装依赖\npnpm install\n\n# 设置 API Key\nexport ANTHROPIC_API_KEY=sk-xxx\n\n# 可选：指定 agentId\nexport OPENCLAW_MINI_AGENT_ID=main\n\n# 启动交互式对话\npnpm dev chat\n```\n\n## 工作区模板（来自 OpenClaw 设计）\n\n模板放在 `examples/openclaw-mini/workspace-templates/`（内容参考 `docs/reference/templates/` 的设计），运行时会从**当前工作区根目录**读取这些文件。  \n需要生效时，把模板复制到工作区根目录即可：\n\n```bash\ncp examples/openclaw-mini/workspace-templates/* examples/openclaw-mini/\n```\n\n## 使用示例\n\n```typescript\nimport { Agent } from \"openclaw-mini\";\n\nconst agent = new Agent({\n  apiKey: process.env.ANTHROPIC_API_KEY,\n  agentId: \"main\",\n  workspaceDir: process.cwd(),\n  enableMemory: true,     // 长期记忆\n  enableContext: true,    // 上下文加载\n  enableSkills: true,     // 技能系统\n  enableHeartbeat: false, // 主动唤醒（默认关闭）\n  // 工具策略与沙箱（示意）\n  toolPolicy: { deny: [\"exec\"] },\n  sandbox: { enabled: true, allowExec: false, allowWrite: true },\n});\n\n// 基本对话（传入 sessionId，会自动补全为 sessionKey）\nconst result = await agent.run(\"session-1\", \"请列出当前目录的文件\");\n\n// 使用技能\nconst review = await agent.run(\"session-1\", \"/review src/agent.ts\");\n\n// 也可以直接使用 sessionKey\nconst result2 = await agent.run(\"agent:main:session-1\", \"继续刚才的任务\");\n\n// 启动主动唤醒\nagent.startHeartbeat((tasks, request) =\u003e {\n  console.log(`[${request.reason}] 检测到 ${tasks.length} 个待办任务`);\n});\n```\n\n\u003e 记忆使用提示：mini 版改为“工具化记忆”，在系统提示中引导模型先调用 `memory_search` 再 `memory_get` 拉取细节。\n\n\u003e 子代理：可通过 `sessions_spawn` 工具启动后台子代理，完成后会在 CLI 输出摘要，并写入父会话记录。\n\n## 学习路径建议\n\n1. **先读 `agent.ts`**：理解 Agent Loop 和子系统整合\n2. **再读 `heartbeat.ts`**：这是最复杂的部分，理解事件驱动架构\n3. **对照 OpenClaw 源码**：验证简化版是否抓住了核心\n4. **尝试扩展**：添加新的技能、工具、或改进记忆检索\n\n## 与 OpenClaw 源码对照\n\n本项目位于 `examples/openclaw-mini`，可直接对照父目录的 OpenClaw 源码学习：\n\n```\nopenclaw/\n├── src/\n│   ├── infra/heartbeat-runner.ts    ← 对照 examples/openclaw-mini/src/heartbeat.ts\n│   ├── infra/heartbeat-wake.ts      ← 对照 examples/openclaw-mini/src/heartbeat.ts\n│   ├── memory/manager.ts            ← 对照 examples/openclaw-mini/src/memory.ts\n│   ├── agents/bootstrap-files.ts    ← 对照 examples/openclaw-mini/src/context/loader.ts\n│   ├── agents/compaction.ts         ← 对照 examples/openclaw-mini/src/context/compaction.ts\n│   ├── agents/pi-extensions/context-pruning/pruner.ts ← 对照 examples/openclaw-mini/src/context/pruning.ts\n│   └── agents/skills/               ← 对照 examples/openclaw-mini/src/skills.ts\n└── examples/\n    └── openclaw-mini/               ← 本项目 (~800 行)\n```\n\n## 精华设计索引（必学 4 点）\n\n1) **上下文的文件化结构**  \n   - OpenClaw：`src/agents/workspace.ts`（bootstrap 文件清单）  \n   - Mini：`examples/openclaw-mini/src/context/bootstrap.ts`\n\n2) **统一注入链路（Project Context）**  \n   - OpenClaw：`src/agents/system-prompt.ts`  \n   - Mini：`examples/openclaw-mini/src/context/loader.ts`\n\n3) **规模控制（截断 + 裁剪）**  \n   - OpenClaw：`src/agents/pi-embedded-helpers/bootstrap.ts` + `src/agents/pi-extensions/context-pruning/pruner.ts`  \n   - Mini：`examples/openclaw-mini/src/context/bootstrap.ts` + `examples/openclaw-mini/src/context/pruning.ts`\n\n4) **压缩继承（摘要）**  \n   - OpenClaw：`src/agents/compaction.ts`  \n   - Mini：`examples/openclaw-mini/src/context/compaction.ts`\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoocel%2Fopenclaw-mini","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvoocel%2Fopenclaw-mini","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoocel%2Fopenclaw-mini/lists"}