edit prediction: Do not log error when prediction cannot be interpolated (#23826)

Previously we returned an error when the interpolation failed in
`process_completion_response`.
However, it is not an error when interpolation returns `None`. That just
means that the predicted edits can be discarded, because the user typed
something that is not a subset of what the model predicted OR if the
model responds with a no-op.
```
2025-01-29T09:44:30.221135+01:00 [ERROR] zeta prediction failed

Caused by:
    Interpolated edits are empty
```

Release Notes:

- N/A
This commit is contained in:
Bennet Bo Fenner 2025-01-29 10:15:46 +01:00 committed by GitHub
parent 6d4ccb0eb1
commit d2d9f492b9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -305,7 +305,7 @@ impl Zeta {
position: language::Anchor, position: language::Anchor,
cx: &mut Context<Self>, cx: &mut Context<Self>,
perform_predict_edits: F, perform_predict_edits: F,
) -> Task<Result<InlineCompletion>> ) -> Task<Result<Option<InlineCompletion>>>
where where
F: FnOnce(Arc<Client>, LlmApiToken, PredictEditsParams) -> R + 'static, F: FnOnce(Arc<Client>, LlmApiToken, PredictEditsParams) -> R + 'static,
R: Future<Output = Result<PredictEditsResponse>> + Send + 'static, R: Future<Output = Result<PredictEditsResponse>> + Send + 'static,
@ -523,7 +523,7 @@ and then another
position: language::Anchor, position: language::Anchor,
response: PredictEditsResponse, response: PredictEditsResponse,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Task<Result<InlineCompletion>> { ) -> Task<Result<Option<InlineCompletion>>> {
use std::future::ready; use std::future::ready;
self.request_completion_impl(buffer, position, cx, |_, _, _| ready(Ok(response))) self.request_completion_impl(buffer, position, cx, |_, _, _| ready(Ok(response)))
@ -534,7 +534,7 @@ and then another
buffer: &Entity<Buffer>, buffer: &Entity<Buffer>,
position: language::Anchor, position: language::Anchor,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Task<Result<InlineCompletion>> { ) -> Task<Result<Option<InlineCompletion>>> {
self.request_completion_impl(buffer, position, cx, Self::perform_predict_edits) self.request_completion_impl(buffer, position, cx, Self::perform_predict_edits)
} }
@ -601,7 +601,7 @@ and then another
input_excerpt: String, input_excerpt: String,
request_sent_at: Instant, request_sent_at: Instant,
cx: &AsyncApp, cx: &AsyncApp,
) -> Task<Result<InlineCompletion>> { ) -> Task<Result<Option<InlineCompletion>>> {
let snapshot = snapshot.clone(); let snapshot = snapshot.clone();
cx.spawn(|cx| async move { cx.spawn(|cx| async move {
let output_excerpt: Arc<str> = output_excerpt.into(); let output_excerpt: Arc<str> = output_excerpt.into();
@ -617,22 +617,22 @@ and then another
.await? .await?
.into(); .into();
let (edits, snapshot, edit_preview) = buffer.read_with(&cx, { let Some((edits, snapshot, edit_preview)) = buffer.read_with(&cx, {
let edits = edits.clone(); let edits = edits.clone();
|buffer, cx| { |buffer, cx| {
let new_snapshot = buffer.snapshot(); let new_snapshot = buffer.snapshot();
let edits: Arc<[(Range<Anchor>, String)]> = let edits: Arc<[(Range<Anchor>, String)]> =
interpolate(&snapshot, &new_snapshot, edits) interpolate(&snapshot, &new_snapshot, edits)?.into();
.context("Interpolated edits are empty")? Some((edits.clone(), new_snapshot, buffer.preview_edits(edits, cx)))
.into();
anyhow::Ok((edits.clone(), new_snapshot, buffer.preview_edits(edits, cx)))
} }
})??; })?
else {
return anyhow::Ok(None);
};
let edit_preview = edit_preview.await; let edit_preview = edit_preview.await;
Ok(InlineCompletion { Ok(Some(InlineCompletion {
id: InlineCompletionId::new(), id: InlineCompletionId::new(),
path, path,
excerpt_range, excerpt_range,
@ -646,7 +646,7 @@ and then another
output_excerpt, output_excerpt,
request_sent_at, request_sent_at,
response_received_at: Instant::now(), response_received_at: Instant::now(),
}) }))
}) })
} }
@ -1128,13 +1128,18 @@ impl inline_completion::InlineCompletionProvider for ZetaInlineCompletionProvide
let completion = match completion_request { let completion = match completion_request {
Ok(completion_request) => { Ok(completion_request) => {
let completion_request = completion_request.await; let completion_request = completion_request.await;
completion_request.map(|completion| CurrentInlineCompletion { completion_request.map(|c| {
buffer_id: buffer.entity_id(), c.map(|completion| CurrentInlineCompletion {
completion, buffer_id: buffer.entity_id(),
completion,
})
}) })
} }
Err(error) => Err(error), Err(error) => Err(error),
}; };
let Some(new_completion) = completion.log_err().flatten() else {
return;
};
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
if this.pending_completions[0].id == pending_completion_id { if this.pending_completions[0].id == pending_completion_id {
@ -1143,22 +1148,19 @@ impl inline_completion::InlineCompletionProvider for ZetaInlineCompletionProvide
this.pending_completions.clear(); this.pending_completions.clear();
} }
if let Some(new_completion) = completion.context("zeta prediction failed").log_err() if let Some(old_completion) = this.current_completion.as_ref() {
{ let snapshot = buffer.read(cx).snapshot();
if let Some(old_completion) = this.current_completion.as_ref() { if new_completion.should_replace_completion(&old_completion, &snapshot) {
let snapshot = buffer.read(cx).snapshot();
if new_completion.should_replace_completion(&old_completion, &snapshot) {
this.zeta.update(cx, |zeta, cx| {
zeta.completion_shown(&new_completion.completion, cx);
});
this.current_completion = Some(new_completion);
}
} else {
this.zeta.update(cx, |zeta, cx| { this.zeta.update(cx, |zeta, cx| {
zeta.completion_shown(&new_completion.completion, cx); zeta.completion_shown(&new_completion.completion, cx);
}); });
this.current_completion = Some(new_completion); this.current_completion = Some(new_completion);
} }
} else {
this.zeta.update(cx, |zeta, cx| {
zeta.completion_shown(&new_completion.completion, cx);
});
this.current_completion = Some(new_completion);
} }
cx.notify(); cx.notify();
@ -1442,7 +1444,7 @@ mod tests {
proto::GetLlmTokenResponse { token: "".into() }, proto::GetLlmTokenResponse { token: "".into() },
); );
let completion = completion_task.await.unwrap(); let completion = completion_task.await.unwrap().unwrap();
buffer.update(cx, |buffer, cx| { buffer.update(cx, |buffer, cx| {
buffer.edit(completion.edits.iter().cloned(), None, cx) buffer.edit(completion.edits.iter().cloned(), None, cx)
}); });