fix: use context variables for block outputs in function block code#4223
fix: use context variables for block outputs in function block code#4223octo-patch wants to merge 30 commits intosimstudioai:stagingfrom
Conversation
…ership workflow edits via sockets, ui improvements
…ng improvements, posthog, secrets mutations
…ration, signup method feature flags, SSO improvements
* feat(posthog): Add tracking on mothership abort (simstudioai#4023) Co-authored-by: Theodore Li <theo@sim.ai> * fix(login): fix captcha headers for manual login (simstudioai#4025) * fix(signup): fix turnstile key loading * fix(login): fix captcha header passing * Catch user already exists, remove login form captcha
…nts, secrets performance, polling refactors, drag resources in mothership
…y invalidation, HITL docs
…endar triggers, docs updates, integrations/models pages improvements
…ions, jira forms endpoints
…mat, logs performance improvements fix(csp): add missing analytics domains, remove unsafe-eval, fix workspace CSP gap (simstudioai#4179) fix(landing): return 404 for invalid dynamic route slugs (simstudioai#4182) improvement(seo): optimize sitemaps, robots.txt, and core web vitals across sim and docs (simstudioai#4170) fix(gemini): support structured output with tools on Gemini 3 models (simstudioai#4184) feat(brightdata): add Bright Data integration with 8 tools (simstudioai#4183) fix(mothership): fix superagent credentials (simstudioai#4185) fix(logs): close sidebar when selected log disappears from filtered list; cleanup (simstudioai#4186)
v0.6.46: mothership streaming fixes, brightdata integration
…m integration, atlassian triggers
When a function block references another block's output via <BlockA.result>,
the executor previously embedded the full value as a JavaScript literal
directly in the code string. For large outputs (>50 KB), this caused the code
string to exceed the terminal console display limit, making inputs appear
truncated or replaced with { __simTruncated: true } in the UI.
Instead, block output references in function block code are now stored as
named global variables (__blockRef_N) in the isolated VM context. The code
string only contains the compact variable name, keeping it small regardless
of the referenced value size.
Loop/parallel/env/workflow references are still inlined as literals since
the API route has no way to resolve them independently.
The _runtimeContextVars key is filtered from sanitizeInputsForLog so it
does not appear in execution logs or SSE events.
Pre-resolved context variables are merged with any variables produced by
the API route resolveCodeVariables, with executor values taking precedence.
Fixes simstudioai#4195
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview The executor now carries these pre-resolved context vars through block execution (hidden from logs) and the function execution tool/API route accept and merge them (including for shell), injecting them as VM globals/envs at runtime to avoid oversized serialized inputs while preserving execution semantics. Reviewed by Cursor Bugbot for commit 2783606. Bugbot is set up for automated code reviews on this repo. Configure here. |
Greptile SummaryThis PR fixes a display bug where embedding large block outputs as JavaScript literals in function block code caused the inputs panel to appear truncated or replaced with Confidence Score: 5/5Safe to merge — the fix is logically sound, execution results are unchanged, and the only finding is a duplicate dead-code interface declaration. All findings are P2 (style/cleanup). The core logic — replacing block output references with named context variables, passing them through the tool/route pipeline, and injecting them as VM globals — is correct and non-overlapping with the route's own variable naming schemes. apps/sim/tools/function/types.ts — accidental duplicate CodeExecutionOutput interface should be removed before merging to keep the type file clean. Important Files Changed
Sequence DiagramsequenceDiagram
participant Executor as BlockExecutor
participant Resolver as VariableResolver
participant Handler as FunctionBlockHandler
participant Tool as functionExecuteTool
participant Route as /api/function/execute
participant VM as IsolatedVM
Executor->>Resolver: resolveInputsForFunctionBlock(params)
Resolver->>Resolver: resolveCodeWithContextVars(code)
Note over Resolver: replaces BlockA.result ref with __blockRef_0 and stores value
Resolver-->>Executor: resolvedInputs plus contextVariables
Executor->>Handler: execute(inputs)
Handler->>Handler: extract inputs[_runtimeContextVars]
Handler->>Tool: executeTool with code and contextVariables
Tool->>Route: POST with code, contextVariables, blockData
Route->>Route: resolveCodeVariables(code)
Route->>Route: merge codeResolution.contextVariables with preResolvedContextVariables
Route->>VM: executeInIsolatedVM(code, contextVariables)
VM->>VM: global.__blockRef_0 = value
VM-->>Route: result
Reviews (1): Last reviewed commit: "fix: use context variables for block out..." | Re-trigger Greptile |
| export interface CodeExecutionOutput extends ToolResponse { | ||
| output: { | ||
| result: any | ||
| stdout: string | ||
| } | ||
| } |
There was a problem hiding this comment.
Duplicate interface declaration
CodeExecutionOutput is already declared at line 31–36 with an identical shape. TypeScript's declaration merging allows this without a compile error, but the second block is dead code accidentally introduced by this PR. Remove it.
| export interface CodeExecutionOutput extends ToolResponse { | |
| output: { | |
| result: any | |
| stdout: string | |
| } | |
| } |
| if (this.blockResolver.canResolve(match)) { | ||
| // Block output: store in contextVarAccumulator, replace with variable name | ||
| const varName = `__blockRef_${Object.keys(contextVarAccumulator).length}` | ||
| contextVarAccumulator[varName] = effectiveValue | ||
| return varName | ||
| } |
There was a problem hiding this comment.
Repeated context variable allocation for duplicate block references
When the same block reference (e.g. <BlockA.result>) appears more than once in the code template, each occurrence resolves independently and is stored under a new key (__blockRef_0, __blockRef_1, …), duplicating the payload value. Consider deduplicating by keying on the reference string before allocating a new slot. This is not a correctness issue — just a small efficiency improvement worth considering.
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 29606901 | Triggered | Generic High Entropy Secret | a54dcbe | apps/sim/providers/utils.test.ts | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
|
@octo-patch please address the automated PR comments and then I can review this. If they are not relevant, please leave a comment there and mark them as resolved. |
- Pass preResolvedContextVariables through to shellEnvs for Shell language (Cursor: shell loses pre-resolved block refs, executes against undefined vars) - Remove duplicate CodeExecutionOutput interface declaration (Cursor + Greptile: dead duplicate declaration in tools/function/types.ts) - Deduplicate identical block references in resolveCodeWithContextVars so the same <BlockA.result> reused multiple times shares one __blockRef_N slot (Greptile P2: avoid duplicating large payloads across the wire)
|
Someone is attempting to deploy a commit to the Sim Team on Vercel. A member of the Team first needs to authorize it. |
|
@icecrasher321 Thanks for the review. I have pushed a follow-up commit addressing the bot comments:
Existing tests still pass: |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 2783606. Configure here.
| const varName = `__blockRef_${Object.keys(contextVarAccumulator).length}` | ||
| contextVarAccumulator[varName] = effectiveValue | ||
| blockRefByMatch.set(match, varName) | ||
| return varName |
There was a problem hiding this comment.
Shell block references break: missing $ prefix and wrong serialization
Medium Severity
For shell function blocks, resolveCodeWithContextVars replaces <BlockA.result> with bare __blockRef_0, but shell requires $__blockRef_0 to dereference an environment variable. The code runs echo __blockRef_0 and outputs the literal string instead of the value. Additionally, in the route, String(v) on complex objects stored as shell env vars produces [object Object] rather than a JSON representation. Before this PR, values were inlined via formatLiteralForCode, so this is a regression for shell function blocks referencing other block outputs.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 2783606. Configure here.


Problem
When a function block references another block's output via
<BlockA.result>, the executor embeds the full value as a JavaScript literal directly in thecodestring. For large outputs this causes two issues:{ __simTruncated: true }, making it look like the function block received no data.The actual execution was correct, but the misleading display caused users to believe their function block was broken. Closes #4195.
Solution
Block output references in function block code are now resolved to named context variables (
__blockRef_N) instead of inlined JavaScript literals. The resolved values are passed to the isolated VM as global variables, exactly like workflow variables and env vars already are.Execution path after this fix:
resolveCodeWithContextVars()replaces<BlockA.result>with__blockRef_0in the code string and stores the actual value incontextVariables.__blockRef_0.contextVariablesto the API route.executeInIsolatedVM.global.__blockRef_0 = <value>before running user code, so the reference resolves correctly.What is NOT changed:
<loop.currentItem>) are still inlined as literals — the API route has no visibility into runtime loop state.blockDatais still passed for backward compatibility and custom tool use cases.Files Changed
executor/variables/resolver.tsresolveInputsForFunctionBlock()method +resolveCodeWithContextVars()helperexecutor/execution/block-executor.tsexecutor/handlers/function/function-handler.tsexecuteTooltools/function/types.tscontextVariablesfield toCodeExecutionInputtools/function/execute.tscontextVariablesin the request bodyapp/api/function/execute/route.ts