Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
0e8c4b4
progress
icecrasher321 Sep 12, 2025
396efc9
progress
icecrasher321 Sep 13, 2025
7b649fb
Merge branch 'staging' into feat/trigger-split
icecrasher321 Sep 13, 2025
d3383c8
deploy command update
icecrasher321 Sep 13, 2025
d4543c2
add trigger mode modal
icecrasher321 Sep 13, 2025
5fc0018
fix trigger icons'
icecrasher321 Sep 13, 2025
d72a84f
fix corners for add trigger card
icecrasher321 Sep 13, 2025
de3ed5c
update serialization error visual in console
icecrasher321 Sep 13, 2025
7e2dae0
works
icecrasher321 Sep 13, 2025
330e0ed
improvement(copilot-context): structured context for copilot
icecrasher321 Sep 16, 2025
b7ad4ec
forgot long description
icecrasher321 Sep 16, 2025
e528b4c
Update metadata params
Sg312 Sep 16, 2025
cd4cb2c
progress
icecrasher321 Sep 17, 2025
68cb52e
add better workflow ux
icecrasher321 Sep 17, 2025
dde230a
progress
icecrasher321 Sep 17, 2025
ce61391
highlighting works
icecrasher321 Sep 17, 2025
fc40a7b
trigger card
icecrasher321 Sep 17, 2025
17ef831
default agent workflow change
icecrasher321 Sep 17, 2025
18459fe
fix build error
icecrasher321 Sep 17, 2025
b5eaa85
remove any casts
icecrasher321 Sep 17, 2025
68a59c9
address greptile comments
icecrasher321 Sep 17, 2025
75425a5
Merge branch 'improvement/metadata-tool-improvement' into integration…
icecrasher321 Sep 17, 2025
46b59b1
Resolve merge conflict in generic_webhook.ts: keep triggerAllowed, al…
icecrasher321 Sep 17, 2025
84fb4e7
Diff input format
Sg312 Sep 17, 2025
a9b8fa8
address greptile comments
icecrasher321 Sep 17, 2025
0302730
Merge latest origin/feat/trigger-split into integration branch; fix l…
icecrasher321 Sep 17, 2025
c58b8ed
improvement: ui/ux
emir-karabeg Sep 20, 2025
ed54526
improvement: changed to vertical scrolling
emir-karabeg Sep 22, 2025
bbe6cf4
Merge origin/staging into integration/metadata-tool-and-trigger-split…
icecrasher321 Sep 22, 2025
007ba71
Merge origin/staging again: resolve conflict in workflow.tsx keeping …
icecrasher321 Sep 22, 2025
a831cd4
fix(workflow): ensure new blocks from sidebar click/drag use getUniqu…
icecrasher321 Sep 22, 2025
5f9a6c7
Validation + build/edit mark complete
Sg312 Sep 23, 2025
a574675
fix trigger dropdown
icecrasher321 Sep 23, 2025
8e30613
Merge branch 'integration/metadata-tool-and-trigger-split-from-stagin…
icecrasher321 Sep 23, 2025
6dc7393
Copilot stuff (lots of it)
Sg312 Sep 23, 2025
4a29775
Temp update prod dns
Sg312 Sep 23, 2025
b737362
fix trigger check
icecrasher321 Sep 23, 2025
4f28f90
fix
icecrasher321 Sep 23, 2025
b190edf
fix trigger mode check
icecrasher321 Sep 23, 2025
7b87060
Fix yaml imports
Sg312 Sep 23, 2025
6b2aa92
Fix autolayout error
Sg312 Sep 23, 2025
2beec04
fix deployed chat
icecrasher321 Sep 23, 2025
1175c7c
Merge branch 'integration/metadata-tool-and-trigger-split-from-stagin…
icecrasher321 Sep 23, 2025
0b2910c
Fix copilot input text overflow
Sg312 Sep 23, 2025
daa1c86
fix trigger mode persistence in addBlock with enableTriggerMode flag …
icecrasher321 Sep 23, 2025
13d833d
Merge branch 'integration/metadata-tool-and-trigger-split-from-stagin…
icecrasher321 Sep 23, 2025
20b2978
Lint
Sg312 Sep 23, 2025
ce4eaf3
Fix failing tests
Sg312 Sep 23, 2025
f1370c5
Reset ishosted
Sg312 Sep 23, 2025
048c1b5
Lint
Sg312 Sep 23, 2025
f533834
input format for legacy starter
icecrasher321 Sep 23, 2025
d9f8784
Merge branch 'integration/metadata-tool-and-trigger-split-from-stagin…
icecrasher321 Sep 23, 2025
0140783
Fix executor
Sg312 Sep 23, 2025
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
34 changes: 29 additions & 5 deletions apps/sim/app/api/chat/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { hasAdminPermission } from '@/lib/permissions/utils'
import { processStreamingBlockLogs } from '@/lib/tokenization'
import { getEmailDomain } from '@/lib/urls/utils'
import { decryptSecret, generateRequestId } from '@/lib/utils'
import { TriggerUtils } from '@/lib/workflows/triggers'
import { getBlock } from '@/blocks'
import { Executor } from '@/executor'
import type { BlockLog, ExecutionResult } from '@/executor/types'
Expand Down Expand Up @@ -430,9 +431,10 @@ export async function executeWorkflowForChat(
(acc, [id, block]) => {
const blockConfig = getBlock(block.type)
const isTriggerBlock = blockConfig?.category === 'triggers'
const isChatTrigger = block.type === 'chat_trigger'

// Skip trigger blocks during chat execution
if (!isTriggerBlock) {
// Keep all non-trigger blocks and also keep the chat_trigger block
if (!isTriggerBlock || isChatTrigger) {
acc[id] = block
}
return acc
Expand Down Expand Up @@ -487,8 +489,10 @@ export async function executeWorkflowForChat(

// Filter edges to exclude connections to/from trigger blocks (same as manual execution)
const triggerBlockIds = Object.keys(mergedStates).filter((id) => {
const blockConfig = getBlock(mergedStates[id].type)
return blockConfig?.category === 'triggers'
const type = mergedStates[id].type
const blockConfig = getBlock(type)
// Exclude chat_trigger from the list so its edges are preserved
return blockConfig?.category === 'triggers' && type !== 'chat_trigger'
})

const filteredEdges = edges.filter(
Expand Down Expand Up @@ -613,9 +617,29 @@ export async function executeWorkflowForChat(
// Set up logging on the executor
loggingSession.setupExecutor(executor)

// Determine the start block for chat execution
const startBlock = TriggerUtils.findStartBlock(mergedStates, 'chat')

if (!startBlock) {
const errorMessage =
'No Chat trigger configured for this workflow. Add a Chat Trigger block to enable chat execution.'
logger.error(`[${requestId}] ${errorMessage}`)
await loggingSession.safeCompleteWithError({
endedAt: new Date().toISOString(),
totalDurationMs: 0,
error: {
message: errorMessage,
stackTrace: undefined,
},
})
throw new Error(errorMessage)
}

const startBlockId = startBlock.blockId

let result
try {
result = await executor.execute(workflowId)
result = await executor.execute(workflowId, startBlockId)
} catch (error: any) {
logger.error(`[${requestId}] Chat workflow execution failed:`, error)
await loggingSession.safeCompleteWithError({
Expand Down
28 changes: 24 additions & 4 deletions apps/sim/app/api/copilot/chat/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,13 +220,20 @@ describe('Copilot Chat API Route', () => {
content: 'Hello',
},
],
chatMessages: [
{
role: 'user',
content: 'Hello',
},
],
workflowId: 'workflow-123',
userId: 'user-123',
stream: true,
streamToolCalls: true,
model: 'gpt-5',
mode: 'agent',
messageId: 'mock-uuid-1234-5678',
depth: 0,
version: '1.0.0',
chatId: 'chat-123',
}),
})
Expand Down Expand Up @@ -284,13 +291,19 @@ describe('Copilot Chat API Route', () => {
{ role: 'assistant', content: 'Previous response' },
{ role: 'user', content: 'New message' },
],
chatMessages: [
{ role: 'user', content: 'Previous message' },
{ role: 'assistant', content: 'Previous response' },
{ role: 'user', content: 'New message' },
],
workflowId: 'workflow-123',
userId: 'user-123',
stream: true,
streamToolCalls: true,
model: 'gpt-5',
mode: 'agent',
messageId: 'mock-uuid-1234-5678',
depth: 0,
version: '1.0.0',
chatId: 'chat-123',
}),
})
Expand Down Expand Up @@ -337,13 +350,18 @@ describe('Copilot Chat API Route', () => {
{ role: 'system', content: 'User seems confused about the workflow' },
{ role: 'user', content: 'Hello' },
],
chatMessages: [
{ role: 'system', content: 'User seems confused about the workflow' },
{ role: 'user', content: 'Hello' },
],
workflowId: 'workflow-123',
userId: 'user-123',
stream: true,
streamToolCalls: true,
model: 'gpt-5',
mode: 'agent',
messageId: 'mock-uuid-1234-5678',
depth: 0,
version: '1.0.0',
chatId: 'chat-123',
}),
})
Expand Down Expand Up @@ -427,13 +445,15 @@ describe('Copilot Chat API Route', () => {
expect.objectContaining({
body: JSON.stringify({
messages: [{ role: 'user', content: 'What is this workflow?' }],
chatMessages: [{ role: 'user', content: 'What is this workflow?' }],
workflowId: 'workflow-123',
userId: 'user-123',
stream: true,
streamToolCalls: true,
model: 'gpt-5',
mode: 'ask',
messageId: 'mock-uuid-1234-5678',
depth: 0,
version: '1.0.0',
chatId: 'chat-123',
}),
})
Expand Down
41 changes: 23 additions & 18 deletions apps/sim/app/api/copilot/chat/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { getCopilotModel } from '@/lib/copilot/config'
import type { CopilotProviderConfig } from '@/lib/copilot/types'
import { env } from '@/lib/env'
import { createLogger } from '@/lib/logs/console/logger'
import { SIM_AGENT_API_URL_DEFAULT } from '@/lib/sim-agent'
import { SIM_AGENT_API_URL_DEFAULT, SIM_AGENT_VERSION } from '@/lib/sim-agent'
import { generateChatTitle } from '@/lib/sim-agent/utils'
import { createFileContent, isSupportedFileType } from '@/lib/uploads/file-utils'
import { S3_COPILOT_CONFIG } from '@/lib/uploads/setup'
Expand All @@ -38,8 +38,21 @@ const ChatMessageSchema = z.object({
userMessageId: z.string().optional(), // ID from frontend for the user message
chatId: z.string().optional(),
workflowId: z.string().min(1, 'Workflow ID is required'),
model: z
.enum([
'gpt-5-fast',
'gpt-5',
'gpt-5-medium',
'gpt-5-high',
'gpt-4o',
'gpt-4.1',
'o3',
'claude-4-sonnet',
'claude-4.1-opus',
])
.optional()
.default('gpt-5'),
mode: z.enum(['ask', 'agent']).optional().default('agent'),
depth: z.number().int().min(0).max(3).optional().default(0),
prefetch: z.boolean().optional(),
createNewChat: z.boolean().optional().default(false),
stream: z.boolean().optional().default(true),
Expand Down Expand Up @@ -97,8 +110,8 @@ export async function POST(req: NextRequest) {
userMessageId,
chatId,
workflowId,
model,
mode,
depth,
prefetch,
createNewChat,
stream,
Expand Down Expand Up @@ -147,19 +160,6 @@ export async function POST(req: NextRequest) {
}
}

// Consolidation mapping: map negative depths to base depth with prefetch=true
let effectiveDepth: number | undefined = typeof depth === 'number' ? depth : undefined
let effectivePrefetch: boolean | undefined = prefetch
if (typeof effectiveDepth === 'number') {
if (effectiveDepth === -2) {
effectiveDepth = 1
effectivePrefetch = true
} else if (effectiveDepth === -1) {
effectiveDepth = 0
effectivePrefetch = true
}
}

// Handle chat context
let currentChat: any = null
let conversationHistory: any[] = []
Expand Down Expand Up @@ -366,16 +366,18 @@ export async function POST(req: NextRequest) {

const requestPayload = {
messages: messagesForAgent,
chatMessages: messages, // Full unfiltered messages array
workflowId,
userId: authenticatedUserId,
stream: stream,
streamToolCalls: true,
model: model,
mode: mode,
messageId: userMessageIdToUse,
version: SIM_AGENT_VERSION,
...(providerConfig ? { provider: providerConfig } : {}),
...(effectiveConversationId ? { conversationId: effectiveConversationId } : {}),
...(typeof effectiveDepth === 'number' ? { depth: effectiveDepth } : {}),
...(typeof effectivePrefetch === 'boolean' ? { prefetch: effectivePrefetch } : {}),
...(typeof prefetch === 'boolean' ? { prefetch: prefetch } : {}),
...(session?.user?.name && { userName: session.user.name }),
...(agentContexts.length > 0 && { context: agentContexts }),
...(actualChatId ? { chatId: actualChatId } : {}),
Expand All @@ -384,6 +386,9 @@ export async function POST(req: NextRequest) {
try {
logger.info(`[${tracker.requestId}] About to call Sim Agent with context`, {
context: (requestPayload as any).context,
messagesCount: messagesForAgent.length,
chatMessagesCount: messages.length,
hasConversationId: !!effectiveConversationId,
})
} catch {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export async function POST(req: NextRequest) {
return createBadRequestResponse('Invalid request body for execute-copilot-server-tool')
}
logger.error(`[${tracker.requestId}] Failed to execute server tool:`, error)
return createInternalServerErrorResponse('Failed to execute server tool')
const errorMessage = error instanceof Error ? error.message : 'Failed to execute server tool'
return createInternalServerErrorResponse(errorMessage)
}
}
4 changes: 2 additions & 2 deletions apps/sim/app/api/workflows/[id]/execute/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ describe('Workflow Execution API Route', () => {
const Executor = (await import('@/executor')).Executor
expect(Executor).toHaveBeenCalled()

expect(executeMock).toHaveBeenCalledWith('workflow-id')
expect(executeMock).toHaveBeenCalledWith('workflow-id', 'starter-id')
})

/**
Expand Down Expand Up @@ -337,7 +337,7 @@ describe('Workflow Execution API Route', () => {
const Executor = (await import('@/executor')).Executor
expect(Executor).toHaveBeenCalled()

expect(executeMock).toHaveBeenCalledWith('workflow-id')
expect(executeMock).toHaveBeenCalledWith('workflow-id', 'starter-id')

expect(Executor).toHaveBeenCalledWith(
expect.objectContaining({
Expand Down
29 changes: 28 additions & 1 deletion apps/sim/app/api/workflows/[id]/execute/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { LoggingSession } from '@/lib/logs/execution/logging-session'
import { buildTraceSpans } from '@/lib/logs/execution/trace-spans/trace-spans'
import { decryptSecret, generateRequestId } from '@/lib/utils'
import { loadDeployedWorkflowState } from '@/lib/workflows/db-helpers'
import { TriggerUtils } from '@/lib/workflows/triggers'
import {
createHttpResponseFromBlock,
updateWorkflowRunCounts,
Expand Down Expand Up @@ -272,6 +273,32 @@ async function executeWorkflow(
true // Enable validation during execution
)

// Determine API trigger start block
// Direct API execution ONLY works with API trigger blocks (or legacy starter in api/run mode)
const startBlock = TriggerUtils.findStartBlock(mergedStates, 'api', false) // isChildWorkflow = false

if (!startBlock) {
logger.error(`[${requestId}] No API trigger configured for this workflow`)
throw new Error(
'No API trigger configured for this workflow. Add an API Trigger block or use a Start block in API mode.'
)
}

const startBlockId = startBlock.blockId
const triggerBlock = startBlock.block

// Check if the API trigger has any outgoing connections (except for legacy starter blocks)
// Legacy starter blocks have their own validation in the executor
if (triggerBlock.type !== 'starter') {
const outgoingConnections = serializedWorkflow.connections.filter(
(conn) => conn.source === startBlockId
)
if (outgoingConnections.length === 0) {
logger.error(`[${requestId}] API trigger has no outgoing connections`)
throw new Error('API Trigger block must be connected to other blocks to execute')
}
}

const executor = new Executor({
workflow: serializedWorkflow,
currentBlockStates: processedBlockStates,
Expand All @@ -287,7 +314,7 @@ async function executeWorkflow(
// Set up logging on the executor
loggingSession.setupExecutor(executor)

const result = await executor.execute(workflowId)
const result = await executor.execute(workflowId, startBlockId)

// Check if we got a StreamingExecution result (with stream + execution properties)
// For API routes, we only care about the ExecutionResult part, not the stream
Expand Down
Loading