package main import ( "encoding/json" "flag" "fmt" "io" "log" "net/http" "os" "strings" ) type ModelsResponse struct { Object string `json:"object"` Data []Model `json:"data"` } type Model struct { ID string `json:"id"` Object string `json:"object"` Created int64 `json:"created,omitempty"` OwnedBy string `json:"owned_by,omitempty"` Metadata map[string]interface{} `json:"metadata,omitempty"` } type Limit struct { Context int `json:"context"` Output int `json:"output"` } type OpencodeModel struct { Name string `json:"name"` Limit Limit `json:"limit"` } type DynamicProvider struct { Npm string `json:"npm"` Name string `json:"name"` Options map[string]string `json:"options"` Models map[string]OpencodeModel `json:"models"` } type OpencodeConfig struct { Schema string `json:"$schema"` Provider map[string]DynamicProvider `json:"provider"` } func getIntFromMetadata(md map[string]interface{}, key string, defaultVal int) int { if md == nil { return defaultVal } if v, ok := md[key]; ok { if i, ok := v.(float64); ok { return int(i) } } return defaultVal } func main() { var providerName, baseURL, apiURL, outputFile string flag.StringVar(&providerName, "provider", "Myprovider", "Name of the provider (default: Myprovider)") flag.StringVar(&baseURL, "baseurl", "", "Base URL for the provider (required, e.g., http://localhost:8080/v1)") flag.StringVar(&apiURL, "apiurl", "", "API URL to fetch models from (default: /models)") flag.StringVar(&outputFile, "output", "opencode.jsonc", "Output file name (default: opencode.jsonc)") flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage: %s [options]\n\n", os.Args[0]) fmt.Fprintf(os.Stderr, "Example:\n") fmt.Fprintf(os.Stderr, " %s --provider Myprovider --baseurl http://localhost:8080/v1\n\n", os.Args[0]) flag.PrintDefaults() } flag.Parse() if baseURL == "" { log.Fatal("--baseurl is required") } if apiURL == "" { apiURL = strings.TrimSuffix(baseURL, "/") + "/models" } if baseURL == "" || apiURL == "" { log.Fatal("Both --baseurl and --apiurl are required") } resp, err := http.Get(apiURL) if err != nil { log.Fatalf("Failed to fetch %s: %v", apiURL, err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { log.Fatalf("Unexpected status code: %d", resp.StatusCode) } body, err := io.ReadAll(resp.Body) if err != nil { log.Fatalf("Failed to read response: %v", err) } var modelsResp ModelsResponse if err := json.Unmarshal(body, &modelsResp); err != nil { log.Fatalf("Failed to parse models response: %v", err) } config := OpencodeConfig{ Schema: "https://opencode.ai/config.json", Provider: map[string]DynamicProvider{ providerName: { Npm: "@ai-sdk/openai-compatible", Name: providerName, Options: map[string]string{ "baseURL": baseURL, "apiKey": "noneneeded", }, Models: make(map[string]OpencodeModel), }, }, } for _, m := range modelsResp.Data { ctx := getIntFromMetadata(m.Metadata, "context_window", 131072) out := getIntFromMetadata(m.Metadata, "max_output_tokens", 8192) config.Provider[providerName].Models[m.ID] = OpencodeModel{ Name: m.ID, Limit: Limit{ Context: ctx, Output: out, }, } } out, err := json.MarshalIndent(config, "", " ") if err != nil { log.Fatalf("Failed to marshal config: %v", err) } if err := os.WriteFile(outputFile, out, 0644); err != nil { log.Fatalf("Failed to write %s: %v", outputFile, err) } fmt.Printf("Successfully wrote %s with %d models for provider %s\n", outputFile, len(config.Provider[providerName].Models), providerName) }