# Remote Agents

## 文档维护规范

0. **先改文档，再动代码**
1. **文档分层，链接代码** — 格式：`module/file.py:function_name`
2. **简洁快照，日志分离** — 决策依据记录在 `knowhub/docs/decisions.md`

---

## 定位

KnowHub 服务器托管的远端 Agent，供客户端通过统一的 `agent` 工具（`agent_type="remote_xxx"`）调用。

目前部署：

| agent_type | 职责 | 允许的 skills | 核心实现 |
|------------|------|---------------|---------|
| `remote_librarian` | 知识库查询整合 / 知识上传图谱编排 | `ask_strategy`（默认）/ `upload_strategy` | `knowhub/agents/librarian.py::run_librarian` |
| `remote_research` | 深度调研，全网搜集 + 总结 | —（不支持动态 skill） | `knowhub/agents/research.py::research` |

**一个 Agent，多种模式**：Librarian 是同一个 AgentRunner，调用方通过 `skills` 参数选择当前的策略——这比通过 task 内容或独立 agent_type 区分模式更显式、更可靠。

**skills 的语义**：
- 由 caller 指定（`agent` 工具的 `skills` 参数透传到 HTTP body）
- 服务器按每个 agent_type 的 `ALLOWED_SKILLS` 白名单过滤（非法 skill 被忽略并打 warning）
- 不在白名单的 skill 不会影响 Agent 行为，也不会导致请求失败

所有 agent 调用同步执行——服务器处理完成后才返回结果。

---

## 远端 Agent 的安全约束

新增远端 Agent 时，handler 构造的 `RunConfig` 必须显式满足三条：

| 约束 | 如何配置 |
|------|---------|
| **禁止调用 `agent` / `evaluate` 工具** | 用 `tools=[...]` 精确列表不含它们；或 `tool_groups + exclude_tools=["agent","evaluate"]` |
| **关闭自动知识提取 / 复盘** | `knowledge=KnowledgeConfig(enable_extraction=False, enable_completion_extraction=False, ...)` |
| **关闭自动知识注入** | `knowledge=KnowledgeConfig(enable_injection=False, ...)` |

原因：
- 递归 `agent`：remote agent 在服务器上再派生子 Agent 会污染服务器 trace；调 `remote_*` 则 HTTP 回调自己
- 自动知识操作：`enable_injection=True` 会在 focus goal 时调 `remote_librarian` → 服务器自己调自己 → 递归

当前实现参考：`knowhub/agents/librarian.py::get_librarian_config`（显式 tool 列表 + knowledge 全关）、`knowhub/agents/research.py::research`（`tool_groups + exclude_tools` + knowledge 全关）。

新增远端 Agent 只需：在 `knowhub/agents/` 下写实现 + prompt + 定义 `ALLOWED_SKILLS`，在 `knowhub/server.py::_get_remote_agent_dispatch` 的分发表里登记 `agent_type`。客户端零改动。

---

## 架构

```
端侧 Agent
  └── agent 工具（统一入口，按 agent_type 路由）
        ↓ HTTP
      POST /api/agent
        → 服务器按 agent_type 分发到对应 AgentRunner
```

远端 Agent 不是常驻进程。每次 HTTP 请求触发一次 `AgentRunner.run()`，状态持久化到服务器本地的 `.trace/`。

**续跑**：客户端显式传 `continue_from=<sub_trace_id>`。服务器不维护 caller → sub_trace 映射，caller 自己记住并回传。

**知识上传**和查询用同一个 `remote_librarian`，靠 `skills=["upload_strategy"]` 切换到上传模式。`task` 此时是 JSON 字符串 `{knowledge, tools, resources}`。服务器同步跑完图谱编排后返回——不再是独立的 `/api/knowledge/upload` 端点。

---

## 调用示例

统一端点 `POST /api/agent`，详见 [api.md § POST /api/agent](api.md#post-apiagent)。

**知识查询**（Librarian + ask_strategy）：

```json
{
  "agent_type": "remote_librarian",
  "task": "ControlNet 相关的工具知识",
  "skills": ["ask_strategy"],
  "continue_from": null
}
```

**知识上传**（Librarian + upload_strategy；`task` 用 JSON 字符串承载结构化数据）：

```json
{
  "agent_type": "remote_librarian",
  "task": "{\"knowledge\": [...], \"tools\": [...], \"resources\": [...]}",
  "skills": ["upload_strategy"],
  "continue_from": null
}
```

**深度调研**（`remote_research` 不接受 skill）：

```json
{
  "agent_type": "remote_research",
  "task": "深度调研 Nano Banana 多图融合",
  "continue_from": null
}
```

所有调用同步返回标准 Agent 结果 `{sub_trace_id, status, summary, stats}`。`summary` 是 Agent 最终产出的 message 文本——结构化信息（引用来源、ID 列表等）由 Agent 的 prompt 约定写进文本，由调用方 parse。不定义 per-agent 的强 schema。

### 审计与运维

知识上传请求会在服务器 `.cache/.knowledge/buffer/` 下写一份 buffer 文件（审计用）。处理失败的文件可通过运维端点查询与重跑：

- `GET /api/knowledge/upload/pending` — 列出 pending 或 failed 的 buffer
- `POST /api/knowledge/upload/retry` — 同步重跑所有 failed

### 知识注入（框架级）

`inject_knowledge_for_goal`（`agent/trace/goal_tool.py`）在 Goal 开始时自动通过 `agent_type="remote_librarian"` 调用 `/api/agent`，把返回的 summary 作为 cognition_log 的 `query` 事件记录（详见 `agent/docs/cognition-log.md`）。

---

## 实现位置

| 组件 | 位置 |
|------|------|
| Librarian 核心 | `knowhub/agents/librarian.py::run_librarian`（skill 决定模式；`ALLOWED_SKILLS` 定义白名单） |
| Research 核心 | `knowhub/agents/research.py`（`research()`） |
| Prompt | `knowhub/agents/librarian_agent.prompt` / `research_agent.prompt` |
| Server 端点 | `knowhub/server.py::agent_api`（`/api/agent`）+ 运维 `/api/knowledge/upload/{pending,retry}` |
| 客户端入口 | `agent/tools/builtin/subagent.py::agent`（按 `remote_` 前缀路由） |
| SDK / CLI | `agent.invoke_agent()` (`agent/client.py`)；Claude Code skill 脚本 `~/.claude/skills/agent/invoke.py` 透传参数 |

---

## 与 Cognition Log 的关系

每次 `remote_librarian` 调用在 Agent 侧产生一个 `query` 事件，记录查询和整合回答。后续评估以 query 为单位。详见 [cognition-log.md](cognition-log.md)。

## 与知识处理流水线的关系

upload 提交的知识进入处理流水线（去重、工具关联分析）。逻辑在 `server.py:KnowledgeProcessor` 中。详见 [processing-pipeline.md](processing-pipeline.md)。
