This commit is contained in:
Ahmed Ibrahim
2025-12-13 21:02:56 -08:00
parent 309c2f5f94
commit a4132d7523
2 changed files with 68 additions and 1 deletions

View File

@@ -253,10 +253,16 @@ impl Codex {
let exec_policy = Arc::new(RwLock::new(exec_policy));
let config = Arc::new(config);
let mut remote_models_error: Option<EventMsg> = None;
if config.features.enabled(Feature::RemoteModels)
&& let Err(err) = models_manager.refresh_available_models(&config).await
{
error!("failed to refresh available models: {err:?}");
remote_models_error = Some(EventMsg::Error(error_event_with_update_nudge(
format!("failed to refresh available models: {err:?}"),
None,
compute_is_up_to_date(&config.codex_home),
)));
}
let model = models_manager.get_model(&config.model, &config).await;
let is_up_to_date = compute_is_up_to_date(&config.codex_home);
@@ -299,13 +305,24 @@ impl Codex {
let conversation_id = session.conversation_id;
// This task will run until Op::Shutdown is received.
tokio::spawn(submission_loop(session, config, rx_sub));
tokio::spawn(submission_loop(session.clone(), config, rx_sub));
let codex = Codex {
next_id: AtomicU64::new(0),
tx_sub,
rx_event,
};
if let Some(remote_models_error) = remote_models_error {
let event = Event {
id: session
.next_internal_sub_id
.fetch_add(1, Ordering::SeqCst)
.to_string(),
msg: remote_models_error,
};
session.send_event_raw(event).await;
}
Ok(CodexSpawnOk {
codex,
conversation_id,

View File

@@ -47,7 +47,11 @@ use tokio::time::Duration;
use tokio::time::Instant;
use tokio::time::sleep;
use wiremock::BodyPrintLimit;
use wiremock::Mock;
use wiremock::MockServer;
use wiremock::ResponseTemplate;
use wiremock::matchers::method;
use wiremock::matchers::path_regex;
const REMOTE_MODEL_SLUG: &str = "codex-test";
@@ -298,6 +302,52 @@ async fn remote_models_apply_remote_base_instructions() -> Result<()> {
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn remote_models_invalid_payload_emits_error() -> Result<()> {
skip_if_no_network!(Ok(()));
skip_if_sandbox!(Ok(()));
let server = MockServer::builder()
.body_print_limit(BodyPrintLimit::Limited(80_000))
.start()
.await;
Mock::given(method("GET"))
.and(path_regex(".*/models$"))
.respond_with(
ResponseTemplate::new(200)
.insert_header("content-type", "application/json")
.set_body_json(json!({
"models": "invalid",
"etag": "etag",
})),
)
.up_to_n_times(1)
.mount(&server)
.await;
let RemoteModelsHarness { codex, .. } = build_remote_models_harness(&server, |config| {
config.features.enable(Feature::RemoteModels);
config.model = Some("gpt-5.1".to_string());
})
.await?;
let error_event = wait_for_event(&codex, |msg| matches!(msg, EventMsg::Error(_))).await;
let EventMsg::Error(error_event) = error_event else {
unreachable!();
};
assert!(
error_event
.message
.contains("failed to refresh available models"),
"unexpected error message: {}",
error_event.message
);
Ok(())
}
async fn wait_for_model_available(
manager: &Arc<ModelsManager>,
slug: &str,