@@ -3,7 +3,6 @@ package models
33import (
44 "cmp"
55 "encoding/json"
6− "log/slog"
76 "net/http"
87 "net/url"
98 "os"
@@ -11,6 +10,7 @@ import (
1110 "strings"
1211 "unicode"
1312
13+ "github.com/opencode-ai/opencode/internal/logging"
1414 "github.com/spf13/viper"
1515)
1616
@@ -25,7 +25,7 @@ func init() {
2525 if endpoint := os.Getenv("LOCAL_ENDPOINT"); endpoint != "" {
2626 localEndpoint, err := url.Parse(endpoint)
2727 if err != nil {
28− slog.Debug("Failed to parse local endpoint",
28+ logging.Debug("Failed to parse local endpoint",
2929 "error", err,
3030 "endpoint", endpoint,
3131 )
@@ -44,7 +44,7 @@ func init() {
4444 }
4545
4646 if len(models) == 0 {
47− slog.Debug("No local models found",
47+ logging.Debug("No local models found",
4848 "endpoint", endpoint,
4949 )
5050 return
@@ -77,7 +77,7 @@ type localModel struct {
7777func listLocalModels(modelsEndpoint string) []localModel {
7878 res, err := http.Get(modelsEndpoint)
7979 if err != nil {
80− slog.Debug("Failed to list local models",
80+ logging.Debug("Failed to list local models",
8181 "error", err,
8282 "endpoint", modelsEndpoint,
8383 )
@@ -85,7 +85,7 @@ func listLocalModels(modelsEndpoint string) []localModel {
8585 defer res.Body.Close()
8686
8787 if res.StatusCode != http.StatusOK {
88− slog.Debug("Failed to list local models",
88+ logging.Debug("Failed to list local models",
8989 "status", res.StatusCode,
9090 "endpoint", modelsEndpoint,
9191 )
@@ -93,7 +93,7 @@ func listLocalModels(modelsEndpoint string) []localModel {
9393
9494 var modelList localModelList
9595 if err = json.NewDecoder(res.Body).Decode(&modelList); err != nil {
96− slog.Debug("Failed to list local models",
96+ logging.Debug("Failed to list local models",
9797 "error", err,
9898 "endpoint", modelsEndpoint,
9999 )
@@ -103,7 +103,7 @@ func listLocalModels(modelsEndpoint string) []localModel {
103103 for _, model := range modelList.Data {
104104 if strings.HasSuffix(modelsEndpoint, lmStudioBetaModelsPath) {
105105 if model.Object != "model" || model.Type != "llm" {
106− slog.Debug("Skipping unsupported LMStudio model",
106+ logging.Debug("Skipping unsupported LMStudio model",
107107 "endpoint", modelsEndpoint,
108108 "id", model.ID,
109109 "object", model.Object,
@@ -125,7 +125,7 @@ func loadLocalModels(models []localModel) {
125125 model := convertLocalModel(m)
126126 SupportedModels[model.ID] = model
127127
128− if i == 1 || m.State == "loaded" {
128+ if i == 0 || m.State == "loaded" {
129129 viper.SetDefault("agents.coder.model", model.ID)
130130 viper.SetDefault("agents.summarizer.model", model.ID)
131131 viper.SetDefault("agents.task.model", model.ID)
@@ -150,7 +150,19 @@ func convertLocalModel(model localModel) Model {
150150var modelInfoRegex = regexp.MustCompile(`(?i)^([a-z0-9]+)(?:[-_]?([rv]?\d[\.\d]*))?(?:[-_]?([a-z]+))?.*`)
151151
152152func friendlyModelName(modelID string) string {
153− match := modelInfoRegex.FindStringSubmatch(modelID)
153+ mainID := modelID
154+ tag := ""
155+
156+ if slash := strings.LastIndex(mainID, "/"); slash != -1 {
157+ mainID = mainID[slash+1:]
158+ }
159+
160+ if at := strings.Index(modelID, "@"); at != -1 {
161+ mainID = modelID[:at]
162+ tag = modelID[at+1:]
163+ }
164+
165+ match := modelInfoRegex.FindStringSubmatch(mainID)
154166 if match == nil {
155167 return modelID
156168 }
@@ -186,6 +198,9 @@ func friendlyModelName(modelID string) string {
186198 if label != "" {
187199 parts = append(parts, label)
188200 }
201+ if tag != "" {
202+ parts = append(parts, tag)
203+ }
189204
190205 return strings.Join(parts, " ")
191206}