diff --git a/src/core/ClaudeDev.ts b/src/core/ClaudeDev.ts index ece83d6..a14e5fc 100644 --- a/src/core/ClaudeDev.ts +++ b/src/core/ClaudeDev.ts @@ -411,28 +411,19 @@ export class ClaudeDev { modifiedClaudeMessages.splice(lastRelevantMessageIndex + 1) } - // remove the last api_req_started message if it has no cancelReason - const lastMessage = modifiedClaudeMessages.at(-1) - if (lastMessage?.say === "api_req_started" && lastMessage.text) { - const apiReqInfo: ClaudeApiReqInfo = JSON.parse(lastMessage.text) - if (apiReqInfo.cancelReason === undefined) { - modifiedClaudeMessages.pop() + // since we don't use api_req_finished anymore, we need to check if the last api_req_started has a cost value, if it doesn't and no cancellation reason to present, then we remove it since it indicates an api request without any partial content streamed + const lastApiReqStartedIndex = findLastIndex( + modifiedClaudeMessages, + (m) => m.type === "say" && m.say === "api_req_started" + ) + if (lastApiReqStartedIndex !== -1) { + const lastApiReqStarted = modifiedClaudeMessages[lastApiReqStartedIndex] + const { cost, cancelReason }: ClaudeApiReqInfo = JSON.parse(lastApiReqStarted.text || "{}") + if (cost === undefined || cancelReason === undefined) { + modifiedClaudeMessages.splice(lastApiReqStartedIndex, 1) } } - // since we don't use api_req_finished anymore, we need to check if the last api_req_started has a cost value, if it doesn't and it's not cancelled, then we remove it since it indicates an api request without any partial content streamed - // const lastApiReqStartedIndex = findLastIndex( - // modifiedClaudeMessages, - // (m) => m.type === "say" && m.say === "api_req_started" - // ) - // if (lastApiReqStartedIndex !== -1) { - // const lastApiReqStarted = modifiedClaudeMessages[lastApiReqStartedIndex] - // const { cost, cancelled }: ClaudeApiReqInfo = JSON.parse(lastApiReqStarted.text || "{}") - // if (cost === undefined || cancelled) { - // modifiedClaudeMessages.splice(lastApiReqStartedIndex, 1) - // } - // } - await this.overwriteClaudeMessages(modifiedClaudeMessages) this.claudeMessages = await this.getSavedClaudeMessages() diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 6ca5456..517d892 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -68,6 +68,7 @@ const ChatRowContent = ({ message, isExpanded, onToggleExpand, lastModifiedMessa } return [undefined, undefined, undefined] }, [message.text, message.say]) + // when resuming task, last wont be api_req_failed but a resume_task message, so api_req_started will show loading spinner. that's why we just remove the last api_req_started that failed without streaming anything const apiRequestFailedMessage = isLast && lastModifiedMessage?.ask === "api_req_failed" // if request is retried then the latest message is a api_req_retried ? lastModifiedMessage?.text @@ -137,31 +138,27 @@ const ChatRowContent = ({ message, isExpanded, onToggleExpand, lastModifiedMessa ) return [ - cost != null ? ( - apiReqCancelReason != null ? ( - apiReqCancelReason === "user_cancelled" ? ( - getIconSpan("error", cancelledColor) - ) : ( - getIconSpan("error", errorColor) - ) + apiReqCancelReason != null ? ( + apiReqCancelReason === "user_cancelled" ? ( + getIconSpan("error", cancelledColor) ) : ( - getIconSpan("check", successColor) + getIconSpan("error", errorColor) ) + ) : cost != null ? ( + getIconSpan("check", successColor) ) : apiRequestFailedMessage ? ( getIconSpan("error", errorColor) ) : ( ), - cost != null ? ( - apiReqCancelReason != null ? ( - apiReqCancelReason === "user_cancelled" ? ( - API Request Cancelled - ) : ( - API Streaming Failed - ) + apiReqCancelReason != null ? ( + apiReqCancelReason === "user_cancelled" ? ( + API Request Cancelled ) : ( - API Request + API Streaming Failed ) + ) : cost != null ? ( + API Request ) : apiRequestFailedMessage ? ( API Request Failed ) : (