☰
ClawX ACP 媒体附件恢复实战:结构化用户回合与 OpenClaw MEDIA 附件对齐机制
2026/9/29 2:54:56 网站建设 项目流程
  • 人工智能
  • AI 应用
  • 桌面应用
  • 交互助手

【免费下载链接】ClawX

ClawX is a desktop app that provides a graphical interface for OpenClaw AI agents. It turns CLI-based AI orchestration into a desktop experience without using the terminal. China website is https://clawx.com.cn.

项目地址:https://gitcode.com/gh_mirrors/cl/ClawX
点击查看免费下载

导读

本文围绕 ClawX(OpenClaw AI 代理的桌面客户端)中 ACP 聊天链路上的一个关键兼容性问题展开:当触发某轮回复的用户提示词本身携带了结构化资源(resource_link、resource)或图片内容时,如何保证该回合助手侧被 OpenClaw ACP 适配器丢弃的显式MEDIA:附件仍能被有界地恢复并正确渲染到同一个回合下。读完本文,你将掌握 ClawX 的"二进制自由提示词投影 + 归一化文本与尾部出现次数对齐"这一整套回合对齐机制的实现原理、安全边界与验证方式,并能直接定位到对应的源码与测试文件。

问题背景:OpenClaw ACP 不投射助手 MEDIA 附件

ClawX 通过 Agent Client Protocol(ACP)与 OpenClaw 网关通信,渲染器将 ACP 通知归约为内存时间线(timeline)。标准 ACP 的resource_link与 URI 托底的resource内容块是首选附件来源,可以直接渲染为回形针附件卡片。但分布式 OpenClaw ACP 适配器存在一个已知行为:它不会把助手侧的MEDIA:附件指令投射为标准的 ACP 资源块——有时会从可见回复中直接删除该指令,有时则会把指令作为普通助手文本回放而不带资源块(详见 harness/reference/acp-generated-media-and-diagnostics.md 的 "Preferred And Compatibility Paths")。

因此 ClawX 需要两条有界的、仅驻留内存的兼容路径来补全这些缺口:

  1. 图像生成完成(需有可证明的image_generate上下文)的恢复;
  2. 通用附件恢复:从规范的持久化助手__openclaw.media事实、整行开头的助手MEDIA:指令(代码围栏之外)、或确认以message_tool_only方式投递到internal-uisink 的message工具结果中恢复附件引用。

这两条路径都不会复活旧版 Chat 渲染器,也不会把兼容数据伪装成原生 ACP 事件。本文聚焦的是第二条路径中一个此前存在的缺陷——"带附件的用户回合"导致 MEDIA 附件无法对齐到正确的回合,对应的修复规格即 harness/specs/tasks/fix-acp-media-attached-turn-alignment.md,其前置任务 harness/specs/tasks/acp-media-attachments.md 定义了整体附件渲染能力。

任务范围与边界

该修复任务的Scope非常明确:

保留结构化 ACP 用户提示块的一个轻量投影,并用它重建现有"有界助手MEDIA:兼容补充"所需的 OpenClaw 转写文本。

即:用户侧不解析、不猜测,只投影;转写侧只用于对齐,不改变证据与授权策略。

与之对应的Out Of Scope包括:

  • 修改 OpenClaw 或其分发包;
  • 用 Gateway Chat 历史替代 ACP 回放;
  • 解析用户自行书写的资源标记文本(如长得像[Resource link]的普通文字);
  • 把助手证据扩展到显式整行MEDIA:指令之外;
  • 改变附件解析、预览、打开或授权策略。

这些边界同时被 harness/specs/rules/acp-compatibility-content-safety.md 与 harness/specs/rules/acp-chat-state-and-history.md 固化:兼容逻辑不得重建普通助手消息、思考、工具、计划、权限、文件活动或平行的 Chat 历史;未匹配或模糊的证据必须跳过,而不是靠猜测就近挂靠。

核心机制一:二进制自由的用户提示词投影

问题根源在于:当用户回合携带图片(image块)或资源链接时,如果直接用原始 content 做文本匹配,会引入二进制 base64 数据、破坏匹配键的稳定性和体积。因此 src/lib/acp/openclaw-prompt-compat.ts 实现了openClawPromptTextBlocks,按 OpenClaw 的提示词扁平化规则把结构化 ACP 用户块投影为有序的、无二进制的文本块数组:

  • text块 → 保留原文;
  • resource块 → 若内嵌resource.text非空则保留该文本(即"嵌入式文本");
  • resource_link块 → 生成 OpenClaw 风格的[Resource link]转义形式(openClawResourceLinkPromptText);
  • image、audio、blob等二进制内容 → 直接省略,不保留 base64。

其中resource_link的转义文本格式为[Resource link (title)] uri,标题与 URI 都会经过escapeInlineControlChars处理:控制字符(\0、\r、\n、\t、\v、\f、U+2028、U+2029 等)被转义为\xNN/\uNNNN,标题中的(、)、[、]被反斜杠转义,避免干扰后续的行级解析。

这个投影在渲染器归约阶段就已落盘:在 src/lib/acp/reducer.ts 的appendMessageChunk中,用户消息段会通过userPromptTextBlocks字段累积这些文本块;replaceMessage(src/lib/acp/reducer.ts)在 ACP 回放回执到达时也会用openClawPromptTextBlocks(blocks)重建该字段。对应的类型定义见 src/lib/acp/timeline-types.ts,注释明确说明这是 "Binary-free text blocks produced by OpenClaw's ACP prompt flattening"。

关键约束:用户侧投影只能从同一条时间线内已有的结构化 ACP 内容重建。用户自己写出的、长得像资源标记的普通文字不是证据,既不能被全局剥离,也不能被当作附件证据——这正是验收标准中 "User-authored text resembling an OpenClaw Resource link marker is not globally stripped or treated as attachment evidence" 所要求的。

核心机制二:回合对齐键——归一化文本 × 尾部出现次数

有了无二进制的投影文本,接下来要解决"如何把转写侧的一条用户回合,精确匹配到 ACP 时间线上的同一回合"。

由于转写历史只是有界后缀(历史加载最多读取最近 1000 条转写消息,普通实时提示词做一次立即读取并在 1500ms 后重试一次,见 harness/reference/acp-generated-media-and-diagnostics.md),且跨来源的消息 ID 不可持久依赖,ClawX 采用从尾向前的逆序出现次数作为锚定方式。相关实现集中在 src/lib/acp/openclaw-media-compat.ts:

  • normalizeUserText(L79-L83):移除已知的 OpenClaw 工作目录包裹(stripAcpWorkingDirectoryPrefix)、统一\r\n为\n、trim 首尾空白。只做这三件事——不采用宽泛模糊匹配,也不会全局剥离资源标记。
  • assignOccurrencesFromTail(L237-L247):从尾部向头部遍历回合,对相同的归一化文本按出现次数从 1 递增编号。
  • turnMatchKey(L375-L377):把[normalizedUserText, userOccurrenceFromTail]序列化为唯一的回合对齐键。

acpUserTurns(L351-L373)从 ACP 时间线快照中按message-segment的真实用户边界收集回合,使用userPromptTextBlocks作为提示词文本来源(若无投影块则回退到 markdown parts 拼接),再统一归一化并分配尾部出现次数。空投影文本(纯附件回合)同样参与编号,这保证了"附件-only"回合也可对齐。

核心机制三:转写证据提取与有界对齐

转写侧的提取由extractOpenClawMediaTurns(L249-L339)完成,它按真实用户边界划分消息,排除inter_session/internal_system等控制记录,只为每个用户回合收集三类有界证据:

  1. 规范的持久化助手媒体事实:__openclaw.media数组中的每项可贡献一条有序的path或url,附带文件名、内容类型、大小(persistedMediaFacts,L155-L176);
  2. message工具投递事实:仅当工具结果状态为ok、投递状态为sent、sourceReplySink为internal-ui且sourceReplyDeliveryMode为message_tool_only时,才读取details.sourceReply.mediaUrl/mediaUrls,按序折叠重复引用(L178-L210);
  3. 显式MEDIA:指令:整行、行首(允许前置空白)、大小写不敏感的MEDIA:标记,恰好一个引用;带引号引用可含空格但必须同引号闭合,无引号引用不能含空白(parseDirectiveReference,L95-L126)。

指令解析还实现了 Markdown 围栏状态机(mediaReferences,L212-L235):围栏内的内容一律忽略,直到出现相同分隔符且长度不小于开启长度的闭合。每条候选证据用消息身份(id:/timestamp:/ 内容稳定哈希)加message-tool/structured/ 行号与 URI 构成evidenceSeed,最终生成形如openclaw-media:<stableHash>的evidenceId。引用上限为 4096 字符(MAX_MEDIA_REFERENCE_LENGTH);未知 URI scheme、畸形 URL 或引号、空引用、Markdown/列表包裹、行内散文、无规范事实的裸路径、以及被包裹的指令都会被拒绝。

对齐动作由alignOpenClawMediaTurns(L406-L435)执行:

  • 对实时场景(传入liveUserMessageId),先把 ACP 回合限定到包含该乐观用户身份的唯一当前回合,其余回合不参与;
  • 建立"对齐键 → ACP 回合"映射,重复键一律标记为歧义并跳过;
  • 转写回合的候选为空则跳过;命中歧义键则跳过;未命中任何 ACP 回合则跳过——缺失、重复、歧义的锚点都不会按序号偏移或就近猜测来分配。

实时回合还可以通过selectOpenClawTranscriptTurn(L379-L404)反查:从 ACP 时间线定位当前实时用户回合的对齐键,再从原始转写消息中找出唯一同键回合,返回该回合的完整消息序列供提取。如此,"文本 + 附件"与"纯附件"两类用户回合,都能在实时完成与历史加载两种路径下恢复 MEDIA 证据,且不会显示原始兼容标记。

渲染与去重:附件锚定到所属用户回合

提取出的OpenClawMediaTurnSupplement(acpTurnId+ 有序候选列表)在 src/stores/acp-chat-session.ts 中被逐条解析:resolveOpenClawMediaCandidate会校验会话、generation、操作与尝试编号,通过 Main 的会话级附件授权解析本地或远端引用,并记录 reason-coded 诊断追踪(openclaw-media:projection-stale、openclaw-media:resolution-available等)。

渲染侧由 src/lib/acp/reducer.ts 的upsertSyntheticTurnAttachments完成:

  • 以compat:openclaw-media:<evidenceId>构造带compat.source: 'openclaw-media'标记的合成助手段(仅渲染器投影,不是 ACP 协议事件);
  • 在itemOrder中找到messageId === turnId的用户段作为锚点,把附件段插到该用户回合之后、下一个用户回合之前;
  • 相同evidenceId的旧投影会被原位替换,最终通过dedupeTimelineAttachments按 Main 授权的不透明附件身份做回合级去重。

这保证了"重复的带附件提示词仍与正确的用户出现次数关联,且不重复恢复附件",也保证了"附件在助手散文之后按声明顺序渲染"。原生 ACP 资源证据优先级高于兼容证据;不可用结果不会占用解析身份,延迟读取中的稳定候选可以升级替换同一合成投影(详见 harness/reference/acp-generated-media-and-diagnostics.md 的 Canonical And Explicit MEDIA Attachments 一节)。

安全边界:授权始终由 Main 持有

对齐机制无论怎么投影与匹配,都不改变附件授权策略:__openclaw.media的规范事实本身不授权访问,每条引用与元数据都保持不可信,必须穿过 Main 现有的附件边界。Main 从成功的 ACP 加载中推导执行 cwd,校验精确的会话与 generation,允许活动工作区之外的既有常规文件,并在每次预览读取或打开时重新解析;HTTP/HTTPS 引用在外部打开前重新校验,外出媒体 URL 保持托管记录绑定(见 harness/reference/acp-attachment-access-control.md 与规则 harness/specs/rules/attachment-access-safety.md)。每次异步结果仅对相同的活动会话键、ACP generation、补充操作、当前尝试以及(实时场景)用户回合身份有效。

验收标准解读

该任务的acceptance逐条对应了上述机制,可概括为七项事实:

  1. 资源链接转写投影不再阻碍同回合 MEDIA 渲染——resource_link被投影为[Resource link]文本后,仍能与转写侧对齐,助手附件照常渲染;
  2. 块序精确——ACP 的 text、embedded text、resource-link、被省略的二进制块按序构成有界对齐键,且不保留图片 base64;
  3. 用户书写的伪资源标记不被全局剥离或当作证据;
  4. 纯附件回合按逆序出现次数对齐,实时提示词额外要求精确的乐观用户身份;
  5. 既有检查完整保留——会话、generation、尝试、歧义、证据、去重与 Main 附件授权检查全部不受影响;
  6. 兼容性理由明确——OpenClaw ACP 不投射助手 MEDIA 附件,因此需要一次有界转写读取;
  7. 零架构回归——不引入 OpenClaw 源码、分发包、旧版 Chat 渲染器、直接 Renderer IPC 或直接 Gateway HTTP 请求。

测试与回归验证

单元测试 tests/unit/acp-media-attachments.test.ts 直接覆盖本机制的核心场景,例如:

  • "aligns a structured resource-link user turn with OpenClaw transcript projection"——结构化资源链接用户回合与转写投影对齐;
  • "aligns attachment-only turns with empty OpenClaw prompt text by occurrence from the tail"——纯附件回合按尾部出现次数对齐;
  • "matches repeated prompts by occurrence from the tail"——重复提示词按尾部出现次数匹配;
  • "aligns an attachment-only assistant output to a user turn without an ACP assistant segment" 与 "anchors marked attachment-only segments inside the matching turn"——附件-only 输出段正确锚定到所属用户回合。

配套的归约与存储测试包括 tests/unit/acp-reducer.test.ts 与 tests/unit/acp-chat-store.test.ts,端到端验证在 tests/e2e/chat-acp-attachments.spec.ts 与 tests/e2e/chat-acp-inline-timeline.spec.ts。

规格要求的完整回归命令(requiredTests)包括:

pnpm exec vitest run tests/unit/harness-specs.test.ts tests/unit/acp-media-attachments.test.ts tests/unit/acp-reducer.test.ts tests/unit/acp-chat-store.test.ts pnpm run typecheck pnpm run lint:check pnpm run build:vite pnpm exec playwright test tests/e2e/chat-acp-attachments.spec.ts pnpm run comms:replay pnpm run comms:compare pnpm harness validate --spec harness/specs/tasks/fix-acp-media-attached-turn-alignment.md pnpm harness run --spec harness/specs/tasks/fix-acp-media-attached-turn-alignment.md pnpm run harness:ci

其中comms:replay/comms:compare对应 scripts/comms 下的通信回归基线,harness validate / run则是本仓库的规格驱动开发工具链(入口见 harness/package.json),确保该任务与acp-chat-state-and-history、acp-compatibility-content-safety、attachment-access-safety等既有规则保持一致。

总结

fix-acp-media-attached-turn-alignment本质上是把"用户回合"从附件恢复的薄弱环节变成了精确锚点:渲染器只投影(无二进制的有序文本块),对齐只靠(归一化文本 × 尾部出现次数)这一个有界键,实时场景额外叠加乐观用户身份,歧义与缺失一律跳过,授权与去重仍由 Main 全权负责。这套设计保证了即便用户提示词携带图片或资源链接、甚至完全没有文本,助手侧被 ACP 丢弃的显式MEDIA:附件也能稳定、正确、不重复地回到它所属的回合中。

  • 人工智能
  • AI 应用
  • 桌面应用
  • 交互助手

【免费下载链接】ClawX

ClawX is a desktop app that provides a graphical interface for OpenClaw AI agents. It turns CLI-based AI orchestration into a desktop experience without using the terminal. China website is https://clawx.com.cn.

项目地址:https://gitcode.com/gh_mirrors/cl/ClawX
点击查看免费下载

相关推荐

上一篇:系统内存优化实战指南:用Mem Reduct提升电脑运行效率
下一篇:SiamFC-PyTorch详解:如何用PyTorch实现高效目标跟踪算法

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询