From c731c760f59a0b2b40d3e7883f9af09ded6a80cb Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 10:48:47 +0000 Subject: [PATCH] feat: Enhance interactive commands and disable color output This commit introduces several improvements to the interactive mode of the chat application and removes terminal color output. The following changes have been made: - **Disable Color Output:** The `tput` function has been modified to return an empty string, effectively removing all ANSI color and style sequences from the terminal output. - **New `/list` Command:** An interactive command `/list` has been added to display the list of supported models. - **Improved `/modelinfo` Command:** The `/modelinfo` command now defaults to showing information for the currently active model if no model name is specified. - **New `/askfor_model_setting` Command:** A new command, `/askfor_model_setting`, has been implemented to allow users to interactively configure the settings for the current model one by one. - **Refined `/help` Command:** The `/help` command in interactive mode now displays a concise list of only the interactive commands, making it more user-friendly. The full help message is still available via the `--help` flag. --- main.go | 106 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 91 insertions(+), 15 deletions(-) diff --git a/main.go b/main.go index c81def3..d5d13b3 100644 --- a/main.go +++ b/main.go @@ -11,7 +11,6 @@ import ( "math/rand" "net/http" "os" - "os/exec" "path/filepath" "regexp" "sort" @@ -81,11 +80,7 @@ type ConversationFile struct { } func tput(name string) string { - out, err := exec.Command("tput", name).Output() - if err != nil { - return "" - } - return string(out) + return "" } var ( @@ -96,6 +91,29 @@ var ( red = tput("setaf 1") ) +func printInteractiveHelp() { + var builder strings.Builder + builder.WriteString(fmt.Sprintf("%sInteractive Commands:%s\n", bold, normal)) + builder.WriteString(" /help Show this help message.\n") + builder.WriteString(" /exit, /quit Exit the program.\n") + builder.WriteString(" /history Print full conversation JSON.\n") + builder.WriteString(" /clear Clear conversation messages.\n") + builder.WriteString(" /save Save conversation to a new file.\n") + builder.WriteString(" /list List supported models.\n") + builder.WriteString(" /model Switch model for the session.\n") + builder.WriteString(" /modelinfo [name] List settings for a model (defaults to current).\n") + builder.WriteString(" /askfor_model_setting Interactively set model parameters.\n") + builder.WriteString(" /persist-settings Save the current session's settings to the conversation file.\n") + builder.WriteString(" /persist-system \n Persist a system prompt from a file.\n") + builder.WriteString(" /exportlast [-t] \n Export last AI response to a markdown file (-t filters thinking).\n") + builder.WriteString(" /exportlastn [-t] \n Export last n AI responses.\n") + builder.WriteString(" /exportn [-t] \n Export the Nth-to-last AI response.\n") + builder.WriteString(" /randomodel Switch to a random supported model.\n\n") + builder.WriteString("For any model setting, you can use `/setting_name ` or `/setting_name unset`.\n") + builder.WriteString("For example: `/temperature 0.8`, `/stop unset`\n\n") + fmt.Print(builder.String()) +} + func printHelp(cfg map[string]string) { var builder strings.Builder @@ -1269,7 +1287,7 @@ func main() { } // Interactive banner - fmt.Fprintln(os.Stderr) + fmt.Fprint(os.Stderr, "\n") fmt.Fprintln(os.Stderr, `AI models generate responses and outputs based on complex algorithms and machine learning techniques, and those responses or outputs may be inaccurate, harmful, biased or indecent. By testing this model, you assume @@ -1665,7 +1683,7 @@ func handleInteractiveInput(userInput, convFile string, cfg map[string]string) b // --- Static commands --- switch commandName { case "exit", "quit": - fmt.Fprintln(os.Stderr, "Bye.") + fmt.Fprint(os.Stderr, "Bye.\n") os.Exit(0) return true case "history": @@ -1760,8 +1778,14 @@ func handleInteractiveInput(userInput, convFile string, cfg map[string]string) b cfg["MODEL"] = newModel fmt.Fprintf(os.Stderr, "%sSwitched model to %s%s\n", green, newModel, normal) return true + case "list": + fmt.Fprintf(os.Stderr, "%sSupported models:%s\n", bold, normal) + for _, m := range modelsList { + fmt.Fprintf(os.Stderr, " %s\n", m) + } + return true case "help": - printHelp(cfg) + printInteractiveHelp() return true case "model": if len(parts) < 2 { @@ -1787,19 +1811,71 @@ func handleInteractiveInput(userInput, convFile string, cfg map[string]string) b fmt.Fprintf(os.Stderr, "%sModel set to %s%s\n", green, modelName, normal) return true case "modelinfo": + var modelName string if len(parts) < 2 { - fmt.Fprintln(os.Stderr, "Usage: /modelinfo ") - return true + modelName = cfg["MODEL"] + } else { + modelName = parts[1] } - modelName := parts[1] - modelDef, exists := ModelDefinitions[modelName] - if !exists { - fmt.Fprintf(os.Stderr, "%sError: Model '%s' not found.%s\n", red, modelName, normal) + + // Validate that the model is known before proceeding + found := false + for _, m := range modelsList { + if m == modelName { + found = true + break + } + } + if !found { + fmt.Fprintf(os.Stderr, "%sError: Model '%s' not found in the list of supported models.%s\n", red, modelName, normal) return true } + + modelDef := GetModelDefinition(modelName) // This will fall back to 'others' if no specific def info := getModelInfoString(modelName, modelDef) fmt.Fprint(os.Stderr, info) return true + + case "askfor_model_setting": + modelDef := GetModelDefinition(cfg["MODEL"]) + paramNames := make([]string, 0, len(modelDef.Parameters)) + for name := range modelDef.Parameters { + paramNames = append(paramNames, name) + } + sort.Strings(paramNames) + + allConfigurableParams := append(paramNames, "stream", "history_limit") + + fmt.Fprintln(os.Stderr, "Interactively configure settings. Press Enter to keep the current value.") + + for _, paramName := range allConfigurableParams { + configKey := strings.ToUpper(paramName) + currentValue, _ := cfg[configKey] + + fmt.Fprintf(os.Stderr, "\nParameter: %s [current: %s]\nEnter new value: ", paramName, currentValue) + + newValue, err := readSingleLine(nil, []string{"\n"}, true) + if err != nil && err != io.EOF { + fmt.Fprintf(os.Stderr, "%sError reading input: %v%s\n", red, err, normal) + break + } + + newValue = strings.TrimSpace(newValue) + if newValue == "" { + fmt.Fprintln(os.Stderr, " (value unchanged)") + continue + } + + if err := validateParameter(paramName, newValue, modelDef); err != nil { + fmt.Fprintf(os.Stderr, "%s Error: %v%s\n", red, err, normal) + continue + } + + cfg[configKey] = newValue + fmt.Fprintf(os.Stderr, " %sSet to %s%s\n", green, newValue, normal) + } + fmt.Fprintf(os.Stderr, "\n%sFinished updating settings.%s\n", green, normal) + return true } // --- Dynamic parameter setting commands ---