mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
feat: add rate limit countdown UI with neutral loading state
- Created RateLimitCountdown component to display rate limit messages - Shows spinner with countdown timer and retry attempt info - Uses neutral styling instead of error colors - Added translations for rate limit messages - Updated ChatRow to properly handle api_req_retry_delayed messages Fixes #7922
This commit is contained in:
parent
08d7f80e22
commit
9a2eee3ca3
3 changed files with 134 additions and 1 deletions
|
|
@ -47,6 +47,7 @@ import { McpExecution } from "./McpExecution"
|
|||
import { ChatTextArea } from "./ChatTextArea"
|
||||
import { MAX_IMAGES_PER_MESSAGE } from "./ChatView"
|
||||
import { useSelectedModel } from "../ui/hooks/useSelectedModel"
|
||||
import { RateLimitCountdown } from "./RateLimitCountdown"
|
||||
|
||||
interface ChatRowProps {
|
||||
message: ClineMessage
|
||||
|
|
@ -262,7 +263,8 @@ export const ChatRowContent = ({
|
|||
<span style={{ color: successColor, fontWeight: "bold" }}>{t("chat:taskCompleted")}</span>,
|
||||
]
|
||||
case "api_req_retry_delayed":
|
||||
return []
|
||||
// Don't return empty array, this will be handled in the switch statement
|
||||
return [null, null]
|
||||
case "api_req_started":
|
||||
const getIconSpan = (iconName: string, color: string) => (
|
||||
<div
|
||||
|
|
@ -1275,6 +1277,14 @@ export const ChatRowContent = ({
|
|||
</div>
|
||||
</>
|
||||
)
|
||||
case "api_req_retry_delayed":
|
||||
// Display the rate limit countdown component
|
||||
return (
|
||||
<RateLimitCountdown
|
||||
message={message.text || ""}
|
||||
isRetrying={message.text?.includes("Retry attempt")}
|
||||
/>
|
||||
)
|
||||
case "shell_integration_warning":
|
||||
return <CommandExecutionError />
|
||||
case "checkpoint_saved":
|
||||
|
|
|
|||
113
webview-ui/src/components/chat/RateLimitCountdown.tsx
Normal file
113
webview-ui/src/components/chat/RateLimitCountdown.tsx
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import React, { useMemo } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { ProgressIndicator } from "./ProgressIndicator"
|
||||
|
||||
interface RateLimitCountdownProps {
|
||||
message: string
|
||||
isRetrying?: boolean
|
||||
}
|
||||
|
||||
export const RateLimitCountdown: React.FC<RateLimitCountdownProps> = ({ message, isRetrying = false }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
// Parse the message to extract countdown seconds and retry attempt info
|
||||
const { seconds, attemptInfo } = useMemo(() => {
|
||||
// Match patterns like "Retrying in X seconds" or "Rate limiting for X seconds"
|
||||
const secondsMatch = message.match(/(\d+)\s+second/i)
|
||||
const seconds = secondsMatch ? parseInt(secondsMatch[1], 10) : null
|
||||
|
||||
// Match retry attempt pattern like "Retry attempt X"
|
||||
const attemptMatch = message.match(/Retry attempt (\d+)/i)
|
||||
const attemptInfo = attemptMatch ? attemptMatch[0] : null
|
||||
|
||||
return { seconds, attemptInfo }
|
||||
}, [message])
|
||||
|
||||
// Check if this is the "Retrying now..." message
|
||||
const isRetryingNow = message.toLowerCase().includes("retrying now")
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "12px",
|
||||
padding: "12px 16px",
|
||||
backgroundColor: "var(--vscode-editor-background)",
|
||||
border: "1px solid var(--vscode-editorWidget-border)",
|
||||
borderRadius: "4px",
|
||||
marginBottom: "8px",
|
||||
}}>
|
||||
{/* Header with spinner and title */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "10px",
|
||||
color: "var(--vscode-foreground)",
|
||||
}}>
|
||||
<ProgressIndicator />
|
||||
<span style={{ fontWeight: "bold", fontSize: "var(--vscode-font-size)" }}>
|
||||
{isRetrying || attemptInfo ? t("chat:rateLimitRetry.title") : t("chat:rateLimit.title")}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Status message */}
|
||||
<div
|
||||
style={{
|
||||
color: "var(--vscode-descriptionForeground)",
|
||||
fontSize: "var(--vscode-font-size)",
|
||||
lineHeight: "1.5",
|
||||
}}>
|
||||
{isRetryingNow ? (
|
||||
<span>{t("chat:rateLimit.retryingNow")}</span>
|
||||
) : seconds !== null ? (
|
||||
<div>
|
||||
{attemptInfo && (
|
||||
<div style={{ marginBottom: "4px" }}>
|
||||
<span style={{ color: "var(--vscode-foreground)" }}>{attemptInfo}</span>
|
||||
</div>
|
||||
)}
|
||||
<span>{t("chat:rateLimit.retryingIn", { seconds })}</span>
|
||||
</div>
|
||||
) : (
|
||||
<span>{t("chat:rateLimit.pleaseWait")}</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Optional error details if present in the message */}
|
||||
{message.includes("\n\n") && !isRetryingNow && (
|
||||
<details
|
||||
style={{
|
||||
marginTop: "4px",
|
||||
cursor: "pointer",
|
||||
}}>
|
||||
<summary
|
||||
style={{
|
||||
color: "var(--vscode-textLink-foreground)",
|
||||
fontSize: "calc(var(--vscode-font-size) - 1px)",
|
||||
userSelect: "none",
|
||||
}}>
|
||||
{t("chat:rateLimit.showDetails")}
|
||||
</summary>
|
||||
<pre
|
||||
style={{
|
||||
marginTop: "8px",
|
||||
padding: "8px",
|
||||
backgroundColor: "var(--vscode-textCodeBlock-background)",
|
||||
borderRadius: "4px",
|
||||
fontSize: "calc(var(--vscode-font-size) - 1px)",
|
||||
color: "var(--vscode-descriptionForeground)",
|
||||
whiteSpace: "pre-wrap",
|
||||
wordBreak: "break-word",
|
||||
overflowWrap: "anywhere",
|
||||
maxHeight: "200px",
|
||||
overflowY: "auto",
|
||||
}}>
|
||||
{message.split("\n\n")[0]}
|
||||
</pre>
|
||||
</details>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -149,6 +149,16 @@
|
|||
"cancelled": "API Request Cancelled",
|
||||
"streamingFailed": "API Streaming Failed"
|
||||
},
|
||||
"rateLimit": {
|
||||
"title": "Rate limit triggered — please wait",
|
||||
"pleaseWait": "Please wait while we handle the rate limit...",
|
||||
"retryingIn": "Retrying in {{seconds}} seconds...",
|
||||
"retryingNow": "Retrying now...",
|
||||
"showDetails": "Show error details"
|
||||
},
|
||||
"rateLimitRetry": {
|
||||
"title": "Rate limit triggered — retrying"
|
||||
},
|
||||
"checkpoint": {
|
||||
"regular": "Checkpoint",
|
||||
"initializingWarning": "Still initializing checkpoint... If this takes too long, you can disable checkpoints in <settingsLink>settings</settingsLink> and restart your task.",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue