Configure OpenClaw admission from bridge config

This commit is contained in:
Haitao Pan 2026-05-11 13:21:30 +08:00
parent e27995a85b
commit b39c9ec084
6 changed files with 104 additions and 11 deletions

View File

@ -12,6 +12,11 @@ upstream:
gateway_url: "ws://127.0.0.1:18789/"
opencode_url: "ws://127.0.0.1:38992"
openclaw_gateway:
max_active: 2
max_queued: 20
queue_timeout: "10m"
# Legacy/Reference structure (Normally managed via code constants or environment)
bridge:
listenAddr: 127.0.0.1:8787

View File

@ -13,7 +13,7 @@ func (s *Server) Bootstrap() {
s.mu.Lock()
defer s.mu.Unlock()
config, providerCatalog, providerOrder := newProductionProviderCatalog()
config, providerCatalog, providerOrder := newProductionProviderCatalogFromConfig(s.config)
s.config = config
s.providerOrder = providerOrder
@ -40,16 +40,16 @@ func (s *Server) Bootstrap() {
ProviderCatalog: make([]any, 0),
GatewayProviders: []any{
map[string]any{
"providerId": "openclaw",
"label": "OpenClaw",
"targets": []string{"gateway"},
"providerId": "openclaw",
"label": "OpenClaw",
"targets": []string{"gateway"},
"providerDisplay": map[string]any{"logoEmoji": "🦞"},
},
},
AvailableExecutionTargets: []any{"agent", "gateway"},
ProviderProbeSummary: make([]any, 0),
}
for _, id := range providerOrder {
p, ok := providerCatalog[id]
if !ok || !p.Enabled {

View File

@ -24,6 +24,13 @@ type BridgeConfig struct {
GeminiURL string `yaml:"gemini_url"`
HermesURL string `yaml:"hermes_url"`
} `yaml:"upstream"`
OpenClawGateway OpenClawGatewayConfig `yaml:"openclaw_gateway"`
}
type OpenClawGatewayConfig struct {
MaxActive *int `yaml:"max_active"`
MaxQueued *int `yaml:"max_queued"`
QueueTimeout string `yaml:"queue_timeout"`
}
func loadBridgeConfig() *BridgeConfig {
@ -65,7 +72,13 @@ func bridgeSharedAuthToken() string {
}
func newProductionProviderCatalog() (*BridgeConfig, map[string]syncedProvider, []string) {
config := loadBridgeConfig()
return newProductionProviderCatalogFromConfig(loadBridgeConfig())
}
func newProductionProviderCatalogFromConfig(config *BridgeConfig) (*BridgeConfig, map[string]syncedProvider, []string) {
if config == nil {
config = &BridgeConfig{}
}
authorizationHeader := bridgeUpstreamAuthorizationHeader()
providers := []struct {

View File

@ -32,17 +32,24 @@ type openClawGatewayAdmissionGate struct {
queued int
}
func newOpenClawGatewayAdmissionGateFromEnv() *openClawGatewayAdmissionGate {
maxActive := envInt("XWORKMATE_BRIDGE_OPENCLAW_GATEWAY_MAX_ACTIVE", defaultOpenClawGatewayMaxActive)
func newOpenClawGatewayAdmissionGate(config *BridgeConfig) *openClawGatewayAdmissionGate {
admissionConfig := OpenClawGatewayConfig{}
if config != nil {
admissionConfig = config.OpenClawGateway
}
maxActive := admissionInt(admissionConfig.MaxActive, "XWORKMATE_BRIDGE_OPENCLAW_GATEWAY_MAX_ACTIVE", defaultOpenClawGatewayMaxActive)
if maxActive < 1 {
log.Printf("level=warn component=openclaw_gateway event=invalid_admission_config key=%q value=%d", "max_active", maxActive)
maxActive = defaultOpenClawGatewayMaxActive
}
maxQueued := envInt("XWORKMATE_BRIDGE_OPENCLAW_GATEWAY_MAX_QUEUED", defaultOpenClawGatewayMaxQueued)
maxQueued := admissionInt(admissionConfig.MaxQueued, "XWORKMATE_BRIDGE_OPENCLAW_GATEWAY_MAX_QUEUED", defaultOpenClawGatewayMaxQueued)
if maxQueued < 0 {
log.Printf("level=warn component=openclaw_gateway event=invalid_admission_config key=%q value=%d", "max_queued", maxQueued)
maxQueued = defaultOpenClawGatewayMaxQueued
}
timeout := envDuration("XWORKMATE_BRIDGE_OPENCLAW_GATEWAY_QUEUE_TIMEOUT", defaultOpenClawGatewayQueueWait)
timeout := admissionDuration(admissionConfig.QueueTimeout, "queue_timeout", "XWORKMATE_BRIDGE_OPENCLAW_GATEWAY_QUEUE_TIMEOUT", defaultOpenClawGatewayQueueWait)
if timeout <= 0 {
log.Printf("level=warn component=openclaw_gateway event=invalid_admission_config key=%q value=%q", "queue_timeout", timeout.String())
timeout = defaultOpenClawGatewayQueueWait
}
return &openClawGatewayAdmissionGate{
@ -53,6 +60,26 @@ func newOpenClawGatewayAdmissionGateFromEnv() *openClawGatewayAdmissionGate {
}
}
func admissionInt(configValue *int, envKey string, fallback int) int {
if configValue != nil {
return *configValue
}
return envInt(envKey, fallback)
}
func admissionDuration(configValue string, configKey string, envKey string, fallback time.Duration) time.Duration {
raw := strings.TrimSpace(configValue)
if raw == "" {
return envDuration(envKey, fallback)
}
value, err := time.ParseDuration(raw)
if err != nil {
log.Printf("level=warn component=openclaw_gateway event=invalid_duration_config key=%q value=%q", configKey, raw)
return fallback
}
return value
}
func (g *openClawGatewayAdmissionGate) acquire(
ctx context.Context,
notifyQueued func(position int, queued int),

View File

@ -0,0 +1,46 @@
package acp
import (
"testing"
"time"
)
func TestOpenClawGatewayAdmissionGateUsesConfigValues(t *testing.T) {
maxActive := 3
maxQueued := 7
gate := newOpenClawGatewayAdmissionGate(&BridgeConfig{
OpenClawGateway: OpenClawGatewayConfig{
MaxActive: &maxActive,
MaxQueued: &maxQueued,
QueueTimeout: "45s",
},
})
if gate.maxActive != 3 {
t.Fatalf("expected max active from config, got %d", gate.maxActive)
}
if gate.maxQueued != 7 {
t.Fatalf("expected max queued from config, got %d", gate.maxQueued)
}
if gate.timeout != 45*time.Second {
t.Fatalf("expected queue timeout from config, got %s", gate.timeout)
}
}
func TestOpenClawGatewayAdmissionGateFallsBackToEnvWithoutConfig(t *testing.T) {
t.Setenv("XWORKMATE_BRIDGE_OPENCLAW_GATEWAY_MAX_ACTIVE", "4")
t.Setenv("XWORKMATE_BRIDGE_OPENCLAW_GATEWAY_MAX_QUEUED", "0")
t.Setenv("XWORKMATE_BRIDGE_OPENCLAW_GATEWAY_QUEUE_TIMEOUT", "30s")
gate := newOpenClawGatewayAdmissionGate(&BridgeConfig{})
if gate.maxActive != 4 {
t.Fatalf("expected max active from env, got %d", gate.maxActive)
}
if gate.maxQueued != 0 {
t.Fatalf("expected max queued from env, got %d", gate.maxQueued)
}
if gate.timeout != 30*time.Second {
t.Fatalf("expected queue timeout from env, got %s", gate.timeout)
}
}

View File

@ -42,11 +42,13 @@ func newHTTPServer(addr string, handler http.Handler) *http.Server {
}
func NewServer() *Server {
config := loadBridgeConfig()
s := &Server{
sessions: make(map[string]*session),
config: config,
allowedOrigins: shared.ParseAllowedOrigins(shared.EnvOrDefault("ACP_ALLOWED_ORIGINS", "https://xworkmate.svc.plus,http://localhost:*,http://127.0.0.1:*")),
authService: service.NewStaticTokenAuthService(shared.EnvOrDefault("BRIDGE_AUTH_TOKEN", "")),
openClawGate: newOpenClawGatewayAdmissionGateFromEnv(),
openClawGate: newOpenClawGatewayAdmissionGate(config),
}
s.Bootstrap()
return s