@@ -22,9 +22,15 @@ const (
2222 defaultWidth = 60
2323)
2424
25+const (
26+ LargeModelType int = iota
27+ SmallModelType
28+)
29+
2530// ModelSelectedMsg is sent when a model is selected
2631type ModelSelectedMsg struct {
27− Model config.PreferredModel
32+ Model config.PreferredModel
33+ ModelType config.ModelType
2834}
2935
3036// CloseModelDialogMsg is sent when a model is selected
@@ -42,12 +48,13 @@ type ModelOption struct {
4248
4349type modelDialogCmp struct {
4450 width int
45− wWidth int // Width of the terminal window
46− wHeight int // Height of the terminal window
51+ wWidth int
52+ wHeight int
4753
4854 modelList list.ListModel
4955 keyMap KeyMap
5056 help help.Model
57+ modelType int
5158}
5259
5360func NewModelDialogCmp() ModelDialog {
@@ -80,34 +87,13 @@ func NewModelDialogCmp() ModelDialog {
8087 width: defaultWidth,
8188 keyMap: DefaultKeyMap(),
8289 help: help,
90+ modelType: LargeModelType,
8391 }
8492}
8593
8694func (m *modelDialogCmp) Init() tea.Cmd {
87− providers := config.Providers()
88−
89− modelItems := []util.Model{}
90− selectIndex := 0
91− agentModel := config.GetAgentModel(config.AgentCoder)
92− agentProvider := config.GetAgentProvider(config.AgentCoder)
93− for _, provider := range providers {
94− name := provider.Name
95− if name == "" {
96− name = string(provider.ID)
97− }
98− modelItems = append(modelItems, commands.NewItemSection(name))
99− for _, model := range provider.Models {
100− modelItems = append(modelItems, completions.NewCompletionItem(model.Name, ModelOption{
101− Provider: provider,
102− Model: model,
103− }))
104− if model.ID == agentModel.ID && provider.ID == agentProvider.ID {
105− selectIndex = len(modelItems) - 1 // Set the selected index to the current model
106− }
107− }
108− }
109−
110− return tea.Sequence(m.modelList.Init(), m.modelList.SetItems(modelItems), m.modelList.SetSelected(selectIndex))
95+ m.SetModelType(m.modelType)
96+ return m.modelList.Init()
11197}
11298
11399func (m *modelDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
@@ -115,24 +101,41 @@ func (m *modelDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
115101 case tea.WindowSizeMsg:
116102 m.wWidth = msg.Width
117103 m.wHeight = msg.Height
104+ m.SetModelType(m.modelType)
118105 return m, m.modelList.SetSize(m.listWidth(), m.listHeight())
119106 case tea.KeyPressMsg:
120107 switch {
121108 case key.Matches(msg, m.keyMap.Select):
122109 selectedItemInx := m.modelList.SelectedIndex()
123110 if selectedItemInx == list.NoSelection {
124− return m, nil // No item selected, do nothing
111+ return m, nil
125112 }
126113 items := m.modelList.Items()
127114 selectedItem := items[selectedItemInx].(completions.CompletionItem).Value().(ModelOption)
128115
116+ var modelType config.ModelType
117+ if m.modelType == LargeModelType {
118+ modelType = config.LargeModel
119+ } else {
120+ modelType = config.SmallModel
121+ }
122+
129123 return m, tea.Sequence(
130124 util.CmdHandler(dialogs.CloseDialogMsg{}),
131− util.CmdHandler(ModelSelectedMsg{Model: config.PreferredModel{
132− ModelID: selectedItem.Model.ID,
133− Provider: selectedItem.Provider.ID,
134− }}),
125+ util.CmdHandler(ModelSelectedMsg{
126+ Model: config.PreferredModel{
127+ ModelID: selectedItem.Model.ID,
128+ Provider: selectedItem.Provider.ID,
129+ },
130+ ModelType: modelType,
131+ }),
135132 )
133+ case key.Matches(msg, m.keyMap.Tab):
134+ if m.modelType == LargeModelType {
135+ return m, m.SetModelType(SmallModelType)
136+ } else {
137+ return m, m.SetModelType(LargeModelType)
138+ }
136139 case key.Matches(msg, m.keyMap.Close):
137140 return m, util.CmdHandler(dialogs.CloseDialogMsg{})
138141 default:
@@ -147,9 +150,10 @@ func (m *modelDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
147150func (m *modelDialogCmp) View() tea.View {
148151 t := styles.CurrentTheme()
149152 listView := m.modelList.View()
153+ radio := m.modelTypeRadio()
150154 content := lipgloss.JoinVertical(
151155 lipgloss.Left,
152− t.S().Base.Padding(0, 1, 1, 1).Render(core.Title("Switch Model", m.width-4)),
156+ t.S().Base.Padding(0, 1, 1, 1).Render(core.Title("Switch Model", m.width-lipgloss.Width(radio)-5)+" "+radio),
153157 listView.String(),
154158 "",
155159 t.S().Base.Width(m.width-2).PaddingLeft(1).AlignHorizontal(lipgloss.Left).Render(m.help.View(m.keyMap)),
@@ -197,3 +201,49 @@ func (m *modelDialogCmp) moveCursor(cursor *tea.Cursor) *tea.Cursor {
197201func (m *modelDialogCmp) ID() dialogs.DialogID {
198202 return ModelsDialogID
199203}
204+
205+func (m *modelDialogCmp) modelTypeRadio() string {
206+ t := styles.CurrentTheme()
207+ choices := []string{"Large", "Small"}
208+ iconSelected := "◉"
209+ iconUnselected := "○"
210+ if m.modelType == LargeModelType {
211+ return t.S().Base.Foreground(t.FgHalfMuted).Render(iconSelected + " " + choices[0] + " " + iconUnselected + " " + choices[1])
212+ }
213+ return t.S().Base.Foreground(t.FgHalfMuted).Render(iconUnselected + " " + choices[0] + " " + iconSelected + " " + choices[1])
214+}
215+
216+func (m *modelDialogCmp) SetModelType(modelType int) tea.Cmd {
217+ m.modelType = modelType
218+
219+ providers := config.Providers()
220+ modelItems := []util.Model{}
221+ selectIndex := 0
222+
223+ cfg := config.Get()
224+ var currentModel config.PreferredModel
225+ if m.modelType == LargeModelType {
226+ currentModel = cfg.Models.Large
227+ } else {
228+ currentModel = cfg.Models.Small
229+ }
230+
231+ for _, provider := range providers {
232+ name := provider.Name
233+ if name == "" {
234+ name = string(provider.ID)
235+ }
236+ modelItems = append(modelItems, commands.NewItemSection(name))
237+ for _, model := range provider.Models {
238+ modelItems = append(modelItems, completions.NewCompletionItem(model.Name, ModelOption{
239+ Provider: provider,
240+ Model: model,
241+ }))
242+ if model.ID == currentModel.ModelID && provider.ID == currentModel.Provider {
243+ selectIndex = len(modelItems) - 1 // Set the selected index to the current model
244+ }
245+ }
246+ }
247+
248+ return tea.Sequence(m.modelList.SetItems(modelItems), m.modelList.SetSelected(selectIndex))
249+}