Skip to content

Commit 19787e1

Browse files
octo-patchocto-patch
andcommitted
fix: shell block references and complex env value serialization
Two follow-ups to the function-block context-variable refactor: - resolveCodeWithContextVars now emits `$__blockRef_N` for shell function blocks so the script dereferences the env var injected by the executor. Other languages still receive the bare identifier. - The function-execute route now JSON-stringifies non-primitive values when building shell env vars, replacing the previous `String(v)` call that produced `[object Object]` for objects/arrays. Co-Authored-By: Octopus <liyuan851277048@icloud.com>
1 parent 2783606 commit 19787e1

2 files changed

Lines changed: 30 additions & 5 deletions

File tree

apps/sim/app/api/function/execute/route.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,26 @@ function cleanStdout(stdout: string): string {
586586
return stdout
587587
}
588588

589+
/**
590+
* Serializes a value for use as a shell environment variable. Strings pass through
591+
* unchanged; primitives are coerced via `String`; objects, arrays, and other complex
592+
* values are JSON-stringified so that referencing them via `$VAR` yields a useful
593+
* representation instead of `[object Object]`. `null`/`undefined` become an empty
594+
* string to match POSIX env semantics.
595+
*/
596+
function serializeForShellEnv(value: unknown): string {
597+
if (value === null || value === undefined) return ''
598+
if (typeof value === 'string') return value
599+
if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
600+
return String(value)
601+
}
602+
try {
603+
return JSON.stringify(value) ?? ''
604+
} catch {
605+
return String(value)
606+
}
607+
}
608+
589609
async function maybeExportSandboxFileToWorkspace(args: {
590610
authUserId: string
591611
workflowId?: string
@@ -788,10 +808,10 @@ export async function POST(req: NextRequest) {
788808

789809
const shellEnvs: Record<string, string> = {}
790810
for (const [k, v] of Object.entries(envVars)) {
791-
shellEnvs[k] = String(v)
811+
shellEnvs[k] = serializeForShellEnv(v)
792812
}
793813
for (const [k, v] of Object.entries(contextVariables)) {
794-
shellEnvs[k] = String(v)
814+
shellEnvs[k] = serializeForShellEnv(v)
795815
}
796816

797817
logger.info(`[${requestId}] E2B shell execution`, {

apps/sim/executor/variables/resolver.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ export class VariableResolver {
237237

238238
let replacementError: Error | null = null
239239

240+
const isShell = language === 'shell'
240241
const blockRefByMatch = new Map<string, string>()
241242

242243
let result = replaceValidReferences(template, (match) => {
@@ -254,11 +255,15 @@ export class VariableResolver {
254255

255256
const effectiveValue = resolved === RESOLVED_EMPTY ? null : resolved
256257

257-
// Block output: store in contextVarAccumulator, replace with variable name
258+
// Block output: store in contextVarAccumulator, replace with variable name.
259+
// For shell, emit `$__blockRef_N` so the script dereferences the env var
260+
// injected by the function-execute route; other languages receive the bare
261+
// identifier and read it as a global injected into the VM.
258262
const varName = `__blockRef_${Object.keys(contextVarAccumulator).length}`
259263
contextVarAccumulator[varName] = effectiveValue
260-
blockRefByMatch.set(match, varName)
261-
return varName
264+
const replacement = isShell ? `$${varName}` : varName
265+
blockRefByMatch.set(match, replacement)
266+
return replacement
262267
}
263268

264269
const resolved = this.resolveReference(match, resolutionContext)

0 commit comments

Comments
 (0)