Poll workspace messages on startup

This commit is contained in:
xli-oai
2026-05-18 05:21:06 -07:00
parent 1f1a7fa1df
commit 4ec43402bd
5 changed files with 86 additions and 0 deletions
+1
View File
@@ -3645,6 +3645,7 @@ dependencies = [
"codex-app-server-client",
"codex-app-server-protocol",
"codex-arg0",
"codex-backend-client",
"codex-chatgpt",
"codex-cli",
"codex-cloud-requirements",
+37
View File
@@ -49,6 +49,43 @@ impl CodexWorkspaceMessagesResponse {
}
}
#[cfg(test)]
mod workspace_message_tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn workspace_messages_response_deserializes_headlines_and_announcements() {
let response: CodexWorkspaceMessagesResponse = serde_json::from_value(serde_json::json!({
"messages": [
{
"message_id": "headline-id",
"message_type": "headline",
"message_body": "Headline body"
},
{
"message_id": "announcement-id",
"message_type": "announcement",
"message_body": "Announcement body"
}
]
}))
.expect("workspace messages response should deserialize");
let headlines = response
.headlines()
.map(|message| message.message_id.as_str())
.collect::<Vec<_>>();
let announcements = response
.announcements()
.map(|message| message.message_id.as_str())
.collect::<Vec<_>>();
assert_eq!(headlines, vec!["headline-id"]);
assert_eq!(announcements, vec!["announcement-id"]);
}
}
/// Hand-rolled models for the Cloud Tasks task-details response.
/// The generated OpenAPI models are pretty bad. This is a half-step
/// towards hand-rolling them.
+1
View File
@@ -29,6 +29,7 @@ codex-ansi-escape = { workspace = true }
codex-app-server-client = { workspace = true }
codex-app-server-protocol = { workspace = true }
codex-arg0 = { workspace = true }
codex-backend-client = { workspace = true }
codex-install-context = { workspace = true }
codex-chatgpt = { workspace = true }
codex-cloud-requirements = { workspace = true }
+5
View File
@@ -42,6 +42,7 @@ use codex_config::format_config_error_with_source;
use codex_exec_server::EnvironmentManager;
use codex_exec_server::EnvironmentManagerArgs;
use codex_exec_server::ExecServerRuntimePaths;
use codex_features::Feature;
use codex_login::AuthConfig;
use codex_login::default_client::set_default_client_residency_requirement;
use codex_login::enforce_login_restrictions;
@@ -190,6 +191,7 @@ mod version;
mod voice;
mod width;
mod workspace_command;
mod workspace_messages;
#[cfg(target_os = "linux")]
#[allow(dead_code)]
mod voice {
@@ -1106,6 +1108,9 @@ async fn run_ratatui_app(
color_eyre::install()?;
tooltips::announcement::prewarm();
if initial_config.features.enabled(Feature::WorkspaceMessages) {
workspace_messages::prewarm_workspace_messages(&initial_config);
}
// Forward panic reports through tracing so they appear in the UI status
// line, but do not swallow the default/color-eyre panic handler.
+42
View File
@@ -0,0 +1,42 @@
use crate::legacy_core::config::Config;
use codex_backend_client::Client as BackendClient;
use codex_backend_client::CodexWorkspaceMessagesResponse;
use codex_login::AuthManager;
use std::sync::OnceLock;
use std::time::Duration;
use tokio::time::timeout;
const WORKSPACE_MESSAGES_FETCH_TIMEOUT: Duration = Duration::from_millis(1000);
static WORKSPACE_MESSAGES: OnceLock<Option<CodexWorkspaceMessagesResponse>> = OnceLock::new();
static WORKSPACE_MESSAGES_FETCH_STARTED: OnceLock<()> = OnceLock::new();
pub(crate) fn prewarm_workspace_messages(config: &Config) {
if WORKSPACE_MESSAGES_FETCH_STARTED.set(()).is_err() {
return;
}
let config = config.clone();
tokio::spawn(async move {
let messages = timeout(
WORKSPACE_MESSAGES_FETCH_TIMEOUT,
fetch_workspace_messages(config),
)
.await
.ok()
.flatten();
let _ = WORKSPACE_MESSAGES.set(messages);
});
}
async fn fetch_workspace_messages(config: Config) -> Option<CodexWorkspaceMessagesResponse> {
let auth_manager =
AuthManager::shared_from_config(&config, /*enable_codex_api_key_env*/ false).await;
let auth = auth_manager.auth().await?;
if !auth.uses_codex_backend() {
return None;
}
let client = BackendClient::from_auth(config.chatgpt_base_url, &auth).ok()?;
client.list_workspace_messages().await.ok()
}