-
Notifications
You must be signed in to change notification settings - Fork 537
fix: clean up log analysis comments on GitHub issues #3925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,3 +1,37 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fn strip_code_fences(s: &str) -> String { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let trimmed = s.trim(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let stripped = trimmed | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .strip_prefix("```") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .and_then(|s| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let s = s.strip_prefix('\n').unwrap_or(s); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| s.strip_suffix("```") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map(|s| s.trim()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .unwrap_or(trimmed); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stripped.to_string() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+12
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The The function strips the opening ``` leaving "markdown\ncontent\n```", then tries to strip '\n' which fails because "markdown" comes first, so it returns "markdown\ncontent\n```", then strips the trailing ``` leaving "markdown\ncontent". This causes "markdown" (or any language identifier) to appear in the summary section. Fix: After stripping the opening fence, skip any non-newline characters before the newline: fn strip_code_fences(s: &str) -> String {
let trimmed = s.trim();
let stripped = trimmed
.strip_prefix("```")
.and_then(|s| {
// Skip language identifier if present
let s = s.trim_start_matches(|c| c != '\n');
let s = s.strip_prefix('\n').unwrap_or(s);
s.strip_suffix("```")
})
.map(|s| s.trim())
.unwrap_or(trimmed);
stripped.to_string()
}
Suggested change
Spotted by Graphite Agent |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pub(crate) fn strip_ansi_escapes(s: &str) -> String { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let mut result = String::with_capacity(s.len()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let mut chars = s.chars().peekable(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while let Some(c) = chars.next() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if c == '\x1b' { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if chars.peek() == Some(&'[') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| chars.next(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while let Some(&next) = chars.peek() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| chars.next(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if next.is_ascii_alphabetic() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+18
to
+27
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incomplete ANSI sequence handling: If a log ends with an incomplete ANSI escape sequence (e.g., Fix: Add a safety limit to the inner loop or check for end-of-string: if c == '\x1b' {
if chars.peek() == Some(&'[') {
chars.next();
let mut count = 0;
while let Some(&next) = chars.peek() {
chars.next();
if next.is_ascii_alphabetic() || count > 20 {
break;
}
count += 1;
}
}
}
Suggested change
Spotted by Graphite Agent |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result.push(c); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pub(crate) fn safe_tail(s: &str, max_bytes: usize) -> &str { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let start = s.len().saturating_sub(max_bytes); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let start = s | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -27,5 +61,5 @@ pub(crate) async fn analyze_logs(api_key: &str, logs: &str) -> Option<String> { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let resp = client.chat_completion(&req).await.ok()?; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let content = resp.choices.first()?.message.content.as_ref()?; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let text = content.as_text()?; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Some(text.chars().take(800).collect()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Some(strip_code_fences(text).chars().take(800).collect()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡
strip_code_fencesfails to strip language identifier from fenced code blocksThe
strip_code_fencesfunction doesn't handle the common LLM pattern of```text\n...\n```or```json\n...\n```. When the LLM returns a code block with a language identifier, the identifier leaks into the output.Root Cause and Impact
The function does
strip_prefix("```")which removes the opening triple backticks, leaving e.g."text\ncontent\n\``". Thenstrip_prefix('\n')fails because the string starts withtext, not a newline. Theunwrap_or(s)fallback keeps the full remainder. Finallystrip_suffix("```")removes the closing fence, yielding"text\ncontent"`—the language identifier `text` is now part of the content.This result then gets embedded at
crates/api-support/src/github.rs:136insideformat!("### Summary\n```\n{s}\n```"), producing broken output like:Since the whole purpose of this function is to clean up LLM output that wraps responses in code fences, and LLMs very commonly use language-tagged fences (
```text,```json,```markdown), this is a significant gap.Fix: After
strip_prefix("```"), skip everything up to and including the first\n(not just a bare\nprefix).Was this helpful? React with 👍 or 👎 to provide feedback.