opencode-provider-switch/internal/opencode/provider_models.go

66 lines
1.6 KiB
Go

package opencode
import (
"encoding/json"
"fmt"
"net/http"
"sort"
"strings"
"time"
)
type ModelListResponse struct {
Data []struct {
ID string `json:"id"`
} `json:"data"`
}
func FetchProviderModels(baseURL, apiKey string, headers map[string]string) ([]string, error) {
url := strings.TrimRight(strings.TrimSpace(baseURL), "/") + "/models"
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, fmt.Errorf("build request: %w", err)
}
if apiKey != "" {
req.Header.Set("Authorization", "Bearer "+apiKey)
}
for key, value := range headers {
key = strings.TrimSpace(key)
if key == "" {
continue
}
req.Header.Set(key, value)
}
client := &http.Client{Timeout: 20 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("request %s: %w", url, err)
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
var body struct {
Error any `json:"error"`
}
if err := json.NewDecoder(resp.Body).Decode(&body); err == nil && body.Error != nil {
return nil, fmt.Errorf("request %s: unexpected status %s: %v", url, resp.Status, body.Error)
}
return nil, fmt.Errorf("request %s: unexpected status %s", url, resp.Status)
}
var payload ModelListResponse
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
return nil, fmt.Errorf("decode %s: %w", url, err)
}
models := make([]string, 0, len(payload.Data))
seen := map[string]bool{}
for _, item := range payload.Data {
id := strings.TrimSpace(item.ID)
if id == "" || seen[id] {
continue
}
seen[id] = true
models = append(models, id)
}
sort.Strings(models)
return models, nil
}