- Supercharge your software development with AI that{" "}
-
+ Simple, transparent pricing that scales with your needs.
+
+ Free 14-day trials to kick the tires.
+
+ The Roo Code extension is free! + Roo Code Cloud is an optional service which takes it to the next level. +
+{tier.description}
++ {tier.featuresIntro} +
++ {tier.price} + {tier.period} +
++ {tier.trial} + {tier.cancellation} +
+ + {tier.cta.isContactForm ? ( +Got questions about our pricing?
++ Yes! The Roo Code VS Code extension is open source and free forever. The extension acts + as a powerful AI coding assistant right in your editor. These are the prices for Roo + Code Cloud. +
++ Yes, all paid plans come with a 14-day free trial. +
++ Yes, but you won't be charged until your trial ends. You can cancel anytime with + one click . +
++ We accept all major credit cards, debit cards, and can arrange invoice billing for + Enterprise customers. +
++ Yes, you can upgrade or downgrade your plan at any time. Changes will be reflected in + your next billing cycle. +
++ Still have questions?{" "} + + Join our Discord + {" "} + or{" "} + + contact our sales team + +
+Code from anywhere.
+Last Updated: August 20, 2025
+Last Updated: September 19, 2025
This Privacy Policy explains how Roo Code, Inc. ("Roo Code," "we," @@ -86,8 +86,8 @@ export default function Privacy() { Your source code does not transit Roo Code servers unless you explicitly choose Roo Code as a model provider (proxy mode). {" "} - When Roo Code Cloud is your model provider, your code briefly transits Roo Code servers only to - forward it to the upstream model, is not stored, and is deleted immediately after + When Roo Code Cloud is your model provider, your code briefly transits Roo Code servers only + to forward it to the upstream model, is not stored, and is deleted immediately after forwarding. Otherwise, your code is sent directly—via client‑to‑provider TLS—to the model you select. Roo Code never stores, inspects, or trains on your code. @@ -184,6 +184,13 @@ export default function Privacy() {
{feature.description}
-,
- title: "Multiple Specialized Modes",
- description:
- "From coding to debugging to architecture, Roo Code has a mode for every dev scenario—just switch on the fly.",
+ icon: ReplaceAll,
+ title: "Model-Agnostic",
+ description: "Bring your own model key or use local inference — no markup, lock-in, no restrictions.",
},
{
- icon: - Everything you need to build faster and write better code. + The features you need to build, debug and ship faster – without compromising quality.
{feature.description}
-+ {feature.description} +
+
- Roo Code is open-source, model-agnostic, and developer-focused. Install from the VS Code
- Marketplace or the CLI in minutes, then bring your own AI model.
+ Install from the VSCode Marketplace or the CLI in minutes, then bring your own AI model.
+
+ Roo Code is also compatible with all VSCode forks.
diff --git a/apps/web-roo-code/src/components/homepage/testimonials-mobile.tsx b/apps/web-roo-code/src/components/homepage/testimonials-mobile.tsx
deleted file mode 100644
index 8b90d27b5a..0000000000
--- a/apps/web-roo-code/src/components/homepage/testimonials-mobile.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-import useEmblaCarousel from "embla-carousel-react"
-import AutoScroll from "embla-carousel-auto-scroll"
-import { testimonials } from "@/components/homepage/testimonials"
-
-export function TestimonialsMobile() {
- const [emblaRef] = useEmblaCarousel({ loop: true }, [
- AutoScroll({
- playOnInit: true,
- speed: 1, // pixels per second - slower for smoother scrolling
- stopOnInteraction: true,
- stopOnMouseEnter: true,
- }),
- ])
-
- return (
-
-
-
- {testimonials.map((testimonial) => (
-
-
-
-
-
-
- "{testimonial.quote}"
-
-
-
-
-
-
- ))}
-
-
-
- )
-}
diff --git a/apps/web-roo-code/src/components/homepage/testimonials.tsx b/apps/web-roo-code/src/components/homepage/testimonials.tsx
index 4df5849d46..01236dfe7e 100644
--- a/apps/web-roo-code/src/components/homepage/testimonials.tsx
+++ b/apps/web-roo-code/src/components/homepage/testimonials.tsx
@@ -1,9 +1,10 @@
"use client"
-import { useRef } from "react"
+import { useRef, useCallback, useEffect } from "react"
import { motion } from "framer-motion"
-import Image from "next/image"
-import { TestimonialsMobile } from "./testimonials-mobile"
+import useEmblaCarousel from "embla-carousel-react"
+import AutoPlay from "embla-carousel-autoplay"
+import { ChevronLeft, ChevronRight } from "lucide-react"
export interface Testimonial {
id: number
@@ -47,26 +48,66 @@ export const testimonials: Testimonial[] = [
export function Testimonials() {
const containerRef = useRef(null)
+ const [emblaRef, emblaApi] = useEmblaCarousel(
+ {
+ loop: true,
+ align: "center",
+ skipSnaps: false,
+ containScroll: false,
+ },
+ [
+ AutoPlay({
+ playOnInit: true,
+ delay: 4000,
+ stopOnInteraction: true,
+ stopOnMouseEnter: true,
+ stopOnFocusIn: true,
+ }),
+ ],
+ )
+
+ const scrollPrev = useCallback(() => {
+ if (emblaApi) emblaApi.scrollPrev()
+ }, [emblaApi])
+
+ const scrollNext = useCallback(() => {
+ if (emblaApi) emblaApi.scrollNext()
+ }, [emblaApi])
+
+ // Re-init auto-play on user interaction
+ useEffect(() => {
+ if (!emblaApi) return
+
+ const autoPlay = emblaApi?.plugins()?.autoPlay as
+ | {
+ isPlaying?: () => boolean
+ play?: () => void
+ }
+ | undefined
+ if (!autoPlay) return
+
+ const handleInteraction = () => {
+ const isPlaying = autoPlay.isPlaying && autoPlay.isPlaying()
+ if (!isPlaying) {
+ setTimeout(() => {
+ if (autoPlay.play) {
+ autoPlay.play()
+ }
+ }, 2000)
+ }
+ }
+
+ emblaApi.on("pointerUp", handleInteraction)
+
+ return () => {
+ emblaApi.off("pointerUp", handleInteraction)
+ }
+ }, [emblaApi])
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
- transition: {
- staggerChildren: 0.15,
- delayChildren: 0.3,
- },
- },
- }
-
- const itemVariants = {
- hidden: {
- opacity: 0,
- y: 20,
- },
- visible: {
- opacity: 1,
- y: 0,
transition: {
duration: 0.6,
ease: [0.21, 0.45, 0.27, 0.9],
@@ -74,123 +115,78 @@ export function Testimonials() {
},
}
- const backgroundVariants = {
- hidden: {
- opacity: 0,
- },
- visible: {
- opacity: 1,
- transition: {
- duration: 1.2,
- ease: "easeOut",
- },
- },
- }
-
return (
-
-
-
-
-
+
+
+
+
-
-
-
- Empowering developers worldwide.
-
-
- Join thousands of developers who are revolutionizing their workflow with AI-powered
- assistance.
-
-
+
+
+ AI-forward developers are using Roo Code
+
+
+ Join more than 800k people revolutionizing their workflow worldwide
+
- {/* Mobile Carousel */}
-
-
- {/* Desktop Grid */}
-
- {testimonials.map((testimonial, index) => (
-
-
-
- {testimonial.image && (
-
-
-
+ {/* Previous Button */}
+
+
+ {/* Next Button */}
+
+
+ {/* Gradient Overlays */}
+
+
+
+ {/* Embla Carousel Container */}
+
+
+ {testimonials.map((testimonial) => (
+
+
+
+
+
+
+ {testimonial.quote}
+
+
+
+
+
+ {testimonial.name}
+
+
+ {testimonial.role} at {testimonial.company}
+
+
- )}
-
-
-
-
-
-
-
-
- {testimonial.quote}
-
-
-
-
-
-
- {testimonial.name}
-
-
- {testimonial.role} at {testimonial.company}
-
-
-
- ))}
+ ))}
+
diff --git a/apps/web-roo-code/src/lib/constants.ts b/apps/web-roo-code/src/lib/constants.ts
index 3b9798926c..c474481805 100644
--- a/apps/web-roo-code/src/lib/constants.ts
+++ b/apps/web-roo-code/src/lib/constants.ts
@@ -24,7 +24,8 @@ export const EXTERNAL_LINKS = {
OFFICE_HOURS_PODCAST: "https://www.youtube.com/@RooCodeYT/podcasts",
FAQ: "https://roocode.com/#faq",
TESTIMONIALS: "https://roocode.com/#testimonials",
- CLOUD_APP: "https://app.roocode.com",
+ CLOUD_APP_LOGIN: "https://app.roocode.com/sign-in",
+ CLOUD_APP_SIGNUP: "https://app.roocode.com/sign-up",
}
export const INTERNAL_LINKS = {
diff --git a/apps/web-roo-code/src/lib/seo.ts b/apps/web-roo-code/src/lib/seo.ts
index 962662bb22..7dfad0550a 100644
--- a/apps/web-roo-code/src/lib/seo.ts
+++ b/apps/web-roo-code/src/lib/seo.ts
@@ -3,15 +3,15 @@ const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://roocode.com"
export const SEO = {
url: SITE_URL,
name: "Roo Code",
- title: "Roo Code – Your AI-Powered Dev Team in VS Code",
+ title: "Roo Code – Your AI-Powered Dev Team in VS Code and Beyond",
description:
"Roo Code puts an entire AI dev team right in your editor, outpacing closed tools with deep project-wide context, multi-step agentic coding, and unmatched developer-centric flexibility.",
locale: "en_US",
ogImage: {
- url: "/android-chrome-512x512.png",
- width: 512,
- height: 512,
- alt: "Roo Code Logo",
+ url: "/opengraph.png",
+ width: 1200,
+ height: 600,
+ alt: "Roo Code",
},
keywords: [
"Roo Code",
diff --git a/packages/cloud/src/CloudService.ts b/packages/cloud/src/CloudService.ts
index ce9e34de8c..1ca13430a5 100644
--- a/packages/cloud/src/CloudService.ts
+++ b/packages/cloud/src/CloudService.ts
@@ -8,6 +8,7 @@ import type {
AuthService,
SettingsService,
CloudUserInfo,
+ CloudOrganizationMembership,
OrganizationAllowList,
OrganizationSettings,
ShareVisibility,
@@ -170,9 +171,9 @@ export class CloudService extends EventEmitter implements Di
// AuthService
- public async login(): Promise {
+ public async login(landingPageSlug?: string): Promise {
this.ensureInitialized()
- return this.authService!.login()
+ return this.authService!.login(landingPageSlug)
}
public async logout(): Promise {
@@ -242,6 +243,21 @@ export class CloudService extends EventEmitter implements Di
return this.authService!.handleCallback(code, state, organizationId)
}
+ public async switchOrganization(organizationId: string | null): Promise {
+ this.ensureInitialized()
+
+ // Perform the organization switch
+ // StaticTokenAuthService will throw an error if organization switching is not supported
+ await this.authService!.switchOrganization(organizationId)
+ }
+
+ public async getOrganizationMemberships(): Promise {
+ this.ensureInitialized()
+
+ // StaticTokenAuthService will throw an error if organization memberships are not supported
+ return await this.authService!.getOrganizationMemberships()
+ }
+
// SettingsService
public getAllowList(): OrganizationAllowList {
diff --git a/packages/cloud/src/StaticTokenAuthService.ts b/packages/cloud/src/StaticTokenAuthService.ts
index 6630a4a2e0..97ce6eac59 100644
--- a/packages/cloud/src/StaticTokenAuthService.ts
+++ b/packages/cloud/src/StaticTokenAuthService.ts
@@ -63,6 +63,14 @@ export class StaticTokenAuthService extends EventEmitter impl
throw new Error("Authentication methods are disabled in StaticTokenAuthService")
}
+ public async switchOrganization(_organizationId: string | null): Promise {
+ throw new Error("Authentication methods are disabled in StaticTokenAuthService")
+ }
+
+ public async getOrganizationMemberships(): Promise {
+ throw new Error("Authentication methods are disabled in StaticTokenAuthService")
+ }
+
public getState(): AuthState {
return this.state
}
diff --git a/packages/cloud/src/WebAuthService.ts b/packages/cloud/src/WebAuthService.ts
index 934ca90b71..6e9c76b463 100644
--- a/packages/cloud/src/WebAuthService.ts
+++ b/packages/cloud/src/WebAuthService.ts
@@ -141,7 +141,8 @@ export class WebAuthService extends EventEmitter implements A
if (
this.credentials === null ||
this.credentials.clientToken !== credentials.clientToken ||
- this.credentials.sessionId !== credentials.sessionId
+ this.credentials.sessionId !== credentials.sessionId ||
+ this.credentials.organizationId !== credentials.organizationId
) {
this.transitionToAttemptingSession(credentials)
}
@@ -174,6 +175,7 @@ export class WebAuthService extends EventEmitter implements A
this.changeState("attempting-session")
+ this.timer.stop()
this.timer.start()
}
@@ -248,8 +250,10 @@ export class WebAuthService extends EventEmitter implements A
*
* This method initiates the authentication flow by generating a state parameter
* and opening the browser to the authorization URL.
+ *
+ * @param landingPageSlug Optional slug of a specific landing page (e.g., "supernova", "special-offer", etc.)
*/
- public async login(): Promise {
+ public async login(landingPageSlug?: string): Promise {
try {
const vscode = await importVscode()
@@ -267,11 +271,17 @@ export class WebAuthService extends EventEmitter implements A
state,
auth_redirect: `${vscode.env.uriScheme}://${publisher}.${name}`,
})
- const url = `${getRooCodeApiUrl()}/extension/sign-in?${params.toString()}`
+
+ // Use landing page URL if slug is provided, otherwise use default sign-in URL
+ const url = landingPageSlug
+ ? `${getRooCodeApiUrl()}/l/${landingPageSlug}?${params.toString()}`
+ : `${getRooCodeApiUrl()}/extension/sign-in?${params.toString()}`
+
await vscode.env.openExternal(vscode.Uri.parse(url))
} catch (error) {
- this.log(`[auth] Error initiating Roo Code Cloud auth: ${error}`)
- throw new Error(`Failed to initiate Roo Code Cloud authentication: ${error}`)
+ const context = landingPageSlug ? ` (landing page: ${landingPageSlug})` : ""
+ this.log(`[auth] Error initiating Roo Code Cloud auth${context}: ${error}`)
+ throw new Error(`Failed to initiate Roo Code Cloud authentication${context}: ${error}`)
}
}
@@ -461,6 +471,42 @@ export class WebAuthService extends EventEmitter implements A
return this.credentials?.organizationId || null
}
+ /**
+ * Switch to a different organization context
+ * @param organizationId The organization ID to switch to, or null for personal account
+ */
+ public async switchOrganization(organizationId: string | null): Promise {
+ if (!this.credentials) {
+ throw new Error("Cannot switch organization: not authenticated")
+ }
+
+ // Update the stored credentials with the new organization ID
+ const updatedCredentials: AuthCredentials = {
+ ...this.credentials,
+ organizationId: organizationId,
+ }
+
+ // Store the updated credentials, handleCredentialsChange will handle the update
+ await this.storeCredentials(updatedCredentials)
+ }
+
+ /**
+ * Get all organization memberships for the current user
+ * @returns Array of organization memberships
+ */
+ public async getOrganizationMemberships(): Promise {
+ if (!this.credentials) {
+ return []
+ }
+
+ try {
+ return await this.clerkGetOrganizationMemberships()
+ } catch (error) {
+ this.log(`[auth] Failed to get organization memberships: ${error}`)
+ return []
+ }
+ }
+
private async clerkSignIn(ticket: string): Promise {
const formData = new URLSearchParams()
formData.append("strategy", "ticket")
@@ -645,9 +691,14 @@ export class WebAuthService extends EventEmitter implements A
}
private async clerkGetOrganizationMemberships(): Promise {
+ if (!this.credentials) {
+ this.log("[auth] Cannot get organization memberships: missing credentials")
+ return []
+ }
+
const response = await fetch(`${getClerkBaseUrl()}/v1/me/organization_memberships`, {
headers: {
- Authorization: `Bearer ${this.credentials!.clientToken}`,
+ Authorization: `Bearer ${this.credentials.clientToken}`,
"User-Agent": this.userAgent(),
},
signal: AbortSignal.timeout(10000),
diff --git a/packages/evals/Dockerfile.web b/packages/evals/Dockerfile.web
index 4c6a8e0258..c578955232 100644
--- a/packages/evals/Dockerfile.web
+++ b/packages/evals/Dockerfile.web
@@ -60,5 +60,5 @@ RUN chmod +x /usr/local/bin/entrypoint.sh
ENV DATABASE_URL=postgresql://postgres:password@db:5432/evals_development
ENV REDIS_URL=redis://redis:6379
-EXPOSE 3000
+EXPOSE 3446
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
diff --git a/packages/evals/README.md b/packages/evals/README.md
index 750454956f..8a54e56b81 100644
--- a/packages/evals/README.md
+++ b/packages/evals/README.md
@@ -29,7 +29,7 @@ Start the evals service:
pnpm evals
```
-The initial build process can take a minute or two. Upon success you should see output indicating that a web service is running on localhost:3000:
+The initial build process can take a minute or two. Upon success you should see output indicating that a web service is running on localhost:3446:
Additionally, you'll find in Docker Desktop that database and redis services are running:
@@ -95,7 +95,7 @@ By default, the evals system uses the following ports:
- **PostgreSQL**: 5433 (external) → 5432 (internal)
- **Redis**: 6380 (external) → 6379 (internal)
-- **Web Service**: 3446 (external) → 3000 (internal)
+- **Web Service**: 3446 (external) → 3446 (internal)
These ports are configured to avoid conflicts with other services that might be running on the standard PostgreSQL (5432) and Redis (6379) ports.
diff --git a/packages/evals/docker-compose.yml b/packages/evals/docker-compose.yml
index 74c25cf260..5928b53114 100644
--- a/packages/evals/docker-compose.yml
+++ b/packages/evals/docker-compose.yml
@@ -52,7 +52,7 @@ services:
context: ../../
dockerfile: packages/evals/Dockerfile.web
ports:
- - "${EVALS_WEB_PORT:-3446}:3000"
+ - "${EVALS_WEB_PORT:-3446}:3446"
environment:
- HOST_EXECUTION_METHOD=docker
volumes:
diff --git a/packages/evals/scripts/setup.sh b/packages/evals/scripts/setup.sh
index cca6f9ce95..f4ba30ce79 100755
--- a/packages/evals/scripts/setup.sh
+++ b/packages/evals/scripts/setup.sh
@@ -12,7 +12,6 @@ build_extension() {
echo "🔨 Building the Roo Code extension..."
pnpm -w vsix -- --out ../bin/roo-code-$(git rev-parse --short HEAD).vsix || exit 1
code --install-extension ../../bin/roo-code-$(git rev-parse --short HEAD).vsix || exit 1
- cd evals
}
check_docker_services() {
@@ -377,7 +376,7 @@ fi
echo -e "\n🚀 You're ready to rock and roll! \n"
-if ! nc -z localhost 3000; then
+if ! nc -z localhost 3446; then
read -p "🌐 Would you like to start the evals web app? (Y/n): " start_evals
if [[ "$start_evals" =~ ^[Yy]|^$ ]]; then
@@ -386,5 +385,5 @@ if ! nc -z localhost 3000; then
echo "💡 You can start it anytime with 'pnpm --filter @roo-code/web-evals dev'."
fi
else
- echo "👟 The evals web app is running at http://localhost:3000 (or http://localhost:3446 if using Docker)"
+ echo "👟 The evals web app is running at http://localhost:3446"
fi
diff --git a/packages/types/src/cloud.ts b/packages/types/src/cloud.ts
index 7ffb28ae5d..903dfcb93f 100644
--- a/packages/types/src/cloud.ts
+++ b/packages/types/src/cloud.ts
@@ -239,9 +239,10 @@ export interface AuthService extends EventEmitter {
broadcast(): void
// Authentication methods
- login(): Promise
+ login(landingPageSlug?: string): Promise
logout(): Promise
handleCallback(code: string | null, state: string | null, organizationId?: string | null): Promise
+ switchOrganization(organizationId: string | null): Promise
// State methods
getState(): AuthState
@@ -253,6 +254,9 @@ export interface AuthService extends EventEmitter {
getSessionToken(): string | undefined
getUserInfo(): CloudUserInfo | null
getStoredOrganizationId(): string | null
+
+ // Organization management
+ getOrganizationMemberships(): Promise
}
/**
diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts
index 7e79855f7e..a56a00fc35 100644
--- a/packages/types/src/global-settings.ts
+++ b/packages/types/src/global-settings.ts
@@ -147,6 +147,7 @@ export const globalSettingsSchema = z.object({
enhancementApiConfigId: z.string().optional(),
includeTaskHistoryInEnhance: z.boolean().optional(),
historyPreviewCollapsed: z.boolean().optional(),
+ reasoningBlockCollapsed: z.boolean().optional(),
profileThresholds: z.record(z.string(), z.number()).optional(),
hasOpenedModeSelector: z.boolean().optional(),
lastModeExportPath: z.string().optional(),
diff --git a/packages/types/src/message.ts b/packages/types/src/message.ts
index b6eb67e171..77c055c6e1 100644
--- a/packages/types/src/message.ts
+++ b/packages/types/src/message.ts
@@ -89,6 +89,7 @@ export function isResumableAsk(ask: ClineAsk): ask is ResumableAsk {
*/
export const interactiveAsks = [
+ "followup",
"command",
"tool",
"browser_action_launch",
diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts
index fd327657b6..8434158541 100644
--- a/packages/types/src/provider-settings.ts
+++ b/packages/types/src/provider-settings.ts
@@ -258,6 +258,7 @@ const ollamaSchema = baseProviderSettingsSchema.extend({
ollamaModelId: z.string().optional(),
ollamaBaseUrl: z.string().optional(),
ollamaApiKey: z.string().optional(),
+ ollamaNumCtx: z.number().int().min(128).optional(),
})
const vsCodeLmSchema = baseProviderSettingsSchema.extend({
diff --git a/packages/types/src/providers/chutes.ts b/packages/types/src/providers/chutes.ts
index 15dea58263..d05bd489b1 100644
--- a/packages/types/src/providers/chutes.ts
+++ b/packages/types/src/providers/chutes.ts
@@ -29,6 +29,7 @@ export type ChutesModelId =
| "tngtech/DeepSeek-R1T-Chimera"
| "zai-org/GLM-4.5-Air"
| "zai-org/GLM-4.5-FP8"
+ | "zai-org/GLM-4.5-turbo"
| "moonshotai/Kimi-K2-Instruct-75k"
| "moonshotai/Kimi-K2-Instruct-0905"
| "Qwen/Qwen3-235B-A22B-Thinking-2507"
@@ -274,6 +275,15 @@ export const chutesModels = {
description:
"GLM-4.5-FP8 model with 128k token context window, optimized for agent-based applications with MoE architecture.",
},
+ "zai-org/GLM-4.5-turbo": {
+ maxTokens: 32768,
+ contextWindow: 131072,
+ supportsImages: false,
+ supportsPromptCache: false,
+ inputPrice: 1,
+ outputPrice: 3,
+ description: "GLM-4.5-turbo model with 128K token context window, optimized for fast inference.",
+ },
"Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8": {
maxTokens: 32768,
contextWindow: 262144,
diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts
index 028027baad..a3eed1b57c 100644
--- a/packages/types/src/providers/openai.ts
+++ b/packages/types/src/providers/openai.ts
@@ -70,6 +70,20 @@ export const openAiNativeModels = {
supportsTemperature: false,
tiers: [{ name: "flex", contextWindow: 400000, inputPrice: 0.025, outputPrice: 0.2, cacheReadsPrice: 0.0025 }],
},
+ "gpt-5-codex": {
+ maxTokens: 128000,
+ contextWindow: 400000,
+ supportsImages: true,
+ supportsPromptCache: true,
+ supportsReasoningEffort: true,
+ reasoningEffort: "medium",
+ inputPrice: 1.25,
+ outputPrice: 10.0,
+ cacheReadsPrice: 0.13,
+ description: "GPT-5-Codex: A version of GPT-5 optimized for agentic coding in Codex",
+ supportsVerbosity: true,
+ supportsTemperature: false,
+ },
"gpt-4.1": {
maxTokens: 32_768,
contextWindow: 1_047_576,
diff --git a/packages/types/src/providers/roo.ts b/packages/types/src/providers/roo.ts
index ee84bbe1b1..01fae43cd5 100644
--- a/packages/types/src/providers/roo.ts
+++ b/packages/types/src/providers/roo.ts
@@ -1,7 +1,10 @@
import type { ModelInfo } from "../model.js"
-// Roo provider with single model
-export type RooModelId = "xai/grok-code-fast-1"
+export type RooModelId =
+ | "xai/grok-code-fast-1"
+ | "roo/code-supernova"
+ | "xai/grok-4-fast"
+ | "deepseek/deepseek-chat-v3.1"
export const rooDefaultModelId: RooModelId = "xai/grok-code-fast-1"
@@ -16,4 +19,34 @@ export const rooModels = {
description:
"A reasoning model that is blazing fast and excels at agentic coding, accessible for free through Roo Code Cloud for a limited time. (Note: the free prompts and completions are logged by xAI and used to improve the model.)",
},
+ "roo/code-supernova": {
+ maxTokens: 16_384,
+ contextWindow: 200_000,
+ supportsImages: true,
+ supportsPromptCache: true,
+ inputPrice: 0,
+ outputPrice: 0,
+ description:
+ "A versatile agentic coding stealth model that supports image inputs, accessible for free through Roo Code Cloud for a limited time. (Note: the free prompts and completions are logged by the model provider and used to improve the model.)",
+ },
+ "xai/grok-4-fast": {
+ maxTokens: 30_000,
+ contextWindow: 2_000_000,
+ supportsImages: false,
+ supportsPromptCache: false,
+ inputPrice: 0,
+ outputPrice: 0,
+ description:
+ "Grok 4 Fast is xAI's latest multimodal model with SOTA cost-efficiency and a 2M token context window. (Note: prompts and completions are logged by xAI and used to improve the model.)",
+ },
+ "deepseek/deepseek-chat-v3.1": {
+ maxTokens: 16_384,
+ contextWindow: 163_840,
+ supportsImages: false,
+ supportsPromptCache: false,
+ inputPrice: 0,
+ outputPrice: 0,
+ description:
+ "DeepSeek-V3.1 is a large hybrid reasoning model (671B parameters, 37B active). It extends the DeepSeek-V3 base with a two-phase long-context training process, reaching up to 128K tokens, and uses FP8 microscaling for efficient inference.",
+ },
} as const satisfies Record
diff --git a/packages/types/src/providers/sambanova.ts b/packages/types/src/providers/sambanova.ts
index bed143f6e5..f339d8bcab 100644
--- a/packages/types/src/providers/sambanova.ts
+++ b/packages/types/src/providers/sambanova.ts
@@ -6,10 +6,12 @@ export type SambaNovaModelId =
| "Meta-Llama-3.3-70B-Instruct"
| "DeepSeek-R1"
| "DeepSeek-V3-0324"
+ | "DeepSeek-V3.1"
| "DeepSeek-R1-Distill-Llama-70B"
| "Llama-4-Maverick-17B-128E-Instruct"
| "Llama-3.3-Swallow-70B-Instruct-v0.4"
| "Qwen3-32B"
+ | "gpt-oss-120b"
export const sambaNovaDefaultModelId: SambaNovaModelId = "Meta-Llama-3.3-70B-Instruct"
@@ -51,6 +53,15 @@ export const sambaNovaModels = {
outputPrice: 4.5,
description: "DeepSeek V3 model with 32K context window.",
},
+ "DeepSeek-V3.1": {
+ maxTokens: 8192,
+ contextWindow: 32768,
+ supportsImages: false,
+ supportsPromptCache: false,
+ inputPrice: 3.0,
+ outputPrice: 4.5,
+ description: "DeepSeek V3.1 model with 32K context window.",
+ },
"DeepSeek-R1-Distill-Llama-70B": {
maxTokens: 8192,
contextWindow: 131072,
@@ -87,4 +98,13 @@ export const sambaNovaModels = {
outputPrice: 0.8,
description: "Alibaba Qwen 3 32B model with 8K context window.",
},
+ "gpt-oss-120b": {
+ maxTokens: 8192,
+ contextWindow: 131072,
+ supportsImages: false,
+ supportsPromptCache: false,
+ inputPrice: 0.22,
+ outputPrice: 0.59,
+ description: "OpenAI gpt oss 120b model with 128k context window.",
+ },
} as const satisfies Record
diff --git a/packages/types/src/single-file-read-models.ts b/packages/types/src/single-file-read-models.ts
index b83a781507..302b8d4202 100644
--- a/packages/types/src/single-file-read-models.ts
+++ b/packages/types/src/single-file-read-models.ts
@@ -10,5 +10,5 @@
* @returns true if the model should use single file reads
*/
export function shouldUseSingleFileRead(modelId: string): boolean {
- return modelId.includes("grok-code-fast-1")
+ return modelId.includes("grok-code-fast-1") || modelId.includes("code-supernova")
}
diff --git a/packages/types/src/telemetry.ts b/packages/types/src/telemetry.ts
index bba1485722..abaceb9fbb 100644
--- a/packages/types/src/telemetry.ts
+++ b/packages/types/src/telemetry.ts
@@ -61,6 +61,11 @@ 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",
+
SCHEMA_VALIDATION_ERROR = "Schema Validation Error",
DIFF_APPLICATION_ERROR = "Diff Application Error",
SHELL_INTEGRATION_ERROR = "Shell Integration Error",
@@ -181,6 +186,9 @@ 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,
TelemetryEventName.DIFF_APPLICATION_ERROR,
TelemetryEventName.SHELL_INTEGRATION_ERROR,
diff --git a/packages/types/src/vscode.ts b/packages/types/src/vscode.ts
index 2838514690..d22ebdab22 100644
--- a/packages/types/src/vscode.ts
+++ b/packages/types/src/vscode.ts
@@ -53,6 +53,7 @@ export const commandIds = [
"focusInput",
"acceptInput",
"focusPanel",
+ "toggleAutoApprove",
] as const
export type CommandId = (typeof commandIds)[number]
diff --git a/releases/3.28.4-release.png b/releases/3.28.4-release.png
new file mode 100644
index 0000000000..ea1e82a8dd
Binary files /dev/null and b/releases/3.28.4-release.png differ
diff --git a/releases/3.28.5-release.png b/releases/3.28.5-release.png
new file mode 100644
index 0000000000..0a22c25c40
Binary files /dev/null and b/releases/3.28.5-release.png differ
diff --git a/releases/3.28.6-release.png b/releases/3.28.6-release.png
new file mode 100644
index 0000000000..e246cffb01
Binary files /dev/null and b/releases/3.28.6-release.png differ
diff --git a/releases/3.28.7-release.png b/releases/3.28.7-release.png
new file mode 100644
index 0000000000..d4690f19c9
Binary files /dev/null and b/releases/3.28.7-release.png differ
diff --git a/releases/3.28.8-release.png b/releases/3.28.8-release.png
new file mode 100644
index 0000000000..8fcfa22453
Binary files /dev/null and b/releases/3.28.8-release.png differ
diff --git a/scripts/find-missing-translations.js b/scripts/find-missing-translations.js
index 9277d935ba..fe7577408e 100755
--- a/scripts/find-missing-translations.js
+++ b/scripts/find-missing-translations.js
@@ -7,12 +7,16 @@
* Options:
* --locale= Only check a specific locale (e.g. --locale=fr)
* --file= Only check a specific file (e.g. --file=chat.json)
- * --area= Only check a specific area (core, webview, or both)
+ * --area= Only check a specific area (core, webview, package-nls, or all)
* --help Show this help message
*/
-const fs = require("fs")
const path = require("path")
+const { promises: fs } = require("fs")
+
+const readFile = fs.readFile
+const readdir = fs.readdir
+const stat = fs.stat
// Process command line arguments
const args = process.argv.slice(2).reduce(
@@ -26,15 +30,15 @@ const args = process.argv.slice(2).reduce(
} else if (arg.startsWith("--area=")) {
acc.area = arg.split("=")[1]
// Validate area value
- if (!["core", "webview", "both"].includes(acc.area)) {
- console.error(`Error: Invalid area '${acc.area}'. Must be 'core', 'webview', or 'both'.`)
+ if (!["core", "webview", "package-nls", "all"].includes(acc.area)) {
+ console.error(`Error: Invalid area '${acc.area}'. Must be 'core', 'webview', 'package-nls', or 'all'.`)
process.exit(1)
}
}
return acc
},
- { area: "both" },
-) // Default to checking both areas
+ { area: "all" },
+) // Default to checking all areas
// Show help if requested
if (args.help) {
@@ -50,10 +54,11 @@ Usage:
Options:
--locale= Only check a specific locale (e.g. --locale=fr)
--file= Only check a specific file (e.g. --file=chat.json)
- --area= Only check a specific area (core, webview, or both)
+ --area= Only check a specific area (core, webview, package-nls, or all)
'core' = Backend (src/i18n/locales)
'webview' = Frontend UI (webview-ui/src/i18n/locales)
- 'both' = Check both areas (default)
+ 'package-nls' = VSCode package.nls.json files
+ 'all' = Check all areas (default)
--help Show this help message
Output:
@@ -69,7 +74,7 @@ const LOCALES_DIRS = {
}
// Determine which areas to check based on args
-const areasToCheck = args.area === "both" ? ["core", "webview"] : [args.area]
+const areasToCheck = args.area === "all" ? ["core", "webview", "package-nls"] : [args.area]
// Recursively find all keys in an object
function findKeys(obj, parentKey = "") {
@@ -105,18 +110,45 @@ function getValueAtPath(obj, path) {
return current
}
+// Shared utility to safely parse JSON files with error handling
+async function parseJsonFile(filePath) {
+ try {
+ const content = await readFile(filePath, "utf8")
+ return JSON.parse(content)
+ } catch (error) {
+ if (error.code === "ENOENT") {
+ return null // File doesn't exist
+ }
+ throw new Error(`Error parsing JSON file '${filePath}': ${error.message}`)
+ }
+}
+
+// Validate that a JSON object has a flat structure (no nested objects)
+function validateFlatStructure(obj, filePath) {
+ for (const [key, value] of Object.entries(obj)) {
+ if (typeof value === "object" && value !== null) {
+ console.error(`Error: ${filePath} should be a flat JSON structure. Found nested object at key '${key}'`)
+ process.exit(1)
+ }
+ }
+}
+
// Function to check translations for a specific area
-function checkAreaTranslations(area) {
+async function checkAreaTranslations(area) {
const LOCALES_DIR = LOCALES_DIRS[area]
// Get all locale directories (or filter to the specified locale)
- const allLocales = fs.readdirSync(LOCALES_DIR).filter((item) => {
- const stats = fs.statSync(path.join(LOCALES_DIR, item))
- return stats.isDirectory() && item !== "en" // Exclude English as it's our source
- })
+ const dirContents = await readdir(LOCALES_DIR)
+ const allLocales = await Promise.all(
+ dirContents.map(async (item) => {
+ const stats = await stat(path.join(LOCALES_DIR, item))
+ return stats.isDirectory() && item !== "en" ? item : null
+ }),
+ )
+ const filteredLocales = allLocales.filter(Boolean)
// Filter to the specified locale if provided
- const locales = args.locale ? allLocales.filter((locale) => locale === args.locale) : allLocales
+ const locales = args.locale ? filteredLocales.filter((locale) => locale === args.locale) : filteredLocales
if (args.locale && locales.length === 0) {
console.error(`Error: Locale '${args.locale}' not found in ${LOCALES_DIR}`)
@@ -129,7 +161,8 @@ function checkAreaTranslations(area) {
// Get all English JSON files
const englishDir = path.join(LOCALES_DIR, "en")
- let englishFiles = fs.readdirSync(englishDir).filter((file) => file.endsWith(".json") && !file.startsWith("."))
+ const englishDirContents = await readdir(englishDir)
+ let englishFiles = englishDirContents.filter((file) => file.endsWith(".json") && !file.startsWith("."))
// Filter to the specified file if provided
if (args.file) {
@@ -140,72 +173,71 @@ function checkAreaTranslations(area) {
englishFiles = englishFiles.filter((file) => file === args.file)
}
- // Load file contents
- let englishFileContents
-
- try {
- englishFileContents = englishFiles.map((file) => ({
- name: file,
- content: JSON.parse(fs.readFileSync(path.join(englishDir, file), "utf8")),
- }))
- } catch (e) {
- console.error(`Error: File '${englishDir}' is not a valid JSON file`)
- process.exit(1)
- }
+ // Load file contents in parallel
+ const englishFileContents = await Promise.all(
+ englishFiles.map(async (file) => {
+ const filePath = path.join(englishDir, file)
+ const content = await parseJsonFile(filePath)
+ if (!content) {
+ console.error(`Error: Could not read file '${filePath}'`)
+ process.exit(1)
+ }
+ return { name: file, content }
+ }),
+ )
console.log(
`Checking ${englishFileContents.length} translation file(s): ${englishFileContents.map((f) => f.name).join(", ")}`,
)
+ // Precompute English keys per file
+ const englishFileKeys = new Map(englishFileContents.map((f) => [f.name, findKeys(f.content)]))
+
// Results object to store missing translations
const missingTranslations = {}
- // For each locale, check for missing translations
- for (const locale of locales) {
- missingTranslations[locale] = {}
+ // Process all locales in parallel
+ await Promise.all(
+ locales.map(async (locale) => {
+ missingTranslations[locale] = {}
- for (const { name, content: englishContent } of englishFileContents) {
- const localeFilePath = path.join(LOCALES_DIR, locale, name)
+ // Process all files for this locale in parallel
+ await Promise.all(
+ englishFileContents.map(async ({ name, content: englishContent }) => {
+ const localeFilePath = path.join(LOCALES_DIR, locale, name)
- // Check if the file exists in the locale
- if (!fs.existsSync(localeFilePath)) {
- missingTranslations[locale][name] = { file: "File is missing entirely" }
- continue
- }
+ // Check if the file exists in the locale
+ const localeContent = await parseJsonFile(localeFilePath)
+ if (!localeContent) {
+ missingTranslations[locale][name] = { file: "File is missing entirely" }
+ return
+ }
- // Load the locale file
- let localeContent
+ // Find all keys in the English file
+ const englishKeys = englishFileKeys.get(name) || []
- try {
- localeContent = JSON.parse(fs.readFileSync(localeFilePath, "utf8"))
- } catch (e) {
- console.error(`Error: File '${localeFilePath}' is not a valid JSON file`)
- process.exit(1)
- }
+ // Check for missing keys in the locale file
+ const missingKeys = []
- // Find all keys in the English file
- const englishKeys = findKeys(englishContent)
+ for (const key of englishKeys) {
+ const englishValue = getValueAtPath(englishContent, key)
+ const localeValue = getValueAtPath(localeContent, key)
- // Check for missing keys in the locale file
- const missingKeys = []
+ if (localeValue === undefined) {
+ missingKeys.push({
+ key,
+ englishValue,
+ })
+ }
+ }
- for (const key of englishKeys) {
- const englishValue = getValueAtPath(englishContent, key)
- const localeValue = getValueAtPath(localeContent, key)
-
- if (localeValue === undefined) {
- missingKeys.push({
- key,
- englishValue,
- })
- }
- }
-
- if (missingKeys.length > 0) {
- missingTranslations[locale][name] = missingKeys
- }
- }
- }
+ if (missingKeys.length > 0) {
+ missingTranslations[locale][name] = missingKeys
+ }
+ }),
+ )
+ }),
+ )
return { missingTranslations, hasMissingTranslations: outputResults(missingTranslations, area) }
}
@@ -244,8 +276,124 @@ function outputResults(missingTranslations, area) {
return hasMissingTranslations
}
+// Function to check package.nls.json translations
+async function checkPackageNlsTranslations() {
+ const SRC_DIR = path.join(__dirname, "../src")
+
+ // Read the base package.nls.json file
+ const baseFilePath = path.join(SRC_DIR, "package.nls.json")
+ const baseContent = await parseJsonFile(baseFilePath)
+
+ if (!baseContent) {
+ console.warn(`Warning: Base package.nls.json not found at ${baseFilePath} - skipping package.nls checks`)
+ return { missingTranslations: {}, hasMissingTranslations: false }
+ }
+
+ // Validate that the base file has a flat structure
+ validateFlatStructure(baseContent, baseFilePath)
+
+ // Get all package.nls.*.json files
+ const srcDirContents = await readdir(SRC_DIR)
+ const nlsFiles = srcDirContents
+ .filter((file) => file.startsWith("package.nls.") && file.endsWith(".json"))
+ .filter((file) => file !== "package.nls.json") // Exclude the base file
+
+ // Filter to the specified locale if provided
+ const filesToCheck = args.locale
+ ? nlsFiles.filter((file) => {
+ const locale = file.replace("package.nls.", "").replace(".json", "")
+ return locale === args.locale
+ })
+ : nlsFiles
+
+ if (args.locale && filesToCheck.length === 0) {
+ console.error(`Error: Locale '${args.locale}' not found in package.nls files`)
+ process.exit(1)
+ }
+
+ console.log(
+ `\nPACKAGE.NLS - Checking ${filesToCheck.length} locale file(s): ${filesToCheck.map((f) => f.replace("package.nls.", "").replace(".json", "")).join(", ")}`,
+ )
+ console.log(`Checking against base package.nls.json with ${Object.keys(baseContent).length} keys`)
+
+ // Results object to store missing translations
+ const missingTranslations = {}
+
+ // Get all keys from the base file (package.nls files are flat, not nested)
+ const baseKeys = Object.keys(baseContent)
+
+ // Process all locale files in parallel
+ await Promise.all(
+ filesToCheck.map(async (file) => {
+ const locale = file.replace("package.nls.", "").replace(".json", "")
+ const localeFilePath = path.join(SRC_DIR, file)
+
+ const localeContent = await parseJsonFile(localeFilePath)
+ if (!localeContent) {
+ console.error(`Error: Could not read file '${localeFilePath}'`)
+ process.exit(1)
+ }
+
+ // Validate that the locale file has a flat structure
+ validateFlatStructure(localeContent, localeFilePath)
+
+ // Check for missing keys
+ const missingKeys = []
+
+ for (const key of baseKeys) {
+ const baseValue = baseContent[key]
+ const localeValue = localeContent[key]
+
+ if (localeValue === undefined) {
+ missingKeys.push({
+ key,
+ englishValue: baseValue,
+ })
+ }
+ }
+
+ if (missingKeys.length > 0) {
+ missingTranslations[locale] = {
+ "package.nls.json": missingKeys,
+ }
+ }
+ }),
+ )
+
+ return { missingTranslations, hasMissingTranslations: outputPackageNlsResults(missingTranslations) }
+}
+
+// Function to output package.nls results
+function outputPackageNlsResults(missingTranslations) {
+ let hasMissingTranslations = false
+
+ console.log(`\nPACKAGE.NLS Missing Translations Report:\n`)
+
+ for (const [locale, files] of Object.entries(missingTranslations)) {
+ if (Object.keys(files).length === 0) {
+ console.log(`✅ ${locale}: No missing translations`)
+ continue
+ }
+
+ hasMissingTranslations = true
+ console.log(`📝 ${locale}:`)
+
+ for (const [fileName, missingItems] of Object.entries(files)) {
+ console.log(` - ${fileName}: ${missingItems.length} missing translations`)
+
+ for (const { key, englishValue } of missingItems) {
+ console.log(` ${key}: "${englishValue}"`)
+ }
+ }
+
+ console.log("")
+ }
+
+ return hasMissingTranslations
+}
+
// Main function to find missing translations
-function findMissingTranslations() {
+async function findMissingTranslations() {
try {
console.log("Starting translation check...")
@@ -253,8 +401,13 @@ function findMissingTranslations() {
// Check each requested area
for (const area of areasToCheck) {
- const { hasMissingTranslations } = checkAreaTranslations(area)
- anyAreaMissingTranslations = anyAreaMissingTranslations || hasMissingTranslations
+ if (area === "package-nls") {
+ const { hasMissingTranslations } = await checkPackageNlsTranslations()
+ anyAreaMissingTranslations = anyAreaMissingTranslations || hasMissingTranslations
+ } else {
+ const { hasMissingTranslations } = await checkAreaTranslations(area)
+ anyAreaMissingTranslations = anyAreaMissingTranslations || hasMissingTranslations
+ }
}
// Summary
diff --git a/src/activate/registerCommands.ts b/src/activate/registerCommands.ts
index c3de58e528..73a9fadf6e 100644
--- a/src/activate/registerCommands.ts
+++ b/src/activate/registerCommands.ts
@@ -221,6 +221,18 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt
visibleProvider.postMessageToWebview({ type: "acceptInput" })
},
+ toggleAutoApprove: async () => {
+ const visibleProvider = getVisibleProviderOrLog(outputChannel)
+
+ if (!visibleProvider) {
+ return
+ }
+
+ visibleProvider.postMessageToWebview({
+ type: "action",
+ action: "toggleAutoApprove",
+ })
+ },
})
export const openClineInNewTab = async ({ context, outputChannel }: Omit) => {
diff --git a/src/api/providers/__tests__/chutes.spec.ts b/src/api/providers/__tests__/chutes.spec.ts
index 398f86ce60..70ee06a923 100644
--- a/src/api/providers/__tests__/chutes.spec.ts
+++ b/src/api/providers/__tests__/chutes.spec.ts
@@ -253,6 +253,28 @@ describe("ChutesHandler", () => {
)
})
+ it("should return zai-org/GLM-4.5-turbo model with correct configuration", () => {
+ const testModelId: ChutesModelId = "zai-org/GLM-4.5-turbo"
+ const handlerWithModel = new ChutesHandler({
+ apiModelId: testModelId,
+ chutesApiKey: "test-chutes-api-key",
+ })
+ const model = handlerWithModel.getModel()
+ expect(model.id).toBe(testModelId)
+ expect(model.info).toEqual(
+ expect.objectContaining({
+ maxTokens: 32768,
+ contextWindow: 131072,
+ supportsImages: false,
+ supportsPromptCache: false,
+ inputPrice: 1,
+ outputPrice: 3,
+ description: "GLM-4.5-turbo model with 128K token context window, optimized for fast inference.",
+ temperature: 0.5, // Default temperature for non-DeepSeek models
+ }),
+ )
+ })
+
it("should return Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8 model with correct configuration", () => {
const testModelId: ChutesModelId = "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8"
const handlerWithModel = new ChutesHandler({
diff --git a/src/api/providers/__tests__/native-ollama.spec.ts b/src/api/providers/__tests__/native-ollama.spec.ts
index f8792937db..4ddeb909bb 100644
--- a/src/api/providers/__tests__/native-ollama.spec.ts
+++ b/src/api/providers/__tests__/native-ollama.spec.ts
@@ -73,6 +73,61 @@ describe("NativeOllamaHandler", () => {
expect(results[2]).toEqual({ type: "usage", inputTokens: 10, outputTokens: 2 })
})
+ it("should not include num_ctx by default", async () => {
+ // Mock the chat response
+ mockChat.mockImplementation(async function* () {
+ yield { message: { content: "Response" } }
+ })
+
+ const stream = handler.createMessage("System", [{ role: "user" as const, content: "Test" }])
+
+ // Consume the stream
+ for await (const _ of stream) {
+ // consume stream
+ }
+
+ // Verify that num_ctx was NOT included in the options
+ expect(mockChat).toHaveBeenCalledWith(
+ expect.objectContaining({
+ options: expect.not.objectContaining({
+ num_ctx: expect.anything(),
+ }),
+ }),
+ )
+ })
+
+ it("should include num_ctx when explicitly set via ollamaNumCtx", async () => {
+ const options: ApiHandlerOptions = {
+ apiModelId: "llama2",
+ ollamaModelId: "llama2",
+ ollamaBaseUrl: "http://localhost:11434",
+ ollamaNumCtx: 8192, // Explicitly set num_ctx
+ }
+
+ handler = new NativeOllamaHandler(options)
+
+ // Mock the chat response
+ mockChat.mockImplementation(async function* () {
+ yield { message: { content: "Response" } }
+ })
+
+ const stream = handler.createMessage("System", [{ role: "user" as const, content: "Test" }])
+
+ // Consume the stream
+ for await (const _ of stream) {
+ // consume stream
+ }
+
+ // Verify that num_ctx was included with the specified value
+ expect(mockChat).toHaveBeenCalledWith(
+ expect.objectContaining({
+ options: expect.objectContaining({
+ num_ctx: 8192,
+ }),
+ }),
+ )
+ })
+
it("should handle DeepSeek R1 models with reasoning detection", async () => {
const options: ApiHandlerOptions = {
apiModelId: "deepseek-r1",
@@ -120,6 +175,49 @@ describe("NativeOllamaHandler", () => {
})
expect(result).toBe("This is the response")
})
+
+ it("should not include num_ctx in completePrompt by default", async () => {
+ mockChat.mockResolvedValue({
+ message: { content: "Response" },
+ })
+
+ await handler.completePrompt("Test prompt")
+
+ // Verify that num_ctx was NOT included in the options
+ expect(mockChat).toHaveBeenCalledWith(
+ expect.objectContaining({
+ options: expect.not.objectContaining({
+ num_ctx: expect.anything(),
+ }),
+ }),
+ )
+ })
+
+ it("should include num_ctx in completePrompt when explicitly set", async () => {
+ const options: ApiHandlerOptions = {
+ apiModelId: "llama2",
+ ollamaModelId: "llama2",
+ ollamaBaseUrl: "http://localhost:11434",
+ ollamaNumCtx: 4096, // Explicitly set num_ctx
+ }
+
+ handler = new NativeOllamaHandler(options)
+
+ mockChat.mockResolvedValue({
+ message: { content: "Response" },
+ })
+
+ await handler.completePrompt("Test prompt")
+
+ // Verify that num_ctx was included with the specified value
+ expect(mockChat).toHaveBeenCalledWith(
+ expect.objectContaining({
+ options: expect.objectContaining({
+ num_ctx: 4096,
+ }),
+ }),
+ )
+ })
})
describe("error handling", () => {
diff --git a/src/api/providers/__tests__/roo.spec.ts b/src/api/providers/__tests__/roo.spec.ts
index 5897156b0a..d4affa2bea 100644
--- a/src/api/providers/__tests__/roo.spec.ts
+++ b/src/api/providers/__tests__/roo.spec.ts
@@ -36,26 +36,12 @@ vitest.mock("openai", () => {
return {
[Symbol.asyncIterator]: async function* () {
yield {
- choices: [
- {
- delta: { content: "Test response" },
- index: 0,
- },
- ],
+ choices: [{ delta: { content: "Test response" }, index: 0 }],
usage: null,
}
yield {
- choices: [
- {
- delta: {},
- index: 0,
- },
- ],
- usage: {
- prompt_tokens: 10,
- completion_tokens: 5,
- total_tokens: 15,
- },
+ choices: [{ delta: {}, index: 0 }],
+ usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 },
}
},
}
@@ -73,6 +59,7 @@ const mockHasInstance = vitest.fn()
// Create mock functions that we can control
const mockGetSessionTokenFn = vitest.fn()
const mockHasInstanceFn = vitest.fn()
+const mockOnFn = vitest.fn()
vitest.mock("@roo-code/cloud", () => ({
CloudService: {
@@ -82,6 +69,8 @@ vitest.mock("@roo-code/cloud", () => ({
authService: {
getSessionToken: () => mockGetSessionTokenFn(),
},
+ on: vitest.fn(),
+ off: vitest.fn(),
}
},
},
@@ -409,11 +398,18 @@ describe("RooHandler", () => {
it("should handle undefined auth service gracefully", () => {
mockHasInstanceFn.mockReturnValue(true)
// Mock CloudService with undefined authService
- const originalGetter = Object.getOwnPropertyDescriptor(CloudService, "instance")?.get
+ const originalGetSessionToken = mockGetSessionTokenFn.getMockImplementation()
+
+ // Temporarily make authService return undefined
+ mockGetSessionTokenFn.mockImplementation(() => undefined)
try {
Object.defineProperty(CloudService, "instance", {
- get: () => ({ authService: undefined }),
+ get: () => ({
+ authService: undefined,
+ on: vitest.fn(),
+ off: vitest.fn(),
+ }),
configurable: true,
})
@@ -424,12 +420,11 @@ describe("RooHandler", () => {
const handler = new RooHandler(mockOptions)
expect(handler).toBeInstanceOf(RooHandler)
} finally {
- // Always restore original getter, even if test fails
- if (originalGetter) {
- Object.defineProperty(CloudService, "instance", {
- get: originalGetter,
- configurable: true,
- })
+ // Restore original mock implementation
+ if (originalGetSessionToken) {
+ mockGetSessionTokenFn.mockImplementation(originalGetSessionToken)
+ } else {
+ mockGetSessionTokenFn.mockReturnValue("test-session-token")
}
}
})
diff --git a/src/api/providers/gemini.ts b/src/api/providers/gemini.ts
index 775d763a05..573adda879 100644
--- a/src/api/providers/gemini.ts
+++ b/src/api/providers/gemini.ts
@@ -286,10 +286,7 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
outputTokens: number
cacheReadTokens?: number
}) {
- if (!info.inputPrice || !info.outputPrice || !info.cacheReadsPrice) {
- return undefined
- }
-
+ // For models with tiered pricing, prices might only be defined in tiers
let inputPrice = info.inputPrice
let outputPrice = info.outputPrice
let cacheReadsPrice = info.cacheReadsPrice
@@ -306,6 +303,16 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
}
}
+ // Check if we have the required prices after considering tiers
+ if (!inputPrice || !outputPrice) {
+ return undefined
+ }
+
+ // cacheReadsPrice is optional - if not defined, treat as 0
+ if (!cacheReadsPrice) {
+ cacheReadsPrice = 0
+ }
+
// Subtract the cached input tokens from the total input tokens.
const uncachedInputTokens = inputTokens - cacheReadTokens
diff --git a/src/api/providers/native-ollama.ts b/src/api/providers/native-ollama.ts
index 80231540e8..83a5c7b36e 100644
--- a/src/api/providers/native-ollama.ts
+++ b/src/api/providers/native-ollama.ts
@@ -8,6 +8,11 @@ import { getOllamaModels } from "./fetchers/ollama"
import { XmlMatcher } from "../../utils/xml-matcher"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
+interface OllamaChatOptions {
+ temperature: number
+ num_ctx?: number
+}
+
function convertToOllamaMessages(anthropicMessages: Anthropic.Messages.MessageParam[]): Message[] {
const ollamaMessages: Message[] = []
@@ -184,15 +189,22 @@ export class NativeOllamaHandler extends BaseProvider implements SingleCompletio
)
try {
+ // Build options object conditionally
+ const chatOptions: OllamaChatOptions = {
+ temperature: this.options.modelTemperature ?? (useR1Format ? DEEP_SEEK_DEFAULT_TEMPERATURE : 0),
+ }
+
+ // Only include num_ctx if explicitly set via ollamaNumCtx
+ if (this.options.ollamaNumCtx !== undefined) {
+ chatOptions.num_ctx = this.options.ollamaNumCtx
+ }
+
// Create the actual API request promise
const stream = await client.chat({
model: modelId,
messages: ollamaMessages,
stream: true,
- options: {
- num_ctx: modelInfo.contextWindow,
- temperature: this.options.modelTemperature ?? (useR1Format ? DEEP_SEEK_DEFAULT_TEMPERATURE : 0),
- },
+ options: chatOptions,
})
let totalInputTokens = 0
@@ -274,13 +286,21 @@ export class NativeOllamaHandler extends BaseProvider implements SingleCompletio
const { id: modelId } = await this.fetchModel()
const useR1Format = modelId.toLowerCase().includes("deepseek-r1")
+ // Build options object conditionally
+ const chatOptions: OllamaChatOptions = {
+ temperature: this.options.modelTemperature ?? (useR1Format ? DEEP_SEEK_DEFAULT_TEMPERATURE : 0),
+ }
+
+ // Only include num_ctx if explicitly set via ollamaNumCtx
+ if (this.options.ollamaNumCtx !== undefined) {
+ chatOptions.num_ctx = this.options.ollamaNumCtx
+ }
+
const response = await client.chat({
model: modelId,
messages: [{ role: "user", content: prompt }],
stream: false,
- options: {
- temperature: this.options.modelTemperature ?? (useR1Format ? DEEP_SEEK_DEFAULT_TEMPERATURE : 0),
- },
+ options: chatOptions,
})
return response.message?.content || ""
diff --git a/src/api/providers/roo.ts b/src/api/providers/roo.ts
index 44b0160862..6f10157a31 100644
--- a/src/api/providers/roo.ts
+++ b/src/api/providers/roo.ts
@@ -1,22 +1,24 @@
import { Anthropic } from "@anthropic-ai/sdk"
+import OpenAI from "openai"
-import { rooDefaultModelId, rooModels, type RooModelId } from "@roo-code/types"
+import { AuthState, rooDefaultModelId, rooModels, type RooModelId } from "@roo-code/types"
import { CloudService } from "@roo-code/cloud"
import type { ApiHandlerOptions } from "../../shared/api"
import { ApiStream } from "../transform/stream"
import type { ApiHandlerCreateMessageMetadata } from "../index"
+import { DEFAULT_HEADERS } from "./constants"
import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider"
export class RooHandler extends BaseOpenAiCompatibleProvider {
+ private authStateListener?: (state: { state: AuthState }) => void
+
constructor(options: ApiHandlerOptions) {
- // Get the session token if available, but don't throw if not.
- // The server will handle authentication errors and return appropriate status codes.
- let sessionToken = ""
+ let sessionToken: string | undefined = undefined
if (CloudService.hasInstance()) {
- sessionToken = CloudService.instance.authService?.getSessionToken() || ""
+ sessionToken = CloudService.instance.authService?.getSessionToken()
}
// Always construct the handler, even without a valid token.
@@ -25,11 +27,39 @@ export class RooHandler extends BaseOpenAiCompatibleProvider {
...options,
providerName: "Roo Code Cloud",
baseURL: process.env.ROO_CODE_PROVIDER_URL ?? "https://api.roocode.com/proxy/v1",
- apiKey: sessionToken || "unauthenticated", // Use a placeholder if no token
+ apiKey: sessionToken || "unauthenticated", // Use a placeholder if no token.
defaultProviderModelId: rooDefaultModelId,
providerModels: rooModels,
defaultTemperature: 0.7,
})
+
+ if (CloudService.hasInstance()) {
+ const cloudService = CloudService.instance
+
+ this.authStateListener = (state: { state: AuthState }) => {
+ if (state.state === "active-session") {
+ this.client = new OpenAI({
+ baseURL: this.baseURL,
+ apiKey: cloudService.authService?.getSessionToken() ?? "unauthenticated",
+ defaultHeaders: DEFAULT_HEADERS,
+ })
+ } else if (state.state === "logged-out") {
+ this.client = new OpenAI({
+ baseURL: this.baseURL,
+ apiKey: "unauthenticated",
+ defaultHeaders: DEFAULT_HEADERS,
+ })
+ }
+ }
+
+ cloudService.on("auth-state-changed", this.authStateListener)
+ }
+ }
+
+ dispose() {
+ if (this.authStateListener && CloudService.hasInstance()) {
+ CloudService.instance.off("auth-state-changed", this.authStateListener)
+ }
}
override async *createMessage(
diff --git a/src/assets/images/roo.png b/src/assets/images/roo.png
new file mode 100644
index 0000000000..5dfc8723e8
Binary files /dev/null and b/src/assets/images/roo.png differ
diff --git a/src/core/condense/__tests__/index.spec.ts b/src/core/condense/__tests__/index.spec.ts
index d86b500f90..6a03298aa6 100644
--- a/src/core/condense/__tests__/index.spec.ts
+++ b/src/core/condense/__tests__/index.spec.ts
@@ -283,6 +283,32 @@ describe("summarizeConversation", () => {
const mockCallArgs = (maybeRemoveImageBlocks as Mock).mock.calls[0][0] as any[]
expect(mockCallArgs[mockCallArgs.length - 1]).toEqual(expectedFinalMessage)
})
+ it("should include the original first user message in summarization input", async () => {
+ const messages: ApiMessage[] = [
+ { role: "user", content: "Initial ask", ts: 1 },
+ { role: "assistant", content: "Ack", ts: 2 },
+ { role: "user", content: "Follow-up", ts: 3 },
+ { role: "assistant", content: "Response", ts: 4 },
+ { role: "user", content: "More", ts: 5 },
+ { role: "assistant", content: "Later", ts: 6 },
+ { role: "user", content: "Newest", ts: 7 },
+ ]
+
+ await summarizeConversation(messages, mockApiHandler, defaultSystemPrompt, taskId, DEFAULT_PREV_CONTEXT_TOKENS)
+
+ const mockCallArgs = (maybeRemoveImageBlocks as Mock).mock.calls[0][0] as any[]
+
+ // Expect the original first user message to be present in the messages sent to the summarizer
+ const hasInitialAsk = mockCallArgs.some(
+ (m) =>
+ m.role === "user" &&
+ (typeof m.content === "string"
+ ? m.content === "Initial ask"
+ : Array.isArray(m.content) &&
+ m.content.some((b: any) => b.type === "text" && b.text === "Initial ask")),
+ )
+ expect(hasInitialAsk).toBe(true)
+ })
it("should calculate newContextTokens correctly with systemPrompt", async () => {
const messages: ApiMessage[] = [
diff --git a/src/core/condense/index.ts b/src/core/condense/index.ts
index 166a8ba4ca..86cfa7ab1e 100644
--- a/src/core/condense/index.ts
+++ b/src/core/condense/index.ts
@@ -103,8 +103,8 @@ export async function summarizeConversation(
// Always preserve the first message (which may contain slash command content)
const firstMessage = messages[0]
- // Get messages to summarize, excluding the first message and last N messages
- const messagesToSummarize = getMessagesSinceLastSummary(messages.slice(1, -N_MESSAGES_TO_KEEP))
+ // Get messages to summarize, including the first message and excluding the last N messages
+ const messagesToSummarize = getMessagesSinceLastSummary(messages.slice(0, -N_MESSAGES_TO_KEEP))
if (messagesToSummarize.length <= 1) {
const error =
diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap
index ced0ede463..1dc60c72ed 100644
--- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap
+++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/architect-mode-prompt.snap
@@ -10,7 +10,7 @@ ALL responses MUST show ANY `language construct` OR filename reference as clicka
TOOL USE
-You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
+You have access to a set of tools that are executed upon the user's approval. You must use exactly one tool per message, and every assistant message must include a tool call. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap
index 90bbc1ae34..b860218ffc 100644
--- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap
+++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/ask-mode-prompt.snap
@@ -10,7 +10,7 @@ ALL responses MUST show ANY `language construct` OR filename reference as clicka
TOOL USE
-You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
+You have access to a set of tools that are executed upon the user's approval. You must use exactly one tool per message, and every assistant message must include a tool call. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap
index 9fdf29df77..553c5a5826 100644
--- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap
+++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-disabled.snap
@@ -10,7 +10,7 @@ ALL responses MUST show ANY `language construct` OR filename reference as clicka
TOOL USE
-You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
+You have access to a set of tools that are executed upon the user's approval. You must use exactly one tool per message, and every assistant message must include a tool call. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap
index 3594c8054f..50220f79ca 100644
--- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap
+++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/mcp-server-creation-enabled.snap
@@ -10,7 +10,7 @@ ALL responses MUST show ANY `language construct` OR filename reference as clicka
TOOL USE
-You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
+You have access to a set of tools that are executed upon the user's approval. You must use exactly one tool per message, and every assistant message must include a tool call. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
diff --git a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap
index 00e7d3f5db..be78c1a121 100644
--- a/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap
+++ b/src/core/prompts/__tests__/__snapshots__/add-custom-instructions/partial-reads-enabled.snap
@@ -10,7 +10,7 @@ ALL responses MUST show ANY `language construct` OR filename reference as clicka
TOOL USE
-You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
+You have access to a set of tools that are executed upon the user's approval. You must use exactly one tool per message, and every assistant message must include a tool call. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap
index ced0ede463..1dc60c72ed 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/consistent-system-prompt.snap
@@ -10,7 +10,7 @@ ALL responses MUST show ANY `language construct` OR filename reference as clicka
TOOL USE
-You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
+You have access to a set of tools that are executed upon the user's approval. You must use exactly one tool per message, and every assistant message must include a tool call. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap
index 72e208ee6a..561360ca6e 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-computer-use-support.snap
@@ -10,7 +10,7 @@ ALL responses MUST show ANY `language construct` OR filename reference as clicka
TOOL USE
-You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
+You have access to a set of tools that are executed upon the user's approval. You must use exactly one tool per message, and every assistant message must include a tool call. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap
index ced0ede463..1dc60c72ed 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-false.snap
@@ -10,7 +10,7 @@ ALL responses MUST show ANY `language construct` OR filename reference as clicka
TOOL USE
-You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
+You have access to a set of tools that are executed upon the user's approval. You must use exactly one tool per message, and every assistant message must include a tool call. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap
index 72aa071ce6..e1147f96bc 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-true.snap
@@ -10,7 +10,7 @@ ALL responses MUST show ANY `language construct` OR filename reference as clicka
TOOL USE
-You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
+You have access to a set of tools that are executed upon the user's approval. You must use exactly one tool per message, and every assistant message must include a tool call. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap
index ced0ede463..1dc60c72ed 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-diff-enabled-undefined.snap
@@ -10,7 +10,7 @@ ALL responses MUST show ANY `language construct` OR filename reference as clicka
TOOL USE
-You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
+You have access to a set of tools that are executed upon the user's approval. You must use exactly one tool per message, and every assistant message must include a tool call. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap
index 83271f47ad..fe856adb40 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-different-viewport-size.snap
@@ -10,7 +10,7 @@ ALL responses MUST show ANY `language construct` OR filename reference as clicka
TOOL USE
-You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
+You have access to a set of tools that are executed upon the user's approval. You must use exactly one tool per message, and every assistant message must include a tool call. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap
index 3594c8054f..50220f79ca 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-mcp-hub-provided.snap
@@ -10,7 +10,7 @@ ALL responses MUST show ANY `language construct` OR filename reference as clicka
TOOL USE
-You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
+You have access to a set of tools that are executed upon the user's approval. You must use exactly one tool per message, and every assistant message must include a tool call. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
diff --git a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap
index ced0ede463..1dc60c72ed 100644
--- a/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap
+++ b/src/core/prompts/__tests__/__snapshots__/system-prompt/with-undefined-mcp-hub.snap
@@ -10,7 +10,7 @@ ALL responses MUST show ANY `language construct` OR filename reference as clicka
TOOL USE
-You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
+You have access to a set of tools that are executed upon the user's approval. You must use exactly one tool per message, and every assistant message must include a tool call. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
diff --git a/src/core/prompts/sections/tool-use.ts b/src/core/prompts/sections/tool-use.ts
index c598fabae3..28d47d0985 100644
--- a/src/core/prompts/sections/tool-use.ts
+++ b/src/core/prompts/sections/tool-use.ts
@@ -3,7 +3,7 @@ export function getSharedToolUseSection(): string {
TOOL USE
-You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
+You have access to a set of tools that are executed upon the user's approval. You must use exactly one tool per message, and every assistant message must include a tool call. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
# Tool Use Formatting
diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts
index cf16df8dcc..2dd9e55c0b 100644
--- a/src/core/task/Task.ts
+++ b/src/core/task/Task.ts
@@ -212,6 +212,7 @@ export class Task extends EventEmitter implements TaskLike {
didFinishAbortingStream = false
abandoned = false
+ abortReason?: ClineApiReqCancelReason
isInitialized = false
isPaused: boolean = false
pausedModeSlug: string = defaultModeSlug
@@ -1264,6 +1265,16 @@ export class Task extends EventEmitter implements TaskLike {
modifiedClineMessages.splice(lastRelevantMessageIndex + 1)
}
+ // Remove any trailing reasoning-only UI messages that were not part of the persisted API conversation
+ while (modifiedClineMessages.length > 0) {
+ const last = modifiedClineMessages[modifiedClineMessages.length - 1]
+ if (last.type === "say" && last.say === "reasoning") {
+ modifiedClineMessages.pop()
+ } else {
+ break
+ }
+ }
+
// Since we don't use `api_req_finished` anymore, we need to check if the
// last `api_req_started` has a cost value, if it doesn't and no
// cancellation reason to present, then we remove it since it indicates
@@ -1884,28 +1895,10 @@ export class Task extends EventEmitter implements TaskLike {
lastMessage.partial = false
// instead of streaming partialMessage events, we do a save and post like normal to persist to disk
console.log("updating partial message", lastMessage)
- // await this.saveClineMessages()
}
- // Let assistant know their response was interrupted for when task is resumed
- await this.addToApiConversationHistory({
- role: "assistant",
- content: [
- {
- type: "text",
- text:
- assistantMessage +
- `\n\n[${
- cancelReason === "streaming_failed"
- ? "Response interrupted by API Error"
- : "Response interrupted by user"
- }]`,
- },
- ],
- })
-
// Update `api_req_started` to have cancelled and cost, so that
- // we can display the cost of the partial stream.
+ // we can display the cost of the partial stream and the cancellation reason
updateApiReqMsg(cancelReason, streamingFailedMessage)
await this.saveClineMessages()
@@ -1951,10 +1944,22 @@ export class Task extends EventEmitter implements TaskLike {
}
switch (chunk.type) {
- case "reasoning":
+ case "reasoning": {
reasoningMessage += chunk.text
- await this.say("reasoning", reasoningMessage, undefined, true)
+ // Only apply formatting if the message contains sentence-ending punctuation followed by **
+ let formattedReasoning = reasoningMessage
+ if (reasoningMessage.includes("**")) {
+ // Add line breaks before **Title** patterns that appear after sentence endings
+ // This targets section headers like "...end of sentence.**Title Here**"
+ // Handles periods, exclamation marks, and question marks
+ formattedReasoning = reasoningMessage.replace(
+ /([.!?])\*\*([^*\n]+)\*\*/g,
+ "$1\n\n**$2**",
+ )
+ }
+ await this.say("reasoning", formattedReasoning, undefined, true)
break
+ }
case "usage":
inputTokens += chunk.inputTokens
outputTokens += chunk.outputTokens
@@ -2187,24 +2192,23 @@ export class Task extends EventEmitter implements TaskLike {
// may have executed), so we just resort to replicating a
// cancel task.
- // Check if this was a user-initiated cancellation BEFORE calling abortTask
- // If this.abort is already true, it means the user clicked cancel, so we should
- // treat this as "user_cancelled" rather than "streaming_failed"
- const cancelReason = this.abort ? "user_cancelled" : "streaming_failed"
+ // Determine cancellation reason BEFORE aborting to ensure correct persistence
+ const cancelReason: ClineApiReqCancelReason = this.abort ? "user_cancelled" : "streaming_failed"
const streamingFailedMessage = this.abort
? undefined
: (error.message ?? JSON.stringify(serializeError(error), null, 2))
- // Now call abortTask after determining the cancel reason.
- await this.abortTask()
+ // Persist interruption details first to both UI and API histories
await abortStream(cancelReason, streamingFailedMessage)
- const history = await provider?.getTaskWithId(this.taskId)
+ // Record reason for provider to decide rehydration path
+ this.abortReason = cancelReason
- if (history) {
- await provider?.createTaskWithHistoryItem(history.historyItem)
- }
+ // Now abort (emits TaskAborted which provider listens to)
+ await this.abortTask()
+
+ // Do not rehydrate here; provider owns rehydration to avoid duplication races
}
} finally {
this.isStreaming = false
diff --git a/src/core/tools/__tests__/updateTodoListTool.spec.ts b/src/core/tools/__tests__/updateTodoListTool.spec.ts
new file mode 100644
index 0000000000..0b7e810572
--- /dev/null
+++ b/src/core/tools/__tests__/updateTodoListTool.spec.ts
@@ -0,0 +1,243 @@
+import { describe, it, expect, beforeEach, vi } from "vitest"
+import { parseMarkdownChecklist } from "../updateTodoListTool"
+import { TodoItem } from "@roo-code/types"
+
+describe("parseMarkdownChecklist", () => {
+ describe("standard checkbox format (without dash prefix)", () => {
+ it("should parse pending tasks", () => {
+ const md = `[ ] Task 1
+[ ] Task 2`
+ const result = parseMarkdownChecklist(md)
+ expect(result).toHaveLength(2)
+ expect(result[0].content).toBe("Task 1")
+ expect(result[0].status).toBe("pending")
+ expect(result[1].content).toBe("Task 2")
+ expect(result[1].status).toBe("pending")
+ })
+
+ it("should parse completed tasks with lowercase x", () => {
+ const md = `[x] Completed task 1
+[x] Completed task 2`
+ const result = parseMarkdownChecklist(md)
+ expect(result).toHaveLength(2)
+ expect(result[0].content).toBe("Completed task 1")
+ expect(result[0].status).toBe("completed")
+ expect(result[1].content).toBe("Completed task 2")
+ expect(result[1].status).toBe("completed")
+ })
+
+ it("should parse completed tasks with uppercase X", () => {
+ const md = `[X] Completed task 1
+[X] Completed task 2`
+ const result = parseMarkdownChecklist(md)
+ expect(result).toHaveLength(2)
+ expect(result[0].content).toBe("Completed task 1")
+ expect(result[0].status).toBe("completed")
+ expect(result[1].content).toBe("Completed task 2")
+ expect(result[1].status).toBe("completed")
+ })
+
+ it("should parse in-progress tasks with dash", () => {
+ const md = `[-] In progress task 1
+[-] In progress task 2`
+ const result = parseMarkdownChecklist(md)
+ expect(result).toHaveLength(2)
+ expect(result[0].content).toBe("In progress task 1")
+ expect(result[0].status).toBe("in_progress")
+ expect(result[1].content).toBe("In progress task 2")
+ expect(result[1].status).toBe("in_progress")
+ })
+
+ it("should parse in-progress tasks with tilde", () => {
+ const md = `[~] In progress task 1
+[~] In progress task 2`
+ const result = parseMarkdownChecklist(md)
+ expect(result).toHaveLength(2)
+ expect(result[0].content).toBe("In progress task 1")
+ expect(result[0].status).toBe("in_progress")
+ expect(result[1].content).toBe("In progress task 2")
+ expect(result[1].status).toBe("in_progress")
+ })
+ })
+
+ describe("dash-prefixed checkbox format", () => {
+ it("should parse pending tasks with dash prefix", () => {
+ const md = `- [ ] Task 1
+- [ ] Task 2`
+ const result = parseMarkdownChecklist(md)
+ expect(result).toHaveLength(2)
+ expect(result[0].content).toBe("Task 1")
+ expect(result[0].status).toBe("pending")
+ expect(result[1].content).toBe("Task 2")
+ expect(result[1].status).toBe("pending")
+ })
+
+ it("should parse completed tasks with dash prefix and lowercase x", () => {
+ const md = `- [x] Completed task 1
+- [x] Completed task 2`
+ const result = parseMarkdownChecklist(md)
+ expect(result).toHaveLength(2)
+ expect(result[0].content).toBe("Completed task 1")
+ expect(result[0].status).toBe("completed")
+ expect(result[1].content).toBe("Completed task 2")
+ expect(result[1].status).toBe("completed")
+ })
+
+ it("should parse completed tasks with dash prefix and uppercase X", () => {
+ const md = `- [X] Completed task 1
+- [X] Completed task 2`
+ const result = parseMarkdownChecklist(md)
+ expect(result).toHaveLength(2)
+ expect(result[0].content).toBe("Completed task 1")
+ expect(result[0].status).toBe("completed")
+ expect(result[1].content).toBe("Completed task 2")
+ expect(result[1].status).toBe("completed")
+ })
+
+ it("should parse in-progress tasks with dash prefix and dash marker", () => {
+ const md = `- [-] In progress task 1
+- [-] In progress task 2`
+ const result = parseMarkdownChecklist(md)
+ expect(result).toHaveLength(2)
+ expect(result[0].content).toBe("In progress task 1")
+ expect(result[0].status).toBe("in_progress")
+ expect(result[1].content).toBe("In progress task 2")
+ expect(result[1].status).toBe("in_progress")
+ })
+
+ it("should parse in-progress tasks with dash prefix and tilde marker", () => {
+ const md = `- [~] In progress task 1
+- [~] In progress task 2`
+ const result = parseMarkdownChecklist(md)
+ expect(result).toHaveLength(2)
+ expect(result[0].content).toBe("In progress task 1")
+ expect(result[0].status).toBe("in_progress")
+ expect(result[1].content).toBe("In progress task 2")
+ expect(result[1].status).toBe("in_progress")
+ })
+ })
+
+ describe("mixed formats", () => {
+ it("should parse mixed formats correctly", () => {
+ const md = `[ ] Task without dash
+- [ ] Task with dash
+[x] Completed without dash
+- [X] Completed with dash
+[-] In progress without dash
+- [~] In progress with dash`
+ const result = parseMarkdownChecklist(md)
+ expect(result).toHaveLength(6)
+
+ expect(result[0].content).toBe("Task without dash")
+ expect(result[0].status).toBe("pending")
+
+ expect(result[1].content).toBe("Task with dash")
+ expect(result[1].status).toBe("pending")
+
+ expect(result[2].content).toBe("Completed without dash")
+ expect(result[2].status).toBe("completed")
+
+ expect(result[3].content).toBe("Completed with dash")
+ expect(result[3].status).toBe("completed")
+
+ expect(result[4].content).toBe("In progress without dash")
+ expect(result[4].status).toBe("in_progress")
+
+ expect(result[5].content).toBe("In progress with dash")
+ expect(result[5].status).toBe("in_progress")
+ })
+ })
+
+ describe("edge cases", () => {
+ it("should handle empty strings", () => {
+ const result = parseMarkdownChecklist("")
+ expect(result).toEqual([])
+ })
+
+ it("should handle non-string input", () => {
+ const result = parseMarkdownChecklist(null as any)
+ expect(result).toEqual([])
+ })
+
+ it("should handle undefined input", () => {
+ const result = parseMarkdownChecklist(undefined as any)
+ expect(result).toEqual([])
+ })
+
+ it("should ignore non-checklist lines", () => {
+ const md = `This is not a checklist
+[ ] Valid task
+Just some text
+- Not a checklist item
+- [x] Valid completed task
+[not valid] Invalid format`
+ const result = parseMarkdownChecklist(md)
+ expect(result).toHaveLength(2)
+ expect(result[0].content).toBe("Valid task")
+ expect(result[0].status).toBe("pending")
+ expect(result[1].content).toBe("Valid completed task")
+ expect(result[1].status).toBe("completed")
+ })
+
+ it("should handle extra spaces", () => {
+ const md = ` [ ] Task with spaces
+- [ ] Task with dash and spaces
+ [x] Completed with spaces
+- [X] Completed with dash and spaces`
+ const result = parseMarkdownChecklist(md)
+ expect(result).toHaveLength(4)
+ expect(result[0].content).toBe("Task with spaces")
+ expect(result[1].content).toBe("Task with dash and spaces")
+ expect(result[2].content).toBe("Completed with spaces")
+ expect(result[3].content).toBe("Completed with dash and spaces")
+ })
+
+ it("should handle Windows line endings", () => {
+ const md = "[ ] Task 1\r\n- [x] Task 2\r\n[-] Task 3"
+ const result = parseMarkdownChecklist(md)
+ expect(result).toHaveLength(3)
+ expect(result[0].content).toBe("Task 1")
+ expect(result[0].status).toBe("pending")
+ expect(result[1].content).toBe("Task 2")
+ expect(result[1].status).toBe("completed")
+ expect(result[2].content).toBe("Task 3")
+ expect(result[2].status).toBe("in_progress")
+ })
+ })
+
+ describe("ID generation", () => {
+ it("should generate consistent IDs for the same content and status", () => {
+ const md1 = `[ ] Task 1
+[x] Task 2`
+ const md2 = `[ ] Task 1
+[x] Task 2`
+ const result1 = parseMarkdownChecklist(md1)
+ const result2 = parseMarkdownChecklist(md2)
+
+ expect(result1[0].id).toBe(result2[0].id)
+ expect(result1[1].id).toBe(result2[1].id)
+ })
+
+ it("should generate different IDs for different content", () => {
+ const md = `[ ] Task 1
+[ ] Task 2`
+ const result = parseMarkdownChecklist(md)
+ expect(result[0].id).not.toBe(result[1].id)
+ })
+
+ it("should generate different IDs for same content but different status", () => {
+ const md = `[ ] Task 1
+[x] Task 1`
+ const result = parseMarkdownChecklist(md)
+ expect(result[0].id).not.toBe(result[1].id)
+ })
+
+ it("should generate same IDs regardless of dash prefix", () => {
+ const md1 = `[ ] Task 1`
+ const md2 = `- [ ] Task 1`
+ const result1 = parseMarkdownChecklist(md1)
+ const result2 = parseMarkdownChecklist(md2)
+ expect(result1[0].id).toBe(result2[0].id)
+ })
+ })
+})
diff --git a/src/core/tools/multiApplyDiffTool.ts b/src/core/tools/multiApplyDiffTool.ts
index d0fe655750..a30778c5af 100644
--- a/src/core/tools/multiApplyDiffTool.ts
+++ b/src/core/tools/multiApplyDiffTool.ts
@@ -463,7 +463,7 @@ Error: ${failPart.error}
Suggested fixes:
1. Verify the search content exactly matches the file content (including whitespace and case)
2. Check for correct indentation and line endings
-3. Use to see the current file content
+3. Use the read_file tool to verify the file's current contents
4. Consider breaking complex changes into smaller diffs
5. Ensure start_line parameter matches the actual content location
${errorDetails ? `\nDetailed error information:\n${errorDetails}\n` : ""}
@@ -476,7 +476,7 @@ Unable to apply diffs to file: ${absolutePath}
Error: ${diffResult.error}
Recovery suggestions:
-1. Use to examine the current file content
+1. Use the read_file tool to verify the file's current contents
2. Verify the diff format matches the expected search/replace pattern
3. Check that the search content exactly matches what's in the file
4. Consider using line numbers with start_line parameter
diff --git a/src/core/tools/updateTodoListTool.ts b/src/core/tools/updateTodoListTool.ts
index de96c3cc76..fcd41914a8 100644
--- a/src/core/tools/updateTodoListTool.ts
+++ b/src/core/tools/updateTodoListTool.ts
@@ -108,7 +108,8 @@ export function parseMarkdownChecklist(md: string): TodoItem[] {
.filter(Boolean)
const todos: TodoItem[] = []
for (const line of lines) {
- const match = line.match(/^\[\s*([ xX\-~])\s*\]\s+(.+)$/)
+ // Support both "[ ] Task" and "- [ ] Task" formats
+ const match = line.match(/^(?:-\s*)?\[\s*([ xX\-~])\s*\]\s+(.+)$/)
if (!match) continue
let status: TodoStatus = "pending"
if (match[1] === "x" || match[1] === "X") status = "completed"
diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts
index 0304c4c6de..1e866b2aa9 100644
--- a/src/core/webview/ClineProvider.ts
+++ b/src/core/webview/ClineProvider.ts
@@ -30,6 +30,7 @@ import {
type TerminalActionPromptType,
type HistoryItem,
type CloudUserInfo,
+ type CloudOrganizationMembership,
type CreateTaskOptions,
type TokenUsage,
RooCodeEventName,
@@ -89,6 +90,8 @@ import { Task } from "../task/Task"
import { getSystemPromptFilePath } from "../prompts/sections/custom-system-prompt"
import { webviewMessageHandler } from "./webviewMessageHandler"
+import type { ClineMessage } from "@roo-code/types"
+import { readApiMessages, saveApiMessages, saveTaskMessages } from "../task-persistence"
import { getNonce } from "./getNonce"
import { getUri } from "./getUri"
@@ -141,7 +144,7 @@ export class ClineProvider
public isViewLaunched = false
public settingsImportedAt?: number
- public readonly latestAnnouncementId = "sep-2025-roo-code-cloud" // Roo Code Cloud announcement
+ public readonly latestAnnouncementId = "sep-2025-code-supernova" // Code Supernova stealth model announcement
public readonly providerSettingsManager: ProviderSettingsManager
public readonly customModesManager: CustomModesManager
@@ -196,7 +199,35 @@ export class ClineProvider
const onTaskStarted = () => this.emit(RooCodeEventName.TaskStarted, instance.taskId)
const onTaskCompleted = (taskId: string, tokenUsage: any, toolUsage: any) =>
this.emit(RooCodeEventName.TaskCompleted, taskId, tokenUsage, toolUsage)
- const onTaskAborted = () => this.emit(RooCodeEventName.TaskAborted, instance.taskId)
+ const onTaskAborted = async () => {
+ this.emit(RooCodeEventName.TaskAborted, instance.taskId)
+
+ try {
+ // Only rehydrate on genuine streaming failures.
+ // User-initiated cancels are handled by cancelTask().
+ if (instance.abortReason === "streaming_failed") {
+ // Defensive safeguard: if another path already replaced this instance, skip
+ const current = this.getCurrentTask()
+ if (current && current.instanceId !== instance.instanceId) {
+ this.log(
+ `[onTaskAborted] Skipping rehydrate: current instance ${current.instanceId} != aborted ${instance.instanceId}`,
+ )
+ return
+ }
+
+ const { historyItem } = await this.getTaskWithId(instance.taskId)
+ const rootTask = instance.rootTask
+ const parentTask = instance.parentTask
+ await this.createTaskWithHistoryItem({ ...historyItem, rootTask, parentTask })
+ }
+ } catch (error) {
+ this.log(
+ `[onTaskAborted] Failed to rehydrate after streaming failure: ${
+ error instanceof Error ? error.message : String(error)
+ }`,
+ )
+ }
+ }
const onTaskFocused = () => this.emit(RooCodeEventName.TaskFocused, instance.taskId)
const onTaskUnfocused = () => this.emit(RooCodeEventName.TaskUnfocused, instance.taskId)
const onTaskActive = (taskId: string) => this.emit(RooCodeEventName.TaskActive, taskId)
@@ -1761,6 +1792,7 @@ export class ClineProvider
maxTotalImageSize,
terminalCompressProgressBar,
historyPreviewCollapsed,
+ reasoningBlockCollapsed,
cloudUserInfo,
cloudIsAuthenticated,
sharingEnabled,
@@ -1785,6 +1817,16 @@ export class ClineProvider
featureRoomoteControlEnabled,
} = await this.getState()
+ let cloudOrganizations: CloudOrganizationMembership[] = []
+
+ try {
+ cloudOrganizations = await CloudService.instance.getOrganizationMemberships()
+ } catch (error) {
+ console.error(
+ `[getStateToPostToWebview] failed to get cloud organizations: ${error instanceof Error ? error.message : String(error)}`,
+ )
+ }
+
const telemetryKey = process.env.POSTHOG_API_KEY
const machineId = vscode.env.machineId
const mergedAllowedCommands = this.mergeAllowedCommands(allowedCommands)
@@ -1884,8 +1926,10 @@ export class ClineProvider
terminalCompressProgressBar: terminalCompressProgressBar ?? true,
hasSystemPromptOverride,
historyPreviewCollapsed: historyPreviewCollapsed ?? false,
+ reasoningBlockCollapsed: reasoningBlockCollapsed ?? true,
cloudUserInfo,
cloudIsAuthenticated: cloudIsAuthenticated ?? false,
+ cloudOrganizations,
sharingEnabled: sharingEnabled ?? false,
organizationAllowList,
organizationSettingsVersion,
@@ -2097,6 +2141,7 @@ export class ClineProvider
maxTotalImageSize: stateValues.maxTotalImageSize ?? 20,
maxConcurrentFileReads: stateValues.maxConcurrentFileReads ?? 5,
historyPreviewCollapsed: stateValues.historyPreviewCollapsed ?? false,
+ reasoningBlockCollapsed: stateValues.reasoningBlockCollapsed ?? true,
cloudUserInfo,
cloudIsAuthenticated,
sharingEnabled,
@@ -2210,6 +2255,18 @@ export class ClineProvider
return
}
+ // Log out from cloud if authenticated
+ if (CloudService.hasInstance()) {
+ try {
+ await CloudService.instance.logout()
+ } catch (error) {
+ this.log(
+ `Failed to logout from cloud during reset: ${error instanceof Error ? error.message : String(error)}`,
+ )
+ // Continue with reset even if logout fails
+ }
+ }
+
await this.contextProxy.resetAllState()
await this.providerSettingsManager.resetAllConfigs()
await this.customModesManager.resetCustomModes()
@@ -2525,14 +2582,24 @@ export class ClineProvider
console.log(`[cancelTask] cancelling task ${task.taskId}.${task.instanceId}`)
- const { historyItem } = await this.getTaskWithId(task.taskId)
+ const { historyItem, uiMessagesFilePath } = await this.getTaskWithId(task.taskId)
// Preserve parent and root task information for history item.
const rootTask = task.rootTask
const parentTask = task.parentTask
+ // Mark this as a user-initiated cancellation so provider-only rehydration can occur
+ task.abortReason = "user_cancelled"
+
+ // Capture the current instance to detect if rehydrate already occurred elsewhere
+ const originalInstanceId = task.instanceId
+
+ // Begin abort (non-blocking)
task.abortTask()
+ // Immediately mark the original instance as abandoned to prevent any residual activity
+ task.abandoned = true
+
await pWaitFor(
() =>
this.getCurrentTask()! === undefined ||
@@ -2549,11 +2616,24 @@ export class ClineProvider
console.error("Failed to abort task")
})
- if (this.getCurrentTask()) {
- // 'abandoned' will prevent this Cline instance from affecting
- // future Cline instances. This may happen if its hanging on a
- // streaming request.
- this.getCurrentTask()!.abandoned = true
+ // Defensive safeguard: if current instance already changed, skip rehydrate
+ const current = this.getCurrentTask()
+ if (current && current.instanceId !== originalInstanceId) {
+ this.log(
+ `[cancelTask] Skipping rehydrate: current instance ${current.instanceId} != original ${originalInstanceId}`,
+ )
+ return
+ }
+
+ // Final race check before rehydrate to avoid duplicate rehydration
+ {
+ const currentAfterCheck = this.getCurrentTask()
+ if (currentAfterCheck && currentAfterCheck.instanceId !== originalInstanceId) {
+ this.log(
+ `[cancelTask] Skipping rehydrate after final check: current instance ${currentAfterCheck.instanceId} != original ${originalInstanceId}`,
+ )
+ return
+ }
}
// Clears task again, so we need to abortTask manually above.
diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts
index c2cec9138d..55cd1e3cb8 100644
--- a/src/core/webview/webviewMessageHandler.ts
+++ b/src/core/webview/webviewMessageHandler.ts
@@ -1060,6 +1060,18 @@ export const webviewMessageHandler = async (
break
}
+ case "openKeyboardShortcuts": {
+ // Open VSCode keyboard shortcuts settings and optionally filter to show the Roo Code commands
+ const searchQuery = message.text || ""
+ if (searchQuery) {
+ // Open with a search query pre-filled
+ await vscode.commands.executeCommand("workbench.action.openGlobalKeybindings", searchQuery)
+ } else {
+ // Just open the keyboard shortcuts settings
+ await vscode.commands.executeCommand("workbench.action.openGlobalKeybindings")
+ }
+ break
+ }
case "openMcpSettings": {
const mcpSettingsFilePath = await provider.getMcpHub()?.getMcpSettingsFilePath()
@@ -1621,6 +1633,10 @@ export const webviewMessageHandler = async (
await updateGlobalState("historyPreviewCollapsed", message.bool ?? false)
// No need to call postStateToWebview here as the UI already updated optimistically
break
+ case "setReasoningBlockCollapsed":
+ await updateGlobalState("reasoningBlockCollapsed", message.bool ?? true)
+ // No need to call postStateToWebview here as the UI already updated optimistically
+ break
case "toggleApiConfigPin":
if (message.text) {
const currentPinned = getGlobalState("pinnedApiConfigs") ?? {}
@@ -2318,6 +2334,17 @@ export const webviewMessageHandler = async (
break
}
+ case "cloudLandingPageSignIn": {
+ try {
+ const landingPageSlug = message.text || "supernova"
+ TelemetryService.instance.captureEvent(TelemetryEventName.AUTHENTICATION_INITIATED)
+ await CloudService.instance.login(landingPageSlug)
+ } catch (error) {
+ provider.log(`CloudService#login failed: ${error}`)
+ vscode.window.showErrorMessage("Sign in failed.")
+ }
+ break
+ }
case "rooCloudSignOut": {
try {
await CloudService.instance.logout()
@@ -2372,6 +2399,38 @@ export const webviewMessageHandler = async (
break
}
+ case "switchOrganization": {
+ try {
+ const organizationId = message.organizationId ?? null
+
+ // Switch to the new organization context
+ await CloudService.instance.switchOrganization(organizationId)
+
+ // Refresh the state to update UI
+ await provider.postStateToWebview()
+
+ // Send success response back to webview
+ await provider.postMessageToWebview({
+ type: "organizationSwitchResult",
+ success: true,
+ organizationId: organizationId,
+ })
+ } catch (error) {
+ provider.log(`Organization switch failed: ${error}`)
+ const errorMessage = error instanceof Error ? error.message : String(error)
+
+ // Send error response back to webview
+ await provider.postMessageToWebview({
+ type: "organizationSwitchResult",
+ success: false,
+ error: errorMessage,
+ organizationId: message.organizationId ?? null,
+ })
+
+ vscode.window.showErrorMessage(`Failed to switch organization: ${errorMessage}`)
+ }
+ break
+ }
case "saveCodeIndexSettingsAtomic": {
if (!message.codeIndexSettings) {
diff --git a/src/extension.ts b/src/extension.ts
index dc96e282c4..5db0996ad6 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -194,7 +194,7 @@ export async function activate(context: vscode.ExtensionContext) {
// Add to subscriptions for proper cleanup on deactivate.
context.subscriptions.push(cloudService)
- // Trigger initial cloud profile sync now that CloudService is ready
+ // Trigger initial cloud profile sync now that CloudService is ready.
try {
await provider.initializeCloudProfileSyncWhenReady()
} catch (error) {
diff --git a/src/i18n/locales/ca/common.json b/src/i18n/locales/ca/common.json
index b71b7eb913..a1f528ef97 100644
--- a/src/i18n/locales/ca/common.json
+++ b/src/i18n/locales/ca/common.json
@@ -165,6 +165,10 @@
"incomplete": "Tasca #{{taskNumber}} (Incompleta)",
"no_messages": "Tasca #{{taskNumber}} (Sense missatges)"
},
+ "interruption": {
+ "responseInterruptedByUser": "Resposta interrompuda per l'usuari",
+ "responseInterruptedByApiError": "Resposta interrompuda per error d'API"
+ },
"storage": {
"prompt_custom_path": "Introdueix una ruta d'emmagatzematge personalitzada per a l'historial de converses o deixa-ho buit per utilitzar la ubicació predeterminada",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json
index 6577d460d1..dbd9452e60 100644
--- a/src/i18n/locales/de/common.json
+++ b/src/i18n/locales/de/common.json
@@ -161,6 +161,10 @@
"incomplete": "Aufgabe #{{taskNumber}} (Unvollständig)",
"no_messages": "Aufgabe #{{taskNumber}} (Keine Nachrichten)"
},
+ "interruption": {
+ "responseInterruptedByUser": "Antwort vom Benutzer unterbrochen",
+ "responseInterruptedByApiError": "Antwort durch API-Fehler unterbrochen"
+ },
"storage": {
"prompt_custom_path": "Gib den benutzerdefinierten Speicherpfad für den Gesprächsverlauf ein, leer lassen für Standardspeicherort",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json
index e8c264ba68..3a613cc1c2 100644
--- a/src/i18n/locales/en/common.json
+++ b/src/i18n/locales/en/common.json
@@ -161,6 +161,10 @@
"incomplete": "Task #{{taskNumber}} (Incomplete)",
"no_messages": "Task #{{taskNumber}} (No messages)"
},
+ "interruption": {
+ "responseInterruptedByUser": "Response interrupted by user",
+ "responseInterruptedByApiError": "Response interrupted by API error"
+ },
"storage": {
"prompt_custom_path": "Enter custom conversation history storage path, leave empty to use default location",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/es/common.json b/src/i18n/locales/es/common.json
index 5cfa3c5749..49dcfe98c5 100644
--- a/src/i18n/locales/es/common.json
+++ b/src/i18n/locales/es/common.json
@@ -161,6 +161,10 @@
"incomplete": "Tarea #{{taskNumber}} (Incompleta)",
"no_messages": "Tarea #{{taskNumber}} (Sin mensajes)"
},
+ "interruption": {
+ "responseInterruptedByUser": "Respuesta interrumpida por el usuario",
+ "responseInterruptedByApiError": "Respuesta interrumpida por error de API"
+ },
"storage": {
"prompt_custom_path": "Ingresa la ruta de almacenamiento personalizada para el historial de conversaciones, déjala vacía para usar la ubicación predeterminada",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/fr/common.json b/src/i18n/locales/fr/common.json
index 5a11c874a7..260bbbf13b 100644
--- a/src/i18n/locales/fr/common.json
+++ b/src/i18n/locales/fr/common.json
@@ -161,6 +161,10 @@
"incomplete": "Tâche #{{taskNumber}} (Incomplète)",
"no_messages": "Tâche #{{taskNumber}} (Aucun message)"
},
+ "interruption": {
+ "responseInterruptedByUser": "Réponse interrompue par l'utilisateur",
+ "responseInterruptedByApiError": "Réponse interrompue par une erreur d'API"
+ },
"storage": {
"prompt_custom_path": "Entrez le chemin de stockage personnalisé pour l'historique des conversations, laissez vide pour utiliser l'emplacement par défaut",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/hi/common.json b/src/i18n/locales/hi/common.json
index e89c16cbd0..ab7d594e8f 100644
--- a/src/i18n/locales/hi/common.json
+++ b/src/i18n/locales/hi/common.json
@@ -161,6 +161,10 @@
"incomplete": "टास्क #{{taskNumber}} (अधूरा)",
"no_messages": "टास्क #{{taskNumber}} (कोई संदेश नहीं)"
},
+ "interruption": {
+ "responseInterruptedByUser": "उपयोगकर्ता द्वारा प्रतिक्रिया बाधित",
+ "responseInterruptedByApiError": "API त्रुटि द्वारा प्रतिक्रिया बाधित"
+ },
"storage": {
"prompt_custom_path": "वार्तालाप इतिहास के लिए कस्टम स्टोरेज पाथ दर्ज करें, डिफ़ॉल्ट स्थान का उपयोग करने के लिए खाली छोड़ दें",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/id/common.json b/src/i18n/locales/id/common.json
index ae1662eb37..ddd549b6f0 100644
--- a/src/i18n/locales/id/common.json
+++ b/src/i18n/locales/id/common.json
@@ -161,6 +161,10 @@
"incomplete": "Tugas #{{taskNumber}} (Tidak lengkap)",
"no_messages": "Tugas #{{taskNumber}} (Tidak ada pesan)"
},
+ "interruption": {
+ "responseInterruptedByUser": "Respons diinterupsi oleh pengguna",
+ "responseInterruptedByApiError": "Respons diinterupsi oleh error API"
+ },
"storage": {
"prompt_custom_path": "Masukkan path penyimpanan riwayat percakapan kustom, biarkan kosong untuk menggunakan lokasi default",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/it/common.json b/src/i18n/locales/it/common.json
index aeaec11d0d..80e8e0633b 100644
--- a/src/i18n/locales/it/common.json
+++ b/src/i18n/locales/it/common.json
@@ -161,6 +161,10 @@
"incomplete": "Attività #{{taskNumber}} (Incompleta)",
"no_messages": "Attività #{{taskNumber}} (Nessun messaggio)"
},
+ "interruption": {
+ "responseInterruptedByUser": "Risposta interrotta dall'utente",
+ "responseInterruptedByApiError": "Risposta interrotta da errore API"
+ },
"storage": {
"prompt_custom_path": "Inserisci il percorso di archiviazione personalizzato per la cronologia delle conversazioni, lascia vuoto per utilizzare la posizione predefinita",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json
index a607dbffd5..accba790a2 100644
--- a/src/i18n/locales/ja/common.json
+++ b/src/i18n/locales/ja/common.json
@@ -161,6 +161,10 @@
"incomplete": "タスク #{{taskNumber}} (未完了)",
"no_messages": "タスク #{{taskNumber}} (メッセージなし)"
},
+ "interruption": {
+ "responseInterruptedByUser": "ユーザーによって応答が中断されました",
+ "responseInterruptedByApiError": "APIエラーによって応答が中断されました"
+ },
"storage": {
"prompt_custom_path": "会話履歴のカスタムストレージパスを入力してください。デフォルトの場所を使用する場合は空のままにしてください",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json
index e48b84fe20..acb7bd47d7 100644
--- a/src/i18n/locales/ko/common.json
+++ b/src/i18n/locales/ko/common.json
@@ -161,6 +161,10 @@
"incomplete": "작업 #{{taskNumber}} (미완료)",
"no_messages": "작업 #{{taskNumber}} (메시지 없음)"
},
+ "interruption": {
+ "responseInterruptedByUser": "사용자에 의해 응답이 중단됨",
+ "responseInterruptedByApiError": "API 오류로 인해 응답이 중단됨"
+ },
"storage": {
"prompt_custom_path": "대화 내역을 위한 사용자 지정 저장 경로를 입력하세요. 기본 위치를 사용하려면 비워두세요",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/nl/common.json b/src/i18n/locales/nl/common.json
index 0e3e2459a0..d43690c435 100644
--- a/src/i18n/locales/nl/common.json
+++ b/src/i18n/locales/nl/common.json
@@ -161,6 +161,10 @@
"incomplete": "Taak #{{taskNumber}} (Onvolledig)",
"no_messages": "Taak #{{taskNumber}} (Geen berichten)"
},
+ "interruption": {
+ "responseInterruptedByUser": "Reactie onderbroken door gebruiker",
+ "responseInterruptedByApiError": "Reactie onderbroken door API-fout"
+ },
"storage": {
"prompt_custom_path": "Voer een aangepast opslagpad voor gespreksgeschiedenis in, laat leeg voor standaardlocatie",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/pl/common.json b/src/i18n/locales/pl/common.json
index 1d48b0f9cc..56c076f785 100644
--- a/src/i18n/locales/pl/common.json
+++ b/src/i18n/locales/pl/common.json
@@ -161,6 +161,10 @@
"incomplete": "Zadanie #{{taskNumber}} (Niekompletne)",
"no_messages": "Zadanie #{{taskNumber}} (Brak wiadomości)"
},
+ "interruption": {
+ "responseInterruptedByUser": "Odpowiedź przerwana przez użytkownika",
+ "responseInterruptedByApiError": "Odpowiedź przerwana przez błąd API"
+ },
"storage": {
"prompt_custom_path": "Wprowadź niestandardową ścieżkę przechowywania dla historii konwersacji lub pozostaw puste, aby użyć lokalizacji domyślnej",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/pt-BR/common.json b/src/i18n/locales/pt-BR/common.json
index 093ef7b0bf..c2cd63255f 100644
--- a/src/i18n/locales/pt-BR/common.json
+++ b/src/i18n/locales/pt-BR/common.json
@@ -165,6 +165,10 @@
"incomplete": "Tarefa #{{taskNumber}} (Incompleta)",
"no_messages": "Tarefa #{{taskNumber}} (Sem mensagens)"
},
+ "interruption": {
+ "responseInterruptedByUser": "Resposta interrompida pelo usuário",
+ "responseInterruptedByApiError": "Resposta interrompida por erro da API"
+ },
"storage": {
"prompt_custom_path": "Digite o caminho de armazenamento personalizado para o histórico de conversas, deixe em branco para usar o local padrão",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json
index 7edd656d8c..9595f1f276 100644
--- a/src/i18n/locales/ru/common.json
+++ b/src/i18n/locales/ru/common.json
@@ -161,6 +161,10 @@
"incomplete": "Задача #{{taskNumber}} (Незавершенная)",
"no_messages": "Задача #{{taskNumber}} (Нет сообщений)"
},
+ "interruption": {
+ "responseInterruptedByUser": "Ответ прерван пользователем",
+ "responseInterruptedByApiError": "Ответ прерван ошибкой API"
+ },
"storage": {
"prompt_custom_path": "Введите пользовательский путь хранения истории разговоров, оставьте пустым для использования расположения по умолчанию",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/tr/common.json b/src/i18n/locales/tr/common.json
index 20b2824b98..aa11041110 100644
--- a/src/i18n/locales/tr/common.json
+++ b/src/i18n/locales/tr/common.json
@@ -161,6 +161,10 @@
"incomplete": "Görev #{{taskNumber}} (Tamamlanmamış)",
"no_messages": "Görev #{{taskNumber}} (Mesaj yok)"
},
+ "interruption": {
+ "responseInterruptedByUser": "Yanıt kullanıcı tarafından kesildi",
+ "responseInterruptedByApiError": "Yanıt API hatası nedeniyle kesildi"
+ },
"storage": {
"prompt_custom_path": "Konuşma geçmişi için özel depolama yolunu girin, varsayılan konumu kullanmak için boş bırakın",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/vi/common.json b/src/i18n/locales/vi/common.json
index f4755162fe..b4b92b373e 100644
--- a/src/i18n/locales/vi/common.json
+++ b/src/i18n/locales/vi/common.json
@@ -161,6 +161,10 @@
"incomplete": "Nhiệm vụ #{{taskNumber}} (Chưa hoàn thành)",
"no_messages": "Nhiệm vụ #{{taskNumber}} (Không có tin nhắn)"
},
+ "interruption": {
+ "responseInterruptedByUser": "Phản hồi bị gián đoạn bởi người dùng",
+ "responseInterruptedByApiError": "Phản hồi bị gián đoạn bởi lỗi API"
+ },
"storage": {
"prompt_custom_path": "Nhập đường dẫn lưu trữ tùy chỉnh cho lịch sử hội thoại, để trống để sử dụng vị trí mặc định",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json
index 787c5c8ae9..8c42744484 100644
--- a/src/i18n/locales/zh-CN/common.json
+++ b/src/i18n/locales/zh-CN/common.json
@@ -166,6 +166,10 @@
"incomplete": "任务 #{{taskNumber}} (未完成)",
"no_messages": "任务 #{{taskNumber}} (无消息)"
},
+ "interruption": {
+ "responseInterruptedByUser": "响应被用户中断",
+ "responseInterruptedByApiError": "响应被 API 错误中断"
+ },
"storage": {
"prompt_custom_path": "输入自定义会话历史存储路径,留空以使用默认位置",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/i18n/locales/zh-TW/common.json b/src/i18n/locales/zh-TW/common.json
index 0ae3549d3e..5a31d601b4 100644
--- a/src/i18n/locales/zh-TW/common.json
+++ b/src/i18n/locales/zh-TW/common.json
@@ -161,6 +161,10 @@
"incomplete": "工作 #{{taskNumber}} (未完成)",
"no_messages": "工作 #{{taskNumber}} (無訊息)"
},
+ "interruption": {
+ "responseInterruptedByUser": "回應被使用者中斷",
+ "responseInterruptedByApiError": "回應被 API 錯誤中斷"
+ },
"storage": {
"prompt_custom_path": "輸入自訂會話歷史儲存路徑,留空以使用預設位置",
"path_placeholder": "D:\\RooCodeStorage",
diff --git a/src/package.json b/src/package.json
index 4016b06f22..249993ecc1 100644
--- a/src/package.json
+++ b/src/package.json
@@ -3,7 +3,7 @@
"displayName": "%extension.displayName%",
"description": "%extension.description%",
"publisher": "RooVeterinaryInc",
- "version": "3.28.3",
+ "version": "3.28.8",
"icon": "assets/icons/icon.png",
"galleryBanner": {
"color": "#617A91",
@@ -174,6 +174,11 @@
"command": "roo-cline.acceptInput",
"title": "%command.acceptInput.title%",
"category": "%configuration.title%"
+ },
+ {
+ "command": "roo-cline.toggleAutoApprove",
+ "title": "%command.toggleAutoApprove.title%",
+ "category": "%configuration.title%"
}
],
"menus": {
@@ -310,6 +315,13 @@
"win": "ctrl+y",
"linux": "ctrl+y",
"when": "editorTextFocus && editorHasSelection"
+ },
+ {
+ "command": "roo-cline.toggleAutoApprove",
+ "key": "cmd+alt+a",
+ "mac": "cmd+alt+a",
+ "win": "ctrl+alt+a",
+ "linux": "ctrl+alt+a"
}
],
"submenus": [
diff --git a/src/package.nls.ca.json b/src/package.nls.ca.json
index 537a4522b2..902f798cbe 100644
--- a/src/package.nls.ca.json
+++ b/src/package.nls.ca.json
@@ -14,6 +14,7 @@
"command.terminal.fixCommand.title": "Corregir Aquesta Ordre",
"command.terminal.explainCommand.title": "Explicar Aquesta Ordre",
"command.acceptInput.title": "Acceptar Entrada/Suggeriment",
+ "command.toggleAutoApprove.title": "Alternar Auto-Aprovació",
"views.activitybar.title": "Roo Code",
"views.contextMenu.label": "Roo Code",
"views.terminalMenu.label": "Roo Code",
@@ -31,6 +32,7 @@
"commands.deniedCommands.description": "Prefixos d'ordres que seran automàticament denegats sense demanar aprovació. En cas de conflictes amb ordres permeses, la coincidència de prefix més llarga té prioritat. Afegeix * per denegar totes les ordres.",
"commands.commandExecutionTimeout.description": "Temps màxim en segons per esperar que l'execució de l'ordre es completi abans d'esgotar el temps (0 = sense temps límit, 1-600s, per defecte: 0s)",
"commands.commandTimeoutAllowlist.description": "Prefixos d'ordres que estan exclosos del temps límit d'execució d'ordres. Les ordres que coincideixin amb aquests prefixos s'executaran sense restriccions de temps límit.",
+ "commands.preventCompletionWithOpenTodos.description": "Evitar la finalització de tasques quan hi ha tasques pendents incompletes a la llista de tasques",
"settings.vsCodeLmModelSelector.description": "Configuració per a l'API del model de llenguatge VSCode",
"settings.vsCodeLmModelSelector.vendor.description": "El proveïdor del model de llenguatge (p. ex. copilot)",
"settings.vsCodeLmModelSelector.family.description": "La família del model de llenguatge (p. ex. gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "Ruta a un fitxer de configuració de RooCode per importar automàticament en iniciar l'extensió. Admet rutes absolutes i rutes relatives al directori d'inici (per exemple, '~/Documents/roo-code-settings.json'). Deixeu-ho en blanc per desactivar la importació automàtica.",
"settings.useAgentRules.description": "Activa la càrrega de fitxers AGENTS.md per a regles específiques de l'agent (vegeu https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "Temps màxim en segons per esperar les respostes de l'API (0 = sense temps d'espera, 1-3600s, per defecte: 600s). Es recomanen valors més alts per a proveïdors locals com LM Studio i Ollama que poden necessitar més temps de processament.",
+ "settings.newTaskRequireTodos.description": "Requerir el paràmetre de tasques pendents quan es creïn noves tasques amb l'eina new_task",
"settings.codeIndex.embeddingBatchSize.description": "La mida del lot per a operacions d'incrustació durant la indexació de codi. Ajusta això segons els límits del teu proveïdor d'API. Per defecte és 60."
}
diff --git a/src/package.nls.de.json b/src/package.nls.de.json
index fb43e28907..d8043da94e 100644
--- a/src/package.nls.de.json
+++ b/src/package.nls.de.json
@@ -14,6 +14,7 @@
"command.terminal.fixCommand.title": "Diesen Befehl Reparieren",
"command.terminal.explainCommand.title": "Diesen Befehl Erklären",
"command.acceptInput.title": "Eingabe/Vorschlag Akzeptieren",
+ "command.toggleAutoApprove.title": "Auto-Genehmigung Umschalten",
"views.activitybar.title": "Roo Code",
"views.contextMenu.label": "Roo Code",
"views.terminalMenu.label": "Roo Code",
@@ -31,6 +32,7 @@
"commands.deniedCommands.description": "Befehlspräfixe, die automatisch abgelehnt werden, ohne nach Genehmigung zu fragen. Bei Konflikten mit erlaubten Befehlen hat die längste Präfix-Übereinstimmung Vorrang. Füge * hinzu, um alle Befehle abzulehnen.",
"commands.commandExecutionTimeout.description": "Maximale Zeit in Sekunden, die auf den Abschluss der Befehlsausführung gewartet wird, bevor ein Timeout auftritt (0 = kein Timeout, 1-600s, Standard: 0s)",
"commands.commandTimeoutAllowlist.description": "Befehlspräfixe, die vom Timeout der Befehlsausführung ausgeschlossen sind. Befehle, die diesen Präfixen entsprechen, werden ohne Timeout-Beschränkungen ausgeführt.",
+ "commands.preventCompletionWithOpenTodos.description": "Aufgabenabschluss verhindern, wenn unvollständige Todos in der Todo-Liste vorhanden sind",
"settings.vsCodeLmModelSelector.description": "Einstellungen für die VSCode-Sprachmodell-API",
"settings.vsCodeLmModelSelector.vendor.description": "Der Anbieter des Sprachmodells (z.B. copilot)",
"settings.vsCodeLmModelSelector.family.description": "Die Familie des Sprachmodells (z.B. gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "Pfad zu einer RooCode-Konfigurationsdatei, die beim Start der Erweiterung automatisch importiert wird. Unterstützt absolute Pfade und Pfade relativ zum Home-Verzeichnis (z.B. '~/Documents/roo-code-settings.json'). Leer lassen, um den automatischen Import zu deaktivieren.",
"settings.useAgentRules.description": "Aktiviert das Laden von AGENTS.md-Dateien für agentenspezifische Regeln (siehe https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "Maximale Wartezeit in Sekunden auf API-Antworten (0 = kein Timeout, 1-3600s, Standard: 600s). Höhere Werte werden für lokale Anbieter wie LM Studio und Ollama empfohlen, die möglicherweise mehr Verarbeitungszeit benötigen.",
+ "settings.newTaskRequireTodos.description": "Todos-Parameter beim Erstellen neuer Aufgaben mit dem new_task-Tool erfordern",
"settings.codeIndex.embeddingBatchSize.description": "Die Batch-Größe für Embedding-Operationen während der Code-Indexierung. Passe dies an die Limits deines API-Anbieters an. Standard ist 60."
}
diff --git a/src/package.nls.es.json b/src/package.nls.es.json
index 95029057a9..000b353550 100644
--- a/src/package.nls.es.json
+++ b/src/package.nls.es.json
@@ -14,6 +14,7 @@
"command.terminal.fixCommand.title": "Corregir Este Comando",
"command.terminal.explainCommand.title": "Explicar Este Comando",
"command.acceptInput.title": "Aceptar Entrada/Sugerencia",
+ "command.toggleAutoApprove.title": "Alternar Auto-Aprobación",
"views.activitybar.title": "Roo Code",
"views.contextMenu.label": "Roo Code",
"views.terminalMenu.label": "Roo Code",
@@ -31,6 +32,7 @@
"commands.deniedCommands.description": "Prefijos de comandos que serán automáticamente denegados sin solicitar aprobación. En caso de conflictos con comandos permitidos, la coincidencia de prefijo más larga tiene prioridad. Añade * para denegar todos los comandos.",
"commands.commandExecutionTimeout.description": "Tiempo máximo en segundos para esperar que se complete la ejecución del comando antes de que expire (0 = sin tiempo límite, 1-600s, predeterminado: 0s)",
"commands.commandTimeoutAllowlist.description": "Prefijos de comandos que están excluidos del tiempo límite de ejecución de comandos. Los comandos que coincidan con estos prefijos se ejecutarán sin restricciones de tiempo límite.",
+ "commands.preventCompletionWithOpenTodos.description": "Prevenir la finalización de tareas cuando hay todos incompletos en la lista de todos",
"settings.vsCodeLmModelSelector.description": "Configuración para la API del modelo de lenguaje VSCode",
"settings.vsCodeLmModelSelector.vendor.description": "El proveedor del modelo de lenguaje (ej. copilot)",
"settings.vsCodeLmModelSelector.family.description": "La familia del modelo de lenguaje (ej. gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "Ruta a un archivo de configuración de RooCode para importar automáticamente al iniciar la extensión. Admite rutas absolutas y rutas relativas al directorio de inicio (por ejemplo, '~/Documents/roo-code-settings.json'). Dejar vacío para desactivar la importación automática.",
"settings.useAgentRules.description": "Habilita la carga de archivos AGENTS.md para reglas específicas del agente (ver https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "Tiempo máximo en segundos de espera para las respuestas de la API (0 = sin tiempo de espera, 1-3600s, por defecto: 600s). Se recomiendan valores más altos para proveedores locales como LM Studio y Ollama que puedan necesitar más tiempo de procesamiento.",
+ "settings.newTaskRequireTodos.description": "Requerir el parámetro todos al crear nuevas tareas con la herramienta new_task",
"settings.codeIndex.embeddingBatchSize.description": "El tamaño del lote para operaciones de embedding durante la indexación de código. Ajusta esto según los límites de tu proveedor de API. Por defecto es 60."
}
diff --git a/src/package.nls.fr.json b/src/package.nls.fr.json
index 3939451d67..0ba6ddeb8f 100644
--- a/src/package.nls.fr.json
+++ b/src/package.nls.fr.json
@@ -14,6 +14,7 @@
"command.terminal.fixCommand.title": "Corriger cette Commande",
"command.terminal.explainCommand.title": "Expliquer cette Commande",
"command.acceptInput.title": "Accepter l'Entrée/Suggestion",
+ "command.toggleAutoApprove.title": "Basculer Auto-Approbation",
"views.activitybar.title": "Roo Code",
"views.contextMenu.label": "Roo Code",
"views.terminalMenu.label": "Roo Code",
@@ -31,6 +32,7 @@
"commands.deniedCommands.description": "Préfixes de commandes qui seront automatiquement refusés sans demander d'approbation. En cas de conflit avec les commandes autorisées, la correspondance de préfixe la plus longue a la priorité. Ajouter * pour refuser toutes les commandes.",
"commands.commandExecutionTimeout.description": "Temps maximum en secondes pour attendre que l'exécution de la commande se termine avant expiration (0 = pas de délai, 1-600s, défaut : 0s)",
"commands.commandTimeoutAllowlist.description": "Préfixes de commandes qui sont exclus du délai d'exécution des commandes. Les commandes correspondant à ces préfixes s'exécuteront sans restrictions de délai.",
+ "commands.preventCompletionWithOpenTodos.description": "Empêcher l'achèvement des tâches lorsqu'il y a des todos incomplets dans la liste de todos",
"settings.vsCodeLmModelSelector.description": "Paramètres pour l'API du modèle de langage VSCode",
"settings.vsCodeLmModelSelector.vendor.description": "Le fournisseur du modèle de langage (ex: copilot)",
"settings.vsCodeLmModelSelector.family.description": "La famille du modèle de langage (ex: gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "Chemin d'accès à un fichier de configuration RooCode à importer automatiquement au démarrage de l'extension. Prend en charge les chemins absolus et les chemins relatifs au répertoire de base (par exemple, '~/Documents/roo-code-settings.json'). Laisser vide pour désactiver l'importation automatique.",
"settings.useAgentRules.description": "Activer le chargement des fichiers AGENTS.md pour les règles spécifiques à l'agent (voir https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "Temps maximum en secondes d'attente pour les réponses de l'API (0 = pas de timeout, 1-3600s, par défaut : 600s). Des valeurs plus élevées sont recommandées pour les fournisseurs locaux comme LM Studio et Ollama qui peuvent nécessiter plus de temps de traitement.",
+ "settings.newTaskRequireTodos.description": "Exiger le paramètre todos lors de la création de nouvelles tâches avec l'outil new_task",
"settings.codeIndex.embeddingBatchSize.description": "La taille du lot pour les opérations d'embedding lors de l'indexation du code. Ajustez ceci selon les limites de votre fournisseur d'API. Par défaut, c'est 60."
}
diff --git a/src/package.nls.hi.json b/src/package.nls.hi.json
index 25481f425f..d4b4bb1cd0 100644
--- a/src/package.nls.hi.json
+++ b/src/package.nls.hi.json
@@ -14,6 +14,7 @@
"command.terminal.fixCommand.title": "यह कमांड ठीक करें",
"command.terminal.explainCommand.title": "यह कमांड समझाएं",
"command.acceptInput.title": "इनपुट/सुझाव स्वीकारें",
+ "command.toggleAutoApprove.title": "ऑटो-अनुमोदन टॉगल करें",
"views.activitybar.title": "Roo Code",
"views.contextMenu.label": "Roo Code",
"views.terminalMenu.label": "Roo Code",
@@ -31,6 +32,7 @@
"commands.deniedCommands.description": "कमांड प्रीफिक्स जो स्वचालित रूप से अस्वीकार कर दिए जाएंगे बिना अनुमोदन मांगे। अनुमतित कमांड के साथ संघर्ष की स्थिति में, सबसे लंबा प्रीफिक्स मैच प्राथमिकता लेता है। सभी कमांड को अस्वीकार करने के लिए * जोड़ें।",
"commands.commandExecutionTimeout.description": "कमांड निष्पादन पूरा होने का इंतजार करने के लिए अधिकतम समय सेकंड में, समय समाप्त होने से पहले (0 = कोई समय सीमा नहीं, 1-600s, डिफ़ॉल्ट: 0s)",
"commands.commandTimeoutAllowlist.description": "कमांड प्रीफिक्स जो कमांड निष्पादन टाइमआउट से बाहर रखे गए हैं। इन प्रीफिक्स से मेल खाने वाले कमांड बिना टाइमआउट प्रतिबंधों के चलेंगे।",
+ "commands.preventCompletionWithOpenTodos.description": "जब टूडू सूची में अधूरे टूडू हों तो कार्य पूर्णता को रोकें",
"settings.vsCodeLmModelSelector.description": "VSCode भाषा मॉडल API के लिए सेटिंग्स",
"settings.vsCodeLmModelSelector.vendor.description": "भाषा मॉडल का विक्रेता (उदा. copilot)",
"settings.vsCodeLmModelSelector.family.description": "भाषा मॉडल का परिवार (उदा. gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "RooCode कॉन्फ़िगरेशन फ़ाइल का पथ जिसे एक्सटेंशन स्टार्टअप पर स्वचालित रूप से आयात किया जाएगा। होम डायरेक्टरी के सापेक्ष पूर्ण पथ और पथों का समर्थन करता है (उदाहरण के लिए '~/Documents/roo-code-settings.json')। ऑटो-इंपोर्ट को अक्षम करने के लिए खाली छोड़ दें।",
"settings.useAgentRules.description": "एजेंट-विशिष्ट नियमों के लिए AGENTS.md फ़ाइलों को लोड करना सक्षम करें (देखें https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "एपीआई प्रतिक्रियाओं की प्रतीक्षा करने के लिए सेकंड में अधिकतम समय (0 = कोई टाइमआउट नहीं, 1-3600s, डिफ़ॉल्ट: 600s)। एलएम स्टूडियो और ओलामा जैसे स्थानीय प्रदाताओं के लिए उच्च मानों की सिफारिश की जाती है जिन्हें अधिक प्रसंस्करण समय की आवश्यकता हो सकती है।",
+ "settings.newTaskRequireTodos.description": "new_task टूल के साथ नए कार्य बनाते समय टूडू पैरामीटर की आवश्यकता होती है",
"settings.codeIndex.embeddingBatchSize.description": "कोड इंडेक्सिंग के दौरान एम्बेडिंग ऑपरेशन के लिए बैच साइज़। इसे अपने API प्रदाता की सीमाओं के अनुसार समायोजित करें। डिफ़ॉल्ट 60 है।"
}
diff --git a/src/package.nls.id.json b/src/package.nls.id.json
index 0c69028e91..eb361a1ef7 100644
--- a/src/package.nls.id.json
+++ b/src/package.nls.id.json
@@ -26,11 +26,13 @@
"command.terminal.fixCommand.title": "Perbaiki Perintah Ini",
"command.terminal.explainCommand.title": "Jelaskan Perintah Ini",
"command.acceptInput.title": "Terima Input/Saran",
+ "command.toggleAutoApprove.title": "Alihkan Persetujuan Otomatis",
"configuration.title": "Roo Code",
"commands.allowedCommands.description": "Perintah yang dapat dijalankan secara otomatis ketika 'Selalu setujui operasi eksekusi' diaktifkan",
"commands.deniedCommands.description": "Awalan perintah yang akan otomatis ditolak tanpa meminta persetujuan. Jika terjadi konflik dengan perintah yang diizinkan, pencocokan awalan terpanjang akan diprioritaskan. Tambahkan * untuk menolak semua perintah.",
"commands.commandExecutionTimeout.description": "Waktu maksimum dalam detik untuk menunggu eksekusi perintah selesai sebelum timeout (0 = tanpa timeout, 1-600s, default: 0s)",
"commands.commandTimeoutAllowlist.description": "Awalan perintah yang dikecualikan dari timeout eksekusi perintah. Perintah yang cocok dengan awalan ini akan berjalan tanpa batasan timeout.",
+ "commands.preventCompletionWithOpenTodos.description": "Mencegah penyelesaian tugas ketika ada todos yang belum selesai dalam daftar todos",
"settings.vsCodeLmModelSelector.description": "Pengaturan untuk API Model Bahasa VSCode",
"settings.vsCodeLmModelSelector.vendor.description": "Vendor dari model bahasa (misalnya copilot)",
"settings.vsCodeLmModelSelector.family.description": "Keluarga dari model bahasa (misalnya gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "Path ke file konfigurasi RooCode untuk diimpor secara otomatis saat ekstensi dimulai. Mendukung path absolut dan path relatif terhadap direktori home (misalnya '~/Documents/roo-code-settings.json'). Biarkan kosong untuk menonaktifkan impor otomatis.",
"settings.useAgentRules.description": "Aktifkan pemuatan file AGENTS.md untuk aturan khusus agen (lihat https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "Waktu maksimum dalam detik untuk menunggu respons API (0 = tidak ada batas waktu, 1-3600s, default: 600s). Nilai yang lebih tinggi disarankan untuk penyedia lokal seperti LM Studio dan Ollama yang mungkin memerlukan lebih banyak waktu pemrosesan.",
+ "settings.newTaskRequireTodos.description": "Memerlukan parameter todos saat membuat tugas baru dengan alat new_task",
"settings.codeIndex.embeddingBatchSize.description": "Ukuran batch untuk operasi embedding selama pengindeksan kode. Sesuaikan ini berdasarkan batas penyedia API kamu. Default adalah 60."
}
diff --git a/src/package.nls.it.json b/src/package.nls.it.json
index 5ce3a76566..78989df6fe 100644
--- a/src/package.nls.it.json
+++ b/src/package.nls.it.json
@@ -14,6 +14,7 @@
"command.terminal.fixCommand.title": "Correggi Questo Comando",
"command.terminal.explainCommand.title": "Spiega Questo Comando",
"command.acceptInput.title": "Accetta Input/Suggerimento",
+ "command.toggleAutoApprove.title": "Attiva/Disattiva Auto-Approvazione",
"views.activitybar.title": "Roo Code",
"views.contextMenu.label": "Roo Code",
"views.terminalMenu.label": "Roo Code",
@@ -31,6 +32,7 @@
"commands.deniedCommands.description": "Prefissi di comandi che verranno automaticamente rifiutati senza richiedere approvazione. In caso di conflitti con comandi consentiti, la corrispondenza del prefisso più lungo ha la precedenza. Aggiungi * per rifiutare tutti i comandi.",
"commands.commandExecutionTimeout.description": "Tempo massimo in secondi per attendere il completamento dell'esecuzione del comando prima del timeout (0 = nessun timeout, 1-600s, predefinito: 0s)",
"commands.commandTimeoutAllowlist.description": "Prefissi di comandi che sono esclusi dal timeout di esecuzione dei comandi. I comandi che corrispondono a questi prefissi verranno eseguiti senza restrizioni di timeout.",
+ "commands.preventCompletionWithOpenTodos.description": "Impedire il completamento delle attività quando ci sono todos incompleti nella lista dei todos",
"settings.vsCodeLmModelSelector.description": "Impostazioni per l'API del modello linguistico VSCode",
"settings.vsCodeLmModelSelector.vendor.description": "Il fornitore del modello linguistico (es. copilot)",
"settings.vsCodeLmModelSelector.family.description": "La famiglia del modello linguistico (es. gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "Percorso di un file di configurazione di RooCode da importare automaticamente all'avvio dell'estensione. Supporta percorsi assoluti e percorsi relativi alla directory home (ad es. '~/Documents/roo-code-settings.json'). Lasciare vuoto per disabilitare l'importazione automatica.",
"settings.useAgentRules.description": "Abilita il caricamento dei file AGENTS.md per regole specifiche dell'agente (vedi https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "Tempo massimo in secondi di attesa per le risposte API (0 = nessun timeout, 1-3600s, predefinito: 600s). Valori più alti sono consigliati per provider locali come LM Studio e Ollama che potrebbero richiedere più tempo di elaborazione.",
+ "settings.newTaskRequireTodos.description": "Richiedere il parametro todos quando si creano nuove attività con lo strumento new_task",
"settings.codeIndex.embeddingBatchSize.description": "La dimensione del batch per le operazioni di embedding durante l'indicizzazione del codice. Regola questo in base ai limiti del tuo provider API. Il valore predefinito è 60."
}
diff --git a/src/package.nls.ja.json b/src/package.nls.ja.json
index b53b94e6ee..3eb059cbd9 100644
--- a/src/package.nls.ja.json
+++ b/src/package.nls.ja.json
@@ -26,11 +26,13 @@
"command.terminal.fixCommand.title": "このコマンドを修正",
"command.terminal.explainCommand.title": "このコマンドを説明",
"command.acceptInput.title": "入力/提案を承認",
+ "command.toggleAutoApprove.title": "自動承認を切替",
"configuration.title": "Roo Code",
"commands.allowedCommands.description": "'常に実行操作を承認する'が有効な場合に自動実行できるコマンド",
"commands.deniedCommands.description": "承認を求めずに自動的に拒否されるコマンドプレフィックス。許可されたコマンドとの競合がある場合、最長プレフィックスマッチが優先されます。すべてのコマンドを拒否するには * を追加してください。",
"commands.commandExecutionTimeout.description": "コマンド実行の完了を待つ最大時間(秒)、タイムアウトまで(0 = タイムアウトなし、1-600秒、デフォルト: 0秒)",
"commands.commandTimeoutAllowlist.description": "コマンド実行タイムアウトから除外されるコマンドプレフィックス。これらのプレフィックスに一致するコマンドは、タイムアウト制限なしで実行されます。",
+ "commands.preventCompletionWithOpenTodos.description": "TODOリストに未完了のTODOがある場合にタスクの完了を防ぐ",
"settings.vsCodeLmModelSelector.description": "VSCode 言語モデル API の設定",
"settings.vsCodeLmModelSelector.vendor.description": "言語モデルのベンダー(例:copilot)",
"settings.vsCodeLmModelSelector.family.description": "言語モデルのファミリー(例:gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "拡張機能の起動時に自動的にインポートするRooCode設定ファイルへのパス。絶対パスとホームディレクトリからの相対パスをサポートします(例:'~/Documents/roo-code-settings.json')。自動インポートを無効にするには、空のままにします。",
"settings.useAgentRules.description": "エージェント固有のルールのためにAGENTS.mdファイルの読み込みを有効にします(参照:https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "API応答を待機する最大時間(秒)(0 = タイムアウトなし、1-3600秒、デフォルト: 600秒)。LM StudioやOllamaのような、より多くの処理時間を必要とする可能性のあるローカルプロバイダーには、より高い値が推奨されます。",
+ "settings.newTaskRequireTodos.description": "new_taskツールで新しいタスクを作成する際にtodosパラメータを必須にする",
"settings.codeIndex.embeddingBatchSize.description": "コードインデックス作成中のエンベディング操作のバッチサイズ。APIプロバイダーの制限に基づいてこれを調整してください。デフォルトは60です。"
}
diff --git a/src/package.nls.json b/src/package.nls.json
index b0b7f401f8..1db69777ac 100644
--- a/src/package.nls.json
+++ b/src/package.nls.json
@@ -26,6 +26,7 @@
"command.terminal.fixCommand.title": "Fix This Command",
"command.terminal.explainCommand.title": "Explain This Command",
"command.acceptInput.title": "Accept Input/Suggestion",
+ "command.toggleAutoApprove.title": "Toggle Auto-Approve",
"configuration.title": "Roo Code",
"commands.allowedCommands.description": "Commands that can be auto-executed when 'Always approve execute operations' is enabled",
"commands.deniedCommands.description": "Command prefixes that will be automatically denied without asking for approval. In case of conflicts with allowed commands, the longest prefix match takes precedence. Add * to deny all commands.",
diff --git a/src/package.nls.ko.json b/src/package.nls.ko.json
index bd03331d4e..a566b2a038 100644
--- a/src/package.nls.ko.json
+++ b/src/package.nls.ko.json
@@ -14,6 +14,7 @@
"command.terminal.fixCommand.title": "이 명령어 수정",
"command.terminal.explainCommand.title": "이 명령어 설명",
"command.acceptInput.title": "입력/제안 수락",
+ "command.toggleAutoApprove.title": "자동 승인 전환",
"views.activitybar.title": "Roo Code",
"views.contextMenu.label": "Roo Code",
"views.terminalMenu.label": "Roo Code",
@@ -31,6 +32,7 @@
"commands.deniedCommands.description": "승인을 요청하지 않고 자동으로 거부될 명령어 접두사. 허용된 명령어와 충돌하는 경우 가장 긴 접두사 일치가 우선됩니다. 모든 명령어를 거부하려면 *를 추가하세요.",
"commands.commandExecutionTimeout.description": "명령어 실행이 완료되기를 기다리는 최대 시간(초), 타임아웃 전까지 (0 = 타임아웃 없음, 1-600초, 기본값: 0초)",
"commands.commandTimeoutAllowlist.description": "명령어 실행 타임아웃에서 제외되는 명령어 접두사. 이러한 접두사와 일치하는 명령어는 타임아웃 제한 없이 실행됩니다.",
+ "commands.preventCompletionWithOpenTodos.description": "할 일 목록에 미완료 할 일이 있을 때 작업 완료를 방지",
"settings.vsCodeLmModelSelector.description": "VSCode 언어 모델 API 설정",
"settings.vsCodeLmModelSelector.vendor.description": "언어 모델 공급자 (예: copilot)",
"settings.vsCodeLmModelSelector.family.description": "언어 모델 계열 (예: gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "확장 프로그램 시작 시 자동으로 가져올 RooCode 구성 파일의 경로입니다. 절대 경로 및 홈 디렉토리에 대한 상대 경로를 지원합니다(예: '~/Documents/roo-code-settings.json'). 자동 가져오기를 비활성화하려면 비워 둡니다.",
"settings.useAgentRules.description": "에이전트별 규칙에 대한 AGENTS.md 파일 로드를 활성화합니다 (참조: https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "API 응답을 기다리는 최대 시간(초) (0 = 시간 초과 없음, 1-3600초, 기본값: 600초). 더 많은 처리 시간이 필요할 수 있는 LM Studio 및 Ollama와 같은 로컬 공급자에게는 더 높은 값을 사용하는 것이 좋습니다.",
+ "settings.newTaskRequireTodos.description": "new_task 도구로 새 작업을 생성할 때 todos 매개변수 필요",
"settings.codeIndex.embeddingBatchSize.description": "코드 인덱싱 중 임베딩 작업의 배치 크기입니다. API 공급자의 제한에 따라 이를 조정하세요. 기본값은 60입니다."
}
diff --git a/src/package.nls.nl.json b/src/package.nls.nl.json
index 683a096c12..006725326b 100644
--- a/src/package.nls.nl.json
+++ b/src/package.nls.nl.json
@@ -26,11 +26,13 @@
"command.terminal.fixCommand.title": "Repareer Dit Commando",
"command.terminal.explainCommand.title": "Leg Dit Commando Uit",
"command.acceptInput.title": "Invoer/Suggestie Accepteren",
+ "command.toggleAutoApprove.title": "Auto-Goedkeuring Schakelen",
"configuration.title": "Roo Code",
"commands.allowedCommands.description": "Commando's die automatisch kunnen worden uitgevoerd wanneer 'Altijd goedkeuren uitvoerbewerkingen' is ingeschakeld",
"commands.deniedCommands.description": "Commando-prefixen die automatisch worden geweigerd zonder om goedkeuring te vragen. Bij conflicten met toegestane commando's heeft de langste prefix-match voorrang. Voeg * toe om alle commando's te weigeren.",
"commands.commandExecutionTimeout.description": "Maximale tijd in seconden om te wachten tot commando-uitvoering voltooid is voordat er een timeout optreedt (0 = geen timeout, 1-600s, standaard: 0s)",
"commands.commandTimeoutAllowlist.description": "Commando-prefixen die zijn uitgesloten van de commando-uitvoering timeout. Commando's die overeenkomen met deze prefixen worden uitgevoerd zonder timeout-beperkingen.",
+ "commands.preventCompletionWithOpenTodos.description": "Taakvoltooiing voorkomen wanneer er onvolledige todos in de todo-lijst staan",
"settings.vsCodeLmModelSelector.description": "Instellingen voor VSCode Language Model API",
"settings.vsCodeLmModelSelector.vendor.description": "De leverancier van het taalmodel (bijv. copilot)",
"settings.vsCodeLmModelSelector.family.description": "De familie van het taalmodel (bijv. gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "Pad naar een RooCode-configuratiebestand om automatisch te importeren bij het opstarten van de extensie. Ondersteunt absolute paden en paden ten opzichte van de thuismap (bijv. '~/Documents/roo-code-settings.json'). Laat leeg om automatisch importeren uit te schakelen.",
"settings.useAgentRules.description": "Laden van AGENTS.md-bestanden voor agentspecifieke regels inschakelen (zie https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "Maximale tijd in seconden om te wachten op API-reacties (0 = geen time-out, 1-3600s, standaard: 600s). Hogere waarden worden aanbevolen voor lokale providers zoals LM Studio en Ollama die mogelijk meer verwerkingstijd nodig hebben.",
+ "settings.newTaskRequireTodos.description": "Todos-parameter vereisen bij het maken van nieuwe taken met de new_task tool",
"settings.codeIndex.embeddingBatchSize.description": "De batchgrootte voor embedding-operaties tijdens code-indexering. Pas dit aan op basis van de limieten van je API-provider. Standaard is 60."
}
diff --git a/src/package.nls.pl.json b/src/package.nls.pl.json
index 76c10ddfe0..bcf80f7230 100644
--- a/src/package.nls.pl.json
+++ b/src/package.nls.pl.json
@@ -14,6 +14,7 @@
"command.terminal.fixCommand.title": "Napraw tę Komendę",
"command.terminal.explainCommand.title": "Wyjaśnij tę Komendę",
"command.acceptInput.title": "Akceptuj Wprowadzanie/Sugestię",
+ "command.toggleAutoApprove.title": "Przełącz Auto-Zatwierdzanie",
"views.activitybar.title": "Roo Code",
"views.contextMenu.label": "Roo Code",
"views.terminalMenu.label": "Roo Code",
@@ -31,6 +32,7 @@
"commands.deniedCommands.description": "Prefiksy poleceń, które będą automatycznie odrzucane bez pytania o zatwierdzenie. W przypadku konfliktów z dozwolonymi poleceniami, najdłuższe dopasowanie prefiksu ma pierwszeństwo. Dodaj * aby odrzucić wszystkie polecenia.",
"commands.commandExecutionTimeout.description": "Maksymalny czas w sekundach oczekiwania na zakończenie wykonania polecenia przed przekroczeniem limitu czasu (0 = brak limitu czasu, 1-600s, domyślnie: 0s)",
"commands.commandTimeoutAllowlist.description": "Prefiksy poleceń, które są wykluczone z limitu czasu wykonania poleceń. Polecenia pasujące do tych prefiksów będą wykonywane bez ograniczeń czasowych.",
+ "commands.preventCompletionWithOpenTodos.description": "Zapobiegaj ukończeniu zadania gdy na liście zadań są niekompletne todos",
"settings.vsCodeLmModelSelector.description": "Ustawienia dla API modelu językowego VSCode",
"settings.vsCodeLmModelSelector.vendor.description": "Dostawca modelu językowego (np. copilot)",
"settings.vsCodeLmModelSelector.family.description": "Rodzina modelu językowego (np. gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "Ścieżka do pliku konfiguracyjnego RooCode, który ma być automatycznie importowany podczas uruchamiania rozszerzenia. Obsługuje ścieżki bezwzględne i ścieżki względne do katalogu domowego (np. '~/Documents/roo-code-settings.json'). Pozostaw puste, aby wyłączyć automatyczne importowanie.",
"settings.useAgentRules.description": "Włącz wczytywanie plików AGENTS.md dla reguł specyficznych dla agenta (zobacz https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "Maksymalny czas w sekundach oczekiwania na odpowiedzi API (0 = brak limitu czasu, 1-3600s, domyślnie: 600s). Wyższe wartości są zalecane dla lokalnych dostawców, takich jak LM Studio i Ollama, którzy mogą potrzebować więcej czasu na przetwarzanie.",
+ "settings.newTaskRequireTodos.description": "Wymagaj parametru todos podczas tworzenia nowych zadań za pomocą narzędzia new_task",
"settings.codeIndex.embeddingBatchSize.description": "Rozmiar partii dla operacji osadzania podczas indeksowania kodu. Dostosuj to w oparciu o limity twojego dostawcy API. Domyślnie to 60."
}
diff --git a/src/package.nls.pt-BR.json b/src/package.nls.pt-BR.json
index 85cea4d870..1843bc476b 100644
--- a/src/package.nls.pt-BR.json
+++ b/src/package.nls.pt-BR.json
@@ -14,6 +14,7 @@
"command.terminal.fixCommand.title": "Corrigir Este Comando",
"command.terminal.explainCommand.title": "Explicar Este Comando",
"command.acceptInput.title": "Aceitar Entrada/Sugestão",
+ "command.toggleAutoApprove.title": "Alternar Auto-Aprovação",
"views.activitybar.title": "Roo Code",
"views.contextMenu.label": "Roo Code",
"views.terminalMenu.label": "Roo Code",
@@ -31,6 +32,7 @@
"commands.deniedCommands.description": "Prefixos de comandos que serão automaticamente negados sem solicitar aprovação. Em caso de conflitos com comandos permitidos, a correspondência de prefixo mais longa tem precedência. Adicione * para negar todos os comandos.",
"commands.commandExecutionTimeout.description": "Tempo máximo em segundos para aguardar a conclusão da execução do comando antes do timeout (0 = sem timeout, 1-600s, padrão: 0s)",
"commands.commandTimeoutAllowlist.description": "Prefixos de comandos que são excluídos do timeout de execução de comandos. Comandos que correspondem a esses prefixos serão executados sem restrições de timeout.",
+ "commands.preventCompletionWithOpenTodos.description": "Impedir a conclusão de tarefas quando há todos incompletos na lista de todos",
"settings.vsCodeLmModelSelector.description": "Configurações para a API do modelo de linguagem do VSCode",
"settings.vsCodeLmModelSelector.vendor.description": "O fornecedor do modelo de linguagem (ex: copilot)",
"settings.vsCodeLmModelSelector.family.description": "A família do modelo de linguagem (ex: gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "Caminho para um arquivo de configuração do RooCode para importar automaticamente na inicialização da extensão. Suporta caminhos absolutos e caminhos relativos ao diretório inicial (por exemplo, '~/Documents/roo-code-settings.json'). Deixe em branco para desativar a importação automática.",
"settings.useAgentRules.description": "Habilita o carregamento de arquivos AGENTS.md para regras específicas do agente (consulte https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "Tempo máximo em segundos de espera pelas respostas da API (0 = sem tempo limite, 1-3600s, padrão: 600s). Valores mais altos são recomendados para provedores locais como LM Studio e Ollama que podem precisar de mais tempo de processamento.",
+ "settings.newTaskRequireTodos.description": "Exigir parâmetro todos ao criar novas tarefas com a ferramenta new_task",
"settings.codeIndex.embeddingBatchSize.description": "O tamanho do lote para operações de embedding durante a indexação de código. Ajuste isso com base nos limites do seu provedor de API. O padrão é 60."
}
diff --git a/src/package.nls.ru.json b/src/package.nls.ru.json
index 83f32373a9..8a50af7389 100644
--- a/src/package.nls.ru.json
+++ b/src/package.nls.ru.json
@@ -26,11 +26,13 @@
"command.terminal.fixCommand.title": "Исправить эту команду",
"command.terminal.explainCommand.title": "Объяснить эту команду",
"command.acceptInput.title": "Принять ввод/предложение",
+ "command.toggleAutoApprove.title": "Переключить Авто-Подтверждение",
"configuration.title": "Roo Code",
"commands.allowedCommands.description": "Команды, которые могут быть автоматически выполнены, когда включена опция 'Всегда подтверждать операции выполнения'",
"commands.deniedCommands.description": "Префиксы команд, которые будут автоматически отклонены без запроса подтверждения. В случае конфликтов с разрешенными командами приоритет имеет самое длинное совпадение префикса. Добавьте * чтобы отклонить все команды.",
"commands.commandExecutionTimeout.description": "Максимальное время в секундах для ожидания завершения выполнения команды до истечения времени ожидания (0 = без тайм-аута, 1-600с, по умолчанию: 0с)",
"commands.commandTimeoutAllowlist.description": "Префиксы команд, которые исключены из тайм-аута выполнения команд. Команды, соответствующие этим префиксам, будут выполняться без ограничений по времени.",
+ "commands.preventCompletionWithOpenTodos.description": "Предотвращать завершение задачи при наличии незавершенных задач в списке задач",
"settings.vsCodeLmModelSelector.description": "Настройки для VSCode Language Model API",
"settings.vsCodeLmModelSelector.vendor.description": "Поставщик языковой модели (например, copilot)",
"settings.vsCodeLmModelSelector.family.description": "Семейство языковой модели (например, gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "Путь к файлу конфигурации RooCode для автоматического импорта при запуске расширения. Поддерживает абсолютные пути и пути относительно домашнего каталога (например, '~/Documents/roo-code-settings.json'). Оставьте пустым, чтобы отключить автоматический импорт.",
"settings.useAgentRules.description": "Включить загрузку файлов AGENTS.md для специфичных для агента правил (см. https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "Максимальное время в секундах для ожидания ответов API (0 = нет тайм-аута, 1-3600 с, по умолчанию: 600 с). Рекомендуются более высокие значения для локальных провайдеров, таких как LM Studio и Ollama, которым может потребоваться больше времени на обработку.",
+ "settings.newTaskRequireTodos.description": "Требовать параметр todos при создании новых задач с помощью инструмента new_task",
"settings.codeIndex.embeddingBatchSize.description": "Размер пакета для операций встраивания во время индексации кода. Настройте это в соответствии с ограничениями вашего API-провайдера. По умолчанию 60."
}
diff --git a/src/package.nls.tr.json b/src/package.nls.tr.json
index faf520c0d2..4eec2c70a0 100644
--- a/src/package.nls.tr.json
+++ b/src/package.nls.tr.json
@@ -14,6 +14,7 @@
"command.terminal.fixCommand.title": "Bu Komutu Düzelt",
"command.terminal.explainCommand.title": "Bu Komutu Açıkla",
"command.acceptInput.title": "Girişi/Öneriyi Kabul Et",
+ "command.toggleAutoApprove.title": "Otomatik Onayı Değiştir",
"views.activitybar.title": "Roo Code",
"views.contextMenu.label": "Roo Code",
"views.terminalMenu.label": "Roo Code",
@@ -31,6 +32,7 @@
"commands.deniedCommands.description": "Onay istenmeden otomatik olarak reddedilecek komut önekleri. İzin verilen komutlarla çakışma durumunda en uzun önek eşleşmesi öncelik alır. Tüm komutları reddetmek için * ekleyin.",
"commands.commandExecutionTimeout.description": "Komut yürütmesinin tamamlanmasını beklemek için maksimum süre (saniye), zaman aşımından önce (0 = zaman aşımı yok, 1-600s, varsayılan: 0s)",
"commands.commandTimeoutAllowlist.description": "Komut yürütme zaman aşımından hariç tutulan komut önekleri. Bu öneklerle eşleşen komutlar zaman aşımı kısıtlamaları olmadan çalışacaktır.",
+ "commands.preventCompletionWithOpenTodos.description": "Todo listesinde tamamlanmamış todolar olduğunda görev tamamlanmasını engelle",
"settings.vsCodeLmModelSelector.description": "VSCode dil modeli API'si için ayarlar",
"settings.vsCodeLmModelSelector.vendor.description": "Dil modelinin sağlayıcısı (örn: copilot)",
"settings.vsCodeLmModelSelector.family.description": "Dil modelinin ailesi (örn: gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "Uzantı başlangıcında otomatik olarak içe aktarılacak bir RooCode yapılandırma dosyasının yolu. Mutlak yolları ve ana dizine göreli yolları destekler (ör. '~/Documents/roo-code-settings.json'). Otomatik içe aktarmayı devre dışı bırakmak için boş bırakın.",
"settings.useAgentRules.description": "Aracıya özgü kurallar için AGENTS.md dosyalarının yüklenmesini etkinleştirin (bkz. https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "API yanıtları için beklenecek maksimum süre (saniye cinsinden) (0 = zaman aşımı yok, 1-3600s, varsayılan: 600s). LM Studio ve Ollama gibi daha fazla işlem süresi gerektirebilecek yerel sağlayıcılar için daha yüksek değerler önerilir.",
+ "settings.newTaskRequireTodos.description": "new_task aracıyla yeni görevler oluştururken todos parametresini gerekli kıl",
"settings.codeIndex.embeddingBatchSize.description": "Kod indeksleme sırasında gömme işlemleri için toplu iş boyutu. Bunu API sağlayıcınızın sınırlarına göre ayarlayın. Varsayılan 60'tır."
}
diff --git a/src/package.nls.vi.json b/src/package.nls.vi.json
index 672707a111..a0c9614dd2 100644
--- a/src/package.nls.vi.json
+++ b/src/package.nls.vi.json
@@ -14,6 +14,7 @@
"command.terminal.fixCommand.title": "Sửa Lệnh Này",
"command.terminal.explainCommand.title": "Giải Thích Lệnh Này",
"command.acceptInput.title": "Chấp Nhận Đầu Vào/Gợi Ý",
+ "command.toggleAutoApprove.title": "Bật/Tắt Tự Động Phê Duyệt",
"views.activitybar.title": "Roo Code",
"views.contextMenu.label": "Roo Code",
"views.terminalMenu.label": "Roo Code",
@@ -31,6 +32,7 @@
"commands.deniedCommands.description": "Các tiền tố lệnh sẽ được tự động từ chối mà không yêu cầu phê duyệt. Trong trường hợp xung đột với các lệnh được phép, việc khớp tiền tố dài nhất sẽ được ưu tiên. Thêm * để từ chối tất cả các lệnh.",
"commands.commandExecutionTimeout.description": "Thời gian tối đa tính bằng giây để chờ việc thực thi lệnh hoàn thành trước khi hết thời gian chờ (0 = không có thời gian chờ, 1-600s, mặc định: 0s)",
"commands.commandTimeoutAllowlist.description": "Các tiền tố lệnh được loại trừ khỏi thời gian chờ thực thi lệnh. Các lệnh khớp với những tiền tố này sẽ chạy mà không có giới hạn thời gian chờ.",
+ "commands.preventCompletionWithOpenTodos.description": "Ngăn hoàn thành nhiệm vụ khi có các todos chưa hoàn thành trong danh sách todos",
"settings.vsCodeLmModelSelector.description": "Cài đặt cho API mô hình ngôn ngữ VSCode",
"settings.vsCodeLmModelSelector.vendor.description": "Nhà cung cấp mô hình ngôn ngữ (ví dụ: copilot)",
"settings.vsCodeLmModelSelector.family.description": "Họ mô hình ngôn ngữ (ví dụ: gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "Đường dẫn đến tệp cấu hình RooCode để tự động nhập khi khởi động tiện ích mở rộng. Hỗ trợ đường dẫn tuyệt đối và đường dẫn tương đối đến thư mục chính (ví dụ: '~/Documents/roo-code-settings.json'). Để trống để tắt tính năng tự động nhập.",
"settings.useAgentRules.description": "Bật tải tệp AGENTS.md cho các quy tắc dành riêng cho tác nhân (xem https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "Thời gian tối đa tính bằng giây để đợi phản hồi API (0 = không có thời gian chờ, 1-3600 giây, mặc định: 600 giây). Nên sử dụng các giá trị cao hơn cho các nhà cung cấp cục bộ như LM Studio và Ollama có thể cần thêm thời gian xử lý.",
+ "settings.newTaskRequireTodos.description": "Yêu cầu tham số todos khi tạo nhiệm vụ mới với công cụ new_task",
"settings.codeIndex.embeddingBatchSize.description": "Kích thước lô cho các hoạt động nhúng trong quá trình lập chỉ mục mã. Điều chỉnh điều này dựa trên giới hạn của nhà cung cấp API của bạn. Mặc định là 60."
}
diff --git a/src/package.nls.zh-CN.json b/src/package.nls.zh-CN.json
index 94d0ed6c74..caab1a633d 100644
--- a/src/package.nls.zh-CN.json
+++ b/src/package.nls.zh-CN.json
@@ -14,6 +14,7 @@
"command.terminal.fixCommand.title": "修复此命令",
"command.terminal.explainCommand.title": "解释此命令",
"command.acceptInput.title": "接受输入/建议",
+ "command.toggleAutoApprove.title": "切换自动批准",
"views.activitybar.title": "Roo Code",
"views.contextMenu.label": "Roo Code",
"views.terminalMenu.label": "Roo Code",
@@ -31,6 +32,7 @@
"commands.deniedCommands.description": "将自动拒绝而无需请求批准的命令前缀。与允许命令冲突时,最长前缀匹配优先。添加 * 拒绝所有命令。",
"commands.commandExecutionTimeout.description": "等待命令执行完成的最大时间(秒),超时前(0 = 无超时,1-600秒,默认:0秒)",
"commands.commandTimeoutAllowlist.description": "从命令执行超时中排除的命令前缀。匹配这些前缀的命令将在没有超时限制的情况下运行。",
+ "commands.preventCompletionWithOpenTodos.description": "当待办事项列表中有未完成的待办事项时阻止任务完成",
"settings.vsCodeLmModelSelector.description": "VSCode 语言模型 API 的设置",
"settings.vsCodeLmModelSelector.vendor.description": "语言模型的供应商(例如:copilot)",
"settings.vsCodeLmModelSelector.family.description": "语言模型的系列(例如:gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "RooCode 配置文件的路径,用于在扩展启动时自动导入。支持绝对路径和相对于主目录的路径(例如 '~/Documents/roo-code-settings.json')。留空以禁用自动导入。",
"settings.useAgentRules.description": "为特定于代理的规则启用 AGENTS.md 文件的加载(请参阅 https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "等待 API 响应的最长时间(秒)(0 = 无超时,1-3600秒,默认值:600秒)。对于像 LM Studio 和 Ollama 这样可能需要更多处理时间的本地提供商,建议使用更高的值。",
+ "settings.newTaskRequireTodos.description": "使用 new_task 工具创建新任务时需要 todos 参数",
"settings.codeIndex.embeddingBatchSize.description": "代码索引期间嵌入操作的批处理大小。根据 API 提供商的限制调整此设置。默认值为 60。"
}
diff --git a/src/package.nls.zh-TW.json b/src/package.nls.zh-TW.json
index b4fd9e3cc7..8ad1011bb4 100644
--- a/src/package.nls.zh-TW.json
+++ b/src/package.nls.zh-TW.json
@@ -14,6 +14,7 @@
"command.terminal.fixCommand.title": "修復此命令",
"command.terminal.explainCommand.title": "解釋此命令",
"command.acceptInput.title": "接受輸入/建議",
+ "command.toggleAutoApprove.title": "切換自動批准",
"views.activitybar.title": "Roo Code",
"views.contextMenu.label": "Roo Code",
"views.terminalMenu.label": "Roo Code",
@@ -31,6 +32,7 @@
"commands.deniedCommands.description": "將自動拒絕而無需請求批准的命令前綴。與允許命令衝突時,最長前綴匹配優先。新增 * 拒絕所有命令。",
"commands.commandExecutionTimeout.description": "等待命令執行完成的最大時間(秒),逾時前(0 = 無逾時,1-600秒,預設:0秒)",
"commands.commandTimeoutAllowlist.description": "從命令執行逾時中排除的命令前綴。符合這些前綴的命令將在沒有逾時限制的情況下執行。",
+ "commands.preventCompletionWithOpenTodos.description": "當待辦事項清單中有未完成的待辦事項時阻止工作完成",
"settings.vsCodeLmModelSelector.description": "VSCode 語言模型 API 的設定",
"settings.vsCodeLmModelSelector.vendor.description": "語言模型供應商(例如:copilot)",
"settings.vsCodeLmModelSelector.family.description": "語言模型系列(例如:gpt-4)",
@@ -39,5 +41,6 @@
"settings.autoImportSettingsPath.description": "RooCode 設定檔案的路徑,用於在擴充功能啟動時自動匯入。支援絕對路徑和相對於主目錄的路徑(例如 '~/Documents/roo-code-settings.json')。留空以停用自動匯入。",
"settings.useAgentRules.description": "為特定於代理的規則啟用 AGENTS.md 檔案的載入(請參閱 https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "等待 API 回應的最長時間(秒)(0 = 無超時,1-3600秒,預設值:600秒)。對於像 LM Studio 和 Ollama 這樣可能需要更多處理時間的本地提供商,建議使用更高的值。",
+ "settings.newTaskRequireTodos.description": "使用 new_task 工具建立新工作時需要 todos 參數",
"settings.codeIndex.embeddingBatchSize.description": "程式碼索引期間嵌入操作的批次大小。根據 API 提供商的限制調整此設定。預設值為 60。"
}
diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts
index 3be28eaa54..d27e6e55aa 100644
--- a/src/shared/ExtensionMessage.ts
+++ b/src/shared/ExtensionMessage.ts
@@ -10,6 +10,7 @@ import type {
MarketplaceItem,
TodoItem,
CloudUserInfo,
+ CloudOrganizationMembership,
OrganizationAllowList,
ShareVisibility,
QueuedMessage,
@@ -125,6 +126,7 @@ export interface ExtensionMessage {
| "insertTextIntoTextarea"
| "dismissedUpsells"
| "pastedImageSaved"
+ | "organizationSwitchResult"
text?: string
payload?: any // Add a generic payload for now, can refine later
action?:
@@ -138,6 +140,7 @@ export interface ExtensionMessage {
| "didBecomeVisible"
| "focusInput"
| "switchTab"
+ | "toggleAutoApprove"
invoke?: "newChat" | "sendMessage" | "primaryButtonClick" | "secondaryButtonClick" | "setChatBoxMessage"
state?: ExtensionState
images?: string[]
@@ -204,6 +207,7 @@ export interface ExtensionMessage {
list?: string[] // For dismissedUpsells
imagePath?: string // For pastedImageSaved
imageUri?: string // For pastedImageSaved
+ organizationId?: string | null // For organizationSwitchResult
}
export type ExtensionState = Pick<
@@ -286,6 +290,7 @@ export type ExtensionState = Pick<
| "maxDiagnosticMessages"
| "openRouterImageGenerationSelectedModel"
| "includeTaskHistoryInEnhance"
+ | "reasoningBlockCollapsed"
> & {
version: string
clineMessages: ClineMessage[]
@@ -329,6 +334,7 @@ export type ExtensionState = Pick<
cloudUserInfo: CloudUserInfo | null
cloudIsAuthenticated: boolean
cloudApiUrl?: string
+ cloudOrganizations?: CloudOrganizationMembership[]
sharingEnabled: boolean
organizationAllowList: OrganizationAllowList
organizationSettingsVersion?: number
diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts
index 786f4b4fd1..67053e5ae7 100644
--- a/src/shared/WebviewMessage.ts
+++ b/src/shared/WebviewMessage.ts
@@ -102,6 +102,7 @@ export interface WebviewMessage {
| "browserViewportSize"
| "screenshotQuality"
| "remoteBrowserHost"
+ | "openKeyboardShortcuts"
| "openMcpSettings"
| "openProjectMcpSettings"
| "restartMcpServer"
@@ -180,8 +181,10 @@ export interface WebviewMessage {
| "hasOpenedModeSelector"
| "cloudButtonClicked"
| "rooCloudSignIn"
+ | "cloudLandingPageSignIn"
| "rooCloudSignOut"
| "rooCloudManualUrl"
+ | "switchOrganization"
| "condenseTaskContextRequest"
| "requestIndexingStatus"
| "startIndexing"
@@ -191,6 +194,7 @@ export interface WebviewMessage {
| "focusPanelRequest"
| "profileThresholds"
| "setHistoryPreviewCollapsed"
+ | "setReasoningBlockCollapsed"
| "openExternal"
| "filterMarketplaceItems"
| "marketplaceButtonClicked"
@@ -273,6 +277,7 @@ export interface WebviewMessage {
checkOnly?: boolean // For deleteCustomMode check
upsellId?: string // For dismissUpsell
list?: string[] // For dismissedUpsells response
+ organizationId?: string | null // For organization switching
codeIndexSettings?: {
// Global state settings
codebaseIndexEnabled: boolean
diff --git a/src/shared/api.ts b/src/shared/api.ts
index 13b6661119..79001cb0ad 100644
--- a/src/shared/api.ts
+++ b/src/shared/api.ts
@@ -18,6 +18,12 @@ export type ApiHandlerOptions = Omit & {
* Defaults to true; set to false to disable summaries.
*/
enableGpt5ReasoningSummary?: boolean
+ /**
+ * Optional override for Ollama's num_ctx parameter.
+ * When set, this value will be used in Ollama chat requests.
+ * When undefined, Ollama will use the model's default num_ctx from the Modelfile.
+ */
+ ollamaNumCtx?: number
}
// RouterName
diff --git a/webview-ui/src/App.tsx b/webview-ui/src/App.tsx
index fa38a566e7..220c8cf3af 100644
--- a/webview-ui/src/App.tsx
+++ b/webview-ui/src/App.tsx
@@ -76,6 +76,7 @@ const App = () => {
cloudUserInfo,
cloudIsAuthenticated,
cloudApiUrl,
+ cloudOrganizations,
renderContext,
mdmCompliant,
} = useExtensionState()
@@ -267,6 +268,7 @@ const App = () => {
userInfo={cloudUserInfo}
isAuthenticated={cloudIsAuthenticated}
cloudApiUrl={cloudApiUrl}
+ organizations={cloudOrganizations}
onDone={() => switchTab("chat")}
/>
)}
diff --git a/webview-ui/src/components/chat/Announcement.tsx b/webview-ui/src/components/chat/Announcement.tsx
index 8c52c41e42..cfe41340bc 100644
--- a/webview-ui/src/components/chat/Announcement.tsx
+++ b/webview-ui/src/components/chat/Announcement.tsx
@@ -6,12 +6,9 @@ import { Package } from "@roo/package"
import { useAppTranslation } from "@src/i18n/TranslationContext"
import { useExtensionState } from "@src/context/ExtensionStateContext"
import { vscode } from "@src/utils/vscode"
-import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@src/components/ui"
+import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@src/components/ui"
import { Button } from "@src/components/ui"
-// Define the production URL constant locally to avoid importing from cloud package in webview
-const PRODUCTION_ROO_CODE_API_URL = "https://app.roocode.com"
-
interface AnnouncementProps {
hideAnnouncement: () => void
}
@@ -28,8 +25,7 @@ interface AnnouncementProps {
const Announcement = ({ hideAnnouncement }: AnnouncementProps) => {
const { t } = useAppTranslation()
const [open, setOpen] = useState(true)
- const { cloudApiUrl } = useExtensionState()
- const cloudUrl = cloudApiUrl || PRODUCTION_ROO_CODE_API_URL
+ const { cloudIsAuthenticated } = useExtensionState()
return (