Selaa lähdekoodia

Add README, go.mod and gofmt cleanup

Paul Klumpp 1 viikko sitten
vanhempi
commit
a814a06648
4 muutettua tiedostoa jossa 194 lisäystä ja 0 poistoa
  1. 3 0
      .gitignore
  2. 40 0
      README.md
  3. 148 0
      fetch_models_for_opencode.go
  4. 3 0
      go.mod

+ 3 - 0
.gitignore

@@ -24,3 +24,6 @@ _testmain.go
 *.test
 *.prof
 
+# Compiled binary
+fetch_models_for_opencode
+

+ 40 - 0
README.md

@@ -1,2 +1,42 @@
 # fetch_models_for_opencode
 
+A small Go tool that fetches the model list from an OpenAI-compatible endpoint
+(`GET <baseurl>/models`) and generates an `opencode.jsonc` config file for
+[OpenCode](https://opencode.ai).
+
+OpenCode only allows adding models manually via `opencode.jsonc` – there is no
+way to import them automatically. This is tedious when your provider offers many
+models.
+
+**Example:** I run this tool against [OmniRoute](https://omniroute.online), a
+local AI gateway that exposes hundreds of models and combo models through a
+single OpenAI-compatible endpoint – exactly the models I want to use in OpenCode.
+Instead of writing every entry by hand, this tool generates the complete provider
+config in one go.
+
+## How it works
+
+- Fetches `/models` from the given base URL
+- Creates a provider entry (`@ai-sdk/openai-compatible`) with all models
+- Context/output limits are read from model metadata (fallbacks: 131072 / 8192)
+
+## Usage
+
+```
+go run . --provider Myprovider --baseurl http://localhost:8080/v1
+```
+
+## Flags
+
+| Flag        | Default            | Description                                 |
+|-------------|--------------------|---------------------------------------------|
+| `-provider` | `Myprovider`       | Provider name                               |
+| `-baseurl`  | – (required)       | Base URL, e.g. `http://localhost:8080/v1`   |
+| `-apiurl`   | `<baseurl>/models` | Alternative URL for fetching the model list |
+| `-output`   | `opencode.jsonc`   | Output file                                 |
+
+## Build
+
+```
+go build -o fetch_models_for_opencode .
+```

+ 148 - 0
fetch_models_for_opencode.go

@@ -0,0 +1,148 @@
+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: <baseurl>/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)
+}

+ 3 - 0
go.mod

@@ -0,0 +1,3 @@
+module gogs.netdome.biz/paul/fetch_models_for_opencode
+
+go 1.26.6