Skip to content

Commit cfbec3c

Browse files
committed
feat: reapply codext changes to rust v0.136.0
1 parent 60d7061 commit cfbec3c

41 files changed

Lines changed: 1507 additions & 157 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

codex-rs/Cargo.lock

Lines changed: 120 additions & 119 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codex-rs/app-server-protocol/src/protocol/v2/account.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,13 @@ pub struct GetAccountParams {
226226
/// themselves and call `account/login/start` with `chatgptAuthTokens`.
227227
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
228228
pub refresh_token: bool,
229+
230+
/// When `true`, reloads the auth snapshot from storage before returning.
231+
///
232+
/// This keeps long-lived clients in sync with `auth.json` updates without
233+
/// requiring a full app-server restart.
234+
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
235+
pub reload_auth_from_storage: bool,
229236
}
230237

231238
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]

codex-rs/app-server/src/request_processors.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ use codex_feedback::FeedbackUploadOptions;
339339
use codex_git_utils::git_diff_to_remote;
340340
use codex_git_utils::resolve_root_git_project_for_trust;
341341
use codex_login::AuthManager;
342+
use codex_login::AuthReloadStatus;
342343
use codex_login::CLIENT_ID;
343344
use codex_login::CodexAuth;
344345
use codex_login::ServerOptions as LoginServerOptions;
@@ -455,6 +456,78 @@ use uuid::Uuid;
455456
#[cfg(test)]
456457
use codex_app_server_protocol::ServerRequest;
457458

459+
async fn reload_auth_from_storage_if_idle(
460+
auth_manager: &Arc<AuthManager>,
461+
thread_manager: &Arc<ThreadManager>,
462+
config_manager: &ConfigManager,
463+
outgoing: &OutgoingMessageSender,
464+
thread_watch_manager: &ThreadWatchManager,
465+
chatgpt_base_url: &str,
466+
reason: &str,
467+
) {
468+
if *thread_watch_manager.subscribe_running_turn_count().borrow() != 0 {
469+
return;
470+
}
471+
472+
let status = auth_manager.reload_with_status().await;
473+
match handle_auth_reload_status(
474+
status,
475+
auth_manager,
476+
thread_manager,
477+
config_manager,
478+
outgoing,
479+
chatgpt_base_url,
480+
reason,
481+
)
482+
.await
483+
{
484+
AuthReloadStatus::Reloaded { .. } => {}
485+
AuthReloadStatus::Failed => {
486+
warn!("failed to reload auth from storage before {reason}");
487+
}
488+
}
489+
}
490+
491+
async fn handle_auth_reload_status(
492+
status: AuthReloadStatus,
493+
auth_manager: &Arc<AuthManager>,
494+
thread_manager: &Arc<ThreadManager>,
495+
config_manager: &ConfigManager,
496+
outgoing: &OutgoingMessageSender,
497+
chatgpt_base_url: &str,
498+
reason: &str,
499+
) -> AuthReloadStatus {
500+
match status {
501+
AuthReloadStatus::Reloaded { changed } => {
502+
if changed {
503+
let invalidated_thread_count =
504+
thread_manager.invalidate_model_transport_caches().await;
505+
info!(
506+
"auth reloaded from storage before {reason}; invalidated model transport caches for {invalidated_thread_count} tracked thread(s)"
507+
);
508+
config_manager.replace_cloud_requirements_loader(
509+
Arc::clone(auth_manager),
510+
chatgpt_base_url.to_string(),
511+
);
512+
config_manager
513+
.sync_default_client_residency_requirement()
514+
.await;
515+
let auth = auth_manager.auth_cached();
516+
outgoing
517+
.send_server_notification(ServerNotification::AccountUpdated(
518+
AccountUpdatedNotification {
519+
auth_mode: auth.as_ref().map(CodexAuth::api_auth_mode),
520+
plan_type: auth.as_ref().and_then(CodexAuth::account_plan_type),
521+
},
522+
))
523+
.await;
524+
}
525+
AuthReloadStatus::Reloaded { changed }
526+
}
527+
AuthReloadStatus::Failed => AuthReloadStatus::Failed,
528+
}
529+
}
530+
458531
mod account_processor;
459532
mod apps_processor;
460533
mod catalog_processor;

codex-rs/app-server/src/request_processors/account_processor.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,26 @@ impl AccountRequestProcessor {
808808
) -> Result<GetAccountResponse, JSONRPCErrorError> {
809809
let do_refresh = params.refresh_token;
810810

811+
if params.reload_auth_from_storage {
812+
let status = self.auth_manager.reload_with_status().await;
813+
match handle_auth_reload_status(
814+
status,
815+
&self.auth_manager,
816+
&self.thread_manager,
817+
&self.config_manager,
818+
&self.outgoing,
819+
&self.config.chatgpt_base_url,
820+
"account/get",
821+
)
822+
.await
823+
{
824+
AuthReloadStatus::Reloaded { .. } => {}
825+
AuthReloadStatus::Failed => {
826+
return Err(internal_error("failed to reload auth from storage"));
827+
}
828+
}
829+
}
830+
811831
self.refresh_token_if_requested(do_refresh).await;
812832

813833
let provider = create_model_provider(

codex-rs/app-server/src/request_processors/thread_processor.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,17 @@ impl ThreadRequestProcessor {
827827
app_server_client_version: Option<String>,
828828
request_context: RequestContext,
829829
) -> Result<(), JSONRPCErrorError> {
830+
reload_auth_from_storage_if_idle(
831+
&self.auth_manager,
832+
&self.thread_manager,
833+
&self.config_manager,
834+
&self.outgoing,
835+
&self.thread_watch_manager,
836+
&self.config.chatgpt_base_url,
837+
"thread/start",
838+
)
839+
.await;
840+
830841
let ThreadStartParams {
831842
model,
832843
model_provider,
@@ -2471,6 +2482,17 @@ impl ThreadRequestProcessor {
24712482
}
24722483
}
24732484

2485+
reload_auth_from_storage_if_idle(
2486+
&self.auth_manager,
2487+
&self.thread_manager,
2488+
&self.config_manager,
2489+
&self.outgoing,
2490+
&self.thread_watch_manager,
2491+
&self.config.chatgpt_base_url,
2492+
"thread/resume",
2493+
)
2494+
.await;
2495+
24742496
let ThreadResumeParams {
24752497
thread_id,
24762498
history,

codex-rs/app-server/src/request_processors/turn_processor.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,17 @@ impl TurnRequestProcessor {
384384
app_server_client_name: Option<String>,
385385
app_server_client_version: Option<String>,
386386
) -> Result<TurnStartResponse, JSONRPCErrorError> {
387+
reload_auth_from_storage_if_idle(
388+
&self.auth_manager,
389+
&self.thread_manager,
390+
&self.config_manager,
391+
&self.outgoing,
392+
&self.thread_watch_manager,
393+
&self.config.chatgpt_base_url,
394+
"turn/start",
395+
)
396+
.await;
397+
387398
if let Err(error) = Self::validate_v2_input_limit(&params.input) {
388399
self.track_error_response(
389400
&request_id,

codex-rs/config/src/types.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,14 @@ pub struct Tui {
731731
#[serde(default)]
732732
pub keymap: TuiKeymap,
733733

734+
/// Optional synthetic user-turn prompt injected after a turn fails with
735+
/// `UsageLimitExceeded`.
736+
///
737+
/// When unset, Codex uses the built-in default recovery prompt.
738+
/// When set to an empty string, Codex disables this automatic recovery turn.
739+
#[serde(default)]
740+
pub usage_limit_resume_prompt: Option<String>,
741+
734742
/// Startup tooltip availability NUX state persisted by the TUI.
735743
#[serde(default)]
736744
pub model_availability_nux: ModelAvailabilityNuxConfig,

codex-rs/core/src/client.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,10 @@ impl ModelClient {
399399
self.store_cached_websocket_session(WebsocketSession::default());
400400
}
401401

402+
pub(crate) fn invalidate_cached_transport_state(&self) {
403+
self.store_cached_websocket_session(WebsocketSession::default());
404+
}
405+
402406
pub(crate) fn current_window_id(&self) -> String {
403407
let thread_id = self.state.thread_id;
404408
let window_generation = self.state.window_generation.load(Ordering::Relaxed);

codex-rs/core/src/codex_thread.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,14 @@ impl CodexThread {
142142
self.codex.shutdown_and_wait().await
143143
}
144144

145+
pub(crate) fn invalidate_model_transport_cache(&self) {
146+
self.codex
147+
.session
148+
.services
149+
.model_client
150+
.invalidate_cached_transport_state();
151+
}
152+
145153
/// Wait until the underlying session loop has terminated.
146154
pub async fn wait_until_terminated(&self) {
147155
self.codex.session_loop_termination.clone().await;

codex-rs/core/src/config/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,13 @@ pub struct Config {
729729
/// 3. built-in defaults
730730
pub tui_keymap: TuiKeymap,
731731

732+
/// Synthetic user-turn prompt injected after a `UsageLimitExceeded` turn
733+
/// failure.
734+
///
735+
/// `None` uses the built-in default prompt. `Some("")` disables the
736+
/// automatic recovery turn.
737+
pub tui_usage_limit_resume_prompt: Option<String>,
738+
732739
/// The absolute directory that should be treated as the current working
733740
/// directory for the session. All relative paths inside the business-logic
734741
/// layer are resolved against this path.
@@ -3557,6 +3564,10 @@ impl Config {
35573564
.as_ref()
35583565
.map(|t| t.keymap.clone())
35593566
.unwrap_or_default(),
3567+
tui_usage_limit_resume_prompt: cfg
3568+
.tui
3569+
.as_ref()
3570+
.and_then(|t| t.usage_limit_resume_prompt.clone()),
35603571
otel,
35613572
};
35623573
Ok(config)

0 commit comments

Comments
 (0)