package gateway import ( "encoding/json" "io" "net/http" "strings" "llmsproxy/internal/config" ) type adapterPayload struct { Name string `json:"name"` Code string `json:"code"` } func (g *Gateway) handleAdaptersAPI(w http.ResponseWriter, r *http.Request) { path := strings.TrimPrefix(r.URL.Path, "/api/adapters") path = strings.Trim(path, "/") switch r.Method { case http.MethodGet: if path == "" { writeJSON(w, http.StatusOK, map[string]interface{}{"adapters": g.core.ListAdapters()}) return } writeError(w, http.StatusNotFound, "not_found", "adapter code not exposed; edit in UI") case http.MethodPost: var p adapterPayload if err := json.NewDecoder(r.Body).Decode(&p); err != nil { writeError(w, http.StatusBadRequest, "invalid_request", "invalid json: "+err.Error()) return } if err := g.core.UploadAdapter(p.Name, p.Code); err != nil { writeError(w, http.StatusBadRequest, "adapter_error", err.Error()) return } writeJSON(w, http.StatusOK, map[string]interface{}{"ok": true, "name": p.Name}) case http.MethodDelete: if path == "" { writeError(w, http.StatusBadRequest, "invalid_request", "adapter name required") return } if err := g.core.RemoveAdapter(path); err != nil { writeError(w, http.StatusBadRequest, "adapter_error", err.Error()) return } writeJSON(w, http.StatusOK, map[string]interface{}{"ok": true}) default: writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "") } } // sourcePayload mirrors config.Source for JSON web UI editing. type sourcePayload struct { Name string `json:"name"` BaseURL string `json:"base_url"` APIKey string `json:"api_key"` Adapter string `json:"adapter"` Endpoint string `json:"endpoint"` ImageEndpoint string `json:"image_endpoint"` Models []config.Model `json:"models"` Headers map[string]string `json:"headers"` Meta map[string]interface{} `json:"meta"` Temperature float64 `json:"temperature"` MaxTokens int `json:"max_tokens"` MaxConcurrent int `json:"max_concurrent"` } func (g *Gateway) handleSourcesAPI(w http.ResponseWriter, r *http.Request) { path := strings.TrimPrefix(r.URL.Path, "/api/sources") path = strings.Trim(path, "/") switch r.Method { case http.MethodGet: writeJSON(w, http.StatusOK, map[string]interface{}{"sources": g.core.Sources()}) case http.MethodPost: var p sourcePayload body, _ := io.ReadAll(r.Body) if err := json.Unmarshal(body, &p); err != nil { writeError(w, http.StatusBadRequest, "invalid_request", "invalid json: "+err.Error()) return } src := config.Source{ Name: p.Name, BaseURL: p.BaseURL, APIKey: p.APIKey, Adapter: p.Adapter, Endpoint: p.Endpoint, ImageEndpoint: p.ImageEndpoint, Models: p.Models, Headers: p.Headers, Meta: p.Meta, Temperature: p.Temperature, MaxTokens: p.MaxTokens, MaxConcurrent: p.MaxConcurrent, } if err := g.core.AddSource(src); err != nil { writeError(w, http.StatusBadRequest, "source_error", err.Error()) return } writeJSON(w, http.StatusOK, map[string]interface{}{"ok": true}) case http.MethodDelete: if path == "" { writeError(w, http.StatusBadRequest, "invalid_request", "source name required") return } if err := g.core.RemoveSource(path); err != nil { writeError(w, http.StatusBadRequest, "source_error", err.Error()) return } writeJSON(w, http.StatusOK, map[string]interface{}{"ok": true}) default: writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "") } }