diff --git a/doc/agentic.txt b/doc/agentic.txt index d7f54a2f..cd7d14b5 100644 --- a/doc/agentic.txt +++ b/doc/agentic.txt @@ -303,6 +303,14 @@ settings ~ window after submitting a prompt. Default: `true`. + *agentic-config-provider-switcher* +provider_switcher ~ + Type: `table` + + `hide_unhealthy_providers` Hide providers whose command is not installed + from the provider switcher UI. + Default: `false`. + *agentic-config-hooks* hooks ~ Type: `table` diff --git a/lua/agentic/config_default.lua b/lua/agentic/config_default.lua index 2e6e209c..89000a58 100644 --- a/lua/agentic/config_default.lua +++ b/lua/agentic/config_default.lua @@ -177,6 +177,10 @@ --- @field on_session_update? fun(data: agentic.UserConfig.SessionUpdateData): nil --- @field on_file_edit? fun(data: agentic.UserConfig.FileEditData): nil +--- Provider switcher UI behavior +--- @class agentic.UserConfig.ProviderSwitcher +--- @field hide_unhealthy_providers boolean Hide providers whose command is not installed + --- Control various behaviors and features of the plugin --- @class agentic.UserConfig.Settings --- @field move_cursor_to_chat_on_submit boolean Automatically move cursor to chat window after submitting a prompt @@ -201,6 +205,7 @@ --- @class (partial) agentic.PartialUserConfig.DiffPreview: agentic.UserConfig.DiffPreview --- @class (partial) agentic.PartialUserConfig.Folding.ToolCalls: agentic.UserConfig.Folding.ToolCalls --- @class (partial) agentic.PartialUserConfig.Settings: agentic.UserConfig.Settings +--- @class (partial) agentic.PartialUserConfig.ProviderSwitcher: agentic.UserConfig.ProviderSwitcher --- Windows partial with nested type overrides --- @class (partial) agentic.PartialUserConfig.Windows: agentic.UserConfig.Windows @@ -232,6 +237,7 @@ --- @field diff_preview? agentic.PartialUserConfig.DiffPreview --- @field folding? agentic.PartialUserConfig.Folding --- @field settings? agentic.PartialUserConfig.Settings +--- @field provider_switcher? agentic.PartialUserConfig.ProviderSwitcher --- @class agentic.UserConfig --- @field debug boolean Enable printing debug messages which can be read via `:messages` @@ -253,6 +259,7 @@ --- @field hooks agentic.UserConfig.Hooks --- @field headers agentic.UserConfig.Headers --- @field settings agentic.UserConfig.Settings +--- @field provider_switcher agentic.UserConfig.ProviderSwitcher local ConfigDefault = { debug = false, @@ -491,6 +498,10 @@ local ConfigDefault = { settings = { move_cursor_to_chat_on_submit = true, }, + + provider_switcher = { + hide_unhealthy_providers = false, + }, } return ConfigDefault diff --git a/lua/agentic/session_registry.lua b/lua/agentic/session_registry.lua index 1e47a6f4..9dd1a963 100644 --- a/lua/agentic/session_registry.lua +++ b/lua/agentic/session_registry.lua @@ -106,7 +106,14 @@ function SessionRegistry.select_provider(on_selected) end end - vim.list_extend(sorted_providers, not_installed) + if not Config.provider_switcher.hide_unhealthy_providers then + vim.list_extend(sorted_providers, not_installed) + elseif #sorted_providers == 0 then + Logger.notify( + "No healthy providers found. Showing unavailable providers." + ) + vim.list_extend(sorted_providers, not_installed) + end vim.ui.select(sorted_providers, { prompt = "Select an ACP provider for the new session:", diff --git a/lua/agentic/session_registry.test.lua b/lua/agentic/session_registry.test.lua index ae945c26..b885c646 100644 --- a/lua/agentic/session_registry.test.lua +++ b/lua/agentic/session_registry.test.lua @@ -59,6 +59,9 @@ describe("agentic.SessionRegistry", function() ["claude-acp"] = { command = "claude-code-acp" }, ["gemini-acp"] = { command = "gemini" }, }, + provider_switcher = { + hide_unhealthy_providers = true, + }, } default_config_mock = { @@ -105,6 +108,9 @@ describe("agentic.SessionRegistry", function() ["claude-acp"] = { command = "claude-code-acp" }, ["gemini-acp"] = { command = "gemini" }, } + config_mock.provider_switcher = { + hide_unhealthy_providers = true, + } default_config_mock.provider = "claude-acp" session_manager_mock.new = function(_, tab_page_id) @@ -487,6 +493,47 @@ describe("agentic.SessionRegistry", function() assert.is_nil(result) end) + describe("hide_unhealthy_providers", function() + before_each(function() + acp_health_mock.get_default_provider_names = function() + return { "claude-acp", "gemini-acp" } + end + acp_health_mock.is_command_available = function(cmd) + return cmd == "claude-code-acp" + end + end) + + it( + "excludes not-installed providers when hide_unhealthy_providers is true", + function() + config_mock.provider_switcher = + { hide_unhealthy_providers = true } + + SessionRegistry.select_provider(function() end) + + assert.equal(1, #captured_items) + assert.equal("claude-acp", captured_items[1].name) + assert.is_true(captured_items[1].installed) + end + ) + + it( + "includes not-installed providers when hide_unhealthy_providers is false", + function() + config_mock.provider_switcher = + { hide_unhealthy_providers = false } + + SessionRegistry.select_provider(function() end) + + assert.equal(2, #captured_items) + assert.equal("claude-acp", captured_items[1].name) + assert.is_true(captured_items[1].installed) + assert.equal("gemini-acp", captured_items[2].name) + assert.is_false(captured_items[2].installed) + end + ) + end) + describe("format_item labels", function() before_each(function() acp_health_mock.get_default_provider_names = function()