mirror of
https://github.com/openai/codex.git
synced 2026-11-13 06:45:07 +00:00
Timestamp app-server notifications at emission (#32905)
## What changed - Add an optional `emittedAtMs` field to server notification envelopes and expose the envelope in the generated JSON and TypeScript schemas. - Populate the Unix timestamp when app-server emits a notification, before transport routing, so every connection in a fan-out receives the same value. - Keep the field optional for clients decoding notifications from older app-server versions. ## Testing - Verify notification serialization includes `emittedAtMs`. - Verify targeted fan-out reuses one timestamp across connections. GitOrigin-RevId: b379cb11e8e91c558bcd3d46ce459311a6e81e54
This commit is contained in:
1 parent
7f3eb8a223
commit
c39520f3d1
22 files changed
+400
-171
No files matched your search
@@ -3,7 +3,7 @@ use std::fmt;
|
||||
use codex_app_server_protocol::JSONRPCErrorError;
|
||||
use codex_app_server_protocol::RequestId;
|
||||
use codex_app_server_protocol::Result;
|
||||
use codex_app_server_protocol::ServerNotification;
|
||||
use codex_app_server_protocol::ServerNotificationEnvelope;
|
||||
use codex_app_server_protocol::ServerRequest;
|
||||
use serde::Serialize;
|
||||
use tokio::sync::oneshot;
|
||||
@@ -25,7 +25,7 @@ pub enum OutgoingMessage {
|
||||
Request(ServerRequest),
|
||||
/// AppServerNotification is specific to the case where this is run as an
|
||||
/// "app server" as opposed to an MCP server.
|
||||
AppServerNotification(ServerNotification),
|
||||
AppServerNotification(ServerNotificationEnvelope),
|
||||
Response(OutgoingResponse),
|
||||
Error(OutgoingError),
|
||||
}
|
||||
|
||||
@@ -281,6 +281,7 @@ mod tests {
|
||||
use codex_app_server_protocol::JSONRPCResponse;
|
||||
use codex_app_server_protocol::RequestId;
|
||||
use codex_app_server_protocol::ServerNotification;
|
||||
use codex_app_server_protocol::ServerNotificationEnvelope;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::json;
|
||||
use tokio::time::Duration;
|
||||
@@ -443,14 +444,15 @@ mod tests {
|
||||
|
||||
writer_tx
|
||||
.send(QueuedOutgoingMessage::new(
|
||||
OutgoingMessage::AppServerNotification(ServerNotification::ConfigWarning(
|
||||
ConfigWarningNotification {
|
||||
OutgoingMessage::AppServerNotification(ServerNotificationEnvelope {
|
||||
notification: ServerNotification::ConfigWarning(ConfigWarningNotification {
|
||||
summary: "queued".to_string(),
|
||||
details: None,
|
||||
path: None,
|
||||
range: None,
|
||||
},
|
||||
)),
|
||||
}),
|
||||
emitted_at_ms: Some(1_234),
|
||||
}),
|
||||
))
|
||||
.await
|
||||
.expect("writer queue should accept first message");
|
||||
@@ -484,6 +486,7 @@ mod tests {
|
||||
"summary": "queued",
|
||||
"details": null,
|
||||
},
|
||||
"emittedAtMs": 1_234,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -448,6 +448,7 @@ mod tests {
|
||||
use codex_app_server_protocol::JSONRPCRequest;
|
||||
use codex_app_server_protocol::RequestId;
|
||||
use codex_app_server_protocol::ServerNotification;
|
||||
use codex_app_server_protocol::ServerNotificationEnvelope;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::json;
|
||||
use tokio::time::timeout;
|
||||
@@ -588,14 +589,15 @@ mod tests {
|
||||
|
||||
writer
|
||||
.send(QueuedOutgoingMessage::new(
|
||||
OutgoingMessage::AppServerNotification(ServerNotification::ConfigWarning(
|
||||
ConfigWarningNotification {
|
||||
OutgoingMessage::AppServerNotification(ServerNotificationEnvelope {
|
||||
notification: ServerNotification::ConfigWarning(ConfigWarningNotification {
|
||||
summary: "test".to_string(),
|
||||
details: None,
|
||||
path: None,
|
||||
range: None,
|
||||
},
|
||||
)),
|
||||
}),
|
||||
emitted_at_ms: Some(1_234),
|
||||
}),
|
||||
))
|
||||
.await
|
||||
.expect("writer should accept queued message");
|
||||
|
||||
@@ -14,6 +14,7 @@ use codex_app_server_protocol::ConfigWarningNotification;
|
||||
use codex_app_server_protocol::JSONRPCMessage;
|
||||
use codex_app_server_protocol::JSONRPCNotification;
|
||||
use codex_app_server_protocol::ServerNotification;
|
||||
use codex_app_server_protocol::ServerNotificationEnvelope;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
@@ -74,12 +75,15 @@ fn splits_large_server_messages_into_wire_chunks() {
|
||||
let envelope = ServerEnvelope {
|
||||
event: ServerEvent::ServerMessage {
|
||||
message: Box::new(OutgoingMessage::AppServerNotification(
|
||||
ServerNotification::ConfigWarning(ConfigWarningNotification {
|
||||
summary: "x".repeat(REMOTE_CONTROL_SEGMENT_MAX_BYTES),
|
||||
details: None,
|
||||
path: None,
|
||||
range: None,
|
||||
}),
|
||||
ServerNotificationEnvelope {
|
||||
notification: ServerNotification::ConfigWarning(ConfigWarningNotification {
|
||||
summary: "x".repeat(REMOTE_CONTROL_SEGMENT_MAX_BYTES),
|
||||
details: None,
|
||||
path: None,
|
||||
range: None,
|
||||
}),
|
||||
emitted_at_ms: Some(1_234),
|
||||
},
|
||||
)),
|
||||
},
|
||||
client_id: ClientId("client-1".to_string()),
|
||||
|
||||
@@ -25,6 +25,7 @@ use codex_app_server_protocol::RemoteControlPairingStartParams;
|
||||
use codex_app_server_protocol::RemoteControlPairingStatusParams;
|
||||
use codex_app_server_protocol::RemoteControlStatusChangedNotification;
|
||||
use codex_app_server_protocol::ServerNotification;
|
||||
use codex_app_server_protocol::ServerNotificationEnvelope;
|
||||
use codex_config::types::AuthCredentialsStoreMode;
|
||||
use codex_core::test_support::auth_manager_from_auth;
|
||||
use codex_core::test_support::auth_manager_from_auth_with_home;
|
||||
@@ -736,14 +737,15 @@ async fn remote_control_transport_manages_virtual_clients_and_routes_messages()
|
||||
|
||||
writer
|
||||
.send(QueuedOutgoingMessage::new(
|
||||
OutgoingMessage::AppServerNotification(ServerNotification::ConfigWarning(
|
||||
ConfigWarningNotification {
|
||||
OutgoingMessage::AppServerNotification(ServerNotificationEnvelope {
|
||||
notification: ServerNotification::ConfigWarning(ConfigWarningNotification {
|
||||
summary: "test".to_string(),
|
||||
details: None,
|
||||
path: None,
|
||||
range: None,
|
||||
},
|
||||
)),
|
||||
}),
|
||||
emitted_at_ms: Some(1_234),
|
||||
}),
|
||||
))
|
||||
.await
|
||||
.expect("remote writer should accept outgoing message");
|
||||
@@ -758,7 +760,8 @@ async fn remote_control_transport_manages_virtual_clients_and_routes_messages()
|
||||
"params": {
|
||||
"summary": "test",
|
||||
"details": null,
|
||||
}
|
||||
},
|
||||
"emittedAtMs": 1_234,
|
||||
}
|
||||
})
|
||||
);
|
||||
@@ -1344,14 +1347,15 @@ async fn remote_control_transport_clears_outgoing_buffer_when_backend_acks() {
|
||||
|
||||
writer
|
||||
.send(QueuedOutgoingMessage::new(
|
||||
OutgoingMessage::AppServerNotification(ServerNotification::ConfigWarning(
|
||||
ConfigWarningNotification {
|
||||
OutgoingMessage::AppServerNotification(ServerNotificationEnvelope {
|
||||
notification: ServerNotification::ConfigWarning(ConfigWarningNotification {
|
||||
summary: "stale".to_string(),
|
||||
details: None,
|
||||
path: None,
|
||||
range: None,
|
||||
},
|
||||
)),
|
||||
}),
|
||||
emitted_at_ms: Some(1_234),
|
||||
}),
|
||||
))
|
||||
.await
|
||||
.expect("remote writer should accept outgoing message");
|
||||
@@ -1367,7 +1371,8 @@ async fn remote_control_transport_clears_outgoing_buffer_when_backend_acks() {
|
||||
"params": {
|
||||
"summary": "stale",
|
||||
"details": null,
|
||||
}
|
||||
},
|
||||
"emittedAtMs": 1_234,
|
||||
}
|
||||
})
|
||||
);
|
||||
@@ -1634,14 +1639,15 @@ async fn remote_control_http_mode_enrolls_before_connecting() {
|
||||
|
||||
writer
|
||||
.send(QueuedOutgoingMessage::new(
|
||||
OutgoingMessage::AppServerNotification(ServerNotification::ConfigWarning(
|
||||
ConfigWarningNotification {
|
||||
OutgoingMessage::AppServerNotification(ServerNotificationEnvelope {
|
||||
notification: ServerNotification::ConfigWarning(ConfigWarningNotification {
|
||||
summary: "backend".to_string(),
|
||||
details: None,
|
||||
path: None,
|
||||
range: None,
|
||||
},
|
||||
)),
|
||||
}),
|
||||
emitted_at_ms: Some(1_234),
|
||||
}),
|
||||
))
|
||||
.await
|
||||
.expect("remote writer should accept outgoing message");
|
||||
@@ -1656,7 +1662,8 @@ async fn remote_control_http_mode_enrolls_before_connecting() {
|
||||
"params": {
|
||||
"summary": "backend",
|
||||
"details": null,
|
||||
}
|
||||
},
|
||||
"emittedAtMs": 1_234,
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1825,6 +1825,7 @@ mod tests {
|
||||
use codex_app_server_protocol::JSONRPCMessage;
|
||||
use codex_app_server_protocol::JSONRPCNotification;
|
||||
use codex_app_server_protocol::ServerNotification;
|
||||
use codex_app_server_protocol::ServerNotificationEnvelope;
|
||||
use codex_config::types::AuthCredentialsStoreMode;
|
||||
use codex_core::test_support::auth_manager_from_auth;
|
||||
use codex_login::AuthDotJson;
|
||||
@@ -3362,12 +3363,17 @@ mod tests {
|
||||
ServerEnvelope {
|
||||
event: ServerEvent::ServerMessage {
|
||||
message: Box::new(OutgoingMessage::AppServerNotification(
|
||||
ServerNotification::ConfigWarning(ConfigWarningNotification {
|
||||
summary: summary.to_string(),
|
||||
details: None,
|
||||
path: None,
|
||||
range: None,
|
||||
}),
|
||||
ServerNotificationEnvelope {
|
||||
notification: ServerNotification::ConfigWarning(
|
||||
ConfigWarningNotification {
|
||||
summary: summary.to_string(),
|
||||
details: None,
|
||||
path: None,
|
||||
range: None,
|
||||
},
|
||||
),
|
||||
emitted_at_ms: Some(1_234),
|
||||
},
|
||||
)),
|
||||
},
|
||||
client_id: client_id.clone(),
|
||||
|
||||
Reference in new issue
Block a user