- 人工智能
- 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.
导读
本文围绕 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 需要两条有界的、仅驻留内存的兼容路径来补全这些缺口:
- 图像生成完成(需有可证明的
image_generate上下文)的恢复; - 通用附件恢复:从规范的持久化助手
__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等控制记录,只为每个用户回合收集三类有界证据:
- 规范的持久化助手媒体事实:
__openclaw.media数组中的每项可贡献一条有序的path或url,附带文件名、内容类型、大小(persistedMediaFacts,L155-L176); message工具投递事实:仅当工具结果状态为ok、投递状态为sent、sourceReplySink为internal-ui且sourceReplyDeliveryMode为message_tool_only时,才读取details.sourceReply.mediaUrl/mediaUrls,按序折叠重复引用(L178-L210);- 显式
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逐条对应了上述机制,可概括为七项事实:
- 资源链接转写投影不再阻碍同回合 MEDIA 渲染——
resource_link被投影为[Resource link]文本后,仍能与转写侧对齐,助手附件照常渲染; - 块序精确——ACP 的 text、embedded text、resource-link、被省略的二进制块按序构成有界对齐键,且不保留图片 base64;
- 用户书写的伪资源标记不被全局剥离或当作证据;
- 纯附件回合按逆序出现次数对齐,实时提示词额外要求精确的乐观用户身份;
- 既有检查完整保留——会话、generation、尝试、歧义、证据、去重与 Main 附件授权检查全部不受影响;
- 兼容性理由明确——OpenClaw ACP 不投射助手 MEDIA 附件,因此需要一次有界转写读取;
- 零架构回归——不引入 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.
相关推荐
ClawX 中 ACP 生成媒体与诊断的兼容实现:有界转录补全、MEDIA 附件与内存 Trace 通道
ClawX 中 ACP 生成媒体与诊断的兼容实现:有界转录补全、MEDIA 附件与内存 Trace 通道 本文基于 ClawX 仓库中的兼容性设计文档 harn
人工智能AI 应用桌面应用交互助手Anomalib 中的 CFLOW-AD 模型:基于条件归一化流的实时无监督异常检测与定位指南
Anomalib 中的 CFLOW AD 模型:基于条件归一化流的实时无监督异常检测与定位指南 本文以 CFLOW AD 模型文档 https://link.g
人工智能AI 应用桌面应用交互助手ClawX ACP 附件 Open With 深度解析:Main 授权的跨平台「用其他应用打开」实现
ClawX ACP 附件 Open With 深度解析:Main 授权的跨平台「用其他应用打开」实现 本篇技术指南围绕 ClawX 桌面端 ACP(Agent
人工智能AI 应用桌面应用交互助手
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考