--- description: Adding new integrations (tools, blocks, triggers) globs: ["apps/sim/tools/**", "apps/sim/blocks/**", "apps/sim/triggers/**"] --- # Adding Integrations ## Overview Adding a new integration typically requires: 1. **Tools** - API operations (`tools/{service}/`) 2. **Block** - UI component (`blocks/blocks/{service}.ts`) 3. **Icon** - SVG icon (`components/icons.tsx`) 4. **Trigger** (optional) - Webhooks/polling (`triggers/{service}/`) Always look up the service's API docs first. ## 1. Tools (`tools/{service}/`) ``` tools/{service}/ ├── index.ts # Export all tools ├── types.ts # Params/response types ├── {action}.ts # Individual tool (e.g., send_message.ts) └── ... ``` **Tool file structure:** ```typescript // tools/{service}/{action}.ts import type { {Service}Params, {Service}Response } from '@/tools/{service}/types' import type { ToolConfig } from '@/tools/types' export const {service}{Action}Tool: ToolConfig<{Service}Params, {Service}Response> = { id: '{service}_{action}', name: '{Service} {Action}', description: 'What this tool does', version: '1.0.0', oauth: { required: true, provider: '{service}' }, // if OAuth params: { /* param definitions */ }, request: { url: '/api/tools/{service}/{action}', method: 'POST', headers: () => ({ 'Content-Type': 'application/json' }), body: (params) => ({ ...params }), }, transformResponse: async (response) => { const data = await response.json() if (!data.success) throw new Error(data.error) return { success: true, output: data.output } }, outputs: { /* output definitions */ }, } ``` **Register in `tools/registry.ts`:** ```typescript import { {service}{Action}Tool } from '@/tools/{service}' // Add to registry object {service}_{action}: {service}{Action}Tool, ``` ## 2. Block (`blocks/blocks/{service}.ts`) ```typescript import { {Service}Icon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' import type { {Service}Response } from '@/tools/{service}/types' export const {Service}Block: BlockConfig<{Service}Response> = { type: '{service}', name: '{Service}', description: 'Short description', longDescription: 'Detailed description', category: 'tools', bgColor: '#hexcolor', icon: {Service}Icon, subBlocks: [ /* see SubBlock Properties below */ ], tools: { access: ['{service}_{action}', ...], config: { tool: (params) => `{service}_${params.operation}`, params: (params) => ({ ...params }), }, }, inputs: { /* input definitions */ }, outputs: { /* output definitions */ }, } ``` ### SubBlock Properties ```typescript { id: 'fieldName', // Unique identifier title: 'Field Label', // UI label type: 'short-input', // See SubBlock Types below placeholder: 'Hint text', required: true, // See Required below condition: { ... }, // See Condition below dependsOn: ['otherField'], // See DependsOn below mode: 'basic', // 'basic' | 'advanced' | 'both' | 'trigger' } ``` **SubBlock Types:** `short-input`, `long-input`, `dropdown`, `code`, `switch`, `slider`, `oauth-input`, `channel-selector`, `user-selector`, `file-upload`, etc. ### `condition` - Show/hide based on another field ```typescript // Show when operation === 'send' condition: { field: 'operation', value: 'send' } // Show when operation is 'send' OR 'read' condition: { field: 'operation', value: ['send', 'read'] } // Show when operation !== 'send' condition: { field: 'operation', value: 'send', not: true } // Complex: NOT in list AND another condition condition: { field: 'operation', value: ['list_channels', 'list_users'], not: true, and: { field: 'destinationType', value: 'dm', not: true } } ``` ### `required` - Field validation ```typescript // Always required required: true // Conditionally required (same syntax as condition) required: { field: 'operation', value: 'send' } ``` ### `dependsOn` - Clear field when dependencies change ```typescript // Clear when credential changes dependsOn: ['credential'] // Clear when authMethod changes AND (credential OR botToken) changes dependsOn: { all: ['authMethod'], any: ['credential', 'botToken'] } ``` ### `mode` - When to show field - `'basic'` - Only in basic mode (default UI) - `'advanced'` - Only in advanced mode (manual input) - `'both'` - Show in both modes (default) - `'trigger'` - Only when block is used as trigger **Register in `blocks/registry.ts`:** ```typescript import { {Service}Block } from '@/blocks/blocks/{service}' // Add to registry object (alphabetically) {service}: {Service}Block, ``` ## 3. Icon (`components/icons.tsx`) ```typescript export function {Service}Icon(props: SVGProps) { return ( {/* SVG path from service's brand assets */} ) } ``` ## 4. Trigger (`triggers/{service}/`) - Optional ``` triggers/{service}/ ├── index.ts # Export all triggers ├── webhook.ts # Webhook handler ├── utils.ts # Shared utilities └── {event}.ts # Specific event handlers ``` **Register in `triggers/registry.ts`:** ```typescript import { {service}WebhookTrigger } from '@/triggers/{service}' // Add to TRIGGER_REGISTRY {service}_webhook: {service}WebhookTrigger, ``` ## Checklist - [ ] Look up API docs for the service - [ ] Create `tools/{service}/types.ts` with proper types - [ ] Create tool files for each operation - [ ] Create `tools/{service}/index.ts` barrel export - [ ] Register tools in `tools/registry.ts` - [ ] Add icon to `components/icons.tsx` - [ ] Create block in `blocks/blocks/{service}.ts` - [ ] Register block in `blocks/registry.ts` - [ ] (Optional) Create triggers in `triggers/{service}/` - [ ] (Optional) Register triggers in `triggers/registry.ts`