models_item.go

  1package dialog
  2
  3import (
  4	"charm.land/catwalk/pkg/catwalk"
  5	"charm.land/lipgloss/v2"
  6	"github.com/charmbracelet/crush/internal/config"
  7	"github.com/charmbracelet/crush/internal/ui/common"
  8	"github.com/charmbracelet/crush/internal/ui/styles"
  9	"github.com/charmbracelet/x/ansi"
 10	"github.com/sahilm/fuzzy"
 11)
 12
 13// ModelGroup represents a group of model items.
 14type ModelGroup struct {
 15	Title      string
 16	Items      []*ModelItem
 17	configured bool
 18	t          *styles.Styles
 19}
 20
 21// NewModelGroup creates a new ModelGroup.
 22func NewModelGroup(t *styles.Styles, title string, configured bool, items ...*ModelItem) ModelGroup {
 23	return ModelGroup{
 24		Title:      title,
 25		Items:      items,
 26		configured: configured,
 27		t:          t,
 28	}
 29}
 30
 31// AppendItems appends [ModelItem]s to the group.
 32func (m *ModelGroup) AppendItems(items ...*ModelItem) {
 33	m.Items = append(m.Items, items...)
 34}
 35
 36// Render implements [list.Item].
 37func (m *ModelGroup) Render(width int) string {
 38	var configured string
 39	if m.configured {
 40		configuredIcon := m.t.ToolCallSuccess.Render()
 41		configuredText := m.t.Subtle.Render("Configured")
 42		configured = configuredIcon + " " + configuredText
 43	}
 44
 45	title := " " + m.Title + " "
 46	title = ansi.Truncate(title, max(0, width-lipgloss.Width(configured)-1), "…")
 47
 48	return common.Section(m.t, title, width, configured)
 49}
 50
 51// ModelItem represents a list item for a model type.
 52type ModelItem struct {
 53	prov      catwalk.Provider
 54	model     catwalk.Model
 55	modelType ModelType
 56
 57	cache        map[int]string
 58	t            *styles.Styles
 59	m            fuzzy.Match
 60	focused      bool
 61	showProvider bool
 62}
 63
 64// SelectedModel returns this model item as a [config.SelectedModel] instance.
 65func (m *ModelItem) SelectedModel() config.SelectedModel {
 66	return config.SelectedModel{
 67		Model:           m.model.ID,
 68		Provider:        string(m.prov.ID),
 69		ReasoningEffort: m.model.DefaultReasoningEffort,
 70		MaxTokens:       m.model.DefaultMaxTokens,
 71	}
 72}
 73
 74// SelectedModelType returns the type of model represented by this item.
 75func (m *ModelItem) SelectedModelType() config.SelectedModelType {
 76	return m.modelType.Config()
 77}
 78
 79var _ ListItem = &ModelItem{}
 80
 81// NewModelItem creates a new ModelItem.
 82func NewModelItem(t *styles.Styles, prov catwalk.Provider, model catwalk.Model, typ ModelType, showProvider bool) *ModelItem {
 83	return &ModelItem{
 84		prov:         prov,
 85		model:        model,
 86		modelType:    typ,
 87		t:            t,
 88		cache:        make(map[int]string),
 89		showProvider: showProvider,
 90	}
 91}
 92
 93// Filter implements ListItem.
 94func (m *ModelItem) Filter() string {
 95	return m.model.Name
 96}
 97
 98// ID implements ListItem.
 99func (m *ModelItem) ID() string {
100	return modelKey(string(m.prov.ID), m.model.ID)
101}
102
103// Render implements ListItem.
104func (m *ModelItem) Render(width int) string {
105	var providerInfo string
106	if m.showProvider {
107		providerInfo = string(m.prov.Name)
108	}
109	styles := ListItemStyles{
110		ItemBlurred:     m.t.Dialog.NormalItem,
111		ItemFocused:     m.t.Dialog.SelectedItem,
112		InfoTextBlurred: m.t.Base,
113		InfoTextFocused: m.t.Base,
114	}
115	return renderItem(styles, m.model.Name, providerInfo, m.focused, width, m.cache, &m.m)
116}
117
118// SetFocused implements ListItem.
119func (m *ModelItem) SetFocused(focused bool) {
120	if m.focused != focused {
121		m.cache = nil
122	}
123	m.focused = focused
124}
125
126// SetMatch implements ListItem.
127func (m *ModelItem) SetMatch(fm fuzzy.Match) {
128	m.cache = nil
129	m.m = fm
130}