主人 2026-10-07 三点裁定:「下划线确实可以保留」「多余的空气泡确实可以丢掉」 「非聊天模式 按照应当有的专业卡片和格式来显示」。 - 白名单回到六项(u 加回,s 仍在外) - 空 p 块也丢(与 br 碎片同一口径);纯注记回复 ⇒ 零气泡 - 非 chat 模式(8 个单卡正文)给它自己的渲染口径 CARD_RENDER: br ⇒ 真换行元素(那些容器没有 whitespace-pre-wrap,文本换行会被 CSS 折叠)、 行内白名单正常出样式;WorkMessageBody 的按行切清单、CodeMessageBody 的 pre 等既有较强约定一律保留 - 🔴 发现并修了一个会炸的下游损失:空气泡原本是承载头像/思维链/工具卡/心情/ 「生成中…」的那一行,丢气泡会把这些用户可见内容一起丢 ⇒ 加 hasBubbleChrome, 补一行无正文外壳 - 测试 99 -> 189 checks;6 个变异(含「外壳行摘掉 ⇒ 工具卡丢失」) - 改掉一条既有断言:三个 p 中首段被注记剥空 ⇒ 气泡数由 3 改为 2(并补按行数断言)
主人 2026-10-07:「对消息内的 <br> 始终处理为多条消息隔断」。 Web 侧(frontend/web): - chat.tsx 的 splitParagraphs(SplitChatBubble 的切分层)新增 BR_SEPARATOR_RE 与 splitBubbleBreaks:<br>/<br/>/</br> 等价、属性不解析、<brow>/<br2> 挡掉、 流式半截 <br 不切;不含 <br> 的段逐字返回原样(既有 p 口径一字节不动) - inlineMarkup.ts 删掉 break 节点(br 不再是行内元素),白名单收窄为 b/strong/i/em/code 五项;renderContent.tsx 同步;测试 76 -> 99 checks - 40 条基线逐字节对照:28 IDENTICAL,12 个 DIFF 恰是含 br/u/s/<BR> 的样例 IM 侧(internal/services/channelbridge): - 新增 inline_tags.go:成对平衡的白名单行内标签剥标签留文本、白名单外与 结构不平衡整段原样保留;br 作为第二级分隔符交给 splitBubbles - 两级切分:p 块为第一级,块内按 br 再切为第二级;空气泡丢弃 - br 切分放在角色注记摘除之后:否则 action 里的 br 会把注记正文漏成聊天气泡 (变异专门钉住这条顺序) 两路各 4 个自带变异均「改坏 -> 编译过 -> 变红 -> 还原 -> 复绿」。
主人 2026-10-07:「她在聊天消息中插入了 html/md 标签,能否增加网页前端 对此类标签的基本渲染支持?」 实测现场(最近 12 条 assistant 消息):<p> 96 次、<action> 34 次 (这两个前端已支持),<b> 6 次(未支持 => 裸标签直接显示给用户); Markdown 记号 0 个 => 她不用 Markdown,所以不引 Markdown 引擎。 - 新增 inlineMarkup.ts(纯逻辑,111 行):把文本切成「文本 / br / 行内元素」 的节点树;渲染与解析分离,不拼 HTML - renderContent.tsx 沿用既有出入口,把节点树映射成 React 元素; 既有 <p> / <action> 机制原样不动 - 白名单:b / strong / i / em / code / u / s(成对)+ br(void), 标签名大小写不敏感;不做块级、不做 a(独立安全面)、不做 Markdown - 安全:全程无 dangerouslySetInnerHTML(文本走 React 子节点,默认转义); 属性一律丢弃(节点类型里没有属性位);白名单外 => 纯文本字面量; 结构不平衡(未闭合/交错)=> 整段降级为原文,字符一个不丢 - 测试 76 条断言(esbuild + node,零新依赖);含 3 条安全性质 - 无回归:改动前后 11 个消息样例过真实 SplitChatBubble 链路逐字节对照, 7 个 SAME,4 个 DIFF 恰是含白名单标签的样例