- 桌面应用
- 开发者工具
- 人工智能
- AI 应用
- AI Agent
- 代码智能体
【免费下载链接】warp
Warp is an agentic development environment, born out of the terminal.
导读
本指南以 Warp 开源仓库中的产品与技术规格(specs/APP-3630/PRODUCT.md 与 specs/APP-3630/TECH.md)为核心,系统讲解 Warp 通知系统的一项关键增强:当 Agent 在对话中产出 Plan、Pull Request、截图等产物(Artifact)时,对话一旦进入终态(成功 / 取消 / 出错),完成通知(Toast 弹窗与通知信箱 Mailbox)都会在标准内容下方渲染一行可交互的 Artifact Chip,点击通知本体即可跳转到对应对话。读完本文,你将理解该功能的完整数据流——从UpdatedConversationArtifacts事件的载体改造,到AgentNotificationsModel的跨轮累积策略,再到NotificationItem数据结构与渲染层的交互组件接入,并掌握每一步对应的仓库源码位置,可直接对照当前实现进行二次开发。
一、问题背景:Agent 产物为何“静默”
Warp 中,Agent 在对话过程中会持续创建各种产物(Artifact),典型包括:
- Plan(行动计划,可同步到 Warp Drive 的 notebook)
- Pull Request(已创建的 PR,携带 URL 与分支名)
- Screenshot(截图)
- File(生成的文件)
- ExternalReference(外部引用)
在增强之前,用户对这些产物的感知存在明显缺口:只有对话状态发生变更(完成、阻塞、出错)时系统才会触发通知,而产物本身并不会触发任何通知。如果用户没有主动进入对话查看,就完全无从得知 Agent 已经生成了计划、提了 PR 或截了图——产物在通知层面是“静默”的。
仓库中的源码可以印证这一现状的“历史边界”:
- 通知数据结构 NotificationItem 原本只承载
title、message、category、agent、origin、is_read、created_at、terminal_view_id,不含任何产物数据; - 通知创建模型 AgentNotificationsModel 监听的是
UpdatedConversationStatus事件,通过handle_history_event_for_mailbox生成通知,并未监听UpdatedConversationArtifacts。
规格书(PRODUCT.md)据此给出明确判断:现有通知只在状态变化时触发,产物的产生对用户完全不可见。
二、期望行为与设计约束(Scope 总览)
规格书为本次增强划定了清晰的边界,这是理解后续实现的关键:
| 维度 | 约束 |
|---|---|
| 触发条件 | 复用现有完成通知(UpdatedConversationStatus到达终态),不新增独立产物通知 |
| 产物范围 | 自上一次终态通知以来新增的全部产物,即跨当前响应的所有轮次累积 |
| 交互性 | Artifact Chip 可交互,使用与管理视图(agent_management 视图)完全相同的按钮 |
| 点击行为 | 点击通知本体导航到对应对话 |
| 展示面 | Toast 弹窗 + 通知信箱(Mailbox)双端一致 |
| 特性开关 | 由hoa_notifications(通知系统现有开关)控制 |
两个值得注意的设计取舍:
- 不新增通知类型。产物信息作为完成通知的“附加行”出现,避免通知轰炸——如果每个产物都单独发一条通知,一轮产生 5 个 PR 就会出现 5 条通知;
- “终态才呈现”。产物在对话进行中会持续累积,只有到达终态(Success / Cancelled / Error)时才一次性呈现在完成通知里。
从源码看,hoa_notifications在仓库中体现为编译特性 + 运行时开关的组合:features.rs中 FeatureFlag::HOANotifications 在#[cfg(feature = "hoa_notifications")]下注册,模型层也通过FeatureFlag::HOANotifications.is_enabled()判断是否走信箱通知路径(见 agent_management_model.rs)。
三、现状盘点:四个关键代码位置
TECH.md 首先对现状做了精确盘点,四个位置分别对应“数据、创建、事件、渲染”四个环节:
3.1 通知数据:NotificationItem
NotificationItem位于 app/src/ai/agent_management/notifications/item.rs。规格撰写时它没有产物字段;当前仓库中该结构已经扩展出artifacts: Vec<Artifact>与branch: Option<String>两个字段(后者用于通知的“富布局”分支头行渲染),NotificationItem::new也相应接收artifacts与branch参数。这印证了本功能在当前分支上已落地,后续源码阅读均以“已实现版本”为准。
3.2 通知创建:AgentNotificationsModel
单例模型 AgentNotificationsModel 负责两类来源的通知:
- Warp Agent 对话:订阅
BlocklistAIHistoryModel,在handle_history_event中响应UpdatedConversationStatus; - CLI Agent 会话(Codex 等):按终端视图(
CLISession)跟踪。
它只监听状态事件、不监听产物事件,这正是本功能需要打通的“缺口”。
3.3 产物事件:UpdatedConversationArtifacts
事件定义在 app/src/ai/blocklist/history_model.rs。规格撰写时该事件只携带terminal_surface_id与conversation_id,不含产物本体;当前仓库中已增加artifact: Artifact字段。
事件的发射点有两处(均在 app/src/ai/agent/conversation.rs):
AIConversation::add_artifact:向对话追加产物并持久化,随后发射事件(先 clone 再 push,保证事件中携带的是独立的产物副本);update_plan_notebook_uid:当 Plan 产物同步到 Warp Drive、获得notebook_uid后更新并发射事件。
此外,从 history_model.rs 可以看到事件的上游来源:远端消息流中的artifact_event(PR / Screenshot / File 的Created事件,以及fork_artifacts)都会被转换为Artifact并调用add_artifact。
3.4 渲染:render_notification_item_content
渲染函数 render_notification_item_content 位于 item_rendering.rs,负责渲染头像 + 标题 + 消息。规格撰写时它只接收&NotificationItem与&Appearance,没有视图上下文,因此无法渲染任何交互组件。
3.5 交互组件范式:ArtifactButtonsRow
管理视图(agent_management/view.rs)中已经存在成熟的产物按钮行模式:创建ViewHandle<ArtifactButtonsRow>、订阅事件、把句柄存进CardState。本功能要做的就是把这套模式复用到通知场景。
交互组件的实现位于 app/src/ai/artifacts/buttons.rs:
ArtifactButtonsRow内部是一组ViewHandle<ActionButton>,渲染产物对应的按钮(计划、分支、PR);- 事件枚举
ArtifactButtonsRowEvent定义了OpenPlan(携带notebook_uid)、CopyBranch(携带分支名)、OpenPullRequest(携带 URL)等动作; - 产物类型枚举
Artifact定义在 app/src/ai/artifacts/mod.rs:PLAN、PULL_REQUEST、EXTERNAL_REFERENCE、SCREENSHOT、FILE五种变体,带serde(tag = "artifact_type")的标签式序列化,并通过#[serde(rename = "...")]与远端协议对齐。
四、实现方案:五步改造链路
TECH.md 将实现拆解为 5 步,其内在依赖关系是:第 1 步必须先行(数据载体是前提),第 2-3 步与第 4-5 步可并行(详见“并行性”一节)。下面按数据流顺序展开。
第 1 步:让事件“携带”产物本体
在UpdatedConversationArtifacts中新增artifact: Artifact字段,并在两个发射点克隆产物:
add_artifact:在 push 进self.artifacts之前 clone(当前实现见 conversation.rs);update_plan_notebook_uid:在修改产物之后 clone(当前实现见 conversation.rs)。
这一步的意义:事件从“信号”升级为“信号 + 载荷”。下游订阅方(通知模型)不再需要反向查询对话状态来推断产物,而是直接拿到产物副本,解耦了数据获取逻辑。
第 2 步:在 AgentNotificationsModel 中跨轮累积产物
在AgentNotificationsModel中新增:
pending_artifacts: HashMap<AIConversationId, Vec<Artifact>>累积规则是整个功能的行为核心,规格给出了明确的状态机语义:
| 事件 | 行为 |
|---|---|
UpdatedConversationArtifacts | 将产物 append 到pending_artifacts[conversation_id] |
InProgress | 不清空pending_artifacts—— 产物跨轮累积 |
| 终态(Success / Cancelled / Error) | drainpending_artifacts[conversation_id],传给add_notification |
| 对话删除 / 移除 | 清理对应pending_artifacts条目 |
| CLI Agent 通知 | 传入空 vec |
当前仓库实现完全遵循了该设计:
- 模型字段即 pending_artifacts;
- 在
handle_history_event_for_mailbox中,ConversationStatus::Success、Cancelled、Error三个分支都先调用self.flush_pending_artifacts(conversation_id)取出累积产物,再传给add_notification(见 agent_management_model.rs); Blocked(Request类别)不进入终态,因此不 flush、不携带产物。
这里有一个值得强调的细节:“InProgress 不清空”保证了多轮产物的完整累积。假设 Agent 先给出 Plan,又等待用户确认后创建 PR,最后才完成——两条产物都会出现在最终的完成通知里,而不是只有最后一轮的 PR。
第 3 步:给 NotificationItem 增加 artifacts 字段
为NotificationItem增加artifacts: Vec<Artifact>,并贯通NotificationItem::new与add_notification的整个调用链。
仓库当前实现中,该字段及其构造参数已经存在(见 item.rs 与 item.rs),通知项还额外携带了branch: Option<String>,用于触发“富布局”渲染。
第 4 步:在 Toast 与 Mailbox 中持有 ArtifactButtonsRow 视图
NotificationToastItem与NotificationMailboxView各自为每条通知存储一个Option<ViewHandle<ArtifactButtonsRow>>:
- 创建时机:通知新增时创建视图;
- 订阅:订阅
ArtifactButtonsRowEvent,处理OpenPlan/CopyBranch/OpenPullRequest等动作; - 行为对齐:动作处理逻辑与
agent_management/view.rs(管理视图)中的ArtifactButtonsRowEvent处理保持一致。
仓库中该环节的封装位于 item_rendering.rs:create_notification_artifact_buttons_view在产物为空时返回None,否则以NotificationArtifactButtonTheme创建ArtifactButtonsRow;事件处理由 handle_notification_artifact_buttons_event 统一接管(打开 Plan、跳转 PR、复制分支等动作均伴随遥测事件上报)。
从文件分布看,两个承载视图分别位于:
- notifications/toast_stack.rs(Toast 弹窗堆栈)
- notifications/view.rs(Mailbox 视图)
第 5 步:把产物视图接入渲染
为render_notification_item_content增加Option<&ViewHandle<ArtifactButtonsRow>>参数,当存在时在消息文本下方渲染ChildView(子视图),并更新 Toast 与 Mailbox 两处调用点。
当前仓库中该函数签名已经是render_notification_item_content(item, artifact_buttons, context, message_expanded, on_expand_click, extra_content)(见 item_rendering.rs),内部按item.branch是否为空分派两种布局:
- 富布局
render_rich_text_column:分支头行 + 截断标题 + 截断消息 + 产物按钮(item_rendering.rs); - 简单布局
render_simple_text_column:标题 + 时间戳行 + 消息 + 产物按钮(item_rendering.rs)。
两种布局最终都通过append_trailing_content把产物按钮行追加到文本列之后(item_rendering.rs),从而保证 Toast 与 Mailbox 的视觉一致性。
五、并行性与实施顺序
规格在最后明确了工程的依赖图:
第 1 步(事件携带产物) │ ├── 第 2 步(模型累积)──┐ └── 第 3 步(Item 字段)──┼── 可并行 │ ┌── 第 4 步(视图持有)──┤ └── 第 5 步(渲染接入)──┘即:第 1 步是硬前置,因为它定义了产物数据到达通知系统的通道;第 2-3 步(模型层累积 + 数据结构)与第 4-5 步(视图层持有 + 渲染接入)在各自内部可以并行推进,因为视图层的ViewHandle只是“选项句柄”,即便通知项尚无产物,Option<ViewHandle>取None时渲染层也能自然回退到无产物布局,不会破坏编译与运行。
这种分层并行也体现在当前仓库的模块划分上:数据层(notifications/item.rs)、模型层(agent_management_model.rs)、渲染层(notifications/item_rendering.rs)、承载层(notifications/toast_stack.rs/notifications/view.rs)各司其职,彼此通过类型与句柄解耦。
六、端到端数据流小结
把上述五步串起来,一次完整的“产物通知”体验是这样的:
- Agent 在对话中创建产物(Plan / PR / 截图 / 文件),远端事件或本地逻辑触发
AIConversation::add_artifact或update_plan_notebook_uid; - 产物被 push 进对话状态,同时克隆后随
UpdatedConversationArtifacts事件(现已携带artifact)广播出去; AgentNotificationsModel收到事件,将产物追加到pending_artifacts[conversation_id];InProgress状态不清空,产物跨轮累积;- 对话到达终态,
UpdatedConversationStatus触发完成通知路径,模型 drain 累积产物并写入NotificationItem.artifacts; - Toast 与 Mailbox 收到通知项后,通过
create_notification_artifact_buttons_view创建ArtifactButtonsRow并订阅其事件; render_notification_item_content在标准内容下方渲染产物按钮行;用户点击按钮可打开 Plan / 跳转 PR / 复制分支,点击通知本体则导航到对应对话。
七、延伸阅读:仓库中的配套实现
- 产品规格:specs/APP-3630/PRODUCT.md
- 技术规格:specs/APP-3630/TECH.md
- 通知数据结构:app/src/ai/agent_management/notifications/item.rs
- 通知创建模型:app/src/ai/agent_management/agent_management_model.rs
- 通知渲染与按钮创建:app/src/ai/agent_management/notifications/item_rendering.rs
- 产物类型定义:app/src/ai/artifacts/mod.rs
- 产物按钮行组件:app/src/ai/artifacts/buttons.rs
- 产物事件定义与发射:app/src/ai/blocklist/history_model.rs、app/src/ai/agent/conversation.rs
- 特性开关注册:app/src/features.rs
如需验证行为逻辑,可进一步查阅agent_management_model_tests.rs中关于产物累积与终态 flush 的测试用例,它们与本功能的状态机语义一一对应。
- 桌面应用
- 开发者工具
- 人工智能
- AI 应用
- AI Agent
- 代码智能体
【免费下载链接】warp
Warp is an agentic development environment, born out of the terminal.
相关推荐
Orleans事件溯源模式应用:从设计到实现
Orleans事件溯源模式应用:从设计到实现 引言:为什么选择事件溯源? 在分布式系统中,传统状态管理方式面临三大挑战:数据一致性难以保证、系统行为缺乏可追溯性
后端微服务Instant-NGP神经网络图形框架:如何实现秒级3D内容生成革命?
Instant NGP神经网络图形框架:如何实现秒级3D内容生成革命? Instant NGP作为NVIDIA实验室推出的革命性神经网络图形框架,正在彻底改变3
人工智能深度学习计算机视觉3D渲染图形学科研Charticulator交互式图表设计:从零到精通的完整指南
Charticulator交互式图表设计:从零到精通的完整指南 为什么选择Charticulator? 在数据可视化领域,传统工具往往限制用户的创造力。Char
前端数据可视化
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考