diff --git a/package.json b/package.json index 6456f6a3f7..2a809fc494 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "@radix-ui/react-slot": "^1.2.2", "@radix-ui/react-toast": "^1.2.13", "@radix-ui/react-tooltip": "^1.1.3", + "@roo-code/types": "^1.11.0", "@sentry/nextjs": "^9.17.0", "@spotlightjs/spotlight": "^2.5.0", "@t3-oss/env-nextjs": "^0.13.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 21a20ff2df..2afbb10ab6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,6 +59,9 @@ importers: '@radix-ui/react-tooltip': specifier: ^1.1.3 version: 1.2.6(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@roo-code/types': + specifier: ^1.11.0 + version: 1.11.0 '@sentry/nextjs': specifier: ^9.17.0 version: 9.17.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(next@15.3.2(@babel/core@7.27.1)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(webpack@5.99.8(@swc/core@1.11.24)(esbuild@0.25.4)) @@ -1820,8 +1823,8 @@ packages: bundledDependencies: - '@libsql/libsql-wasm-experimental' - '@libsql/core@0.15.5': - resolution: {integrity: sha512-18hhESfHuOdBNAXIAqZbXfe1xskpOn+vEuYIbWgtbzq7On8lGBA1FASQ8LpzBsP+Xv8fK2JoiDKIFDTc8jQ3mg==} + '@libsql/core@0.15.6': + resolution: {integrity: sha512-eqxxwB5Wsd4xxqt+RAVIAP05IobrBe6LFH4nSgGAE5dWauTlpMByVsYchYjvVdDSHk3EnByKJlSQuNr0RQiFxA==} '@logtail/core@0.5.4': resolution: {integrity: sha512-UlbxvUg5MDroqk6gEhtfKuuBShrvD/VaXl3T3jGU1U6I19Y1OwfB7e681LvH7RbsCAnOJFziM/7rMQib/CJTdg==} @@ -3048,6 +3051,9 @@ packages: cpu: [x64] os: [win32] + '@roo-code/types@1.11.0': + resolution: {integrity: sha512-hL8fohdd6qVre2sK2DOSXOfyMazaWEow4qfeffNDZQgNsye6xTw1eYlQ1D+7Jcb+Z7IYTORg2StyA+qQzLkc0Q==} + '@schummar/icu-type-parser@1.21.5': resolution: {integrity: sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==} @@ -10448,11 +10454,11 @@ snapshots: '@libsql/client-wasm@0.15.5': dependencies: - '@libsql/core': 0.15.5 + '@libsql/core': 0.15.6 js-base64: 3.7.7 optional: true - '@libsql/core@0.15.5': + '@libsql/core@0.15.6': dependencies: js-base64: 3.7.7 optional: true @@ -11786,6 +11792,10 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.40.2': optional: true + '@roo-code/types@1.11.0': + dependencies: + zod: 3.24.4 + '@schummar/icu-type-parser@1.21.5': {} '@sentry-internal/browser-utils@9.17.0': diff --git a/src/actions/analytics.ts b/src/actions/analytics.ts index a72fed41ac..5e2906bd9c 100644 --- a/src/actions/analytics.ts +++ b/src/actions/analytics.ts @@ -1,8 +1,9 @@ 'use server'; import { z } from 'zod'; +import { TelemetryEventName } from '@roo-code/types'; -import { TelemetryEventName, type TimePeriod } from '@/schemas'; +import { type TimePeriod } from '@/schemas'; import { client } from '@/lib/server/analytics'; /** diff --git a/src/app/api/events/route.ts b/src/app/api/events/route.ts index aaea0ff084..e5298c544a 100644 --- a/src/app/api/events/route.ts +++ b/src/app/api/events/route.ts @@ -2,7 +2,8 @@ import { auth } from '@clerk/nextjs/server'; import { NextRequest, NextResponse } from 'next/server'; import { v4 as uuidv4 } from 'uuid'; -import { telemetryEventSchema } from '@/schemas'; +import { rooCodeTelemetryEventSchema } from '@roo-code/types'; + import { captureEvent } from '@/lib/server/analytics'; export async function POST(request: NextRequest) { @@ -24,7 +25,7 @@ export async function POST(request: NextRequest) { const id = uuidv4(); const timestamp = Math.round(Date.now() / 1000); - const result = telemetryEventSchema.safeParse(await request.json()); + const result = rooCodeTelemetryEventSchema.safeParse(await request.json()); if (!result.success) { console.error(result.error); diff --git a/src/components/dashboard/UsageAnalyticsCard.tsx b/src/components/dashboard/UsageAnalyticsCard.tsx index 66ad564486..cf683269dc 100644 --- a/src/components/dashboard/UsageAnalyticsCard.tsx +++ b/src/components/dashboard/UsageAnalyticsCard.tsx @@ -5,8 +5,9 @@ import Link from 'next/link'; import { useTranslations } from 'next-intl'; import { useAuth } from '@clerk/nextjs'; import { useQuery } from '@tanstack/react-query'; +import { TelemetryEventName } from '@roo-code/types'; -import { TelemetryEventName, type TimePeriod, timePeriods } from '@/schemas'; +import { type TimePeriod, timePeriods } from '@/schemas'; import { getUsage } from '@/actions/analytics'; import { Button } from '@/components/ui'; diff --git a/src/lib/server/analytics.ts b/src/lib/server/analytics.ts index 57d5e88a50..1c8f80c3bc 100644 --- a/src/lib/server/analytics.ts +++ b/src/lib/server/analytics.ts @@ -1,6 +1,7 @@ import { createClient } from '@clickhouse/client'; -import type { TelemetryEvent } from '@/schemas'; +import type { RooCodeTelemetryEvent } from '@roo-code/types'; + import { Env } from './env'; export const client = createClient({ @@ -14,7 +15,7 @@ type AnalyticsEvent = { orgId: string; userId: string; timestamp: number; - event: TelemetryEvent; + event: RooCodeTelemetryEvent; }; export const captureEvent = async ({ diff --git a/src/schemas/index.ts b/src/schemas/index.ts index f23a930665..b8de0f47b5 100644 --- a/src/schemas/index.ts +++ b/src/schemas/index.ts @@ -1,114 +1,3 @@ -import { z } from 'zod'; - -/** - * ProviderName - */ - -export const providerNames = [ - 'anthropic', - 'glama', - 'openrouter', - 'bedrock', - 'vertex', - 'openai', - 'ollama', - 'vscode-lm', - 'lmstudio', - 'gemini', - 'openai-native', - 'mistral', - 'deepseek', - 'unbound', - 'requesty', - 'human-relay', - 'fake-ai', - 'xai', - 'groq', - 'chutes', - 'litellm', -] as const; - -export type ProviderName = (typeof providerNames)[number]; - -/** - * TelemetryEventName - */ - -export enum TelemetryEventName { - TASK_CREATED = 'Task Created', - TASK_RESTARTED = 'Task Reopened', - TASK_COMPLETED = 'Task Completed', - TASK_CONVERSATION_MESSAGE = 'Conversation Message', - LLM_COMPLETION = 'LLM Completion', - MODE_SWITCH = 'Mode Switched', - TOOL_USED = 'Tool Used', - - CHECKPOINT_CREATED = 'Checkpoint Created', - CHECKPOINT_RESTORED = 'Checkpoint Restored', - CHECKPOINT_DIFFED = 'Checkpoint Diffed', - - CODE_ACTION_USED = 'Code Action Used', - PROMPT_ENHANCED = 'Prompt Enhanced', - - TITLE_BUTTON_CLICKED = 'Title Button Clicked', - - AUTHENTICATION_INITIATED = 'Authentication Initiated', - - SCHEMA_VALIDATION_ERROR = 'Schema Validation Error', - DIFF_APPLICATION_ERROR = 'Diff Application Error', - SHELL_INTEGRATION_ERROR = 'Shell Integration Error', - CONSECUTIVE_MISTAKE_ERROR = 'Consecutive Mistake Error', -} - -/** - * TelemetryEvent - */ - -export const appPropertiesSchema = z.object({ - appVersion: z.string(), - vscodeVersion: z.string(), - platform: z.string(), - editorName: z.string(), - language: z.string(), - mode: z.string(), -}); - -export const taskPropertiesSchema = z.object({ - taskId: z.string(), - apiProvider: z.enum(providerNames).optional(), - modelId: z.string().optional(), - diffStrategy: z.string().optional(), - isSubtask: z.boolean().optional(), -}); - -export const completionPropertiesSchema = z.object({ - inputTokens: z.number(), - outputTokens: z.number(), - cacheReadTokens: z.number().optional(), - cacheWriteTokens: z.number().optional(), - cost: z.number().optional(), -}); - -export const telemetryEventSchema = z.discriminatedUnion('type', [ - z.object({ - type: z.literal(TelemetryEventName.TASK_CREATED), - properties: z.object({ - ...appPropertiesSchema.shape, - ...taskPropertiesSchema.shape, - }), - }), - z.object({ - type: z.literal(TelemetryEventName.LLM_COMPLETION), - properties: z.object({ - ...appPropertiesSchema.shape, - ...taskPropertiesSchema.shape, - ...completionPropertiesSchema.shape, - }), - }), -]); - -export type TelemetryEvent = z.infer; - /** * TimePeriod */