diff --git a/internal/ui/common/elements.go b/internal/ui/common/elements.go index 1475d123a514b75b930b9479ec59f5e5d8a19cf3..248a40dd3fc1c2b4e75b2d4251a114c91f45cd81 100644 --- a/internal/ui/common/elements.go +++ b/internal/ui/common/elements.go @@ -26,15 +26,35 @@ type ModelContextInfo struct { Cost float64 } -// ModelInfo renders model information including name, reasoning settings, and -// optional context usage/cost. -func ModelInfo(t *styles.Styles, modelName string, reasoningInfo string, context *ModelContextInfo, width int) string { +// ModelInfo renders model information including name, provider, reasoning +// settings, and optional context usage/cost. +func ModelInfo(t *styles.Styles, modelName, providerName, reasoningInfo string, context *ModelContextInfo, width int) string { modelIcon := t.Subtle.Render(styles.ModelIcon) modelName = t.Base.Render(modelName) - modelInfo := fmt.Sprintf("%s %s", modelIcon, modelName) - parts := []string{ - modelInfo, + // Build first line with model name and optionally provider on the same line + var firstLine string + if providerName != "" { + providerInfo := t.Muted.Render(fmt.Sprintf("via %s", providerName)) + modelWithProvider := fmt.Sprintf("%s %s %s", modelIcon, modelName, providerInfo) + + // Check if it fits on one line + if lipgloss.Width(modelWithProvider) <= width { + firstLine = modelWithProvider + } else { + // If it doesn't fit, put provider on next line + firstLine = fmt.Sprintf("%s %s", modelIcon, modelName) + } + } else { + firstLine = fmt.Sprintf("%s %s", modelIcon, modelName) + } + + parts := []string{firstLine} + + // If provider didn't fit on first line, add it as second line + if providerName != "" && !strings.Contains(firstLine, "via") { + providerInfo := fmt.Sprintf("via %s", providerName) + parts = append(parts, t.Muted.PaddingLeft(2).Render(providerInfo)) } if reasoningInfo != "" { diff --git a/internal/ui/model/sidebar.go b/internal/ui/model/sidebar.go index 11d7b73baee60fbf68514ae34fb5aeaf459a16d9..97fc28615d4b4d80a1c3e3ce360153c51afa73aa 100644 --- a/internal/ui/model/sidebar.go +++ b/internal/ui/model/sidebar.go @@ -18,23 +18,32 @@ import ( func (m *UI) modelInfo(width int) string { model := m.selectedLargeModel() reasoningInfo := "" - if model != nil && model.CatwalkCfg.CanReason { + providerName := "" + + if model != nil { + // Get provider name first providerConfig, ok := m.com.Config().Providers.Get(model.ModelCfg.Provider) if ok { - switch providerConfig.Type { - case catwalk.TypeAnthropic: - if model.ModelCfg.Think { - reasoningInfo = "Thinking On" - } else { - reasoningInfo = "Thinking Off" + providerName = providerConfig.Name + + // Only check reasoning if model can reason + if model.CatwalkCfg.CanReason { + switch providerConfig.Type { + case catwalk.TypeAnthropic: + if model.ModelCfg.Think { + reasoningInfo = "Thinking On" + } else { + reasoningInfo = "Thinking Off" + } + default: + formatter := cases.Title(language.English, cases.NoLower) + reasoningEffort := cmp.Or(model.ModelCfg.ReasoningEffort, model.CatwalkCfg.DefaultReasoningEffort) + reasoningInfo = formatter.String(fmt.Sprintf("Reasoning %s", reasoningEffort)) } - default: - formatter := cases.Title(language.English, cases.NoLower) - reasoningEffort := cmp.Or(model.ModelCfg.ReasoningEffort, model.CatwalkCfg.DefaultReasoningEffort) - reasoningInfo = formatter.String(fmt.Sprintf("Reasoning %s", reasoningEffort)) } } } + var modelContext *common.ModelContextInfo if m.session != nil { modelContext = &common.ModelContextInfo{ @@ -43,7 +52,7 @@ func (m *UI) modelInfo(width int) string { ModelContext: model.CatwalkCfg.ContextWindow, } } - return common.ModelInfo(m.com.Styles, model.CatwalkCfg.Name, reasoningInfo, modelContext, width) + return common.ModelInfo(m.com.Styles, model.CatwalkCfg.Name, providerName, reasoningInfo, modelContext, width) } // getDynamicHeightLimits will give us the num of items to show in each section based on the hight