Skip to content

Commit 6d1b93e

Browse files
committed
improvement(start): revert to start block
1 parent 47ddfb6 commit 6d1b93e

File tree

16 files changed

+280
-123
lines changed

16 files changed

+280
-123
lines changed

apps/docs/content/docs/en/triggers/index.mdx

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,46 +7,35 @@ import { Card, Cards } from 'fumadocs-ui/components/card'
77

88
## Core Triggers
99

10-
Pick one trigger per workflow to define how it starts:
10+
Use the Start block for everything originating from the editor, deploy-to-API, or deploy-to-chat experiences. Other triggers remain available for event-driven workflows:
1111

1212
<Cards>
13-
<Card title="API" href="/triggers/api">
14-
HTTP endpoint that maps JSON bodies into workflow inputs
13+
<Card title="Start" href="/triggers/start">
14+
Unified entry point that supports editor runs, API deployments and chat deployments
1515
</Card>
16-
<Card title="Chat" href="/triggers/chat">
17-
Deployed chat interface with streaming responses
18-
</Card>
19-
<Card title="Input Form" href="/triggers/input-form">
20-
Typed manual input used in editor runs and child workflows
21-
</Card>
22-
<Card title="Manual" href="/triggers/manual">
23-
On-demand runs with no additional data
16+
<Card title="Webhook" href="/triggers/webhook">
17+
Receive external webhook payloads
2418
</Card>
2519
<Card title="Schedule" href="/triggers/schedule">
2620
Cron or interval based execution
2721
</Card>
28-
<Card title="Webhook" href="/triggers/webhook">
29-
Receive external webhook payloads
30-
</Card>
3122
</Cards>
3223

3324
## Quick Comparison
3425

3526
| Trigger | Start condition |
3627
|---------|-----------------|
37-
| **API** | Authenticated HTTP POST |
38-
| **Chat** | Chat deployment message |
39-
| **Input Form** | On manual submit in editor or parent workflow |
40-
| **Manual** | Run button in editor |
28+
| **Start** | Editor runs, deploy-to-API requests, or chat messages |
4129
| **Schedule** | Timer managed in schedule modal |
4230
| **Webhook** | On inbound HTTP request |
4331

32+
> The Start block always exposes `input`, `conversationId`, and `files` fields. Add custom fields to the input format for additional structured data.
33+
4434
## Using Triggers
4535

46-
1. Drop the trigger block in the start slot.
36+
1. Drop the Start block in the start slot (or an alternate trigger like Webhook/Schedule).
4737
2. Configure any required schema or auth.
4838
3. Connect the block to the rest of the workflow.
4939

5040
> Deployments power every trigger. Update the workflow, redeploy, and all trigger entry points pick up the new snapshot. Learn more in [Execution → Deployment Snapshots](/execution).
5141
52-
Legacy Starter blocks remain for existing flows but no longer appear in new builds.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"pages": ["index", "api", "chat", "input-form", "manual", "schedule", "starter", "webhook"]
2+
"pages": ["index", "start", "schedule", "webhook", "starter"]
33
}

apps/sim/app/api/workflows/[id]/execute/route.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ export async function POST(
553553
: undefined),
554554
workflowTriggerType:
555555
body.workflowTriggerType || (isInternalCall && body.stream ? 'chat' : 'api'),
556-
input: body.input !== undefined ? body.input : body,
556+
input: body,
557557
}
558558
}
559559

@@ -576,13 +576,19 @@ export async function POST(
576576
const blocks = deployedData.blocks || {}
577577
logger.info(`[${requestId}] Loaded ${Object.keys(blocks).length} blocks from workflow`)
578578

579+
const startTriggerBlock = Object.values(blocks).find(
580+
(block: any) => block.type === 'start_trigger'
581+
) as any
579582
const apiTriggerBlock = Object.values(blocks).find(
580583
(block: any) => block.type === 'api_trigger'
581584
) as any
585+
logger.info(`[${requestId}] Start trigger block found:`, !!startTriggerBlock)
582586
logger.info(`[${requestId}] API trigger block found:`, !!apiTriggerBlock)
583587

584-
if (apiTriggerBlock?.subBlocks?.inputFormat?.value) {
585-
const inputFormat = apiTriggerBlock.subBlocks.inputFormat.value as Array<{
588+
const triggerBlock = startTriggerBlock || apiTriggerBlock
589+
590+
if (triggerBlock?.subBlocks?.inputFormat?.value) {
591+
const inputFormat = triggerBlock.subBlocks.inputFormat.value as Array<{
586592
name: string
587593
type: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'files'
588594
}>

apps/sim/app/api/workflows/[id]/status/route.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,14 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
3131
const normalizedData = await loadWorkflowFromNormalizedTables(id)
3232

3333
if (!normalizedData) {
34-
return createErrorResponse('Failed to load workflow state', 500)
34+
// Workflow exists but has no blocks in normalized tables (empty workflow or not migrated)
35+
// This is valid state - return success with no redeployment needed
36+
return createSuccessResponse({
37+
isDeployed: validation.workflow.isDeployed,
38+
deployedAt: validation.workflow.deployedAt,
39+
isPublished: validation.workflow.isPublished,
40+
needsRedeployment: false,
41+
})
3542
}
3643

3744
const currentState = {

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/deploy-modal.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,12 @@ export function DeployModal({
121121
try {
122122
const blocks = Object.values(useWorkflowStore.getState().blocks)
123123

124-
// Check for API trigger block first (takes precedence)
124+
// Check for start_trigger first, then API trigger, then legacy starter
125+
const startTriggerBlock = blocks.find((block) => block.type === 'start_trigger')
125126
const apiTriggerBlock = blocks.find((block) => block.type === 'api_trigger')
126-
// Fall back to legacy starter block
127127
const starterBlock = blocks.find((block) => block.type === 'starter')
128128

129-
const targetBlock = apiTriggerBlock || starterBlock
129+
const targetBlock = startTriggerBlock || apiTriggerBlock || starterBlock
130130

131131
if (targetBlock) {
132132
const inputFormat = useSubBlockStore.getState().getValue(targetBlock.id, 'inputFormat')

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/control-bar.tsx

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { useCallback, useEffect, useState } from 'react'
3+
import { useCallback, useEffect, useMemo, useState } from 'react'
44
import {
55
Bug,
66
ChevronLeft,
@@ -47,6 +47,7 @@ import {
4747
getKeyboardShortcutText,
4848
useKeyboardShortcuts,
4949
} from '@/app/workspace/[workspaceId]/w/hooks/use-keyboard-shortcuts'
50+
import { useDebounce } from '@/hooks/use-debounce'
5051
import { useFolderStore } from '@/stores/folders/store'
5152
import { useOperationQueueStore } from '@/stores/operation-queue/store'
5253
import { usePanelStore } from '@/stores/panel/store'
@@ -265,6 +266,17 @@ export function ControlBar({ hasValidationErrors = false }: ControlBarProps) {
265266
activeWorkflowId ? state.workflowValues[activeWorkflowId] : null
266267
)
267268

269+
const statusCheckTrigger = useMemo(() => {
270+
return JSON.stringify({
271+
blocks: Object.keys(currentBlocks || {}).length,
272+
edges: currentEdges?.length || 0,
273+
subBlocks: Object.keys(subBlockValues || {}).length,
274+
timestamp: Date.now(),
275+
})
276+
}, [currentBlocks, currentEdges, subBlockValues])
277+
278+
const debouncedStatusCheckTrigger = useDebounce(statusCheckTrigger, 500)
279+
268280
useEffect(() => {
269281
// Avoid off-by-one false positives: wait until operation queue is idle
270282
const { operations, isProcessing } = useOperationQueueStore.getState()
@@ -299,16 +311,7 @@ export function ControlBar({ hasValidationErrors = false }: ControlBarProps) {
299311
}
300312

301313
checkForChanges()
302-
}, [
303-
activeWorkflowId,
304-
deployedState,
305-
currentBlocks,
306-
currentEdges,
307-
subBlockValues,
308-
isLoadingDeployedState,
309-
useOperationQueueStore.getState().isProcessing,
310-
useOperationQueueStore.getState().operations.length,
311-
])
314+
}, [activeWorkflowId, deployedState, debouncedStatusCheckTrigger, isLoadingDeployedState])
312315

313316
useEffect(() => {
314317
if (session?.user?.id && !isRegistryLoading) {

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -857,14 +857,18 @@ export function useWorkflowExecution() {
857857
selectedBlockId = blockEntry[0]
858858

859859
// Extract test values from the API trigger's inputFormat
860-
if (selectedTrigger.type === 'api_trigger' || selectedTrigger.type === 'starter') {
860+
if (
861+
selectedTrigger.type === 'api_trigger' ||
862+
selectedTrigger.type === 'start_trigger' ||
863+
selectedTrigger.type === 'starter'
864+
) {
861865
const inputFormatValue = selectedTrigger.subBlocks?.inputFormat?.value
862866
const testInput = extractTestValuesFromInputFormat(inputFormatValue)
863867

864868
// Use the test input as workflow input
865869
if (Object.keys(testInput).length > 0) {
866870
finalWorkflowInput = testInput
867-
logger.info('Using API trigger test values for manual run:', testInput)
871+
logger.info('Using trigger test values for manual run:', testInput)
868872
}
869873
}
870874
}
@@ -884,15 +888,18 @@ export function useWorkflowExecution() {
884888
if (blockEntry) {
885889
selectedBlockId = blockEntry[0]
886890

887-
// Extract test values from input trigger's inputFormat if it's an input_trigger
888-
if (selectedTrigger.type === 'input_trigger') {
891+
// Extract test values from input trigger's inputFormat if it's an input_trigger or start_trigger
892+
if (
893+
selectedTrigger.type === 'input_trigger' ||
894+
selectedTrigger.type === 'start_trigger'
895+
) {
889896
const inputFormatValue = selectedTrigger.subBlocks?.inputFormat?.value
890897
const testInput = extractTestValuesFromInputFormat(inputFormatValue)
891898

892899
// Use the test input as workflow input
893900
if (Object.keys(testInput).length > 0) {
894901
finalWorkflowInput = testInput
895-
logger.info('Using Input trigger test values for manual run:', testInput)
902+
logger.info('Using trigger test values for manual run:', testInput)
896903
}
897904
}
898905
}

apps/sim/blocks/blocks/api_trigger.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import type { BlockConfig } from '@/blocks/types'
44
export const ApiTriggerBlock: BlockConfig = {
55
type: 'api_trigger',
66
triggerAllowed: true,
7-
name: 'API',
8-
description: 'Expose as HTTP API endpoint',
7+
name: 'API (Legacy)',
8+
description: 'Legacy block for exposing HTTP API endpoint. Prefer Start block.',
99
longDescription:
1010
'API trigger to start the workflow via authenticated HTTP calls with structured input.',
1111
bestPractices: `
@@ -14,6 +14,7 @@ export const ApiTriggerBlock: BlockConfig = {
1414
- In production, the curl would come in as e.g. curl -X POST -H "X-API-Key: $SIM_API_KEY" -H "Content-Type: application/json" -d '{"paramName":"example"}' https://www.staging.sim.ai/api/workflows/9e7e4f26-fc5e-4659-b270-7ea474b14f4a/execute -- If user asks to test via API, you might need to clarify the API key.
1515
`,
1616
category: 'triggers',
17+
hideFromToolbar: true,
1718
bgColor: '#2F55FF',
1819
icon: ApiIcon,
1920
subBlocks: [

apps/sim/blocks/blocks/chat_trigger.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ export const ChatTriggerBlock: BlockConfig = {
99
type: 'chat_trigger',
1010
triggerAllowed: true,
1111
name: 'Chat',
12-
description: 'Start workflow from a chat deployment',
12+
description: 'Legacy chat start block. Prefer the unified Start block.',
1313
longDescription: 'Chat trigger to run the workflow via deployed chat interfaces.',
1414
bestPractices: `
1515
- Can run the workflow manually to test implementation when this is the trigger point by passing in a message.
1616
`,
1717
category: 'triggers',
18+
hideFromToolbar: true,
1819
bgColor: '#6F3DFA',
1920
icon: ChatTriggerIcon,
2021
subBlocks: [],

apps/sim/blocks/blocks/input_trigger.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ const InputTriggerIcon = (props: SVGProps<SVGSVGElement>) => createElement(FormI
88
export const InputTriggerBlock: BlockConfig = {
99
type: 'input_trigger',
1010
triggerAllowed: true,
11-
name: 'Input Form',
12-
description: 'Start workflow manually with a defined input schema',
11+
name: 'Input Form (Legacy)',
12+
description: 'Legacy manual start block with structured input. Prefer Start block.',
1313
longDescription:
1414
'Manually trigger the workflow from the editor with a structured input schema. This enables typed inputs for parent workflows to map into.',
1515
bestPractices: `
@@ -18,6 +18,7 @@ export const InputTriggerBlock: BlockConfig = {
1818
- Also used in child workflows to map variables from the parent workflow.
1919
`,
2020
category: 'triggers',
21+
hideFromToolbar: true,
2122
bgColor: '#3B82F6',
2223
icon: InputTriggerIcon,
2324
subBlocks: [

0 commit comments

Comments
 (0)