mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-14 01:18:15 -05:00
Compare commits
27 Commits
fix/trigge
...
v0.5.59
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e8c843241 | ||
|
|
4be420311c | ||
|
|
7bf3d73ee6 | ||
|
|
7ffc11a738 | ||
|
|
be578e2ed7 | ||
|
|
f415e5edc4 | ||
|
|
13a6e6c3fa | ||
|
|
f5ab7f21ae | ||
|
|
bfb6fffe38 | ||
|
|
4fbec0a43f | ||
|
|
585f5e365b | ||
|
|
3792bdd252 | ||
|
|
eb5d1f3e5b | ||
|
|
54ab82c8dd | ||
|
|
f895bf469b | ||
|
|
dd3209af06 | ||
|
|
b6ba3b50a7 | ||
|
|
b304233062 | ||
|
|
57e4b49bd6 | ||
|
|
e12dd204ed | ||
|
|
3d9d9cbc54 | ||
|
|
0f4ec962ad | ||
|
|
4827866f9a | ||
|
|
3e697d9ed9 | ||
|
|
4431a1a484 | ||
|
|
4d1a9a3f22 | ||
|
|
eb07a080fb |
@@ -384,7 +384,7 @@ async function handleMessageSend(
|
||||
headers,
|
||||
body: JSON.stringify({
|
||||
...workflowInput,
|
||||
triggerType: 'api',
|
||||
triggerType: 'a2a',
|
||||
...(useInternalAuth && { workflowId: agent.workflowId }),
|
||||
}),
|
||||
signal: AbortSignal.timeout(A2A_DEFAULT_TIMEOUT),
|
||||
@@ -613,7 +613,7 @@ async function handleMessageStream(
|
||||
headers,
|
||||
body: JSON.stringify({
|
||||
...workflowInput,
|
||||
triggerType: 'api',
|
||||
triggerType: 'a2a',
|
||||
stream: true,
|
||||
...(useInternalAuth && { workflowId: agent.workflowId }),
|
||||
}),
|
||||
|
||||
@@ -27,7 +27,7 @@ import { ExecutionSnapshot } from '@/executor/execution/snapshot'
|
||||
import type { ExecutionMetadata, IterationContext } from '@/executor/execution/types'
|
||||
import type { StreamingExecution } from '@/executor/types'
|
||||
import { Serializer } from '@/serializer'
|
||||
import { CORE_TRIGGER_TYPES } from '@/stores/logs/filters/types'
|
||||
import { CORE_TRIGGER_TYPES, type CoreTriggerType } from '@/stores/logs/filters/types'
|
||||
|
||||
const logger = createLogger('WorkflowExecuteAPI')
|
||||
|
||||
@@ -109,7 +109,7 @@ type AsyncExecutionParams = {
|
||||
workflowId: string
|
||||
userId: string
|
||||
input: any
|
||||
triggerType: 'api' | 'webhook' | 'schedule' | 'manual' | 'chat' | 'mcp'
|
||||
triggerType: CoreTriggerType
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,17 +253,9 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id:
|
||||
})
|
||||
|
||||
const executionId = uuidv4()
|
||||
type LoggingTriggerType = 'api' | 'webhook' | 'schedule' | 'manual' | 'chat' | 'mcp'
|
||||
let loggingTriggerType: LoggingTriggerType = 'manual'
|
||||
if (
|
||||
triggerType === 'api' ||
|
||||
triggerType === 'chat' ||
|
||||
triggerType === 'webhook' ||
|
||||
triggerType === 'schedule' ||
|
||||
triggerType === 'manual' ||
|
||||
triggerType === 'mcp'
|
||||
) {
|
||||
loggingTriggerType = triggerType as LoggingTriggerType
|
||||
let loggingTriggerType: CoreTriggerType = 'manual'
|
||||
if (CORE_TRIGGER_TYPES.includes(triggerType as CoreTriggerType)) {
|
||||
loggingTriggerType = triggerType as CoreTriggerType
|
||||
}
|
||||
const loggingSession = new LoggingSession(
|
||||
workflowId,
|
||||
|
||||
@@ -72,6 +72,7 @@ const TRIGGER_VARIANT_MAP: Record<string, React.ComponentProps<typeof Badge>['va
|
||||
schedule: 'green',
|
||||
chat: 'purple',
|
||||
webhook: 'orange',
|
||||
a2a: 'teal',
|
||||
}
|
||||
|
||||
interface StatusBadgeProps {
|
||||
|
||||
@@ -204,7 +204,8 @@ export function A2aDeploy({
|
||||
const [skillTags, setSkillTags] = useState<string[]>([])
|
||||
const [language, setLanguage] = useState<CodeLanguage>('curl')
|
||||
const [useStreamingExample, setUseStreamingExample] = useState(false)
|
||||
const [copied, setCopied] = useState(false)
|
||||
const [urlCopied, setUrlCopied] = useState(false)
|
||||
const [codeCopied, setCodeCopied] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (existingAgent) {
|
||||
@@ -451,7 +452,7 @@ export function A2aDeploy({
|
||||
}
|
||||
|
||||
try {
|
||||
if (!isDeployed && onDeployWorkflow) {
|
||||
if ((!isDeployed || workflowNeedsRedeployment) && onDeployWorkflow) {
|
||||
await onDeployWorkflow()
|
||||
}
|
||||
|
||||
@@ -475,6 +476,7 @@ export function A2aDeploy({
|
||||
}, [
|
||||
existingAgent,
|
||||
isDeployed,
|
||||
workflowNeedsRedeployment,
|
||||
onDeployWorkflow,
|
||||
name,
|
||||
description,
|
||||
@@ -643,8 +645,8 @@ console.log(data);`
|
||||
|
||||
const handleCopyCommand = useCallback(() => {
|
||||
navigator.clipboard.writeText(getCurlCommand())
|
||||
setCopied(true)
|
||||
setTimeout(() => setCopied(false), 2000)
|
||||
setCodeCopied(true)
|
||||
setTimeout(() => setCodeCopied(false), 2000)
|
||||
}, [getCurlCommand])
|
||||
|
||||
if (isLoading) {
|
||||
@@ -702,12 +704,12 @@ console.log(data);`
|
||||
type='button'
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(endpoint)
|
||||
setCopied(true)
|
||||
setTimeout(() => setCopied(false), 2000)
|
||||
setUrlCopied(true)
|
||||
setTimeout(() => setUrlCopied(false), 2000)
|
||||
}}
|
||||
className='-translate-y-1/2 absolute top-1/2 right-2'
|
||||
>
|
||||
{copied ? (
|
||||
{urlCopied ? (
|
||||
<Check className='h-3 w-3 text-[var(--brand-tertiary-2)]' />
|
||||
) : (
|
||||
<Clipboard className='h-3 w-3 text-[var(--text-tertiary)]' />
|
||||
@@ -715,7 +717,7 @@ console.log(data);`
|
||||
</button>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Content>
|
||||
<span>{copied ? 'Copied' : 'Copy'}</span>
|
||||
<span>{urlCopied ? 'Copied' : 'Copy'}</span>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Root>
|
||||
</div>
|
||||
@@ -871,11 +873,15 @@ console.log(data);`
|
||||
aria-label='Copy command'
|
||||
className='!p-1.5 -my-1.5'
|
||||
>
|
||||
{copied ? <Check className='h-3 w-3' /> : <Clipboard className='h-3 w-3' />}
|
||||
{codeCopied ? (
|
||||
<Check className='h-3 w-3' />
|
||||
) : (
|
||||
<Clipboard className='h-3 w-3' />
|
||||
)}
|
||||
</Button>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Content>
|
||||
<span>{copied ? 'Copied' : 'Copy'}</span>
|
||||
<span>{codeCopied ? 'Copied' : 'Copy'}</span>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Root>
|
||||
</div>
|
||||
|
||||
@@ -2319,6 +2319,8 @@ const WorkflowContent = React.memo(() => {
|
||||
/**
|
||||
* Handles connection drag end. Detects if the edge was dropped over a block
|
||||
* and automatically creates a connection to that block's target handle.
|
||||
* Only creates a connection if ReactFlow didn't already handle it (e.g., when
|
||||
* dropping on the block body instead of a handle).
|
||||
*/
|
||||
const onConnectEnd = useCallback(
|
||||
(event: MouseEvent | TouchEvent) => {
|
||||
@@ -2340,14 +2342,25 @@ const WorkflowContent = React.memo(() => {
|
||||
// Find node under cursor
|
||||
const targetNode = findNodeAtPosition(flowPosition)
|
||||
|
||||
// Create connection if valid target found
|
||||
// Create connection if valid target found AND edge doesn't already exist
|
||||
// ReactFlow's onConnect fires first when dropping on a handle, so we check
|
||||
// if that connection already exists to avoid creating duplicates.
|
||||
// IMPORTANT: We must read directly from the store (not React state) because
|
||||
// the store update from ReactFlow's onConnect may not have triggered a
|
||||
// React re-render yet when this callback runs (typically 1-2ms later).
|
||||
if (targetNode && targetNode.id !== source.nodeId) {
|
||||
onConnect({
|
||||
source: source.nodeId,
|
||||
sourceHandle: source.handleId,
|
||||
target: targetNode.id,
|
||||
targetHandle: 'target',
|
||||
})
|
||||
const currentEdges = useWorkflowStore.getState().edges
|
||||
const edgeAlreadyExists = currentEdges.some(
|
||||
(e) => e.source === source.nodeId && e.target === targetNode.id
|
||||
)
|
||||
if (!edgeAlreadyExists) {
|
||||
onConnect({
|
||||
source: source.nodeId,
|
||||
sourceHandle: source.handleId,
|
||||
target: targetNode.id,
|
||||
targetHandle: 'target',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
connectionSourceRef.current = null
|
||||
|
||||
@@ -10,6 +10,7 @@ import { getWorkflowById } from '@/lib/workflows/utils'
|
||||
import { ExecutionSnapshot } from '@/executor/execution/snapshot'
|
||||
import type { ExecutionMetadata } from '@/executor/execution/types'
|
||||
import type { ExecutionResult } from '@/executor/types'
|
||||
import type { CoreTriggerType } from '@/stores/logs/filters/types'
|
||||
|
||||
const logger = createLogger('TriggerWorkflowExecution')
|
||||
|
||||
@@ -17,7 +18,7 @@ export type WorkflowExecutionPayload = {
|
||||
workflowId: string
|
||||
userId: string
|
||||
input?: any
|
||||
triggerType?: 'api' | 'webhook' | 'schedule' | 'manual' | 'chat' | 'mcp'
|
||||
triggerType?: CoreTriggerType
|
||||
metadata?: Record<string, any>
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ const badgeVariants = cva(
|
||||
orange: `${STATUS_BASE} bg-[#fed7aa] text-[#c2410c] dark:bg-[rgba(249,115,22,0.2)] dark:text-[#fdba74]`,
|
||||
amber: `${STATUS_BASE} bg-[#fde68a] text-[#a16207] dark:bg-[rgba(245,158,11,0.2)] dark:text-[#fcd34d]`,
|
||||
teal: `${STATUS_BASE} bg-[#99f6e4] text-[#0f766e] dark:bg-[rgba(20,184,166,0.2)] dark:text-[#5eead4]`,
|
||||
cyan: `${STATUS_BASE} bg-[#a5f3fc] text-[#0e7490] dark:bg-[rgba(14,165,233,0.2)] dark:text-[#7dd3fc]`,
|
||||
'gray-secondary': `${STATUS_BASE} bg-[var(--surface-4)] text-[var(--text-secondary)]`,
|
||||
},
|
||||
size: {
|
||||
@@ -51,6 +52,7 @@ const STATUS_VARIANTS = [
|
||||
'orange',
|
||||
'amber',
|
||||
'teal',
|
||||
'cyan',
|
||||
'gray-secondary',
|
||||
] as const
|
||||
|
||||
@@ -84,7 +86,7 @@ export interface BadgeProps
|
||||
* Supports two categories of variants:
|
||||
* - **Bordered**: `default`, `outline` - traditional badges with borders
|
||||
* - **Status colors**: `green`, `red`, `gray`, `blue`, `blue-secondary`, `purple`,
|
||||
* `orange`, `amber`, `teal`, `gray-secondary` - borderless colored badges
|
||||
* `orange`, `amber`, `teal`, `cyan`, `gray-secondary` - borderless colored badges
|
||||
*
|
||||
* Status color variants can display a dot indicator via the `dot` prop.
|
||||
* All variants support an optional `icon` prop for leading icons.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import type { CoreTriggerType } from '@/stores/logs/filters/types'
|
||||
|
||||
const logger = createLogger('NotificationQueries')
|
||||
|
||||
@@ -18,7 +19,7 @@ export const notificationKeys = {
|
||||
|
||||
type NotificationType = 'webhook' | 'email' | 'slack'
|
||||
type LogLevel = 'info' | 'error'
|
||||
type TriggerType = 'api' | 'webhook' | 'schedule' | 'manual' | 'chat' | 'mcp'
|
||||
type TriggerType = CoreTriggerType
|
||||
|
||||
type AlertRuleType =
|
||||
| 'consecutive_failures'
|
||||
|
||||
@@ -78,12 +78,16 @@ export interface A2AFile {
|
||||
export function extractFileContent(message: Message): A2AFile[] {
|
||||
return message.parts
|
||||
.filter((part): part is FilePart => part.kind === 'file')
|
||||
.map((part) => ({
|
||||
name: part.file.name,
|
||||
mimeType: part.file.mimeType,
|
||||
...('uri' in part.file ? { uri: part.file.uri } : {}),
|
||||
...('bytes' in part.file ? { bytes: part.file.bytes } : {}),
|
||||
}))
|
||||
.map((part) => {
|
||||
const file = part.file as unknown as Record<string, unknown>
|
||||
const uri = (file.url as string) || (file.uri as string)
|
||||
return {
|
||||
name: file.name as string | undefined,
|
||||
mimeType: file.mimeType as string | undefined,
|
||||
...(uri ? { uri } : {}),
|
||||
...(file.bytes ? { bytes: file.bytes as string } : {}),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export interface ExecutionFileInput {
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
import { env } from '@/lib/core/config/env'
|
||||
import type { CoreTriggerType } from '@/stores/logs/filters/types'
|
||||
import type { TokenBucketConfig } from './storage'
|
||||
|
||||
export type TriggerType =
|
||||
| 'api'
|
||||
| 'webhook'
|
||||
| 'schedule'
|
||||
| 'manual'
|
||||
| 'chat'
|
||||
| 'mcp'
|
||||
| 'form'
|
||||
| 'api-endpoint'
|
||||
export type TriggerType = CoreTriggerType | 'form' | 'api-endpoint'
|
||||
|
||||
export type RateLimitCounterType = 'sync' | 'async' | 'api-endpoint'
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { getHighestPrioritySubscription } from '@/lib/billing/core/subscription'
|
||||
import { RateLimiter } from '@/lib/core/rate-limiter/rate-limiter'
|
||||
import { LoggingSession } from '@/lib/logs/execution/logging-session'
|
||||
import { getWorkspaceBilledAccountUserId } from '@/lib/workspaces/utils'
|
||||
import type { CoreTriggerType } from '@/stores/logs/filters/types'
|
||||
|
||||
const logger = createLogger('ExecutionPreprocessing')
|
||||
|
||||
@@ -108,7 +109,7 @@ export interface PreprocessExecutionOptions {
|
||||
// Required fields
|
||||
workflowId: string
|
||||
userId: string // The authenticated user ID
|
||||
triggerType: 'manual' | 'api' | 'webhook' | 'schedule' | 'chat' | 'mcp' | 'form'
|
||||
triggerType: CoreTriggerType | 'form'
|
||||
executionId: string
|
||||
requestId: string
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ export function getTriggerOptions(): TriggerOption[] {
|
||||
{ value: 'form', label: 'Form', color: '#06b6d4' },
|
||||
{ value: 'webhook', label: 'Webhook', color: '#ea580c' },
|
||||
{ value: 'mcp', label: 'MCP', color: '#dc2626' },
|
||||
{ value: 'a2a', label: 'A2A', color: '#14b8a6' },
|
||||
]
|
||||
|
||||
for (const trigger of triggers) {
|
||||
|
||||
@@ -174,7 +174,15 @@ export type TimeRange =
|
||||
|
||||
export type LogLevel = 'error' | 'info' | 'running' | 'pending' | 'all' | (string & {})
|
||||
/** Core trigger types for workflow execution */
|
||||
export const CORE_TRIGGER_TYPES = ['manual', 'api', 'schedule', 'chat', 'webhook', 'mcp'] as const
|
||||
export const CORE_TRIGGER_TYPES = [
|
||||
'manual',
|
||||
'api',
|
||||
'schedule',
|
||||
'chat',
|
||||
'webhook',
|
||||
'mcp',
|
||||
'a2a',
|
||||
] as const
|
||||
|
||||
export type CoreTriggerType = (typeof CORE_TRIGGER_TYPES)[number]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user