ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Hermes Studio 系统通知内容预览:STUDIO_PUSH_CONTENT_PREVIEW 的隐私边界、格式化管线与终端消息选择

Hermes Studio 系统通知内容预览:STUDIO_PUSH_CONTENT_PREVIEW 的隐私边界、格式化管线与终端消息选择 AI 应用人工智能AI Agent本地部署前端后端工作流自动化【免费下载链接】ekko-studioEkko Studio is a local-first AI workspace for multi-agent chat, coding, and visual workflows, available on desktop and the web.项目地址https://gitcode.com/gh_mirrors/he/ekko-studio点击查看免费下载导读本文以 docs/notification-content-preview.md 为核心骨架系统讲解 Hermes StudioEkko Studio 桌面与 Web 端iOS APNs 推送通知中「内容预览」机制的完整设计环境变量STUDIO_PUSH_CONTENT_PREVIEW的三态语义、基于事件信封显示字段的 40/160 字素grapheme截断与 Markdown 清理管线、以及精确锁定终端助手消息terminal assistant message的取文策略。读完本文你将掌握该功能的部署配置方法、隐私取舍原则、底层实现调用链run-push.ts、notification-preview.ts、chat-completion-text.ts以及对应的验证测试run-push-consumer.test.ts。一、功能定位推送通知中的「内容预览」是什么在 Hermes Studio 的移动端推送链路中Studio 服务端在检测到聊天完成chat.run.completed、失败chat.run.failed、审批请求chat.approval.requested、澄清请求chat.clarification.requested等业务事件后会通过 App Relay 网关向该用户名下的 iOS 设备通过 APNs发送推送。推送负载里除了一条用于点击回跳的ekko_run路由信息外还有一个notification字段携带title与body——这正是用户会在系统通知中心、锁屏上看到的内容。在内容预览机制引入之前网关侧默认按事件类型选择固定文案会话标题与生成回复一律不出 Studio。而「内容预览」则允许在满足隐私配置的前提下把当前会话标题和当前回合的 AI 回复摘要一并发送给网关与 APNs让用户在锁屏上就能看到大致回复内容。相关背景与设备注册、事件路由的完整机制可进一步阅读 docs/run-push-registration.md。关键设计原则原文档核心主张沿用既有权限路由接收者是「已认证的 Studio 登录用户」推送内容预览不改变既有的用户/设备权限判定canReceiveAppEvent预览只是附加在原有消费链路之上的内容增强。只使用事件信封的显示字段预览数据仅来源于appEventEnvelope产出的display字段单聊取content群聊取preview绝不使用 prompt、原始错误、工具调用或历史消息作为回退。这不是敏感数据过滤器格式化规则截断、去 Markdown只是让文本可读并不具备分类、脱敏能力。可见的 AI 回复中仍可能包含私密内容需要部署者在配置层面自行决策。二、部署配置STUDIO_PUSH_CONTENT_PREVIEW 三态语义原文档给出了该环境变量的完整语义以下是逐条展开与源码印证。取值行为说明未设置unset默认启用预览推送请求携带真实 title/body1显式启用预览与默认行为一致用于部署清单中显式声明0禁用预览发送{ title: , body: }由网关生成通用回退文案在源码 run-push.ts 中逻辑清晰对应// Preview is enabled by default; set 0 to keep notification content private. // Custom content requires a gateway that honors notification title/body. notification: process.env.STUDIO_PUSH_CONTENT_PREVIEW ! 0 ? notificationPreview(...) : { title: , body: },几个必须注意的运维要点修改后必须重启 Studio该环境变量在服务进程启动后读取属于进程级配置热更新不生效。既有部署的「0」保持退出状态已经显式配置0的部署不会因升级而自动开启预览避免存量隐私策略被悄然改变。0模式仍走完整推送链路禁用预览只是让notification为空对象网关按事件类型显示固定文案Android 等价文本点击回跳、设备注册、权限校验等全部照常。1只是部署开关不是用户级同意控制原文档明确指出per-user/per-device 的预览设置、同意/设置 UX 与完整隐私政策尚未实现切勿把该环境变量当作面向终端用户的授权机制使用。真实部署中的教训LPK 遗漏环境变量原文档记录了 2026-09-19 的真实设备验收结果第一个 LPK部署包对应 PR3106PR3111遗漏了STUDIO_PUSH_CONTENT_PREVIEW1导致网关正确回退到通用文案同时一个未命名的结构化移动端会话需要安全的文本提取而非直接吐原始 JSON。后续补丁为结构化标题增加了回归测试替换版 LPK 显式开启了经评审的预览模式。这条记录说明该功能是部署级默认开启的若你的部署策略要求内容不出站必须在环境变量中显式写0而不能依赖默认值之外的空想。三、预览格式化的实现display 字段 40/160 字素 Markdown 清理3.1 数据来源appEventEnvelope 的 display 字段预览的输入来自 app-events.ts 的appEventEnvelope(event)。它把内部业务事件转换为对外统一信封单聊完成事件display包含title会话标题预览与content当前回复来自chatCompletionText群聊group.message.createddisplay包含title与preview群内最终助手回复摘要以及 agent 列表工作流/其他事件display直接透传event.payload.display。推送消费者在组装负载时run-push.ts对单聊完成事件会把chatCompletionText(event)的结果合入content其余情况直接取envelope.display——这正是原文档所说「Uses only the existing appEventEnvelope display fields (content for chat, preview for group)」。3.2 格式化管线notificationPreview核心实现位于 notification-preview.tsreturn { title: plain(display.title, 40), body: completion ? plain(display.content || display.preview, 160) : }要点标题上限 40 字素正文上限 160 字素completion类事件才有正文审批/澄清类交互事件body为空截断按grapheme字素簇计算而非 UTF-16 码元使用Intl.Segmenter切分保证 emoji、组合字符等不会被拦腰截断超限时以…收尾基础 Markdown 清理顺序如下移除围栏代码块 与 ~~~含未闭合情形移除图片语法alt链接语法text只保留可见文本移除行首 0~3 个空格后的#/标题与引用标记剥离*、_、反引号、~等强调/行内代码标记将控制字符与空白折叠为单个空格JSON 安全提取当输入以[或{开头时尝试JSON.parse若解析结果是内容块数组content数组则拼接其中type text的text字段解析失败则原样返回。这正是为「未命名结构化移动端会话」提供的安全文本提取避免把原始 JSON 直接推给 APNs。3.3 源码注释明确的两条红线无任意原始错误/命令回退notification-preview.ts头注释「Explicit display fields only. Never use prompt, raw error, tool or history fallback.」对应测试run-push-consumer.test.ts中chat.run.failed携带error: SECRET、审批事件携带command: SECRET时断言整个请求体不包含SECRET。空当前输出绝不回退旧聊天文本预览正文为空就发送空宁可让网关显示通用文案也不从会话历史里捞旧回复详见下文第四节。四、终端消息选择为什么 output 不可靠以及共享选择器的修复4.1 背景两次真实设备验收暴露的问题原文档记载了两次验收发现直接推动了选择器演进第一次2026-09-19coding-agent 的run.completed可能携带空output但精确的助手message_id对应消息其实已持久化同时未命名结构化会话需要安全文本提取。第二次非空output也可能拼接了最终答案之前的中间回复interim replies导致 Android 与 iOS 都预览了第一条回复而非最终答案。4.2 共享选择器精确终端助手行优先解决方案是共享取文函数 chat-completion-text.ts其逻辑export function chatCompletionText(event: BusinessEvent): string { if (event.type ! chat.run.completed) return const sessionId event.subject.session_id const messageId Number(event.subject.message_id) const message sessionId Number.isSafeInteger(messageId) messageId 0 ? getSessionContextMessage(sessionId, messageId) : null if (message?.role assistant) { for (const text of [message.display_content, message.content]) { if (typeof text string text.trim()) return text } } return typeof event.payload.output string ? event.payload.output : }选择优先级明确优先读取完成事件message_id定位到的精确持久化助手消息先看display_content再看content仅当该行没有可用助手文本时才回退到event.payload.output绝不回退到最新一条或上一条助手消息——保留回合归属turn attribution与既有隐私边界不把历史内容外泄绝不回退会话历史即使精确行与 output 都为空正文就是空字符串。该函数被两个消费方共享appEventEnvelope生成display.content、run-push消费者组装推送正文所以 Android 事件流与 iOS APNs 走的是同一选择器保证双端行为一致。此修复落在 Studio 的事件/推送消费端只需更新 Studio无需原生 App 重新构建。4.3 测试验证run-push-consumer.test.ts 中的关键用例uses the exact persisted terminal message when the completion payload output is emptyoutput: message_id: 42→ body 为Persisted current replyuses the terminal assistant message ahead of accumulated output on both Android and iOSoutput是First progress reply. 重复 30 次再拼接最终答案断言两端信封与推送 body 都是Persisted current reply且session.preview中的旧回复不参与回退never falls back to session history on Android or iOS when the current reply is unavailable输出为空时display.content与推送 body 均为空串defaults to current title and reply when the preview setting is absentSTUDIO_PUSH_CONTENT_PREVIEW未设置时Markdown 加粗的**Current reply**被清理为纯文本Current reply。五、隐私边界与合规提醒务必阅读原文档以「Privacy change」单独强调这是部署者必须向用户交代的变更内容出站启用预览后会话标题与有界bounded的当前回复摘要会经过推送网关与 APNs可能按 iOS 锁屏设置显示在锁屏上这不是脱敏器格式化规则无法识别、过滤敏感信息。可见 AI 回复仍可能包含私密材料需要敏感数据合规的部署请使用0建议对不得传输内容的部署明确设置STUDIO_PUSH_CONTENT_PREVIEW0并纳入部署清单LPK/环境配置避免因默认开启而意外出站。已知未完成需求原文档如实列明网关契约待确认标题/正文是否被真正采用、空字段回退行为、端到端负载大小强制需网关侧确认本仓库不拥有 APNs 最终序列化器。Android/群聊全管线检查未完成Android 端与群聊事件的事件显示格式化仍需独立的全管线校验。同意/设置 UX 未实现per-user/per-device 预览设置与完整隐私政策尚不存在部署级环境开关不是用户级同意控制。真实设备验收未完成iOS 与 Android 的内容/路由验收尚未全部通过。Live Activity 不在此范围其投递、令牌与状态是独立系统不属于本 PR。原文档同时给出验证状态加入消费者选择加入集成回归后16 个聚焦测试通过harness 与生产构建通过空当前输出绝不回退旧聊天文本。六、完整调用链速览与源码索引业务事件 BusinessEventchat.run.completed / group.message.created / ... └─ run-push.ts 的 createRunPushConsumer(event) ├─ 过滤replayed/restored/background_snapshot/interrupted/queue_insertion 等不发送 ├─ appEventEnvelope(event) → display 字段chat 用 contentgroup 用 preview │ └─ chatCompletionText(event) → 精确终端助手行display_content/content → payload.output ├─ notificationPreview(display, isCompletion) → { title: ≤40 字素, body: ≤160 字素 } Markdown 清理 JSON 安全提取 ├─ 按设备组装 /push/v1/send 负载含 ekko_run 点击回跳路由 └─ POST 到 App Relay 网关official: config.appRelay.urlCloudflare: https://cn.ekkostudio.xyz延伸阅读索引功能设计文档docs/notification-content-preview.md推送注册与所有权背景docs/run-push-registration.md推送消费者实现run-push.ts预览格式化实现notification-preview.ts终端消息选择实现chat-completion-text.ts事件信封实现app-events.ts聚焦测试run-push-consumer.test.ts结语Hermes Studio 的通知内容预览机制是一个「功能克制、边界清晰」的工程案例通过单一环境变量三态控制部署级隐私策略通过事件信封显示字段限定数据来源通过字素级截断与 Markdown 清理保证可读性通过精确终端消息选择器解决流式拼接带来的预览错位并用一组聚焦测试16 个用例固化行为。部署者只需记住两件事默认开启、0关闭且修改后重启若合规要求内容不出站请在 LPK 中显式写入STUDIO_PUSH_CONTENT_PREVIEW0。赞分享AI 应用人工智能AI Agent本地部署前端后端工作流自动化【免费下载链接】ekko-studioEkko Studio is a local-first AI workspace for multi-agent chat, coding, and visual workflows, available on desktop and the web.项目地址https://gitcode.com/gh_mirrors/he/ekko-studio点击查看免费下载相关推荐Open Design开源AI设计革命如何用259技能打造专业级设计原型Open Design开源AI设计革命如何用259技能打造专业级设计原型 Open Design是一款革命性的开源AI设计工具它正在重新定义设计工作流程AI 应用人工智能AI 技能设计系统媒体生成掌握Visual Studio Code通知系统从消息提示到进度管理的完整指南掌握Visual Studio Code通知系统从消息提示到进度管理的完整指南 Visual Studio CodeVS Code作为一款广受欢迎的代码编开发工具代码编辑器5个技巧让Mac第三方鼠标超越苹果触控板Mac Mouse Fix深度解析5个技巧让Mac第三方鼠标超越苹果触控板Mac Mouse Fix深度解析 还在为macOS上第三方鼠标的糟糕体验而烦恼吗滚动生硬、侧键闲置、功能单一——这桌面应用系统编程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表