mirror of
https://github.com/openai/codex.git
synced 2026-10-28 18:58:46 +00:00
Centralize Guardian classification of multi-agent tool calls (#57455)
## What changed Add `GuardianScope::for_multi_agent_tool` and use it for both tool review requirements and asynchronous scoring. Classify `spawn_agent`, `send_message`, `followup_task`, and `interrupt_agent` as native tools when they match the configured namespace, accepting default namespace spellings when none is configured. Keep review enablement checks at each call site. GitOrigin-RevId: 9180ccdc629532f6c171d899dc5881e15b447141
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
use crate::session::session::Session;
|
||||
use crate::tools::context::ToolInvocation;
|
||||
use crate::tools::registry::CoreToolRuntime;
|
||||
use codex_protocol::openai_models::GuardianScope;
|
||||
use codex_tools::JsonSchema;
|
||||
use codex_tools::ResponsesApiNamespace;
|
||||
use codex_tools::ResponsesApiNamespaceTool;
|
||||
@@ -123,10 +124,8 @@ impl CoreToolRuntime for MultiAgentV2ToolOverrides {
|
||||
.config
|
||||
.features
|
||||
.enabled(codex_features::Feature::GuardianNativeMultiAgentHistory)
|
||||
&& matches!(
|
||||
self.handler.tool_name().name.as_str(),
|
||||
"spawn_agent" | "send_message" | "followup_task" | "interrupt_agent"
|
||||
)
|
||||
&& GuardianScope::for_multi_agent_tool(&self.tool_name(), self.namespace.as_deref())
|
||||
.is_some()
|
||||
}
|
||||
|
||||
fn wait_until_ready<'a>(&'a self, session: &'a Arc<Session>) -> Option<BoxFuture<'a, ()>> {
|
||||
|
||||
@@ -77,21 +77,16 @@ impl GuardianV2Extension {
|
||||
GuardianScope::for_mcp_connector(&info.server_name, info.connector_id.as_deref())
|
||||
})
|
||||
.or_else(|| {
|
||||
if guardian_config.review_multi_agent_calls
|
||||
&& match guardian_config.multi_agent_namespace.as_deref() {
|
||||
Some(namespace) => input.tool_name.namespace.as_deref() == Some(namespace),
|
||||
None => input.tool_name.is_default_namespace(),
|
||||
}
|
||||
&& matches!(
|
||||
input.tool_name.name.as_str(),
|
||||
"spawn_agent" | "send_message" | "followup_task" | "interrupt_agent"
|
||||
if guardian_config.review_multi_agent_calls {
|
||||
GuardianScope::for_multi_agent_tool(
|
||||
input.tool_name,
|
||||
guardian_config.multi_agent_namespace.as_deref(),
|
||||
)
|
||||
{
|
||||
Some(GuardianScope::NativeTool)
|
||||
} else {
|
||||
GuardianScope::for_tool(input.tool_name)
|
||||
None
|
||||
}
|
||||
});
|
||||
})
|
||||
.or_else(|| GuardianScope::for_tool(input.tool_name));
|
||||
// Model policies review nested actions; the Code Mode wrapper leaves their scores alone.
|
||||
// The legacy all-tools policy still scores wrappers through `other_tools`.
|
||||
if scope.is_none()
|
||||
|
||||
@@ -138,6 +138,25 @@ impl GuardianScope {
|
||||
}
|
||||
}
|
||||
|
||||
/// Classifies state-changing MAv2 calls in the configured namespace.
|
||||
/// An absent namespace accepts the default namespace spellings; callers gate this lookup.
|
||||
pub fn for_multi_agent_tool(tool: &ToolName, namespace: Option<&str>) -> Option<Self> {
|
||||
let matches_namespace = match namespace {
|
||||
Some(namespace) => tool.namespace.as_deref() == Some(namespace),
|
||||
None => tool.is_default_namespace(),
|
||||
};
|
||||
if matches_namespace
|
||||
&& matches!(
|
||||
tool.name.as_str(),
|
||||
"spawn_agent" | "send_message" | "followup_task" | "interrupt_agent"
|
||||
)
|
||||
{
|
||||
Some(Self::NativeTool)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn for_tool(tool: &ToolName) -> Option<Self> {
|
||||
if is_node_repl_backed_tool(&tool.name, tool.namespace.as_deref()) {
|
||||
return Some(Self::ComputerUse);
|
||||
|
||||
Reference in New Issue
Block a user