mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-09 15:07:55 -05:00
fix(condition): async execution isolated vm error (#2446)
* fix(condition): async execution isolated vm error * fix tests
This commit is contained in:
committed by
GitHub
parent
7ef1150383
commit
78b7643e65
@@ -17,27 +17,32 @@ vi.mock('@/lib/core/utils/request', () => ({
|
|||||||
generateRequestId: vi.fn(() => 'test-request-id'),
|
generateRequestId: vi.fn(() => 'test-request-id'),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
vi.mock('@/lib/execution/isolated-vm', () => ({
|
vi.mock('@/tools', () => ({
|
||||||
executeInIsolatedVM: vi.fn(),
|
executeTool: vi.fn(),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
import { executeInIsolatedVM } from '@/lib/execution/isolated-vm'
|
import { executeTool } from '@/tools'
|
||||||
|
|
||||||
const mockExecuteInIsolatedVM = executeInIsolatedVM as ReturnType<typeof vi.fn>
|
const mockExecuteTool = executeTool as ReturnType<typeof vi.fn>
|
||||||
|
|
||||||
function simulateIsolatedVMExecution(
|
/**
|
||||||
code: string,
|
* Simulates what the function_execute tool does when evaluating condition code
|
||||||
contextVariables: Record<string, unknown>
|
*/
|
||||||
): { result: unknown; stdout: string; error?: { message: string; name: string } } {
|
function simulateConditionExecution(code: string): {
|
||||||
|
success: boolean
|
||||||
|
output?: { result: unknown }
|
||||||
|
error?: string
|
||||||
|
} {
|
||||||
try {
|
try {
|
||||||
const fn = new Function(...Object.keys(contextVariables), code)
|
// The code is in format: "const context = {...};\nreturn Boolean(...)"
|
||||||
const result = fn(...Object.values(contextVariables))
|
// We need to execute it and return the result
|
||||||
return { result, stdout: '' }
|
const fn = new Function(code)
|
||||||
|
const result = fn()
|
||||||
|
return { success: true, output: { result } }
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
return {
|
return {
|
||||||
result: null,
|
success: false,
|
||||||
stdout: '',
|
error: error.message,
|
||||||
error: { message: error.message, name: error.name || 'Error' },
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,8 +148,8 @@ describe('ConditionBlockHandler', () => {
|
|||||||
|
|
||||||
vi.clearAllMocks()
|
vi.clearAllMocks()
|
||||||
|
|
||||||
mockExecuteInIsolatedVM.mockImplementation(async ({ code, contextVariables }) => {
|
mockExecuteTool.mockImplementation(async (_toolId: string, params: { code: string }) => {
|
||||||
return simulateIsolatedVMExecution(code, contextVariables)
|
return simulateConditionExecution(params.code)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { generateRequestId } from '@/lib/core/utils/request'
|
|
||||||
import { executeInIsolatedVM } from '@/lib/execution/isolated-vm'
|
|
||||||
import { createLogger } from '@/lib/logs/console/logger'
|
import { createLogger } from '@/lib/logs/console/logger'
|
||||||
import type { BlockOutput } from '@/blocks/types'
|
import type { BlockOutput } from '@/blocks/types'
|
||||||
import { BlockType, CONDITION, DEFAULTS, EDGE } from '@/executor/constants'
|
import { BlockType, CONDITION, DEFAULTS, EDGE } from '@/executor/constants'
|
||||||
import type { BlockHandler, ExecutionContext } from '@/executor/types'
|
import type { BlockHandler, ExecutionContext } from '@/executor/types'
|
||||||
import type { SerializedBlock } from '@/serializer/types'
|
import type { SerializedBlock } from '@/serializer/types'
|
||||||
|
import { executeTool } from '@/tools'
|
||||||
|
|
||||||
const logger = createLogger('ConditionBlockHandler')
|
const logger = createLogger('ConditionBlockHandler')
|
||||||
|
|
||||||
@@ -39,32 +38,38 @@ export async function evaluateConditionExpression(
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const requestId = generateRequestId()
|
const contextSetup = `const context = ${JSON.stringify(evalContext)};`
|
||||||
|
const code = `${contextSetup}\nreturn Boolean(${resolvedConditionValue})`
|
||||||
|
|
||||||
const code = `return Boolean(${resolvedConditionValue})`
|
const result = await executeTool(
|
||||||
|
'function_execute',
|
||||||
|
{
|
||||||
|
code,
|
||||||
|
timeout: CONDITION_TIMEOUT_MS,
|
||||||
|
envVars: {},
|
||||||
|
_context: {
|
||||||
|
workflowId: ctx.workflowId,
|
||||||
|
workspaceId: ctx.workspaceId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
ctx
|
||||||
|
)
|
||||||
|
|
||||||
const result = await executeInIsolatedVM({
|
if (!result.success) {
|
||||||
code,
|
logger.error(`Failed to evaluate condition: ${result.error}`, {
|
||||||
params: {},
|
|
||||||
envVars: {},
|
|
||||||
contextVariables: { context: evalContext },
|
|
||||||
timeoutMs: CONDITION_TIMEOUT_MS,
|
|
||||||
requestId,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (result.error) {
|
|
||||||
logger.error(`Failed to evaluate condition: ${result.error.message}`, {
|
|
||||||
originalCondition: conditionExpression,
|
originalCondition: conditionExpression,
|
||||||
resolvedCondition: resolvedConditionValue,
|
resolvedCondition: resolvedConditionValue,
|
||||||
evalContext,
|
evalContext,
|
||||||
error: result.error,
|
error: result.error,
|
||||||
})
|
})
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Evaluation error in condition: ${result.error.message}. (Resolved: ${resolvedConditionValue})`
|
`Evaluation error in condition: ${result.error}. (Resolved: ${resolvedConditionValue})`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Boolean(result.result)
|
return Boolean(result.output?.result)
|
||||||
} catch (evalError: any) {
|
} catch (evalError: any) {
|
||||||
logger.error(`Failed to evaluate condition: ${evalError.message}`, {
|
logger.error(`Failed to evaluate condition: ${evalError.message}`, {
|
||||||
originalCondition: conditionExpression,
|
originalCondition: conditionExpression,
|
||||||
|
|||||||
Reference in New Issue
Block a user