Worxflow
Sdks

TypeScript/JavaScript SDK

Worxflow 的官方 TypeScript/JavaScript SDK 提供完整的类型安全,支持 Node.js 和浏览器环境,允许您从 Node.js 应用程序、Web 应用程序和其他 JavaScript 环境中以编程方式执行工作流。

TypeScript SDK 提供完整的类型安全、异步执行支持、带有指数回退的自动速率限制以及使用跟踪。

安装

使用您喜欢的包管理器安装 SDK:

npm install simstudio-ts-sdk
yarn add simstudio-ts-sdk
bun add simstudio-ts-sdk

快速开始

以下是一个简单的示例,帮助您快速入门:

import { SimStudioClient } from 'simstudio-ts-sdk';

// Initialize the client
const client = new SimStudioClient({
  apiKey: 'your-api-key-here',
  baseUrl: 'https://worxflow.ai' // optional, defaults to https://worxflow.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 参考

SimStudioClient

构造函数

new SimStudioClient(config: SimStudioConfig)

配置:

  • config.apiKey (字符串): 您的 Worxflow API 密钥
  • config.baseUrl (字符串,可选): Worxflow API 的基础 URL(默认为 https://worxflow.ai

方法

executeWorkflow()

执行带有可选输入数据的工作流。

const result = await client.executeWorkflow('workflow-id', {
  input: { message: 'Hello, world!' },
  timeout: 30000 // 30 seconds
});

参数:

  • workflowId (字符串): 要执行的工作流的 ID
  • options (ExecutionOptions,可选):
    • input (任意类型): 传递给工作流的输入数据
    • timeout (数字): 超时时间(以毫秒为单位,默认值:30000)
    • stream (布尔值): 启用流式响应(默认值:false)
    • selectedOutputs (字符串数组): 以 blockName.attribute 格式阻止流中的输出(例如,["agent1.content"]
    • async (布尔值): 异步执行(默认值:false)

返回值: Promise<WorkflowExecutionResult | AsyncExecutionResult>

async: true 时,立即返回一个用于轮询的任务 ID。否则,等待完成。

getWorkflowStatus()

获取工作流的状态(部署状态等)。

const status = await client.getWorkflowStatus('workflow-id');
console.log('Is deployed:', status.isDeployed);

参数:

  • workflowId (字符串): 工作流的 ID

返回值: Promise<WorkflowStatus>

validateWorkflow()

验证工作流是否已准备好执行。

const isReady = await client.validateWorkflow('workflow-id');
if (isReady) {
  // Workflow is deployed and ready
}

参数:

  • workflowId (字符串): 工作流的 ID

返回值: Promise<boolean>

getJobStatus()

获取异步任务执行的状态。

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

参数:

  • taskId (字符串): 异步执行返回的任务 ID

返回值: Promise<JobStatus>

响应字段:

  • success (布尔值): 请求是否成功
  • taskId (字符串): 任务 ID
  • status (字符串): 可能的值包括 'queued', 'processing', 'completed', 'failed', 'cancelled'
  • metadata (对象): 包含 startedAt, completedAtduration
  • output (任意类型,可选): 工作流输出(完成时)
  • error (任意类型,可选): 错误详情(失败时)
  • estimatedDuration (数字,可选): 估计持续时间(以毫秒为单位,处理中/排队时)
executeWithRetry()

使用指数退避机制,在遇到速率限制错误时自动重试执行工作流。

const result = await client.executeWithRetry('workflow-id', {
  input: { 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
});

参数:

  • workflowId(字符串):要执行的工作流的 ID
  • options(ExecutionOptions,可选):与 executeWorkflow() 相同
  • retryOptions(RetryOptions,可选):
    • maxRetries(数字):最大重试次数(默认值:3)
    • initialDelay(数字):初始延迟时间(以毫秒为单位,默认值:1000)
    • maxDelay(数字):最大延迟时间(以毫秒为单位,默认值:30000)
    • backoffMultiplier(数字):退避倍数(默认值:2)

返回值: Promise<WorkflowExecutionResult | AsyncExecutionResult>

重试逻辑使用指数退避(1秒 → 2秒 → 4秒 → 8秒...),并带有 ±25% 的抖动以防止蜂拥效应。如果 API 提供了 retry-after 头,则会使用该头。

getRateLimitInfo()

从上一次 API 响应中获取当前速率限制信息。

const rateLimitInfo = client.getRateLimitInfo();
if (rateLimitInfo) {
  console.log('Limit:', rateLimitInfo.limit);
  console.log('Remaining:', rateLimitInfo.remaining);
  console.log('Reset:', new Date(rateLimitInfo.reset * 1000));
}

返回值: RateLimitInfo | null

getUsageLimits()

获取您的账户当前的使用限制和配额信息。

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

返回值: Promise<UsageLimits>

响应结构:

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

更新 API 密钥。

client.setApiKey('new-api-key');
setBaseUrl()

更新基础 URL。

client.setBaseUrl('https://my-custom-domain.com');

类型

WorkflowExecutionResult

interface WorkflowExecutionResult {
  success: boolean;
  output?: any;
  error?: string;
  logs?: any[];
  metadata?: {
    duration?: number;
    executionId?: string;
    [key: string]: any;
  };
  traceSpans?: any[];
  totalDuration?: number;
}

AsyncExecutionResult

interface AsyncExecutionResult {
  success: boolean;
  taskId: string;
  status: 'queued';
  createdAt: string;
  links: {
    status: string;  // e.g., "/api/jobs/{taskId}"
  };
}

WorkflowStatus

interface WorkflowStatus {
  isDeployed: boolean;
  deployedAt?: string;
  isPublished: boolean;
  needsRedeployment: boolean;
}

RateLimitInfo

interface RateLimitInfo {
  limit: number;
  remaining: number;
  reset: number;
  retryAfter?: number;
}

UsageLimits

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

class SimStudioError extends Error {
  code?: string;
  status?: number;
}

常见错误代码:

  • UNAUTHORIZED: 无效的 API 密钥
  • TIMEOUT: 请求超时
  • RATE_LIMIT_EXCEEDED: 超出速率限制
  • USAGE_LIMIT_EXCEEDED: 超出使用限制
  • EXECUTION_ERROR: 工作流执行失败

示例

基本工作流执行

使用您的 API 密钥设置 SimStudioClient。

检查工作流是否已部署并准备好执行。

使用您的输入数据运行工作流。

处理执行结果并处理任何错误。

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', {
      input: {
        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();

错误处理

处理工作流执行过程中可能发生的不同类型的错误:

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;
  }
}

环境配置

使用环境变量配置客户端:

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
});
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://worxflow.ai'
});

Node.js Express 集成

与 Express.js 服务器集成:

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 路由

与 Next.js API 路由一起使用:

// 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'
    });
  }
}

浏览器使用

在浏览器中使用(需正确配置 CORS):

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://worxflow.ai'
});

async function executeClientSideWorkflow() {
  try {
    const result = await client.executeWorkflow('workflow-id', {
      input: {
        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);
  }
}

// Attach to button click
document.getElementById('executeBtn')?.addEventListener('click', executeClientSideWorkflow);

在浏览器中使用 SDK 时,请注意不要暴露敏感的 API 密钥。建议使用后端代理或具有有限权限的公共 API 密钥。

React Hook 示例

为工作流执行创建自定义 React hook:

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<void>;
}

export function useWorkflow(): UseWorkflowResult {
  const [result, setResult] = useState<WorkflowExecutionResult | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<Error | null>(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 (
    <div>
      <button onClick={handleExecute} disabled={loading}>
        {loading ? 'Executing...' : 'Execute Workflow'}
      </button>

      {error && <div>Error: {error.message}</div>}
      {result && (
        <div>
          <h3>Result:</h3>
          <pre>{JSON.stringify(result, null, 2)}</pre>
        </div>
      )}
    </div>
  );
}

异步工作流执行

为长时间运行的任务异步执行工作流:

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', {
      input: { 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();

速率限制和重试

通过指数退避自动处理速率限制:

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', {
      input: { 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));
      }
    }
  }
}

使用监控

监控您的账户使用情况和限制:

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: 

### 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 {
    // 为特定的块输出启用流式传输
    const result = await client.executeWorkflow('workflow-id', {
      input: { message: 'Count to five' },
      stream: true,
      selectedOutputs: ['agent1.content'] // 使用 blockName.attribute 格式
    });

    console.log('工作流结果:', result);
  } catch (error) {
    console.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:

import { useState, useEffect } from 'react';

function StreamingWorkflow() {
  const [output, setOutput] = useState('');
  const [loading, setLoading] = useState(false);

  const executeStreaming = async () => {
    setLoading(true);
    setOutput('');

    // 重要提示:请从您的后端服务器发起此 API 调用,而不是从浏览器发起
    // 切勿在客户端代码中暴露您的 API 密钥
    const response = await fetch('https://worxflow.ai/api/workflows/WORKFLOW_ID/execute', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': process.env.SIM_API_KEY! // 仅限服务器端环境变量
      },
      body: JSON.stringify({
        message: '生成一个故事',
        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('执行完成:', parsed.metadata);
            }
          } catch (e) {
            // 跳过无效的 JSON
          }
        }
      }
    }
  };

  return (
    <div>
      <button onClick={executeStreaming} disabled={loading}>
        {loading ? '生成中...' : '开始流式处理'}
      </button>
      <div style={{ whiteSpace: 'pre-wrap' }}>{output}</div>
    </div>
  );
}

Getting Your API Key

Navigate to Sim 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.

Keep your API key secure and never commit it to version control. Use environment variables or secure configuration management.

Requirements

  • Node.js 16+
  • TypeScript 5.0+ (for TypeScript projects)

TypeScript Support

The SDK is written in TypeScript and provides full type safety:

import { 
  SimStudioClient, 
  WorkflowExecutionResult, 
  WorkflowStatus,
  SimStudioError 
} from 'simstudio-ts-sdk';

// 类型安全的客户端初始化
const client: SimStudioClient = new SimStudioClient({
  apiKey: process.env.SIM_API_KEY!
});

// 类型安全的工作流执行
const result: WorkflowExecutionResult = await client.executeWorkflow('workflow-id', {
  input: {
    message: '你好,TypeScript!'
  }
});

// 类型安全的状态检查
const status: WorkflowStatus = await client.getWorkflowStatus('workflow-id');

许可证

Apache-2.0

TypeScript/JavaScript SDK