From 3c9d39b4e3bac7080ed1d10f317578cba1e773b0 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Wed, 7 May 2025 11:44:30 -0400 Subject: [PATCH] Send up Zed version with edit prediction and completion requests (#30136) This PR makes it so we send up an `x-zed-version` header with the client's version when making a request to llm.zed.dev for edit predictions and completions. Release Notes: - N/A --- Cargo.lock | 5 +++-- Cargo.toml | 2 +- crates/agent/src/thread.rs | 4 ++-- crates/language_models/Cargo.toml | 1 + crates/language_models/src/provider/cloud.rs | 20 +++++++++++++++++--- crates/zeta/src/zeta.rs | 3 ++- 6 files changed, 26 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e088b5a00b71ae3f98b456e54298f14e3b2203e4..d5c63ab5cc68f1d67df04d9066bba010e0b60da7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7901,6 +7901,7 @@ dependencies = [ "partial-json-fixer", "project", "proto", + "release_channel", "schemars", "serde", "serde_json", @@ -18873,9 +18874,9 @@ dependencies = [ [[package]] name = "zed_llm_client" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe0d60001c02d0d21a4114a13bee3a905fbb9e146ada80a90435c05fda18852" +checksum = "a23b2fd00776b0c55072f389654910ceb501eb0083d7f78905ab0e5cc86949ec" dependencies = [ "anyhow", "serde", diff --git a/Cargo.toml b/Cargo.toml index ea82544af9ffeaf28becb66baedf6e4dc8aa04c8..937c81694f6ba8e804fb47ead7a6acefe17e0e7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -609,7 +609,7 @@ wasmtime-wasi = "29" which = "6.0.0" wit-component = "0.221" workspace-hack = "0.1.0" -zed_llm_client = "0.7.5" +zed_llm_client = "0.8.0" zstd = "0.11" [workspace.dependencies.async-stripe] diff --git a/crates/agent/src/thread.rs b/crates/agent/src/thread.rs index 72c5a5a01dbc037f9b44a0c20985d805b81a13ea..5ffea3a4a289ddd39b0a4a9753b0d91321ecfffd 100644 --- a/crates/agent/src/thread.rs +++ b/crates/agent/src/thread.rs @@ -1546,9 +1546,9 @@ impl Thread { completion.queue_state = QueueState::Started; } CompletionRequestStatus::Failed { - code, message + code, message, request_id } => { - return Err(anyhow!("completion request failed. code: {code}, message: {message}")); + return Err(anyhow!("completion request failed. request_id: {request_id}, code: {code}, message: {message}")); } CompletionRequestStatus::UsageUpdated { amount, limit diff --git a/crates/language_models/Cargo.toml b/crates/language_models/Cargo.toml index 5ded3386b5af3b53a28d175ae70b0f4105705a11..7c55284929068d83f87da75c077292ce41d5e90e 100644 --- a/crates/language_models/Cargo.toml +++ b/crates/language_models/Cargo.toml @@ -41,6 +41,7 @@ open_ai = { workspace = true, features = ["schemars"] } partial-json-fixer.workspace = true project.workspace = true proto.workspace = true +release_channel.workspace = true schemars.workspace = true serde.workspace = true serde_json.workspace = true diff --git a/crates/language_models/src/provider/cloud.rs b/crates/language_models/src/provider/cloud.rs index 75ea219fa5578a74ae53f3b3647098402db354b0..7b46a7d1b1712f5931141a4a82ff5210568da43f 100644 --- a/crates/language_models/src/provider/cloud.rs +++ b/crates/language_models/src/provider/cloud.rs @@ -6,7 +6,9 @@ use feature_flags::{FeatureFlagAppExt, LlmClosedBetaFeatureFlag, ZedProFeatureFl use futures::{ AsyncBufReadExt, FutureExt, Stream, StreamExt, future::BoxFuture, stream::BoxStream, }; -use gpui::{AnyElement, AnyView, App, AsyncApp, Context, Entity, Subscription, Task}; +use gpui::{ + AnyElement, AnyView, App, AsyncApp, Context, Entity, SemanticVersion, Subscription, Task, +}; use http_client::{AsyncBody, HttpClient, Method, Response, StatusCode}; use language_model::{ AuthenticateError, CloudModel, LanguageModel, LanguageModelCacheConfiguration, @@ -20,6 +22,7 @@ use language_model::{ MaxMonthlySpendReachedError, PaymentRequiredError, RefreshLlmTokenListener, }; use proto::Plan; +use release_channel::AppVersion; use schemars::JsonSchema; use serde::{Deserialize, Serialize, de::DeserializeOwned}; use settings::{Settings, SettingsStore}; @@ -39,7 +42,7 @@ use zed_llm_client::{ CompletionRequestStatus, CountTokensBody, CountTokensResponse, EXPIRED_LLM_TOKEN_HEADER_NAME, MAX_LLM_MONTHLY_SPEND_REACHED_HEADER_NAME, MODEL_REQUESTS_RESOURCE_HEADER_VALUE, SERVER_SUPPORTS_STATUS_MESSAGES_HEADER_NAME, SUBSCRIPTION_LIMIT_RESOURCE_HEADER_NAME, - TOOL_USE_LIMIT_REACHED_HEADER_NAME, + TOOL_USE_LIMIT_REACHED_HEADER_NAME, ZED_VERSION_HEADER_NAME, }; use crate::AllLanguageModelSettings; @@ -526,6 +529,7 @@ impl CloudLanguageModel { async fn perform_llm_completion( client: Arc, llm_api_token: LlmApiToken, + app_version: Option, body: CompletionBody, ) -> Result { let http_client = &client.http_client(); @@ -542,6 +546,12 @@ impl CloudLanguageModel { } else { request_builder.uri(http_client.build_zed_llm_url("/completions", &[])?.as_ref()) }; + let request_builder = if let Some(app_version) = app_version { + request_builder.header(ZED_VERSION_HEADER_NAME, app_version.to_string()) + } else { + request_builder + }; + let request = request_builder .header("Content-Type", "application/json") .header("Authorization", format!("Bearer {token}")) @@ -773,7 +783,7 @@ impl LanguageModel for CloudLanguageModel { fn stream_completion( &self, request: LanguageModelRequest, - _cx: &AsyncApp, + cx: &AsyncApp, ) -> BoxFuture< 'static, Result< @@ -783,6 +793,7 @@ impl LanguageModel for CloudLanguageModel { let thread_id = request.thread_id.clone(); let prompt_id = request.prompt_id.clone(); let mode = request.mode; + let app_version = cx.update(|cx| AppVersion::global(cx)).ok(); match &self.model { CloudModel::Anthropic(model) => { let request = into_anthropic( @@ -803,6 +814,7 @@ impl LanguageModel for CloudLanguageModel { } = Self::perform_llm_completion( client.clone(), llm_api_token, + app_version, CompletionBody { thread_id, prompt_id, @@ -854,6 +866,7 @@ impl LanguageModel for CloudLanguageModel { } = Self::perform_llm_completion( client.clone(), llm_api_token, + app_version, CompletionBody { thread_id, prompt_id, @@ -890,6 +903,7 @@ impl LanguageModel for CloudLanguageModel { } = Self::perform_llm_completion( client.clone(), llm_api_token, + app_version, CompletionBody { thread_id, prompt_id, diff --git a/crates/zeta/src/zeta.rs b/crates/zeta/src/zeta.rs index 1a95cc7ba067ab3b2c5e7720c205a0c4fa32f4a3..eb82e97ec1c034b96699636c17867e437b061e9f 100644 --- a/crates/zeta/src/zeta.rs +++ b/crates/zeta/src/zeta.rs @@ -55,7 +55,7 @@ use workspace::notifications::{ErrorMessagePrompt, NotificationId}; use worktree::Worktree; use zed_llm_client::{ EXPIRED_LLM_TOKEN_HEADER_NAME, MINIMUM_REQUIRED_VERSION_HEADER_NAME, PredictEditsBody, - PredictEditsResponse, + PredictEditsResponse, ZED_VERSION_HEADER_NAME, }; const CURSOR_MARKER: &'static str = "<|user_cursor_is_here|>"; @@ -754,6 +754,7 @@ and then another let request = request_builder .header("Content-Type", "application/json") .header("Authorization", format!("Bearer {}", token)) + .header(ZED_VERSION_HEADER_NAME, app_version.to_string()) .body(serde_json::to_string(&body)?.into())?; let mut response = http_client.send(request).await?;