@@ -206,6 +206,34 @@ impl CloudApiClient {
Ok(())
}
+
+ pub async fn submit_edit_prediction_feedback(
+ &self,
+ body: SubmitEditPredictionFeedbackBody,
+ ) -> Result<()> {
+ let request = self.build_request(
+ Request::builder().method(Method::POST).uri(
+ self.http_client
+ .build_zed_cloud_url("/client/feedback/edit_prediction")?
+ .as_ref(),
+ ),
+ AsyncBody::from(serde_json::to_string(&body)?),
+ )?;
+
+ let mut response = self.http_client.send(request).await?;
+
+ if !response.status().is_success() {
+ let mut body = String::new();
+ response.body_mut().read_to_string(&mut body).await?;
+
+ anyhow::bail!(
+ "Failed to submit edit prediction feedback.\nStatus: {:?}\nBody: {body}",
+ response.status()
+ )
+ }
+
+ Ok(())
+ }
}
fn build_request(
@@ -65,3 +65,13 @@ pub struct SubmitAgentThreadFeedbackBody {
pub rating: String,
pub thread: serde_json::Value,
}
+
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+pub struct SubmitEditPredictionFeedbackBody {
+ pub organization_id: Option<OrganizationId>,
+ pub request_id: String,
+ pub rating: String,
+ pub inputs: serde_json::Value,
+ pub output: Option<String>,
+ pub feedback: String,
+}
@@ -21,6 +21,7 @@ arrayvec.workspace = true
brotli.workspace = true
buffer_diff.workspace = true
client.workspace = true
+cloud_api_types.workspace = true
cloud_llm_client.workspace = true
collections.workspace = true
copilot.workspace = true
@@ -69,7 +70,6 @@ zstd.workspace = true
[dev-dependencies]
clock = { workspace = true, features = ["test-support"] }
-cloud_api_types.workspace = true
cloud_llm_client = { workspace = true, features = ["test-support"] }
ctor.workspace = true
gpui = { workspace = true, features = ["test-support"] }
@@ -1,6 +1,7 @@
use anyhow::Result;
use arrayvec::ArrayVec;
use client::{Client, EditPredictionUsage, UserStore};
+use cloud_api_types::SubmitEditPredictionFeedbackBody;
use cloud_llm_client::predict_edits_v3::{
PredictEditsV3Request, PredictEditsV3Response, RawCompletionRequest, RawCompletionResponse,
};
@@ -2256,18 +2257,38 @@ impl EditPredictionStore {
feedback: String,
cx: &mut Context<Self>,
) {
+ let organization = self.user_store.read(cx).current_organization();
+
self.rated_predictions.insert(prediction.id.clone());
- telemetry::event!(
- "Edit Prediction Rated",
- request_id = prediction.id.to_string(),
- rating,
- inputs = prediction.inputs,
- output = prediction
+
+ cx.background_spawn({
+ let client = self.client.clone();
+ let prediction_id = prediction.id.to_string();
+ let inputs = serde_json::to_value(&prediction.inputs);
+ let output = prediction
.edit_preview
- .as_unified_diff(prediction.snapshot.file(), &prediction.edits),
- feedback
- );
- self.client.telemetry().flush_events().detach();
+ .as_unified_diff(prediction.snapshot.file(), &prediction.edits);
+ async move {
+ client
+ .cloud_client()
+ .submit_edit_prediction_feedback(SubmitEditPredictionFeedbackBody {
+ organization_id: organization.map(|organization| organization.id.clone()),
+ request_id: prediction_id,
+ rating: match rating {
+ EditPredictionRating::Positive => "positive".to_string(),
+ EditPredictionRating::Negative => "negative".to_string(),
+ },
+ inputs: inputs?,
+ output,
+ feedback,
+ })
+ .await?;
+
+ anyhow::Ok(())
+ }
+ })
+ .detach_and_log_err(cx);
+
cx.notify();
}
}