diff --git a/packages/@n8n/ai-workflow-builder.ee/src/multi-agent-workflow-subgraphs.ts b/packages/@n8n/ai-workflow-builder.ee/src/multi-agent-workflow-subgraphs.ts index 8eedb2ede37..db539f98307 100644 --- a/packages/@n8n/ai-workflow-builder.ee/src/multi-agent-workflow-subgraphs.ts +++ b/packages/@n8n/ai-workflow-builder.ee/src/multi-agent-workflow-subgraphs.ts @@ -369,12 +369,7 @@ export function createMultiAgentWorkflowWithSubgraphs(config: MultiAgentSubgraph // After discovery in plan mode, getNextPhaseFromLog returns 'builder'. // With builder removed, redirect back to discovery to retry planning. - if ( - next === 'builder' && - featureFlags?.planMode === true && - state.mode === 'plan' && - !state.planOutput - ) { + if (next === 'builder' && state.mode === 'plan' && !state.planOutput) { return { nextPhase: 'discovery', planDecision: null }; } @@ -384,16 +379,10 @@ export function createMultiAgentWorkflowWithSubgraphs(config: MultiAgentSubgraph .addNode('check_state', (state) => { const action = determineStateAction(state, autoCompactThresholdTokens); - // In plan mode (without mergeAskBuild), skip the supervisor and - // route directly to discovery (which contains the planner). + // In plan mode (without mergeAskBuild), skip the supervisor and route directly to + // discovery (which contains the planner). // Set nextPhase to 'discovery' so create_workflow_name can route correctly. - if ( - action === 'continue' && - featureFlags?.planMode === true && - state.mode === 'plan' && - !state.planOutput && - !mergeAskBuild - ) { + if (action === 'continue' && state.mode === 'plan' && !state.planOutput && !mergeAskBuild) { return { nextPhase: 'discovery' }; } diff --git a/packages/@n8n/ai-workflow-builder.ee/src/prompts/agents/discovery.prompt.ts b/packages/@n8n/ai-workflow-builder.ee/src/prompts/agents/discovery.prompt.ts index ffcc25e8b25..ca92f56cefb 100644 --- a/packages/@n8n/ai-workflow-builder.ee/src/prompts/agents/discovery.prompt.ts +++ b/packages/@n8n/ai-workflow-builder.ee/src/prompts/agents/discovery.prompt.ts @@ -41,7 +41,6 @@ export function formatExampleCategorizations(): string { export interface DiscoveryPromptOptions { includeExamples: boolean; - includeQuestions: boolean; } const ROLE = `You are a Discovery Agent for n8n AI Workflow Builder. @@ -52,21 +51,11 @@ const N8N_EXECUTION_MODEL = `n8n executes each node once per input item. When a trigger or node outputs multiple items (e.g., Gmail returns 10 emails), every downstream node runs once for each item. Flow control nodes like Aggregate and Split Out change how items flow through the workflow by combining or expanding them.`; -const PROCESS = `1. Search for nodes matching the user's request using search_nodes tool -2. Identify connection-changing parameters from input/output expressions (look for $parameter.X) -3. Call submit_discovery_results with your nodesFound array`; - const PROCESS_WITH_QUESTIONS = `1. Search for nodes matching the user's request using search_nodes tool 2. Identify connection-changing parameters from input/output expressions (look for $parameter.X) 3. Assess: do you have enough information to build exactly what the user wants, or would you need to make assumptions about their intent? If assumptions are needed, ask clarifying questions using submit_questions (see clarifying_questions section) 4. Call submit_discovery_results with your nodesFound array`; -const PROCESS_WITH_EXAMPLES = `1. Search for nodes matching the user's request using search_nodes tool -2. Identify connection-changing parameters from input/output expressions (look for $parameter.X) -3. Use get_documentation to retrieve best practices for relevant workflow techniques—this provides proven patterns that improve workflow quality -4. Use get_workflow_examples to find real community workflows using mentioned services—these examples show how experienced users structure similar integrations -5. Call submit_discovery_results with your nodesFound array`; - const PROCESS_WITH_EXAMPLES_AND_QUESTIONS = `1. Search for nodes matching the user's request using search_nodes tool 2. Identify connection-changing parameters from input/output expressions (look for $parameter.X) 3. Use get_documentation to retrieve best practices for relevant workflow techniques—this provides proven patterns that improve workflow quality @@ -367,8 +356,7 @@ Guidelines: - Prioritize native nodes in your searches because they provide better UX and visual debugging than Code node alternatives`; function generateToolCallRequirement(options: DiscoveryPromptOptions): string { - const toolExamples = ['search_nodes']; - if (options.includeQuestions) toolExamples.push('submit_questions'); + const toolExamples = ['search_nodes', 'submit_questions']; if (options.includeExamples) toolExamples.push('get_documentation', 'get_workflow_examples'); return ` @@ -382,10 +370,8 @@ Do not output the results as text or XML. function generateAvailableToolsList(options: DiscoveryPromptOptions): string { const tools = [ '- search_nodes: Find n8n nodes by keyword (returns name, version, inputs, outputs)', + '- submit_questions: Ask clarifying questions when critical details are missing', ]; - if (options.includeQuestions) { - tools.push('- submit_questions: Ask clarifying questions when critical details are missing'); - } if (options.includeExamples) { tools.push( '- get_documentation: Retrieve best practices for workflow techniques to improve quality', @@ -400,11 +386,7 @@ function generateAvailableToolsList(options: DiscoveryPromptOptions): string { } function selectProcessSection(options: DiscoveryPromptOptions): string { - if (options.includeExamples && options.includeQuestions) - return PROCESS_WITH_EXAMPLES_AND_QUESTIONS; - if (options.includeExamples) return PROCESS_WITH_EXAMPLES; - if (options.includeQuestions) return PROCESS_WITH_QUESTIONS; - return PROCESS; + return options.includeExamples ? PROCESS_WITH_EXAMPLES_AND_QUESTIONS : PROCESS_WITH_QUESTIONS; } export function buildDiscoveryPrompt(options: DiscoveryPromptOptions): string { @@ -415,7 +397,7 @@ export function buildDiscoveryPrompt(options: DiscoveryPromptOptions): string { .section('available_tools', availableTools) .section('process', selectProcessSection(options)) .section('tool_call_requirement', generateToolCallRequirement(options)) - .sectionIf(options.includeQuestions, 'clarifying_questions', CLARIFYING_QUESTIONS) + .section('clarifying_questions', CLARIFYING_QUESTIONS) .section('n8n_execution_model', N8N_EXECUTION_MODEL) .section('baseline_flow_control', BASELINE_FLOW_CONTROL) .section('trigger_selection', TRIGGER_SELECTION) diff --git a/packages/@n8n/ai-workflow-builder.ee/src/subgraphs/discovery.subgraph.ts b/packages/@n8n/ai-workflow-builder.ee/src/subgraphs/discovery.subgraph.ts index fc819832676..5f73c9e1ba2 100644 --- a/packages/@n8n/ai-workflow-builder.ee/src/subgraphs/discovery.subgraph.ts +++ b/packages/@n8n/ai-workflow-builder.ee/src/subgraphs/discovery.subgraph.ts @@ -265,7 +265,6 @@ export class DiscoverySubgraph extends BaseSubgraph< private toolMap!: Map; private logger?: Logger; private parsedNodeTypes!: INodeTypeDescription[]; - private featureFlags?: BuilderFeatureFlags; /** Mutable state for planner web_fetch hooks, updated before each planner invocation */ private plannerWebFetchState: MutableWebFetchState = { @@ -278,11 +277,9 @@ export class DiscoverySubgraph extends BaseSubgraph< create(config: DiscoverySubgraphConfig) { this.logger = config.logger; this.parsedNodeTypes = config.parsedNodeTypes; - this.featureFlags = config.featureFlags; // Check feature flags const includeExamples = config.featureFlags?.templateExamples === true; - const includePlanMode = config.featureFlags?.planMode === true; const enableIntrospection = config.featureFlags?.enableIntrospection === true; // Create security manager factories for web_fetch in each context @@ -293,16 +290,11 @@ export class DiscoverySubgraph extends BaseSubgraph< const ssrf = config.ssrf ?? createPassthroughSsrfGuard(); // Create base tools - search_nodes provides all data needed for discovery - const baseTools: StructuredTool[] = includePlanMode - ? [ - createNodeSearchTool(config.parsedNodeTypes).tool, - submitQuestionsTool, - createWebFetchTool(discoverySecurityFactory, ssrf).tool, - ] - : [ - createNodeSearchTool(config.parsedNodeTypes).tool, - createWebFetchTool(discoverySecurityFactory, ssrf).tool, - ]; + const baseTools: StructuredTool[] = [ + createNodeSearchTool(config.parsedNodeTypes).tool, + submitQuestionsTool, + createWebFetchTool(discoverySecurityFactory, ssrf).tool, + ]; // Conditionally add introspect tool if feature flag is enabled if (enableIntrospection) { @@ -330,7 +322,6 @@ export class DiscoverySubgraph extends BaseSubgraph< // Generate prompt based on feature flags const discoveryPrompt = buildDiscoveryPrompt({ includeExamples, - includeQuestions: includePlanMode, }); // Create agent with tools bound (including submit tool) @@ -418,7 +409,7 @@ export class DiscoverySubgraph extends BaseSubgraph< state: typeof DiscoverySubgraphState.State, runnableConfig?: RunnableConfig, ) { - if (!this.featureFlags?.planMode || state.mode !== 'plan' || state.planOutput) { + if (state.mode !== 'plan' || state.planOutput) { return {}; } @@ -459,7 +450,6 @@ export class DiscoverySubgraph extends BaseSubgraph< } private shouldPlan(state: typeof DiscoverySubgraphState.State): 'planner' | typeof END { - if (!this.featureFlags?.planMode) return END; if (state.mode !== 'plan') return END; return state.planOutput ? END : 'planner'; } diff --git a/packages/@n8n/ai-workflow-builder.ee/src/subgraphs/test/integration/plan-mode-discovery.integration.test.ts b/packages/@n8n/ai-workflow-builder.ee/src/subgraphs/test/integration/plan-mode-discovery.integration.test.ts index 7ad828470e4..c86be5c8942 100644 --- a/packages/@n8n/ai-workflow-builder.ee/src/subgraphs/test/integration/plan-mode-discovery.integration.test.ts +++ b/packages/@n8n/ai-workflow-builder.ee/src/subgraphs/test/integration/plan-mode-discovery.integration.test.ts @@ -114,7 +114,6 @@ describe('Plan Mode Discovery - Integration Tests', () => { parsedNodeTypes, llm, plannerLLM: llm, - featureFlags: { planMode: true }, checkpointer: new MemorySaver(), }); } @@ -317,7 +316,6 @@ describe('Plan Mode Discovery - Integration Tests', () => { parsedNodeTypes, llm, plannerLLM: llm, - featureFlags: { planMode: true }, }); console.log('Invoking in build mode...'); diff --git a/packages/@n8n/ai-workflow-builder.ee/src/subgraphs/test/integration/question-quality.integration.test.ts b/packages/@n8n/ai-workflow-builder.ee/src/subgraphs/test/integration/question-quality.integration.test.ts index 41d77d21099..1a3d9d5fdc6 100644 --- a/packages/@n8n/ai-workflow-builder.ee/src/subgraphs/test/integration/question-quality.integration.test.ts +++ b/packages/@n8n/ai-workflow-builder.ee/src/subgraphs/test/integration/question-quality.integration.test.ts @@ -356,7 +356,6 @@ describe('Question Quality - Integration Tests', () => { parsedNodeTypes, llm, plannerLLM: llm, - featureFlags: { planMode: true }, checkpointer: new MemorySaver(), }); } diff --git a/packages/@n8n/ai-workflow-builder.ee/src/test/workflow-builder-agent.test.ts b/packages/@n8n/ai-workflow-builder.ee/src/test/workflow-builder-agent.test.ts index 212aa63b9db..f04581b6402 100644 --- a/packages/@n8n/ai-workflow-builder.ee/src/test/workflow-builder-agent.test.ts +++ b/packages/@n8n/ai-workflow-builder.ee/src/test/workflow-builder-agent.test.ts @@ -128,8 +128,6 @@ describe('WorkflowBuilderAgent', () => { mockPayload = { id: '12345', message: 'Create a workflow', - // Test for plan mode as it's the only case when legacy multi-agent implementation is still in use - featureFlags: { planMode: true }, mode: 'plan', workflowContext: { currentWorkflow: { id: 'workflow-123' }, @@ -160,7 +158,6 @@ describe('WorkflowBuilderAgent', () => { const payload: ChatPayload = { id: '12345', message: validMessage, - featureFlags: { planMode: true }, mode: 'plan', }; @@ -360,11 +357,10 @@ describe('WorkflowBuilderAgent', () => { ); }); - it('should route to multi-agent for initial plan request when planMode enabled', async () => { + it('should route to multi-agent for initial plan request', async () => { const payload: ChatPayload = { id: '123', message: 'Create a weather alert workflow', - featureFlags: { planMode: true }, mode: 'plan', }; @@ -390,7 +386,6 @@ describe('WorkflowBuilderAgent', () => { const payload: ChatPayload = { id: '123', message: 'Create a weather alert workflow', - featureFlags: { planMode: true }, resumeData: { action: 'approve' }, resumeInterrupt: mockPlanInterrupt, }; @@ -416,7 +411,6 @@ describe('WorkflowBuilderAgent', () => { const payload: ChatPayload = { id: '123', message: 'Create a weather alert workflow', - featureFlags: { planMode: true }, resumeData: { action: 'modify', feedback: 'Add error handling' }, resumeInterrupt: mockPlanInterrupt, }; @@ -442,7 +436,6 @@ describe('WorkflowBuilderAgent', () => { const payload: ChatPayload = { id: '123', message: 'Create a weather alert workflow', - featureFlags: { planMode: true }, resumeData: { action: 'reject' }, resumeInterrupt: mockPlanInterrupt, }; diff --git a/packages/@n8n/ai-workflow-builder.ee/src/workflow-builder-agent.ts b/packages/@n8n/ai-workflow-builder.ee/src/workflow-builder-agent.ts index 10dfd5c87c7..a0b0b18bf3d 100644 --- a/packages/@n8n/ai-workflow-builder.ee/src/workflow-builder-agent.ts +++ b/packages/@n8n/ai-workflow-builder.ee/src/workflow-builder-agent.ts @@ -111,7 +111,6 @@ export interface BuilderFeatureFlags { templateExamples?: boolean; /** Enable pin data generation in code builder (default: true). */ pinData?: boolean; - planMode?: boolean; /** Enable introspection tool for diagnostic data collection. Disabled by default. */ enableIntrospection?: boolean; /** Enable merged ask/build experience with assistant subgraph (default: false). */ @@ -240,8 +239,6 @@ export class WorkflowBuilderAgent { externalCallbacks: Callbacks | undefined, historicalMessages: BaseMessage[] | undefined, ) { - const usePlanMode = payload.featureFlags?.planMode === true; - // web_fetch_approval resumes always go through multi-agent (where the interrupt lives) if (payload.resumeData && payload.resumeInterrupt?.type === 'web_fetch_approval') { this.logger?.debug('web_fetch_approval resume, routing to multi-agent system', { @@ -292,7 +289,7 @@ export class WorkflowBuilderAgent { } // Initial plan request: route to multi-agent for discovery + planning - if (usePlanMode && payload.mode === 'plan') { + if (payload.mode === 'plan') { this.logger?.debug('Plan mode with code builder, routing to multi-agent for planning', { userId, }); diff --git a/packages/@n8n/api-types/src/dto/ai/ai-build-request.dto.ts b/packages/@n8n/api-types/src/dto/ai/ai-build-request.dto.ts index 8b17b440b3a..525585d72e6 100644 --- a/packages/@n8n/api-types/src/dto/ai/ai-build-request.dto.ts +++ b/packages/@n8n/api-types/src/dto/ai/ai-build-request.dto.ts @@ -108,7 +108,6 @@ export class AiBuilderChatRequestDto extends Z.class({ .object({ templateExamples: z.boolean().optional(), pinData: z.boolean().optional(), - planMode: z.boolean().optional(), mergeAskBuild: z.boolean().optional(), }) .optional(), diff --git a/packages/frontend/editor-ui/src/app/constants/experiments.ts b/packages/frontend/editor-ui/src/app/constants/experiments.ts index 47c41a66a23..5bc2b867a15 100644 --- a/packages/frontend/editor-ui/src/app/constants/experiments.ts +++ b/packages/frontend/editor-ui/src/app/constants/experiments.ts @@ -49,8 +49,6 @@ export const AI_BUILDER_TEMPLATE_EXAMPLES_EXPERIMENT = createExperiment( '056_ai_builder_template_examples', ); -export const AI_BUILDER_PLAN_MODE_EXPERIMENT = createExperiment('073_builder_plan_mode'); - export const AI_BUILDER_REVIEW_CHANGES_EXPERIMENT = createExperiment( '075_ai_builder_review_changes', ); @@ -67,10 +65,6 @@ export const CREDENTIALS_APP_SELECTION_EXPERIMENT = createExperiment( '065_credentials_app_selection', ); -export const EMPTY_STATE_BUILDER_PROMPT_EXPERIMENT = createExperiment( - '063_empty_state_builder_prompt', -); - export const FOCUSED_NODES_EXPERIMENT = createExperiment('064_focused_nodes'); export const RESOURCE_CENTER_EXPERIMENT = createExperiment('063_resource_center_1'); @@ -130,7 +124,6 @@ export const EXPERIMENTS_TO_TRACK = [ TEMPLATE_RECO_V2.name, READY_TO_RUN_V2_P3_EXPERIMENT.name, AI_BUILDER_TEMPLATE_EXAMPLES_EXPERIMENT.name, - AI_BUILDER_PLAN_MODE_EXPERIMENT.name, TEMPLATE_SETUP_EXPERIENCE.name, RESOURCE_CENTER_EXPERIMENT.name, EXECUTION_LOGIC_V2_EXPERIMENT.name, @@ -140,7 +133,6 @@ export const EXPERIMENTS_TO_TRACK = [ EMPTY_STATE_EXPERIMENT.name, SETUP_PANEL.name, CODE_WORKFLOW_BUILDER_EXPERIMENT.name, - EMPTY_STATE_BUILDER_PROMPT_EXPERIMENT.name, FOCUSED_NODES_EXPERIMENT.name, AI_BUILDER_REVIEW_CHANGES_EXPERIMENT.name, MERGE_ASK_BUILD_EXPERIMENT.name, diff --git a/packages/frontend/editor-ui/src/features/ai/assistant/assistant.types.ts b/packages/frontend/editor-ui/src/features/ai/assistant/assistant.types.ts index 172720a0909..9e757e5309f 100644 --- a/packages/frontend/editor-ui/src/features/ai/assistant/assistant.types.ts +++ b/packages/frontend/editor-ui/src/features/ai/assistant/assistant.types.ts @@ -126,7 +126,6 @@ export namespace ChatRequest { export interface BuilderFeatureFlags { templateExamples?: boolean; pinData?: boolean; - planMode?: boolean; mergeAskBuild?: boolean; } diff --git a/packages/frontend/editor-ui/src/features/ai/assistant/builder.store.test.ts b/packages/frontend/editor-ui/src/features/ai/assistant/builder.store.test.ts index 06637f0c155..346b4facc14 100644 --- a/packages/frontend/editor-ui/src/features/ai/assistant/builder.store.test.ts +++ b/packages/frontend/editor-ui/src/features/ai/assistant/builder.store.test.ts @@ -19,13 +19,13 @@ import { useSettingsStore } from '@/app/stores/settings.store'; import { defaultSettings } from '@/__tests__/defaults'; import { createTestNode } from '@/__tests__/mocks'; import merge from 'lodash/merge'; -import { DEFAULT_POSTHOG_SETTINGS } from '@/app/stores/posthog.store.test'; import { nextTick, reactive } from 'vue'; import * as chatAPI from '@/features/ai/assistant/assistant.api'; import * as telemetryModule from '@/app/composables/useTelemetry'; import type { Telemetry } from '@/app/plugins/telemetry'; import type { ChatUI } from '@n8n/design-system/types/assistant'; import type { ChatRequest } from '@/features/ai/assistant/assistant.types'; +import type { FrontendSettings } from '@n8n/api-types'; import type { INodeUi } from '@/Interface'; import { mockedStore } from '@/__tests__/utils'; import { useWorkflowsStore } from '@/app/stores/workflows.store'; @@ -36,7 +36,16 @@ import { useWorkflowDocumentStore, createWorkflowDocumentId, } from '@/app/stores/workflowDocument.store'; -import { AI_BUILDER_PLAN_MODE_EXPERIMENT } from '@/app/constants/experiments'; + +const DEFAULT_POSTHOG_SETTINGS: FrontendSettings['posthog'] = { + enabled: true, + apiHost: 'host', + apiKey: 'key', + autocapture: false, + disableSessionRecording: true, + debug: false, + proxy: 'proxy', +}; // Mock useI18n to return the keys instead of translations vi.mock('@n8n/i18n', () => ({ @@ -2227,16 +2236,7 @@ describe('AI Builder store', () => { }); describe('default plan mode based on canvas nodes', () => { - function enablePlanModeExperiment() { - vi.spyOn(posthogStore, 'getVariant').mockImplementation((experiment) => - experiment === AI_BUILDER_PLAN_MODE_EXPERIMENT.name - ? AI_BUILDER_PLAN_MODE_EXPERIMENT.variant - : undefined, - ); - } - - it('should switch to plan mode when nodes become empty and plan mode is available', async () => { - enablePlanModeExperiment(); + it('should switch to plan mode when nodes become empty', async () => { const builderStore = useBuilderStore(); const workflowDocumentStore = useWorkflowDocumentStore( createWorkflowDocumentId(workflowsStore.workflowId), @@ -2253,7 +2253,6 @@ describe('AI Builder store', () => { }); it('should switch to build mode when nodes are added', async () => { - enablePlanModeExperiment(); // Start with nodes so the watcher can observe changes const workflowDocumentStore = useWorkflowDocumentStore( createWorkflowDocumentId(workflowsStore.workflowId), @@ -2274,18 +2273,7 @@ describe('AI Builder store', () => { expect(builderStore.builderMode).toBe('build'); }); - it('should stay in build mode when plan mode experiment is not enabled', async () => { - const builderStore = useBuilderStore(); - - // Change workflowId to trigger the watcher (nodes stay empty) - workflowsStore.setWorkflowId('different-workflow-id'); - await nextTick(); - - expect(builderStore.builderMode).toBe('build'); - }); - it('should not change mode when chat has messages', async () => { - enablePlanModeExperiment(); const builderStore = useBuilderStore(); const workflowDocumentStore = useWorkflowDocumentStore( createWorkflowDocumentId(workflowsStore.workflowId), @@ -2307,7 +2295,6 @@ describe('AI Builder store', () => { }); it('should default to plan mode when workflowId changes with empty canvas', async () => { - enablePlanModeExperiment(); const builderStore = useBuilderStore(); // Simulate navigating to a new empty workflow @@ -2322,7 +2309,6 @@ describe('AI Builder store', () => { }); it('should not switch to plan mode after restoreToVersion truncates messages', async () => { - enablePlanModeExperiment(); const builderStore = useBuilderStore(); const workflowDocumentStore = useWorkflowDocumentStore( createWorkflowDocumentId(workflowsStore.workflowId), @@ -3430,14 +3416,6 @@ describe('AI Builder store', () => { }); describe('Plan mode telemetry', () => { - function enablePlanMode() { - vi.spyOn(posthogStore, 'getVariant').mockImplementation((experiment) => - experiment === AI_BUILDER_PLAN_MODE_EXPERIMENT.name - ? AI_BUILDER_PLAN_MODE_EXPERIMENT.variant - : undefined, - ); - } - function addPlanMessageToChat(builderStore: ReturnType) { builderStore.chatMessages.push({ role: 'assistant', @@ -3452,7 +3430,6 @@ describe('AI Builder store', () => { describe('user_switched_builder_mode', () => { it('tracks journey event when switching to plan mode', () => { const builderStore = useBuilderStore(); - enablePlanMode(); track.mockClear(); builderStore.setBuilderMode('plan'); @@ -3468,7 +3445,6 @@ describe('AI Builder store', () => { it('tracks journey event when switching to build mode', () => { const builderStore = useBuilderStore(); - enablePlanMode(); builderStore.setBuilderMode('plan'); track.mockClear(); @@ -3482,27 +3458,11 @@ describe('AI Builder store', () => { }), ); }); - - it('does not track when plan mode is unavailable', () => { - const builderStore = useBuilderStore(); - // Do NOT enable plan mode - - track.mockClear(); - builderStore.setBuilderMode('plan'); - - expect(track).not.toHaveBeenCalledWith( - 'Workflow builder journey', - expect.objectContaining({ - event_type: 'user_switched_builder_mode', - }), - ); - }); }); describe('user_clicked_implement_plan', () => { it('tracks journey event when user approves plan', async () => { const builderStore = useBuilderStore(); - enablePlanMode(); builderStore.setBuilderMode('plan'); // Set up interrupted state with a plan message @@ -3527,7 +3487,6 @@ describe('AI Builder store', () => { describe('mode in User submitted builder message', () => { it('includes plan mode', async () => { const builderStore = useBuilderStore(); - enablePlanMode(); builderStore.setBuilderMode('plan'); apiSpy.mockImplementationOnce(() => {}); @@ -3572,7 +3531,6 @@ describe('AI Builder store', () => { it('includes plan mode on abort when in plan mode', async () => { const builderStore = useBuilderStore(); - enablePlanMode(); builderStore.setBuilderMode('plan'); apiSpy.mockImplementationOnce(() => {}); @@ -3589,7 +3547,6 @@ describe('AI Builder store', () => { it('includes plan_approved when plan was approved', async () => { const builderStore = useBuilderStore(); - enablePlanMode(); builderStore.setBuilderMode('plan'); // Set up interrupted state with a plan message diff --git a/packages/frontend/editor-ui/src/features/ai/assistant/builder.store.ts b/packages/frontend/editor-ui/src/features/ai/assistant/builder.store.ts index 5e1ffdaabd4..1f46e39269f 100644 --- a/packages/frontend/editor-ui/src/features/ai/assistant/builder.store.ts +++ b/packages/frontend/editor-ui/src/features/ai/assistant/builder.store.ts @@ -44,7 +44,6 @@ import { useWorkflowSaving } from '@/app/composables/useWorkflowSaving'; import { useUIStore } from '@/app/stores/ui.store'; import { useDocumentTitle } from '@/app/composables/useDocumentTitle'; import { useBrowserNotifications } from '@/app/composables/useBrowserNotifications'; -import { AI_BUILDER_PLAN_MODE_EXPERIMENT } from '@/app/constants/experiments'; import type { QuickReplyType } from '@n8n/api-types'; import { isVersionCardMessage, @@ -374,11 +373,6 @@ export const useBuilderStore = defineStore(STORES.BUILDER, () => { return { id: last.data.versionId, createdAt: last.data.createdAt }; }); - const isPlanModeAvailable = computed(() => { - const variant = posthogStore.getVariant(AI_BUILDER_PLAN_MODE_EXPERIMENT.name); - return variant === true || variant === AI_BUILDER_PLAN_MODE_EXPERIMENT.variant; - }); - /** * Finds the last interrupt message (questions or plan) by searching backwards. * This is more robust than checking only the last message, because error messages @@ -454,7 +448,6 @@ export const useBuilderStore = defineStore(STORES.BUILDER, () => { } function setBuilderMode(mode: 'build' | 'plan') { - if (mode === 'plan' && !isPlanModeAvailable.value) return; builderMode.value = mode; trackWorkflowBuilderJourney('user_switched_builder_mode', { mode }); } @@ -1008,7 +1001,6 @@ export const useBuilderStore = defineStore(STORES.BUILDER, () => { executionData: executionResult, nodesForSchema: Object.keys(workflowDocumentStore.value.nodesByName), mode: modeForPayload, - isPlanModeEnabled: isPlanModeAvailable.value, allowSendingParameterValues: settings.settings.ai.allowSendingParameterValues, }); if (resumeData !== undefined) { @@ -1521,7 +1513,6 @@ export const useBuilderStore = defineStore(STORES.BUILDER, () => { [() => workflowsStore.workflowId, () => workflowDocumentStore.value.allNodes.length], ([, nodesCount]) => { if (chatMessages.value.length > 0) return; - if (!isPlanModeAvailable.value) return; builderMode.value = nodesCount === 0 ? 'plan' : 'build'; }, ); @@ -1673,7 +1664,6 @@ export const useBuilderStore = defineStore(STORES.BUILDER, () => { isAIBuilderEnabled, isCodeBuilder, builderMode, - isPlanModeAvailable, isInterrupted, hasPendingPlan, shouldDisableChatInput, diff --git a/packages/frontend/editor-ui/src/features/ai/assistant/builder.utils.ts b/packages/frontend/editor-ui/src/features/ai/assistant/builder.utils.ts index 35034284cb3..ad251e17082 100644 --- a/packages/frontend/editor-ui/src/features/ai/assistant/builder.utils.ts +++ b/packages/frontend/editor-ui/src/features/ai/assistant/builder.utils.ts @@ -35,7 +35,6 @@ export async function createBuilderPayload( workflow?: IWorkflowDb; nodesForSchema?: string[]; mode?: 'build' | 'plan'; - isPlanModeEnabled?: boolean; allowSendingParameterValues?: boolean; }, ): Promise { @@ -86,7 +85,6 @@ export async function createBuilderPayload( posthogStore.getVariant(AI_BUILDER_TEMPLATE_EXAMPLES_EXPERIMENT.name) === AI_BUILDER_TEMPLATE_EXAMPLES_EXPERIMENT.variant, pinData: isPinDataEnabled, - planMode: options.isPlanModeEnabled ?? false, mergeAskBuild: posthogStore.isFeatureEnabled(MERGE_ASK_BUILD_EXPERIMENT.name), }; diff --git a/packages/frontend/editor-ui/src/features/ai/assistant/components/Agent/AskAssistantBuild.vue b/packages/frontend/editor-ui/src/features/ai/assistant/components/Agent/AskAssistantBuild.vue index c60808779b4..c5ecf43102f 100644 --- a/packages/frontend/editor-ui/src/features/ai/assistant/components/Agent/AskAssistantBuild.vue +++ b/packages/frontend/editor-ui/src/features/ai/assistant/components/Agent/AskAssistantBuild.vue @@ -869,7 +869,7 @@ defineExpose({ @upgrade-click="onUpgradeClick" @vue:mounted="registerFocus(() => suggestionsInputRef?.focusInput())" > -