Skip to content

improvement(resolver): use context variables for block outputs in function block code#4223

Merged
icecrasher321 merged 37 commits intosimstudioai:stagingfrom
octo-patch:fix/issue-4195-function-block-context-vars
May 6, 2026
Merged

improvement(resolver): use context variables for block outputs in function block code#4223
icecrasher321 merged 37 commits intosimstudioai:stagingfrom
octo-patch:fix/issue-4195-function-block-context-vars

Conversation

@octo-patch
Copy link
Copy Markdown
Contributor

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 the code string. For large outputs this causes two issues:

  1. The code string exceeds the terminal console's 50,000-character display limit, so users see truncated code in the block's input panel.
  2. When the serialized inputs exceed 256 KB the terminal replaces the entire input with { __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:

  1. resolveCodeWithContextVars() replaces <BlockA.result> with __blockRef_0 in the code string and stores the actual value in contextVariables.__blockRef_0.
  2. The function handler passes these contextVariables to the API route.
  3. The API route merges them with its own context variables and passes everything to executeInIsolatedVM.
  4. The isolated VM worker sets global.__blockRef_0 = <value> before running user code, so the reference resolves correctly.

What is NOT changed:

  • Loop/parallel iteration variables (e.g. <loop.currentItem>) are still inlined as literals — the API route has no visibility into runtime loop state.
  • Execution results are unchanged; only the code string representation is smaller.
  • blockData is still passed for backward compatibility and custom tool use cases.

Files Changed

File Change
executor/variables/resolver.ts New resolveInputsForFunctionBlock() method + resolveCodeWithContextVars() helper
executor/execution/block-executor.ts Use new resolution path for function blocks; filter internal key from logs
executor/handlers/function/function-handler.ts Extract context vars from inputs and pass to executeTool
tools/function/types.ts Add contextVariables field to CodeExecutionInput
tools/function/execute.ts Include contextVariables in the request body
app/api/function/execute/route.ts Accept and merge pre-resolved context variables

waleedlatif1 and others added 29 commits April 3, 2026 23:30
…ership workflow edits via sockets, ui improvements
…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
…endar triggers, docs updates, integrations/models pages improvements
…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
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
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Apr 18, 2026 3:11am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 18, 2026

PR Summary

Medium Risk
Changes how function-block references are resolved and injected at runtime across JavaScript/Python/Shell, which could affect execution correctness and quoting/serialization edge cases. Scope spans resolver, executor, tool contract, and execution API.

Overview
Function blocks no longer inline referenced block outputs directly into the code string; they are now replaced with generated runtime variables (e.g. __blockRef_0) and the actual values are passed separately as contextVariables for VM/global injection.

This introduces VariableResolver.resolveInputsForFunctionBlock() and threads the new _runtimeContextVars payload from BlockExecutorFunctionBlockHandlerfunction_execute tool → /api/function/execute, where the API merges pre-resolved context with its own variable resolution and injects them for isolated VM/E2B runs (including shell env var serialization improvements and JS E2B using globalThis[...]). Tests were added/updated to validate the new behavior and log sanitization now omits the internal context-vars key.

Reviewed by Cursor Bugbot for commit a6be984. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 18, 2026

Greptile Summary

This PR fixes a display issue where large block output values inlined into function block code strings caused truncation in the UI. Instead of embedding serialized JavaScript literals for block output references, the executor now replaces them with named context variables (__blockRef_N) and passes the actual values as VM globals — matching how workflow variables and env vars already work.

  • resolver.ts: New resolveInputsForFunctionBlock() and resolveCodeWithContextVars() methods replace <Block.field> references in the code field with __blockRef_N identifiers (or $__blockRef_N for shell), collecting values in an accumulator that flows through to the isolated VM.
  • block-executor.ts / function-handler.ts: The new resolution path is wired in for function blocks, with the context variable map piggybacking through inputs under the internal key _runtimeContextVars (filtered from logs).
  • route.ts: Accepts and merges pre-resolved contextVariables from the executor, and a new serializeForShellEnv helper properly JSON-serializes complex values for E2B shell env vars instead of calling String() on them.

Confidence Score: 5/5

Safe to merge — the change is additive and purely affects how block output values are carried through to the VM, not execution semantics.

The extraction-to-context-variable approach is mechanically sound: deduplication within a single code item prevents duplicate payload entries, the internal _runtimeContextVars key is consistently filtered from logs, the shell path correctly uses $__blockRef_N syntax and serializes values via serializeForShellEnv, and the merge order in the route (pre-resolved vars take precedence) matches the design intent.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/executor/variables/resolver.ts Core of the fix — adds resolveInputsForFunctionBlock() and resolveCodeWithContextVars() that extract block output references into a context variable accumulator instead of inlining them; deduplication within a single code item works correctly via blockRefByMatch.
apps/sim/executor/execution/block-executor.ts Routes function blocks through the new resolution path and correctly filters _runtimeContextVars from the sanitized log inputs.
apps/sim/executor/handlers/function/function-handler.ts Extracts contextVariables from the inputs map and forwards them to executeTool; clean and minimal change.
apps/sim/app/api/function/execute/route.ts Accepts preResolvedContextVariables, merges them into contextVariables (with pre-resolved taking precedence), and adds serializeForShellEnv to properly handle complex objects in shell env vars instead of String().
apps/sim/tools/function/execute.ts Trivial one-liner: passes contextVariables through to the request body.
apps/sim/tools/function/types.ts Adds optional contextVariables field to CodeExecutionInput; clean after the previously noted duplicate interface was resolved.

Sequence Diagram

sequenceDiagram
    participant BE as BlockExecutor
    participant VR as VariableResolver
    participant FH as FunctionBlockHandler
    participant RT as /api/function/execute

    BE->>VR: resolveInputsForFunctionBlock()
    Note over VR: replaces block refs with __blockRef_N identifiers
    VR-->>BE: resolvedInputs + contextVariables map
    BE->>BE: attach contextVariables under _runtimeContextVars
    BE->>FH: execute(ctx, block, resolvedInputs)
    FH->>FH: extract contextVariables from inputs
    FH->>RT: POST code with __blockRef_N + contextVariables
    Note over RT: merge pre-resolved vars with route-resolved vars
    RT-->>FH: execution result
    FH-->>BE: output
Loading

Reviews (2): Last reviewed commit: "fix: shell block references and complex ..." | Re-trigger Greptile

Comment thread apps/sim/tools/function/types.ts Outdated
Comment thread apps/sim/executor/variables/resolver.ts Outdated
Comment thread apps/sim/app/api/function/execute/route.ts
Comment thread apps/sim/tools/function/types.ts Outdated
@icecrasher321 icecrasher321 changed the base branch from main to staging April 18, 2026 03:48
@gitguardian
Copy link
Copy Markdown

gitguardian Bot commented Apr 18, 2026

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

Since your pull request originates from a forked repository, GitGuardian is not able to associate the secrets uncovered with secret incidents on your GitGuardian dashboard.
Skipping this check run and merging your pull request will create secret incidents on your GitGuardian dashboard.

🔎 Detected hardcoded secret in your pull request
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
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. 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


🦉 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.

@icecrasher321
Copy link
Copy Markdown
Collaborator

@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.

@icecrasher321 icecrasher321 self-assigned this Apr 18, 2026
- 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)
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 18, 2026

Someone is attempting to deploy a commit to the Sim Team on Vercel.

A member of the Team first needs to authorize it.

@octo-patch
Copy link
Copy Markdown
Contributor Author

@icecrasher321 Thanks for the review. I have pushed a follow-up commit addressing the bot comments:

  • Cursor (medium): Shell language loses pre-resolved context variables. Fixed. The Shell branch in apps/sim/app/api/function/execute/route.ts now seeds contextVariables from preResolvedContextVariables so the executor-supplied __blockRef_N values are exposed as shell env vars and referenced block outputs are not undefined at runtime.

  • Cursor (low) + Greptile (P2): Duplicate CodeExecutionOutput interface in apps/sim/tools/function/types.ts. Fixed. Removed the duplicate declaration.

  • Greptile (P2): Repeated context variable allocation for duplicate block references. Addressed. resolveCodeWithContextVars now deduplicates by the matched reference string so identical <BlockA.result> occurrences share a single __blockRef_N slot and the payload value is not duplicated across the wire.

  • GitGuardian: Generic high-entropy secret in apps/sim/providers/utils.test.ts. Not relevant to this PR. The flagged commit a54dcbe is not part of this PR; the diff for this branch does not touch apps/sim/providers/utils.test.ts. The match looks like a pre-existing test fixture.

Existing tests still pass: app/api/function/execute/route.test.ts (30/30) and executor/variables/ suite (196/196).

Comment thread apps/sim/executor/variables/resolver.ts Outdated
@icecrasher321
Copy link
Copy Markdown
Collaborator

icecrasher321 commented May 6, 2026

Hey @octo-patch -- could you address the continued comments. If the comment is inaccurate -- please leave a reply to the comment. We usually go until it's good to go and then perform a human code review.

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>
@octo-patch
Copy link
Copy Markdown
Contributor Author

@icecrasher321 Thanks for the bump. I've pushed a follow-up commit (19787e1) addressing the remaining Cursor Bugbot finding:

  • Cursor (medium): Shell block references break — missing $ prefix and wrong serialization. Fixed.
    • resolveCodeWithContextVars in apps/sim/executor/variables/resolver.ts now emits $__blockRef_N instead of the bare identifier when the function block language is shell, so the generated script dereferences the env var injected by the executor (echo __blockRef_0 previously printed the literal name; it now prints the value). JS/Python continue to receive the bare identifier and read it as a global injected into the VM.
    • The Shell branch in apps/sim/app/api/function/execute/route.ts no longer calls String(v) directly when building shellEnvs. A new serializeForShellEnv helper passes strings through as-is, coerces primitives, and JSON-stringifies objects/arrays so $VAR yields a useful representation instead of [object Object]. null/undefined map to "" to match POSIX env semantics.

Existing tests still pass: app/api/function/execute/route.test.ts (30/30) and executor/variables/ (196/196). Let me know if you'd like a dedicated shell-language test added before the human review pass.

@icecrasher321
Copy link
Copy Markdown
Collaborator

bugbot run

@icecrasher321
Copy link
Copy Markdown
Collaborator

@greptile

Comment thread apps/sim/executor/variables/resolver.ts
@icecrasher321
Copy link
Copy Markdown
Collaborator

bugbot run

@icecrasher321 icecrasher321 changed the title fix: use context variables for block outputs in function block code improvement(resolver): use context variables for block outputs in function block code May 6, 2026
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit a6be984. Configure here.

@icecrasher321 icecrasher321 merged commit 7b6aa72 into simstudioai:staging May 6, 2026
10 of 12 checks passed
waleedlatif1 added a commit that referenced this pull request May 7, 2026
…ction block code (#4223)

* v0.6.29: login improvements, posthog telemetry (#4026)

* feat(posthog): Add tracking on mothership abort (#4023)

Co-authored-by: Theodore Li <theo@sim.ai>

* fix(login): fix captcha headers for manual login  (#4025)

* fix(signup): fix turnstile key loading

* fix(login): fix captcha header passing

* Catch user already exists, remove login form captcha

* fix: use context variables for block outputs in function block code

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 #4195

* fix: address Cursor and Greptile bot review comments

- 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)

* 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>

* fix lint

* review pass

* ignore shell comments

* update contract

* fix tests

---------

Co-authored-by: Waleed <walif6@gmail.com>
Co-authored-by: Theodore Li <theodoreqili@gmail.com>
Co-authored-by: Siddharth Ganesan <33737564+Sg312@users.noreply.github.com>
Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com>
Co-authored-by: octo-patch <octo-patch@github.com>
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Function block truncating input and returning bad result

5 participants