This commit is contained in:
Ahmed Ibrahim
2025-12-16 12:26:46 -08:00
parent bbc5675974
commit 23579e2a76
5 changed files with 58 additions and 0 deletions

View File

@@ -532,6 +532,7 @@ server_notification_definitions! {
McpToolCallProgress => "item/mcpToolCall/progress" (v2::McpToolCallProgressNotification),
McpServerOauthLoginCompleted => "mcpServer/oauthLogin/completed" (v2::McpServerOauthLoginCompletedNotification),
AccountUpdated => "account/updated" (v2::AccountUpdatedNotification),
ModelPresetsUpdated => "model/presets/updated" (v2::ModelPresetsUpdatedNotification),
AccountRateLimitsUpdated => "account/rateLimits/updated" (v2::AccountRateLimitsUpdatedNotification),
ReasoningSummaryTextDelta => "item/reasoning/summaryTextDelta" (v2::ReasoningSummaryTextDeltaNotification),
ReasoningSummaryPartAdded => "item/reasoning/summaryPartAdded" (v2::ReasoningSummaryPartAddedNotification),

View File

@@ -1074,6 +1074,13 @@ pub struct AccountUpdatedNotification {
pub auth_mode: Option<AuthMode>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ModelPresetsUpdatedNotification {
pub models: Vec<Model>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]

View File

@@ -61,6 +61,7 @@ use codex_app_server_protocol::McpServerOauthLoginParams;
use codex_app_server_protocol::McpServerOauthLoginResponse;
use codex_app_server_protocol::ModelListParams;
use codex_app_server_protocol::ModelListResponse;
use codex_app_server_protocol::ModelPresetsUpdatedNotification;
use codex_app_server_protocol::NewConversationParams;
use codex_app_server_protocol::NewConversationResponse;
use codex_app_server_protocol::RemoveConversationListenerParams;
@@ -231,6 +232,17 @@ pub(crate) enum ApiVersion {
V2,
}
async fn emit_model_presets_notification(
outgoing: Arc<OutgoingMessageSender>,
conversation_manager: Arc<ConversationManager>,
config: Arc<Config>,
) {
let models = supported_models(conversation_manager, &config).await;
let notification =
ServerNotification::ModelPresetsUpdated(ModelPresetsUpdatedNotification { models });
outgoing.send_server_notification(notification).await;
}
impl CodexMessageProcessor {
async fn conversation_from_thread_id(
&self,
@@ -281,6 +293,15 @@ impl CodexMessageProcessor {
}
}
pub(crate) async fn send_model_presets_notification(&self) {
emit_model_presets_notification(
self.outgoing.clone(),
self.conversation_manager.clone(),
self.config.clone(),
)
.await;
}
async fn load_latest_config(&self) -> Result<Config, JSONRPCErrorError> {
Config::load_with_cli_overrides(self.cli_overrides.clone(), ConfigOverrides::default())
.await
@@ -573,6 +594,7 @@ impl CodexMessageProcessor {
self.outgoing
.send_server_notification(ServerNotification::AuthStatusChange(payload))
.await;
self.send_model_presets_notification().await;
}
Err(error) => {
self.outgoing.send_error(request_id, error).await;
@@ -603,6 +625,7 @@ impl CodexMessageProcessor {
self.outgoing
.send_server_notification(ServerNotification::AccountUpdated(payload_v2))
.await;
self.send_model_presets_notification().await;
}
Err(error) => {
self.outgoing.send_error(request_id, error).await;
@@ -659,6 +682,8 @@ impl CodexMessageProcessor {
let outgoing_clone = self.outgoing.clone();
let active_login = self.active_login.clone();
let auth_manager = self.auth_manager.clone();
let conversation_manager = self.conversation_manager.clone();
let config = self.config.clone();
let auth_url = server.auth_url.clone();
tokio::spawn(async move {
let (success, error_msg) = match tokio::time::timeout(
@@ -699,6 +724,12 @@ impl CodexMessageProcessor {
payload,
))
.await;
emit_model_presets_notification(
outgoing_clone,
conversation_manager,
config,
)
.await;
}
// Clear the active login if it matches this attempt. It may have been replaced or cancelled.
@@ -749,6 +780,8 @@ impl CodexMessageProcessor {
let outgoing_clone = self.outgoing.clone();
let active_login = self.active_login.clone();
let auth_manager = self.auth_manager.clone();
let conversation_manager = self.conversation_manager.clone();
let config = self.config.clone();
let auth_url = server.auth_url.clone();
tokio::spawn(async move {
let (success, error_msg) = match tokio::time::timeout(
@@ -789,6 +822,12 @@ impl CodexMessageProcessor {
payload_v2,
))
.await;
emit_model_presets_notification(
outgoing_clone,
conversation_manager,
config,
)
.await;
}
// Clear the active login if it matches this attempt. It may have been replaced or cancelled.
@@ -908,6 +947,7 @@ impl CodexMessageProcessor {
self.outgoing
.send_server_notification(ServerNotification::AuthStatusChange(payload))
.await;
self.send_model_presets_notification().await;
}
Err(error) => {
self.outgoing.send_error(request_id, error).await;
@@ -928,6 +968,7 @@ impl CodexMessageProcessor {
self.outgoing
.send_server_notification(ServerNotification::AccountUpdated(payload_v2))
.await;
self.send_model_presets_notification().await;
}
Err(error) => {
self.outgoing.send_error(request_id, error).await;

View File

@@ -128,6 +128,9 @@ impl MessageProcessor {
self.outgoing.send_response(request_id, response).await;
self.initialized = true;
self.codex_message_processor
.send_model_presets_notification()
.await;
return;
}

View File

@@ -20,6 +20,7 @@ At a glance:
- Configuration and info
- `getUserSavedConfig`, `setDefaultModel`, `getUserAgent`, `userInfo`
- `model/list` → enumerate available models and reasoning options
- notifications: `model/presets/updated`
- Auth
- `account/read`, `account/login/start`, `account/login/cancel`, `account/logout`, `account/rateLimits/read`
- notifications: `account/login/completed`, `account/updated`, `account/rateLimits/updated`
@@ -94,12 +95,17 @@ Each response yields:
- `isDefault` whether the model is recommended for most users
- `nextCursor` pass into the next request to continue paging (optional)
The server also emits `model/presets/updated` notifications after initialization and after auth state changes (login/logout). The payload is:
- `models` the full list of available models, with the same shape as `model/list` items.
## Event stream
While a conversation runs, the server sends notifications:
- `codex/event` with the serialized Codex event payload. The shape matches `core/src/protocol.rs`s `Event` and `EventMsg` types. Some notifications include a `_meta.requestId` to correlate with the originating request.
- Auth notifications via method names `loginChatGptComplete` and `authStatusChange`.
- Model catalog notifications via method name `model/presets/updated`.
Clients should render events and, when present, surface approval requests (see next section).