From 11c87546c37adfba6512fe3c1a8b830d12789ef7 Mon Sep 17 00:00:00 2001 From: Owen Lin Date: Sat, 1 Nov 2025 13:34:22 -0700 Subject: [PATCH] use macros to generate notifications --- codex-rs/app-server-protocol/src/export.rs | 6 +- .../src/protocol/common.rs | 109 +++++++++++++----- 2 files changed, 85 insertions(+), 30 deletions(-) diff --git a/codex-rs/app-server-protocol/src/export.rs b/codex-rs/app-server-protocol/src/export.rs index 09fed54994..10e5da73ba 100644 --- a/codex-rs/app-server-protocol/src/export.rs +++ b/codex-rs/app-server-protocol/src/export.rs @@ -2,9 +2,11 @@ use crate::ClientNotification; use crate::ClientRequest; use crate::ServerNotification; use crate::ServerRequest; +use crate::export_client_notification_schemas; use crate::export_client_param_schemas; use crate::export_client_response_schemas; use crate::export_client_responses; +use crate::export_server_notification_schemas; use crate::export_server_param_schemas; use crate::export_server_response_schemas; use crate::export_server_responses; @@ -122,11 +124,13 @@ pub fn generate_json(out_dir: &Path) -> Result<()> { bundle.insert((*name).to_string(), schema); } - // Have the macros generate per-type JSON for params and responses. + // Have the macros generate per-type JSON for params, responses, and notifications. export_client_param_schemas(out_dir)?; export_client_response_schemas(out_dir)?; export_server_param_schemas(out_dir)?; export_server_response_schemas(out_dir)?; + export_client_notification_schemas(out_dir)?; + export_server_notification_schemas(out_dir)?; let mut definitions = Map::new(); diff --git a/codex-rs/app-server-protocol/src/protocol/common.rs b/codex-rs/app-server-protocol/src/protocol/common.rs index be52e56a0b..921107edd5 100644 --- a/codex-rs/app-server-protocol/src/protocol/common.rs +++ b/codex-rs/app-server-protocol/src/protocol/common.rs @@ -350,6 +350,84 @@ macro_rules! server_request_definitions { }; } +/// Generates `ServerNotification` enum and helpers, including a JSON Schema +/// exporter for each variant payload type. +macro_rules! server_notification_definitions { + ( + $( + $(#[$variant_meta:meta])* + $variant:ident ( $payload:ty ) + ),* $(,)? + ) => { + /// Notification sent from the server to the client. + #[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, TS, Display)] + #[serde(tag = "method", content = "params", rename_all = "camelCase")] + #[strum(serialize_all = "camelCase")] + pub enum ServerNotification { + $( + $(#[$variant_meta])* + $variant($payload), + )* + } + + impl ServerNotification { + pub fn to_params(self) -> Result { + match self { + $(Self::$variant(params) => serde_json::to_value(params),)* + } + } + } + + impl TryFrom for ServerNotification { + type Error = serde_json::Error; + + fn try_from(value: JSONRPCNotification) -> Result { + serde_json::from_value(serde_json::to_value(value)?) + } + } + + pub fn export_server_notification_schemas( + _out_dir: &::std::path::Path, + ) -> ::anyhow::Result<()> { + $( + crate::export::write_json_schema::<$payload>(_out_dir, stringify!($payload))?; + )* + Ok(()) + } + }; +} + +/// Generates `ClientNotification` enum and a JSON Schema exporter for +/// any payload-bearing variants (unit variants produce no payload schema). +macro_rules! client_notification_definitions { + ( + $( + $(#[$variant_meta:meta])* + $variant:ident $( ( $payload:ty ) )? + ),* $(,)? + ) => { + /// Notification sent from the client to the server. + #[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, TS, Display)] + #[serde(tag = "method", content = "params", rename_all = "camelCase")] + #[strum(serialize_all = "camelCase")] + pub enum ClientNotification { + $( + $(#[$variant_meta])* + $variant $( ( $payload ) )? , + )* + } + + pub fn export_client_notification_schemas( + _out_dir: &::std::path::Path, + ) -> ::anyhow::Result<()> { + $( + $(crate::export::write_json_schema::<$payload>(_out_dir, stringify!($payload))?;)? + )* + Ok(()) + } + }; +} + impl TryFrom for ServerRequest { type Error = serde_json::Error; @@ -429,11 +507,7 @@ pub struct FuzzyFileSearchResponse { pub files: Vec, } -/// Notification sent from the server to the client. -#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, TS, Display)] -#[serde(tag = "method", content = "params", rename_all = "camelCase")] -#[strum(serialize_all = "camelCase")] -pub enum ServerNotification { +server_notification_definitions! { /// NEW NOTIFICATIONS #[serde(rename = "account/rateLimits/updated")] #[ts(rename = "account/rateLimits/updated")] @@ -451,30 +525,7 @@ pub enum ServerNotification { SessionConfigured(v1::SessionConfiguredNotification), } -impl ServerNotification { - pub fn to_params(self) -> Result { - match self { - ServerNotification::AccountRateLimitsUpdated(params) => serde_json::to_value(params), - ServerNotification::AuthStatusChange(params) => serde_json::to_value(params), - ServerNotification::LoginChatGptComplete(params) => serde_json::to_value(params), - ServerNotification::SessionConfigured(params) => serde_json::to_value(params), - } - } -} - -impl TryFrom for ServerNotification { - type Error = serde_json::Error; - - fn try_from(value: JSONRPCNotification) -> Result { - serde_json::from_value(serde_json::to_value(value)?) - } -} - -/// Notification sent from the client to the server. -#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, TS, Display)] -#[serde(tag = "method", content = "params", rename_all = "camelCase")] -#[strum(serialize_all = "camelCase")] -pub enum ClientNotification { +client_notification_definitions! { Initialized, }