mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
core: allow excluding tool namespaces from code mode (#26320)
## Why Research and training setups need to control which tool namespaces appear inside code mode's nested `tools` surface without disabling those tools entirely. This makes it possible to train against a deliberately reduced nested-tool setup while preserving the normal direct and deferred tool paths. ## What - Extend `features.code_mode` to accept structured configuration while preserving the existing boolean syntax. - Add an exact `excluded_tool_namespaces` list under `[features.code_mode]`: ```toml [features.code_mode] enabled = true excluded_tool_namespaces = ["mcp__codex_apps", "multi_agent_v1"] ``` - Filter matching canonical `ToolName` namespaces when constructing code mode's nested router and code-mode-specific direct tool descriptions. - Keep excluded tools registered, directly exposed in mixed code mode, and discoverable through top-level `tool_search` when otherwise eligible. - Derive deferred nested-tool guidance after namespace filtering so the `exec` description does not advertise excluded-only deferred tools. - Preserve the boolean/table representation when materializing config locks and update the generated config schema. ## Testing - `just test -p codex-features` - `just test -p codex-config` - `just test -p codex-core load_config_resolves_code_mode_config` - `just test -p codex-core lock_contains_prompts_and_materializes_features` - `just test -p codex-core excluded_deferred_namespaces_do_not_enable_nested_tool_guidance` - `just test -p codex-core code_mode_excludes_configured_nested_tool_namespaces` - `cargo check -p codex-thread-manager-sample`
This commit is contained in:
@@ -4,6 +4,26 @@ use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct CodeModeConfigToml {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enabled: Option<bool>,
|
||||
/// Exact tool namespaces to omit from the code-mode nested tool surface.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub excluded_tool_namespaces: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl FeatureConfig for CodeModeConfigToml {
|
||||
fn enabled(&self) -> Option<bool> {
|
||||
self.enabled
|
||||
}
|
||||
|
||||
fn set_enabled(&mut self, enabled: bool) {
|
||||
self.enabled = Some(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct MultiAgentV2ConfigToml {
|
||||
|
||||
@@ -17,6 +17,7 @@ use toml::Table;
|
||||
mod feature_configs;
|
||||
mod legacy;
|
||||
pub use feature_configs::AppsMcpPathOverrideConfigToml;
|
||||
pub use feature_configs::CodeModeConfigToml;
|
||||
pub use feature_configs::MultiAgentV2ConfigToml;
|
||||
pub use feature_configs::NetworkProxyConfigToml;
|
||||
pub use feature_configs::NetworkProxyDomainPermissionToml;
|
||||
@@ -600,6 +601,8 @@ pub fn is_known_feature_key(key: &str) -> bool {
|
||||
/// Deserializable features table for TOML.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, JsonSchema)]
|
||||
pub struct FeaturesToml {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub code_mode: Option<FeatureToml<CodeModeConfigToml>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub multi_agent_v2: Option<FeatureToml<MultiAgentV2ConfigToml>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
@@ -620,6 +623,9 @@ impl Features {
|
||||
impl FeaturesToml {
|
||||
pub fn entries(&self) -> BTreeMap<String, bool> {
|
||||
let mut entries = self.entries.clone();
|
||||
if let Some(enabled) = self.code_mode.as_ref().and_then(FeatureToml::enabled) {
|
||||
entries.insert(Feature::CodeMode.key().to_string(), enabled);
|
||||
}
|
||||
if let Some(enabled) = self.multi_agent_v2.as_ref().and_then(FeatureToml::enabled) {
|
||||
entries.insert(Feature::MultiAgentV2.key().to_string(), enabled);
|
||||
}
|
||||
@@ -638,6 +644,7 @@ impl FeaturesToml {
|
||||
|
||||
pub fn materialize_resolved_enabled(&mut self, features: &Features) {
|
||||
let Self {
|
||||
code_mode,
|
||||
multi_agent_v2,
|
||||
apps_mcp_path_override,
|
||||
network_proxy,
|
||||
@@ -648,7 +655,9 @@ impl FeaturesToml {
|
||||
}
|
||||
for spec in FEATURES {
|
||||
let enabled = features.enabled(spec.id);
|
||||
if spec.id == Feature::MultiAgentV2 {
|
||||
if spec.id == Feature::CodeMode {
|
||||
materialize_resolved_feature_enabled(code_mode, enabled);
|
||||
} else if spec.id == Feature::MultiAgentV2 {
|
||||
materialize_resolved_feature_enabled(multi_agent_v2, enabled);
|
||||
} else if spec.id == Feature::AppsMcpPathOverride {
|
||||
materialize_resolved_feature_enabled(apps_mcp_path_override, enabled);
|
||||
|
||||
Reference in New Issue
Block a user