From f14499a01fb7f0124faca6cfc35f9b2dd2d38206 Mon Sep 17 00:00:00 2001 From: Qwen Autofix Bot Date: Thu, 2 Jul 2026 13:13:22 +0000 Subject: [PATCH 1/4] fix(core): skip abbreviations in multiple_sentences filter (#6077) The follow-up suggestion generator was falsely flagging suggestions containing common abbreviations like 'vs.' or 'Dr.' as multiple sentences, because the filter regex matched any period followed by a capitalized word. Replace the inline regex with a named MULTIPLE_SENTENCES_RE that uses a negative lookbehind to skip common honorifics (Mr, Mrs, Dr, Ms, Prof, Sr, Jr, St), abbreviations (vs, etc), and Latin shorthands (e.g., i.e.). Add vitest coverage for the issue's reported case, the common abbreviations, and an explicit multi-sentence case so the filter still catches real run-on suggestions. Fixes #6077 --- .../src/followup/suggestionGenerator.test.ts | 21 +++++++++++++++++++ .../core/src/followup/suggestionGenerator.ts | 11 +++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/core/src/followup/suggestionGenerator.test.ts b/packages/core/src/followup/suggestionGenerator.test.ts index 86f2225cee3..f02d1b97490 100644 --- a/packages/core/src/followup/suggestionGenerator.test.ts +++ b/packages/core/src/followup/suggestionGenerator.test.ts @@ -157,6 +157,27 @@ describe('shouldFilterSuggestion', () => { it('filters multiple sentences', () => { expect(shouldFilterSuggestion('Run the tests. Then commit.')).toBe(true); + expect(shouldFilterSuggestion('Hello! How are you?')).toBe(true); + expect(shouldFilterSuggestion('Do this. Then do that.')).toBe(true); + }); + + it('does not filter abbreviations as multiple sentences', () => { + // Issue #6077 — "vs." followed by a capitalized word should pass. + expect( + shouldFilterSuggestion( + "Let's start with the Weeds vs. Wildflowers audit.", + ), + ).toBe(false); + expect(shouldFilterSuggestion('Weeds vs. Wildflowers audit')).toBe(false); + // Common honorifics and abbreviations + expect(shouldFilterSuggestion('Check Dr. Smith notes')).toBe(false); + expect(shouldFilterSuggestion('Ask Mr. Jones for help')).toBe(false); + expect(shouldFilterSuggestion('Talk to Ms. Patel next')).toBe(false); + expect(shouldFilterSuggestion('See Prof. Lee today')).toBe(false); + expect(shouldFilterSuggestion('Visit St. Petersburg office')).toBe(false); + expect(shouldFilterSuggestion('Review the etc. items')).toBe(false); + // Latin shorthands with an internal period + expect(shouldFilterSuggestion('Use e.g. Docker to build')).toBe(false); }); it('filters formatting', () => { diff --git a/packages/core/src/followup/suggestionGenerator.ts b/packages/core/src/followup/suggestionGenerator.ts index c84b430e930..7e268d9bf7d 100644 --- a/packages/core/src/followup/suggestionGenerator.ts +++ b/packages/core/src/followup/suggestionGenerator.ts @@ -238,6 +238,15 @@ const ALLOWED_SINGLE_WORDS = new Set([ 'no', ]); +/** + * Abbreviations whose trailing period should not look like a sentence boundary. + * The negative lookbehind skips common honorifics, abbreviations, and Latin + * shorthands (e.g., i.e.) so that "Dr. Smith" or "Weeds vs. Wildflowers" is + * not mistaken for two sentences. + */ +const MULTIPLE_SENTENCES_RE = + /(? 30) return 'too_many_words'; } if (suggestion.length >= 100) return 'too_long'; - if (/[.!?]\s+[A-Z]/.test(suggestion)) return 'multiple_sentences'; + if (MULTIPLE_SENTENCES_RE.test(suggestion)) return 'multiple_sentences'; if (/[\n*]|\*\*/.test(suggestion)) return 'has_formatting'; if ( From dc50675f3fa93b26228698185914d21346f6f5d0 Mon Sep 17 00:00:00 2001 From: Qwen Autofix Bot Date: Sat, 4 Jul 2026 00:50:41 +0000 Subject: [PATCH 2/4] fix(core): replace blanket abbreviation lookbehind with per-boundary check (#6077) The negative lookbehind in MULTIPLE_SENTENCES_RE exempted every abbreviation (including etc, eg, ie) from sentence-boundary detection, so 'Review options etc. Then commit.' incorrectly passed the filter. Replace the regex with hasSentenceBoundary(), which checks each potential boundary individually: honorifics (Dr., Mr., etc.) and vs. are recognized as safe continuations, while etc. at the end of a real sentence is still correctly detected. Latin shorthands (e.g., i.e.) are handled by checking the two-part pattern before the period. --- .../src/followup/suggestionGenerator.test.ts | 3 ++ .../core/src/followup/suggestionGenerator.ts | 41 +++++++++++++++---- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/packages/core/src/followup/suggestionGenerator.test.ts b/packages/core/src/followup/suggestionGenerator.test.ts index f02d1b97490..c7441cb7bcc 100644 --- a/packages/core/src/followup/suggestionGenerator.test.ts +++ b/packages/core/src/followup/suggestionGenerator.test.ts @@ -159,6 +159,9 @@ describe('shouldFilterSuggestion', () => { expect(shouldFilterSuggestion('Run the tests. Then commit.')).toBe(true); expect(shouldFilterSuggestion('Hello! How are you?')).toBe(true); expect(shouldFilterSuggestion('Do this. Then do that.')).toBe(true); + expect(shouldFilterSuggestion('Review options etc. Then commit.')).toBe( + true, + ); }); it('does not filter abbreviations as multiple sentences', () => { diff --git a/packages/core/src/followup/suggestionGenerator.ts b/packages/core/src/followup/suggestionGenerator.ts index 7e268d9bf7d..c30e547692f 100644 --- a/packages/core/src/followup/suggestionGenerator.ts +++ b/packages/core/src/followup/suggestionGenerator.ts @@ -238,14 +238,37 @@ const ALLOWED_SINGLE_WORDS = new Set([ 'no', ]); -/** - * Abbreviations whose trailing period should not look like a sentence boundary. - * The negative lookbehind skips common honorifics, abbreviations, and Latin - * shorthands (e.g., i.e.) so that "Dr. Smith" or "Weeds vs. Wildflowers" is - * not mistaken for two sentences. - */ -const MULTIPLE_SENTENCES_RE = - /(? 30) return 'too_many_words'; } if (suggestion.length >= 100) return 'too_long'; - if (MULTIPLE_SENTENCES_RE.test(suggestion)) return 'multiple_sentences'; + if (hasSentenceBoundary(suggestion)) return 'multiple_sentences'; if (/[\n*]|\*\*/.test(suggestion)) return 'has_formatting'; if ( From e19306774e6d428745a783246a1724296698d1c6 Mon Sep 17 00:00:00 2001 From: Qwen Autofix Bot Date: Sat, 4 Jul 2026 09:08:46 +0000 Subject: [PATCH 3/4] fix(core): add etc to abbreviation set, rename constant, strengthen tests (#6077) --- .../core/src/followup/suggestionGenerator.test.ts | 11 +++++++---- packages/core/src/followup/suggestionGenerator.ts | 5 +++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/core/src/followup/suggestionGenerator.test.ts b/packages/core/src/followup/suggestionGenerator.test.ts index c7441cb7bcc..1f702fb3d42 100644 --- a/packages/core/src/followup/suggestionGenerator.test.ts +++ b/packages/core/src/followup/suggestionGenerator.test.ts @@ -159,9 +159,8 @@ describe('shouldFilterSuggestion', () => { expect(shouldFilterSuggestion('Run the tests. Then commit.')).toBe(true); expect(shouldFilterSuggestion('Hello! How are you?')).toBe(true); expect(shouldFilterSuggestion('Do this. Then do that.')).toBe(true); - expect(shouldFilterSuggestion('Review options etc. Then commit.')).toBe( - true, - ); + // Abbreviation skipped, then real sentence boundary detected + expect(shouldFilterSuggestion('Check Dr. Smith. Then commit.')).toBe(true); }); it('does not filter abbreviations as multiple sentences', () => { @@ -178,9 +177,13 @@ describe('shouldFilterSuggestion', () => { expect(shouldFilterSuggestion('Talk to Ms. Patel next')).toBe(false); expect(shouldFilterSuggestion('See Prof. Lee today')).toBe(false); expect(shouldFilterSuggestion('Visit St. Petersburg office')).toBe(false); - expect(shouldFilterSuggestion('Review the etc. items')).toBe(false); + expect(shouldFilterSuggestion('Check etc. Tasks remaining')).toBe(false); + expect(shouldFilterSuggestion('Review options etc. Then commit')).toBe( + false, + ); // Latin shorthands with an internal period expect(shouldFilterSuggestion('Use e.g. Docker to build')).toBe(false); + expect(shouldFilterSuggestion('Use i.e. Docker to build')).toBe(false); }); it('filters formatting', () => { diff --git a/packages/core/src/followup/suggestionGenerator.ts b/packages/core/src/followup/suggestionGenerator.ts index c30e547692f..e6ba178d99a 100644 --- a/packages/core/src/followup/suggestionGenerator.ts +++ b/packages/core/src/followup/suggestionGenerator.ts @@ -238,7 +238,7 @@ const ALLOWED_SINGLE_WORDS = new Set([ 'no', ]); -const ABBREV_HONORIFICS = new Set([ +const KNOWN_ABBREVIATIONS = new Set([ 'Mr', 'Mrs', 'Dr', @@ -248,6 +248,7 @@ const ABBREV_HONORIFICS = new Set([ 'Jr', 'St', 'vs', + 'etc', ]); const SENTENCE_BOUNDARY_RE = /[.!?]\s+[A-Z]/g; @@ -259,7 +260,7 @@ function hasSentenceBoundary(suggestion: string): boolean { const wordMatch = before.match(/(\w+)$/); if (!wordMatch) return true; const word = wordMatch[1]; - if (ABBREV_HONORIFICS.has(word)) continue; + if (KNOWN_ABBREVIATIONS.has(word)) continue; if ( (word === 'g' && /e\.g$/.test(before)) || (word === 'e' && /i\.e$/.test(before)) From 1c2124487e9cd5d74ce32f5c4841cfc7630cf1b2 Mon Sep 17 00:00:00 2001 From: Qwen Code Date: Sat, 4 Jul 2026 12:36:22 +0000 Subject: [PATCH 4/4] fix(core): address review feedback (#6077) - Make e.g./i.e. abbreviation check case-insensitive to handle capitalized variants (E.g., I.e.) - Add test for non-word-char-before-punctuation branch in hasSentenceBoundary --- packages/core/src/followup/suggestionGenerator.test.ts | 5 +++++ packages/core/src/followup/suggestionGenerator.ts | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/core/src/followup/suggestionGenerator.test.ts b/packages/core/src/followup/suggestionGenerator.test.ts index 1f702fb3d42..2245e5906c2 100644 --- a/packages/core/src/followup/suggestionGenerator.test.ts +++ b/packages/core/src/followup/suggestionGenerator.test.ts @@ -161,6 +161,8 @@ describe('shouldFilterSuggestion', () => { expect(shouldFilterSuggestion('Do this. Then do that.')).toBe(true); // Abbreviation skipped, then real sentence boundary detected expect(shouldFilterSuggestion('Check Dr. Smith. Then commit.')).toBe(true); + // Non-word char before punctuation — still detected as sentence boundary + expect(shouldFilterSuggestion('Run (see docs). Then deploy')).toBe(true); }); it('does not filter abbreviations as multiple sentences', () => { @@ -184,6 +186,9 @@ describe('shouldFilterSuggestion', () => { // Latin shorthands with an internal period expect(shouldFilterSuggestion('Use e.g. Docker to build')).toBe(false); expect(shouldFilterSuggestion('Use i.e. Docker to build')).toBe(false); + // Capitalized variants still recognized as abbreviations + expect(shouldFilterSuggestion('Use E.g. Docker to build')).toBe(false); + expect(shouldFilterSuggestion('Use I.e. Docker to build')).toBe(false); }); it('filters formatting', () => { diff --git a/packages/core/src/followup/suggestionGenerator.ts b/packages/core/src/followup/suggestionGenerator.ts index e6ba178d99a..df3d72b2e0d 100644 --- a/packages/core/src/followup/suggestionGenerator.ts +++ b/packages/core/src/followup/suggestionGenerator.ts @@ -262,8 +262,8 @@ function hasSentenceBoundary(suggestion: string): boolean { const word = wordMatch[1]; if (KNOWN_ABBREVIATIONS.has(word)) continue; if ( - (word === 'g' && /e\.g$/.test(before)) || - (word === 'e' && /i\.e$/.test(before)) + (word === 'g' && /e\.g$/i.test(before)) || + (word === 'e' && /i\.e$/i.test(before)) ) continue; return true;