This commit is contained in:
Ahmed Ibrahim
2025-07-11 17:23:45 -07:00
parent 99df99d006
commit f8d6e97450

View File

@@ -70,177 +70,3 @@ async fn test_summarize_context_spawns_new_agent_task() {
"Expected TaskStarted when no current task exists - should spawn new AgentTask"
);
}
#[tokio::test]
async fn test_summarize_context_injects_into_running_task() {
if std::env::var(CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR).is_ok() {
println!(
"Skipping test because it cannot execute when network is disabled in a Codex sandbox."
);
return;
}
// Set up mock server
let server = MockServer::start().await;
// Custom responder that tracks request count and responds differently
struct SequentialResponder;
impl Respond for SequentialResponder {
fn respond(&self, req: &Request) -> ResponseTemplate {
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
static CALLS: AtomicUsize = AtomicUsize::new(0);
let n = CALLS.fetch_add(1, Ordering::SeqCst);
println!(
"Mock server received request #{n}: {}",
std::str::from_utf8(&req.body).unwrap_or("invalid utf8")
);
if n == 0 {
// First request: respond to initial message but DON'T complete the task
let response = sse_message_no_complete(
"I understand you need help with a coding task. Please go ahead and explain what you're trying to do.",
);
println!("Sending response without complete: {}", response);
ResponseTemplate::new(200)
.insert_header("content-type", "text/event-stream")
.set_body_raw(response, "text/event-stream")
} else {
// Second request: this should be the summary request
let response = sse_message_with_complete(
"resp2",
"Here's a summary of our conversation: You mentioned needing help with a coding task and were about to explain what you're trying to do.",
);
println!("Sending response with complete: {}", response);
ResponseTemplate::new(200)
.insert_header("content-type", "text/event-stream")
.set_body_raw(response, "text/event-stream")
}
}
}
Mock::given(method("POST"))
.and(path("/v1/responses"))
.respond_with(SequentialResponder {})
.expect(2)
.mount(&server)
.await;
// Configure environment
unsafe {
std::env::set_var("OPENAI_REQUEST_MAX_RETRIES", "0");
std::env::set_var("OPENAI_STREAM_MAX_RETRIES", "0");
}
let model_provider = ModelProviderInfo {
name: "openai".into(),
base_url: format!("{}/v1", server.uri()),
env_key: Some("PATH".into()),
env_key_instructions: None,
wire_api: codex_core::WireApi::Responses,
query_params: None,
http_headers: None,
env_http_headers: None,
};
// Set up codex with mock configuration
let codex_home = TempDir::new().unwrap();
let mut config = load_default_config_for_test(&codex_home);
config.model_provider = model_provider;
let ctrl_c = std::sync::Arc::new(tokio::sync::Notify::new());
let (codex, _) = Codex::spawn(config, ctrl_c).await.unwrap();
// Wait for SessionConfigured event
let event = timeout(Duration::from_secs(5), codex.next_event())
.await
.expect("timeout waiting for session configured")
.expect("codex closed");
assert!(
matches!(event.msg, EventMsg::SessionConfigured(_)),
"Expected SessionConfigured event, got: {:?}",
event.msg
);
// First, start a task by submitting user input
let _input_sub_id = codex
.submit(Op::UserInput {
items: vec![InputItem::Text {
text:
"I need help with a coding task. First, let me explain what I'm trying to do..."
.to_string(),
}],
})
.await
.unwrap();
// Wait for the task to start
let event = timeout(Duration::from_secs(5), codex.next_event())
.await
.expect("timeout waiting for task started")
.expect("codex closed");
println!("Got event after UserInput: {:?}", event.msg);
assert!(
matches!(event.msg, EventMsg::TaskStarted),
"First task should start"
);
// Wait for the initial response message
let mut got_initial_response = false;
while !got_initial_response {
let event = timeout(Duration::from_secs(5), codex.next_event())
.await
.expect("timeout waiting for initial response")
.expect("codex closed");
match event.msg {
EventMsg::AgentReasoning(_) | EventMsg::TokenCount(_) => continue,
EventMsg::AgentMessage(_) => {
got_initial_response = true;
}
EventMsg::TaskComplete(_) => {
panic!(
"Task should NOT complete after first message - mock should keep it running"
);
}
other => panic!("Unexpected event: {other:?}"),
}
}
// Now submit SummarizeContext while the task is still running
let _summary_sub_id = codex.submit(Op::SummarizeContext).await.unwrap();
// We should NOT get a new TaskStarted event (that would mean a new task was spawned)
// Instead we should get an AgentMessage with the summary
loop {
let event = timeout(Duration::from_secs(5), codex.next_event())
.await
.expect("timeout waiting for summary message")
.expect("codex closed");
match event.msg {
EventMsg::TaskStarted => {
panic!(
"Got TaskStarted - summary request spawned a new task instead of injecting into existing one!"
);
}
EventMsg::AgentReasoning(_) | EventMsg::TokenCount(_) => continue,
EventMsg::AgentMessage(AgentMessageEvent { message }) => {
// Verify this is the summary message
assert!(
message.contains("summary") || message.contains("conversation"),
"Expected summary content, got: {message}"
);
break;
}
EventMsg::TaskComplete(_) => {
// This is OK after we get the summary message
break;
}
other => panic!("Unexpected event: {other:?}"),
}
}
}