@@ -3,7 +3,6 @@ package models
5 "encoding/json"
5 "encoding/json"
@@ -11,6 +10,7 @@ import (
13+ "github.com/opencode-ai/opencode/internal/logging"
14 "github.com/spf13/viper"
14 "github.com/spf13/viper"
@@ -25,7 +25,7 @@ func init() {
25 if endpoint := os.Getenv("LOCAL_ENDPOINT"); endpoint != "" {
25 if endpoint := os.Getenv("LOCAL_ENDPOINT"); endpoint != "" {
26 localEndpoint, err := url.Parse(endpoint)
26 localEndpoint, err := url.Parse(endpoint)
27 if err != nil {
27 if err != nil {
28− slog.Debug("Failed to parse local endpoint",
28+ logging.Debug("Failed to parse local endpoint",
29 "error", err,
29 "error", err,
30 "endpoint", endpoint,
30 "endpoint", endpoint,
@@ -44,7 +44,7 @@ func init() {
46 if len(models) == 0 {
46 if len(models) == 0 {
47− slog.Debug("No local models found",
47+ logging.Debug("No local models found",
48 "endpoint", endpoint,
48 "endpoint", endpoint,
@@ -77,7 +77,7 @@ type localModel struct {
77func listLocalModels(modelsEndpoint string) []localModel {
77func listLocalModels(modelsEndpoint string) []localModel {
78 res, err := http.Get(modelsEndpoint)
78 res, err := http.Get(modelsEndpoint)
79 if err != nil {
79 if err != nil {
80− slog.Debug("Failed to list local models",
80+ logging.Debug("Failed to list local models",
81 "error", err,
81 "error", err,
82 "endpoint", modelsEndpoint,
82 "endpoint", modelsEndpoint,
@@ -85,7 +85,7 @@ func listLocalModels(modelsEndpoint string) []localModel {
85 defer res.Body.Close()
85 defer res.Body.Close()
87 if res.StatusCode != http.StatusOK {
87 if res.StatusCode != http.StatusOK {
88− slog.Debug("Failed to list local models",
88+ logging.Debug("Failed to list local models",
89 "status", res.StatusCode,
89 "status", res.StatusCode,
90 "endpoint", modelsEndpoint,
90 "endpoint", modelsEndpoint,
@@ -93,7 +93,7 @@ func listLocalModels(modelsEndpoint string) []localModel {
94 var modelList localModelList
94 var modelList localModelList
95 if err = json.NewDecoder(res.Body).Decode(&modelList); err != nil {
95 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",
97 "error", err,
97 "error", err,
98 "endpoint", modelsEndpoint,
98 "endpoint", modelsEndpoint,
@@ -103,7 +103,7 @@ func listLocalModels(modelsEndpoint string) []localModel {
103 for _, model := range modelList.Data {
103 for _, model := range modelList.Data {
104 if strings.HasSuffix(modelsEndpoint, lmStudioBetaModelsPath) {
104 if strings.HasSuffix(modelsEndpoint, lmStudioBetaModelsPath) {
105 if model.Object != "model" || model.Type != "llm" {
105 if model.Object != "model" || model.Type != "llm" {
106− slog.Debug("Skipping unsupported LMStudio model",
106+ logging.Debug("Skipping unsupported LMStudio model",
107 "endpoint", modelsEndpoint,
107 "endpoint", modelsEndpoint,
108 "id", model.ID,
108 "id", model.ID,
109 "object", model.Object,
109 "object", model.Object,
@@ -125,7 +125,7 @@ func loadLocalModels(models []localModel) {
125 model := convertLocalModel(m)
125 model := convertLocalModel(m)
126 SupportedModels[model.ID] = model
126 SupportedModels[model.ID] = model
128− if i == 1 || m.State == "loaded" {
128+ if i == 0 || m.State == "loaded" {
129 viper.SetDefault("agents.coder.model", model.ID)
129 viper.SetDefault("agents.coder.model", model.ID)
130 viper.SetDefault("agents.summarizer.model", model.ID)
130 viper.SetDefault("agents.summarizer.model", model.ID)
131 viper.SetDefault("agents.task.model", model.ID)
131 viper.SetDefault("agents.task.model", model.ID)
@@ -150,7 +150,19 @@ func convertLocalModel(model localModel) Model {
150var modelInfoRegex = regexp.MustCompile(`(?i)^([a-z0-9]+)(?:[-_]?([rv]?\d[\.\d]*))?(?:[-_]?([a-z]+))?.*`)
150var modelInfoRegex = regexp.MustCompile(`(?i)^([a-z0-9]+)(?:[-_]?([rv]?\d[\.\d]*))?(?:[-_]?([a-z]+))?.*`)
152func friendlyModelName(modelID string) string {
152func friendlyModelName(modelID string) string {
156+ if slash := strings.LastIndex(mainID, "/"); slash != -1 {
157+ mainID = mainID[slash+1:]
160+ if at := strings.Index(modelID, "@"); at != -1 {
161+ mainID = modelID[:at]
162+ tag = modelID[at+1:]
153− match := modelInfoRegex.FindStringSubmatch(modelID)
165+ match := modelInfoRegex.FindStringSubmatch(mainID)
154 if match == nil {
166 if match == nil {
155 return modelID
167 return modelID
@@ -186,6 +198,9 @@ func friendlyModelName(modelID string) string {
186 if label != "" {
198 if label != "" {
187 parts = append(parts, label)
199 parts = append(parts, label)
202+ parts = append(parts, tag)
190 return strings.Join(parts, " ")
205 return strings.Join(parts, " ")