Skip to content

Commit 8a29a1a

Browse files
authored
release/v4.205.0 (#20)
* fix race condition with the isUserInput flag * API Streaming Failed to have retry button * fix previous commands still show run/reject buttons * better checkpoint handling * feat: migrate KiloTaskHeader and TaskItem to use ReadOnlyChatText MIGRATION CHANGES: - Update KiloTaskHeader.tsx to import and use ReadOnlyChatText component - Replace custom highlightText function calls with ReadOnlyChatText - Remove unused highlighting functions (highlightSlashCommands, highlightMentions, highlightText) - Update TaskItem.tsx to use ReadOnlyChatText for consistent text rendering - Remove unused highlight property from DisplayHistoryItem interface - Remove empty DisplayHistoryItem interface to fix linting warning LINTING FIXES: - Clean up unused imports (validateSlashCommand, mentionRegexGlobal, vscode) - Remove unused customModes variable in KiloTaskHeader - Remove unused Mention import in ChatRow.tsx - Remove unused imports in ChatTextArea.tsx (getIconForFilePath, getIconUrlByName, formatMentionChipParts, getFileIconForMention, valueToHtml) - Remove unused mentionRegex import in ReadOnlyChatText.tsx BENEFITS: - Provides better text formatting with HTML conversion and mention support - Maintains all existing styling and layout functionality - Improves code consistency across chat components - Eliminates custom highlighting logic in favor of established component * add chat renderer * fix duplicate code * update changelog
1 parent c6719d5 commit 8a29a1a

File tree

12 files changed

+409
-246
lines changed

12 files changed

+409
-246
lines changed

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
11
# Changelog
22

3+
## [v4.205.0] - 2025-12-26
4+
5+
### Added
6+
7+
- New chat renderer utility for improved message rendering
8+
- Retry button functionality for API streaming failures
9+
- Enhanced checkpoint handling system
10+
11+
### Changed
12+
13+
- Migrated KiloTaskHeader and TaskItem components to use ReadOnlyChatText
14+
- Refactored ChatTextArea component with code cleanup
15+
- Improved ChatRow component with better checkpoint integration
16+
17+
### Fixed
18+
19+
- Fixed duplicate code removal in ChatTextArea
20+
- Resolved race condition with isUserInput flag
21+
- Fixed previous commands still showing run/reject buttons
22+
- Improved UI consistency and functionality
23+
24+
---
25+
326
## [v4.204.1] - 2025-12-20
427

528
### Added

src/core/task/Task.ts

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3198,7 +3198,10 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
31983198
errorMsg = "Unknown error"
31993199
}
32003200

3201-
const baseDelay = requestDelaySeconds || 5
3201+
await this.ask("api_req_failed", errorMsg)
3202+
3203+
// Wait for the delay before retrying
3204+
const baseDelay = requestDelaySeconds || 0
32023205
let exponentialDelay = Math.min(
32033206
Math.ceil(baseDelay * Math.pow(2, retryAttempt)),
32043207
MAX_EXPONENTIAL_BACKOFF_SECONDS,
@@ -3212,21 +3215,16 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
32123215
if (geminiRetryDetails) {
32133216
const match = geminiRetryDetails?.retryDelay?.match(/^(\d+)s$/)
32143217
if (match) {
3215-
exponentialDelay = Number(match[1]) + 1
3218+
exponentialDelay = parseInt(match[1], 10)
32163219
}
32173220
}
32183221
}
32193222

3220-
// Wait for the greater of the exponential delay or the rate limit delay
3221-
const finalDelay = Math.max(exponentialDelay, rateLimitDelay)
3222-
3223-
// Show countdown timer with exponential backoff
3224-
for (let i = finalDelay; i > 0; i--) {
3223+
for (let i = exponentialDelay; i > 0; i--) {
32253224
await this.say(
32263225
"api_req_retry_delayed",
32273226
`${errorMsg}\n\nRetry attempt ${retryAttempt + 1}\nRetrying in ${i} seconds...`,
32283227
undefined,
3229-
true,
32303228
)
32313229
await delay(1000)
32323230
}
@@ -3235,7 +3233,6 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
32353233
"api_req_retry_delayed",
32363234
`${errorMsg}\n\nRetry attempt ${retryAttempt + 1}\nRetrying now...`,
32373235
undefined,
3238-
false,
32393236
)
32403237

32413238
// Delegate generator output from the recursive call with
@@ -3263,15 +3260,65 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
32633260
}
32643261
}
32653262

3266-
// No error, so we can continue to yield all remaining chunks.
3267-
// (Needs to be placed outside of try/catch since it we want caller to
3268-
// handle errors not with api_req_failed as that is reserved for first
3269-
// chunk failures only.)
3270-
// This delegates to another generator or iterable object. In this case,
3271-
// it's saying "yield all remaining values from this iterator". This
3272-
// effectively passes along all subsequent chunks from the original
3273-
// stream.
3274-
yield* iterator
3263+
// No error on first chunk, so we can continue to yield all remaining chunks.
3264+
// Wrap in try/catch to handle mid-stream errors and allow retry.
3265+
try {
3266+
yield* iterator
3267+
} catch (error) {
3268+
// Reset streaming state since we encountered an error
3269+
this.isStreaming = false
3270+
3271+
// kilocode_change start
3272+
if (apiConfiguration?.apiProvider === "kilocode" && isAnyRecognizedKiloCodeError(error)) {
3273+
const { response } = await (isPaymentRequiredError(error)
3274+
? this.ask(
3275+
"payment_required_prompt",
3276+
JSON.stringify({
3277+
title: error.error?.title ?? t("kilocode:lowCreditWarning.title"),
3278+
message: error.error?.message ?? t("kilocode:lowCreditWarning.message"),
3279+
balance: error.error?.balance ?? "0.00",
3280+
buyCreditsUrl: error.error?.buyCreditsUrl ?? getAppUrl("/profile"),
3281+
}),
3282+
)
3283+
: this.ask(
3284+
"invalid_model",
3285+
JSON.stringify({
3286+
modelId: apiConfiguration.kilocodeModel,
3287+
error: {
3288+
status: error.status,
3289+
message: error.message,
3290+
},
3291+
}),
3292+
))
3293+
3294+
if (response === "retry_clicked") {
3295+
yield* this.attemptApiRequest(retryAttempt + 1)
3296+
} else {
3297+
// Handle other responses or cancellations if necessary
3298+
throw error // Rethrow to signal failure upwards
3299+
}
3300+
return
3301+
}
3302+
// kilocode_change end
3303+
3304+
// For mid-stream failures, show the retry dialog to allow user to retry
3305+
const { response } = await this.ask(
3306+
"api_req_failed",
3307+
error.message ?? JSON.stringify(serializeError(error), null, 2),
3308+
)
3309+
3310+
if (response !== "yesButtonClicked") {
3311+
// This will never happen since if noButtonClicked, we will
3312+
// clear current task, aborting this instance.
3313+
throw new Error("API request failed")
3314+
}
3315+
3316+
await this.say("api_req_retried")
3317+
3318+
// Delegate generator output from the recursive call.
3319+
yield* this.attemptApiRequest()
3320+
return
3321+
}
32753322
}
32763323

32773324
// Checkpoints

src/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"displayName": "%extension.displayName%",
44
"description": "%extension.description%",
55
"publisher": "matterai",
6-
"version": "4.204.1",
6+
"version": "4.205.0",
77
"icon": "assets/icons/matterai-ic.png",
88
"galleryBanner": {
99
"color": "#FFFFFF",

webview-ui/src/components/chat/ChatRow.tsx

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { VSCodeBadge, VSCodeButton } from "@vscode/webview-ui-toolkit/react"
22
import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from "react"
33
import { Trans, useTranslation } from "react-i18next"
44
import { useSize } from "react-use"
5+
import { Undo2 } from "lucide-react"
56

67
import type { ClineMessage, FollowUpData, SuggestionItem } from "@roo-code/types"
78
import { Mode } from "@roo/modes"
@@ -34,9 +35,9 @@ import { CommandExecution } from "./CommandExecution"
3435
import { CommandExecutionError } from "./CommandExecutionError"
3536
import { FollowUpSuggest } from "./FollowUpSuggest"
3637
import { Markdown } from "./Markdown"
37-
import { Mention } from "./Mention"
3838
import { ProgressIndicator } from "./ProgressIndicator"
3939
import ReportBugPreview from "./ReportBugPreview"
40+
import { ReadOnlyChatText } from "./ReadOnlyChatText"
4041

4142
import { cn } from "@/lib/utils"
4243
import { appendImages } from "@src/utils/imageUtils"
@@ -1323,7 +1324,9 @@ export const ChatRowContent = ({
13231324
<div
13241325
className={cn(
13251326
"mb-2",
1326-
"border rounded-lg whitespace-pre-wrap",
1327+
"mr-2",
1328+
"rounded-lg whitespace-pre-wrap",
1329+
"bg-vscode-editor-background",
13271330
isEditing ? "overflow-visible" : "overflow-hidden", // kilocode_change
13281331
isEditing ? "text-vscode-editor-foreground" : "cursor-text p-1",
13291332
)}>
@@ -1347,18 +1350,32 @@ export const ChatRowContent = ({
13471350
/>
13481351
</div>
13491352
) : (
1350-
<div className="flex justify-between">
1351-
<div
1352-
className="flex-grow px-2 py-1 wrap-anywhere rounded-lg transition-colors"
1353-
onClick={(e) => {
1354-
e.stopPropagation()
1355-
if (!isStreaming) {
1356-
handleEditClick()
1357-
}
1358-
}}
1359-
title={t("chat:queuedMessages.clickToEdit")}>
1360-
<Mention text={message.text} withShadow />
1353+
<div className="flex justify-between items-end">
1354+
<div className="flex-grow">
1355+
<ReadOnlyChatText
1356+
value={message.text || ""}
1357+
className="px-2 py-1 wrap-anywhere rounded-lg transition-colors hover:bg-vscode-editor-hover-highlight"
1358+
onClick={() => {
1359+
if (!isStreaming) {
1360+
handleEditClick()
1361+
}
1362+
}}
1363+
title={t("chat:queuedMessages.clickToEdit")}
1364+
/>
13611365
</div>
1366+
1367+
<StandardTooltip content={t("chat:checkpoint.menu.restore")}>
1368+
<div
1369+
className="cursor-pointer shrink-0 mb-1.5 opacity-20 hover:opacity-100 transition-opacity"
1370+
style={{ visibility: isStreaming ? "hidden" : "visible" }}
1371+
onClick={(e) => {
1372+
e.stopPropagation()
1373+
handleEditClick()
1374+
}}
1375+
title={t("chat:checkpoint.restore")}>
1376+
<Undo2 className="w-3.5 h-3.5" />
1377+
</div>
1378+
</StandardTooltip>
13621379
<div className="flex gap-2 pr-1">
13631380
<div
13641381
className="cursor-pointer shrink-0 opacity-0 group-hover:opacity-100 transition-opacity"

0 commit comments

Comments
 (0)