diff --git a/internal/app/app.go b/internal/app/app.go index 1c65ce8616b45f13e9797ace033b02d0a3565ebb..dca3d899fc41df8f6079b7feb85c723ef7987198 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -61,7 +61,6 @@ type App struct { LSPClients *csync.Map[string, *lsp.Client] configService *config.Service - config *config.Config serviceEventsWG *sync.WaitGroup eventsCtx context.Context @@ -97,7 +96,6 @@ func New(ctx context.Context, conn *sql.DB, cfgSvc *config.Service) (*App, error globalCtx: ctx, configService: cfgSvc, - config: cfg, events: make(chan tea.Msg, 100), serviceEventsWG: &sync.WaitGroup{}, @@ -133,11 +131,6 @@ func (app *App) ConfigService() *config.Service { return app.configService } -// Config returns the application configuration. -func (app *App) Config() *config.Config { - return app.config -} - // RunNonInteractive runs the application in non-interactive mode with the // given prompt, printing to stdout. func (app *App) RunNonInteractive(ctx context.Context, output io.Writer, prompt, largeModel, smallModel string, hideSpinner bool) error { @@ -328,7 +321,7 @@ func (app *App) UpdateAgentModel(ctx context.Context) error { // If largeModel is provided but smallModel is not, the small model defaults to // the provider's default small model. func (app *App) overrideModelsForNonInteractive(ctx context.Context, largeModel, smallModel string) error { - providers := app.config.Providers.Copy() + providers := app.configService.Config().Providers.Copy() largeMatches, smallMatches, err := findModels(providers, largeModel, smallModel) if err != nil { @@ -376,7 +369,7 @@ func (app *App) overrideModelsForNonInteractive(ctx context.Context, largeModel, // GetDefaultSmallModel returns the default small model for the given // provider. Falls back to the large model if no default is found. func (app *App) GetDefaultSmallModel(providerID string) config.SelectedModel { - cfg := app.config + cfg := app.configService.Config() largeModelCfg := cfg.Models[config.SelectedModelTypeLarge] // Find the provider in the known providers list to get its default small model. diff --git a/internal/app/lsp.go b/internal/app/lsp.go index a1c8c8044327a4192ae1881ed14da06c0d98d6eb..4abbb2f54843de787d7910e362fe3379aa9fab02 100644 --- a/internal/app/lsp.go +++ b/internal/app/lsp.go @@ -22,7 +22,7 @@ func (app *App) initLSPClients(ctx context.Context) { manager.LoadDefaults() var userConfiguredLSPs []string - for name, clientConfig := range app.config.LSP { + for name, clientConfig := range app.configService.LSP() { if clientConfig.Disabled { slog.Info("Skipping disabled LSP client", "name", name) manager.RemoveServer(name) @@ -70,7 +70,7 @@ func (app *App) initLSPClients(ctx context.Context) { wg.Go(func() { app.createAndStartLSPClient( ctx, name, - toOurConfig(server, app.config.LSP[name]), + toOurConfig(server, app.configService.LSP()[name]), slices.Contains(userConfiguredLSPs, name), ) }) diff --git a/internal/ui/common/common.go b/internal/ui/common/common.go index 281bc7f8abcff0726cdc166c190e4ccb54c84d19..4fb08df4cecaeb23683a0c56c54b081c70dd9743 100644 --- a/internal/ui/common/common.go +++ b/internal/ui/common/common.go @@ -26,11 +26,6 @@ type Common struct { Styles *styles.Styles } -// Config returns the configuration associated with this [Common] instance. -func (c *Common) Config() *config.Config { - return c.App.Config() -} - // ConfigService returns the config service associated with this [Common] instance. func (c *Common) ConfigService() *config.Service { return c.App.ConfigService() diff --git a/internal/ui/dialog/commands.go b/internal/ui/dialog/commands.go index 47858bdb17914cd8105a24fe45fdb34399879619..06d23723fab169b9778f8f2fb4f66618af0e0d16 100644 --- a/internal/ui/dialog/commands.go +++ b/internal/ui/dialog/commands.go @@ -396,12 +396,12 @@ func (c *Commands) defaultCommands() []*CommandItem { } // Add reasoning toggle for models that support it - cfg := c.com.Config() - if agentCfg, ok := cfg.Agents[config.AgentCoder]; ok { - providerCfg := c.com.ConfigService().GetProviderForModel(agentCfg.Model) - model := c.com.ConfigService().GetModelByType(agentCfg.Model) + svc := c.com.ConfigService() + if agentCfg, ok := svc.Agent(config.AgentCoder); ok { + providerCfg := svc.GetProviderForModel(agentCfg.Model) + model := svc.GetModelByType(agentCfg.Model) if providerCfg != nil && model != nil && model.CanReason { - selectedModel := cfg.Models[agentCfg.Model] + selectedModel, _ := svc.SelectedModel(agentCfg.Model) // Anthropic models: thinking toggle if model.CanReason && len(model.ReasoningLevels) == 0 { @@ -425,9 +425,9 @@ func (c *Commands) defaultCommands() []*CommandItem { commands = append(commands, NewCommandItem(c.com.Styles, "toggle_sidebar", "Toggle Sidebar", "", ActionToggleCompactMode{})) } if c.sessionID != "" { - cfg := c.com.Config() - agentCfg := cfg.Agents[config.AgentCoder] - model := c.com.ConfigService().GetModelByType(agentCfg.Model) + svc := c.com.ConfigService() + agentCfg, _ := svc.Agent(config.AgentCoder) + model := svc.GetModelByType(agentCfg.Model) if model != nil && model.SupportsImages { commands = append(commands, NewCommandItem(c.com.Styles, "file_picker", "Open File Picker", "ctrl+f", ActionOpenDialog{ // TODO: Pass in the file picker dialog id diff --git a/internal/ui/dialog/models.go b/internal/ui/dialog/models.go index e18b849bf78128be1dab3f62d65f04c103f37547..1451c0f4fe04d3dc4f0207bdce95007fe782ffcf 100644 --- a/internal/ui/dialog/models.go +++ b/internal/ui/dialog/models.go @@ -138,7 +138,7 @@ func NewModels(com *common.Common, isOnboarding bool) (*Models, error) { ) m.keyMap.Close = CloseKey - providers, err := getFilteredProviders(com.Config()) + providers, err := getFilteredProviders(com.ConfigService()) if err != nil { return nil, fmt.Errorf("failed to get providers: %w", err) } @@ -335,12 +335,13 @@ func (m *Models) FullHelp() [][]key.Binding { // setProviderItems sets the provider items in the list. func (m *Models) setProviderItems() error { t := m.com.Styles - cfg := m.com.Config() + svc := m.com.ConfigService() + cfg := svc.Config() var selectedItemID string selectedType := m.modelType.Config() - currentModel := cfg.Models[selectedType] - recentItems := cfg.RecentModels[selectedType] + currentModel, _ := svc.SelectedModel(selectedType) + recentItems := svc.RecentModels(selectedType) // Track providers already added to avoid duplicates addedProviders := make(map[string]bool) @@ -505,7 +506,8 @@ func (m *Models) setProviderItems() error { return nil } -func getFilteredProviders(cfg *config.Config) ([]catwalk.Provider, error) { +func getFilteredProviders(svc *config.Service) ([]catwalk.Provider, error) { + cfg := svc.Config() providers, err := config.Providers(cfg) if err != nil { return nil, fmt.Errorf("failed to get providers: %w", err) diff --git a/internal/ui/dialog/reasoning.go b/internal/ui/dialog/reasoning.go index 9017c5f0853a70b641a2fd6a66328e482df9e33e..03e1b83640575bea5dea588b891bf749598483fd 100644 --- a/internal/ui/dialog/reasoning.go +++ b/internal/ui/dialog/reasoning.go @@ -220,14 +220,14 @@ func (r *Reasoning) FullHelp() [][]key.Binding { } func (r *Reasoning) setReasoningItems() error { - cfg := r.com.Config() - agentCfg, ok := cfg.Agents[config.AgentCoder] + svc := r.com.ConfigService() + agentCfg, ok := svc.Agent(config.AgentCoder) if !ok { return errors.New("agent configuration not found") } - selectedModel := cfg.Models[agentCfg.Model] - model := r.com.ConfigService().GetModelByType(agentCfg.Model) + selectedModel, _ := svc.SelectedModel(agentCfg.Model) + model := svc.GetModelByType(agentCfg.Model) if model == nil { return errors.New("model configuration not found") } diff --git a/internal/ui/model/onboarding.go b/internal/ui/model/onboarding.go index 9207f445c0b988c8c19a49a56c7889bd8c61d63e..4002702dbc8c228b23e7e108a69538a4f120e69e 100644 --- a/internal/ui/model/onboarding.go +++ b/internal/ui/model/onboarding.go @@ -19,7 +19,7 @@ import ( // markProjectInitialized marks the current project as initialized in the config. func (m *UI) markProjectInitialized() tea.Msg { // TODO: handle error so we show it in the tui footer - err := config.MarkProjectInitialized(m.com.Config()) + err := config.MarkProjectInitialized(m.com.ConfigService().Config()) if err != nil { slog.Error(err.Error()) } @@ -52,7 +52,7 @@ func (m *UI) initializeProject() tea.Cmd { if cmd := m.newSession(); cmd != nil { cmds = append(cmds, cmd) } - cfg := m.com.Config() + cfg := m.com.ConfigService().Config() initialize := func() tea.Msg { initPrompt, err := agent.InitializePrompt(*cfg) @@ -77,7 +77,7 @@ func (m *UI) skipInitializeProject() tea.Cmd { // initializeView renders the project initialization prompt with Yes/No buttons. func (m *UI) initializeView() string { - cfg := m.com.Config() + cfg := m.com.ConfigService().Config() s := m.com.Styles.Initialize cwd := home.Short(m.com.ConfigService().WorkingDir()) initFile := cfg.Options.InitializeAs diff --git a/internal/ui/model/ui.go b/internal/ui/model/ui.go index 29e7142a05099c73d81bdb0a1569cefc3ad3643e..481c9a1a449be5cfde170e3943f524a543991ff9 100644 --- a/internal/ui/model/ui.go +++ b/internal/ui/model/ui.go @@ -298,7 +298,7 @@ func New(com *common.Common) *UI { desiredFocus := uiFocusEditor if !com.ConfigService().IsConfigured() { desiredState = uiOnboarding - } else if n, _ := config.ProjectNeedsInitialization(com.Config()); n { + } else if n, _ := config.ProjectNeedsInitialization(com.ConfigService().Config()); n { desiredState = uiInitialize } @@ -345,7 +345,7 @@ func (m *UI) setState(state uiState, focus uiFocusState) { // loadCustomCommands loads the custom commands asynchronously. func (m *UI) loadCustomCommands() tea.Cmd { return func() tea.Msg { - customCommands, err := commands.LoadCustomCommands(m.com.Config()) + customCommands, err := commands.LoadCustomCommands(m.com.ConfigService().Config()) if err != nil { slog.Error("Failed to load custom commands", "error", err) } @@ -776,7 +776,7 @@ func (m *UI) setSessionMessages(msgs []message.Message) tea.Cmd { case message.Assistant: items = append(items, chat.ExtractMessageItems(m.com.Styles, msg, toolResultMap)...) if msg.FinishPart() != nil && msg.FinishPart().Reason == message.FinishReasonEndTurn { - infoItem := chat.NewAssistantInfoItem(m.com.Styles, msg, m.com.Config(), time.Unix(m.lastUserMessageTime, 0)) + infoItem := chat.NewAssistantInfoItem(m.com.Styles, msg, m.com.ConfigService().Config(), time.Unix(m.lastUserMessageTime, 0)) items = append(items, infoItem) } default: @@ -906,7 +906,7 @@ func (m *UI) appendSessionMessage(msg message.Message) tea.Cmd { } } if msg.FinishPart() != nil && msg.FinishPart().Reason == message.FinishReasonEndTurn { - infoItem := chat.NewAssistantInfoItem(m.com.Styles, &msg, m.com.Config(), time.Unix(m.lastUserMessageTime, 0)) + infoItem := chat.NewAssistantInfoItem(m.com.Styles, &msg, m.com.ConfigService().Config(), time.Unix(m.lastUserMessageTime, 0)) m.chat.AppendMessages(infoItem) if atBottom { if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil { @@ -977,7 +977,7 @@ func (m *UI) updateSessionMessage(msg message.Message) tea.Cmd { if shouldRenderAssistant && msg.FinishPart() != nil && msg.FinishPart().Reason == message.FinishReasonEndTurn { if infoItem := m.chat.MessageItem(chat.AssistantInfoID(msg.ID)); infoItem == nil { - newInfoItem := chat.NewAssistantInfoItem(m.com.Styles, &msg, m.com.Config(), time.Unix(m.lastUserMessageTime, 0)) + newInfoItem := chat.NewAssistantInfoItem(m.com.Styles, &msg, m.com.ConfigService().Config(), time.Unix(m.lastUserMessageTime, 0)) m.chat.AppendMessages(newInfoItem) } } @@ -1196,7 +1196,7 @@ func (m *UI) handleDialogMsg(msg tea.Msg) tea.Cmd { m.dialog.CloseDialog(dialog.CommandsID) case dialog.ActionToggleThinking: cmds = append(cmds, func() tea.Msg { - cfg := m.com.Config() + cfg := m.com.ConfigService().Config() if cfg == nil { return util.ReportError(errors.New("configuration not found"))() } @@ -1235,7 +1235,7 @@ func (m *UI) handleDialogMsg(msg tea.Msg) tea.Cmd { break } - cfg := m.com.Config() + cfg := m.com.ConfigService().Config() if cfg == nil { cmds = append(cmds, util.ReportError(errors.New("configuration not found"))) break @@ -1297,7 +1297,7 @@ func (m *UI) handleDialogMsg(msg tea.Msg) tea.Cmd { break } - cfg := m.com.Config() + cfg := m.com.ConfigService().Config() if cfg == nil { cmds = append(cmds, util.ReportError(errors.New("configuration not found"))) break @@ -3063,7 +3063,7 @@ func (m *UI) drawSessionDetails(scr uv.Screen, area uv.Rectangle) { func (m *UI) runMCPPrompt(clientID, promptID string, arguments map[string]string) tea.Cmd { load := func() tea.Msg { - prompt, err := commands.GetMCPPrompt(m.com.Config(), clientID, promptID, arguments) + prompt, err := commands.GetMCPPrompt(m.com.ConfigService().Config(), clientID, promptID, arguments) if err != nil { // TODO: make this better return util.ReportError(err)()