Detailed changes
@@ -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.
@@ -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),
)
})
@@ -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()
@@ -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
@@ -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)
@@ -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")
}
@@ -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
@@ -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)()