Files
Cyrene_v2/internal/services/gateway/session_pending.go
T
AskaEth 89e13cf53d
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
feat(gateway,loop): 忙时并行回合基础管线(I1′ 有条件放宽)
- turnId 由编排器生成、loop Run 复用(硬前提:否则 turn_begin 与流帧各铸一个,客户端两级分桶立即失配)
- StateSink 增带 turnId 的变体(未接线时退化为现签名,不丢状态帧)
- 上行 chat.parallel(WS chat 帧 + REST 三入口同形;省略 = 逐字不变)
- 单会话额度默认 2 / 硬上限 3 / <2 关闭;额度满或未声明 ⇒ 落回既有排队语义
- I1′:checkpoint 归属、历史配对、忙态计数三处从会话级单例升为路级
- session_idle 收紧为「所有在途路收尾且 pending 空」(仅并行时生效;单路逐字不变)
- 预留接口(形状定死、无实现无接线):tool/legfile.go 的 FileClaimer / ErrFileBusy / WithLegID
- 顺手修一个真 bug:并行路 ctx 派生自提交请求作用域,REST 同步入口一写响应就把它连坐杀死(改 context.WithoutCancel 派生)
- 23 个新用例(含 -race -count=3);变异 6 条(turnId 复用 / idle 时点 / 并行升级 / checkpoint 键 / 编排器交 id / pending_ack reason)
- 契约变更点 10 条待监工升 v0.65(本人未改 Docs/**)
2026-10-05 09:18:50 +08:00

47 lines
2.2 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
import (
"context"
"time"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/loop"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
)
// 本文件归属会话编排器的**待处理队列**(design/15 §2.1/§2.2):忙时到达、且
// 未声明并行(或并行额度已满)的消息怎么入队、怎么落库、怎么回 ack。它从
// session_orchestrator.go 拆出,使那个文件继续只留状态机骨架(并守住
// 「函数 ≤80 行」的硬约束)。
// enqueueLocked 把一条忙时到达的用户消息放进有界待处理队列,并返回本次提交的
// 判定。它**必须在 o.mu 下调用**,并在返回前解锁:落库是慢操作,绝不能在状态
// 锁下做,因此它自己解锁后再做落库与状态帧广播(与 startParallelLocked 同一
// 约定,调用方直接 return 它的返回值)。
//
// 入队时携带该消息到达时的设备 / 模式 / 语音回调,使它的续跑回合与「它就是当前
// 回合」时逐项一致(design/16 §4.5、§5.1;协同 C1)。落库两段式的第一段在这里:
// 用户消息立刻进历史(抽取结论等回合跑起来才有,由续跑结算回写,见
// session_document_status.go)。
func (o *Orchestrator) enqueueLocked(ctx context.Context, st *sessionState, sessionID string, messages []model.Message, env loop.SessionEnv, deviceID, msgMode string, hint clientMsgHint) SubmitResult {
st.pendingSeq++
seq := st.pendingSeq
st.pending = append(st.pending, pendingMsg{
messages: messages,
env: env,
deviceID: deviceID,
mode: msgMode,
at: time.Now(),
seq: seq,
voice: voiceReplySinkFrom(ctx),
})
depth := len(st.pending)
mode := st.mode
o.mu.Unlock()
o.attachPendingDocuments(sessionID, seq, o.persistUserMessages(ctx, sessionID, messages, deviceID, msgMode, env.PersonaID))
// 声明了并行却落回排队时如实给出 reason,让客户端把气泡渲染成「排队中」而不是
// 「被拒」(design/15 §2.6);未声明时该键缺席,帧与今天逐字相同。
o.emitState(sessionID, EventPendingAck, pendingAckPayload(sessionID, mode, depth, parallelRequested(ctx)))
return SubmitResult{Accepted: true, Pending: true, QueueDepth: depth, MessageID: hint.MessageID}
}