mirror of
https://github.com/openai/codex.git
synced 2026-10-28 18:58:46 +00:00
## What changed Add `model` and `reasoningEffort` to `subAgentActivity` items for multi-agent v2 spawns. Capture startup settings before the child begins its turn and resolve the reported effort against model metadata, including model defaults, while preserving the child's configured effort. Carry these fields through live notifications, persisted activity, thread history, and legacy rollout migration. Update the JSON schemas and generated TypeScript and Python types. Older records and other activity kinds retain null values. ## Testing Add coverage for resolved spawn settings matching the child's request across legacy and paginated history, preserving configured effort, forwarding metadata through events and history, and reading and migrating older records without the new fields. GitOrigin-RevId: a9e4241ae21bb8db1ead293f78ffba8257cca0ae
152 lines
5.2 KiB
Rust
152 lines
5.2 KiB
Rust
use codex_protocol::AgentPath;
|
|
use codex_protocol::ThreadId;
|
|
use codex_protocol::protocol::EventMsg;
|
|
use codex_protocol::protocol::ExecCommandBeginEvent;
|
|
use codex_protocol::protocol::ExecCommandEndEvent;
|
|
use codex_protocol::protocol::ExecCommandSource;
|
|
use codex_protocol::protocol::ExecCommandStatus;
|
|
use codex_protocol::protocol::SubAgentActivityEvent;
|
|
use codex_protocol::protocol::SubAgentActivityKind;
|
|
use pretty_assertions::assert_eq;
|
|
use serde_json::json;
|
|
use std::time::Duration;
|
|
|
|
use super::ToolRuntimeTraceEvent;
|
|
use super::tool_runtime_trace_event;
|
|
use crate::ExecutionStatus;
|
|
|
|
#[test]
|
|
fn sub_agent_activity_is_a_terminal_tool_runtime_event() -> anyhow::Result<()> {
|
|
let agent_thread_id = ThreadId::new();
|
|
let event = EventMsg::SubAgentActivity(SubAgentActivityEvent {
|
|
model: Some("gpt-5".into()),
|
|
reasoning_effort: Some(codex_protocol::openai_models::ReasoningEffort::High),
|
|
event_id: "call-spawn".to_string(),
|
|
occurred_at_ms: 1234,
|
|
agent_thread_id,
|
|
agent_path: AgentPath::try_from("/root/reviewer").map_err(anyhow::Error::msg)?,
|
|
kind: SubAgentActivityKind::Started,
|
|
});
|
|
|
|
let Some(ToolRuntimeTraceEvent::Ended {
|
|
tool_call_id,
|
|
status,
|
|
payload,
|
|
}) = tool_runtime_trace_event(&event)
|
|
else {
|
|
panic!("expected terminal tool runtime event");
|
|
};
|
|
|
|
assert_eq!(tool_call_id, "call-spawn");
|
|
assert_eq!(status, ExecutionStatus::Completed);
|
|
assert_eq!(
|
|
serde_json::to_value(payload)?,
|
|
json!({
|
|
"event_id": "call-spawn",
|
|
"occurred_at_ms": 1234,
|
|
"agent_thread_id": agent_thread_id,
|
|
"agent_path": "/root/reviewer",
|
|
"kind": "started",
|
|
"model": "gpt-5",
|
|
"reasoning_effort": "high"
|
|
})
|
|
);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn completed_sub_agent_activity_is_not_a_tool_runtime_event() -> anyhow::Result<()> {
|
|
let event = EventMsg::SubAgentActivity(SubAgentActivityEvent {
|
|
model: None,
|
|
reasoning_effort: None,
|
|
event_id: "child-turn-completed".to_string(),
|
|
occurred_at_ms: 1234,
|
|
agent_thread_id: ThreadId::new(),
|
|
agent_path: AgentPath::try_from("/root/reviewer").map_err(anyhow::Error::msg)?,
|
|
kind: SubAgentActivityKind::Completed,
|
|
});
|
|
|
|
assert!(tool_runtime_trace_event(&event).is_none());
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn exec_command_trace_payloads_use_inferred_native_cwd() -> anyhow::Result<()> {
|
|
// Convention inference depends on the URI spelling, not the test host, so exercise both
|
|
// Windows and POSIX paths on every platform.
|
|
let begin = EventMsg::ExecCommandBegin(ExecCommandBeginEvent {
|
|
call_id: "call-begin".to_string(),
|
|
plugin_id: Some("sample@openai-curated".to_string()),
|
|
script_path: Some("scripts/run.py".to_string()),
|
|
process_id: Some("process-1".to_string()),
|
|
turn_id: "turn-1".to_string(),
|
|
started_at_ms: 1234,
|
|
command: vec!["pwd".to_string()],
|
|
cwd: "file:///C:/windows".parse()?,
|
|
parsed_cmd: Vec::new(),
|
|
source: ExecCommandSource::Agent,
|
|
interaction_input: None,
|
|
});
|
|
let end = EventMsg::ExecCommandEnd(ExecCommandEndEvent {
|
|
call_id: "call-end".to_string(),
|
|
plugin_id: Some("sample@openai-curated".to_string()),
|
|
script_path: Some("scripts/run.py".to_string()),
|
|
process_id: None,
|
|
turn_id: "turn-1".to_string(),
|
|
completed_at_ms: 2345,
|
|
command: vec!["pwd".to_string()],
|
|
cwd: "file:///workspace/project".parse()?,
|
|
parsed_cmd: Vec::new(),
|
|
source: ExecCommandSource::UnifiedExecInteraction,
|
|
interaction_input: Some("input".to_string()),
|
|
aggregated_output: "combined output".to_string(),
|
|
exit_code: 0,
|
|
duration: Duration::from_millis(250),
|
|
status: ExecCommandStatus::Completed,
|
|
});
|
|
|
|
let Some(ToolRuntimeTraceEvent::Started { payload, .. }) = tool_runtime_trace_event(&begin)
|
|
else {
|
|
panic!("expected started tool runtime event");
|
|
};
|
|
assert_eq!(
|
|
serde_json::to_value(payload)?,
|
|
json!({
|
|
"call_id": "call-begin",
|
|
"plugin_id": "sample@openai-curated",
|
|
"script_path": "scripts/run.py",
|
|
"process_id": "process-1",
|
|
"turn_id": "turn-1",
|
|
"started_at_ms": 1234,
|
|
"command": ["pwd"],
|
|
"cwd": r"C:\windows",
|
|
"parsed_cmd": [],
|
|
"source": "agent"
|
|
})
|
|
);
|
|
|
|
let Some(ToolRuntimeTraceEvent::Ended { payload, .. }) = tool_runtime_trace_event(&end) else {
|
|
panic!("expected ended tool runtime event");
|
|
};
|
|
assert_eq!(
|
|
serde_json::to_value(payload)?,
|
|
json!({
|
|
"call_id": "call-end",
|
|
"plugin_id": "sample@openai-curated",
|
|
"script_path": "scripts/run.py",
|
|
"turn_id": "turn-1",
|
|
"completed_at_ms": 2345,
|
|
"command": ["pwd"],
|
|
"cwd": "/workspace/project",
|
|
"parsed_cmd": [],
|
|
"source": "unified_exec_interaction",
|
|
"interaction_input": "input",
|
|
"aggregated_output": "combined output",
|
|
"exit_code": 0,
|
|
"duration": {"secs": 0, "nanos": 250000000},
|
|
"status": "completed"
|
|
})
|
|
);
|
|
Ok(())
|
|
}
|