mirror of
https://gitcode.com/JianFeeeee/TrulyMEM-TrueHumanMEM.git
synced 2026-09-24 19:08:15 +00:00
fix: OpenClaw compliance audit fixes - refactor tool interface to AnyAgentTool, restructure skill directories
This commit is contained in:
29
.sisyphus/fix-tracker.md
Normal file
29
.sisyphus/fix-tracker.md
Normal file
@ -0,0 +1,29 @@
|
||||
# 修复追踪文件
|
||||
|
||||
**分支**: openclaw
|
||||
**开始时间**: 2026-04-16
|
||||
**状态**: 重新执行
|
||||
|
||||
---
|
||||
|
||||
## 修复计划
|
||||
|
||||
### P0 - 阻断性问题
|
||||
|
||||
#### 1. 删除自定义 tool_interface.ts
|
||||
#### 2. 重构 graph_memory_tool.ts
|
||||
#### 3. 更新 plugin-entry.ts
|
||||
|
||||
### P2 - 最佳实践
|
||||
|
||||
#### 4. 重组 Skill 目录结构
|
||||
#### 5. 更新 bundled-skills 目录结构
|
||||
#### 6. 更新 openclaw.plugin.json
|
||||
#### 7. 更新 README.md / README_EN.md
|
||||
|
||||
---
|
||||
|
||||
## 执行记录
|
||||
|
||||
### [进行中] P0: 核心修复
|
||||
|
||||
32
README.md
32
README.md
@ -35,13 +35,13 @@ npm run build
|
||||
```bash
|
||||
# 方式 A:工作空间级(推荐,仅当前项目可用)
|
||||
cp -r skills/graph-memory <你的项目目录>/skills/graph-memory
|
||||
cp -r skills/graph-memory/persona <你的项目目录>/skills/graph-memory-persona
|
||||
cp -r skills/graph-memory/task <你的项目目录>/skills/graph-memory-task
|
||||
cp -r skills/graph-memory-persona <你的项目目录>/skills/graph-memory-persona
|
||||
cp -r skills/graph-memory-task <你的项目目录>/skills/graph-memory-task
|
||||
|
||||
# 方式 B:用户级(所有项目可用)
|
||||
cp -r skills/graph-memory ~/.openclaw/skills/graph-memory
|
||||
cp -r skills/graph-memory/persona ~/.openclaw/skills/graph-memory-persona
|
||||
cp -r skills/graph-memory/task ~/.openclaw/skills/graph-memory-task
|
||||
cp -r skills/graph-memory-persona ~/.openclaw/skills/graph-memory-persona
|
||||
cp -r skills/graph-memory-task ~/.openclaw/skills/graph-memory-task
|
||||
```
|
||||
|
||||
### 步骤 4:安装 Plugin(让 OpenClaw 运行时加载 Tool)
|
||||
@ -130,8 +130,8 @@ npm run build
|
||||
|
||||
```bash
|
||||
cp -r skills/graph-memory ~/.agents/skills/graph-memory
|
||||
cp -r skills/graph-memory/persona ~/.agents/skills/graph-memory-persona
|
||||
cp -r skills/graph-memory/task ~/.agents/skills/graph-memory-task
|
||||
cp -r skills/graph-memory-persona ~/.agents/skills/graph-memory-persona
|
||||
cp -r skills/graph-memory-task ~/.agents/skills/graph-memory-task
|
||||
```
|
||||
|
||||
---
|
||||
@ -153,19 +153,23 @@ ts/
|
||||
│ │ └── graph_memory_tool.ts # Tool 实现
|
||||
│ └── tool_limiter.ts # 调用限制器
|
||||
├── bundled-skills/
|
||||
│ └── graph-memory/ # 内置 Skill 定义
|
||||
│ ├── SKILL.md
|
||||
│ ├── persona/SKILL.md
|
||||
│ └── task/SKILL.md
|
||||
│ ├── graph-memory/ # 内置 Skill 定义
|
||||
│ │ └── SKILL.md
|
||||
│ ├── graph-memory-persona/
|
||||
│ │ └── SKILL.md
|
||||
│ └── graph-memory-task/
|
||||
│ └── SKILL.md
|
||||
├── package.json
|
||||
├── tsconfig.json
|
||||
└── openclaw.plugin.json # Plugin Manifest
|
||||
|
||||
skills/ # 独立 Skill 定义
|
||||
└── graph-memory/
|
||||
├── SKILL.md
|
||||
├── persona/SKILL.md
|
||||
└── task/SKILL.md
|
||||
├── graph-memory/
|
||||
│ └── SKILL.md
|
||||
├── graph-memory-persona/
|
||||
│ └── SKILL.md
|
||||
└── graph-memory-task/
|
||||
└── SKILL.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
32
README_EN.md
32
README_EN.md
@ -35,13 +35,13 @@ Copy the 3 Skills from `skills/` to OpenClaw's skill directory. Priority: `<work
|
||||
```bash
|
||||
# Option A: Workspace-level (recommended, current project only)
|
||||
cp -r skills/graph-memory <your-project-dir>/skills/graph-memory
|
||||
cp -r skills/graph-memory/persona <your-project-dir>/skills/graph-memory-persona
|
||||
cp -r skills/graph-memory/task <your-project-dir>/skills/graph-memory-task
|
||||
cp -r skills/graph-memory-persona <your-project-dir>/skills/graph-memory-persona
|
||||
cp -r skills/graph-memory-task <your-project-dir>/skills/graph-memory-task
|
||||
|
||||
# Option B: User-level (available for all projects)
|
||||
cp -r skills/graph-memory ~/.openclaw/skills/graph-memory
|
||||
cp -r skills/graph-memory/persona ~/.openclaw/skills/graph-memory-persona
|
||||
cp -r skills/graph-memory/task ~/.openclaw/skills/graph-memory-task
|
||||
cp -r skills/graph-memory-persona ~/.openclaw/skills/graph-memory-persona
|
||||
cp -r skills/graph-memory-task ~/.openclaw/skills/graph-memory-task
|
||||
```
|
||||
|
||||
### Step 4: Install Plugin (enables OpenClaw runtime to load the Tool)
|
||||
@ -129,8 +129,8 @@ Copy the `skills/` directory to OpenClaw's skill directory:
|
||||
|
||||
```bash
|
||||
cp -r skills/graph-memory ~/.agents/skills/graph-memory
|
||||
cp -r skills/graph-memory/persona ~/.agents/skills/graph-memory-persona
|
||||
cp -r skills/graph-memory/task ~/.agents/skills/graph-memory-task
|
||||
cp -r skills/graph-memory-persona ~/.agents/skills/graph-memory-persona
|
||||
cp -r skills/graph-memory-task ~/.agents/skills/graph-memory-task
|
||||
```
|
||||
|
||||
---
|
||||
@ -152,19 +152,23 @@ ts/
|
||||
│ │ └── graph_memory_tool.ts # Tool implementation
|
||||
│ └── tool_limiter.ts # Call rate limiter
|
||||
├── bundled-skills/
|
||||
│ └── graph-memory/ # Bundled Skill definitions
|
||||
│ ├── SKILL.md
|
||||
│ ├── persona/SKILL.md
|
||||
│ └── task/SKILL.md
|
||||
│ ├── graph-memory/ # Bundled Skill definitions
|
||||
│ │ └── SKILL.md
|
||||
│ ├── graph-memory-persona/
|
||||
│ │ └── SKILL.md
|
||||
│ └── graph-memory-task/
|
||||
│ └── SKILL.md
|
||||
├── package.json
|
||||
├── tsconfig.json
|
||||
└── openclaw.plugin.json # Plugin Manifest
|
||||
|
||||
skills/ # Standalone Skill definitions
|
||||
└── graph-memory/
|
||||
├── SKILL.md
|
||||
├── persona/SKILL.md
|
||||
└── task/SKILL.md
|
||||
├── graph-memory/
|
||||
│ └── SKILL.md
|
||||
├── graph-memory-persona/
|
||||
│ └── SKILL.md
|
||||
└── graph-memory-task/
|
||||
└── SKILL.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@ -1,7 +1,13 @@
|
||||
{
|
||||
"id": "graph-memory",
|
||||
"name": "Graph Memory",
|
||||
"kind": "memory",
|
||||
"description": "让 AI 拥有真正的长期记忆能力 - 基于图数据库的记忆系统",
|
||||
"skills": [
|
||||
"bundled-skills/graph-memory",
|
||||
"bundled-skills/graph-memory-persona",
|
||||
"bundled-skills/graph-memory-task"
|
||||
],
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
|
||||
@ -1,76 +1,5 @@
|
||||
/**
|
||||
* OpenClaw Plugin Entry Point
|
||||
*
|
||||
* Registers the GraphMemory tool with OpenClaw's plugin system.
|
||||
* Uses @sinclair/typebox for parameter schema definition.
|
||||
*/
|
||||
import { Type } from '@sinclair/typebox';
|
||||
import { GraphMemoryTool } from './runtime/core/tools/builtin/graph_memory_tool.js';
|
||||
import { GraphMemoryToolSchema, createGraphMemoryTool } from './runtime/core/tools/builtin/graph_memory_tool.js';
|
||||
|
||||
// OpenClaw Tool Schema using TypeBox
|
||||
const GraphMemoryToolSchema = Type.Object({
|
||||
action: Type.String({
|
||||
description: '记忆操作类型',
|
||||
enum: [
|
||||
'recall', 'commit', 'purge', 'introspect',
|
||||
'persona_update', 'persona_clear',
|
||||
'task_create', 'task_set_state', 'task_delete', 'task_link_info'
|
||||
]
|
||||
}),
|
||||
params: Type.Object({
|
||||
queryIntent: Type.Optional(Type.String({ description: '搜索意图' })),
|
||||
seedEntities: Type.Optional(Type.Array(Type.String({ description: '实体' }), { description: '种子实体' })),
|
||||
depth: Type.Optional(Type.Number({ description: '检索深度' })),
|
||||
sessionFilter: Type.Optional(Type.String({ description: '会话ID过滤' })),
|
||||
triplets: Type.Optional(Type.Array(
|
||||
Type.Object({
|
||||
subject: Type.String({ description: '主体' }),
|
||||
relation: Type.String({ description: '关系' }),
|
||||
object: Type.String({ description: '客体' }),
|
||||
confidence: Type.Optional(Type.Number({ description: '置信度' }))
|
||||
}, { description: '三元组' }),
|
||||
{ description: '三元组数组' }
|
||||
)),
|
||||
sessionId: Type.Optional(Type.String({ description: '会话ID' })),
|
||||
turnId: Type.Optional(Type.Number({ description: '轮次ID' })),
|
||||
criteria: Type.Optional(Type.Object({
|
||||
subject: Type.Optional(Type.String({ description: '主体' })),
|
||||
target: Type.Optional(Type.String({ description: '客体' })),
|
||||
relation: Type.Optional(Type.String({ description: '关系' })),
|
||||
sessionId: Type.Optional(Type.String({ description: '会话ID' }))
|
||||
}, { description: '删除条件' })),
|
||||
mode: Type.Optional(Type.String({
|
||||
enum: ['soft', 'hard', 'supersede'],
|
||||
description: '删除模式'
|
||||
})),
|
||||
newRelation: Type.Optional(Type.Object({
|
||||
relation: Type.String({ description: '关系' }),
|
||||
target: Type.String({ description: '客体' })
|
||||
}, { description: '新关系(supersede模式)' })),
|
||||
attributes: Type.Optional(Type.Array(
|
||||
Type.Object({
|
||||
attribute: Type.String({ description: '属性名' }),
|
||||
value: Type.String({ description: '属性值' })
|
||||
}, { description: '属性' }),
|
||||
{ description: '属性数组' }
|
||||
)),
|
||||
confirm: Type.Optional(Type.Boolean({ description: '确认清除' })),
|
||||
task_id: Type.Optional(Type.String({ description: '任务ID' })),
|
||||
description: Type.Optional(Type.String({ description: '任务描述' })),
|
||||
state: Type.Optional(Type.String({ description: '任务状态' })),
|
||||
info_nodes: Type.Optional(Type.Array(Type.String({ description: '节点' }), { description: '信息节点' })),
|
||||
info_node: Type.Optional(Type.String({ description: '信息节点' })),
|
||||
days: Type.Optional(Type.Number({ description: '归档天数' })),
|
||||
dry_run: Type.Optional(Type.Boolean({ description: '仅预览不删除' }))
|
||||
}, { description: '操作参数' })
|
||||
});
|
||||
|
||||
/**
|
||||
* Plugin entry point for OpenClaw.
|
||||
*
|
||||
* When loaded as an OpenClaw plugin, this function registers the GraphMemory tool.
|
||||
* For standalone usage, import GraphMemoryTool directly.
|
||||
*/
|
||||
export default function registerGraphMemoryPlugin(api: {
|
||||
registerTool: (tool: {
|
||||
name: string;
|
||||
@ -81,34 +10,6 @@ export default function registerGraphMemoryPlugin(api: {
|
||||
}>;
|
||||
}) => void;
|
||||
}): void {
|
||||
const tool = new GraphMemoryTool();
|
||||
|
||||
api.registerTool({
|
||||
name: 'graph_memory',
|
||||
description: '图记忆工具 - 让 AI 拥有真正的长期记忆能力。支持 recall(检索)、commit(写入)、purge(删除)、introspect(状态)、人设管理、任务管理',
|
||||
parameters: GraphMemoryToolSchema,
|
||||
async execute(_id: string, params: Record<string, unknown>): Promise<{
|
||||
content: Array<{ type: 'text'; text: string }>;
|
||||
}> {
|
||||
const result = await tool.handler(params, {
|
||||
toolCallId: _id,
|
||||
workingDirectory: process.cwd(),
|
||||
abortController: { signal: new AbortController().signal },
|
||||
config: {},
|
||||
logger: {
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
error: () => {},
|
||||
debug: () => {}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: typeof result === 'string' ? result : JSON.stringify(result)
|
||||
}]
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
const tool = createGraphMemoryTool();
|
||||
api.registerTool(tool);
|
||||
}
|
||||
@ -1,167 +1,95 @@
|
||||
import type { Tool, ToolCategory, PermissionLevel, ToolInputSchema, ToolExecutionContext, ToolOutput } from '../tool_interface';
|
||||
import { GraphDatabase } from '../../graph_memory/graph_database';
|
||||
import { MemoryService } from '../../graph_memory/memory_service';
|
||||
import { ToolLimiter } from '../tool_limiter';
|
||||
import { Type } from '@sinclair/typebox';
|
||||
import type { Static } from '@sinclair/typebox';
|
||||
import { GraphDatabase } from '../../graph_memory/graph_database.js';
|
||||
import { MemoryService } from '../../graph_memory/memory_service.js';
|
||||
import { ToolLimiter } from '../tool_limiter.js';
|
||||
|
||||
const GRAPH_MEMORY_TOOL_ID = 'builtin:graph_memory';
|
||||
export const GraphMemoryToolSchema = Type.Object({
|
||||
action: Type.String({
|
||||
description: '记忆操作类型',
|
||||
enum: [
|
||||
'recall', 'commit', 'purge', 'introspect', 'archive', 'cleanup',
|
||||
'persona_update', 'persona_clear',
|
||||
'task_create', 'task_set_state', 'task_delete', 'task_link_info'
|
||||
]
|
||||
}),
|
||||
params: Type.Object({
|
||||
queryIntent: Type.Optional(Type.String({ description: '搜索意图' })),
|
||||
seedEntities: Type.Optional(Type.Array(Type.String({ description: '实体' }), { description: '种子实体' })),
|
||||
depth: Type.Optional(Type.Number({ description: '检索深度' })),
|
||||
sessionFilter: Type.Optional(Type.String({ description: '会话ID过滤' })),
|
||||
triplets: Type.Optional(Type.Array(
|
||||
Type.Object({
|
||||
subject: Type.String({ description: '主体' }),
|
||||
relation: Type.String({ description: '关系' }),
|
||||
object: Type.String({ description: '客体' }),
|
||||
confidence: Type.Optional(Type.Number({ description: '置信度' }))
|
||||
}, { description: '三元组' }),
|
||||
{ description: '三元组数组' }
|
||||
)),
|
||||
sessionId: Type.Optional(Type.String({ description: '会话ID' })),
|
||||
turnId: Type.Optional(Type.Number({ description: '轮次ID' })),
|
||||
criteria: Type.Optional(Type.Object({
|
||||
subject: Type.Optional(Type.String({ description: '主体' })),
|
||||
target: Type.Optional(Type.String({ description: '客体' })),
|
||||
relation: Type.Optional(Type.String({ description: '关系' })),
|
||||
sessionId: Type.Optional(Type.String({ description: '会话ID' }))
|
||||
}, { description: '删除条件' })),
|
||||
mode: Type.Optional(Type.String({
|
||||
enum: ['soft', 'hard', 'supersede'],
|
||||
description: '删除模式'
|
||||
})),
|
||||
newRelation: Type.Optional(Type.Object({
|
||||
relation: Type.String({ description: '关系' }),
|
||||
target: Type.String({ description: '客体' })
|
||||
}, { description: '新关系(supersede模式)' })),
|
||||
attributes: Type.Optional(Type.Array(
|
||||
Type.Object({
|
||||
attribute: Type.String({ description: '属性名' }),
|
||||
value: Type.String({ description: '属性值' })
|
||||
}, { description: '属性' }),
|
||||
{ description: '属性数组' }
|
||||
)),
|
||||
confirm: Type.Optional(Type.Boolean({ description: '确认清除' })),
|
||||
task_id: Type.Optional(Type.String({ description: '任务ID' })),
|
||||
description: Type.Optional(Type.String({ description: '任务描述' })),
|
||||
state: Type.Optional(Type.String({ description: '任务状态' })),
|
||||
info_nodes: Type.Optional(Type.Array(Type.String({ description: '节点' }), { description: '信息节点' })),
|
||||
info_node: Type.Optional(Type.String({ description: '信息节点' })),
|
||||
days: Type.Optional(Type.Number({ description: '归档天数' })),
|
||||
dry_run: Type.Optional(Type.Boolean({ description: '仅预览不删除' }))
|
||||
}, { description: '操作参数' })
|
||||
});
|
||||
|
||||
export type GraphMemoryToolParams = Static<typeof GraphMemoryToolSchema>;
|
||||
|
||||
const GRAPH_MEMORY_TOOL_DESCRIPTION = `图记忆工具 - 让 AI 拥有真正的长期记忆能力
|
||||
|
||||
操作:
|
||||
- recall: 检索记忆
|
||||
- commit: 写入记忆
|
||||
- commit: 写入记忆
|
||||
- purge: 删除记忆
|
||||
- introspect: 查看状态
|
||||
- archive: 归档旧记忆
|
||||
- cleanup: 清理无效数据
|
||||
- persona_update/clear: 人设管理
|
||||
- task_create/set_state/delete: 任务管理`;
|
||||
- task_create/set_state/delete/link_info: 任务管理`;
|
||||
|
||||
export interface OpenClawToolResult {
|
||||
content: Array<{ type: 'text'; text: string }>;
|
||||
}
|
||||
export function createGraphMemoryTool(dbPath?: string, sessionId?: string) {
|
||||
const db = new GraphDatabase(dbPath, sessionId);
|
||||
const service = new MemoryService(db);
|
||||
const limiter = new ToolLimiter();
|
||||
|
||||
export class GraphMemoryTool implements Tool {
|
||||
readonly id = GRAPH_MEMORY_TOOL_ID;
|
||||
readonly name = 'GraphMemory';
|
||||
readonly description = GRAPH_MEMORY_TOOL_DESCRIPTION;
|
||||
readonly category: ToolCategory = 'analysis';
|
||||
readonly permissionLevel: PermissionLevel = 'safe';
|
||||
|
||||
readonly inputSchema: ToolInputSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
action: {
|
||||
type: 'string',
|
||||
enum: [
|
||||
'recall', 'commit', 'purge', 'introspect', 'archive', 'cleanup',
|
||||
'persona_update', 'persona_clear',
|
||||
'task_create', 'task_set_state', 'task_delete', 'task_link_info'
|
||||
],
|
||||
description: '记忆操作类型'
|
||||
},
|
||||
params: {
|
||||
type: 'object',
|
||||
description: '操作参数',
|
||||
properties: {
|
||||
queryIntent: { type: 'string', description: '搜索意图' },
|
||||
seedEntities: { type: 'array', items: { type: 'string', description: '实体' }, description: '种子实体' },
|
||||
depth: { type: 'number', description: '检索深度' },
|
||||
sessionFilter: { type: 'string', description: '会话ID过滤' },
|
||||
triplets: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
description: '三元组',
|
||||
properties: {
|
||||
subject: { type: 'string', description: '主体' },
|
||||
relation: { type: 'string', description: '关系' },
|
||||
object: { type: 'string', description: '客体' },
|
||||
confidence: { type: 'number', description: '置信度' }
|
||||
}
|
||||
},
|
||||
description: '三元组数组'
|
||||
},
|
||||
sessionId: { type: 'string', description: '会话ID' },
|
||||
turnId: { type: 'number', description: '轮次ID' },
|
||||
criteria: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
subject: { type: 'string', description: '主体' },
|
||||
target: { type: 'string', description: '客体' },
|
||||
relation: { type: 'string', description: '关系' },
|
||||
sessionId: { type: 'string', description: '会话ID' }
|
||||
},
|
||||
description: '删除条件'
|
||||
},
|
||||
mode: { type: 'string', enum: ['soft', 'hard', 'supersede'], description: '删除模式' },
|
||||
newRelation: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
relation: { type: 'string', description: '关系' },
|
||||
target: { type: 'string', description: '客体' }
|
||||
},
|
||||
description: '新关系(supersede模式)'
|
||||
},
|
||||
attributes: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
description: '属性',
|
||||
properties: {
|
||||
attribute: { type: 'string', description: '属性名' },
|
||||
value: { type: 'string', description: '属性值' }
|
||||
}
|
||||
},
|
||||
description: '属性数组'
|
||||
},
|
||||
confirm: { type: 'boolean', description: '确认清除' },
|
||||
task_id: { type: 'string', description: '任务ID' },
|
||||
description: { type: 'string', description: '任务描述' },
|
||||
state: { type: 'string', description: '任务状态' },
|
||||
info_nodes: { type: 'array', items: { type: 'string', description: '节点' }, description: '信息节点' },
|
||||
info_node: { type: 'string', description: '信息节点' },
|
||||
days: { type: 'number', description: '归档天数' },
|
||||
dry_run: { type: 'boolean', description: '仅预览不删除' }
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ['action', 'params']
|
||||
};
|
||||
|
||||
private db: GraphDatabase;
|
||||
private service: MemoryService;
|
||||
private limiter: ToolLimiter;
|
||||
|
||||
constructor(dbPath?: string, sessionId?: string) {
|
||||
this.db = new GraphDatabase(dbPath, sessionId);
|
||||
this.service = new MemoryService(this.db);
|
||||
this.limiter = new ToolLimiter();
|
||||
}
|
||||
|
||||
async handler(params: Record<string, unknown>, _context: ToolExecutionContext): Promise<ToolOutput> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
async execute(_toolCallId: string, params: Record<string, unknown>): Promise<OpenClawToolResult> {
|
||||
const result = await this.handler(params, {
|
||||
toolCallId: _toolCallId,
|
||||
workingDirectory: process.cwd(),
|
||||
abortController: { signal: new AbortController().signal },
|
||||
config: {},
|
||||
logger: { info: () => {}, warn: () => {}, error: () => {}, debug: () => {} }
|
||||
});
|
||||
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: typeof result === 'string' ? result : JSON.stringify(result)
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
private async executeAction(action: string, params: Record<string, unknown>): Promise<unknown> {
|
||||
const [allowed, reason] = this.limiter.canCall(action);
|
||||
async function executeAction(action: string, params: Record<string, unknown>): Promise<unknown> {
|
||||
const [allowed, reason] = limiter.canCall(action);
|
||||
if (!allowed) {
|
||||
throw new Error(reason);
|
||||
}
|
||||
this.limiter.recordCall(action);
|
||||
limiter.recordCall(action);
|
||||
|
||||
switch (action) {
|
||||
case 'recall':
|
||||
return this.service.recall({
|
||||
return service.recall({
|
||||
queryIntent: params.queryIntent as string || '',
|
||||
seedEntities: params.seedEntities as string[] | undefined,
|
||||
depth: params.depth as number | undefined,
|
||||
@ -169,79 +97,100 @@ export class GraphMemoryTool implements Tool {
|
||||
});
|
||||
|
||||
case 'commit':
|
||||
return this.service.commit({
|
||||
return service.commit({
|
||||
triplets: params.triplets as Array<{ subject: string; relation: string; object: string; confidence?: number }>,
|
||||
sessionId: params.sessionId as string | undefined,
|
||||
turnId: params.turnId as number | undefined
|
||||
});
|
||||
|
||||
case 'purge':
|
||||
return this.service.purge({
|
||||
criteria: params.criteria as { subject?: string | undefined; target?: string | undefined; relation?: string | undefined; sessionId?: string | undefined } | undefined,
|
||||
return service.purge({
|
||||
criteria: params.criteria as { subject?: string; target?: string; relation?: string; sessionId?: string } | undefined,
|
||||
mode: params.mode as 'soft' | 'hard' | 'supersede' | undefined,
|
||||
newRelation: params.newRelation as { relation: string; target: string } | undefined
|
||||
});
|
||||
|
||||
case 'introspect':
|
||||
return this.service.introspect();
|
||||
return service.introspect();
|
||||
|
||||
case 'persona_update':
|
||||
return this.service.updatePersona({
|
||||
return service.updatePersona({
|
||||
attributes: params.attributes as Array<{ attribute: string; value: string }>,
|
||||
mode: params.mode as 'merge' | 'replace'
|
||||
});
|
||||
|
||||
case 'persona_clear':
|
||||
return this.service.clearPersona({
|
||||
return service.clearPersona({
|
||||
confirm: params.confirm as boolean
|
||||
});
|
||||
|
||||
case 'task_create':
|
||||
return this.service.createTask({
|
||||
return service.createTask({
|
||||
task_id: params.task_id as string,
|
||||
description: params.description as string,
|
||||
info_nodes: params.info_nodes as string[] | undefined
|
||||
});
|
||||
|
||||
case 'task_set_state':
|
||||
return this.service.setTaskState({
|
||||
return service.setTaskState({
|
||||
task_id: params.task_id as string,
|
||||
state: params.state as string
|
||||
});
|
||||
|
||||
case 'task_delete':
|
||||
return this.service.deleteTask({
|
||||
return service.deleteTask({
|
||||
task_id: params.task_id as string
|
||||
});
|
||||
|
||||
case 'task_link_info':
|
||||
return this.service.linkInfoToTask({
|
||||
return service.linkInfoToTask({
|
||||
task_id: params.task_id as string,
|
||||
info_node: params.info_node as string
|
||||
});
|
||||
|
||||
case 'archive':
|
||||
return this.service.archive(params.days as number | undefined);
|
||||
return service.archive(params.days as number | undefined);
|
||||
|
||||
case 'cleanup':
|
||||
return this.service.cleanup(params.dry_run as boolean | undefined);
|
||||
return service.cleanup(params.dry_run as boolean | undefined);
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown action: ${action}`);
|
||||
}
|
||||
}
|
||||
|
||||
resetLimiter(): void {
|
||||
this.limiter.reset();
|
||||
}
|
||||
return {
|
||||
name: 'graph_memory',
|
||||
description: GRAPH_MEMORY_TOOL_DESCRIPTION,
|
||||
parameters: GraphMemoryToolSchema,
|
||||
|
||||
getLimiterSummary(): string {
|
||||
return this.limiter.getSummary();
|
||||
}
|
||||
async execute(_toolCallId: string, params: Record<string, unknown>): Promise<{
|
||||
content: Array<{ type: 'text'; text: string }>;
|
||||
}> {
|
||||
const action = params.action as string;
|
||||
const actionParams = params.params as Record<string, unknown>;
|
||||
|
||||
try {
|
||||
const result = await executeAction(action, actionParams);
|
||||
return {
|
||||
content: [{ type: 'text', text: JSON.stringify({ success: true, data: result }) }]
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: JSON.stringify({
|
||||
success: false,
|
||||
error: {
|
||||
type: 'execution_error',
|
||||
message: error instanceof Error ? error.message : String(error)
|
||||
}
|
||||
})
|
||||
}]
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createGraphMemoryTool(dbPath?: string, sessionId?: string): GraphMemoryTool {
|
||||
return new GraphMemoryTool(dbPath, sessionId);
|
||||
}
|
||||
|
||||
export { ToolLimiter } from '../tool_limiter';
|
||||
export { ToolLimiter } from '../tool_limiter.js';
|
||||
@ -1,59 +0,0 @@
|
||||
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?: unknown;
|
||||
examples?: unknown[];
|
||||
items?: SchemaProperty;
|
||||
properties?: Record<string, SchemaProperty>;
|
||||
}
|
||||
|
||||
export interface ToolInputSchema {
|
||||
type: 'object';
|
||||
properties: Record<string, SchemaProperty>;
|
||||
required?: string[];
|
||||
additionalProperties?: boolean;
|
||||
}
|
||||
|
||||
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 ToolExecutionContext {
|
||||
toolCallId: string;
|
||||
workingDirectory: string;
|
||||
abortController: { signal: AbortSignal };
|
||||
config: { timeout?: number };
|
||||
logger: { info: (...args: unknown[]) => void; warn: (...args: unknown[]) => void; error: (...args: unknown[]) => void; debug: (...args: unknown[]) => void };
|
||||
}
|
||||
|
||||
export type ToolHandler = (params: ToolInput, context: ToolExecutionContext) => Promise<ToolOutput>;
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user