chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { isMetadataOnlyBlockType, isTriggerBlockType } from '@/executor/constants'
|
||||
import { extractBaseBlockId } from '@/executor/utils/subflow-utils'
|
||||
import type { SerializedBlock, SerializedWorkflow } from '@/serializer/types'
|
||||
|
||||
const logger = createLogger('PathConstructor')
|
||||
|
||||
export class PathConstructor {
|
||||
execute(
|
||||
workflow: SerializedWorkflow,
|
||||
triggerBlockId?: string,
|
||||
includeAllBlocks?: boolean
|
||||
): Set<string> {
|
||||
// For run-from-block mode, include all enabled blocks regardless of trigger reachability
|
||||
if (includeAllBlocks) {
|
||||
return this.getAllEnabledBlocks(workflow)
|
||||
}
|
||||
|
||||
const resolvedTriggerId = this.findTriggerBlock(workflow, triggerBlockId)
|
||||
|
||||
if (!resolvedTriggerId) {
|
||||
logger.warn('No trigger block found, including all enabled blocks as fallback')
|
||||
return this.getAllEnabledBlocks(workflow)
|
||||
}
|
||||
|
||||
const adjacency = this.buildAdjacencyMap(workflow)
|
||||
const reachable = this.performBFS(resolvedTriggerId, adjacency)
|
||||
|
||||
return reachable
|
||||
}
|
||||
|
||||
private findTriggerBlock(
|
||||
workflow: SerializedWorkflow,
|
||||
triggerBlockId?: string
|
||||
): string | undefined {
|
||||
if (triggerBlockId) {
|
||||
const block = workflow.blocks.find((b) => b.id === triggerBlockId)
|
||||
|
||||
if (block) {
|
||||
if (!block.enabled) {
|
||||
logger.error('Provided triggerBlockId is disabled, finding alternative', {
|
||||
triggerBlockId,
|
||||
blockEnabled: block.enabled,
|
||||
})
|
||||
// Try to find an alternative enabled trigger instead of failing
|
||||
const alternativeTrigger = this.findExplicitTrigger(workflow)
|
||||
if (alternativeTrigger) {
|
||||
logger.info('Using alternative enabled trigger', {
|
||||
disabledTriggerId: triggerBlockId,
|
||||
alternativeTriggerId: alternativeTrigger,
|
||||
})
|
||||
return alternativeTrigger
|
||||
}
|
||||
throw new Error(
|
||||
`Trigger block ${triggerBlockId} is disabled and no alternative enabled trigger found`
|
||||
)
|
||||
}
|
||||
return triggerBlockId
|
||||
}
|
||||
|
||||
const fallbackTriggerId = this.resolveResumeTriggerFallback(triggerBlockId, workflow)
|
||||
|
||||
if (fallbackTriggerId) {
|
||||
return fallbackTriggerId
|
||||
}
|
||||
|
||||
logger.error('Provided triggerBlockId not found in workflow', {
|
||||
triggerBlockId,
|
||||
availableBlocks: workflow.blocks.map((b) => ({ id: b.id, type: b.metadata?.id })),
|
||||
})
|
||||
|
||||
throw new Error(`Trigger block not found: ${triggerBlockId}`)
|
||||
}
|
||||
|
||||
const explicitTrigger = this.findExplicitTrigger(workflow)
|
||||
|
||||
if (explicitTrigger) {
|
||||
return explicitTrigger
|
||||
}
|
||||
|
||||
const rootBlock = this.findRootBlock(workflow)
|
||||
|
||||
if (rootBlock) {
|
||||
return rootBlock
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
private findExplicitTrigger(workflow: SerializedWorkflow): string | undefined {
|
||||
for (const block of workflow.blocks) {
|
||||
if (block.enabled && this.isTriggerBlock(block)) {
|
||||
return block.id
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
private findRootBlock(workflow: SerializedWorkflow): string | undefined {
|
||||
const hasIncoming = new Set(workflow.connections.map((c) => c.target))
|
||||
|
||||
for (const block of workflow.blocks) {
|
||||
if (
|
||||
!hasIncoming.has(block.id) &&
|
||||
block.enabled &&
|
||||
!isMetadataOnlyBlockType(block.metadata?.id)
|
||||
) {
|
||||
return block.id
|
||||
}
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
private isTriggerBlock(block: SerializedBlock): boolean {
|
||||
return isTriggerBlockType(block.metadata?.id)
|
||||
}
|
||||
|
||||
private getAllEnabledBlocks(workflow: SerializedWorkflow): Set<string> {
|
||||
return new Set(workflow.blocks.filter((b) => b.enabled).map((b) => b.id))
|
||||
}
|
||||
|
||||
private buildAdjacencyMap(workflow: SerializedWorkflow): Map<string, string[]> {
|
||||
const adjacency = new Map<string, string[]>()
|
||||
const enabledBlocks = new Set(workflow.blocks.filter((b) => b.enabled).map((b) => b.id))
|
||||
|
||||
for (const connection of workflow.connections) {
|
||||
if (!enabledBlocks.has(connection.source) || !enabledBlocks.has(connection.target)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const neighbors = adjacency.get(connection.source) ?? []
|
||||
neighbors.push(connection.target)
|
||||
adjacency.set(connection.source, neighbors)
|
||||
}
|
||||
|
||||
return adjacency
|
||||
}
|
||||
|
||||
private performBFS(triggerBlockId: string, adjacency: Map<string, string[]>): Set<string> {
|
||||
const reachable = new Set<string>([triggerBlockId])
|
||||
const queue = [triggerBlockId]
|
||||
|
||||
while (queue.length > 0) {
|
||||
const currentBlockId = queue.shift()
|
||||
|
||||
if (!currentBlockId) break
|
||||
|
||||
const neighbors = adjacency.get(currentBlockId) ?? []
|
||||
|
||||
for (const neighborId of neighbors) {
|
||||
if (!reachable.has(neighborId)) {
|
||||
reachable.add(neighborId)
|
||||
queue.push(neighborId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return reachable
|
||||
}
|
||||
|
||||
private resolveResumeTriggerFallback(
|
||||
triggerBlockId: string,
|
||||
workflow: SerializedWorkflow
|
||||
): string | undefined {
|
||||
if (!triggerBlockId.endsWith('__trigger')) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const baseId = triggerBlockId.replace(/__trigger$/, '')
|
||||
const normalizedBaseId = extractBaseBlockId(baseId)
|
||||
const candidates = baseId === normalizedBaseId ? [baseId] : [baseId, normalizedBaseId]
|
||||
|
||||
for (const candidate of candidates) {
|
||||
const block = workflow.blocks.find((b) => b.id === candidate)
|
||||
|
||||
if (block) {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user