Files
sim/apps/sim/executor/variables/resolvers/parallel.ts
Siddharth Ganesan 3bf00cbd2a improvement(executor): redesign executor + add start block (#1790)
* fix(billing): should allow restoring subscription (#1728)

* fix(already-cancelled-sub): UI should allow restoring subscription

* restore functionality fixed

* fix

* improvement(start): revert to start block

* make it work with start block

* fix start block persistence

* cleanup triggers

* debounce status checks

* update docs

* improvement(start): revert to start block

* make it work with start block

* fix start block persistence

* cleanup triggers

* debounce status checks

* update docs

* SSE v0.1

* v0.2

* v0.3

* v0.4

* v0.5

* v0.6

* broken checkpoint

* Executor progress - everything preliminarily tested except while loops and triggers

* Executor fixes

* Fix var typing

* Implement while loop execution

* Loop and parallel result agg

* Refactor v1 - loops work

* Fix var resolution in for each loop

* Fix while loop condition and variable resolution

* Fix loop iteration counts

* Fix loop badges

* Clean logs

* Fix variable references from start block

* Fix condition block

* Fix conditional convergence

* Dont execute orphaned nodse

* Code cleanup 1 and error surfacing

* compile time try catch

* Some fixes

* Fix error throwing

* Sentinels v1

* Fix multiple start and end nodes in loop

* Edge restoration

* Fix reachable nodes execution

* Parallel subflows

* Fix loop/parallel sentinel convergence

* Loops and parallels orchestrator

* Split executor

* Variable resolution split

* Dag phase

* Refactor

* Refactor

* Refactor 3

* Lint + refactor

* Lint + cleanup + refactor

* Readability

* Initial logs

* Fix trace spans

* Console pills for iters

* Add input/output pills

* Checkpoint

* remove unused code

* THIS IS THE COMMIT THAT CAN BREAK A LOT OF THINGS

* ANOTHER BIG REFACTOR

* Lint + fix tests

* Fix webhook

* Remove comment

* Merge stash

* Fix triggers?

* Stuff

* Fix error port

* Lint

* Consolidate state

* Clean up some var resolution

* Remove some var resolution logs

* Fix chat

* Fix chat triggers

* Fix chat trigger fully

* Snapshot refactor

* Fix mcp and custom tools

* Lint

* Fix parallel default count and trace span overlay

* Agent purple

* Fix test

* Fix test

---------

Co-authored-by: Waleed <walif6@gmail.com>
Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com>
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
2025-11-02 12:21:16 -08:00

101 lines
3.3 KiB
TypeScript

import { createLogger } from '@/lib/logs/console/logger'
import { isReference, parseReferencePath, REFERENCE } from '@/executor/consts'
import { extractBaseBlockId, extractBranchIndex } from '@/executor/utils/subflow-utils'
import type { SerializedWorkflow } from '@/serializer/types'
import type { ResolutionContext, Resolver } from './reference'
const logger = createLogger('ParallelResolver')
export class ParallelResolver implements Resolver {
constructor(private workflow: SerializedWorkflow) {}
canResolve(reference: string): boolean {
if (!isReference(reference)) {
return false
}
const parts = parseReferencePath(reference)
if (parts.length === 0) {
return false
}
const [type] = parts
return type === REFERENCE.PREFIX.PARALLEL
}
resolve(reference: string, context: ResolutionContext): any {
const parts = parseReferencePath(reference)
if (parts.length < 2) {
logger.warn('Invalid parallel reference - missing property', { reference })
return undefined
}
const [_, property] = parts
const parallelId = this.findParallelForBlock(context.currentNodeId)
if (!parallelId) {
logger.debug('Block not in a parallel', { nodeId: context.currentNodeId })
return undefined
}
const parallelConfig = this.workflow.parallels?.[parallelId]
if (!parallelConfig) {
logger.warn('Parallel config not found', { parallelId })
return undefined
}
const branchIndex = extractBranchIndex(context.currentNodeId)
if (branchIndex === null) {
logger.debug('Node ID does not have branch index', { nodeId: context.currentNodeId })
return undefined
}
const distributionItems = this.getDistributionItems(parallelConfig)
switch (property) {
case 'index':
return branchIndex
case 'currentItem':
if (Array.isArray(distributionItems)) {
return distributionItems[branchIndex]
}
if (typeof distributionItems === 'object' && distributionItems !== null) {
const keys = Object.keys(distributionItems)
const key = keys[branchIndex]
return key !== undefined ? distributionItems[key] : undefined
}
return undefined
case 'items':
return distributionItems
default:
logger.warn('Unknown parallel property', { property })
return undefined
}
}
private findParallelForBlock(blockId: string): string | undefined {
const baseId = extractBaseBlockId(blockId)
if (!this.workflow.parallels) {
return undefined
}
for (const parallelId of Object.keys(this.workflow.parallels)) {
const parallelConfig = this.workflow.parallels[parallelId]
if (parallelConfig?.nodes.includes(baseId)) {
return parallelId
}
}
return undefined
}
private getDistributionItems(parallelConfig: any): any {
let distributionItems = parallelConfig.distributionItems || parallelConfig.distribution || []
if (typeof distributionItems === 'string' && !distributionItems.startsWith('<')) {
try {
distributionItems = JSON.parse(distributionItems.replace(/'/g, '"'))
} catch (e) {
logger.error('Failed to parse distribution items', { distributionItems })
return []
}
}
return distributionItems
}
}