ep: Fix moving cursor to a predicted position (#55079)

Starting ~3 weeks ago, `output` no longer contains the cursor marker,
cloud strips it on parsing. Instead, it should return a cursor offset.


Release Notes:

- Fixed moving the cursor to a predicted position in Zeta 2
This commit is contained in:
Oleksiy Syvokon 2026-04-28 18:44:17 +03:00 committed by GitHub
parent 16daaa7fe1
commit 4bea755dee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 15 additions and 8 deletions

View file

@ -46,6 +46,9 @@ pub struct PredictEditsV3Response {
pub editable_range: Range<usize>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub model_version: Option<String>,
/// Predicted cursor offset within `output`.
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor_offset: Option<usize>,
}
#[derive(Debug, Deserialize, Serialize)]

View file

@ -2356,6 +2356,7 @@ fn model_response(request: &PredictEditsV3Request, diff_to_apply: &str) -> Predi
request_id: Uuid::new_v4().to_string(),
editable_range,
output: new_excerpt,
cursor_offset: None,
model_version: None,
}
}
@ -2365,6 +2366,7 @@ fn empty_response() -> PredictEditsV3Response {
request_id: Uuid::new_v4().to_string(),
editable_range: 0..0,
output: String::new(),
cursor_offset: None,
model_version: None,
}
}
@ -2713,6 +2715,7 @@ async fn test_edit_prediction_no_spurious_trailing_newline(cx: &mut TestAppConte
output: "hello world\n".to_string(),
editable_range: 0..excerpt_length,
model_version: None,
cursor_offset: None,
};
respond_tx.send(response).unwrap();
@ -2771,9 +2774,10 @@ async fn test_v3_prediction_strips_cursor_marker_from_edit_text(cx: &mut TestApp
respond_tx
.send(PredictEditsV3Response {
request_id: Uuid::new_v4().to_string(),
output: "hello<|user_cursor|> world".to_string(),
output: "hello world".to_string(),
editable_range: 0..excerpt_length,
model_version: None,
cursor_offset: Some(5),
})
.unwrap();
@ -2878,6 +2882,7 @@ async fn make_test_ep_store(
editable_range: 0..req.input.cursor_excerpt.len(),
output: completion_response.lock().clone(),
model_version: None,
cursor_offset: None,
})
.unwrap()
.into(),

View file

@ -25,8 +25,7 @@ use zeta_prompt::{ParsedOutput, ZetaPromptInput};
use std::{env, ops::Range, path::Path, sync::Arc};
use zeta_prompt::{
ZetaFormat, format_zeta_prompt, get_prefill, parse_zeta2_model_output,
parsed_output_from_editable_region, prompt_input_contains_special_tokens,
stop_tokens_for_format,
prompt_input_contains_special_tokens, stop_tokens_for_format,
zeta1::{self, EDITABLE_REGION_END_MARKER},
};
@ -280,12 +279,12 @@ pub fn request_prediction_with_zeta(
.await?;
let request_id = EditPredictionId(response.request_id.into());
let output_text = Some(response.output).filter(|s| !s.is_empty());
let model_version = response.model_version;
let parsed_output = parsed_output_from_editable_region(
response.editable_range,
output_text.unwrap_or_default(),
);
let parsed_output = ParsedOutput {
new_editable_region: response.output,
range_in_excerpt: response.editable_range,
cursor_offset_in_new_editable_region: response.cursor_offset,
};
Some((request_id, Some(parsed_output), model_version, usage))
})