ARTICLE DETAIL

资讯详情

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

Warp 云到云会话交接(Cloud-to-Cloud Handoff)第一阶段:功能开关、follow-up API 与任务/执行访问器的脚手架实现

Warp 云到云会话交接(Cloud-to-Cloud Handoff)第一阶段:功能开关、follow-up API 与任务/执行访问器的脚手架实现 桌面应用开发者工具人工智能AI 应用AI Agent代码智能体【免费下载链接】warpWarp is an agentic development environment, born out of the terminal.项目地址https://gitcode.com/GitHub_Trending/wa/warp点击查看免费下载导读本文围绕 Warp 开源仓库中specs/APP-4319/TECH.md所定义的 cloud-to-cloud handoff 计划第一阶段PR 1展开讲解如何在不改变任何终端用户行为的前提下为后续的云端会话接续tombstone Continue 入口、UI 提交、共享会话热切换铺好三块地基新增默认关闭的HandoffCloudCloud功能开关、在公开 API 客户端中新增类型化的submit_run_followup方法、以及为AmbientAgentTask引入区分任务身份与执行期数据的访问器run_id/conversation_id/active_run_execution。读者学完后将掌握该仓库中特性开关的声明与 Cargo 特性依赖的映射方式、公开 API 客户端新增端点的完整模式请求类型 路径 helper 序列化测试以及将扁平化字段安全重构为执行作用域投影的实践方法。背景与问题陈述Warp 的云端 Agentambient agent在一次执行结束后用户往往希望在云端继续同一段对话而不是重新发起一次全新运行。这套能力由 master cloud-to-cloud handoff 计划统一规划而 PR 1 是整个计划中第一个可合并的脚手架 PR目标只做三件事让客户端感知HandoffCloudCloud这一灰度边界rollout boundary为服务端 follow-up API 增加一个类型化客户端方法在客户端模型中开始将任务/运行身份task/run identity与执行/会话作用域数据execution/session-scoped data分离。PR 1明确不做以下事项不添加 tombstone Continue 入口、不从 UI 提交 follow-up、也不把 follow-up 的共享会话挂接到既有终端上。这些行为留给后续 PR在基础 API 就绪后再实现。整份规格对边界的强调是所有脚手架 PR 的核心纪律先有可合并的接缝seam再谈功能落地。前置关联为既有共享会话查看器挂接新的共享会话所需的 UI/模型层基础记录在specs/REMOTE-1478/TECH.md整体时序与用户流程见specs/handoff-cloud-cloud/TECH.md。现状核实仓库中的相关代码基座功能开关枚举与 rollout 数组特性开关全部定义在 crates/warp_features/src/lib.rs。文档撰写时CloudModeSetupV2已存在于枚举尾部附近文档记录的行号 827 附近当前代码中位于 840 行rollout 数组定义于 852、910、926 行附近彼时尚无HandoffCloudCloud开关。对照当前仓库HandoffCloudCloud已按规格落地crates/warp_features/src/lib.rs:849 声明了HandoffCloudCloud描述为Enables continuing cloud mode conversations in the cloud after an execution ends启用云端模式对话在一次执行结束后于云端继续它紧随CloudModeSetupV2第 840 行之后保持了枚举的时间顺序chronological ordering。公开 API 客户端公开 API 客户端AIClienttrait 中已有 ambient run 的 spawn / list / get 方法。文档指出AIClient包含spawn_agent、list_ambient_agent_tasks、get_ambient_agent_taskapp/src/server/server_api/ai.rs约 799 行处当前代码中 trait 声明位于 app/src/server/server_api/ai.rs:1381-1422 附近ServerApi实现分别POST agent/run、GET agent/runs、GET agent/runs/{task_id}文档记录 1404 行附近相邻的公开 API 方法会 POST 到 run 作用域子资源例如agent/runs/{task_id}/attachments/prepare文档记录约 1785 行这正是 follow-up API 的自然实现范式。服务端 follow-up 契约服务端 follow-up API 为POST /api/v1/agent/runs/{runId}/followupsJSON body 仅含message字段。服务端路由与请求类型位于服务端 worktreecloud-agent-task-name分支的public_api/openapi.yaml、router/handlers/public_api/agent_webhooks.go与public_api/types/types.gen.go中。由于该路径在客户端仓库之外本文不引用其内容但客户端实现正是围绕这一契约展开的。客户端任务模型的扁平化现状AmbientAgentTask目前把执行作用域字段直接扁平暴露在任务上session_id、session_link、conversation_id、request_usage、is_sandbox_running文档记录位于 app/src/ai/ambient_agents/task.rs:217 附近当前实现中为结构体字段 app/src/ai/ambient_agents/task.rs:239-246is_no_longer_running已把 sandbox 存活状态与运行状态结合文档记录 task.rs:257 附近当前实现见 task.rs:496-498SessionJoinInfo::from_task直接读task.session_link与task.session_idapp/src/ai/ambient_agents/spawn.rs:32当前实现已迁移到active_run_execution()见下文。Agent 管理与详情代码直接读取这些扁平字段用于会话状态、链接、会话去重、打开动作与详情面板展示包括app/src/ai/agent_conversations_model.rs的 468/515/528/553/1293 行与app/src/ai/conversation_details_panel.rs:337行号以文档记录为参考。目标与非目标目标Goals新增默认禁用的HandoffCloudCloud功能开关并让 app 的 Cargo 特性依赖cloud_mode_setup_v2为公开 API 增加类型化的 follow-up 提交客户端支持在AmbientAgentTask上引入 run/execution 感知的访问器保持现有行为不变为后续 PR 提供路由活动/最新执行语义的落点将最重要且低风险的既有调用点从直接读扁平字段迁移到新访问器为新的 API 序列化/路径 helper 与任务访问器行为增加针对性单元测试。非目标Non-goals不做任何可见的云端会话 tombstone 变化不改变终端输入提交行为不做云端模式设置 UI 变化不做 follow-up 轮询或共享会话热切换编排除非公开 API 当前 schema 已返回完整的 run-executions 数组否则不尝试解析或存储该数组——PR 1 只定义能吸收该形状的接缝不将开关加入DOGFOOD_FLAGS、PREVIEW_FLAGS或RELEASE_FLAGS。方案一功能开关脚手架在 FeatureFlag 枚举中新增开关将HandoffCloudCloud加入 crates/warp_features/src/lib.rs 的FeatureFlag枚举保持枚举的时间顺序放在CloudModeSetupV2之后。描述保持简洁、面向产品例如gating cloud-to-cloud continuation of cloud mode conversations为云端模式对话的云到云续接做灰度。当前仓库中的落地代码即为示例/// Enables continuing cloud mode conversations in the cloud after an execution ends. HandoffCloudCloud,不加入 rollout 数组PR 1不把该开关加入任何 rollout 数组DOGFOOD_FLAGS、PREVIEW_FLAGS、RELEASE_FLAGS因此默认处于禁用状态只可供本地覆盖local override与后续 PR 使用。这保证了合并该 PR 不会对运行时行为产生任何影响。Cargo 特性依赖与映射构建层面的依赖需要在app/Cargo.toml中显式编码handoff_cloud_cloud依赖cloud_mode_setup_v2。当前仓库的配置app/Cargo.tomlcloud_mode_setup_v2 [cloud_mode] handoff_cloud_cloud [cloud_mode_setup_v2]随后在app/src/lib.rs中把 Cargo 特性映射到FeatureFlag::HandoffCloudCloud。这样依赖关系被固化在构建特性图build feature graph中而无需新增 rollout 依赖测试。运行时HandoffCloudCloud对CloudModeSetupV2的影响在 PR 1 中有意不实现——Cargo 特性依赖只覆盖编译产物本地运行时覆盖仍可强制出特殊状态用于定向测试。方案二follow-up API 客户端请求类型在 app/src/server/server_api/ai.rs 中靠近SpawnAgentRequest的位置新增请求类型序列化为{message:...}。当前仓库实现ai.rs:392-395#[derive(Debug, Clone, serde::Serialize)] pub struct RunFollowupRequest { pub message: String, }AIClient trait 方法在AIClienttrait 中新增submit_run_followup参数为run_id: AmbientAgentTaskId与request: RunFollowupRequest返回anyhow::Result(), anyhow::Error。由于当前服务端行为不返回客户端需要的响应载荷实现直接使用post_public_api_unit发送单元响应请求。当前仓库实现ai.rs:1418-1422 的 trait 声明ai.rs:2557-2562 的ServerApi实现async fn submit_run_followup( self, run_id: AmbientAgentTaskId, request: RunFollowupRequest, ) - anyhow::Result(), anyhow::Error;async fn submit_run_followup( self, run_id: AmbientAgentTaskId, request: RunFollowupRequest, ) - anyhow::Result(), anyhow::Error { self.post_public_api_unit(build_run_followup_url(run_id), request) }路径 helper可独立单测的 URL 构建仿照build_list_agent_runs_urlapp/src/server/server_api/ai.rs:886新增一个小型路径 helper例如build_run_followup_url(run_id: AmbientAgentTaskId) - String使端点路径的单测不依赖 HTTP mock。当前仓库实现ai.rs:958-960pub(crate) fn build_run_followup_url(run_id: AmbientAgentTaskId) - String { format!(agent/runs/{run_id}/followups) }调用约束PR 1 中不从 UI 或编排代码调用该方法保证其在服务端 rollout 之前合入也是安全的——只要它能对既有客户端代码编译通过即可。方案三run/execution 感知的任务访问器这一部分是整份规格中最有架构味道的设计把任务身份与某次执行从数据模型上区分开。AmbientAgentTask本身是任务的持久标识与元数据task identity metadata而session_id、session_link、request_usage、is_sandbox_running这些字段本质上是**某次执行execution**的属性。PR 1 不真正引入多执行模型而是定义三个轻量访问器把这些扁平字段投影为活动/最新执行从而让调用方停止编码任务级字段天然是任务作用域的错误假设。新增的访问器在 app/src/ai/ambient_agents/task.rs 中pub fn run_id(self) - AmbientAgentTaskId { self.task_id } pub fn conversation_id(self) - Optionstr { self.conversation_id.as_deref() } pub fn active_run_execution(self) - RunExecution_ { RunExecution { session_id: self.session_id.as_deref(), session_link: self.session_link.as_deref().filter(|link| !link.is_empty()), request_usage: self.request_usage.as_ref(), is_sandbox_running: self.is_sandbox_running, } }对应落地代码见 task.rs:332-335、task.rs:357-359 与 task.rs:402-409。RunExecution 借用投影新增RunExecutiona结构持有借用的session_id、非空session_link、request_usage与is_sandbox_running字段。当前仓库实现task.rs:280-286#[derive(Clone, Copy, Debug, PartialEq)] pub struct RunExecutiona { pub session_id: Optiona str, pub session_link: Optiona str, pub request_usage: Optiona RequestUsage, pub is_sandbox_running: bool, }注意session_link在投影时通过.filter(|link| !link.is_empty())过滤掉了空字符串——这与SessionJoinInfo只认非空链接的既有语义保持一致。RunExecution上还提供了两个实用的派生判定task.rs:299-307impl RunExecution_ { pub fn has_joinable_session(self) - bool { self.session_id.is_some() || self.session_link.is_some() } pub fn is_active(self) - bool { self.is_sandbox_running self.has_joinable_session() } }更新 is_no_longer_runningis_no_longer_running改为使用active_run_execution().is_sandbox_running并保持既有行为。当前实现task.rs:496-498pub fn is_no_longer_running(self) - bool { !self.active_run_execution().is_sandbox_running !self.state.is_working() }迁移 SessionJoinInfo::from_taskSessionJoinInfo::from_taskapp/src/ai/ambient_agents/spawn.rs:44-63当前实现已按规格迁移到active_run_execution()并保留了优先服务端链接、回退构造链接、取不到则返回 None的三段式逻辑pub fn from_task(task: AmbientAgentTask) - OptionSelf { let run_execution task.active_run_execution(); // 云端模式面板按 session_id 加入没有它时独立的 session_link 不可用。 let session_id_str run_execution.session_id?; let session_id SessionId::from_str(session_id_str).ok()?; // 优先服务端提供的 session_link回退为从 session_id 构造。 // active_run_execution() 已过滤掉空链接。 let session_link run_execution .session_link .map(String::from) .unwrap_or_else(|| shared_session::join_link(session_id)); Some(Self { session_id: Some(session_id), session_link, }) }低风险调用点的迁移清单规格列出以下 UI/模型调用点应改用新访问器均为行为保持的投影替换ConversationOrTask::session_id解析active_run_execution().session_idlink_preference使用active_run_execution().is_sandbox_runningsession_or_conversation_link使用active_run_execution().session_link与conversation_id()get_session_status使用 session/link 访问器get_open_action与会话遮蔽conversation shadowing使用run_id()与conversation_id()ConversationDetailsData::from_task详情面板会话 ID 用conversation_id()credits 用active_run_execution().request_usage。相关调用点在app/src/ai/agent_conversations_model.rs与app/src/ai/conversation_details_panel.rs中详见规格文档记录的行号。明确不迁移的字段对于明显属于任务元数据而非执行数据的字段——如title、prompt、state、source、creator、artifact 列表、config 快照——避免大规模机械改写broad mechanical churn保持调用点原样。命名清理的取舍PR 1 中不重命名AmbientAgentTaskId也不改动公开 UI 标签服务端与客户端大量代码仍混用 run/task 术语大范围重命名只会制造噪音而无益于合并性。新增的run_id()访问器已足够为后续 PR 澄清稳定身份。测试策略规格与当前仓库落地代码对应如下。公开 API helper 测试在app/src/server/server_api/ai_tests.rs中为 follow-up 端点路径添加测试。当前仓库的两个核心用例#[test] fn build_run_followup_url_routes_to_run_followups() { let run_id 550e8400-e29b-41d4-a716-446655440000.parse().unwrap(); assert_eq!( build_run_followup_url(run_id), agent/runs/550e8400-e29b-41d4-a716-446655440000/followups ); } #[test] fn serialize_run_followup_request() { let request RunFollowupRequest { message: continue from here.to_string(), }; let json serde_json::to_value(request).unwrap(); assert_eq!(json, serde_json::json!({ message: continue from here })); }对应代码见 app/src/server/server_api/ai_tests.rs:1373-1396。序列化测试直接断言 JSON 形状精确为{message:...}。任务/会话访问器测试在app/src/ai/ambient_agents/spawn_tests.rs或新建app/src/ai/ambient_agents/task_tests.rs中覆盖SessionJoinInfo::from_task仍优先使用服务端提供的会话链接仍能从session_id回退构造 join 链接当既无活动链接也无可解析的 session id 时返回None新访问器保持既有扁平字段行为不变。针对性检查命令规格给出的检查命令执行前应从Cargo.toml核实准确的包名cargo nextest run -p warp server::server_api::ai::tests::build_run_followup_url_routes_to_run_followups server::server_api::ai::tests::serialize_run_followup_request ai::ambient_agents::spawn::tests cargo nextest run -p warp ai::agent_conversations_model::tests ai::conversation_details_panel::tests cargo check -p warp --features handoff_cloud_cloud规格特别提醒不要使用cargo fmt --all或针对单文件的cargo fmt若评审前需要格式化按仓库标准流程执行cargo fmt。上线与兼容性开关默认禁用PR 1 不改变运行时行为新 API 客户端方法在 PR 1 中未被调用只要对既有客户端代码编译通过即可在服务端 rollout 之前安全合入访问器迁移是行为保持的——每个访问器最初投影的正是同一批扁平字段。若某处直接字段使用存在歧义或风险宁可保留原位并记录为后续工作也不扩大 PR 范围。风险与缓解管理视图链接选择或会话打开行为被意外改变这是最大风险。应保持改动小而局部优先做本地化的访问器替换并依赖既有的 spawn 与 agent 管理测试兜底。follow-up 端点响应形状与假设的空响应不符实现前应核对服务端契约再决定是否用post_public_api_unit若服务端返回 body则增加最小响应类型并测试反序列化。HandoffCloudCloud到CloudModeSetupV2的运行时影响未实现PR 1 有意不实现Cargo 特性依赖仅覆盖编译构建本地运行时覆盖可强制异常状态用于定向测试。访问器命名可能需调整一旦客户端消费一等公民的 run-execution 数据访问器命名可能变化。PR 1 应保持命名有描述性但避免引入当前 API 数据支撑不了的庞大抽象。完成标准Definition of DoneHandoffCloudCloud已存在且默认禁用app/Cargo.toml中handoff_cloud_cloud依赖cloud_mode_setup_v2AIClient与ServerApi暴露了类型化的 follow-up 提交方法对应POST agent/runs/{run_id}/followupsAmbientAgentTask暴露 run/execution 感知访问器主要 session/conversation 调用点改用它们且行为不变定向测试覆盖 follow-up API 路径/序列化与任务/会话访问器行为且特性门控的编译检查通过。对照当前仓库上述完成标准均已落地开关位于 crates/warp_features/src/lib.rs:849Cargo 特性映射见 app/Cargo.toml:687-688 与 app/Cargo.toml:1024客户端方法见 app/src/server/server_api/ai.rs:1418-1422 与 ai.rs:2557-2562访问器见 app/src/ai/ambient_agents/task.rs:332-409对应测试见 app/src/server/server_api/ai_tests.rs:1373-1396。小结PR 1 的价值不在用户可见功能而在于以零行为变化的方式为后续 cloud-to-cloud handoff 铺好可合并的地基一个默认禁用的灰度开关、一条类型化的 follow-up 客户端通道、以及一套把执行期数据从任务元数据中剥离开的访问器语义。对后续实现者而言这些接缝让 tombstone Continue 入口、UI 提交与共享会话热切换等后续 PR 可以直接落在清晰的语义边界上而无需在既有扁平字段上继续堆叠假设。赞分享桌面应用开发者工具人工智能AI 应用AI Agent代码智能体【免费下载链接】warpWarp is an agentic development environment, born out of the terminal.项目地址https://gitcode.com/GitHub_Trending/wa/warp点击查看免费下载相关推荐《拼团交易平台系统》第1阶段部署云环境实战从选购云服务器到开放端口实现公网访问《拼团交易平台系统》第1阶段部署云环境实战从选购云服务器到开放端口实现公网访问 本篇技术指南围绕《拼团交易平台系统》的第4 1节部署环节展开讲解把拼团营销系文档教程后端browser-use 云端实战基于 Browser Use Cloud API V4 从零跑通第一个浏览器 Agent 任务browser use 云端实战基于 Browser Use Cloud API V4 从零跑通第一个浏览器 Agent 任务 Browser Use Clo人工智能AI Agent浏览器控制GUI 自动化MCP 服务会话交接Session Handoff工程实践让长任务在会话边界上无缝续跑会话交接Session Handoff工程实践让长任务在会话边界上无缝续跑 导读 在 AI 编码 Agent 的长期任务中上下文窗口总是有限的一次会话上一篇Pocket Casts Android 开源项目常见问题解决方案下一篇Droid-ify 项目常见问题解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表