-
Notifications
You must be signed in to change notification settings - Fork 2.6k
fix: handle Roo provider authentication errors gracefully #7298
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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) { | ||
cte marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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) | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enhancement: Consider adding JSDoc documentation for better code maintainability: