feat(trigger-docs): new trigger docs, function block rce imports fix (#1462)
* fix(sidebar): draggable cursor on sidebar when switching workflows (#1276) * remove inline css for edge labels * fix remote code execution imports for javascript * add docs for new triggers * fix * fix draggable link --------- Co-authored-by: Waleed Latif <walif6@gmail.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: Adam Gough <77861281+aadamgough@users.noreply.github.com> Co-authored-by: Adam Gough <adamgough@Mac.attlocal.net> Co-authored-by: Siddharth Ganesan <33737564+Sg312@users.noreply.github.com>
@@ -9,13 +9,13 @@ import { Image } from '@/components/ui/image'
|
||||
|
||||
Der Workflow-Block ermöglicht es, andere Workflows als wiederverwendbare Komponenten innerhalb deines aktuellen Workflows auszuführen. Dies ermöglicht modulares Design, Codewiederverwendung und die Erstellung komplexer verschachtelter Workflows, die aus kleineren, fokussierten Workflows zusammengesetzt werden können.
|
||||
|
||||
<div className="flex justify-center">
|
||||
<div className="flex justify-center my-6">
|
||||
<Image
|
||||
src="/static/blocks/workflow.png"
|
||||
alt="Workflow-Block"
|
||||
width={500}
|
||||
height={350}
|
||||
className="my-6"
|
||||
width={400}
|
||||
height={280}
|
||||
className="rounded-xl border border-border shadow-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,169 +1,40 @@
|
||||
---
|
||||
title: Workflow
|
||||
title: Workflow Block
|
||||
description: Run another workflow inside the current flow
|
||||
---
|
||||
|
||||
import { Callout } from 'fumadocs-ui/components/callout'
|
||||
import { Step, Steps } from 'fumadocs-ui/components/steps'
|
||||
import { Tab, Tabs } from 'fumadocs-ui/components/tabs'
|
||||
import { Image } from '@/components/ui/image'
|
||||
|
||||
The Workflow block allows you to execute other workflows as reusable components within your current workflow. This enables modular design, code reuse, and the creation of complex nested workflows that can be composed from smaller, focused workflows.
|
||||
## What It Does
|
||||
|
||||
<div className="flex justify-center">
|
||||
<div className='flex justify-center my-6'>
|
||||
<Image
|
||||
src="/static/blocks/workflow.png"
|
||||
alt="Workflow Block"
|
||||
width={500}
|
||||
height={350}
|
||||
className="my-6"
|
||||
src='/static/blocks/workflow.png'
|
||||
alt='Workflow block configuration'
|
||||
width={400}
|
||||
height={280}
|
||||
className='rounded-xl border border-border shadow-sm'
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Callout type="info">
|
||||
Workflow blocks enable modular design by allowing you to compose complex workflows from smaller, reusable components.
|
||||
Drop a Workflow block when you want to call a child workflow as part of a larger flow. The block runs the latest deployed version of that workflow, waits for it to finish, and then continues with the parent.
|
||||
|
||||
## Configure It
|
||||
|
||||
1. **Pick a workflow** from the dropdown (self-references are blocked to prevent loops).
|
||||
2. **Map inputs**: If the child workflow has an Input Form trigger, you’ll see each field and can connect parent variables. The mapped values are what the child receives.
|
||||
3. **Outputs**: After the child finishes, the block exposes:
|
||||
- `result` – the child workflow’s final response
|
||||
- `success` – whether it ran without errors
|
||||
- `error` – message when the run fails
|
||||
|
||||
## Execution Notes
|
||||
|
||||
- Child workflows run in the same workspace context, so environment variables and tools carry over.
|
||||
- The block uses deployment versioning: any API, schedule, webhook, manual, or chat execution calls the deployed snapshot. Redeploy the child when you change it.
|
||||
- If the child fails, the block raises an error unless you handle it downstream.
|
||||
|
||||
<Callout>
|
||||
Keep child workflows focused. Small, reusable flows make it easier to combine them without creating deep nesting.
|
||||
</Callout>
|
||||
|
||||
## Overview
|
||||
|
||||
The Workflow block serves as a bridge between workflows, enabling you to:
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
<strong>Reuse existing workflows</strong>: Execute previously created workflows as components within new workflows
|
||||
</Step>
|
||||
<Step>
|
||||
<strong>Create modular designs</strong>: Break down complex processes into smaller, manageable workflows
|
||||
</Step>
|
||||
<Step>
|
||||
<strong>Maintain separation of concerns</strong>: Keep different business logic isolated in separate workflows
|
||||
</Step>
|
||||
<Step>
|
||||
<strong>Enable team collaboration</strong>: Share and reuse workflows across different projects and team members
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## How It Works
|
||||
|
||||
The Workflow block:
|
||||
|
||||
1. Takes a reference to another workflow in your workspace
|
||||
2. Passes input data from the current workflow to the child workflow (available via start.input)
|
||||
3. Executes the child workflow in an isolated context
|
||||
4. Returns the result back to the parent workflow for further processing
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Workflow Selection
|
||||
|
||||
Choose which workflow to execute from a dropdown list of available workflows in your workspace. The list includes:
|
||||
|
||||
- All workflows you have access to in the current workspace
|
||||
- Workflows shared with you by other team members
|
||||
- Both enabled and disabled workflows (though only enabled workflows can be executed)
|
||||
|
||||
|
||||
### Execution Context
|
||||
|
||||
The child workflow executes with:
|
||||
|
||||
- Its own isolated execution context
|
||||
- Access to the same workspace resources (API keys, environment variables)
|
||||
- Proper workspace membership and permission checks
|
||||
- Nested tracespan in the execution log
|
||||
|
||||
<Callout type="warning">
|
||||
**Cycle Detection**: The system automatically detects and prevents circular dependencies between workflows to avoid infinite loops.
|
||||
</Callout>
|
||||
|
||||
## Inputs and Outputs
|
||||
|
||||
<Tabs items={['Configuration', 'Variables', 'Results']}>
|
||||
<Tab>
|
||||
<ul className="list-disc space-y-2 pl-6">
|
||||
<li>
|
||||
<strong>Workflow Selection</strong>: Choose which workflow to execute
|
||||
</li>
|
||||
<li>
|
||||
<strong>Input Data</strong>: Variable or block reference to pass to child workflow
|
||||
</li>
|
||||
<li>
|
||||
<strong>Execution Context</strong>: Isolated environment with workspace resources
|
||||
</li>
|
||||
</ul>
|
||||
</Tab>
|
||||
<Tab>
|
||||
<ul className="list-disc space-y-2 pl-6">
|
||||
<li>
|
||||
<strong>workflow.success</strong>: Boolean indicating completion status
|
||||
</li>
|
||||
<li>
|
||||
<strong>workflow.childWorkflowName</strong>: Name of executed child workflow
|
||||
</li>
|
||||
<li>
|
||||
<strong>workflow.result</strong>: Result returned by the child workflow
|
||||
</li>
|
||||
<li>
|
||||
<strong>workflow.error</strong>: Error details if workflow failed
|
||||
</li>
|
||||
</ul>
|
||||
</Tab>
|
||||
<Tab>
|
||||
<ul className="list-disc space-y-2 pl-6">
|
||||
<li>
|
||||
<strong>Workflow Response</strong>: Primary output from child workflow
|
||||
</li>
|
||||
<li>
|
||||
<strong>Execution Status</strong>: Success status and error information
|
||||
</li>
|
||||
<li>
|
||||
<strong>Access</strong>: Available in blocks after the workflow
|
||||
</li>
|
||||
</ul>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Example Use Cases
|
||||
|
||||
### Modular Customer Onboarding
|
||||
|
||||
<div className="mb-4 rounded-md border p-4">
|
||||
<h4 className="font-medium">Scenario: Break down complex onboarding into reusable components</h4>
|
||||
<ol className="list-decimal pl-5 text-sm">
|
||||
<li>Main workflow receives customer data</li>
|
||||
<li>Workflow block executes validation workflow</li>
|
||||
<li>Workflow block executes account setup workflow</li>
|
||||
<li>Workflow block executes welcome email workflow</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
### Microservice Architecture
|
||||
|
||||
<div className="mb-4 rounded-md border p-4">
|
||||
<h4 className="font-medium">Scenario: Create independent service workflows</h4>
|
||||
<ol className="list-decimal pl-5 text-sm">
|
||||
<li>Payment processing workflow handles transactions</li>
|
||||
<li>Inventory management workflow updates stock</li>
|
||||
<li>Notification workflow sends confirmations</li>
|
||||
<li>Main workflow orchestrates all services</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
### Conditional Processing
|
||||
|
||||
<div className="mb-4 rounded-md border p-4">
|
||||
<h4 className="font-medium">Scenario: Execute different workflows based on conditions</h4>
|
||||
<ol className="list-decimal pl-5 text-sm">
|
||||
<li>Condition block evaluates user type</li>
|
||||
<li>Enterprise users → Complex approval workflow</li>
|
||||
<li>Standard users → Simple approval workflow</li>
|
||||
<li>Free users → Basic processing workflow</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Keep workflows focused**: Design child workflows to handle specific, well-defined tasks with clear inputs and outputs
|
||||
- **Minimize nesting depth**: Avoid deeply nested workflow hierarchies for better maintainability and performance
|
||||
- **Handle errors gracefully**: Implement proper error handling for child workflow failures and provide fallback mechanisms
|
||||
- **Test independently**: Ensure child workflows can be tested and validated independently from parent workflows
|
||||
- **Use semantic naming**: Give workflows descriptive names that clearly indicate their purpose and functionality
|
||||
|
||||
@@ -4,6 +4,7 @@ title: Execution
|
||||
|
||||
import { Callout } from 'fumadocs-ui/components/callout'
|
||||
import { Card, Cards } from 'fumadocs-ui/components/card'
|
||||
import { Image } from '@/components/ui/image'
|
||||
|
||||
Sim's execution engine brings your workflows to life by processing blocks in the correct order, managing data flow, and handling errors gracefully, so you can understand exactly how workflows are executed in Sim.
|
||||
|
||||
@@ -88,6 +89,22 @@ Chat deployment creates a conversational interface for your workflow:
|
||||
|
||||
Each deployment method passes data to your workflow's starter block, beginning the execution flow.
|
||||
|
||||
## Deployment Snapshots
|
||||
|
||||
All public entry points—API, Chat, Schedule, Webhook, and Manual runs—execute the workflow’s active deployment snapshot. Publish a new deployment whenever you change the canvas so every trigger uses the updated version.
|
||||
|
||||
<div className='flex justify-center my-6'>
|
||||
<Image
|
||||
src='/static/execution/deployment-versions-light.png'
|
||||
alt='Deployment versions table'
|
||||
width={500}
|
||||
height={280}
|
||||
className='rounded-xl border border-border shadow-sm'
|
||||
/>
|
||||
</div>
|
||||
|
||||
The Deploy modal keeps a full version history—inspect any snapshot, compare it against your draft, and promote or roll back with one click when you need to restore a prior release.
|
||||
|
||||
## Programmatic Execution
|
||||
|
||||
Execute workflows from your applications using our official SDKs:
|
||||
|
||||
60
apps/docs/content/docs/en/triggers/api.mdx
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
title: API Trigger
|
||||
description: Start a workflow from an authenticated HTTP request
|
||||
---
|
||||
|
||||
import { Callout } from 'fumadocs-ui/components/callout'
|
||||
import { Image } from '@/components/ui/image'
|
||||
|
||||
## Overview
|
||||
|
||||
The API trigger exposes your workflow as a secure HTTP endpoint. Send JSON data to the endpoint and your workflow processes it immediately. API calls always execute against your latest deployment.
|
||||
|
||||
## Configure Input Format
|
||||
|
||||
<div className='flex justify-center my-6'>
|
||||
<Image
|
||||
src='/static/triggers/api-trigger-light.png'
|
||||
alt='API trigger input format'
|
||||
width={400}
|
||||
height={250}
|
||||
className='rounded-xl border border-border shadow-sm'
|
||||
/>
|
||||
</div>
|
||||
|
||||
Add an **Input Format** field for each parameter. Runtime output keys mirror the schema and are also available under `<api.input>`.
|
||||
|
||||
```yaml
|
||||
- type: string
|
||||
name: userId
|
||||
value: demo-user # optional manual test value
|
||||
- type: number
|
||||
name: maxTokens
|
||||
```
|
||||
|
||||
Manual runs in the editor use the `value` column so you can test without sending a request. During execution the resolver populates both `<api.userId>` and `<api.input.userId>`.
|
||||
|
||||
## Request Example
|
||||
|
||||
```bash
|
||||
curl -X POST \
|
||||
https://sim.ai/api/workflows/WORKFLOW_ID/execute \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'X-API-Key: YOUR_KEY' \
|
||||
-d '{"userId":"demo-user","maxTokens":1024}'
|
||||
```
|
||||
|
||||
Successful responses return the serialized execution result from the Executor. Errors surface validation, auth, or workflow failures.
|
||||
|
||||
## Output Reference
|
||||
|
||||
| Reference | Description |
|
||||
|-----------|-------------|
|
||||
| `<api.field>` | Field defined in the Input Format |
|
||||
| `<api.input>` | Entire structured request body |
|
||||
|
||||
If no Input Format is defined, the executor exposes the raw JSON at `<api.input>` only.
|
||||
|
||||
<Callout type="warning">
|
||||
A workflow can contain only one API Trigger. Publish a new deployment after changes so the endpoint stays up to date.
|
||||
</Callout>
|
||||
43
apps/docs/content/docs/en/triggers/chat.mdx
Normal file
@@ -0,0 +1,43 @@
|
||||
---
|
||||
title: Chat Trigger
|
||||
description: Start a workflow from a chat deployment
|
||||
---
|
||||
|
||||
import { Callout } from 'fumadocs-ui/components/callout'
|
||||
import { Image } from '@/components/ui/image'
|
||||
|
||||
## Overview
|
||||
|
||||
The Chat trigger creates a conversational interface for your workflow. Deploy your workflow as a chat and users can interact with it through a shareable URL. Each message starts a new workflow execution using your latest deployment.
|
||||
|
||||
## Runtime Outputs
|
||||
|
||||
<div className='flex justify-center my-6'>
|
||||
<Image
|
||||
src='/static/triggers/chat-trigger-light.png'
|
||||
alt='Chat deployment conversation'
|
||||
width={400}
|
||||
height={250}
|
||||
className='rounded-xl border border-border shadow-sm'
|
||||
/>
|
||||
</div>
|
||||
|
||||
The trigger writes three fields that downstream blocks can reference:
|
||||
|
||||
| Reference | Description |
|
||||
|-----------|-------------|
|
||||
| `<chat.input>` | Latest user message |
|
||||
| `<chat.conversationId>` | Conversation thread ID |
|
||||
| `<chat.files>` | Optional uploaded files |
|
||||
|
||||
Files include `name`, `mimeType`, and a signed download `url`.
|
||||
|
||||
## Usage Notes
|
||||
|
||||
1. Add one Chat Trigger block per workflow.
|
||||
2. Deploy the workflow in chat mode.
|
||||
3. Share the deployment link—every reply reuses the conversation ID so the workflow can keep context.
|
||||
|
||||
<Callout type="info">
|
||||
The builder blocks multiple Chat Trigger blocks in the same workflow.
|
||||
</Callout>
|
||||
52
apps/docs/content/docs/en/triggers/index.mdx
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
title: Triggers
|
||||
description: Core ways to start Sim workflows
|
||||
---
|
||||
|
||||
import { Card, Cards } from 'fumadocs-ui/components/card'
|
||||
|
||||
## Core Triggers
|
||||
|
||||
Pick one trigger per workflow to define how it starts:
|
||||
|
||||
<Cards>
|
||||
<Card title="API" href="/triggers/api">
|
||||
HTTP endpoint that maps JSON bodies into workflow inputs
|
||||
</Card>
|
||||
<Card title="Chat" href="/triggers/chat">
|
||||
Deployed chat interface with streaming responses
|
||||
</Card>
|
||||
<Card title="Input Form" href="/triggers/input-form">
|
||||
Typed manual input used in editor runs and child workflows
|
||||
</Card>
|
||||
<Card title="Manual" href="/triggers/manual">
|
||||
On-demand runs with no additional data
|
||||
</Card>
|
||||
<Card title="Schedule" href="/triggers/schedule">
|
||||
Cron or interval based execution
|
||||
</Card>
|
||||
<Card title="Webhook" href="/triggers/webhook">
|
||||
Receive external webhook payloads
|
||||
</Card>
|
||||
</Cards>
|
||||
|
||||
## Quick Comparison
|
||||
|
||||
| Trigger | Start condition |
|
||||
|---------|-----------------|
|
||||
| **API** | Authenticated HTTP POST |
|
||||
| **Chat** | Chat deployment message |
|
||||
| **Input Form** | On manual submit in editor or parent workflow |
|
||||
| **Manual** | Run button in editor |
|
||||
| **Schedule** | Timer managed in schedule modal |
|
||||
| **Webhook** | On inbound HTTP request |
|
||||
|
||||
## Using Triggers
|
||||
|
||||
1. Drop the trigger block in the start slot.
|
||||
2. Configure any required schema or auth.
|
||||
3. Connect the block to the rest of the workflow.
|
||||
|
||||
> Deployments power every trigger. Update the workflow, redeploy, and all trigger entry points pick up the new snapshot. Learn more in [Execution → Deployment Snapshots](/execution).
|
||||
|
||||
Legacy Starter blocks remain for existing flows but no longer appear in new builds.
|
||||
52
apps/docs/content/docs/en/triggers/input-form.mdx
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
title: Input Form Trigger
|
||||
description: Manual trigger with a structured input schema
|
||||
---
|
||||
|
||||
import { Callout } from 'fumadocs-ui/components/callout'
|
||||
import { Image } from '@/components/ui/image'
|
||||
|
||||
## Overview
|
||||
|
||||
Use an Input Form trigger when a workflow should start from the editor with typed fields. The run panel shows exactly the fields you define, so the workflow always receives clean data.
|
||||
|
||||
## What You Define
|
||||
|
||||
Add fields in the Input Format builder (text, number, boolean, JSON, etc.). For each field:
|
||||
|
||||
- The value appears as `<blockName.field>` in the workflow.
|
||||
- The full payload is mirrored at `<blockName.input>` for convenience.
|
||||
|
||||
If you leave the form empty, the trigger has no outputs.
|
||||
|
||||
## Manual Runs
|
||||
|
||||
<div className='flex justify-center my-6'>
|
||||
<Image
|
||||
src='/static/triggers/input-form-panel-light.png'
|
||||
alt='Input form run panel'
|
||||
width={400}
|
||||
height={250}
|
||||
className='rounded-xl border border-border shadow-sm'
|
||||
/>
|
||||
</div>
|
||||
|
||||
When you press Run in the editor, the panel renders the form. Submitted values feed directly into the trigger output, so downstream blocks can reference them without extra parsing. Numbers are cast to numbers, booleans become true/false, and JSON fields are parsed before the workflow sees them.
|
||||
|
||||
## Child Workflows
|
||||
|
||||
<div className='flex justify-center my-6'>
|
||||
<Image
|
||||
src='/static/triggers/workflow-input-mapping-light.png'
|
||||
alt='Workflow input mapping'
|
||||
width={400}
|
||||
height={250}
|
||||
className='rounded-xl border border-border shadow-sm'
|
||||
/>
|
||||
</div>
|
||||
|
||||
Input Form triggers also power the Workflow block. When you embed a child workflow, the mapping step shows the child form fields so you can connect variables from the parent. Whatever you map becomes the child workflow’s Input Form submission.
|
||||
|
||||
<Callout>
|
||||
Need a quick run button with no fields? Drop a Manual Trigger. Choose Input Form when you want validation and predictable structure.
|
||||
</Callout>
|
||||
41
apps/docs/content/docs/en/triggers/manual.mdx
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
title: Manual Trigger
|
||||
description: Run a workflow on demand without inputs
|
||||
---
|
||||
|
||||
import { Callout } from 'fumadocs-ui/components/callout'
|
||||
import { Image } from '@/components/ui/image'
|
||||
|
||||
## Overview
|
||||
|
||||
The Manual trigger adds a simple Run button to the top of your workflow. Use it when you want to execute the workflow immediately without collecting extra data.
|
||||
|
||||
## How It Works
|
||||
|
||||
<div className='flex justify-center my-6'>
|
||||
<Image
|
||||
src='/static/triggers/manual-run-light.png'
|
||||
alt='Manual trigger run button'
|
||||
width={400}
|
||||
height={250}
|
||||
className='rounded-xl border border-border shadow-sm'
|
||||
/>
|
||||
</div>
|
||||
|
||||
- Launches the workflow using the active deployment snapshot
|
||||
- Sends no payload—downstream blocks only see what they already have configured
|
||||
- Perfect for quick sanity checks, smoke tests, or flows that only rely on internal variables
|
||||
|
||||
## When to Use
|
||||
|
||||
- Kick off a workflow after publishing a new deployment to confirm everything still works
|
||||
- Run maintenance jobs that don’t require external input
|
||||
- Trigger child workflows that read state or environment variables only
|
||||
|
||||
## Compared to Input Form
|
||||
|
||||
Need structured values or type validation at runtime? Switch to an Input Form trigger instead—the run panel will collect those fields before the workflow starts.
|
||||
|
||||
<Callout>
|
||||
Manual trigger runs don’t override your deployment history. Update and redeploy whenever canvas changes need to go live.
|
||||
</Callout>
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Starter
|
||||
title: Starter (Deprecated)
|
||||
---
|
||||
|
||||
import { Callout } from 'fumadocs-ui/components/callout'
|
||||
@@ -7,6 +7,10 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'
|
||||
import { Image } from '@/components/ui/image'
|
||||
import { Video } from '@/components/ui/video'
|
||||
|
||||
<Callout type="warning">
|
||||
The Starter block has been deprecated and replaced with more specialized Core Triggers. Please see the [Core Triggers documentation](/triggers) for the new API, Chat, Input Form, Manual, Schedule, and Webhook triggers.
|
||||
</Callout>
|
||||
|
||||
The Starter block allows you to manually initiate workflow execution with input parameters, offering two input modes: structured parameters or conversational chat.
|
||||
|
||||
<div className="flex justify-center">
|
||||
|
||||
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 22 KiB |
BIN
apps/docs/public/static/execution/deployment-versions-light.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
apps/docs/public/static/triggers/api-trigger-light.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
apps/docs/public/static/triggers/chat-trigger-light.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
apps/docs/public/static/triggers/deployment-preview-light.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
apps/docs/public/static/triggers/input-form-panel-light.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
apps/docs/public/static/triggers/manual-run-light.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 38 KiB |
@@ -39,6 +39,89 @@ function createSecureFetch(requestId: string) {
|
||||
const E2B_JS_WRAPPER_LINES = 3 // Lines before user code: ';(async () => {', ' try {', ' const __sim_result = await (async () => {'
|
||||
const E2B_PYTHON_WRAPPER_LINES = 1 // Lines before user code: 'def __sim_main__():'
|
||||
|
||||
type TypeScriptModule = typeof import('typescript')
|
||||
|
||||
let typescriptModulePromise: Promise<TypeScriptModule> | null = null
|
||||
|
||||
async function loadTypeScriptModule(): Promise<TypeScriptModule> {
|
||||
if (!typescriptModulePromise) {
|
||||
typescriptModulePromise = import('typescript').then((mod) => {
|
||||
const tsModule = (mod?.default ?? mod) as TypeScriptModule
|
||||
return tsModule
|
||||
})
|
||||
}
|
||||
|
||||
return typescriptModulePromise
|
||||
}
|
||||
|
||||
async function extractJavaScriptImports(
|
||||
code: string
|
||||
): Promise<{ imports: string; remainingCode: string; importLineCount: number }> {
|
||||
try {
|
||||
const tsModule = await loadTypeScriptModule()
|
||||
|
||||
const sourceFile = tsModule.createSourceFile(
|
||||
'user-code.js',
|
||||
code,
|
||||
tsModule.ScriptTarget.Latest,
|
||||
true,
|
||||
tsModule.ScriptKind.JS
|
||||
)
|
||||
|
||||
const importSegments: Array<{ text: string; start: number; end: number }> = []
|
||||
|
||||
sourceFile.statements.forEach((statement) => {
|
||||
if (
|
||||
tsModule.isImportDeclaration(statement) ||
|
||||
tsModule.isImportEqualsDeclaration(statement)
|
||||
) {
|
||||
importSegments.push({
|
||||
text: statement.getFullText(sourceFile).trim(),
|
||||
start: statement.getFullStart(),
|
||||
end: statement.getEnd(),
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if (importSegments.length === 0) {
|
||||
return { imports: '', remainingCode: code, importLineCount: 0 }
|
||||
}
|
||||
|
||||
importSegments.sort((a, b) => a.start - b.start)
|
||||
|
||||
const imports = importSegments.map((segment) => segment.text).join('\n')
|
||||
|
||||
let cursor = 0
|
||||
const parts: string[] = []
|
||||
let importLineCount = 0
|
||||
|
||||
for (const segment of importSegments) {
|
||||
if (segment.start > cursor) {
|
||||
parts.push(code.slice(cursor, segment.start))
|
||||
}
|
||||
|
||||
const removedSegment = code.slice(segment.start, segment.end)
|
||||
importLineCount += removedSegment.split('\n').length - 1
|
||||
|
||||
const newlinePlaceholder = removedSegment.replace(/[^\n]/g, '')
|
||||
parts.push(newlinePlaceholder)
|
||||
|
||||
cursor = segment.end
|
||||
}
|
||||
|
||||
if (cursor < code.length) {
|
||||
parts.push(code.slice(cursor))
|
||||
}
|
||||
|
||||
const remainingCode = parts.join('')
|
||||
|
||||
return { imports, remainingCode, importLineCount: Math.max(importLineCount, 0) }
|
||||
} catch (error) {
|
||||
logger.error('Failed to extract JavaScript imports', { error })
|
||||
return { imports: '', remainingCode: code, importLineCount: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enhanced error information interface
|
||||
*/
|
||||
@@ -624,6 +707,15 @@ export async function POST(req: NextRequest) {
|
||||
if (lang === CodeLanguage.JavaScript) {
|
||||
// Track prologue lines for error adjustment
|
||||
let prologueLineCount = 0
|
||||
|
||||
const { imports, remainingCode } = await extractJavaScriptImports(resolvedCode)
|
||||
|
||||
const importSection: string = imports ? `${imports}\n` : ''
|
||||
const importLineCount = imports ? imports.split('\n').length : 0
|
||||
|
||||
const codeBody = remainingCode
|
||||
resolvedCode = importSection ? `${imports}\n\n${codeBody}` : codeBody
|
||||
|
||||
prologue += `const params = JSON.parse(${JSON.stringify(JSON.stringify(executionParams))});\n`
|
||||
prologueLineCount++
|
||||
prologue += `const environmentVariables = JSON.parse(${JSON.stringify(JSON.stringify(envVars))});\n`
|
||||
@@ -632,11 +724,12 @@ export async function POST(req: NextRequest) {
|
||||
prologue += `const ${k} = JSON.parse(${JSON.stringify(JSON.stringify(v))});\n`
|
||||
prologueLineCount++
|
||||
}
|
||||
|
||||
const wrapped = [
|
||||
';(async () => {',
|
||||
' try {',
|
||||
' const __sim_result = await (async () => {',
|
||||
` ${resolvedCode.split('\n').join('\n ')}`,
|
||||
` ${codeBody.split('\n').join('\n ')}`,
|
||||
' })();',
|
||||
" console.log('__SIM_RESULT__=' + JSON.stringify(__sim_result));",
|
||||
' } catch (error) {',
|
||||
@@ -645,7 +738,7 @@ export async function POST(req: NextRequest) {
|
||||
' }',
|
||||
'})();',
|
||||
].join('\n')
|
||||
const codeForE2B = prologue + wrapped + epilogue
|
||||
const codeForE2B = importSection + prologue + wrapped + epilogue
|
||||
|
||||
const execStart = Date.now()
|
||||
const {
|
||||
@@ -674,7 +767,7 @@ export async function POST(req: NextRequest) {
|
||||
e2bStdout,
|
||||
lang,
|
||||
resolvedCode,
|
||||
prologueLineCount
|
||||
prologueLineCount + importLineCount
|
||||
)
|
||||
return NextResponse.json(
|
||||
{
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
z-index: 0 !important;
|
||||
}
|
||||
|
||||
.workflow-container .react-flow__edge-labels {
|
||||
z-index: 60 !important;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
LANDING LOOP ANIMATION
|
||||
========================================================================== */
|
||||
|
||||
@@ -924,7 +924,7 @@ const WorkflowContent = React.memo(() => {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No existing children: connect from the container's start handle
|
||||
// No existing children: connect from the container's start handle to the moved node
|
||||
const containerNode = getNodes().find((n) => n.id === containerInfo.loopId)
|
||||
const startSourceHandle =
|
||||
(containerNode?.data as any)?.kind === 'loop'
|
||||
@@ -1863,12 +1863,6 @@ const WorkflowContent = React.memo(() => {
|
||||
return (
|
||||
<div className='flex h-screen w-full flex-col overflow-hidden'>
|
||||
<div className='relative h-full w-full flex-1 transition-all duration-200'>
|
||||
<style jsx global>{`
|
||||
/* Ensure edge labels (e.g., delete X) render above group/subflow nodes */
|
||||
.react-flow__edge-labels {
|
||||
z-index: 60 !important;
|
||||
}
|
||||
`}</style>
|
||||
<div className='fixed top-0 right-0 z-10'>
|
||||
<Panel />
|
||||
</div>
|
||||
|
||||
@@ -128,7 +128,7 @@ export function WorkflowItem({
|
||||
}
|
||||
|
||||
const handleClick = (e: React.MouseEvent) => {
|
||||
if (dragStartedRef.current || isEditing) {
|
||||
if (isDragging || isEditing) {
|
||||
e.preventDefault()
|
||||
return
|
||||
}
|
||||
@@ -193,6 +193,7 @@ export function WorkflowItem({
|
||||
href={`/workspace/${workspaceId}/w/${workflow.id}`}
|
||||
className='flex min-w-0 flex-1 items-center'
|
||||
onClick={handleClick}
|
||||
draggable={false}
|
||||
>
|
||||
<div
|
||||
className='mr-2 flex h-[14px] w-[14px] flex-shrink-0 items-center justify-center overflow-hidden'
|
||||
|
||||