Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions packages/types/src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ export const clineMessageSchema = z.object({
contextCondense: contextCondenseSchema.optional(),
isProtected: z.boolean().optional(),
apiProtocol: z.union([z.literal("openai"), z.literal("anthropic")]).optional(),
isAnswered: z.boolean().optional(),
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider adding a JSDoc comment for the isAnswered field to explain its purpose and when it's set. This would help future developers understand that this field specifically tracks whether a follow-up question has been answered to prevent the countdown timer from reappearing in task history.

metadata: z
.object({
gpt5: z
Expand Down
18 changes: 18 additions & 0 deletions src/core/task/Task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,24 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
this.askResponse = askResponse
this.askResponseText = text
this.askResponseImages = images

// Mark the last follow-up question as answered
if (askResponse === "messageResponse" || askResponse === "yesButtonClicked") {
// Find the last unanswered follow-up message using findLastIndex
const lastFollowUpIndex = findLastIndex(
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider extracting this follow-up marking logic to a separate method like markFollowUpAsAnswered() for better code organization and potential reuse. This would make the code more maintainable and testable.

this.clineMessages,
(msg) => msg.type === "ask" && msg.ask === "followup" && !msg.isAnswered,
)

if (lastFollowUpIndex !== -1) {
// Mark this follow-up as answered
this.clineMessages[lastFollowUpIndex].isAnswered = true
// Save the updated messages
this.saveClineMessages().catch((error) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

The error handling here only logs to console. Consider propagating this error or at least tracking it with telemetry since persistence failures could lead to the bug reoccurring. Also, the async saveClineMessages() call is not awaited - if the user quickly navigates away or the task is aborted, the answered state might not be persisted.

Suggested change
this.saveClineMessages().catch((error) => {
// Mark this follow-up as answered
this.clineMessages[lastFollowUpIndex].isAnswered = true
// Save the updated messages
this.saveClineMessages().catch((error) => {
console.error("Failed to save answered follow-up state:", error)
// Consider adding telemetry here
TelemetryService.instance.captureError(this.taskId, error, "follow_up_persistence_failed")
})

console.error("Failed to save answered follow-up state:", error)
})
}
}
}

public approveAsk({ text, images }: { text?: string; images?: string[] } = {}) {
Expand Down
2 changes: 1 addition & 1 deletion webview-ui/src/components/chat/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1499,7 +1499,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
onSuggestionClick={handleSuggestionClickInRow} // This was already stabilized
onBatchFileResponse={handleBatchFileResponse}
onFollowUpUnmount={handleFollowUpUnmount}
isFollowUpAnswered={messageOrGroup.ts === currentFollowUpTs}
isFollowUpAnswered={messageOrGroup.isAnswered === true || messageOrGroup.ts === currentFollowUpTs}
editable={
messageOrGroup.type === "ask" &&
messageOrGroup.ask === "tool" &&
Expand Down
Loading