From 3e61c287f07b6b794500c7a9a5d95082d01f5c31 Mon Sep 17 00:00:00 2001 From: "zed-zippy[bot]" <234243425+zed-zippy[bot]@users.noreply.github.com> Date: Fri, 29 May 2026 07:31:14 +0000 Subject: [PATCH] edit_prediction: Skip cloud Zeta requests when not signed in (#57615) (cherry-pick to stable) (#58044) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cherry-pick of #57615 to stable ---- Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Closes #57962 ## What When a user is not signed in to their Zed account, the edit prediction system was still attempting a cloud API request on every keystroke. The request would fail deep in the credential check (`CloudApiClient::build_request`) with a `ClientApiError::NotSignedIn` error, which propagated back up and was logged at `ERROR` level via `.log_err()` at line 2389 of `edit_prediction.rs`. ## Why The sign-in check was happening too late — only discovered after async tasks were already spawned and the full request pipeline entered. This fix gates the request at the top of `request_prediction_internal`, returning `Task::ready(Ok(None))` immediately before any inputs are built or tasks spawned. The guard mirrors the existing `is_cloud` provider check already used elsewhere in the same file, and only applies to the `Zeta` model on the cloud provider path. Local providers (Ollama, `OpenAiCompatibleApi`) and other models (Mercury, Fim) are unaffected. Note: I haven't added a test for this — testing the early-return would require mocking auth state, which I wasn't sure was worth the complexity for a one-liner guard. Happy to add one if preferred. Release Notes: - Fixed noisy `not signed in` error log on every keystroke when not signed in to Zed --------- Co-authored-by: Oleksiy Syvokon Co-authored-by: MrSubidubi Co-authored-by: David3u <3udavid@gmail.com> Co-authored-by: Seth Wood Co-authored-by: Oleksiy Syvokon Co-authored-by: MrSubidubi Co-authored-by: David3u <3udavid@gmail.com> --- crates/edit_prediction/src/edit_prediction.rs | 9 +++++++ .../src/edit_prediction_tests.rs | 24 +++++++++++-------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/crates/edit_prediction/src/edit_prediction.rs b/crates/edit_prediction/src/edit_prediction.rs index 8b57c442c22..84b2e8be1a8 100644 --- a/crates/edit_prediction/src/edit_prediction.rs +++ b/crates/edit_prediction/src/edit_prediction.rs @@ -2444,6 +2444,15 @@ impl EditPredictionStore { allow_jump: bool, cx: &mut Context, ) -> Task>> { + let is_cloud_zeta = matches!(self.edit_prediction_model, EditPredictionModel::Zeta) + && !matches!( + all_language_settings(None, cx).edit_predictions.provider, + EditPredictionProvider::Ollama | EditPredictionProvider::OpenAiCompatibleApi + ); + if is_cloud_zeta && !self.client.cloud_client().has_credentials() { + return Task::ready(Ok(None)); + } + self.get_or_init_project(&project, cx); let project_state = self.projects.get(&project.entity_id()).unwrap(); let stored_events = project_state.events(cx); diff --git a/crates/edit_prediction/src/edit_prediction_tests.rs b/crates/edit_prediction/src/edit_prediction_tests.rs index 86f218b401e..32da5397886 100644 --- a/crates/edit_prediction/src/edit_prediction_tests.rs +++ b/crates/edit_prediction/src/edit_prediction_tests.rs @@ -3107,11 +3107,18 @@ async fn test_unauthenticated_without_custom_url_blocks_prediction_impl(cx: &mut let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await; - let http_client = FakeHttpClient::create(|_req| async move { - Ok(gpui::http_client::Response::builder() - .status(401) - .body("Unauthorized".into()) - .unwrap()) + let request_count = Arc::new(std::sync::atomic::AtomicUsize::default()); + let http_client = FakeHttpClient::create({ + let request_count = request_count.clone(); + move |_req| { + request_count.fetch_add(1, std::sync::atomic::Ordering::SeqCst); + async move { + Ok(gpui::http_client::Response::builder() + .status(401) + .body("Unauthorized".into()) + .unwrap()) + } + } }); let client = @@ -3144,11 +3151,8 @@ async fn test_unauthenticated_without_custom_url_blocks_prediction_impl(cx: &mut ep_store.request_prediction(&project, &buffer, cursor, Default::default(), cx) }); - let result = completion_task.await; - assert!( - result.is_err(), - "Without authentication and without custom URL, prediction should fail" - ); + assert!(completion_task.await.unwrap().is_none()); + assert_eq!(request_count.load(std::sync::atomic::Ordering::SeqCst), 0); } #[gpui::test]