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/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/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/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/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/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/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 6261af27a80..a6455f832b6 100644 --- a/apps/docs/content/docs/en/tools/custom-tools.mdx +++ b/apps/docs/content/docs/en/tools/custom-tools.mdx @@ -151,7 +151,7 @@ From **Settings → Custom Tools** you can: |--------|-------------------| | View custom tools | **Read**, **Write**, or **Admin** | | Create or edit tools | **Write** or **Admin** | -| Delete tools | **Write** or **Admin** | +| Delete tools | **Admin** | 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 diff --git a/apps/sim/providers/anthropic/core.ts b/apps/sim/providers/anthropic/core.ts index 01e8c08aa27..457b63a9613 100644 --- a/apps/sim/providers/anthropic/core.ts +++ b/apps/sim/providers/anthropic/core.ts @@ -12,6 +12,7 @@ import { getMaxOutputTokensForModel, getThinkingCapability, supportsNativeStructuredOutputs, + supportsTemperature, } from '@/providers/models' import type { ProviderRequest, ProviderResponse, TimeSegment } from '@/providers/types' import { ProviderError } from '@/providers/types' @@ -298,7 +299,9 @@ export async function executeAnthropicProviderRequest( system: systemPrompt, max_tokens: Number.parseInt(String(request.maxTokens)) || getMaxOutputTokensForModel(request.model), - temperature: Number.parseFloat(String(request.temperature ?? 0.7)), + ...(supportsTemperature(request.model) && { + temperature: Number.parseFloat(String(request.temperature ?? 0.7)), + }), } if (request.responseFormat) { diff --git a/apps/sim/providers/models.ts b/apps/sim/providers/models.ts index 49cf756f43a..3d8cd0f8cc6 100644 --- a/apps/sim/providers/models.ts +++ b/apps/sim/providers/models.ts @@ -528,11 +528,10 @@ export const PROVIDER_DEFINITIONS: Record = { 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', }, }, 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