fetch_models_for_opencode.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package main
  2. import (
  3. "encoding/json"
  4. "flag"
  5. "fmt"
  6. "io"
  7. "log"
  8. "net/http"
  9. "os"
  10. "strings"
  11. )
  12. type ModelsResponse struct {
  13. Object string `json:"object"`
  14. Data []Model `json:"data"`
  15. }
  16. type Model struct {
  17. ID string `json:"id"`
  18. Object string `json:"object"`
  19. Created int64 `json:"created,omitempty"`
  20. OwnedBy string `json:"owned_by,omitempty"`
  21. Metadata map[string]interface{} `json:"metadata,omitempty"`
  22. }
  23. type Limit struct {
  24. Context int `json:"context"`
  25. Output int `json:"output"`
  26. }
  27. type OpencodeModel struct {
  28. Name string `json:"name"`
  29. Limit Limit `json:"limit"`
  30. }
  31. type DynamicProvider struct {
  32. Npm string `json:"npm"`
  33. Name string `json:"name"`
  34. Options map[string]string `json:"options"`
  35. Models map[string]OpencodeModel `json:"models"`
  36. }
  37. type OpencodeConfig struct {
  38. Schema string `json:"$schema"`
  39. Provider map[string]DynamicProvider `json:"provider"`
  40. }
  41. func getIntFromMetadata(md map[string]interface{}, key string, defaultVal int) int {
  42. if md == nil {
  43. return defaultVal
  44. }
  45. if v, ok := md[key]; ok {
  46. if i, ok := v.(float64); ok {
  47. return int(i)
  48. }
  49. }
  50. return defaultVal
  51. }
  52. func main() {
  53. var providerName, baseURL, apiURL, outputFile string
  54. flag.StringVar(&providerName, "provider", "Myprovider", "Name of the provider (default: Myprovider)")
  55. flag.StringVar(&baseURL, "baseurl", "", "Base URL for the provider (required, e.g., http://localhost:8080/v1)")
  56. flag.StringVar(&apiURL, "apiurl", "", "API URL to fetch models from (default: <baseurl>/models)")
  57. flag.StringVar(&outputFile, "output", "opencode.jsonc", "Output file name (default: opencode.jsonc)")
  58. flag.Usage = func() {
  59. fmt.Fprintf(os.Stderr, "Usage: %s [options]\n\n", os.Args[0])
  60. fmt.Fprintf(os.Stderr, "Example:\n")
  61. fmt.Fprintf(os.Stderr, " %s --provider Myprovider --baseurl http://localhost:8080/v1\n\n", os.Args[0])
  62. flag.PrintDefaults()
  63. }
  64. flag.Parse()
  65. if baseURL == "" {
  66. log.Fatal("--baseurl is required")
  67. }
  68. if apiURL == "" {
  69. apiURL = strings.TrimSuffix(baseURL, "/") + "/models"
  70. }
  71. if baseURL == "" || apiURL == "" {
  72. log.Fatal("Both --baseurl and --apiurl are required")
  73. }
  74. resp, err := http.Get(apiURL)
  75. if err != nil {
  76. log.Fatalf("Failed to fetch %s: %v", apiURL, err)
  77. }
  78. defer resp.Body.Close()
  79. if resp.StatusCode != http.StatusOK {
  80. log.Fatalf("Unexpected status code: %d", resp.StatusCode)
  81. }
  82. body, err := io.ReadAll(resp.Body)
  83. if err != nil {
  84. log.Fatalf("Failed to read response: %v", err)
  85. }
  86. var modelsResp ModelsResponse
  87. if err := json.Unmarshal(body, &modelsResp); err != nil {
  88. log.Fatalf("Failed to parse models response: %v", err)
  89. }
  90. config := OpencodeConfig{
  91. Schema: "https://opencode.ai/config.json",
  92. Provider: map[string]DynamicProvider{
  93. providerName: {
  94. Npm: "@ai-sdk/openai-compatible",
  95. Name: providerName,
  96. Options: map[string]string{
  97. "baseURL": baseURL,
  98. "apiKey": "noneneeded",
  99. },
  100. Models: make(map[string]OpencodeModel),
  101. },
  102. },
  103. }
  104. for _, m := range modelsResp.Data {
  105. ctx := getIntFromMetadata(m.Metadata, "context_window", 131072)
  106. out := getIntFromMetadata(m.Metadata, "max_output_tokens", 8192)
  107. config.Provider[providerName].Models[m.ID] = OpencodeModel{
  108. Name: m.ID,
  109. Limit: Limit{
  110. Context: ctx,
  111. Output: out,
  112. },
  113. }
  114. }
  115. out, err := json.MarshalIndent(config, "", " ")
  116. if err != nil {
  117. log.Fatalf("Failed to marshal config: %v", err)
  118. }
  119. if err := os.WriteFile(outputFile, out, 0644); err != nil {
  120. log.Fatalf("Failed to write %s: %v", outputFile, err)
  121. }
  122. fmt.Printf("Successfully wrote %s with %d models for provider %s\n", outputFile, len(config.Provider[providerName].Models), providerName)
  123. }