diff --git a/apps/web-roo-code/public/illustrations/form-factor-cloud.png b/apps/web-roo-code/public/illustrations/form-factor-cloud.png
new file mode 100644
index 0000000000..6746c96b01
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/form-factor-cloud.png differ
diff --git a/apps/web-roo-code/public/illustrations/form-factor-extension.png b/apps/web-roo-code/public/illustrations/form-factor-extension.png
new file mode 100644
index 0000000000..490728ec18
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/form-factor-extension.png differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/1.jpg b/apps/web-roo-code/public/illustrations/user-faces/1.jpg
new file mode 100644
index 0000000000..71b358b156
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/1.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/10.jpg b/apps/web-roo-code/public/illustrations/user-faces/10.jpg
new file mode 100644
index 0000000000..0a11fe5dc7
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/10.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/11.jpg b/apps/web-roo-code/public/illustrations/user-faces/11.jpg
new file mode 100644
index 0000000000..1d6d3acde5
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/11.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/12.jpg b/apps/web-roo-code/public/illustrations/user-faces/12.jpg
new file mode 100644
index 0000000000..5ffa4c1888
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/12.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/13.jpg b/apps/web-roo-code/public/illustrations/user-faces/13.jpg
new file mode 100644
index 0000000000..24cd94ef30
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/13.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/14.jpg b/apps/web-roo-code/public/illustrations/user-faces/14.jpg
new file mode 100644
index 0000000000..ab13a07b42
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/14.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/15.jpg b/apps/web-roo-code/public/illustrations/user-faces/15.jpg
new file mode 100644
index 0000000000..b8dc44213b
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/15.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/16.jpg b/apps/web-roo-code/public/illustrations/user-faces/16.jpg
new file mode 100644
index 0000000000..22652b2f40
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/16.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/17.jpg b/apps/web-roo-code/public/illustrations/user-faces/17.jpg
new file mode 100644
index 0000000000..e6ac7ec84b
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/17.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/18.jpg b/apps/web-roo-code/public/illustrations/user-faces/18.jpg
new file mode 100644
index 0000000000..21bfae28bf
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/18.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/19.jpg b/apps/web-roo-code/public/illustrations/user-faces/19.jpg
new file mode 100644
index 0000000000..9f54700dbc
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/19.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/2.jpg b/apps/web-roo-code/public/illustrations/user-faces/2.jpg
new file mode 100644
index 0000000000..9bf713c80d
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/2.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/20.jpg b/apps/web-roo-code/public/illustrations/user-faces/20.jpg
new file mode 100644
index 0000000000..631f9c0730
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/20.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/21.jpg b/apps/web-roo-code/public/illustrations/user-faces/21.jpg
new file mode 100644
index 0000000000..9f9a7aa335
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/21.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/22.jpg b/apps/web-roo-code/public/illustrations/user-faces/22.jpg
new file mode 100644
index 0000000000..cef0eadcb1
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/22.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/23.jpg b/apps/web-roo-code/public/illustrations/user-faces/23.jpg
new file mode 100644
index 0000000000..fafd86f6ea
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/23.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/24.jpg b/apps/web-roo-code/public/illustrations/user-faces/24.jpg
new file mode 100644
index 0000000000..bd6813409f
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/24.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/3.jpg b/apps/web-roo-code/public/illustrations/user-faces/3.jpg
new file mode 100644
index 0000000000..7ba55f1ed9
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/3.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/4.jpg b/apps/web-roo-code/public/illustrations/user-faces/4.jpg
new file mode 100644
index 0000000000..98a3722df8
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/4.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/5.jpg b/apps/web-roo-code/public/illustrations/user-faces/5.jpg
new file mode 100644
index 0000000000..0368881c09
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/5.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/6.jpg b/apps/web-roo-code/public/illustrations/user-faces/6.jpg
new file mode 100644
index 0000000000..2e110c0b6f
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/6.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/7.jpg b/apps/web-roo-code/public/illustrations/user-faces/7.jpg
new file mode 100644
index 0000000000..29a9134970
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/7.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/8.jpg b/apps/web-roo-code/public/illustrations/user-faces/8.jpg
new file mode 100644
index 0000000000..a643823cd6
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/8.jpg differ
diff --git a/apps/web-roo-code/public/illustrations/user-faces/9.jpg b/apps/web-roo-code/public/illustrations/user-faces/9.jpg
new file mode 100644
index 0000000000..4cfeaed27a
Binary files /dev/null and b/apps/web-roo-code/public/illustrations/user-faces/9.jpg differ
diff --git a/apps/web-roo-code/public/logos/bedrock.svg b/apps/web-roo-code/public/logos/bedrock.svg
new file mode 100644
index 0000000000..a564939929
--- /dev/null
+++ b/apps/web-roo-code/public/logos/bedrock.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/web-roo-code/public/logos/moonshot.svg b/apps/web-roo-code/public/logos/moonshot.svg
new file mode 100644
index 0000000000..fb56ac106c
--- /dev/null
+++ b/apps/web-roo-code/public/logos/moonshot.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/web-roo-code/public/logos/openrouter.svg b/apps/web-roo-code/public/logos/openrouter.svg
new file mode 100644
index 0000000000..e6cca2a869
--- /dev/null
+++ b/apps/web-roo-code/public/logos/openrouter.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/web-roo-code/src/app/layout.tsx b/apps/web-roo-code/src/app/layout.tsx
index 5e510eb848..b96cef0eea 100644
--- a/apps/web-roo-code/src/app/layout.tsx
+++ b/apps/web-roo-code/src/app/layout.tsx
@@ -14,7 +14,7 @@ import "./globals.css"
const inter = Inter({ subsets: ["latin"] })
const OG_TITLE = "Meet Roo Code"
-const OG_DESCRIPTION = "The AI dev team that gets things done."
+const OG_DESCRIPTION = "Your AI Software Engineering Team in the IDE and the Cloud."
export const metadata: Metadata = {
metadataBase: new URL(SEO.url),
diff --git a/apps/web-roo-code/src/app/page.tsx b/apps/web-roo-code/src/app/page.tsx
index b973e0cc70..f7ac47cf93 100644
--- a/apps/web-roo-code/src/app/page.tsx
+++ b/apps/web-roo-code/src/app/page.tsx
@@ -1,16 +1,12 @@
-/* eslint-disable react/jsx-no-target-blank */
-
-import { getVSCodeDownloads } from "@/lib/stats"
-
import { Button } from "@/components/ui"
import {
- AnimatedBackground,
- CodeExample,
CompanyLogos,
FAQSection,
- Features,
- InstallSection,
Testimonials,
+ CTASection,
+ OptionOverviewSection,
+ PillarsSection,
+ UseExamplesSection,
} from "@/components/homepage"
import { EXTERNAL_LINKS } from "@/lib/constants"
import { ArrowRight } from "lucide-react"
@@ -20,70 +16,67 @@ import { StructuredData } from "@/components/structured-data"
export const revalidate = 3600
export default async function Home() {
- const downloads = await getVSCodeDownloads()
-
return (
<>
-
-
-
-
-
-
-
- The AI dev team that gets things done.
-
-
- CoStrict's specialized modes stay on task and ship great code. Open source and
- works with any model.
-
-
-
-
-
-
-
+
+
+
+
+
+
+ Your AI Software Engineering Team is here.
+
+ Interactive in the IDE, autonomous in the cloud.
+
+
+
+ Use the Roo Code Extension on your computer for
+ full control, or delegate work to your{" "}
+ Roo Code Cloud Agents from the web, Slack, Github
+ or wherever your team is.
+
+
+
+
+
+ Free and Open Source
-
-
-
-
+
+
+
+ No credit card needed
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
>
)
}
diff --git a/apps/web-roo-code/src/components/chromes/nav-bar.tsx b/apps/web-roo-code/src/components/chromes/nav-bar.tsx
index a01e1e8538..2442e3b759 100644
--- a/apps/web-roo-code/src/components/chromes/nav-bar.tsx
+++ b/apps/web-roo-code/src/components/chromes/nav-bar.tsx
@@ -13,7 +13,7 @@ import { EXTERNAL_LINKS } from "@/lib/constants"
import { useLogoSrc } from "@/lib/hooks/use-logo-src"
import { ScrollButton } from "@/components/ui"
import ThemeToggle from "@/components/chromes/theme-toggle"
-import { ChevronDown, Cloud, X } from "lucide-react"
+import { ChevronDown, X } from "lucide-react"
interface NavBarProps {
stars: string | null
@@ -104,6 +104,20 @@ export function NavBar({ stars, downloads }: NavBarProps) {
{stars !== null && {stars}}
+ To trust an agent, you have to do it on your own terms.
+
+
+ Roo is designed from the ground up to give you the confidence to do ever more with AI.
+
+
+
+
+
+
+
+
+
+
+
Model-agnostic by design
+
Flexible and future-proof.
+
+
+ "The best model in the world" changes every other week. Providers
+ throttle models with no warning. 1st-party coding agents only work with their
+ own models.
+
+
Roo doesn't care.
+
+ It works great with 10s of models, from frontier to open weight. Choose from{" "}
+ the curated selection we offer at-cost or
+ bring your own key.
+
+
+
+
+ Compatible with dozens of providers
+
+
+ {MODEL_LOGOS.map((logo, index) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
Role-specific Modes
+
On-task and under control.
+
+
+ As capable as they are, when let loose, LLMs hallucinate, cheat and can cause
+ real damage.
+
+
+ Roo's Modes keep models focused on a given task and limit their access to
+ tools which are relevant to their role, keeping the context window clearer and
+ avoiding surprises.
+
+
+ Modes are even smart enough to ask to switch to another when stepping outside
+ their responsibilities.
+
+ Developer tools need to fit like gloves. Highly tweakable,
+ keyboard-shortcut-heavy gloves.
+
+
We made Roo thoughtfully configurable to fit your workflow as best it can.
+
+
+
+
+
+
+
+
+
+
+
+
Secure and transparent
+
Open source from the get go.
+
+
+ The Roo Code Extension is{" "}
+
+ open source
+ {" "}
+ so you can see for yourself exactly what it's doing and we don't use
+ your data for training.
+
+
+ Plus we're fully SOC2 Type 2 compliant and follow industry-standard
+ security practices.
+
+
+ )
+}
diff --git a/apps/web-roo-code/src/components/ui/button.tsx b/apps/web-roo-code/src/components/ui/button.tsx
index 18324ad791..2884f45c81 100644
--- a/apps/web-roo-code/src/components/ui/button.tsx
+++ b/apps/web-roo-code/src/components/ui/button.tsx
@@ -5,12 +5,12 @@ import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
- default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
- destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
+ default: "bg-primary text-primary-foreground shadow hover:bg-primary/80",
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/80",
outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
@@ -18,8 +18,9 @@ const buttonVariants = cva(
},
size: {
default: "h-9 px-4 py-2",
- sm: "h-8 rounded-md px-3 text-xs",
- lg: "h-10 rounded-md px-8",
+ sm: "h-8 px-3 text-xs",
+ lg: "h-10 px-8",
+ xl: "h-14 px-8 text-lg",
icon: "h-9 w-9",
},
},
diff --git a/apps/web-roo-code/src/components/ui/index.ts b/apps/web-roo-code/src/components/ui/index.ts
index 737046e479..18420eee0c 100644
--- a/apps/web-roo-code/src/components/ui/index.ts
+++ b/apps/web-roo-code/src/components/ui/index.ts
@@ -3,3 +3,4 @@ export * from "./chart"
export * from "./modal"
export * from "./scroll-button"
export * from "./table"
+export * from "./link"
diff --git a/apps/web-roo-code/src/components/ui/link.tsx b/apps/web-roo-code/src/components/ui/link.tsx
new file mode 100644
index 0000000000..2a2cbf4375
--- /dev/null
+++ b/apps/web-roo-code/src/components/ui/link.tsx
@@ -0,0 +1,38 @@
+import * as React from "react"
+import NextLink from "next/link"
+
+import { cn } from "@/lib/utils"
+
+type BaseLinkProps = React.ComponentPropsWithoutRef
+
+type LinkProps = BaseLinkProps & {
+ newWindow?: boolean
+}
+
+const Link = React.forwardRef, LinkProps>(
+ ({ className, newWindow = false, target, rel, ...props }, ref) => {
+ const computedTarget = newWindow ? "_blank" : target
+ const computedRel = newWindow
+ ? rel
+ ? rel.includes("noreferrer")
+ ? rel
+ : `${rel} noreferrer`
+ : "noreferrer"
+ : rel
+
+ return (
+
+ )
+ },
+)
+
+Link.displayName = "Link"
+
+export { Link }
+export type { LinkProps }
diff --git a/apps/web-roo-code/src/lib/constants.ts b/apps/web-roo-code/src/lib/constants.ts
index 084c214634..18d605107b 100644
--- a/apps/web-roo-code/src/lib/constants.ts
+++ b/apps/web-roo-code/src/lib/constants.ts
@@ -26,6 +26,7 @@ export const EXTERNAL_LINKS = {
TESTIMONIALS: "https://roocode.com/#testimonials",
CLOUD_APP_LOGIN: "https://app.roocode.com/sign-in",
CLOUD_APP_SIGNUP: "https://app.roocode.com/sign-up",
+ CLOUD_APP_SIGNUP_HOME: "https://app.roocode.com/sign-up?redirect_url=/cloud-agents/setup",
CLOUD_APP_SIGNUP_PRO: "https://app.roocode.com/sign-up?redirect_url=/cloud-agents/setup",
}
diff --git a/apps/web-roo-code/src/lib/stats.ts b/apps/web-roo-code/src/lib/stats.ts
index e479ce5010..9ce2714109 100644
--- a/apps/web-roo-code/src/lib/stats.ts
+++ b/apps/web-roo-code/src/lib/stats.ts
@@ -107,7 +107,7 @@ function formatNumber(num: number): string {
// if number is 1 million or more, format as millions
if (num >= 1000000) {
const truncated = Math.floor((num / 1000000) * 10) / 10
- return truncated.toFixed(1) + "M"
+ return truncated.toFixed(2) + "M"
}
// otherwise, format as thousands
diff --git a/packages/types/src/model.ts b/packages/types/src/model.ts
index e908886515..8aaa489be4 100644
--- a/packages/types/src/model.ts
+++ b/packages/types/src/model.ts
@@ -112,6 +112,8 @@ export const modelInfoSchema = z.object({
cachableFields: z.array(z.string()).optional(),
// Flag to indicate if the model is deprecated and should not be used
deprecated: z.boolean().optional(),
+ // Flag to indicate if the model should hide vendor/company identity in responses
+ isStealthModel: z.boolean().optional(),
// Flag to indicate if the model is free (no cost)
isFree: z.boolean().optional(),
// Flag to indicate if the model supports native tool calling (OpenAI-style function calling)
diff --git a/packages/types/src/providers/zai.ts b/packages/types/src/providers/zai.ts
index 3dcc352b1d..e21fcc698b 100644
--- a/packages/types/src/providers/zai.ts
+++ b/packages/types/src/providers/zai.ts
@@ -17,7 +17,6 @@ export const internationalZAiModels = {
supportsImages: false,
supportsPromptCache: true,
supportsNativeTools: true,
- supportsReasoningBinary: true,
inputPrice: 0.6,
outputPrice: 2.2,
cacheWritesPrice: 0,
@@ -94,7 +93,6 @@ export const internationalZAiModels = {
supportsImages: false,
supportsPromptCache: true,
supportsNativeTools: true,
- supportsReasoningBinary: true,
inputPrice: 0.6,
outputPrice: 2.2,
cacheWritesPrice: 0,
@@ -125,7 +123,6 @@ export const mainlandZAiModels = {
supportsImages: false,
supportsPromptCache: true,
supportsNativeTools: true,
- supportsReasoningBinary: true,
inputPrice: 0.29,
outputPrice: 1.14,
cacheWritesPrice: 0,
@@ -202,7 +199,6 @@ export const mainlandZAiModels = {
supportsImages: false,
supportsPromptCache: true,
supportsNativeTools: true,
- supportsReasoningBinary: true,
inputPrice: 0.29,
outputPrice: 1.14,
cacheWritesPrice: 0,
diff --git a/src/api/providers/__tests__/zai.spec.ts b/src/api/providers/__tests__/zai.spec.ts
index 15f3fef911..083fdc13ef 100644
--- a/src/api/providers/__tests__/zai.spec.ts
+++ b/src/api/providers/__tests__/zai.spec.ts
@@ -295,145 +295,5 @@ describe("ZAiHandler", () => {
undefined,
)
})
-
- describe("Reasoning functionality", () => {
- it("should include thinking parameter when enableReasoningEffort is true and model supports reasoning in createMessage", async () => {
- const handlerWithReasoning = new ZAiHandler({
- apiModelId: "glm-4.6", // GLM-4.6 has supportsReasoningBinary: true
- zaiApiKey: "test-zai-api-key",
- zaiApiLine: "international_coding",
- enableReasoningEffort: true,
- })
-
- mockCreate.mockImplementationOnce(() => {
- return {
- [Symbol.asyncIterator]: () => ({
- async next() {
- return { done: true }
- },
- }),
- }
- })
-
- const systemPrompt = "Test system prompt"
- const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Test message" }]
-
- const messageGenerator = handlerWithReasoning.createMessage(systemPrompt, messages)
- await messageGenerator.next()
-
- expect(mockCreate).toHaveBeenCalledWith(
- expect.objectContaining({
- thinking: { type: "enabled" },
- }),
- undefined,
- )
- })
-
- it("should not include thinking parameter when enableReasoningEffort is false in createMessage", async () => {
- const handlerWithoutReasoning = new ZAiHandler({
- apiModelId: "glm-4.6", // GLM-4.6 has supportsReasoningBinary: true
- zaiApiKey: "test-zai-api-key",
- zaiApiLine: "international_coding",
- enableReasoningEffort: false,
- })
-
- mockCreate.mockImplementationOnce(() => {
- return {
- [Symbol.asyncIterator]: () => ({
- async next() {
- return { done: true }
- },
- }),
- }
- })
-
- const systemPrompt = "Test system prompt"
- const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Test message" }]
-
- const messageGenerator = handlerWithoutReasoning.createMessage(systemPrompt, messages)
- await messageGenerator.next()
-
- expect(mockCreate).toHaveBeenCalledWith(
- expect.not.objectContaining({
- thinking: expect.anything(),
- }),
- undefined,
- )
- })
-
- it("should not include thinking parameter when model does not support reasoning in createMessage", async () => {
- const handlerWithNonReasoningModel = new ZAiHandler({
- apiModelId: "glm-4-32b-0414-128k", // This model doesn't have supportsReasoningBinary: true
- zaiApiKey: "test-zai-api-key",
- zaiApiLine: "international_coding",
- enableReasoningEffort: true,
- })
-
- mockCreate.mockImplementationOnce(() => {
- return {
- [Symbol.asyncIterator]: () => ({
- async next() {
- return { done: true }
- },
- }),
- }
- })
-
- const systemPrompt = "Test system prompt"
- const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Test message" }]
-
- const messageGenerator = handlerWithNonReasoningModel.createMessage(systemPrompt, messages)
- await messageGenerator.next()
-
- expect(mockCreate).toHaveBeenCalledWith(
- expect.not.objectContaining({
- thinking: expect.anything(),
- }),
- undefined,
- )
- })
-
- it("should include thinking parameter when enableReasoningEffort is true and model supports reasoning in completePrompt", async () => {
- const handlerWithReasoning = new ZAiHandler({
- apiModelId: "glm-4.5", // GLM-4.5 has supportsReasoningBinary: true
- zaiApiKey: "test-zai-api-key",
- zaiApiLine: "international_coding",
- enableReasoningEffort: true,
- })
-
- const expectedResponse = "This is a test response"
- mockCreate.mockResolvedValueOnce({ choices: [{ message: { content: expectedResponse } }] })
-
- await handlerWithReasoning.completePrompt("test prompt")
-
- expect(mockCreate).toHaveBeenCalledWith(
- expect.objectContaining({
- thinking: { type: "enabled" },
- }),
- { signal: undefined },
- )
- })
-
- it("should not include thinking parameter when enableReasoningEffort is false in completePrompt", async () => {
- const handlerWithoutReasoning = new ZAiHandler({
- apiModelId: "glm-4.5", // GLM-4.5 has supportsReasoningBinary: true
- zaiApiKey: "test-zai-api-key",
- zaiApiLine: "international_coding",
- enableReasoningEffort: false,
- })
-
- const expectedResponse = "This is a test response"
- mockCreate.mockResolvedValueOnce({ choices: [{ message: { content: expectedResponse } }] })
-
- await handlerWithoutReasoning.completePrompt("test prompt")
-
- expect(mockCreate).toHaveBeenCalledWith(
- expect.not.objectContaining({
- thinking: expect.anything(),
- }),
- { signal: undefined },
- )
- })
- })
})
})
diff --git a/src/api/providers/fetchers/__tests__/roo.spec.ts b/src/api/providers/fetchers/__tests__/roo.spec.ts
index c557dedd48..84d7284cfa 100644
--- a/src/api/providers/fetchers/__tests__/roo.spec.ts
+++ b/src/api/providers/fetchers/__tests__/roo.spec.ts
@@ -645,4 +645,70 @@ describe("getRooModels", () => {
expect(models["test/non-native-model"].supportsNativeTools).toBe(true)
expect(models["test/non-native-model"].defaultToolProtocol).toBeUndefined()
})
+
+ it("should detect stealth mode from tags", async () => {
+ const mockResponse = {
+ object: "list",
+ data: [
+ {
+ id: "test/stealth-model",
+ object: "model",
+ created: 1234567890,
+ owned_by: "test",
+ name: "Stealth Model",
+ description: "Model with stealth mode",
+ context_window: 128000,
+ max_tokens: 8192,
+ type: "language",
+ tags: ["stealth"],
+ pricing: {
+ input: "0.0001",
+ output: "0.0002",
+ },
+ },
+ ],
+ }
+
+ mockFetch.mockResolvedValueOnce({
+ ok: true,
+ json: async () => mockResponse,
+ })
+
+ const models = await getRooModels(baseUrl, apiKey)
+
+ expect(models["test/stealth-model"].isStealthModel).toBe(true)
+ })
+
+ it("should not set isStealthModel when stealth tag is absent", async () => {
+ const mockResponse = {
+ object: "list",
+ data: [
+ {
+ id: "test/non-stealth-model",
+ object: "model",
+ created: 1234567890,
+ owned_by: "test",
+ name: "Non-Stealth Model",
+ description: "Model without stealth mode",
+ context_window: 128000,
+ max_tokens: 8192,
+ type: "language",
+ tags: [],
+ pricing: {
+ input: "0.0001",
+ output: "0.0002",
+ },
+ },
+ ],
+ }
+
+ mockFetch.mockResolvedValueOnce({
+ ok: true,
+ json: async () => mockResponse,
+ })
+
+ const models = await getRooModels(baseUrl, apiKey)
+
+ expect(models["test/non-stealth-model"].isStealthModel).toBeUndefined()
+ })
})
diff --git a/src/api/providers/fetchers/roo.ts b/src/api/providers/fetchers/roo.ts
index 42b30139f6..004ff84cc0 100644
--- a/src/api/providers/fetchers/roo.ts
+++ b/src/api/providers/fetchers/roo.ts
@@ -115,6 +115,9 @@ export async function getRooModels(baseUrl: string, apiKey?: string): Promise
}
break
diff --git a/src/core/assistant-message/__tests__/AssistantMessageParser.spec.ts b/src/core/assistant-message/__tests__/AssistantMessageParser.spec.ts
index d1347b3794..bea4eeed91 100644
--- a/src/core/assistant-message/__tests__/AssistantMessageParser.spec.ts
+++ b/src/core/assistant-message/__tests__/AssistantMessageParser.spec.ts
@@ -179,7 +179,7 @@ describe("AssistantMessageParser (streaming)", () => {
// This has XML-like content:
return true;
}
- 5`
+ `
const result = streamChunks(parser, message).filter((block) => !isEmptyTextContent(block))
@@ -188,7 +188,6 @@ describe("AssistantMessageParser (streaming)", () => {
expect(toolUse.type).toBe("tool_use")
expect(toolUse.name).toBe("write_to_file")
expect(toolUse.params.path).toBe("src/file.ts")
- expect(toolUse.params.line_count).toBe("5")
expect(toolUse.params.content).toContain("function example()")
expect(toolUse.params.content).toContain("// This has XML-like content: ")
expect(toolUse.params.content).toContain("return true;")
@@ -263,7 +262,7 @@ describe("AssistantMessageParser (streaming)", () => {
line 1
line 2
line 3
- 3`
+ `
const result = streamChunks(parser, message).filter((block) => !isEmptyTextContent(block))
expect(result).toHaveLength(1)
@@ -274,7 +273,6 @@ describe("AssistantMessageParser (streaming)", () => {
expect(toolUse.params.content).toContain("line 1")
expect(toolUse.params.content).toContain("line 2")
expect(toolUse.params.content).toContain("line 3")
- expect(toolUse.params.line_count).toBe("3")
expect(toolUse.partial).toBe(false)
})
it("should handle a complex message with multiple content types", () => {
@@ -287,7 +285,7 @@ describe("AssistantMessageParser (streaming)", () => {
src/index.ts
// Updated content
console.log("Hello world");
- 2
+
Let's run the code:
diff --git a/src/core/assistant-message/__tests__/parseAssistantMessage.spec.ts b/src/core/assistant-message/__tests__/parseAssistantMessage.spec.ts
index f5ae600bee..80d2502626 100644
--- a/src/core/assistant-message/__tests__/parseAssistantMessage.spec.ts
+++ b/src/core/assistant-message/__tests__/parseAssistantMessage.spec.ts
@@ -168,7 +168,7 @@ const isEmptyTextContent = (block: AssistantMessageContent) =>
// This has XML-like content:
return true;
}
- 5`
+ `
const result = parser(message).filter((block) => !isEmptyTextContent(block))
@@ -177,7 +177,6 @@ const isEmptyTextContent = (block: AssistantMessageContent) =>
expect(toolUse.type).toBe("tool_use")
expect(toolUse.name).toBe("write_to_file")
expect(toolUse.params.path).toBe("src/file.ts")
- expect(toolUse.params.line_count).toBe("5")
expect(toolUse.params.content).toContain("function example()")
expect(toolUse.params.content).toContain("// This has XML-like content: ")
expect(toolUse.params.content).toContain("return true;")
@@ -276,7 +275,7 @@ const isEmptyTextContent = (block: AssistantMessageContent) =>
line 1
line 2
line 3
- 3`
+ `
const result = parser(message).filter((block) => !isEmptyTextContent(block))
expect(result).toHaveLength(1)
@@ -287,7 +286,6 @@ const isEmptyTextContent = (block: AssistantMessageContent) =>
expect(toolUse.params.content).toContain("line 1")
expect(toolUse.params.content).toContain("line 2")
expect(toolUse.params.content).toContain("line 3")
- expect(toolUse.params.line_count).toBe("3")
expect(toolUse.partial).toBe(false)
})
@@ -301,7 +299,7 @@ const isEmptyTextContent = (block: AssistantMessageContent) =>
src/index.ts
// Updated content
console.log("Hello world");
- 2
+
Let's run the code:
diff --git a/src/core/assistant-message/__tests__/parseAssistantMessageBenchmark.ts b/src/core/assistant-message/__tests__/parseAssistantMessageBenchmark.ts
index d5450988c9..a32b1173ce 100644
--- a/src/core/assistant-message/__tests__/parseAssistantMessageBenchmark.ts
+++ b/src/core/assistant-message/__tests__/parseAssistantMessageBenchmark.ts
@@ -62,17 +62,17 @@ const testCases = [
},
{
name: "Message with a complex tool use (write_to_file)",
- input: "src/file.ts\nfunction example() {\n // This has XML-like content: \n return true;\n}\n5",
+ input: "src/file.ts\nfunction example() {\n // This has XML-like content: \n return true;\n}\n",
},
{
name: "Message with multiple tool uses",
- input: "First file: src/file1.ts\nSecond file: src/file2.ts\nLet's write a new file: src/file3.ts\nexport function newFunction() {\n return 'Hello world';\n}\n3",
+ input: "First file: src/file1.ts\nSecond file: src/file2.ts\nLet's write a new file: src/file3.ts\nexport function newFunction() {\n return 'Hello world';\n}\n",
},
{
name: "Large message with repeated tool uses",
input: Array(50)
.fill(
- 'src/file.ts\noutput.tsconsole.log("hello");1',
+ 'src/file.ts\noutput.tsconsole.log("hello");',
)
.join("\n"),
},
diff --git a/src/core/assistant-message/presentAssistantMessage.ts b/src/core/assistant-message/presentAssistantMessage.ts
index 8a3eb51d8f..fe3aa8ce1e 100644
--- a/src/core/assistant-message/presentAssistantMessage.ts
+++ b/src/core/assistant-message/presentAssistantMessage.ts
@@ -492,6 +492,7 @@ export async function presentAssistantMessage(cline: Task) {
)
const pushToolResult = (content: ToolResponse) => {
+ const editTools = ["insert_content", "apply_diff", "search_and_replace", "apply_patch", "write_to_file"]
if (toolProtocol === TOOL_PROTOCOL.NATIVE) {
// For native protocol, only allow ONE tool_result per tool call
if (hasToolResult) {
@@ -532,10 +533,7 @@ export async function presentAssistantMessage(cline: Task) {
}
hasToolResult = true
- if (
- ["write_to_file", "apply_diff", "insert_content"].includes(block.name) &&
- block.partial === false
- ) {
+ if (editTools.includes(block.name) && block.partial === false) {
updateCospecMetadata(cline, block?.params?.path)
}
} else {
@@ -550,10 +548,7 @@ export async function presentAssistantMessage(cline: Task) {
} else {
cline.userMessageContent.push(...content)
}
- if (
- ["write_to_file", "apply_diff", "insert_content"].includes(block.name) &&
- block.partial === false
- ) {
+ if (editTools.includes(block.name) && block.partial === false) {
updateCospecMetadata(cline, block?.params?.path)
}
}
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 d6594633a0..a458972a3e 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
@@ -164,14 +164,12 @@ Description: Request to write content to a file. This tool is primarily used for
Parameters:
- path: (required) The path of the file to write to (relative to the current workspace directory /test/path)
- content: (required) The content to write to the file. When performing a full rewrite of an existing file or creating a new one, ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified. Do NOT include the line numbers in the content though, just the actual content of the file.
-- line_count: (required) The number of lines in the file. Make sure to compute this based on the actual content of the file, not the number of lines in the content you're providing.
Usage:
File path here
Your file content here
-total number of lines in the file, including empty lines
Example: Requesting to write to frontend-config.json
@@ -193,7 +191,6 @@ Example: Requesting to write to frontend-config.json
"version": "1.0.0"
}
-14
## insert_content
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 7bdbda4cda..4e38bce395 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
@@ -163,14 +163,12 @@ Description: Request to write content to a file. This tool is primarily used for
Parameters:
- path: (required) The path of the file to write to (relative to the current workspace directory /test/path)
- content: (required) The content to write to the file. When performing a full rewrite of an existing file or creating a new one, ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified. Do NOT include the line numbers in the content though, just the actual content of the file.
-- line_count: (required) The number of lines in the file. Make sure to compute this based on the actual content of the file, not the number of lines in the content you're providing.
Usage:
File path here
Your file content here
-total number of lines in the file, including empty lines
Example: Requesting to write to frontend-config.json
@@ -192,7 +190,6 @@ Example: Requesting to write to frontend-config.json
"version": "1.0.0"
}
-14
## insert_content
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 e2914575ea..ba309a06a5 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
@@ -164,14 +164,12 @@ Description: Request to write content to a file. This tool is primarily used for
Parameters:
- path: (required) The path of the file to write to (relative to the current workspace directory /test/path)
- content: (required) The content to write to the file. When performing a full rewrite of an existing file or creating a new one, ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified. Do NOT include the line numbers in the content though, just the actual content of the file.
-- line_count: (required) The number of lines in the file. Make sure to compute this based on the actual content of the file, not the number of lines in the content you're providing.
Usage:
File path here
Your file content here
-total number of lines in the file, including empty lines
Example: Requesting to write to frontend-config.json
@@ -193,7 +191,6 @@ Example: Requesting to write to frontend-config.json
"version": "1.0.0"
}
-14
## insert_content
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 8370cee3df..ba7207d736 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
@@ -169,14 +169,12 @@ Description: Request to write content to a file. This tool is primarily used for
Parameters:
- path: (required) The path of the file to write to (relative to the current workspace directory /test/path)
- content: (required) The content to write to the file. When performing a full rewrite of an existing file or creating a new one, ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified. Do NOT include the line numbers in the content though, just the actual content of the file.
-- line_count: (required) The number of lines in the file. Make sure to compute this based on the actual content of the file, not the number of lines in the content you're providing.
Usage:
File path here
Your file content here
-total number of lines in the file, including empty lines
Example: Requesting to write to frontend-config.json
@@ -198,7 +196,6 @@ Example: Requesting to write to frontend-config.json
"version": "1.0.0"
}
-14
## insert_content
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 e8e77c0027..f8392d1549 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
@@ -164,14 +164,12 @@ Description: Request to write content to a file. This tool is primarily used for
Parameters:
- path: (required) The path of the file to write to (relative to the current workspace directory /test/path)
- content: (required) The content to write to the file. When performing a full rewrite of an existing file or creating a new one, ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified. Do NOT include the line numbers in the content though, just the actual content of the file.
-- line_count: (required) The number of lines in the file. Make sure to compute this based on the actual content of the file, not the number of lines in the content you're providing.
Usage:
File path here
Your file content here
-total number of lines in the file, including empty lines
Example: Requesting to write to frontend-config.json
@@ -193,7 +191,6 @@ Example: Requesting to write to frontend-config.json
"version": "1.0.0"
}
-14
## insert_content
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 94977209d2..03efe8df40 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
@@ -164,14 +164,12 @@ Description: Request to write content to a file. This tool is primarily used for
Parameters:
- path: (required) The path of the file to write to (relative to the current workspace directory /test/path)
- content: (required) The content to write to the file. When performing a full rewrite of an existing file or creating a new one, ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified. Do NOT include the line numbers in the content though, just the actual content of the file.
-- line_count: (required) The number of lines in the file. Make sure to compute this based on the actual content of the file, not the number of lines in the content you're providing.
Usage:
File path here
Your file content here
-total number of lines in the file, including empty lines
Example: Requesting to write to frontend-config.json
@@ -193,7 +191,6 @@ Example: Requesting to write to frontend-config.json
"version": "1.0.0"
}
-14
## insert_content
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 e8e77c0027..f8392d1549 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
@@ -164,14 +164,12 @@ Description: Request to write content to a file. This tool is primarily used for
Parameters:
- path: (required) The path of the file to write to (relative to the current workspace directory /test/path)
- content: (required) The content to write to the file. When performing a full rewrite of an existing file or creating a new one, ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified. Do NOT include the line numbers in the content though, just the actual content of the file.
-- line_count: (required) The number of lines in the file. Make sure to compute this based on the actual content of the file, not the number of lines in the content you're providing.
Usage:
File path here
Your file content here
-total number of lines in the file, including empty lines
Example: Requesting to write to frontend-config.json
@@ -193,7 +191,6 @@ Example: Requesting to write to frontend-config.json
"version": "1.0.0"
}
-14
## insert_content
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 3b38149b6d..7629d56c9b 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
@@ -252,14 +252,12 @@ Description: Request to write content to a file. This tool is primarily used for
Parameters:
- path: (required) The path of the file to write to (relative to the current workspace directory /test/path)
- content: (required) The content to write to the file. When performing a full rewrite of an existing file or creating a new one, ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified. Do NOT include the line numbers in the content though, just the actual content of the file.
-- line_count: (required) The number of lines in the file. Make sure to compute this based on the actual content of the file, not the number of lines in the content you're providing.
Usage:
File path here
Your file content here
-total number of lines in the file, including empty lines
Example: Requesting to write to frontend-config.json
@@ -281,7 +279,6 @@ Example: Requesting to write to frontend-config.json
"version": "1.0.0"
}
-14
## insert_content
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 e8e77c0027..f8392d1549 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
@@ -164,14 +164,12 @@ Description: Request to write content to a file. This tool is primarily used for
Parameters:
- path: (required) The path of the file to write to (relative to the current workspace directory /test/path)
- content: (required) The content to write to the file. When performing a full rewrite of an existing file or creating a new one, ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified. Do NOT include the line numbers in the content though, just the actual content of the file.
-- line_count: (required) The number of lines in the file. Make sure to compute this based on the actual content of the file, not the number of lines in the content you're providing.
Usage:
File path here
Your file content here
-total number of lines in the file, including empty lines
Example: Requesting to write to frontend-config.json
@@ -193,7 +191,6 @@ Example: Requesting to write to frontend-config.json
"version": "1.0.0"
}
-14
## insert_content
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 e8e77c0027..f8392d1549 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
@@ -164,14 +164,12 @@ Description: Request to write content to a file. This tool is primarily used for
Parameters:
- path: (required) The path of the file to write to (relative to the current workspace directory /test/path)
- content: (required) The content to write to the file. When performing a full rewrite of an existing file or creating a new one, ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified. Do NOT include the line numbers in the content though, just the actual content of the file.
-- line_count: (required) The number of lines in the file. Make sure to compute this based on the actual content of the file, not the number of lines in the content you're providing.
Usage:
File path here
Your file content here
-total number of lines in the file, including empty lines
Example: Requesting to write to frontend-config.json
@@ -193,7 +191,6 @@ Example: Requesting to write to frontend-config.json
"version": "1.0.0"
}
-14
## insert_content
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 e2914575ea..ba309a06a5 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
@@ -164,14 +164,12 @@ Description: Request to write content to a file. This tool is primarily used for
Parameters:
- path: (required) The path of the file to write to (relative to the current workspace directory /test/path)
- content: (required) The content to write to the file. When performing a full rewrite of an existing file or creating a new one, ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified. Do NOT include the line numbers in the content though, just the actual content of the file.
-- line_count: (required) The number of lines in the file. Make sure to compute this based on the actual content of the file, not the number of lines in the content you're providing.
Usage:
File path here
Your file content here
-total number of lines in the file, including empty lines
Example: Requesting to write to frontend-config.json
@@ -193,7 +191,6 @@ Example: Requesting to write to frontend-config.json
"version": "1.0.0"
}
-14
## insert_content
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 e8e77c0027..f8392d1549 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
@@ -164,14 +164,12 @@ Description: Request to write content to a file. This tool is primarily used for
Parameters:
- path: (required) The path of the file to write to (relative to the current workspace directory /test/path)
- content: (required) The content to write to the file. When performing a full rewrite of an existing file or creating a new one, ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified. Do NOT include the line numbers in the content though, just the actual content of the file.
-- line_count: (required) The number of lines in the file. Make sure to compute this based on the actual content of the file, not the number of lines in the content you're providing.
Usage:
File path here
Your file content here
-total number of lines in the file, including empty lines
Example: Requesting to write to frontend-config.json
@@ -193,7 +191,6 @@ Example: Requesting to write to frontend-config.json
"version": "1.0.0"
}
-14
## insert_content
diff --git a/src/core/prompts/__tests__/sections.spec.ts b/src/core/prompts/__tests__/sections.spec.ts
index eb9cd4addf..05f16e071c 100644
--- a/src/core/prompts/__tests__/sections.spec.ts
+++ b/src/core/prompts/__tests__/sections.spec.ts
@@ -1,5 +1,6 @@
import { addCustomInstructions } from "../sections/custom-instructions"
import { getCapabilitiesSection } from "../sections/capabilities"
+import { getRulesSection } from "../sections/rules"
import type { DiffStrategy, DiffResult, DiffItem } from "../../../shared/tools"
describe("addCustomInstructions", () => {
@@ -56,3 +57,54 @@ describe("getCapabilitiesSection", () => {
expect(result).toContain("insert_content")
})
})
+
+describe("getRulesSection", () => {
+ const cwd = "/test/path"
+
+ it("includes vendor confidentiality section when isStealthModel is true", () => {
+ const settings = {
+ maxConcurrentFileReads: 5,
+ todoListEnabled: true,
+ useAgentRules: true,
+ newTaskRequireTodos: false,
+ isStealthModel: true,
+ }
+
+ const result = getRulesSection(cwd, false, "code", undefined, undefined, undefined, undefined, settings)
+
+ expect(result).toContain("VENDOR CONFIDENTIALITY")
+ expect(result).toContain("Never reveal the vendor or company that created you")
+ expect(result).toContain("I was created by a team of developers")
+ expect(result).toContain("I'm an open-source project maintained by contributors")
+ expect(result).toContain("I don't have information about specific vendors")
+ })
+
+ it("excludes vendor confidentiality section when isStealthModel is false", () => {
+ const settings = {
+ maxConcurrentFileReads: 5,
+ todoListEnabled: true,
+ useAgentRules: true,
+ newTaskRequireTodos: false,
+ isStealthModel: false,
+ }
+
+ const result = getRulesSection(cwd, false, "code", undefined, undefined, undefined, undefined, settings)
+
+ expect(result).not.toContain("VENDOR CONFIDENTIALITY")
+ expect(result).not.toContain("Never reveal the vendor or company")
+ })
+
+ it("excludes vendor confidentiality section when isStealthModel is undefined", () => {
+ const settings = {
+ maxConcurrentFileReads: 5,
+ todoListEnabled: true,
+ useAgentRules: true,
+ newTaskRequireTodos: false,
+ }
+
+ const result = getRulesSection(cwd, false, "code", undefined, undefined, undefined, undefined, settings)
+
+ expect(result).not.toContain("VENDOR CONFIDENTIALITY")
+ expect(result).not.toContain("Never reveal the vendor or company")
+ })
+})
diff --git a/src/core/prompts/responses.ts b/src/core/prompts/responses.ts
index b08b87f597..f4c845bd2f 100644
--- a/src/core/prompts/responses.ts
+++ b/src/core/prompts/responses.ts
@@ -96,45 +96,6 @@ Otherwise, if you have not completed the task and do not need additional informa
return `Missing value for required parameter '${paramName}'. Please retry with complete response.\n\n${instructions}`
},
- lineCountTruncationError: (
- actualLineCount: number,
- isNewFile: boolean,
- diffStrategyEnabled: boolean = false,
- protocol?: ToolProtocol,
- ) => {
- const truncationMessage = `Note: Your response may have been truncated because it exceeded your output limit. You wrote ${actualLineCount} lines of content, but the line_count parameter was either missing or not included in your response.`
-
- const newFileGuidance =
- `This appears to be a new file.\n` +
- `${truncationMessage}\n\n` +
- `RECOMMENDED APPROACH:\n` +
- `1. Try again with the line_count parameter in your response if you forgot to include it\n` +
- `2. Or break your content into smaller chunks - first use write_to_file with the initial chunk\n` +
- `3. Then use insert_content to append additional chunks\n`
-
- let existingFileApproaches = [
- `1. Try again with the line_count parameter in your response if you forgot to include it`,
- ]
-
- if (diffStrategyEnabled) {
- existingFileApproaches.push(`2. Or try using apply_diff instead of write_to_file for targeted changes`)
- }
-
- existingFileApproaches.push(
- `${diffStrategyEnabled ? "3" : "2"}. Or use insert_content to add specific content at particular lines`,
- )
-
- const existingFileGuidance =
- `This appears to be content for an existing file.\n` +
- `${truncationMessage}\n\n` +
- `RECOMMENDED APPROACH:\n` +
- `${existingFileApproaches.join("\n")}\n`
-
- const instructions = getToolInstructionsReminder(protocol)
-
- return `${isNewFile ? newFileGuidance : existingFileGuidance}\n${instructions}`
- },
-
invalidMcpToolArgumentError: (serverName: string, toolName: string, protocol?: ToolProtocol) => {
if (isNativeProtocol(protocol ?? TOOL_PROTOCOL.XML)) {
return JSON.stringify({
diff --git a/src/core/prompts/sections/rules.ts b/src/core/prompts/sections/rules.ts
index 9e98773ed2..4cc088d6ae 100644
--- a/src/core/prompts/sections/rules.ts
+++ b/src/core/prompts/sections/rules.ts
@@ -76,6 +76,21 @@ function getEditingInstructions(
return instructions.join("\n")
}
+function getVendorConfidentialitySection(): string {
+ return `
+
+====
+
+VENDOR CONFIDENTIALITY
+
+Never reveal the vendor or company that created you to users.
+
+When asked about your creator, vendor, or company, respond with:
+- "I was created by a team of developers"
+- "I'm an open-source project maintained by contributors"
+- "I don't have information about specific vendors"`
+}
+
export function getRulesSection(
cwd: string,
supportsComputerUse: boolean,
@@ -177,5 +192,5 @@ ${getEditingInstructions(mode, customModes, experiments, codeIndexManager, setti
hasBrowserAction
? " Then if you want to test your work, you might use browser_action to launch the site, wait for the user's response confirming the site was launched along with a screenshot, then perhaps e.g., click a button to test functionality if needed, wait for the user's response confirming the button was clicked along with a screenshot of the new state, before finally closing the browser."
: ""
- }`
+ }${settings?.isStealthModel ? getVendorConfidentialitySection() : ""}`
}
diff --git a/src/core/prompts/tools/native-tools/write_to_file.ts b/src/core/prompts/tools/native-tools/write_to_file.ts
index 2febb32b2e..4ab7c53b6e 100644
--- a/src/core/prompts/tools/native-tools/write_to_file.ts
+++ b/src/core/prompts/tools/native-tools/write_to_file.ts
@@ -5,17 +5,14 @@ const WRITE_TO_FILE_DESCRIPTION = `Request to write content to a file. This tool
Parameters:
- path: (required) The path of the file to write to (relative to the current workspace directory)
- content: (required) The content to write to the file. When performing a full rewrite of an existing file or creating a new one, ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified. Do NOT include the line numbers in the content though, just the actual content of the file.
-- line_count: (required) The number of lines in the file. Make sure to compute this based on the actual content of the file, not the number of lines in the content you're providing.
Example: Writing a configuration file
-{ "path": "frontend-config.json", "content": "{\\n \\"apiEndpoint\\": \\"https://api.example.com\\",\\n \\"theme\\": {\\n \\"primaryColor\\": \\"#007bff\\"\\n }\\n}", "line_count": 5 }`
+{ "path": "frontend-config.json", "content": "{\\n \\"apiEndpoint\\": \\"https://api.example.com\\",\\n \\"theme\\": {\\n \\"primaryColor\\": \\"#007bff\\"\\n }\\n}" }`
const PATH_PARAMETER_DESCRIPTION = `Path to the file to write, relative to the workspace`
const CONTENT_PARAMETER_DESCRIPTION = `Full contents that the file should contain with no omissions or line numbers`
-const LINE_COUNT_PARAMETER_DESCRIPTION = `Total number of lines in the written file, counting blank lines`
-
export default {
type: "function",
function: {
@@ -33,12 +30,8 @@ export default {
type: "string",
description: CONTENT_PARAMETER_DESCRIPTION,
},
- line_count: {
- type: "integer",
- description: LINE_COUNT_PARAMETER_DESCRIPTION,
- },
},
- required: ["path", "content", "line_count"],
+ required: ["path", "content"],
additionalProperties: false,
},
},
diff --git a/src/core/prompts/tools/write-to-file.ts b/src/core/prompts/tools/write-to-file.ts
index 221103b04f..c957f0891e 100644
--- a/src/core/prompts/tools/write-to-file.ts
+++ b/src/core/prompts/tools/write-to-file.ts
@@ -6,14 +6,12 @@ Description: Request to write content to a file. This tool is primarily used for
Parameters:
- path: (required) The path of the file to write to (relative to the current workspace directory ${args.cwd})
- content: (required) The content to write to the file. When performing a full rewrite of an existing file or creating a new one, ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified. Do NOT include the line numbers in the content though, just the actual content of the file.
-- line_count: (required) The number of lines in the file. Make sure to compute this based on the actual content of the file, not the number of lines in the content you're providing.
Usage:
File path here
Your file content here
-total number of lines in the file, including empty lines
Example: Requesting to write to frontend-config.json
@@ -35,6 +33,5 @@ Example: Requesting to write to frontend-config.json
"version": "1.0.0"
}
-14
`
}
diff --git a/src/core/prompts/types.ts b/src/core/prompts/types.ts
index cab5228f08..30cc4e4700 100644
--- a/src/core/prompts/types.ts
+++ b/src/core/prompts/types.ts
@@ -11,4 +11,6 @@ export interface SystemPromptSettings {
newTaskRequireTodos: boolean
terminalShellIntegrationDisabled?: boolean
toolProtocol?: ToolProtocol
+ /** When true, model should hide vendor/company identity in responses */
+ isStealthModel?: boolean
}
diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts
index a3a399ff99..13580c32a9 100644
--- a/src/core/task/Task.ts
+++ b/src/core/task/Task.ts
@@ -2277,8 +2277,7 @@ export class Task extends EventEmitter implements TaskLike {
// Add environment details as its own text block, separate from tool
// results.
- const finalUserContent = [...contentWithoutEnvDetails, { type: "text" as const, text: environmentDetails }]
-
+ let finalUserContent = [...contentWithoutEnvDetails, { type: "text" as const, text: environmentDetails }]
// Only add user message to conversation history if:
// 1. This is the first attempt (retryAttempt === 0), AND
// 2. The original userContent was not empty (empty signals delegation resume where
@@ -3383,6 +3382,7 @@ export class Task extends EventEmitter implements TaskLike {
.getConfiguration(Package.name)
.get("newTaskRequireTodos", false),
toolProtocol,
+ isStealthModel: modelInfo?.isStealthModel,
},
undefined, // todoList
this.api.getModel().id,
diff --git a/src/core/tools/WriteToFileTool.ts b/src/core/tools/WriteToFileTool.ts
index f7d7d2c6a6..f1bae7ff2f 100644
--- a/src/core/tools/WriteToFileTool.ts
+++ b/src/core/tools/WriteToFileTool.ts
@@ -18,12 +18,10 @@ import { EXPERIMENT_IDS, experiments } from "../../shared/experiments"
import { convertNewFileToUnifiedDiff, computeDiffStats, sanitizeUnifiedDiff } from "../diff/stats"
import { BaseTool, ToolCallbacks } from "./BaseTool"
import type { ToolUse } from "../../shared/tools"
-import { resolveToolProtocol } from "../../utils/resolveToolProtocol"
interface WriteToFileParams {
path: string
content: string
- line_count: number
}
export class WriteToFileTool extends BaseTool<"write_to_file"> {
@@ -33,15 +31,13 @@ export class WriteToFileTool extends BaseTool<"write_to_file"> {
return {
path: params.path || "",
content: params.content || "",
- line_count: parseInt(params.line_count ?? "0", 10),
}
}
async execute(params: WriteToFileParams, task: Task, callbacks: ToolCallbacks): Promise {
- const { pushToolResult, handleError, askApproval, removeClosingTag, toolProtocol } = callbacks
+ const { pushToolResult, handleError, askApproval, removeClosingTag } = callbacks
const relPath = params.path
let newContent = params.content
- const predictedLineCount = params.line_count
if (!relPath) {
task.consecutiveMistakeCount++
@@ -63,7 +59,7 @@ export class WriteToFileTool extends BaseTool<"write_to_file"> {
if (!accessAllowed) {
await task.say("rooignore_error", relPath)
- pushToolResult(formatResponse.rooIgnoreError(relPath, toolProtocol))
+ pushToolResult(formatResponse.rooIgnoreError(relPath))
return
}
@@ -109,38 +105,6 @@ export class WriteToFileTool extends BaseTool<"write_to_file"> {
}
try {
- if (predictedLineCount === undefined || predictedLineCount === 0) {
- task.consecutiveMistakeCount++
- task.recordToolError("write_to_file")
- task.didToolFailInCurrentTurn = true
-
- const actualLineCount = newContent.split("\n").length
- const isNewFile = !fileExists
- const diffStrategyEnabled = !!task.diffStrategy
- const modelInfo = task.api.getModel().info
- const toolProtocol = resolveToolProtocol(task.apiConfiguration, modelInfo)
-
- await task.say(
- "error",
- `Roo tried to use write_to_file${
- relPath ? ` for '${relPath.toPosix()}'` : ""
- } but the required parameter 'line_count' was missing or truncated after ${actualLineCount} lines of content were written. Retrying...`,
- )
-
- pushToolResult(
- formatResponse.toolError(
- formatResponse.lineCountTruncationError(
- actualLineCount,
- isNewFile,
- diffStrategyEnabled,
- toolProtocol,
- ),
- ),
- )
- await task.diffViewProvider.revertChanges()
- return
- }
-
task.consecutiveMistakeCount = 0
const provider = task.providerRef.deref()
@@ -161,24 +125,22 @@ export class WriteToFileTool extends BaseTool<"write_to_file"> {
task.diffViewProvider.originalContent = ""
}
- if (detectCodeOmission(task.diffViewProvider.originalContent || "", newContent, predictedLineCount)) {
+ if (detectCodeOmission(task.diffViewProvider.originalContent || "", newContent)) {
if (task.diffStrategy) {
pushToolResult(
formatResponse.toolError(
- `Content appears to be truncated (file has ${
- newContent.split("\n").length
- } lines but was predicted to have ${predictedLineCount} lines), and found comments indicating omitted code (e.g., '// rest of code unchanged', '/* previous code */'). Please provide the complete file content without any omissions if possible, or otherwise use the 'apply_diff' tool to apply the diff to the original file.`,
+ `Content appears to contain comments indicating omitted code (e.g., '// rest of code unchanged', '/* previous code */'). Please provide the complete file content without any omissions if possible, or otherwise use the 'apply_diff' tool to apply the diff to the original file.`,
),
)
return
} else {
vscode.window
.showWarningMessage(
- "Potential code truncation detected. cline happens when the AI reaches its max output limit.",
- "Follow cline guide to fix the issue",
+ "Potential code truncation detected. This happens when the AI reaches its max output limit.",
+ "Follow guide to fix the issue",
)
.then((selection) => {
- if (selection === "Follow cline guide to fix the issue") {
+ if (selection === "Follow guide to fix the issue") {
vscode.env.openExternal(
vscode.Uri.parse(
"https://github.com/cline/cline/wiki/Troubleshooting-%E2%80%90-Cline-Deleting-Code-with-%22Rest-of-Code-Here%22-Comments",
@@ -221,26 +183,24 @@ export class WriteToFileTool extends BaseTool<"write_to_file"> {
await delay(300)
task.diffViewProvider.scrollToFirstDiff()
- if (detectCodeOmission(task.diffViewProvider.originalContent || "", newContent, predictedLineCount)) {
+ if (detectCodeOmission(task.diffViewProvider.originalContent || "", newContent)) {
if (task.diffStrategy) {
await task.diffViewProvider.revertChanges()
pushToolResult(
formatResponse.toolError(
- `Content appears to be truncated (file has ${
- newContent.split("\n").length
- } lines but was predicted to have ${predictedLineCount} lines), and found comments indicating omitted code (e.g., '// rest of code unchanged', '/* previous code */'). Please provide the complete file content without any omissions if possible, or otherwise use the 'apply_diff' tool to apply the diff to the original file.`,
+ `Content appears to contain comments indicating omitted code (e.g., '// rest of code unchanged', '/* previous code */'). Please provide the complete file content without any omissions if possible, or otherwise use the 'apply_diff' tool to apply the diff to the original file.`,
),
)
return
} else {
vscode.window
.showWarningMessage(
- "Potential code truncation detected. cline happens when the AI reaches its max output limit.",
- "Follow cline guide to fix the issue",
+ "Potential code truncation detected. This happens when the AI reaches its max output limit.",
+ "Follow guide to fix the issue",
)
.then((selection) => {
- if (selection === "Follow cline guide to fix the issue") {
+ if (selection === "Follow guide to fix the issue") {
vscode.env.openExternal(
vscode.Uri.parse(
"https://github.com/cline/cline/wiki/Troubleshooting-%E2%80%90-Cline-Deleting-Code-with-%22Rest-of-Code-Here%22-Comments",
diff --git a/src/core/tools/__tests__/writeToFileTool.spec.ts b/src/core/tools/__tests__/writeToFileTool.spec.ts
index 62ec037242..fffa1f07fd 100644
--- a/src/core/tools/__tests__/writeToFileTool.spec.ts
+++ b/src/core/tools/__tests__/writeToFileTool.spec.ts
@@ -36,9 +36,6 @@ vi.mock("../../prompts/responses", () => ({
formatResponse: {
toolError: vi.fn((msg) => `Error: ${msg}`),
rooIgnoreError: vi.fn((path) => `Access denied: ${path}`),
- lineCountTruncationError: vi.fn(
- (count, isNew, diffEnabled) => `Line count error: ${count}, new: ${isNew}, diff: ${diffEnabled}`,
- ),
createPrettyPatch: vi.fn(() => "mock-diff"),
},
}))
@@ -235,7 +232,6 @@ describe("writeToFileTool", () => {
params: {
path: testFilePath,
content: testContent,
- line_count: "3",
...params,
},
partial: isPartial,
@@ -394,8 +390,9 @@ describe("writeToFileTool", () => {
expect(mockedIsPathOutsideWorkspace).toHaveBeenCalled()
})
- it("processes files with very large line counts", async () => {
- await executeWriteFileTool({ line_count: "999999" })
+ it("processes files with large content", async () => {
+ const largeContent = "Line\n".repeat(10000)
+ await executeWriteFileTool({ content: largeContent })
// Should process normally without issues
expect(mockCline.consecutiveMistakeCount).toBe(0)
diff --git a/src/core/webview/generateSystemPrompt.ts b/src/core/webview/generateSystemPrompt.ts
index 335a4330c3..02c077fb36 100644
--- a/src/core/webview/generateSystemPrompt.ts
+++ b/src/core/webview/generateSystemPrompt.ts
@@ -99,6 +99,7 @@ export const generateSystemPrompt = async (provider: ClineProvider, message: Web
.getConfiguration(Package.name)
.get("newTaskRequireTodos", false),
toolProtocol,
+ isStealthModel: modelInfo?.isStealthModel,
},
)
diff --git a/src/integrations/editor/__tests__/detect-omission.spec.ts b/src/integrations/editor/__tests__/detect-omission.spec.ts
index 3f0ffceb7d..6ff31c390a 100644
--- a/src/integrations/editor/__tests__/detect-omission.spec.ts
+++ b/src/integrations/editor/__tests__/detect-omission.spec.ts
@@ -8,7 +8,8 @@ describe("detectCodeOmission", () => {
return x + y;
}`
- const generateLongContent = (commentLine: string, length: number = 90) => {
+ // Generate content with a specified number of lines (100+ lines triggers detection)
+ const generateLongContent = (commentLine: string, length: number = 110) => {
return `${commentLine}
${Array.from({ length }, (_, i) => `const x${i} = ${i};`).join("\n")}
const y = 2;`
@@ -17,126 +18,63 @@ describe("detectCodeOmission", () => {
it("should skip comment checks for files under 100 lines", () => {
const newContent = `// Lines 1-50 remain unchanged
const z = 3;`
- const predictedLineCount = 50
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(false)
+ expect(detectCodeOmission(originalContent, newContent)).toBe(false)
})
it("should not detect regular comments without omission keywords", () => {
const newContent = generateLongContent("// Adding new functionality")
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(false)
+ expect(detectCodeOmission(originalContent, newContent)).toBe(false)
})
it("should not detect when comment is part of original content", () => {
const originalWithComment = `// Content remains unchanged
${originalContent}`
const newContent = generateLongContent("// Content remains unchanged")
- const predictedLineCount = 150
- expect(detectCodeOmission(originalWithComment, newContent, predictedLineCount)).toBe(false)
+ expect(detectCodeOmission(originalWithComment, newContent)).toBe(false)
})
it("should not detect code that happens to contain omission keywords", () => {
const newContent = generateLongContent(`const remains = 'some value';
const unchanged = true;`)
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(false)
+ expect(detectCodeOmission(originalContent, newContent)).toBe(false)
})
- it("should detect suspicious single-line comment when content is more than 20% shorter", () => {
+ it("should detect suspicious single-line comment for files with 100+ lines", () => {
const newContent = generateLongContent("// Previous content remains here\nconst x = 1;")
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(true)
+ expect(detectCodeOmission(originalContent, newContent)).toBe(true)
})
- it("should not flag suspicious single-line comment when content is less than 20% shorter", () => {
- const newContent = generateLongContent("// Previous content remains here", 130)
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(false)
- })
-
- it("should detect suspicious Python-style comment when content is more than 20% shorter", () => {
+ it("should detect suspicious Python-style comment for files with 100+ lines", () => {
const newContent = generateLongContent("# Previous content remains here\nconst x = 1;")
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(true)
+ expect(detectCodeOmission(originalContent, newContent)).toBe(true)
})
- it("should not flag suspicious Python-style comment when content is less than 20% shorter", () => {
- const newContent = generateLongContent("# Previous content remains here", 130)
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(false)
- })
-
- it("should detect suspicious multi-line comment when content is more than 20% shorter", () => {
+ it("should detect suspicious multi-line comment for files with 100+ lines", () => {
const newContent = generateLongContent("/* Previous content remains the same */\nconst x = 1;")
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(true)
- })
-
- it("should not flag suspicious multi-line comment when content is less than 20% shorter", () => {
- const newContent = generateLongContent("/* Previous content remains the same */", 130)
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(false)
+ expect(detectCodeOmission(originalContent, newContent)).toBe(true)
})
- it("should detect suspicious JSX comment when content is more than 20% shorter", () => {
+ it("should detect suspicious JSX comment for files with 100+ lines", () => {
const newContent = generateLongContent("{/* Rest of the code remains the same */}\nconst x = 1;")
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(true)
- })
-
- it("should not flag suspicious JSX comment when content is less than 20% shorter", () => {
- const newContent = generateLongContent("{/* Rest of the code remains the same */}", 130)
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(false)
+ expect(detectCodeOmission(originalContent, newContent)).toBe(true)
})
- it("should detect suspicious HTML comment when content is more than 20% shorter", () => {
+ it("should detect suspicious HTML comment for files with 100+ lines", () => {
const newContent = generateLongContent("\nconst x = 1;")
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(true)
- })
-
- it("should not flag suspicious HTML comment when content is less than 20% shorter", () => {
- const newContent = generateLongContent("", 130)
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(false)
+ expect(detectCodeOmission(originalContent, newContent)).toBe(true)
})
- it("should detect suspicious square bracket notation when content is more than 20% shorter", () => {
+ it("should detect suspicious square bracket notation for files with 100+ lines", () => {
const newContent = generateLongContent(
"[Previous content from line 1-305 remains exactly the same]\nconst x = 1;",
)
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(true)
+ expect(detectCodeOmission(originalContent, newContent)).toBe(true)
})
- it("should not flag suspicious square bracket notation when content is less than 20% shorter", () => {
- const newContent = generateLongContent("[Previous content from line 1-305 remains exactly the same]", 130)
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(false)
- })
-
- it("should not flag content very close to predicted length", () => {
- const newContent = generateLongContent(
- `const x = 1;
-const y = 2;
-// This is a legitimate comment that remains here`,
- 130,
- )
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(false)
- })
-
- it("should not flag when content is longer than predicted", () => {
- const newContent = generateLongContent(
- `const x = 1;
-const y = 2;
-// Previous content remains here but we added more
-const z = 3;
-const w = 4;`,
- 160,
- )
- const predictedLineCount = 150
- expect(detectCodeOmission(originalContent, newContent, predictedLineCount)).toBe(false)
+ it("should not flag legitimate comments in files with 100+ lines when in original", () => {
+ const originalWithComment = `// This is a legitimate comment that remains here
+${originalContent}`
+ const newContent = generateLongContent("// This is a legitimate comment that remains here")
+ expect(detectCodeOmission(originalWithComment, newContent)).toBe(false)
})
})
diff --git a/src/integrations/editor/detect-omission.ts b/src/integrations/editor/detect-omission.ts
index 50bef62281..d55acd4183 100644
--- a/src/integrations/editor/detect-omission.ts
+++ b/src/integrations/editor/detect-omission.ts
@@ -1,23 +1,18 @@
/**
* Detects potential AI-generated code omissions in the given file content.
+ * Looks for comments containing omission keywords that weren't in the original file.
* @param originalFileContent The original content of the file.
* @param newFileContent The new content of the file to check.
- * @param predictedLineCount The predicted number of lines in the new content.
* @returns True if a potential omission is detected, false otherwise.
*/
-export function detectCodeOmission(
- originalFileContent: string,
- newFileContent: string,
- predictedLineCount: number,
-): boolean {
- // Skip all checks if predictedLineCount is less than 100
- if (!predictedLineCount || predictedLineCount < 100) {
+export function detectCodeOmission(originalFileContent: string, newFileContent: string): boolean {
+ const actualLineCount = newFileContent.split("\n").length
+
+ // Skip checks for small files (less than 100 lines)
+ if (actualLineCount < 100) {
return false
}
- const actualLineCount = newFileContent.split("\n").length
- const lengthRatio = actualLineCount / predictedLineCount
-
const originalLines = originalFileContent.split("\n")
const newLines = newFileContent.split("\n")
const omissionKeywords = [
@@ -48,10 +43,7 @@ export function detectCodeOmission(
const words = line.toLowerCase().split(/\s+/)
if (omissionKeywords.some((keyword) => words.includes(keyword))) {
if (!originalLines.includes(line)) {
- // For files with 100+ lines, only flag if content is more than 20% shorter
- if (lengthRatio <= 0.8) {
- return true
- }
+ return true
}
}
}
diff --git a/src/shared/tools.ts b/src/shared/tools.ts
index e993c81dd9..b754bb3614 100644
--- a/src/shared/tools.ts
+++ b/src/shared/tools.ts
@@ -39,7 +39,6 @@ export const toolParamNames = [
"command",
"path",
"content",
- "line_count",
"regex",
"file_pattern",
"recursive",
@@ -106,7 +105,7 @@ export type NativeToolArgs = {
switch_mode: { mode_slug: string; reason: string }
update_todo_list: { todos: string }
use_mcp_tool: { server_name: string; tool_name: string; arguments?: Record }
- write_to_file: { path: string; content: string; line_count: number }
+ write_to_file: { path: string; content: string }
// Add more tools as they are migrated to native protocol
}
@@ -164,7 +163,7 @@ export interface FetchInstructionsToolUse extends ToolUse<"fetch_instructions">
export interface WriteToFileToolUse extends ToolUse<"write_to_file"> {
name: "write_to_file"
- params: Partial, "path" | "content" | "line_count">>
+ params: Partial, "path" | "content">>
}
export interface InsertCodeBlockToolUse extends ToolUse<"insert_content"> {
diff --git a/webview-ui/src/App.tsx b/webview-ui/src/App.tsx
index 355bb35f21..8a18b66fdb 100644
--- a/webview-ui/src/App.tsx
+++ b/webview-ui/src/App.tsx
@@ -1,7 +1,6 @@
import React, { useCallback, useEffect, useRef, useState, useMemo } from "react"
import { useEvent } from "react-use"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
-// import posthog from "posthog-js"
import { ExtensionMessage } from "@roo/ExtensionMessage"
import TranslationProvider from "./i18n/TranslationContext"
@@ -15,14 +14,8 @@ import { ExtensionStateContextProvider, useExtensionState } from "./context/Exte
import ChatView, { ChatViewRef } from "./components/chat/ChatView"
import HistoryView from "./components/history/HistoryView"
import SettingsView, { SettingsViewRef } from "./components/settings/SettingsView"
-import WelcomeView from "./components/welcome/WelcomeView"
-// import WelcomeViewProvider from "./components/welcome/WelcomeViewProvider"
-// import McpView from "./components/mcp/McpView"
-// import { MarketplaceView } from "./components/marketplace/MarketplaceView"
-// import ModesView from "./components/modes/ModesView"
import CodeReviewPage from "./components/code-review"
-// import WelcomeViewProvider from "./components/welcome/WelcomeViewProvider"
-// import { MarketplaceView } from "./components/marketplace/MarketplaceView"
+import WelcomeView from "./components/welcome/WelcomeViewProvider"
import { HumanRelayDialog } from "./components/human-relay/HumanRelayDialog"
import { CheckpointRestoreDialog } from "./components/chat/CheckpointRestoreDialog"
import { DeleteMessageDialog, EditMessageDialog } from "./components/chat/MessageModificationConfirmationDialog"
@@ -106,21 +99,6 @@ const App = () => {
} = useExtensionState()
const { t } = useTranslation()
- // const [useProviderSignupView, setUseProviderSignupView] = useState(false)
-
- // // Check PostHog feature flag for provider signup view
- // // Wait for telemetry to be initialized before checking feature flags
- // useEffect(() => {
- // if (!didHydrateState || telemetrySetting === "disabled") {
- // return
- // }
-
- // posthog.onFeatureFlags(function () {
- // // Feature flag for new provider-focused welcome view
- // setUseProviderSignupView(posthog?.getFeatureFlag("welcome-provider-signup") === "test")
- // })
- // }, [didHydrateState, telemetrySetting])
-
// Create a persistent state manager
// const marketplaceStateManager = useMemo(() => new MarketplaceViewStateManager(), [])
diff --git a/webview-ui/src/__tests__/App.spec.tsx b/webview-ui/src/__tests__/App.spec.tsx
index d550c62ef1..4580b6c345 100644
--- a/webview-ui/src/__tests__/App.spec.tsx
+++ b/webview-ui/src/__tests__/App.spec.tsx
@@ -5,14 +5,6 @@ import { render, screen, act, cleanup } from "@/utils/test-utils"
import AppWithProviders from "../App"
-// Mock posthog
-vi.mock("posthog-js", () => ({
- default: {
- onFeatureFlags: vi.fn(),
- getFeatureFlag: vi.fn(),
- },
-}))
-
vi.mock("@src/utils/vscode", () => ({
vscode: {
postMessage: vi.fn(),
@@ -307,6 +299,12 @@ describe("App", () => {
// marketplaceView.click()
// })
+ // const marketplaceView = await screen.findByTestId("marketplace-view")
+
+ // act(() => {
+ // marketplaceView.click()
+ // })
+
// const chatView = screen.getByTestId("chat-view")
// expect(chatView.getAttribute("data-hidden")).toBe("false")
// expect(screen.queryByTestId("marketplace-view")).not.toBeInTheDocument()
diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx
index b3056d5f38..514ffc902c 100644
--- a/webview-ui/src/components/chat/ChatView.tsx
+++ b/webview-ui/src/components/chat/ChatView.tsx
@@ -1581,7 +1581,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction}
onClick={() => openUpsell()}
dismissOnClick={false}
- className="bg-none mt-6 border-border rounded-xl p-0 py-3 !text-base">
+ className="bg-none mt-6 border-border rounded-xl p-0 py-3 !text-base">
opt.value === "openrouter")
+ const zgsmIndex = options.findIndex((opt) => opt.value === "zgsm")
+ if (openRouterIndex > 0) {
+ options.splice(zgsmIndex, 1)
+ }
if (openRouterIndex > 0) {
const [openRouterOption] = options.splice(openRouterIndex, 1)
options.unshift(openRouterOption)
@@ -564,7 +568,7 @@ const ApiOptions = ({