mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-09 06:58:07 -05:00
feat(supabase): added vector search tool and updated docs (#1707)
* feat(supabase): added vector search tool and updated docs * exclude generic webhook from docs gen * change items to pages in meta.json for tools directory in the docs
This commit is contained in:
@@ -75,6 +75,7 @@ Send a message to a Discord channel
|
||||
| `channelId` | string | Yes | The Discord channel ID to send the message to |
|
||||
| `content` | string | No | The text content of the message |
|
||||
| `serverId` | string | Yes | The Discord server ID \(guild ID\) |
|
||||
| `files` | file[] | No | Files to attach to the message |
|
||||
|
||||
#### Output
|
||||
|
||||
|
||||
@@ -230,4 +230,4 @@ curl -X POST https://sim.ai/api/webhooks/trigger/{webhook-path} \
|
||||
- Category: `triggers`
|
||||
- Type: `generic_webhook`
|
||||
- **File Support**: Available via input format configuration
|
||||
- **Max File Size**: 20MB per file
|
||||
- **Max File Size**: 20MB per file
|
||||
@@ -88,8 +88,9 @@ Upload a file to Google Drive
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `fileName` | string | Yes | The name of the file to upload |
|
||||
| `content` | string | Yes | The content of the file to upload |
|
||||
| `mimeType` | string | No | The MIME type of the file to upload |
|
||||
| `file` | file | No | Binary file to upload \(UserFile object\) |
|
||||
| `content` | string | No | Text content to upload \(use this OR file, not both\) |
|
||||
| `mimeType` | string | No | The MIME type of the file to upload \(auto-detected from file if not provided\) |
|
||||
| `folderSelector` | string | No | Select the folder to upload the file to |
|
||||
| `folderId` | string | No | The ID of the folder to upload the file to \(internal use\) |
|
||||
|
||||
|
||||
@@ -138,6 +138,7 @@ Write or update content in a Microsoft Teams chat
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `chatId` | string | Yes | The ID of the chat to write to |
|
||||
| `content` | string | Yes | The content to write to the message |
|
||||
| `files` | file[] | No | Files to attach to the message |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -187,6 +188,7 @@ Write or send a message to a Microsoft Teams channel
|
||||
| `teamId` | string | Yes | The ID of the team to write to |
|
||||
| `channelId` | string | Yes | The ID of the channel to write to |
|
||||
| `content` | string | Yes | The content to write to the channel |
|
||||
| `files` | file[] | No | Files to attach to the message |
|
||||
|
||||
#### Output
|
||||
|
||||
|
||||
@@ -66,7 +66,8 @@ Upload a file to OneDrive
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `fileName` | string | Yes | The name of the file to upload |
|
||||
| `content` | string | Yes | The content of the file to upload |
|
||||
| `file` | file | No | The file to upload \(binary\) |
|
||||
| `content` | string | No | The text content to upload \(if no file is provided\) |
|
||||
| `folderSelector` | string | No | Select the folder to upload the file to |
|
||||
| `manualFolderId` | string | No | Manually entered folder ID \(advanced mode\) |
|
||||
|
||||
|
||||
@@ -161,6 +161,7 @@ Send emails using Outlook
|
||||
| `conversationId` | string | No | Conversation ID for threading |
|
||||
| `cc` | string | No | CC recipients \(comma-separated\) |
|
||||
| `bcc` | string | No | BCC recipients \(comma-separated\) |
|
||||
| `attachments` | file[] | No | Files to attach to the email |
|
||||
|
||||
#### Output
|
||||
|
||||
@@ -184,6 +185,7 @@ Draft emails using Outlook
|
||||
| `body` | string | Yes | Email body content |
|
||||
| `cc` | string | No | CC recipients \(comma-separated\) |
|
||||
| `bcc` | string | No | BCC recipients \(comma-separated\) |
|
||||
| `attachments` | file[] | No | Files to attach to the email draft |
|
||||
|
||||
#### Output
|
||||
|
||||
|
||||
@@ -202,6 +202,26 @@ Add a new item to a SharePoint list
|
||||
| --------- | ---- | ----------- |
|
||||
| `item` | object | Created SharePoint list item |
|
||||
|
||||
### `sharepoint_upload_file`
|
||||
|
||||
Upload files to a SharePoint document library
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `siteId` | string | No | The ID of the SharePoint site |
|
||||
| `driveId` | string | No | The ID of the document library \(drive\). If not provided, uses default drive. |
|
||||
| `folderPath` | string | No | Optional folder path within the document library \(e.g., /Documents/Subfolder\) |
|
||||
| `fileName` | string | No | Optional: override the uploaded file name |
|
||||
| `files` | file[] | No | Files to upload to SharePoint |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `uploadedFiles` | array | Array of uploaded file objects |
|
||||
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
@@ -82,6 +82,7 @@ Send messages to Slack channels or users through the Slack API. Supports Slack m
|
||||
| `botToken` | string | No | Bot token for Custom Bot |
|
||||
| `channel` | string | Yes | Target Slack channel \(e.g., #general\) |
|
||||
| `text` | string | Yes | Message text to send \(supports Slack mrkdwn formatting\) |
|
||||
| `files` | file[] | No | Files to attach to the message |
|
||||
|
||||
#### Output
|
||||
|
||||
|
||||
@@ -205,6 +205,28 @@ Insert or update data in a Supabase table (upsert operation)
|
||||
| `message` | string | Operation status message |
|
||||
| `results` | array | Array of upserted records |
|
||||
|
||||
### `supabase_vector_search`
|
||||
|
||||
Perform similarity search using pgvector in a Supabase table
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `projectId` | string | Yes | Your Supabase project ID \(e.g., jdrkgepadsdopsntdlom\) |
|
||||
| `functionName` | string | Yes | The name of the PostgreSQL function that performs vector search \(e.g., match_documents\) |
|
||||
| `queryEmbedding` | array | Yes | The query vector/embedding to search for similar items |
|
||||
| `matchThreshold` | number | No | Minimum similarity threshold \(0-1\), typically 0.7-0.9 |
|
||||
| `matchCount` | number | No | Maximum number of results to return \(default: 10\) |
|
||||
| `apiKey` | string | Yes | Your Supabase service role secret key |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `message` | string | Operation status message |
|
||||
| `results` | array | Array of records with similarity scores from the vector search. Each record includes a similarity field \(0-1\) indicating how similar it is to the query vector. |
|
||||
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
@@ -191,6 +191,26 @@ Send animations (GIFs) to Telegram channels or users through the Telegram Bot AP
|
||||
| `message` | string | Success or error message |
|
||||
| `data` | object | Telegram message data including optional media |
|
||||
|
||||
### `telegram_send_document`
|
||||
|
||||
Send documents (PDF, ZIP, DOC, etc.) to Telegram channels or users through the Telegram Bot API.
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `botToken` | string | Yes | Your Telegram Bot API Token |
|
||||
| `chatId` | string | Yes | Target Telegram chat ID |
|
||||
| `files` | file[] | No | Document file to send \(PDF, ZIP, DOC, etc.\). Max size: 50MB |
|
||||
| `caption` | string | No | Document caption \(optional\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `message` | string | Success or error message |
|
||||
| `data` | object | Telegram message data including document |
|
||||
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
@@ -62,7 +62,8 @@ Process and analyze images using advanced vision models. Capable of understandin
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `apiKey` | string | Yes | API key for the selected model provider |
|
||||
| `imageUrl` | string | Yes | Publicly accessible image URL |
|
||||
| `imageUrl` | string | No | Publicly accessible image URL |
|
||||
| `imageFile` | file | No | Image file to analyze |
|
||||
| `model` | string | No | Vision model to use \(gpt-4o, claude-3-opus-20240229, etc\) |
|
||||
| `prompt` | string | No | Custom prompt for image analysis |
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ export const SupabaseBlock: BlockConfig<SupabaseResponse> = {
|
||||
{ label: 'Update a Row', id: 'update' },
|
||||
{ label: 'Delete a Row', id: 'delete' },
|
||||
{ label: 'Upsert a Row', id: 'upsert' },
|
||||
{ label: 'Vector Search', id: 'vector_search' },
|
||||
],
|
||||
value: () => 'query',
|
||||
},
|
||||
@@ -381,6 +382,41 @@ Return ONLY the PostgREST filter expression - no explanations, no markdown, no e
|
||||
placeholder: '100',
|
||||
condition: { field: 'operation', value: 'query' },
|
||||
},
|
||||
// Vector search operation fields
|
||||
{
|
||||
id: 'functionName',
|
||||
title: 'Function Name',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'match_documents',
|
||||
condition: { field: 'operation', value: 'vector_search' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'queryEmbedding',
|
||||
title: 'Query Embedding',
|
||||
type: 'code',
|
||||
layout: 'full',
|
||||
placeholder: '[0.1, 0.2, 0.3, ...]',
|
||||
condition: { field: 'operation', value: 'vector_search' },
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'matchThreshold',
|
||||
title: 'Match Threshold (optional)',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: '0.78',
|
||||
condition: { field: 'operation', value: 'vector_search' },
|
||||
},
|
||||
{
|
||||
id: 'matchCount',
|
||||
title: 'Match Count (optional)',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: '10',
|
||||
condition: { field: 'operation', value: 'vector_search' },
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
access: [
|
||||
@@ -390,6 +426,7 @@ Return ONLY the PostgREST filter expression - no explanations, no markdown, no e
|
||||
'supabase_update',
|
||||
'supabase_delete',
|
||||
'supabase_upsert',
|
||||
'supabase_vector_search',
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
@@ -406,12 +443,14 @@ Return ONLY the PostgREST filter expression - no explanations, no markdown, no e
|
||||
return 'supabase_delete'
|
||||
case 'upsert':
|
||||
return 'supabase_upsert'
|
||||
case 'vector_search':
|
||||
return 'supabase_vector_search'
|
||||
default:
|
||||
throw new Error(`Invalid Supabase operation: ${params.operation}`)
|
||||
}
|
||||
},
|
||||
params: (params) => {
|
||||
const { operation, data, filter, ...rest } = params
|
||||
const { operation, data, filter, queryEmbedding, ...rest } = params
|
||||
|
||||
// Parse JSON data if it's a string
|
||||
let parsedData
|
||||
@@ -435,6 +474,21 @@ Return ONLY the PostgREST filter expression - no explanations, no markdown, no e
|
||||
parsedFilter = filter.trim()
|
||||
}
|
||||
|
||||
// Handle query embedding for vector search
|
||||
let parsedQueryEmbedding
|
||||
if (queryEmbedding && typeof queryEmbedding === 'string' && queryEmbedding.trim()) {
|
||||
try {
|
||||
parsedQueryEmbedding = JSON.parse(queryEmbedding)
|
||||
} catch (parseError) {
|
||||
const errorMsg = parseError instanceof Error ? parseError.message : 'Unknown JSON error'
|
||||
throw new Error(
|
||||
`Invalid query embedding format: ${errorMsg}. Please provide a valid array of numbers like [0.1, 0.2, 0.3].`
|
||||
)
|
||||
}
|
||||
} else if (queryEmbedding && Array.isArray(queryEmbedding)) {
|
||||
parsedQueryEmbedding = queryEmbedding
|
||||
}
|
||||
|
||||
// Build params object, only including defined values
|
||||
const result = { ...rest }
|
||||
|
||||
@@ -446,6 +500,10 @@ Return ONLY the PostgREST filter expression - no explanations, no markdown, no e
|
||||
result.filter = parsedFilter
|
||||
}
|
||||
|
||||
if (parsedQueryEmbedding !== undefined) {
|
||||
result.queryEmbedding = parsedQueryEmbedding
|
||||
}
|
||||
|
||||
return result
|
||||
},
|
||||
},
|
||||
@@ -462,6 +520,11 @@ Return ONLY the PostgREST filter expression - no explanations, no markdown, no e
|
||||
// Query operation inputs
|
||||
orderBy: { type: 'string', description: 'Sort column' },
|
||||
limit: { type: 'number', description: 'Result limit' },
|
||||
// Vector search operation inputs
|
||||
functionName: { type: 'string', description: 'PostgreSQL function name for vector search' },
|
||||
queryEmbedding: { type: 'array', description: 'Query vector/embedding for similarity search' },
|
||||
matchThreshold: { type: 'number', description: 'Minimum similarity threshold (0-1)' },
|
||||
matchCount: { type: 'number', description: 'Maximum number of similar results to return' },
|
||||
},
|
||||
outputs: {
|
||||
message: {
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { JSX, SVGProps } from 'react'
|
||||
import type { ToolResponse } from '@/tools/types'
|
||||
|
||||
export type BlockIcon = (props: SVGProps<SVGSVGElement>) => JSX.Element
|
||||
export type ParamType = 'string' | 'number' | 'boolean' | 'json'
|
||||
export type ParamType = 'string' | 'number' | 'boolean' | 'json' | 'array'
|
||||
export type PrimitiveValueType =
|
||||
| 'string'
|
||||
| 'number'
|
||||
|
||||
@@ -180,6 +180,7 @@ import {
|
||||
supabaseQueryTool,
|
||||
supabaseUpdateTool,
|
||||
supabaseUpsertTool,
|
||||
supabaseVectorSearchTool,
|
||||
} from '@/tools/supabase'
|
||||
import { tavilyExtractTool, tavilySearchTool } from '@/tools/tavily'
|
||||
import {
|
||||
@@ -271,6 +272,7 @@ export const tools: Record<string, ToolConfig> = {
|
||||
supabase_update: supabaseUpdateTool,
|
||||
supabase_delete: supabaseDeleteTool,
|
||||
supabase_upsert: supabaseUpsertTool,
|
||||
supabase_vector_search: supabaseVectorSearchTool,
|
||||
typeform_responses: typeformResponsesTool,
|
||||
typeform_files: typeformFilesTool,
|
||||
typeform_insights: typeformInsightsTool,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { insertTool } from '@/tools/supabase/insert'
|
||||
import { queryTool } from '@/tools/supabase/query'
|
||||
import { updateTool } from '@/tools/supabase/update'
|
||||
import { upsertTool } from '@/tools/supabase/upsert'
|
||||
import { vectorSearchTool } from '@/tools/supabase/vector_search'
|
||||
|
||||
export const supabaseQueryTool = queryTool
|
||||
export const supabaseInsertTool = insertTool
|
||||
@@ -11,3 +12,4 @@ export const supabaseGetRowTool = getRowTool
|
||||
export const supabaseUpdateTool = updateTool
|
||||
export const supabaseDeleteTool = deleteTool
|
||||
export const supabaseUpsertTool = upsertTool
|
||||
export const supabaseVectorSearchTool = vectorSearchTool
|
||||
|
||||
@@ -45,6 +45,15 @@ export interface SupabaseUpsertParams {
|
||||
data: any
|
||||
}
|
||||
|
||||
export interface SupabaseVectorSearchParams {
|
||||
apiKey: string
|
||||
projectId: string
|
||||
functionName: string
|
||||
queryEmbedding: number[]
|
||||
matchThreshold?: number
|
||||
matchCount?: number
|
||||
}
|
||||
|
||||
export interface SupabaseBaseResponse extends ToolResponse {
|
||||
output: {
|
||||
message: string
|
||||
@@ -65,4 +74,6 @@ export interface SupabaseDeleteResponse extends SupabaseBaseResponse {}
|
||||
|
||||
export interface SupabaseUpsertResponse extends SupabaseBaseResponse {}
|
||||
|
||||
export interface SupabaseVectorSearchResponse extends SupabaseBaseResponse {}
|
||||
|
||||
export interface SupabaseResponse extends SupabaseBaseResponse {}
|
||||
|
||||
125
apps/sim/tools/supabase/vector_search.ts
Normal file
125
apps/sim/tools/supabase/vector_search.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import type {
|
||||
SupabaseVectorSearchParams,
|
||||
SupabaseVectorSearchResponse,
|
||||
} from '@/tools/supabase/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const vectorSearchTool: ToolConfig<
|
||||
SupabaseVectorSearchParams,
|
||||
SupabaseVectorSearchResponse
|
||||
> = {
|
||||
id: 'supabase_vector_search',
|
||||
name: 'Supabase Vector Search',
|
||||
description: 'Perform similarity search using pgvector in a Supabase table',
|
||||
version: '1.0',
|
||||
|
||||
params: {
|
||||
projectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Your Supabase project ID (e.g., jdrkgepadsdopsntdlom)',
|
||||
},
|
||||
functionName: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'The name of the PostgreSQL function that performs vector search (e.g., match_documents)',
|
||||
},
|
||||
queryEmbedding: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The query vector/embedding to search for similar items',
|
||||
},
|
||||
matchThreshold: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Minimum similarity threshold (0-1), typically 0.7-0.9',
|
||||
},
|
||||
matchCount: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of results to return (default: 10)',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Your Supabase service role secret key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
// Use RPC endpoint for calling PostgreSQL functions
|
||||
return `https://${params.projectId}.supabase.co/rest/v1/rpc/${params.functionName}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
apikey: params.apiKey,
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
// Build the RPC call parameters
|
||||
const rpcParams: Record<string, any> = {
|
||||
query_embedding: params.queryEmbedding,
|
||||
}
|
||||
|
||||
// Add optional parameters if provided
|
||||
if (params.matchThreshold !== undefined) {
|
||||
rpcParams.match_threshold = params.matchThreshold
|
||||
}
|
||||
|
||||
if (params.matchCount !== undefined) {
|
||||
rpcParams.match_count = params.matchCount
|
||||
}
|
||||
|
||||
return rpcParams
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
let data
|
||||
try {
|
||||
data = await response.json()
|
||||
} catch (parseError) {
|
||||
throw new Error(`Failed to parse Supabase vector search response: ${parseError}`)
|
||||
}
|
||||
|
||||
const resultCount = Array.isArray(data) ? data.length : 0
|
||||
|
||||
if (resultCount === 0) {
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
message: 'No similar vectors found matching the search criteria',
|
||||
results: data,
|
||||
},
|
||||
error: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
message: `Successfully found ${resultCount} similar vector${resultCount === 1 ? '' : 's'}`,
|
||||
results: data,
|
||||
},
|
||||
error: undefined,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
message: { type: 'string', description: 'Operation status message' },
|
||||
results: {
|
||||
type: 'array',
|
||||
description:
|
||||
'Array of records with similarity scores from the vector search. Each record includes a similarity field (0-1) indicating how similar it is to the query vector.',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -838,7 +838,7 @@ async function generateBlockDoc(blockPath: string, icons: Record<string, string>
|
||||
return
|
||||
}
|
||||
|
||||
if (blockConfig.type.includes('_trigger')) {
|
||||
if (blockConfig.type.includes('_trigger') || blockConfig.type.includes('_webhook')) {
|
||||
console.log(`Skipping ${blockConfig.type} - contains '_trigger'`)
|
||||
return
|
||||
}
|
||||
@@ -1111,7 +1111,7 @@ function updateMetaJson() {
|
||||
]
|
||||
|
||||
const metaJson = {
|
||||
items,
|
||||
pages: items,
|
||||
}
|
||||
|
||||
fs.writeFileSync(metaJsonPath, JSON.stringify(metaJson, null, 2))
|
||||
|
||||
Reference in New Issue
Block a user