Agent Sandbox Registry

python-sdk

托管代理

docs/zh/guide/hosted-agents.md

托管代理

用户向的说明和一条能跑完的案例在 Agents API。本页是路由参考。

目前支持 Codex 和 Qwen Code。目前未支持的适配器名称,包括 Claude Code、Cursor、Qoder 和通用 command,返回 HTTP 404,错误类型是 not_found_error,响应头 x-should-retry: false。

路由在沙箱服务端(agent_sandbox.server)的 agents 能力组上。该组默认关闭,只有 ABX_SERVER_ENABLED_GROUPS 包含 agents 时才打开。组关闭时,同样的路径返回 404,正文会说明路由已禁用。

export ABX_SERVER_ENABLED_GROUPS=agents
python -m agent_sandbox.server

模板服务监听 9000 端口。OpenAI 风格的客户端把 base_url 指到 http://127.0.0.1:9000/v1。设置了 ABX_SERVER_TOKEN 时,agents 路由同时接受 X-Access-Token 和 Authorization: Bearer。其他路由仍然只认 X-Access-Token。

最佳实践

全部是本地操作,并且会标明

这里没有任何操作在 OpenAI 上运行。每个操作要么是本地进程,要么是本地状态,并且都带标记:

differences 代码 含义
queued_not_steered 回合进行中发送的输入会排成新回合。两个 CLI 都不能向运行中的进程写入字节。
usage_adapter_best_effort usage 是 CLI 报告的值;CLI 什么都没报告时是 null。
redaction_best_effort 脱敏只覆盖已登记的密钥和常见的令牌形态。
update_in_place、snapshot_at_session_start 定义原地更新。会话在创建时复制一份定义。
hosted_request_converted、nothing_provisioned 空的 openai_hosted 环境请求被转成 self_hosted。环境只是一个目录绑定。
local_workspace、no_overwrite 路径相对于环境的工作目录。内容不同的已有文件会被拒绝。
local_blob 文件 id 是服务端内存里的 blob。
not_hosted_template、applies_env_and_files_only 模板只是 {name, env, 内联文件},没有别的。
memory_only 密钥和 vault 记录只在内存里,重启即丢失。
secret_in_agent_env 代理运行的代码可以从 CLI 环境里读到凭据。
snapshot_copy、reported_paths_only、delete_removes_snapshot_only 产物是 CLI 报告的路径的副本。删除产物不会动原文件。
trace_from_journal_timing_only span 来自日志时间戳,不含任何文本。
ids_from_cli_only、turns_grouped_from_parent_stream、turns_from_rollout 子代理 id 是 CLI 自己给出的。
summary_not_encrypted_compaction compact 是本地摘要。
response_is_cli_turn、model_passthrough、stream_replayed_after_turn、queued_steer Responses 的语义。
local_signer 由本服务签名并投递 webhook 事件。
not_implemented_locally 出现在没有本地能力的路由的 404 上。

拒绝遵循同一条规则。服务端做不到的字段或变体是 400 invalid_request_error,param 指出字段,并带 x-should-retry: false,绝不会先接受再忽略。没有本地能力的路由是 404 not_found_error,带 x-should-retry: false,绝不是 501,也绝不是空的 200。

适配器

JSON 里的选择 规范 id PATH 上的二进制 只有要用时才安装
codex codex codex npm install -g @openai/codex
qwen-code、qwen、qwencode qwen-code qwen npm install -g @qwen-code/qwen-code

选择顺序:

  1. 请求头 X-ABX-Adapter,或正文里的 adapter / runtime(顶层或 agent 内)
  2. agent.model 或 model,且这个字符串是上面的名字之一(gpt-5-codex 这种真实模型 id 会传给 CLI,不会用来选适配器)
  3. 配置 agents.default:环境变量 ABX_AGENTS_DEFAULT,或 ABX_AGENTS_CONFIG 指向的 JSON 里的 default / agents.default
  4. 都没有时,用产品顺序里的第一个:codex,然后才是 qwen-code

GET /v1/agents/runtimes 默认 order=desc。order=asc 才是上面的产品顺序。default: true 标出第 4 步选中的那一个,不看数组下标。真实模型 id(gpt-5)传给被选中的 CLI,不改变适配器。要换一个,在请求里点名。

会话、事件、条目、回合

这些路由上的错误使用 OpenAI 的错误信封 {"error": {"message", "type", "param", "code"}}。

创建会话:

curl -s -X POST http://127.0.0.1:9000/v1/agents/sessions \
  -H 'Content-Type: application/json' \
  -d '{"agent":{"model":"codex"}}'

GET /v1/agents/sessions 列出会话(可用 agent_id 过滤)。GET 和 DELETE /v1/agents/sessions/{id} 读取和删除一个会话,删除时也会清掉产物快照。POST /v1/agents/sessions/{id} 只更新 metadata:agent、vault_ids、environment 返回 400,其他任何键也是 400。会话对象是 agent.session,environment.type 为 self_hosted,environment.workspace_directory 默认是 /workspace。

会话可以用内联的 agent,也可以用定义的 agent_id,再加可选的 environment: {"type": "self_hosted", "id": "env_..."} 和 vault_ids。内联 agent 与定义用同样的规则校验:mcp 以外的 tools、multi_agent.enabled、不在 auto|default 内的 service_tier、非 text 的 text.format 都是 400。

会话、定义、环境、vault、模板、response 和 webhook 端点都归调用者所有。有服务端策略时,调用者是身份 id;没有策略时只有一个本地所有者。别人的 id 与不存在的 id 得到完全相同的应答。

排入一个回合。正文是一条输入消息;响应是 HTTP 202,空响应体。相同的 Idempotency-Key 加相同正文会重放这个 202,不会启动第二个回合。相同的键加不同正文是 409 idempotency.mismatch(x-should-retry: false)。input.tool_result、computer_use_approval_request_result、input_image、input_file 都是 400。

curl -s -D - -o /dev/null -X POST \
  http://127.0.0.1:9000/v1/agents/sessions/$ID/events \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: turn-1' \
  -d '{"events":[{"type":"agent.session.input.message","input":"Say hello"}]}'

带 Accept: text/event-stream 的 GET /v1/agents/sessions/{id}/events 以 text/event-stream 流式返回映射后的事件(id 是运行时序号)。不带 after 时从现在开始跟踪;流会一直开着,直到你看到的那个回合结束、会话重新空闲。?after=0(或 ?after=evt_<seq>)会回放环形缓冲区,送出 idle 事件且没有更新的排队内容后关闭。

GET .../items、GET .../turns、GET .../turns/{turn_id}、GET .../turns/{turn_id}/items 返回列表信封 {object, data, first_id, last_id, has_more}。limit 取 1–100(默认 20),order 为 asc 或 desc(默认 desc)。

GET /v1/agents/runtimes 只列出 codex 和 qwen-code,并说明各自的二进制是否在 PATH 上。

Agent 定义

POST /v1/agents、GET /v1/agents、GET、POST(更新)和 DELETE /v1/agents/{agent_id}。id 是不透明的(agent_...)。model 必填,除非它是适配器名,否则作为 -m 传给 CLI。更新是原地的;运行中的会话保留它启动时的那份副本,删除定义不会停止任何会话。

只有走 http 传输的 mcp 工具是真实的。下面这些是 400:其他工具类型、stdio 传输、allowed_tools、request_metadata、required、不是 environment 的 connection_origin、带用户信息、查询串或片段的 URL、multi_agent.enabled、不在 auto|default 内的 service_tier、不是 medium 的 text.verbosity、reasoning.summary,以及 Qwen Code 上的 reasoning.effort(Codex 支持)。MCP 请求头的值只写不读:响应里显示 "***"。

环境、文件、模板

Vault 与凭据

/v1/vaults 和 /v1/vaults/{vault_id}/credentials 使用官方的对象形状。Vault 在内存里(memory_only),计入 ABX_AGENTS_MAX_VAULTS(每个所有者默认 100 个),只显示 id、name、metadata、created_at。

凭据是 static_bearer,或带访问令牌的 mcp_oauth。任何响应、错误消息或事件都不含密钥的值、前缀、长度或哈希。下面这些是 400:environment_variable(没有出口代理,唯一的投递方式会把密钥交给代理运行的代码)、mcp_oauth.refresh(没有刷新代理)、networking.unrestricted、凭据自己主机以外的 limited 主机、不是 https 或指向私有主机的 mcp_server_url,以及含换行的令牌。

用会话(或环境)的 vault_ids 挂载 vault。每个回合,凭据会注入到该会话中 URL 的协议、主机、端口都相同的 MCP 工具,形式是放在子进程环境里的 Authorization: Bearer 请求头(Codex 用 env_http_headers,Qwen 用 .qwen/settings.json 里的 ${VAR} 占位符),绝不出现在 argv。没有匹配凭据的工具以无认证方式运行;匹配到两个就必须显式给出 credential_id。轮换凭据从下一个回合起生效。会话创建后凭据或 vault 被删除,或 expires_at 已过期,下一个事件会返回 400(agents.credential_unavailable、agents.credential_expired),而不是悄悄地无认证运行。每个凭据对象都带 secret_in_agent_env。

产物、追踪、子代理

Responses

POST /v1/responses 运行本地 CLI 的一个回合,返回 response 对象。model 是已保存定义的 id,或者作为 CLI 的模型透传(gpt-5-codex);qwen 这样的运行时名字表示“CLI 的默认模型”,对象里会写 model_resolved: false。没有 previous_response_id 时,在 ABX_AGENTS_RESPONSES_WORKSPACE(默认 /workspace)里创建新的 CLI 会话。带了它,回合会续接那段对话,但只能从该对话最新的 response 续接(CLI 会话是线性的),否则是 400 agents.previous_response_not_latest。

模型与 webhook

GET /v1/models 列出调用者的定义和两个适配器,owned_by: agent-sandbox-local,并带 x_agent_sandbox.kind / installed。GET /v1/models/{id} 对未列出的 id 返回 404 model_not_found,且没有副作用。

Webhook 端点(/v1/webhook_endpoints,创建、读取、更新、列出、删除、rotate_secret、test;GET /v1/webhook_event_types)是本地记录。whsec_ 签名密钥只在创建和轮换时返回一次。服务端为所有者的会话发送 agent.session.created、in_progress、idle、failed,按 Standard Webhooks 方式签名(webhook-id、webhook-timestamp、webhook-signature),所以 client.webhooks.unwrap 可以验证。agent.session.action_required 永远不会发生,也不被接受。URL 必须是 https,不含用户信息和查询串,且不是私有或回环主机;不跟随重定向。本地开发时设置 ABX_AGENTS_WEBHOOK_ALLOW_HTTP=1 和 ABX_AGENTS_ALLOW_PRIVATE_URLS=1。keep_old_secret_active_for_24_hours 是 400。

没有本地能力:404

操作 原因
POST /v1/responses/input_tokens 没有与 CLI 将要调用的模型一致的分词器,真实计数只有在生成之后才知道。
DELETE /v1/models/{id} 没有微调模型。用 DELETE /v1/agents/{agent_id} 删除定义。
执行器注册和执行器通道(environment.remote_url) 它们是 OpenAI 托管编排器的客户端。POST /v1/agents/environments/{id}/register 和 GET .../{id}/connect 返回同样带标记的 404(真实的注册路径未公开)。

每一个都返回 404、type: not_found_error、code: agents.not_implemented_locally、x-should-retry: false、X-Agent-Sandbox-Local: 1。

只演示调用方式的客户端,对着你已经启动的服务:hosted_codex.py 和 hosted_qwen.py。local_files_and_session.py 对着本地服务上传一个文件并开一个会话。它在 PATH 上放名为 codex 的本地程序,不读取模型 API key。见 examples/agents/README.md。