@@ -299,6 +299,11 @@ func (m *UI) Init() tea.Cmd {
299 if m.QueryCapabilities {
299 if m.QueryCapabilities {
300 cmds = append(cmds, tea.RequestTerminalVersion)
300 cmds = append(cmds, tea.RequestTerminalVersion)
302+ if m.state == uiOnboarding {
303+ if cmd := m.openModelsDialog(); cmd != nil {
304+ cmds = append(cmds, cmd)
302 // load the user commands async
307 // load the user commands async
303 cmds = append(cmds, m.loadCustomCommands())
308 cmds = append(cmds, m.loadCustomCommands())
304 return tea.Batch(cmds...)
309 return tea.Batch(cmds...)
@@ -1028,10 +1033,23 @@ func (m *UI) handleDialogMsg(msg tea.Msg) tea.Cmd {
1028 return tea.Batch(cmds...)
1033 return tea.Batch(cmds...)
1036+ isOnboarding := m.state == uiOnboarding
1031 switch msg := action.(type) {
1038 switch msg := action.(type) {
1032 // Generic dialog messages
1039 // Generic dialog messages
1033 case dialog.ActionClose:
1040 case dialog.ActionClose:
1041+ if isOnboarding && m.dialog.ContainsDialog(dialog.ModelsID) {
1034 m.dialog.CloseFrontDialog()
1045 m.dialog.CloseFrontDialog()
1048+ if cmd := m.openModelsDialog(); cmd != nil {
1049+ cmds = append(cmds, cmd)
1035 if m.focus == uiFocusEditor {
1053 if m.focus == uiFocusEditor {
1036 cmds = append(cmds, m.textarea.Focus())
1054 cmds = append(cmds, m.textarea.Focus())
@@ -1164,10 +1182,18 @@ func (m *UI) handleDialogMsg(msg tea.Msg) tea.Cmd {
1165 if err := cfg.UpdatePreferredModel(msg.ModelType, msg.Model); err != nil {
1183 if err := cfg.UpdatePreferredModel(msg.ModelType, msg.Model); err != nil {
1166 cmds = append(cmds, uiutil.ReportError(err))
1184 cmds = append(cmds, uiutil.ReportError(err))
1185+ } else if _, ok := cfg.Models[config.SelectedModelTypeSmall]; !ok {
1186+ // Ensure small model is set is unset.
1187+ smallModel := m.com.App.GetDefaultSmallModel(providerID)
1188+ if err := cfg.UpdatePreferredModel(config.SelectedModelTypeSmall, smallModel); err != nil {
1189+ cmds = append(cmds, uiutil.ReportError(err))
1169 cmds = append(cmds, func() tea.Msg {
1193 cmds = append(cmds, func() tea.Msg {
1170− m.com.App.UpdateAgentModel(context.TODO())
1194+ if err := m.com.App.UpdateAgentModel(context.TODO()); err != nil {
1195+ return uiutil.ReportError(err)
1172 modelMsg := fmt.Sprintf("%s model changed to %s", msg.ModelType, msg.Model.Model)
1198 modelMsg := fmt.Sprintf("%s model changed to %s", msg.ModelType, msg.Model.Model)
@@ -1177,6 +1203,16 @@ func (m *UI) handleDialogMsg(msg tea.Msg) tea.Cmd {
1177 m.dialog.CloseDialog(dialog.APIKeyInputID)
1203 m.dialog.CloseDialog(dialog.APIKeyInputID)
1178 m.dialog.CloseDialog(dialog.OAuthID)
1204 m.dialog.CloseDialog(dialog.OAuthID)
1179 m.dialog.CloseDialog(dialog.ModelsID)
1205 m.dialog.CloseDialog(dialog.ModelsID)
1208+ m.state = uiLanding
1209+ m.focus = uiFocusEditor
1211+ m.com.Config().SetupAgents()
1212+ if err := m.com.App.InitCoderAgent(context.TODO()); err != nil {
1213+ cmds = append(cmds, uiutil.ReportError(err))
1180 case dialog.ActionSelectReasoningEffort:
1216 case dialog.ActionSelectReasoningEffort:
1181 if m.isAgentBusy() {
1217 if m.isAgentBusy() {
1182 cmds = append(cmds, uiutil.ReportWarn("Agent is busy, please wait..."))
1218 cmds = append(cmds, uiutil.ReportWarn("Agent is busy, please wait..."))
@@ -1284,15 +1320,17 @@ func (m *UI) openAuthenticationDialog(provider catwalk.Provider, model config.Se
1285 dlg dialog.Dialog
1321 dlg dialog.Dialog
1286 cmd tea.Cmd
1322 cmd tea.Cmd
1324+ isOnboarding = m.state == uiOnboarding
1289 switch provider.ID {
1327 switch provider.ID {
1290 case "hyper":
1328 case "hyper":
1291− dlg, cmd = dialog.NewOAuthHyper(m.com, provider, model, modelType)
1329+ dlg, cmd = dialog.NewOAuthHyper(m.com, isOnboarding, provider, model, modelType)
1292 case catwalk.InferenceProviderCopilot:
1330 case catwalk.InferenceProviderCopilot:
1293− dlg, cmd = dialog.NewOAuthCopilot(m.com, provider, model, modelType)
1331+ dlg, cmd = dialog.NewOAuthCopilot(m.com, isOnboarding, provider, model, modelType)
1294 default:
1332 default:
1295− dlg, cmd = dialog.NewAPIKeyInput(m.com, provider, model, modelType)
1333+ dlg, cmd = dialog.NewAPIKeyInput(m.com, isOnboarding, provider, model, modelType)
1298 if m.dialog.ContainsDialog(dlg.ID()) {
1336 if m.dialog.ContainsDialog(dlg.ID()) {
@@ -1648,12 +1686,8 @@ func (m *UI) Draw(scr uv.Screen, area uv.Rectangle) *tea.Cursor {
1648 header := uv.NewStyledString(m.header)
1686 header := uv.NewStyledString(m.header)
1649 header.Draw(scr, layout.header)
1687 header.Draw(scr, layout.header)
1651− mainView := lipgloss.NewStyle().Width(layout.main.Dx()).
1689+ // NOTE: Onboarding flow will be rendered as dialogs below, but
1652− Height(layout.main.Dy()).
1690+ // positioned at the bottom left of the screen.
1653− Background(lipgloss.ANSIColor(rand.Intn(256))).
1654− Render(" Onboarding ")
1655− main := uv.NewStyledString(mainView)
1656− main.Draw(scr, layout.main)
1658 case uiInitialize:
1692 case uiInitialize:
1659 header := uv.NewStyledString(m.header)
1693 header := uv.NewStyledString(m.header)
@@ -1697,11 +1731,14 @@ func (m *UI) Draw(scr uv.Screen, area uv.Rectangle) *tea.Cursor {
1734+ isOnboarding := m.state == uiOnboarding
1700 // Add status and help layer
1736 // Add status and help layer
1737+ m.status.SetHideHelp(isOnboarding)
1701 m.status.Draw(scr, layout.status)
1738 m.status.Draw(scr, layout.status)
1703 // Draw completions popup if open
1740 // Draw completions popup if open
1704− if m.completionsOpen && m.completions.HasItems() {
1741+ if !isOnboarding && m.completionsOpen && m.completions.HasItems() {
1705 w, h := m.completions.Size()
1742 w, h := m.completions.Size()
1706 x := m.completionsPositionStart.X
1743 x := m.completionsPositionStart.X
1707 y := m.completionsPositionStart.Y - h
1744 y := m.completionsPositionStart.Y - h
@@ -2606,7 +2643,8 @@ func (m *UI) openModelsDialog() tea.Cmd {
2606 return nil
2643 return nil
2646+ isOnboarding := m.state == uiOnboarding
2609− modelsDialog, err := dialog.NewModels(m.com)
2647+ modelsDialog, err := dialog.NewModels(m.com, isOnboarding)
2610 if err != nil {
2648 if err != nil {
2611 return uiutil.ReportError(err)
2649 return uiutil.ReportError(err)