Cherry Studio Composer Rich Clipboard 深度解析:消息表面与编辑器之间的 Token 无损复制粘贴机制

发布时间:2026/9/13 12:17:37

Cherry Studio Composer Rich Clipboard 深度解析:消息表面与编辑器之间的 Token 无损复制粘贴机制 Cherry Studio Composer Rich Clipboard 深度解析消息表面与编辑器之间的 Token 无损复制粘贴机制【免费下载链接】cherry-studioAI productivity studio with smart chat, autonomous agents, and 300 assistants. Unified access to frontier LLMs项目地址: https://gitcode.com/GitHub_Trending/ch/cherry-studio导读本文围绕 Cherry Studio 中消息表面Chat 对话、Agent 会话与 Composer 输入框之间的复制粘贴链路剖析一套私有剪贴板格式web application/x-cherry-composer-fragmentjson它如何在复制/粘贴时保留skill、file、command、knowledge、reference、quote、promptVariable等 Composer Token 的语义身份同时保证text/plain/text/html对外部应用保持可用且不泄露本地路径。读完本文你将理解该机制的目标、剪贴板载荷形状、同步粘贴流程、文件句柄与会话缓存的恢复规则、安全边界以及如何用聚焦测试快速验证相关改动。背景为什么需要私有剪贴板格式Cherry Studio 的 Composer 基于富文本编辑器TipTap/ProseMirror实现用户输入内容由「文本 有序 Token 片段」构成Token 覆盖技能skill、文件file、命令command、知识库knowledge、引用reference、引用块quote、提示词变量promptVariable等类型。当用户把一条包含这些 Token 的消息复制到剪贴板再粘贴回另一个消息表面或 Composer 时如果只走系统标准text/plain/text/htmlToken 结构就会丢失、退化为普通文本——例如/pdf/技能标记会变成一段纯文本而无法恢复成可执行的技能 Token。docs/references/chat/composer-rich-clipboard.md定义的 Composer Rich Clipboard富剪贴板正是为了解决这个问题在标准剪贴板格式之外额外写入一个带版本号的私有 JSON 片段完整保留有序的 text/token 分段粘贴时优先解析私有片段还原 Token私有片段缺失时则退而求其次通过纯文本标记如/skill/、#knowledge#或直接插入纯文本完成降级。该机制的目标可归纳为四点见 composer-rich-clipboard.md在 Cherry Studio 内部复制粘贴时保留skill、file、command、knowledge、reference、quote、promptVariable的 Token 身份通过text/plain与text/html让剪贴板在 Cherry Studio 之外仍然可用绝不在任何剪贴板载荷中暴露未经净化的 Token JSON、可解析的 Token 元数据或本地文件路径当剪贴板中没有 Composer Token 片段时保留原有富 HTML 复制行为如 Markdown 表格复制。剪贴板载荷形状三路写入与私有片段结构三种格式的分工Rich Composer 复制时向系统剪贴板写入三种载荷见 composer-rich-clipboard.md 的 Clipboard Shape 一节格式用途text/plain人类可读的回退文本粘贴到任意应用都可用text/html人类可读的 HTML不含可被解析的 Composer Token 元数据web application/x-cherry-composer-fragmentjsonCherry Studio 私有 Token 片段第三个私有格式的 MIME 常量定义在 composerClipboard.tsCOMPOSER_CLIPBOARD_FRAGMENT_MIME web application/x-cherry-composer-fragmentjson。私有片段的内部结构私有片段是带版本号的 JSONversion固定为 1COMPOSER_CLIPBOARD_FRAGMENT_VERSION 1segments是有序数组每个 segment 二选一{ type: text, text: string }纯文本段{ type: token, token: {...}, fallbackText: string }Token 段fallbackText是粘贴时无法恢复 Token 时的可见回退文本。Token 的 payload 字段在白名单内type、ext、name、origin_name、size文件 Token 还会带一个handle。写入前会对 Token 做一次净化sanitize且净化与文件句柄注册只发生一次即在createComposerClipboardFragment中完成源码注释明确说明这一点见 composerClipboard.ts。写入的片段还受COMPOSER_CLIPBOARD_FRAGMENT_MAX_LENGTH 250_000长度上限约束读取时超过上限直接拒绝。文件 Token路径永不落盘句柄只存活于会话内存文件 Token 是隐私敏感度最高的类型。其写入 payload 只保留展示字段文件名、扩展名、大小、类型绝不携带本地路径或由路径派生的 id可恢复的文件 Token 只携带一个不可猜测的句柄handle对应的文件元数据存放在当前渲染进程会话的内存恢复上下文中。恢复上下文由两部分组成见 composerClipboard.ts 中的实现文件恢复句柄注册表fileRestorationRegistry一个Maphandle, { sourceId, file, expiresAt }句柄用 UUID 生成createComposerFileTokenSourceId/createComposerSecureRandomId(composer-file)见 composerFileTokenSource.tsTTL 为COMPOSER_CLIPBOARD_FILE_HANDLE_TTL_MS 30 * 60 * 100030 分钟过期条目在注册与解析时惰性清除。会话缓存sessionCachedRichClipboardWrite保存最近一次通过异步剪贴板 API 写入的富复制片段以其纯文本为键使「粘贴该复制内容」无需读取系统剪贴板即可恢复 Token。测试用例keeps the file path out of the private fragment while preserving a session restore handle见 composerClipboard.test.ts验证了这一点片段文本中不含/Users/example/private/...路径也不含providerMetadata但写入时注册的句柄可在同一会话内还原出完整的FileMetadata。完整流程从复制到粘贴文档给出的流程图可以概括为以下链路原文 Mermaid 见 composer-rich-clipboard.md 的 Flow 一节用户复制选中的 Composer 内容或消息部件message parts把「可见文本 Composer Token」投影project为有序分段写入text/plain、安全的text/html浏览器支持时写入私有 Web 自定义格式含句柄并把片段记录进会话缓存粘贴到ComposerSurface若粘贴事件数据中带私有片段 → 解析并恢复支持的 Token 与文件句柄否则若粘贴文本与会话缓存中的最近富复制匹配 → 从缓存恢复否则 → 解析纯文本标记/skill/、#knowledge#或直接插入纯文本更新编辑器内容并将恢复出的FileMetadata合并进 Composer 文件列表去重键为id:path。复制侧实现复制分为两个入口消息表面复制MessageListActions.copyRichContent是富剪贴板写入的共享动作表面。消息组件请求该能力页面/窗口适配器提供实现。核心动作注册在 messageMenuBarActions.tsxregisterCommand(message.copy, async ({ actions, mainTextContent, messageParts, setCopied, t }) { const richContent actions.copyRichContent ? createComposerRichClipboardContentFromParts(messageParts) : null if (richContent) { const plainText removeTrailingDoubleSpaces(richContent.plainText.trimStart()) await actions.copyRichContent?.( { ...richContent, plainText }, { successMessage: t(message.copied) } ) } else { await actions.copyText?.(removeTrailingDoubleSpaces(mainTextContent.trimStart()), { successMessage: t(message.copied) }) } setCopied(true) })注意存在copyRichContent能力时普通复制路径的text/plain规范化去尾部双空格、去前导空白会被应用到富复制内容上但私有片段保留原始文本保证粘贴还原无损。页面/窗口适配器如 useMessagePlatformActions.ts的默认实现直接调用writeComposerRichClipboardContent(content)并弹出成功提示。useMessageSelectionControlleruseMessageSelectionController.ts则支持多选消息复制时合并生成一个片段。Composer 编辑器复制/剪切ComposerSurfaceRuntime的handleComposerCopyComposerSurfaceRuntime.tsx把当前选区序列化为草稿draft用createComposerRichClipboardContentFromDraft生成富内容并同步合并 live Token 的文件路径mergeLiveFileTokenPayload。剪切执行同样的富复制后删除选区因此剪切出的 Token 仍可恢复而不是退化为默认的「剥离 Token 的剪贴板 HTML」。片段生成的核心是投影函数projectTokensOverText按textOffset顺序把文本与 Token 交错切分为分段Token 的 fallbackText 由getTokenFallbackText按类型决定Token 类型fallbackTextquotepromptText ?? description ?? labelpromptVariablepromptText ?? description ?? labelskill/${marker}/从skill:前缀 id 提取标记knowledge#${marker}#从knowledge:前缀 id 提取标记其余含file、link等promptText ?? label这解释了为什么应用重启后skill/knowledgeToken 仍可通过纯文本标记恢复——/pdf/与#kb#本身就是可重解析的文本标记。粘贴侧实现ComposerSurfaceRuntime的memoizedHandlePasteComposerSurfaceRuntime.tsx中粘贴优先级如下若光标位于提示词变量 Token 内先把粘贴文本写入该变量值长文本粘贴超过阈值LONG_TEXT_PASTE_THRESHOLD 1500字符交给文件处理路径优先解析私有片段readComposerClipboardFragmentFromDataTransfer(event.clipboardData)读取粘贴事件数据失败则readComposerClipboardFragmentFromSessionCache(pastedText)按纯文本命中会话缓存两者都失败则继续降级片段解析成功 →getComposerClipboardPasteOverride生成编辑器内容与ComposerAttachment[]合并文件附件否则走getComposerPlainTextPasteOverride识别链接、/skill/、#knowledge#、提示词变量标记或插入纯文本仍失败则回退到通用handlePaste。getComposerClipboardPasteOverridecomposerPaste.ts遍历片段分段文本段直接建纯文本内容Token 段调用resolvePrivateClipboardToken按类型解析——skill/knowledge通过当前表面的 resolver 重新解析标记file通过createComposerAttachmentFromComposerClipboardToken解析句柄其余类型直接构造 Token。解析失败的分段一律降级为fallbackText纯文本。同步粘贴设计永不读取系统剪贴板粘贴处理完全同步绝不调用navigator.clipboard.read()。这是文档明确的设计约束原因在于通过异步剪贴板 API 写入的私有片段在 paste 事件的DataTransfer中不可见因此writeComposerRichClipboardContent会把写出的片段记录进会话缓存当一次粘贴的纯文本与最近一次富复制完全一致经过换行符规范化\r\n → \n时从缓存恢复避免读取系统剪贴板。文档还记录了被否决的替代方案粘贴时读取系统剪贴板会让每一次外部粘贴都变成异步操作且会读取无关的剪贴板数据通过合成复制事件写入需要已废弃的execCommand对text/html做指纹标记会泄露来源标识。该设计付出的代价是明确的quote与promptVariableToken 在应用重启或另一个 Cherry Studio 实例中会失去 Token 身份因为它们的恢复依赖会话内 nonce 或会话缓存而skill/knowledgeToken 仍可通过纯文本标记恢复。写入侧对应实现为writeComposerRichClipboardContentcomposerClipboard.ts其降级策略浏览器支持navigator.clipboard且存在ClipboardItem时若ClipboardItem.supports(私有 MIME)为 true写入text/plaintext/html 私有片段写入成功后若片段可被回读解析则写入会话缓存若自定义格式写入抛错降级为仅text/plaintext/html若浏览器不支持私有 MIME仅写text/plaintext/html连ClipboardItem都不可用时降级为navigator.clipboard.writeText(plainText)。每一次降级都会清空会话缓存sessionCachedRichClipboardWrite null置于函数开头测试clears the session cache when the private format is not supported与clears the session cache when writing the private format failscomposerClipboard.test.ts分别验证了这两种场景。恢复规则每种 Token 的还原策略文档定义的恢复规则结合源码可以逐条对应Token 类型恢复策略源码依据skill/knowledge仅通过当前表面的 resolver 重新解析保持 Chat 与 Agent 各自的 Token 归属边界resolvePrivateClipboardToken中调用resolveSkillMarker/resolveKnowledgeBaseMarker见 composerPaste.tsreference及无恢复规则的类型如command回退为可见文本fallbackTextgetComposerClipboardPasteOverride中resolvePrivateClipboardToken返回 null 时插入 fallbackTextfile仅当私有载荷带有能在当前会话恢复上下文中解析的句柄时恢复恢复文件按id:path去重createComposerAttachmentFromComposerClipboardTokenmergeComposerClipboardFilesfileTokenSourceId:path键见 composerClipboard.ts 与 ComposerSurfaceRuntime.tsxquote/promptVariable从净化后的 Token 字段恢复promptText ?? description ?? labelsanitizeComposerClipboardSegment中的 nonce 校验见 composerClipboard.ts不支持 / 不安全 / 无法解析的片段一律回退可见文本同上文件句柄的安全语义文件句柄不是受信任的剪贴板数据。它只是「定位本渲染进程会话中已有恢复上下文」的索引缺失、未知、过期、跨窗口、重启后或伪造的句柄一律回退为可见文本。测试覆盖了多种伪造场景does not reuse incoming file handles when writing private fragments写入时忽略传入的伪造 handle不为其注册composerClipboard.test.tsstops resolving file restoration handles after the handle TTL expires句柄 30 分钟过期后返回 nullcomposerClipboard.test.tsstrips forged path payloads from private file fragments read from the clipboard读取侧剥离伪造的path字段composerClipboard.test.ts。另外两条值得强调的规则消息文件 Token 的来源匹配从用户消息复制的文件 Token只有当消息文件部件携带的fileTokenSourceId与文本 Token 的源 id 完全一致时才可恢复文件名、显示名、Token label 一律不作为回退身份。测试does not restore message file tokens by filename when source ids do not match验证了这一点composerClipboard.test.ts。路径型 id 永不写入剪贴板isComposerFileTokenPathLike会把以file://、/、\、~开头或匹配^[A-Za-z]:[\\/]的 id 判定为不安全composerFileTokenSource.ts写入侧降级为 fallbackText 纯文本读取侧同样拒绝伪造的路径型 id。测试downgrades file tokens with unsafe id系列覆盖了读写两侧composerClipboard.test.ts。会话 nonce防伪造提示注入quote、promptVariable以及folder、link、reference的promptText会原样从片段恢复。由于任何应用都可以伪造私有 MIME一个可见的短 label 背后可能隐藏着会在发送时悄悄注入给模型的提示文本。因此这类 Token 只有在片段携带「会话私有 nonce」证明是本渲染进程写入时才被信任否则降级为可见回退文本。实现见 composerClipboard.tsCOMPOSER_CLIPBOARD_PROMPT_NONCE_TTL_MS 30 * 60 * 100030 分钟 TTLregisterTrustedPromptFragmentNonce在写入侧为含promptText的这类 Token 生成并记录 nonce写入 JSON 顶层isTrustedPromptFragmentNonce在读取侧校验sanitizeComposerClipboardSegment对无 nonce 且携带promptText的这类 Token 直接降级为 fallbackText。测试downgrades forged folder tokens without a session nonce to visible fallback text与restores folder tokens carrying a valid session noncecomposerClipboard.test.ts成对验证了拒绝与放行两种路径。能力边界与职责划分模块职责MessageListActions.copyRichContent富剪贴板写入的共享动作表面。消息组件请求能力页面/窗口适配器提供实现如 homeMessageListAdapter.tsx 层面的能力接线。composerClipboard.ts唯一拥有私有片段解析、序列化、HTML 转义、恢复上下文文件句柄注册表 会话缓存与系统剪贴板写入辅助函数的模块。ComposerSurface拥有编辑器 copy/cut/paste 事件处理并把片段解析/投影委托给工具函数剪切执行与复制相同的富复制后再删除选区。特性边界操作系统文件粘贴 / 拖放是独立流程使用浏览器或 Electron 文件 API不从私有 Composer 片段恢复文件。文件恢复不重新读取文件、不重跑支持扩展名校验后续发送/文件处理路径仍负责文件可用性。文件部件的mediaType推断不属于本特性如需 MIME 归一化应作为独立改动文档明确要求保持分离。commandToken 默认不具备剪贴板能力能力表COMPOSER_TOKEN_CAPABILITIEScomposerTokenPolicy.ts中command: { clipboard: false }而skill、link、file、folder、knowledge、reference、quote、promptVariable均为clipboard: true。这与恢复规则中「command属于无恢复规则类型、回退可见文本」的语义一致。已知取舍由于同步粘贴不读取系统剪贴板且会话缓存只保留最近一次富复制应用重启或另一个 Cherry Studio 实例粘贴quote/promptVariableToken 会丢失 Token 身份skill/knowledge因纯文本标记/x/、#x#可跨会话恢复file因句柄 TTL30 分钟且绑定当前渲染进程会话跨窗口、重启后均不可恢复。聚焦验证用最小测试集迭代文档建议在本地迭代时使用聚焦检查而非全量测试套件。原文命令如下两条命令分别覆盖粘贴解析与复制动作pnpm test:renderer src/renderer/components/composer/__tests__/ComposerSurface.test.tsx src/renderer/utils/message/__tests__/composerClipboard.test.ts pnpm test:renderer src/renderer/components/chat/messages/frame/__tests__/messageMenuBarActions.test.tsx src/renderer/components/chat/messages/utils/__tests__/messageSelection.test.ts src/renderer/components/chat/messages/hooks/__tests__/useMessagePlatformActions.test.tsx src/renderer/components/chat/messages/hooks/__tests__/useMessageSelectionController.test.tsx各测试文件的分工composerClipboard.test.ts核心单元测试覆盖片段净化路径不出现在片段中、句柄 TTL 过期、伪造句柄/路径拒绝、nonce 信任、会话缓存命中与清空、多消息组投影、草稿 Token 投影、promptVariable序列化、畸形片段拒绝非法 JSON、版本号不符、未知 kind、超长片段。ComposerSurface.test.tsx 与 composerPaste.test.ts粘贴行为集成测试验证私有片段解析、纯文本标记解析与降级路径。messageMenuBarActions.test.tsx验证message.copy命令在copyRichContent能力存在/缺失时的分支行为。useMessagePlatformActions.test.tsx 与 useMessageSelectionController.test.tsx验证适配器实现与多选复制调用链。总结Cherry Studio 的 Composer Rich Clipboard 是一套以「安全优先、标准格式兼容」为核心的私有剪贴板协议一次富复制同时产出text/plain、text/html与带版本的私有 JSON 片段粘贴完全同步通过会话缓存与文件句柄注册表在「不读取系统剪贴板」的前提下恢复 Token 身份路径与可解析 Token 元数据被严格排除在剪贴板载荷之外伪造片段通过 nonce 与来源 id 匹配被拦截。理解这份协议可以帮助你在为消息表面或 Composer 增加新 Token 类型时同步补齐能力表composerTokenPolicy.ts、片段净化与恢复规则并借助聚焦测试快速验证行为是否符合安全预期。【免费下载链接】cherry-studioAI productivity studio with smart chat, autonomous agents, and 300 assistants. Unified access to frontier LLMs项目地址: https://gitcode.com/GitHub_Trending/ch/cherry-studio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/13 12:12:36

DiffSynth-Studio:AI图像与视频生成、低显存训练的完整路径

DiffSynth-Studio:AI图像与视频生成、低显存训练的完整路径 【免费下载链接】DiffSynth-Studio Enjoy the magic of Diffusion models! 项目地址: https://gitcode.com/GitHub_Trending/dif/DiffSynth-Studio DiffSynth-Studio 是魔搭社区团队开发的开源扩散…

2026/9/13 13:12:39

GPU推理冷启动优化:从8分钟到1分钟的五阶段并行预热实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/13 13:12:39

Mac玩米游免费方案:GPTK+Whisky实测原神与绝区零

我这台MacBook Pro(M1 Pro)装原神和绝区零已经快三个月了。如果你还在用CrossOver的14天试用期反复折腾米游,或者被它每年几百块的订阅费劝退,那这篇东西应该能帮你省下不少时间——我也不卖关子,直接说结论&#xff1…

2026/9/13 13:12:39

NLP技术如何优化AI内容生成的自然度与可信度

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/13 13:12:39

球杆系统建模与控制:MATLAB符号推导与鲁棒极点配置

简介:本资源是一套面向控制工程专业本科生与初学者的球杆系统建模与稳定性分析实践材料,聚焦线性系统理论在典型机电装置中的建模、仿真与稳定性判据应用。资源包含3个核心文件:2个MATLAB源码文件(极点配置.m、判断系统能控能观.m…

2026/9/13 13:12:39

Mermaid Live Editor:用代码高效绘制流程图、时序图与ER图

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/13 13:07:39

ESP32-S3 N16R8硬件特性与PlatformIO工业级开发实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/13 0:01:16

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/13 0:01:16

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/12 14:32:17

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/13 11:18:28

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码