fix(slack): don't double-emit trailing text on odd number of ``` fences (#1436)

extractCodeBlocks split on "```" and treated every odd-indexed part as a
closed code block. With an odd number of fences (>=3), Split returns an even
number of parts, so the final segment -- which follows an unpaired opening
fence and must stay literal -- landed on an odd index and was both emitted as
a \x00CB\x00 placeholder (later restored as ```seg```) AND re-appended
verbatim by the trailing len(parts)%2==0 block. The segment was therefore
duplicated in the rendered Slack message (and blocks gained a spurious entry).
Unclosed trailing fences are common in streamed LLM output.

Exclude the final unpaired part from the paired-scan loop. Add a regression
test covering the closed-block-then-unpaired-fence case.
This commit is contained in:
Syed Osama Ali Shah authored and GitHub committed 2026-07-15 00:54:17 +07:00
1 parent 27f4b7743b
commit 6f91b937c1
2 files changed
+18 -1

No files matched your search

+10 -1
View File
@@ -113,8 +113,17 @@ func extractCodeBlocks(text string) (blocks []string, result string) {
return nil, text
}
// An odd number of ``` fences makes Split return an even number of parts;
// the final segment then follows an unpaired opening fence and must stay
// literal (it is re-appended verbatim below), so exclude it from the
// paired-scan loop instead of misclassifying it as a closed code block.
scanEnd := len(parts)
if scanEnd%2 == 0 {
scanEnd--
}
var sb strings.Builder
for i, part := range parts {
for i := 0; i < scanEnd; i++ {
part := parts[i]
if i%2 == 1 {
blocks = append(blocks, part)
sb.WriteString(fmt.Sprintf("\x00CB%d\x00", len(blocks)-1))
+8
View File
@@ -318,6 +318,14 @@ func TestExtractCodeBlocks(t *testing.T) {
input: "text\n```\ncode (no closing)",
expectedCount: 0,
},
{
// A closed block followed by an unpaired opening fence: 3 fences ->
// 4 parts. Only the middle part is a real code block; the trailing
// segment must stay literal, not be counted (and re-emitted) as one.
name: "closed block then unpaired trailing fence",
input: "a```b```c```d",
expectedCount: 1,
},
{
name: "empty code block",
input: "```\n\n```",