mirror of
https://github.com/openai/codex.git
synced 2026-11-07 20:30:33 +00:00
Track multi-agent v2 spawn calls in analytics (#39722)
## What changed - Emit started and completed collaboration tool events for multi-agent v2 `spawn_agent` calls, including failed invocations. - Record execution duration and successful child-agent configuration metadata without including the spawn prompt. - Deduplicate collaboration and subagent activity items by call ID when calculating per-turn subagent tool counts. ## Testing - Extend the app-server multi-agent v2 integration test to cover successful and failed spawn telemetry, duration, prompt omission, and turn counts. GitOrigin-RevId: c1c2fb9cc2a1a9b0f63ef68509ad36d11a92d1e5
This commit is contained in:
@@ -5,11 +5,15 @@ use crate::agent::next_thread_spawn_depth;
|
||||
use crate::agent::role::DEFAULT_ROLE_NAME;
|
||||
use crate::agent_communication::AgentCommunicationContext;
|
||||
use crate::agent_communication::AgentCommunicationKind;
|
||||
use crate::codex_thread::ThreadConfigSnapshot;
|
||||
use crate::session::multi_agents::resolve_usage_hints;
|
||||
use crate::tools::handlers::multi_agents::collab_tool_call_status;
|
||||
use crate::tools::handlers::multi_agents_spec::SpawnAgentToolOptions;
|
||||
use crate::tools::handlers::multi_agents_spec::create_spawn_agent_tool_v2;
|
||||
use crate::tools::handlers::multi_agents_v2::message_tool::message_content;
|
||||
use crate::turn_timing::now_unix_timestamp_ms;
|
||||
use codex_protocol::AgentPath;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::protocol::MultiAgentVersion;
|
||||
use codex_tools::ToolSpec;
|
||||
|
||||
@@ -34,13 +38,66 @@ impl ToolExecutor<ToolInvocation> for Handler {
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
Box::pin(async move { handle_spawn_agent(invocation).await.map(boxed_tool_output) })
|
||||
Box::pin(async move {
|
||||
let analytics = invocation.session.services.analytics_events_client.clone();
|
||||
let sender_thread_id = invocation.session.thread_id;
|
||||
let turn_id = invocation.step_context.turn.sub_id.clone();
|
||||
let call_id = invocation.call_id.clone();
|
||||
let started_at_ms = now_unix_timestamp_ms();
|
||||
let result = handle_spawn_agent(invocation).await;
|
||||
let completed_at_ms = now_unix_timestamp_ms();
|
||||
let (status, receiver_thread_ids, agents_states) = match &result {
|
||||
Ok((_, thread_id, agent_status, _)) => (
|
||||
collab_tool_call_status(agent_status, Some(*thread_id)),
|
||||
vec![*thread_id],
|
||||
[(*thread_id, agent_status.clone())].into_iter().collect(),
|
||||
),
|
||||
Err(_) => (
|
||||
CollabAgentToolCallStatus::Failed,
|
||||
Vec::new(),
|
||||
Default::default(),
|
||||
),
|
||||
};
|
||||
let agent_snapshot = result
|
||||
.as_ref()
|
||||
.ok()
|
||||
.and_then(|(_, _, _, snapshot)| snapshot.as_ref());
|
||||
|
||||
analytics.track_collab_tool_call(
|
||||
turn_id,
|
||||
CollabAgentToolCallItem {
|
||||
id: call_id,
|
||||
tool: CollabAgentTool::SpawnAgent,
|
||||
status,
|
||||
sender_thread_id,
|
||||
receiver_thread_ids,
|
||||
receiver_agents: Vec::new(),
|
||||
prompt: None,
|
||||
model: agent_snapshot.map(|snapshot| snapshot.model.clone()),
|
||||
reasoning_effort: agent_snapshot
|
||||
.and_then(|snapshot| snapshot.reasoning_effort.clone()),
|
||||
agents_states,
|
||||
},
|
||||
started_at_ms,
|
||||
completed_at_ms,
|
||||
);
|
||||
|
||||
result.map(|(output, _, _, _)| boxed_tool_output(output))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_spawn_agent(
|
||||
invocation: ToolInvocation,
|
||||
) -> Result<SpawnAgentResult, FunctionCallError> {
|
||||
) -> Result<
|
||||
(
|
||||
SpawnAgentResult,
|
||||
ThreadId,
|
||||
AgentStatus,
|
||||
Option<ThreadConfigSnapshot>,
|
||||
),
|
||||
FunctionCallError,
|
||||
> {
|
||||
let ToolInvocation {
|
||||
session,
|
||||
step_context,
|
||||
@@ -163,6 +220,7 @@ async fn handle_spawn_agent(
|
||||
.await
|
||||
.map_err(collab_spawn_error)?;
|
||||
let new_thread_id = spawned_agent.thread_id;
|
||||
let agent_status = spawned_agent.status;
|
||||
let agent_snapshot = session
|
||||
.services
|
||||
.agent_control
|
||||
@@ -192,14 +250,15 @@ async fn handle_spawn_agent(
|
||||
let task_name = String::from(new_agent_path);
|
||||
|
||||
let hide_agent_metadata = turn.config.multi_agent_v2.hide_spawn_agent_metadata;
|
||||
if hide_agent_metadata {
|
||||
Ok(SpawnAgentResult::HiddenMetadata { task_name })
|
||||
let output = if hide_agent_metadata {
|
||||
SpawnAgentResult::HiddenMetadata { task_name }
|
||||
} else {
|
||||
Ok(SpawnAgentResult::WithNickname {
|
||||
SpawnAgentResult::WithNickname {
|
||||
task_name,
|
||||
nickname,
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok((output, new_thread_id, agent_status, agent_snapshot))
|
||||
}
|
||||
|
||||
impl CoreToolRuntime for Handler {
|
||||
|
||||
Reference in New Issue
Block a user