Finalize model-specific tool plans in ToolRouter (#41195)

## Why

Planning tools for a candidate model must not change the selected model or its
Responses Lite tool inventory. Otherwise, preparing a fallback can overwrite
metadata before the current model's request is sent.

## What changed

- Build tool registries and visible specs from an explicit `ModelInfo`.
- Store the finalized tool mode, code-mode names, namespace inventory, and
  terminal and child-management capabilities on `ToolRouter`.
- Publish namespace inventory only after selecting the step's router, and use
  that router's mode when dispatching and recording tool calls.

## Testing

Added coverage for candidate-model isolation, fallback compaction metadata,
code-mode worker selection, normalized tool names, and router capabilities.

GitOrigin-RevId: 56df2de8f42c7e93a4c4dcd117720e40a0cca3db
This commit is contained in:
Abhinav authored and copyberry committed 2026-08-27 20:01:39 +00:00
1 parent 8aea62b2d8
commit 0182ff3480
13 files changed
+532 -127

No files matched your search

+5 -4
View File
@@ -25,6 +25,7 @@ use crate::session::turn_context::TurnContext;
pub(crate) use approvals::ApprovalContext;
use codex_features::Feature;
use codex_protocol::exec_output::ExecToolCallOutput;
use codex_protocol::openai_models::ModelInfo;
use codex_protocol::openai_models::ToolMode;
use codex_tools::ToolName;
use codex_utils_output_truncation::TruncationPolicy;
@@ -64,8 +65,8 @@ pub(crate) fn tool_user_shell_type(
}
}
pub(crate) fn requested_tool_mode(turn_context: &TurnContext) -> ToolMode {
turn_context.model_info().tool_mode.unwrap_or_else(|| {
pub(crate) fn requested_tool_mode(turn_context: &TurnContext, model_info: &ModelInfo) -> ToolMode {
model_info.tool_mode.unwrap_or_else(|| {
if turn_context.config.features.enabled(Feature::CodeModeOnly) {
ToolMode::CodeModeOnly
} else if turn_context.config.features.enabled(Feature::CodeMode) {
@@ -76,8 +77,8 @@ pub(crate) fn requested_tool_mode(turn_context: &TurnContext) -> ToolMode {
})
}
pub(crate) fn effective_tool_mode(turn_context: &TurnContext) -> ToolMode {
let requested_tool_mode = requested_tool_mode(turn_context);
pub(crate) fn effective_tool_mode(turn_context: &TurnContext, model_info: &ModelInfo) -> ToolMode {
let requested_tool_mode = requested_tool_mode(turn_context, model_info);
if !turn_context.code_mode_available
&& requested_tool_mode == ToolMode::CodeMode
&& !turn_context.config.code_mode.disable_in_process_fallback