diff --git a/src/api/index.ts b/src/api/index.ts index 48a0a89ec5..eeea88e367 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -4,6 +4,14 @@ import type { ProviderSettings, ModelInfo } from "@roo-code/types" import { ApiStream } from "./transform/stream" +// Custom error class for Roo authentication failures +export class RooAuthenticationError extends Error { + constructor(message: string) { + super(message) + this.name = "RooAuthenticationError" + } +} + import { GlamaHandler, AnthropicHandler, @@ -143,7 +151,15 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler { case "io-intelligence": return new IOIntelligenceHandler(options) case "roo": - return new RooHandler(options) + try { + return new RooHandler(options) + } catch (error) { + // If Roo authentication fails, throw a specific error that can be caught upstream + // This allows proper handling in the UI rather than silently falling back + const errorMessage = error instanceof Error ? error.message : "Authentication required for Roo provider" + console.error("[API] Roo provider authentication failed:", errorMessage) + throw new RooAuthenticationError(errorMessage) + } case "featherless": return new FeatherlessHandler(options) default: diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 77dfa42a3b..4c3ae20aa2 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -75,7 +75,7 @@ import { setPanel } from "../../activate/registerCommands" import { t } from "../../i18n" -import { buildApiHandler } from "../../api" +import { buildApiHandler, RooAuthenticationError } from "../../api" import { forceFullModelDetailsLoad, hasLoadedFullDetails } from "../../api/providers/fetchers/lmstudio" import { ContextProxy } from "../config/ContextProxy" @@ -776,6 +776,44 @@ export class ClineProvider throw new OrganizationAllowListViolationError(t("common:errors.violated_organization_allowlist")) } + // Check if Roo provider is selected and not authenticated BEFORE creating the task + if (apiConfiguration.apiProvider === "roo") { + try { + // Try to build the API handler to check if authentication works + buildApiHandler(apiConfiguration) + } catch (error) { + if (error instanceof RooAuthenticationError) { + // Show error message to user + const signInText = t("common:mdm.buttons.signIn") + const settingsText = t("common:mdm.buttons.settings") + const selection = await vscode.window.showErrorMessage( + t("common:errors.roo.authenticationRequiredWithOptions"), + signInText, + settingsText, + ) + + if (selection === signInText) { + // Navigate to account view + await this.postMessageToWebview({ type: "action", action: "accountButtonClicked" }) + } else if (selection === settingsText) { + // Open settings to allow provider change + await this.postMessageToWebview({ type: "action", action: "switchTab", tab: "settings" }) + } + + // Return the current task if it exists to prevent UI issues + const currentTask = this.getCurrentTask() + if (currentTask) { + return currentTask + } + + // Throw a specific error that the webview can handle + throw new RooAuthenticationError("Authentication required for Roo provider") + } + // Re-throw other errors + throw error + } + } + const task = new Task({ provider: this, apiConfiguration, diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 5e4971ecaf..dc903810b0 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -288,7 +288,38 @@ export const webviewMessageHandler = async ( // Initializing new instance of Cline will make sure that any // agentically running promises in old instance don't affect our new // task. This essentially creates a fresh slate for the new task. - await provider.createTask(message.text, message.images) + try { + await provider.createTask(message.text, message.images) + // Task created successfully - notify the UI to reset + await provider.postMessageToWebview({ + type: "invoke", + invoke: "newChat", + }) + } catch (error) { + // Check if it's a RooAuthenticationError by checking the error name + // The RooAuthenticationError class sets error.name = 'RooAuthenticationError' + if (error instanceof Error && error.name === "RooAuthenticationError") { + // The error has already been handled in createTask with a user-friendly dialog + // Send a specific message to unlock the UI without resetting the chat + provider.log(`Task creation cancelled due to Roo authentication: ${error.message}`) + await provider.postMessageToWebview({ + type: "taskCreationFailed", + reason: "rooAuthenticationError", + }) + // Exit without sending newChat to keep the chat state + break + } + + // For all other errors, reset the UI and show error + await provider.postMessageToWebview({ + type: "invoke", + invoke: "newChat", + }) + // Show error to user + vscode.window.showErrorMessage( + `Failed to create task: ${error instanceof Error ? error.message : String(error)}`, + ) + } break case "customInstructions": await provider.updateCustomInstructions(message.text) diff --git a/src/i18n/locales/ca/common.json b/src/i18n/locales/ca/common.json index 74b265f513..b21b7d4acb 100644 --- a/src/i18n/locales/ca/common.json +++ b/src/i18n/locales/ca/common.json @@ -105,7 +105,8 @@ "completionError": "Error de finalització de Cerebras: {{error}}" }, "roo": { - "authenticationRequired": "El proveïdor Roo requereix autenticació al núvol. Si us plau, inicieu sessió a Roo Code Cloud." + "authenticationRequired": "El proveïdor Roo requereix autenticació al núvol. Si us plau, inicieu sessió a Roo Code Cloud.", + "authenticationRequiredWithOptions": "El proveïdor Roo requereix autenticació. Si us plau, inicieu sessió a Roo Code Cloud o canvieu a un proveïdor diferent." }, "mode_import_failed": "Ha fallat la importació del mode: {{error}}" }, @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "La teva organització requereix autenticació." + }, + "buttons": { + "signIn": "Inicia sessió", + "settings": "Configuració" } }, "prompts": { diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json index 856e4e1dce..fe218eec66 100644 --- a/src/i18n/locales/de/common.json +++ b/src/i18n/locales/de/common.json @@ -102,7 +102,8 @@ "completionError": "Cerebras-Vervollständigungsfehler: {{error}}" }, "roo": { - "authenticationRequired": "Roo-Anbieter erfordert Cloud-Authentifizierung. Bitte melde dich bei Roo Code Cloud an." + "authenticationRequired": "Roo-Anbieter erfordert Cloud-Authentifizierung. Bitte melde dich bei Roo Code Cloud an.", + "authenticationRequiredWithOptions": "Roo-Anbieter erfordert Authentifizierung. Bitte melde dich bei Roo Code Cloud an oder wechsle zu einem anderen Anbieter." } }, "warnings": { @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "Deine Organisation erfordert eine Authentifizierung." + }, + "buttons": { + "signIn": "Anmelden", + "settings": "Einstellungen" } }, "prompts": { diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index e413bc0890..808c57845d 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -102,7 +102,8 @@ "completionError": "Cerebras completion error: {{error}}" }, "roo": { - "authenticationRequired": "Roo provider requires cloud authentication. Please sign in to Roo Code Cloud." + "authenticationRequired": "Roo provider requires cloud authentication. Please sign in to Roo Code Cloud.", + "authenticationRequiredWithOptions": "Roo provider requires authentication. Please sign in to Roo Code Cloud or switch to a different provider." } }, "warnings": { @@ -183,6 +184,10 @@ }, "info": { "organization_requires_auth": "Your organization requires authentication." + }, + "buttons": { + "signIn": "Sign In", + "settings": "Settings" } }, "prompts": { diff --git a/src/i18n/locales/es/common.json b/src/i18n/locales/es/common.json index 7b2b9a4347..6545a50065 100644 --- a/src/i18n/locales/es/common.json +++ b/src/i18n/locales/es/common.json @@ -102,7 +102,8 @@ "completionError": "Error de finalización de Cerebras: {{error}}" }, "roo": { - "authenticationRequired": "El proveedor Roo requiere autenticación en la nube. Por favor, inicia sesión en Roo Code Cloud." + "authenticationRequired": "El proveedor Roo requiere autenticación en la nube. Por favor, inicia sesión en Roo Code Cloud.", + "authenticationRequiredWithOptions": "El proveedor Roo requiere autenticación. Por favor, inicia sesión en Roo Code Cloud o cambia a un proveedor diferente." } }, "warnings": { @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "Tu organización requiere autenticación." + }, + "buttons": { + "signIn": "Iniciar sesión", + "settings": "Configuración" } }, "prompts": { diff --git a/src/i18n/locales/fr/common.json b/src/i18n/locales/fr/common.json index e9282a0b97..534a6fcc36 100644 --- a/src/i18n/locales/fr/common.json +++ b/src/i18n/locales/fr/common.json @@ -102,7 +102,8 @@ "completionError": "Erreur d'achèvement de Cerebras : {{error}}" }, "roo": { - "authenticationRequired": "Le fournisseur Roo nécessite une authentification cloud. Veuillez vous connecter à Roo Code Cloud." + "authenticationRequired": "Le fournisseur Roo nécessite une authentification cloud. Veuillez vous connecter à Roo Code Cloud.", + "authenticationRequiredWithOptions": "Le fournisseur Roo nécessite une authentification. Veuillez vous connecter à Roo Code Cloud ou passer à un autre fournisseur." } }, "warnings": { @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "Votre organisation nécessite une authentification." + }, + "buttons": { + "signIn": "Se connecter", + "settings": "Paramètres" } }, "prompts": { diff --git a/src/i18n/locales/hi/common.json b/src/i18n/locales/hi/common.json index 3f5ab60413..acfe346b36 100644 --- a/src/i18n/locales/hi/common.json +++ b/src/i18n/locales/hi/common.json @@ -102,7 +102,8 @@ "completionError": "Cerebras पूर्णता त्रुटि: {{error}}" }, "roo": { - "authenticationRequired": "Roo प्रदाता को क्लाउड प्रमाणीकरण की आवश्यकता है। कृपया Roo Code Cloud में साइन इन करें।" + "authenticationRequired": "Roo प्रदाता को क्लाउड प्रमाणीकरण की आवश्यकता है। कृपया Roo Code Cloud में साइन इन करें।", + "authenticationRequiredWithOptions": "Roo प्रदाता को प्रमाणीकरण की आवश्यकता है। कृपया Roo Code Cloud में साइन इन करें या किसी अन्य प्रदाता पर स्विच करें।" } }, "warnings": { @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "आपके संगठन को प्रमाणीकरण की आवश्यकता है।" + }, + "buttons": { + "signIn": "साइन इन करें", + "settings": "सेटिंग्स" } }, "prompts": { diff --git a/src/i18n/locales/id/common.json b/src/i18n/locales/id/common.json index 3c43056503..a950aedd21 100644 --- a/src/i18n/locales/id/common.json +++ b/src/i18n/locales/id/common.json @@ -102,7 +102,8 @@ "completionError": "Kesalahan penyelesaian Cerebras: {{error}}" }, "roo": { - "authenticationRequired": "Penyedia Roo memerlukan autentikasi cloud. Silakan masuk ke Roo Code Cloud." + "authenticationRequired": "Penyedia Roo memerlukan autentikasi cloud. Silakan masuk ke Roo Code Cloud.", + "authenticationRequiredWithOptions": "Penyedia Roo memerlukan autentikasi. Silakan masuk ke Roo Code Cloud atau beralih ke penyedia yang berbeda." } }, "warnings": { @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "Organisasi kamu memerlukan autentikasi." + }, + "buttons": { + "signIn": "Masuk", + "settings": "Pengaturan" } }, "prompts": { diff --git a/src/i18n/locales/it/common.json b/src/i18n/locales/it/common.json index c19114baf1..eb2e4d3a19 100644 --- a/src/i18n/locales/it/common.json +++ b/src/i18n/locales/it/common.json @@ -102,7 +102,8 @@ "completionError": "Errore di completamento Cerebras: {{error}}" }, "roo": { - "authenticationRequired": "Il provider Roo richiede l'autenticazione cloud. Accedi a Roo Code Cloud." + "authenticationRequired": "Il provider Roo richiede l'autenticazione cloud. Accedi a Roo Code Cloud.", + "authenticationRequiredWithOptions": "Il provider Roo richiede l'autenticazione. Accedi a Roo Code Cloud o passa a un provider diverso." } }, "warnings": { @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "La tua organizzazione richiede l'autenticazione." + }, + "buttons": { + "signIn": "Accedi", + "settings": "Impostazioni" } }, "prompts": { diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json index d595484fa1..0a4ae91a76 100644 --- a/src/i18n/locales/ja/common.json +++ b/src/i18n/locales/ja/common.json @@ -102,7 +102,8 @@ "completionError": "Cerebras完了エラー: {{error}}" }, "roo": { - "authenticationRequired": "Rooプロバイダーはクラウド認証が必要です。Roo Code Cloudにサインインしてください。" + "authenticationRequired": "Rooプロバイダーはクラウド認証が必要です。Roo Code Cloudにサインインしてください。", + "authenticationRequiredWithOptions": "Rooプロバイダーは認証が必要です。Roo Code Cloudにサインインするか、別のプロバイダーに切り替えてください。" } }, "warnings": { @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "あなたの組織では認証が必要です。" + }, + "buttons": { + "signIn": "サインイン", + "settings": "設定" } }, "prompts": { diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json index 3209952c6d..8da79129a5 100644 --- a/src/i18n/locales/ko/common.json +++ b/src/i18n/locales/ko/common.json @@ -102,7 +102,8 @@ "completionError": "Cerebras 완료 오류: {{error}}" }, "roo": { - "authenticationRequired": "Roo 제공업체는 클라우드 인증이 필요합니다. Roo Code Cloud에 로그인하세요." + "authenticationRequired": "Roo 제공업체는 클라우드 인증이 필요합니다. Roo Code Cloud에 로그인하세요.", + "authenticationRequiredWithOptions": "Roo 제공업체는 인증이 필요합니다. Roo Code Cloud에 로그인하거나 다른 제공업체로 변경하세요." } }, "warnings": { @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "조직에서 인증이 필요합니다." + }, + "buttons": { + "signIn": "로그인", + "settings": "설정" } }, "prompts": { diff --git a/src/i18n/locales/nl/common.json b/src/i18n/locales/nl/common.json index c0c6ba35e9..ee7dccf1a8 100644 --- a/src/i18n/locales/nl/common.json +++ b/src/i18n/locales/nl/common.json @@ -102,7 +102,8 @@ "completionError": "Cerebras-voltooiingsfout: {{error}}" }, "roo": { - "authenticationRequired": "Roo provider vereist cloud authenticatie. Log in bij Roo Code Cloud." + "authenticationRequired": "Roo provider vereist cloud authenticatie. Log in bij Roo Code Cloud.", + "authenticationRequiredWithOptions": "Roo provider vereist authenticatie. Log in bij Roo Code Cloud of schakel over naar een andere provider." } }, "warnings": { @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "Je organisatie vereist authenticatie." + }, + "buttons": { + "signIn": "Inloggen", + "settings": "Instellingen" } }, "prompts": { diff --git a/src/i18n/locales/pl/common.json b/src/i18n/locales/pl/common.json index 475ba069ee..a648a053b0 100644 --- a/src/i18n/locales/pl/common.json +++ b/src/i18n/locales/pl/common.json @@ -102,7 +102,8 @@ "completionError": "Błąd uzupełniania Cerebras: {{error}}" }, "roo": { - "authenticationRequired": "Dostawca Roo wymaga uwierzytelnienia w chmurze. Zaloguj się do Roo Code Cloud." + "authenticationRequired": "Dostawca Roo wymaga uwierzytelnienia w chmurze. Zaloguj się do Roo Code Cloud.", + "authenticationRequiredWithOptions": "Dostawca Roo wymaga uwierzytelnienia. Zaloguj się do Roo Code Cloud lub przełącz na innego dostawcę." } }, "warnings": { @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "Twoja organizacja wymaga uwierzytelnienia." + }, + "buttons": { + "signIn": "Zaloguj się", + "settings": "Ustawienia" } }, "prompts": { diff --git a/src/i18n/locales/pt-BR/common.json b/src/i18n/locales/pt-BR/common.json index 55a41fcf1b..8114c849f5 100644 --- a/src/i18n/locales/pt-BR/common.json +++ b/src/i18n/locales/pt-BR/common.json @@ -106,7 +106,8 @@ "completionError": "Erro de conclusão do Cerebras: {{error}}" }, "roo": { - "authenticationRequired": "O provedor Roo requer autenticação na nuvem. Faça login no Roo Code Cloud." + "authenticationRequired": "O provedor Roo requer autenticação na nuvem. Faça login no Roo Code Cloud.", + "authenticationRequiredWithOptions": "O provedor Roo requer autenticação. Faça login no Roo Code Cloud ou mude para um provedor diferente." } }, "warnings": { @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "Sua organização requer autenticação." + }, + "buttons": { + "signIn": "Entrar", + "settings": "Configurações" } }, "prompts": { diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json index 505998daa2..32924c008e 100644 --- a/src/i18n/locales/ru/common.json +++ b/src/i18n/locales/ru/common.json @@ -102,7 +102,8 @@ "completionError": "Ошибка завершения Cerebras: {{error}}" }, "roo": { - "authenticationRequired": "Провайдер Roo требует облачной аутентификации. Войдите в Roo Code Cloud." + "authenticationRequired": "Провайдер Roo требует облачной аутентификации. Войдите в Roo Code Cloud.", + "authenticationRequiredWithOptions": "Провайдер Roo требует аутентификации. Войдите в Roo Code Cloud или переключитесь на другого провайдера." } }, "warnings": { @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "Ваша организация требует аутентификации." + }, + "buttons": { + "signIn": "Войти", + "settings": "Настройки" } }, "prompts": { diff --git a/src/i18n/locales/tr/common.json b/src/i18n/locales/tr/common.json index 9b8af8d94c..42982ae447 100644 --- a/src/i18n/locales/tr/common.json +++ b/src/i18n/locales/tr/common.json @@ -102,7 +102,8 @@ "completionError": "Cerebras tamamlama hatası: {{error}}" }, "roo": { - "authenticationRequired": "Roo sağlayıcısı bulut kimlik doğrulaması gerektirir. Lütfen Roo Code Cloud'a giriş yapın." + "authenticationRequired": "Roo sağlayıcısı bulut kimlik doğrulaması gerektirir. Lütfen Roo Code Cloud'a giriş yapın.", + "authenticationRequiredWithOptions": "Roo sağlayıcısı kimlik doğrulaması gerektirir. Lütfen Roo Code Cloud'a giriş yapın veya farklı bir sağlayıcıya geçin." } }, "warnings": { @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "Kuruluşunuz kimlik doğrulaması gerektiriyor." + }, + "buttons": { + "signIn": "Oturum Aç", + "settings": "Ayarlar" } }, "prompts": { diff --git a/src/i18n/locales/vi/common.json b/src/i18n/locales/vi/common.json index 4877f297ad..3ad6005e1c 100644 --- a/src/i18n/locales/vi/common.json +++ b/src/i18n/locales/vi/common.json @@ -102,7 +102,8 @@ "completionError": "Lỗi hoàn thành Cerebras: {{error}}" }, "roo": { - "authenticationRequired": "Nhà cung cấp Roo yêu cầu xác thực đám mây. Vui lòng đăng nhập vào Roo Code Cloud." + "authenticationRequired": "Nhà cung cấp Roo yêu cầu xác thực đám mây. Vui lòng đăng nhập vào Roo Code Cloud.", + "authenticationRequiredWithOptions": "Nhà cung cấp Roo yêu cầu xác thực. Vui lòng đăng nhập vào Roo Code Cloud hoặc chuyển sang nhà cung cấp khác." } }, "warnings": { @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "Tổ chức của bạn yêu cầu xác thực." + }, + "buttons": { + "signIn": "Đăng nhập", + "settings": "Cài đặt" } }, "prompts": { diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json index 5bac0d2847..582db6c6a9 100644 --- a/src/i18n/locales/zh-CN/common.json +++ b/src/i18n/locales/zh-CN/common.json @@ -107,7 +107,8 @@ "completionError": "Cerebras 完成错误:{{error}}" }, "roo": { - "authenticationRequired": "Roo 提供商需要云认证。请登录 Roo Code Cloud。" + "authenticationRequired": "Roo 提供商需要云认证。请登录 Roo Code Cloud。", + "authenticationRequiredWithOptions": "Roo 提供商需要身份验证。请登录 Roo Code Cloud 或切换到其他提供商。" } }, "warnings": { @@ -199,6 +200,10 @@ }, "info": { "organization_requires_auth": "您的组织需要身份验证。" + }, + "buttons": { + "signIn": "登录", + "settings": "设置" } }, "prompts": { diff --git a/src/i18n/locales/zh-TW/common.json b/src/i18n/locales/zh-TW/common.json index 0f82f48d13..e89567c0e0 100644 --- a/src/i18n/locales/zh-TW/common.json +++ b/src/i18n/locales/zh-TW/common.json @@ -101,7 +101,8 @@ "completionError": "Cerebras 完成錯誤:{{error}}" }, "roo": { - "authenticationRequired": "Roo 提供者需要雲端認證。請登入 Roo Code Cloud。" + "authenticationRequired": "Roo 提供者需要雲端認證。請登入 Roo Code Cloud。", + "authenticationRequiredWithOptions": "Roo 提供者需要身分驗證。請登入 Roo Code Cloud 或切換至其他提供者。" }, "mode_import_failed": "匯入模式失敗:{{error}}" }, @@ -194,6 +195,10 @@ }, "info": { "organization_requires_auth": "您的組織需要身份驗證。" + }, + "buttons": { + "signIn": "登入", + "settings": "設定" } }, "prompts": { diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index ebdc137432..b27475783a 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -119,8 +119,10 @@ export interface ExtensionMessage { | "showEditMessageDialog" | "commands" | "insertTextIntoTextarea" + | "taskCreationFailed" text?: string payload?: any // Add a generic payload for now, can refine later + reason?: string // Reason for task creation failure action?: | "chatButtonClicked" | "mcpButtonClicked" diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index 3b77bbdb7d..ffdaf74e5c 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -875,6 +875,17 @@ const ChatViewComponent: React.ForwardRefRenderFunction