<!-- 来源: https://hostanagent.com/docs/reference/tools/ | 协议: 1.0 | 更新: 2026-09-30 -->

# 执行器与工具回执协议

配置工具 Schema 与执行真实业务是两个阶段。Agent 引用的工具集版本描述工具名、输入和绑定；产品执行器必须在线、在授权范围内取得唯一 claim，并在业务操作前确认 grant/accepted 回执。

| 类别 | 公开 REST 路径 | 行为 |
|---|---|---|
| 配置与诊断 | `/executor-bindings`、`/agents/{agent_id}/executor-bindings/{binding_id}/diagnostics`、`/tools/dry-run` | 登记、查询连接元数据和模拟校验；dry-run 不执行业务 |
| 执行器连接 | `/executors/connect`、`/executors/{executor_id}/heartbeat`、`.../pending`、`.../calls/report`、`.../disconnect` | 产品维持稳定身份与范围，查询分页候选、报告待核对/待投递 |
| 工具领取与回执 | `/runs/{run_id}/tool-calls/{call_id}/claim`、`.../receipts` | 以工具 grant 和稳定 executor ID 领取并提交已保存结果 |

路径省略 `/v1` 前缀。`tools:execute` 只准入通用协议；产品还必须按自己的 Subject、Agent、资源版本、参数摘要及业务权限逐次校验。执行器连接许可不能替代 claim/receipt 权限。候选列表不给工具参数或执行 grant，不能从一个 binding ID 推断有执行权。[身份范围](/docs/reference/authentication/)。

写工具先持久化操作键与 assignment，收到 accepted 的明确确认后才开始副作用。进度和最终回执先保存再发送，重投沿用同一 receipt_id/正文；`replayed=true` 只核对并重投，不重跑 handler。普通异常视为可能已有业务结果，进入 `reconciliation_required`；明确业务失败/取消须由产品确认后提交相应终态。迟到回执不会复活已终止 Run。

`cancel`、断开浏览器、执行器 `detach`、业务任务取消和补偿是不同操作。完整请求 Schema 查看[OpenAPI](/docs/reference/openapi.json)，产品实现步骤查看[ToolRunner](/docs/integration/tool-runner/)和[异步任务](/docs/integration/long-running-tools/)。

## 工具结果的上下文上限

工具定义示例（`binding_id` 替换为已注册执行绑定）：

```json
{
  "name": "tasks.read",
  "description": "分页读取任务",
  "binding_id": "binding_example",
  "input_schema": {"type": "object", "properties": {"cursor": {"type": "string"}}},
  "output_schema": {"type": "object"},
  "max_result_context_bytes": 16384
}
```

`max_result_context_bytes` 默认 **16,384 字节（16 KiB）**，可设 **1,024–32,768 字节（1–32 KiB）**。计量对象是 `result` 的紧凑 JSON：UTF-8 编码、直接保留中文与 emoji、无缩进和分隔空格；字符串的引号、JSON 转义和裁剪提示本身都计入预算，不包含外层回执或消息封套。它不依赖 Token 估算系数，32 KiB 也不代表 32k Token。

完整工具回执按原样持久保存；完成结果首次进入执行历史时超限才形成头尾预览。裁剪保持合法 Unicode 和 JSON，但可能把原始嵌套结构换成 `preview.head` / `preview.tail`，中间字段可能不再可见，不能假设 `data.next_cursor` 等分页信息会完整保留。部分短状态字段会尽量放入 `preserved_fields`，仍受同一字节预算约束。已有投影不会在每轮重新生成，保障未压缩时的上下文前缀稳定。

**单工具可配置上限是 32 KiB，即 32,768 字节。** 超过上限的配置会校验失败。多个工具结果会累积占用 Agent 输入窗口；整个请求仍按 `max_context_tokens` 和真实 usage 校准后的 Token 估算决定是否压缩。

如果一个工具经常需要返回超过 32 KiB 的内容，应调整工具设计：支持分页或游标续读、按条件与字段筛选，先返回摘要和标识，再按需读取片段。开发者和接入 Agent 不应依赖提高配置上限解决大结果问题，也不能假设头尾预览保留了中间全部事实。分页游标、状态与关键标识应放在紧凑结果中，并使用下面的预览核验它们是否可见。

submission、未知业务结果和不透明回放受协议保护，不进行此裁剪。多模态结果仅裁剪文本块，文本块及包装、转义、裁剪提示计入预算；图片等非文本内容原样保留、不占文本裁剪预算，所以完整结果的 `retained_bytes` 可以超过配置值。最终完整请求仍须通过输入 Token 窗口检查。完整回执不会因为这个裁剪预算而被拒收；通用 HTTP 传输限制仍适用，较大的业务数据应分页或提供可继续读取的引用。

旧 `max_result_tokens` 与旧回执拒收字段 `max_result_bytes` 已删除，传入会校验失败，不提供别名兼容。本次服务升级已将存量 Token 配置一次性替换为默认 16 KiB，保留已提交执行历史。此后修改预算需要发布新工具集与 Agent 版本，并新建 Session。[配置迁移](/docs/reference/configuration/)。

## 检查模型实际看到什么

用具有目标 Agent 范围、且具备 `runtime:read` / `configuration:read` / `tools:execute` 其中一项权限的服务端身份调用 `POST /v1/tools/dry-run`，将下面版本 ID 换成真实发布版本，工具名和参数匹配该版本的工具定义：

```json
{
  "agent_version": "替换为已发布的固定版本 ID",
  "tool_name": "tasks.read",
  "arguments": {},
  "mock_receipts": [
    {
      "receipt_id": "dry-run-page-001",
      "kind": "completed",
      "result": {"next_cursor": "page-2", "tasks": []}
    }
  ]
}
```

响应的 `context_preview` 包含 `max_result_context_bytes`、`original_bytes`、`retained_bytes`、`truncated` 和 `result`。`original_bytes` / `retained_bytes` 是裁剪前后完整 `result` 的紧凑 JSON UTF-8 字节数；`result` 是这条回执首次进入执行历史时的内容，之后仍可能随整体上下文压缩而变化。没有 completed 模拟回执时，预览为 null。

将示例 `result` 换成产品的真实大小样本，检查是否截断，以及游标、ID、状态和关键事实是否仍可见。控制台“检查 Schema 与模拟回执”展示同一预览；这一步不创建 Run、不调用模型、不执行业务。`execution_verified=false`，即使 Schema 校验通过也不证明真实业务可用。

本地可先用 Python 测量原始结果，裁剪后的准确内容仍以 dry-run 为准：

```python
import json

result = {"next_cursor": "page-2", "tasks": []}
size_bytes = len(json.dumps(
    result, ensure_ascii=False, sort_keys=True,
    separators=(",", ":"), allow_nan=False,
).encode("utf-8"))
```

测量的是 JSON 编码后的 `result`，不能用字符长度、文件大小或 Token 估算系数代替。分页和字段筛选应尽量让每页完整落在预算内，避免把必要信息寄托于头尾裁剪。
