Files
Cyrene_v2/internal/services/gateway/session_events.go
T
AskaEth c0dc435770 feat(gateway): 忙时并行帧层(turn_begin + steer_ack.turnId + interrupt.turnId)
新下行帧 turn_begin:编排器每启动一路恰好一帧(单路 kind:"turn" / 并行路 "parallel"),
data{kind, messageIds, leg, activeTurns};角色门 fail-closed 仅 owner+admin,未进 frameReachesAll。
steer_ack 增帧壳 turnId(与该路 turn_begin 同源)—— 并行下没有它配不上正确的 turn.end。
上行 interrupt.turnId(仅 scope:"current" 生效):精确停某一路;目标不存在 ⇒ 定向
{type:"error",data:{code:"bad_request"}},不广播、不动任何会话;省略 turnId = v0.65 原口径(全部在途路)。
帧序按实现:session_busy / pending_drain → message_persisted(user) → turn_begin
(规范草案 §2.9 的时序图需按实现更正:messageIds 必须是已落库的权威 id,故只能在落库之后)。
测试:编排器侧 + 真 WS/JWT 端到端;变异 5 条(每路一帧 / 帧壳 turnId / 目标化打断 / 取消筛选)。
Docs 待升 v0.66(由监工登记)。
2026-10-05 09:38:11 +08:00

41 lines
2.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package gateway
// 本文件归属编排器推给前端的每会话状态事件类型(design/15 §5/§2.1)。
// 它们从 session_orchestrator.go 拆出,使编排器本体只留消息状态机,并保持在
// 「单文件 ≤500 行」的硬约束内。帧名即契约:客户端按 type 分发,因此这些取值
// 绝不随重构改名(要改就是契约变更,须先登记)。
//
// 这里只放**状态机信号**(不含消息内容)。带内容的帧(message.*、steer_ack、
// chat_duplicate 等)由 design/11 §7.1 的帧门按 fail-closed 默认档只投给
// owner + admin,见 ws_frame_scope.go。
// 经 WS 通道推给前端的状态事件类型。每个的 data map 都
// 携带 sessionId,使客户端能按会话关联状态。
const (
EventSessionBusy = "session_busy"
EventPendingAck = "pending_ack"
EventPendingDrain = "pending_drain"
EventSessionIdle = "session_idle"
EventSessionInterrupt = "session_interrupted"
EventPendingFull = "pending_full"
// EventChatDuplicate 是一次重复到达的明确应答(G4 幂等):本条 clientMsgId
// 已有落库的消息,本次没有新回合、也不会有新帧。它的 data 携带
// {sessionId, clientMsgId, messageId},让客户端把本地乐观气泡对齐到既有
// 消息;没有发过这个 clientMsgId 的其他客户端自行忽略即可。它不是状态机
// 迁移,因此不在 design/11 §7.1 的「状态信号」白名单里 —— 帧门默认只把它
// 投给 owner/admin(fail-closed)。
EventChatDuplicate = "chat_duplicate"
// EventTurnBegin 是「编排器刚起了这一路」的通知(design/15 §2.5.9、
// 忙时并行规范草案 §2.4):帧壳带该路的权威 turnId,data 带
// {kind, messageIds, leg, activeTurns},把「这一路 ↔ 它归属的用户消息 id」
// 钉死。客户端靠它(而不是靠猜)把这些气泡置为「已受理·回答中」,并按
// 帧壳 turnId 与会话 id 做**两级分桶** —— 真并行下两路的 message.delta
// 交错到达,只按 sessionId 分桶会把两条回复糊成一条。
//
// 它**携带具体消息身份**,因此**不进** frameReachesAll 的「状态机信号」
// 白名单,落 design/11 §7.1 的 fail-closed 默认档:只发 owner + admin。
// 两条路径都发(单路 kind:"turn"、并行照准 kind:"parallel"),因为串行
// 路径同样受益于「消息 ↔ 回合」绑定。
EventTurnBegin = "turn_begin"
)