feat(gateway,loop): A1 流式帧附加 sessionId/turnId — 多会话并发流式可路由

- model.StreamEvent 增 SessionID/TurnID(适配器在 loop 之下,恒留零值)
- loop 在回合边界注入;覆盖 stream.go 与 tools.go 的 tool_execution 发射点
- 网关 runTurn 每回合生成 turnID 并经 loop.WithTurnID 挂进运行上下文(编排层与 legacy 直连的唯一收口点);broadcastStream 填充 wsEvent
- Docs/api-client v0.36 契约与变更日志;v0.10 条目标注为已被补齐
- 新增 loop/gateway 测试,含变异验证
This commit is contained in:
AskaEth committed 2026-10-03 16:08:52 +08:00
1 parent 29aa60d0eb
commit 61cc32c44b
9 files changed
+332 -10

No files matched your search

+19
View File
@@ -19,3 +19,22 @@ func loopSession(ctx context.Context) string {
s, _ := ctx.Value(loopSessionIDKey{}).(string)
return s
}
// loopTurnIDKey is the context key for the assistant turn the current Run is
// producing. The gateway attaches it (WithTurnID) before starting a turn so the
// streaming events the loop emits can be correlated to that turn by the client.
type loopTurnIDKey struct{}
// WithTurnID attaches turnID to ctx so the streaming events the loop emits carry
// the turn they belong to. It is exported because the gateway calls it once per
// turn, before Run; a caller that attaches none leaves the events' TurnID empty,
// which keeps the correlation fields backward compatible.
func WithTurnID(ctx context.Context, turnID string) context.Context {
return context.WithValue(ctx, loopTurnIDKey{}, turnID)
}
// loopTurn returns the turn id on ctx, or "" when none was attached.
func loopTurn(ctx context.Context) string {
s, _ := ctx.Value(loopTurnIDKey{}).(string)
return s
}