Paseo 协议兼容性工程实践:App 与 Daemon 跨版本共存的契约设计
Paseo 协议兼容性工程实践App 与 Daemon 跨版本共存的契约设计【免费下载链接】paseoOrchestrate multiple coding agents from desktop and mobile项目地址: https://gitcode.com/gh_mirrors/pa/paseo导读Paseo 的桌面端/移动端 App 与后台 Daemon 是分开发布的两个产品用户通过应用商店或桌面自动更新升级 App而 Daemon 则按自己的节奏升级因此在真实环境中新 App 配旧 Daemon旧 App 配新 Daemon甚至两端相差数月的组合都会出现。本文基于仓库中的协议兼容性规范文档系统讲解 Paseo 如何通过协议契约永远可解析与特性契约按特性一次性门控双轨机制保证任意版本组合下既有功能不回归、新功能优雅降级并给出COMPAT兼容垫片标记、客户端能力宣告、自有订阅owned subscriptions协商等可落地的工程细则与仓库源码佐证。读完本文你将掌握在多端异步发布架构下维护长生命周期协议的正确姿势。一、问题背景App 与 Daemon 永远存在版本组合Paseo 中App 与 Daemon 是两个独立产品App通过应用商店或桌面自动更新机制升级Daemon由用户按需自行升级。这导致开发环境与生产环境的一个关键差异在开发过程中两端永远是同版本这正是贡献者最容易忽略约束的地方——开发时同版本发布后不同版本才是常态。任何一端发布新功能另一端可能落后数月。因此协议层必须同时满足两个方向上的兼容性。从这一前提推导出两条必须遵守的契约协议契约schema 变更不得破坏任何方向的解析特性契约新特性按特性单独门控旧 Daemon 不支持就明确告知用户升级而不是降级模拟。二、协议契约schema 永远双向可解析2.1 核心规则一条 schema 变更必须保证旧 App 仍能解析新 Daemon 发来的消息新 Daemon 仍能解析旧 App 发来的消息。具体约束如下新字段必须声明为.optional()并带有合理默认值禁止将 optional 翻转为 required、删除字段或收窄类型——string收窄为enum、nullable 收窄为 non-null 都属于收窄某个字段你停止发送后接收端仍要继续接受它——停止写入不等于停止读取wire schema 必须是纯结构化声明WebSocket 消息 schema 上不允许.transform()、.catch()或.preprocess()归一化逻辑必须在校验之后的显式 pass 中完成。原因见 协议校验文档入站校验器是生成的而生成器只编译纯 schema当所有分支共享字面量 tag 时禁止使用普通z.union()必须使用z.discriminatedUnion().default()只能放在原始类型叶子字段上绝不能放在大数组内的条目 schema 或大型入站容器上。2.2 提交 schema 变更前回答两个问题在提交任何 schema 变更前必须能对以下两个问题同时回答是一个六个月前的旧 App 还能解析这条消息吗一个六个月前的旧 Daemon 发来的内容这个 App 还能接受吗两个都答是变更才算完成。2.3 Schema 与 RPC 命名规范所有协议 schema 集中在 packages/protocol/src/messages.ts。以server_info为例其features对象中每一个布尔标志都带COMPAT注释说明引入版本与移除日期例如// COMPAT(sessionPermissions): optional while clients support older daemons. permissions: z.array(DaemonPermissionSchema).optional(), // COMPAT(providersSnapshot): added in v0.1.48, remove gating when all clients use snapshot providersSnapshot: z.boolean().optional(),新增 RPC 的命名必须遵循 RPC 命名空间规范使用点号不是斜杠分层命名方向作为最后一段例如checkout.forge.set_auto_merge.request/checkout.forge.set_auto_merge.response普通请求必须有同前缀的成对响应requestId同时保留在请求与响应中作为关联键不要新增扁平命名如旧的checkout_pr_merge_request旧名称在兼容窗口内保持接受。2.4 测试佐证wire 兼容回归仓库用 packages/protocol/src/messages.wire-compat.test.ts 固化这一契约例如hello消息在有无 project update 能力时都能解析server_info能剥离未知的遗留 features同时接受旧的 turn identity旧的sub_agenttool-call payload 仍能按 v0.1.65-beta.3 的 schema 解析旧客户端解析带 rewind 能力的 agent snapshot、新客户端解析不带 rewind 能力的 snapshot 均成功。这些用例正是六个月前旧 App 仍可解析这一要求在测试层的落地。三、特性契约按特性门控一次绝不降级协议契约保证的是既有功能跨版本不回归而新特性通常需要新的 Daemon 能力旧 Daemon 并不具备。因此特性的策略是不建降级路径不要为旧 Daemon 构建劣化版特性不要通过打散到遗留 RPC 来模拟不存在的能力。用户要么升级主机要么没有这个特性不把防御分支散布在特性代码里能力检测只发生在一处下游所有代码读取的都是一个干净的形状能力标志集中在server_info消息的features字段中定义见 packages/protocol/src/messages.ts 的ServerInfoStatusPayloadSchema。features中每个布尔标志都代表一项可由 App 检测的 Daemon 能力例如directorySync、workspaceLabels、plugins、checkoutForgeSetAutoMerge、forgeSearch等每个都带COMPAT注释标注引入版本与移除门槛。App 在连接时读取这些标志决定运行新特性还是提示用户更新主机。值得强调的是特性门控永远不能替代协议契约。既有功能继续工作靠的是协议契约新特性靠门控两者分工明确。四、客户端能力归属能力默认值全量宣告4.1 能力清单与默认值客户端包负责宣告自己实现的协议行为。每个新能力都要加入其穷尽式默认值并在该处实现对应的订阅或解码行为App、CLI 和插件继承这些默认值只补充主机资源如浏览器自动化或显式覆盖。能力枚举定义在 packages/protocol/src/client-capabilities.tsexport const CLIENT_CAPS { ownedSubscriptions: owned_subscriptions, explicitEventSubscriptions: explicit_event_subscriptions, allProviders: all_providers, selectiveAgentTimeline: selective_agent_timeline, reasoningMergeEnum: reasoning_merge_enum, customModeIcons: custom_mode_icons, terminalReflowableSnapshot: terminal_reflowable_snapshot, providerSubagents: provider_subagents, projectUpdates: project_updates, compactProviderSnapshots: compact_provider_snapshots, timelineReplacementInvalidation: timeline_replacement_invalidation, timelineNotifications: timeline_notifications, pluginTimelineItems: plugin_timeline_items, workspaceSetupBlocked: workspace_setup_blocked, browserHost: browser_host, } as const;每个能力都带有精确的引入版本与淘汰日期注释例如customModeIcons是因为旧客户端把AgentModeIcon钉死在封闭枚举上、遇到未知值会崩溃所以 Daemon 在该能力缺失时把图标降级为ShieldCheck。4.2 为什么 schema 接受不等于支持一个关键原则schema 能接受某条消息并不代表客户端支持其投递语义。因此客户端必须显式宣告能力。默认宣告位于 packages/client/src/connection/index.ts// Protocol support belongs to the installed client. Only browser hosting needs // a resource supplied by the caller. Keep this exhaustive as the protocol evolves. export const DEFAULT_CLIENT_CAPABILITIES { [CLIENT_CAPS.ownedSubscriptions]: true, [CLIENT_CAPS.allProviders]: true, [CLIENT_CAPS.selectiveAgentTimeline]: true, [CLIENT_CAPS.reasoningMergeEnum]: true, [CLIENT_CAPS.customModeIcons]: true, [CLIENT_CAPS.terminalReflowableSnapshot]: true, [CLIENT_CAPS.providerSubagents]: true, [CLIENT_CAPS.projectedSubagentTimeline]: true, [CLIENT_CAPS.projectUpdates]: true, [CLIENT_CAPS.compactProviderSnapshots]: true, [CLIENT_CAPS.providerSnapshotReferences]: true, [CLIENT_CAPS.timelineReplacementInvalidation]: true, [CLIENT_CAPS.timelineNotifications]: true, [CLIENT_CAPS.pluginTimelineItems]: true, [CLIENT_CAPS.workspaceSetupBlocked]: true, [CLIENT_CAPS.explicitEventSubscriptions]: true, } satisfies RecordExcludeClientCapability, typeof CLIENT_CAPS.browserHost, true;注意browserHost被排除在默认值之外——它需要调用方提供真实的主机资源属于主机资源而非协议行为。连接测试 packages/client/src/connection.test.ts 中有专门用例断言普通客户端宣告全部协议能力且不宣告 browser host且注释明确每个新能力都需要一个有意的默认值或主机资源例外。4.3 订阅成员关系归属在有能力capable的 Daemon 上连接本身不产生任何 timeline 或 event 需求客户端订阅拥有自己的网络成员关系取消订阅时释放重连后恢复原始消息观察者raw message observers只检视流量不请求流应用缓存、可见的 agents 集合等由调用方持有不归连接层管理。五、自有订阅Owned Observations能力协商与遗留路径5.1 协商机制owned_subscriptions与server_info.features.ownedSubscriptions共同协商源自有契约底层 WebSocket 协议描述见 架构文档。客户端在连接边界处一次性选定投递行为App 工作流在两种模式下使用同一个观察接口。协商逻辑在 packages/client/src/connection/index.ts 中一目了然const owned info.features?.ownedSubscriptions true clientCapabilities[CLIENT_CAPS.ownedSubscriptions] true;即只有当 Daemon 宣告能力且客户端宣告能力时才启用自有订阅否则回退到遗留订阅LegacySubscriptions。5.2 与旧 Daemon 交互的遗留行为面对旧 Daemon 时客户端使用现有连接与遗留 RPC并保持以下语义目录订阅保持共享、last-query-wins最后一次查询生效本地 handle ID 仅标识监听者不承诺独立的服务器过滤器timeline 与 event 成员关系保持既有共享行为释放 handle 即分离其监听器并在存在旧 unsubscribe 操作时使用它仅广播broadcast的主机继续广播此时就绪只代表本地监听已挂载而非 Daemon 确认不引入额外 socket 或复用模拟multiplexing emulation。connection/index.ts中observeRequest的实现正是如此在遗留模式下广播时代的主机没有确认机制就绪状态直接本地接受快照请求失败时通过legacy.release发送旧式释放消息。相关能力在 packages/client/src/connection/legacy.ts 中以// COMPAT(ownedSubscriptions): added in v0.8.0; remove after 2027-03-11 once daemon floor v0.8.0.标记。5.3 边界与职责划分保持既有工作流独立过滤器independent filters与安静连接quiet connections需要有能力 Daemon而打开 App、读取历史、使用终端则不需要预注册pre-registry的工作区分组与遗留事件归一化属于客户端边界内部职责旧客户端在 Daemon 源边界保留其既有 wire 形状与槽位slot行为适配器按物理 socket给遗留槽位定键因此即使两个连接使用相同逻辑 client ID旧连接也不能顶替现代同级的观察可选的 wire ID 为解析兼容继续被接受但现代请求不能选择自己的订阅 ID。六、每个兼容垫片都要打标签并注明日期兼容垫片shim如果是为了支持旧 App 或旧 Daemon 而存在必须携带注释注明名称、引入版本与可移除时间// COMPAT(workspaceFileEditing): added in v0.2.0, remove after 2027-01-18 once daemon floor v0.2.0.rg COMPAT\(就是完整的清理积压清单backlog因此要求每个垫片一个标签放在必须被删除的代码位置标签包含名称、版本、移除条件或日期——通常以六个月为默认窗口绝不允许把兼容逻辑埋在未打标签的??兜底或可选链隧道里——未打标签的兼容代码永远不会被删除因为没人能找到它。当标签条件满足时在同一处变更中同时删除垫片与标签。仓库中COMPAT(遍布 App 与协议层例如 packages/app/src/components/add-project-flow.tsx 中的// COMPAT(stableProjectIdentity): added in v0.1.109, remove gate after 2027-01-15.以及desktopManaged字段的// COMPAT(desktopManaged): added in v0.1.X, remove optional parsing after 2027-01-16.都是这一规范的实例。七、QA 要求测试永远无法完全覆盖兼容性测试无法穷尽所有版本组合因此兼容性最终靠人工论证。规范要求只要改动涉及 packages/protocol 包就必须在 Pull Request 中说明为什么旧 App 仍能解析你新增/修改的消息为什么旧 Daemon 仍能满足你的 App。详细 QA 流程见 qa.md。配合 协议校验文档 中入站校验器由 zod-aot 在构建期生成、schema 必须保持纯净的约束这一论证通常可以落实到具体字段的 optional/默认值设置与生成代码回归测试上。八、实践清单综合全文为 Paseo 贡献协议相关代码时的自检清单schema 变更新字段 optional 默认值不删字段、不收窄类型不在 wire schema 上用 transform/catch/preprocess共享 tag 的 union 用z.discriminatedUnion()default 只放叶子。双问题自检六个月前的 App 还能解析吗六个月前的 Daemon 还能被接受吗新特性在server_info.features加布尔标志客户端检测一次不建降级路径不散布防御分支。新能力加入 client-capabilities.ts 的CLIENT_CAPS与 connection/index.ts 的DEFAULT_CLIENT_CAPABILITIES并实现对应订阅/解码行为。兼容垫片打COMPAT(name)标签注明版本与移除日期默认六个月条件满足时连同标签一起删除。命名新 RPC 按 rpc-namespacing.md 的点号分层命名不新增扁平名称。QA改动packages/protocol时在 PR 中书面论证双向兼容。这套协议契约保底、特性契约门控、能力显式宣告、垫片限期清理的组合拳就是 Paseo 能在 App 与 Daemon 各自异步发布的现实约束下长期保持任意版本组合可用性的核心工程方法论。【免费下载链接】paseoOrchestrate multiple coding agents from desktop and mobile项目地址: https://gitcode.com/gh_mirrors/pa/paseo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

C语言Win32 API窗口编程入门:从控制台到窗体应用实战

C语言Win32 API窗口编程入门:从控制台到窗体应用实战

1. 为什么窗口程序不是"高级玩法",而是C语言学习的一道分水岭很多人学C语言,学到指针和链表就卡住了,觉得再往下就是无尽的算法题和黑框框。我当年也是这样,对着控制台输出一堆字符,心里想的是:这…

2026/9/21 15:19:22 阅读更多 →
Boostnote 构建与打包全指南:从 Webpack HMR 开发调试到生成 deb/rpm 发行包

Boostnote 构建与打包全指南:从 Webpack HMR 开发调试到生成 deb/rpm 发行包

Boostnote 构建与打包全指南:从 Webpack HMR 开发调试到生成 deb/rpm 发行包 【免费下载链接】BoostNote-Legacy This repository is outdated and new Boost Note app is available! Weve launched a new Boost Note app which supports real-time collaborative w…

2026/9/21 15:19:22 阅读更多 →
科研数据可视化:柱状图误差线与显著性标记全流程

科研数据可视化:柱状图误差线与显著性标记全流程

1. 科研图表制作实战:柱状图误差线显著性标记全流程解析在生物医学和实验科学领域,数据可视化是研究成果呈现的核心环节。Cell期刊作为生命科学领域的顶级刊物,其图表规范性和信息密度一直是行业标杆。今天我们就来拆解一个经典组合——带误差…

2026/9/21 15:19:22 阅读更多 →

最新新闻

CodeIgniter 3.0.2 升级至 3.0.3 实战指南:base_url 自动检测变更与 Host 头注入防护

CodeIgniter 3.0.2 升级至 3.0.3 实战指南:base_url 自动检测变更与 Host 头注入防护

CodeIgniter 3.0.2 升级至 3.0.3 实战指南:base_url 自动检测变更与 Host 头注入防护 【免费下载链接】CodeIgniter Open Source PHP Framework (originally from EllisLab) 项目地址: https://gitcode.com/gh_mirrors/co/CodeIgniter 本文面向正在使用 Code…

2026/9/21 15:51:58 阅读更多 →
使用 Native Image Gradle Plugin 集成 Reachability Metadata:从元数据仓库到 Tracing Agent 的完整实战指南

使用 Native Image Gradle Plugin 集成 Reachability Metadata:从元数据仓库到 Tracing Agent 的完整实战指南

使用 Native Image Gradle Plugin 集成 Reachability Metadata:从元数据仓库到 Tracing Agent 的完整实战指南 【免费下载链接】graal GraalVM compiles applications into native executables that start instantly, scale fast, and use fewer compute resources …

2026/9/21 15:51:58 阅读更多 →
FoundationDB Go 绑定(fdb-go)开发指南:安装、构建与事务编程实战

FoundationDB Go 绑定(fdb-go)开发指南:安装、构建与事务编程实战

FoundationDB Go 绑定(fdb-go)开发指南:安装、构建与事务编程实战 【免费下载链接】foundationdb FoundationDB - the open source, distributed, transactional key-value store 项目地址: https://gitcode.com/gh_mirrors/fo/foundationd…

2026/9/21 15:51:58 阅读更多 →
Moya 端点(Endpoint)深度指南:理解 Target 到 Endpoint 再到 URLRequest 的完整映射链路

Moya 端点(Endpoint)深度指南:理解 Target 到 Endpoint 再到 URLRequest 的完整映射链路

Moya 端点(Endpoint)深度指南:理解 Target 到 Endpoint 再到 URLRequest 的完整映射链路 【免费下载链接】Moya Network abstraction layer written in Swift. 项目地址: https://gitcode.com/gh_mirrors/mo/Moya Endpoint 是 Moya 中…

2026/9/21 15:51:58 阅读更多 →
做一套企业招聘系统,传统开发要7天,飞算JavaAI为什么15分钟就跑通了?

做一套企业招聘系统,传统开发要7天,飞算JavaAI为什么15分钟就跑通了?

一个中等复杂度的管理后台,传统开发通常会排出这样的时间:前端约3天、后端约2天、前后端联调约2天,加起来约7天。 这7天到底花在了哪里?同一套需求换成飞算JavaAI后,由一名Java后端从需求输入推进到前后端项目运行&…

2026/9/21 15:51:58 阅读更多 →
Swagger Codegen Bash 客户端模型文档解读:以 Petstore 的 Category 模型为例

Swagger Codegen Bash 客户端模型文档解读:以 Petstore 的 Category 模型为例

开发工具代码生成API设计 【免费下载链接】swagger-codegen swagger-codegen contains a template-driven engine to generate documentation, API clients and server stubs in different languages by parsing your OpenAPI / Swagger definition. 项目地址: http…

2026/9/21 15:50:58 阅读更多 →

日新闻

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and …

2026/9/21 0:00:01 阅读更多 →
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,…

2026/9/21 0:00:01 阅读更多 →
Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

桌面应用AI 应用插件系统 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 点击查看 免费下载 全功能插件(Full-featured Plugin)是 Wox 三类插件实现方式中能力最完整的…

2026/9/21 0:00:01 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →