Add support for Sonic model (#7207)

Co-authored-by: cte <cestreich@gmail.com>
This commit is contained in:
Matt Rubens 2025-08-19 00:53:32 -07:00 committed by GitHub
parent 87c42c1f26
commit fd3535c21a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
68 changed files with 739 additions and 66 deletions

View file

@ -47,6 +47,7 @@ export const providerNames = [
"zai",
"fireworks",
"io-intelligence",
"roo",
] as const
export const providerNamesSchema = z.enum(providerNames)
@ -288,6 +289,10 @@ const ioIntelligenceSchema = apiModelIdProviderModelSchema.extend({
ioIntelligenceApiKey: z.string().optional(),
})
const rooSchema = apiModelIdProviderModelSchema.extend({
// No additional fields needed - uses cloud authentication
})
const defaultSchema = z.object({
apiProvider: z.undefined(),
})
@ -324,6 +329,7 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv
zaiSchema.merge(z.object({ apiProvider: z.literal("zai") })),
fireworksSchema.merge(z.object({ apiProvider: z.literal("fireworks") })),
ioIntelligenceSchema.merge(z.object({ apiProvider: z.literal("io-intelligence") })),
rooSchema.merge(z.object({ apiProvider: z.literal("roo") })),
defaultSchema,
])
@ -360,6 +366,7 @@ export const providerSettingsSchema = z.object({
...zaiSchema.shape,
...fireworksSchema.shape,
...ioIntelligenceSchema.shape,
...rooSchema.shape,
...codebaseIndexProviderSchema.shape,
})

View file

@ -25,3 +25,4 @@ export * from "./xai.js"
export * from "./doubao.js"
export * from "./zai.js"
export * from "./fireworks.js"
export * from "./roo.js"

View file

@ -0,0 +1,19 @@
import type { ModelInfo } from "../model.js"
// Roo provider with single model
export type RooModelId = "roo/sonic"
export const rooDefaultModelId: RooModelId = "roo/sonic"
export const rooModels = {
"roo/sonic": {
maxTokens: 8192,
contextWindow: 262_144,
supportsImages: false,
supportsPromptCache: false,
inputPrice: 0,
outputPrice: 0,
description:
"Stealth coding model with 262K context window, accessible for free through Roo Code Cloud for a limited time. (Note: prompts and completions are logged by the model creator and used to improve the model.)",
},
} as const satisfies Record<string, ModelInfo>

18
pnpm-lock.yaml generated
View file

@ -584,8 +584,8 @@ importers:
specifier: ^1.14.0
version: 1.14.0(typescript@5.8.3)
'@roo-code/cloud':
specifier: ^0.17.0
version: 0.17.0
specifier: ^0.18.0
version: 0.18.0
'@roo-code/ipc':
specifier: workspace:^
version: link:../packages/ipc
@ -3106,11 +3106,11 @@ packages:
cpu: [x64]
os: [win32]
'@roo-code/cloud@0.17.0':
resolution: {integrity: sha512-Sh7KGbVapxocnoyDzWkvvtVzam5jZnU2RGKT7V0v3CbFMQc329NBnHRAgVtJUwcGPHUFyAkwEHo181Fn3rFpZw==}
'@roo-code/cloud@0.18.0':
resolution: {integrity: sha512-Y2jbcUVB9RCQFAxHDPrfjWQU1o7yRvWaPAdA3eZjsUf+zfDL59Rwfghg6loqDfE/8HCkcJmHfLCKovNX5ju5qA==}
'@roo-code/types@1.52.0':
resolution: {integrity: sha512-jPCVZ2j4Y0MUiHvAJbXduR3yFGb5A3KDvIThi8cKBAUg8zb7jhIYKTvJ5vub1MGZkpK11K0JG6ex4RL19FjobA==}
'@roo-code/types@1.54.0':
resolution: {integrity: sha512-Xj3Zn2FhXbG2bpwXuhrjKnkeuWypQCIPKljOLXnOCUqaMUhP1zkWwNZ+I3gIBUpDng/iWN3KHon1if0UaoXYQw==}
'@sec-ant/readable-stream@0.4.1':
resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
@ -12314,9 +12314,9 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.40.2':
optional: true
'@roo-code/cloud@0.17.0':
'@roo-code/cloud@0.18.0':
dependencies:
'@roo-code/types': 1.52.0
'@roo-code/types': 1.54.0
ioredis: 5.6.1
p-wait-for: 5.0.2
socket.io-client: 4.8.1
@ -12326,7 +12326,7 @@ snapshots:
- supports-color
- utf-8-validate
'@roo-code/types@1.52.0':
'@roo-code/types@1.54.0':
dependencies:
zod: 3.25.76

View file

@ -35,6 +35,7 @@ import {
DoubaoHandler,
ZAiHandler,
FireworksHandler,
RooHandler,
} from "./providers"
import { NativeOllamaHandler } from "./providers/native-ollama"
@ -140,6 +141,8 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler {
return new FireworksHandler(options)
case "io-intelligence":
return new IOIntelligenceHandler(options)
case "roo":
return new RooHandler(options)
default:
apiProvider satisfies "gemini-cli" | undefined
return new AnthropicHandler(options)

View file

@ -0,0 +1,436 @@
// npx vitest run api/providers/__tests__/roo.spec.ts
import { Anthropic } from "@anthropic-ai/sdk"
import { rooDefaultModelId, rooModels } from "@roo-code/types"
import { ApiHandlerOptions } from "../../../shared/api"
// Mock OpenAI client
const mockCreate = vitest.fn()
vitest.mock("openai", () => {
return {
__esModule: true,
default: vitest.fn().mockImplementation(() => ({
chat: {
completions: {
create: mockCreate.mockImplementation(async (options) => {
if (!options.stream) {
return {
id: "test-completion",
choices: [
{
message: { role: "assistant", content: "Test response" },
finish_reason: "stop",
index: 0,
},
],
usage: {
prompt_tokens: 10,
completion_tokens: 5,
total_tokens: 15,
},
}
}
return {
[Symbol.asyncIterator]: async function* () {
yield {
choices: [
{
delta: { content: "Test response" },
index: 0,
},
],
usage: null,
}
yield {
choices: [
{
delta: {},
index: 0,
},
],
usage: {
prompt_tokens: 10,
completion_tokens: 5,
total_tokens: 15,
},
}
},
}
}),
},
},
})),
}
})
// Mock CloudService - Define functions outside to avoid initialization issues
const mockGetSessionToken = vitest.fn()
const mockHasInstance = vitest.fn()
// Create mock functions that we can control
const mockGetSessionTokenFn = vitest.fn()
const mockHasInstanceFn = vitest.fn()
vitest.mock("@roo-code/cloud", () => ({
CloudService: {
hasInstance: () => mockHasInstanceFn(),
get instance() {
return {
authService: {
getSessionToken: () => mockGetSessionTokenFn(),
},
}
},
},
}))
// Mock i18n
vitest.mock("../../../i18n", () => ({
t: vitest.fn((key: string) => {
if (key === "common:errors.roo.authenticationRequired") {
return "Authentication required for Roo Code Cloud"
}
return key
}),
}))
// Import after mocks are set up
import { RooHandler } from "../roo"
import { CloudService } from "@roo-code/cloud"
import { t } from "../../../i18n"
describe("RooHandler", () => {
let handler: RooHandler
let mockOptions: ApiHandlerOptions
const systemPrompt = "You are a helpful assistant."
const messages: Anthropic.Messages.MessageParam[] = [
{
role: "user",
content: "Hello!",
},
]
beforeEach(() => {
mockOptions = {
apiModelId: "roo/sonic",
}
// Set up CloudService mocks for successful authentication
mockHasInstanceFn.mockReturnValue(true)
mockGetSessionTokenFn.mockReturnValue("test-session-token")
mockCreate.mockClear()
vitest.clearAllMocks()
})
describe("constructor", () => {
it("should initialize with valid session token", () => {
handler = new RooHandler(mockOptions)
expect(handler).toBeInstanceOf(RooHandler)
expect(handler.getModel().id).toBe(mockOptions.apiModelId)
})
it("should throw error if CloudService is not available", () => {
mockHasInstanceFn.mockReturnValue(false)
expect(() => {
new RooHandler(mockOptions)
}).toThrow("Authentication required for Roo Code Cloud")
expect(t).toHaveBeenCalledWith("common:errors.roo.authenticationRequired")
})
it("should throw error if session token is not available", () => {
mockHasInstanceFn.mockReturnValue(true)
mockGetSessionTokenFn.mockReturnValue(null)
expect(() => {
new RooHandler(mockOptions)
}).toThrow("Authentication required for Roo Code Cloud")
expect(t).toHaveBeenCalledWith("common:errors.roo.authenticationRequired")
})
it("should initialize with default model if no model specified", () => {
handler = new RooHandler({})
expect(handler).toBeInstanceOf(RooHandler)
expect(handler.getModel().id).toBe(rooDefaultModelId)
})
it("should pass correct configuration to base class", () => {
handler = new RooHandler(mockOptions)
expect(handler).toBeInstanceOf(RooHandler)
// The handler should be initialized with correct base URL and API key
// We can't directly test the parent class constructor, but we can verify the handler works
expect(handler).toBeDefined()
})
})
describe("createMessage", () => {
beforeEach(() => {
handler = new RooHandler(mockOptions)
})
it("should handle streaming responses", async () => {
const stream = handler.createMessage(systemPrompt, messages)
const chunks: any[] = []
for await (const chunk of stream) {
chunks.push(chunk)
}
expect(chunks.length).toBeGreaterThan(0)
const textChunks = chunks.filter((chunk) => chunk.type === "text")
expect(textChunks).toHaveLength(1)
expect(textChunks[0].text).toBe("Test response")
})
it("should include usage information", async () => {
const stream = handler.createMessage(systemPrompt, messages)
const chunks: any[] = []
for await (const chunk of stream) {
chunks.push(chunk)
}
const usageChunks = chunks.filter((chunk) => chunk.type === "usage")
expect(usageChunks).toHaveLength(1)
expect(usageChunks[0].inputTokens).toBe(10)
expect(usageChunks[0].outputTokens).toBe(5)
})
it("should handle API errors", async () => {
mockCreate.mockRejectedValueOnce(new Error("API Error"))
const stream = handler.createMessage(systemPrompt, messages)
await expect(async () => {
for await (const _chunk of stream) {
// Should not reach here
}
}).rejects.toThrow("API Error")
})
it("should handle empty response content", async () => {
mockCreate.mockResolvedValueOnce({
[Symbol.asyncIterator]: async function* () {
yield {
choices: [
{
delta: { content: null },
index: 0,
},
],
usage: {
prompt_tokens: 10,
completion_tokens: 0,
total_tokens: 10,
},
}
},
})
const stream = handler.createMessage(systemPrompt, messages)
const chunks: any[] = []
for await (const chunk of stream) {
chunks.push(chunk)
}
const textChunks = chunks.filter((chunk) => chunk.type === "text")
expect(textChunks).toHaveLength(0)
const usageChunks = chunks.filter((chunk) => chunk.type === "usage")
expect(usageChunks).toHaveLength(1)
})
it("should handle multiple messages in conversation", async () => {
const multipleMessages: Anthropic.Messages.MessageParam[] = [
{ role: "user", content: "First message" },
{ role: "assistant", content: "First response" },
{ role: "user", content: "Second message" },
]
const stream = handler.createMessage(systemPrompt, multipleMessages)
const chunks: any[] = []
for await (const chunk of stream) {
chunks.push(chunk)
}
expect(mockCreate).toHaveBeenCalledWith(
expect.objectContaining({
messages: expect.arrayContaining([
expect.objectContaining({ role: "system", content: systemPrompt }),
expect.objectContaining({ role: "user", content: "First message" }),
expect.objectContaining({ role: "assistant", content: "First response" }),
expect.objectContaining({ role: "user", content: "Second message" }),
]),
}),
)
})
})
describe("completePrompt", () => {
beforeEach(() => {
handler = new RooHandler(mockOptions)
})
it("should complete prompt successfully", async () => {
const result = await handler.completePrompt("Test prompt")
expect(result).toBe("Test response")
expect(mockCreate).toHaveBeenCalledWith({
model: mockOptions.apiModelId,
messages: [{ role: "user", content: "Test prompt" }],
})
})
it("should handle API errors", async () => {
mockCreate.mockRejectedValueOnce(new Error("API Error"))
await expect(handler.completePrompt("Test prompt")).rejects.toThrow(
"Roo Code Cloud completion error: API Error",
)
})
it("should handle empty response", async () => {
mockCreate.mockResolvedValueOnce({
choices: [{ message: { content: "" } }],
})
const result = await handler.completePrompt("Test prompt")
expect(result).toBe("")
})
it("should handle missing response content", async () => {
mockCreate.mockResolvedValueOnce({
choices: [{ message: {} }],
})
const result = await handler.completePrompt("Test prompt")
expect(result).toBe("")
})
})
describe("getModel", () => {
beforeEach(() => {
handler = new RooHandler(mockOptions)
})
it("should return model info for specified model", () => {
const modelInfo = handler.getModel()
expect(modelInfo.id).toBe(mockOptions.apiModelId)
expect(modelInfo.info).toBeDefined()
// roo/sonic is a valid model in rooModels
expect(modelInfo.info).toBe(rooModels["roo/sonic"])
})
it("should return default model when no model specified", () => {
const handlerWithoutModel = new RooHandler({})
const modelInfo = handlerWithoutModel.getModel()
expect(modelInfo.id).toBe(rooDefaultModelId)
expect(modelInfo.info).toBeDefined()
expect(modelInfo.info).toBe(rooModels[rooDefaultModelId])
})
it("should handle unknown model ID with fallback info", () => {
const handlerWithUnknownModel = new RooHandler({
apiModelId: "unknown-model-id",
})
const modelInfo = handlerWithUnknownModel.getModel()
expect(modelInfo.id).toBe("unknown-model-id")
expect(modelInfo.info).toBeDefined()
// Should return fallback info for unknown models
expect(modelInfo.info.maxTokens).toBe(8192)
expect(modelInfo.info.contextWindow).toBe(262_144)
expect(modelInfo.info.supportsImages).toBe(false)
expect(modelInfo.info.supportsPromptCache).toBe(false)
expect(modelInfo.info.inputPrice).toBe(0)
expect(modelInfo.info.outputPrice).toBe(0)
})
it("should return correct model info for all Roo models", () => {
// Test each model in rooModels
const modelIds = Object.keys(rooModels) as Array<keyof typeof rooModels>
for (const modelId of modelIds) {
const handlerWithModel = new RooHandler({ apiModelId: modelId })
const modelInfo = handlerWithModel.getModel()
expect(modelInfo.id).toBe(modelId)
expect(modelInfo.info).toBe(rooModels[modelId])
}
})
})
describe("temperature and model configuration", () => {
it("should use default temperature of 0.7", async () => {
handler = new RooHandler(mockOptions)
const stream = handler.createMessage(systemPrompt, messages)
for await (const _chunk of stream) {
// Consume stream
}
expect(mockCreate).toHaveBeenCalledWith(
expect.objectContaining({
temperature: 0.7,
}),
)
})
it("should respect custom temperature setting", async () => {
handler = new RooHandler({
...mockOptions,
modelTemperature: 0.9,
})
const stream = handler.createMessage(systemPrompt, messages)
for await (const _chunk of stream) {
// Consume stream
}
expect(mockCreate).toHaveBeenCalledWith(
expect.objectContaining({
temperature: 0.9,
}),
)
})
it("should use correct API endpoint", () => {
// The base URL should be set to Roo's API endpoint
// We can't directly test the OpenAI client configuration, but we can verify the handler initializes
handler = new RooHandler(mockOptions)
expect(handler).toBeInstanceOf(RooHandler)
// The handler should work with the Roo API endpoint
})
})
describe("authentication flow", () => {
it("should use session token as API key", () => {
const testToken = "test-session-token-123"
mockGetSessionTokenFn.mockReturnValue(testToken)
handler = new RooHandler(mockOptions)
expect(handler).toBeInstanceOf(RooHandler)
expect(mockGetSessionTokenFn).toHaveBeenCalled()
})
it("should handle undefined auth service", () => {
mockHasInstanceFn.mockReturnValue(true)
// Mock CloudService with undefined authService
const originalGetter = Object.getOwnPropertyDescriptor(CloudService, "instance")?.get
try {
Object.defineProperty(CloudService, "instance", {
get: () => ({ authService: undefined }),
configurable: true,
})
expect(() => {
new RooHandler(mockOptions)
}).toThrow("Authentication required for Roo Code Cloud")
} finally {
// Always restore original getter, even if test fails
if (originalGetter) {
Object.defineProperty(CloudService, "instance", {
get: originalGetter,
configurable: true,
})
}
}
})
it("should handle empty session token", () => {
mockGetSessionTokenFn.mockReturnValue("")
expect(() => {
new RooHandler(mockOptions)
}).toThrow("Authentication required for Roo Code Cloud")
})
})
})

View file

@ -29,3 +29,4 @@ export { VsCodeLmHandler } from "./vscode-lm"
export { XAIHandler } from "./xai"
export { ZAiHandler } from "./zai"
export { FireworksHandler } from "./fireworks"
export { RooHandler } from "./roo"

53
src/api/providers/roo.ts Normal file
View file

@ -0,0 +1,53 @@
import { rooDefaultModelId, rooModels, type RooModelId } from "@roo-code/types"
import { CloudService } from "@roo-code/cloud"
import type { ApiHandlerOptions } from "../../shared/api"
import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider"
import { t } from "../../i18n"
export class RooHandler extends BaseOpenAiCompatibleProvider<RooModelId> {
constructor(options: ApiHandlerOptions) {
// Check if CloudService is available and get the session token.
if (!CloudService.hasInstance()) {
throw new Error(t("common:errors.roo.authenticationRequired"))
}
const sessionToken = CloudService.instance.authService?.getSessionToken()
if (!sessionToken) {
throw new Error(t("common:errors.roo.authenticationRequired"))
}
super({
...options,
providerName: "Roo Code Cloud",
baseURL: "https://api.roocode.com/proxy/v1",
apiKey: sessionToken,
defaultProviderModelId: rooDefaultModelId,
providerModels: rooModels,
defaultTemperature: 0.7,
})
}
override getModel() {
const modelId = this.options.apiModelId || rooDefaultModelId
const modelInfo = this.providerModels[modelId as RooModelId] ?? this.providerModels[rooDefaultModelId]
if (modelInfo) {
return { id: modelId as RooModelId, info: modelInfo }
}
// Return the requested model ID even if not found, with fallback info.
return {
id: modelId as RooModelId,
info: {
maxTokens: 8192,
contextWindow: 262_144,
supportsImages: false,
supportsPromptCache: false,
inputPrice: 0,
outputPrice: 0,
},
}
}
}

View file

@ -104,6 +104,9 @@
"noResponseBody": "Error de l'API de Cerebras: No hi ha cos de resposta",
"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."
},
"mode_import_failed": "Ha fallat la importació del mode: {{error}}"
},
"warnings": {

View file

@ -100,6 +100,9 @@
"genericError": "Cerebras API-Fehler ({{status}}): {{message}}",
"noResponseBody": "Cerebras API-Fehler: Kein Antworttext vorhanden",
"completionError": "Cerebras-Vervollständigungsfehler: {{error}}"
},
"roo": {
"authenticationRequired": "Roo-Anbieter erfordert Cloud-Authentifizierung. Bitte melde dich bei Roo Code Cloud an."
}
},
"warnings": {

View file

@ -100,6 +100,9 @@
"genericError": "Cerebras API Error ({{status}}): {{message}}",
"noResponseBody": "Cerebras API Error: No response body",
"completionError": "Cerebras completion error: {{error}}"
},
"roo": {
"authenticationRequired": "Roo provider requires cloud authentication. Please sign in to Roo Code Cloud."
}
},
"warnings": {

View file

@ -100,6 +100,9 @@
"genericError": "Error de la API de Cerebras ({{status}}): {{message}}",
"noResponseBody": "Error de la API de Cerebras: Sin cuerpo de respuesta",
"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."
}
},
"warnings": {

View file

@ -100,6 +100,9 @@
"genericError": "Erreur de l'API Cerebras ({{status}}) : {{message}}",
"noResponseBody": "Erreur de l'API Cerebras : Aucun corps de réponse",
"completionError": "Erreur d'achèvement de Cerebras : {{error}}"
},
"roo": {
"authenticationRequired": "Le fournisseur Roo nécessite une authentification cloud. Veuillez vous connecter à Roo Code Cloud."
}
},
"warnings": {

View file

@ -100,6 +100,9 @@
"genericError": "Cerebras API त्रुटि ({{status}}): {{message}}",
"noResponseBody": "Cerebras API त्रुटि: कोई प्रतिक्रिया मुख्य भाग नहीं",
"completionError": "Cerebras पूर्णता त्रुटि: {{error}}"
},
"roo": {
"authenticationRequired": "Roo प्रदाता को क्लाउड प्रमाणीकरण की आवश्यकता है। कृपया Roo Code Cloud में साइन इन करें।"
}
},
"warnings": {

View file

@ -100,6 +100,9 @@
"genericError": "Kesalahan API Cerebras ({{status}}): {{message}}",
"noResponseBody": "Kesalahan API Cerebras: Tidak ada isi respons",
"completionError": "Kesalahan penyelesaian Cerebras: {{error}}"
},
"roo": {
"authenticationRequired": "Penyedia Roo memerlukan autentikasi cloud. Silakan masuk ke Roo Code Cloud."
}
},
"warnings": {

View file

@ -100,6 +100,9 @@
"genericError": "Errore API Cerebras ({{status}}): {{message}}",
"noResponseBody": "Errore API Cerebras: Nessun corpo di risposta",
"completionError": "Errore di completamento Cerebras: {{error}}"
},
"roo": {
"authenticationRequired": "Il provider Roo richiede l'autenticazione cloud. Accedi a Roo Code Cloud."
}
},
"warnings": {

View file

@ -100,6 +100,9 @@
"genericError": "Cerebras APIエラー ({{status}}): {{message}}",
"noResponseBody": "Cerebras APIエラー: レスポンスボディなし",
"completionError": "Cerebras完了エラー: {{error}}"
},
"roo": {
"authenticationRequired": "Rooプロバイダーはクラウド認証が必要です。Roo Code Cloudにサインインしてください。"
}
},
"warnings": {

View file

@ -100,6 +100,9 @@
"genericError": "Cerebras API 오류 ({{status}}): {{message}}",
"noResponseBody": "Cerebras API 오류: 응답 본문 없음",
"completionError": "Cerebras 완료 오류: {{error}}"
},
"roo": {
"authenticationRequired": "Roo 제공업체는 클라우드 인증이 필요합니다. Roo Code Cloud에 로그인하세요."
}
},
"warnings": {

View file

@ -100,6 +100,9 @@
"genericError": "Cerebras API-fout ({{status}}): {{message}}",
"noResponseBody": "Cerebras API-fout: Geen responslichaam",
"completionError": "Cerebras-voltooiingsfout: {{error}}"
},
"roo": {
"authenticationRequired": "Roo provider vereist cloud authenticatie. Log in bij Roo Code Cloud."
}
},
"warnings": {

View file

@ -100,6 +100,9 @@
"genericError": "Błąd API Cerebras ({{status}}): {{message}}",
"noResponseBody": "Błąd API Cerebras: Brak treści odpowiedzi",
"completionError": "Błąd uzupełniania Cerebras: {{error}}"
},
"roo": {
"authenticationRequired": "Dostawca Roo wymaga uwierzytelnienia w chmurze. Zaloguj się do Roo Code Cloud."
}
},
"warnings": {

View file

@ -104,6 +104,9 @@
"genericError": "Erro da API Cerebras ({{status}}): {{message}}",
"noResponseBody": "Erro da API Cerebras: Sem corpo de resposta",
"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."
}
},
"warnings": {

View file

@ -100,6 +100,9 @@
"genericError": "Ошибка Cerebras API ({{status}}): {{message}}",
"noResponseBody": "Ошибка Cerebras API: Нет тела ответа",
"completionError": "Ошибка завершения Cerebras: {{error}}"
},
"roo": {
"authenticationRequired": "Провайдер Roo требует облачной аутентификации. Войдите в Roo Code Cloud."
}
},
"warnings": {

View file

@ -100,6 +100,9 @@
"genericError": "Cerebras API Hatası ({{status}}): {{message}}",
"noResponseBody": "Cerebras API Hatası: Yanıt gövdesi yok",
"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."
}
},
"warnings": {

View file

@ -100,6 +100,9 @@
"genericError": "Lỗi API Cerebras ({{status}}): {{message}}",
"noResponseBody": "Lỗi API Cerebras: Không có nội dung phản hồi",
"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."
}
},
"warnings": {

View file

@ -105,6 +105,9 @@
"genericError": "Cerebras API 错误 ({{status}}){{message}}",
"noResponseBody": "Cerebras API 错误:无响应主体",
"completionError": "Cerebras 完成错误:{{error}}"
},
"roo": {
"authenticationRequired": "Roo 提供商需要云认证。请登录 Roo Code Cloud。"
}
},
"warnings": {

View file

@ -100,6 +100,9 @@
"noResponseBody": "Cerebras API 錯誤:無回應主體",
"completionError": "Cerebras 完成錯誤:{{error}}"
},
"roo": {
"authenticationRequired": "Roo 提供者需要雲端認證。請登入 Roo Code Cloud。"
},
"mode_import_failed": "匯入模式失敗:{{error}}"
},
"warnings": {

View file

@ -427,7 +427,7 @@
"@mistralai/mistralai": "^1.3.6",
"@modelcontextprotocol/sdk": "^1.9.0",
"@qdrant/js-client-rest": "^1.14.0",
"@roo-code/cloud": "^0.17.0",
"@roo-code/cloud": "^0.18.0",
"@roo-code/ipc": "workspace:^",
"@roo-code/telemetry": "workspace:^",
"@roo-code/types": "workspace:^",

View file

@ -1,7 +1,7 @@
import React, { memo, useCallback, useEffect, useMemo, useState } from "react"
import { convertHeadersToObject } from "./utils/headers"
import { useDebounce } from "react-use"
import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"
import { VSCodeLink, VSCodeButton } from "@vscode/webview-ui-toolkit/react"
import { ExternalLinkIcon } from "@radix-ui/react-icons"
import {
@ -32,6 +32,7 @@ import {
mainlandZAiDefaultModelId,
fireworksDefaultModelId,
ioIntelligenceDefaultModelId,
rooDefaultModelId,
} from "@roo-code/types"
import { vscode } from "@src/utils/vscode"
@ -124,7 +125,7 @@ const ApiOptions = ({
setErrorMessage,
}: ApiOptionsProps) => {
const { t } = useAppTranslation()
const { organizationAllowList } = useExtensionState()
const { organizationAllowList, cloudIsAuthenticated } = useExtensionState()
const [customHeaders, setCustomHeaders] = useState<[string, string][]>(() => {
const headers = apiConfiguration?.openAiHeaders || {}
@ -327,6 +328,7 @@ const ApiOptions = ({
},
fireworks: { field: "apiModelId", default: fireworksDefaultModelId },
"io-intelligence": { field: "ioIntelligenceModelId", default: ioIntelligenceDefaultModelId },
roo: { field: "apiModelId", default: rooDefaultModelId },
openai: { field: "openAiModelId" },
ollama: { field: "ollamaModelId" },
lmstudio: { field: "lmStudioModelId" },
@ -579,6 +581,25 @@ const ApiOptions = ({
<Fireworks apiConfiguration={apiConfiguration} setApiConfigurationField={setApiConfigurationField} />
)}
{selectedProvider === "roo" && (
<div className="flex flex-col gap-3">
{cloudIsAuthenticated ? (
<div className="text-sm text-vscode-descriptionForeground">
{t("settings:providers.roo.authenticatedMessage")}
</div>
) : (
<div className="flex flex-col gap-2">
<VSCodeButton
appearance="primary"
onClick={() => vscode.postMessage({ type: "rooCloudSignIn" })}
className="w-fit">
{t("settings:providers.roo.connectButton")}
</VSCodeButton>
</div>
)}
</div>
)}
{selectedProviderModels.length > 0 && (
<>
<div>

View file

@ -34,7 +34,7 @@ export const ModelDescriptionMarkdown = memo(
return (
<Collapsible open={isExpanded} onOpenChange={setIsExpanded} className="relative">
<div ref={textContainerRef} className={cn({ "line-clamp-3": !isExpanded })}>
<div ref={textContainerRef} className={cn({ "line-clamp-4": !isExpanded })}>
<div ref={textRef}>
<StyledMarkdown key={key}>{content}</StyledMarkdown>
</div>

View file

@ -26,6 +26,18 @@ export const ModelInfoView = ({
const { t } = useAppTranslation()
const infoItems = [
typeof modelInfo?.contextWindow === "number" && modelInfo.contextWindow > 0 && (
<>
<span className="font-medium">{t("settings:modelInfo.contextWindow")}</span>{" "}
{modelInfo.contextWindow?.toLocaleString()} tokens
</>
),
typeof modelInfo?.maxTokens === "number" && modelInfo.maxTokens > 0 && (
<>
<span className="font-medium">{t("settings:modelInfo.maxOutput")}:</span>{" "}
{modelInfo.maxTokens?.toLocaleString()} tokens
</>
),
<ModelInfoSupportsItem
isSupported={modelInfo?.supportsImages ?? false}
supportsLabel={t("settings:modelInfo.supportsImages")}
@ -41,18 +53,6 @@ export const ModelInfoView = ({
supportsLabel={t("settings:modelInfo.supportsPromptCache")}
doesNotSupportLabel={t("settings:modelInfo.noPromptCache")}
/>,
typeof modelInfo?.contextWindow === "number" && modelInfo.contextWindow > 0 && (
<>
<span className="font-medium">{t("settings:modelInfo.contextWindow")}</span>{" "}
{modelInfo.contextWindow?.toLocaleString()} tokens
</>
),
typeof modelInfo?.maxTokens === "number" && modelInfo.maxTokens > 0 && (
<>
<span className="font-medium">{t("settings:modelInfo.maxOutput")}:</span>{" "}
{modelInfo.maxTokens?.toLocaleString()} tokens
</>
),
modelInfo?.inputPrice !== undefined && modelInfo.inputPrice > 0 && (
<>
<span className="font-medium">{t("settings:modelInfo.inputPrice")}:</span>{" "}
@ -119,11 +119,7 @@ const ModelInfoSupportsItem = ({
supportsLabel: string
doesNotSupportLabel: string
}) => (
<div
className={cn(
"flex items-center gap-1 font-medium",
isSupported ? "text-vscode-charts-green" : "text-vscode-errorForeground",
)}>
<div className="flex items-center gap-1 font-medium">
<span className={cn("codicon", isSupported ? "codicon-check" : "codicon-x")} />
{isSupported ? supportsLabel : doesNotSupportLabel}
</div>

View file

@ -18,6 +18,7 @@ import {
doubaoModels,
internationalZAiModels,
fireworksModels,
rooModels,
} from "@roo-code/types"
export const MODELS_BY_PROVIDER: Partial<Record<ProviderName, Record<string, ModelInfo>>> = {
@ -38,6 +39,7 @@ export const MODELS_BY_PROVIDER: Partial<Record<ProviderName, Record<string, Mod
sambanova: sambaNovaModels,
zai: internationalZAiModels,
fireworks: fireworksModels,
roo: rooModels,
}
export const PROVIDERS = [
@ -70,4 +72,5 @@ export const PROVIDERS = [
{ value: "zai", label: "Z AI" },
{ value: "fireworks", label: "Fireworks AI" },
{ value: "io-intelligence", label: "IO Intelligence" },
{ value: "roo", label: "Roo Code Cloud" },
].sort((a, b) => a.label.localeCompare(b.label))

View file

@ -48,6 +48,8 @@ import {
fireworksDefaultModelId,
ioIntelligenceDefaultModelId,
ioIntelligenceModels,
rooDefaultModelId,
rooModels,
BEDROCK_CLAUDE_SONNET_4_MODEL_ID,
} from "@roo-code/types"
@ -296,6 +298,11 @@ function getSelectedModel({
routerModels["io-intelligence"]?.[id] ?? ioIntelligenceModels[id as keyof typeof ioIntelligenceModels]
return { id, info }
}
case "roo": {
const id = apiConfiguration.apiModelId ?? rooDefaultModelId
const info = rooModels[id as keyof typeof rooModels]
return { id, info }
}
// case "anthropic":
// case "human-relay":
// case "fake-ai":

View file

@ -349,9 +349,9 @@
"ariaLabel": "Versió {{version}} - Feu clic per veure les notes de llançament"
},
"rooCloudCTA": {
"title": "Roo Code Cloud arribarà aviat!",
"title": "Roo Code Cloud està evolucionant!",
"description": "Executa agents remots al núvol, accedeix a les teves tasques des de qualsevol lloc, col·labora amb altres i molt més.",
"joinWaitlist": "Uneix-te a la llista d'espera per obtenir accés anticipat."
"joinWaitlist": "Registra't per rebre les últimes actualitzacions."
},
"editMessage": {
"placeholder": "Edita el teu missatge..."

View file

@ -377,6 +377,10 @@
"description": "No es requereix clau API, però l'usuari necessita ajuda per copiar i enganxar informació al xat d'IA web.",
"instructions": "Durant l'ús, apareixerà un diàleg i el missatge actual es copiarà automàticament al porta-retalls. Necessiteu enganxar-lo a les versions web d'IA (com ChatGPT o Claude), després copiar la resposta de l'IA de nou al diàleg i fer clic al botó de confirmació."
},
"roo": {
"authenticatedMessage": "Autenticat de forma segura a través del teu compte de Roo Code Cloud.",
"connectButton": "Connecta amb Roo Code Cloud"
},
"openRouter": {
"providerRouting": {
"title": "Encaminament de Proveïdors d'OpenRouter",

View file

@ -349,9 +349,9 @@
"ariaLabel": "Version {{version}} - Klicken Sie, um die Versionshinweise anzuzeigen"
},
"rooCloudCTA": {
"title": "Roo Code Cloud kommt bald!",
"title": "Roo Code Cloud entwickelt sich weiter!",
"description": "Führe Remote-Agenten in der Cloud aus, greife von überall auf deine Aufgaben zu, arbeite mit anderen zusammen und vieles mehr.",
"joinWaitlist": "Tritt der Warteliste bei, um frühen Zugang zu erhalten."
"joinWaitlist": "Melde dich an, um die neuesten Updates zu erhalten."
},
"command": {
"triggerDescription": "Starte den {{name}} Befehl"

View file

@ -377,6 +377,10 @@
"description": "Es ist kein API-Schlüssel erforderlich, aber der Benutzer muss beim Kopieren und Einfügen der Informationen in den Web-Chat-KI helfen.",
"instructions": "Während der Verwendung wird ein Dialogfeld angezeigt und die aktuelle Nachricht wird automatisch in die Zwischenablage kopiert. Du musst diese in Web-Versionen von KI (wie ChatGPT oder Claude) einfügen, dann die Antwort der KI zurück in das Dialogfeld kopieren und auf die Bestätigungsschaltfläche klicken."
},
"roo": {
"authenticatedMessage": "Sicher authentifiziert über dein Roo Code Cloud-Konto.",
"connectButton": "Mit Roo Code Cloud verbinden"
},
"openRouter": {
"providerRouting": {
"title": "OpenRouter Anbieter-Routing",

View file

@ -352,9 +352,9 @@
"ariaLabel": "Version {{version}} - Click to view release notes"
},
"rooCloudCTA": {
"title": "Roo Code Cloud is coming soon!",
"title": "Roo Code Cloud is evolving!",
"description": "Run Roomote agents in the cloud, access your tasks from anywhere, collaborate with others, and more.",
"joinWaitlist": "Join the waitlist to get early access."
"joinWaitlist": "Sign up to get the latest updates."
},
"command": {
"triggerDescription": "Trigger the {{name}} command"

View file

@ -376,6 +376,10 @@
"description": "No API key is required, but the user needs to help copy and paste the information to the web chat AI.",
"instructions": "During use, a dialog box will pop up and the current message will be copied to the clipboard automatically. You need to paste these to web versions of AI (such as ChatGPT or Claude), then copy the AI's reply back to the dialog box and click the confirm button."
},
"roo": {
"authenticatedMessage": "Securely authenticated through your Roo Code Cloud account.",
"connectButton": "Connect to Roo Code Cloud"
},
"openRouter": {
"providerRouting": {
"title": "OpenRouter Provider Routing",

View file

@ -349,9 +349,9 @@
"ariaLabel": "Versión {{version}} - Haz clic para ver las notas de la versión"
},
"rooCloudCTA": {
"title": "¡Roo Code Cloud llegará pronto!",
"title": "¡Roo Code Cloud está evolucionando!",
"description": "Ejecuta agentes remotos en la nube, accede a tus tareas desde cualquier lugar, colabora con otros y mucho más.",
"joinWaitlist": "Únete a la lista de espera para obtener acceso anticipado."
"joinWaitlist": "Regístrate para recibir las últimas actualizaciones."
},
"editMessage": {
"placeholder": "Edita tu mensaje..."

View file

@ -377,6 +377,10 @@
"description": "No se requiere clave API, pero el usuario necesita ayudar a copiar y pegar la información en el chat web de IA.",
"instructions": "Durante el uso, aparecerá un cuadro de diálogo y el mensaje actual se copiará automáticamente al portapapeles. Debe pegarlo en las versiones web de IA (como ChatGPT o Claude), luego copiar la respuesta de la IA de vuelta al cuadro de diálogo y hacer clic en el botón de confirmar."
},
"roo": {
"authenticatedMessage": "Autenticado de forma segura a través de tu cuenta de Roo Code Cloud.",
"connectButton": "Conectar a Roo Code Cloud"
},
"openRouter": {
"providerRouting": {
"title": "Enrutamiento de Proveedores de OpenRouter",

View file

@ -349,9 +349,9 @@
"ariaLabel": "Version {{version}} - Cliquez pour voir les notes de version"
},
"rooCloudCTA": {
"title": "Roo Code Cloud arrive bientôt !",
"title": "Roo Code Cloud évolue !",
"description": "Exécutez des agents distants dans le cloud, accédez à vos tâches de n'importe où, collaborez avec d'autres et bien plus encore.",
"joinWaitlist": "Rejoignez la liste d'attente pour obtenir un accès anticipé."
"joinWaitlist": "Inscrivez-vous pour recevoir les dernières mises à jour."
},
"editMessage": {
"placeholder": "Modifiez votre message..."

View file

@ -377,6 +377,10 @@
"description": "Aucune clé API n'est requise, mais l'utilisateur doit aider à copier et coller les informations dans le chat web de l'IA.",
"instructions": "Pendant l'utilisation, une boîte de dialogue apparaîtra et le message actuel sera automatiquement copié dans le presse-papiers. Vous devez le coller dans les versions web de l'IA (comme ChatGPT ou Claude), puis copier la réponse de l'IA dans la boîte de dialogue et cliquer sur le bouton de confirmation."
},
"roo": {
"authenticatedMessage": "Authentifié de manière sécurisée via ton compte Roo Code Cloud.",
"connectButton": "Se connecter à Roo Code Cloud"
},
"openRouter": {
"providerRouting": {
"title": "Routage des fournisseurs OpenRouter",

View file

@ -349,9 +349,9 @@
"ariaLabel": "संस्करण {{version}} - रिलीज़ नोट्स देखने के लिए क्लिक करें"
},
"rooCloudCTA": {
"title": "Roo Code Cloud जल्द आ रहा है!",
"title": "Roo Code Cloud विकसित हो रहा है!",
"description": "क्लाउड में रिमोट एजेंट चलाएं, कहीं से भी अपने कार्यों तक पहुंचें, दूसरों के साथ सहयोग करें, और बहुत कुछ।",
"joinWaitlist": "जल्दी पहुंच पाने के लिए प्रतीक्षा सूची में शामिल हों।"
"joinWaitlist": "नवीनतम अपडेट प्राप्त करने के लिए साइन अप करें।"
},
"editMessage": {
"placeholder": "अपना संदेश संपादित करें..."

View file

@ -377,6 +377,10 @@
"description": "कोई API कुंजी आवश्यक नहीं है, लेकिन उपयोगकर्ता को वेब चैट AI में जानकारी कॉपी और पेस्ट करने में मदद करनी होगी।",
"instructions": "उपयोग के दौरान, एक डायलॉग बॉक्स पॉप अप होगा और वर्तमान संदेश स्वचालित रूप से क्लिपबोर्ड पर कॉपी हो जाएगा। आपको इन्हें AI के वेब संस्करणों (जैसे ChatGPT या Claude) में पेस्ट करना होगा, फिर AI की प्रतिक्रिया को डायलॉग बॉक्स में वापस कॉपी करें और पुष्टि बटन पर क्लिक करें।"
},
"roo": {
"authenticatedMessage": "आपके Roo Code Cloud खाते के माध्यम से सुरक्षित रूप से प्रमाणित।",
"connectButton": "Roo Code Cloud से कनेक्ट करें"
},
"openRouter": {
"providerRouting": {
"title": "OpenRouter प्रदाता रूटिंग",

View file

@ -355,9 +355,9 @@
"ariaLabel": "Versi {{version}} - Klik untuk melihat catatan rilis"
},
"rooCloudCTA": {
"title": "Roo Code Cloud segera hadir!",
"title": "Roo Code Cloud sedang berkembang!",
"description": "Jalankan agen jarak jauh di cloud, akses tugas Anda dari mana saja, berkolaborasi dengan orang lain, dan banyak lagi.",
"joinWaitlist": "Bergabunglah dengan daftar tunggu untuk mendapatkan akses awal."
"joinWaitlist": "Daftar untuk mendapatkan pembaruan terbaru."
},
"editMessage": {
"placeholder": "Edit pesan Anda..."

View file

@ -381,6 +381,10 @@
"description": "Tidak diperlukan API key, tetapi pengguna perlu membantu menyalin dan menempel informasi ke web chat AI.",
"instructions": "Selama penggunaan, kotak dialog akan muncul dan pesan saat ini akan disalin ke clipboard secara otomatis. Kamu perlu menempel ini ke versi web AI (seperti ChatGPT atau Claude), lalu salin balasan AI kembali ke kotak dialog dan klik tombol konfirmasi."
},
"roo": {
"authenticatedMessage": "Terautentikasi dengan aman melalui akun Roo Code Cloud Anda.",
"connectButton": "Hubungkan ke Roo Code Cloud"
},
"openRouter": {
"providerRouting": {
"title": "OpenRouter Provider Routing",

View file

@ -349,9 +349,9 @@
"ariaLabel": "Versione {{version}} - Clicca per visualizzare le note di rilascio"
},
"rooCloudCTA": {
"title": "Roo Code Cloud arriva presto!",
"title": "Roo Code Cloud si sta evolvendo!",
"description": "Esegui agenti remoti nel cloud, accedi alle tue attività da qualsiasi luogo, collabora con altri e molto altro.",
"joinWaitlist": "Unisciti alla lista d'attesa per ottenere l'accesso anticipato."
"joinWaitlist": "Registrati per ricevere gli ultimi aggiornamenti."
},
"editMessage": {
"placeholder": "Modifica il tuo messaggio..."

View file

@ -377,6 +377,10 @@
"description": "Non è richiesta alcuna chiave API, ma l'utente dovrà aiutare a copiare e incollare le informazioni nella chat web AI.",
"instructions": "Durante l'uso, apparirà una finestra di dialogo e il messaggio corrente verrà automaticamente copiato negli appunti. Dovrai incollarlo nelle versioni web dell'AI (come ChatGPT o Claude), quindi copiare la risposta dell'AI nella finestra di dialogo e fare clic sul pulsante di conferma."
},
"roo": {
"authenticatedMessage": "Autenticato in modo sicuro tramite il tuo account Roo Code Cloud.",
"connectButton": "Connetti a Roo Code Cloud"
},
"openRouter": {
"providerRouting": {
"title": "Routing dei fornitori OpenRouter",

View file

@ -349,9 +349,9 @@
"ariaLabel": "バージョン {{version}} - クリックしてリリースノートを表示"
},
"rooCloudCTA": {
"title": "Roo Code Cloud が間もなく登場",
"title": "Roo Code Cloud が進化中",
"description": "クラウドでリモートエージェントを実行し、どこからでもタスクにアクセスし、他の人と協力し、その他多くの機能を利用できます。",
"joinWaitlist": "早期アクセスを取得するためにウェイトリストに参加してください。"
"joinWaitlist": "最新のアップデートを受け取るためにサインアップしてください。"
},
"editMessage": {
"placeholder": "メッセージを編集..."

View file

@ -377,6 +377,10 @@
"description": "APIキーは不要ですが、ユーザーはウェブチャットAIに情報をコピーペーストする必要があります。",
"instructions": "使用中にダイアログボックスが表示され、現在のメッセージが自動的にクリップボードにコピーされます。これらをウェブ版のAIChatGPTやClaudeなどに貼り付け、AIの返答をダイアログボックスにコピーして確認ボタンをクリックする必要があります。"
},
"roo": {
"authenticatedMessage": "Roo Code Cloudアカウントを通じて安全に認証されています。",
"connectButton": "Roo Code Cloudに接続"
},
"openRouter": {
"providerRouting": {
"title": "OpenRouterプロバイダールーティング",

View file

@ -349,9 +349,9 @@
"ariaLabel": "버전 {{version}} - 릴리스 노트를 보려면 클릭하세요"
},
"rooCloudCTA": {
"title": "Roo Code Cloud가 곧 출시됩니다!",
"title": "Roo Code Cloud가 진화하고 있습니다!",
"description": "클라우드에서 원격 에이전트를 실행하고, 어디서나 작업에 액세스하고, 다른 사람들과 협업하는 등 다양한 기능을 이용하세요.",
"joinWaitlist": "얼리 액세스를 받으려면 대기 목록에 가입하세요."
"joinWaitlist": "최신 업데이트를 받으려면 가입하세요."
},
"editMessage": {
"placeholder": "메시지 편집..."

View file

@ -377,6 +377,10 @@
"description": "API 키가 필요하지 않지만, 사용자가 웹 채팅 AI에 정보를 복사하여 붙여넣어야 합니다.",
"instructions": "사용 중에 대화 상자가 나타나고 현재 메시지가 자동으로 클립보드에 복사됩니다. 이를 웹 버전 AI(예: ChatGPT 또는 Claude)에 붙여넣은 다음, AI의 응답을 대화 상자에 복사하고 확인 버튼을 클릭해야 합니다."
},
"roo": {
"authenticatedMessage": "Roo Code Cloud 계정을 통해 안전하게 인증되었습니다.",
"connectButton": "Roo Code Cloud에 연결"
},
"openRouter": {
"providerRouting": {
"title": "OpenRouter 제공자 라우팅",

View file

@ -349,9 +349,9 @@
"ariaLabel": "Versie {{version}} - Klik om release notes te bekijken"
},
"rooCloudCTA": {
"title": "Roo Code Cloud komt binnenkort!",
"title": "Roo Code Cloud evolueert!",
"description": "Voer externe agenten uit in de cloud, krijg overal toegang tot je taken, werk samen met anderen en nog veel meer.",
"joinWaitlist": "Sluit je aan bij de wachtlijst voor vroege toegang."
"joinWaitlist": "Meld je aan om de laatste updates te ontvangen."
},
"editMessage": {
"placeholder": "Bewerk je bericht..."

View file

@ -377,6 +377,10 @@
"description": "Geen API-sleutel vereist, maar de gebruiker moet helpen met kopiëren en plakken naar de webchat-AI.",
"instructions": "Tijdens gebruik verschijnt een dialoogvenster en wordt het huidige bericht automatisch naar het klembord gekopieerd. Je moet deze plakken in webversies van AI (zoals ChatGPT of Claude), vervolgens het antwoord van de AI terugkopiëren naar het dialoogvenster en op bevestigen klikken."
},
"roo": {
"authenticatedMessage": "Veilig geauthenticeerd via je Roo Code Cloud-account.",
"connectButton": "Verbinden met Roo Code Cloud"
},
"openRouter": {
"providerRouting": {
"title": "OpenRouter-providerroutering",

View file

@ -349,9 +349,9 @@
"ariaLabel": "Wersja {{version}} - Kliknij, aby wyświetlić informacje o wydaniu"
},
"rooCloudCTA": {
"title": "Roo Code Cloud już wkrótce!",
"title": "Roo Code Cloud się rozwija!",
"description": "Uruchamiaj zdalne agenty w chmurze, uzyskuj dostęp do swoich zadań z dowolnego miejsca, współpracuj z innymi i wiele więcej.",
"joinWaitlist": "Dołącz do listy oczekujących, aby uzyskać wczesny dostęp."
"joinWaitlist": "Zarejestruj się, aby otrzymywać najnowsze aktualizacje."
},
"editMessage": {
"placeholder": "Edytuj swoją wiadomość..."

View file

@ -377,6 +377,10 @@
"description": "Nie jest wymagany klucz API, ale użytkownik będzie musiał pomóc w kopiowaniu i wklejaniu informacji do czatu internetowego AI.",
"instructions": "Podczas użytkowania pojawi się okno dialogowe, a bieżąca wiadomość zostanie automatycznie skopiowana do schowka. Będziesz musiał wkleić ją do internetowych wersji AI (takich jak ChatGPT lub Claude), a następnie skopiować odpowiedź AI z powrotem do okna dialogowego i kliknąć przycisk potwierdzenia."
},
"roo": {
"authenticatedMessage": "Bezpiecznie uwierzytelniony przez twoje konto Roo Code Cloud.",
"connectButton": "Połącz z Roo Code Cloud"
},
"openRouter": {
"providerRouting": {
"title": "Routing dostawców OpenRouter",

View file

@ -349,9 +349,9 @@
"ariaLabel": "Versão {{version}} - Clique para ver as notas de lançamento"
},
"rooCloudCTA": {
"title": "Roo Code Cloud chegará em breve!",
"title": "Roo Code Cloud está evoluindo!",
"description": "Execute agentes remotos na nuvem, acesse suas tarefas de qualquer lugar, colabore com outros e muito mais.",
"joinWaitlist": "Junte-se à lista de espera para obter acesso antecipado."
"joinWaitlist": "Cadastre-se para receber as últimas atualizações."
},
"editMessage": {
"placeholder": "Edite sua mensagem..."

View file

@ -377,6 +377,10 @@
"description": "Não é necessária chave de API, mas o usuário precisa ajudar a copiar e colar as informações para a IA do chat web.",
"instructions": "Durante o uso, uma caixa de diálogo será exibida e a mensagem atual será copiada para a área de transferência automaticamente. Você precisa colar isso nas versões web de IA (como ChatGPT ou Claude), depois copiar a resposta da IA de volta para a caixa de diálogo e clicar no botão confirmar."
},
"roo": {
"authenticatedMessage": "Autenticado com segurança através da sua conta Roo Code Cloud.",
"connectButton": "Conectar ao Roo Code Cloud"
},
"openRouter": {
"providerRouting": {
"title": "Roteamento de Provedores OpenRouter",

View file

@ -349,9 +349,9 @@
"ariaLabel": "Версия {{version}} - Нажмите, чтобы просмотреть примечания к выпуску"
},
"rooCloudCTA": {
"title": "Roo Code Cloud скоро появится!",
"title": "Roo Code Cloud развивается!",
"description": "Запускайте удаленные агенты в облаке, получайте доступ к своим задачам из любого места, сотрудничайте с другими и многое другое.",
"joinWaitlist": "Присоединитесь к списку ожидания для получения раннего доступа."
"joinWaitlist": "Зарегистрируйтесь, чтобы получать последние обновления."
},
"editMessage": {
"placeholder": "Редактировать сообщение..."

View file

@ -377,6 +377,10 @@
"description": "API-ключ не требуется, но пользователю нужно вручную копировать и вставлять информацию в веб-чат ИИ.",
"instructions": "Во время использования появится диалоговое окно, и текущее сообщение будет скопировано в буфер обмена автоматически. Вам нужно вставить его в веб-версию ИИ (например, ChatGPT или Claude), затем скопировать ответ ИИ обратно в диалоговое окно и нажать кнопку подтверждения."
},
"roo": {
"authenticatedMessage": "Безопасно аутентифицирован через твой аккаунт Roo Code Cloud.",
"connectButton": "Подключиться к Roo Code Cloud"
},
"openRouter": {
"providerRouting": {
"title": "Маршрутизация провайдера OpenRouter",

View file

@ -349,9 +349,9 @@
"ariaLabel": "Sürüm {{version}} - Sürüm notlarını görüntülemek için tıklayın"
},
"rooCloudCTA": {
"title": "Roo Code Cloud yakında geliyor!",
"title": "Roo Code Cloud gelişiyor!",
"description": "Bulutta uzak ajanlar çalıştırın, görevlerinize her yerden erişin, başkalarıyla işbirliği yapın ve daha fazlası.",
"joinWaitlist": "Erken erişim için bekleme listesine katılın."
"joinWaitlist": "En son güncellemeleri almak için kaydolun."
},
"editMessage": {
"placeholder": "Mesajını düzenle..."

View file

@ -377,6 +377,10 @@
"description": "API anahtarı gerekmez, ancak kullanıcının bilgileri web sohbet yapay zekasına kopyalayıp yapıştırması gerekir.",
"instructions": "Kullanım sırasında bir iletişim kutusu açılacak ve mevcut mesaj otomatik olarak panoya kopyalanacaktır. Bunları web yapay zekalarına (ChatGPT veya Claude gibi) yapıştırmanız, ardından yapay zekanın yanıtını iletişim kutusuna kopyalayıp onay düğmesine tıklamanız gerekir."
},
"roo": {
"authenticatedMessage": "Roo Code Cloud hesabın üzerinden güvenli bir şekilde kimlik doğrulandı.",
"connectButton": "Roo Code Cloud'a Bağlan"
},
"openRouter": {
"providerRouting": {
"title": "OpenRouter Sağlayıcı Yönlendirmesi",

View file

@ -349,9 +349,9 @@
"ariaLabel": "Phiên bản {{version}} - Nhấp để xem ghi chú phát hành"
},
"rooCloudCTA": {
"title": "Roo Code Cloud sắp ra mắt!",
"title": "Roo Code Cloud đang phát triển!",
"description": "Chạy các agent từ xa trên cloud, truy cập các tác vụ của bạn từ mọi nơi, cộng tác với người khác và nhiều hơn nữa.",
"joinWaitlist": "Tham gia danh sách chờ để được truy cập sớm."
"joinWaitlist": "Đăng ký để nhận các cập nhật mới nhất."
},
"editMessage": {
"placeholder": "Chỉnh sửa tin nhắn của bạn..."

View file

@ -377,6 +377,10 @@
"description": "Không cần khóa API, nhưng người dùng cần giúp sao chép và dán thông tin vào AI trò chuyện web.",
"instructions": "Trong quá trình sử dụng, một hộp thoại sẽ xuất hiện và tin nhắn hiện tại sẽ được tự động sao chép vào clipboard. Bạn cần dán chúng vào các phiên bản web của AI (như ChatGPT hoặc Claude), sau đó sao chép phản hồi của AI trở lại hộp thoại và nhấp vào nút xác nhận."
},
"roo": {
"authenticatedMessage": "Đã xác thực an toàn thông qua tài khoản Roo Code Cloud của bạn.",
"connectButton": "Kết nối với Roo Code Cloud"
},
"openRouter": {
"providerRouting": {
"title": "Định tuyến nhà cung cấp OpenRouter",

View file

@ -349,9 +349,9 @@
"ariaLabel": "版本 {{version}} - 点击查看发布说明"
},
"rooCloudCTA": {
"title": "Roo Code Cloud 即将推出",
"title": "Roo Code Cloud 正在进化",
"description": "在云端运行远程代理,随时随地访问任务,与他人协作等更多功能。",
"joinWaitlist": "加入等待列表获取早期访问权限。"
"joinWaitlist": "注册获取最新更新。"
},
"command": {
"triggerDescription": "触发 {{name}} 命令"

View file

@ -377,6 +377,10 @@
"description": "不需要 API 密钥,但用户需要帮助将信息复制并粘贴到网页聊天 AI。",
"instructions": "使用期间,将弹出对话框并自动将当前消息复制到剪贴板。您需要将这些内容粘贴到 AI 的网页版本(如 ChatGPT 或 Claude然后将 AI 的回复复制回对话框并点击确认按钮。"
},
"roo": {
"authenticatedMessage": "已通过 Roo Code Cloud 账户安全认证。",
"connectButton": "连接到 Roo Code Cloud"
},
"openRouter": {
"providerRouting": {
"title": "OpenRouter 提供商路由",

View file

@ -352,9 +352,9 @@
"ariaLabel": "版本 {{version}} - 點選查看發布說明"
},
"rooCloudCTA": {
"title": "Roo Code Cloud 即將推出",
"title": "Roo Code Cloud 正在進化",
"description": "在雲端執行 Roomote 遠端代理、隨時隨地存取您的工作、與他人協作等等。",
"joinWaitlist": "加入等候名單以獲得早期存取權限。"
"joinWaitlist": "註冊以獲得最新更新。"
},
"command": {
"triggerDescription": "觸發 {{name}} 命令"

View file

@ -377,6 +377,10 @@
"description": "不需要 API 金鑰,但使用者需要協助將資訊複製並貼上到網頁聊天 AI。",
"instructions": "使用期間會彈出對話框,並自動將目前訊息複製到剪貼簿。您需要將這些內容貼上到網頁版 AI如 ChatGPT 或 Claude然後將 AI 的回覆複製回對話框並點選確認按鈕。"
},
"roo": {
"authenticatedMessage": "已透過 Roo Code Cloud 帳戶安全認證。",
"connectButton": "連接到 Roo Code Cloud"
},
"openRouter": {
"providerRouting": {
"title": "OpenRouter 供應商路由",