codex-tools: extract collaboration tool specs (#16141)

## Why

The recent `codex-tools` migration steps have moved shared tool models
and low-coupling spec helpers out of `codex-core`, but
`core/src/tools/spec.rs` still owned a large block of pure
collaboration-tool spec construction. Those builders do not need session
state or runtime behavior; they only need a small amount of core-owned
configuration injected at the seam.

Moving that cohesive slice into `codex-tools` makes the crate boundary
more honest and removes a substantial amount of passive tool-spec logic
from `codex-core` without trying to move the runtime-coupled multi-agent
handlers at the same time.

## What changed

- added `agent_tool.rs`, `request_user_input_tool.rs`, and
`agent_job_tool.rs` to `codex-tools`, with sibling `*_tests.rs` coverage
and an exports-only `lib.rs`
- moved the pure `ToolSpec` builders for:
- collaboration tools such as `spawn_agent`, `send_input`,
`send_message`, `assign_task`, `resume_agent`, `wait_agent`,
`list_agents`, and `close_agent`
  - `request_user_input`
  - agent-job specs `spawn_agents_on_csv` and `report_agent_job_result`
- rewired `core/src/tools/spec.rs` to call the extracted builders while
still supplying the core-owned inputs, such as spawn-agent role
descriptions and wait timeout bounds
- updated the `core/src/tools/spec.rs` seam tests to build expected
collaboration specs through `codex-tools`
- updated `codex-rs/tools/README.md` so the crate documentation reflects
the broader collaboration-tool boundary

## Test plan

- `CARGO_TARGET_DIR=/tmp/codex-tools-collab-specs cargo test -p
codex-tools`
- `CARGO_TARGET_DIR=/tmp/codex-core-collab-specs cargo test -p
codex-core --lib tools::spec::`
- `just fix -p codex-tools -p codex-core`
- `just argument-comment-lint`

## References

- #15923
- #15928
- #15944
- #15953
- #16031
- #16047
- #16129
- #16132
- #16138
This commit is contained in:
Michael Bolin
2026-03-28 20:39:47 -07:00
committed by GitHub
parent 3807807f91
commit 7880414a27
10 changed files with 1461 additions and 940 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -16,14 +16,27 @@ use codex_tools::ConfiguredToolSpec;
use codex_tools::FreeformTool;
use codex_tools::ResponsesApiWebSearchFilters;
use codex_tools::ResponsesApiWebSearchUserLocation;
use codex_tools::SpawnAgentToolOptions;
use codex_tools::ViewImageToolOptions;
use codex_tools::WaitAgentTimeoutOptions;
use codex_tools::create_close_agent_tool_v1;
use codex_tools::create_close_agent_tool_v2;
use codex_tools::create_exec_command_tool;
use codex_tools::create_request_permissions_tool;
use codex_tools::create_request_user_input_tool;
use codex_tools::create_resume_agent_tool;
use codex_tools::create_send_input_tool_v1;
use codex_tools::create_send_message_tool;
use codex_tools::create_spawn_agent_tool_v1;
use codex_tools::create_spawn_agent_tool_v2;
use codex_tools::create_view_image_tool;
use codex_tools::create_wait_agent_tool_v1;
use codex_tools::create_wait_agent_tool_v2;
use codex_tools::create_write_stdin_tool;
use codex_tools::mcp_tool_to_deferred_responses_api_tool;
use codex_utils_absolute_path::AbsolutePathBuf;
use pretty_assertions::assert_eq;
use serde_json::json;
use std::path::PathBuf;
use super::*;
@@ -153,6 +166,27 @@ fn shell_tool_name(config: &ToolsConfig) -> Option<&'static str> {
}
}
fn request_user_input_tool_spec(default_mode_request_user_input: bool) -> ToolSpec {
create_request_user_input_tool(request_user_input_tool_description(
default_mode_request_user_input,
))
}
fn spawn_agent_tool_options(config: &ToolsConfig) -> SpawnAgentToolOptions<'_> {
SpawnAgentToolOptions {
available_models: &config.available_models,
agent_type_description: crate::agent::role::spawn_tool_spec::build(&config.agent_roles),
}
}
fn wait_agent_timeout_options() -> WaitAgentTimeoutOptions {
WaitAgentTimeoutOptions {
default_timeout_ms: DEFAULT_WAIT_TIMEOUT_MS,
min_timeout_ms: MIN_WAIT_TIMEOUT_MS,
max_timeout_ms: MAX_WAIT_TIMEOUT_MS,
}
}
fn find_tool<'a>(tools: &'a [ConfiguredToolSpec], expected_name: &str) -> &'a ConfiguredToolSpec {
tools
.iter()
@@ -307,7 +341,7 @@ fn test_full_toolset_specs_for_gpt5_codex_unified_exec_web_search() {
}),
create_write_stdin_tool(),
PLAN_TOOL.clone(),
create_request_user_input_tool(CollaborationModesConfig::default()),
request_user_input_tool_spec(/*default_mode_request_user_input*/ false),
create_apply_patch_freeform_tool(),
ToolSpec::WebSearch {
external_web_access: Some(true),
@@ -324,16 +358,16 @@ fn test_full_toolset_specs_for_gpt5_codex_unified_exec_web_search() {
}
let collab_specs = if config.multi_agent_v2 {
vec![
create_spawn_agent_tool_v2(&config),
create_spawn_agent_tool_v2(spawn_agent_tool_options(&config)),
create_send_message_tool(),
create_wait_agent_tool_v2(),
create_wait_agent_tool_v2(wait_agent_timeout_options()),
create_close_agent_tool_v2(),
]
} else {
vec![
create_spawn_agent_tool_v1(&config),
create_spawn_agent_tool_v1(spawn_agent_tool_options(&config)),
create_send_input_tool_v1(),
create_wait_agent_tool_v1(),
create_wait_agent_tool_v1(wait_agent_timeout_options()),
create_close_agent_tool_v1(),
]
};
@@ -734,7 +768,7 @@ fn request_user_input_description_reflects_default_mode_feature_flag() {
let request_user_input_tool = find_tool(&tools, "request_user_input");
assert_eq!(
request_user_input_tool.spec,
create_request_user_input_tool(CollaborationModesConfig::default())
request_user_input_tool_spec(/*default_mode_request_user_input*/ false)
);
features.enable(Feature::DefaultModeRequestUserInput);
@@ -758,9 +792,7 @@ fn request_user_input_description_reflects_default_mode_feature_flag() {
let request_user_input_tool = find_tool(&tools, "request_user_input");
assert_eq!(
request_user_input_tool.spec,
create_request_user_input_tool(CollaborationModesConfig {
default_mode_request_user_input: true,
})
request_user_input_tool_spec(/*default_mode_request_user_input*/ true)
);
}