Worxflow
Sdks

TypeScript/JavaScript SDK

El SDK oficial de TypeScript/JavaScript para Worxflow proporciona seguridad de tipos completa y es compatible tanto con entornos Node.js como de navegador, lo que te permite ejecutar flujos de trabajo programáticamente desde tus aplicaciones Node.js, aplicaciones web y otros entornos JavaScript.

El SDK de TypeScript proporciona seguridad de tipos completa, soporte para ejecución asíncrona, limitación automática de velocidad con retroceso exponencial y seguimiento de uso.

Instalación

Instala el SDK usando tu gestor de paquetes preferido:

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

Inicio rápido

Aquí tienes un ejemplo sencillo para empezar:

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

Referencia de la API

SimStudioClient

Constructor

new SimStudioClient(config: SimStudioConfig)

Configuración:

  • config.apiKey (string): Tu clave API de Sim
  • config.baseUrl (string, opcional): URL base para la API de Worxflow (por defecto es https://worxflow.ai)

Métodos

executeWorkflow()

Ejecuta un flujo de trabajo con datos de entrada opcionales.

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

Parámetros:

  • workflowId (string): El ID del flujo de trabajo a ejecutar
  • options (ExecutionOptions, opcional):
    • input (any): Datos de entrada para pasar al flujo de trabajo
    • timeout (number): Tiempo de espera en milisegundos (predeterminado: 30000)
    • stream (boolean): Habilitar respuestas en streaming (predeterminado: false)
    • selectedOutputs (string[]): Bloquear salidas para transmitir en formato blockName.attribute (por ejemplo, ["agent1.content"])
    • async (boolean): Ejecutar de forma asíncrona (predeterminado: false)

Devuelve: Promise<WorkflowExecutionResult | AsyncExecutionResult>

Cuando async: true, devuelve inmediatamente un ID de tarea para sondeo. De lo contrario, espera a que se complete.

getWorkflowStatus()

Obtener el estado de un flujo de trabajo (estado de implementación, etc.).

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

Parámetros:

  • workflowId (string): El ID del flujo de trabajo

Devuelve: Promise<WorkflowStatus>

validateWorkflow()

Validar que un flujo de trabajo está listo para su ejecución.

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

Parámetros:

  • workflowId (string): El ID del flujo de trabajo

Devuelve: Promise<boolean>

getJobStatus()

Obtener el estado de una ejecución de trabajo asíncrono.

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

Parámetros:

  • taskId (string): El ID de tarea devuelto de la ejecución asíncrona

Devuelve: Promise<JobStatus>

Campos de respuesta:

  • success (boolean): Si la solicitud fue exitosa
  • taskId (string): El ID de la tarea
  • status (string): Uno de 'queued', 'processing', 'completed', 'failed', 'cancelled'
  • metadata (object): Contiene startedAt, completedAt, y duration
  • output (any, opcional): La salida del flujo de trabajo (cuando se completa)
  • error (any, opcional): Detalles del error (cuando falla)
  • estimatedDuration (number, opcional): Duración estimada en milisegundos (cuando está procesando/en cola)
executeWithRetry()

Ejecuta un flujo de trabajo con reintento automático en errores de límite de tasa utilizando retroceso exponencial.

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

Parámetros:

  • workflowId (string): El ID del flujo de trabajo a ejecutar
  • options (ExecutionOptions, opcional): Igual que executeWorkflow()
  • retryOptions (RetryOptions, opcional):
    • maxRetries (number): Número máximo de reintentos (predeterminado: 3)
    • initialDelay (number): Retraso inicial en ms (predeterminado: 1000)
    • maxDelay (number): Retraso máximo en ms (predeterminado: 30000)
    • backoffMultiplier (number): Multiplicador de retroceso (predeterminado: 2)

Devuelve: Promise<WorkflowExecutionResult | AsyncExecutionResult>

La lógica de reintento utiliza retroceso exponencial (1s → 2s → 4s → 8s...) con fluctuación de ±25% para evitar el efecto de manada. Si la API proporciona una cabecera retry-after, se utilizará en su lugar.

getRateLimitInfo()

Obtiene la información actual del límite de tasa de la última respuesta de la 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));
}

Devuelve: RateLimitInfo | null

getUsageLimits()

Obtiene los límites de uso actuales y la información de cuota para tu cuenta.

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

Devuelve: Promise<UsageLimits>

Estructura de respuesta:

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

Actualiza la clave API.

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

Actualiza la URL base.

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

Tipos

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

Códigos de error comunes:

  • UNAUTHORIZED: Clave API inválida
  • TIMEOUT: Tiempo de espera agotado
  • RATE_LIMIT_EXCEEDED: Límite de tasa excedido
  • USAGE_LIMIT_EXCEEDED: Límite de uso excedido
  • EXECUTION_ERROR: Ejecución del flujo de trabajo fallida

Ejemplos

Ejecución básica de flujo de trabajo

Configura el SimStudioClient con tu clave API.

Comprueba si el flujo de trabajo está desplegado y listo para su ejecución.

Ejecuta el flujo de trabajo con tus datos de entrada.

Procesa el resultado de la ejecución y gestiona cualquier error.

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

Manejo de errores

Maneja diferentes tipos de errores que pueden ocurrir durante la ejecución del flujo de trabajo:

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

Configuración del entorno

Configura el cliente usando variables de entorno:

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

Integración con Express de Node.js

Integra con un servidor 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');
});

Ruta API de Next.js

Uso con rutas API de Next.js:

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

Uso del navegador

Uso en el navegador (con configuración CORS adecuada):

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

Cuando uses el SDK en el navegador, ten cuidado de no exponer claves API sensibles. Considera usar un proxy de backend o claves API públicas con permisos limitados.

Ejemplo de hook de React

Crea un hook personalizado de React para la ejecución de flujos de trabajo:

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

Ejecución asíncrona de flujos de trabajo

Ejecuta flujos de trabajo de forma asíncrona para tareas de larga duración:

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

Límite de tasa y reintentos

Maneja límites de tasa automáticamente con retroceso exponencial:

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

Monitoreo de uso

Monitorea el uso de tu cuenta y sus límites:

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 {
    // Habilita streaming para salidas de bloques específicos
    const result = await client.executeWorkflow('workflow-id', {
      input: { message: 'Count to five' },
      stream: true,
      selectedOutputs: ['agent1.content'] // Usa el formato blockName.attribute
    });

    console.log('Resultado del flujo de trabajo:', 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":", dos"}

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

    // 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://worxflow.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 (
    <div>
      <button onClick={executeStreaming} disabled={loading}>
        {loading ? 'Generando...' : 'Iniciar streaming'}
      </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';

// Type-safe client initialization
const client: SimStudioClient = new SimStudioClient({
  apiKey: process.env.SIM_API_KEY!
});

// Type-safe workflow execution
const result: WorkflowExecutionResult = await client.executeWorkflow('workflow-id', {
  input: {
    message: '¡Hola, TypeScript!'
  }
});

// Type-safe status checking
const status: WorkflowStatus = await client.getWorkflowStatus('workflow-id');

License

Apache-2.0

TypeScript/JavaScript SDK