Support disabling tool suggest for specific tools. (#20072)

## Summary
- Add `disable_tool_suggest` to app and plugin config, schema, and
TypeScript output
- Exclude disabled connectors and plugins from tool suggestion discovery
- Persist "never show again" tool-suggestion choices back into
`config.toml`
- Update config docs and add coverage for connector and plugin
suppression

## Testing
- Added and updated unit tests for config persistence and tool-suggest
filtering
- Not run (not requested)
This commit is contained in:
Matthew Zeng
2026-04-28 17:19:34 -07:00
committed by GitHub
Unverified
parent 1211a90a35
commit ebdf3a878c
17 changed files with 681 additions and 6 deletions
@@ -43,6 +43,13 @@ pub(crate) async fn list_tool_suggest_discoverable_plugins(
.filter(|discoverable| discoverable.kind == ToolSuggestDiscoverableType::Plugin)
.map(|discoverable| discoverable.id.as_str())
.collect::<HashSet<_>>();
let disabled_plugin_ids = config
.tool_suggest
.disabled_tools
.iter()
.filter(|disabled_tool| disabled_tool.kind == ToolSuggestDiscoverableType::Plugin)
.map(|disabled_tool| disabled_tool.id.as_str())
.collect::<HashSet<_>>();
let marketplaces = plugins_manager
.list_marketplaces_for_config(config, &[])
.context("failed to list plugin marketplaces for tool suggestions")?
@@ -56,6 +63,7 @@ pub(crate) async fn list_tool_suggest_discoverable_plugins(
for plugin in marketplace.plugins {
if plugin.installed
|| disabled_plugin_ids.contains(plugin.id.as_str())
|| (!TOOL_SUGGEST_DISCOVERABLE_PLUGIN_ALLOWLIST.contains(&plugin.id.as_str())
&& !configured_plugin_ids.contains(plugin.id.as_str()))
{
@@ -230,6 +230,31 @@ async fn list_tool_suggest_discoverable_plugins_omits_installed_curated_plugins(
assert_eq!(discoverable_plugins, Vec::<DiscoverablePluginInfo>::new());
}
#[tokio::test]
async fn list_tool_suggest_discoverable_plugins_omits_disabled_tool_suggestions() {
let codex_home = tempdir().expect("tempdir should succeed");
let curated_root = curated_plugins_repo_path(codex_home.path());
write_openai_curated_marketplace(&curated_root, &["slack"]);
write_file(
&codex_home.path().join(crate::config::CONFIG_TOML_FILE),
r#"[features]
plugins = true
[tool_suggest]
disabled_tools = [
{ type = "plugin", id = "slack@openai-curated" }
]
"#,
);
let config = load_plugins_config(codex_home.path()).await;
let discoverable_plugins = list_tool_suggest_discoverable_plugins(&config)
.await
.unwrap();
assert_eq!(discoverable_plugins, Vec::<DiscoverablePluginInfo>::new());
}
#[tokio::test]
async fn list_tool_suggest_discoverable_plugins_includes_configured_plugin_ids() {
let codex_home = tempdir().expect("tempdir should succeed");