ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OpenShell TypeScript SDK 完全指南:从网关连接到沙箱生命周期管理

OpenShell TypeScript SDK 完全指南:从网关连接到沙箱生命周期管理 【免费下载链接】OpenShellOpenShell is the safe, private runtime for autonomous AI agents.项目地址https://gitcode.com/gh_mirrors/op/OpenShell点击查看免费下载导读nvidia/openshell-sdk是 OpenShell 网关的官方 TypeScript 客户端一个基于 Connect 协议gRPC-Web 兼容的轻量级、惯用化绑定层代码由 OpenShell protobuf 定义自动生成。对于在 Node.js 中编排自主 AI Agent 沙箱的开发者本文将带你完成从安装、认证连接到沙箱创建、执行、流式交互、端口转发、SSH、策略配置与工作负载模板的完整闭环并深入源码级原理说明每个 API 背后的实现机制与边界约束。读完本文你将能够用类型安全的方式在代码中驱动 OpenShell 网关的全部核心能力而不再局限于 CLI。安装与认证连接网关的第一公里安装方式该 SDK 通过 GitHub Packages 发布publishConfig.registry指向https://npm.pkg.github.com见 package.json。安装前需要在项目根目录创建.npmrc将nvidiascope 指向 GitHub Packages registrynvidia:registryhttps://npm.pkg.github.com使用具有read:packages权限的 GitHub token 完成认证后即可安装npm install nvidia/openshell-sdk关于版本package.json 中的版本号为0.0.0占位符CI 在发布时从 git release tag 写入真实版本与 Rust、Python 包保持一致。官方建议 SDK 与网关使用同一 OpenShell release原始类型与 RPC 描述符由该 release 的 protobuf 定义生成只要 RPC 契约保持兼容经整理curated的方法就保持兼容。连接选项与传输层OpenShellClient.connect()接收一个ConnectOptions对象。从 transport.ts 的源码可以看到完整的选项集选项说明gateway网关 URL支持http://本地开发走 h2c或https://Node TLS 直通caCertCA 证书PEM省略则使用系统根证书clientCert/clientKeymTLS 客户端证书与私钥PEM必须成对提供默认本地 OpenShell 网关Docker、VM、Homebrew、Linux 包要求 mTLS 认证调用方oidcToken直接 OIDC bearer token与edgeToken互斥oidcTokenProvider可续期的 OIDC bearer provider与oidcToken、edgeToken互斥edgeTokenCloudflare Access token仅限cf-access-jwt-assertion/cookie 字符集见assertEdgeTokeninsecureSkipVerify关闭 TLS 校验仅限开发/调试allowInsecureAuth允许通过明文http://向非回环主机发送认证 token默认拒绝防止凭据在线缆上泄露传输层在buildTransport中做了四道前置校验assertMtlsPair、assertTokenExclusivity、assertEdgeToken、assertTokenTransportSecurity例如只传clientCert而不传clientKey会在连接前直接抛出SdkError(invalid_config)而不是等 TLS 握手失败后才暴露。authInterceptor的优先级为oidcTokenProvideroidcToken写入authorization: BeareredgeToken写入cf-access-jwt-assertion头与CF_Authorizationcookie。一个最小可用的连接示例import { OpenShellClient } from nvidia/openshell-sdk const client await OpenShellClient.connect({ gateway: https://gateway.example.com, oidcToken: process.env.OPENSHELL_TOKEN, })connect()构造的是惰性客户端在首个 RPC 之前不会发起任何网络请求源码注释明确 No network request is made until the first RPC。如果启动时必须验证网关可达性请显式调用health()。静态oidcToken与edgeToken在客户端生命周期内保持不变。面向长生命周期服务client-credentials 提供器对于长期运行的服务自动化静态 token 无法续期应使用clientCredentials()提供器实现见 oidc.tsimport { clientCredentials, OpenShellClient } from nvidia/openshell-sdk const client await OpenShellClient.connect({ gateway, oidcTokenProvider: clientCredentials({ issuer: https://idp.example.com/realms/openshell, clientId: openshell-service, clientSecret: () process.env.OPENSHELL_OIDC_CLIENT_SECRET!, scopes: [sandbox:read, sandbox:write], audience: openshell-gateway, }), })该提供器内部实现了完整的 OAuth 2.0 client-credentials 流程发现并校验 issuer请求{issuer}/.well-known/openid-configuration校验返回的issuer与配置一致且存在token_endpointissuer 必须使用 HTTPS回环地址允许 HTTPURL 不得包含 userinfo 或 fragmentsecureUrl校验。内存缓存与提前续期token 缓存在内存中在过期前 30 秒EXPIRY_LEEWAY_MS 30_000即视为过期重新换取并发请求共享同一个 in-flight 交换#inFlight避免令牌风暴。响应边界保护响应体上限 1 MiBMAX_RESPONSE_BYTES默认 30 秒超时expires_in必须是正有限数值。根客户端没有显式close()方法——因为 Connect 不保留专用会话只需关闭操作级operation-scoped的流与 forward 句柄即可。沙箱生命周期创建、等待、执行与删除创建沙箱并暴露服务const sandbox await client.sandbox.create({ image: registry.example.com/agents/python:latest, serviceExposures: [{ targetPort: 8080 }], }) console.log(sandbox.serviceUrls[]) await client.sandbox.waitReady(sandbox.name, 120)从 client.ts 的实现看create()会把整理的字段组装成SandboxSpecSchemaenvironment默认空对象、providers默认空数组、template承载 image、gpu映射到resourceRequirements.gpu、tty默认false。返回的SandboxRef包含id、name、workspace、phase、labels、resourceVersionu64 以字符串渲染避免 JS number 精度丢失以及serviceUrls按服务名索引的地址表。SandboxSpec的完整字段含默认值说明参见源码中的接口定义。waitReady(name, timeoutSecs)是轮询实现从 250ms 起始指数退避至 2s 上限每次轮询 RPC 携带剩余 deadlinedeadlineOptions保证卡死的get()会被 abort 而不是无限挂起。ready与completed都视为就绪stopped/error阶段会抛出SdkError(connect)。执行命令const result await client.sandbox.exec(sandbox.name, [/bin/sh, -c, echo hello]) console.log(result.stdout.toString())exec()返回ExecResult { exitCode, stdout, stderr }本质上是内部execStream的缓冲区聚合实现execStream的 drain 逻辑。ExecOptions支持workdir、environment、timeoutSecs、stdin、noLoginShell跳过 login shell 启动文件自动化场景建议true以及signalAbortSignal 提前中止。删除类型化结果而非布尔值const deletion await client.sandbox.delete(sandbox.name) console.log(deletion.outcome) // completed, accepted, or already_absent if (deletion.outcome accepted) { await client.sandbox.waitDeleted(sandbox.name, 60, { expectedSandboxId: deletion.sandboxId, }) }delete()返回DeletionResult这是一个类型化结果而不是布尔值accepted表示清理挂起中unspecified与未知取值不建立完成语义。sandboxId标识原始沙箱。缺失目标默认报错除非传入{ allowMissing: true }——但该选项不会掩盖父级缺失也不会让名字被复用时的重试变得安全。这是 pre-1.0 的 API 变更升级时网关与 SDK 需同步。waitDeleted配合expectedSandboxId时在名字消失或解析到不同 ID 时完成不带该选项则等待名字消失包括同名替换。使用非默认 workspace 时删除与其 wait 需传入相同的workspace。流式执行与交互式 execexecStream增量输出 带内 exit 事件for await (const event of client.sandbox.execStream(name, [pytest, -q])) { if (type in event) console.log(exit ${event.exitCode}) else process[event.stream].write(event.data) // stdout | stderr }execStream边到达边产出 stdout/stderr 分块长输出或高频率输出的命令不必等到进程退出。流的终点是一个带内in-band的{ type: exit, exitCode }事件——之所以放在流内而非返回值是让for await消费者无法丢弃它失败的命令不可能被误认为成功。用type in event判别。若网关在未给出 exit 事件前关闭流execStream会抛出SdkError(rpc)。exec()内部 drain 同一路径因此其缓冲的ExecResult语义不变。execInteractiveTTY stdin 传输原语const session await client.sandbox.execInteractive(name, [bash]) session.write(Buffer.from(echo hi\n)) session.resize(120, 40) for await (const event of session.output) { if (!(type in event)) process.stdout.write(event.data) } const code await session.doneexecInteractive是双向流第一个客户端帧是start携带 exec 请求后续帧是stdin/resize。返回的ExecInteractiveSessionControl在原始ExecInteractiveSession基础上扩展了closeInput()、cancel()与只读exitCode。既有 mock 与 wrapper 无需新增成员即可继续实现原接口wrapper 暴露新控制能力时应使用扩展类型。实现细节值得注意见 client.ts 中execInteractiveRPC 立即启动会话创建后即使尚未消费outputRPC 也会立刻开始后台接收器receiver观察传输错误并将输出以 64 KiB 分块缓冲队列上限 1 MiB16 chunk × 64 KiB。队列满时接收会等待调用方排空取消会中断该等待。该边界不含传输层当前响应帧及其自身缓冲。done的完成语义done仅在收到 exit 事件且最终 gRPC 状态成功后才 resolve传输完成失败时donereject而session.exitCode仍保留观察到的进程退出码。重复的 exit 事件与 exit 后的输出都会抛错。closeInput()与cancel()closeInput()兼容别名close()结束 stdin 与 resize 输入但继续接收输出之后的写入与 resize 会抛错cancel()中止 RPC。两者皆幂等。helper 只搬运原始字节——raw 模式、信号转发与 SIGWINCH 由调用方负责输入关闭不是终端 Ctrl-D 按键。输出放弃保护消费output的for await提前 break 会触发SdkError(rpc, exec output abandoned before completion)并中止 RPC。端口转发把沙箱服务带到本地const fwd await client.sandbox.forward(name, { targetPort: 8000, onConnectionError: (error) console.error(error), }) // ... 通过 127.0.0.1:fwd.localPort 访问沙箱服务 ... await fwd.close()forward在本地绑定一个 TCP 监听器把每个被接受的连接隧道进沙箱生命周期与 Node 进程一致。ForwardOptions支持targetHost默认127.0.0.1、localPort默认 0即临时端口、localHost默认127.0.0.1、signal与onConnectionError。从源码看其实现forwardforwardConnection先get()校验沙箱phase ready随后对每个被接受的 socket 铸一个短生命周期 SSH 会话 token打开forwardTcp双向流首帧init携带 TCP 目标与 token按 ~64 KiB 分块双向转发字节并处理背压本地 socket 缓冲满时暂停拉取waitForDrain等待排空关闭时 best-effort 撤销 token。close()幂等取消活动转发 RPC、销毁已接受 socket 并等待清理完成closedpromise 在完全拆除后 resolve。默认本地 mTLS 网关下这个路径复用了 SSH 会话 token 作为 forwardTcp 授权凭据。SSH、Providers、配置与策略const ssh await client.sandbox.createSshSession(name) await client.sandbox.revokeSshSession(ssh.token) await client.sandbox.attachProvider(name, claude) await client.sandbox.listProviders(name) await client.sandbox.detachProvider(name, claude) const config await client.sandbox.getConfig(name) config.policy!.networkPolicies[web] { name: web, endpoints: [], binaries: [] } await client.sandbox.setPolicy(name, config.policy!, { wait: true }) await client.sandbox.setSetting(name, feature.enabled, { value: { case: boolValue, value: true } })SSH 会话createSshSession为沙箱铸一个短期 token返回SshSession { sandboxId, token, gatewayHost, gatewayPort, gatewayScheme, hostKeyFingerprint?, expiresAtMs? }。响应经过validateSshResponsessh-validate.ts的信任边界校验后才交给调用方这些值会喂给 OpenSSH ProxyCommandrevokeSshSession支持allowMissing。沙箱级 ProvidersattachProvider/detachProvider返回ProviderChange { sandbox, changed }changed表示是否真正改变了附件集合。ProviderChangeOptions.expectedResourceVersion用于乐观并发u64 字符串版本不匹配会以aborted代码浮出。配置与策略getConfig返回SandboxConfigpolicy、version、policyHash、settings、configRevision、policySource、globalPolicyVersion、providerEnvRevision。沙箱级setPolicy只能修改networkPolicies静态字段filesystem、landlock、process必须与创建时策略一致否则网关拒绝更新。setPolicy的wait: true会轮询getConfig直到观察到已应用的策略哈希默认 60s 上限见waitForPolicyHash。沙箱级设置删除会被网关拒绝因此此面只暴露 upsertsetSetting。创建时的安全边界policy 与 rawSpec创建时的安全边界必须用policy表达——沙箱级setPolicy之后无法引入静态策略字段因此文件系统、landlock、进程与初始网络策略都要在创建时设置。对于整理形态未覆盖的 proto spec 字段rawSpec是逃生舱它在最顶层对组装好的 spec 做浅覆盖Object.assign见create()实现any field it sets winsawait client.sandbox.create({ image, policy: { version: 1, networkPolicies: {} }, rawSpec: { logLevel: debug, template: { runtimeClassName: gvisor } }, })沙箱工作负载模板沙箱工作负载模板SandboxWorkloadTemplate是可复用的、workspace 作用域的运行时形态拥有镜像、环境、资源与驱动特定设置从模板创建沙箱时仍可附加 labels、providers 与创建时策略。import { OpenShellClient, type SandboxWorkloadTemplate } from nvidia/openshell-sdk const client await OpenShellClient.connect({ gateway, oidcToken }) const template: SandboxWorkloadTemplate await client.sandboxTemplates.create( { metadata: { name: python, labels: { team: runtime } }, spec: { workload: { image: registry.example.com/agents/python:latest, environment: { FEATURE_FLAG: on }, resources: { cpu: 1, memory: 512Mi }, }, driverConfig: { kubernetes: { pod: { runtime_class_name: kata-containers } } }, }, }, { workspace: default }, ) const sandbox await client.sandbox.createFromTemplate({ workloadTemplate: template.metadata!.name, workspace: default, providers: [github], policy: { version: 1, networkPolicies: {} }, }) await client.sandboxTemplates.get(python, { workspace: default }) await client.sandboxTemplates.listAll({ workspace: default, pageSize: 100 }) await client.sandboxTemplates.delete(python, { workspace: default })模板 CRUD 对应 openshell.proto 中的CreateSandboxTemplate/GetSandboxTemplate/ListSandboxTemplates/DeleteSandboxTemplateRPC。SandboxTemplateClient特意返回生成的 proto 消息而非整理类型因为资源承载可移植工作负载字段加驱动特定配置在整理层不应有损。分页语义list()返回惰性Pager每次前进拉取一页 RPClistAll()只在你确实想耗尽集合时使用。pageSize控制单次请求pageToken恢复已保存的遍历。allWorkspaces: true用于平台管理员视角——判别联合类型让workspace与allWorkspaces互斥两者都省略时显式选择defaultworkspaceconst pages client.sandbox.list({ workspace: default, pageSize: 100 }) for await (const page of pages) { for (const sandbox of page.items) console.log(sandbox.name) }Pager内部还有续期 token 历史预算防护上限 10,000 个 token、1 MiB 字节见 client.ts 的maxConsumedPageTokens/maxConsumedPageTokenBytes并检测重复的续期 token 抛错防止遍历死循环。API 表面与路线图SDK 的目标是agent 对等agent parity网关能做到的就应该能通过类型化代码触达而不只限于 CLI。API 组织为共享连接之上的多个 scoped 子客户端镜像 CLI 的名词-动词模型client.sandboxSandboxClient今日可用沙箱生命周期、exec、forward、SSH、沙箱级 providers、配置与策略。client.sandboxTemplatesSandboxTemplateClient今日可用可复用沙箱工作负载模板 CRUD。client.gatewayGatewayClient规划中网关级配置与设置、健康、集群状态。client.providersProviderClient规划中网关级 provider CRUD 与 profiles。health()目前位于根级将来client.gateway落地后会移入其下保留根级别名。整理方法是被刻意、审慎地添加的因此部分网关 RPC 尚无类型化 helper。与其发布存在但会抛错的方法SDK 选择省略未整理的内容并通过下面的逃生舱让你今天就触达完整网关表面。省略意味着尚不人体工学绝不意味着不可能。高级raw 逃生舱与共享传输client.raw是覆盖每个网关 RPC 的生成客户端包括整理子客户端尚未包装的表面网关配置、provider CRUD、策略状态、watch、logs 与完整观测Sandbox。client.transport是共享连接因此额外客户端复用同一 socket。生成的请求/响应类型位于nvidia/openshell-sdk/raw子路径raw.ts 重新导出所有生成的 proto 模块import { create } from bufbuild/protobuf import { OpenShellClient } from nvidia/openshell-sdk import { WorkspaceSelectorSchema } from nvidia/openshell-sdk/raw import type { GetGatewayConfigResponse } from nvidia/openshell-sdk/raw const client await OpenShellClient.connect({ gateway, oidcToken }) // 触达整理表面尚未包装的 RPC const cfg: GetGatewayConfigResponse await client.raw.getGatewayConfig({}) const defaultWorkspace create(WorkspaceSelectorSchema, { selection: { case: workspace, value: default }, }) const status await client.raw.getSandboxPolicyStatus({ sandbox: my-sandbox, version: 0, global: false, workspaceScope: defaultWorkspace, })raw 层原样返回生成的 wire 消息保留 proto 层面的区分省略的 optional 与显式空 map而这些是整理类型可能平滑掉的。整理子客户端落地后优先使用整理方法raw永远是可用底层的常备选择。错误处理SdkError 分类体系SDK 把所有错误归一为SdkErrorerrors.ts消息统一带[code]前缀可用errorCode()提取分类。代码集合为invalid_config、tls、connect、auth、io、not_found、already_exists、aborted、canceled、rpc。fromConnect将 Connect 状态映射到这些代码NotFound→not_found、InvalidArgument→invalid_config、Unauthenticated/PermissionDenied→auth、Canceled/DeadlineExceeded→canceled等并把原始ConnectError保留为cause、其状态作为connectCode。SdkError还解码网关返回的丰富错误详情fieldViolations字段校验失败、errorInforeason/domain/metadata与retryDelayMs建议的最小重试延迟注意它不建立变更重试安全。versionPin会把非 u64 的expectedResourceVersion转成invalid_config错误保持错误分类的稳定。边界SDK 不做什么SDK 交付原语primitives而不是 CLI 的终端体验。以下内容有意超出范围交互式connect()/ PTY 所有权execInteractive、createSshSession、forward是传输原语raw 模式、OpenSSHProxyCommand与终端胶水留在 CLI。upload()/download()没有文件传输 RPC——CLI 走 tar-over-SSH。小负载可用带stdin的exec/execStream覆盖一流的网关文件传输 RPC 是后续计划。分离 / 后台 forward进程内 forward 无法比调用方活得更久forward仅限进程生命周期。开发与贡献TypeScript SDK 的开发任务通过 mise 任务编排参见mise.toml代码生成由 buf 驱动buf.gen.yaml限定客户端表面闭包生成目标为src/genmise run sdk:ts:proto # 从 proto/ 用 buf 生成 stubs mise run sdk:ts:format # Biome格式化 安全修复写文件 mise run sdk:ts:lint # Biomelint 格式检查只读 mise run sdk:ts:typecheck # tsc --noEmit mise run sdk:ts:test # Vitest 单元测试80% 行覆盖率门槛 mise run sdk:ts:build # 产出 dist/ mise run e2e:sdk:ts:exec # 针对隔离 Docker 网关的公开交互式 helper格式与 lint 由 Biome 处理biome.json2 空格缩进、单引号、分号、120 列宽生成的src/gen/被排除。sdk:ts:lint作为sdk:ts:ci的一部分在 CI 运行。运行时依赖仅三个bufbuild/protobuf、connectrpc/connect、connectrpc/connect-nodeConnect 生态Node 引擎要求20.3见 package.json。测试覆盖见 client.test.ts、oidc.test.ts、raw.test.ts 与 transport.test.ts其中包含枚举名漂移测试、传输契约测试与 OAuth 提供器行为测试可作实现行为的权威参考。赞分享【免费下载链接】OpenShellOpenShell is the safe, private runtime for autonomous AI agents.项目地址https://gitcode.com/gh_mirrors/op/OpenShell点击查看免费下载相关推荐OpenShell CLIopenshell完整使用指南沙箱生命周期、网关注册、策略与 Provider 管理实战OpenShell CLIopenshell完整使用指南沙箱生命周期、网关注册、策略与 Provider 管理实战 导读 openshell 是 OpCubeSandbox Node.js/TypeScript SDK 完全指南从沙箱创建到生命周期管理的实战手册CubeSandbox Node.js/TypeScript SDK 完全指南从沙箱创建到生命周期管理的实战手册 cubesandbox/sdk 是 CubAgent 沙箱虚拟化云原生人工智能后端容器运行时Qinglong 面板启动异常时如何用 ql check 检测并修复运行环境Qinglong 面板启动异常时如何用 ql check 检测并修复运行环境 Qinglong青龙部署后有时会遇到面板打不开、页面一直卡在“启动中”或直接上一篇华硕笔记本屏幕发灰G-Helper 三级操作完整修复色彩配置文件一次搞定下一篇Heroicons与无代码平台集成Webflow和Bubble终极使用指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表