From 6eeb9190131469d646f0d0bea2b01d2594988e10 Mon Sep 17 00:00:00 2001 From: Gregory Gauthier Date: Wed, 4 Mar 2026 11:04:08 +0000 Subject: [PATCH] refactor(chat): improve chat command with better UI, prompts, and model handling - Simplify model selection and defaults in config - Enhance system prompt and history management - Update CLI output with colors and exit commands - Remove placeholder tool handling for cleaner agent mode --- cmd/chat.go | 107 +++++++++++++++++++---------------------------- config/config.go | 8 ++-- 2 files changed, 47 insertions(+), 68 deletions(-) diff --git a/cmd/chat.go b/cmd/chat.go index a15fa14..3e84acb 100644 --- a/cmd/chat.go +++ b/cmd/chat.go @@ -9,8 +9,7 @@ import ( "github.com/fatih/color" "github.com/spf13/cobra" "gmgauthier.com/grokkit/config" - _ "gmgauthier.com/grokkit/internal/grok" - "gmgauthier.com/grokkit/internal/logger" + "gmgauthier.com/grokkit/internal/grok" ) var chatCmd = &cobra.Command{ @@ -18,101 +17,83 @@ var chatCmd = &cobra.Command{ Short: "Interactive chat with Grok (use --agent for tool-enabled mode)", Long: `Start a persistent conversation with Grok. -Normal mode: coherent, reasoning-focused chat. -Agent mode (--agent): Grok can call tools (edit, scaffold, testgen, lint, commit, etc.) -with full safety previews and confirmations.`, +Normal mode: coherent, reasoning-focused chat (uses full model). +Agent mode (--agent): Grok can call tools with safety previews (uses fast model).`, Run: runChat, } func init() { - chatCmd.Flags().Bool("agent", false, "Enable agent mode with tool calling (uses fast model)") - chatCmd.Flags().String("model", "", "Override model (normal: grok-4-1, agent: grok-4-1-fast-non-reasoning)") + chatCmd.Flags().Bool("agent", false, "Enable agent mode with tool calling (uses fast non-reasoning model)") + chatCmd.Flags().String("model", "", "Override model") rootCmd.AddCommand(chatCmd) } func runChat(cmd *cobra.Command, args []string) { agentMode, _ := cmd.Flags().GetBool("agent") - overrideModel, _ := cmd.Flags().GetString("model") + modelFlag, _ := cmd.Flags().GetString("model") - // Model selection + // Model switching logic var model string - if overrideModel != "" { - model = overrideModel + if modelFlag != "" { + model = modelFlag } else if agentMode { - model = config.GetModel("chat-agent", "") + model = config.GetModel("chat-agent", "") // we'll add this default next } else { model = config.GetModel("chat", "") } - logger.Info("starting chat", "mode", map[bool]string{true: "agent", false: "normal"}[agentMode], "model", model) + client := grok.NewClient() - color.Cyan("Grokkit Chat %s — Model: %s", map[bool]string{true: "(Agent Mode)", false: ""}[agentMode], model) - color.Cyan("Type /quit to exit. Type /new to start fresh session.\n") - - client := newGrokClient() - history := loadChatHistory() - - // Agent system prompt - systemPrompt := `You are Grok, a helpful AI built by xAI.` - if agentMode { - systemPrompt = `You are Grok in Agent Mode. -You have access to the following tools: -- edit -- scaffold -- testgen -- lint -- commit - -Always use tools when the user asks you to change code, generate tests, lint, or commit. -Be concise and action-oriented. After every tool call, wait for the result before continuing. -Never make up file contents — always use the tools.` + systemPrompt := map[string]string{ + "role": "system", + "content": fmt.Sprintf("You are Grok 4, the latest and most powerful model from xAI (2026). You are currently running as `%s`. Be helpful, truthful, and a little irreverent.", model), } - history = append([]map[string]string{{"role": "system", "content": systemPrompt}}, history...) + if agentMode { + systemPrompt["content"] = `You are Grok in Agent Mode. +You have access to tools: edit, scaffold, testgen, lint, commit, etc. +Always use tools when the user wants you to change code, generate tests, lint or commit. +Be concise and action-oriented. After every tool call, wait for the result.` + } + + history := loadChatHistory() + if history == nil || len(history) == 0 { + history = []map[string]string{systemPrompt} + } else if history[0]["role"] != "system" { + history = append([]map[string]string{systemPrompt}, history...) + } else { + history[0] = systemPrompt // refresh system prompt + } + + color.Cyan("┌──────────────────────────────────────────────────────────────┐") + color.Cyan("│ Grokkit Chat %s — Model: %s │", map[bool]string{true: "(Agent Mode)", false: ""}[agentMode], model) + color.Cyan("│ Type /quit to exit │") + color.Cyan("└──────────────────────────────────────────────────────────────┘\n") scanner := bufio.NewScanner(os.Stdin) for { - color.Green("You: ") + color.Yellow("You > ") if !scanner.Scan() { break } - input := strings.TrimSpace(scanner.Text()) - if input == "/quit" || input == "/q" { - break - } - if input == "/new" { - history = []map[string]string{{"role": "system", "content": systemPrompt}} - color.Yellow("New session started.\n") - continue - } + input := strings.TrimSpace(scanner.Text()) if input == "" { continue } + if input == "/quit" || input == "/q" || input == "exit" { + color.Cyan("\nGoodbye 👋\n") + break + } history = append(history, map[string]string{"role": "user", "content": input}) - // In agent mode, we allow Grok to output tool calls in a simple JSON block + color.Green("Grok > ") reply := client.Stream(history, model) - // Simple tool-call detection (can be expanded later) - if agentMode && strings.Contains(reply, "```tool") { - handleToolCall(reply, &history, model) - continue - } - history = append(history, map[string]string{"role": "assistant", "content": reply}) - saveChatHistory(history) + _ = saveChatHistory(history) + + fmt.Println() } - - saveChatHistory(history) - color.Yellow("Goodbye!") -} - -// Placeholder — we'll flesh this out in the next step if you want more tools -func handleToolCall(reply string, history *[]map[string]string, model string) { - color.Yellow("\n[Agent] Grok wants to call a tool...") - // For now we just echo — full implementation in next message if you approve - fmt.Println(reply) - *history = append(*history, map[string]string{"role": "assistant", "content": reply}) } diff --git a/config/config.go b/config/config.go index d0fbfe5..b0767c7 100644 --- a/config/config.go +++ b/config/config.go @@ -36,9 +36,8 @@ func Load() { viper.SetDefault("commands.prdescribe.model", "grok-4") viper.SetDefault("commands.review.model", "grok-4") viper.SetDefault("commands.docs.model", "grok-4") - viper.SetDefault("models.chat", "grok-4-1") - viper.SetDefault("models.chat-agent", "grok-4-1-fast-non-reasoning") // ← new - + viper.SetDefault("commands.chat", "grok-4-1") + viper.SetDefault("commands.chat-agent.model", "grok-4-1-fast-non-reasoning") // Config file is optional, so we ignore read errors _ = viper.ReadInConfig() } @@ -50,8 +49,7 @@ func GetModel(commandName string, flagModel string) string { } return flagModel } - cmdModel := viper.GetString("commands." + commandName + ".model") - if cmdModel != "" { + if cmdModel := viper.GetString("commands." + commandName + ".model"); cmdModel != "" { return cmdModel } return viper.GetString("default_model")