From 7ab2e69c8d9e8016ecbb4dcb8b954753cf75038b Mon Sep 17 00:00:00 2001 From: waleed Date: Thu, 16 Apr 2026 12:21:18 -0700 Subject: [PATCH 1/4] fix(misc): remove duplicate docs page, update clopus 4.7 --- .../content/docs/en/custom-tools/index.mdx | 100 ------------------ apps/docs/content/docs/en/meta.json | 1 - .../content/docs/en/tools/custom-tools.mdx | 11 +- apps/sim/providers/anthropic/core.ts | 5 +- apps/sim/providers/models.ts | 3 +- 5 files changed, 15 insertions(+), 105 deletions(-) delete mode 100644 apps/docs/content/docs/en/custom-tools/index.mdx diff --git a/apps/docs/content/docs/en/custom-tools/index.mdx b/apps/docs/content/docs/en/custom-tools/index.mdx deleted file mode 100644 index b73dd33c768..00000000000 --- a/apps/docs/content/docs/en/custom-tools/index.mdx +++ /dev/null @@ -1,100 +0,0 @@ ---- -title: Custom Tools -description: Extend your agents with your own functions — defined by a schema and executed as JavaScript ---- - -import { Image } from '@/components/ui/image' -import { Callout } from 'fumadocs-ui/components/callout' - -Custom Tools let you define your own functions that agents can call, without needing an external MCP server. You write a JSON schema describing the function and the JavaScript code that runs when the agent invokes it. - -## What Is a Custom Tool? - -A custom tool has three parts: - -| Part | Description | -|------|-------------| -| **Schema** | OpenAI function-calling format — name, description, and parameters. This is what the agent sees when deciding whether to call the tool. | -| **Code** | JavaScript that runs when the tool is called. Parameters come in as variables matching the schema. | -| **Scope** | Custom tools are workspace-scoped and available to every agent in that workspace. | - -Use custom tools when you need tightly-scoped logic that doesn't warrant spinning up a full MCP server — one-off API calls, formatting helpers, internal utilities, etc. - -## Creating a Custom Tool - -1. Navigate to **Settings → Custom Tools** -2. Click **Add** -3. Fill out the **Schema** tab with your function definition - -
- Custom tool schema editor -
- - -Use the **Generate** button to have AI draft the schema from a plain-English description. - - -4. Write your implementation in the **Code** tab -5. Click **Save** - - -You can also create a custom tool directly from an Agent block — click **Add tool… → Create Tool** in the tool dropdown. - - -## Schema Format - -Custom tool schemas follow the OpenAI function-calling spec: - -```json -{ - "type": "function", - "function": { - "name": "get_weather", - "description": "Get the current weather for a city", - "parameters": { - "type": "object", - "properties": { - "city": { - "type": "string", - "description": "The city to get weather for" - } - }, - "required": ["city"] - } - } -} -``` - -The `name` must be lowercase, use underscores, and match what your code expects as input. - -## Using Custom Tools in Agents - -Once created, your tools become available in any Agent block: - -1. Open an **Agent** block -2. In the **Tools** section, click **Add tool…** -3. Under **Custom Tools**, click the tool you want to add -4. The agent can now call the tool the same way it calls MCP tools or built-in tools - -## Custom Tools vs MCP Tools - -| | **Custom Tools** | **MCP Tools** | -|---|---|---| -| **Defined** | Inline — schema + code in Sim | External MCP server | -| **Hosting** | Runs inside Sim | Runs on your server | -| **Best for** | Small, workspace-specific helpers | Shared tools, third-party services, complex integrations | -| **Setup** | One modal | Deploy and register a server | - -## Permission Requirements - -| Action | Required Permission | -|--------|-------------------| -| Create or update custom tools | **Write** or **Admin** | -| Delete custom tools | **Admin** | -| Use custom tools in agents | **Read**, **Write**, or **Admin** | diff --git a/apps/docs/content/docs/en/meta.json b/apps/docs/content/docs/en/meta.json index 53ba23da826..24eb6eba869 100644 --- a/apps/docs/content/docs/en/meta.json +++ b/apps/docs/content/docs/en/meta.json @@ -21,7 +21,6 @@ "variables", "integrations", "credentials", - "custom-tools", "---Platform---", "execution", "permissions", diff --git a/apps/docs/content/docs/en/tools/custom-tools.mdx b/apps/docs/content/docs/en/tools/custom-tools.mdx index 6261af27a80..f29e7adace5 100644 --- a/apps/docs/content/docs/en/tools/custom-tools.mdx +++ b/apps/docs/content/docs/en/tools/custom-tools.mdx @@ -145,13 +145,22 @@ From **Settings → Custom Tools** you can: Deleting a custom tool removes it from all Agent blocks that reference it. Make sure no active workflows depend on the tool before deleting. +## Custom Tools vs MCP Tools + +| | **Custom Tools** | **MCP Tools** | +|---|---|---| +| **Defined** | Inline — schema + code in Sim | External MCP server | +| **Hosting** | Runs inside Sim | Runs on your server | +| **Best for** | Small, workspace-specific helpers | Shared tools, third-party services, complex integrations | +| **Setup** | One modal | Deploy and register a server | + ## Permissions | Action | Required Permission | |--------|-------------------| | View custom tools | **Read**, **Write**, or **Admin** | | Create or edit tools | **Write** or **Admin** | -| Delete tools | **Write** or **Admin** | +| Delete tools | **Admin** | = { updatedAt: '2026-04-16', }, capabilities: { - temperature: { min: 0, max: 1 }, nativeStructuredOutputs: true, maxOutputTokens: 128000, thinking: { - levels: ['low', 'medium', 'high', 'max'], + levels: ['low', 'medium', 'high', 'xhigh', 'max'], default: 'high', }, }, From b6d4c931746c3d784978c944d5f31691c70af359 Mon Sep 17 00:00:00 2001 From: waleed Date: Thu, 16 Apr 2026 12:30:43 -0700 Subject: [PATCH 2/4] fix(docs): consolidate duplicate docs and fix SDK API signatures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove duplicate custom-tools page (custom-tools/index.mdx → tools/custom-tools.mdx is canonical) - Remove comparison table from custom-tools per product preference - Fix permissions inconsistency: delete now requires Admin across all docs - Consolidate sdks/ into api-reference/ (sdks/ directory deleted) - Fix Python SDK docs: correct param is `input`, not `input_data` - Fix TypeScript SDK docs: correct signature is executeWorkflow(id, input, options) not options-object form - Add FAQ sections to both SDK reference pages --- .../content/docs/en/api-reference/python.mdx | 29 +- .../docs/en/api-reference/typescript.mdx | 47 +- apps/docs/content/docs/en/sdks/meta.json | 4 - apps/docs/content/docs/en/sdks/python.mdx | 772 ------------ apps/docs/content/docs/en/sdks/typescript.mdx | 1030 ----------------- .../content/docs/en/tools/custom-tools.mdx | 9 - 6 files changed, 41 insertions(+), 1850 deletions(-) delete mode 100644 apps/docs/content/docs/en/sdks/meta.json delete mode 100644 apps/docs/content/docs/en/sdks/python.mdx delete mode 100644 apps/docs/content/docs/en/sdks/typescript.mdx diff --git a/apps/docs/content/docs/en/api-reference/python.mdx b/apps/docs/content/docs/en/api-reference/python.mdx index 3ab1cdee763..903bac51f1c 100644 --- a/apps/docs/content/docs/en/api-reference/python.mdx +++ b/apps/docs/content/docs/en/api-reference/python.mdx @@ -65,14 +65,14 @@ Execute a workflow with optional input data. ```python result = client.execute_workflow( "workflow-id", - input_data={"message": "Hello, world!"}, + input={"message": "Hello, world!"}, timeout=30.0 # 30 seconds ) ``` **Parameters:** - `workflow_id` (str): The ID of the workflow to execute -- `input_data` (dict, optional): Input data to pass to the workflow +- `input` (dict, optional): Input data to pass to the workflow - `timeout` (float, optional): Timeout in seconds (default: 30.0) - `stream` (bool, optional): Enable streaming responses (default: False) - `selected_outputs` (list[str], optional): Block outputs to stream in `blockName.attribute` format (e.g., `["agent1.content"]`) @@ -144,7 +144,7 @@ Execute a workflow with automatic retry on rate limit errors using exponential b ```python result = client.execute_with_retry( "workflow-id", - input_data={"message": "Hello"}, + input={"message": "Hello"}, timeout=30.0, max_retries=3, # Maximum number of retries initial_delay=1.0, # Initial delay in seconds @@ -155,7 +155,7 @@ result = client.execute_with_retry( **Parameters:** - `workflow_id` (str): The ID of the workflow to execute -- `input_data` (dict, optional): Input data to pass to the workflow +- `input` (dict, optional): Input data to pass to the workflow - `timeout` (float, optional): Timeout in seconds - `stream` (bool, optional): Enable streaming responses - `selected_outputs` (list, optional): Block outputs to stream @@ -359,7 +359,7 @@ def run_workflow(): # Execute the workflow result = client.execute_workflow( "my-workflow-id", - input_data={ + input={ "message": "Process this data", "user_id": "12345" } @@ -488,7 +488,7 @@ def execute_async(): # Start async execution result = client.execute_workflow( "workflow-id", - input_data={"data": "large dataset"}, + input={"data": "large dataset"}, async_execution=True # Execute asynchronously ) @@ -533,7 +533,7 @@ def execute_with_retry_handling(): # Automatically retries on rate limit result = client.execute_with_retry( "workflow-id", - input_data={"message": "Process this"}, + input={"message": "Process this"}, max_retries=5, initial_delay=1.0, max_delay=60.0, @@ -615,7 +615,7 @@ def execute_with_streaming(): # Enable streaming for specific block outputs result = client.execute_workflow( "workflow-id", - input_data={"message": "Count to five"}, + input={"message": "Count to five"}, stream=True, selected_outputs=["agent1.content"] # Use blockName.attribute format ) @@ -758,4 +758,15 @@ Configure the client using environment variables: ## License -Apache-2.0 \ No newline at end of file +Apache-2.0 + +import { FAQ } from '@/components/ui/faq' + + \ No newline at end of file diff --git a/apps/docs/content/docs/en/api-reference/typescript.mdx b/apps/docs/content/docs/en/api-reference/typescript.mdx index 6364384c8b4..476cfb964d4 100644 --- a/apps/docs/content/docs/en/api-reference/typescript.mdx +++ b/apps/docs/content/docs/en/api-reference/typescript.mdx @@ -78,16 +78,15 @@ new SimStudioClient(config: SimStudioConfig) Execute a workflow with optional input data. ```typescript -const result = await client.executeWorkflow('workflow-id', { - input: { message: 'Hello, world!' }, +const result = await client.executeWorkflow('workflow-id', { message: 'Hello, world!' }, { timeout: 30000 // 30 seconds }); ``` **Parameters:** - `workflowId` (string): The ID of the workflow to execute +- `input` (any, optional): Input data to pass to the workflow - `options` (ExecutionOptions, optional): - - `input` (any): Input data to pass to the workflow - `timeout` (number): Timeout in milliseconds (default: 30000) - `stream` (boolean): Enable streaming responses (default: false) - `selectedOutputs` (string[]): Block outputs to stream in `blockName.attribute` format (e.g., `["agent1.content"]`) @@ -158,8 +157,7 @@ if (status.status === 'completed') { Execute a workflow with automatic retry on rate limit errors using exponential backoff. ```typescript -const result = await client.executeWithRetry('workflow-id', { - input: { message: 'Hello' }, +const result = await client.executeWithRetry('workflow-id', { message: 'Hello' }, { timeout: 30000 }, { maxRetries: 3, // Maximum number of retries @@ -171,6 +169,7 @@ const result = await client.executeWithRetry('workflow-id', { **Parameters:** - `workflowId` (string): The ID of the workflow to execute +- `input` (any, optional): Input data to pass to the workflow - `options` (ExecutionOptions, optional): Same as `executeWorkflow()` - `retryOptions` (RetryOptions, optional): - `maxRetries` (number): Maximum number of retries (default: 3) @@ -389,10 +388,8 @@ async function runWorkflow() { // Execute the workflow const result = await client.executeWorkflow('my-workflow-id', { - input: { message: 'Process this data', userId: '12345' - } }); if (result.success) { @@ -508,8 +505,7 @@ app.post('/execute-workflow', async (req, res) => { try { const { workflowId, input } = req.body; - const result = await client.executeWorkflow(workflowId, { - input, + const result = await client.executeWorkflow(workflowId, input, { timeout: 60000 }); @@ -555,8 +551,7 @@ export default async function handler( try { const { workflowId, input } = req.body; - const result = await client.executeWorkflow(workflowId, { - input, + const result = await client.executeWorkflow(workflowId, input, { timeout: 30000 }); @@ -586,9 +581,7 @@ const client = new SimStudioClient({ async function executeClientSideWorkflow() { try { const result = await client.executeWorkflow('workflow-id', { - input: { userInput: 'Hello from browser' - } }); console.log('Workflow result:', result); @@ -642,10 +635,8 @@ Alternatively, you can manually provide files using the URL format: // Include files under the field name from your API trigger's input format const result = await client.executeWorkflow('workflow-id', { - input: { documents: files, // Must match your workflow's "files" field name instructions: 'Analyze these documents' - } }); console.log('Result:', result); @@ -669,10 +660,8 @@ Alternatively, you can manually provide files using the URL format: // Include files under the field name from your API trigger's input format const result = await client.executeWorkflow('workflow-id', { - input: { documents: [file], // Must match your workflow's "files" field name query: 'Summarize this document' - } }); ``` @@ -712,8 +701,7 @@ export function useWorkflow(): UseWorkflowResult { setResult(null); try { - const workflowResult = await client.executeWorkflow(workflowId, { - input, + const workflowResult = await client.executeWorkflow(workflowId, input, { timeout: 30000 }); setResult(workflowResult); @@ -774,8 +762,7 @@ const client = new SimStudioClient({ async function executeAsync() { try { // Start async execution - const result = await client.executeWorkflow('workflow-id', { - input: { data: 'large dataset' }, + const result = await client.executeWorkflow('workflow-id', { data: 'large dataset' }, { async: true // Execute asynchronously }); @@ -823,9 +810,7 @@ const client = new SimStudioClient({ async function executeWithRetryHandling() { try { // Automatically retries on rate limit - const result = await client.executeWithRetry('workflow-id', { - input: { message: 'Process this' } - }, { + const result = await client.executeWithRetry('workflow-id', { message: 'Process this' }, {}, { maxRetries: 5, initialDelay: 1000, maxDelay: 60000, @@ -908,8 +893,7 @@ const client = new SimStudioClient({ async function executeWithStreaming() { try { // Enable streaming for specific block outputs - const result = await client.executeWorkflow('workflow-id', { - input: { message: 'Count to five' }, + const result = await client.executeWorkflow('workflow-id', { message: 'Count to five' }, { stream: true, selectedOutputs: ['agent1.content'] // Use blockName.attribute format }); @@ -1033,3 +1017,14 @@ function StreamingWorkflow() { ## License Apache-2.0 + +import { FAQ } from '@/components/ui/faq' + + diff --git a/apps/docs/content/docs/en/sdks/meta.json b/apps/docs/content/docs/en/sdks/meta.json deleted file mode 100644 index a46a15897f8..00000000000 --- a/apps/docs/content/docs/en/sdks/meta.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "SDKs", - "pages": ["python", "typescript"] -} diff --git a/apps/docs/content/docs/en/sdks/python.mdx b/apps/docs/content/docs/en/sdks/python.mdx deleted file mode 100644 index 903bac51f1c..00000000000 --- a/apps/docs/content/docs/en/sdks/python.mdx +++ /dev/null @@ -1,772 +0,0 @@ ---- -title: Python ---- - -import { Callout } from 'fumadocs-ui/components/callout' -import { Card, Cards } from 'fumadocs-ui/components/card' -import { Step, Steps } from 'fumadocs-ui/components/steps' -import { Tab, Tabs } from 'fumadocs-ui/components/tabs' - -The official Python SDK for Sim allows you to execute workflows programmatically from your Python applications using the official Python SDK. - - - The Python SDK supports Python 3.8+ with async execution support, automatic rate limiting with exponential backoff, and usage tracking. - - -## Installation - -Install the SDK using pip: - -```bash -pip install simstudio-sdk -``` - -## Quick Start - -Here's a simple example to get you started: - -```python -from simstudio import SimStudioClient - -# Initialize the client -client = SimStudioClient( - api_key="your-api-key-here", - base_url="https://sim.ai" # optional, defaults to https://sim.ai -) - -# Execute a workflow -try: - result = client.execute_workflow("workflow-id") - print("Workflow executed successfully:", result) -except Exception as error: - print("Workflow execution failed:", error) -``` - -## API Reference - -### SimStudioClient - -#### Constructor - -```python -SimStudioClient(api_key: str, base_url: str = "https://sim.ai") -``` - -**Parameters:** -- `api_key` (str): Your Sim API key -- `base_url` (str, optional): Base URL for the Sim API - -#### Methods - -##### execute_workflow() - -Execute a workflow with optional input data. - -```python -result = client.execute_workflow( - "workflow-id", - input={"message": "Hello, world!"}, - timeout=30.0 # 30 seconds -) -``` - -**Parameters:** -- `workflow_id` (str): The ID of the workflow to execute -- `input` (dict, optional): Input data to pass to the workflow -- `timeout` (float, optional): Timeout in seconds (default: 30.0) -- `stream` (bool, optional): Enable streaming responses (default: False) -- `selected_outputs` (list[str], optional): Block outputs to stream in `blockName.attribute` format (e.g., `["agent1.content"]`) -- `async_execution` (bool, optional): Execute asynchronously (default: False) - -**Returns:** `WorkflowExecutionResult | AsyncExecutionResult` - -When `async_execution=True`, returns immediately with a task ID for polling. Otherwise, waits for completion. - -##### get_workflow_status() - -Get the status of a workflow (deployment status, etc.). - -```python -status = client.get_workflow_status("workflow-id") -print("Is deployed:", status.is_deployed) -``` - -**Parameters:** -- `workflow_id` (str): The ID of the workflow - -**Returns:** `WorkflowStatus` - -##### validate_workflow() - -Validate that a workflow is ready for execution. - -```python -is_ready = client.validate_workflow("workflow-id") -if is_ready: - # Workflow is deployed and ready - pass -``` - -**Parameters:** -- `workflow_id` (str): The ID of the workflow - -**Returns:** `bool` - -##### get_job_status() - -Get the status of an async job execution. - -```python -status = client.get_job_status("task-id-from-async-execution") -print("Status:", status["status"]) # 'queued', 'processing', 'completed', 'failed' -if status["status"] == "completed": - print("Output:", status["output"]) -``` - -**Parameters:** -- `task_id` (str): The task ID returned from async execution - -**Returns:** `Dict[str, Any]` - -**Response fields:** -- `success` (bool): Whether the request was successful -- `taskId` (str): The task ID -- `status` (str): One of `'queued'`, `'processing'`, `'completed'`, `'failed'`, `'cancelled'` -- `metadata` (dict): Contains `startedAt`, `completedAt`, and `duration` -- `output` (any, optional): The workflow output (when completed) -- `error` (any, optional): Error details (when failed) -- `estimatedDuration` (int, optional): Estimated duration in milliseconds (when processing/queued) - -##### execute_with_retry() - -Execute a workflow with automatic retry on rate limit errors using exponential backoff. - -```python -result = client.execute_with_retry( - "workflow-id", - input={"message": "Hello"}, - timeout=30.0, - max_retries=3, # Maximum number of retries - initial_delay=1.0, # Initial delay in seconds - max_delay=30.0, # Maximum delay in seconds - backoff_multiplier=2.0 # Exponential backoff multiplier -) -``` - -**Parameters:** -- `workflow_id` (str): The ID of the workflow to execute -- `input` (dict, optional): Input data to pass to the workflow -- `timeout` (float, optional): Timeout in seconds -- `stream` (bool, optional): Enable streaming responses -- `selected_outputs` (list, optional): Block outputs to stream -- `async_execution` (bool, optional): Execute asynchronously -- `max_retries` (int, optional): Maximum number of retries (default: 3) -- `initial_delay` (float, optional): Initial delay in seconds (default: 1.0) -- `max_delay` (float, optional): Maximum delay in seconds (default: 30.0) -- `backoff_multiplier` (float, optional): Backoff multiplier (default: 2.0) - -**Returns:** `WorkflowExecutionResult | AsyncExecutionResult` - -The retry logic uses exponential backoff (1s → 2s → 4s → 8s...) with ±25% jitter to prevent thundering herd. If the API provides a `retry-after` header, it will be used instead. - -##### get_rate_limit_info() - -Get the current rate limit information from the last API response. - -```python -rate_limit_info = client.get_rate_limit_info() -if rate_limit_info: - print("Limit:", rate_limit_info.limit) - print("Remaining:", rate_limit_info.remaining) - print("Reset:", datetime.fromtimestamp(rate_limit_info.reset)) -``` - -**Returns:** `RateLimitInfo | None` - -##### get_usage_limits() - -Get current usage limits and quota information for your account. - -```python -limits = client.get_usage_limits() -print("Sync requests remaining:", limits.rate_limit["sync"]["remaining"]) -print("Async requests remaining:", limits.rate_limit["async"]["remaining"]) -print("Current period cost:", limits.usage["currentPeriodCost"]) -print("Plan:", limits.usage["plan"]) -``` - -**Returns:** `UsageLimits` - -**Response structure:** -```python -{ - "success": bool, - "rateLimit": { - "sync": { - "isLimited": bool, - "limit": int, - "remaining": int, - "resetAt": str - }, - "async": { - "isLimited": bool, - "limit": int, - "remaining": int, - "resetAt": str - }, - "authType": str # 'api' or 'manual' - }, - "usage": { - "currentPeriodCost": float, - "limit": float, - "plan": str # e.g., 'free', 'pro' - } -} -``` - -##### set_api_key() - -Update the API key. - -```python -client.set_api_key("new-api-key") -``` - -##### set_base_url() - -Update the base URL. - -```python -client.set_base_url("https://my-custom-domain.com") -``` - -##### close() - -Close the underlying HTTP session. - -```python -client.close() -``` - -## Data Classes - -### WorkflowExecutionResult - -```python -@dataclass -class WorkflowExecutionResult: - success: bool - output: Optional[Any] = None - error: Optional[str] = None - logs: Optional[List[Any]] = None - metadata: Optional[Dict[str, Any]] = None - trace_spans: Optional[List[Any]] = None - total_duration: Optional[float] = None -``` - -### AsyncExecutionResult - -```python -@dataclass -class AsyncExecutionResult: - success: bool - task_id: str - status: str # 'queued' - created_at: str - links: Dict[str, str] # e.g., {"status": "/api/jobs/{taskId}"} -``` - -### WorkflowStatus - -```python -@dataclass -class WorkflowStatus: - is_deployed: bool - deployed_at: Optional[str] = None - needs_redeployment: bool = False -``` - -### RateLimitInfo - -```python -@dataclass -class RateLimitInfo: - limit: int - remaining: int - reset: int - retry_after: Optional[int] = None -``` - -### UsageLimits - -```python -@dataclass -class UsageLimits: - success: bool - rate_limit: Dict[str, Any] - usage: Dict[str, Any] -``` - -### SimStudioError - -```python -class SimStudioError(Exception): - def __init__(self, message: str, code: Optional[str] = None, status: Optional[int] = None): - super().__init__(message) - self.code = code - self.status = status -``` - -**Common error codes:** -- `UNAUTHORIZED`: Invalid API key -- `TIMEOUT`: Request timed out -- `RATE_LIMIT_EXCEEDED`: Rate limit exceeded -- `USAGE_LIMIT_EXCEEDED`: Usage limit exceeded -- `EXECUTION_ERROR`: Workflow execution failed - -## Examples - -### Basic Workflow Execution - - - - Set up the SimStudioClient with your API key. - - - Check if the workflow is deployed and ready for execution. - - - Run the workflow with your input data. - - - Process the execution result and handle any errors. - - - -```python -import os -from simstudio import SimStudioClient - -client = SimStudioClient(api_key=os.getenv("SIM_API_KEY")) - -def run_workflow(): - try: - # Check if workflow is ready - is_ready = client.validate_workflow("my-workflow-id") - if not is_ready: - raise Exception("Workflow is not deployed or ready") - - # Execute the workflow - result = client.execute_workflow( - "my-workflow-id", - input={ - "message": "Process this data", - "user_id": "12345" - } - ) - - if result.success: - print("Output:", result.output) - print("Duration:", result.metadata.get("duration") if result.metadata else None) - else: - print("Workflow failed:", result.error) - - except Exception as error: - print("Error:", error) - -run_workflow() -``` - -### Error Handling - -Handle different types of errors that may occur during workflow execution: - -```python -from simstudio import SimStudioClient, SimStudioError -import os - -client = SimStudioClient(api_key=os.getenv("SIM_API_KEY")) - -def execute_with_error_handling(): - try: - result = client.execute_workflow("workflow-id") - return result - except SimStudioError as error: - if error.code == "UNAUTHORIZED": - print("Invalid API key") - elif error.code == "TIMEOUT": - print("Workflow execution timed out") - elif error.code == "USAGE_LIMIT_EXCEEDED": - print("Usage limit exceeded") - elif error.code == "INVALID_JSON": - print("Invalid JSON in request body") - else: - print(f"Workflow error: {error}") - raise - except Exception as error: - print(f"Unexpected error: {error}") - raise -``` - -### Context Manager Usage - -Use the client as a context manager to automatically handle resource cleanup: - -```python -from simstudio import SimStudioClient -import os - -# Using context manager to automatically close the session -with SimStudioClient(api_key=os.getenv("SIM_API_KEY")) as client: - result = client.execute_workflow("workflow-id") - print("Result:", result) -# Session is automatically closed here -``` - -### Batch Workflow Execution - -Execute multiple workflows efficiently: - -```python -from simstudio import SimStudioClient -import os - -client = SimStudioClient(api_key=os.getenv("SIM_API_KEY")) - -def execute_workflows_batch(workflow_data_pairs): - """Execute multiple workflows with different input data.""" - results = [] - - for workflow_id, input_data in workflow_data_pairs: - try: - # Validate workflow before execution - if not client.validate_workflow(workflow_id): - print(f"Skipping {workflow_id}: not deployed") - continue - - result = client.execute_workflow(workflow_id, input_data) - results.append({ - "workflow_id": workflow_id, - "success": result.success, - "output": result.output, - "error": result.error - }) - - except Exception as error: - results.append({ - "workflow_id": workflow_id, - "success": False, - "error": str(error) - }) - - return results - -# Example usage -workflows = [ - ("workflow-1", {"type": "analysis", "data": "sample1"}), - ("workflow-2", {"type": "processing", "data": "sample2"}), -] - -results = execute_workflows_batch(workflows) -for result in results: - print(f"Workflow {result['workflow_id']}: {'Success' if result['success'] else 'Failed'}") -``` - -### Async Workflow Execution - -Execute workflows asynchronously for long-running tasks: - -```python -import os -import time -from simstudio import SimStudioClient - -client = SimStudioClient(api_key=os.getenv("SIM_API_KEY")) - -def execute_async(): - try: - # Start async execution - result = client.execute_workflow( - "workflow-id", - input={"data": "large dataset"}, - async_execution=True # Execute asynchronously - ) - - # Check if result is an async execution - if hasattr(result, 'task_id'): - print(f"Task ID: {result.task_id}") - print(f"Status endpoint: {result.links['status']}") - - # Poll for completion - status = client.get_job_status(result.task_id) - - while status["status"] in ["queued", "processing"]: - print(f"Current status: {status['status']}") - time.sleep(2) # Wait 2 seconds - status = client.get_job_status(result.task_id) - - if status["status"] == "completed": - print("Workflow completed!") - print(f"Output: {status['output']}") - print(f"Duration: {status['metadata']['duration']}") - else: - print(f"Workflow failed: {status['error']}") - - except Exception as error: - print(f"Error: {error}") - -execute_async() -``` - -### Rate Limiting and Retry - -Handle rate limits automatically with exponential backoff: - -```python -import os -from simstudio import SimStudioClient, SimStudioError - -client = SimStudioClient(api_key=os.getenv("SIM_API_KEY")) - -def execute_with_retry_handling(): - try: - # Automatically retries on rate limit - result = client.execute_with_retry( - "workflow-id", - input={"message": "Process this"}, - max_retries=5, - initial_delay=1.0, - max_delay=60.0, - backoff_multiplier=2.0 - ) - - print(f"Success: {result}") - except SimStudioError as error: - if error.code == "RATE_LIMIT_EXCEEDED": - print("Rate limit exceeded after all retries") - - # Check rate limit info - rate_limit_info = client.get_rate_limit_info() - if rate_limit_info: - from datetime import datetime - reset_time = datetime.fromtimestamp(rate_limit_info.reset) - print(f"Rate limit resets at: {reset_time}") - -execute_with_retry_handling() -``` - -### Usage Monitoring - -Monitor your account usage and limits: - -```python -import os -from simstudio import SimStudioClient - -client = SimStudioClient(api_key=os.getenv("SIM_API_KEY")) - -def check_usage(): - try: - limits = client.get_usage_limits() - - print("=== Rate Limits ===") - print("Sync requests:") - print(f" Limit: {limits.rate_limit['sync']['limit']}") - print(f" Remaining: {limits.rate_limit['sync']['remaining']}") - print(f" Resets at: {limits.rate_limit['sync']['resetAt']}") - print(f" Is limited: {limits.rate_limit['sync']['isLimited']}") - - print("\nAsync requests:") - print(f" Limit: {limits.rate_limit['async']['limit']}") - print(f" Remaining: {limits.rate_limit['async']['remaining']}") - print(f" Resets at: {limits.rate_limit['async']['resetAt']}") - print(f" Is limited: {limits.rate_limit['async']['isLimited']}") - - print("\n=== Usage ===") - print(f"Current period cost: ${limits.usage['currentPeriodCost']:.2f}") - print(f"Limit: ${limits.usage['limit']:.2f}") - print(f"Plan: {limits.usage['plan']}") - - percent_used = (limits.usage['currentPeriodCost'] / limits.usage['limit']) * 100 - print(f"Usage: {percent_used:.1f}%") - - if percent_used > 80: - print("⚠️ Warning: You are approaching your usage limit!") - - except Exception as error: - print(f"Error checking usage: {error}") - -check_usage() -``` - -### Streaming Workflow Execution - -Execute workflows with real-time streaming responses: - -```python -from simstudio import SimStudioClient -import os - -client = SimStudioClient(api_key=os.getenv("SIM_API_KEY")) - -def execute_with_streaming(): - """Execute workflow with streaming enabled.""" - try: - # Enable streaming for specific block outputs - result = client.execute_workflow( - "workflow-id", - input={"message": "Count to five"}, - stream=True, - selected_outputs=["agent1.content"] # Use blockName.attribute format - ) - - print("Workflow result:", result) - except Exception as error: - print("Error:", error) - -execute_with_streaming() -``` - -The streaming response follows the Server-Sent Events (SSE) format: - -``` -data: {"blockId":"7b7735b9-19e5-4bd6-818b-46aae2596e9f","chunk":"One"} - -data: {"blockId":"7b7735b9-19e5-4bd6-818b-46aae2596e9f","chunk":", two"} - -data: {"event":"done","success":true,"output":{},"metadata":{"duration":610}} - -data: [DONE] -``` - -**Flask Streaming Example:** - -```python -from flask import Flask, Response, stream_with_context -import requests -import json -import os - -app = Flask(__name__) - -@app.route('/stream-workflow') -def stream_workflow(): - """Stream workflow execution to the client.""" - - def generate(): - response = requests.post( - 'https://sim.ai/api/workflows/WORKFLOW_ID/execute', - headers={ - 'Content-Type': 'application/json', - 'X-API-Key': os.getenv('SIM_API_KEY') - }, - json={ - 'message': 'Generate a story', - 'stream': True, - 'selectedOutputs': ['agent1.content'] - }, - stream=True - ) - - for line in response.iter_lines(): - if line: - decoded_line = line.decode('utf-8') - if decoded_line.startswith('data: '): - data = decoded_line[6:] # Remove 'data: ' prefix - - if data == '[DONE]': - break - - try: - parsed = json.loads(data) - if 'chunk' in parsed: - yield f"data: {json.dumps(parsed)}\n\n" - elif parsed.get('event') == 'done': - yield f"data: {json.dumps(parsed)}\n\n" - print("Execution complete:", parsed.get('metadata')) - except json.JSONDecodeError: - pass - - return Response( - stream_with_context(generate()), - mimetype='text/event-stream' - ) - -if __name__ == '__main__': - app.run(debug=True) -``` - -### Environment Configuration - -Configure the client using environment variables: - - - - ```python - import os - from simstudio import SimStudioClient - - # Development configuration - client = SimStudioClient( - api_key=os.getenv("SIM_API_KEY") - base_url=os.getenv("SIM_BASE_URL", "https://sim.ai") - ) - ``` - - - ```python - import os - from simstudio import SimStudioClient - - # Production configuration with error handling - api_key = os.getenv("SIM_API_KEY") - if not api_key: - raise ValueError("SIM_API_KEY environment variable is required") - - client = SimStudioClient( - api_key=api_key, - base_url=os.getenv("SIM_BASE_URL", "https://sim.ai") - ) - ``` - - - -## Getting Your API Key - - - - Navigate to [Sim](https://sim.ai) and log in to your account. - - - Navigate to the workflow you want to execute programmatically. - - - Click on "Deploy" to deploy your workflow if it hasn't been deployed yet. - - - During the deployment process, select or create an API key. - - - Copy the API key to use in your Python application. - - - -## Requirements - -- Python 3.8+ -- requests >= 2.25.0 - -## License - -Apache-2.0 - -import { FAQ } from '@/components/ui/faq' - - \ No newline at end of file diff --git a/apps/docs/content/docs/en/sdks/typescript.mdx b/apps/docs/content/docs/en/sdks/typescript.mdx deleted file mode 100644 index 476cfb964d4..00000000000 --- a/apps/docs/content/docs/en/sdks/typescript.mdx +++ /dev/null @@ -1,1030 +0,0 @@ ---- -title: TypeScript ---- - -import { Callout } from 'fumadocs-ui/components/callout' -import { Card, Cards } from 'fumadocs-ui/components/card' -import { Step, Steps } from 'fumadocs-ui/components/steps' -import { Tab, Tabs } from 'fumadocs-ui/components/tabs' - -The official TypeScript/JavaScript SDK for Sim provides full type safety and supports both Node.js and browser environments, allowing you to execute workflows programmatically from your Node.js applications, web applications, and other JavaScript environments. - - - The TypeScript SDK provides full type safety, async execution support, automatic rate limiting with exponential backoff, and usage tracking. - - -## Installation - -Install the SDK using your preferred package manager: - - - - ```bash - npm install simstudio-ts-sdk - ``` - - - ```bash - yarn add simstudio-ts-sdk - ``` - - - ```bash - bun add simstudio-ts-sdk - ``` - - - -## Quick Start - -Here's a simple example to get you started: - -```typescript -import { SimStudioClient } from 'simstudio-ts-sdk'; - -// Initialize the client -const client = new SimStudioClient({ - apiKey: 'your-api-key-here', - baseUrl: 'https://sim.ai' // optional, defaults to https://sim.ai -}); - -// Execute a workflow -try { - const result = await client.executeWorkflow('workflow-id'); - console.log('Workflow executed successfully:', result); -} catch (error) { - console.error('Workflow execution failed:', error); -} -``` - -## API Reference - -### SimStudioClient - -#### Constructor - -```typescript -new SimStudioClient(config: SimStudioConfig) -``` - -**Configuration:** -- `config.apiKey` (string): Your Sim API key -- `config.baseUrl` (string, optional): Base URL for the Sim API (defaults to `https://sim.ai`) - -#### Methods - -##### executeWorkflow() - -Execute a workflow with optional input data. - -```typescript -const result = await client.executeWorkflow('workflow-id', { message: 'Hello, world!' }, { - timeout: 30000 // 30 seconds -}); -``` - -**Parameters:** -- `workflowId` (string): The ID of the workflow to execute -- `input` (any, optional): Input data to pass to the workflow -- `options` (ExecutionOptions, optional): - - `timeout` (number): Timeout in milliseconds (default: 30000) - - `stream` (boolean): Enable streaming responses (default: false) - - `selectedOutputs` (string[]): Block outputs to stream in `blockName.attribute` format (e.g., `["agent1.content"]`) - - `async` (boolean): Execute asynchronously (default: false) - -**Returns:** `Promise` - -When `async: true`, returns immediately with a task ID for polling. Otherwise, waits for completion. - -##### getWorkflowStatus() - -Get the status of a workflow (deployment status, etc.). - -```typescript -const status = await client.getWorkflowStatus('workflow-id'); -console.log('Is deployed:', status.isDeployed); -``` - -**Parameters:** -- `workflowId` (string): The ID of the workflow - -**Returns:** `Promise` - -##### validateWorkflow() - -Validate that a workflow is ready for execution. - -```typescript -const isReady = await client.validateWorkflow('workflow-id'); -if (isReady) { - // Workflow is deployed and ready -} -``` - -**Parameters:** -- `workflowId` (string): The ID of the workflow - -**Returns:** `Promise` - -##### getJobStatus() - -Get the status of an async job execution. - -```typescript -const status = await client.getJobStatus('task-id-from-async-execution'); -console.log('Status:', status.status); // 'queued', 'processing', 'completed', 'failed' -if (status.status === 'completed') { - console.log('Output:', status.output); -} -``` - -**Parameters:** -- `taskId` (string): The task ID returned from async execution - -**Returns:** `Promise` - -**Response fields:** -- `success` (boolean): Whether the request was successful -- `taskId` (string): The task ID -- `status` (string): One of `'queued'`, `'processing'`, `'completed'`, `'failed'`, `'cancelled'` -- `metadata` (object): Contains `startedAt`, `completedAt`, and `duration` -- `output` (any, optional): The workflow output (when completed) -- `error` (any, optional): Error details (when failed) -- `estimatedDuration` (number, optional): Estimated duration in milliseconds (when processing/queued) - -##### executeWithRetry() - -Execute a workflow with automatic retry on rate limit errors using exponential backoff. - -```typescript -const result = await client.executeWithRetry('workflow-id', { message: 'Hello' }, { - timeout: 30000 -}, { - maxRetries: 3, // Maximum number of retries - initialDelay: 1000, // Initial delay in ms (1 second) - maxDelay: 30000, // Maximum delay in ms (30 seconds) - backoffMultiplier: 2 // Exponential backoff multiplier -}); -``` - -**Parameters:** -- `workflowId` (string): The ID of the workflow to execute -- `input` (any, optional): Input data to pass to the workflow -- `options` (ExecutionOptions, optional): Same as `executeWorkflow()` -- `retryOptions` (RetryOptions, optional): - - `maxRetries` (number): Maximum number of retries (default: 3) - - `initialDelay` (number): Initial delay in ms (default: 1000) - - `maxDelay` (number): Maximum delay in ms (default: 30000) - - `backoffMultiplier` (number): Backoff multiplier (default: 2) - -**Returns:** `Promise` - -The retry logic uses exponential backoff (1s → 2s → 4s → 8s...) with ±25% jitter to prevent thundering herd. If the API provides a `retry-after` header, it will be used instead. - -##### getRateLimitInfo() - -Get the current rate limit information from the last API response. - -```typescript -const rateLimitInfo = client.getRateLimitInfo(); -if (rateLimitInfo) { - console.log('Limit:', rateLimitInfo.limit); - console.log('Remaining:', rateLimitInfo.remaining); - console.log('Reset:', new Date(rateLimitInfo.reset * 1000)); -} -``` - -**Returns:** `RateLimitInfo | null` - -##### getUsageLimits() - -Get current usage limits and quota information for your account. - -```typescript -const limits = await client.getUsageLimits(); -console.log('Sync requests remaining:', limits.rateLimit.sync.remaining); -console.log('Async requests remaining:', limits.rateLimit.async.remaining); -console.log('Current period cost:', limits.usage.currentPeriodCost); -console.log('Plan:', limits.usage.plan); -``` - -**Returns:** `Promise` - -**Response structure:** -```typescript -{ - success: boolean - rateLimit: { - sync: { - isLimited: boolean - limit: number - remaining: number - resetAt: string - } - async: { - isLimited: boolean - limit: number - remaining: number - resetAt: string - } - authType: string // 'api' or 'manual' - } - usage: { - currentPeriodCost: number - limit: number - plan: string // e.g., 'free', 'pro' - } -} -``` - -##### setApiKey() - -Update the API key. - -```typescript -client.setApiKey('new-api-key'); -``` - -##### setBaseUrl() - -Update the base URL. - -```typescript -client.setBaseUrl('https://my-custom-domain.com'); -``` - -## Types - -### WorkflowExecutionResult - -```typescript -interface WorkflowExecutionResult { - success: boolean; - output?: any; - error?: string; - logs?: any[]; - metadata?: { - duration?: number; - executionId?: string; - [key: string]: any; - }; - traceSpans?: any[]; - totalDuration?: number; -} -``` - -### AsyncExecutionResult - -```typescript -interface AsyncExecutionResult { - success: boolean; - taskId: string; - status: 'queued'; - createdAt: string; - links: { - status: string; // e.g., "/api/jobs/{taskId}" - }; -} -``` - -### WorkflowStatus - -```typescript -interface WorkflowStatus { - isDeployed: boolean; - deployedAt?: string; - needsRedeployment: boolean; -} -``` - -### RateLimitInfo - -```typescript -interface RateLimitInfo { - limit: number; - remaining: number; - reset: number; - retryAfter?: number; -} -``` - -### UsageLimits - -```typescript -interface UsageLimits { - success: boolean; - rateLimit: { - sync: { - isLimited: boolean; - limit: number; - remaining: number; - resetAt: string; - }; - async: { - isLimited: boolean; - limit: number; - remaining: number; - resetAt: string; - }; - authType: string; - }; - usage: { - currentPeriodCost: number; - limit: number; - plan: string; - }; -} -``` - -### SimStudioError - -```typescript -class SimStudioError extends Error { - code?: string; - status?: number; -} -``` - -**Common error codes:** -- `UNAUTHORIZED`: Invalid API key -- `TIMEOUT`: Request timed out -- `RATE_LIMIT_EXCEEDED`: Rate limit exceeded -- `USAGE_LIMIT_EXCEEDED`: Usage limit exceeded -- `EXECUTION_ERROR`: Workflow execution failed - -## Examples - -### Basic Workflow Execution - - - - Set up the SimStudioClient with your API key. - - - Check if the workflow is deployed and ready for execution. - - - Run the workflow with your input data. - - - Process the execution result and handle any errors. - - - -```typescript -import { SimStudioClient } from 'simstudio-ts-sdk'; - -const client = new SimStudioClient({ - apiKey: process.env.SIM_API_KEY! -}); - -async function runWorkflow() { - try { - // Check if workflow is ready - const isReady = await client.validateWorkflow('my-workflow-id'); - if (!isReady) { - throw new Error('Workflow is not deployed or ready'); - } - - // Execute the workflow - const result = await client.executeWorkflow('my-workflow-id', { - message: 'Process this data', - userId: '12345' - }); - - if (result.success) { - console.log('Output:', result.output); - console.log('Duration:', result.metadata?.duration); - } else { - console.error('Workflow failed:', result.error); - } - } catch (error) { - console.error('Error:', error); - } -} - -runWorkflow(); -``` - -### Error Handling - -Handle different types of errors that may occur during workflow execution: - -```typescript -import { SimStudioClient, SimStudioError } from 'simstudio-ts-sdk'; - -const client = new SimStudioClient({ - apiKey: process.env.SIM_API_KEY! -}); - -async function executeWithErrorHandling() { - try { - const result = await client.executeWorkflow('workflow-id'); - return result; - } catch (error) { - if (error instanceof SimStudioError) { - switch (error.code) { - case 'UNAUTHORIZED': - console.error('Invalid API key'); - break; - case 'TIMEOUT': - console.error('Workflow execution timed out'); - break; - case 'USAGE_LIMIT_EXCEEDED': - console.error('Usage limit exceeded'); - break; - case 'INVALID_JSON': - console.error('Invalid JSON in request body'); - break; - default: - console.error('Workflow error:', error.message); - } - } else { - console.error('Unexpected error:', error); - } - throw error; - } -} -``` - -### Environment Configuration - -Configure the client using environment variables: - - - - ```typescript - import { SimStudioClient } from 'simstudio-ts-sdk'; - - // Development configuration - const apiKey = process.env.SIM_API_KEY; - if (!apiKey) { - throw new Error('SIM_API_KEY environment variable is required'); - } - - const client = new SimStudioClient({ - apiKey, - baseUrl: process.env.SIM_BASE_URL // optional - }); - ``` - - - ```typescript - import { SimStudioClient } from 'simstudio-ts-sdk'; - - // Production configuration with validation - const apiKey = process.env.SIM_API_KEY; - if (!apiKey) { - throw new Error('SIM_API_KEY environment variable is required'); - } - - const client = new SimStudioClient({ - apiKey, - baseUrl: process.env.SIM_BASE_URL || 'https://sim.ai' - }); - ``` - - - -### Node.js Express Integration - -Integrate with an Express.js server: - -```typescript -import express from 'express'; -import { SimStudioClient } from 'simstudio-ts-sdk'; - -const app = express(); -const client = new SimStudioClient({ - apiKey: process.env.SIM_API_KEY! -}); - -app.use(express.json()); - -app.post('/execute-workflow', async (req, res) => { - try { - const { workflowId, input } = req.body; - - const result = await client.executeWorkflow(workflowId, input, { - timeout: 60000 - }); - - res.json({ - success: true, - data: result - }); - } catch (error) { - console.error('Workflow execution error:', error); - res.status(500).json({ - success: false, - error: error instanceof Error ? error.message : 'Unknown error' - }); - } -}); - -app.listen(3000, () => { - console.log('Server running on port 3000'); -}); -``` - -### Next.js API Route - -Use with Next.js API routes: - -```typescript -// pages/api/workflow.ts or app/api/workflow/route.ts -import { NextApiRequest, NextApiResponse } from 'next'; -import { SimStudioClient } from 'simstudio-ts-sdk'; - -const client = new SimStudioClient({ - apiKey: process.env.SIM_API_KEY! -}); - -export default async function handler( - req: NextApiRequest, - res: NextApiResponse -) { - if (req.method !== 'POST') { - return res.status(405).json({ error: 'Method not allowed' }); - } - - try { - const { workflowId, input } = req.body; - - const result = await client.executeWorkflow(workflowId, input, { - timeout: 30000 - }); - - res.status(200).json(result); - } catch (error) { - console.error('Error executing workflow:', error); - res.status(500).json({ - error: 'Failed to execute workflow' - }); - } -} -``` - -### Browser Usage - -Use in the browser (with proper CORS configuration): - -```typescript -import { SimStudioClient } from 'simstudio-ts-sdk'; - -// Note: In production, use a proxy server to avoid exposing API keys -const client = new SimStudioClient({ - apiKey: 'your-public-api-key', // Use with caution in browser - baseUrl: 'https://sim.ai' -}); - -async function executeClientSideWorkflow() { - try { - const result = await client.executeWorkflow('workflow-id', { - userInput: 'Hello from browser' - }); - - console.log('Workflow result:', result); - - // Update UI with result - document.getElementById('result')!.textContent = - JSON.stringify(result.output, null, 2); - } catch (error) { - console.error('Error:', error); - } -} -``` - -### File Upload - -File objects are automatically detected and converted to base64 format. Include them in your input under the field name matching your workflow's API trigger input format. - -The SDK converts File objects to this format: -```typescript -{ - type: 'file', - data: 'data:mime/type;base64,base64data', - name: 'filename', - mime: 'mime/type' -} -``` - -Alternatively, you can manually provide files using the URL format: -```typescript -{ - type: 'url', - data: 'https://example.com/file.pdf', - name: 'file.pdf', - mime: 'application/pdf' -} -``` - - - - ```typescript - import { SimStudioClient } from 'simstudio-ts-sdk'; - - const client = new SimStudioClient({ - apiKey: process.env.NEXT_PUBLIC_SIM_API_KEY! - }); - - // From file input - async function handleFileUpload(event: Event) { - const input = event.target as HTMLInputElement; - const files = Array.from(input.files || []); - - // Include files under the field name from your API trigger's input format - const result = await client.executeWorkflow('workflow-id', { - documents: files, // Must match your workflow's "files" field name - instructions: 'Analyze these documents' - }); - - console.log('Result:', result); - } - ``` - - - ```typescript - import { SimStudioClient } from 'simstudio-ts-sdk'; - import fs from 'fs'; - - const client = new SimStudioClient({ - apiKey: process.env.SIM_API_KEY! - }); - - // Read file and create File object - const fileBuffer = fs.readFileSync('./document.pdf'); - const file = new File([fileBuffer], 'document.pdf', { - type: 'application/pdf' - }); - - // Include files under the field name from your API trigger's input format - const result = await client.executeWorkflow('workflow-id', { - documents: [file], // Must match your workflow's "files" field name - query: 'Summarize this document' - }); - ``` - - - - - When using the SDK in the browser, be careful not to expose sensitive API keys. Consider using a backend proxy or public API keys with limited permissions. - - -### React Hook Example - -Create a custom React hook for workflow execution: - -```typescript -import { useState, useCallback } from 'react'; -import { SimStudioClient, WorkflowExecutionResult } from 'simstudio-ts-sdk'; - -const client = new SimStudioClient({ - apiKey: process.env.SIM_API_KEY! -}); - -interface UseWorkflowResult { - result: WorkflowExecutionResult | null; - loading: boolean; - error: Error | null; - executeWorkflow: (workflowId: string, input?: any) => Promise; -} - -export function useWorkflow(): UseWorkflowResult { - const [result, setResult] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - - const executeWorkflow = useCallback(async (workflowId: string, input?: any) => { - setLoading(true); - setError(null); - setResult(null); - - try { - const workflowResult = await client.executeWorkflow(workflowId, input, { - timeout: 30000 - }); - setResult(workflowResult); - } catch (err) { - setError(err instanceof Error ? err : new Error('Unknown error')); - } finally { - setLoading(false); - } - }, []); - - return { - result, - loading, - error, - executeWorkflow - }; -} - -// Usage in component -function WorkflowComponent() { - const { result, loading, error, executeWorkflow } = useWorkflow(); - - const handleExecute = () => { - executeWorkflow('my-workflow-id', { - message: 'Hello from React!' - }); - }; - - return ( -
- - - {error &&
Error: {error.message}
} - {result && ( -
-

Result:

-
{JSON.stringify(result, null, 2)}
-
- )} -
- ); -} -``` - -### Async Workflow Execution - -Execute workflows asynchronously for long-running tasks: - -```typescript -import { SimStudioClient, AsyncExecutionResult } from 'simstudio-ts-sdk'; - -const client = new SimStudioClient({ - apiKey: process.env.SIM_API_KEY! -}); - -async function executeAsync() { - try { - // Start async execution - const result = await client.executeWorkflow('workflow-id', { data: 'large dataset' }, { - async: true // Execute asynchronously - }); - - // Check if result is an async execution - if ('taskId' in result) { - console.log('Task ID:', result.taskId); - console.log('Status endpoint:', result.links.status); - - // Poll for completion - let status = await client.getJobStatus(result.taskId); - - while (status.status === 'queued' || status.status === 'processing') { - console.log('Current status:', status.status); - await new Promise(resolve => setTimeout(resolve, 2000)); // Wait 2 seconds - status = await client.getJobStatus(result.taskId); - } - - if (status.status === 'completed') { - console.log('Workflow completed!'); - console.log('Output:', status.output); - console.log('Duration:', status.metadata.duration); - } else { - console.error('Workflow failed:', status.error); - } - } - } catch (error) { - console.error('Error:', error); - } -} - -executeAsync(); -``` - -### Rate Limiting and Retry - -Handle rate limits automatically with exponential backoff: - -```typescript -import { SimStudioClient, SimStudioError } from 'simstudio-ts-sdk'; - -const client = new SimStudioClient({ - apiKey: process.env.SIM_API_KEY! -}); - -async function executeWithRetryHandling() { - try { - // Automatically retries on rate limit - const result = await client.executeWithRetry('workflow-id', { message: 'Process this' }, {}, { - maxRetries: 5, - initialDelay: 1000, - maxDelay: 60000, - backoffMultiplier: 2 - }); - - console.log('Success:', result); - } catch (error) { - if (error instanceof SimStudioError && error.code === 'RATE_LIMIT_EXCEEDED') { - console.error('Rate limit exceeded after all retries'); - - // Check rate limit info - const rateLimitInfo = client.getRateLimitInfo(); - if (rateLimitInfo) { - console.log('Rate limit resets at:', new Date(rateLimitInfo.reset * 1000)); - } - } - } -} -``` - -### Usage Monitoring - -Monitor your account usage and limits: - -```typescript -import { SimStudioClient } from 'simstudio-ts-sdk'; - -const client = new SimStudioClient({ - apiKey: process.env.SIM_API_KEY! -}); - -async function checkUsage() { - try { - const limits = await client.getUsageLimits(); - - console.log('=== Rate Limits ==='); - console.log('Sync requests:'); - console.log(' Limit:', limits.rateLimit.sync.limit); - console.log(' Remaining:', limits.rateLimit.sync.remaining); - console.log(' Resets at:', limits.rateLimit.sync.resetAt); - console.log(' Is limited:', limits.rateLimit.sync.isLimited); - - console.log('\nAsync requests:'); - console.log(' Limit:', limits.rateLimit.async.limit); - console.log(' Remaining:', limits.rateLimit.async.remaining); - console.log(' Resets at:', limits.rateLimit.async.resetAt); - console.log(' Is limited:', limits.rateLimit.async.isLimited); - - console.log('\n=== Usage ==='); - console.log('Current period cost: $' + limits.usage.currentPeriodCost.toFixed(2)); - console.log('Limit: $' + limits.usage.limit.toFixed(2)); - console.log('Plan:', limits.usage.plan); - - const percentUsed = (limits.usage.currentPeriodCost / limits.usage.limit) * 100; - console.log('Usage: ' + percentUsed.toFixed(1) + '%'); - - if (percentUsed > 80) { - console.warn('⚠️ Warning: You are approaching your usage limit!'); - } - } catch (error) { - console.error('Error checking usage:', error); - } -} - -checkUsage(); -``` - -### Streaming Workflow Execution - -Execute workflows with real-time streaming responses: - -```typescript -import { SimStudioClient } from 'simstudio-ts-sdk'; - -const client = new SimStudioClient({ - apiKey: process.env.SIM_API_KEY! -}); - -async function executeWithStreaming() { - try { - // Enable streaming for specific block outputs - const result = await client.executeWorkflow('workflow-id', { message: 'Count to five' }, { - stream: true, - selectedOutputs: ['agent1.content'] // Use blockName.attribute format - }); - - console.log('Workflow result:', result); - } catch (error) { - console.error('Error:', error); - } -} -``` - -The streaming response follows the Server-Sent Events (SSE) format: - -``` -data: {"blockId":"7b7735b9-19e5-4bd6-818b-46aae2596e9f","chunk":"One"} - -data: {"blockId":"7b7735b9-19e5-4bd6-818b-46aae2596e9f","chunk":", two"} - -data: {"event":"done","success":true,"output":{},"metadata":{"duration":610}} - -data: [DONE] -``` - -**React Streaming Example:** - -```typescript -import { useState, useEffect } from 'react'; - -function StreamingWorkflow() { - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const executeStreaming = async () => { - setLoading(true); - setOutput(''); - - // IMPORTANT: Make this API call from your backend server, not the browser - // Never expose your API key in client-side code - const response = await fetch('https://sim.ai/api/workflows/WORKFLOW_ID/execute', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-API-Key': process.env.SIM_API_KEY! // Server-side environment variable only - }, - body: JSON.stringify({ - message: 'Generate a story', - stream: true, - selectedOutputs: ['agent1.content'] - }) - }); - - const reader = response.body?.getReader(); - const decoder = new TextDecoder(); - - while (reader) { - const { done, value } = await reader.read(); - if (done) break; - - const chunk = decoder.decode(value); - const lines = chunk.split('\n\n'); - - for (const line of lines) { - if (line.startsWith('data: ')) { - const data = line.slice(6); - if (data === '[DONE]') { - setLoading(false); - break; - } - - try { - const parsed = JSON.parse(data); - if (parsed.chunk) { - setOutput(prev => prev + parsed.chunk); - } else if (parsed.event === 'done') { - console.log('Execution complete:', parsed.metadata); - } - } catch (e) { - // Skip invalid JSON - } - } - } - } - }; - - return ( -
- -
{output}
-
- ); -} -``` - -## Getting Your API Key - - - - Navigate to [Sim](https://sim.ai) and log in to your account. - - - Navigate to the workflow you want to execute programmatically. - - - Click on "Deploy" to deploy your workflow if it hasn't been deployed yet. - - - During the deployment process, select or create an API key. - - - Copy the API key to use in your TypeScript/JavaScript application. - - - -## Requirements - -- Node.js 16+ -- TypeScript 5.0+ (for TypeScript projects) - -## License - -Apache-2.0 - -import { FAQ } from '@/components/ui/faq' - - diff --git a/apps/docs/content/docs/en/tools/custom-tools.mdx b/apps/docs/content/docs/en/tools/custom-tools.mdx index f29e7adace5..a6455f832b6 100644 --- a/apps/docs/content/docs/en/tools/custom-tools.mdx +++ b/apps/docs/content/docs/en/tools/custom-tools.mdx @@ -145,15 +145,6 @@ From **Settings → Custom Tools** you can: Deleting a custom tool removes it from all Agent blocks that reference it. Make sure no active workflows depend on the tool before deleting. -## Custom Tools vs MCP Tools - -| | **Custom Tools** | **MCP Tools** | -|---|---|---| -| **Defined** | Inline — schema + code in Sim | External MCP server | -| **Hosting** | Runs inside Sim | Runs on your server | -| **Best for** | Small, workspace-specific helpers | Shared tools, third-party services, complex integrations | -| **Setup** | One modal | Deploy and register a server | - ## Permissions | Action | Required Permission | From a330661c48f4e16f33d653ef45f7b70974689510 Mon Sep 17 00:00:00 2001 From: waleed Date: Thu, 16 Apr 2026 12:31:52 -0700 Subject: [PATCH 3/4] fix(docs): update SDKs card links from /sdks to /api-reference --- apps/docs/content/docs/de/index.mdx | 2 +- apps/docs/content/docs/en/index.mdx | 2 +- apps/docs/content/docs/es/index.mdx | 2 +- apps/docs/content/docs/fr/index.mdx | 2 +- apps/docs/content/docs/ja/index.mdx | 2 +- apps/docs/content/docs/zh/index.mdx | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/docs/content/docs/de/index.mdx b/apps/docs/content/docs/de/index.mdx index 92ebaf1f632..d6f678e658c 100644 --- a/apps/docs/content/docs/de/index.mdx +++ b/apps/docs/content/docs/de/index.mdx @@ -51,7 +51,7 @@ Willkommen bei Sim, einem visuellen Workflow-Builder für KI-Anwendungen. Erstel Externe Dienste mit dem Model Context Protocol verbinden - + Sim in Ihre Anwendungen integrieren \ No newline at end of file diff --git a/apps/docs/content/docs/en/index.mdx b/apps/docs/content/docs/en/index.mdx index 6ad3ec93550..ee56612ae3a 100644 --- a/apps/docs/content/docs/en/index.mdx +++ b/apps/docs/content/docs/en/index.mdx @@ -51,7 +51,7 @@ Welcome to Sim, the open-source AI workspace where teams build, deploy, and mana Connect external services with Model Context Protocol - + Integrate Sim into your applications \ No newline at end of file diff --git a/apps/docs/content/docs/es/index.mdx b/apps/docs/content/docs/es/index.mdx index a8fb4342b2e..43310736165 100644 --- a/apps/docs/content/docs/es/index.mdx +++ b/apps/docs/content/docs/es/index.mdx @@ -51,7 +51,7 @@ Bienvenido a Sim, un constructor visual de flujos de trabajo para aplicaciones d Conecta servicios externos con el Protocolo de Contexto de Modelo - + Integra Sim en tus aplicaciones \ No newline at end of file diff --git a/apps/docs/content/docs/fr/index.mdx b/apps/docs/content/docs/fr/index.mdx index 5d6f163c8da..561464eeeba 100644 --- a/apps/docs/content/docs/fr/index.mdx +++ b/apps/docs/content/docs/fr/index.mdx @@ -51,7 +51,7 @@ Bienvenue sur Sim, un constructeur visuel de flux de travail pour les applicatio Connectez des services externes avec le protocole de contexte de modèle - + Intégrez Sim dans vos applications \ No newline at end of file diff --git a/apps/docs/content/docs/ja/index.mdx b/apps/docs/content/docs/ja/index.mdx index 7d7e25bc24c..7766b79a179 100644 --- a/apps/docs/content/docs/ja/index.mdx +++ b/apps/docs/content/docs/ja/index.mdx @@ -51,7 +51,7 @@ Simへようこそ。AIアプリケーション用のビジュアルワークフ モデルコンテキストプロトコルで外部サービスを接続する - + アプリケーションにSimを統合する \ No newline at end of file diff --git a/apps/docs/content/docs/zh/index.mdx b/apps/docs/content/docs/zh/index.mdx index 8976ea607ae..68619ae0e6e 100644 --- a/apps/docs/content/docs/zh/index.mdx +++ b/apps/docs/content/docs/zh/index.mdx @@ -51,7 +51,7 @@ import { Card, Cards } from 'fumadocs-ui/components/card' 使用模型上下文协议连接外部服务 - + 将 Sim 集成到您的应用程序中 \ No newline at end of file From 79f1e819bc07e26880931436916d3076f4bd911d Mon Sep 17 00:00:00 2001 From: waleed Date: Thu, 16 Apr 2026 12:32:18 -0700 Subject: [PATCH 4/4] fix(docs): update /sdks references to /api-reference in llms.txt files --- apps/docs/app/llms.txt/route.ts | 2 +- apps/sim/public/llms.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/docs/app/llms.txt/route.ts b/apps/docs/app/llms.txt/route.ts index 969a5c97260..f172dd07156 100644 --- a/apps/docs/app/llms.txt/route.ts +++ b/apps/docs/app/llms.txt/route.ts @@ -62,7 +62,7 @@ ${Object.entries(sections) - Full documentation content: ${baseUrl}/llms-full.txt - Individual page content: ${baseUrl}/llms.mdx/[page-path] -- API documentation: ${baseUrl}/sdks/ +- API documentation: ${baseUrl}/api-reference/ - Tool integrations: ${baseUrl}/tools/ ## Statistics diff --git a/apps/sim/public/llms.txt b/apps/sim/public/llms.txt index ea33e518c7e..cfe929b6dba 100644 --- a/apps/sim/public/llms.txt +++ b/apps/sim/public/llms.txt @@ -56,4 +56,4 @@ The Sim blog covers announcements, technical deep-dives, and guides for building - MCP Protocol: https://docs.sim.ai/mcp - Self-Hosting: https://docs.sim.ai/self-hosting - API Reference: https://docs.sim.ai/api-reference/getting-started -- SDKs: https://docs.sim.ai/sdks +- SDKs: https://docs.sim.ai/api-reference