Skip to content

fix: clean up log analysis comments on GitHub issues#3925

Open
devin-ai-integration[bot] wants to merge 2 commits intomainfrom
devin/1770910157-fix-log-analysis-summary
Open

fix: clean up log analysis comments on GitHub issues#3925
devin-ai-integration[bot] wants to merge 2 commits intomainfrom
devin/1770910157-fix-log-analysis-summary

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Feb 12, 2026

Summary

Fixes three formatting issues with the log analysis comments that hyper-charlie bot attaches to user-submitted GitHub issues:

  1. Broken code blocks from LLM output: Gemini sometimes wraps its response in ``` fences, which nest inside the existing code block wrapper and produce broken markdown. Added strip_code_fences to remove wrapping fences from the LLM response before embedding it.

  2. ANSI escape sequences in raw logs: Logs from the desktop app can contain ANSI color/formatting codes (e.g. \x1b[0m, \x1b[3m) that render as garbled text on GitHub. Added strip_ansi_escapes to clean these before both the LLM analysis and the raw log tail. (ref: ## Error Details #3921)

  3. HTML entity escaping (" for "): Askama auto-escapes HTML entities by default, but these templates produce GitHub markdown, not HTML. Added escape = "none" to all three Askama markdown templates.

Review & Testing Checklist for Human

  • escape = "none" on all templates: This disables HTML escaping for bug_report, feature_request, and log_analysis templates. Since GitHub handles its own markdown sanitization this should be safe, but verify there's no injection concern with user-controlled description fields.
  • strip_code_fences edge cases: Only handles exact ``` prefix/suffix. If the LLM returns ```text\n...\n```, the language identifier (text) will leak into the output. Consider whether this matters in practice.
  • strip_ansi_escapes coverage: Only strips CSI sequences (ESC[...letter). Other escape types (OSC, single-char escapes) are not handled—orphan ESC bytes are silently dropped. Likely sufficient for typical Tauri log output.
  • End-to-end test: Submit a bug report from the desktop app and verify the resulting GitHub issue comment has clean formatting—no broken code blocks, no ", no ANSI artifacts.

Notes


Open with Devin

devin-ai-integration bot and others added 2 commits February 12, 2026 15:36
Co-Authored-By: john@hyprnote.com <john@hyprnote.com>
Co-Authored-By: john@hyprnote.com <john@hyprnote.com>
@netlify
Copy link

netlify bot commented Feb 12, 2026

Deploy Preview for hyprnote canceled.

Name Link
🔨 Latest commit d84105f
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/698df44585cf8900087ff1db

@netlify
Copy link

netlify bot commented Feb 12, 2026

Deploy Preview for hyprnote-storybook canceled.

Name Link
🔨 Latest commit d84105f
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/698df4456825600008603b4e

@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +4 to +8
.strip_prefix("```")
.and_then(|s| {
let s = s.strip_prefix('\n').unwrap_or(s);
s.strip_suffix("```")
})
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 strip_code_fences fails to strip language identifier from fenced code blocks

The strip_code_fences function 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\``". Then strip_prefix('\n')fails because the string starts withtext, not a newline. The unwrap_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:136 inside format!("### Summary\n```\n{s}\n```"), producing broken output like:

### Summary
` ` `
text
ERROR: something went wrong
` ` `

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 \n prefix).

Suggested change
.strip_prefix("```")
.and_then(|s| {
let s = s.strip_prefix('\n').unwrap_or(s);
s.strip_suffix("```")
})
.strip_prefix("```")
.and_then(|s| {
let s = match s.find('\n') {
Some(pos) => &s[pos + 1..],
None => s,
};
s.strip_suffix("```")
})
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +18 to +27
if c == '\x1b' {
if chars.peek() == Some(&'[') {
chars.next();
while let Some(&next) = chars.peek() {
chars.next();
if next.is_ascii_alphabetic() {
break;
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The 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., \x1b[31 without a terminating alphabetic character), the inner while loop at line 21-26 will consume all remaining characters while searching for the terminating letter. This causes the trailing content to be silently dropped.

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
if c == '\x1b' {
if chars.peek() == Some(&'[') {
chars.next();
while let Some(&next) = chars.peek() {
chars.next();
if next.is_ascii_alphabetic() {
break;
}
}
}
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;
}
}

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant