feat: add model selection synchronization to main config in TUI

This commit is contained in:
taorye
2026-03-20 17:37:04 +08:00
parent 74a145c291
commit 545b7afe41
4 changed files with 99 additions and 0 deletions
@@ -8,6 +8,7 @@ package config
import (
"bytes"
"encoding/json"
"fmt"
"os"
"path/filepath"
@@ -149,6 +150,78 @@ func (p *Provider) UsersForScheme(schemeName string) []User {
return out
}
// SyncSelectedModelToMainConfig syncs the currently selected model to ~/.picoclaw/config.json
// Adds/replaces a "tui-prefer" model entry and sets it as the default model.
// Preserves all other existing fields in the config file unchanged.
func SyncSelectedModelToMainConfig(scheme Scheme, user User, modelID string) error {
home, err := os.UserHomeDir()
if err != nil {
home = "."
}
mainConfigPath := filepath.Join(home, ".picoclaw", "config.json")
var cfg map[string]interface{}
if data, err := os.ReadFile(mainConfigPath); err == nil {
if err := json.Unmarshal(data, &cfg); err != nil {
cfg = make(map[string]interface{})
}
} else {
cfg = make(map[string]interface{})
}
if _, ok := cfg["agents"]; !ok {
cfg["agents"] = make(map[string]interface{})
}
agents, ok := cfg["agents"].(map[string]interface{})
if ok {
if _, ok := agents["defaults"]; !ok {
agents["defaults"] = make(map[string]interface{})
}
defaults, ok := agents["defaults"].(map[string]interface{})
if ok {
defaults["model"] = "tui-prefer"
}
}
tuiModel := map[string]interface{}{
"model_name": "tui-prefer",
"model": modelID,
"api_key": user.Key,
"api_base": scheme.BaseURL,
}
modelList := []interface{}{}
if ml, ok := cfg["model_list"].([]interface{}); ok {
modelList = ml
}
found := false
for i, m := range modelList {
if entry, ok := m.(map[string]interface{}); ok {
if name, ok := entry["model_name"].(string); ok && name == "tui-prefer" {
modelList[i] = tuiModel
found = true
break
}
}
}
if !found {
modelList = append(modelList, tuiModel)
}
cfg["model_list"] = modelList
data, err := json.MarshalIndent(cfg, "", " ")
if err != nil {
return err
}
if err := os.MkdirAll(filepath.Dir(mainConfigPath), 0o700); err != nil {
return err
}
return os.WriteFile(mainConfigPath, data, 0o600)
}
func (cfg *TUIConfig) CurrentModelLabel() string {
cur := cfg.Provider.Current
if cur.Model == "" {
+4
View File
@@ -26,6 +26,10 @@ func main() {
}
app := ui.New(cfg, configPath)
// Bind model selection hook to sync to main config
app.OnModelSelected = func(scheme tuicfg.Scheme, user tuicfg.User, modelID string) {
_ = tuicfg.SyncSelectedModelToMainConfig(scheme, user, modelID)
}
if err := app.Run(); err != nil {
fmt.Fprintf(os.Stderr, "picoclaw-launcher-tui: %v\n", err)
os.Exit(1)
+4
View File
@@ -25,6 +25,10 @@ type App struct {
headerModelTV *tview.TextView
modalOpen map[string]bool
// OnModelSelected is called when a model is selected in the UI.
// Can be nil to disable.
OnModelSelected func(scheme tuicfg.Scheme, user tuicfg.User, modelID string)
modelCache map[string][]modelEntry
modelCacheMu sync.RWMutex
refreshMu sync.Mutex
+18
View File
@@ -116,6 +116,24 @@ func (a *App) newModelsPage(schemeName, userName, baseURL string) tview.Primitiv
Model: modelIDs[row],
}
a.save()
// Trigger model selected callback if set
if a.OnModelSelected != nil && a.cfg.Model.Type == "provider" {
scheme := a.cfg.Provider.SchemeByName(schemeName)
if scheme == nil {
a.goBack()
return
}
var user tuicfg.User
for _, u := range a.cfg.Provider.Users {
if u.Scheme == schemeName && u.Name == userName {
user = u
break
}
}
a.OnModelSelected(*scheme, user, modelIDs[row])
}
a.goBack()
})