Expose selecte namespaces as direct model tools#28825
Conversation
| ); | ||
| let output_tool = dynamic_tool_to_responses_api_tool(tool).ok()?; | ||
| let mut output_tool = dynamic_tool_to_responses_api_tool(tool).ok()?; | ||
| output_tool.defer_loading = None; |
There was a problem hiding this comment.
The dynamic input currently drives both ToolExposure and ResponsesApiTool.defer_loading. Once the planner promotes a configured deferred runtime to DirectModelOnly, leaving this field set would serialize the now-top-level tool with defer_loading: true even though it has also been removed from tool_search. Clearing it at construction keeps the stored spec direct-shaped; ToolSearchInfo::from_tool_spec adds the marker back only when the tool is actually returned as a deferred search result. A short comment here would make that invariant clearer.
There was a problem hiding this comment.
thanks codex lol
maybe comment like // ToolExposure is canonical; tool search adds the wire-level marker for deferred results.
| for runtime in &mut planned_tools.runtimes { | ||
| let configured = runtime | ||
| .tool_name() | ||
| .namespace | ||
| .as_ref() | ||
| .is_some_and(|namespace| { | ||
| turn_context | ||
| .config | ||
| .code_mode | ||
| .direct_only_tool_namespaces | ||
| .contains(namespace) | ||
| }); | ||
| match runtime.exposure() { | ||
| ToolExposure::Direct | ToolExposure::Deferred if configured => { | ||
| *runtime = | ||
| override_tool_exposure(Arc::clone(runtime), ToolExposure::DirectModelOnly); | ||
| } | ||
| ToolExposure::Direct | ||
| | ToolExposure::Deferred | ||
| | ToolExposure::DirectModelOnly | ||
| | ToolExposure::Hidden => {} | ||
| } | ||
| } |
There was a problem hiding this comment.
i know we're against one-time helpers but i think in this case its warranted; this is logic very specific to this custom config setup and imo it shouldnt pollute build_tool_specs_and_registry
There was a problem hiding this comment.
Agreed. This is a good exception to the one-use-helper rule because it is self-contained config policy, while build_tool_specs_and_registry should read as orchestration. I would extract apply_direct_model_only_namespace_overrides(turn_context, &mut planned_tools) so the pipeline remains obvious: add sources, apply exposure policy, build tool_search, then build code-mode executors.

Why
Som tools, such as history and notes, must remain top-level when MCP deferral is enabled while staying unavailable through code-mode
exec.What changed
features.code_mode.direct_only_tool_namespaces.DirectModelOnly.code_mode_only.tool_searchdeferral and the nestedexecsurface.Validation
code_mode_only_exposes_direct_model_only_mcp_namespacesload_config_resolves_code_mode_config