fix: 修正 WaterFlow Skill/Tool 兼容性问题 + 类型声明完善
Skill 格式修正: - allowed_tools → allowed-tools (kebab-case) - user_invocable → user-invocable (kebab-case) - persona skill name: graph_memory_persona → persona (匹配目录名) - task skill name: graph_memory_task → task (匹配目录名) Tool 接口优化: - installTrulyMEM: require() → ESM dynamic import - handler: 添加 abort 信号检查 - graph_database: _platform 类型 any → Platform - graph_database: 修复 fs null 检查和 ArrayBuffer 类型转换 类型声明完善: - waterflow.d.ts 从 193 行扩展到 400+ 行 - 添加 SchemaType, ToolFeatures, ToolMetadata 等完整类型 - 添加 network, tools, builtinTools 等缺失字段 - 添加 waterflow/runtime/core/tools/builtin 模块声明 - 添加 waterflow/runtime/core/tools/tool_registry 模块声明 清理: - 删除 TRACKING.md, 重构.md, migration_plan.md, todo_progress.md - 删除 docs/integration/waterflow-design.md
This commit is contained in:
@ -1,117 +0,0 @@
|
||||
# TrulyMEM → WaterFlow 迁移计划
|
||||
|
||||
> ⚠️ **修改只在 TrulyMEM 的 waterflow 分支执行** ⚠️
|
||||
>
|
||||
> 所有代码修改仅应用于 TrulyMEM 仓库的 `waterflow` 分支,作为 WaterFlow 框架的适配版本。
|
||||
|
||||
---
|
||||
|
||||
## 迁移目标
|
||||
|
||||
将 TrulyMEM 的图记忆能力从 Python 迁移到 TypeScript,适配 WaterFlow 框架。
|
||||
|
||||
**代码位置**: `/home/program/TrulyMEM-TrueHumanMEM/` (waterflow 分支)
|
||||
|
||||
---
|
||||
|
||||
## 迁移策略
|
||||
|
||||
将图记忆能力作为 TypeScript 模块添加到 waterflow 分支:
|
||||
|
||||
| TrulyMEM (Python) | WaterFlow (TypeScript) |
|
||||
|-------------------|------------------------|
|
||||
| `EmbeddedGraphDB` | `GraphDatabase` |
|
||||
| `GraphMemoryClient` | `MemoryService` |
|
||||
| 12 个记忆工具 | `GraphMemoryTool` + Skills |
|
||||
|
||||
---
|
||||
|
||||
## 实施步骤
|
||||
|
||||
### Phase 1: 项目结构
|
||||
|
||||
- [x] 1.1 创建 `ts/` 目录 - TypeScript 项目
|
||||
- [x] 1.2 创建 `package.json` - 项目配置
|
||||
- [x] 1.3 创建 `tsconfig.json` - TypeScript 配置
|
||||
|
||||
### Phase 2: 核心库
|
||||
|
||||
- [x] 2.1 创建 `ts/src/runtime/core/graph_memory/types.ts` - 类型定义
|
||||
- [x] 2.2 创建 `ts/src/runtime/core/graph_memory/graph_database.ts` - 图数据库
|
||||
- [x] 2.3 创建 `ts/src/runtime/core/graph_memory/memory_service.ts` - 记忆服务
|
||||
- [x] 2.4 创建 `ts/src/runtime/core/graph_memory/index.ts` - 模块导出
|
||||
|
||||
### Phase 3: Tool 接口
|
||||
|
||||
- [x] 3.1 创建 `ts/src/runtime/core/tools/builtin/graph_memory_tool.ts` - Tool 实现
|
||||
- [x] 3.2 注册 Tool (作为独立模块导出)
|
||||
|
||||
### Phase 4: Skill 定义
|
||||
|
||||
- [x] 4.1 创建 `ts/bundled-skills/graph_memory/SKILL.md` - 主 Skill
|
||||
- [x] 4.2 创建 `ts/bundled-skills/graph_memory/persona/SKILL.md` - Persona
|
||||
- [x] 4.3 创建 `ts/bundled-skills/graph_memory/task/SKILL.md` - 任务管理
|
||||
|
||||
### Phase 5: 验证
|
||||
|
||||
- [x] 5.1 编译 TypeScript - 无错误
|
||||
- [ ] 5.2 运行测试
|
||||
|
||||
---
|
||||
|
||||
## 目录结构 (在 TrulyMEM waterflow 分支)
|
||||
|
||||
```
|
||||
TrulyMEM-TrueHumanMEM/
|
||||
├── ts/ # TypeScript 项目 (保留)
|
||||
│ ├── src/
|
||||
│ │ └── runtime/core/
|
||||
│ │ ├── graph_memory/ # 图记忆模块
|
||||
│ │ │ ├── index.ts
|
||||
│ │ │ ├── types.ts
|
||||
│ │ │ ├── graph_database.ts
|
||||
│ │ │ └── memory_service.ts
|
||||
│ │ └── tools/
|
||||
│ │ └── builtin/
|
||||
│ │ └── graph_memory_tool.ts
|
||||
│ ├── bundled-skills/
|
||||
│ │ └── graph_memory/
|
||||
│ │ ├── SKILL.md
|
||||
│ │ ├── persona/SKILL.md
|
||||
│ │ └── task/SKILL.md
|
||||
│ ├── package.json
|
||||
│ └── tsconfig.json
|
||||
│
|
||||
├── docs/integration/waterflow-design.md # 迁移设计文档 (保留)
|
||||
│
|
||||
└── (其他文件迁移后删除)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 迁移后清理
|
||||
|
||||
迁移完成后,waterflow 分支将删除以下文件:
|
||||
|
||||
- `core/` - Python 核心代码
|
||||
- `ui/` - Python UI 代码
|
||||
- `tests/` - Python 测试
|
||||
- `tools/` - Python 工具
|
||||
- `trulymem_entry.py` - Python 入口
|
||||
- `build/` - 构建脚本
|
||||
- `pic/` - 图片资源 (除图标外)
|
||||
- `requirements.txt` - Python 依赖
|
||||
- `TrulyMEM.spec` - Python 打包配置
|
||||
|
||||
只保留:
|
||||
- `ts/` - TypeScript 源码
|
||||
- `docs/integration/waterflow-design.md` - 迁移文档
|
||||
- `.gitignore`, `LICENSE`
|
||||
|
||||
---
|
||||
|
||||
## 工作追踪
|
||||
|
||||
工作进度记录在: `todo_progress.md`
|
||||
|
||||
每次修改文件前后请查看此文件并更新进度。
|
||||
@ -1,81 +0,0 @@
|
||||
# 迁移工作进度追踪
|
||||
|
||||
> ⚠️ **修改只在 TrulyMEM 的 waterflow 分支执行** ⚠️
|
||||
|
||||
---
|
||||
|
||||
## 当前状态
|
||||
|
||||
- **开始时间**: 2026-04-15
|
||||
- **当前任务**: 迁移完成,等待测试
|
||||
- **最后更新**: 2026-04-15
|
||||
- **状态**: TypeScript 编译通过
|
||||
|
||||
---
|
||||
|
||||
## Phase 完成状态
|
||||
|
||||
### Phase 1: 项目结构
|
||||
|
||||
| 任务 | 状态 | 备注 |
|
||||
|------|------|------|
|
||||
| 1.1 ts/ 目录 | ✅ done | |
|
||||
| 1.2 package.json | ✅ done | |
|
||||
| 1.3 tsconfig.json | ✅ done | |
|
||||
|
||||
### Phase 2: 核心库
|
||||
|
||||
| 任务 | 状态 | 备注 |
|
||||
|------|------|------|
|
||||
| 2.1 types.ts | ✅ done | |
|
||||
| 2.2 graph_database.ts | ✅ done | |
|
||||
| 2.3 memory_service.ts | ✅ done | |
|
||||
| 2.4 index.ts | ✅ done | |
|
||||
|
||||
### Phase 3: Tool 接口
|
||||
|
||||
| 任务 | 状态 | 备注 |
|
||||
|------|------|------|
|
||||
| 3.1 graph_memory_tool.ts | ✅ done | |
|
||||
| 3.2 tool_interface.ts | ✅ done | |
|
||||
|
||||
### Phase 4: Skill 定义
|
||||
|
||||
| 任务 | 状态 | 备注 |
|
||||
|------|------|------|
|
||||
| 4.1 SKILL.md (主) | ✅ done | |
|
||||
| 4.2 persona/SKILL.md | ✅ done | |
|
||||
| 4.3 task/SKILL.md | ✅ done | |
|
||||
|
||||
### Phase 5: 验证
|
||||
|
||||
| 任务 | 状态 | 备注 |
|
||||
|------|------|------|
|
||||
| 5.1 编译 | ✅ done | TypeScript 编译通过 |
|
||||
| 5.2 测试 | ⏳ pending | |
|
||||
|
||||
---
|
||||
|
||||
## 创建的文件
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `ts/package.json` | 项目配置 |
|
||||
| `ts/tsconfig.json` | TypeScript 配置 |
|
||||
| `ts/src/runtime/core/graph_memory/types.ts` | 类型定义 |
|
||||
| `ts/src/runtime/core/graph_memory/graph_database.ts` | 图数据库 |
|
||||
| `ts/src/runtime/core/graph_memory/memory_service.ts` | 记忆服务 |
|
||||
| `ts/src/runtime/core/graph_memory/index.ts` | 模块导出 |
|
||||
| `ts/src/runtime/core/tools/tool_interface.ts` | Tool 接口 |
|
||||
| `ts/src/runtime/core/tools/builtin/graph_memory_tool.ts` | GraphMemory Tool |
|
||||
| `ts/bundled-skills/graph_memory/SKILL.md` | 主 Skill |
|
||||
| `ts/bundled-skills/graph_memory/persona/SKILL.md` | Persona Skill |
|
||||
| `ts/bundled-skills/graph_memory/task/SKILL.md` | Task Skill |
|
||||
|
||||
---
|
||||
|
||||
## 说明
|
||||
|
||||
- 每次修改文件前后更新此文件
|
||||
- 记录每次修改的文件和操作
|
||||
- 方便意外终止后恢复任务
|
||||
102
TRACKING.md
102
TRACKING.md
@ -1,102 +0,0 @@
|
||||
# TrulyMEM WaterFlow 重构 - 工程追踪
|
||||
|
||||
> 每次文件操作前更新此文件,确保中断可恢复。
|
||||
> 最后更新: 2026-04-16
|
||||
|
||||
---
|
||||
|
||||
## 当前状态
|
||||
|
||||
**状态**: ✅ 全部完成
|
||||
**最后更新**: 2026-04-16
|
||||
|
||||
---
|
||||
|
||||
## 任务清单
|
||||
|
||||
| # | 任务 | 状态 | 备注 |
|
||||
|---|------|------|------|
|
||||
| 0 | 创建工程追踪文件 | ✅ 完成 | |
|
||||
| 1 | 同步 main 分支核心优化 | ✅ 完成 | BFS搜索、depth标注、工具限制器 |
|
||||
| 2 | Phase 1: 清理重复定义 | ✅ 完成 | 删除 platform/, tool_interface.ts |
|
||||
| 3 | Phase 2: 适配 WaterFlow 平台层 | ✅ 完成 | graph_database.ts, graph_memory_tool.ts |
|
||||
| 4 | Phase 3: 完善 SKILL.md | ✅ 完成 | 10 个完整操作 |
|
||||
| 5 | Phase 4: 调整构建配置 | ✅ 完成 | package.json, tsconfig.json, waterflow.d.ts |
|
||||
| 6 | Phase 5: 编译验证 | ✅ 完成 | 0 错误,dist/ 输出完整 |
|
||||
|
||||
---
|
||||
|
||||
## 操作日志
|
||||
|
||||
### 2026-04-16 开始
|
||||
- [x] 创建 TRACKING.md
|
||||
- [x] 同步 main 分支核心优化
|
||||
- [x] BFS 广度优先搜索 → graph_database.ts(含 depth 标注)
|
||||
- [x] 工具限制器调整 → 在 Tool 层面处理(WaterFlow 治理层已有)
|
||||
- [x] 提示词优化 → SKILL.md(后续 Phase 3 处理)
|
||||
- [x] Entity/Relation 类型添加 depth? 字段
|
||||
- [x] 改用 WaterFlow platform.fs 替代自定义 storage
|
||||
- [x] 缓存 platform 实例避免重复 import
|
||||
- [x] Phase 1: 删除重复文件
|
||||
- [x] 删除 ts/src/platform/ 目录(index.ts, node.ts, types.ts)
|
||||
- [x] 删除 ts/src/runtime/core/tools/tool_interface.ts
|
||||
- [x] Phase 2: 适配 WaterFlow 接口
|
||||
- [x] graph_memory_tool.ts → 使用 waterflow Tool 接口
|
||||
- [x] graph_database.ts → 使用 waterflow platform.fs(binary)
|
||||
- [x] config.ts → 内联类型定义,移除 platform 依赖
|
||||
- [x] builtin/index.ts → 添加 registerGraphMemoryTool()
|
||||
- [x] Phase 3: 完善 SKILL.md
|
||||
- [x] 主 SKILL.md 补充 10 个完整操作
|
||||
- [x] persona/SKILL.md 已验证完整
|
||||
- [x] task/SKILL.md 已验证完整
|
||||
- [x] Phase 4: 构建配置
|
||||
- [x] package.json → 添加 exports, peerDependencies
|
||||
- [x] tsconfig.json → 添加 typeRoots
|
||||
- [x] Phase 5: 验证
|
||||
- [x] tsc --noEmit 通过(0 错误)
|
||||
- [x] npm run build 成功
|
||||
- [x] dist/ 输出完整(.js, .d.ts, .map)
|
||||
- [x] 新增 waterflow.d.ts 类型声明
|
||||
- [x] 安装 waterflow-ts 作为 devDependency
|
||||
|
||||
---
|
||||
|
||||
## 变更摘要
|
||||
|
||||
### 删除(4 文件)
|
||||
- `ts/src/platform/index.ts`
|
||||
- `ts/src/platform/node.ts`
|
||||
- `ts/src/platform/types.ts`
|
||||
- `ts/src/runtime/core/tools/tool_interface.ts`
|
||||
|
||||
### 修改(8 文件)
|
||||
- `ts/src/runtime/core/graph_memory/graph_database.ts` — BFS + WaterFlow fs
|
||||
- `ts/src/runtime/core/graph_memory/types.ts` — 添加 depth? 字段
|
||||
- `ts/src/runtime/core/graph_memory/config.ts` — 内联类型,移除 platform 依赖
|
||||
- `ts/src/runtime/core/graph_memory/memory_service.ts` — 无变化(已兼容)
|
||||
- `ts/src/runtime/core/tools/builtin/graph_memory_tool.ts` — WaterFlow Tool 接口
|
||||
- `ts/src/runtime/core/tools/builtin/index.ts` — 添加 registerGraphMemoryTool()
|
||||
- `ts/package.json` — exports, peerDependencies
|
||||
- `ts/tsconfig.json` — typeRoots
|
||||
- `ts/bundled-skills/graph_memory/SKILL.md` — 10 个完整操作
|
||||
|
||||
### 新增(1 文件)
|
||||
- `ts/src/types/waterflow.d.ts` — WaterFlow 类型声明
|
||||
|
||||
---
|
||||
|
||||
## 中断恢复指南
|
||||
|
||||
如果任务中断,按以下步骤恢复:
|
||||
|
||||
1. 读取此文件,找到最后一个 ✅ 完成的任务
|
||||
2. 找到下一个 🔄 或 ⏳ 的任务
|
||||
3. 继续执行该任务
|
||||
4. 完成后更新此文件的状态
|
||||
|
||||
**关键文件路径**:
|
||||
- 重构计划: `重构.md`
|
||||
- 追踪文件: `TRACKING.md`
|
||||
- 核心代码: `ts/src/runtime/core/graph_memory/`
|
||||
- Tool 代码: `ts/src/runtime/core/tools/builtin/`
|
||||
- Skill 定义: `ts/bundled-skills/graph_memory/`
|
||||
@ -1,811 +0,0 @@
|
||||
# TrulyMEM → WaterFlow 迁移设计文档
|
||||
|
||||
**版本**: 1.0
|
||||
**日期**: 2026-04-15
|
||||
**目标**: 用 TypeScript 完全重写 TrulyMEM 的图记忆能力,集成到 WaterFlow
|
||||
|
||||
---
|
||||
|
||||
## 一、迁移策略
|
||||
|
||||
### 1.1 核心原则
|
||||
|
||||
- **完全重写**: 不保留 Python 代码,用 TypeScript 实现
|
||||
- **架构一致**: 遵循 WaterFlow 的架构风格和设计模式
|
||||
- **原生集成**: 作为 WaterFlow 的内置模块,而非外部依赖
|
||||
|
||||
### 1.2 迁移范围
|
||||
|
||||
| TrulyMEM (Python) | WaterFlow (TypeScript) | 说明 |
|
||||
|-------------------|------------------------|------|
|
||||
| `EmbeddedGraphDB` | `GraphDatabase` | SQLite 图数据库重写 |
|
||||
| `GraphMemoryClient` | `MemoryService` | 记忆服务 |
|
||||
| 12 个记忆工具 | `GraphMemoryTool` | WaterFlow Tool 接口 |
|
||||
| System Prompt | 提示词模板 | 提示词管理 |
|
||||
| TUI | ❌ 不迁移 | WaterFlow 无 TUI |
|
||||
|
||||
---
|
||||
|
||||
## 二、架构设计
|
||||
|
||||
### 2.1 整体架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ WaterFlow Core │
|
||||
│ ┌─────────────┐ ┌──────────────┐ ┌────────────────────────┐ │
|
||||
│ │ Agent / │───>│ Query │───>│ ToolExecutor │ │
|
||||
│ │ Workflow │ │ Engine │ │ │ │
|
||||
│ └─────────────┘ └──────────────┘ └───────────┬────────────┘ │
|
||||
│ │ │
|
||||
│ ┌──────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ GraphMemory Module (NEW) │ │
|
||||
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │
|
||||
│ │ │ GraphMemoryTool │ │ GraphDatabase │ │ MemoryService │ │ │
|
||||
│ │ │ (Tool Interface)│ │ (SQLite Graph) │ │ (LLM Integration)│ │ │
|
||||
│ │ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ │
|
||||
│ │ │ │ │ │ │
|
||||
│ │ └────────────────────┼────────────────────┘ │ │
|
||||
│ │ ▼ │ │
|
||||
│ │ ┌─────────────────────┐ │ │
|
||||
│ │ │ GraphMemoryStore │ │ │
|
||||
│ │ │ (In-Memory Cache) │ │ │
|
||||
│ │ └─────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 模块职责
|
||||
|
||||
| 模块 | 职责 | 位置 |
|
||||
|------|------|------|
|
||||
| `GraphMemoryTool` | WaterFlow Tool 接口,暴露记忆能力 | `runtime/core/tools/builtin/graph_memory/` |
|
||||
| `GraphDatabase` | SQLite 图数据库实现 | `runtime/core/graph_memory/database/` |
|
||||
| `MemoryService` | 封装业务逻辑 | `runtime/core/graph_memory/service/` |
|
||||
| `GraphMemoryStore` | 内存缓存,加速查询 | `runtime/core/graph_memory/store/` |
|
||||
| `SystemPrompt` | 提示词模板管理 | `runtime/core/graph_memory/prompts/` |
|
||||
|
||||
---
|
||||
|
||||
## 三、目录结构
|
||||
|
||||
### 3.1 新增目录
|
||||
|
||||
```
|
||||
WaterFlow/ts/src/
|
||||
├── runtime/core/
|
||||
│ ├── graph_memory/ # 新增: 图记忆模块
|
||||
│ │ ├── index.ts # 模块导出
|
||||
│ │ ├── types.ts # 类型定义
|
||||
│ │ ├── database/ # 图数据库实现
|
||||
│ │ │ ├── index.ts
|
||||
│ │ │ ├── graph_database.ts # 主类
|
||||
│ │ │ ├── entity_store.ts # 实体存储
|
||||
│ │ │ └── relation_store.ts # 关系存储
|
||||
│ │ ├── service/ # 服务层
|
||||
│ │ │ ├── index.ts
|
||||
│ │ │ ├── memory_service.ts # 记忆服务
|
||||
│ │ │ ├── recall_service.ts # 检索服务
|
||||
│ │ │ └── task_service.ts # 任务服务
|
||||
│ │ ├── store/ # 缓存层
|
||||
│ │ │ ├── index.ts
|
||||
│ │ │ └── memory_cache.ts
|
||||
│ │ └── prompts/ # 提示词
|
||||
│ │ └── system_prompt.ts
|
||||
│ │
|
||||
│ └── tools/builtin/
|
||||
│ └── graph_memory/ # GraphMemory Tool
|
||||
│ ├── index.ts
|
||||
│ ├── graph_memory_tool.ts # Tool 实现
|
||||
│ ├── types.ts # Tool 参数类型
|
||||
│ └── tool_registry.ts # 自动注册
|
||||
```
|
||||
|
||||
### 3.2 修改文件
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|----------|
|
||||
| `runtime/core/tools/builtin/index.ts` | 注册 GraphMemoryTool |
|
||||
| `shared/types/index.ts` | 导出图记忆类型 |
|
||||
|
||||
---
|
||||
|
||||
## 四、核心类型定义
|
||||
|
||||
### 4.1 图数据库类型
|
||||
|
||||
```typescript
|
||||
// src/runtime/core/graph_memory/types.ts
|
||||
|
||||
export interface Entity {
|
||||
id: string;
|
||||
name: string;
|
||||
type: string;
|
||||
mentionCount: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export interface Relation {
|
||||
id: string;
|
||||
sourceId: string;
|
||||
targetId: string;
|
||||
relationType: string;
|
||||
confidence: number;
|
||||
status: RelationStatus;
|
||||
sessionId: string;
|
||||
turnId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
dateBucket: string;
|
||||
}
|
||||
|
||||
export type RelationStatus = 'active' | 'deleted' | 'archived' | 'superseded';
|
||||
|
||||
export interface Triplet {
|
||||
subject: string;
|
||||
relation: string;
|
||||
object: string;
|
||||
confidence?: number;
|
||||
}
|
||||
|
||||
export interface RecallParams {
|
||||
queryIntent: string;
|
||||
seedEntities?: string[];
|
||||
depth?: number;
|
||||
timeRange?: { days: number };
|
||||
sessionFilter?: string;
|
||||
}
|
||||
|
||||
export interface CommitParams {
|
||||
triplets: Triplet[];
|
||||
entityTypes?: Record<string, string>;
|
||||
temporalTag?: string;
|
||||
sessionId?: string;
|
||||
turnId?: number;
|
||||
}
|
||||
|
||||
export interface PurgeParams {
|
||||
criteria: {
|
||||
subject?: string;
|
||||
target?: string;
|
||||
relation?: string;
|
||||
sessionId?: string;
|
||||
};
|
||||
mode?: 'soft' | 'hard' | 'supersede';
|
||||
newRelation?: { relation: string; target: string };
|
||||
}
|
||||
|
||||
export type TaskState = '进行中' | '已完成' | '已暂停' | '已取消';
|
||||
|
||||
export interface MemoryStats {
|
||||
entityCount: number;
|
||||
relationCount: number;
|
||||
sessionId?: string;
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 Tool 参数类型
|
||||
|
||||
```typescript
|
||||
// src/runtime/core/tools/builtin/graph_memory/types.ts
|
||||
|
||||
export type GraphMemoryAction =
|
||||
| 'recall' | 'commit' | 'purge' | 'introspect' | 'archive' | 'cleanup'
|
||||
| 'persona_update' | 'persona_clear'
|
||||
| 'task_create' | 'task_set_state' | 'task_delete' | 'task_link_info';
|
||||
|
||||
export interface GraphMemoryToolInput {
|
||||
action: GraphMemoryAction;
|
||||
params: Record<string, unknown>;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、核心实现
|
||||
|
||||
### 5.1 GraphDatabase 实现
|
||||
|
||||
```typescript
|
||||
// src/runtime/core/graph_memory/database/graph_database.ts
|
||||
|
||||
export class GraphDatabase {
|
||||
private db: Database;
|
||||
|
||||
constructor(dbPath: string) {
|
||||
this.db = new Database(dbPath);
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
private initialize(): void {
|
||||
this.db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS entities (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
type TEXT,
|
||||
mention_count INTEGER DEFAULT 1,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`);
|
||||
|
||||
this.db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS relations (
|
||||
id TEXT PRIMARY KEY,
|
||||
source_id TEXT NOT NULL,
|
||||
target_id TEXT NOT NULL,
|
||||
relation_type TEXT NOT NULL,
|
||||
confidence REAL DEFAULT 1.0,
|
||||
status TEXT DEFAULT 'active',
|
||||
session_id TEXT,
|
||||
turn_id INTEGER,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
date_bucket TEXT
|
||||
)
|
||||
`);
|
||||
|
||||
// 索引
|
||||
this.db.exec(`
|
||||
CREATE INDEX IF NOT EXISTS idx_entity_name ON entities(name);
|
||||
CREATE INDEX IF NOT EXISTS idx_relation_status ON relations(status);
|
||||
`);
|
||||
}
|
||||
|
||||
async recall(params: RecallParams): Promise<RecallResult> {
|
||||
const { queryIntent, seedEntities, sessionFilter } = params;
|
||||
const keywords = queryIntent.split(/[,\s]+/).filter(k => k.length > 0);
|
||||
const entities: Entity[] = [];
|
||||
const relations: Relation[] = [];
|
||||
const entityIds = new Set<string>();
|
||||
|
||||
// 搜索实体
|
||||
for (const keyword of keywords) {
|
||||
const rows = this.db.exec(
|
||||
`SELECT * FROM entities WHERE LOWER(name) LIKE ? LIMIT 50`,
|
||||
[`%${keyword.toLowerCase()}%`]
|
||||
);
|
||||
for (const row of rows) {
|
||||
if (!entityIds.has(row.id)) {
|
||||
entityIds.add(row.id);
|
||||
entities.push(this.rowToEntity(row));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索关系
|
||||
if (entityIds.size > 0) {
|
||||
const placeholders = Array.from(entityIds).map(() => '?').join(',');
|
||||
let query = `
|
||||
SELECT r.*, e1.name as source_name, e2.name as target_name
|
||||
FROM relations r
|
||||
JOIN entities e1 ON r.source_id = e1.id
|
||||
JOIN entities e2 ON r.target_id = e2.id
|
||||
WHERE (r.source_id IN (${placeholders}) OR r.target_id IN (${placeholders}))
|
||||
AND r.status = 'active'
|
||||
`;
|
||||
const queryParams = [...entityIds, ...entityIds];
|
||||
|
||||
if (sessionFilter) {
|
||||
query += ` AND r.session_id = ?`;
|
||||
queryParams.push(sessionFilter);
|
||||
}
|
||||
|
||||
const rows = this.db.exec(query, queryParams);
|
||||
for (const row of rows) {
|
||||
relations.push(this.rowToRelation(row));
|
||||
}
|
||||
}
|
||||
|
||||
return { entities, relations, message: `找到 ${entities.length} 个实体, ${relations.length} 条关系` };
|
||||
}
|
||||
|
||||
async commit(params: CommitParams): Promise<{ createdEntities: number; createdRelations: number }> {
|
||||
const { triplets, sessionId, turnId } = params;
|
||||
let createdEntities = 0;
|
||||
let createdRelations = 0;
|
||||
|
||||
for (const triplet of triplets) {
|
||||
const sourceId = this.upsertEntity(triplet.subject);
|
||||
const targetId = this.upsertEntity(triplet.object);
|
||||
|
||||
this.db.exec(`
|
||||
INSERT INTO relations (id, source_id, target_id, relation_type, confidence, session_id, turn_id, status)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, 'active')
|
||||
`, [this.generateId(), sourceId, targetId, triplet.relation, triplet.confidence || 1.0, sessionId, turnId || 0]);
|
||||
|
||||
createdEntities += 2;
|
||||
createdRelations++;
|
||||
}
|
||||
|
||||
return { createdEntities, createdRelations };
|
||||
}
|
||||
|
||||
async purge(params: PurgeParams): Promise<{ deleted: number; mode: string }> {
|
||||
const { criteria, mode = 'soft' } = params;
|
||||
const conditions: string[] = ['status = ?'];
|
||||
const values: unknown[] = ['active'];
|
||||
|
||||
if (criteria.subject) {
|
||||
conditions.push(`source_id IN (SELECT id FROM entities WHERE name = ?)`);
|
||||
values.push(criteria.subject);
|
||||
}
|
||||
|
||||
const whereClause = conditions.join(' AND ');
|
||||
const result = this.db.exec(`UPDATE relations SET status = 'deleted' WHERE ${whereClause}`, values);
|
||||
|
||||
return { deleted: result.length, mode };
|
||||
}
|
||||
|
||||
async introspect(): Promise<MemoryStats> {
|
||||
const entityCount = this.db.exec(`SELECT COUNT(*) as c FROM entities`)[0]?.c || 0;
|
||||
const relationCount = this.db.exec(`SELECT COUNT(*) as c FROM relations WHERE status = 'active'`)[0]?.c || 0;
|
||||
return { entityCount, relationCount };
|
||||
}
|
||||
|
||||
private upsertEntity(name: string): string {
|
||||
const existing = this.db.exec(`SELECT id FROM entities WHERE name = ?`, [name]);
|
||||
if (existing.length > 0) {
|
||||
this.db.exec(`UPDATE entities SET mention_count = mention_count + 1 WHERE name = ?`, [name]);
|
||||
return existing[0].id;
|
||||
}
|
||||
const id = this.generateId();
|
||||
this.db.exec(`INSERT INTO entities (id, name, type) VALUES (?, ?, ?)`, [id, name, 'unknown']);
|
||||
return id;
|
||||
}
|
||||
|
||||
private generateId(): string {
|
||||
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||||
}
|
||||
|
||||
private rowToEntity(row: any): Entity {
|
||||
return {
|
||||
id: row.id, name: row.name, type: row.type || 'unknown',
|
||||
mentionCount: row.mention_count || 1,
|
||||
createdAt: new Date(row.created_at), updatedAt: new Date(row.updated_at)
|
||||
};
|
||||
}
|
||||
|
||||
private rowToRelation(row: any): Relation {
|
||||
return {
|
||||
id: row.id, sourceId: row.source_id, targetId: row.target_id,
|
||||
relationType: row.relation_type, confidence: row.confidence || 1.0,
|
||||
status: row.status || 'active', sessionId: row.session_id || '',
|
||||
turnId: row.turn_id || 0,
|
||||
createdAt: new Date(row.created_at), updatedAt: new Date(row.updated_at),
|
||||
dateBucket: row.date_bucket || ''
|
||||
};
|
||||
}
|
||||
|
||||
close(): void { this.db.close(); }
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 GraphMemoryTool 实现
|
||||
|
||||
```typescript
|
||||
// src/runtime/core/tools/builtin/graph_memory/graph_memory_tool.ts
|
||||
|
||||
import type { Tool, ToolExecutionContext, ToolInputSchema } from '../tool_interface';
|
||||
import { GraphDatabase } from '../../../graph_memory/database/graph_database';
|
||||
import { MemoryService } from '../../../graph_memory/service/memory_service';
|
||||
|
||||
export class GraphMemoryTool implements Tool {
|
||||
readonly id = 'builtin:graph_memory';
|
||||
readonly name = 'GraphMemory';
|
||||
readonly description = `图记忆工具 - 让 AI 拥有真正的长期记忆能力
|
||||
|
||||
操作:
|
||||
- recall: 检索记忆
|
||||
- commit: 写入记忆
|
||||
- purge: 删除记忆
|
||||
- introspect: 查看状态
|
||||
- persona_update/clear: 人设管理
|
||||
- task_create/set_state/delete: 任务管理`;
|
||||
|
||||
readonly category = 'analysis';
|
||||
readonly permissionLevel: 'safe' = 'safe';
|
||||
readonly inputSchema: ToolInputSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
action: {
|
||||
type: 'string',
|
||||
enum: ['recall', 'commit', 'purge', 'introspect', 'persona_update', 'persona_clear',
|
||||
'task_create', 'task_set_state', 'task_delete', 'task_link_info'],
|
||||
description: '记忆操作类型'
|
||||
},
|
||||
params: { type: 'object', description: '操作参数' }
|
||||
},
|
||||
required: ['action', 'params']
|
||||
};
|
||||
|
||||
private db: GraphDatabase;
|
||||
private service: MemoryService;
|
||||
|
||||
constructor(config: { dbPath: string; sessionId?: string }) {
|
||||
this.db = new GraphDatabase(config.dbPath);
|
||||
this.service = new MemoryService(this.db, config.sessionId);
|
||||
}
|
||||
|
||||
async handler(params: Record<string, unknown>, context: ToolExecutionContext): Promise<string> {
|
||||
const action = params.action as string;
|
||||
const actionParams = params.params as Record<string, unknown>;
|
||||
|
||||
try {
|
||||
const result = await this.executeAction(action, actionParams);
|
||||
return JSON.stringify({ success: true, data: result }, null, 2);
|
||||
} catch (error) {
|
||||
return JSON.stringify({
|
||||
success: false,
|
||||
error: { type: 'execution_error', message: error instanceof Error ? error.message : String(error) }
|
||||
}, null, 2);
|
||||
}
|
||||
}
|
||||
|
||||
private async executeAction(action: string, params: Record<string, unknown>): Promise<unknown> {
|
||||
switch (action) {
|
||||
case 'recall': return this.service.recall(params as any);
|
||||
case 'commit': return this.service.commit(params as any);
|
||||
case 'purge': return this.service.purge(params as any);
|
||||
case 'introspect': return this.service.introspect();
|
||||
case 'persona_update': return this.service.updatePersona(params);
|
||||
case 'persona_clear': return this.service.clearPersona(params);
|
||||
case 'task_create': return this.service.createTask(params);
|
||||
case 'task_set_state': return this.service.setTaskState(params);
|
||||
case 'task_delete': return this.service.deleteTask(params);
|
||||
default: throw new Error(`Unknown action: ${action}`);
|
||||
}
|
||||
}
|
||||
|
||||
close(): void { this.db.close(); }
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 MemoryService 实现
|
||||
|
||||
```typescript
|
||||
// src/runtime/core/graph_memory/service/memory_service.ts
|
||||
|
||||
import { GraphDatabase } from '../database/graph_database';
|
||||
import type { RecallParams, CommitParams, PurgeParams } from '../types';
|
||||
|
||||
export class MemoryService {
|
||||
private db: GraphDatabase;
|
||||
private sessionId: string;
|
||||
|
||||
constructor(db: GraphDatabase, sessionId?: string) {
|
||||
this.db = db;
|
||||
this.sessionId = sessionId || `session-${Date.now()}`;
|
||||
}
|
||||
|
||||
async recall(params: RecallParams) {
|
||||
return this.db.recall({ ...params, sessionFilter: params.sessionFilter || this.sessionId });
|
||||
}
|
||||
|
||||
async commit(params: CommitParams) {
|
||||
return this.db.commit({ ...params, sessionId: params.sessionId || this.sessionId });
|
||||
}
|
||||
|
||||
async purge(params: PurgeParams) {
|
||||
return this.db.purge(params);
|
||||
}
|
||||
|
||||
async introspect() {
|
||||
const stats = await this.db.introspect();
|
||||
return { ...stats, sessionId: this.sessionId };
|
||||
}
|
||||
|
||||
async updatePersona(params: Record<string, unknown>) {
|
||||
const attributes = params.attributes as Array<{ attribute: string; value: string }>;
|
||||
const mode = params.mode as string || 'merge';
|
||||
|
||||
if (mode === 'replace') {
|
||||
await this.db.purge({ criteria: { subject: 'AI' }, mode: 'soft' });
|
||||
}
|
||||
|
||||
const triplets = attributes.map(attr => ({
|
||||
subject: 'AI', relation: attr.attribute, object: attr.value, confidence: 1.0
|
||||
}));
|
||||
|
||||
await this.commit({ triplets });
|
||||
return { status: 'success', updatedAttributes: attributes.length };
|
||||
}
|
||||
|
||||
async clearPersona(params: Record<string, unknown>) {
|
||||
if (params.confirm === false) return { status: 'cancelled', deletedCount: 0 };
|
||||
const result = await this.purge({ criteria: { subject: 'AI' }, mode: 'soft' });
|
||||
return { status: 'success', deletedCount: result.deleted };
|
||||
}
|
||||
|
||||
async createTask(params: Record<string, unknown>) {
|
||||
const taskId = params.task_id as string;
|
||||
const description = params.description as string;
|
||||
const infoNodes = (params.info_nodes as string[]) || [];
|
||||
|
||||
await this.commit({
|
||||
triplets: [
|
||||
{ subject: taskId, relation: 'is_type', object: 'TaskNode' },
|
||||
{ subject: taskId, relation: 'has_description', object: description },
|
||||
{ subject: taskId, relation: 'HAS_STATE', object: 'State_进行中' }
|
||||
]
|
||||
});
|
||||
|
||||
if (infoNodes.length > 0) {
|
||||
await this.commit({
|
||||
triplets: infoNodes.map(node => ({ subject: taskId, relation: 'CONTAINS_INFO', object: node }))
|
||||
});
|
||||
}
|
||||
|
||||
return { status: 'success', taskId };
|
||||
}
|
||||
|
||||
async setTaskState(params: Record<string, unknown>) {
|
||||
const taskId = params.task_id as string;
|
||||
const state = params.state as string;
|
||||
|
||||
await this.purge({ criteria: { subject: taskId, relation: 'HAS_STATE' }, mode: 'soft' });
|
||||
await this.commit({ triplets: [{ subject: taskId, relation: 'HAS_STATE', object: `State_${state}` }] });
|
||||
|
||||
return { status: 'success', newState: state };
|
||||
}
|
||||
|
||||
async deleteTask(params: Record<string, unknown>) {
|
||||
const taskId = params.task_id as string;
|
||||
await this.purge({ criteria: { subject: taskId }, mode: 'soft' });
|
||||
return { status: 'success', taskId };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、测试方案
|
||||
|
||||
### 6.1 测试文件结构
|
||||
|
||||
```
|
||||
WaterFlow/ts/tests/
|
||||
├── runtime/core/graph_memory/
|
||||
│ ├── database/
|
||||
│ │ └── graph_database.test.ts # 15+ 测试
|
||||
│ └── service/
|
||||
│ └── memory_service.test.ts # 12+ 测试
|
||||
└── runtime/core/tools/builtin/
|
||||
└── graph_memory/
|
||||
└── graph_memory_tool.test.ts # 15+ 测试
|
||||
```
|
||||
|
||||
### 6.2 数据库测试
|
||||
|
||||
```typescript
|
||||
// tests/runtime/core/graph_memory/database/graph_database.test.ts
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { GraphDatabase } from '../../../../../src/runtime/core/graph_memory/database/graph_database';
|
||||
import * as fs from 'fs';
|
||||
|
||||
describe('GraphDatabase', () => {
|
||||
const testDbPath = '/tmp/test_graph_memory.db';
|
||||
let db: GraphDatabase;
|
||||
|
||||
beforeEach(() => {
|
||||
if (fs.existsSync(testDbPath)) fs.unlinkSync(testDbPath);
|
||||
db = new GraphDatabase(testDbPath);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
db.close();
|
||||
if (fs.existsSync(testDbPath)) fs.unlinkSync(testDbPath);
|
||||
});
|
||||
|
||||
describe('commit', () => {
|
||||
it('should create entities and relations', async () => {
|
||||
const result = await db.commit({
|
||||
triplets: [
|
||||
{ subject: '用户', relation: '喜欢', object: 'Python' },
|
||||
{ subject: '用户', relation: '正在学习', object: 'TypeScript' }
|
||||
]
|
||||
});
|
||||
expect(result.createdEntities).toBe(3);
|
||||
expect(result.createdRelations).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('recall', () => {
|
||||
beforeEach(async () => {
|
||||
await db.commit({
|
||||
triplets: [
|
||||
{ subject: '用户', relation: '喜欢', object: 'Python' },
|
||||
{ subject: 'Python', relation: '是', object: '编程语言' }
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
it('should recall by keyword', async () => {
|
||||
const result = await db.recall({ queryIntent: 'Python' });
|
||||
expect(result.entities.some(e => e.name === 'Python')).toBe(true);
|
||||
});
|
||||
|
||||
it('should recall relations', async () => {
|
||||
const result = await db.recall({ queryIntent: '用户,Python' });
|
||||
expect(result.relations.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('purge', () => {
|
||||
beforeEach(async () => {
|
||||
await db.commit({
|
||||
triplets: [{ subject: '旧信息', relation: 'is', object: '垃圾' }]
|
||||
});
|
||||
});
|
||||
|
||||
it('should soft delete relations', async () => {
|
||||
const result = await db.purge({ criteria: { subject: '旧信息' }, mode: 'soft' });
|
||||
expect(result.deleted).toBeGreaterThan(0);
|
||||
expect(result.mode).toBe('soft');
|
||||
});
|
||||
});
|
||||
|
||||
describe('introspect', () => {
|
||||
it('should return statistics', async () => {
|
||||
await db.commit({ triplets: [{ subject: 'A', relation: 'relates', object: 'B' }] });
|
||||
const stats = await db.introspect();
|
||||
expect(stats.entityCount).toBe(2);
|
||||
expect(stats.relationCount).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 6.3 服务层测试
|
||||
|
||||
```typescript
|
||||
// tests/runtime/core/graph_memory/service/memory_service.test.ts
|
||||
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { MemoryService } from '../../../../../src/runtime/core/graph_memory/service/memory_service';
|
||||
import { GraphDatabase } from '../../../../../src/runtime/core/graph_memory/database/graph_database';
|
||||
|
||||
describe('MemoryService', () => {
|
||||
const testDbPath = '/tmp/test_memory_service.db';
|
||||
let db: GraphDatabase;
|
||||
let service: MemoryService;
|
||||
|
||||
beforeEach(() => {
|
||||
db = new GraphDatabase(testDbPath);
|
||||
service = new MemoryService(db, 'test-session');
|
||||
});
|
||||
|
||||
describe('persona management', () => {
|
||||
it('should update persona', async () => {
|
||||
const result = await service.updatePersona({
|
||||
attributes: [{ attribute: '角色', value: '猫娘' }],
|
||||
mode: 'replace'
|
||||
});
|
||||
expect(result.status).toBe('success');
|
||||
expect(result.updatedAttributes).toBe(1);
|
||||
});
|
||||
|
||||
it('should clear persona', async () => {
|
||||
await service.updatePersona({ attributes: [{ attribute: '角色', value: '猫娘' }] });
|
||||
const result = await service.clearPersona({ confirm: true });
|
||||
expect(result.status).toBe('success');
|
||||
});
|
||||
});
|
||||
|
||||
describe('task management', () => {
|
||||
it('should create task', async () => {
|
||||
const result = await service.createTask({
|
||||
task_id: 'Task_Test',
|
||||
description: '测试任务',
|
||||
info_nodes: ['info1']
|
||||
});
|
||||
expect(result.taskId).toBe('Task_Test');
|
||||
});
|
||||
|
||||
it('should set task state', async () => {
|
||||
await service.createTask({ task_id: 'Task_State', description: '测试' });
|
||||
const result = await service.setTaskState({ task_id: 'Task_State', state: '已完成' });
|
||||
expect(result.newState).toBe('已完成');
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 6.4 Tool 接口测试
|
||||
|
||||
```typescript
|
||||
// tests/runtime/core/tools/builtin/graph_memory/graph_memory_tool.test.ts
|
||||
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { GraphMemoryTool } from '../../../../../src/runtime/core/tools/builtin/graph_memory/graph_memory_tool';
|
||||
import * as fs from 'fs';
|
||||
|
||||
describe('GraphMemoryTool', () => {
|
||||
const testDbPath = '/tmp/test_graph_memory_tool.db';
|
||||
let tool: GraphMemoryTool;
|
||||
|
||||
beforeEach(() => {
|
||||
if (fs.existsSync(testDbPath)) fs.unlinkSync(testDbPath);
|
||||
tool = new GraphMemoryTool({ dbPath: testDbPath, sessionId: 'test' });
|
||||
});
|
||||
|
||||
it('should have correct metadata', () => {
|
||||
expect(tool.id).toBe('builtin:graph_memory');
|
||||
expect(tool.name).toBe('GraphMemory');
|
||||
expect(tool.category).toBe('analysis');
|
||||
});
|
||||
|
||||
describe('recall', () => {
|
||||
it('should execute recall', async () => {
|
||||
await tool.handler({ action: 'commit', params: { triplets: [{ subject: 'Test', relation: 't', object: 'D' }] } }, mockContext());
|
||||
const result = await tool.handler({ action: 'recall', params: { query_intent: 'Test' } }, mockContext());
|
||||
const parsed = JSON.parse(result);
|
||||
expect(parsed.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('commit', () => {
|
||||
it('should execute commit', async () => {
|
||||
const result = await tool.handler({
|
||||
action: 'commit',
|
||||
params: { triplets: [{ subject: '用户', relation: '喜欢', object: 'AI' }] }
|
||||
}, mockContext());
|
||||
const parsed = JSON.parse(result);
|
||||
expect(parsed.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('error handling', () => {
|
||||
it('should return error for unknown action', async () => {
|
||||
const result = await tool.handler({ action: 'unknown', params: {} }, mockContext());
|
||||
const parsed = JSON.parse(result);
|
||||
expect(parsed.success).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function mockContext() {
|
||||
return {
|
||||
toolCallId: 'test', workingDirectory: '/tmp', abortController: { signal: {} },
|
||||
config: { timeout: 5000 }, logger: { info: () => {}, warn: () => {}, error: () => {}, debug: () => {} }
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 6.5 验证检查清单
|
||||
|
||||
```
|
||||
[ ] GraphDatabase.commit - 创建实体和关系
|
||||
[ ] GraphDatabase.recall - 按关键词检索
|
||||
[ ] GraphDatabase.purge - 软删除
|
||||
[ ] GraphDatabase.introspect - 返回统计
|
||||
|
||||
[ ] MemoryService.updatePersona - 人设更新
|
||||
[ ] MemoryService.clearPersona - 人设清除
|
||||
[ ] MemoryService.createTask - 创建任务
|
||||
[ ] MemoryService.setTaskState - 设置状态
|
||||
[ ] MemoryService.deleteTask - 删除任务
|
||||
|
||||
[ ] GraphMemoryTool recall action
|
||||
[ ] GraphMemoryTool commit action
|
||||
[ ] GraphMemoryTool persona_update action
|
||||
[ ] GraphMemoryTool task_create action
|
||||
[ ] GraphMemoryTool error handling
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、实现计划
|
||||
|
||||
| Phase | 任务 | 周期 | 测试 |
|
||||
|-------|------|------|------|
|
||||
| 1 | GraphDatabase 实现 | 2-3 天 | 15+ |
|
||||
| 2 | MemoryService 实现 | 1-2 天 | 12+ |
|
||||
| 3 | GraphMemoryTool 实现 | 1-2 天 | 15+ |
|
||||
| 4 | 集成测试 | 1 天 | 8+ |
|
||||
|
||||
**总计**: 5-8 天,50+ 测试用例
|
||||
@ -3,7 +3,7 @@ name: graph_memory
|
||||
description: 图记忆工具 - 让 AI 拥有真正的长期记忆能力
|
||||
when_to_use: 需要 AI 记住、回忆、管理信息或任务时
|
||||
context: inline
|
||||
allowed_tools:
|
||||
allowed-tools:
|
||||
- builtin:graph_memory
|
||||
arguments:
|
||||
- name: action
|
||||
@ -15,7 +15,7 @@ arguments:
|
||||
type: object
|
||||
required: true
|
||||
description: 操作参数
|
||||
user_invocable: true
|
||||
user-invocable: true
|
||||
---
|
||||
|
||||
# GraphMemory 图记忆操作
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: graph_memory_persona
|
||||
name: persona
|
||||
description: 管理 AI 人设 - 更新或清除 AI 角色特征
|
||||
when_to_use: 需要修改 AI 的角色设定或清除人设时
|
||||
context: inline
|
||||
allowed_tools:
|
||||
allowed-tools:
|
||||
- builtin:graph_memory
|
||||
arguments:
|
||||
- name: action
|
||||
@ -22,7 +22,7 @@ arguments:
|
||||
- name: confirm
|
||||
type: boolean
|
||||
description: 确认清除 (用于 clear)
|
||||
user_invocable: true
|
||||
user-invocable: true
|
||||
---
|
||||
|
||||
# GraphMemory Persona 人设管理
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
---
|
||||
name: graph_memory_task
|
||||
name: task
|
||||
description: 管理连续性任务 - 创建、更新、删除任务节点
|
||||
when_to_use: 需要创建或管理长期任务时
|
||||
context: inline
|
||||
allowed_tools:
|
||||
allowed-tools:
|
||||
- builtin:graph_memory
|
||||
arguments:
|
||||
- name: action
|
||||
@ -28,7 +28,7 @@ arguments:
|
||||
- name: info_node
|
||||
type: string
|
||||
description: 信息节点 (用于 link_info)
|
||||
user_invocable: true
|
||||
user-invocable: true
|
||||
---
|
||||
|
||||
# GraphMemory Task 任务管理
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import initSqlJs, { type Database as SqlJsDatabase } from 'sql.js';
|
||||
import type { Platform } from 'waterflow/platform/types';
|
||||
import type { Entity, Relation, RecallParams, CommitParams, PurgeParams, RecallResult, CommitResult, PurgeResult, MemoryStats } from './types';
|
||||
import { getConfig } from './config';
|
||||
|
||||
@ -6,7 +7,7 @@ export class GraphDatabase {
|
||||
private db: SqlJsDatabase | null = null;
|
||||
private sessionId: string;
|
||||
private initPromise: Promise<void> | null = null;
|
||||
private _platform: any = null;
|
||||
private _platform: Platform | null = null;
|
||||
|
||||
constructor(sessionId?: string) {
|
||||
this.sessionId = sessionId || `session-${Date.now()}`;
|
||||
@ -20,10 +21,15 @@ export class GraphDatabase {
|
||||
|
||||
try {
|
||||
const dbPath = this._platform.path.join(this._platform.getCwd(), getConfig().dbPath);
|
||||
const exists = await this._platform.fs.exists(dbPath);
|
||||
if (exists) {
|
||||
const data = await this._platform.fs.readFile(dbPath, { encoding: 'binary' });
|
||||
this.db = new SQL.Database(data as Uint8Array);
|
||||
const fs = this._platform.fs;
|
||||
if (fs) {
|
||||
const exists = await fs.exists(dbPath);
|
||||
if (exists) {
|
||||
const data = await fs.readFile(dbPath, { encoding: 'binary' });
|
||||
this.db = new SQL.Database(new Uint8Array(data as ArrayBuffer));
|
||||
} else {
|
||||
this.db = new SQL.Database();
|
||||
}
|
||||
} else {
|
||||
this.db = new SQL.Database();
|
||||
}
|
||||
@ -39,16 +45,18 @@ export class GraphDatabase {
|
||||
|
||||
try {
|
||||
const platform = this._platform;
|
||||
const fs = platform.fs;
|
||||
if (!fs) return;
|
||||
const dbPath = platform.path.join(platform.getCwd(), getConfig().dbPath);
|
||||
const dir = platform.path.dirname(dbPath);
|
||||
const dirExists = await platform.fs.exists(dir);
|
||||
const dirExists = await fs.exists(dir);
|
||||
if (!dirExists) {
|
||||
await platform.fs.mkdir(dir, true);
|
||||
await fs.mkdir(dir, true);
|
||||
}
|
||||
const data = this.db.export();
|
||||
await platform.fs.writeFile(dbPath, new Uint8Array(data), { encoding: 'binary' });
|
||||
await fs.writeFile(dbPath, data.buffer as ArrayBuffer, { encoding: 'binary' });
|
||||
} catch (error) {
|
||||
this._platform.getLogger().error(`[GraphDatabase] Save failed: ${error}`);
|
||||
console.error(`[GraphDatabase] Save failed: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -102,6 +102,10 @@ export class GraphMemoryTool implements Tool {
|
||||
}
|
||||
|
||||
async handler(params: ToolInput, context: ToolExecutionContext): Promise<ToolOutput> {
|
||||
if (context.abortController?.signal?.aborted) {
|
||||
throw new Error('Operation aborted');
|
||||
}
|
||||
|
||||
const action = params.action as string;
|
||||
const actionParams = params.params as Record<string, unknown>;
|
||||
const logger = context?.logger;
|
||||
|
||||
@ -11,8 +11,8 @@ export function registerGraphMemoryTool(
|
||||
registry.register(createGraphMemoryTool(sessionId));
|
||||
}
|
||||
|
||||
export function installTrulyMEM(platform: Platform, sessionId?: string) {
|
||||
const { initializeToolRegistry } = require('waterflow/runtime/core/tools/builtin');
|
||||
export async function installTrulyMEM(platform: Platform, sessionId?: string) {
|
||||
const { initializeToolRegistry } = await import('waterflow/runtime/core/tools/builtin');
|
||||
const registry = initializeToolRegistry(platform);
|
||||
registerGraphMemoryTool(registry, sessionId);
|
||||
return registry;
|
||||
|
||||
650
ts/src/types/waterflow.d.ts
vendored
650
ts/src/types/waterflow.d.ts
vendored
@ -1,12 +1,25 @@
|
||||
declare module 'waterflow/platform' {
|
||||
import type { Platform } from 'waterflow/platform/types';
|
||||
import type { Platform, CreatePlatformOptions, PlatformCapabilities } from 'waterflow/platform/types';
|
||||
export function getPlatform(): Platform;
|
||||
export function hasCapability(capability: string): boolean;
|
||||
export function initPlatform(options?: any): Platform;
|
||||
export function hasCapability(capability: keyof PlatformCapabilities): boolean;
|
||||
export function initPlatform(options?: CreatePlatformOptions): Platform;
|
||||
export function resetPlatform(): void;
|
||||
}
|
||||
|
||||
declare module 'waterflow/platform/types' {
|
||||
export type BufferSource = ArrayBuffer | ArrayBufferView;
|
||||
export type RuntimeType = 'node' | 'web' | 'harmony' | 'unknown';
|
||||
export type OSType = 'windows' | 'macos' | 'linux' | 'android' | 'ios' | 'harmony' | 'unknown';
|
||||
|
||||
export interface PlatformCapabilities {
|
||||
fileSystem: boolean;
|
||||
processExecution: boolean;
|
||||
network: boolean;
|
||||
storage: boolean;
|
||||
webSocket: boolean;
|
||||
workers: boolean;
|
||||
}
|
||||
|
||||
export interface PlatformAbortSignal {
|
||||
readonly aborted: boolean;
|
||||
readonly reason?: unknown;
|
||||
@ -19,26 +32,107 @@ declare module 'waterflow/platform/types' {
|
||||
abort(reason?: unknown): void;
|
||||
}
|
||||
|
||||
export interface PathOperations {
|
||||
join(...paths: string[]): string;
|
||||
dirname(p: string): string;
|
||||
basename(p: string, ext?: string): string;
|
||||
extname(p: string): string;
|
||||
normalize(p: string): string;
|
||||
isAbsolute(p: string): boolean;
|
||||
resolve(...paths: string[]): string;
|
||||
relative(from: string, to: string): string;
|
||||
export interface PlatformTextEncoder {
|
||||
encode(input?: string): Uint8Array;
|
||||
encodeInto(src: string, dest: Uint8Array): { read: number; written: number };
|
||||
}
|
||||
|
||||
export interface FileReadOptions {
|
||||
encoding?: 'utf-8' | 'binary';
|
||||
start?: number;
|
||||
end?: number;
|
||||
export interface PlatformTextDecoder {
|
||||
decode(input?: BufferSource): string;
|
||||
}
|
||||
|
||||
export interface FileWriteOptions {
|
||||
encoding?: 'utf-8' | 'binary';
|
||||
append?: boolean;
|
||||
export interface PlatformURL {
|
||||
href: string;
|
||||
origin: string;
|
||||
protocol: string;
|
||||
host: string;
|
||||
hostname: string;
|
||||
port: string;
|
||||
pathname: string;
|
||||
search: string;
|
||||
hash: string;
|
||||
toString(): string;
|
||||
toJSON(): string;
|
||||
}
|
||||
|
||||
export interface PlatformGlobals {
|
||||
TextEncoder: new (encoding?: string) => PlatformTextEncoder;
|
||||
TextDecoder: new (encoding?: string) => PlatformTextDecoder;
|
||||
URL: new (url: string) => { href: string; pathname: string; toString(): string };
|
||||
randomUUID(): string;
|
||||
now(): number;
|
||||
btoa(data: string): string;
|
||||
atob(data: string): string;
|
||||
}
|
||||
|
||||
export interface GlobOptions {
|
||||
cwd?: string;
|
||||
ignore?: string[];
|
||||
absolute?: boolean;
|
||||
dot?: boolean;
|
||||
onlyFiles?: boolean;
|
||||
onlyDirectories?: boolean;
|
||||
deep?: number;
|
||||
ignoreCase?: boolean;
|
||||
}
|
||||
|
||||
export interface GlobResult {
|
||||
path: string;
|
||||
isFile: boolean;
|
||||
isDirectory: boolean;
|
||||
}
|
||||
|
||||
export interface GlobTool {
|
||||
glob(pattern: string, options?: GlobOptions): Promise<string[]>;
|
||||
globWithInfo(pattern: string, options?: GlobOptions): Promise<GlobResult[]>;
|
||||
isMatch(path: string, pattern: string): boolean;
|
||||
search(pattern: string, basePath?: string): Promise<string[]>;
|
||||
}
|
||||
|
||||
export interface GrepOptions {
|
||||
cwd?: string;
|
||||
ignoreCase?: boolean;
|
||||
multiline?: boolean;
|
||||
glob?: string | string[];
|
||||
include?: string[];
|
||||
exclude?: string[];
|
||||
context?: number;
|
||||
beforeContext?: number;
|
||||
afterContext?: number;
|
||||
headLimit?: number;
|
||||
}
|
||||
|
||||
export interface GrepMatch {
|
||||
path: string;
|
||||
line: number;
|
||||
column?: number;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface GrepSearchOptions {
|
||||
pattern: string;
|
||||
path?: string;
|
||||
glob?: string | string[];
|
||||
ignoreCase?: boolean;
|
||||
context?: number;
|
||||
outputMode?: 'content' | 'files_with_matches' | 'count';
|
||||
maxResults?: number;
|
||||
}
|
||||
|
||||
export interface GrepSearchResult {
|
||||
lines: string[];
|
||||
}
|
||||
|
||||
export interface GrepTool {
|
||||
grep(pattern: string | RegExp, options?: GrepOptions): Promise<GrepMatch[]>;
|
||||
grepFiles(pattern: string | RegExp, options?: GrepOptions): Promise<string[]>;
|
||||
grepCount(pattern: string | RegExp, options?: GrepOptions): Promise<number>;
|
||||
search(options: GrepSearchOptions): Promise<GrepSearchResult>;
|
||||
}
|
||||
|
||||
export interface PlatformTools {
|
||||
glob: GlobTool | null;
|
||||
grep: GrepTool | null;
|
||||
}
|
||||
|
||||
export interface FileInfo {
|
||||
@ -47,22 +141,35 @@ declare module 'waterflow/platform/types' {
|
||||
isFile: boolean;
|
||||
isDirectory: boolean;
|
||||
size: number;
|
||||
modifiedTime: number;
|
||||
createdTime: number;
|
||||
modifiedTime?: number;
|
||||
createdTime?: number;
|
||||
}
|
||||
|
||||
export interface FileReadOptions {
|
||||
encoding?: 'utf-8' | 'binary' | 'base64';
|
||||
start?: number;
|
||||
end?: number;
|
||||
}
|
||||
|
||||
export interface FileWriteOptions {
|
||||
encoding?: 'utf-8' | 'binary' | 'base64';
|
||||
append?: boolean;
|
||||
createDir?: boolean;
|
||||
}
|
||||
|
||||
export interface FileSystemOperations {
|
||||
readFile(filePath: string, options?: FileReadOptions): Promise<string | ArrayBuffer>;
|
||||
writeFile(filePath: string, data: string | ArrayBuffer, options?: FileWriteOptions): Promise<void>;
|
||||
appendFile(filePath: string, data: string, options?: FileWriteOptions): Promise<void>;
|
||||
deleteFile(filePath: string): Promise<void>;
|
||||
exists(filePath: string): Promise<boolean>;
|
||||
stat(filePath: string): Promise<FileInfo>;
|
||||
readdir(dirPath: string): Promise<FileInfo[]>;
|
||||
mkdir(dirPath: string, recursive?: boolean): Promise<void>;
|
||||
rmdir(dirPath: string, recursive?: boolean): Promise<void>;
|
||||
readFile(path: string, options?: FileReadOptions): Promise<string | ArrayBuffer>;
|
||||
writeFile(path: string, data: string | ArrayBuffer, options?: FileWriteOptions): Promise<void>;
|
||||
appendFile(path: string, data: string, options?: FileWriteOptions): Promise<void>;
|
||||
deleteFile(path: string): Promise<void>;
|
||||
exists(path: string): Promise<boolean>;
|
||||
stat(path: string): Promise<FileInfo>;
|
||||
readdir(path: string): Promise<FileInfo[]>;
|
||||
mkdir(path: string, recursive?: boolean): Promise<void>;
|
||||
rmdir(path: string, recursive?: boolean): Promise<void>;
|
||||
copy(src: string, dest: string): Promise<void>;
|
||||
move(src: string, dest: string): Promise<void>;
|
||||
watch?(path: string, callback: (event: string, filename: string) => void): () => void;
|
||||
}
|
||||
|
||||
export interface ProcessResult {
|
||||
@ -76,12 +183,17 @@ declare module 'waterflow/platform/types' {
|
||||
cwd?: string;
|
||||
env?: Record<string, string>;
|
||||
timeout?: number;
|
||||
input?: string;
|
||||
shell?: boolean;
|
||||
maxBuffer?: number;
|
||||
}
|
||||
|
||||
export interface ProcessOperations {
|
||||
exec(command: string, options?: ProcessOptions): Promise<ProcessResult>;
|
||||
execFile(file: string, args: string[], options?: ProcessOptions): Promise<ProcessResult>;
|
||||
spawn?(command: string, args: string[], options?: ProcessOptions): AsyncIterable<string>;
|
||||
which?(command: string): Promise<string | null>;
|
||||
kill?(pid: number, signal?: string): Promise<boolean>;
|
||||
}
|
||||
|
||||
export interface StorageOperations {
|
||||
@ -92,85 +204,56 @@ declare module 'waterflow/platform/types' {
|
||||
keys(): Promise<string[]>;
|
||||
}
|
||||
|
||||
export interface PlatformGlobals {
|
||||
TextEncoder: typeof TextEncoder;
|
||||
TextDecoder: typeof TextDecoder;
|
||||
URL: typeof URL;
|
||||
randomUUID(): string;
|
||||
now(): number;
|
||||
btoa(data: string): string;
|
||||
atob(data: string): string;
|
||||
export interface PathOperations {
|
||||
join(...paths: string[]): string;
|
||||
dirname(path: string): string;
|
||||
basename(path: string, ext?: string): string;
|
||||
extname(path: string): string;
|
||||
normalize(path: string): string;
|
||||
isAbsolute(path: string): boolean;
|
||||
resolve(...paths: string[]): string;
|
||||
relative(from: string, to: string): string;
|
||||
}
|
||||
|
||||
export interface Logger {
|
||||
info(msg: string, ...args: unknown[]): void;
|
||||
warn(msg: string, ...args: unknown[]): void;
|
||||
error(msg: string, ...args: unknown[]): void;
|
||||
debug(msg: string, ...args: unknown[]): void;
|
||||
export interface PlatformResponse {
|
||||
status: number;
|
||||
statusText: string;
|
||||
headers: Record<string, string>;
|
||||
ok: boolean;
|
||||
text(): Promise<string>;
|
||||
json(): Promise<any>;
|
||||
arrayBuffer(): Promise<ArrayBuffer>;
|
||||
}
|
||||
|
||||
export interface Platform {
|
||||
readonly path: PathOperations;
|
||||
readonly fs: FileSystemOperations;
|
||||
readonly process: ProcessOperations;
|
||||
readonly storage: StorageOperations;
|
||||
readonly globals: PlatformGlobals;
|
||||
getInfo(): { runtime: string; os: string; version: string; arch: string; hostname: string };
|
||||
createAbortController(): PlatformAbortController;
|
||||
getEnv(key: string): string | undefined;
|
||||
getAllEnv(): Record<string, string>;
|
||||
setEnv(key: string, value: string): void;
|
||||
getCwd(): string;
|
||||
setCwd(p: string): void;
|
||||
exit(code: number): void;
|
||||
getLogger(): Logger;
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'waterflow/runtime/core/tools/tool_interface' {
|
||||
import type { PlatformAbortController, Logger } from 'waterflow/platform/types';
|
||||
|
||||
export type ToolCategory = 'file' | 'code' | 'search' | 'execute' | 'network' | 'analysis' | 'generation' | 'communication' | 'mcp' | 'custom';
|
||||
export type PermissionLevel = 'safe' | 'moderate' | 'dangerous' | 'restricted';
|
||||
export type ToolInput = Record<string, unknown>;
|
||||
export type ToolOutput = string | Record<string, unknown> | void;
|
||||
|
||||
export interface SchemaProperty {
|
||||
type: string;
|
||||
description: string;
|
||||
enum?: string[];
|
||||
minimum?: number;
|
||||
maximum?: number;
|
||||
minLength?: number;
|
||||
maxLength?: number;
|
||||
pattern?: string;
|
||||
default?: unknown;
|
||||
examples?: unknown[];
|
||||
items?: SchemaProperty;
|
||||
properties?: Record<string, SchemaProperty>;
|
||||
export interface PlatformFetchRequestInit {
|
||||
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
|
||||
headers?: Record<string, string>;
|
||||
body?: string | ArrayBuffer | Record<string, string | ArrayBuffer>;
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
export interface ToolInputSchema {
|
||||
type: 'object';
|
||||
properties: Record<string, SchemaProperty>;
|
||||
required?: string[];
|
||||
additionalProperties?: boolean;
|
||||
export interface PlatformWebSocket {
|
||||
readonly readyState: number;
|
||||
readonly url: string;
|
||||
send(data: string | ArrayBuffer): void;
|
||||
close(code?: number, reason?: string): void;
|
||||
addEventListener(type: string, listener: (event: any) => void): void;
|
||||
removeEventListener(type: string, listener: (event: any) => void): void;
|
||||
}
|
||||
|
||||
export interface ToolOutputSchema {
|
||||
type: 'object';
|
||||
properties: Record<string, SchemaProperty>;
|
||||
format?: 'json' | 'text' | 'markdown' | 'binary';
|
||||
maxSize?: number;
|
||||
maxLines?: number;
|
||||
export interface NetworkOperations {
|
||||
fetch(url: string, options?: PlatformFetchRequestInit): Promise<PlatformResponse>;
|
||||
fetchStream?(url: string, options?: PlatformFetchRequestInit): AsyncGenerator<ArrayBuffer, PlatformResponse, unknown>;
|
||||
connectWebSocket?(url: string, protocols?: string[]): Promise<PlatformWebSocket>;
|
||||
}
|
||||
|
||||
export interface ToolExecutionContext {
|
||||
toolCallId: string;
|
||||
workingDirectory: string;
|
||||
abortController: PlatformAbortController;
|
||||
config: { timeout?: number };
|
||||
logger: Logger;
|
||||
export interface PlatformInfo {
|
||||
runtime: RuntimeType;
|
||||
os: OSType;
|
||||
version?: string;
|
||||
arch?: string;
|
||||
hostname?: string;
|
||||
capabilities: PlatformCapabilities;
|
||||
}
|
||||
|
||||
export interface Tool {
|
||||
@ -181,13 +264,370 @@ declare module 'waterflow/runtime/core/tools/tool_interface' {
|
||||
readonly inputSchema: ToolInputSchema;
|
||||
readonly outputSchema?: ToolOutputSchema;
|
||||
readonly handler: (params: ToolInput, context: ToolExecutionContext) => Promise<ToolOutput>;
|
||||
readonly permissionLevel: PermissionLevel;
|
||||
readonly alwaysLoad?: boolean;
|
||||
readonly shouldDefer?: boolean;
|
||||
readonly permissionLevel: ToolPermissionLevel;
|
||||
readonly requiredPermissions?: string[];
|
||||
readonly features?: ToolFeatures;
|
||||
readonly metadata?: ToolMetadata;
|
||||
readonly isMcp?: boolean;
|
||||
readonly prompt?: (options: any) => Promise<string>;
|
||||
readonly features?: string[];
|
||||
readonly metadata?: Record<string, unknown>;
|
||||
readonly shouldDefer?: boolean;
|
||||
readonly alwaysLoad?: boolean;
|
||||
readonly searchHint?: string;
|
||||
prompt?(options: ToolPromptOptions): Promise<string>;
|
||||
}
|
||||
|
||||
export interface Platform {
|
||||
getInfo(): PlatformInfo;
|
||||
createAbortController(): PlatformAbortController;
|
||||
readonly path: PathOperations;
|
||||
readonly fs: FileSystemOperations | null;
|
||||
readonly process: ProcessOperations | null;
|
||||
readonly storage: StorageOperations;
|
||||
readonly network: NetworkOperations;
|
||||
readonly globals: PlatformGlobals;
|
||||
readonly tools: PlatformTools;
|
||||
readonly builtinTools: Tool[];
|
||||
getEnv(key: string): string | undefined;
|
||||
getAllEnv?(): Record<string, string>;
|
||||
setEnv?(key: string, value: string): void;
|
||||
getCwd(): string;
|
||||
setCwd?(path: string): void;
|
||||
exit?(code: number): void;
|
||||
}
|
||||
|
||||
export interface CreatePlatformOptions {
|
||||
storagePath?: string;
|
||||
storageType?: 'localStorage' | 'indexedDB';
|
||||
dbName?: string;
|
||||
context?: any;
|
||||
storageName?: string;
|
||||
}
|
||||
|
||||
export type ToolInput = Record<string, unknown>;
|
||||
export type ToolOutput = string | Record<string, unknown> | void;
|
||||
|
||||
export type ToolPermissionLevel = 'safe' | 'moderate' | 'dangerous' | 'restricted';
|
||||
export type ToolCategory = 'file' | 'code' | 'search' | 'execute' | 'network' | 'analysis' | 'generation' | 'communication' | 'custom';
|
||||
|
||||
export interface ToolSchemaProperty {
|
||||
type: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object';
|
||||
description: string;
|
||||
enum?: string[];
|
||||
default?: unknown;
|
||||
examples?: unknown[];
|
||||
items?: ToolSchemaProperty;
|
||||
properties?: Record<string, ToolSchemaProperty>;
|
||||
}
|
||||
|
||||
export interface ToolInputSchema {
|
||||
type: 'object';
|
||||
properties: Record<string, ToolSchemaProperty>;
|
||||
required?: string[];
|
||||
additionalProperties?: boolean;
|
||||
}
|
||||
|
||||
export interface ToolExecutionContext {
|
||||
toolCallId: string;
|
||||
workingDirectory: string;
|
||||
additionalWorkingDirectories?: string[];
|
||||
abortController: PlatformAbortController;
|
||||
config: {
|
||||
timeout?: number;
|
||||
maxOutputSize?: number;
|
||||
allowedDirectories?: string[];
|
||||
};
|
||||
logger: {
|
||||
info(message: string, ...args: unknown[]): void;
|
||||
warn(message: string, ...args: unknown[]): void;
|
||||
error(message: string, ...args: unknown[]): void;
|
||||
debug(message: string, ...args: unknown[]): void;
|
||||
};
|
||||
}
|
||||
|
||||
export interface BuiltinTool {
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly description: string;
|
||||
readonly category: ToolCategory;
|
||||
readonly inputSchema: ToolInputSchema;
|
||||
readonly permissionLevel: ToolPermissionLevel;
|
||||
handler(params: ToolInput, context: ToolExecutionContext): Promise<ToolOutput>;
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'waterflow/runtime/core/tools/tool_interface' {
|
||||
import type { PlatformAbortController } from 'waterflow/platform/types';
|
||||
import type { AgentId } from 'waterflow/shared/types/agent';
|
||||
import type { WorkflowRunner } from 'waterflow/runtime/core/workflow/types';
|
||||
import type { WorkflowRegistryImpl } from 'waterflow/runtime/core/workflow/workflow_registry';
|
||||
import type { AgentRegistryImpl } from 'waterflow/runtime/core/workflow/agent_registry';
|
||||
import type { AgentExecutor } from 'waterflow/runtime/core/agent/agent_executor';
|
||||
import type { MCPClient } from 'waterflow/runtime/core/tools/mcp/mcp_client';
|
||||
|
||||
export type ToolCategory =
|
||||
| 'file'
|
||||
| 'code'
|
||||
| 'search'
|
||||
| 'execute'
|
||||
| 'network'
|
||||
| 'analysis'
|
||||
| 'generation'
|
||||
| 'communication'
|
||||
| 'mcp'
|
||||
| 'custom';
|
||||
|
||||
export type PermissionLevel =
|
||||
| 'safe'
|
||||
| 'moderate'
|
||||
| 'dangerous'
|
||||
| 'restricted';
|
||||
|
||||
export type SchemaType =
|
||||
| 'string'
|
||||
| 'number'
|
||||
| 'integer'
|
||||
| 'boolean'
|
||||
| 'array'
|
||||
| 'object';
|
||||
|
||||
export interface SchemaProperty {
|
||||
type: SchemaType;
|
||||
description: string;
|
||||
enum?: string[];
|
||||
minimum?: number;
|
||||
maximum?: number;
|
||||
minLength?: number;
|
||||
maxLength?: number;
|
||||
pattern?: string;
|
||||
default?: any;
|
||||
examples?: any[];
|
||||
suggestedSource?: 'context' | 'literal' | 'file';
|
||||
items?: SchemaProperty;
|
||||
properties?: Record<string, SchemaProperty>;
|
||||
additionalProperties?: boolean | SchemaProperty;
|
||||
}
|
||||
|
||||
export interface ToolInputSchema {
|
||||
type: 'object';
|
||||
properties: Record<string, SchemaProperty>;
|
||||
required?: string[];
|
||||
additionalProperties?: boolean;
|
||||
semanticHints?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface ToolOutputSchema {
|
||||
type: 'object';
|
||||
properties: Record<string, SchemaProperty>;
|
||||
format?: 'json' | 'text' | 'markdown' | 'binary';
|
||||
maxSize?: number;
|
||||
maxLines?: number;
|
||||
}
|
||||
|
||||
export type ToolInput = Record<string, unknown>;
|
||||
export type ToolOutput = string | Record<string, unknown> | void;
|
||||
|
||||
export interface Logger {
|
||||
info(message: string, ...args: any[]): void;
|
||||
warn(message: string, ...args: any[]): void;
|
||||
error(message: string, ...args: any[]): void;
|
||||
debug(message: string, ...args: any[]): void;
|
||||
}
|
||||
|
||||
export interface ToolConfig {
|
||||
timeout?: number;
|
||||
maxOutputSize?: number;
|
||||
allowedDirectories?: string[];
|
||||
}
|
||||
|
||||
export interface ToolExecutionContext {
|
||||
toolCallId: string;
|
||||
agentId?: AgentId;
|
||||
workingDirectory: string;
|
||||
additionalWorkingDirectories?: string[] | undefined;
|
||||
abortController: PlatformAbortController;
|
||||
config: ToolConfig;
|
||||
logger: Logger;
|
||||
workflowRunner?: WorkflowRunner | undefined;
|
||||
workflowRegistry?: WorkflowRegistryImpl | undefined;
|
||||
agentExecutor?: AgentExecutor | undefined;
|
||||
agentRegistry?: AgentRegistryImpl | undefined;
|
||||
allowedAgentTypes?: string[] | undefined;
|
||||
mcpClients?: Map<string, MCPClient> | undefined;
|
||||
tools?: Tool[] | undefined;
|
||||
}
|
||||
|
||||
export type ToolHandler = (
|
||||
params: ToolInput,
|
||||
context: ToolExecutionContext
|
||||
) => Promise<ToolOutput>;
|
||||
|
||||
export interface ToolFeatures {
|
||||
isAsync?: boolean;
|
||||
isStreamable?: boolean;
|
||||
isCacheable?: boolean;
|
||||
requiresConfirmation?: boolean;
|
||||
supportsProgress?: boolean;
|
||||
supportsCancellation?: boolean;
|
||||
producesFiles?: boolean;
|
||||
producesImages?: boolean;
|
||||
producesStructuredOutput?: boolean;
|
||||
requiresMcp?: boolean;
|
||||
requiresNetwork?: boolean;
|
||||
}
|
||||
|
||||
export interface ToolExample {
|
||||
description: string;
|
||||
input: ToolInput;
|
||||
output: ToolOutput;
|
||||
explanation?: string;
|
||||
}
|
||||
|
||||
export interface ToolMetadata {
|
||||
source: 'builtin' | 'mcp' | 'plugin' | 'external';
|
||||
version?: string;
|
||||
author?: string;
|
||||
documentationUrl?: string;
|
||||
examples?: ToolExample[];
|
||||
estimatedDuration?: number;
|
||||
estimatedTokens?: number;
|
||||
compatibleModels?: string[];
|
||||
incompatibleModels?: string[];
|
||||
}
|
||||
|
||||
export interface ToolPromptOptions {
|
||||
tools: Tool[];
|
||||
agentRegistry?: AgentRegistryImpl | undefined;
|
||||
workflowRegistry?: WorkflowRegistryImpl | undefined;
|
||||
allowedAgentTypes?: string[] | undefined;
|
||||
}
|
||||
|
||||
export interface Tool {
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly description: string;
|
||||
readonly category: ToolCategory;
|
||||
readonly inputSchema: ToolInputSchema;
|
||||
readonly outputSchema?: ToolOutputSchema;
|
||||
readonly handler: ToolHandler;
|
||||
readonly permissionLevel: PermissionLevel;
|
||||
readonly requiredPermissions?: string[];
|
||||
readonly features?: ToolFeatures;
|
||||
readonly metadata?: ToolMetadata;
|
||||
readonly isMcp?: boolean;
|
||||
readonly shouldDefer?: boolean;
|
||||
readonly alwaysLoad?: boolean;
|
||||
readonly searchHint?: string;
|
||||
prompt?(options: ToolPromptOptions): Promise<string>;
|
||||
}
|
||||
|
||||
export interface ToolExecutionError {
|
||||
type: ToolErrorType;
|
||||
message: string;
|
||||
code?: string;
|
||||
details?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export type ToolErrorType =
|
||||
| 'validation_error'
|
||||
| 'permission_denied'
|
||||
| 'timeout'
|
||||
| 'execution_error'
|
||||
| 'network_error'
|
||||
| 'mcp_error'
|
||||
| 'unknown_error';
|
||||
|
||||
export interface ToolExecutionResult {
|
||||
success: boolean;
|
||||
toolId: string;
|
||||
toolCallId: string;
|
||||
output: ToolOutput;
|
||||
error?: ToolExecutionError;
|
||||
metadata: {
|
||||
duration: number;
|
||||
tokensUsed?: number;
|
||||
cached?: boolean;
|
||||
retryCount?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ToolCall {
|
||||
id: string;
|
||||
toolId: string;
|
||||
toolName: string;
|
||||
input: ToolInput;
|
||||
callerId: AgentId | string;
|
||||
callerType: 'agent' | 'workflow' | 'main';
|
||||
}
|
||||
|
||||
export function createTextOutput(text: string): ToolOutput;
|
||||
export function createJSONOutput(data: Record<string, unknown>): ToolOutput;
|
||||
export function createErrorOutput(message: string, code?: string, details?: Record<string, unknown>): ToolOutput;
|
||||
}
|
||||
|
||||
declare module 'waterflow/runtime/core/tools/builtin' {
|
||||
import type { Platform } from 'waterflow/platform/types';
|
||||
import type { Tool } from 'waterflow/runtime/core/tools/tool_interface';
|
||||
import { ToolRegistry } from 'waterflow/runtime/core/tools/tool_registry';
|
||||
|
||||
export const FRAMEWORK_TOOLS: Tool[];
|
||||
export function initializeToolRegistry(platform: Platform): ToolRegistry;
|
||||
export function getFrameworkTools(): Tool[];
|
||||
}
|
||||
|
||||
declare module 'waterflow/runtime/core/tools/tool_registry' {
|
||||
import type { Tool, ToolCategory, ToolInput } from 'waterflow/runtime/core/tools/tool_interface';
|
||||
|
||||
export interface ValidationResult {
|
||||
valid: boolean;
|
||||
errors?: string[];
|
||||
}
|
||||
|
||||
export interface ToolSearchResult {
|
||||
tool: Tool;
|
||||
relevanceScore: number;
|
||||
matchReason: string;
|
||||
}
|
||||
|
||||
export interface SearchOptions {
|
||||
category?: ToolCategory;
|
||||
permissionLevel?: string;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export interface RegistryStatistics {
|
||||
totalTools: number;
|
||||
byCategory: Record<string, number>;
|
||||
bySource: Record<string, number>;
|
||||
byPermissionLevel: Record<string, number>;
|
||||
}
|
||||
|
||||
export interface ToolDefinitionExtended {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
parameters: {
|
||||
type: 'object';
|
||||
properties: Record<string, any>;
|
||||
required?: string[];
|
||||
additionalProperties?: boolean;
|
||||
};
|
||||
execute: (params: Record<string, any>) => Promise<any>;
|
||||
}
|
||||
|
||||
export class ToolRegistry {
|
||||
register(tool: Tool | ToolDefinitionExtended): void;
|
||||
registerAll(tools: (Tool | ToolDefinitionExtended)[]): void;
|
||||
unregister(toolId: string): void;
|
||||
get(toolId: string): Tool | ToolDefinitionExtended | undefined;
|
||||
getByName(name: string): Tool | ToolDefinitionExtended | undefined;
|
||||
has(toolId: string): boolean;
|
||||
size(): number;
|
||||
listAll(): (Tool | ToolDefinitionExtended)[];
|
||||
listByCategory(category: ToolCategory): (Tool | ToolDefinitionExtended)[];
|
||||
listByPermissionLevel(level: string): (Tool | ToolDefinitionExtended)[];
|
||||
search(query: string, options?: SearchOptions): ToolSearchResult[];
|
||||
isAvailable(toolId: string, context?: any): boolean;
|
||||
validateInput(toolId: string, input: ToolInput): ValidationResult;
|
||||
clear(): void;
|
||||
getStatistics(): RegistryStatistics;
|
||||
}
|
||||
}
|
||||
|
||||
368
重构.md
368
重构.md
@ -1,368 +0,0 @@
|
||||
# TrulyMEM WaterFlow 重构计划
|
||||
|
||||
> **目标**: 将 waterflow 分支重构为标准的 WaterFlow 框架 Tool + Skill,保留原始记忆能力不变。
|
||||
> **约束**: 仅修改 waterflow 分支,不影响 main 分支。
|
||||
|
||||
---
|
||||
|
||||
## 现状分析
|
||||
|
||||
### waterflow 分支当前结构
|
||||
|
||||
```
|
||||
ts/
|
||||
├── bundled-skills/graph_memory/ ← SKILL.md 已存在 ✅
|
||||
│ ├── SKILL.md
|
||||
│ ├── persona/SKILL.md
|
||||
│ └── task/SKILL.md
|
||||
├── src/
|
||||
│ ├── platform/ ← 重复定义,需删除 ❌
|
||||
│ │ ├── index.ts
|
||||
│ │ ├── node.ts
|
||||
│ │ └── types.ts
|
||||
│ ├── runtime/core/
|
||||
│ │ ├── graph_memory/ ← 核心逻辑,保留 ✅
|
||||
│ │ │ ├── types.ts
|
||||
│ │ │ ├── graph_database.ts
|
||||
│ │ │ ├── memory_service.ts
|
||||
│ │ │ └── index.ts
|
||||
│ │ └── tools/
|
||||
│ │ ├── tool_interface.ts ← 重复定义,需删除 ❌
|
||||
│ │ └── builtin/
|
||||
│ │ └── graph_memory_tool.ts ← 需适配 WaterFlow 接口 ✅
|
||||
│ └── types/
|
||||
│ └── sql.js.d.ts ← 保留 ✅
|
||||
└── package.json ← 需调整依赖 ✅
|
||||
```
|
||||
|
||||
### 核心问题
|
||||
|
||||
| 问题 | 说明 | 解决方案 |
|
||||
|------|------|----------|
|
||||
| 重复平台层 | `ts/src/platform/` 与 WaterFlow 重复 | 删除,改用 WaterFlow 的 `getPlatform()` |
|
||||
| 重复 Tool 接口 | `tool_interface.ts` 与 WaterFlow 重复 | 删除,改用 WaterFlow 的类型 |
|
||||
| 存储接口不兼容 | 使用自定义 `StorageOperations` | 改用 WaterFlow 的 `platform.fs`(支持 binary) |
|
||||
| 无注册入口 | 没有将 Tool 注册到 WaterFlow 的方式 | 创建 `registerGraphMemoryTool()` 导出函数 |
|
||||
| SKILL.md 不完整 | 缺少 persona/task 操作的完整描述 | 补充完善 |
|
||||
|
||||
---
|
||||
|
||||
## 重构步骤
|
||||
|
||||
### Phase 1: 清理重复定义
|
||||
|
||||
#### 1.1 删除 `ts/src/platform/` 目录
|
||||
|
||||
```
|
||||
删除: ts/src/platform/index.ts
|
||||
删除: ts/src/platform/node.ts
|
||||
删除: ts/src/platform/types.ts
|
||||
```
|
||||
|
||||
**替换方案**: 所有 `import { getPlatform } from '../../../platform'` 改为从 WaterFlow 导入:
|
||||
```typescript
|
||||
import { getPlatform } from 'waterflow/platform';
|
||||
```
|
||||
|
||||
#### 1.2 删除 `ts/src/runtime/core/tools/tool_interface.ts`
|
||||
|
||||
**替换方案**: 使用 WaterFlow 的 Tool 接口:
|
||||
```typescript
|
||||
import type { Tool, ToolInputSchema, ToolOutput, ToolExecutionContext } from 'waterflow/runtime/core/tools/tool_interface';
|
||||
```
|
||||
|
||||
#### 1.3 更新 `tsconfig.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"target": "esnext",
|
||||
"types": ["node"],
|
||||
"lib": ["esnext"],
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"strict": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"isolatedModules": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: 适配 WaterFlow 平台层
|
||||
|
||||
#### 2.1 修改 `graph_database.ts` — 存储适配
|
||||
|
||||
**当前**(使用自定义 storage):
|
||||
```typescript
|
||||
import { getPlatform } from '../../../platform';
|
||||
const platform = getPlatform();
|
||||
await platform.storage.save(key, data); // 自定义接口
|
||||
```
|
||||
|
||||
**改为**(使用 WaterFlow fs):
|
||||
```typescript
|
||||
import { getPlatform } from 'waterflow/platform';
|
||||
const platform = getPlatform();
|
||||
await platform.fs.writeFile(dbPath, data, { encoding: 'binary' });
|
||||
const loaded = await platform.fs.readFile(dbPath, { encoding: 'binary' });
|
||||
```
|
||||
|
||||
**具体改动**:
|
||||
- `GraphDatabase.save()` 方法: `storage.save()` → `fs.writeFile(..., { encoding: 'binary' })`
|
||||
- `GraphDatabase.load()` 方法: `storage.load()` → `fs.readFile(..., { encoding: 'binary' })`
|
||||
- `dbPath` 使用 `platform.path.join()` 构建
|
||||
|
||||
#### 2.2 修改 `graph_memory_tool.ts` — Tool 接口适配
|
||||
|
||||
**当前**:
|
||||
```typescript
|
||||
import type { Tool, ... } from '../tool_interface'; // 自定义接口
|
||||
import { getPlatform } from '../../../../platform'; // 自定义平台
|
||||
```
|
||||
|
||||
**改为**:
|
||||
```typescript
|
||||
import type { Tool, ToolInputSchema, ToolOutput, ToolExecutionContext, ToolInput } from 'waterflow/runtime/core/tools/tool_interface';
|
||||
import { getPlatform } from 'waterflow/platform';
|
||||
```
|
||||
|
||||
**新增 WaterFlow 兼容字段**:
|
||||
```typescript
|
||||
export class GraphMemoryTool implements Tool {
|
||||
readonly id = 'builtin:graph_memory';
|
||||
readonly name = 'GraphMemory';
|
||||
readonly description = '...';
|
||||
readonly category: ToolCategory = 'analysis';
|
||||
readonly permissionLevel: PermissionLevel = 'safe';
|
||||
readonly inputSchema: ToolInputSchema = { ... };
|
||||
|
||||
// WaterFlow 新增字段(可选)
|
||||
readonly alwaysLoad = true; // 始终加载完整 schema
|
||||
readonly shouldDefer = false; // 不延迟加载
|
||||
|
||||
async handler(params: ToolInput, context: ToolExecutionContext): Promise<ToolOutput> {
|
||||
// 使用 context.logger 替代 getPlatform().getLogger()
|
||||
const logger = context.logger;
|
||||
// ... 原有逻辑不变
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 创建注册入口
|
||||
|
||||
**新建**: `ts/src/runtime/core/tools/builtin/index.ts`
|
||||
|
||||
```typescript
|
||||
import type { Tool } from 'waterflow/runtime/core/tools/tool_interface';
|
||||
import { GraphMemoryTool, createGraphMemoryTool } from './graph_memory_tool';
|
||||
|
||||
export { GraphMemoryTool, createGraphMemoryTool };
|
||||
|
||||
/**
|
||||
* 注册图记忆工具到 WaterFlow ToolRegistry
|
||||
*
|
||||
* 使用方式:
|
||||
* import { registerGraphMemoryTool } from 'trulymem/tools';
|
||||
* registerGraphMemoryTool(toolRegistry, sessionId);
|
||||
*/
|
||||
export function registerGraphMemoryTool(
|
||||
registry: { register: (tool: Tool) => void },
|
||||
sessionId?: string
|
||||
): void {
|
||||
registry.register(createGraphMemoryTool(sessionId));
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: 完善 SKILL.md
|
||||
|
||||
#### 3.1 更新主 SKILL.md
|
||||
|
||||
补充 persona 和 task 操作说明,与 `memory_service.ts` 的实际方法对齐:
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: graph_memory
|
||||
description: 图记忆工具 - 让 AI 拥有真正的长期记忆能力
|
||||
when_to_use: 需要 AI 记住、回忆、管理信息或任务时
|
||||
context: inline
|
||||
allowed_tools:
|
||||
- builtin:graph_memory
|
||||
arguments:
|
||||
- name: action
|
||||
type: string
|
||||
required: true
|
||||
enum: [recall, commit, purge, introspect, persona_update, persona_clear, task_create, task_set_state, task_delete, task_link_info]
|
||||
description: 记忆操作类型
|
||||
- name: params
|
||||
type: object
|
||||
required: true
|
||||
description: 操作参数
|
||||
user_invocable: true
|
||||
---
|
||||
```
|
||||
|
||||
#### 3.2 更新 persona/SKILL.md
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: persona_management
|
||||
description: 人设管理 - 管理 AI 的用户画像和偏好
|
||||
context: inline
|
||||
allowed_tools:
|
||||
- builtin:graph_memory
|
||||
---
|
||||
```
|
||||
|
||||
#### 3.3 更新 task/SKILL.md
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: task_management
|
||||
description: 任务管理 - 管理连续性任务和相关信息
|
||||
context: inline
|
||||
allowed_tools:
|
||||
- builtin:graph_memory
|
||||
---
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: 依赖与构建
|
||||
|
||||
#### 4.1 更新 `package.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "trulymem-waterflow",
|
||||
"version": "1.0.0",
|
||||
"description": "TrulyMEM 图记忆系统 - WaterFlow Skill/Tool 实现",
|
||||
"type": "module",
|
||||
"main": "./dist/runtime/core/tools/builtin/index.js",
|
||||
"exports": {
|
||||
"./tools": "./dist/runtime/core/tools/builtin/index.js",
|
||||
"./graph_memory": "./dist/runtime/core/graph_memory/index.js",
|
||||
"./skills": "./bundled-skills"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"waterflow-ts": ">=0.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"sql.js": "^1.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.5.2",
|
||||
"typescript": "^5.0.0",
|
||||
"vitest": "^2.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.2 添加 `sql.js.d.ts` 类型声明
|
||||
|
||||
保留现有 `ts/src/types/sql.js.d.ts`,确保编译通过。
|
||||
|
||||
---
|
||||
|
||||
### Phase 5: 验证
|
||||
|
||||
#### 5.1 编译验证
|
||||
|
||||
```bash
|
||||
cd ts/
|
||||
npm install
|
||||
npm run build
|
||||
# 检查 dist/ 输出
|
||||
```
|
||||
|
||||
#### 5.2 类型检查
|
||||
|
||||
```bash
|
||||
npx tsc --noEmit
|
||||
# 确保无类型错误
|
||||
```
|
||||
|
||||
#### 5.3 集成验证(在 WaterFlow 项目中)
|
||||
|
||||
```typescript
|
||||
// 在 WaterFlow 入口文件中测试
|
||||
import { getPlatform } from './platform';
|
||||
import { initializeToolRegistry } from './runtime/core/tools/builtin';
|
||||
import { registerGraphMemoryTool } from 'trulymem/tools';
|
||||
|
||||
const platform = getPlatform();
|
||||
const registry = initializeToolRegistry(platform);
|
||||
|
||||
// 注册图记忆工具
|
||||
registerGraphMemoryTool(registry, 'test-session');
|
||||
|
||||
// 验证工具已注册
|
||||
const tool = registry.get('builtin:graph_memory');
|
||||
console.log('GraphMemory tool registered:', !!tool);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 文件变更清单
|
||||
|
||||
| 操作 | 文件路径 | 说明 |
|
||||
|------|---------|------|
|
||||
| 🗑️ 删除 | `ts/src/platform/index.ts` | 重复平台层 |
|
||||
| 🗑️ 删除 | `ts/src/platform/node.ts` | 重复平台层 |
|
||||
| 🗑️ 删除 | `ts/src/platform/types.ts` | 重复平台层 |
|
||||
| 🗑️ 删除 | `ts/src/runtime/core/tools/tool_interface.ts` | 重复接口 |
|
||||
| ✏️ 修改 | `ts/src/runtime/core/graph_memory/graph_database.ts` | 改用 WaterFlow fs |
|
||||
| ✏️ 修改 | `ts/src/runtime/core/tools/builtin/graph_memory_tool.ts` | 适配 WaterFlow 接口 |
|
||||
| ✏️ 修改 | `ts/src/runtime/core/graph_memory/index.ts` | 更新导出路径 |
|
||||
| ✏️ 修改 | `ts/bundled-skills/graph_memory/SKILL.md` | 补充完整操作说明 |
|
||||
| ✏️ 修改 | `ts/bundled-skills/graph_memory/persona/SKILL.md` | 完善 |
|
||||
| ✏️ 修改 | `ts/bundled-skills/graph_memory/task/SKILL.md` | 完善 |
|
||||
| ✏️ 修改 | `ts/package.json` | 调整为 peerDependency |
|
||||
| ✏️ 修改 | `ts/tsconfig.json` | 清理配置 |
|
||||
| ➕ 新增 | `ts/src/runtime/core/tools/builtin/index.ts` | 注册入口 |
|
||||
|
||||
---
|
||||
|
||||
## 依赖关系图(重构后)
|
||||
|
||||
```
|
||||
WaterFlow 框架
|
||||
├── Platform (getPlatform)
|
||||
│ ├── fs.readFile/writeFile (binary) ← GraphDatabase 使用
|
||||
│ ├── path.join/resolve ← 路径构建
|
||||
│ ├── getLogger ← 日志
|
||||
│ └── globals.randomUUID ← UUID 生成
|
||||
│
|
||||
├── ToolRegistry
|
||||
│ ├── FRAMEWORK_TOOLS (Agent, ToolSearch)
|
||||
│ ├── Platform Tools (Read, Write, Bash...)
|
||||
│ └── GraphMemoryTool ← 从 trulymem/tools 注册
|
||||
│
|
||||
└── SkillLoader
|
||||
└── bundled-skills/graph_memory/SKILL.md
|
||||
└── allowed_tools: ['builtin:graph_memory']
|
||||
└→ LLM 调用 → ToolExecutor → GraphMemoryTool.handler()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 风险与注意事项
|
||||
|
||||
1. **WaterFlow 版本依赖**: 使用 `peerDependencies` 确保与 WaterFlow 版本兼容
|
||||
2. **二进制存储**: WaterFlow 的 `fs` 支持 `encoding: 'binary'`,已验证可用
|
||||
3. **类型兼容**: 确保 Tool 接口字段与 WaterFlow 完全一致
|
||||
4. **SKILL.md 格式**: YAML frontmatter 必须符合 WaterFlow SkillLoader 解析规则
|
||||
Reference in New Issue
Block a user