From 6b8aecaba2257880753afc50458a1352801b7437 Mon Sep 17 00:00:00 2001 From: Kujtim Hoxha Date: Wed, 16 Jul 2025 13:33:20 +0200 Subject: [PATCH 1/3] chore: add thinking/reasoning indicator --- .../tui/components/chat/sidebar/sidebar.go | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/internal/tui/components/chat/sidebar/sidebar.go b/internal/tui/components/chat/sidebar/sidebar.go index cf1fd12dff512475fa77f0cd9fb657646c0cc2fd..c4df4edac10b24d15c09b6059fcb97a15d8b97b3 100644 --- a/internal/tui/components/chat/sidebar/sidebar.go +++ b/internal/tui/components/chat/sidebar/sidebar.go @@ -12,6 +12,7 @@ import ( "github.com/charmbracelet/crush/internal/config" "github.com/charmbracelet/crush/internal/diff" "github.com/charmbracelet/crush/internal/fsext" + "github.com/charmbracelet/crush/internal/fur/provider" "github.com/charmbracelet/crush/internal/history" "github.com/charmbracelet/crush/internal/lsp" "github.com/charmbracelet/crush/internal/lsp/protocol" @@ -880,8 +881,13 @@ func formatTokensAndCost(tokens, contextWindow int64, cost float64) string { } func (s *sidebarCmp) currentModelBlock() string { - agentCfg := config.Get().Agents["coder"] + cfg := config.Get() + agentCfg := cfg.Agents["coder"] + + selectedModel := cfg.Models[agentCfg.Model] + model := config.Get().GetModelByType(agentCfg.Model) + modelProvider := config.Get().GetProviderForModel(agentCfg.Model) t := styles.CurrentTheme() @@ -891,6 +897,23 @@ func (s *sidebarCmp) currentModelBlock() string { parts := []string{ modelInfo, } + if model.CanReason { + reasoningInfoStyle := t.S().Subtle.PaddingLeft(2) + switch modelProvider.Type { + case provider.TypeOpenAI: + reasoningEffort := model.DefaultReasoningEffort + if selectedModel.ReasoningEffort != "" { + reasoningEffort = selectedModel.ReasoningEffort + } + parts = append(parts, reasoningInfoStyle.Render(fmt.Sprintf("Reasoning %s", reasoningEffort))) + case provider.TypeAnthropic: + if selectedModel.Think { + parts = append(parts, reasoningInfoStyle.Render("Thinking on")) + } else { + parts = append(parts, reasoningInfoStyle.Render("Thinking off")) + } + } + } if s.session.ID != "" { parts = append( parts, From 140afea9828ae1e9f1a57fefad911e9039e2f5a9 Mon Sep 17 00:00:00 2001 From: Kujtim Hoxha Date: Wed, 16 Jul 2025 22:40:48 +0200 Subject: [PATCH 2/3] chore: small fixes --- internal/tui/components/chat/messages/messages.go | 3 +++ internal/tui/components/chat/sidebar/sidebar.go | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/tui/components/chat/messages/messages.go b/internal/tui/components/chat/messages/messages.go index 078caf7dcd941eebab7d1a2989b25539c41989e4..bff149c72807f637a58a6d14878b3ac209f05541 100644 --- a/internal/tui/components/chat/messages/messages.go +++ b/internal/tui/components/chat/messages/messages.go @@ -252,6 +252,7 @@ func (m *messageCmp) renderThinkingContent() string { m.thinkingViewport.SetWidth(m.textWidth()) m.thinkingViewport.SetContent(fullContent) m.thinkingViewport.GotoBottom() + finishReason := m.message.FinishPart() var footer string if reasoningContent.StartedAt > 0 { duration := m.message.ThinkingDuration() @@ -263,6 +264,8 @@ func (m *messageCmp) renderThinkingContent() string { NoIcon: true, } footer = t.S().Base.PaddingLeft(1).Render(core.Status(opts, m.textWidth()-1)) + } else if finishReason != nil && finishReason.Reason == message.FinishReasonCanceled { + footer = t.S().Base.PaddingLeft(1).Render(m.toMarkdown("*Canceled*")) } else { footer = m.anim.View() } diff --git a/internal/tui/components/chat/sidebar/sidebar.go b/internal/tui/components/chat/sidebar/sidebar.go index c4df4edac10b24d15c09b6059fcb97a15d8b97b3..3dd090d598341658c919f50de61ec0a4f3f7186f 100644 --- a/internal/tui/components/chat/sidebar/sidebar.go +++ b/internal/tui/components/chat/sidebar/sidebar.go @@ -27,6 +27,8 @@ import ( "github.com/charmbracelet/crush/internal/version" "github.com/charmbracelet/lipgloss/v2" "github.com/charmbracelet/x/ansi" + "golang.org/x/text/cases" + "golang.org/x/text/language" ) type FileHistory struct { @@ -905,7 +907,8 @@ func (s *sidebarCmp) currentModelBlock() string { if selectedModel.ReasoningEffort != "" { reasoningEffort = selectedModel.ReasoningEffort } - parts = append(parts, reasoningInfoStyle.Render(fmt.Sprintf("Reasoning %s", reasoningEffort))) + formatter := cases.Title(language.English) + parts = append(parts, reasoningInfoStyle.Render(formatter.String(fmt.Sprintf("Reasoning %s", reasoningEffort)))) case provider.TypeAnthropic: if selectedModel.Think { parts = append(parts, reasoningInfoStyle.Render("Thinking on")) From 270f0d259cffa8f18f7b0625503fb89457d0c4f2 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 16 Jul 2025 16:58:19 -0400 Subject: [PATCH 3/3] fix: properly capitalize reasoning and thinking status text in sidebar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 💖 Generated with Crush Co-Authored-By: Crush --- internal/tui/components/chat/sidebar/sidebar.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/tui/components/chat/sidebar/sidebar.go b/internal/tui/components/chat/sidebar/sidebar.go index 3dd090d598341658c919f50de61ec0a4f3f7186f..ecb88e7d60dbaf09dfc2e88f789ed0057ee756fc 100644 --- a/internal/tui/components/chat/sidebar/sidebar.go +++ b/internal/tui/components/chat/sidebar/sidebar.go @@ -907,13 +907,14 @@ func (s *sidebarCmp) currentModelBlock() string { if selectedModel.ReasoningEffort != "" { reasoningEffort = selectedModel.ReasoningEffort } - formatter := cases.Title(language.English) + formatter := cases.Title(language.English, cases.NoLower) parts = append(parts, reasoningInfoStyle.Render(formatter.String(fmt.Sprintf("Reasoning %s", reasoningEffort)))) case provider.TypeAnthropic: + formatter := cases.Title(language.English, cases.NoLower) if selectedModel.Think { - parts = append(parts, reasoningInfoStyle.Render("Thinking on")) + parts = append(parts, reasoningInfoStyle.Render(formatter.String("Thinking on"))) } else { - parts = append(parts, reasoningInfoStyle.Render("Thinking off")) + parts = append(parts, reasoningInfoStyle.Render(formatter.String("Thinking off"))) } } }