GPU_GUARD_MONOREPO/docs/superpowers/plans/2026-04-18-tool-management-and-agent-tool-governance-impl-plan.md

1085 lines
25 KiB
Markdown
Raw Normal View History

2026-05-20 21:39:12 +08:00
# Tool 管理 + Agent 工具授权 + 多模态 OCR 前置治理 实施文档
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 为 Neta 实现一套真正可落地的 Tool 治理体系,包括全局 Tool 管理、Agent 级 toolset/tool 授权、运行时统一 Tool 解析、Prompt Builder 接入、前端管理页面和后续多模态 OCR 接入的前置能力。
**Architecture:** 保留现有 `catalog.ts` 作为代码注册层,新增 `netaclaw_tool` 作为全局治理表,扩展 `netaclaw_agent``toolsets/tools` 配置,新增 `tool_registry.ts``tool_resolver.ts` 统一打通 catalog、DB 配置、Agent 授权、模型能力约束和运行时 Tool 实例组装。前端新增 Tool 管理页和 Agent 编辑页中的工具配置 Tab。Prompt Builder 改为消费 resolver 的结果,而不是静态推导工具列表。
**V1 Scope Constraint:** 首版 Agent 授权模型收敛为 `toolsets + tools.disabled``tools.enabled` 不进入首版实施,避免 UI、运行时、数据库语义同时过重。
**Tech Stack:** MySQL + TypeORM + Midway.js + Vue 3 + Element Plus + TypeScript
**Spec:** `docs/superpowers/specs/2026-04-18-tool-management-and-agent-tool-governance-design.md`
---
## 一、实施范围
本实施覆盖以下内容:
1. 数据库表与字段设计落库
2. 后端 Tool 元数据同步与运行时解析
3. Agent 配置模型扩展
4. Prompt Builder 接入 Tool Resolver
5. 前端 Tool 管理页面
6. 前端 Agent 编辑页工具配置
7. 联调、验收、回滚预案
本实施不直接实现 OCR但会为 OCR 接入完成全部前置基础设施。
---
## 二、文件结构
### 新增文件
| 文件 | 职责 |
|------|------|
| `packages/backend/src/modules/netaclaw/entity/tool.ts` | Tool 全局治理实体 |
| `packages/backend/src/modules/netaclaw/service/tool_registry.ts` | catalog -> DB 同步、后台查询 |
| `packages/backend/src/modules/netaclaw/service/tool_resolver.ts` | 运行时统一工具解析 |
| `packages/backend/src/modules/netaclaw/controller/admin/tool.ts` | Tool 管理接口 |
| `packages/frontend/src/modules/agent/views/tools.vue` | Tool 管理页面 |
### 修改文件
| 文件 | 改动 |
|------|------|
| `packages/backend/src/entities.ts` | 注册新实体 |
| `packages/backend/src/modules/netaclaw/tools/catalog.ts` | 扩展 ToolSchema 元数据 |
| `packages/backend/src/modules/netaclaw/tools/common.ts` | 对齐 visibility/capability 类型 |
| `packages/backend/src/modules/netaclaw/entity/agent.ts` | 新增 `toolsets``tools` 字段 |
| `packages/backend/src/modules/netaclaw/service/agent_executor.ts` | 改为使用 Tool Resolver |
| `packages/backend/src/modules/netaclaw/gateway/server.ts` | 改为使用 Tool Resolver |
| `packages/backend/src/modules/netaclaw/service/crew_orchestrator.ts` | 接入 Tool Resolver |
| `packages/backend/src/modules/netaclaw/service/crew_delegate.ts` | 接入 Tool Resolver |
| `packages/backend/src/modules/netaclaw/runtime/prompt_builder.ts` | 接入 resolved tool names + prompt hints |
| `packages/backend/src/modules/netaclaw/runtime/prompt_guidance.ts` | 支持 tool prompt hint 注入 |
| `packages/backend/src/modules/netaclaw/service/skill_context.ts` | 改为消费 resolver 输出的 builtin tool names |
| `packages/backend/src/modules/netaclaw/controller/agent.ts` | previewPrompt 接入 resolver |
| `packages/frontend/src/modules/agent/config.ts` | 新增 Tool 管理菜单 |
| `packages/frontend/src/modules/agent/views/agent-edit.vue` | 新增“工具配置”Tab |
| `packages/frontend/src/modules/agent/types/index.d.ts` | 扩展 Agent 类型定义 |
---
## 三、数据库实施
## Task 1: 新增 Tool 治理表
**Files:**
- Create: `packages/backend/src/modules/netaclaw/entity/tool.ts`
- Modify: `packages/backend/src/entities.ts`
- [ ] **Step 1: 创建 `tool.ts` Entity**
```typescript
// packages/backend/src/modules/netaclaw/entity/tool.ts
import { BaseEntity } from '../../base/entity/base.js';
import { Column, Entity, Index } from 'typeorm';
@Entity('netaclaw_tool')
export class NetaClawToolEntity extends BaseEntity {
@Index({ unique: true })
@Column({ comment: 'Tool 名称', length: 100 })
name: string;
@Column({ comment: '展示名', length: 200, nullable: true })
label: string;
@Index()
@Column({ comment: '所属 toolset', length: 50 })
toolset: string;
@Column({ comment: '描述', type: 'text', nullable: true })
description: string;
@Column({ comment: '可见性', length: 20, nullable: true })
visibility: string;
@Column({ comment: '能力要求', length: 20, nullable: true })
capability: string;
@Index()
@Column({ comment: '状态 0=禁用 1=启用', default: 1 })
status: number;
@Column({ comment: '是否核心工具', default: 0 })
isCore: number;
@Column({ comment: '是否允许禁用', default: 1 })
canDisable: number;
@Column({ comment: 'Prompt Hint 覆写', type: 'text', nullable: true })
promptHint: string;
@Column({ comment: '排序', default: 0 })
sort: number;
@Column({ comment: '扩展字段', type: 'json', nullable: true })
extra: Record<string, unknown>;
}
```
说明:
- `toolset/visibility/capability/isCore/canDisable` 属于代码注册镜像字段
- 后台只允许修改 `label/description/status/promptHint/sort/extra`
- 不允许将运行时能力语义下放为运营配置
- [ ] **Step 2: 在 `entities.ts` 注册 Entity**
仿照现有模式添加:
```typescript
import * as entityXX from './modules/netaclaw/entity/tool';
```
并在 `entities` 数组中追加:
```typescript
...Object.values(entityXX),
```
- [ ] **Step 3: 启动后端验证表创建**
Run: `cd packages/backend && npx midway-bin dev`
Expected:
- `netaclaw_tool` 自动建表成功
- [ ] **Step 4: 提交**
```bash
git add packages/backend/src/modules/netaclaw/entity/tool.ts packages/backend/src/entities.ts
git commit -m "feat(netaclaw): add netaclaw_tool entity for global tool governance"
```
---
## Task 2: 扩展 Agent 表
**Files:**
- Modify: `packages/backend/src/modules/netaclaw/entity/agent.ts`
- [ ] **Step 1: 新增 `toolsets` 和 `tools` 字段**
`NetaClawAgentEntity` 中新增:
```typescript
@Column({ type: 'json', comment: '启用的 toolset 列表', nullable: true })
toolsets: string[];
@Column({ type: 'json', comment: '工具精细配置', nullable: true })
tools: {
disabled?: string[];
};
```
- [ ] **Step 2: 启动后端验证字段增加**
Expected:
- `netaclaw_agent` 表新增 `toolsets``tools`
- [ ] **Step 3: 提交**
```bash
git add packages/backend/src/modules/netaclaw/entity/agent.ts
git commit -m "feat(netaclaw): extend agent entity with toolsets and tools config"
```
---
## 四、后端基础设施实施
## Task 3: 扩展 catalog 元数据
**Files:**
- Modify: `packages/backend/src/modules/netaclaw/tools/catalog.ts`
- Modify: `packages/backend/src/modules/netaclaw/tools/builtin/*.ts`(按需)
- [ ] **Step 1: 扩展 `ToolSchema`**
将:
```typescript
export interface ToolSchema {
name: string;
toolset: string;
description: string;
}
```
改为:
```typescript
export interface ToolSchema {
name: string;
toolset: string;
description: string;
visibility?: 'internal' | 'tool' | 'skill';
capability?: 'text' | 'vision' | 'multimodal';
isCore?: boolean;
canDisable?: boolean;
supportsPromptHint?: boolean;
}
```
- [ ] **Step 2: 增加 catalog 查询方法**
新增:
```typescript
export function getAllToolSchemas(): ToolSchema[] { ... }
export function getToolSchema(name: string): ToolSchema | undefined { ... }
export function getToolNamesByToolset(toolset: string): string[] { ... }
```
- [ ] **Step 3: 为核心工具补默认元数据**
至少给以下工具补齐:
- `bash`
- `read_file`
- `write_file`
- `list_dir`
- `patch`
- `clarify`
- `todo`
建议规则:
- `base` 工具默认 `capability=text`
- `clarify/todo` 默认 `isCore=1`
- `todo``visibility=internal`
- `clarify``visibility=tool`
- [ ] **Step 4: 预留 `vision` / `document` toolset 常量**
不必现在接入 OCR只需允许这些 toolset 名存在。
- [ ] **Step 5: 编译验证**
Run: `cd packages/backend && npm run build`
- [ ] **Step 6: 提交**
```bash
git add packages/backend/src/modules/netaclaw/tools/catalog.ts packages/backend/src/modules/netaclaw/tools/builtin
git commit -m "feat(netaclaw): extend tool catalog metadata for governance"
```
---
## Task 4: 新增 Tool Registry Service
**Files:**
- Create: `packages/backend/src/modules/netaclaw/service/tool_registry.ts`
- [ ] **Step 1: 创建 Service**
职责:
1. 读取 catalog 全量工具
2. 同步到 `netaclaw_tool`
3. 分页查询
4. 返回 Agent 配置可选工具
建议结构:
```typescript
@Provide()
@Scope(ScopeEnum.Singleton)
export class NetaClawToolRegistryService {
@InjectEntityModel(NetaClawToolEntity)
toolRepo: Repository<NetaClawToolEntity>;
async syncCatalogToDb() { ... }
async page(params) { ... }
async info(id: number) { ... }
async update(data) { ... }
async all() { ... }
async listForAgentConfig() { ... }
}
```
- [ ] **Step 2: 实现 `syncCatalogToDb()`**
逻辑:
1. 读取 `getAllToolSchemas()`
2. DB 无记录则插入
3. DB 已有记录则保留人工字段,仅补齐缺失元数据
4. catalog 中不存在但 DB 中存在的记录不物理删除
启动策略:
- 后端启动时自动执行一次幂等 `syncCatalogToDb()`
- `/admin/netaclaw/tool/sync` 仅作为人工刷新入口
- 不允许把首屏正确性依赖在手工点击同步按钮上
默认回填规则:
- `label = name`
- `status = 1`
- `capability = schema.capability ?? 'text'`
- `visibility = schema.visibility ?? 'tool'`
- `isCore = schema.isCore ? 1 : 0`
- `canDisable = schema.canDisable ?? (schema.isCore ? 0 : 1)`
- [ ] **Step 3: 实现 `update()` 的保护逻辑**
要求:
- `isCore=1 && canDisable=0` 时,禁止将 `status` 改为 0
- `name/toolset/visibility/capability/isCore/canDisable` 默认不允许后台修改
-`supportsPromptHint !== true`,则禁止写入 `promptHint`
- [ ] **Step 4: 编译验证**
- [ ] **Step 5: 提交**
```bash
git add packages/backend/src/modules/netaclaw/service/tool_registry.ts
git commit -m "feat(netaclaw): add tool registry service for catalog-db sync"
```
---
## Task 5: 新增 Tool Resolver Service
**Files:**
- Create: `packages/backend/src/modules/netaclaw/service/tool_resolver.ts`
- [ ] **Step 1: 创建解析接口**
```typescript
interface ResolveToolParams {
agent: NetaClawAgentEntity | null;
modelCapability?: 'text' | 'vision' | 'multimodal';
memoryEnabled?: boolean;
hasSkills?: boolean;
crewRole?: 'master' | 'sub';
}
interface ResolveToolResult {
tools: AnyAgentTool[];
toolNames: string[];
builtinToolNames: string[];
toolPromptHints: Record<string, string>;
disabledReasons: Array<{ name: string; reason: string }>;
}
```
- [ ] **Step 2: 实现 toolset 展开逻辑**
默认规则:
1. 老 Agent 无 `toolsets` 时:
- 使用 `TOOLSET_DEFAULTS`
2.`toolsets` 时:
-`toolsets` 从 catalog 展开
3. 再剔除 `tools.disabled`
- [ ] **Step 3: 实现全局 Tool 配置过滤**
`netaclaw_tool` 查询配置,过滤:
- `status=0`
- 不满足场景约束
- [ ] **Step 4: 实现 capability 过滤**
统一判断:
```typescript
function matchCapability(toolCap: string, modelCap?: string): boolean { ... }
```
规则:
- `text` 工具允许任意模型
- `vision` 工具要求 `vision|multimodal`
- `multimodal` 工具要求 `multimodal`
- [ ] **Step 4.1: 补齐模型能力来源**
要求:
- 优先在 `model_channel.ts` 的运行时解析接口中直接返回 `capability`
- `agent_executor.ts` / `gateway/server.ts` / `crew_*` 禁止各自重复解析模型能力
- 若 Agent 未绑定 channel需定义统一 fallback:
- 显式配置 capability 时用显式值
- 未配置时按 `text` 处理,并在 disabledReasons 中保留解释能力
- [ ] **Step 5: 组装运行时工具实例**
这里不要复刻 Hermes 的 handler registry。
Neta 应继续按现有工厂方式组装:
- 静态工具:
- `bashTool`
- `readFileTool`
- `writeFileTool`
- `listDirTool`
- `patchTool`
- `clarifyTool`
- Memory 工具:
-`memoryEnabled` 时工厂创建
- Skill 工具:
-`hasSkills` 时工厂创建
- Crew 工具:
-`crewRole=master` 时工厂创建
- [ ] **Step 5.1: 输出 `builtinToolNames` 给 skill context**
要求:
- resolver 需要区分“所有注入工具名”和“提供给 skill system 的 builtin tool names”
- `buildSkillContext()` 不再使用硬编码 builtin 列表
- [ ] **Step 6: 输出 `toolPromptHints`**
`netaclaw_tool.promptHint` 收集:
```typescript
{
patch: '...',
clarify: '...'
}
```
- [ ] **Step 7: 编译验证**
- [ ] **Step 8: 提交**
```bash
git add packages/backend/src/modules/netaclaw/service/tool_resolver.ts
git commit -m "feat(netaclaw): add tool resolver for runtime tool governance"
```
---
## Task 6: 新增 Tool 管理 Controller
**Files:**
- Create: `packages/backend/src/modules/netaclaw/controller/admin/tool.ts`
- [ ] **Step 1: 创建 Admin Controller**
接口:
- `/admin/netaclaw/tool/page`
- `/admin/netaclaw/tool/info`
- `/admin/netaclaw/tool/update`
- `/admin/netaclaw/tool/all`
- `/admin/netaclaw/tool/sync`
- `/admin/netaclaw/tool/forAgent`
- [ ] **Step 2: `sync` 接口调用 `syncCatalogToDb()`**
建议首次进入页面前手动调用一次,也可在服务启动时懒同步。
- [ ] **Step 3: 启动后端验证接口可达**
- [ ] **Step 4: 提交**
```bash
git add packages/backend/src/modules/netaclaw/controller/admin/tool.ts
git commit -m "feat(netaclaw): add admin tool controller"
```
---
## 五、运行时接入实施
## Task 7: 改造 agent_executor.ts
**Files:**
- Modify: `packages/backend/src/modules/netaclaw/service/agent_executor.ts`
- [ ] **Step 1: 注入 `NetaClawToolResolverService`**
新增:
```typescript
@Inject()
toolResolver: NetaClawToolResolverService;
```
- [ ] **Step 2: 删除 `defaultTools` 硬编码依赖**
从:
```typescript
private readonly defaultTools: AnyAgentTool[] = [...]
```
迁移为 resolver 统一输出。
- [ ] **Step 3: 在解析模型后得到 `modelCapability`**
从当前 channel / modelConfig 推导 capability:
1. 优先调用 `model_channel.ts` 统一运行时解析接口
2. 直接拿到 `capability`
3. 禁止在 executor 内手写重复解析逻辑
- [ ] **Step 4: 调用 resolver**
```typescript
const resolvedTools = await this.toolResolver.resolve({
agent: agentEntity,
modelCapability,
memoryEnabled: !!memoryConfig?.enabled,
hasSkills: !!agentEntity.skills?.length,
});
```
- [ ] **Step 5: 将 `resolvedTools.builtinToolNames` 传给 `buildSkillContext()`**
替换现在的硬编码:
```typescript
const builtinToolNames = ['bash', 'read_file', 'write_file', 'list_dir', 'patch'];
```
-- [ ] **Step 6: 将 `resolvedTools.toolNames` 传给 Prompt Builder**
替换现在的:
```typescript
collectAvailableToolNames(...)
```
为:
```typescript
availableToolNames: resolvedTools.toolNames
```
- [ ] **Step 7: 将 `resolvedTools.tools` 传给 runAgent**
- [ ] **Step 8: 编译验证**
- [ ] **Step 9: 提交**
```bash
git add packages/backend/src/modules/netaclaw/service/agent_executor.ts
git commit -m "refactor(netaclaw): agent executor uses tool resolver"
```
---
## Task 8: 改造 gateway/server.ts
**Files:**
- Modify: `packages/backend/src/modules/netaclaw/gateway/server.ts`
- [ ] **Step 1: 注入 Tool Resolver**
- [ ] **Step 2: 替换默认工具拼装**
要求:
- WS 路径与 REST 路径使用相同解析逻辑
- 不再各自维护工具集合
- [ ] **Step 3: Prompt Builder 改用 resolved tool names**
- [ ] **Step 4: 编译验证**
- [ ] **Step 5: 提交**
```bash
git add packages/backend/src/modules/netaclaw/gateway/server.ts
git commit -m "refactor(netaclaw): gateway uses tool resolver"
```
---
## Task 9: 改造 crew_orchestrator.ts / crew_delegate.ts
**Files:**
- Modify: `packages/backend/src/modules/netaclaw/service/crew_orchestrator.ts`
- Modify: `packages/backend/src/modules/netaclaw/service/crew_delegate.ts`
- [ ] **Step 1: master 场景接入 resolver**
`crewRole='master'`
- [ ] **Step 2: sub 场景接入 resolver**
`crewRole='sub'`
- [ ] **Step 3: 验证 `delegate_*` 只在 master 中出现**
- [ ] **Step 4: 编译验证**
- [ ] **Step 5: 提交**
```bash
git add packages/backend/src/modules/netaclaw/service/crew_orchestrator.ts packages/backend/src/modules/netaclaw/service/crew_delegate.ts
git commit -m "refactor(netaclaw): crew runtime uses tool resolver"
```
---
## 六、Prompt Builder 实施
## Task 10: prompt_builder.ts 接入 Tool Prompt Hint
**Files:**
- Modify: `packages/backend/src/modules/netaclaw/runtime/prompt_builder.ts`
- Modify: `packages/backend/src/modules/netaclaw/runtime/prompt_guidance.ts`
- Modify: `packages/backend/src/modules/netaclaw/service/skill_context.ts`
- Modify: `packages/backend/src/modules/netaclaw/controller/agent.ts`
- [ ] **Step 1: 扩展 `getToolBehaviorGuidance()`**
从:
```typescript
getToolBehaviorGuidance(toolNames: string[])
```
改为:
```typescript
getToolBehaviorGuidance(
toolNames: string[],
toolPromptHints?: Record<string, string>
)
```
逻辑:
- 若某 Tool 有 DB `promptHint` 覆写,则优先使用覆写
- 否则回退默认 guidance
- [ ] **Step 2: Prompt Builder 接收 `toolPromptHints`**
`BuildSystemPromptParams` 中新增:
```typescript
toolPromptHints?: Record<string, string>;
```
- [ ] **Step 3: skill_context 改为消费 resolver 输出**
要求:
- `buildSkillContext()` 的 builtin tool names 参数由 resolver 提供
- 不能再保留硬编码 builtin 工具列表
- [ ] **Step 4: previewPrompt 接口接入 resolver**
让预览接口返回:
- `layers`
- `toolNames`
- `disabledReasons`
这样前端可解释“为什么某工具没有被注入”。
- [ ] **Step 5: 编译验证**
- [ ] **Step 6: 提交**
```bash
git add packages/backend/src/modules/netaclaw/runtime/prompt_builder.ts packages/backend/src/modules/netaclaw/runtime/prompt_guidance.ts packages/backend/src/modules/netaclaw/service/skill_context.ts packages/backend/src/modules/netaclaw/controller/agent.ts
git commit -m "feat(netaclaw): prompt builder supports resolved tools and prompt hints"
```
---
## 七、前端实施
## Task 11: 新增 Tool 管理菜单
**Files:**
- Modify: `packages/frontend/src/modules/agent/config.ts`
- [ ] **Step 1: 在 Skill 管理上方插入路由**
```typescript
{
path: '/agent/tools',
meta: { label: 'Tool 管理' },
component: () => import('./views/tools.vue')
},
```
- [ ] **Step 2: 本地验证菜单顺序**
- [ ] **Step 3: 提交**
```bash
git add packages/frontend/src/modules/agent/config.ts
git commit -m "feat(frontend): add tool management route"
```
---
## Task 12: 实现 Tool 管理页
**Files:**
- Create: `packages/frontend/src/modules/agent/views/tools.vue`
- [ ] **Step 1: 创建页面骨架**
包含:
- 筛选区
- 表格区
- 编辑抽屉
- 同步按钮
- [ ] **Step 2: 对接接口**
使用:
- `/admin/netaclaw/tool/page`
- `/admin/netaclaw/tool/update`
- `/admin/netaclaw/tool/sync`
- [ ] **Step 3: 页面字段**
表格列:
- name
- label
- toolset
- capability
- visibility
- isCore
- status
- promptHint 状态
- [ ] **Step 4: 编辑抽屉**
允许编辑:
- label
- description
- status
- promptHint
- sort
只读:
- name
- toolset
- capability
- visibility
- isCore
- canDisable
- [ ] **Step 5: 对核心工具加禁用保护**
前端禁用开关,后端再次校验。
- [ ] **Step 6: 浏览器验证**
验证:
- 页面可打开
- 同步后出现工具列表
- 可编辑提示词
- 核心工具不能关闭
- [ ] **Step 7: 提交**
```bash
git add packages/frontend/src/modules/agent/views/tools.vue
git commit -m "feat(frontend): add tool management page"
```
---
## Task 13: 扩展前端 Agent 类型
**Files:**
- Modify: `packages/frontend/src/modules/agent/types/index.d.ts`
- [ ] **Step 1: 为 AgentInfo 增加字段**
新增:
```typescript
toolsets?: string[];
tools?: {
disabled?: string[];
};
```
- [ ] **Step 2: 编译验证**
- [ ] **Step 3: 提交**
```bash
git add packages/frontend/src/modules/agent/types/index.d.ts
git commit -m "feat(frontend): extend agent types with toolsets and tools"
```
---
## Task 14: 改造 agent-edit.vue
**Files:**
- Modify: `packages/frontend/src/modules/agent/views/agent-edit.vue`
- [ ] **Step 1: 新增“工具配置”Tab**
位置:
-`Skill配置` 平级
- [ ] **Step 2: 新增 toolset 多选区**
数据源:
- `/admin/netaclaw/tool/forAgent`
从接口中提取唯一 toolset 列表。
- [ ] **Step 3: 新增工具精细控制双栏**
展示:
- 可用工具
- 已禁用覆盖
最小实现建议:
- 左栏: 可选工具
- 右栏: 已禁用工具
通过 `toolsets` 先决定默认启用范围,`tools.disabled` 做剔除。
- [ ] **Step 4: loadAgent 回填**
回填:
- `toolsets`
- `tools.disabled`
- [ ] **Step 5: handleSave 提交**
请求体追加:
```typescript
toolsets: form.value.toolsets,
tools: form.value.tools,
```
- [ ] **Step 6: Prompt 预览展示被过滤工具**
若后端 previewPrompt 返回:
- `toolNames`
- `disabledReasons`
则页面增加一个提示区域显示。
- [ ] **Step 7: 浏览器验证**
验证:
- 可勾选 toolsets
- 可禁用单工具
- 保存后再次打开可回填
- preview 可看到过滤原因
- [ ] **Step 8: 提交**
```bash
git add packages/frontend/src/modules/agent/views/agent-edit.vue
git commit -m "feat(frontend): add agent toolsets and tools configuration tab"
```
---
## 八、联调与验收
## Task 15: 数据同步验证
- [ ] **Step 1: 启动后端**
- [ ] **Step 2: 调用 `/admin/netaclaw/tool/sync`**
Expected:
- `netaclaw_tool` 中出现 catalog 全量工具
- [ ] **Step 3: 检查核心字段**
至少检查:
- `todo`
- `clarify`
- `bash`
- `read_file`
- `patch`
---
## Task 16: Agent 工具授权联调
- [ ] **Step 1: 新建一个 Agent**
配置:
- `toolsets = ['base', 'planning']`
- `tools.disabled = ['bash']`
- [ ] **Step 2: 预览 Prompt**
Expected:
- `bash` 不在 toolNames 中
- `read_file/write_file/list_dir/patch/todo` 仍在
- [ ] **Step 3: 发起真实对话**
构造任务要求执行 bash。
Expected:
- 模型看不到 `bash`
- 不应产生 bash tool call
---
## Task 17: capability 过滤联调
- [ ] **Step 1: 准备一个 text 模型 Agent**
- [ ] **Step 2: 准备一个代码注册层声明 `capability=vision` 的测试 Tool**
要求:
- 不通过后台或 DB 手工修改 `capability`
- 若暂时没有真实视觉工具,可在本地临时注册一个测试 Tool 用于联调
- [ ] **Step 3: 预览 Prompt**
Expected:
- 该工具被过滤
- disabledReasons 中出现 `capability_mismatch`
---
## Task 18: Tool Prompt Hint 联调
- [ ] **Step 1: 在 Tool 管理页给 `patch` 写入 promptHint**
- [ ] **Step 2: 预览 Prompt**
Expected:
- Layer 4 中优先出现 DB 覆写内容,而不是默认 guidance
---
## 九、验收标准
以下全部满足才算完成:
### 数据库
- `netaclaw_tool` 表存在
- `netaclaw_agent` 新增 `toolsets/tools`
### 后端
- catalog 可同步到 DB
- Tool Resolver 成为统一事实来源
- `model_channel.ts` 统一提供运行时 `capability`
- REST/WS/Crew 三条路径都走 resolver
- skill_context 消费 resolver 输出的 builtin tool names
- previewPrompt 可返回 toolNames 和 disabledReasons
### 前端
- 出现 Tool 管理菜单与页面
- Tool 管理页可编辑全局状态和 promptHint
- Agent 编辑页可配置 toolsets 与单工具覆盖
- Prompt 预览能看到工具生效与过滤原因
### 行为
- 全局禁用的工具不会被注入
- Agent 禁用的工具不会被注入
- capability 不满足的工具不会被注入
- 核心不可禁用工具不能被后台关闭
---
## 十、回滚预案
若某阶段出问题,按以下顺序回滚。
### 1. 页面级回滚
- 隐藏 `/agent/tools`
- 隐藏 Agent 编辑页中的“工具配置”Tab
不影响现有 Agent 基本能力。
### 2. 运行时回滚
若 resolver 逻辑异常,可临时回退:
- `agent_executor.ts` 恢复 `defaultTools`
- `gateway/server.ts` 恢复原工具拼装
数据库结构可保留,不影响运行。
### 3. 数据级回滚
- `netaclaw_tool` 表可保留
- `toolsets/tools` 字段即使存在,也不影响老代码
因此本方案具备较好的渐进式上线条件。
---
## 十一、实施顺序建议
建议严格按以下顺序推进:
1. 数据库实体
2. catalog 扩展
3. tool_registry
4. tool_resolver
5. model capability 统一解析链路
6. agent_executor / gateway / crew 接入
7. prompt_builder / skill_context 接入
7. Tool 管理页
8. Agent 编辑页工具配置
9. 联调验收
不要先做前端页面。否则会出现“配置存在但运行时无效”的假闭环。
---
## 十二、后续 OCR 接入说明
当本实施完成后,接入 OCR 的工作将降维为一项普通功能开发:
1.`catalog.ts` 注册 `vision_ocr`
2. 设置:
- `toolset='vision'`
- `capability='vision'`
3. 在 Tool 管理页全局启用
4. 在 Agent 工具配置中勾选
5. 由 resolver 自动判断模型是否支持
也就是说这份实施文档完成后OCR 不再是架构问题,而只是业务工具实现问题。