news 2026/9/23 23:23:24

AO Cloud API 客户端 `@aoagents/cloud-client` 实战指南:运行时中立的 fetch 客户端与 Worker 生命周期契约

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AO Cloud API 客户端 `@aoagents/cloud-client` 实战指南:运行时中立的 fetch 客户端与 Worker 生命周期契约

【免费下载链接】agent-orchestrator

Run and supervise teams of coding agents from planning to merge. Any harness (Claude code, codex, +25 more). Desktop, web, mobile, and cloud agents.

项目地址:https://gitcode.com/gh_mirrors/ag/agent-orchestrator
点击查看免费下载

导读

@aoagents/cloud-client是 Agent Orchestrator 仓库中面向 AO Cloud 公开 API 的运行时中立 TypeScript 契约包,同时内置一个零依赖的 fetch 客户端实现。它定义了客户端与云端之间的调用边界:既为桌面、Web、移动端提供面向组织、项目、会话的CloudClient,也为沙箱 Worker 提供覆盖 bootstrap、心跳、fenced turn、凭据、checkout-grant、子编排、工作区与终端传输的WorkerClient。读完本文,你将掌握该包的配置方式、认证模型、两类客户端的完整 API 面、SSE 事件流重连机制、幂等与分页约定,以及如何基于仓库内的 OpenAPI 契约自行生成类型。

一、包定位:只定义客户端边界,不实现服务端路由

从 packages/cloud-client/README.md 的定位描述可以明确:本包是"runtime-neutral TypeScript contracts and a small fetch-based client for AO Cloud's public API"。它只负责定义"客户端边界"(client boundary),当前仓库并不实现 Cloud 的服务端路由,服务端由独立的 AO Cloud 实现提供。

这一点在 contracts/cloud/openapi.yaml 的info.description中同样被强调:这是 "Client-facing contract for a separate AO Cloud implementation. This repository does not serve these routes",其中 Worker 部分文档化了沙箱 Worker 使用的精确出站 HTTP 协议——一次性 bootstrap、轮换凭据、fenced turn 执行、编排,以及持久化的工作区与终端传输。

包结构非常精简(见 packages/cloud-client):

文件作用
src/client.tsCloudClientWorkerClient两个类的完整实现与工厂函数
src/index.ts包入口,重新导出客户端类、工厂函数与全部类型
src/types.ts从生成 schema 映射出来的领域类型别名与请求选项接口
src/schema.ts由 OpenAPI 契约生成的 TypeScript 类型(提交进仓库)
test/client.test.ts基于 vitest 的客户端行为测试
package.json包元信息与generatebuildtypechecktest脚本

从 package.json 可以看出,它同时导出了主入口../schema子路径,type: "module"sideEffects: false,打包产物只包含dist与 README,publishConfig.accesspublic

二、快速上手:两个客户端的最小用法

2.1 CloudClient:面向用户/组织资源的客户端

import { createCloudClient } from "@aoagents/cloud-client"; const cloud = createCloudClient({ baseUrl: "https://cloud.example.com", getAccessToken: () => authSession.getAccessToken(), fetch, }); const sessions = await cloud.listSessions(orgId, { limit: 50 });

配置项说明(对应 client.ts 中的CloudClientConfig):

配置项类型说明
baseUrlstringCloud 服务根地址。构造时会被new URL()校验,若包含查询串或片段(query/fragment)会抛出TypeError,尾部的/会被去除
getAccessToken() => MaybePromise<string \| null \| undefined>每个请求发起前立即调用的取 token 回调,由调用方负责认证与刷新
fetchtypeof globalThis.fetch(可选)注入自定义 fetch 实现,便于测试(如 Node/测试环境 mock)或自定义传输

2.2 WorkerClient:面向沙箱 Worker 的客户端

import { createWorkerClient } from "@aoagents/cloud-client"; let workerToken: string | null = null; const worker = createWorkerClient({ baseUrl: "https://cloud.example.com", getWorkerToken: () => workerToken, fetch, }); const bootstrap = await worker.bootstrap({ bootstrapToken: oneTimeTicket, version: workerVersion, capabilities, }); workerToken = bootstrap.workerToken; const heartbeat = await worker.heartbeat({ version: workerVersion, capabilities }); workerToken = heartbeat.workerToken;

WorkerClientConfig(client.ts)与CloudClientConfig结构相同,只是 token 回调是getWorkerToken

三、认证模型:调用方持有 token,客户端按请求即时取用

该包的核心设计原则是"The caller owns authentication and token refresh"

  • createCloudClient会在每次用户请求之前立即调用getAccessToken()获取最新 token;
  • createWorkerClient对每个已认证的 Worker 请求做同样的事。

这一点在源码里有明确体现:CloudClient.authorizedFetch(client.ts)每次请求前调用getAccessToken(),token 缺失时抛出 401 的CloudApiError,随后以Authorization: Bearer <token>注入请求头;WorkerClient.authorizedFetch(client.ts)则以Authorization: Worker <token>前缀注入。

测试 client.test.ts 专门验证了这一行为:连续两次listProviderConnections调用会触发getAccessToken两次,且两次请求头分别为Bearer first-tokenBearer second-token,证明客户端不会缓存 token,永远取最新值——这为 token 刷新场景提供了天然支持。

Worker 侧的认证细节由契约定义。在 openapi.yaml 的securitySchemes中:

  • bearerAuth:HTTP Bearer 认证(JWT),用于用户侧 API;
  • workerAuth:header 中的 apiKey,格式为Worker <token>,要求 token 携带当前 worker ID 与 epoch,沙箱被替换时未过期 token 会被STALE_WORKER_TOKEN围栏(fence)掉;
  • 路由级作用域包括worker:connect(心跳)、worker:event(事件)、worker:turn:claim/worker:turn:poll/worker:turn:complete(turn 执行)、worker:credential:read(agent 密钥)、worker:git(checkout grant)、worker:orchestrate(子编排)、worker:transport(工作区与终端传输)。

四、Worker 生命周期:bootstrap → 心跳 → 轮换凭据

4.1 一次性 bootstrap 交换

WorkerClient.bootstrap(client.ts)是唯一的免认证请求,走unauthenticatedRequest,即不会附加Authorization头(测试 client.test.ts 明确断言 bootstrap 请求没有 Authorization 头)。

契约 openapi.yaml 说明:bootstrap token 是一次性(one-time)票据,原子消费、不可重放;成功响应会分配 worker epoch 并返回首个短生命周期 worker token,该 token 携带票据的 scopes,禁止被记录日志或持久化。测试中的响应体{ workerToken, workerId, epoch, expiresIn, sessionId, launch }(client.test.ts)展示了 bootstrap 成功后的完整返回结构,launch内含 sessionId、projectId、harness、displayName、branch、repositoryUrl、defaultBranch 等启动上下文。

4.2 心跳与 token 轮换

WorkerClient.heartbeat(client.ts)在每次心跳时都会返回一个新签发的 token(同一 worker 身份、epoch 与 scopes),调用方需要把返回值中的workerToken写回内存供下次使用——这正是 README 示例中workerToken = heartbeat.workerToken;的意义。

契约 openapi.yaml 补充了底层语义:心跳记录 worker 存活,将"引导中"的沙箱提升为"运行中",且旧 token 不会被吊销,在过期前仍有效,除非 worker epoch 被替换。WorkerClient.bootstrapheartbeat都使用cache: "no-store",测试断言了这一点(client.test.ts)。

4.3 凭据与 checkout-grant 的安全处理

README 明确规定:bootstrap、worker、agent-credential、checkout-grant 四类秘密只能保存在内存中,绝不写入日志。携带秘密的请求统一使用cache: "no-store",且 credential 与 checkout-grant 的响应还要求服务端返回Cache-Control: no-store

对应源码:getCredential(client.ts)与createCheckoutGrant(client.ts)均带cache: "no-store";契约侧 openapi.yaml 与 openapi.yaml 在响应头中要求Cache-Control: no-store。测试 client.test.ts 同样覆盖了这两个请求的 no-store 断言。

五、CloudClient 全 API 面:账户、GitHub、项目、会话、工作区与 Provider

CloudClient(client.ts)的方法围绕组织作用域资源组织,路由统一以/api/cloud/v1/orgs/{orgId}/...拼接(orgPath,client.ts),并会对orgIdsessionIdprojectId等做encodeURIComponent编码(测试 client.test.ts 验证了含空格、/?等特殊字符的编码行为)。

按功能域划分:

  • 账户getCurrentAccount()/api/cloud/v1/me,返回当前用户与组织成员关系;
  • AgentslistAgents(orgId)/orgs/{orgId}/agents,返回运行时与组织宿主提供的 agent profile(含 capabilities 与 availability 状态,见测试 client.test.ts);
  • ProjectslistProjects(支持 cursor/limit 分页)、createProjectupdateProject(PATCH)、deleteProject(返回 202 持久化删除);
  • GitHub 集成:用户级getGitHubUserConnectionstartGitHubUserAuthorizationdisconnectGitHubUser;组织级listGitHubInstallationsstartGitHubInstallationsyncGitHubInstallationdisconnectGitHubInstallationlistGitHubRepositoriescreateProjectFromGitHubcreateGitHubScratchProject
  • SessionslistSessions(可按projectId过滤)、getSessioncreateSessiondeleteSessionsendMessagecancelTurnlistSessionPullRequestsgetSessionReviewState
  • 事件流replayEvents(游标回放)与streamEvents(实时 SSE 流);
  • TerminalcreateTerminalTicketterminalUrl(构造wss://WebSocket URL,见 client.ts);
  • WorkspacelistWorkspaceFilesreadWorkspaceFilewriteWorkspaceFile(PUT)、getWorkspaceDiff
  • Provider 连接listProviderConnectionsputAgentProviderConnectionclaude-code/codex/cursor三选一)、deleteAgentProviderConnection,用于管理 coding-agent 的凭据连接(测试见 client.test.ts)。

六、SSE 事件流:断线重连与游标续传

streamEvents(client.ts)是客户端最复杂也最值得研究的方法,它以AsyncGenerator形式消费text/event-stream

  1. Accept: text/event-stream请求/sessions/{sessionId}/events?after=<sequence>
  2. 使用ReadableStreamreader 按块解码,将\r\n归一为\n,按\n\n边界解析 SSE 块(parseSSEBlock只提取data:行);
  3. 每个事件带单调递增的sequence序号,仅当event.sequence > after时才 yield,天然实现去重与续传;
  4. 流中断或可重试错误时(isRetryableStreamError判定 408/425/429/5xx,client.ts),用已消费的最大 sequence作为新的after参数重新连接;
  5. 重试退避采用指数退避加抖动(waitForRetry,client.ts),上限 4 秒;
  6. 支持AbortSignal优雅取消。

测试 client.test.ts 展示了重连语义:第一次连接收到 sequence 8,断开后用after=8重连,即使服务端重发 sequence 8 也会被跳过,最终只 yield 8、9 两个事件;而 401 这类不可重试错误(client.test.ts)不会触发重连。

七、幂等与分页:防重复与游标约定

7.1 幂等键(Idempotency-Key)

所有变更类操作(创建项目、发送消息、取消 turn、创建子会话等)都接受IdempotentRequestOptions,其中idempotencyKey为必填字符串,通过Idempotency-Key请求头传递。validateIdempotencyKey(client.ts)强制1~200 个字符

契约侧语义(openapi.yaml):同一 key 用于相同命令时返回原始结果;用于不同命令时返回IDEMPOTENCY_CONFLICT。测试 client.test.ts 验证了冲突场景下CloudApiError携带status: 409code: "IDEMPOTENCY_CONFLICT"requestIddetails的完整错误信封。

7.2 分页与事件游标

分页统一使用PaginationOptions { cursor?, limit?, signal? }(types.ts),limit默认 50、最大 100(契约Limit参数,openapi.yaml)。事件回放使用EventReplayOptions { after?, limit?, signal? }after为 int64 序号,默认 0,limit默认 100、最大 500(契约EventLimit/After参数,openapi.yaml)。withQuery辅助方法(client.ts)保证未提供的查询参数不会被序列化。

八、错误处理:统一错误信封CloudApiError

客户端把所有失败响应统一归一为CloudApiError(client.ts),其字段:

字段来源
statusHTTP 状态码
code错误信封中的机器可读 code(如AUTH_REQUIREDIDEMPOTENCY_CONFLICT
requestId服务端错误信封或x-request-id响应头
details可选的附加结构化信息
envelope完整错误信封ErrorEnvelope

非 JSON 的失败响应会被包装为INVALID_RESPONSE错误;本地缺少 token 时抛出AUTH_REQUIRED/WORKER_AUTH_REQUIREDtoErrorEnvelope(client.ts)负责从响应体或响应头中尽力恢复错误结构。

九、契约驱动开发:从 OpenAPI 生成类型

README 明确了契约驱动工作流:

The source contract iscontracts/cloud/openapi.yaml. Runnpm run generatefrom this directory after changing it. The generatedsrc/schema.tsfile is committed so consumers do not need an OpenAPI toolchain.

即:

  1. 契约唯一事实来源是仓库根目录的 contracts/cloud/openapi.yaml(约 3700 行,OpenAPI 3.1.0,覆盖 Account/Agents/Projects/Sessions/GitHub/Pull Requests/Reviews/Events/Terminal/Workspace/Providers/Worker Lifecycle/Worker Execution/Worker Orchestration/Worker Transport 等标签);
  2. 修改契约后在packages/cloud-client目录下执行npm run generate(脚本为openapi-typescript ../../contracts/cloud/openapi.yaml -o src/schema.ts,见 package.json);
  3. 生成的 src/schema.ts直接提交进仓库,消费者无需安装 OpenAPI 工具链即可获得完整类型;
  4. src/types.ts 再从 schema 的components["schemas"]映射出全部领域类型(SessionProjectClientEventWorkerTurnWorkerTransportRequest等),并定义PaginationOptionsEventReplayOptionsIdempotentRequestOptionsRequestOptions四个请求选项接口。

测试与类型检查脚本:npm run typecheck(同时检查主 tsconfig 与测试 tsconfig)、npm test(vitest 运行 test/client.test.ts)。

十、Worker 路由覆盖范围:明确包含与明确排除

README 对 Worker 客户端的边界做了精确声明:

明确覆盖(与 openapi.yaml 的 worker 路由一一对应):

  • bootstrap / heartbeatPOST /worker/bootstrapPOST /worker/heartbeat
  • eventPOST /worker/eventsworker.readyagent.activitychat.assistant_delta等 allowlist 事件);
  • fenced turnPOST /worker/turns/claimGET /worker/turns/{turnId}/cancellation?attempt=POST /worker/turns/{turnId}/completePOST /worker/turns/{turnId}/fail
  • credentialGET /worker/credential
  • checkout-grantPOST /worker/checkout-grant
  • child orchestrationGET/POST /worker/childrenDELETE /worker/children/{sessionId}POST /worker/children/{sessionId}/messages(另有契约中的父会话上报POST /worker/parent/messages);
  • workspace transportPOST /worker/transport/claimPOST /worker/transport/{requestId}/completePOST /worker/transport/{requestId}/fail(承载 workspace list/read/write/diff 等操作);
  • terminal transportPOST /worker/terminals/agentPOST /worker/terminals/{terminalId}/outputPOST /worker/terminals/{terminalId}/exit

明确排除:worker provisioning(沙箱供应)、数据库细节、秘密存储、本地 daemon 路由——这些不属于公开客户端契约,消费者不应期待在包内找到对应方法。

claimTurnclaimTransport在无任务可领时返回null(服务端返回{ turn: null }/{ request: null }),测试 client.test.ts 专门验证了这一"空领取"语义;完整的 19 个路由调用链端到端断言见 client.test.ts,可作为理解 Worker 客户端全生命周期的最佳参考。

结语

@aoagents/cloud-client是一个小而精的契约型客户端:通过getAccessToken/getWorkerToken回调把认证与刷新完全交给调用方,通过 OpenAPI 契约生成提交进仓库的完整类型,通过CloudApiError统一错误信封、Idempotency-Key保证幂等、SSE 游标实现可续传事件流,并严格划分用户侧CloudClient与沙箱侧WorkerClient的边界。无论你要为桌面/移动端接入 AO Cloud 的组织、项目与会话 API,还是为沙箱 Worker 实现 bootstrap、fenced turn 与传输协议,本包都是开箱即用的 TypeScript 边界层。深入阅读 src/client.ts、test/client.test.ts 与 contracts/cloud/openapi.yaml 三份文件,即可完整掌握其实现细节。

【免费下载链接】agent-orchestrator

Run and supervise teams of coding agents from planning to merge. Any harness (Claude code, codex, +25 more). Desktop, web, mobile, and cloud agents.

项目地址:https://gitcode.com/gh_mirrors/ag/agent-orchestrator
点击查看免费下载

相关推荐

上一篇:Seafile自定义文件格式渲染器开发终极指南:打造专属预览体验
下一篇:Flexbugs完全攻略:Web工程师必备的Flexbox兼容性解决方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 23:16:00

佛山家用壁挂炉维修电话|漏水漏气预约检测|欧米到家报修热线

&#x1f4dd; 文章简介佛山家庭使用壁挂炉时&#xff0c;常见问题包括不点火、不出热水、地暖或暖气片不热、故障代码、水压下降、漏水、风机异响、频繁启停等。欧米到家提供壁挂炉检测、维修、清洗保养、采暖调试及配件更换建议服务&#xff0c;覆盖佛山各区&#xff1a;禅城…

作者头像 李华
网站建设 2026/9/23 23:08:40

Genshi模板引擎进阶实战:py:match、流式处理与性能调优

掐指一算&#xff0c;距离我上一次系统整理 Genshi 的笔记已经过去挺久了。那篇记录的是最基础的环境搭建、语法概览&#xff0c;还有模板加载的入门流程。这几个月里&#xff0c;我陆陆续续把几个内部项目从原先的字符串拼接式 HTML 生成&#xff0c;整体迁移到了 Genshi 上&a…

作者头像 李华
网站建设 2026/9/23 23:05:14

微信小程序 image 组件实战:14 种图片显示模式完整解析

前言 在微信小程序开发当中&#xff0c;image图片组件是使用频率极高的基础组件。我们在开发时经常遇到图片尺寸和容器尺寸不匹配的问题&#xff1a;图片被拉伸变形、部分画面被裁剪、留白过多等等。小程序 image 组件内置了多种 mode 显示模式&#xff0c;用来控制图片的缩放、…

作者头像 李华
网站建设 2026/9/23 23:04:29

Python+Flask+dlib人脸识别考勤系统:从环境搭建到阈值调优全流程

简介&#xff1a;本资源是一套基于Python、Flask与dlib实现的人脸识别企业考勤管理系统&#xff0c;属于高分毕业设计项目源码&#xff0c;面向计算机相关专业的毕业生及课程设计学习者&#xff0c;可帮助解决人脸考勤场景下的身份验证与出勤统计问题。项目已通过导师指导与答辩…

作者头像 李华
网站建设 2026/9/23 23:04:11

Ubuntu 24.04 双系统 GPU 环境搭建:Nvidia 驱动、CUDA 与 cuDNN 全链路指南

简介&#xff1a;这份PDF资料面向需要在Windows 11基础上搭建Ubuntu 24.04双系统的开发者与深度学习入门者&#xff0c;重点解决从系统安装到GPU开发环境配置的完整链路问题。内容覆盖Ubuntu 24.04安装、Nvidia驱动、CUDA、cuDNN、Anaconda、Python虚拟环境以及VS Code与PyChar…

作者头像 李华
网站建设 2026/9/23 23:00:16

Tyk Gateway 测试框架完全指南:从 TestCase 到端到端 HTTP 测试

API网关后端云原生 【免费下载链接】tyk Open Source API and AI Gateway supporting REST, GraphQL, TCP, gRPC and MCP (Model Context Protocol) 项目地址&#xff1a; https://gitcode.com/gh_mirrors/ty/tyk 点击查看 免费下载 Tyk 是一个开源 API 与 AI 网关&#xff0c…

作者头像 李华