Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions src/app/api/chat/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
function getMaxTokens(length: ResponseLength): number {
switch (length) {
case "short":
return 200
return 350
case "long":
return 1024
default:
Expand All @@ -41,7 +41,7 @@
let lastAllowedIndex = text.length
let match: RegExpExecArray | null

while ((match = wordRegex.exec(text)) !== null) {

Check warning on line 44 in src/app/api/chat/route.ts

View workflow job for this annotation

GitHub Actions / ci

'match' is assigned a value but never used
wordCount += 1
if (wordCount === wordLimit) {
lastAllowedIndex = wordRegex.lastIndex
Expand All @@ -56,7 +56,7 @@
return { text, truncated: false }
}

function countWords(text: string): number {

Check warning on line 59 in src/app/api/chat/route.ts

View workflow job for this annotation

GitHub Actions / ci

'countWords' is defined but never used
return text.trim().split(/\s+/).filter(Boolean).length
}

Expand All @@ -72,12 +72,19 @@

function polishTruncatedShortResponse(text: string, wordLimit: number): string {
let result = text.trimEnd()
const sentenceMatches = [...result.matchAll(/[.!?。!?](?=\s|$)/g)]

// Already ends cleanly - just enforce word limit
if (/[.!?。!?]$/u.test(result)) {
return clampToWordLimit(result, wordLimit).text
}

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

polishTruncatedShortResponse returns early when the original text ends with sentence punctuation, but clampToWordLimit can still truncate the content to the word limit and produce a string that no longer ends with punctuation (and won’t get the later cleanup/ellipsis). Consider clamping first, then re-checking the ending, or using the { truncated } flag to only early-return when no truncation occurred.

Copilot uses AI. Check for mistakes.

// Try to truncate at the last complete sentence
const sentenceMatches = [...result.matchAll(/[.!?。!?](?=\s|$)/g)]
if (sentenceMatches.length > 0) {
const lastSentence = sentenceMatches[sentenceMatches.length - 1]
const sentenceSafe = result.slice(0, (lastSentence.index ?? 0) + lastSentence[0].length).trimEnd()
Comment on lines +82 to 86

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

The sentence-boundary detection only matches punctuation when followed by whitespace/end (/(?=\s|$)/). Short responses often end with quotes/parentheses (e.g., ..." or ...)), which will bypass sentence detection and cause the function to append ... even when the sentence is complete. Consider allowing common closing delimiters after the punctuation in both the ends cleanly check and sentenceMatches regex.

Copilot uses AI. Check for mistakes.
if (countWords(sentenceSafe) >= Math.min(40, wordLimit)) {
// Accept if we keep at least 30% of the content (works for both EN and KO)
if (sentenceSafe.length >= result.length * 0.3) {
result = sentenceSafe
}
}
Comment on lines 86 to 91

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

countWords is no longer used after switching the sentence-fallback threshold to a length-based check. Removing the unused helper will avoid dead code and potential lint noise.

Copilot uses AI. Check for mistakes.
Expand Down Expand Up @@ -227,7 +234,7 @@
}

if (!request.signal?.aborted) {
if (wordLimit && truncatedShortResponse) {
if (wordLimit) {
fullContent = polishTruncatedShortResponse(fullContent, wordLimit)
}

Expand Down
2 changes: 1 addition & 1 deletion src/app/chat/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ function ChatPageContent() {
prevMessageCount.current = 0
persistence.reset()
handleReset()
router.push("/chat")
router.replace("/chat")
}, [persistence, handleReset, router])

// When user continues a completed thread, mark it active again
Expand Down
2 changes: 1 addition & 1 deletion src/components/ThreadDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export default function ThreadDropdown({
// Close before navigation to minimize visible flicker during the route change
isNavigatingRef.current = true
setIsOpen(false)
router.push(`/chat?thread=${threadId}`)
router.replace(`/chat?thread=${threadId}`)
}

const handleDelete = async (e: React.MouseEvent, threadId: string) => {
Expand Down
Loading