From cb2f9fe94af531ccc8d855f3e0fef0cd28da1bab Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Tue, 4 Aug 2026 12:06:04 -0700 Subject: [PATCH] chore(copilot): remove the training controls feature --- .../api/copilot/training/examples/route.ts | 82 ---------------- apps/sim/app/api/copilot/training/route.ts | 94 ------------------- .../settings/components/general/general.tsx | 19 ---- .../components/output-panel/output-panel.tsx | 33 ------- .../components/terminal/terminal.tsx | 62 +----------- apps/sim/hooks/queries/general-settings.ts | 7 -- apps/sim/lib/api/contracts/copilot.ts | 53 ----------- apps/sim/lib/api/contracts/user.ts | 2 - apps/sim/lib/core/config/env.ts | 2 - apps/sim/lib/users/queries.ts | 3 - 10 files changed, 1 insertion(+), 356 deletions(-) delete mode 100644 apps/sim/app/api/copilot/training/examples/route.ts delete mode 100644 apps/sim/app/api/copilot/training/route.ts diff --git a/apps/sim/app/api/copilot/training/examples/route.ts b/apps/sim/app/api/copilot/training/examples/route.ts deleted file mode 100644 index e69cfc5ecd1..00000000000 --- a/apps/sim/app/api/copilot/training/examples/route.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { createLogger } from '@sim/logger' -import { getErrorMessage } from '@sim/utils/errors' -import { type NextRequest, NextResponse } from 'next/server' -import { copilotTrainingExampleContract } from '@/lib/api/contracts/copilot' -import { parseRequest, validationErrorResponse } from '@/lib/api/server' -import { checkInternalApiKey, createUnauthorizedResponse } from '@/lib/copilot/request/http' -import { env } from '@/lib/core/config/env' -import { withRouteHandler } from '@/lib/core/utils/with-route-handler' - -const logger = createLogger('CopilotTrainingExamplesAPI') - -export const runtime = 'nodejs' -export const dynamic = 'force-dynamic' - -export const POST = withRouteHandler(async (request: NextRequest) => { - const auth = checkInternalApiKey(request) - if (!auth.success) { - return createUnauthorizedResponse() - } - - const baseUrl = env.AGENT_INDEXER_URL - if (!baseUrl) { - logger.error('Missing AGENT_INDEXER_URL environment variable') - return NextResponse.json({ error: 'Missing AGENT_INDEXER_URL env' }, { status: 500 }) - } - - const apiKey = env.AGENT_INDEXER_API_KEY - if (!apiKey) { - logger.error('Missing AGENT_INDEXER_API_KEY environment variable') - return NextResponse.json({ error: 'Missing AGENT_INDEXER_API_KEY env' }, { status: 500 }) - } - - try { - const parsed = await parseRequest( - copilotTrainingExampleContract, - request, - {}, - { - validationErrorResponse: (error) => { - logger.warn('Invalid training example format', { errors: error.issues }) - return validationErrorResponse(error, 'Invalid training example format') - }, - } - ) - if (!parsed.success) return parsed.response - const validatedData = parsed.data.body - - logger.info('Sending workflow example to agent indexer', { - hasJsonField: typeof validatedData.json === 'string', - title: validatedData.title, - }) - - const upstream = await fetch(`${baseUrl}/examples/add`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': apiKey, - }, - body: JSON.stringify(validatedData), - }) - - if (!upstream.ok) { - const errorText = await upstream.text() - logger.error('Agent indexer rejected the example', { - status: upstream.status, - error: errorText, - }) - return NextResponse.json({ error: errorText }, { status: upstream.status }) - } - - const data = await upstream.json() - logger.info('Successfully sent workflow example to agent indexer') - - return NextResponse.json(data, { - headers: { 'content-type': 'application/json' }, - }) - } catch (err) { - const errorMessage = getErrorMessage(err, 'Failed to add example') - logger.error('Failed to send workflow example', { error: err }) - return NextResponse.json({ error: errorMessage }, { status: 502 }) - } -}) diff --git a/apps/sim/app/api/copilot/training/route.ts b/apps/sim/app/api/copilot/training/route.ts deleted file mode 100644 index 100b53b77a3..00000000000 --- a/apps/sim/app/api/copilot/training/route.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { createLogger } from '@sim/logger' -import { getErrorMessage } from '@sim/utils/errors' -import { type NextRequest, NextResponse } from 'next/server' -import { copilotTrainingDataContract } from '@/lib/api/contracts/copilot' -import { parseRequest, validationErrorResponse } from '@/lib/api/server' -import { checkInternalApiKey, createUnauthorizedResponse } from '@/lib/copilot/request/http' -import { env } from '@/lib/core/config/env' -import { withRouteHandler } from '@/lib/core/utils/with-route-handler' - -const logger = createLogger('CopilotTrainingAPI') - -export const POST = withRouteHandler(async (request: NextRequest) => { - const auth = checkInternalApiKey(request) - if (!auth.success) { - return createUnauthorizedResponse() - } - - try { - const baseUrl = env.AGENT_INDEXER_URL - if (!baseUrl) { - logger.error('Missing AGENT_INDEXER_URL environment variable') - return NextResponse.json({ error: 'Agent indexer not configured' }, { status: 500 }) - } - - const apiKey = env.AGENT_INDEXER_API_KEY - if (!apiKey) { - logger.error('Missing AGENT_INDEXER_API_KEY environment variable') - return NextResponse.json( - { error: 'Agent indexer authentication not configured' }, - { status: 500 } - ) - } - - const parsed = await parseRequest( - copilotTrainingDataContract, - request, - {}, - { - validationErrorResponse: (error) => { - logger.warn('Invalid training data format', { errors: error.issues }) - return validationErrorResponse(error, 'Invalid training data format') - }, - } - ) - if (!parsed.success) return parsed.response - const { title, prompt, input, output, operations } = parsed.data.body - - logger.info('Sending training data to agent indexer', { - title, - operationsCount: operations.length, - }) - - const upstreamUrl = `${baseUrl}/operations/add` - const upstreamResponse = await fetch(upstreamUrl, { - method: 'POST', - headers: { - 'x-api-key': apiKey, - 'content-type': 'application/json', - }, - body: JSON.stringify({ - title, - prompt, - input, - output, - operations: { operations }, - }), - }) - - const responseData = await upstreamResponse.json() - - if (!upstreamResponse.ok) { - logger.error('Agent indexer rejected the data', { - status: upstreamResponse.status, - response: responseData, - }) - return NextResponse.json(responseData, { status: upstreamResponse.status }) - } - - logger.info('Successfully sent training data to agent indexer', { - title, - response: responseData, - }) - - return NextResponse.json(responseData) - } catch (error) { - logger.error('Failed to send training data to agent indexer', { error }) - return NextResponse.json( - { - error: getErrorMessage(error, 'Failed to send training data'), - }, - { status: 502 } - ) - } -}) diff --git a/apps/sim/app/workspace/[workspaceId]/settings/components/general/general.tsx b/apps/sim/app/workspace/[workspaceId]/settings/components/general/general.tsx index 6c0866dd8dd..dac5312012c 100644 --- a/apps/sim/app/workspace/[workspaceId]/settings/components/general/general.tsx +++ b/apps/sim/app/workspace/[workspaceId]/settings/components/general/general.tsx @@ -23,7 +23,6 @@ import { requestJson } from '@/lib/api/client/request' import { telemetryContract } from '@/lib/api/contracts/telemetry' import { signOut, useSession } from '@/lib/auth/auth-client' import { ANONYMOUS_USER_ID } from '@/lib/auth/constants' -import { getEnv, isTruthy } from '@/lib/core/config/env' import { isHosted } from '@/lib/core/config/env-flags' import { getBrowserTimezone, getTimezoneOptions } from '@/lib/core/utils/timezone' import { getBaseUrl } from '@/lib/core/utils/urls' @@ -79,7 +78,6 @@ export function General() { const isLoading = isProfileLoading || isSettingsLoading - const isTrainingEnabled = isTruthy(getEnv('NEXT_PUBLIC_COPILOT_TRAINING_ENABLED')) const isAuthDisabled = session?.user?.id === ANONYMOUS_USER_ID const [name, setName] = useState(profile?.name || '') @@ -232,12 +230,6 @@ export function General() { } } - const handleTrainingControlsChange = async (checked: boolean) => { - if (checked !== settings?.showTrainingControls && !updateSetting.isPending) { - await updateSetting.mutateAsync({ key: 'showTrainingControls', value: checked }) - } - } - const handleErrorNotificationsChange = async (checked: boolean) => { if (checked !== settings?.errorNotificationsEnabled && !updateSetting.isPending) { await updateSetting.mutateAsync({ key: 'errorNotificationsEnabled', value: checked }) @@ -528,17 +520,6 @@ export function General() { onCheckedChange={handleShowActionBarChange} /> - - {isTrainingEnabled && ( -
- - -
- )} diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/components/output-panel/output-panel.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/components/output-panel/output-panel.tsx index 5de4df91e19..d7ccae9a6ca 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/components/output-panel/output-panel.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/components/output-panel/output-panel.tsx @@ -16,11 +16,9 @@ import { ArrowUp, Check, Clipboard, - Database, Download, MoreHorizontal, Palette, - Pause, Search, Trash, X, @@ -94,9 +92,6 @@ export interface OutputPanelProps { setShowInput: (show: boolean) => void hasInputData: boolean isPlaygroundEnabled: boolean - shouldShowTrainingButton: boolean - isTraining: boolean - handleTrainingClick: (e: React.MouseEvent) => void showCopySuccess: boolean handleCopy: () => void hasEntries: boolean @@ -121,9 +116,6 @@ export const OutputPanel = React.memo(function OutputPanel({ setShowInput, hasInputData, isPlaygroundEnabled, - shouldShowTrainingButton, - isTraining, - handleTrainingClick, showCopySuccess, handleCopy, hasEntries, @@ -392,31 +384,6 @@ export const OutputPanel = React.memo(function OutputPanel({ )} - {shouldShowTrainingButton && ( - - - - - - {isTraining ? 'Stop Training' : 'Train Sim'} - - - )} - - - - {isTraining ? 'Stop Training' : 'Train Sim'} - - - )} - {filteredEntries.length > 0 && ( <> @@ -1528,9 +1471,6 @@ export const Terminal = memo(function Terminal() { setShowInput={setShowInput} hasInputData={hasInputData} isPlaygroundEnabled={isPlaygroundEnabled} - shouldShowTrainingButton={shouldShowTrainingButton} - isTraining={isTraining} - handleTrainingClick={handleTrainingClick} showCopySuccess={showCopySuccess} handleCopy={handleCopy} hasEntries={filteredEntries.length > 0} diff --git a/apps/sim/hooks/queries/general-settings.ts b/apps/sim/hooks/queries/general-settings.ts index d6eeb3a89f4..e857abed51a 100644 --- a/apps/sim/hooks/queries/general-settings.ts +++ b/apps/sim/hooks/queries/general-settings.ts @@ -28,7 +28,6 @@ export const GENERAL_SETTINGS_STALE_TIME = 60 * 60 * 1000 */ export interface GeneralSettings { autoConnect: boolean - showTrainingControls: boolean superUserModeEnabled: boolean mothershipEnvironment: MothershipEnvironment theme: 'light' | 'dark' | 'system' @@ -50,7 +49,6 @@ export interface GeneralSettings { export function mapGeneralSettingsResponse(data: UserSettingsApi): GeneralSettings { return { autoConnect: data.autoConnect, - showTrainingControls: data.showTrainingControls, superUserModeEnabled: data.superUserModeEnabled, mothershipEnvironment: data.mothershipEnvironment, theme: data.theme, @@ -114,11 +112,6 @@ export function useAutoConnect(): boolean { return data?.autoConnect ?? true } -export function useShowTrainingControls(): boolean { - const { data } = useGeneralSettings() - return data?.showTrainingControls ?? false -} - export function useSnapToGridSize(): number { const { data } = useGeneralSettings() return data?.snapToGridSize ?? 0 diff --git a/apps/sim/lib/api/contracts/copilot.ts b/apps/sim/lib/api/contracts/copilot.ts index 8da3f338c30..ff2df7e8b13 100644 --- a/apps/sim/lib/api/contracts/copilot.ts +++ b/apps/sim/lib/api/contracts/copilot.ts @@ -90,29 +90,6 @@ export const createWorkflowCopilotChatBodySchema = z.object({ }) export type CreateWorkflowCopilotChatBody = z.input -export const copilotTrainingExampleBodySchema = z.object({ - json: z.string().min(1, 'JSON string is required'), - title: z.string().min(1, 'Title is required'), - tags: z.array(z.string()).optional(), - metadata: z.record(z.string(), z.unknown()).optional(), -}) -export type CopilotTrainingExampleBody = z.input - -const copilotTrainingOperationSchema = z.object({ - operation_type: z.string(), - block_id: z.string(), - params: z.record(z.string(), z.unknown()).optional(), -}) - -export const copilotTrainingDataBodySchema = z.object({ - title: z.string().min(1, 'Title is required'), - prompt: z.string().min(1, 'Prompt is required'), - input: z.record(z.string(), z.unknown()), - output: z.record(z.string(), z.unknown()), - operations: z.array(copilotTrainingOperationSchema), -}) -export type CopilotTrainingDataBody = z.input - export const renameCopilotChatBodySchema = z.object({ chatId: z.string().min(1), title: z.string().min(1).max(200), @@ -711,36 +688,6 @@ export const removeCopilotChatResourceContract = defineRouteContract({ }, }) -/** - * Forwards the agent indexer's free-form JSON response. - * Shape varies by upstream version. - */ -export const copilotTrainingDataContract = defineRouteContract({ - method: 'POST', - path: '/api/copilot/training', - body: copilotTrainingDataBodySchema, - response: { - mode: 'json', - // untyped-response: forwards external agent indexer /operations/add response unchanged; shape varies by upstream version - schema: z.unknown(), - }, -}) - -/** - * Forwards the agent indexer's free-form JSON response. - * Shape varies by upstream version. - */ -export const copilotTrainingExampleContract = defineRouteContract({ - method: 'POST', - path: '/api/copilot/training/examples', - body: copilotTrainingExampleBodySchema, - response: { - mode: 'json', - // untyped-response: forwards external agent indexer /examples/add response unchanged; shape varies by upstream version - schema: z.unknown(), - }, -}) - export const renameCopilotChatContract = defineRouteContract({ method: 'PATCH', path: '/api/copilot/chat/rename', diff --git a/apps/sim/lib/api/contracts/user.ts b/apps/sim/lib/api/contracts/user.ts index 286eda6fa03..ef4127cacde 100644 --- a/apps/sim/lib/api/contracts/user.ts +++ b/apps/sim/lib/api/contracts/user.ts @@ -84,7 +84,6 @@ export const userSettingsSchema = z.object({ telemetryEnabled: z.boolean().default(true), emailPreferences: userSettingsEmailPreferencesSchema.optional().default({}), billingUsageNotificationsEnabled: z.boolean().default(true), - showTrainingControls: z.boolean().default(false), superUserModeEnabled: z.boolean().default(false), mothershipEnvironment: mothershipEnvironmentSchema.default('default'), errorNotificationsEnabled: z.boolean().default(true), @@ -105,7 +104,6 @@ export const updateUserSettingsBodySchema = z.object({ telemetryEnabled: z.boolean().optional(), emailPreferences: userSettingsEmailPreferencesSchema.optional(), billingUsageNotificationsEnabled: z.boolean().optional(), - showTrainingControls: z.boolean().optional(), superUserModeEnabled: z.boolean().optional(), mothershipEnvironment: mothershipEnvironmentSchema.optional(), errorNotificationsEnabled: z.boolean().optional(), diff --git a/apps/sim/lib/core/config/env.ts b/apps/sim/lib/core/config/env.ts index a2decad9680..290e97d6617 100644 --- a/apps/sim/lib/core/config/env.ts +++ b/apps/sim/lib/core/config/env.ts @@ -577,7 +577,6 @@ export const env = createEnv({ NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS: z.string().optional(), // Hide Bedrock credential fields when deployment uses AWS default credential chain (IAM roles, instance profiles, ECS task roles, IRSA) NEXT_PUBLIC_AZURE_CONFIGURED: z.string().optional(), // Hide Azure credential fields when endpoint/key/version are pre-configured server-side NEXT_PUBLIC_COHERE_CONFIGURED: z.string().optional(), // Hide Cohere API key field on Knowledge block when COHERE_API_KEY is pre-configured server-side - NEXT_PUBLIC_COPILOT_TRAINING_ENABLED: z.string().optional(), NEXT_PUBLIC_ENABLE_PLAYGROUND: z.string().optional(), // Enable component playground at /playground NEXT_PUBLIC_DOCUMENTATION_URL: z.string().url().optional(), // Custom documentation URL NEXT_PUBLIC_TERMS_URL: z.string().url().optional(), // Custom terms of service URL @@ -661,7 +660,6 @@ export const env = createEnv({ NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS: process.env.NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS, NEXT_PUBLIC_AZURE_CONFIGURED: process.env.NEXT_PUBLIC_AZURE_CONFIGURED, NEXT_PUBLIC_COHERE_CONFIGURED: process.env.NEXT_PUBLIC_COHERE_CONFIGURED, - NEXT_PUBLIC_COPILOT_TRAINING_ENABLED: process.env.NEXT_PUBLIC_COPILOT_TRAINING_ENABLED, NEXT_PUBLIC_ENABLE_PLAYGROUND: process.env.NEXT_PUBLIC_ENABLE_PLAYGROUND, NEXT_PUBLIC_POSTHOG_ENABLED: process.env.NEXT_PUBLIC_POSTHOG_ENABLED, NEXT_PUBLIC_POSTHOG_KEY: process.env.NEXT_PUBLIC_POSTHOG_KEY, diff --git a/apps/sim/lib/users/queries.ts b/apps/sim/lib/users/queries.ts index 6543dd45095..defaf9f6122 100644 --- a/apps/sim/lib/users/queries.ts +++ b/apps/sim/lib/users/queries.ts @@ -17,7 +17,6 @@ export const defaultUserSettings: UserSettingsApi = { telemetryEnabled: true, emailPreferences: {}, billingUsageNotificationsEnabled: true, - showTrainingControls: false, superUserModeEnabled: false, mothershipEnvironment: 'default', errorNotificationsEnabled: true, @@ -54,7 +53,6 @@ export async function getUserSettings(userId: string | null): Promise