98 lines
2.1 KiB
Go
98 lines
2.1 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// OpenClaw HTTP API client — uses the OpenAI-compatible /v1/chat/completions endpoint
|
|
|
|
type GatewayConfig struct {
|
|
URL string // http://host:port
|
|
Token string
|
|
}
|
|
|
|
type GatewayPool struct {
|
|
mu sync.Mutex
|
|
gateways map[string]*GatewayConfig
|
|
client *http.Client
|
|
}
|
|
|
|
func NewGatewayPool() *GatewayPool {
|
|
return &GatewayPool{
|
|
gateways: make(map[string]*GatewayConfig),
|
|
client: &http.Client{Timeout: 120 * time.Second},
|
|
}
|
|
}
|
|
|
|
func (gp *GatewayPool) Register(host string, cfg *GatewayConfig) {
|
|
gp.mu.Lock()
|
|
defer gp.mu.Unlock()
|
|
gp.gateways[host] = cfg
|
|
}
|
|
|
|
func (gp *GatewayPool) Get(host string) *GatewayConfig {
|
|
gp.mu.Lock()
|
|
defer gp.mu.Unlock()
|
|
return gp.gateways[host]
|
|
}
|
|
|
|
func (gp *GatewayPool) CallAgent(host, agentID, message, session string) (string, error) {
|
|
cfg := gp.Get(host)
|
|
if cfg == nil {
|
|
return "", fmt.Errorf("no gateway configured for host %s", host)
|
|
}
|
|
|
|
body, _ := json.Marshal(map[string]any{
|
|
"model": "openclaw:" + agentID,
|
|
"user": session,
|
|
"messages": []map[string]string{
|
|
{"role": "user", "content": message},
|
|
},
|
|
})
|
|
|
|
req, err := http.NewRequest("POST", cfg.URL+"/v1/chat/completions", bytes.NewReader(body))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+cfg.Token)
|
|
|
|
resp, err := gp.client.Do(req)
|
|
if err != nil {
|
|
return "", fmt.Errorf("http: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
data, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return "", fmt.Errorf("read body: %w", err)
|
|
}
|
|
|
|
if resp.StatusCode != 200 {
|
|
return "", fmt.Errorf("http %d: %s", resp.StatusCode, string(data))
|
|
}
|
|
|
|
var result struct {
|
|
Choices []struct {
|
|
Message struct {
|
|
Content string `json:"content"`
|
|
} `json:"message"`
|
|
} `json:"choices"`
|
|
}
|
|
if err := json.Unmarshal(data, &result); err != nil {
|
|
return "", fmt.Errorf("parse: %w", err)
|
|
}
|
|
|
|
if len(result.Choices) == 0 || result.Choices[0].Message.Content == "" {
|
|
return "[completed, no text reply]", nil
|
|
}
|
|
|
|
return result.Choices[0].Message.Content, nil
|
|
}
|