# 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 不再是架构问题，而只是业务工具实现问题。
