Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions PRIVACY.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,10 @@ Roo Code respects your privacy and is committed to transparency about how we han
- **Commands**: Any commands executed through Roo Code happen on your local environment. However, when you use AI-powered features, the relevant code and context from your commands may be transmitted to your chosen AI model provider (e.g., OpenAI, Anthropic, OpenRouter) to generate responses. We do not have access to or store this data, but AI providers may process it per their privacy policies.
- **Prompts & AI Requests**: When you use AI-powered features, your prompts and relevant project context are sent to your chosen AI model provider (e.g., OpenAI, Anthropic, OpenRouter) to generate responses. We do not store or process this data. These AI providers have their own privacy policies and may store data per their terms of service.
- **API Keys & Credentials**: If you enter an API key (e.g., to connect an AI model), it is stored locally on your device and never sent to us or any third party, except the provider you have chosen.
- **Telemetry (Usage Data)**: We only collect feature usage and error data if you explicitly opt-in. This telemetry is powered by PostHog and helps us understand feature usage to improve Roo Code. This includes your VS Code machine ID and feature usage patterns and exception reports. We do **not** collect personally identifiable information, your code, or AI prompts.

### **How We Use Your Data (If Collected)**

- If you opt-in to telemetry, we use it to understand feature usage and improve Roo Code.
- We do **not** sell or share your data.
- We do **not** train any models on your data.

### **Your Choices & Control**

- You can run models locally to prevent data being sent to third-parties.
- By default, telemetry collection is off and if you turn it on, you can opt out of telemetry at any time.
- You can delete Roo Code to stop all data collection.

### **Security & Updates**

Expand Down
21 changes: 0 additions & 21 deletions src/core/Cline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ import { McpHub } from "../services/mcp/McpHub"
import crypto from "crypto"
import { insertGroups } from "./diff/insert-groups"
import { OutputBuilder } from "../integrations/terminal/OutputBuilder"
import { telemetryService } from "../services/telemetry/TelemetryService"

const cwd =
vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0) ?? path.join(os.homedir(), "Desktop") // may or may not exist but fs checking existence would immediately ask for permission which would be bad UX, need to come up with a better solution
Expand Down Expand Up @@ -191,12 +190,6 @@ export class Cline {
this.enableCheckpoints = enableCheckpoints
this.checkpointStorage = checkpointStorage

if (historyItem) {
telemetryService.captureTaskRestarted(this.taskId)
} else {
telemetryService.captureTaskCreated(this.taskId)
}

// Initialize diffStrategy based on current state
this.updateDiffStrategy(
Experiments.isEnabled(experiments ?? {}, EXPERIMENT_IDS.DIFF_STRATEGY),
Expand Down Expand Up @@ -1468,10 +1461,6 @@ export class Cline {
await this.browserSession.closeBrowser()
}

if (!block.partial) {
telemetryService.captureToolUsage(this.taskId, block.name)
}

// Validate tool use before execution
const { mode, customModes } = (await this.providerRef.deref()?.getState()) ?? {}
try {
Expand Down Expand Up @@ -2956,7 +2945,6 @@ export class Cline {
if (lastMessage && lastMessage.ask !== "command") {
// havent sent a command message yet so first send completion_result then command
await this.say("completion_result", result, undefined, false)
telemetryService.captureTaskCompleted(this.taskId)
}

// complete command message
Expand All @@ -2974,7 +2962,6 @@ export class Cline {
commandResult = execCommandResult
} else {
await this.say("completion_result", result, undefined, false)
telemetryService.captureTaskCompleted(this.taskId)
}

if (this.isSubTask) {
Expand Down Expand Up @@ -3144,7 +3131,6 @@ export class Cline {
userContent.push({ type: "text", text: environmentDetails })

await this.addToApiConversationHistory({ role: "user", content: userContent })
telemetryService.captureConversationMessage(this.taskId, "user")

// since we sent off a placeholder api_req_started message to update the webview while waiting to actually start the API request (to load potential details for example), we need to update the text of that message
const lastApiReqIndex = findLastIndex(this.clineMessages, (m) => m.say === "api_req_started")
Expand Down Expand Up @@ -3346,7 +3332,6 @@ export class Cline {
role: "assistant",
content: [{ type: "text", text: assistantMessage }],
})
telemetryService.captureConversationMessage(this.taskId, "assistant")

// NOTE: this comment is here for future reference - this was a workaround for userMessageContent not getting set to true. It was due to it not recursively calling for partial blocks when didRejectTool, so it would get stuck waiting for a partial block to complete before it could continue.
// in case the content blocks finished
Expand Down Expand Up @@ -3798,8 +3783,6 @@ export class Cline {
return
}

telemetryService.captureCheckpointDiffed(this.taskId)

if (!previousCommitHash && mode === "checkpoint") {
const previousCheckpoint = this.clineMessages
.filter(({ say }) => say === "checkpoint_saved")
Expand Down Expand Up @@ -3851,8 +3834,6 @@ export class Cline {
return
}

telemetryService.captureCheckpointCreated(this.taskId)

// Start the checkpoint process in the background.
service.saveCheckpoint(`Task: ${this.taskId}, Time: ${Date.now()}`).catch((err) => {
console.error("[Cline#checkpointSave] caught unexpected error, disabling checkpoints", err)
Expand Down Expand Up @@ -3884,8 +3865,6 @@ export class Cline {
try {
await service.restoreCheckpoint(commitHash)

telemetryService.captureCheckpointRestored(this.taskId)

await this.providerRef.deref()?.postMessageToWebview({ type: "currentCheckpointUpdated", text: commitHash })

if (mode === "restore") {
Expand Down
78 changes: 1 addition & 77 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ import { Cline, ClineOptions } from "../Cline"
import { openMention } from "../mentions"
import { getNonce } from "./getNonce"
import { getUri } from "./getUri"
import { telemetryService } from "../../services/telemetry/TelemetryService"
import { TelemetrySetting } from "../../shared/TelemetrySetting"

/**
* https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts
Expand Down Expand Up @@ -85,9 +83,6 @@ export class ClineProvider implements vscode.WebviewViewProvider {
this.contextProxy = new ContextProxy(context)
ClineProvider.activeInstances.add(this)

// Register this provider with the telemetry service to enable it to add properties like mode and provider
telemetryService.setProvider(this)

this.workspaceTracker = new WorkspaceTracker(this)
this.configManager = new ConfigManager(this.context)
this.customModesManager = new CustomModesManager(this.context, async () => {
Expand Down Expand Up @@ -931,13 +926,6 @@ export class ClineProvider implements vscode.WebviewViewProvider {
),
)

// If user already opted in to telemetry, enable telemetry service
this.getStateToPostToWebview().then((state) => {
const { telemetrySetting } = state
const isOptedIn = telemetrySetting === "enabled"
telemetryService.updateTelemetryState(isOptedIn)
})

this.isViewLaunched = true
break
case "newTask":
Expand Down Expand Up @@ -1799,15 +1787,6 @@ export class ClineProvider implements vscode.WebviewViewProvider {
})
}
break

case "telemetrySetting": {
const telemetrySetting = message.text as TelemetrySetting
await this.updateGlobalState("telemetrySetting", telemetrySetting)
const isOptedIn = telemetrySetting === "enabled"
telemetryService.updateTelemetryState(isOptedIn)
await this.postStateToWebview()
break
}
}
},
null,
Expand Down Expand Up @@ -1867,12 +1846,6 @@ export class ClineProvider implements vscode.WebviewViewProvider {
* @param newMode The mode to switch to
*/
public async handleModeSwitch(newMode: Mode) {
// Capture mode switch telemetry event
const currentTaskId = this.getCurrentCline()?.taskId
if (currentTaskId) {
telemetryService.captureModeSwitch(currentTaskId, newMode)
}

await this.updateGlobalState("mode", newMode)

// Load the saved API config for the new mode if it exists
Expand Down Expand Up @@ -2211,10 +2184,8 @@ export class ClineProvider implements vscode.WebviewViewProvider {
experiments,
maxOpenTabsContext,
browserToolEnabled,
telemetrySetting,
showRooIgnoredFiles,
} = await this.getState()
const telemetryKey = process.env.POSTHOG_API_KEY
const machineId = vscode.env.machineId

const allowedCommands = vscode.workspace.getConfiguration("roo-cline").get<string[]>("allowedCommands") || []
Expand Down Expand Up @@ -2244,8 +2215,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
diffEnabled: diffEnabled ?? true,
enableCheckpoints: enableCheckpoints ?? true,
checkpointStorage: checkpointStorage ?? "task",
shouldShowAnnouncement:
telemetrySetting !== "unset" && lastShownAnnouncementId !== this.latestAnnouncementId,
shouldShowAnnouncement: lastShownAnnouncementId !== this.latestAnnouncementId,
allowedCommands,
soundVolume: soundVolume ?? 0.5,
browserViewportSize: browserViewportSize ?? "900x600",
Expand All @@ -2272,8 +2242,6 @@ export class ClineProvider implements vscode.WebviewViewProvider {
maxOpenTabsContext: maxOpenTabsContext ?? 20,
cwd,
browserToolEnabled: browserToolEnabled ?? true,
telemetrySetting,
telemetryKey,
machineId,
showRooIgnoredFiles: showRooIgnoredFiles ?? true,
}
Expand Down Expand Up @@ -2455,7 +2423,6 @@ export class ClineProvider implements vscode.WebviewViewProvider {
maxOpenTabsContext: stateValues.maxOpenTabsContext ?? 20,
openRouterUseMiddleOutTransform: stateValues.openRouterUseMiddleOutTransform ?? true,
browserToolEnabled: stateValues.browserToolEnabled ?? true,
telemetrySetting: stateValues.telemetrySetting || "unset",
showRooIgnoredFiles: stateValues.showRooIgnoredFiles ?? true,
}
}
Expand Down Expand Up @@ -2535,47 +2502,4 @@ export class ClineProvider implements vscode.WebviewViewProvider {
public getMcpHub(): McpHub | undefined {
return this.mcpHub
}

/**
* Returns properties to be included in every telemetry event
* This method is called by the telemetry service to get context information
* like the current mode, API provider, etc.
*/
public async getTelemetryProperties(): Promise<Record<string, any>> {
const { mode, apiConfiguration } = await this.getState()
const appVersion = this.context.extension?.packageJSON?.version
const vscodeVersion = vscode.version
const platform = process.platform

const properties: Record<string, any> = {
vscodeVersion,
platform,
}

// Add extension version
if (appVersion) {
properties.appVersion = appVersion
}

// Add current mode
if (mode) {
properties.mode = mode
}

// Add API provider
if (apiConfiguration?.apiProvider) {
properties.apiProvider = apiConfiguration.apiProvider
}

// Add model ID if available
const currentCline = this.getCurrentCline()
if (currentCline?.api) {
const { id: modelId } = currentCline.api.getModel()
if (modelId) {
properties.modelId = modelId
}
}

return properties
}
}
60 changes: 0 additions & 60 deletions src/core/webview/__tests__/ClineProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,6 @@ describe("ClineProvider", () => {
experiments: experimentDefault,
maxOpenTabsContext: 20,
browserToolEnabled: true,
telemetrySetting: "unset",
showRooIgnoredFiles: true,
}

Expand Down Expand Up @@ -1652,62 +1651,3 @@ describe("ContextProxy integration", () => {
expect(mockContextProxy.setValues).toBeDefined()
})
})

describe("getTelemetryProperties", () => {
let provider: ClineProvider
let mockContext: vscode.ExtensionContext
let mockOutputChannel: vscode.OutputChannel
let mockCline: any

beforeEach(() => {
// Reset mocks
jest.clearAllMocks()

// Setup basic mocks
mockContext = {
globalState: {
get: jest.fn().mockImplementation((key: string) => {
if (key === "mode") return "code"
if (key === "apiProvider") return "anthropic"
return undefined
}),
update: jest.fn(),
keys: jest.fn().mockReturnValue([]),
},
secrets: { get: jest.fn(), store: jest.fn(), delete: jest.fn() },
extensionUri: {} as vscode.Uri,
globalStorageUri: { fsPath: "/test/path" },
extension: { packageJSON: { version: "1.0.0" } },
} as unknown as vscode.ExtensionContext

mockOutputChannel = { appendLine: jest.fn() } as unknown as vscode.OutputChannel
provider = new ClineProvider(mockContext, mockOutputChannel)

// Setup Cline instance with mocked getModel method
const { Cline } = require("../../Cline")
mockCline = new Cline()
mockCline.api = {
getModel: jest.fn().mockReturnValue({
id: "claude-3-7-sonnet-20250219",
info: { contextWindow: 200000 },
}),
}
})

test("includes basic properties in telemetry", async () => {
const properties = await provider.getTelemetryProperties()

expect(properties).toHaveProperty("vscodeVersion")
expect(properties).toHaveProperty("platform")
expect(properties).toHaveProperty("appVersion", "1.0.0")
})

test("includes model ID from current Cline instance if available", async () => {
// Add mock Cline to stack
await provider.addClineToStack(mockCline)

const properties = await provider.getTelemetryProperties()

expect(properties).toHaveProperty("modelId", "claude-3-7-sonnet-20250219")
})
})
6 changes: 0 additions & 6 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { CodeActionProvider } from "./core/CodeActionProvider"
import { DIFF_VIEW_URI_SCHEME } from "./integrations/editor/DiffViewProvider"
import { handleUri, registerCommands, registerCodeActions } from "./activate"
import { McpServerManager } from "./services/mcp/McpServerManager"
import { telemetryService } from "./services/telemetry/TelemetryService"

/**
* Built using https://github.com/microsoft/vscode-webview-ui-toolkit
Expand Down Expand Up @@ -51,9 +50,6 @@ export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(outputChannel)
outputChannel.appendLine("Roo-Code extension activated")

// Initialize telemetry service after environment variables are loaded
telemetryService.initialize()

// Get default commands from configuration.
const defaultCommands = vscode.workspace.getConfiguration("roo-cline").get<string[]>("allowedCommands") || []

Expand All @@ -62,7 +58,6 @@ export function activate(context: vscode.ExtensionContext) {
context.globalState.update("allowedCommands", defaultCommands)
}
const sidebarProvider = new ClineProvider(context, outputChannel)
telemetryService.setProvider(sidebarProvider)

context.subscriptions.push(
vscode.window.registerWebviewViewProvider(ClineProvider.sideBarId, sidebarProvider, {
Expand Down Expand Up @@ -151,5 +146,4 @@ export async function deactivate() {
outputChannel.appendLine("Roo-Code extension deactivated")
// Clean up MCP server manager
await McpServerManager.cleanup(extensionContext)
telemetryService.shutdown()
}
Loading