Stop emitting item/fileChange/outputDelta output delta notifications (#20471)

## Why

`item/fileChange/outputDelta` text output was only the tool's summary or
error text and not used by client surfaces.

We keep `item/fileChange/outputDelta` in the app-server protocol as a
deprecated compatibility entry, but the server no longer emits it.

## What changed

- stop the `apply_patch` runtime from emitting `ExecCommandOutputDelta`
events
- simplify `item_event_to_server_notification` so command output deltas
always map to `item/commandExecution/outputDelta`
- remove the app-server bookkeeping that tried to detect whether an
output delta belonged to a file change
- mark `item/fileChange/outputDelta` as a deprecated legacy protocol
entry in the v2 types, schema, and README
- simplify the file-change approval tests so they only wait for
completion instead of expecting output-delta notifications

## Testing

- `cargo test -p codex-app-server-protocol`
- `cargo test -p codex-thread-manager-sample`
- `cargo test -p codex-app-server-protocol
protocol::event_mapping::tests::exec_command_output_delta_maps_to_command_execution_output_delta
-- --exact`
- `cargo test -p codex-app-server
turn_start_file_change_approval_accept_for_session_persists_v2 --
--exact` *(failed before the test assertions because the wiremock
`/responses` mock received 0 requests in setup)*
This commit is contained in:
pakrym-oai
2026-04-30 11:42:07 -07:00
committed by GitHub
Unverified
parent f2bc2f26a9
commit b52083146c
13 changed files with 59 additions and 96 deletions
@@ -1397,6 +1397,7 @@ server_notification_definitions! {
CommandExecOutputDelta => "command/exec/outputDelta" (v2::CommandExecOutputDeltaNotification),
CommandExecutionOutputDelta => "item/commandExecution/outputDelta" (v2::CommandExecutionOutputDeltaNotification),
TerminalInteraction => "item/commandExecution/terminalInteraction" (v2::TerminalInteractionNotification),
/// Deprecated legacy apply_patch output stream notification.
FileChangeOutputDelta => "item/fileChange/outputDelta" (v2::FileChangeOutputDeltaNotification),
FileChangePatchUpdated => "item/fileChange/patchUpdated" (v2::FileChangePatchUpdatedNotification),
ServerRequestResolved => "serverRequest/resolved" (v2::ServerRequestResolvedNotification),
@@ -10,7 +10,6 @@ use crate::protocol::v2::CollabAgentToolCallStatus;
use crate::protocol::v2::CommandExecutionOutputDeltaNotification;
use crate::protocol::v2::DynamicToolCallOutputContentItem;
use crate::protocol::v2::DynamicToolCallStatus;
use crate::protocol::v2::FileChangeOutputDeltaNotification;
use crate::protocol::v2::FileChangePatchUpdatedNotification;
use crate::protocol::v2::ItemCompletedNotification;
use crate::protocol::v2::ItemStartedNotification;
@@ -37,7 +36,6 @@ pub fn item_event_to_server_notification(
msg: EventMsg,
thread_id: &str,
turn_id: &str,
is_file_change_output: bool,
) -> ServerNotification {
let thread_id = thread_id.to_string();
let turn_id = turn_id.to_string();
@@ -477,23 +475,14 @@ pub fn item_event_to_server_notification(
EventMsg::ExecCommandOutputDelta(exec_command_output_delta_event) => {
let item_id = exec_command_output_delta_event.call_id;
let delta = String::from_utf8_lossy(&exec_command_output_delta_event.chunk).to_string();
if is_file_change_output {
ServerNotification::FileChangeOutputDelta(FileChangeOutputDeltaNotification {
ServerNotification::CommandExecutionOutputDelta(
CommandExecutionOutputDeltaNotification {
thread_id,
turn_id,
item_id,
delta,
})
} else {
ServerNotification::CommandExecutionOutputDelta(
CommandExecutionOutputDeltaNotification {
thread_id,
turn_id,
item_id,
delta,
},
)
}
},
)
}
EventMsg::TerminalInteraction(terminal_event) => {
ServerNotification::TerminalInteraction(TerminalInteractionNotification {
@@ -522,6 +511,8 @@ mod tests {
use codex_protocol::mcp::CallToolResult;
use codex_protocol::protocol::CollabResumeBeginEvent;
use codex_protocol::protocol::CollabResumeEndEvent;
use codex_protocol::protocol::ExecCommandOutputDeltaEvent;
use codex_protocol::protocol::ExecOutputStream;
use codex_protocol::protocol::McpInvocation;
use codex_protocol::protocol::McpToolCallBeginEvent;
use codex_protocol::protocol::McpToolCallEndEvent;
@@ -549,6 +540,18 @@ mod tests {
}
}
fn assert_command_execution_output_delta_server_notification(
notification: ServerNotification,
expected: CommandExecutionOutputDeltaNotification,
) {
match notification {
ServerNotification::CommandExecutionOutputDelta(payload) => {
assert_eq!(payload, expected)
}
other => panic!("expected command execution output delta, got {other:?}"),
}
}
#[test]
fn collab_resume_begin_maps_to_item_started_resume_agent() {
let event = CollabResumeBeginEvent {
@@ -563,7 +566,6 @@ mod tests {
EventMsg::CollabResumeBegin(event.clone()),
"thread-1",
"turn-1",
/*is_file_change_output*/ false,
);
assert_item_started_server_notification(
notification,
@@ -601,7 +603,6 @@ mod tests {
EventMsg::CollabResumeEnd(event.clone()),
"thread-2",
"turn-2",
/*is_file_change_output*/ false,
);
assert_item_completed_server_notification(
notification,
@@ -644,7 +645,6 @@ mod tests {
EventMsg::McpToolCallBegin(begin_event.clone()),
"thread-1",
"turn_1",
/*is_file_change_output*/ false,
);
assert_item_started_server_notification(
notification,
@@ -682,7 +682,6 @@ mod tests {
EventMsg::McpToolCallBegin(begin_event.clone()),
"thread-2",
"turn_2",
/*is_file_change_output*/ false,
);
assert_item_started_server_notification(
notification,
@@ -735,7 +734,6 @@ mod tests {
EventMsg::McpToolCallEnd(end_event.clone()),
"thread-3",
"turn_3",
/*is_file_change_output*/ false,
);
assert_item_completed_server_notification(
notification,
@@ -781,7 +779,6 @@ mod tests {
EventMsg::McpToolCallEnd(end_event.clone()),
"thread-4",
"turn_4",
/*is_file_change_output*/ false,
);
assert_item_completed_server_notification(
notification,
@@ -804,4 +801,27 @@ mod tests {
},
);
}
#[test]
fn exec_command_output_delta_maps_to_command_execution_output_delta() {
let notification = item_event_to_server_notification(
EventMsg::ExecCommandOutputDelta(ExecCommandOutputDeltaEvent {
call_id: "call-1".to_string(),
stream: ExecOutputStream::Stdout,
chunk: b"hello".to_vec(),
}),
"thread-1",
"turn-1",
);
assert_command_execution_output_delta_server_notification(
notification,
CommandExecutionOutputDeltaNotification {
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
item_id: "call-1".to_string(),
delta: "hello".to_string(),
},
);
}
}
@@ -6992,6 +6992,9 @@ pub struct CommandExecOutputDeltaNotification {
pub cap_reached: bool,
}
/// Deprecated legacy notification for `apply_patch` textual output.
///
/// The server no longer emits this notification.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]