feat(gateway): 未读面 unreadCount 进 message_persisted 帧(契约 v0.76 ②)
- broadcastPersisted 是 Web 与 IM 两条路的**共用**函数 ⇒ 两处口径天然一致,不存在分叉
- 口径 = 绝对未读 + 主人单一已读游标(chat_sessions.read_at)⇒ 多端共享
- 可选键 omitempty:只在 >0 且确实算得出来时出现;0 与「算不出来」都不顶位
(0 只能从「会话有游标」推出,否则那个 0 就是编的)⇒ 缺席 = 老行为
- Docs/api-client.md:v0.76 ① 按实测改标「未实现且无实现路径」(见下),② 已实现,
并更正「GET /sessions 的 unreadCount 自 D4 起已在」、新增 §4.13 与 §7.4 第 23 条
⚠️ ① toolCalls[] 本版未落地(取证结论,非推断):chat_messages.turn_id(编排器随机路标识
turn-<16hex>)与 flow_graphs.turn_id(trace.FlowGraph.ID = <session>-<轮次序号>,进程内递增)
不同源,真实库中 66 条消息行 vs 21 条图行字面交集为空 ⇒ 无法 join;按时间窗硬凑属于猜,不做。
补齐路径:链路图带回合标识(新键 + 迁移 0023 起)+ 落盘列,之后 toolCalls[] 是一条批量 SQL。
我亲自复跑的变异:去掉帧里的 n > 0 守卫 ⇒ TestBroadcastPersistedUnreadCountAbsentWhenUnknown
与 TestBroadcastPersistedCarriesUnreadCount 双双 FAIL(断言「0 不该顶位」)⇒ 测试是真护栏。
This commit is contained in:
1 parent
cb232e7360
commit
fe4c702f87
6 files changed
+369
-8
No files matched your search
@@ -32,6 +32,11 @@ func (s *Server) BroadcastPersisted(msg history.Message) {
|
||||
// 「这是她主动说的话」的结构化判据 `proactive:true`(切片 P0b,见 proactive.go 的
|
||||
// BroadcastProactivePersisted)。两条入口走**同一个**函数,因此帧类型推导、thinking
|
||||
// 抹除与角色门(design/11 §7.1)逐字一致 —— 差别只有那一个键。
|
||||
//
|
||||
// 帧的 data 另带**可选**的 `unreadCount`(契约 v0.76):该会话此刻的绝对未读数,
|
||||
// 与 GET /sessions 的 `unreadCount` 同一口径。它只在 >0 且真能算出来时出现(见
|
||||
// unreadCountOf),缺席即老行为。Web 路径与 IM 路径共用本函数 ⇒ 两处口径天然一致,
|
||||
// 不存在「Web 帧带、IM 帧不带」的分叉。
|
||||
func (s *Server) broadcastPersisted(msg history.Message, proactive bool) {
|
||||
wire := toHistoryMessage(msg)
|
||||
wire.Thinking = ""
|
||||
@@ -43,6 +48,13 @@ func (s *Server) broadcastPersisted(msg history.Message, proactive bool) {
|
||||
if proactive {
|
||||
data["proactive"] = true
|
||||
}
|
||||
// 未读数只在**确实算出来、且非零**时进帧(契约 v0.76)。缺席 = 老行为:老客户端
|
||||
// 忽略未知键,新客户端落下这帧时角标已经是对的,不必再拉一次 GET /sessions。
|
||||
// 不用 0 顶位:0 只能从「会话有游标」推出来,而算不出来(未接线/查询失败/
|
||||
// 会话没有游标)时那个 0 就是编的(见 unreadCountOf)。
|
||||
if n, ok := s.unreadCountOf(msg.SessionID); ok && n > 0 {
|
||||
data["unreadCount"] = n
|
||||
}
|
||||
s.hub.broadcast(wsEvent{Type: typ, SessionID: msg.SessionID, Data: data})
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user