Show the Roo provider on the welcome screen (#8317)

This commit is contained in:
Matt Rubens 2025-09-25 16:13:04 -04:00 committed by GitHub
parent a0d6a4b4f9
commit 8485548f53
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 138 additions and 11 deletions

View file

@ -61,6 +61,8 @@ export enum TelemetryEventName {
ACCOUNT_LOGOUT_CLICKED = "Account Logout Clicked",
ACCOUNT_LOGOUT_SUCCESS = "Account Logout Success",
FEATURED_PROVIDER_CLICKED = "Featured Provider Clicked",
UPSELL_DISMISSED = "Upsell Dismissed",
UPSELL_CLICKED = "Upsell Clicked",
@ -184,6 +186,7 @@ export const rooCodeTelemetryEventSchema = z.discriminatedUnion("type", [
TelemetryEventName.ACCOUNT_CONNECT_SUCCESS,
TelemetryEventName.ACCOUNT_LOGOUT_CLICKED,
TelemetryEventName.ACCOUNT_LOGOUT_SUCCESS,
TelemetryEventName.FEATURED_PROVIDER_CLICKED,
TelemetryEventName.UPSELL_DISMISSED,
TelemetryEventName.UPSELL_CLICKED,
TelemetryEventName.SCHEMA_VALIDATION_ERROR,

BIN
src/assets/images/roo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

@ -1,15 +1,18 @@
import { useCallback, useState } from "react"
import { useCallback, useState, useEffect } from "react"
import knuthShuffle from "knuth-shuffle-seeded"
import { Trans } from "react-i18next"
import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
import posthog from "posthog-js"
import type { ProviderSettings } from "@roo-code/types"
import { TelemetryEventName } from "@roo-code/types"
import { useExtensionState } from "@src/context/ExtensionStateContext"
import { validateApiConfiguration } from "@src/utils/validate"
import { vscode } from "@src/utils/vscode"
import { useAppTranslation } from "@src/i18n/TranslationContext"
import { getRequestyAuthUrl, getOpenRouterAuthUrl } from "@src/oauth/urls"
import { telemetryClient } from "@src/utils/TelemetryClient"
import ApiOptions from "../settings/ApiOptions"
import { Tab, TabContent } from "../common/Tab"
@ -20,6 +23,14 @@ const WelcomeView = () => {
const { apiConfiguration, currentApiConfigName, setApiConfiguration, uriScheme, machineId } = useExtensionState()
const { t } = useAppTranslation()
const [errorMessage, setErrorMessage] = useState<string | undefined>(undefined)
const [showRooProvider, setShowRooProvider] = useState(false)
// Check PostHog feature flag for Roo provider
useEffect(() => {
posthog.onFeatureFlags(function () {
setShowRooProvider(posthog?.getFeatureFlag("roo-provider-featured") === "test")
})
}, [])
// Memoize the setApiConfigurationField function to pass to ApiOptions
const setApiConfigurationFieldForApiOptions = useCallback(
@ -69,7 +80,7 @@ const WelcomeView = () => {
{/* Define the providers */}
{(() => {
// Provider card configuration
const providers = [
const baseProviders = [
{
slug: "requesty",
name: "Requesty",
@ -85,6 +96,20 @@ const WelcomeView = () => {
},
]
// Conditionally add Roo provider based on feature flag
const providers = showRooProvider
? [
...baseProviders,
{
slug: "roo",
name: "Roo Code Cloud",
description: t("welcome:routers.roo.description"),
incentive: t("welcome:routers.roo.incentive"),
authUrl: "#", // Placeholder since onClick handler will prevent default
},
]
: baseProviders
// Shuffle providers based on machine ID (will be consistent for the same machine)
const orderedProviders = [...providers]
knuthShuffle(orderedProviders, (machineId as any) || Date.now())
@ -94,9 +119,41 @@ const WelcomeView = () => {
<a
key={index}
href={provider.authUrl}
className="flex-1 border border-vscode-panel-border hover:bg-secondary rounded-md py-3 px-4 mb-2 flex flex-row gap-3 cursor-pointer transition-all no-underline text-inherit"
className="relative flex-1 border border-vscode-panel-border hover:bg-secondary rounded-md py-3 px-4 mb-2 flex flex-row gap-3 cursor-pointer transition-all no-underline text-inherit"
target="_blank"
rel="noopener noreferrer">
rel="noopener noreferrer"
onClick={(e) => {
// Track telemetry for featured provider click
telemetryClient.capture(TelemetryEventName.FEATURED_PROVIDER_CLICKED, {
provider: provider.slug,
})
// Special handling for Roo provider
if (provider.slug === "roo") {
e.preventDefault()
// Set the Roo provider configuration
const rooConfig: ProviderSettings = {
apiProvider: "roo",
}
// Save the Roo provider configuration
vscode.postMessage({
type: "upsertApiConfiguration",
text: currentApiConfigName,
apiConfiguration: rooConfig,
})
// Then trigger cloud sign-in
vscode.postMessage({ type: "rooCloudSignIn" })
}
// For other providers, let the default link behavior work
}}>
{provider.incentive && (
<div className="absolute top-0 right-0 text-[10px] text-vscode-badge-foreground bg-vscode-badge-background px-2 py-0.5 rounded-bl rounded-tr-md">
{provider.incentive}
</div>
)}
<div className="w-8 h-8 flex-shrink-0">
<img
src={`${imagesBaseUri}/${provider.slug}.png`}
@ -108,13 +165,8 @@ const WelcomeView = () => {
<div className="text-sm font-medium text-vscode-foreground">
{provider.name}
</div>
<div>
<div className="text-xs text-vscode-descriptionForeground">
{provider.description}
</div>
{provider.incentive && (
<div className="text-xs mt-1">{provider.incentive}</div>
)}
<div className="text-xs text-vscode-descriptionForeground">
{provider.description}
</div>
</div>
</a>

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "Una interfície unificada per a LLMs"
},
"roo": {
"description": "Els millors models gratuïts per començar",
"incentive": "Prova Roo gratis"
}
},
"chooseProvider": "Per fer la seva màgia, Roo necessita una clau API.",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "Eine einheitliche Schnittstelle für LLMs"
},
"roo": {
"description": "Die besten kostenlosen Modelle für den Einstieg",
"incentive": "Probier Roo kostenlos aus"
}
},
"chooseProvider": "Um seine Magie zu entfalten, benötigt Roo einen API-Schlüssel.",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "A unified interface for LLMs"
},
"roo": {
"description": "The best free models to get started",
"incentive": "Try Roo out for free"
}
},
"chooseProvider": "To do its magic, Roo needs an API key.",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "Una interfaz unificada para LLMs"
},
"roo": {
"description": "Los mejores modelos gratuitos para empezar",
"incentive": "Prueba Roo gratis"
}
},
"chooseProvider": "Para hacer su magia, Roo necesita una clave API.",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "Une interface unifiée pour les LLMs"
},
"roo": {
"description": "Les meilleurs modèles gratuits pour commencer",
"incentive": "Essayez Roo gratuitement"
}
},
"chooseProvider": "Pour faire sa magie, Roo a besoin d'une clé API.",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "LLMs के लिए एक एकीकृत इंटरफेस"
},
"roo": {
"description": "शुरू करने के लिए सर्वोत्तम निःशुल्क मॉडल",
"incentive": "Roo को निःशुल्क आज़माएं"
}
},
"chooseProvider": "अपना जादू दिखाने के लिए, Roo को एक API कुंजी की आवश्यकता है।",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "Interface terpadu untuk LLM"
},
"roo": {
"description": "Model gratis terbaik untuk memulai",
"incentive": "Coba Roo gratis"
}
},
"chooseProvider": "Untuk melakukan keajaibannya, Roo membutuhkan API key.",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "Un'interfaccia unificata per LLMs"
},
"roo": {
"description": "I migliori modelli gratuiti per iniziare",
"incentive": "Prova Roo gratuitamente"
}
},
"chooseProvider": "Per fare la sua magia, Roo ha bisogno di una chiave API.",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "LLMsのための統一インターフェース"
},
"roo": {
"description": "始めるための最高の無料モデル",
"incentive": "Rooを無料で試す"
}
},
"chooseProvider": "Rooが機能するには、APIキーが必要です。",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "LLM을 위한 통합 인터페이스"
},
"roo": {
"description": "시작하기에 최고의 무료 모델",
"incentive": "Roo를 무료로 체험해보세요"
}
},
"chooseProvider": "Roo가 작동하려면 API 키가 필요합니다.",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "Een uniforme interface voor LLM's"
},
"roo": {
"description": "De beste gratis modellen om mee te beginnen",
"incentive": "Probeer Roo gratis uit"
}
},
"chooseProvider": "Om zijn magie te doen, heeft Roo een API-sleutel nodig.",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "Ujednolicony interfejs dla LLMs"
},
"roo": {
"description": "Najlepsze darmowe modele na start",
"incentive": "Wypróbuj Roo za darmo"
}
},
"chooseProvider": "Aby działać, Roo potrzebuje klucza API.",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "Uma interface unificada para LLMs"
},
"roo": {
"description": "Os melhores modelos gratuitos para começar",
"incentive": "Experimente o Roo gratuitamente"
}
},
"chooseProvider": "Para fazer sua mágica, o Roo precisa de uma chave API.",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "Унифицированный интерфейс для LLM"
},
"roo": {
"description": "Лучшие бесплатные модели для начала работы",
"incentive": "Попробуй Roo бесплатно"
}
},
"chooseProvider": "Для своей магии Roo нуждается в API-ключе.",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "LLM'ler için birleşik bir arayüz"
},
"roo": {
"description": "Başlamak için en iyi ücretsiz modeller",
"incentive": "Roo'yu ücretsiz dene"
}
},
"chooseProvider": "Sihirini yapabilmesi için Roo'nun bir API anahtarına ihtiyacı var.",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "Giao diện thống nhất cho các LLM"
},
"roo": {
"description": "Những mô hình miễn phí tốt nhất để bắt đầu",
"incentive": "Dùng thử Roo miễn phí"
}
},
"chooseProvider": "Để thực hiện phép màu của mình, Roo cần một khóa API.",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "统一了大语言模型的接口"
},
"roo": {
"description": "最优秀的免费模型助你开始",
"incentive": "免费试用 Roo"
}
},
"chooseProvider": "Roo 需要一个 API 密钥才能发挥魔力。",

View file

@ -10,6 +10,10 @@
},
"openrouter": {
"description": "LLM 的統一介面"
},
"roo": {
"description": "最優秀的免費模型助你開始",
"incentive": "免費試用 Roo"
}
},
"chooseProvider": "Roo 需要 API 金鑰才能發揮魔力。",