Skip to content

Commit d3d83c4

Browse files
committed
make source code for func blocks dispay resolved code instead
1 parent 2eecb5e commit d3d83c4

5 files changed

Lines changed: 75 additions & 17 deletions

File tree

apps/sim/executor/execution/block-executor.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import { isJSONString } from '@/executor/utils/json'
4747
import { filterOutputForLog } from '@/executor/utils/output-filter'
4848
import {
4949
FUNCTION_BLOCK_CONTEXT_VARS_KEY,
50+
FUNCTION_BLOCK_DISPLAY_CODE_KEY,
5051
type VariableResolver,
5152
} from '@/executor/variables/resolver'
5253
import type { SerializedBlock } from '@/serializer/types'
@@ -126,7 +127,13 @@ export class BlockExecutor {
126127
displayInputs,
127128
contextVariables,
128129
} = this.resolver.resolveInputsForFunctionBlock(ctx, node.id, block.config.params, block)
129-
resolvedInputs = { ...fnInputs, [FUNCTION_BLOCK_CONTEXT_VARS_KEY]: contextVariables }
130+
resolvedInputs = {
131+
...fnInputs,
132+
[FUNCTION_BLOCK_CONTEXT_VARS_KEY]: contextVariables,
133+
...(displayInputs.code !== undefined
134+
? { [FUNCTION_BLOCK_DISPLAY_CODE_KEY]: displayInputs.code }
135+
: {}),
136+
}
130137
inputsForLog = displayInputs
131138
} else {
132139
resolvedInputs = this.resolver.resolveInputs(ctx, node.id, block.config.params, block)
@@ -446,7 +453,8 @@ export class BlockExecutor {
446453
if (
447454
SYSTEM_SUBBLOCK_IDS.includes(key) ||
448455
key === 'triggerMode' ||
449-
key === FUNCTION_BLOCK_CONTEXT_VARS_KEY
456+
key === FUNCTION_BLOCK_CONTEXT_VARS_KEY ||
457+
key === FUNCTION_BLOCK_DISPLAY_CODE_KEY
450458
) {
451459
continue
452460
}

apps/sim/executor/handlers/function/function-handler.test.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import { DEFAULT_EXECUTION_TIMEOUT_MS } from '@/lib/execution/constants'
33
import { BlockType } from '@/executor/constants'
44
import { FunctionBlockHandler } from '@/executor/handlers/function/function-handler'
55
import type { ExecutionContext } from '@/executor/types'
6-
import { FUNCTION_BLOCK_CONTEXT_VARS_KEY } from '@/executor/variables/resolver'
6+
import {
7+
FUNCTION_BLOCK_CONTEXT_VARS_KEY,
8+
FUNCTION_BLOCK_DISPLAY_CODE_KEY,
9+
} from '@/executor/variables/resolver'
710
import type { SerializedBlock } from '@/serializer/types'
811
import { executeTool } from '@/tools'
912

@@ -196,19 +199,20 @@ describe('FunctionBlockHandler', () => {
196199
)
197200
})
198201

199-
it('should pass original function code for error display after reference resolution', async () => {
202+
it('should pass display-resolved function code for error display', async () => {
200203
mockBlock.config.params = { code: 'retur <start.reqerror>' }
201204

202205
await handler.execute(mockContext, mockBlock, {
203206
code: 'retur globalThis["__blockRef_0"]',
207+
[FUNCTION_BLOCK_DISPLAY_CODE_KEY]: 'retur "value"',
204208
[FUNCTION_BLOCK_CONTEXT_VARS_KEY]: { __blockRef_0: 'value' },
205209
})
206210

207211
expect(mockExecuteTool).toHaveBeenCalledWith(
208212
'function_execute',
209213
expect.objectContaining({
210214
code: 'retur globalThis["__blockRef_0"]',
211-
sourceCode: 'retur <start.reqerror>',
215+
sourceCode: 'retur "value"',
212216
}),
213217
false,
214218
mockContext

apps/sim/executor/handlers/function/function-handler.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ import { DEFAULT_CODE_LANGUAGE } from '@/lib/execution/languages'
88
import { BlockType } from '@/executor/constants'
99
import type { BlockHandler, ExecutionContext } from '@/executor/types'
1010
import { collectBlockData } from '@/executor/utils/block-data'
11-
import { FUNCTION_BLOCK_CONTEXT_VARS_KEY } from '@/executor/variables/resolver'
11+
import {
12+
FUNCTION_BLOCK_CONTEXT_VARS_KEY,
13+
FUNCTION_BLOCK_DISPLAY_CODE_KEY,
14+
} from '@/executor/variables/resolver'
1215
import type { SerializedBlock } from '@/serializer/types'
1316
import { executeTool } from '@/tools'
1417

@@ -42,9 +45,9 @@ export class FunctionBlockHandler implements BlockHandler {
4245
inputs: Record<string, any>
4346
): Promise<any> {
4447
const codeContent = readCodeContent(inputs.code) ?? inputs.code
45-
const sourceCode = readCodeContent(
46-
(block.config?.params as Record<string, unknown> | undefined)?.code
47-
)
48+
const sourceCode =
49+
readCodeContent(inputs[FUNCTION_BLOCK_DISPLAY_CODE_KEY]) ??
50+
readCodeContent((block.config?.params as Record<string, unknown> | undefined)?.code)
4851

4952
const { blockData, blockNameMapping, blockOutputSchemas } = collectBlockData(ctx)
5053

apps/sim/executor/variables/resolver.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ describe('VariableResolver function block inputs', () => {
8080
)
8181

8282
expect(result.resolvedInputs.code).toBe('return globalThis["__blockRef_0"]')
83-
expect(result.displayInputs.code).toBe('return <Producer.result>')
83+
expect(result.displayInputs.code).toBe('return "hello world"')
8484
expect(result.contextVariables).toEqual({ __blockRef_0: 'hello world' })
8585
})
8686

@@ -95,7 +95,7 @@ describe('VariableResolver function block inputs', () => {
9595
)
9696

9797
expect(result.resolvedInputs.code).toBe('return globals()["__blockRef_0"]')
98-
expect(result.displayInputs.code).toBe('return <Producer.result>')
98+
expect(result.displayInputs.code).toBe('return "hello world"')
9999
expect(result.contextVariables).toEqual({ __blockRef_0: 'hello world' })
100100
})
101101

@@ -112,7 +112,9 @@ describe('VariableResolver function block inputs', () => {
112112
expect(result.resolvedInputs.code).toBe(
113113
'a = globals()["__blockRef_0"]\nb = globals()["__blockRef_1"]\nreturn b'
114114
)
115-
expect(result.displayInputs.code).toBe('a = <Producer.items>\nb = <Producer.items>\nreturn b')
115+
expect(result.displayInputs.code).toBe(
116+
'a = json.loads("[\\"a\\",\\"b\\"]")\nb = json.loads("[\\"a\\",\\"b\\"]")\nreturn b'
117+
)
116118
expect(result.contextVariables).toEqual({
117119
__blockRef_0: ['a', 'b'],
118120
__blockRef_1: ['a', 'b'],
@@ -132,9 +134,7 @@ describe('VariableResolver function block inputs', () => {
132134
expect(result.resolvedInputs.code).toBe(
133135
`echo "\${__blockRef_0}"suffix && echo "\${__blockRef_1}"`
134136
)
135-
expect(result.displayInputs.code).toBe(
136-
'echo <Producer.result>suffix && echo "<Producer.result>"'
137-
)
137+
expect(result.displayInputs.code).toBe('echo "hello world"suffix && echo "hello world"')
138138
expect(result.contextVariables).toEqual({
139139
__blockRef_0: 'hello world',
140140
__blockRef_1: 'hello world',
@@ -154,7 +154,7 @@ describe('VariableResolver function block inputs', () => {
154154
expect(result.resolvedInputs.code).toBe(
155155
`# don't confuse quote tracking\necho "\${__blockRef_0}"`
156156
)
157-
expect(result.displayInputs.code).toBe("# don't confuse quote tracking\necho <Producer.result>")
157+
expect(result.displayInputs.code).toBe('# don\'t confuse quote tracking\necho "hello world"')
158158
expect(result.contextVariables).toEqual({ __blockRef_0: 'hello world' })
159159
})
160160
})

apps/sim/executor/variables/resolver.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import type { SerializedBlock, SerializedWorkflow } from '@/serializer/types'
1818

1919
/** Key used to carry pre-resolved context variables through the inputs map. */
2020
export const FUNCTION_BLOCK_CONTEXT_VARS_KEY = '_runtimeContextVars'
21+
/** Key used to carry display-resolved code through the function execution path. */
22+
export const FUNCTION_BLOCK_DISPLAY_CODE_KEY = '_runtimeDisplayCode'
2123

2224
const logger = createLogger('VariableResolver')
2325

@@ -292,7 +294,12 @@ export class VariableResolver {
292294
index,
293295
effectiveValue
294296
)
295-
displayResult += match
297+
displayResult += this.formatDisplayValueForCodeContext(
298+
effectiveValue,
299+
language,
300+
template,
301+
index
302+
)
296303
return replacement
297304
}
298305

@@ -354,6 +361,42 @@ export class VariableResolver {
354361
return `globalThis[${JSON.stringify(varName)}]`
355362
}
356363

364+
private formatDisplayValueForCodeContext(
365+
value: unknown,
366+
language: string | undefined,
367+
template: string,
368+
matchIndex: number
369+
): string {
370+
if (language === 'shell') {
371+
return this.formatShellDisplayValue(value, template, matchIndex)
372+
}
373+
374+
return this.blockResolver.formatValueForBlock(value, BlockType.FUNCTION, language)
375+
}
376+
377+
private formatShellDisplayValue(value: unknown, template: string, matchIndex: number): string {
378+
const text = this.stringifyShellDisplayValue(value)
379+
const quoteContext = this.getShellQuoteContext(template, matchIndex)
380+
if (quoteContext === 'double') {
381+
return text.replace(/["\\$`]/g, '\\$&')
382+
}
383+
384+
return `"${text.replace(/["\\$`]/g, '\\$&')}"`
385+
}
386+
387+
private stringifyShellDisplayValue(value: unknown): string {
388+
if (value === null || value === undefined) {
389+
return ''
390+
}
391+
if (typeof value === 'string') {
392+
return value
393+
}
394+
if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
395+
return String(value)
396+
}
397+
return JSON.stringify(value)
398+
}
399+
357400
private formatShellContextVariableReference(
358401
varName: string,
359402
template: string,

0 commit comments

Comments
 (0)