agentchat/gateway.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
}