服务对象与地域限制
PuppyIP 仅面向海外合规企业及其授权人员提供服务,不面向中国大陆地区开放或提供代理服务。本服务仅限用于中国大陆境外的合法业务活动,严禁在中国大陆境内使用本服务。
代理 IP 或服务器位于境外,不改变上述限制。不得通过中转、转接、共享或转售向中国大陆境内的最终使用者提供本服务。使用前请阅读用户服务协议。
本文要点
- 需要Agents SDK 0.28.0或更高版本;此集成的OpenCode可选peer包支持^2.0.24。
- SQLite保存会话、消息与持久事件,Lifecycle任务负责唤醒崩溃或被回收后的工作。
- read、write、edit、patch、glob、grep、shell等本地工具不能直接沿用;插件与外部执行环境要明确配置。
- 后台任务用会话内的operationId去重;重连读取历史与持久事件,未提交的实时文字不会自动重播。
这次能做什么,适合谁?
Cloudflare在10月12日宣布支持OpenCode 2.0,并明确把OpenCodeHarness标为实验性集成。它让开发者将模型调用、工具与会话能力嵌入自己的Worker应用;Durable Object是带持久存储的应用对象,不是自带文件系统和终端的完整开发机。
OpenCode负责代理循环、对话记录、工具与会话恢复;OpenCodeHarness提供SQLite存储和中断后的唤醒。公告中的Workers AI通过AI binding接入。已读资料没有给出所有账户的准入、地区可用性或完整费用,接入前仍需核对自己的计划、模型和用量限制。
先把依赖、存储和模型配齐
第一步,在自己的开发项目核对agents版本至少为0.28.0,并加入@opencode/sdk与@opencode/plugin。两包是可选peer依赖,但此集成需要它们,文档给出的支持范围为^2.0.24;公告中的@2安装示例不能替代实际版本核对。
第二步,按官方Wrangler示例配置Workers AI binding、SQLite-backed Durable Object和nodejs_compat。类名、绑定与new_sqlite_classes迁移声明要对应;示例要求compatibility_date使用当天日期,不能把10月12日当作永久固定值。
第三步,用agents/harness/opencode创建OpenCodeHarness,工厂把传入的storage交给OpenCodeWorkerd.create(),并通过Lifecycle.install(this).use(this.harness)接管生命周期。把this.ai.plugin注册进plugins,模型用agents/models/opencode的createAI连接自己的AI binding。
models: { fetch: false }跳过外部模型目录刷新,提供器会注册this.ai()中指定的模型。文档用Kimi模型演示,不意味着必须选择它或免费调用。宿主闲置30秒且没有工作或事件订阅时会关闭,下次调用重新打开,因此工厂要支持重复执行。
本地读文件和shell,为什么不能直接搬过来?
官方workerTools示例移除read、write、edit、patch、glob、grep和shell,随后加入能在Worker内运行的current_time工具。前七项依赖的本地文件和进程能力不能按桌面环境直接沿用;需要自己的工具实现,或明确连接外部执行环境。
假设你希望代理修改一个代码仓库:会话能持久保存,不等于仓库文件已经挂载,更不等于shell命令可以运行。这是设计例子。先决定文件存放、执行权限与结果如何返回,再把这些能力通过插件交给代理。
插件、远程MCP配置和技能内容应随Worker打包,在工厂的plugins数组中注册;不要依赖运行时读取本地插件文件或npm包。技能示例直接提供content,不是在云端偷偷读一份本地SKILL.md。
后台任务如何提交,避免重连后重复排队?
harness.prompt()向根会话提交并等待结果;检查status,done表示已回答,unanswered可能是失败、中断、撤回或未找到。只收到text片段不能替代完成状态。
需要后台处理时,用submit()取得回执,保留operationId和session,再在后续请求中wait()。operationId只在同一会话内去重;重复使用会返回accepted: false,不能当作全应用或跨会话的唯一性保证。
会话忙时,新输入默认排为后续任务。whenBusy: "steer"或session.steer()则在运行工作的下一步加入输入;harness.pending()可查看排队与运行中的操作。客户端应先查原任务,再决定重发。
对象被回收或浏览器断线,分别恢复什么?
会话、消息和持久事件写入对象的SQLite,表和索引使用opencode_前缀。活动会话有Lifecycle任务与心跳;对象崩溃或被回收后,alarm唤醒对象,OpenCode恢复中断工作。这是文档能力说明,不是本站实测的不停机保证。
客户端断线是另一层问题。session.events()提供实时事件,不附带完整对话快照;先用messages()读取当前上下文,或history()读取含已压缩消息的完整记录,再接续事件。持久重播使用session.log(),保存event.durable.seq并作为after传回。
持久日志不重播尚未提交的实时文字片段。对象重启后需要重建订阅,不再使用时用AbortSignal停止;订阅会让宿主保持打开。恢复会话、恢复客户端显示和重新执行有副作用的工具,要分别设计。
把演示改成应用前,先确认哪几件事?
官方示例用getByName("demo")取得同一个对象。实际应用应根据已认证的用户或会话选择对象名;照搬一个共享demo名称不能替代用户隔离。对象内不同会话可以独立运行,根会话默认ID为ses_root。
建议在自己的隔离测试环境检查三条路径:正常任务能得到done;中断后能从同一会话接回任务且重复operationId不再排队;客户端重连能恢复历史和已提交事件。再核对工具权限、模型费用、存储用量与访问控制,完整配置和插件例子见来源。
OpenCode的Cloudflare SDK还提醒:对象被回收时可能不执行清理,正确性不能依赖close()一定被调用。本站仅核对公开公告与文档,没有安装依赖、运行Worker、调用模型或验证某个账户的上线效果。
资料来源
常见问题
取消wait()就会停止后台任务吗?
不会。会话API说明,中止wait()的signal只停止等待。要撤回指定排队操作或中断它加入的运行,使用session.abort(operationId);不传ID时会中止该会话的全部工作。
messages()和history()该选哪个?
messages()返回最近一次压缩后的活动上下文,适合当前显示与继续处理;history()包含已压缩消息在内的完整对话记录。需要恢复完整历史时,应按后者的数据结构映射到自己的界面。