裁定(已发安卓):**能修**,走**写入侧规整** —— 不指望模型输出、不动客户端。 - 新增 internal/runtime/turnreply/paragraph.go 的 NormalizeParagraphs: 把未被 <p> 包裹的段落补上 <p>(按空行分段;<action>/<narration> 段也包进 <p>, 与正确形态 <p><action>…</action>…</p> 一致) - **幂等**守门断言:已完全包裹的文本逐字不变(防二次加工) - 落点覆盖 Web 与 IM 两条落库路径(gateway/session_turn_reply.go、channelbridge/turnreply.go、 proactive.go)⇒ 两边共用同一份规整文本 ⇒ **历史一次性变好、两个客户端零改动**、渲染口径不分叉 (测试与变异详见切片报告)
根因(agent-191,均给出文件:行): 1) knowledge 的 persona 在 schema 里是 optional,模型省略时工具把空串透给 memory.Retriever → 硬校验 ErrMissingPersona → 模型只能重复调用同一堵墙。 修:新增 tool/turncontext.go(loop 播种本回合角色),knowledge 依次取 「参数 → 本回合角色 → 可消化拒绝」,拒绝文案明确「重试不会成功」。 2) persistAssistantReply 对空文本直接 return,而三条正常收尾出口(空回复 / 轮次用尽 / 回合内部报错)都会给空文本 ⇒ 历史只剩 user 消息、客户端静默。 修:新增 session_turn_reply.go 的 persistTurnReply(唯一落库入口 + 按原因 的中文诚实说明);中断 / 陈旧代次 / 静默内部流程(backthink、子代理调度) 仍不落库,真实文本行为逐字未改。 测试:knowledge_test 改断言 + turn_persona_test(新)+ session_turn_reply_test(新,7 条) 变异:去掉 loop 角色发布 ⇒ loop×2 + gateway「工具执行次数 = 0, want 2」红