Make eval more resilient to bad input from LLM (#29703)

I saw a slice panic (for begin > end) in a debug build of the eval. This
should just be a failed assertion, not a panic that takes out the whole
eval run!

Release Notes:

- N/A
This commit is contained in:
Richard Feldman 2025-04-30 18:13:45 -04:00 committed by GitHub
parent 92dd6b67c7
commit afeb3d4fd9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -98,54 +98,64 @@ impl Example for CodeBlockCitations {
if let Some(content_len) = content_len { if let Some(content_len) = content_len {
// + 1 because there's a newline character after the citation. // + 1 because there's a newline character after the citation.
let content = let start_index = citation.len() + 1;
&text[(citation.len() + 1)..content_len - (citation.len() + 1)]; let end_index = content_len.saturating_sub(start_index);
// deindent (trim the start of each line) because sometimes the model if cx
// chooses to deindent its code snippets for the sake of readability, .assert(
// which in markdown is not only reasonable but usually desirable. start_index <= end_index,
cx.assert( "Code block had a valid citation",
deindent(&buffer_text) )
.trim() .is_ok()
.contains(deindent(&content).trim()), {
"Code block content was found in file", let content = &text[start_index..end_index];
)
.ok();
if let Some(range) = path_range.range {
let start_line_index = range.start.line.saturating_sub(1);
let line_count =
range.end.line.saturating_sub(start_line_index);
let mut snippet = buffer_text
.lines()
.skip(start_line_index as usize)
.take(line_count as usize)
.collect::<Vec<&str>>()
.join("\n");
if let Some(start_col) = range.start.col {
snippet = snippet[start_col as usize..].to_string();
}
if let Some(end_col) = range.end.col {
let last_line = snippet.lines().last().unwrap();
snippet = snippet
[..snippet.len() - last_line.len() + end_col as usize]
.to_string();
}
// deindent (trim the start of each line) because sometimes the model // deindent (trim the start of each line) because sometimes the model
// chooses to deindent its code snippets for the sake of readability, // chooses to deindent its code snippets for the sake of readability,
// which in markdown is not only reasonable but usually desirable. // which in markdown is not only reasonable but usually desirable.
cx.assert_eq( cx.assert(
deindent(snippet.as_str()).trim(), deindent(&buffer_text)
deindent(content).trim(), .trim()
format!( .contains(deindent(&content).trim()),
"Code block was at {:?}-{:?}", "Code block content was found in file",
range.start, range.end
),
) )
.ok(); .ok();
if let Some(range) = path_range.range {
let start_line_index = range.start.line.saturating_sub(1);
let line_count =
range.end.line.saturating_sub(start_line_index);
let mut snippet = buffer_text
.lines()
.skip(start_line_index as usize)
.take(line_count as usize)
.collect::<Vec<&str>>()
.join("\n");
if let Some(start_col) = range.start.col {
snippet = snippet[start_col as usize..].to_string();
}
if let Some(end_col) = range.end.col {
let last_line = snippet.lines().last().unwrap();
snippet = snippet[..snippet.len() - last_line.len()
+ end_col as usize]
.to_string();
}
// deindent (trim the start of each line) because sometimes the model
// chooses to deindent its code snippets for the sake of readability,
// which in markdown is not only reasonable but usually desirable.
cx.assert_eq(
deindent(snippet.as_str()).trim(),
deindent(content).trim(),
format!(
"Code block was at {:?}-{:?}",
range.start, range.end
),
)
.ok();
}
} }
} }
} }