Skip to content

Commit ad83676

Browse files
committed
feat(docs): fill documentation gaps across platform features
1 parent 20cc018 commit ad83676

File tree

14 files changed

+1020
-35
lines changed

14 files changed

+1020
-35
lines changed

apps/docs/content/docs/en/blocks/function.mdx

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
title: Function
33
---
44

5+
import { Callout } from 'fumadocs-ui/components/callout'
6+
import { Tab, Tabs } from 'fumadocs-ui/components/tabs'
57
import { Image } from '@/components/ui/image'
68
import { FAQ } from '@/components/ui/faq'
79

8-
The Function block executes custom JavaScript or TypeScript code in your workflows. Transform data, perform calculations, or implement custom logic.
10+
The Function block executes custom JavaScript, TypeScript, or Python code in your workflows. Transform data, perform calculations, or implement custom logic.
911

1012
<div className="flex justify-center">
1113
<Image
@@ -41,6 +43,8 @@ Input → Function (Validate & Sanitize) → API (Save to Database)
4143

4244
### Example: Loyalty Score Calculator
4345

46+
<Tabs items={['JavaScript', 'Python']}>
47+
<Tab value="JavaScript">
4448
```javascript title="loyalty-calculator.js"
4549
// Process customer data and calculate loyalty score
4650
const { purchaseHistory, accountAge, supportTickets } = <agent>;
@@ -64,6 +68,112 @@ return {
6468
metrics: { spendScore, frequencyScore, supportScore }
6569
};
6670
```
71+
</Tab>
72+
<Tab value="Python">
73+
```python title="loyalty-calculator.py"
74+
import json
75+
76+
# Reference outputs from other blocks using angle bracket syntax
77+
data = json.loads('<agent>')
78+
purchase_history = data["purchaseHistory"]
79+
account_age = data["accountAge"]
80+
support_tickets = data["supportTickets"]
81+
82+
# Calculate metrics
83+
total_spent = sum(p["amount"] for p in purchase_history)
84+
purchase_frequency = len(purchase_history) / (account_age / 365)
85+
ticket_ratio = support_tickets["resolved"] / support_tickets["total"]
86+
87+
# Calculate loyalty score (0-100)
88+
spend_score = min(total_spent / 1000 * 30, 30)
89+
frequency_score = min(purchase_frequency * 20, 40)
90+
support_score = ticket_ratio * 30
91+
92+
loyalty_score = round(spend_score + frequency_score + support_score)
93+
94+
tier = "Platinum" if loyalty_score >= 80 else "Gold" if loyalty_score >= 60 else "Silver"
95+
96+
result = {
97+
"customer": data["name"],
98+
"loyaltyScore": loyalty_score,
99+
"loyaltyTier": tier,
100+
"metrics": {
101+
"spendScore": spend_score,
102+
"frequencyScore": frequency_score,
103+
"supportScore": support_score
104+
}
105+
}
106+
print(json.dumps(result))
107+
```
108+
</Tab>
109+
</Tabs>
110+
111+
## Python Support
112+
113+
The Function block supports Python as an alternative to JavaScript. Python code runs in a secure [E2B](https://e2b.dev) cloud sandbox.
114+
115+
{/* TODO: Screenshot of the Function block with Python language selected */}
116+
117+
### Enabling Python
118+
119+
Select **Python** from the language dropdown in the Function block. Python execution requires E2B to be enabled on your Sim instance.
120+
121+
<Callout type="warn">
122+
If you don't see Python as an option in the language dropdown, E2B is not enabled. This only applies to self-hosted instances — E2B is enabled by default on sim.ai.
123+
</Callout>
124+
125+
<Callout type="info">
126+
Python code always runs in the E2B sandbox, even for simple scripts without imports. This ensures a secure, isolated execution environment.
127+
</Callout>
128+
129+
### Returning Results
130+
131+
In Python, print your result as JSON to stdout. The Function block captures stdout and makes it available via `<function.result>`:
132+
133+
```python title="example.py"
134+
import json
135+
136+
data = {"status": "processed", "count": 42}
137+
print(json.dumps(data))
138+
```
139+
140+
### Available Libraries
141+
142+
The E2B sandbox includes the Python standard library (`json`, `re`, `datetime`, `math`, `os`, `collections`, etc.) and common packages like `matplotlib` for visualization. Charts generated with matplotlib are captured as images automatically.
143+
144+
<Callout type="info">
145+
The exact set of pre-installed packages depends on the E2B sandbox configuration. If a package you need isn't available, consider calling an external API from your code instead.
146+
</Callout>
147+
148+
### Matplotlib Charts
149+
150+
When your Python code generates matplotlib figures, they are automatically captured and returned as base64-encoded PNG images in the output:
151+
152+
```python title="chart.py"
153+
import matplotlib.pyplot as plt
154+
import json
155+
156+
data = json.loads('<api.data>')
157+
158+
plt.figure(figsize=(10, 6))
159+
plt.bar(data["labels"], data["values"])
160+
plt.title("Monthly Revenue")
161+
plt.xlabel("Month")
162+
plt.ylabel("Revenue ($)")
163+
plt.savefig("chart.png")
164+
plt.show()
165+
```
166+
167+
{/* TODO: Screenshot of Python code execution output in the logs panel */}
168+
169+
### JavaScript vs. Python
170+
171+
| | JavaScript | Python |
172+
|--|-----------|--------|
173+
| **Execution** | Local VM (fast) or E2B sandbox (with imports) | Always E2B sandbox |
174+
| **Returning results** | `return { ... }` | `print(json.dumps({ ... }))` |
175+
| **HTTP requests** | `fetch()` built-in | `requests` or `httpx` |
176+
| **Best for** | Quick transforms, JSON manipulation | Data science, charting, complex math |
67177

68178
## Best Practices
69179

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
---
2+
title: API Deployment
3+
---
4+
5+
import { Callout } from 'fumadocs-ui/components/callout'
6+
import { Tab, Tabs } from 'fumadocs-ui/components/tabs'
7+
import { FAQ } from '@/components/ui/faq'
8+
9+
Deploy your workflow as a REST API endpoint that applications can call directly. Supports synchronous, streaming, and asynchronous execution modes.
10+
11+
## Deploying a Workflow
12+
13+
1. Open your workflow and click **Deploy**
14+
2. The **General** tab shows deployment status — click **Deploy** to publish
15+
3. Switch to the **API** tab to see your endpoint URL and code examples
16+
17+
{/* TODO: Screenshot of the API tab in the deploy modal showing code examples */}
18+
19+
Once deployed, your workflow is available at:
20+
21+
```
22+
POST https://sim.ai/api/workflows/{workflow-id}/execute
23+
```
24+
25+
<Callout type="info">
26+
API executions run against the active deployment snapshot. After making canvas changes, click **Update** in the Deploy modal to publish a new version.
27+
</Callout>
28+
29+
## Authentication
30+
31+
By default, API endpoints require an API key in the `x-api-key` header. You can generate keys in **Settings → Sim Keys**.
32+
33+
```bash
34+
curl -X POST https://sim.ai/api/workflows/{workflow-id}/execute \
35+
-H "Content-Type: application/json" \
36+
-H "x-api-key: $SIM_API_KEY" \
37+
-d '{ "input": "Hello" }'
38+
```
39+
40+
### Public APIs
41+
42+
You can make an API endpoint public so it doesn't require authentication. This is useful for public-facing integrations or webhooks from external services.
43+
44+
{/* TODO: Screenshot of the public/private API toggle */}
45+
46+
<Callout type="warn">
47+
Public endpoints can be called by anyone with the URL. Only use this for workflows that don't expose sensitive data or perform sensitive actions.
48+
</Callout>
49+
50+
## Execution Modes
51+
52+
The API tab in the Deploy modal shows code examples for each mode in **cURL**, **Python**, **JavaScript**, and **TypeScript**.
53+
54+
### Synchronous
55+
56+
The default mode. Send a request and wait for the complete response:
57+
58+
<Tabs items={['cURL', 'Python']}>
59+
<Tab value="cURL">
60+
```bash
61+
curl -X POST https://sim.ai/api/workflows/{workflow-id}/execute \
62+
-H "Content-Type: application/json" \
63+
-H "x-api-key: $SIM_API_KEY" \
64+
-d '{ "input": "Summarize this article" }'
65+
```
66+
</Tab>
67+
<Tab value="Python">
68+
```python
69+
import requests
70+
import os
71+
72+
response = requests.post(
73+
"https://sim.ai/api/workflows/{workflow-id}/execute",
74+
headers={
75+
"Content-Type": "application/json",
76+
"x-api-key": os.environ.get("SIM_API_KEY")
77+
},
78+
json={"input": "Summarize this article"}
79+
)
80+
81+
print(response.json())
82+
```
83+
</Tab>
84+
</Tabs>
85+
86+
### Streaming
87+
88+
Stream the response as it's generated. Choose which block outputs to stream using the output selector in the API tab.
89+
90+
{/* TODO: Screenshot of the streaming output selector dropdown */}
91+
92+
<Tabs items={['cURL', 'Python']}>
93+
<Tab value="cURL">
94+
```bash
95+
curl -X POST https://sim.ai/api/workflows/{workflow-id}/execute \
96+
-H "Content-Type: application/json" \
97+
-H "x-api-key: $SIM_API_KEY" \
98+
-d '{
99+
"input": "Write a long essay",
100+
"stream": true,
101+
"selectedOutputs": ["agent_1.content"]
102+
}'
103+
```
104+
</Tab>
105+
<Tab value="Python">
106+
```python
107+
import requests
108+
import os
109+
110+
response = requests.post(
111+
"https://sim.ai/api/workflows/{workflow-id}/execute",
112+
headers={
113+
"Content-Type": "application/json",
114+
"x-api-key": os.environ.get("SIM_API_KEY")
115+
},
116+
json={
117+
"input": "Write a long essay",
118+
"stream": True,
119+
"selectedOutputs": ["agent_1.content"]
120+
},
121+
stream=True
122+
)
123+
124+
for line in response.iter_lines():
125+
if line:
126+
print(line.decode())
127+
```
128+
</Tab>
129+
</Tabs>
130+
131+
### Asynchronous
132+
133+
For long-running workflows, use async mode to start a job and poll for results. Set the `X-Execution-Mode: async` header to submit the workflow and receive a job ID immediately without waiting for completion.
134+
135+
<Tabs items={['Start Job', 'Check Status']}>
136+
<Tab value="Start Job">
137+
```bash
138+
curl -X POST https://sim.ai/api/workflows/{workflow-id}/execute \
139+
-H "Content-Type: application/json" \
140+
-H "x-api-key: $SIM_API_KEY" \
141+
-H "X-Execution-Mode: async" \
142+
-d '{ "input": "Process this large dataset" }'
143+
```
144+
145+
**Response** (HTTP 202):
146+
```json
147+
{
148+
"success": true,
149+
"async": true,
150+
"jobId": "run_abc123",
151+
"executionId": "exec_xyz",
152+
"message": "Workflow execution queued",
153+
"statusUrl": "https://sim.ai/api/jobs/run_abc123"
154+
}
155+
```
156+
</Tab>
157+
<Tab value="Check Status">
158+
```bash
159+
curl https://sim.ai/api/jobs/{jobId} \
160+
-H "x-api-key: $SIM_API_KEY"
161+
```
162+
163+
**Response** (while processing):
164+
```json
165+
{
166+
"success": true,
167+
"taskId": "run_abc123",
168+
"status": "processing",
169+
"metadata": {
170+
"createdAt": "2025-09-10T12:00:00.000Z",
171+
"startedAt": "2025-09-10T12:00:01.000Z"
172+
},
173+
"estimatedDuration": 300000
174+
}
175+
```
176+
177+
**Response** (when completed):
178+
```json
179+
{
180+
"success": true,
181+
"taskId": "run_abc123",
182+
"status": "completed",
183+
"metadata": {
184+
"createdAt": "2025-09-10T12:00:00.000Z",
185+
"startedAt": "2025-09-10T12:00:01.000Z",
186+
"completedAt": "2025-09-10T12:00:05.000Z",
187+
"duration": 4000
188+
},
189+
"output": { "result": "..." }
190+
}
191+
```
192+
</Tab>
193+
</Tabs>
194+
195+
#### Job Status Values
196+
197+
| Status | Description |
198+
|--------|-------------|
199+
| `queued` | Job is waiting to be picked up |
200+
| `processing` | Workflow is actively executing |
201+
| `completed` | Finished successfully — `output` field contains the result |
202+
| `failed` | Execution failed — `error` field contains the message |
203+
204+
Poll the `statusUrl` returned in the initial response until the status is `completed` or `failed`.
205+
206+
#### Execution Time Limits
207+
208+
Async jobs can run significantly longer than synchronous requests:
209+
210+
| Plan | Sync Limit | Async Limit |
211+
|------|-----------|-------------|
212+
| **Community** | 5 minutes | 90 minutes |
213+
| **Pro / Max / Team / Enterprise** | 50 minutes | 90 minutes |
214+
215+
If a job exceeds its time limit, it is automatically marked as `failed`.
216+
217+
#### Job Retention
218+
219+
Completed and failed job results are retained for **24 hours**. After that, the job data is cleaned up and the status endpoint returns `404`. If you need results longer, retrieve and store them on your end after completion.
220+
221+
#### Capacity Limits
222+
223+
If the execution queue is full, the API returns a `503` response with a `Retry-After` header:
224+
225+
```json
226+
{
227+
"error": "Service temporarily at capacity",
228+
"retryAfterSeconds": 10
229+
}
230+
```
231+
232+
Wait the indicated number of seconds before retrying.
233+
234+
<Callout type="info">
235+
Async mode always runs against the deployed version. It does not support draft state, block overrides, or partial execution options like `runFromBlock` or `stopAfterBlockId`.
236+
</Callout>
237+
238+
## API Key Management
239+
240+
Generate and manage API keys in **Settings → Sim Keys**:
241+
242+
- **Create** new keys for different applications or environments
243+
- **Revoke** keys that are no longer needed
244+
- Keys are scoped to your workspace
245+
246+
<Callout type="info">
247+
The API tab in the Deploy modal shows a masked version of your key in the code examples. Copy the examples directly — they include the correct authentication header.
248+
</Callout>
249+
250+
## Rate Limits
251+
252+
API calls are subject to rate limits based on your plan. Rate limit details are returned in response headers (`X-RateLimit-*`) and in the response body. Use async mode for high-volume or long-running workloads.
253+
254+
For detailed rate limit information and the logs/webhooks API, see [External API](/execution/api).
255+
256+
<FAQ items={[
257+
{ question: "What's the difference between the API tab and the External API docs?", answer: "The API tab in the Deploy modal is for deploying your workflow as a callable endpoint. The External API documentation covers the logs query API and webhook notifications for monitoring executions." },
258+
{ question: "Can I deploy the same workflow as both an API and a chat?", answer: "Yes. A workflow can be deployed as an API, chat, MCP tool, and more simultaneously. Each deployment type runs against the same active snapshot." },
259+
{ question: "How do I choose between sync, streaming, and async?", answer: "Use sync for quick workflows (under a few seconds). Use streaming when you want to show progressive output to users. Use async for long-running workflows where you don't want to hold a connection open." },
260+
{ question: "How long are async job results available?", answer: "Completed and failed job results are retained for 24 hours. After that, the status endpoint returns 404. Retrieve and store results on your end if you need them longer." },
261+
{ question: "What happens if my API key is compromised?", answer: "Revoke the key immediately in Settings → Sim Keys and create a new one. Revoked keys stop working instantly." },
262+
]} />

0 commit comments

Comments
 (0)