mirror of
https://github.com/openai/codex.git
synced 2026-11-06 20:20:34 +00:00
Enable server-side output truncation for Code Mode sessions (#57870)
## Why Code Mode sessions always used client-side output handling, leaving server truncation settings and observation budgets unused. ## What changed - Honor each session's `output_truncation` setting in the runtime and both host transports, and advertise the bounded-output capability. - Apply `max_output_tokens` independently to execute, wait, and terminate responses in server mode. Keep client mode as the default when the setting is omitted. - Use bounded output collection and rendering in server mode, preserving head and tail output with omission notices. Include script errors in the output budget while retaining failure status and a separate diagnostic capped at 64 KiB. - Estimate audio tokens without the Tokio-dependent cache when rendering bounded output. ## Testing Add runtime and host regression tests for session mode selection, per-request budgets, output overflow, oversized images, zero-token audio output, diagnostic preservation, and termination under output backpressure. GitOrigin-RevId: 3d9661edcdd2dde31526bb92eb83fa0614f0fa88
This commit is contained in:
@@ -474,8 +474,11 @@ async fn run_cell<H: CellHost>(
|
||||
host.closed().await;
|
||||
}
|
||||
|
||||
/// Construct completion only after it has won the terminal decision.
|
||||
fn take_completed_event(output: &mut OutputCollector, error_text: Option<String>) -> CellEvent {
|
||||
/// Construct completion only after the terminal outcome is settled.
|
||||
pub(crate) fn take_completed_event(
|
||||
output: &mut OutputCollector,
|
||||
error_text: Option<String>,
|
||||
) -> CellEvent {
|
||||
let error_text = error_text.map(|error_text| output.collect_error(error_text));
|
||||
CellEvent::Completed {
|
||||
content_items: output.take(),
|
||||
|
||||
@@ -178,6 +178,66 @@ fn spawn_cell_actor_harness_with_host_and_failure_handler<H: CellHost>(
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn termination_drains_a_send_already_blocked_by_backpressure() {
|
||||
let harness = spawn_cell_actor_harness_with_host_and_failure_handler(
|
||||
ObserveMode::YieldAfter(Duration::from_secs(60)),
|
||||
Arc::new(TestHost::default()),
|
||||
CodeModeOutputTruncation::Server,
|
||||
/*task_failure_handler*/ None,
|
||||
);
|
||||
let (termination, capacity) = {
|
||||
let RuntimeEventSender::Bounded(tx) = &harness.event_tx else {
|
||||
panic!("server runtime must use a bounded sender");
|
||||
};
|
||||
// This test owns the V8-side events. The current-thread actor cannot run
|
||||
// before our first await; fill its actual FIFO and register a sender.
|
||||
for _ in 0..tx.max_capacity() {
|
||||
tx.try_send(RuntimeEvent::ContentItem(OutputItem::InputText {
|
||||
text: "queued".to_string(),
|
||||
}))
|
||||
.unwrap();
|
||||
}
|
||||
let mut send = std::pin::pin!(tx.send(RuntimeEvent::ContentItem(OutputItem::InputText {
|
||||
text: "blocked".to_string(),
|
||||
})));
|
||||
assert!(futures::poll!(send.as_mut()).is_pending());
|
||||
// terminate() synchronously cancels. No event was consumed between the
|
||||
// Pending poll and cancellation; run_cell must drain while terminating.
|
||||
let termination = harness.handle.terminate();
|
||||
tokio::time::timeout(Duration::from_secs(1), send)
|
||||
.await
|
||||
.expect("termination must release the registered sender")
|
||||
.expect("actor must drain the blocked item");
|
||||
(termination, tx.max_capacity())
|
||||
};
|
||||
drop(harness.event_tx);
|
||||
let event = tokio::time::timeout(Duration::from_secs(1), termination)
|
||||
.await
|
||||
.expect("termination must finish after draining")
|
||||
.expect("termination event");
|
||||
let mut expected = OutputCollector::new(CodeModeOutputTruncation::Server);
|
||||
for _ in 0..capacity {
|
||||
expected.push(OutputItem::InputText {
|
||||
text: "queued".to_string(),
|
||||
});
|
||||
}
|
||||
expected.push(OutputItem::InputText {
|
||||
text: "blocked".to_string(),
|
||||
});
|
||||
assert_eq!(
|
||||
event,
|
||||
CellEvent::Terminated {
|
||||
content_items: expected,
|
||||
}
|
||||
);
|
||||
assert_eq!(harness.initial_event_rx.await.unwrap(), Ok(event));
|
||||
tokio::time::timeout(Duration::from_secs(1), harness.task)
|
||||
.await
|
||||
.expect("actor must close")
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn unexpected_runtime_thread_exit_is_reported_to_the_session_owner() {
|
||||
let (failure_tx, mut failure_rx) = mpsc::unbounded_channel();
|
||||
|
||||
Reference in New Issue
Block a user