- 桌面应用
- 开发者工具
- 人工智能
- AI 应用
- AI Agent
- 代码智能体
【免费下载链接】warp
Warp is an agentic development environment, born out of the terminal.
导读
Warp 是一个源于终端的 agentic 开发环境,其云模式(Cloud Mode)允许用户在云端会话中运行 AI Agent。本文基于仓库中 specs/APP-4459/TECH.md 技术方案,讲解 Cloud Mode 设置流程 v2(Setup-v2)下启动失败(spawn failure)的 UI 呈现改造:当云 Agent 启动失败时,不再在 Agent 消息栏渲染红色错误条,而是以"会话终结墓碑视图"(conversation-ended tombstone)呈现错误、隐藏输入框并抑制 Continue 操作。读者将掌握AmbientAgentViewModelEvent::Failed的完整处理链路、ConversationEndedTombstoneView的数据来源与渲染逻辑,以及TaskStatusMessage.error_code对"环境设置失败"类错误的标记机制。
一、改造背景:Setup-v2 失败 UI 的痛点
在 Cloud Mode 中,用户发起一个云 Agent 任务后,客户端需要依次完成环境选择、会话建立(spawn session)等步骤。当会话建立失败时,当前的 UI 处理链路是:
AmbientAgentViewModel::handle_spawn_error将 ViewModel 状态置为Status::Failed { error_message },并发出AmbientAgentViewModelEvent::Failed,见 app/src/terminal/view/ambient_agent/model.rs。TerminalView::handle_ambient_agent_event收到Failed事件后,移除排队的 prompt block、更新活跃云会话状态、刷新详情面板并通知重绘,见 app/src/terminal/view/ambient_agent/view_impl.rs。- 最终由
BlocklistAIStatusBar::render_cloud_mode_setup_terminal_message把ambient_agent_model.error_message()渲染成一条红色错误消息栏,见 app/src/ai/blocklist/block/status_bar.rs。
这种做法的体验问题在于:失败信息出现在"Agent 消息栏"这一轻量 UI 载体中,既没有会话终结的语义(会话实际上已经结束了),也没有为错误提供足够的展示空间,更无法像正常会话终结那样组织标题、错误信息、耗时、积分消耗与 Artifact 等结构化元数据。
会话终结墓碑视图:既有的正确范式
仓库中已经存在一个成熟的"会话终结"呈现范式:TerminalView::insert_conversation_ended_tombstone(app/src/terminal/view/shared_session/view_impl.rs)。它会在会话结束后插入一个ConversationEndedTombstoneView,并记录conversation_ended_tombstone_view_id。该视图是一个可承载标题、错误消息、目录、来源、Skill、运行时长、积分、Artifact 按钮以及 "Continue" 类操作按钮的富内容卡片。
关键优势:输入框隐藏逻辑已经天然以该墓碑 ID 为开关。TerminalView::is_input_box_visible在 app/src/terminal/view.rs 附近实现,当存在conversation_ended_tombstone_view_id时输入框不可见。这意味着只要失败也能走墓碑插入路径,输入隐藏就"免费"获得,无需新增独立的输入隐藏状态。
二、核心改造方案总览
APP-4459 的改动范围被刻意限定在Setup-v2 专属:Setup-v1 仍沿用旧的整屏/状态页脚失败 UI,两条路径互不影响。整体改造包含四个文件/模块:
| 模块 | 位置 | 改动要点 |
|---|---|---|
TerminalView::handle_ambient_agent_event | view_impl.rs | 保留既有Failed状态更新与详情面板刷新;Setup-v2 启用时追加插入墓碑;以conversation_ended_tombstone_view_id防重复插入 |
conversation_output_status_from_conversation | app/src/ai/ambient_agents/mod.rs | 无已完成根交换且会话状态为Error时,回退为AmbientConversationStatus::Error,错误载体为RenderableAIError::Other(will_attempt_resume: false、waiting_for_network: false) |
ConversationEndedTombstoneView | app/src/terminal/view/shared_session/conversation_ended_tombstone_view.rs | 从会话状态读取错误展示数据;支持hide_continue_actions;处理"任务前失败"(pre-task failure)特殊文案 |
TaskStatusMessage | app/src/ai/ambient_agents/task.rs | 新增可选error_code字段(serde 映射errorCode)与is_environment_setup_failure()辅助方法 |
BlocklistAIStatusBar | app/src/ai/blocklist/block/status_bar.rs | 移除或按 Setup-v2 门控ambient_agent_model.error_message()分支,保留 GitHub 鉴权与取消分支 |
错误来源优先级
方案明确了墓碑错误数据的来源优先级(第 1 优先级最高):
AmbientAgentTask.status_message.message—— 有任务支撑(task-backed)的失败,尤其是第三方 harness 运行时,本地AIConversation仅作为 UI 载体,任务消息才是事实来源;- 会话状态错误(conversation status error)—— 包括尚未建立任务、但已有活跃本地会话的"任务前失败"。
三、Failed事件的墓碑化插入路径
3.1 事件处理:保持既有行为,追加墓碑插入
在handle_ambient_agent_event的Failed分支中,原逻辑(状态更新 + 详情面板刷新)被原样保留,仅增加一行墓碑插入:
AmbientAgentViewModelEvent::Failed { error_message } => { self.pending_cloud_followup_task_id = None; self.update_active_ambient_agent_conversation_status( ConversationStatus::Error, Some(RenderableAIError::other(error_message.clone(), false)), ctx, ); if FeatureFlag::CloudModeSetupV2.is_enabled() { self.insert_conversation_ended_tombstone_with_resolved_cta(ctx); } // Refresh the details panel to show failed status if self.is_conversation_details_panel_open { self.fetch_and_update_conversation_details_panel(ctx); } // Re-render to show the error state. ctx.emit(TerminalViewEvent::TerminalViewStateChanged); ctx.notify(); }要点解读:
- 状态写入发生在墓碑插入之前:
Failed处理逻辑先把错误写入会话(ConversationStatus::Error),再插入墓碑,这样墓碑在读取会话状态时能拿到错误信息。这正好对应"Setup 失败可能发生在AmbientAgentTask建立之前、但仍有活跃本地AIConversation"的场景。 RenderableAIError::other(message, false):第二个布尔参数即will_attempt_resume标记,此处传false表示该错误不附带自动恢复尝试,避免用户误以为失败后还会继续。- 复用
insert_conversation_ended_tombstone_with_resolved_cta:该函数内部按HandoffCloudCloud特性与cloud_conversation_continuation_ui_state决定使用何种 CTA(Continue in Cloud / Continue locally / 无 CTA),见 app/src/terminal/view/shared_session/view_impl.rs。
3.2 防重复插入
墓碑插入统一收敛在insert_conversation_ended_tombstone_with_cta:
if self.conversation_ended_tombstone_view_id.is_some() { self.remove_conversation_ended_tombstone(ctx); } // ... 构造 tombstone_view_handle ... self.insert_rich_content(None, tombstone_view_handle, None, insertion_position, ctx); self.conversation_ended_tombstone_view_id = Some(tombstone_view_id);即:插入前检查conversation_ended_tombstone_view_id,已存在则先移除旧墓碑再插入新墓碑,最终只保留一个墓碑富内容视图。这保证即使Failed事件重复到达(例如同一 spawn 错误被多次上报),用户看到的也始终只有一个墓碑,不会堆叠。
3.3 输入框隐藏的联动
is_input_box_visible已经以墓碑 ID 为开关,同时在 app/src/terminal/view.rs 附近,输入更新广播也会在"存在墓碑且输入隐藏"时被抑制:
let input_is_visible = self.is_input_box_visible(model, app); // 如果存在会话墓碑且输入隐藏,不应继续广播输入更新, // 因为云 Agent 会话已经结束。 self.conversation_ended_tombstone_view_id.is_none() || input_is_visible因此失败墓碑插入后,输入框自动隐藏,云会话结束的语义被完整传达。
四、conversation_output_status_from_conversation的错误回退
conversation_output_status_from_conversation位于 app/src/ai/ambient_agents/mod.rs,它从AIConversation推导出面向 ambient agent 的终结状态AmbientConversationStatus。现状逻辑是:
ConversationStatus::TransientError视为非终结状态,返回None;Blocked、InProgress、Success、Cancelled、WaitingForEvents走各自分支;Error分支优先取最后根交换(root exchange)的FinishedAIAgentOutput::Error,其次取conversation.status_error(),兜底取最后一个交换的终结状态。
APP-4459 的增量是:当没有已完成的根交换(即失败发生在任何交换完成之前),且conversation.status()为ConversationStatus::Error时,直接把conversation.status_error_message()转换为AmbientConversationStatus::Error,并规定错误载体为:
RenderableAIError::Other;will_attempt_resume: false;waiting_for_network: false。
这确保了"任务前失败"(任务尚未建立、没有交换可读)也能被墓碑正确识别为错误状态,而不是因为找不到根交换而丢失错误信息。
五、ConversationEndedTombstoneView的错误数据来源
5.1 展示数据结构
墓碑的核心数据结构为TombstoneDisplayData(app/src/terminal/view/shared_session/conversation_ended_tombstone_view.rs),包含标题、错误标记、错误消息、是否为快照、来源、Skill 名、运行时长、积分、工作目录与 Artifact 列表。
from_conversation从会话派生初始数据:
let conversation_status = conversation_output_status_from_conversation(conversation); let is_error = matches!( conversation_status, Some(AmbientConversationStatus::Error { .. }) ); let error_message = conversation_status .as_ref() .and_then(|status| match status { AmbientConversationStatus::Error { error } => Some(error.to_string()), _ => None, });改造后,is_error的判定扩展为:conversation.status().is_error()或会话输出状态本身带错误,两者任一成立即视为错误展示数据。
5.2 任务前失败(Pre-task Failure)的特殊呈现
在ConversationEndedTombstoneView::new中,新增如下判定:
if display_data.is_error && task_id.is_none() && !display_data.conversation_is_transcript { display_data.title = Some("Cloud agent failed to start".to_string()); display_data.credits = None; }即:当检测到"错误会话 + 无任务 ID + 无 transcript(非快照查看模式)"时,说明这是发生在任务建立之前的 Setup 失败,此时:
- 标题固定为
Cloud agent failed to start; - 积分(credits)字段清空(任务都没建立,自然没有积分消耗可展示);
- 后续新增的
hide_continue_actions会同时抑制 "Continue locally" 与 "Continue in cloud" 两类按钮——对一个从未启动的任务提供"继续"操作没有意义。
5.3 异步任务数据丰富(Task Enrichment)
墓碑在创建时会根据task_id异步拉取AmbientAgentTask(ai_client.get_ambient_agent_task),通过enrich_from_task丰富展示数据(app/src/terminal/view/shared_session/conversation_ended_tombstone_view.rs):
- 无会话标题时使用任务标题;
- 填充来源(Source)与 Skill/配置名;
- 任务失败状态(
task.state.is_failure_like())会用task.status_message.message覆盖错误消息——这正是"任务支撑失败优先于会话错误"的实现; - 用任务的运行时长、完整积分成本(inference + compute)覆盖会话侧数据;
- 任务非空 Artifact 列表(plans、PRs、files、screenshots)覆盖会话侧 Artifact。
改造保持该异步丰富链路不变,并让"任务失败元数据优先于会话错误"成为明确规则。
5.4 环境设置失败抑制 Continue 操作
当任务丰富发现失败状态且TaskStatusMessage.error_code == environment_setup_failed时,同样隐藏 Continue 操作。原因:环境设置失败意味着 Agent 从未真正进入可运行环境,继续执行无从谈起。
六、TaskStatusMessage的错误码扩展
TaskStatusMessage位于 app/src/ai/ambient_agents/task.rs:
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct TaskStatusMessage { pub message: String, #[serde(default, alias = "errorCode")] pub error_code: Option<TaskStatusErrorCode>, /// Deadline of an open post-failure debug window (REMOTE-2208/REMOTE-2661)... #[serde(default)] pub session_debug_until: Option<DateTime<Utc>>, ... }要点:
error_code为可选字段,#[serde(default)]保证服务端未下发该字段时反序列化为None,不破坏旧数据结构兼容性;alias = "errorCode"让 Rust 侧字段名error_code能与服务端 JSON 的errorCode正确互转;- 辅助方法
is_environment_setup_failure()(TaskStatusMessage与TaskStatusErrorCode两层均有)用于墓碑展示决策:识别"环境设置失败"类错误码,从而决定隐藏 Continue 操作。
错误码语义:environment_setup_failed专门标记"设置命令失败"类错误,这类失败不应提供继续操作(continue actions)。
七、状态栏的减法:移除通用失败分支
BlocklistAIStatusBar::render_cloud_mode_setup_terminal_message(app/src/ai/blocklist/block/status_bar.rs)在 Setup-v2 下渲染"云模式设置终结消息",包含三个分支:
- GitHub 鉴权分支(
github_auth_url()存在时):渲染警示图标 + 错误消息 + "Authenticate GitHub" 超链接 ——保留不变; - 取消分支(
is_cancelled()):渲染 "Cloud agent run cancelled" ——保留不变; - 通用失败分支(
ambient_agent_model.error_message()):渲染红色纯文本消息栏 ——在 Setup-v2 下移除或门控。
改造后,Setup-v2 的失败不再走通用失败消息栏,因为错误已经由墓碑视图承载;而 GitHub 鉴权与取消这两类"会话并未终结"的状态仍需要轻量消息栏,故原样保留。Setup-v1 不受影响,继续使用旧的失败 UI。
八、测试与验证计划
APP-4459 规划了针对性的 Rust 覆盖测试,每一项都直接对应前述行为:
| 测试目标 | 验证点 |
|---|---|
Setup-v2Failed事件处理 | 插入恰好一个墓碑,并移除排队的 prompt block |
| 输入隐藏联动 | 失败墓碑插入后TerminalView::is_input_box_visible返回false |
重复Failed事件 | 仍只保留一个墓碑富内容视图 |
| 任务前失败墓碑 | 标题为Cloud agent failed to start,隐藏积分与 Continue 操作 |
| 任务支撑失败墓碑 | 渲染AmbientAgentTask.status_message.message作为错误消息 |
| 环境设置失败 | 通过TaskStatusMessage.error_code识别并隐藏 Continue 操作 |
| 状态栏回归 | Setup-v2 下状态栏不再渲染通用失败消息分支 |
测试辅助入口已在ConversationEndedTombstoneView中提供(#[cfg(test)]的title_for_test、error_message_for_test、credits_for_test、has_continue_locally_button_for_test、has_continue_in_cloud_button_for_test,见 conversation_ended_tombstone_view.rs),方便测试直接断言标题、错误消息、积分与按钮可见性。
九、总结
APP-4459 将 Cloud Mode Setup-v2 的启动失败呈现从"Agent 消息栏红色错误条"整体迁移到"会话终结墓碑视图",形成一条完整的失败语义链:
handle_spawn_error记录Status::Failed并发出Failed事件;handle_ambient_agent_event把错误写入会话状态,并在 Setup-v2 下插入墓碑(防重复);- 墓碑从会话状态 /
AmbientAgentTask双来源汇总错误数据(任务优先); TaskStatusMessage.error_code == environment_setup_failed或任务前失败时抑制 Continue 操作;- 状态栏在 Setup-v2 下退役通用失败分支,仅保留鉴权与取消分支。
该方案复用了既有墓碑的输入隐藏联动、元数据展示与 Artifact 交互,让"失败"获得与"正常会话终结"同等的结构化呈现,同时通过错误码机制精确区分"环境设置失败"与普通任务失败,避免对失败任务提供无效的继续操作。
- 桌面应用
- 开发者工具
- 人工智能
- AI 应用
- AI Agent
- 代码智能体
【免费下载链接】warp
Warp is an agentic development environment, born out of the terminal.
相关推荐
RocksDB 范围墓碑转换(Range Tombstone Conversion):扫描路径上的墓碑合并优化
RocksDB 范围墓碑转换(Range Tombstone Conversion):扫描路径上的墓碑合并优化 本文基于 RocksDB 官方技术博客 docs
数据库KV存储嵌入式数据库存储Elsa Workflows 中 HTTP 上下文丢失的错误消息改进:从静默挂起到快速失败
Elsa Workflows 中 HTTP 上下文丢失的错误消息改进:从静默挂起到快速失败 当一条由 HTTP 端点发起的工作流在挂起后被转移到不同执行上下文(
后端工作流自动化流程编排低代码Warp 云端 Agent 会话结束态行为:基于 Harness 与对话编辑权限的 Tombstone / 续聊设计(APP-4483)
Warp 云端 Agent 会话结束态行为:基于 Harness 与对话编辑权限的 Tombstone / 续聊设计(APP 4483) 本指南以仓库内 spe
桌面应用开发者工具人工智能AI 应用AI Agent代码智能体
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考