Skip to content

Latest commit

 

History

History
916 lines (674 loc) · 18.9 KB

File metadata and controls

916 lines (674 loc) · 18.9 KB

Onlyboxes API 统一参考

English

本文档统一收录 Onlyboxes 当前公开的全部 API。

  • Console HTTP 基地址:http://<console-host>:8089
  • Console Worker gRPC 地址:<console-host>:50051
  • REST API 前缀:/api/v1

1. 鉴权模型

Onlyboxes 有两套鉴权路径:

  1. 控制台会话(Cookie):用于管理类 API
  2. 访问令牌(Bearer Token):用于执行类 API 与 MCP

1.1 控制台会话(Cookie)

  • Cookie 名称:onlyboxes_console_session
  • POST /api/v1/console/login 创建
  • 用于:
    • /api/v1/console/session
    • /api/v1/console/logout
    • /api/v1/console/password
    • /api/v1/console/register
    • /api/v1/console/accounts*
    • /api/v1/console/tokens*
    • /api/v1/workers*(按角色作用域)
  • 会话有效期为 12 小时(内存态);console 重启后会话全部失效。

1.2 访问令牌(Bearer)

  • 请求头格式:Authorization: Bearer <access-token>
  • 用于:
    • /api/v1/commands/*
    • /api/v1/tasks*
    • /mcp
  • 若系统中没有 token,所有 token 鉴权接口会返回 401

2. REST 通用约定

  • 内容类型:application/json
  • 常见错误结构:
{ "error": "message" }
  • 时间字段使用 RFC3339。
  • ID 字段均为不透明字符串(如 acc_*tok_*、worker UUID、task ID)。

3. 控制台认证 API

3.1 登录

POST /api/v1/console/login

请求:

{
  "username": "admin",
  "password": "secret"
}

成功 200

{
  "authenticated": true,
  "account": {
    "account_id": "acc_xxx",
    "username": "admin",
    "is_admin": true
  },
  "registration_enabled": false,
  "console_version": "v0.0.0",
  "console_repo_url": "https://..."
}

错误:

  • 400 JSON 结构非法
  • 401 用户名或密码错误
  • 500 会话创建失败

3.2 会话信息

GET /api/v1/console/session

  • 需要控制台 Cookie 会话。
  • 成功返回结构与登录响应一致。

错误:

  • 401 未登录

3.3 登出

POST /api/v1/console/logout

  • 清理 Cookie,并删除内存会话(若存在)。

响应:

  • 204 No Content

3.4 注册普通账号(仅管理员)

POST /api/v1/console/register

请求:

{
  "username": "dev-user",
  "password": "strong-password"
}

成功 201

{
  "account": {
    "account_id": "acc_xxx",
    "username": "dev-user",
    "is_admin": false
  },
  "created_at": "2026-02-21T00:00:00Z",
  "updated_at": "2026-02-21T00:00:00Z"
}

校验与错误:

  • 403 注册开关关闭(CONSOLE_ENABLE_REGISTRATION=false
  • 403 当前账号不是管理员
  • 400 用户名为空、用户名长度 > 64、或密码为空
  • 409 用户名冲突(不区分大小写)
  • 500 数据库或内部错误

3.5 修改当前账号密码

POST /api/v1/console/password

请求:

{
  "current_password": "old-password",
  "new_password": "new-password"
}

响应:

  • 204 修改成功
  • 400 JSON 结构非法、current_password 缺失或 new_password 缺失
  • 401 当前密码错误
  • 500 内部错误

说明:

  • 该接口需要控制台会话鉴权。
  • 密码更新后会轮换该账号的活动会话。

3.6 查询账号列表(仅管理员)

GET /api/v1/console/accounts?page=1&page_size=20

查询参数:

  • page:正整数,默认 1
  • page_size:正整数,默认 20,最大 100

成功 200

{
  "items": [
    {
      "account_id": "acc_xxx",
      "username": "admin",
      "is_admin": true,
      "created_at": "2026-02-21T00:00:00Z",
      "updated_at": "2026-02-21T00:00:00Z"
    }
  ],
  "total": 1,
  "page": 1,
  "page_size": 20
}

错误:

  • 400 查询参数非法
  • 403 当前账号不是管理员
  • 500 数据库或内部错误

3.7 删除账号(仅管理员)

DELETE /api/v1/console/accounts/:account_id

响应:

  • 204 删除成功
  • 403 禁止删除当前登录账号
  • 403 禁止删除管理员账号
  • 404 账号不存在
  • 500 内部错误

4. Token 管理 API(控制台会话鉴权)

Token 按账号隔离;每个账号只能管理自己的 token。

4.1 查询 Token 列表

GET /api/v1/console/tokens

成功 200

{
  "items": [
    {
      "id": "tok_xxx",
      "name": "default-token",
      "token_masked": "obx_******abcd",
      "created_at": "2026-02-21T00:00:00Z",
      "updated_at": "2026-02-21T00:00:00Z"
    }
  ],
  "total": 1
}

4.2 创建 Token

POST /api/v1/console/tokens

请求:

{
  "name": "ci-prod",
  "token": "optional-manual-token"
}

约束:

  • name 必填,trim 后长度 <= 64,同账号内大小写不敏感唯一
  • token 可选:
    • 省略时自动生成(obx_<hex>
    • 手动提供时:trim 后不能为空、不能含空白字符、长度 <= 256

成功 201

{
  "id": "tok_xxx",
  "name": "ci-prod",
  "token": "obx_plaintext_or_manual",
  "token_masked": "obx_******abcd",
  "generated": true,
  "created_at": "2026-02-21T00:00:00Z",
  "updated_at": "2026-02-21T00:00:00Z"
}

错误:

  • 400 参数校验失败
  • 409 token 名称冲突或 token 值冲突
  • 500 内部错误

4.3 删除 Token

DELETE /api/v1/console/tokens/:token_id

响应:

  • 204 删除成功
  • 404 token 不存在(或不属于当前账号)

4.4 查询 Token 明文

GET /api/v1/console/tokens/:token_id/value

固定返回 410 Gone

{
  "error": "token value is only returned at creation time; delete and recreate the token to obtain a new value"
}

5. Worker 管理 API(控制台会话鉴权,按角色作用域)

Worker 类型:

  • normal(对应 worker-docker
  • worker-sys(对应 worker-sys

权限矩阵:

  • 管理员:
    • list/stats/inflight:查看全部
    • delete:可删任意 worker
    • create:可创建 normalworker-sys
  • 普通用户:
    • list/stats/inflight:仅本人 worker-sys
    • delete:仅本人 worker-sys(其他目标返回 404
    • create:仅可创建 worker-sys,且每账号最多一个

5.1 查询 Worker 列表

GET /api/v1/workers?page=1&page_size=20&status=all

查询参数:

  • page:正整数,默认 1
  • page_size:正整数,默认 20,最大 100
  • statusall|online|offline,默认 all

成功 200

{
  "items": [
    {
      "node_id": "worker-1",
      "node_name": "node-a",
      "executor_kind": "docker",
      "capabilities": [
        { "name": "echo", "max_inflight": 4 }
      ],
      "labels": {
        "region": "us",
        "obx.owner_id": "acc_xxx",
        "obx.worker_type": "normal"
      },
      "version": "v0.1.0",
      "status": "online",
      "registered_at": "2026-02-21T00:00:00Z",
      "last_seen_at": "2026-02-21T00:00:00Z"
    }
  ],
  "total": 1,
  "page": 1,
  "page_size": 20
}

错误:

  • 400 查询参数非法

5.2 Worker 统计

GET /api/v1/workers/stats?stale_after_sec=30

查询参数:

  • stale_after_sec:正整数,默认 30

成功 200

{
  "total": 5,
  "online": 4,
  "offline": 1,
  "stale": 1,
  "stale_after_sec": 30,
  "generated_at": "2026-02-21T00:00:00Z"
}

说明:普通用户响应仅统计本人 worker-sys

5.3 Worker 并发占用统计

GET /api/v1/workers/inflight

成功 200

{
  "workers": [
    {
      "node_id": "worker-1",
      "capabilities": [
        { "name": "pythonExec", "inflight": 1, "max_inflight": 4 }
      ]
    }
  ],
  "generated_at": "2026-02-21T00:00:00Z"
}

说明:普通用户响应仅包含本人 worker-sys

5.4 创建 Worker 凭据

POST /api/v1/workers

请求体:

{
  "type": "normal"
}

规则:

  • type 必填,取值 normal|worker-sys
  • 仅管理员可创建 normal
  • 每个账号最多创建一个 worker-sys

成功 201

{
  "node_id": "2f51f8f9-77f2-4c1a-a4f5-2036fc9fcb9e",
  "type": "normal",
  "command": "WORKER_CONSOLE_GRPC_TARGET=127.0.0.1:50051 WORKER_ID=... WORKER_SECRET=... WORKER_HEARTBEAT_INTERVAL_SEC=5 WORKER_HEARTBEAT_JITTER_PCT=20 ./path-to-binary"
}

说明:

  • WORKER_SECRET 仅在该接口创建时返回一次。
  • ./path-to-binary 为占位符,需要替换为实际 worker 启动命令。

错误:

  • 400 请求体不合法 / type 非法
  • 403 普通用户创建 normal
  • 409 当前账号已存在 worker-sys
  • 503 provisioning 不可用
  • 500 创建失败

5.5 删除 Worker

DELETE /api/v1/workers/:node_id

响应:

  • 204 删除成功
  • 404 worker 不存在(普通用户删除越权目标也返回 404
  • 400 缺少 node_id
  • 503 provisioning 不可用

5.6 获取 Worker 启动命令

GET /api/v1/workers/:node_id/startup-command

固定返回 410 Gone

{
  "error": "worker secret is returned only when creating the worker; delete and recreate to get a new startup command"
}

6. 命令执行 API(Bearer Token 鉴权)

6.1 Echo 命令

POST /api/v1/commands/echo

请求:

{
  "message": "hello",
  "timeout_ms": 5000
}

约束:

  • message 必填,trim 后不能为空
  • timeout_ms 可选,范围 1..60000,默认 5000

成功 200

{ "message": "hello" }

错误:

  • 400 请求体错误 / message 缺失 / timeout 超范围
  • 429 无可用并发容量
  • 503 无在线 echo worker
  • 504 超时
  • 502 执行或内部异常

6.2 Terminal 命令

POST /api/v1/commands/terminal

请求:

{
  "command": "pwd",
  "session_id": "optional-session",
  "create_if_missing": false,
  "lease_ttl_sec": 60,
  "timeout_ms": 60000,
  "request_id": "optional-idempotency-key"
}

约束:

  • command 必填,trim 后不能为空
  • timeout_ms 可选,范围 1..600000,默认 60000
  • request_id 可选,幂等键(按账号隔离)

成功 200

{
  "session_id": "sess_xxx",
  "created": true,
  "stdout": "...",
  "stderr": "...",
  "exit_code": 0,
  "stdout_truncated": false,
  "stderr_truncated": false,
  "lease_expires_unix_ms": 1770000000000
}

错误:

  • 400 请求参数非法或 invalid_payload
  • 404 session_not_found
  • 409 session_busy 或任务被取消
  • 429 无可用并发容量
  • 503 无可用 worker
  • 504 超时
  • 502 其他执行失败

6.3 Computer Use 命令

POST /api/v1/commands/computer-use

请求:

{
  "command": "pwd",
  "timeout_ms": 60000,
  "request_id": "optional-idempotency-key"
}

约束:

  • command 必填,trim 后不能为空
  • timeout_ms 可选,范围 1..600000,默认 60000
  • request_id 可选,幂等键(按账号隔离)
  • 兼容旧客户端时,传入 lease_ttl_sec 会被忽略
  • 调度只会路由到调用账号自己的 worker-sys
  • 单账号并发固定为 1(max_inflight=1

成功 200

{
  "stdout": "...",
  "stderr": "...",
  "exit_code": 0,
  "stdout_truncated": false,
  "stderr_truncated": false
}

错误:

  • 400 请求参数非法或 invalid_payload
  • 409 worker session_busy 或任务被取消
  • 429 无可用并发容量(no_capacity
  • 503 当前账号无在线 worker-sysno_worker
  • 504 超时
  • 502 其他执行失败

7. 任务 API(Bearer Token 鉴权)

Task 所有权按账号隔离(由 token 对应账号决定)。

7.1 提交任务

POST /api/v1/tasks

请求:

{
  "capability": "pythonExec",
  "input": { "code": "print(1)" },
  "mode": "auto",
  "wait_ms": 1500,
  "timeout_ms": 60000,
  "request_id": "optional-idempotency-key"
}

约束:

  • capability 必填且非空
  • input 必须是合法 JSON(省略时默认为 {}
  • modesync|async|auto,默认 auto
  • wait_ms1..60000,默认 1500
  • timeout_ms1..600000,默认 60000
  • request_id:可选幂等键(账号维度去重)

可能响应:

  • 202 任务未完成(包含 status_url
  • 200 任务完成且成功
  • 409 任务完成且被取消
  • 504 任务完成且超时
  • 429 任务完成失败且 error.code=no_capacity
  • 503 任务完成失败且 error.code=no_worker
  • 502 任务完成失败(其他错误码)

202 示例:

{
  "task_id": "task_xxx",
  "request_id": "req-1",
  "command_id": "cmd_xxx",
  "capability": "pythonexec",
  "status": "running",
  "created_at": "2026-02-21T00:00:00Z",
  "updated_at": "2026-02-21T00:00:01Z",
  "deadline_at": "2026-02-21T00:01:00Z",
  "status_url": "/api/v1/tasks/task_xxx"
}

已完成示例:

{
  "task_id": "task_xxx",
  "capability": "pythonexec",
  "status": "succeeded",
  "result": {
    "output": "1\n",
    "stderr": "",
    "exit_code": 0
  },
  "created_at": "2026-02-21T00:00:00Z",
  "updated_at": "2026-02-21T00:00:01Z",
  "deadline_at": "2026-02-21T00:01:00Z",
  "completed_at": "2026-02-21T00:00:01Z"
}

任务错误字段:

"error": {
  "code": "execution_failed",
  "message": "..."
}

提交阶段错误:

  • 400 参数/模式/时间范围/请求体非法
  • 409 request_id 已在处理中
  • 429 无可用并发容量
  • 503 无匹配能力 worker
  • 504 请求超时
  • 502 提交失败

7.2 查询任务

GET /api/v1/tasks/:task_id

响应:

  • 200 返回任务快照
  • 404 任务不存在(包含跨账号访问)

7.3 取消任务

POST /api/v1/tasks/:task_id/cancel

响应:

  • 200 取消成功(或已受理 best-effort 取消)
  • 404 任务不存在(包含跨账号访问)
  • 409 任务已终态(返回任务快照)
  • 500 取消失败

8. MCP API(Bearer Token 鉴权)

端点:POST /mcp

  • 传输:MCP Streamable HTTP
  • 服务模式:无状态 JSON 响应
  • GET /mcp 返回 405Allow: POST
  • 需要请求头:Authorization: Bearer <access-token>
  • 建议请求头:
    • Content-Type: application/json
    • Accept: application/json, text/event-stream

8.1 MCP 基础方法

支持标准 MCP 调用流程,包括:

  • initialize
  • tools/list
  • tools/call

8.2 工具定义

所有工具参数 schema 都是 additionalProperties=false。 传入未定义参数会返回 JSON-RPC -32602 invalid params

CONSOLE_HIDDEN_TOOLS 中列出的工具不会出现在 tools/list 中;如果客户端已知工具名,仍可继续通过 tools/call 调用。

每个工具的 title / description、以及每个参数的 description 可以通过 CONSOLE_MCP_TOOL_<TOOL>_TITLECONSOLE_MCP_TOOL_<TOOL>_DESCRIPTIONCONSOLE_MCP_TOOL_<TOOL>_PARAM_<PARAM>_DESCRIPTION 在运行时覆盖。将参数描述设置为空字符串会把该参数从 inputSchema.propertiesrequired 中移除(并把对应 schema 的 additionalProperties 翻转为 true),但 tools/call 依然会接受该字段。完整的 <TOOL> / <PARAM> 映射详见 Console 配置文档。

工具:echo

输入:

{ "message": "hello", "timeout_ms": 5000 }
  • message 必填
  • timeout_ms 可选,1..60000,默认 5000

输出:

{ "message": "hello" }

工具:pythonExec

输入:

{ "code": "print(1)", "timeout_ms": 60000 }
  • code 必填
  • timeout_ms 可选,1..600000,默认 60000

输出:

{ "output": "1\n", "stderr": "", "exit_code": 0 }

说明:exit_code 非 0 也按正常工具输出返回,不是协议错误。

工具:terminalExec

输入:

{
  "command": "pwd",
  "session_id": "optional",
  "create_if_missing": false,
  "lease_ttl_sec": 60,
  "timeout_ms": 60000
}
  • command 必填
  • session_id 可选
  • create_if_missing 可选,默认 false
  • lease_ttl_sec 可选
  • timeout_ms 可选,1..600000,默认 60000

输出:

{
  "session_id": "sess_xxx",
  "created": true,
  "stdout": "...",
  "stderr": "...",
  "exit_code": 0,
  "stdout_truncated": false,
  "stderr_truncated": false,
  "lease_expires_unix_ms": 1770000000000
}

工具:computerUse

输入:

{
  "command": "pwd",
  "timeout_ms": 60000,
  "request_id": "optional-idempotency-key"
}
  • command 必填
  • timeout_ms 可选,1..600000,默认 60000
  • request_id 可选,幂等键(账号维度)
  • 只会路由到调用账号自己的 worker-sys
  • 不包含终端会话字段(session_idcreate_if_missingcreated

输出:

{
  "stdout": "...",
  "stderr": "...",
  "exit_code": 0,
  "stdout_truncated": false,
  "stderr_truncated": false
}

工具:readImage

输入:

{ "session_id": "sess_xxx", "file_path": "/workspace/a.png", "timeout_ms": 60000 }
  • session_id 必填
  • file_path 必填
  • timeout_ms 可选,1..600000,默认 60000
  • session_id 精确等于 computerUse 时,路由到调用账号自有 worker-sysreadImage capability
  • 其他 session_id 仍路由到 terminalResource capability

行为:

  • 若目标 MIME 为 image/*:返回一个图片内容项。
  • 若目标 MIME 非图片:返回一个文本内容项:
    • unsupported mime type: <mime>; expected image/*

8.3 MCP 错误行为

  • Token 缺失或无效:HTTP 401
  • 参数校验失败:JSON-RPC -32602
  • 执行异常:作为 MCP tool error 内容返回(isError=true

9. Worker gRPC API(api/proto/registry/v1/registry.proto

服务定义:

service WorkerRegistryService {
  rpc Connect(stream ConnectRequest) returns (stream ConnectResponse);
}

9.1 流程

Worker 建立双向流后,通常会发送:

  1. ConnectRequest.helloConnectHello
  2. 周期性 ConnectRequest.heartbeatHeartbeatFrame
  3. 对调度任务回传 ConnectRequest.command_resultCommandResult

Console 回包:

  1. ConnectResponse.connect_ackConnectAck
  2. ConnectResponse.heartbeat_ackHeartbeatAck
  3. 下发执行任务 ConnectResponse.command_dispatchCommandDispatch

9.2 核心消息

  • ConnectHello 包含 worker 标识、能力声明、labels、version、worker_secret
  • CommandDispatch 包含:
    • command_id
    • capability
    • payload_json
    • deadline_unix_ms
  • CommandResult 包含:
    • command_id
    • 可选 error { code, message }
    • payload_json
    • completed_unix_ms

10. 安全说明

  • 当前版本 console gRPC 不提供内建 TLS/mTLS。
  • worker-docker 默认会拒绝不安全 console 端点,只有显式设置 WORKER_CONSOLE_INSECURE=true 才允许明文连接。
  • worker-syscomputerUse 在宿主机直接执行 /bin/sh -lc,不提供容器隔离。
  • worker-sysreadImage 直接读取宿主机文件,且仅接受 session_id=computerUse
  • worker-sys 必须部署在独立主机并配合严格的操作系统权限控制。
  • 请将 console HTTP(:8089)和 gRPC(:50051)端点放在反向代理/网关之后,并对外访问强制 TLS。
  • 生产环境应将 gRPC 端口保持内网并通过隧道/链路加密。
  • Token 明文与 WORKER_SECRET 仅在创建时返回一次。
  • GET /api/v1/console/tokens/:token_id/valueGET /api/v1/workers/:node_id/startup-command 设计为永久 410 Gone