# Tool Agent 内部接口文档

## 目录

1. [数据模型](#1-数据模型)
2. [工具注册表格式](#2-工具注册表格式-registryjson)
3. [来源存储格式](#3-来源存储格式-sourcesjson)
4. [容器状态表格式](#4-容器状态表格式-containersjson)
5. [任务书格式](#5-任务书格式-task_spec)
6. [内部消息格式](#6-内部消息格式-agentmessage)
7. [对外 HTTP 接口](#7-对外-http-接口)
8. [Coding Agent 工具接口](#8-coding-agent-工具接口)
9. [配置参数](#9-配置参数)
10. [Router 工具匹配与对接](#10-router-工具匹配与对接)

---

## 1. 数据模型

### 1.1 枚举类型

> **架构约束**：所有工具对外统一为本地 Python/FastAPI 调用层（uv 管理）。
> `SourceType` / `BackendRuntime` 表示工具**内部的后端执行环境**，不是调用方式。

| 枚举 | 值 | 说明 |
|------|-----|------|
| ToolStatus | `active`, `inactive`, `staging`, `building` | 工具生命周期状态 |
| MessageType | `tool_request`, `tool_ready`, `tool_error`, `health_alert` | 内部消息类型 |
| ContainerStatus | `running`, `destroyed` | 容器状态 |
| SourceType | `local`, `docker`, `remote` | 工具来源类型（后端执行环境） |
| ProcessState | `stopped`, `starting`, `running`, `error` | 进程运行状态 |

### 1.2 ToolMeta（工具元信息）

```json
{
  "tool_id": "image_compress_api",
  "name": "图片压缩 API",
  "category": "cv",
  "description": "基于 PIL 的图片压缩服务",
  "input_schema": {
    "type": "object",
    "properties": {
      "image_path": {"type": "string"},
      "quality": {"type": "integer", "minimum": 1, "maximum": 100}
    },
    "required": ["image_path"]
  },
  "output_schema": {
    "type": "object",
    "properties": {
      "compressed_size": {"type": "integer"},
      "compression_ratio": {"type": "number"}
    }
  },
  "stream_support": false,
  "status": "active"
}
```

### 1.3 ToolSource（工具来源）

```json
{
  "type": "local",
  "host_dir": "tools/local/image_compress_api",
  "endpoint_path": "/",
  "http_method": "POST",
  "internal_port": 0
}
```

Docker 类型：
```json
{
  "type": "docker",
  "container_id": "25e884ca6cec...",
  "image": "ubuntu:22.04",
  "internal_port": 8080,
  "endpoint_path": "/api/compress",
  "http_method": "POST"
}
```

Hub 类型（外部 API）：
```json
{
  "type": "remote",
  "remote_url": "https://api.example.com",
  "remote_path": "/v1/compress",
  "remote_api_key": "sk-***",
  "endpoint_path": "/v1/compress",
  "http_method": "POST"
}
```

### 1.4 ToolRoute（运行状态）

```json
{
  "tool_id": "image_compress_api",
  "sources": [
    {"type": "local", "host_dir": "tools/local/image_compress_api"}
  ],
  "active_source": 0,
  "state": "running",
  "pid": 12345,
  "port": 52341,
  "started_at": "2026-03-26T10:30:00Z",
  "last_error": null
}
```

### 1.5 ContainerInfo（容器信息）

```json
{
  "container_id": "25e884ca6cecfa87e19ea737315a8773d...",
  "tool_id": "test_git_tool",
  "image": "ubuntu:22.04",
  "port_mapping": {"8080": 9001, "3306": 9002},
  "volumes": {"C:/staging/project": "/app"},
  "mem_limit": "1g",
  "nano_cpus": 1000000000,
  "use_gpu": false,
  "gpu_count": -1,
  "status": "running",
  "created_at": "2026-03-20T07:31:50.421101Z",
  "last_accessed": "2026-03-20T07:33:16.214642+00:00",
  "destroyed_at": null
}
```

---

## 2. 工具注册表格式 (registry.json)

路径：`data/registry.json`

```json
{
  "tools": [
    {
      "tool_id": "image_compress_api",
      "name": "图片压缩 API",
      "category": "cv",
      "description": "基于 PIL 的图片压缩",
      "input_schema": {},
      "output_schema": {},
      "stream_support": false,
      "status": "active"
    }
  ],
  "version": "2.0"
}
```

### Registry 查询接口

**ToolRegistry 类方法**：

| 方法 | 参数 | 返回 |
|------|------|------|
| `get(tool_id)` | tool_id | ToolMeta \| None |
| `list_all()` | - | list[ToolMeta] |
| `list_active()` | - | list[ToolMeta] |
| `find_by_category(category)` | category | list[ToolMeta] |
| `search(keyword)` | keyword | list[ToolMeta] |
| `register(tool)` | ToolMeta | None |
| `unregister(tool_id)` | tool_id | bool |
| `destroy(tool_id)` | tool_id | dict（清理结果） |

---

## 3. 来源存储格式 (sources.json)

路径：`data/sources.json`

```json
{
  "sources": {
    "image_compress_api": [
      {
        "type": "local",
        "host_dir": "tools/local/image_compress_api",
        "endpoint_path": "/",
        "http_method": "POST",
        "internal_port": 0
      }
    ],
    "gpu_tool": [
      {
        "type": "docker",
        "container_id": "abc123...",
        "internal_port": 8080,
        "endpoint_path": "/api/run",
        "http_method": "POST"
      }
    ]
  }
}
```

### SourceStore 接口

| 方法 | 参数 | 返回 |
|------|------|------|
| `load()` | - | dict[str, list[dict]] |
| `save(sources)` | sources | None |
| `add_source(tool_id, source)` | tool_id, ToolSource | None |
| `get_sources(tool_id)` | tool_id | list[ToolSource] |
| `remove_tool(tool_id)` | tool_id | None |

---

## 4. 容器状态表格式 (containers.json)

路径：`data/containers.json`

```json
{
  "containers": [
    {
      "container_id": "25e884ca6cec...",
      "tool_id": "gpu_tool",
      "image": "ubuntu:22.04",
      "port_mapping": {"8080": 9001},
      "volumes": {"C:/staging/project": "/app"},
      "mem_limit": "1g",
      "nano_cpus": 1000000000,
      "use_gpu": false,
      "status": "running",
      "created_at": "2026-03-20T07:31:50Z"
    }
  ]
}
```

---

## 5. 任务书格式 (task_spec)

Router 生成任务书，通过 `asyncio.create_task` 提交给 CodingAgent。

### 5.1 GitHub 项目接入任务

```json
{
  "type": "github_deploy",
  "repo_url": "https://github.com/user/project",
  "tool_name": "project_api",
  "runtime": "docker",
  "description": "将该项目部署为 HTTP API 工具"
}
```

### 5.2 自主编写工具任务

```json
{
  "type": "build_tool",
  "tool_name": "text_summarizer_api",
  "runtime": "uv",
  "description": "编写一个文本摘要工具，接受文本输入，返回摘要"
}
```

### 5.3 工具修复任务

```json
{
  "type": "repair_tool",
  "tool_id": "image_compress_api",
  "error": "HTTP 503: Service Unavailable",
  "description": "工具健康检查失败，需要诊断并修复"
}
```

---

## 6. 内部消息格式 (AgentMessage)

Router 与 CodingAgent 通过 `MessageBus`（`asyncio.Queue`）通信。

**当前状态**：MessageBus 已实现但未集成，Router 通过直接函数调用启动 CodingAgent。

```json
{
  "type": "tool_request | tool_ready | tool_error | health_alert",
  "payload": {}
}
```

### 6.1 tool_request（Router → Coding）

```json
{
  "type": "tool_request",
  "payload": {
    "task_spec": "{ /* 任务书 JSON */ }",
    "task_id": "550e8400-e29b-41d4-a716-446655440000",
    "description": "需要一个图片压缩工具",
    "reference_files": ["tools/local/example/main.py"]
  }
}
```

### 6.2 tool_ready（Coding → Router）

```json
{
  "type": "tool_ready",
  "payload": {
    "tool_id": "image_compress_api",
    "result": "部署成功，工具已注册",
    "task_id": "550e8400-..."
  }
}
```

### 6.3 tool_error（Coding → Router）

```json
{
  "type": "tool_error",
  "payload": {
    "tool_id": "failed_tool",
    "error": "依赖安装失败：torch 需要 CUDA 但未检测到 GPU",
    "task_id": "550e8400-..."
  }
}
```

### 6.4 health_alert（Router → Coding）

```json
{
  "type": "health_alert",
  "payload": {
    "tool_id": "image_compress_api",
    "error": "HTTP 503",
    "last_healthy": "2026-03-20T10:00:00Z"
  }
}
```

---

## 7. 对外 HTTP 接口

基础地址：`http://localhost:8001`

### GET /health

```json
// Response
{"status": "ok"}
```

### POST /search_tools

搜索可用工具列表，返回工具信息及运行状态。

```json
// Request
{
  "keyword": "图片",
  "category": "cv"
}

// Response
{
  "tools": [
    {
      "tool_id": "image_compress_api",
      "name": "图片压缩 API",
      "category": "cv",
      "description": "基于 PIL 的图片压缩",
      "params": [
        {
          "name": "image_path",
          "type": "string",
          "description": "图片路径",
          "required": true
        }
      ],
      "required_params": ["image_path"],
      "input_schema": {},
      "output_schema": {},
      "backend_runtime": "local",
      "host_dir": "tools/local/image_compress_api",
      "endpoint_path": "/",
      "http_method": "POST",
      "state": "running",
      "port": 52341,
      "pid": 12345
    }
  ],
  "total": 1
}
```

### POST /select_tool

选择并调用工具（未启动则自动启动）。

```json
// Request
{
  "tool_id": "image_compress_api",
  "params": {"image_path": "/path/to/img.jpg", "quality": 85},
  "stream": false
}

// Response
{
  "status": "success",
  "result": {"compressed_size": 256000, "compression_ratio": 0.25},
  "error": null
}
```

### POST /create_tool

提交新工具创建需求（异步）。

```json
// Request
{
  "description": "需要一个图片压缩工具",
  "task_spec": "详细任务描述..."
}

// Response
{
  "task_id": "create_a1b2c3d4",
  "status": "pending",
  "message": "Task submitted"
}
```

### GET /tasks/{task_id}

查询异步任务状态。

```json
// Response
{
  "task_id": "create_a1b2c3d4",
  "status": "completed",
  "result": "工具已成功注册",
  "task_spec": "..."
}
```

### GET /tools/status

列出所有工具运行状态。

```json
// Response
{
  "tools": [
    {
      "tool_id": "image_compress_api",
      "sources": [...],
      "active_source": 0,
      "state": "running",
      "pid": 12345,
      "port": 52341
    }
  ]
}
```

### POST /tools/{tool_id}/start

手动启动工具。

```json
// Response
{
  "tool_id": "image_compress_api",
  "state": "running",
  "port": 52341
}
```

### POST /tools/{tool_id}/stop

手动停止工具。

```json
// Response
{
  "tool_id": "image_compress_api",
  "state": "stopped"
}
```

### POST /agent/chat

与 Router Agent 对话交互（自然语言）。

**设计理念**：外部 Agent 通过自然语言与 Router 交互，Router 理解意图后返回结构化方案，更加人性化和灵活。

**支持场景**：
- 工具发现与推荐
- 工具使用方案指导
- 组合工具使用说明（如 ComfyUI）
- 工具创建请求

```json
// Request
{
  "message": "用户的自然语言请求",
  "context": {}  // 可选的上下文信息
}

// Response
{
  "reply": "Router 的回复",
  "tools": [],      // 相关工具列表（可选）
  "solution": {},   // 解决方案（可选）
  "task_id": "",    // 任务 ID（创建工具时）
  "next_steps": []  // 后续操作建议
}
```

**示例 1：工具发现**

```json
// Request
{
  "message": "我需要处理图片的工具",
  "context": {"task": "批量压缩图片"}
}

// Response
{
  "reply": "找到 2 个图片处理工具，推荐使用 image_compress_api",
  "tools": [
    {
      "tool_id": "image_compress_api",
      "name": "图片压缩 API",
      "reason": "专门用于图片压缩，支持质量调节",
      "usage_example": {
        "params": {"image_path": "/path/to/image.jpg", "quality": 85}
      }
    }
  ],
  "next_steps": ["调用 /select_tool 使用该工具"]
}
```

**示例 2：ComfyUI 工具使用指导**

```json
// Request
{
  "message": "如何使用 ComfyUI 的 LoadImage 和 SaveImage 节点？"
}

// Response
{
  "reply": "ComfyUI 节点已通过 runcomfy 工具接入，需要三步操作",
  "solution": {
    "type": "composite_workflow",
    "base_tools": ["runcomfy_launch_env", "runcomfy_run_only", "runcomfy_stop_env"],
    "steps": [
      {
        "step": 1,
        "action": "启动环境",
        "tool": "runcomfy_launch_env",
        "params": {},
        "returns": "container_id"
      },
      {
        "step": 2,
        "action": "执行 workflow",
        "tool": "runcomfy_run_only",
        "params": {
          "container_id": "<from_step_1>",
          "workflow": {
            "nodes": [
              {"id": 1, "type": "LoadImage", "inputs": {"image": "input.png"}},
              {"id": 2, "type": "SaveImage", "inputs": {"images": ["1", 0]}}
            ]
          }
        }
      },
      {
        "step": 3,
        "action": "清理环境",
        "tool": "runcomfy_stop_env",
        "params": {"container_id": "<from_step_1>"}
      }
    ]
  }
}
```

**示例 3：工具创建**

```json
// Request
{
  "message": "帮我创建一个文本摘要工具",
  "context": {"requirements": "支持中英文，最大长度 500 字"}
}

// Response
{
  "reply": "已提交工具创建任务，预计 2-3 分钟完成",
  "task_id": "create_a1b2c3d4",
  "status": "pending",
  "tracking": "使用 GET /tasks/create_a1b2c3d4 查询进度",
  "estimated_time": "2-3 分钟"
}
```

---

## 8. Coding Agent 工具接口

CodingAgent 通过 `claude_agent_sdk` 暴露以下 10 个工具：

### Docker 环境

| 工具 | 必填参数 | 可选参数 | 返回 |
|------|----------|----------|------|
| `create_docker_env` | `image` | `mem_limit`, `nano_cpus`, `ports`, `volumes`, `use_gpu` | `container_id`, `port_mapping` |
| `run_in_docker` | `container_id`, `command` | `is_background`, `timeout` | `exit_code`, `stdout`, `stderr` 或 `log_file` |
| `rebuild_docker_ports` | `container_id`, `ports` | `mem_limit`, `nano_cpus` | `new_container_id`, `port_mapping` |
| `destroy_docker_env` | `container_id` | — | `status`, `message` |

### 本地 uv 环境

| 工具 | 必填参数 | 可选参数 | 返回 |
|------|----------|----------|------|
| `create_uv_project` | `name` | `python_version` | `project_dir` |
| `run_in_uv` | `project_dir`, `command` | `is_background`, `timeout` | `exit_code`, `stdout`, `stderr` |
| `uv_add_dependency` | `project_dir`, `package` | `dev` | `status`, `message` |

### 文件操作

| 工具 | 必填参数 | 返回 |
|------|----------|------|
| `write_file` | `path`, `content` | `status`, `path`, `size` |
| `read_file` | `path` | `status`, `path`, `content` |

### 注册

| 工具 | 必填参数 | 可选参数 | 返回 |
|------|----------|----------|------|
| `register_tool` | `tool_id`, `name`, `description`, `runtime_type`, `internal_port` | `category`, `input_schema`, `output_schema`, `container_id`, `host_dir`, `endpoint_path`, `http_method`, `group_ids` | `status`, `tool_id`, `backend_runtime`, `message` |

---

## 9. 配置参数

### Settings（环境变量前缀：`TOOL_AGENT_`）

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `fastapi_port` | int | `8001` | 对外 HTTP 端口 |
| `mcp_port` | int | `8001` | MCP Server 端口 |
| `docker_port_start` | int | `9001` | Docker 端口起始 |
| `docker_base_image` | str | `"agent-sandbox:latest"` | 默认基础镜像 |
| `docker_mem_limit` | str | `"1g"` | 默认容器内存 |
| `docker_nano_cpus` | int | `1000000000` | 默认 CPU（1 核） |
| `docker_ttl_seconds` | int | `1800` | 容器自动清理 TTL |
| `cold_tool_idle_timeout_s` | int | `300` | 冷工具空闲超时 |
| `hot_tool_max_containers` | int | `5` | 最大热工具容器数 |
| `eviction_policy` | str | `"lru"` | 置换策略 |
| `monthly_limit_usd` | float | `100.0` | 月预算上限 |
| `single_tx_limit_usd` | float | `20.0` | 单笔上限 |
| `require_approval_above_usd` | float | `10.0` | 需审批阈值 |
| `health_check_interval_s` | int | `60` | 健康检查间隔 |

---

## 10. Router 工具匹配与对接

### 10.1 职责

Router 负责与外部 Agent 对话，将自身工具库与外部工具表进行匹配和对接。

### 10.2 工具匹配策略

当外部 Agent 请求工具时，Router 执行以下匹配逻辑：

```
外部 Agent 请求工具 X
       │
       ▼
Router 查询 registry.json
       │
       ├─ 直接匹配：tool_id 或 name 完全匹配
       │   → 返回工具信息，调用 /select_tool
       │
       ├─ 模糊匹配：keyword 匹配 description
       │   → 返回候选列表，由外部 Agent 选择
       │
       ├─ 组合工具匹配：检测是否为复合工具需求
       │   → 例如：ComfyUI 节点工具
       │   → 检查是否有基础工具（如 runcomfy）
       │   → 返回基础工具 + 使用说明
       │
       └─ 无匹配：返回 404
           → 外部 Agent 可选择提交 /create_tool 请求
```

### 10.3 ComfyUI 工具对接示例

**场景**：外部 Agent 请求使用 ComfyUI 内部节点（如 `LoadImage`, `SaveImage`）

**Router 响应策略**：

1. **检测 ComfyUI 相关关键词**：
   - 请求中包含 `comfyui`, `workflow`, `node` 等关键词
   - 或请求的 tool_id 包含 comfyui 相关命名

2. **查询基础工具**：
   - 检查 registry 中是否有 `runcomfy` 相关工具
   - 例如：`runcomfy_launch_env`, `runcomfy_run_only`, `runcomfy_stop_env`

3. **返回组合工具信息**：

```json
{
  "status": "composite_tool",
  "message": "ComfyUI 节点工具已通过 runcomfy 基础工具接入",
  "base_tools": [
    {
      "tool_id": "runcomfy_launch_env",
      "name": "启动 ComfyUI 环境",
      "description": "启动 ComfyUI Docker 环境，返回容器 ID 和端口",
      "usage": "先调用此工具启动环境，获取 container_id"
    },
    {
      "tool_id": "runcomfy_run_only",
      "name": "执行 ComfyUI Workflow",
      "description": "在已启动的环境中执行 workflow JSON",
      "usage": "传入 workflow JSON 和 container_id，执行节点流程"
    },
    {
      "tool_id": "runcomfy_stop_env",
      "name": "停止 ComfyUI 环境",
      "description": "停止并清理 ComfyUI 容器",
      "usage": "任务完成后调用，释放资源"
    }
  ],
  "workflow_example": {
    "description": "使用 LoadImage 和 SaveImage 节点的示例",
    "steps": [
      "1. 调用 runcomfy_launch_env 启动环境",
      "2. 构造 workflow JSON（包含 LoadImage, SaveImage 节点）",
      "3. 调用 runcomfy_run_only 执行 workflow",
      "4. 获取输出结果",
      "5. 调用 runcomfy_stop_env 清理环境"
    ],
    "workflow_json": {
      "nodes": [
        {"id": 1, "type": "LoadImage", "inputs": {"image": "input.png"}},
        {"id": 2, "type": "SaveImage", "inputs": {"images": ["1", 0]}}
      ]
    }
  }
}
```

### 10.4 工具对接接口

Router 提供以下内部方法支持工具匹配：

| 方法 | 参数 | 返回 | 说明 |
|------|------|------|------|
| `match_tool(query)` | query: str | ToolMeta \| None | 精确匹配 tool_id 或 name |
| `search_tools(keyword, category)` | keyword, category | list[ToolMeta] | 模糊搜索 |
| `detect_composite_tool(query)` | query: str | dict \| None | 检测是否为组合工具需求 |
| `get_base_tools(composite_type)` | composite_type: str | list[ToolMeta] | 获取基础工具列表 |

### 10.5 扩展：外部工具表对接

**未来规划**：Router 可对接外部工具表（如其他 Agent 系统的工具库）

```json
// 外部工具表注册
POST /external_tools/register
{
  "source": "agent_system_x",
  "tools_url": "https://agent-x.com/api/tools",
  "api_key": "sk-***"
}

// Router 查询时同时搜索本地 + 外部工具表
// 返回统一格式的工具列表
```

---

## 附录：工作日志格式

### LocalRunner 命令日志 (last_run.log)

路径：`{project_dir}/last_run.log`

```
Command: python main.py
Exit Code: 0
--- STDOUT ---
Server started on port 8080
--- STDERR ---
WARNING: Using development server
```

### CodingAgent 执行日志（stdout）

```
2026-03-26 15:09:32 [tool_agent.tool.agent] INFO: [CodingAgent] Starting task: 部署 flask 项目...
2026-03-26 15:09:35 [tool_agent.tool.agent] INFO: [TOOL_USE] create_docker_env | {"image":"python:3.12-slim","ports":[8080]}
2026-03-26 15:09:40 [tool_agent.tool.agent] INFO: [TEXT] 正在创建 Docker 环境...
2026-03-26 15:10:15 [tool_agent.tool.agent] INFO: [TOOL_USE] register_tool | {"tool_id":"flask_api",...}
2026-03-26 15:10:16 [tool_agent.tool.agent] INFO: [DONE] duration=44000ms
2026-03-26 15:10:16 [tool_agent.tool.agent] INFO: [COST] $0.12
```
