mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-08-01 01:26:19 +00:00
a36472b55f
* feat(model): add `picoclaw model add` for custom OpenAI-compatible endpoints Onboards a model from a user-supplied API base + key by hitting GET <base>/models, prompting the user to pick one, and writing the entry into model_list[] (with api_keys) plus setting it as the default model. This was previously only available in the TUI launcher (issue #2208) and is now accessible from the CLI: picoclaw model add -b URL -k KEY [-m MODEL] [-n ALIAS] * chore: remove deprecated picoclaw-launcher-tui Per RFC #2208, the TUI launcher is deprecated in favor of the CLI; its "online model picker" feature has been ported to `picoclaw model add` in the previous commit. This drops the binary and all build/release/docs references: - delete cmd/picoclaw-launcher-tui/ and assets/launcher-tui.jpg - Makefile: remove the `build-launcher-tui` target - .goreleaser.yaml: drop the build entry plus the `picoclaw-launcher-tui` ids from the launcher docker image, macOS notarize list, and nfpms contents - docker/Dockerfile.goreleaser.launcher: drop the COPY for the TUI binary - READMEs (root + 8 locales): remove the "TUI Launcher" section and screenshot link - docs/guides/docker.*: update the "launcher image includes …" sentence to reflect the two remaining binaries `make build` still succeeds; `go build ./web/backend` (the launcher target) still succeeds. `picoclaw-launcher` (web console) is unaffected.
140 lines
3.7 KiB
Go
140 lines
3.7 KiB
Go
package model
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/sipeed/picoclaw/cmd/picoclaw/internal"
|
|
"github.com/sipeed/picoclaw/pkg/config"
|
|
)
|
|
|
|
// LocalModel is a special model name that indicates that the model is local and with or without api_key.
|
|
const LocalModel = "local-model"
|
|
|
|
func NewModelCommand() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "model [model_name]",
|
|
Short: "Show or change the default model",
|
|
Long: `Show or change the default model configuration.
|
|
|
|
If no argument is provided, shows the current default model.
|
|
If a model name is provided, sets it as the default model.
|
|
|
|
To onboard a model from a custom OpenAI-compatible endpoint (fetch the
|
|
available list online and pick one), use the 'add' subcommand:
|
|
|
|
picoclaw model add --help
|
|
|
|
Examples:
|
|
picoclaw model # Show current default model
|
|
picoclaw model gpt-5.2 # Set gpt-5.2 as default
|
|
picoclaw model claude-sonnet-4.6 # Set claude-sonnet-4.6 as default
|
|
picoclaw model local-model # Set local VLLM server as default
|
|
picoclaw model add -b URL -k KEY # Add a model from a custom endpoint
|
|
|
|
Note: 'local-model' is a special value for using a local VLLM server
|
|
(running at localhost:8000 by default) which does not require an API key.`,
|
|
Args: cobra.MaximumNArgs(1),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
configPath := internal.GetConfigPath()
|
|
|
|
// Load current config
|
|
cfg, err := config.LoadConfig(configPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to load config: %w", err)
|
|
}
|
|
|
|
if len(args) == 0 {
|
|
// Show current default model
|
|
showCurrentModel(cfg)
|
|
return nil
|
|
}
|
|
|
|
// Set new default model
|
|
modelName := args[0]
|
|
return setDefaultModel(configPath, cfg, modelName)
|
|
},
|
|
}
|
|
|
|
cmd.AddCommand(newAddCommand())
|
|
|
|
return cmd
|
|
}
|
|
|
|
func showCurrentModel(cfg *config.Config) {
|
|
defaultModel := cfg.Agents.Defaults.ModelName
|
|
|
|
if defaultModel == "" {
|
|
fmt.Println("No default model is currently set.")
|
|
fmt.Println("\nAvailable models in your config:")
|
|
listAvailableModels(cfg)
|
|
} else {
|
|
fmt.Printf("Current default model: %s\n", defaultModel)
|
|
fmt.Println("\nAvailable models in your config:")
|
|
listAvailableModels(cfg)
|
|
}
|
|
|
|
fmt.Println("\nTip: 'picoclaw model add -b URL -k KEY' adds a model from a custom")
|
|
fmt.Println(" OpenAI-compatible endpoint (see 'picoclaw model add --help').")
|
|
}
|
|
|
|
func listAvailableModels(cfg *config.Config) {
|
|
if len(cfg.ModelList) == 0 {
|
|
fmt.Println(" No models configured in model_list")
|
|
return
|
|
}
|
|
|
|
defaultModel := cfg.Agents.Defaults.ModelName
|
|
|
|
for _, model := range cfg.ModelList {
|
|
marker := " "
|
|
if model.ModelName == defaultModel {
|
|
marker = "> "
|
|
}
|
|
if !model.Enabled {
|
|
continue
|
|
}
|
|
fmt.Printf("%s- %s (%s)\n", marker, model.ModelName, model.Model)
|
|
}
|
|
}
|
|
|
|
func setDefaultModel(configPath string, cfg *config.Config, modelName string) error {
|
|
// Validate that the model exists in model_list
|
|
modelFound := false
|
|
for _, model := range cfg.ModelList {
|
|
if model.Enabled && model.ModelName == modelName {
|
|
modelFound = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !modelFound && modelName != LocalModel {
|
|
return fmt.Errorf("cannot found model '%s' in config", modelName)
|
|
}
|
|
|
|
// Update the default model
|
|
// Clear old model field and set new model_name
|
|
oldModel := cfg.Agents.Defaults.ModelName
|
|
|
|
cfg.Agents.Defaults.ModelName = modelName
|
|
|
|
// Save config back to file
|
|
if err := config.SaveConfig(configPath, cfg); err != nil {
|
|
return fmt.Errorf("failed to save config: %w", err)
|
|
}
|
|
|
|
fmt.Printf("✓ Default model changed from '%s' to '%s'\n",
|
|
formatModelName(oldModel), modelName)
|
|
fmt.Println("\nThe new default model will be used for all agent interactions.")
|
|
|
|
return nil
|
|
}
|
|
|
|
func formatModelName(name string) string {
|
|
if name == "" {
|
|
return "(none)"
|
|
}
|
|
return name
|
|
}
|