mirror of
https://github.com/simstudioai/sim.git
synced 2026-02-05 04:05:14 -05:00
* improvement(collab): do not refetch active workflow id * progress on files * more integrations * separate server and client logic * consolidate more code * fix integrations * fix types * consolidate more code * fix tests * fix more bugbot comments * fix type check * fix circular impport * address more bugbot comments * fix ocr integrations * fix typing * remove leftover type * address bugbot comment * fix file block adv mode * fix * normalize file input * fix v2 blocmks for ocr * fix for v2 versions * fix more v2 blocks * update single file blocks * make interface simpler * cleanup fireflies * remove file only annotation * accept all types * added wand to ssh block * user files should be passed through * improve docs * fix slack to include successful execs * fix dropbox upload file * fix sendgrid * fix dropbox * fix * fix * update skills * fix uploaded file --------- Co-authored-by: waleed <walif6@gmail.com>
256 lines
7.5 KiB
Plaintext
256 lines
7.5 KiB
Plaintext
---
|
|
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<SVGSVGElement>) {
|
|
return (
|
|
<svg {...props} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
{/* SVG path from service's brand assets */}
|
|
</svg>
|
|
)
|
|
}
|
|
```
|
|
|
|
## 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,
|
|
```
|
|
|
|
## File Handling
|
|
|
|
When integrations handle file uploads/downloads, use `UserFile` objects consistently.
|
|
|
|
### File Input (Uploads)
|
|
|
|
1. **Block subBlocks:** Use basic/advanced mode pattern with `canonicalParamId`
|
|
2. **Normalize in block config:** Use `normalizeFileInput` from `@/blocks/utils`
|
|
3. **Internal API route:** Create route that uses `downloadFileFromStorage` to get file content
|
|
4. **Tool routes to internal API:** Don't call external APIs directly with files
|
|
|
|
```typescript
|
|
// In block tools.config:
|
|
import { normalizeFileInput } from '@/blocks/utils'
|
|
|
|
const normalizedFile = normalizeFileInput(
|
|
params.uploadFile || params.fileRef || params.fileContent,
|
|
{ single: true }
|
|
)
|
|
if (normalizedFile) params.file = normalizedFile
|
|
```
|
|
|
|
### File Output (Downloads)
|
|
|
|
Use `FileToolProcessor` in tool `transformResponse` to store files:
|
|
|
|
```typescript
|
|
import { FileToolProcessor } from '@/executor/utils/file-tool-processor'
|
|
|
|
const processor = new FileToolProcessor(context)
|
|
const file = await processor.processFileData({
|
|
data: base64Content,
|
|
mimeType: 'application/pdf',
|
|
filename: 'doc.pdf',
|
|
})
|
|
```
|
|
|
|
### Key Helpers
|
|
|
|
| Helper | Location | Purpose |
|
|
|--------|----------|---------|
|
|
| `normalizeFileInput` | `@/blocks/utils` | Normalize file params in block config |
|
|
| `processFilesToUserFiles` | `@/lib/uploads/utils/file-utils` | Convert raw inputs to UserFile[] |
|
|
| `downloadFileFromStorage` | `@/lib/uploads/utils/file-utils.server` | Get Buffer from UserFile |
|
|
| `FileToolProcessor` | `@/executor/utils/file-tool-processor` | Process tool output files |
|
|
|
|
## 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`
|
|
- [ ] (If file uploads) Create internal API route with `downloadFileFromStorage`
|
|
- [ ] (If file uploads) Use `normalizeFileInput` in block config
|