Files
yuan-lab-llm--clawmanager/docs/clawmanager-agent-v2-development-guide.md
wehub-resource-sync 6d978fe483
Build / Frontend Build (push) Has been cancelled
Build / Backend Build (push) Has been cancelled
Build / Docker Build (push) Has been cancelled
Build / Kubernetes Deploy Smoke Test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:24 +08:00

26 KiB
Raw Permalink Blame History

ClawManager Agent V2 开发规范

本文整理当前 ClawManager 代码中的最新 agent 约定,面向 OpenClaw、Hermes 以及后续新增的托管 runtime。开发或改造 runtime 镜像时,应优先遵守本文;字段级契约以 docs/clawmanager-agent-v2-contract.md 和后端代码为准。

1. 架构定位

最新架构中有两类 agent 通信面:

  1. Runtime Pod Agent,也就是本文主线的 V2 agent 运行在共享 runtime Pod 内,负责本 Pod 内多个 gateway 子进程的创建、删除、端口、workspace、资源隔离、健康检查和状态上报。ClawManager 通过它把一个实例绑定到 pod_ip + gateway_port

  2. Instance Agent Control Plane,旧的 /api/v1/agent/* 协议 面向单个实例的状态、命令、skill inventory、skill package 上传和配置 revision 下载。当前后端仍保留这套协议,runtime 可以继续复用它完成实例级状态与 skill 管理;但 gateway 生命周期管理必须走 Runtime Pod Agent。

一句话原则:Runtime Pod Agent 是 Pod 内 gateway 管理器,不是一个阻塞式启动脚本。

2. 支持范围

当前 V2 托管 runtime 类型:

类型 说明
openclaw OpenClaw runtime
hermes Hermes runtime

当前平台默认值:

默认值
workspace root /workspaces
workspace path /workspaces/{runtime}/user-{user_id}/instance-{instance_id}
gateway 端口范围 20000-20099
单 Runtime Pod 容量 100
实例 UID/GID 200000 + instance_id
agent 控制端口 19090

3. Runtime Pod Agent 职责

Runtime Pod Agent 必须实现:

  • 启动本地控制服务:GET /v1/healthPOST /v1/gatewaysDELETE /v1/gateways/{gateway_id}POST /v1/drain
  • 向 ClawManager 上报 runtime pod 注册、heartbeat、metrics、gateway 状态和 skill 状态。
  • 管理本 Pod 内 gateway 子进程生命周期。
  • 管理端口池,避免同一 Pod 内端口冲突。
  • 创建并校验 workspace,设置正确 UID/GID。
  • 将 ClawManager 下发的 LLM、代理、实例 token、runtime 配置写入实例自己的 workspace。
  • 实现 drain,拒绝新 gateway,保持已有 gateway 运行,等待 ClawManager 迁移和删除。
  • 避免任何敏感 token、API key、Authorization header 出现在日志中。

不应该由 Runtime Pod Agent 实现:

  • 直接对浏览器暴露 gateway 自签地址。
  • 管理 ClawManager 用户权限。
  • 删除用户 workspace。
  • 把外部 NodePort、外部 HTTPS 入口或固定内网 IP 写死进 runtime 配置。

4. 运行环境变量

当前 Runtime Deployment 构建器注入以下变量,agent 实现应优先支持:

变量 说明
CLAWMANAGER_RUNTIME_TYPE openclawhermes
CLAWMANAGER_AGENT_PORT agent 控制端口,当前为 19090
CLAWMANAGER_GATEWAY_PORT_START gateway 起始端口
CLAWMANAGER_GATEWAY_PORT_END gateway 结束端口
CLAWMANAGER_AGENT_CONTROL_TOKEN ClawManager 调 agent 控制接口使用
CLAWMANAGER_AGENT_REPORT_TOKEN agent 上报 ClawManager 使用

为了兼容早期文档和旧镜像,agent 建议同时识别以下别名:

新变量 兼容别名
CLAWMANAGER_AGENT_CONTROL_TOKEN RUNTIME_AGENT_CONTROL_TOKEN
CLAWMANAGER_AGENT_REPORT_TOKEN RUNTIME_AGENT_REPORT_TOKEN
CLAWMANAGER_GATEWAY_PORT_START RUNTIME_GATEWAY_PORT_START
CLAWMANAGER_GATEWAY_PORT_END RUNTIME_GATEWAY_PORT_END
CLAWMANAGER_AGENT_PORT RUNTIME_AGENT_PUBLIC_PORT

建议支持的附加变量:

变量 默认值/要求
RUNTIME_WORKSPACE_ROOT 默认 /workspaces
RUNTIME_AGENT_LISTEN_ADDR 默认 0.0.0.0:19090
CLAWMANAGER_BACKEND_URL ClawManager backend 内部地址,推荐 Kubernetes Service DNS
CLAWMANAGER_RUNTIME_IMAGE_REF 当前镜像标识,用于注册上报
POD_NAME / POD_NAMESPACE / POD_IP / NODE_NAME 建议通过 Downward API 注入
CLAWMANAGER_TRUSTED_PROXY_CIDRS ClawManager app/gateway 的可信代理网段

CLAWMANAGER_BACKEND_URL 必须使用集群内部地址,例如:

http://clawmanager-gateway.clawmanager-system.svc.cluster.local:9001

不要在 runtime 内部配置中写入浏览器外部入口,例如 https://172.16.1.12:39443

5. Agent 到 ClawManager 的上报接口

所有 Runtime Pod Agent 上报请求必须带:

X-ClawManager-Agent-Token: ${CLAWMANAGER_AGENT_REPORT_TOKEN}
Content-Type: application/json

后端统一返回:

{
  "success": true,
  "message": "...",
  "data": {}
}

5.1 注册 Runtime Pod

POST {CLAWMANAGER_BACKEND_URL}/api/v1/runtime-agent/register

必填字段:

  • runtime_type
  • namespace
  • pod_name
  • deployment_name
  • image_ref

推荐完整 payload

{
  "runtime_type": "openclaw",
  "namespace": "clawmanager-system",
  "pod_name": "openclaw-runtime-6f77f8b8c7-abcde",
  "pod_uid": "pod-uid",
  "pod_ip": "10.42.0.31",
  "node_name": "node-a",
  "deployment_name": "openclaw-runtime",
  "image_ref": "ghcr.io/yuan-lab-llm/agentsruntime/openclaw:latest",
  "agent_endpoint": "http://10.42.0.31:19090",
  "state": "ready",
  "capacity": 100,
  "used_slots": 0,
  "draining": false,
  "metrics": {
    "agent_version": "0.1.0"
  },
  "reported_at": "2026-06-08T09:00:00Z"
}

要求:

  • agent_endpoint 必须是 ClawManager Pod 可以访问的地址,通常是 http://{POD_IP}:19090,不能是 127.0.0.1
  • capacity <= 0 时后端会按 100 处理,但 agent 应主动上报真实容量。
  • state 为空时后端按 ready 处理;agent 不应在初始化未完成时上报 ready。
  • metrics 必须是合法 JSON。

5.2 Heartbeat

POST {CLAWMANAGER_BACKEND_URL}/api/v1/runtime-agent/heartbeat

payload

{
  "pod_id": 17,
  "namespace": "clawmanager-system",
  "pod_name": "openclaw-runtime-6f77f8b8c7-abcde",
  "state": "ready",
  "used_slots": 37,
  "draining": false,
  "reported_at": "2026-06-08T09:00:02Z"
}

要求:

  • 优先使用注册返回的 data.pod.id 作为 pod_id
  • 没有 pod_id 时必须带 namespace + pod_name
  • state 必填。
  • used_slots 必须来自当前真实 starting/running gateway 数量,不要使用过期缓存。
  • 建议 heartbeat 间隔 2 秒;如果环境压力较大,可放宽,但必须小于 ClawManager 的 heartbeat 超时窗口。

5.3 Metrics

POST {CLAWMANAGER_BACKEND_URL}/api/v1/runtime-agent/metrics/report

payload

{
  "pod_id": 17,
  "cpu_millis_used": 13600,
  "memory_bytes_used": 42949672960,
  "disk_bytes_used": 214748364800,
  "network_rx_bytes": 9223372,
  "network_tx_bytes": 19223372,
  "metrics": {
    "gateway_count": 37,
    "load_1m": 2.4
  },
  "reported_at": "2026-06-08T09:00:05Z"
}

要求:

  • CPU 单位是 millicore。
  • memory/disk/network 单位是 bytes。
  • network 字段必须是单调递增 counter,不要填瞬时速率。
  • metrics 是扩展 JSON,必须合法。

5.4 Gateway Report

POST {CLAWMANAGER_BACKEND_URL}/api/v1/runtime-agent/gateways/report

payload

{
  "pod_id": 17,
  "gateways": [
    {
      "instance_id": 123,
      "gateway_id": "gw-123-7",
      "gateway_port": 20017,
      "gateway_pid": 8842,
      "state": "running",
      "generation": 7,
      "health_at": "2026-06-08T09:00:05Z"
    }
  ]
}

要求:

  • gateways 必填。
  • 每个 gateway 的 instance_idstategeneration 必填。
  • 后端只接受“当前绑定 Pod + 当前 generation”的上报;旧 Pod 或旧 generation 上报会被忽略。
  • state=runningstate=healthy 会把绑定更新为 running。
  • startingstoppederrorunhealthy 等状态会更新绑定状态。
  • 错误状态必须带 error_message,不要只上报空状态。

5.5 Skills Report

POST {CLAWMANAGER_BACKEND_URL}/api/v1/runtime-agent/skills/report

当前后端接收并发布任意 JSON payload。推荐按实例分组:

{
  "pod_id": 17,
  "runtime_type": "openclaw",
  "mode": "full",
  "reported_at": "2026-06-08T09:00:05Z",
  "instances": [
    {
      "instance_id": 123,
      "workspace_path": "/workspaces/openclaw/user-45/instance-123",
      "skills": [
        {
          "skill_id": "weather",
          "skill_version": "1.0.0",
          "identifier": "weather",
          "install_path": "/workspaces/openclaw/user-45/instance-123/.openclaw/skills/weather",
          "content_md5": "0123456789abcdef0123456789abcdef",
          "source": "runtime",
          "type": "agent-skill"
        }
      ]
    }
  ]
}

skill inventory 必须按 instance_idworkspace_path 隔离,不要把一个实例的 skill 混到另一个实例。

6. ClawManager 到 Agent 的控制接口

所有控制请求必须校验:

X-ClawManager-Control-Token: ${CLAWMANAGER_AGENT_CONTROL_TOKEN}

token 错误返回 401。不要返回 3xx redirect;后端会把 redirect 当成失败。

6.1 Health

GET /v1/health

任意 HTTP 2xx 都会被后端视为成功。建议响应:

{
  "status": "ready"
}

以下情况必须返回 503

  • 必填环境变量缺失。
  • workspace root 不可访问。
  • 端口池不可用。
  • control/report token 缺失。
  • clock skew 超过健康阈值。
  • agent 正在关闭,不再接受新请求。

6.2 Create Gateway

POST /v1/gateways

请求:

{
  "instance_id": 123,
  "user_id": 45,
  "agent_type": "openclaw",
  "workspace_path": "/workspaces/openclaw/user-45/instance-123",
  "port_range": {
    "start": 20000,
    "end": 20099
  },
  "uid": 200123,
  "gid": 200123,
  "cpu_cores": 2,
  "memory_mb": 4096,
  "disk_quota_mb": 20480,
  "generation": 7,
  "environment": {
    "CLAWMANAGER_LLM_BASE_URL": "http://clawmanager-gateway.clawmanager-system.svc.cluster.local:9001/api/v1/gateway/llm",
    "CLAWMANAGER_LLM_API_KEY": "instance-token",
    "CLAWMANAGER_LLM_MODEL": "[\"auto\"]",
    "CLAWMANAGER_LLM_PROVIDER": "openai-compatible",
    "CLAWMANAGER_INSTANCE_TOKEN": "instance-token",
    "OPENAI_API_KEY": "instance-token"
  }
}

响应:

{
  "gateway_id": "gw-123-7",
  "port": 20017,
  "pid": 8842,
  "status": "starting"
}

实现要求:

  • handler 必须快速返回,通常 1 到 3 秒内返回 starting 或已有 gateway 元数据。
  • 不能在 HTTP handler 内阻塞等待前台 gateway 进程完整运行。
  • agent_type 必须等于当前 Pod runtime type。
  • Pod draining 时返回 409503,拒绝新建。
  • instance_id + generation 为幂等键;重复请求不能重复启动进程。
  • 收到更高 generation 时,停止同实例旧 generation gateway 并释放端口。
  • 端口必须来自请求的 port_range
  • 没有可用端口时返回:
HTTP/1.1 409 Conflict
Content-Type: text/plain

no free port
  • 启动失败、健康检查失败、配置写入失败时,上报 gateway error 并释放端口。

6.3 Delete Gateway

DELETE /v1/gateways/{gateway_id}

要求:

  • gateway_id 是 URL path escapedagent 必须 decode 后再查找。
  • 优雅停止进程组,超时后强制 kill。
  • 释放端口、cgroup、进程表和本地状态。
  • 不删除 workspace。
  • gateway 不存在时建议返回 204,保持删除幂等。
  • 成功状态可以是 200202204

6.4 Drain

POST /v1/drain

请求:

{
  "draining": true
}

要求:

  • 设置本地 draining 状态。
  • 立即拒绝新的 POST /v1/gateways
  • 已有 gateway 不主动停止,继续健康检查和上报。
  • 立即补发 heartbeatstate=draining, draining=true
  • 等 ClawManager 迁移实例后,逐个收到 DELETE 再清理。

7. Gateway 生命周期

推荐状态机:

requested -> reserved_port -> starting -> running
                              -> error
running -> stopping -> stopped
running -> unhealthy -> running/error

创建流程:

  1. 校验 token、runtime type、instance/user/generation、workspace、端口范围。
  2. 如果 draining,拒绝创建。
  3. 查本地状态,处理幂等。
  4. 如果 generation 更高,清理旧 generation。
  5. 加锁分配端口,标记为 reserved。
  6. 创建 workspace 和 home,设置 owner 为请求中的 uid/gid
  7. 写入 runtime 配置和 LLM/proxy 配置。
  8. 持久化 gateway 元数据为 starting
  9. 后台启动 gateway 子进程,立即返回。
  10. 健康检查通过后上报 running
  11. 失败时上报 error,记录短错误信息并释放端口。

running 必须以真实进程和真实健康检查为准,不能只读旧状态文件。

8. 端口管理

agent 必须实现并发安全的端口分配器:

reserve(instance_id, generation, count) -> port_set
commit(instance_id, generation, port_set)
release(instance_id, generation)
list_used()

要求:

  • 分配时持有互斥锁。
  • 在锁内检查 agent 内存状态和系统监听端口。
  • 启动失败、健康检查失败、DELETE 成功后必须释放端口。
  • 如果 runtime 需要多个端口,必须一次性分配端口组,避免部分成功。
  • 同一 Pod 内端口不能冲突;不同 Pod 可以复用相同端口,因为路由使用 pod_ip + port

9. Workspace 与资源隔离

workspace 固定格式:

/workspaces/{runtime}/user-{user_id}/instance-{instance_id}

agent 必须:

  • 对 workspace root 和请求路径执行 realpath。
  • 拒绝 ..、绝对路径逃逸、符号链接逃逸、跨用户、跨实例路径。
  • 创建 ${workspace}/home,并设置 HOME=${workspace}/home
  • owner 设置为请求中的 uid/gid,当前默认 200000 + instance_id
  • token、provider、配置文件权限建议 0600
  • 删除 gateway 时不删除 workspace。

资源限制要求:

  • 每个 gateway 使用独立进程组。
  • 业务进程最终以实例 UID/GID 运行。
  • CPU/Memory 使用 cgroup 限制。
  • Disk 优先使用 filesystem quota;不支持时至少周期扫描并在超限时上报错误。
  • 资源限制无法启用时必须在 report 或错误消息中体现,不要静默忽略。

10. Runtime 配置和 LLM 注入

ClawManager 会通过 POST /v1/gatewaysenvironment 字段下发实例级 LLM 环境变量。agent 只能转发白名单变量:

CLAWMANAGER_LLM_BASE_URL
CLAWMANAGER_LLM_API_KEY
CLAWMANAGER_LLM_MODEL
CLAWMANAGER_LLM_PROVIDER
CLAWMANAGER_INSTANCE_TOKEN
OPENAI_BASE_URL
OPENAI_API_BASE
OPENAI_API_KEY
OPENAI_MODEL

要求:

  • LLM base URL 使用 ClawManager 内部 Service DNS。
  • API key 使用当前实例 token。
  • 不要求用户在 runtime 页面手工填写 OpenAI key。
  • 不打印 token/API key。
  • 如果缺少 LLM key,不能上报 gateway running;应上报 error 并说明缺少实例 LLM token。

runtime 配置必须写在实例 workspace 内,例如:

Runtime 推荐路径
OpenClaw {workspace}/home/.openclaw/openclaw.json
Hermes {workspace}/home/.hermes/hermes.json 或 Hermes 原生配置路径

JSON merge 规则:

  • 对象字段递归 merge。
  • 保留用户已有未知字段。
  • 平台必须控制的字段可以覆盖,但要在代码中显式列出。
  • 数组 append 后去重,例如 allowedOrigins
  • 写入前先生成临时文件,再原子 rename。

11. 代理和浏览器访问

浏览器访问链路必须是:

Browser HTTPS -> ClawManager HTTPS -> ClawManager backend proxy -> Runtime Pod HTTP gateway

agent 写 runtime 配置时必须保证:

  • gateway 支持 /api/v1/instances/{instance_id}/proxy base path。
  • allowed origin 使用 ClawManager 内部 origin,例如 http://clawmanager-gateway.clawmanager-system.svc.cluster.local:9001
  • trusted proxies 来自 CLAWMANAGER_TRUSTED_PROXY_CIDRS 或等价 env。
  • 不使用外部地址作为 runtime 内部 trusted origin。
  • 通过 ClawManager proxy 访问时,不应要求用户手工粘贴 gateway token。

12. 时间同步

agent 必须处理 clock skew

  • 注册和 heartbeat 响应如果带 server_time,记录本地时间和服务端时间偏移。
  • 偏移超过 30 秒时记录 warning,并在 health 中暴露 clock_skew_warning
  • 偏移超过 120 秒时不应上报 ready 或 gateway running
  • 所有签名、token 时间和上报时间使用 UTC。
  • 不在容器里修改系统时间,时间同步由 Kubernetes 节点 NTP/chrony 负责。

常见症状包括 device signature expired、JWT/WebSocket 鉴权异常、签名 URL 过期和 gateway 实际状态与 ClawManager 展示不一致。

13. Instance Agent v1 兼容协议

当前后端仍提供 /api/v1/agent/*,用于实例级状态、命令和 skill 管理。托管 runtime 如果需要复用这套能力,应由具体实例的 gateway/agent 逻辑使用实例级环境变量。

ClawManager 会为支持托管集成的实例注入:

变量 说明
CLAWMANAGER_AGENT_ENABLED true 时启用实例 agent
CLAWMANAGER_AGENT_BASE_URL ClawManager API base URL,不带 /api/v1/agent 后缀
CLAWMANAGER_AGENT_BOOTSTRAP_TOKEN 首次注册使用
CLAWMANAGER_AGENT_INSTANCE_ID 当前实例 ID
CLAWMANAGER_AGENT_PROTOCOL_VERSION 当前为 v1
CLAWMANAGER_AGENT_PERSISTENT_DIR 当前实例持久化目录
CLAWMANAGER_AGENT_DISK_LIMIT_BYTES 实例磁盘配额

13.1 Register

POST {base}/api/v1/agent/register
Authorization: Bearer ${CLAWMANAGER_AGENT_BOOTSTRAP_TOKEN}

payload

{
  "instance_id": 123,
  "agent_id": "openclaw-123-main",
  "agent_version": "0.1.0",
  "protocol_version": "v1",
  "capabilities": [
    "runtime.status",
    "runtime.health",
    "metrics.report",
    "skills.inventory",
    "skills.upload",
    "commands.poll",
    "llm.gateway"
  ],
  "host_info": {
    "runtime_type": "openclaw",
    "runtime_name": "OpenClaw",
    "image": "ghcr.io/yuan-lab-llm/agentsruntime/openclaw:latest",
    "persistent_dir": "/config"
  }
}

响应 data 包含:

  • session_token
  • session_expires_at
  • heartbeat_interval_seconds,当前默认 15
  • command_poll_interval_seconds,当前默认 5
  • server_time

session token 每次成功 heartbeat 会续期 24 小时。收到 401 时删除本地 session,并用 bootstrap token 重新注册。

13.2 Heartbeat

POST {base}/api/v1/agent/heartbeat
Authorization: Bearer ${session_token}

payload

{
  "agent_id": "openclaw-123-main",
  "timestamp": "2026-06-08T09:00:15Z",
  "openclaw_status": "running",
  "current_config_revision_id": null,
  "summary": {
    "runtime_type": "openclaw",
    "runtime_status": "running",
    "runtime_pid": 245,
    "openclaw_pid": 245,
    "skill_count": 8,
    "disk_used_bytes": 2147483648,
    "disk_limit_bytes": 10737418240
  }
}

兼容要求:

  • openclaw_statusopenclaw_pidopenclaw_version 是历史字段名;非 OpenClaw runtime 也需要填自己的主进程状态、PID 和版本,直到协议升级。
  • 后端 45 秒内收到 heartbeat 展示 online45 到 120 秒展示 stale,超过 120 秒展示 offline。
  • heartbeat 响应里的 has_pending_command=true 时,应立即拉取命令。

13.3 State Report

POST {base}/api/v1/agent/state/report
Authorization: Bearer ${session_token}

payload

{
  "agent_id": "openclaw-123-main",
  "reported_at": "2026-06-08T09:00:20Z",
  "runtime": {
    "openclaw_status": "running",
    "openclaw_pid": 245,
    "openclaw_version": "openclaw-2026.5.4",
    "current_config_revision_id": null
  },
  "system_info": {
    "runtime_type": "openclaw",
    "cpu": {
      "cores": 2,
      "load": {
        "1m": 0.64,
        "5m": 0.52,
        "15m": 0.4
      }
    },
    "memory": {
      "mem_total_bytes": 4294967296,
      "mem_available_bytes": 2147483648
    },
    "disk": {
      "root_total_bytes": 10737418240,
      "root_free_bytes": 8589934592
    },
    "network": {
      "interfaces": [
        {
          "name": "eth0",
          "status": "up",
          "addresses": ["10.42.0.12"],
          "rx_bytes": 123456789,
          "tx_bytes": 98765432
        }
      ]
    }
  },
  "health": {
    "runtime_process": "ok",
    "agent": "ok",
    "metrics_collector": "ok"
  }
}

network 的 rx_bytes / tx_bytes 必须是单调递增 counter。

13.4 Commands

拉取:

GET {base}/api/v1/agent/commands/next
Authorization: Bearer ${session_token}

开始:

POST {base}/api/v1/agent/commands/{id}/start
Authorization: Bearer ${session_token}

完成:

POST {base}/api/v1/agent/commands/{id}/finish
Authorization: Bearer ${session_token}

finish 只允许:

  • succeeded
  • failed

当前支持的命令类型:

start_openclaw
stop_openclaw
restart_openclaw
collect_system_info
apply_config_revision
reload_config
health_check
install_skill
update_skill
uninstall_skill
remove_skill
disable_skill
quarantine_skill
handle_skill_risk
sync_skill_inventory
refresh_skill_inventory
collect_skill_package

未知命令必须 finish 为 failederror_message 写明 unsupported command type: <type>

13.5 Skills

inventory

POST {base}/api/v1/agent/skills/inventory
Authorization: Bearer ${session_token}

upload

POST {base}/api/v1/agent/skills/upload
Authorization: Bearer ${session_token}
Content-Type: multipart/form-data

上传表单字段:

  • file
  • agent_id
  • skill_id
  • skill_version
  • identifier
  • content_md5
  • source

要求:

  • identifiercontent_md5 必须稳定。
  • mode=full 的 inventory 代表全量结果,平台会用它对齐实例 skill 状态。
  • content_md5 按目录内容指纹计算,不是 zip 文件 MD5;算法见 docs/skill-content-md5-spec.md
  • 打包和解压必须防止路径逃逸。

14. 安全规范

  • 控制接口只接受正确 X-ClawManager-Control-Token
  • 上报接口只使用 X-ClawManager-Agent-Token
  • 实例级接口使用 Bearer bootstrap/session token。
  • 日志不得打印 token、API key、完整 Authorization header、channel secret。
  • 启动进程使用 argv 数组,不使用 shell 拼接:
execve(binary, ["openclaw", "gateway", "run", "--port", "20017"], env)
  • 不允许用户环境变量覆盖 agent 自己的 control/report token。
  • 不允许 allowedOrigins=["*"] 作为生产配置。
  • 所有用户输入路径都要边界校验。
  • 命令执行必须有超时,超过 timeout_seconds 主动终止并 finish failed。

15. 测试要求

单元测试至少覆盖:

  • Runtime type 只接受 openclaw / hermes
  • create gateway 幂等。
  • 更高 generation 替换旧 generation。
  • 端口并发分配无冲突。
  • 端口被系统占用时跳过。
  • 端口耗尽返回 409 no free port
  • workspace path 越权被拒绝。
  • JSON merge 保留用户字段,数组去重。
  • LLM env 白名单转发。
  • 缺少 LLM token 时 gateway 不报 running
  • trusted proxy 和 allowed origin 配置生成。
  • clock skew 阈值判断。
  • redirect 响应不被当成成功。
  • DELETE gateway id path escape/decode。

集成测试至少覆盖:

  • Runtime Pod 注册为 readycapacity/used_slots/draining 正确。
  • heartbeat 更新 Pod 状态。
  • metrics 上报后管理端 Runtime Pods 页面能看到指标。
  • 创建 100 个 gateway 端口唯一,第 101 个触发扩容或 no capacity。
  • 重复 create 同一 instance_id + generation 不重复启动。
  • gateway report 旧 generation 不覆盖新 generation。
  • ClawManager 通过 proxy 能访问 gateway 页面和 WebSocket。
  • 通过 ClawManager proxy 访问时不要求用户手工粘贴 gateway token。
  • Pod drain 后拒绝新 create,已有 gateway 持续上报,DELETE 后释放端口。
  • Pod 重启后不误报旧 gateway running。
  • instance agent register/heartbeat/state/commands/skills 全链路可用。
  • 日志中没有 token 和 API key。

16. Do / Don't

Do Don't
使用 Kubernetes Service DNS 访问 ClawManager backend 写死外部 NodePort、172.16.1.12 或浏览器 HTTPS 入口
POST /v1/gateways 快速返回 starting 在 HTTP handler 中阻塞等待前台进程退出
instance_id + generation 幂等 重试时重复启动多个 gateway
以真实进程和健康检查决定 running 只读旧状态文件就上报 running
JSON merge runtime 配置 覆盖用户整个配置文件
只转发白名单 env 把用户请求里的全部 env 原样传给进程
trusted proxy 模式下通过 ClawManager 自动进入 要求用户手工粘贴 gateway token
检测并上报 clock skew 忽略时间导致签名和 WebSocket 鉴权问题反复出现
DELETE gateway 不删除 workspace 清理进程时顺手删除用户数据

17. 代码位置

后端关键实现:

  • Runtime Pod 上报接口:backend/internal/handlers/runtime_agent_handler.go
  • ClawManager 调 agent 客户端:backend/internal/services/runtime_agent_client.go
  • Runtime 调度器:backend/internal/services/runtime_scheduler.go
  • Runtime Deployment 构建:backend/internal/services/k8s/runtime_deployment_service.go
  • Runtime 常量与路径:backend/internal/services/runtime_capacity.go
  • 实例 agent handlerbackend/internal/handlers/agent_handler.go
  • 实例 agent servicebackend/internal/services/instance_agent_service.go
  • 实例命令 servicebackend/internal/services/instance_command_service.go
  • 实例 runtime 状态 servicebackend/internal/services/instance_runtime_status_service.go

相关文档:

  • docs/clawmanager-agent-v2-contract.md
  • docs/runtime-agent-integration-guide.md
  • docs/hermes-lite-pro-agent-development.md
  • docs/hermes-runtime-agent-development.md
  • docs/skill-content-md5-spec.md