Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions backend/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,12 @@ type GatewayOpenAIWSConfig struct {
StoreDisabledForceNewConn bool `mapstructure:"store_disabled_force_new_conn"`
// PrewarmGenerateEnabled: 是否启用 WSv2 generate=false 预热(默认 false)
PrewarmGenerateEnabled bool `mapstructure:"prewarm_generate_enabled"`
// ClientReadLimitBytes: 入站客户端 WS 单帧读取上限。
ClientReadLimitBytes int64 `mapstructure:"client_read_limit_bytes"`
// HTTPBridgeEnabled: 首包过大时,保持客户端 WS,改用 HTTP Responses 上游。
HTTPBridgeEnabled bool `mapstructure:"http_bridge_enabled"`
// HTTPBridgeThresholdBytes: 触发 HTTP bridge 的入站 WS payload 阈值。
HTTPBridgeThresholdBytes int64 `mapstructure:"http_bridge_threshold_bytes"`

// Feature 开关:v2 优先于 v1
ResponsesWebsockets bool `mapstructure:"responses_websockets"`
Expand Down Expand Up @@ -1806,6 +1812,9 @@ func setDefaults() {
viper.SetDefault("gateway.openai_ws.store_disabled_conn_mode", "strict")
viper.SetDefault("gateway.openai_ws.store_disabled_force_new_conn", true)
viper.SetDefault("gateway.openai_ws.prewarm_generate_enabled", false)
viper.SetDefault("gateway.openai_ws.client_read_limit_bytes", 64*1024*1024)
viper.SetDefault("gateway.openai_ws.http_bridge_enabled", true)
viper.SetDefault("gateway.openai_ws.http_bridge_threshold_bytes", 15*1024*1024)
viper.SetDefault("gateway.openai_ws.responses_websockets", false)
viper.SetDefault("gateway.openai_ws.responses_websockets_v2", true)
viper.SetDefault("gateway.openai_ws.max_conns_per_account", 128)
Expand Down Expand Up @@ -2543,6 +2552,15 @@ func (c *Config) Validate() error {
if c.Gateway.OpenAIWS.PrewarmCooldownMS < 0 {
return fmt.Errorf("gateway.openai_ws.prewarm_cooldown_ms must be non-negative")
}
if c.Gateway.OpenAIWS.ClientReadLimitBytes <= 0 {
return fmt.Errorf("gateway.openai_ws.client_read_limit_bytes must be positive")
}
if c.Gateway.OpenAIWS.HTTPBridgeThresholdBytes < 0 {
return fmt.Errorf("gateway.openai_ws.http_bridge_threshold_bytes must be non-negative")
}
if c.Gateway.OpenAIWS.HTTPBridgeEnabled && c.Gateway.OpenAIWS.HTTPBridgeThresholdBytes == 0 {
return fmt.Errorf("gateway.openai_ws.http_bridge_threshold_bytes must be positive when http_bridge_enabled is true")
}
if c.Gateway.OpenAIWS.FallbackCooldownSeconds < 0 {
return fmt.Errorf("gateway.openai_ws.fallback_cooldown_seconds must be non-negative")
}
Expand Down
9 changes: 9 additions & 0 deletions backend/internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,15 @@ func TestLoadDefaultOpenAIWSConfig(t *testing.T) {
if cfg.Gateway.OpenAIWS.PrewarmCooldownMS != 300 {
t.Fatalf("Gateway.OpenAIWS.PrewarmCooldownMS = %d, want 300", cfg.Gateway.OpenAIWS.PrewarmCooldownMS)
}
if cfg.Gateway.OpenAIWS.ClientReadLimitBytes != 64*1024*1024 {
t.Fatalf("Gateway.OpenAIWS.ClientReadLimitBytes = %d, want %d", cfg.Gateway.OpenAIWS.ClientReadLimitBytes, 64*1024*1024)
}
if !cfg.Gateway.OpenAIWS.HTTPBridgeEnabled {
t.Fatalf("Gateway.OpenAIWS.HTTPBridgeEnabled = false, want true")
}
if cfg.Gateway.OpenAIWS.HTTPBridgeThresholdBytes != 15*1024*1024 {
t.Fatalf("Gateway.OpenAIWS.HTTPBridgeThresholdBytes = %d, want %d", cfg.Gateway.OpenAIWS.HTTPBridgeThresholdBytes, 15*1024*1024)
}
if cfg.Gateway.OpenAIWS.RetryBackoffInitialMS != 120 {
t.Fatalf("Gateway.OpenAIWS.RetryBackoffInitialMS = %d, want 120", cfg.Gateway.OpenAIWS.RetryBackoffInitialMS)
}
Expand Down
2 changes: 1 addition & 1 deletion backend/internal/handler/openai_gateway_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -1167,7 +1167,7 @@ func (h *OpenAIGatewayHandler) ResponsesWebSocket(c *gin.Context) {
defer func() {
_ = wsConn.CloseNow()
}()
wsConn.SetReadLimit(16 * 1024 * 1024)
wsConn.SetReadLimit(service.ResolveOpenAIWSClientReadLimitBytes(h.cfg))

ctx := c.Request.Context()
readCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
Expand Down
3 changes: 3 additions & 0 deletions backend/internal/service/openai_gateway_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,9 @@ type OpenAIForwardResult struct {
ImageOutputSizes []string
ImageSizeSource string
ImageSizeBreakdown map[string]int

wsReplayInput []json.RawMessage
wsReplayInputExists bool
}

type OpenAIWSRetryMetricsSnapshot struct {
Expand Down
Loading
Loading