@@ -11,7 +11,6 @@ import (
1111 "math/rand"
1212 "net/http"
1313 "os"
14- "os/exec"
1514 "path/filepath"
1615 "regexp"
1716 "sort"
@@ -81,11 +80,7 @@ type ConversationFile struct {
8180}
8281
8382func tput (name string ) string {
84- out , err := exec .Command ("tput" , name ).Output ()
85- if err != nil {
86- return ""
87- }
88- return string (out )
83+ return ""
8984}
9085
9186var (
9691 red = tput ("setaf 1" )
9792)
9893
94+ func printInteractiveHelp () {
95+ var builder strings.Builder
96+ builder .WriteString (fmt .Sprintf ("%sInteractive Commands:%s\n " , bold , normal ))
97+ builder .WriteString (" /help Show this help message.\n " )
98+ builder .WriteString (" /exit, /quit Exit the program.\n " )
99+ builder .WriteString (" /history Print full conversation JSON.\n " )
100+ builder .WriteString (" /clear Clear conversation messages.\n " )
101+ builder .WriteString (" /save <file> Save conversation to a new file.\n " )
102+ builder .WriteString (" /list List supported models.\n " )
103+ builder .WriteString (" /model <model_name> Switch model for the session.\n " )
104+ builder .WriteString (" /modelinfo [name] List settings for a model (defaults to current).\n " )
105+ builder .WriteString (" /askfor_model_setting Interactively set model parameters.\n " )
106+ builder .WriteString (" /persist-settings Save the current session's settings to the conversation file.\n " )
107+ builder .WriteString (" /persist-system <file>\n Persist a system prompt from a file.\n " )
108+ builder .WriteString (" /exportlast [-t] <file>\n Export last AI response to a markdown file (-t filters thinking).\n " )
109+ builder .WriteString (" /exportlastn [-t] <n> <file>\n Export last n AI responses.\n " )
110+ builder .WriteString (" /exportn [-t] <n> <file>\n Export the Nth-to-last AI response.\n " )
111+ builder .WriteString (" /randomodel Switch to a random supported model.\n \n " )
112+ builder .WriteString ("For any model setting, you can use `/setting_name <value>` or `/setting_name unset`.\n " )
113+ builder .WriteString ("For example: `/temperature 0.8`, `/stop unset`\n \n " )
114+ fmt .Print (builder .String ())
115+ }
116+
99117func printHelp (cfg map [string ]string ) {
100118 var builder strings.Builder
101119
@@ -1269,7 +1287,7 @@ func main() {
12691287 }
12701288
12711289 // Interactive banner
1272- fmt .Fprintln (os .Stderr )
1290+ fmt .Fprint (os .Stderr , " \n " )
12731291 fmt .Fprintln (os .Stderr , `AI models generate responses and outputs based on complex algorithms and
12741292machine learning techniques, and those responses or outputs may be
12751293inaccurate, harmful, biased or indecent. By testing this model, you assume
@@ -1665,7 +1683,7 @@ func handleInteractiveInput(userInput, convFile string, cfg map[string]string) b
16651683 // --- Static commands ---
16661684 switch commandName {
16671685 case "exit" , "quit" :
1668- fmt .Fprintln (os .Stderr , "Bye." )
1686+ fmt .Fprint (os .Stderr , "Bye.\n " )
16691687 os .Exit (0 )
16701688 return true
16711689 case "history" :
@@ -1760,8 +1778,14 @@ func handleInteractiveInput(userInput, convFile string, cfg map[string]string) b
17601778 cfg ["MODEL" ] = newModel
17611779 fmt .Fprintf (os .Stderr , "%sSwitched model to %s%s\n " , green , newModel , normal )
17621780 return true
1781+ case "list" :
1782+ fmt .Fprintf (os .Stderr , "%sSupported models:%s\n " , bold , normal )
1783+ for _ , m := range modelsList {
1784+ fmt .Fprintf (os .Stderr , " %s\n " , m )
1785+ }
1786+ return true
17631787 case "help" :
1764- printHelp ( cfg )
1788+ printInteractiveHelp ( )
17651789 return true
17661790 case "model" :
17671791 if len (parts ) < 2 {
@@ -1787,19 +1811,71 @@ func handleInteractiveInput(userInput, convFile string, cfg map[string]string) b
17871811 fmt .Fprintf (os .Stderr , "%sModel set to %s%s\n " , green , modelName , normal )
17881812 return true
17891813 case "modelinfo" :
1814+ var modelName string
17901815 if len (parts ) < 2 {
1791- fmt .Fprintln (os .Stderr , "Usage: /modelinfo <model_name>" )
1792- return true
1816+ modelName = cfg ["MODEL" ]
1817+ } else {
1818+ modelName = parts [1 ]
17931819 }
1794- modelName := parts [1 ]
1795- modelDef , exists := ModelDefinitions [modelName ]
1796- if ! exists {
1797- fmt .Fprintf (os .Stderr , "%sError: Model '%s' not found.%s\n " , red , modelName , normal )
1820+
1821+ // Validate that the model is known before proceeding
1822+ found := false
1823+ for _ , m := range modelsList {
1824+ if m == modelName {
1825+ found = true
1826+ break
1827+ }
1828+ }
1829+ if ! found {
1830+ fmt .Fprintf (os .Stderr , "%sError: Model '%s' not found in the list of supported models.%s\n " , red , modelName , normal )
17981831 return true
17991832 }
1833+
1834+ modelDef := GetModelDefinition (modelName ) // This will fall back to 'others' if no specific def
18001835 info := getModelInfoString (modelName , modelDef )
18011836 fmt .Fprint (os .Stderr , info )
18021837 return true
1838+
1839+ case "askfor_model_setting" :
1840+ modelDef := GetModelDefinition (cfg ["MODEL" ])
1841+ paramNames := make ([]string , 0 , len (modelDef .Parameters ))
1842+ for name := range modelDef .Parameters {
1843+ paramNames = append (paramNames , name )
1844+ }
1845+ sort .Strings (paramNames )
1846+
1847+ allConfigurableParams := append (paramNames , "stream" , "history_limit" )
1848+
1849+ fmt .Fprintln (os .Stderr , "Interactively configure settings. Press Enter to keep the current value." )
1850+
1851+ for _ , paramName := range allConfigurableParams {
1852+ configKey := strings .ToUpper (paramName )
1853+ currentValue , _ := cfg [configKey ]
1854+
1855+ fmt .Fprintf (os .Stderr , "\n Parameter: %s [current: %s]\n Enter new value: " , paramName , currentValue )
1856+
1857+ newValue , err := readSingleLine (nil , []string {"\n " }, true )
1858+ if err != nil && err != io .EOF {
1859+ fmt .Fprintf (os .Stderr , "%sError reading input: %v%s\n " , red , err , normal )
1860+ break
1861+ }
1862+
1863+ newValue = strings .TrimSpace (newValue )
1864+ if newValue == "" {
1865+ fmt .Fprintln (os .Stderr , " (value unchanged)" )
1866+ continue
1867+ }
1868+
1869+ if err := validateParameter (paramName , newValue , modelDef ); err != nil {
1870+ fmt .Fprintf (os .Stderr , "%s Error: %v%s\n " , red , err , normal )
1871+ continue
1872+ }
1873+
1874+ cfg [configKey ] = newValue
1875+ fmt .Fprintf (os .Stderr , " %sSet to %s%s\n " , green , newValue , normal )
1876+ }
1877+ fmt .Fprintf (os .Stderr , "\n %sFinished updating settings.%s\n " , green , normal )
1878+ return true
18031879 }
18041880
18051881 // --- Dynamic parameter setting commands ---
0 commit comments