Просмотр исходного кода

feat: add error details modal with on-demand display (#9985)

* feat: add error details modal with on-demand display

- Add errorDetails prop to ErrorRow component
- Show Info icon on hover in error header when errorDetails is provided
- Display detailed error message in modal dialog on Info icon click
- Add Copy to Clipboard button in error details modal
- Update generic error case to show localized message with details on demand
- Add i18n translations for error details UI

* UI Tweaks

* Properly handles error details

* i18n

* Lighter visual treatment for errors

---------

Co-authored-by: Roo Code <[email protected]>
Co-authored-by: Bruno Bergher <[email protected]>
roomote[bot] 3 недель назад
Родитель
Сommit
ab18bf3e50

+ 1 - 1
src/core/task/Task.ts

@@ -3903,7 +3903,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
 					throw new Error(`[Task#${this.taskId}] Aborted during retry countdown`)
 				}
 
-				await this.say("api_req_retry_delayed", `${headerText}\n↻ ${i}s...`, undefined, true)
+				await this.say("api_req_retry_delayed", `${headerText}<retry_timer>${i}</retry_timer>`, undefined, true)
 				await delay(1000)
 			}
 

+ 27 - 10
webview-ui/src/components/chat/ChatRow.tsx

@@ -59,6 +59,7 @@ import {
 	FolderTree,
 	TerminalSquare,
 	MessageCircle,
+	Repeat2,
 } from "lucide-react"
 import { cn } from "@/lib/utils"
 import { PathTooltip } from "../ui/PathTooltip"
@@ -1110,11 +1111,11 @@ export const ChatRowContent = ({
 					)
 				case "api_req_retry_delayed":
 					let body = t(`chat:apiRequest.failed`)
-					let retryInfo, code, docsURL
+					let retryInfo, rawError, code, docsURL
 					if (message.text !== undefined) {
 						// Try to show richer error message for that code, if available
 						const potentialCode = parseInt(message.text.substring(0, 3))
-						if (potentialCode >= 400) {
+						if (!isNaN(potentialCode) && potentialCode >= 400) {
 							code = potentialCode
 							const stringForError = `chat:apiRequest.errorMessage.${code}`
 							if (i18n.exists(stringForError)) {
@@ -1130,15 +1131,30 @@ export const ChatRowContent = ({
 								body = t("chat:apiRequest.errorMessage.unknown")
 								docsURL = "mailto:[email protected]?subject=Unknown API Error"
 							}
-							retryInfo = (
-								<p className="mt-1 font-light text-xs text-vscode-errorForeground/80 cursor-default">
-									{message.text.substring(4)}
-								</p>
-							)
+						} else if (message.text.indexOf("Connection error") === 0) {
+							body = t("chat:apiRequest.errorMessage.connection")
 						} else {
-							// Non-HTTP-status-code error message - display the actual error text
-							body = message.text
+							// Non-HTTP-status-code error message - store full text as errorDetails
+							body = t("chat:apiRequest.errorMessage.unknown")
+							docsURL = "mailto:[email protected]?subject=Unknown API Error"
 						}
+
+						// This isn't pretty, but since the retry logic happens at a lower level
+						// and the message object is just a flat string, we need to extract the
+						// retry information using this "tag" as a convention
+						const retryTimerMatch = message.text.match(/<retry_timer>(.*?)<\/retry_timer>/)
+						const retryTimer = retryTimerMatch && retryTimerMatch[1] ? parseInt(retryTimerMatch[1], 10) : 0
+						rawError = message.text.replace(/<retry_timer>(.*?)<\/retry_timer>/, "").trim()
+						retryInfo = retryTimer > 0 && (
+							<p
+								className={cn(
+									"mt-2 font-light text-xs  text-vscode-descriptionForeground cursor-default flex items-center gap-1 transition-all duration-1000",
+									retryTimer === 0 ? "opacity-0 max-h-0" : "max-h-2 opacity-100",
+								)}>
+								<Repeat2 className="size-3" strokeWidth={1.5} />
+								<span>{retryTimer}s</span>
+							</p>
+						)
 					}
 					return (
 						<ErrorRow
@@ -1147,6 +1163,7 @@ export const ChatRowContent = ({
 							message={body}
 							docsURL={docsURL}
 							additionalContent={retryInfo}
+							errorDetails={rawError}
 						/>
 					)
 				case "api_req_finished":
@@ -1259,7 +1276,7 @@ export const ChatRowContent = ({
 						</div>
 					)
 				case "error":
-					return <ErrorRow type="error" message={message.text || ""} />
+					return <ErrorRow type="error" message={t("chat:error")} errorDetails={message.text || undefined} />
 				case "completion_result":
 					return (
 						<>

+ 100 - 30
webview-ui/src/components/chat/ErrorRow.tsx

@@ -1,10 +1,12 @@
 import React, { useState, useCallback, memo } from "react"
 import { useTranslation } from "react-i18next"
 import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
-import { BookOpenText, MessageCircleWarning } from "lucide-react"
+import { BookOpenText, MessageCircleWarning, Info, Copy, Check } from "lucide-react"
 import { useCopyToClipboard } from "@src/utils/clipboard"
 import { vscode } from "@src/utils/vscode"
 import CodeBlock from "../common/CodeBlock"
+import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@src/components/ui/dialog"
+import { Button, Tooltip, TooltipContent, TooltipTrigger } from "../ui"
 
 /**
  * Unified error display component for all error types in the chat.
@@ -61,7 +63,8 @@ export interface ErrorRowProps {
 	headerClassName?: string
 	messageClassName?: string
 	code?: number
-	docsURL?: string // NEW: Optional documentation link
+	docsURL?: string // Optional documentation link
+	errorDetails?: string // Optional detailed error message shown in modal
 }
 
 /**
@@ -80,10 +83,13 @@ export const ErrorRow = memo(
 		messageClassName,
 		docsURL,
 		code,
+		errorDetails,
 	}: ErrorRowProps) => {
 		const { t } = useTranslation()
 		const [isExpanded, setIsExpanded] = useState(defaultExpanded)
 		const [showCopySuccess, setShowCopySuccess] = useState(false)
+		const [isDetailsDialogOpen, setIsDetailsDialogOpen] = useState(false)
+		const [showDetailsCopySuccess, setShowDetailsCopySuccess] = useState(false)
 		const { copyWithFeedback } = useCopyToClipboard()
 
 		// Default titles for different error types
@@ -130,6 +136,22 @@ export const ErrorRow = memo(
 			[message, copyWithFeedback],
 		)
 
+		const handleCopyDetails = useCallback(
+			async (e: React.MouseEvent) => {
+				e.stopPropagation()
+				if (errorDetails) {
+					const success = await copyWithFeedback(errorDetails)
+					if (success) {
+						setShowDetailsCopySuccess(true)
+						setTimeout(() => {
+							setShowDetailsCopySuccess(false)
+						}, 1000)
+					}
+				}
+			},
+			[errorDetails, copyWithFeedback],
+		)
+
 		const errorTitle = getDefaultTitle()
 
 		// For diff_error type with expandable content
@@ -168,36 +190,84 @@ export const ErrorRow = memo(
 
 		// Standard error display
 		return (
-			<div className="group pr-2">
-				{errorTitle && (
-					<div className={headerClassName || "flex items-center justify-between gap-2 break-words"}>
-						<MessageCircleWarning className="w-4 text-vscode-errorForeground" />
-						<span className="text-vscode-errorForeground font-bold grow cursor-default">{errorTitle}</span>
-						{docsURL && (
-							<a
-								href={docsURL}
-								className="text-sm flex items-center gap-1 transition-opacity opacity-0 group-hover:opacity-100"
-								onClick={(e) => {
-									e.preventDefault()
-									vscode.postMessage({ type: "openExternal", url: docsURL })
-								}}>
-								<BookOpenText className="size-3 mt-[3px]" />
-								{t("chat:apiRequest.errorMessage.docs")}
-							</a>
-						)}
+			<>
+				<div className="group pr-2">
+					{errorTitle && (
+						<div className={headerClassName || "flex items-center justify-between gap-2 break-words"}>
+							<MessageCircleWarning className="w-4 text-vscode-errorForeground" />
+							<span className="font-bold grow cursor-default">{errorTitle}</span>
+							<div className="flex items-center gap-2">
+								{docsURL && (
+									<a
+										href={docsURL}
+										className="text-sm flex items-center gap-1 transition-opacity opacity-0 group-hover:opacity-100"
+										onClick={(e) => {
+											e.preventDefault()
+											vscode.postMessage({ type: "openExternal", url: docsURL })
+										}}>
+										<BookOpenText className="size-3 mt-[3px]" />
+										{t("chat:apiRequest.errorMessage.docs")}
+									</a>
+								)}
+								{errorDetails && (
+									<Tooltip>
+										<TooltipTrigger asChild>
+											<button
+												onClick={() => setIsDetailsDialogOpen(true)}
+												className="transition-opacity opacity-0 group-hover:opacity-100 cursor-pointer"
+												aria-label={t("chat:errorDetails.title")}>
+												<Info className="size-4" />
+											</button>
+										</TooltipTrigger>
+										<TooltipContent>{t("chat:errorDetails.title")}</TooltipContent>
+									</Tooltip>
+								)}
+							</div>
+						</div>
+					)}
+					<div className="ml-2 pl-4 mt-1 pt-1 border-l border-vscode-errorForeground/50">
+						<p
+							className={
+								messageClassName ||
+								"my-0 font-light whitespace-pre-wrap break-words text-vscode-descriptionForeground"
+							}>
+							{message}
+						</p>
+						{additionalContent}
 					</div>
-				)}
-				<div className="pl-6 py-1">
-					<p
-						className={
-							messageClassName ||
-							"my-0 font-light whitespace-pre-wrap break-words text-vscode-errorForeground"
-						}>
-						{message}
-					</p>
-					{additionalContent}
 				</div>
-			</div>
+
+				{/* Error Details Dialog */}
+				{errorDetails && (
+					<Dialog open={isDetailsDialogOpen} onOpenChange={setIsDetailsDialogOpen}>
+						<DialogContent className="max-w-2xl">
+							<DialogHeader>
+								<DialogTitle>{t("chat:errorDetails.title")}</DialogTitle>
+							</DialogHeader>
+							<div className="max-h-96 overflow-auto px-3 bg-vscode-editor-background rounded-xl border border-vscode-editorGroup-border">
+								<pre className="font-mono text-sm whitespace-pre-wrap break-words bg-transparent">
+									{errorDetails}
+								</pre>
+							</div>
+							<DialogFooter>
+								<Button variant="secondary" onClick={handleCopyDetails}>
+									{showDetailsCopySuccess ? (
+										<>
+											<Check className="size-3" />
+											{t("chat:errorDetails.copied")}
+										</>
+									) : (
+										<>
+											<Copy className="size-3" />
+											{t("chat:errorDetails.copyToClipboard")}
+										</>
+									)}
+								</Button>
+							</DialogFooter>
+						</DialogContent>
+					</Dialog>
+				)}
+			</>
 		)
 	},
 )

+ 1 - 1
webview-ui/src/components/ui/dialog.tsx

@@ -78,7 +78,7 @@ function DialogTitle({ className, ...props }: React.ComponentProps<typeof Dialog
 	return (
 		<DialogPrimitive.Title
 			data-slot="dialog-title"
-			className={cn("text-lg leading-none font-semibold my-0", className)}
+			className={cn("text-lg leading-none font-semibold my-0 cursor-default", className)}
 			{...props}
 		/>
 	)

+ 7 - 1
webview-ui/src/i18n/locales/ca/chat.json

@@ -146,7 +146,8 @@
 			"403": "No autoritzat. La teva clau API és vàlida, però el proveïdor ha rebutjat completar aquesta sol·licitud.",
 			"429": "Massa sol·licituds. Estàs sent limitat pel proveïdor. Si us plau espera una mica abans de la teva propera crida API.",
 			"500": "Error del servidor del proveïdor. Quelcom va malament del costat del proveïdor, no hi ha res de malament amb la teva sol·licitud.",
-			"unknown": "Error API desconegut. Si us plau contacta amb el suport de Roo Code."
+			"unknown": "Error API desconegut. Si us plau contacta amb el suport de Roo Code.",
+			"connection": "Error de connexió. Assegureu-vos que teniu una connexió a Internet funcional."
 		}
 	},
 	"checkpoint": {
@@ -258,6 +259,11 @@
 		"hasQuestion": "Roo té una pregunta"
 	},
 	"taskCompleted": "Tasca completada",
+	"errorDetails": {
+		"title": "Detalls de l'error",
+		"copyToClipboard": "Copiar al porta-retalls",
+		"copied": "Copiat!"
+	},
 	"powershell": {
 		"issues": "Sembla que estàs tenint problemes amb Windows PowerShell, si us plau consulta aquesta documentació per a més informació."
 	},

+ 7 - 1
webview-ui/src/i18n/locales/de/chat.json

@@ -146,7 +146,8 @@
 			"403": "Nicht autorisiert. Dein API-Schlüssel ist gültig, aber der Anbieter hat sich geweigert, diese Anfrage zu erfüllen.",
 			"429": "Zu viele Anfragen. Du wirst vom Anbieter rate-limitiert. Bitte warte ein wenig, bevor du den nächsten API-Aufruf machst.",
 			"500": "Fehler auf dem Server des Anbieters. Es stimmt etwas mit der Anbieterseite nicht, mit deiner Anfrage stimmt alles.",
-			"unknown": "Unbekannter API-Fehler. Bitte kontaktiere den Roo Code Support."
+			"unknown": "Unbekannter API-Fehler. Bitte kontaktiere den Roo Code Support.",
+			"connection": "Verbindungsfehler. Stelle sicher, dass du eine funktionierende Internetverbindung hast."
 		}
 	},
 	"checkpoint": {
@@ -258,6 +259,11 @@
 		"hasQuestion": "Roo hat eine Frage"
 	},
 	"taskCompleted": "Aufgabe abgeschlossen",
+	"errorDetails": {
+		"title": "Fehlerdetails",
+		"copyToClipboard": "In Zwischenablage kopieren",
+		"copied": "Kopiert!"
+	},
 	"powershell": {
 		"issues": "Es scheint, dass du Probleme mit Windows PowerShell hast, bitte sieh dir dies an"
 	},

+ 6 - 0
webview-ui/src/i18n/locales/en/chat.json

@@ -152,6 +152,7 @@
 			"403": "Unauthorized. Your API key is valid, but the provider refused to complete this request.",
 			"429": "Too many requests. You're being rate-limited by the provider. Please wait a bit before your next API call.",
 			"500": "Provider server error. Something is wrong on the provider side, there's nothing wrong with your request.",
+			"connection": "Connection error. Make sure you have a working internet connection.",
 			"unknown": "Unknown API error. Please contact Roo Code support."
 		}
 	},
@@ -285,6 +286,11 @@
 	},
 	"taskCompleted": "Task Completed",
 	"error": "Error",
+	"errorDetails": {
+		"title": "Error Details",
+		"copyToClipboard": "Copy to Clipboard",
+		"copied": "Copied!"
+	},
 	"diffError": {
 		"title": "Edit Unsuccessful"
 	},

+ 7 - 1
webview-ui/src/i18n/locales/es/chat.json

@@ -146,7 +146,8 @@
 			"403": "No autorizado. Tu clave API es válida, pero el proveedor se negó a completar esta solicitud.",
 			"429": "Demasiadas solicitudes. Te estás viendo limitado por el proveedor. Por favor espera un poco antes de tu próxima llamada API.",
 			"500": "Error del servidor del proveedor. Algo está mal en el lado del proveedor, no hay nada mal con tu solicitud.",
-			"unknown": "Error API desconocido. Por favor contacta al soporte de Roo Code."
+			"unknown": "Error API desconocido. Por favor contacta al soporte de Roo Code.",
+			"connection": "Error de conexión. Asegúrate de tener una conexión a Internet funcional."
 		}
 	},
 	"checkpoint": {
@@ -258,6 +259,11 @@
 		"hasQuestion": "Roo tiene una pregunta"
 	},
 	"taskCompleted": "Tarea completada",
+	"errorDetails": {
+		"title": "Detalles del error",
+		"copyToClipboard": "Copiar al portapapeles",
+		"copied": "¡Copiado!"
+	},
 	"powershell": {
 		"issues": "Parece que estás teniendo problemas con Windows PowerShell, por favor consulta esta"
 	},

+ 7 - 1
webview-ui/src/i18n/locales/fr/chat.json

@@ -146,7 +146,8 @@
 			"403": "Non autorisé. Votre clé API est valide, mais le fournisseur a refusé de compléter cette demande.",
 			"429": "Trop de demandes. Vous êtes limité par le fournisseur. Veuillez attendre un peu avant votre prochain appel API.",
 			"500": "Erreur du serveur du fournisseur. Quelque chose ne va pas du côté du fournisseur, il n'y a rien de mal avec votre demande.",
-			"unknown": "Erreur API inconnue. Veuillez contacter le support Roo Code."
+			"unknown": "Erreur API inconnue. Veuillez contacter le support Roo Code.",
+			"connection": "Erreur de connexion. Assurez-vous que vous avez une connexion Internet fonctionnelle."
 		}
 	},
 	"checkpoint": {
@@ -258,6 +259,11 @@
 		"hasQuestion": "Roo a une question"
 	},
 	"taskCompleted": "Tâche terminée",
+	"errorDetails": {
+		"title": "Détails de l'erreur",
+		"copyToClipboard": "Copier dans le presse-papiers",
+		"copied": "Copié !"
+	},
 	"powershell": {
 		"issues": "Il semble que vous rencontriez des problèmes avec Windows PowerShell, veuillez consulter ce"
 	},

+ 7 - 1
webview-ui/src/i18n/locales/hi/chat.json

@@ -146,7 +146,8 @@
 			"403": "अनुमति नहीं। आपकी API कुंजी वैध है, लेकिन प्रदाता ने इस अनुरोध को पूरा करने से इनकार कर दिया।",
 			"429": "बहुत सारे अनुरोध। आप प्रदाता द्वारा दर-सीमित हो रहे हैं। कृपया अपनी अगली API कॉल से पहले थोड़ी देर प्रतीक्षा करें।",
 			"500": "प्रदाता सर्वर त्रुटि। प्रदाता की ओर से कुछ गलत है, आपके अनुरोध में कुछ गलत नहीं है।",
-			"unknown": "अज्ञात API त्रुटि। कृपया Roo Code सहायता से संपर्क करें।"
+			"unknown": "अज्ञात API त्रुटि। कृपया Roo Code सहायता से संपर्क करें।",
+			"connection": "कनेक्शन त्रुटि। सुनिश्चित करें कि आपके पास कार्यशील इंटरनेट कनेक्शन है।"
 		}
 	},
 	"checkpoint": {
@@ -258,6 +259,11 @@
 		"hasQuestion": "Roo का एक प्रश्न है"
 	},
 	"taskCompleted": "कार्य पूरा हुआ",
+	"errorDetails": {
+		"title": "त्रुटि विवरण",
+		"copyToClipboard": "क्लिपबोर्ड पर कॉपी करें",
+		"copied": "कॉपी किया गया!"
+	},
 	"powershell": {
 		"issues": "ऐसा लगता है कि आपको Windows PowerShell के साथ समस्याएँ हो रही हैं, कृपया इसे देखें"
 	},

+ 7 - 1
webview-ui/src/i18n/locales/id/chat.json

@@ -155,7 +155,8 @@
 			"403": "Tidak sah. Kunci API Anda valid, tetapi penyedia menolak untuk menyelesaikan permintaan ini.",
 			"429": "Terlalu banyak permintaan. Anda dibatasi tingkat oleh penyedia. Harap tunggu sebentar sebelum panggilan API berikutnya Anda.",
 			"500": "Kesalahan server penyedia. Ada yang salah di sisi penyedia, tidak ada yang salah dengan permintaan Anda.",
-			"unknown": "Kesalahan API yang tidak diketahui. Harap hubungi dukungan Roo Code."
+			"unknown": "Kesalahan API yang tidak diketahui. Harap hubungi dukungan Roo Code.",
+			"connection": "Kesalahan koneksi. Pastikan Anda memiliki koneksi internet yang berfungsi."
 		}
 	},
 	"checkpoint": {
@@ -294,6 +295,11 @@
 		"title": "Edit Tidak Berhasil"
 	},
 	"troubleMessage": "Roo mengalami masalah...",
+	"errorDetails": {
+		"title": "Detail Kesalahan",
+		"copyToClipboard": "Salin ke Clipboard",
+		"copied": "Disalin!"
+	},
 	"powershell": {
 		"issues": "Sepertinya kamu mengalami masalah Windows PowerShell, silakan lihat ini"
 	},

+ 7 - 1
webview-ui/src/i18n/locales/it/chat.json

@@ -149,7 +149,8 @@
 			"403": "Non autorizzato. La tua chiave API è valida, ma il provider ha rifiutato di completare questa richiesta.",
 			"429": "Troppe richieste. Sei limitato dal provider. Attendi un po' prima della tua prossima chiamata API.",
 			"500": "Errore del server del provider. C'è qualcosa di sbagliato dal lato del provider, non c'è nulla di sbagliato nella tua richiesta.",
-			"unknown": "Errore API sconosciuto. Contatta il supporto di Roo Code."
+			"unknown": "Errore API sconosciuto. Contatta il supporto di Roo Code.",
+			"connection": "Errore di connessione. Assicurati di avere una connessione Internet funzionante."
 		}
 	},
 	"checkpoint": {
@@ -258,6 +259,11 @@
 		"hasQuestion": "Roo ha una domanda"
 	},
 	"taskCompleted": "Attività completata",
+	"errorDetails": {
+		"title": "Dettagli errore",
+		"copyToClipboard": "Copia negli appunti",
+		"copied": "Copiato!"
+	},
 	"powershell": {
 		"issues": "Sembra che tu stia avendo problemi con Windows PowerShell, consulta questa"
 	},

+ 7 - 1
webview-ui/src/i18n/locales/ja/chat.json

@@ -146,7 +146,8 @@
 			"403": "認可されていません。API キーは有効ですが、プロバイダーがこのリクエストの完了を拒否しました。",
 			"429": "リクエストが多すぎます。プロバイダーによってレート制限されています。次の API 呼び出しの前にお待ちください。",
 			"500": "プロバイダー サーバー エラー。プロバイダー側に問題があり、リクエスト自体に問題はありません。",
-			"unknown": "不明な API エラー。Roo Code のサポートにお問い合わせください。"
+			"unknown": "不明な API エラー。Roo Code のサポートにお問い合わせください。",
+			"connection": "接続エラー。インターネット接続が機能していることを確認してください。"
 		}
 	},
 	"checkpoint": {
@@ -258,6 +259,11 @@
 		"hasQuestion": "Rooは質問があります"
 	},
 	"taskCompleted": "タスク完了",
+	"errorDetails": {
+		"title": "エラー詳細",
+		"copyToClipboard": "クリップボードにコピー",
+		"copied": "コピーしました!"
+	},
 	"powershell": {
 		"issues": "Windows PowerShellに問題があるようです。こちらを参照してください"
 	},

+ 7 - 1
webview-ui/src/i18n/locales/ko/chat.json

@@ -146,7 +146,8 @@
 			"403": "권한 없음. API 키는 유효하지만 공급자가 이 요청을 완료하기를 거부했습니다.",
 			"429": "너무 많은 요청입니다. 공급자에 의해 요청 제한이 적용되고 있습니다. 다음 API 호출 전에 잠깐 기다려주세요.",
 			"500": "공급자 서버 오류입니다. 공급자 쪽에 문제가 있으며 요청에는 문제가 없습니다.",
-			"unknown": "알 수 없는 API 오류입니다. Roo Code 지원팀에 문의하세요."
+			"unknown": "알 수 없는 API 오류입니다. Roo Code 지원팀에 문의하세요.",
+			"connection": "연결 오류입니다. 인터넷 연결이 제대로 작동하는지 확인하세요."
 		}
 	},
 	"checkpoint": {
@@ -258,6 +259,11 @@
 		"hasQuestion": "Roo에게 질문이 있습니다"
 	},
 	"taskCompleted": "작업 완료",
+	"errorDetails": {
+		"title": "오류 세부 정보",
+		"copyToClipboard": "클립보드에 복사",
+		"copied": "복사됨!"
+	},
 	"powershell": {
 		"issues": "Windows PowerShell에 문제가 있는 것 같습니다. 다음을 참조하세요"
 	},

+ 7 - 1
webview-ui/src/i18n/locales/nl/chat.json

@@ -141,7 +141,8 @@
 			"403": "Niet geautoriseerd. Je API-sleutel is geldig, maar de provider weigerde dit verzoek in te willigen.",
 			"429": "Te veel verzoeken. Je bent rate-gelimiteerd door de provider. Wacht alsjeblieft even voor je volgende API-aanroep.",
 			"500": "Provider-serverfout. Er is iets mis aan de kant van de provider, er is niets mis met je verzoek.",
-			"unknown": "Onbekende API-fout. Neem alsjeblieft contact op met Roo Code-ondersteuning."
+			"unknown": "Onbekende API-fout. Neem alsjeblieft contact op met Roo Code-ondersteuning.",
+			"connection": "Verbindingsfout. Zorg ervoor dat je een werkende internetverbinding hebt."
 		}
 	},
 	"checkpoint": {
@@ -258,6 +259,11 @@
 		"title": "Bewerking mislukt"
 	},
 	"troubleMessage": "Roo ondervindt problemen...",
+	"errorDetails": {
+		"title": "Foutdetails",
+		"copyToClipboard": "Naar klembord kopiëren",
+		"copied": "Gekopieerd!"
+	},
 	"powershell": {
 		"issues": "Het lijkt erop dat je problemen hebt met Windows PowerShell, zie deze"
 	},

+ 7 - 1
webview-ui/src/i18n/locales/pl/chat.json

@@ -146,7 +146,8 @@
 			"403": "Brak autoryzacji. Twój klucz API jest ważny, ale dostawca odmówił ukończenia tego żądania.",
 			"429": "Zbyt wiele żądań. Dostawca ogranicza Ci szybkość żądań. Poczekaj chwilę przed następnym wywołaniem API.",
 			"500": "Błąd serwera dostawcy. Po stronie dostawcy coś się nie powiodło, w Twoim żądaniu nie ma nic złego.",
-			"unknown": "Nieznany błąd API. Skontaktuj się z pomocą techniczną Roo Code."
+			"unknown": "Nieznany błąd API. Skontaktuj się z pomocą techniczną Roo Code.",
+			"connection": "Błąd połączenia. Upewnij się, że masz działające połączenie internetowe."
 		}
 	},
 	"checkpoint": {
@@ -258,6 +259,11 @@
 		"hasQuestion": "Roo ma pytanie"
 	},
 	"taskCompleted": "Zadanie zakończone",
+	"errorDetails": {
+		"title": "Szczegóły błędu",
+		"copyToClipboard": "Kopiuj do schowka",
+		"copied": "Skopiowano!"
+	},
 	"powershell": {
 		"issues": "Wygląda na to, że masz problemy z Windows PowerShell, proszę zapoznaj się z tym"
 	},

+ 7 - 1
webview-ui/src/i18n/locales/pt-BR/chat.json

@@ -146,7 +146,8 @@
 			"403": "Não autorizado. Sua chave API é válida, mas o provedor se recusou a concluir esta solicitação.",
 			"429": "Muitas solicitações. Você está sendo limitado pelo provedor. Por favor, aguarde um pouco antes de sua próxima chamada de API.",
 			"500": "Erro do servidor do provedor. Algo está errado do lado do provedor, não há nada de errado com sua solicitação.",
-			"unknown": "Erro de API desconhecido. Por favor, entre em contato com o suporte do Roo Code."
+			"unknown": "Erro de API desconhecido. Por favor, entre em contato com o suporte do Roo Code.",
+			"connection": "Erro de conexão. Certifique-se de que você tem uma conexão de internet funcionando."
 		}
 	},
 	"checkpoint": {
@@ -258,6 +259,11 @@
 		"hasQuestion": "Roo tem uma pergunta"
 	},
 	"taskCompleted": "Tarefa concluída",
+	"errorDetails": {
+		"title": "Detalhes do erro",
+		"copyToClipboard": "Copiar para área de transferência",
+		"copied": "Copiado!"
+	},
 	"powershell": {
 		"issues": "Parece que você está tendo problemas com o Windows PowerShell, por favor veja este"
 	},

+ 7 - 1
webview-ui/src/i18n/locales/ru/chat.json

@@ -141,7 +141,8 @@
 			"403": "Без авторизации. Ваш ключ API действителен, но провайдер отказался выполнить этот запрос.",
 			"429": "Слишком много запросов. Провайдер ограничивает частоту ваших запросов. Пожалуйста, подождите немного перед следующим вызовом API.",
 			"500": "Ошибка сервера провайдера. На стороне провайдера что-то пошло не так, с вашим запросом все в порядке.",
-			"unknown": "Неизвестная ошибка API. Пожалуйста, свяжитесь с поддержкой Roo Code."
+			"unknown": "Неизвестная ошибка API. Пожалуйста, свяжитесь с поддержкой Roo Code.",
+			"connection": "Ошибка подключения. Убедитесь, что у вас есть рабочее подключение к Интернету."
 		}
 	},
 	"checkpoint": {
@@ -259,6 +260,11 @@
 		"title": "Не удалось выполнить редактирование"
 	},
 	"troubleMessage": "У Roo возникли проблемы...",
+	"errorDetails": {
+		"title": "Детали ошибки",
+		"copyToClipboard": "Скопировать в буфер обмена",
+		"copied": "Скопировано!"
+	},
 	"powershell": {
 		"issues": "Похоже, у вас проблемы с Windows PowerShell, пожалуйста, ознакомьтесь с этим"
 	},

+ 7 - 1
webview-ui/src/i18n/locales/tr/chat.json

@@ -146,7 +146,8 @@
 			"403": "Yetkisiz. API anahtarınız geçerli ama sağlayıcı bu isteği tamamlamayı reddetti.",
 			"429": "Çok fazla istek. Sağlayıcı tarafından oran sınırlaması uygulanıyor. Lütfen sonraki API çağrısından önce biraz bekle.",
 			"500": "Sağlayıcı sunucu hatası. Sağlayıcı tarafında bir sorun var, isteğinizde sorun yok.",
-			"unknown": "Bilinmeyen API hatası. Lütfen Roo Code desteğiyle iletişime geç."
+			"unknown": "Bilinmeyen API hatası. Lütfen Roo Code desteğiyle iletişime geç.",
+			"connection": "Bağlantı hatası. Çalışan bir internet bağlantınız olduğundan emin olun."
 		}
 	},
 	"checkpoint": {
@@ -259,6 +260,11 @@
 		"hasQuestion": "Roo'nun bir sorusu var"
 	},
 	"taskCompleted": "Görev Tamamlandı",
+	"errorDetails": {
+		"title": "Hata Detayları",
+		"copyToClipboard": "Panoya Kopyala",
+		"copied": "Kopyalandı!"
+	},
 	"powershell": {
 		"issues": "Windows PowerShell ile ilgili sorunlar yaşıyor gibi görünüyorsunuz, lütfen şu konuya bakın"
 	},

+ 7 - 1
webview-ui/src/i18n/locales/vi/chat.json

@@ -146,7 +146,8 @@
 			"403": "Truy cập bị từ chối. Khóa API của bạn hợp lệ, nhưng nhà cung cấp từ chối hoàn thành yêu cầu này.",
 			"429": "Quá nhiều yêu cầu. Nhà cung cấp đang giới hạn tốc độ yêu cầu của bạn. Vui lòng chờ một chút trước khi gọi API tiếp theo.",
 			"500": "Lỗi máy chủ của nhà cung cấp. Có sự cố ở phía nhà cung cấp, không có gì sai với yêu cầu của bạn.",
-			"unknown": "Lỗi API không xác định. Vui lòng liên hệ hỗ trợ Roo Code."
+			"unknown": "Lỗi API không xác định. Vui lòng liên hệ hỗ trợ Roo Code.",
+			"connection": "Lỗi kết nối. Đảm bảo rằng bạn có kết nối Internet hoạt động."
 		}
 	},
 	"checkpoint": {
@@ -259,6 +260,11 @@
 		"hasQuestion": "Roo có một câu hỏi"
 	},
 	"taskCompleted": "Nhiệm vụ hoàn thành",
+	"errorDetails": {
+		"title": "Chi tiết lỗi",
+		"copyToClipboard": "Sao chép vào clipboard",
+		"copied": "Đã sao chép!"
+	},
 	"powershell": {
 		"issues": "Có vẻ như bạn đang gặp vấn đề với Windows PowerShell, vui lòng xem"
 	},

+ 7 - 1
webview-ui/src/i18n/locales/zh-CN/chat.json

@@ -146,7 +146,8 @@
 			"403": "无权限。您的 API 密钥有效,但提供商拒绝完成此请求。",
 			"429": "请求过于频繁。提供商已对您的请求进行速率限制。请在下一次 API 调用前稍候。",
 			"500": "提供商服务器错误。提供商端出现问题,您的请求无问题。",
-			"unknown": "未知 API 错误。请联系 Roo Code 支持。"
+			"unknown": "未知 API 错误。请联系 Roo Code 支持。",
+			"connection": "连接错误。确保您有可用的互联网连接。"
 		}
 	},
 	"checkpoint": {
@@ -259,6 +260,11 @@
 		"hasQuestion": "Roo有一个问题"
 	},
 	"taskCompleted": "任务完成",
+	"errorDetails": {
+		"title": "错误详情",
+		"copyToClipboard": "复制到剪贴板",
+		"copied": "已复制!"
+	},
 	"powershell": {
 		"issues": "看起来您遇到了Windows PowerShell问题,请参阅此"
 	},

+ 7 - 1
webview-ui/src/i18n/locales/zh-TW/chat.json

@@ -152,7 +152,8 @@
 			"403": "無權存取。您的 API 金鑰有效,但提供商拒絕完成此請求。",
 			"429": "請求次數過多。提供商已對您的請求進行速率限制。請在下一次 API 呼叫前稍候。",
 			"500": "提供商伺服器錯誤。提供商端發生問題,您的請求沒有問題。",
-			"unknown": "未知 API 錯誤。請聯絡 Roo Code 支援。"
+			"unknown": "未知 API 錯誤。請聯絡 Roo Code 支援。",
+			"connection": "連線錯誤。請確保您有可用的網際網路連線。"
 		}
 	},
 	"checkpoint": {
@@ -292,6 +293,11 @@
 		"title": "編輯失敗"
 	},
 	"troubleMessage": "Roo 遇到問題...",
+	"errorDetails": {
+		"title": "錯誤詳細資訊",
+		"copyToClipboard": "複製到剪貼簿",
+		"copied": "已複製!"
+	},
 	"powershell": {
 		"issues": "您似乎遇到了 Windows PowerShell 的問題,請參閱此說明文件"
 	},