Compare commits

...

3 Commits

Author SHA1 Message Date
waleed
3696658b03 changed zapier to use oauth 2025-12-09 14:28:04 -08:00
waleed
4d9ae94047 working checkbox, need to add zapier oauth2 2025-12-09 14:13:50 -08:00
waleed
ce72880935 feat(tools): added zapier 2025-12-09 13:20:48 -08:00
25 changed files with 2974 additions and 19 deletions

View File

@@ -4151,7 +4151,7 @@ export function DuckDuckGoIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='-108 -108 216 216'>
<circle r='108' fill='#d53' />
<circle r='96' fill='none' stroke='#ffffff' stroke-width='7' />
<circle r='96' fill='none' stroke='#ffffff' strokeWidth='7' />
<path
d='M-32-55C-62-48-51-6-51-6l19 93 7 3M-39-73h-8l11 4s-11 0-11 7c24-1 35 5 35 5'
fill='#ddd'
@@ -4199,3 +4199,25 @@ export function RssIcon(props: SVGProps<SVGSVGElement>) {
</svg>
)
}
export function ZapierIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
{...props}
width='800px'
height='800px'
viewBox='0 0 256 256'
version='1.1'
xmlns='http://www.w3.org/2000/svg'
xmlnsXlink='http://www.w3.org/1999/xlink'
>
<g>
<path
d='M128.080089,-0.000183105 C135.311053,0.0131003068 142.422517,0.624138494 149.335663,1.77979593 L149.335663,1.77979593 L149.335663,76.2997796 L202.166953,23.6044907 C208.002065,27.7488446 213.460883,32.3582023 218.507811,37.3926715 C223.557281,42.4271407 228.192318,47.8867213 232.346817,53.7047992 L232.346817,53.7047992 L179.512985,106.400063 L254.227854,106.400063 C255.387249,113.29414 256,120.36111 256,127.587243 L256,127.587243 L256,127.759881 C256,134.986013 255.387249,142.066204 254.227854,148.960282 L254.227854,148.960282 L179.500273,148.960282 L232.346817,201.642324 C228.192318,207.460402 223.557281,212.919983 218.523066,217.954452 L218.523066,217.954452 L218.507811,217.954452 C213.460883,222.988921 208.002065,227.6115 202.182208,231.742607 L202.182208,231.742607 L149.335663,179.04709 L149.335663,253.5672 C142.435229,254.723036 135.323765,255.333244 128.092802,255.348499 L128.092802,255.348499 L127.907197,255.348499 C120.673691,255.333244 113.590195,254.723036 106.677048,253.5672 L106.677048,253.5672 L106.677048,179.04709 L53.8457596,231.742607 C42.1780766,223.466917 31.977435,213.278734 23.6658953,201.642324 L23.6658953,201.642324 L76.4997269,148.960282 L1.78485803,148.960282 C0.612750404,142.052729 0,134.946095 0,127.719963 L0,127.719963 L0,127.349037 C0.0121454869,125.473817 0.134939797,123.182933 0.311311815,120.812834 L0.36577283,120.099764 C0.887996182,113.428547 1.78485803,106.400063 1.78485803,106.400063 L1.78485803,106.400063 L76.4997269,106.400063 L23.6658953,53.7047992 C27.8076812,47.8867213 32.4300059,42.4403618 37.4769335,37.4193681 L37.4769335,37.4193681 L37.5023588,37.3926715 C42.5391163,32.3582023 48.0106469,27.7488446 53.8457596,23.6044907 L53.8457596,23.6044907 L106.677048,76.2997796 L106.677048,1.77979593 C113.590195,0.624138494 120.688946,0.0131003068 127.932622,-0.000183105 L127.932622,-0.000183105 L128.080089,-0.000183105 Z M128.067377,95.7600714 L127.945335,95.7600714 C118.436262,95.7600714 109.32891,97.5001809 100.910584,100.661566 C97.7553011,109.043534 96.0085811,118.129275 95.9958684,127.613685 L95.9958684,127.733184 C96.0085811,137.217594 97.7553011,146.303589 100.923296,154.685303 C109.32891,157.846943 118.436262,159.587052 127.945335,159.587052 L128.067377,159.587052 C137.576449,159.587052 146.683802,157.846943 155.089415,154.685303 C158.257411,146.290368 160.004131,137.217594 160.004131,127.733184 L160.004131,127.613685 C160.004131,118.129275 158.257411,109.043534 155.089415,100.661566 C146.683802,97.5001809 137.576449,95.7600714 128.067377,95.7600714 Z'
fill='#FF4A00'
fillRule='nonzero'
/>
</g>
</svg>
)
}

View File

@@ -110,6 +110,7 @@ import {
WordpressIcon,
xIcon,
YouTubeIcon,
ZapierIcon,
ZendeskIcon,
ZepIcon,
ZoomIcon,
@@ -121,6 +122,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
zoom: ZoomIcon,
zep: ZepIcon,
zendesk: ZendeskIcon,
zapier: ZapierIcon,
youtube: YouTubeIcon,
x: xIcon,
wordpress: WordpressIcon,

View File

@@ -110,6 +110,7 @@
"wordpress",
"x",
"youtube",
"zapier",
"zendesk",
"zep",
"zoom"

View File

@@ -0,0 +1,275 @@
---
title: Zapier
description: Execute actions across 7,000+ apps using Zapier AI Actions
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="zapier"
color="#FFFFFF"
/>
{/* MANUAL-CONTENT-START:intro */}
[Zapier](https://zapier.com/) connects 7,000+ apps and automates workflows without manual coding. The Zapier integration in Sim empowers you to execute, search, build, and manage powerful AI-driven actions across thousands of applications—all with plain English instructions.
With Zapier AI Actions in Sim, you can:
- **Execute Actions:** Instantly trigger any stored AI Action in your Zapier account. Launch emails, messages, project updates, document workflows, CRM updates, and much more.
- **List Actions:** Retrieve a list of your available AI Actions configured in Zapier. Discover what's possible and find the right tool for your workflow.
- **Search Apps:** Find apps in Zapiers ecosystem by name or keyword. Easily check if the app you need is supported before building automations.
- **Find Actions (Guess):** Describe what you want to accomplish in plain English (e.g., "send a Slack message", "create a Google Sheet row"), and let Zapiers AI suggest matching actions—even across unfamiliar apps or APIs.
- **Create Actions:** Programmatically define new AI Actions by specifying the target app, action type (write, read, search), and required parameters, directly from your workflow.
By combining these capabilities, you can search for apps, define new AI Actions, discover possible automations, list available actions, and execute any workflow—fully automated, with the power of both Sim and Zapier.
{/* MANUAL-CONTENT-END */}
## Usage Instructions
Connect to Zapier AI Actions to execute any of 30,000+ actions across 7,000+ apps. Send emails, create documents, update CRMs, post messages, and more - all through natural language instructions. Requires a Zapier AI Actions API key.
## Tools
### `zapier_execute_action`
Execute a stored AI Action in Zapier. Runs any of the 30,000+ actions across 7,000+ apps that Zapier supports.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Zapier AI Actions API key from actions.zapier.com/credentials |
| `actionId` | string | Yes | The ID of the AI Action to execute |
| `instructions` | string | Yes | Plain English instructions for what the action should do \(e.g., "Send a message about the weekly report to #general"\) |
| `previewOnly` | boolean | No | If true, preview the execution without actually running it |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `executionLogId` | string | Unique identifier for this execution \(can be used for feedback\) |
| `actionUsed` | string | Name of the action that was executed |
| `inputParams` | json | Parameters that were passed to the API |
| `resolvedParams` | json | Parameters that the AI resolved for execution |
| `results` | json | Results from the action execution |
| `resultFieldLabels` | json | Human-readable labels for result fields |
| `status` | string | Execution status: success, error, empty, preview, or halted |
| `error` | string | Error message if execution failed |
### `zapier_list_actions`
List all AI Actions configured in your Zapier account. Returns stored actions that can be executed.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Zapier AI Actions API key from actions.zapier.com/credentials |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `actions` | json | Array of configured AI Actions with id, description, actionType, app, appLabel, action, actionLabel, params, accountId, authenticationId, needs |
| `configurationLink` | string | Link to configure more actions in Zapier |
### `zapier_search_apps`
Search for apps available in Zapier. Returns apps with their available action counts.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Zapier AI Actions API key from actions.zapier.com/credentials |
| `query` | string | No | Optional search query to filter apps by name |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `apps` | json | Array of apps with app, name, logoUrl, authType, actions \(raw counts by type\), actionCount, writeActionCount, searchActionCount, readActionCount |
### `zapier_guess_actions`
Find relevant Zapier actions using natural language. Searches across 30,000+ actions to find the best matches for your query.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Zapier AI Actions API key from actions.zapier.com/credentials |
| `query` | string | Yes | Natural language description of what you want to do \(e.g., "send a Slack message", "create a Google Doc"\) |
| `actionTypes` | array | No | Types of actions to search for: write, search, read. If not specified, returns all types. |
| `count` | number | No | Maximum number of results to return \(default: 25\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `actions` | json | Array of matching actions with app, action, actionType, name \(combined app/action name\), description, image, and score |
### `zapier_create_action`
Create a new stored AI Action in Zapier. The action can then be executed with zapier_execute_action.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Zapier AI Actions API key from actions.zapier.com/credentials |
| `app` | string | Yes | The app identifier \(e.g., "slack", "gmail", "google-docs"\) |
| `action` | string | Yes | The action identifier \(e.g., "send_channel_message", "send_email"\) |
| `actionType` | string | No | Type of action: write, search, or read. Defaults to write. |
| `accountId` | number | No | Zapier account ID |
| `authenticationId` | number | No | Authentication ID for the app connection |
| `meta` | json | No | Metadata object with params labels, app_label, action_label, authentication_label, app_needs_auth |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | The ID of the created AI Action \(use this with execute_action\) |
| `description` | string | Description of the action |
| `actionType` | string | Type of action \(write, search, read, read_bulk, search_or_write, search_and_write\) |
| `app` | string | App identifier |
| `appLabel` | string | Human-readable app label from meta |
| `action` | string | Action identifier |
| `actionLabel` | string | Human-readable action label from meta |
### `zapier_stateless_execute`
Execute any Zapier action directly without creating a stored AI Action first. Provide the app, action, and instructions.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Zapier AI Actions API key from actions.zapier.com/credentials |
| `app` | string | Yes | The app to use \(e.g., "SlackAPI", "GoogleSheetsV2API", "GmailV2API"\) |
| `action` | string | Yes | The action to run \(e.g., "direct_message", "add_row", "send_email"\) |
| `instructions` | string | Yes | Plain English instructions about how to run the action \(e.g., "Send a message saying hello to #general"\) |
| `actionType` | string | No | Type of action: write, search, read, read_bulk, search_or_write, search_and_write |
| `previewOnly` | boolean | No | If true, preview the execution without actually running it |
| `authenticationId` | number | No | Authentication ID for the app connection |
| `accountId` | number | No | Zapier account ID |
| `providerId` | string | No | Provider ID for AI Actions |
| `tokenBudget` | number | No | Max tokens per field \(default: 1000\) |
| `skipParamGuessing` | boolean | No | Skip AI parameter guessing |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `executionLogId` | string | Unique identifier for this execution |
| `actionUsed` | string | Name of the action that was executed |
| `inputParams` | json | Parameters that were passed to the API |
| `resolvedParams` | json | Parameters that the AI resolved for execution |
| `results` | json | Results from the action execution |
| `resultFieldLabels` | json | Human-readable labels for result fields |
| `status` | string | Execution status: success, error, empty, preview, or halted |
| `error` | string | Error message if execution failed |
### `zapier_search_app_actions`
Search for available actions within a specific Zapier app. Returns all actions the app supports.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Zapier AI Actions API key from actions.zapier.com/credentials |
| `app` | string | Yes | The app identifier to search actions for \(e.g., "SlackAPI", "GmailV2API"\) |
| `query` | string | No | Optional search query to filter actions by name or description |
| `actionTypes` | array | No | Filter by action types: write, search, read, read_bulk, search_or_write, search_and_write. Defaults to write and search. |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `actions` | json | Array of actions with app, action, actionType, displayName, description, relevancyScore, appNeedsAuth, appInfo |
### `zapier_get_action_details`
Get detailed information about a specific action including its required inputs (needs) and outputs (gives).
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Zapier AI Actions API key from actions.zapier.com/credentials |
| `app` | string | Yes | The app identifier \(e.g., "SlackAPI", "GmailV2API"\) |
| `action` | string | Yes | The action identifier \(e.g., "send_channel_message", "send_email"\) |
| `actionType` | string | No | Type of action: write, search, read. Defaults to write. |
| `includeNeeds` | boolean | No | Include input requirements \(needs\). Defaults to true. |
| `includeGives` | boolean | No | Include output specifications \(gives\). Defaults to false. |
| `includeSample` | boolean | No | Include sample execution result. Defaults to false. |
| `accountId` | number | No | Zapier account ID |
| `authenticationId` | number | No | Authentication ID for the app connection |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `action` | json | Action metadata including type, key, name, noun, and description |
| `needs` | json | Array of input requirements with key, type, label, required, helpText, defaultValue, choices, dependsOn |
| `gives` | json | Array of output fields with key, label, type, important, sample |
| `sample` | json | Sample execution result if requested |
| `customNeedsProbability` | number | Probability \(0-1\) that this action has custom/dynamic input fields |
### `zapier_update_action`
Update an existing stored AI Action configuration in Zapier.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Zapier AI Actions API key from actions.zapier.com/credentials |
| `actionId` | string | Yes | The ID of the AI Action to update |
| `app` | string | Yes | The app identifier \(e.g., "SlackAPI", "GmailV2API"\) |
| `action` | string | Yes | The action identifier \(e.g., "send_channel_message", "send_email"\) |
| `actionType` | string | No | Type of action: write, search, read, read_bulk, search_or_write, search_and_write |
| `accountId` | number | No | Zapier account ID |
| `authenticationId` | number | No | Authentication ID for the app connection |
| `meta` | json | No | Metadata object with params labels, app_label, action_label, authentication_label, app_needs_auth |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | The ID of the updated AI Action |
| `description` | string | Description of the action |
| `actionType` | string | Type of action |
| `app` | string | App identifier |
| `appLabel` | string | Human-readable app label |
| `action` | string | Action identifier |
| `actionLabel` | string | Human-readable action label |
### `zapier_delete_action`
Delete a stored AI Action from Zapier.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Zapier AI Actions API key from actions.zapier.com/credentials |
| `actionId` | string | Yes | The ID of the AI Action to delete |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `deleted` | boolean | Whether the action was successfully deleted |
| `message` | string | Status message |
## Notes
- Category: `tools`
- Type: `zapier`

View File

@@ -262,6 +262,8 @@ const SCOPE_DESCRIPTIONS: Record<string, string> = {
'sharing.write': 'Share files and folders with others',
// WordPress.com scopes
global: 'Full access to manage your WordPress.com sites, posts, pages, media, and settings',
// Zapier AI Actions scopes
'nla:exposed_actions:execute': 'Execute Zapier AI Actions on your behalf',
}
function getScopeDescription(scope: string): string {

View File

@@ -0,0 +1,808 @@
import { ZapierIcon } from '@/components/icons'
import type { BlockConfig } from '@/blocks/types'
import { AuthMode } from '@/blocks/types'
import type { ZapierResponse } from '@/tools/zapier/types'
export const ZapierBlock: BlockConfig<ZapierResponse> = {
type: 'zapier',
name: 'Zapier',
description: 'Execute actions across 7,000+ apps using Zapier AI Actions',
authMode: AuthMode.OAuth,
longDescription:
'Connect to Zapier AI Actions to execute any of 30,000+ actions across 7,000+ apps. Send emails, create documents, update CRMs, post messages, and more - all through natural language instructions.',
docsLink: 'https://docs.sim.ai/tools/zapier',
category: 'tools',
bgColor: '#FFFFFF',
icon: ZapierIcon,
subBlocks: [
{
id: 'operation',
title: 'Operation',
type: 'dropdown',
options: [
{ label: 'Execute Action', id: 'execute' },
{ label: 'Stateless Execute', id: 'stateless_execute' },
{ label: 'List Actions', id: 'list' },
{ label: 'Search Apps', id: 'search_apps' },
{ label: 'Search App Actions', id: 'search_app_actions' },
{ label: 'Find Actions', id: 'guess' },
{ label: 'Get Action Details', id: 'get_action_details' },
{ label: 'Create Action', id: 'create' },
{ label: 'Update Action', id: 'update' },
{ label: 'Delete Action', id: 'delete' },
],
value: () => 'execute',
},
{
id: 'credential',
title: 'Zapier Account',
type: 'oauth-input',
serviceId: 'zapier',
requiredScopes: ['openid', 'nla:exposed_actions:execute'],
placeholder: 'Select Zapier account',
required: true,
},
// Execute Action fields
{
id: 'actionId',
title: 'Action ID',
type: 'short-input',
placeholder: 'Enter the AI Action ID to execute',
condition: {
field: 'operation',
value: 'execute',
},
required: true,
},
{
id: 'instructions',
title: 'Instructions',
type: 'long-input',
placeholder:
'Describe what you want to do in plain English (e.g., "Send a message to #general saying hello")',
condition: {
field: 'operation',
value: 'execute',
},
required: true,
},
{
id: 'params',
title: 'Parameters',
type: 'code',
placeholder: '{\n "channel": {"mode": "locked", "value": "#general"}\n}',
condition: {
field: 'operation',
value: 'execute',
},
},
{
id: 'previewOnly',
title: 'Preview Mode',
type: 'dropdown',
options: [
{ label: 'Execute', id: 'false' },
{ label: 'Preview Only', id: 'true' },
],
value: () => 'false',
condition: {
field: 'operation',
value: 'execute',
},
},
// Search Apps fields
{
id: 'searchQuery',
title: 'Search Query',
type: 'short-input',
placeholder: 'Enter app name to search (e.g., "slack", "google")',
condition: {
field: 'operation',
value: 'search_apps',
},
},
// Guess Actions fields
{
id: 'guessQuery',
title: 'What do you want to do?',
type: 'long-input',
placeholder:
'Describe in plain English (e.g., "send a Slack message", "create a Google Doc")',
condition: {
field: 'operation',
value: 'guess',
},
required: true,
},
{
id: 'actionTypes',
title: 'Action Types',
type: 'checkbox-list',
options: [
{ label: 'Write (Create/Send)', id: 'actionTypes_write' },
{ label: 'Search (Find)', id: 'actionTypes_search' },
{ label: 'Read (Get)', id: 'actionTypes_read' },
],
condition: {
field: 'operation',
value: 'guess',
},
},
{
id: 'resultCount',
title: 'Max Results',
type: 'short-input',
placeholder: '25',
condition: {
field: 'operation',
value: 'guess',
},
},
// Create Action fields
{
id: 'app',
title: 'App',
type: 'short-input',
placeholder: 'App identifier (e.g., "slack", "gmail")',
condition: {
field: 'operation',
value: 'create',
},
required: true,
},
{
id: 'action',
title: 'Action',
type: 'short-input',
placeholder: 'Action identifier (e.g., "send_channel_message")',
condition: {
field: 'operation',
value: 'create',
},
required: true,
},
{
id: 'createActionType',
title: 'Action Type',
type: 'dropdown',
options: [
{ label: 'Write', id: 'write' },
{ label: 'Search', id: 'search' },
{ label: 'Read', id: 'read' },
],
value: () => 'write',
condition: {
field: 'operation',
value: 'create',
},
},
{
id: 'createParams',
title: 'Parameters',
type: 'code',
placeholder: '{\n "channel": "#general"\n}',
condition: {
field: 'operation',
value: 'create',
},
},
// Stateless Execute fields
{
id: 'statelessApp',
title: 'App',
type: 'short-input',
placeholder: 'App identifier (e.g., "SlackAPI", "GmailV2API")',
condition: {
field: 'operation',
value: 'stateless_execute',
},
required: true,
},
{
id: 'statelessAction',
title: 'Action',
type: 'short-input',
placeholder: 'Action identifier (e.g., "send_channel_message")',
condition: {
field: 'operation',
value: 'stateless_execute',
},
required: true,
},
{
id: 'statelessInstructions',
title: 'Instructions',
type: 'long-input',
placeholder: 'Describe what you want to do in plain English',
condition: {
field: 'operation',
value: 'stateless_execute',
},
required: true,
},
{
id: 'statelessActionType',
title: 'Action Type',
type: 'dropdown',
options: [
{ label: 'Write', id: 'write' },
{ label: 'Search', id: 'search' },
{ label: 'Read', id: 'read' },
],
value: () => 'write',
condition: {
field: 'operation',
value: 'stateless_execute',
},
},
{
id: 'statelessParams',
title: 'Parameters',
type: 'code',
placeholder: '{\n "channel": {"mode": "locked", "value": "#general"}\n}',
condition: {
field: 'operation',
value: 'stateless_execute',
},
},
{
id: 'statelessPreviewOnly',
title: 'Preview Mode',
type: 'dropdown',
options: [
{ label: 'Execute', id: 'false' },
{ label: 'Preview Only', id: 'true' },
],
value: () => 'false',
condition: {
field: 'operation',
value: 'stateless_execute',
},
},
// Search App Actions fields
{
id: 'searchAppActionsApp',
title: 'App',
type: 'short-input',
placeholder: 'App identifier (e.g., "SlackAPI", "GmailV2API")',
condition: {
field: 'operation',
value: 'search_app_actions',
},
required: true,
},
{
id: 'searchAppActionsQuery',
title: 'Search Query',
type: 'short-input',
placeholder: 'Optional: filter actions by name',
condition: {
field: 'operation',
value: 'search_app_actions',
},
},
{
id: 'searchAppActionsTypes',
title: 'Action Types',
type: 'checkbox-list',
options: [
{ label: 'Write (Create/Send)', id: 'searchAppActionsTypes_write' },
{ label: 'Search (Find)', id: 'searchAppActionsTypes_search' },
{ label: 'Read (Get)', id: 'searchAppActionsTypes_read' },
],
condition: {
field: 'operation',
value: 'search_app_actions',
},
},
// Get Action Details fields
{
id: 'detailsApp',
title: 'App',
type: 'short-input',
placeholder: 'App identifier (e.g., "SlackAPI", "GmailV2API")',
condition: {
field: 'operation',
value: 'get_action_details',
},
required: true,
},
{
id: 'detailsAction',
title: 'Action',
type: 'short-input',
placeholder: 'Action identifier (e.g., "send_channel_message")',
condition: {
field: 'operation',
value: 'get_action_details',
},
required: true,
},
{
id: 'detailsActionType',
title: 'Action Type',
type: 'dropdown',
options: [
{ label: 'Write', id: 'write' },
{ label: 'Search', id: 'search' },
{ label: 'Read', id: 'read' },
],
value: () => 'write',
condition: {
field: 'operation',
value: 'get_action_details',
},
},
{
id: 'includeNeeds',
title: 'Include Inputs (Needs)',
type: 'dropdown',
options: [
{ label: 'Yes', id: 'true' },
{ label: 'No', id: 'false' },
],
value: () => 'true',
condition: {
field: 'operation',
value: 'get_action_details',
},
},
{
id: 'includeGives',
title: 'Include Outputs (Gives)',
type: 'dropdown',
options: [
{ label: 'Yes', id: 'true' },
{ label: 'No', id: 'false' },
],
value: () => 'false',
condition: {
field: 'operation',
value: 'get_action_details',
},
},
{
id: 'includeSample',
title: 'Include Sample',
type: 'dropdown',
options: [
{ label: 'Yes', id: 'true' },
{ label: 'No', id: 'false' },
],
value: () => 'false',
condition: {
field: 'operation',
value: 'get_action_details',
},
},
// Update Action fields
{
id: 'updateActionId',
title: 'Action ID',
type: 'short-input',
placeholder: 'The ID of the AI Action to update',
condition: {
field: 'operation',
value: 'update',
},
required: true,
},
{
id: 'updateApp',
title: 'App',
type: 'short-input',
placeholder: 'App identifier (e.g., "SlackAPI")',
condition: {
field: 'operation',
value: 'update',
},
required: true,
},
{
id: 'updateAction',
title: 'Action',
type: 'short-input',
placeholder: 'Action identifier (e.g., "send_channel_message")',
condition: {
field: 'operation',
value: 'update',
},
required: true,
},
{
id: 'updateActionType',
title: 'Action Type',
type: 'dropdown',
options: [
{ label: 'Write', id: 'write' },
{ label: 'Search', id: 'search' },
{ label: 'Read', id: 'read' },
],
value: () => 'write',
condition: {
field: 'operation',
value: 'update',
},
},
{
id: 'updateParams',
title: 'Parameters',
type: 'code',
placeholder: '{\n "channel": "#general"\n}',
condition: {
field: 'operation',
value: 'update',
},
},
// Delete Action fields
{
id: 'deleteActionId',
title: 'Action ID',
type: 'short-input',
placeholder: 'The ID of the AI Action to delete',
condition: {
field: 'operation',
value: 'delete',
},
required: true,
},
],
tools: {
access: [
'zapier_execute_action',
'zapier_list_actions',
'zapier_search_apps',
'zapier_guess_actions',
'zapier_create_action',
'zapier_stateless_execute',
'zapier_search_app_actions',
'zapier_get_action_details',
'zapier_update_action',
'zapier_delete_action',
],
config: {
tool: (params) => {
switch (params.operation) {
case 'execute':
return 'zapier_execute_action'
case 'stateless_execute':
return 'zapier_stateless_execute'
case 'list':
return 'zapier_list_actions'
case 'search_apps':
return 'zapier_search_apps'
case 'search_app_actions':
return 'zapier_search_app_actions'
case 'guess':
return 'zapier_guess_actions'
case 'get_action_details':
return 'zapier_get_action_details'
case 'create':
return 'zapier_create_action'
case 'update':
return 'zapier_update_action'
case 'delete':
return 'zapier_delete_action'
default:
throw new Error(`Invalid Zapier operation: ${params.operation}`)
}
},
params: (params) => {
const {
operation,
credential,
actionId,
instructions,
params: execParams,
previewOnly,
searchQuery,
guessQuery,
resultCount,
app,
action,
createActionType,
createParams,
statelessApp,
statelessAction,
statelessInstructions,
statelessActionType,
statelessParams,
statelessPreviewOnly,
searchAppActionsApp,
searchAppActionsQuery,
detailsApp,
detailsAction,
detailsActionType,
includeNeeds,
includeGives,
includeSample,
updateActionId,
updateApp,
updateAction,
updateActionType,
updateParams,
deleteActionId,
} = params
const baseParams: Record<string, any> = { credential }
// Helper to parse JSON params
const parseJsonParams = (jsonParams: any) => {
if (!jsonParams) return undefined
try {
return typeof jsonParams === 'string' ? JSON.parse(jsonParams) : jsonParams
} catch {
throw new Error('Invalid JSON in parameters field')
}
}
// Helper to collect checkbox-list values
// Use truthy check since values may be boolean true or string "true" after serialization
const collectActionTypes = (prefix: string) => {
const types: string[] = []
const writeVal = params[`${prefix}_write`]
const searchVal = params[`${prefix}_search`]
const readVal = params[`${prefix}_read`]
if (writeVal === true || writeVal === 'true') types.push('write')
if (searchVal === true || searchVal === 'true') types.push('search')
if (readVal === true || readVal === 'true') types.push('read')
return types.length > 0 ? types : undefined
}
switch (operation) {
case 'execute':
baseParams.actionId = actionId
baseParams.instructions = instructions
baseParams.params = parseJsonParams(execParams)
baseParams.previewOnly = previewOnly === 'true'
break
case 'stateless_execute':
baseParams.app = statelessApp
baseParams.action = statelessAction
baseParams.instructions = statelessInstructions
baseParams.actionType = statelessActionType || 'write'
baseParams.params = parseJsonParams(statelessParams)
baseParams.previewOnly = statelessPreviewOnly === 'true'
break
case 'list':
break
case 'search_apps':
if (searchQuery) baseParams.query = searchQuery
break
case 'search_app_actions':
baseParams.app = searchAppActionsApp
if (searchAppActionsQuery) baseParams.query = searchAppActionsQuery
baseParams.actionTypes = collectActionTypes('searchAppActionsTypes')
break
case 'guess': {
baseParams.query = guessQuery
// Checkbox-list values are stored under prefixed option IDs (actionTypes_write, etc.)
baseParams.actionTypes = collectActionTypes('actionTypes')
if (resultCount) {
const count = Number.parseInt(resultCount, 10)
if (!Number.isNaN(count)) baseParams.count = count
}
break
}
case 'get_action_details':
baseParams.app = detailsApp
baseParams.action = detailsAction
baseParams.actionType = detailsActionType || 'write'
baseParams.includeNeeds = includeNeeds !== 'false'
baseParams.includeGives = includeGives === 'true'
baseParams.includeSample = includeSample === 'true'
break
case 'create':
baseParams.app = app
baseParams.action = action
baseParams.actionType = createActionType || 'write'
baseParams.params = parseJsonParams(createParams)
break
case 'update':
baseParams.actionId = updateActionId
baseParams.app = updateApp
baseParams.action = updateAction
baseParams.actionType = updateActionType || 'write'
baseParams.params = parseJsonParams(updateParams)
break
case 'delete':
baseParams.actionId = deleteActionId
break
}
return baseParams
},
},
},
inputs: {
operation: { type: 'string', description: 'Operation to perform' },
credential: { type: 'string', description: 'Zapier OAuth credential' },
// Execute inputs
actionId: { type: 'string', description: 'AI Action ID to execute' },
instructions: { type: 'string', description: 'Plain English instructions for the action' },
params: { type: 'json', description: 'Optional parameter constraints' },
previewOnly: { type: 'string', description: 'Whether to preview without executing' },
// Stateless execute inputs
statelessApp: { type: 'string', description: 'App identifier for stateless execute' },
statelessAction: { type: 'string', description: 'Action identifier for stateless execute' },
statelessInstructions: { type: 'string', description: 'Instructions for stateless execute' },
statelessActionType: { type: 'string', description: 'Action type for stateless execute' },
statelessParams: { type: 'json', description: 'Parameters for stateless execute' },
statelessPreviewOnly: { type: 'string', description: 'Preview mode for stateless execute' },
// Search inputs
searchQuery: { type: 'string', description: 'App search query' },
// Search app actions inputs
searchAppActionsApp: { type: 'string', description: 'App to search actions for' },
searchAppActionsQuery: { type: 'string', description: 'Query to filter actions' },
searchAppActionsTypes_write: { type: 'boolean', description: 'Include write actions' },
searchAppActionsTypes_search: { type: 'boolean', description: 'Include search actions' },
searchAppActionsTypes_read: { type: 'boolean', description: 'Include read actions' },
// Guess inputs
guessQuery: { type: 'string', description: 'Natural language query to find actions' },
actionTypes_write: { type: 'boolean', description: 'Include write actions' },
actionTypes_search: { type: 'boolean', description: 'Include search actions' },
actionTypes_read: { type: 'boolean', description: 'Include read actions' },
resultCount: { type: 'string', description: 'Maximum number of results' },
// Get action details inputs
detailsApp: { type: 'string', description: 'App identifier for action details' },
detailsAction: { type: 'string', description: 'Action identifier for action details' },
detailsActionType: { type: 'string', description: 'Action type for action details' },
includeNeeds: { type: 'string', description: 'Include input requirements' },
includeGives: { type: 'string', description: 'Include output specifications' },
includeSample: { type: 'string', description: 'Include sample data' },
// Create inputs
app: { type: 'string', description: 'App identifier' },
action: { type: 'string', description: 'Action identifier' },
createActionType: { type: 'string', description: 'Type of action to create' },
createParams: { type: 'json', description: 'Pre-configured parameters' },
// Update inputs
updateActionId: { type: 'string', description: 'AI Action ID to update' },
updateApp: { type: 'string', description: 'App identifier for update' },
updateAction: { type: 'string', description: 'Action identifier for update' },
updateActionType: { type: 'string', description: 'Action type for update' },
updateParams: { type: 'json', description: 'Parameters for update' },
// Delete inputs
deleteActionId: { type: 'string', description: 'AI Action ID to delete' },
},
outputs: {
// Execute Action outputs
executionLogId: {
type: 'string',
description: 'Unique identifier for the execution',
},
actionUsed: {
type: 'string',
description: 'Name of the action that was executed',
},
inputParams: {
type: 'json',
description: 'Parameters passed to the API',
},
resolvedParams: {
type: 'json',
description: 'Parameters resolved by AI for execution',
},
results: {
type: 'json',
description: 'Results from action execution',
},
resultFieldLabels: {
type: 'json',
description: 'Human-readable labels for result fields',
},
status: {
type: 'string',
description: 'Execution status (success, error, preview, etc.)',
},
error: {
type: 'string',
description: 'Error message if execution failed',
},
// List Actions outputs
actions: {
type: 'json',
description:
'Array of AI Actions with id, description, actionType, app, appLabel, action, actionLabel, params, accountId, authenticationId, configurationLink (list) or guessed actions (find)',
},
configurationLink: {
type: 'string',
description: 'Link to configure actions in Zapier (list operation only)',
},
// Search Apps outputs
apps: {
type: 'json',
description:
'Array of apps with app, name, logoUrl, authType, actionCount, writeActionCount, searchActionCount, readActionCount',
},
// Guess Actions outputs (in addition to 'actions' above)
name: {
type: 'string',
description: 'Combined app and action name (find operation)',
},
image: {
type: 'string',
description: 'App logo URL (find operation)',
},
score: {
type: 'number',
description: 'Relevance score for guessed actions (find operation)',
},
// Create Action outputs
id: {
type: 'string',
description: 'ID of the created AI Action',
},
description: {
type: 'string',
description: 'Description of the action',
},
actionType: {
type: 'string',
description:
'Type of action (write, search, read, read_bulk, search_or_write, search_and_write)',
},
app: {
type: 'string',
description: 'App identifier',
},
appLabel: {
type: 'string',
description: 'Human-readable app label',
},
action: {
type: 'string',
description: 'Action identifier',
},
actionLabel: {
type: 'string',
description: 'Human-readable action label',
},
params: {
type: 'json',
description: 'Configured parameter values',
},
accountId: {
type: 'number',
description: 'Zapier account ID',
},
authenticationId: {
type: 'number',
description: 'Authentication ID used for the app',
},
// Get Action Details outputs
needs: {
type: 'json',
description: 'Array of input requirements for the action',
},
gives: {
type: 'json',
description: 'Array of output fields from the action',
},
sample: {
type: 'json',
description: 'Sample execution result',
},
customNeedsProbability: {
type: 'number',
description: 'Probability that action has custom/dynamic input fields',
},
// Delete Action outputs
deleted: {
type: 'boolean',
description: 'Whether the action was successfully deleted',
},
message: {
type: 'string',
description: 'Status message for delete operation',
},
},
}

View File

@@ -133,6 +133,7 @@ import { WorkflowBlock } from '@/blocks/blocks/workflow'
import { WorkflowInputBlock } from '@/blocks/blocks/workflow_input'
import { XBlock } from '@/blocks/blocks/x'
import { YouTubeBlock } from '@/blocks/blocks/youtube'
import { ZapierBlock } from '@/blocks/blocks/zapier'
import { ZendeskBlock } from '@/blocks/blocks/zendesk'
import { ZepBlock } from '@/blocks/blocks/zep'
import { ZoomBlock } from '@/blocks/blocks/zoom'
@@ -275,8 +276,9 @@ export const registry: Record<string, BlockConfig> = {
workflow_input: WorkflowInputBlock,
x: XBlock,
youtube: YouTubeBlock,
zep: ZepBlock,
zapier: ZapierBlock,
zendesk: ZendeskBlock,
zep: ZepBlock,
zoom: ZoomBlock,
}

View File

@@ -4151,7 +4151,7 @@ export function DuckDuckGoIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='-108 -108 216 216'>
<circle r='108' fill='#d53' />
<circle r='96' fill='none' stroke='#ffffff' stroke-width='7' />
<circle r='96' fill='none' stroke='#ffffff' strokeWidth='7' />
<path
d='M-32-55C-62-48-51-6-51-6l19 93 7 3M-39-73h-8l11 4s-11 0-11 7c24-1 35 5 35 5'
fill='#ddd'
@@ -4199,3 +4199,25 @@ export function RssIcon(props: SVGProps<SVGSVGElement>) {
</svg>
)
}
export function ZapierIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg
{...props}
width='800px'
height='800px'
viewBox='0 0 256 256'
version='1.1'
xmlns='http://www.w3.org/2000/svg'
xmlnsXlink='http://www.w3.org/1999/xlink'
>
<g>
<path
d='M128.080089,-0.000183105 C135.311053,0.0131003068 142.422517,0.624138494 149.335663,1.77979593 L149.335663,1.77979593 L149.335663,76.2997796 L202.166953,23.6044907 C208.002065,27.7488446 213.460883,32.3582023 218.507811,37.3926715 C223.557281,42.4271407 228.192318,47.8867213 232.346817,53.7047992 L232.346817,53.7047992 L179.512985,106.400063 L254.227854,106.400063 C255.387249,113.29414 256,120.36111 256,127.587243 L256,127.587243 L256,127.759881 C256,134.986013 255.387249,142.066204 254.227854,148.960282 L254.227854,148.960282 L179.500273,148.960282 L232.346817,201.642324 C228.192318,207.460402 223.557281,212.919983 218.523066,217.954452 L218.523066,217.954452 L218.507811,217.954452 C213.460883,222.988921 208.002065,227.6115 202.182208,231.742607 L202.182208,231.742607 L149.335663,179.04709 L149.335663,253.5672 C142.435229,254.723036 135.323765,255.333244 128.092802,255.348499 L128.092802,255.348499 L127.907197,255.348499 C120.673691,255.333244 113.590195,254.723036 106.677048,253.5672 L106.677048,253.5672 L106.677048,179.04709 L53.8457596,231.742607 C42.1780766,223.466917 31.977435,213.278734 23.6658953,201.642324 L23.6658953,201.642324 L76.4997269,148.960282 L1.78485803,148.960282 C0.612750404,142.052729 0,134.946095 0,127.719963 L0,127.719963 L0,127.349037 C0.0121454869,125.473817 0.134939797,123.182933 0.311311815,120.812834 L0.36577283,120.099764 C0.887996182,113.428547 1.78485803,106.400063 1.78485803,106.400063 L1.78485803,106.400063 L76.4997269,106.400063 L23.6658953,53.7047992 C27.8076812,47.8867213 32.4300059,42.4403618 37.4769335,37.4193681 L37.4769335,37.4193681 L37.5023588,37.3926715 C42.5391163,32.3582023 48.0106469,27.7488446 53.8457596,23.6044907 L53.8457596,23.6044907 L106.677048,76.2997796 L106.677048,1.77979593 C113.590195,0.624138494 120.688946,0.0131003068 127.932622,-0.000183105 L127.932622,-0.000183105 L128.080089,-0.000183105 Z M128.067377,95.7600714 L127.945335,95.7600714 C118.436262,95.7600714 109.32891,97.5001809 100.910584,100.661566 C97.7553011,109.043534 96.0085811,118.129275 95.9958684,127.613685 L95.9958684,127.733184 C96.0085811,137.217594 97.7553011,146.303589 100.923296,154.685303 C109.32891,157.846943 118.436262,159.587052 127.945335,159.587052 L128.067377,159.587052 C137.576449,159.587052 146.683802,157.846943 155.089415,154.685303 C158.257411,146.290368 160.004131,137.217594 160.004131,127.733184 L160.004131,127.613685 C160.004131,118.129275 158.257411,109.043534 155.089415,100.661566 C146.683802,97.5001809 137.576449,95.7600714 128.067377,95.7600714 Z'
fill='#FF4A00'
fillRule='nonzero'
/>
</g>
</svg>
)
}

View File

@@ -1847,6 +1847,59 @@ export const auth = betterAuth({
}
},
},
// Zapier AI Actions provider
{
providerId: 'zapier',
clientId: env.ZAPIER_CLIENT_ID as string,
clientSecret: env.ZAPIER_CLIENT_SECRET as string,
authorizationUrl: 'https://actions.zapier.com/oauth/authorize/',
tokenUrl: 'https://actions.zapier.com/oauth/token/',
userInfoUrl: 'https://actions.zapier.com/api/v2/check/',
scopes: ['openid', 'nla:exposed_actions:execute'],
responseType: 'code',
pkce: true,
accessType: 'offline',
prompt: 'consent',
redirectURI: `${getBaseUrl()}/api/auth/oauth2/callback/zapier`,
getUserInfo: async (tokens) => {
try {
logger.info('Fetching Zapier user profile')
// Zapier's check endpoint returns account info when using OAuth
const response = await fetch('https://actions.zapier.com/api/v2/check/', {
headers: {
Authorization: `Bearer ${tokens.accessToken}`,
},
})
if (!response.ok) {
logger.error('Failed to fetch Zapier user info', {
status: response.status,
statusText: response.statusText,
})
throw new Error('Failed to fetch user info')
}
const data = await response.json()
// Zapier check endpoint returns account_id and other info
const userId = data.account_id || data.user_id || `zapier-${Date.now()}`
return {
id: userId.toString(),
name: data.email || 'Zapier User',
email: data.email || `${userId}@zapier.user`,
emailVerified: !!data.email,
createdAt: new Date(),
updatedAt: new Date(),
}
} catch (error) {
logger.error('Error in Zapier getUserInfo:', { error })
return null
}
},
},
],
}),
// Include SSO plugin when enabled

View File

@@ -230,6 +230,8 @@ export const env = createEnv({
ZOOM_CLIENT_SECRET: z.string().optional(), // Zoom OAuth client secret
WORDPRESS_CLIENT_ID: z.string().optional(), // WordPress.com OAuth client ID
WORDPRESS_CLIENT_SECRET: z.string().optional(), // WordPress.com OAuth client secret
ZAPIER_CLIENT_ID: z.string().optional(), // Zapier AI Actions OAuth client ID
ZAPIER_CLIENT_SECRET: z.string().optional(), // Zapier AI Actions OAuth client secret
// E2B Remote Code Execution
E2B_ENABLED: z.string().optional(), // Enable E2B remote code execution

View File

@@ -37,6 +37,7 @@ import {
WebflowIcon,
WordpressIcon,
xIcon,
ZapierIcon,
ZoomIcon,
} from '@/components/icons'
import { env } from '@/lib/core/config/env'
@@ -70,6 +71,7 @@ export type OAuthProvider =
| 'shopify'
| 'zoom'
| 'wordpress'
| 'zapier'
| string
export type OAuthService =
@@ -111,6 +113,7 @@ export type OAuthService =
| 'shopify'
| 'zoom'
| 'wordpress'
| 'zapier'
export interface OAuthProviderConfig {
id: OAuthProvider
name: string
@@ -891,6 +894,23 @@ export const OAUTH_PROVIDERS: Record<string, OAuthProviderConfig> = {
},
defaultService: 'wordpress',
},
zapier: {
id: 'zapier',
name: 'Zapier',
icon: (props) => ZapierIcon(props),
services: {
zapier: {
id: 'zapier',
name: 'Zapier AI Actions',
description: 'Execute actions across 7,000+ apps using Zapier AI Actions.',
providerId: 'zapier',
icon: (props) => ZapierIcon(props),
baseProviderIcon: (props) => ZapierIcon(props),
scopes: ['openid', 'nla:exposed_actions:execute'],
},
},
defaultService: 'zapier',
},
}
/**
@@ -1470,6 +1490,20 @@ function getProviderAuthConfig(provider: string): ProviderAuthConfig {
supportsRefreshTokenRotation: false,
}
}
case 'zapier': {
// Zapier AI Actions OAuth - tokens expire after 10 hours
const { clientId, clientSecret } = getCredentials(
env.ZAPIER_CLIENT_ID,
env.ZAPIER_CLIENT_SECRET
)
return {
tokenEndpoint: 'https://actions.zapier.com/oauth/token/',
clientId,
clientSecret,
useBasicAuth: false,
supportsRefreshTokenRotation: true,
}
}
default:
throw new Error(`Unsupported provider: ${provider}`)
}

View File

@@ -115,10 +115,6 @@ export class Serializer {
safeParallels
)
if (validateRequired) {
this.validateSubflowsBeforeExecution(blocks, safeLoops, safeParallels)
}
return {
version: '1.0',
blocks: Object.values(blocks).map((block) =>
@@ -139,18 +135,6 @@ export class Serializer {
}
}
/**
* Validate loop and parallel subflows for required inputs when running in "each/collection" modes
*/
private validateSubflowsBeforeExecution(
blocks: Record<string, BlockState>,
loops: Record<string, Loop>,
parallels: Record<string, Parallel>
): void {
// Note: Empty collections in forEach loops and parallel collection mode are handled gracefully
// at runtime - the loop/parallel will simply be skipped. No build-time validation needed.
}
private serializeBlock(
block: BlockState,
options: {
@@ -367,6 +351,15 @@ export class Serializer {
) {
params[id] = subBlock.value
}
if (subBlockConfig?.type === 'checkbox-list' && Array.isArray(subBlockConfig.options)) {
subBlockConfig.options.forEach((option: { id: string; label: string }) => {
const optionSubBlock = block.subBlocks[option.id]
if (optionSubBlock !== undefined) {
params[option.id] = optionSubBlock.value
}
})
}
})
// Then check for any subBlocks with default values

View File

@@ -1260,6 +1260,18 @@ import {
youtubeSearchTool,
youtubeVideoDetailsTool,
} from '@/tools/youtube'
import {
zapierCreateAiActionTool,
zapierDeleteAiActionTool,
zapierExecuteActionTool,
zapierGetActionDetailsTool,
zapierGuessActionsTool,
zapierListActionsTool,
zapierSearchAppActionsTool,
zapierSearchAppsTool,
zapierStatelessExecuteTool,
zapierUpdateAiActionTool,
} from '@/tools/zapier'
import {
zendeskAutocompleteOrganizationsTool,
zendeskCreateOrganizationsBulkTool,
@@ -2501,4 +2513,16 @@ export const tools: Record<string, ToolConfig> = {
zoom_get_meeting_recordings: zoomGetMeetingRecordingsTool,
zoom_delete_recording: zoomDeleteRecordingTool,
zoom_list_past_participants: zoomListPastParticipantsTool,
// Zapier tools
zapier_execute_action: zapierExecuteActionTool,
zapier_list_actions: zapierListActionsTool,
zapier_search_apps: zapierSearchAppsTool,
zapier_guess_actions: zapierGuessActionsTool,
zapier_create_action: zapierCreateAiActionTool,
zapier_stateless_execute: zapierStatelessExecuteTool,
zapier_search_app_actions: zapierSearchAppActionsTool,
zapier_get_action_details: zapierGetActionDetailsTool,
zapier_update_action: zapierUpdateAiActionTool,
zapier_delete_action: zapierDeleteAiActionTool,
}

View File

@@ -0,0 +1,172 @@
import type { ToolConfig } from '@/tools/types'
import type { ZapierCreateAiActionParams, ZapierCreateAiActionResponse } from '@/tools/zapier/types'
export const zapierCreateAiActionTool: ToolConfig<
ZapierCreateAiActionParams,
ZapierCreateAiActionResponse
> = {
id: 'zapier_create_action',
name: 'Zapier Create AI Action',
description:
'Create a new stored AI Action in Zapier. The action can then be executed with zapier_execute_action.',
version: '1.0.0',
oauth: {
required: true,
provider: 'zapier',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Access token for Zapier AI Actions API',
},
app: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'The app identifier (e.g., "slack", "gmail", "google-docs")',
},
action: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'The action identifier (e.g., "send_channel_message", "send_email")',
},
actionType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Type of action: write, search, or read. Defaults to write.',
default: 'write',
},
params: {
type: 'json',
required: false,
visibility: 'user-or-llm',
description: 'Pre-configured parameter values for the action',
},
accountId: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Zapier account ID',
},
authenticationId: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Authentication ID for the app connection',
},
meta: {
type: 'json',
required: false,
visibility: 'user-only',
description:
'Metadata object with params labels, app_label, action_label, authentication_label, app_needs_auth',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.accountId !== undefined) {
queryParams.append('account_id', String(params.accountId))
}
if (params.authenticationId !== undefined) {
queryParams.append('authentication_id', String(params.authenticationId))
}
const query = queryParams.toString()
return `https://actions.zapier.com/api/v2/ai-actions/${query ? `?${query}` : ''}`
},
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => ({
app: params.app,
action: params.action,
action_type: params.actionType || 'write',
params: params.params || {},
meta: params.meta || { params: {} },
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || data.detail || `Zapier API error: ${response.status}`)
}
// API response includes: id, description, account_id, authentication_id, app, action, action_type, params, meta, needs
// Labels come from meta object if available
const appLabel = data.meta?.app_label || ''
const actionLabel = data.meta?.action_label || ''
return {
success: true,
output: {
id: data.id || '',
description: data.description || '',
actionType: data.action_type || '',
app: data.app || '',
appLabel,
action: data.action || '',
actionLabel,
params: data.params || {},
accountId: data.account_id ?? null,
authenticationId: data.authentication_id ?? null,
},
}
},
outputs: {
id: {
type: 'string',
description: 'The ID of the created AI Action (use this with execute_action)',
},
description: {
type: 'string',
description: 'Description of the action',
},
actionType: {
type: 'string',
description:
'Type of action (write, search, read, read_bulk, search_or_write, search_and_write)',
},
app: {
type: 'string',
description: 'App identifier',
},
appLabel: {
type: 'string',
description: 'Human-readable app label from meta',
},
action: {
type: 'string',
description: 'Action identifier',
},
actionLabel: {
type: 'string',
description: 'Human-readable action label from meta',
},
params: {
type: 'json',
description: 'Configured parameter values',
},
accountId: {
type: 'number',
description: 'Zapier account ID',
optional: true,
},
authenticationId: {
type: 'number',
description: 'Authentication ID used for the app',
optional: true,
},
},
}

View File

@@ -0,0 +1,73 @@
import type { ToolConfig } from '@/tools/types'
import type { ZapierDeleteAiActionParams, ZapierDeleteAiActionResponse } from '@/tools/zapier/types'
export const zapierDeleteAiActionTool: ToolConfig<
ZapierDeleteAiActionParams,
ZapierDeleteAiActionResponse
> = {
id: 'zapier_delete_action',
name: 'Zapier Delete AI Action',
description: 'Delete a stored AI Action from Zapier.',
version: '1.0.0',
oauth: {
required: true,
provider: 'zapier',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Access token for Zapier AI Actions API',
},
actionId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'The ID of the AI Action to delete',
},
},
request: {
url: (params) =>
`https://actions.zapier.com/api/v2/ai-actions/${encodeURIComponent(params.actionId)}/`,
method: 'DELETE',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
// DELETE returns a boolean directly
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || data.detail || `Zapier API error: ${response.status}`)
}
// API returns true if deleted, false if not found
const deleted = data === true
return {
success: true,
output: {
deleted,
message: deleted ? 'AI Action deleted successfully' : 'AI Action not found',
},
}
},
outputs: {
deleted: {
type: 'boolean',
description: 'Whether the action was successfully deleted',
},
message: {
type: 'string',
description: 'Status message',
},
},
}

View File

@@ -0,0 +1,136 @@
import type { ToolConfig } from '@/tools/types'
import type { ZapierExecuteActionParams, ZapierExecuteActionResponse } from '@/tools/zapier/types'
export const zapierExecuteActionTool: ToolConfig<
ZapierExecuteActionParams,
ZapierExecuteActionResponse
> = {
id: 'zapier_execute_action',
name: 'Zapier Execute Action',
description:
'Execute a stored AI Action in Zapier. Runs any of the 30,000+ actions across 7,000+ apps that Zapier supports.',
version: '1.0.0',
oauth: {
required: true,
provider: 'zapier',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Access token for Zapier AI Actions API',
},
actionId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'The ID of the AI Action to execute',
},
instructions: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Plain English instructions for what the action should do (e.g., "Send a message about the weekly report to #general")',
},
params: {
type: 'json',
required: false,
visibility: 'user-or-llm',
description:
'Optional parameter constraints. Each key maps to {mode: "locked"|"guess"|"choose_from"|"ignored", value: string}',
},
previewOnly: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'If true, preview the execution without actually running it',
default: false,
},
},
request: {
url: (params) =>
`https://actions.zapier.com/api/v2/ai-actions/${encodeURIComponent(params.actionId)}/execute/${params.previewOnly ? '?preview_only=true' : ''}`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => {
const body: Record<string, any> = {
instructions: params.instructions,
}
if (params.params !== undefined) {
body.params = params.params
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || data.detail || `Zapier API error: ${response.status}`)
}
const isSuccess = data.status === 'success' || data.status === 'preview'
const errorMessage =
data.error || (isSuccess ? undefined : `Zapier action ${data.status || 'failed'}`)
return {
success: isSuccess,
error: errorMessage, // Top-level error for the framework to capture
output: {
executionLogId: data.execution_log_id || '',
actionUsed: data.action_used || '',
inputParams: data.input_params || {},
resolvedParams: data.resolved_params || {},
results: data.results || [],
resultFieldLabels: data.result_field_labels || {},
status: data.status || 'error',
error: data.error || undefined,
},
}
},
outputs: {
executionLogId: {
type: 'string',
description: 'Unique identifier for this execution (can be used for feedback)',
},
actionUsed: {
type: 'string',
description: 'Name of the action that was executed',
},
inputParams: {
type: 'json',
description: 'Parameters that were passed to the API',
},
resolvedParams: {
type: 'json',
description: 'Parameters that the AI resolved for execution',
},
results: {
type: 'json',
description: 'Results from the action execution',
},
resultFieldLabels: {
type: 'json',
description: 'Human-readable labels for result fields',
},
status: {
type: 'string',
description: 'Execution status: success, error, empty, preview, or halted',
},
error: {
type: 'string',
description: 'Error message if execution failed',
optional: true,
},
},
}

View File

@@ -0,0 +1,202 @@
import type { ToolConfig } from '@/tools/types'
import type {
ZapierGetActionDetailsParams,
ZapierGetActionDetailsResponse,
} from '@/tools/zapier/types'
export const zapierGetActionDetailsTool: ToolConfig<
ZapierGetActionDetailsParams,
ZapierGetActionDetailsResponse
> = {
id: 'zapier_get_action_details',
name: 'Zapier Get Action Details',
description:
'Get detailed information about a specific action including its required inputs (needs) and outputs (gives).',
version: '1.0.0',
oauth: {
required: true,
provider: 'zapier',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Access token for Zapier AI Actions API',
},
app: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The app identifier (e.g., "SlackAPI", "GmailV2API")',
},
action: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The action identifier (e.g., "send_channel_message", "send_email")',
},
actionType: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Type of action: write, search, read. Defaults to write.',
},
includeNeeds: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'Include input requirements (needs). Defaults to true.',
},
includeGives: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'Include output specifications (gives). Defaults to false.',
},
includeSample: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'Include sample execution result. Defaults to false.',
},
params: {
type: 'json',
required: false,
visibility: 'user-or-llm',
description: 'Optional params to pass for dynamic field resolution',
},
accountId: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Zapier account ID',
},
authenticationId: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Authentication ID for the app connection',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.actionType) {
queryParams.append('action_type', params.actionType)
}
if (params.accountId !== undefined) {
queryParams.append('account_id', String(params.accountId))
}
if (params.authenticationId !== undefined) {
queryParams.append('authentication_id', String(params.authenticationId))
}
// Build action_extra array based on flags
const actionExtra: string[] = []
if (params.includeNeeds !== false) {
actionExtra.push('action_needs')
}
if (params.includeGives) {
actionExtra.push('action_gives')
}
if (params.includeSample) {
actionExtra.push('action_sample')
}
actionExtra.forEach((extra) => {
queryParams.append('action_extra', extra)
})
const query = queryParams.toString()
return `https://actions.zapier.com/api/v2/apps/${encodeURIComponent(params.app)}/actions/${encodeURIComponent(params.action)}/${query ? `?${query}` : ''}`
},
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => ({
params: params.params || {},
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || data.detail || `Zapier API error: ${response.status}`)
}
const results = data.results || []
const result = results[0] || {}
// Transform needs array
const needs = (result.action_needs || []).map((need: any) => ({
key: need.key || '',
type: need.type || '',
label: need.label || '',
required: need.required || false,
helpText: need.help_text || '',
defaultValue: need.default ?? null,
choices: need.choices || null,
dependsOn: need.depends_on || null,
customField: need.custom_field || false,
}))
// Transform gives array
const gives = (result.action_gives || []).map((give: any) => ({
key: give.key || '',
label: give.label || '',
type: give.type || '',
score: give.score ?? null,
subscore: give.subscore ?? null,
important: give.important || false,
sample: give.zap_meta_sample ?? null,
}))
return {
success: true,
output: {
action: result.action
? {
type: result.action.type || '',
key: result.action.key || '',
name: result.action.name || '',
noun: result.action.noun || '',
description: result.action.description || '',
}
: null,
needs,
gives,
sample: result.action_sample || null,
customNeedsProbability: result.action_has_custom_needs_probability ?? 0,
},
}
},
outputs: {
action: {
type: 'json',
description: 'Action metadata including type, key, name, noun, and description',
},
needs: {
type: 'json',
description:
'Array of input requirements with key, type, label, required, helpText, defaultValue, choices, dependsOn',
},
gives: {
type: 'json',
description: 'Array of output fields with key, label, type, important, sample',
},
sample: {
type: 'json',
description: 'Sample execution result if requested',
optional: true,
},
customNeedsProbability: {
type: 'number',
description: 'Probability (0-1) that this action has custom/dynamic input fields',
},
},
}

View File

@@ -0,0 +1,103 @@
import type { ToolConfig } from '@/tools/types'
import type { ZapierGuessActionsParams, ZapierGuessActionsResponse } from '@/tools/zapier/types'
export const zapierGuessActionsTool: ToolConfig<
ZapierGuessActionsParams,
ZapierGuessActionsResponse
> = {
id: 'zapier_guess_actions',
name: 'Zapier Guess Actions',
description:
'Find relevant Zapier actions using natural language. Searches across 30,000+ actions to find the best matches for your query.',
version: '1.0.0',
oauth: {
required: true,
provider: 'zapier',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Access token for Zapier AI Actions API',
},
query: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Natural language description of what you want to do (e.g., "send a Slack message", "create a Google Doc")',
},
actionTypes: {
type: 'array',
required: false,
visibility: 'user-only',
description:
'Types of actions to search for: write, search, read. If not specified, returns all types.',
},
count: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Maximum number of results to return (default: 25)',
default: 25,
},
},
request: {
url: 'https://actions.zapier.com/api/v2/guess-actions/',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => {
const body: Record<string, any> = {
query: params.query,
count: params.count || 25,
}
// Only include action_types if explicitly provided (user selected filters)
// If not provided, API returns all action types
if (params.actionTypes && params.actionTypes.length > 0) {
body.action_types = params.actionTypes
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || data.detail || `Zapier API error: ${response.status}`)
}
const actions = Array.isArray(data) ? data : data.results || []
return {
success: true,
output: {
actions: actions.map((action: any) => ({
// API returns: app, action, action_type, name (combined), description, image, score
app: action.app || '',
action: action.action || '',
actionType: action.action_type || '',
name: action.name || '', // Combined app and action name from API
description: action.description || '',
image: action.image || '',
score: action.score || 0,
})),
},
}
},
outputs: {
actions: {
type: 'json',
description:
'Array of matching actions with app, action, actionType, name (combined app/action name), description, image, and score',
},
},
}

View File

@@ -0,0 +1,23 @@
import { zapierCreateAiActionTool } from '@/tools/zapier/create_action'
import { zapierDeleteAiActionTool } from '@/tools/zapier/delete_action'
import { zapierExecuteActionTool } from '@/tools/zapier/execute_action'
import { zapierGetActionDetailsTool } from '@/tools/zapier/get_action_details'
import { zapierGuessActionsTool } from '@/tools/zapier/guess_actions'
import { zapierListActionsTool } from '@/tools/zapier/list_actions'
import { zapierSearchAppActionsTool } from '@/tools/zapier/search_app_actions'
import { zapierSearchAppsTool } from '@/tools/zapier/search_apps'
import { zapierStatelessExecuteTool } from '@/tools/zapier/stateless_execute'
import { zapierUpdateAiActionTool } from '@/tools/zapier/update_action'
export {
zapierExecuteActionTool,
zapierListActionsTool,
zapierSearchAppsTool,
zapierGuessActionsTool,
zapierCreateAiActionTool,
zapierStatelessExecuteTool,
zapierSearchAppActionsTool,
zapierGetActionDetailsTool,
zapierUpdateAiActionTool,
zapierDeleteAiActionTool,
}

View File

@@ -0,0 +1,78 @@
import type { ToolConfig } from '@/tools/types'
import type { ZapierListActionsParams, ZapierListActionsResponse } from '@/tools/zapier/types'
export const zapierListActionsTool: ToolConfig<ZapierListActionsParams, ZapierListActionsResponse> =
{
id: 'zapier_list_actions',
name: 'Zapier List Actions',
description:
'List all AI Actions configured in your Zapier account. Returns stored actions that can be executed.',
version: '1.0.0',
oauth: {
required: true,
provider: 'zapier',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Access token for Zapier AI Actions API',
},
},
request: {
url: 'https://actions.zapier.com/api/v2/ai-actions/',
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || data.detail || `Zapier API error: ${response.status}`)
}
// API returns an array of actions and a configuration_link
const actions = Array.isArray(data) ? data : data.results || []
const configurationLink = data.configuration_link || 'https://actions.zapier.com/providers/'
return {
success: true,
output: {
actions: actions.map((action: any) => ({
id: action.id || '',
description: action.description || '',
actionType: action.action_type || '',
app: action.app || '',
appLabel: action.meta?.app_label || '',
action: action.action || '',
actionLabel: action.meta?.action_label || '',
params: action.params || {},
accountId: action.account_id ?? null,
authenticationId: action.authentication_id ?? null,
needs: action.needs || null,
})),
configurationLink,
},
}
},
outputs: {
actions: {
type: 'json',
description:
'Array of configured AI Actions with id, description, actionType, app, appLabel, action, actionLabel, params, accountId, authenticationId, needs',
},
configurationLink: {
type: 'string',
description: 'Link to configure more actions in Zapier',
},
},
}

View File

@@ -0,0 +1,111 @@
import type { ToolConfig } from '@/tools/types'
import type {
ZapierSearchAppActionsParams,
ZapierSearchAppActionsResponse,
} from '@/tools/zapier/types'
export const zapierSearchAppActionsTool: ToolConfig<
ZapierSearchAppActionsParams,
ZapierSearchAppActionsResponse
> = {
id: 'zapier_search_app_actions',
name: 'Zapier Search App Actions',
description:
'Search for available actions within a specific Zapier app. Returns all actions the app supports.',
version: '1.0.0',
oauth: {
required: true,
provider: 'zapier',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Access token for Zapier AI Actions API',
},
app: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The app identifier to search actions for (e.g., "SlackAPI", "GmailV2API")',
},
query: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional search query to filter actions by name or description',
},
actionTypes: {
type: 'array',
required: false,
visibility: 'user-only',
description:
'Filter by action types: write, search, read, read_bulk, search_or_write, search_and_write. Defaults to write and search.',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.query) {
queryParams.append('query', params.query)
}
if (params.actionTypes && params.actionTypes.length > 0) {
params.actionTypes.forEach((type: string) => {
queryParams.append('filter_action_type', type)
})
}
const query = queryParams.toString()
return `https://actions.zapier.com/api/v2/apps/${encodeURIComponent(params.app)}/actions/${query ? `?${query}` : ''}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || data.detail || `Zapier API error: ${response.status}`)
}
const actions = data.results || []
return {
success: true,
output: {
actions: actions.map((action: any) => ({
app: action.app || '',
action: action.action || '',
actionType: action.type || '',
displayName: action.display_name || '',
description: action.description || '',
relevancyScore: action.search_relevancy_score || 0,
appNeedsAuth: action.app_needs_auth || false,
appInfo: action.app_info
? {
app: action.app_info.app || '',
name: action.app_info.name || '',
logoUrl: action.app_info.logo_url || '',
authType: action.app_info.auth_type || '',
}
: null,
})),
},
}
},
outputs: {
actions: {
type: 'json',
description:
'Array of actions with app, action, actionType, displayName, description, relevancyScore, appNeedsAuth, appInfo',
},
},
}

View File

@@ -0,0 +1,106 @@
import type { ToolConfig } from '@/tools/types'
import type { ZapierSearchAppsParams, ZapierSearchAppsResponse } from '@/tools/zapier/types'
export const zapierSearchAppsTool: ToolConfig<ZapierSearchAppsParams, ZapierSearchAppsResponse> = {
id: 'zapier_search_apps',
name: 'Zapier Search Apps',
description:
'Search for apps available in Zapier. Returns apps with their available action counts.',
version: '1.0.0',
oauth: {
required: true,
provider: 'zapier',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Access token for Zapier AI Actions API',
},
query: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional search query to filter apps by name',
},
},
request: {
url: (params) => {
const baseUrl = 'https://actions.zapier.com/api/v2/apps/search/'
if (params.query) {
return `${baseUrl}?query=${encodeURIComponent(params.query)}`
}
return baseUrl
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || data.detail || `Zapier API error: ${response.status}`)
}
const apps = Array.isArray(data) ? data : data.results || []
return {
success: true,
output: {
apps: apps.map((app: any) => {
// The API returns an 'actions' dictionary with action type counts
// Keys can be: write, search, read, read_bulk, search_or_write, search_and_write
const actions = app.actions || {}
// Sum all action counts
const actionCount =
typeof actions === 'object'
? Object.values(actions).reduce(
(sum: number, count: any) => sum + (typeof count === 'number' ? count : 0),
0
)
: 0
// Sum write-type actions (write, search_or_write, search_and_write)
const writeActionCount =
(actions.write || 0) + (actions.search_or_write || 0) + (actions.search_and_write || 0)
// Sum search-type actions (search, search_or_write, search_and_write)
const searchActionCount =
(actions.search || 0) + (actions.search_or_write || 0) + (actions.search_and_write || 0)
// Sum read-type actions (read, read_bulk)
const readActionCount = (actions.read || 0) + (actions.read_bulk || 0)
return {
app: app.app || '',
name: app.name || '',
logoUrl: app.logo_url || '',
authType: app.auth_type ?? null,
actions,
actionCount,
writeActionCount,
searchActionCount,
readActionCount,
}
}),
},
}
},
outputs: {
apps: {
type: 'json',
description:
'Array of apps with app, name, logoUrl, authType, actions (raw counts by type), actionCount, writeActionCount, searchActionCount, readActionCount',
},
},
}

View File

@@ -0,0 +1,207 @@
import type { ToolConfig } from '@/tools/types'
import type {
ZapierStatelessExecuteParams,
ZapierStatelessExecuteResponse,
} from '@/tools/zapier/types'
export const zapierStatelessExecuteTool: ToolConfig<
ZapierStatelessExecuteParams,
ZapierStatelessExecuteResponse
> = {
id: 'zapier_stateless_execute',
name: 'Zapier Stateless Execute',
description:
'Execute any Zapier action directly without creating a stored AI Action first. Provide the app, action, and instructions.',
version: '1.0.0',
oauth: {
required: true,
provider: 'zapier',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Access token for Zapier AI Actions API',
},
app: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The app to use (e.g., "SlackAPI", "GoogleSheetsV2API", "GmailV2API")',
},
action: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The action to run (e.g., "direct_message", "add_row", "send_email")',
},
instructions: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Plain English instructions about how to run the action (e.g., "Send a message saying hello to #general")',
},
actionType: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'Type of action: write, search, read, read_bulk, search_or_write, search_and_write',
},
params: {
type: 'json',
required: false,
visibility: 'user-or-llm',
description:
'Optional parameter constraints. Each key maps to {mode: "locked"|"guess"|"choose_from"|"ignored", value: any}',
},
previewOnly: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'If true, preview the execution without actually running it',
},
authenticationId: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Authentication ID for the app connection',
},
accountId: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Zapier account ID',
},
providerId: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Provider ID for AI Actions',
},
tokenBudget: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Max tokens per field (default: 1000)',
},
skipParamGuessing: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'Skip AI parameter guessing',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.previewOnly) {
queryParams.append('preview_only', 'true')
}
if (params.providerId) {
queryParams.append('provider_id', params.providerId)
}
if (params.tokenBudget !== undefined) {
queryParams.append('token_budget', String(params.tokenBudget))
}
if (params.skipParamGuessing) {
queryParams.append('skip_param_guessing', 'true')
}
const query = queryParams.toString()
return `https://actions.zapier.com/api/v2/execute/${query ? `?${query}` : ''}`
},
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => {
const body: Record<string, any> = {
instructions: params.instructions,
app: params.app,
action: params.action,
}
if (params.actionType) {
body.action_type = params.actionType
}
if (params.params) {
body.params = params.params
}
if (params.authenticationId !== undefined) {
body.authentication_id = params.authenticationId
}
if (params.accountId !== undefined) {
body.account_id = params.accountId
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || data.detail || `Zapier API error: ${response.status}`)
}
const isSuccess = data.status === 'success' || data.status === 'preview'
const errorMessage =
data.error || (isSuccess ? undefined : `Zapier action ${data.status || 'failed'}`)
return {
success: isSuccess,
error: errorMessage,
output: {
executionLogId: data.execution_log_id || '',
actionUsed: data.action_used || '',
inputParams: data.input_params || {},
resolvedParams: data.resolved_params || {},
results: data.results || [],
resultFieldLabels: data.result_field_labels || {},
status: data.status || 'error',
error: data.error || undefined,
},
}
},
outputs: {
executionLogId: {
type: 'string',
description: 'Unique identifier for this execution',
},
actionUsed: {
type: 'string',
description: 'Name of the action that was executed',
},
inputParams: {
type: 'json',
description: 'Parameters that were passed to the API',
},
resolvedParams: {
type: 'json',
description: 'Parameters that the AI resolved for execution',
},
results: {
type: 'json',
description: 'Results from the action execution',
},
resultFieldLabels: {
type: 'json',
description: 'Human-readable labels for result fields',
},
status: {
type: 'string',
description: 'Execution status: success, error, empty, preview, or halted',
},
error: {
type: 'string',
description: 'Error message if execution failed',
optional: true,
},
},
}

View File

@@ -0,0 +1,330 @@
import type { ToolResponse } from '@/tools/types'
// Base params - all Zapier tools require OAuth access token
export interface ZapierBaseParams {
accessToken: string
}
// Parameter constraint for execute action
export interface ZapierParamConstraint {
mode: 'locked' | 'guess' | 'choose_from' | 'ignored'
value?: string | number | boolean | any[] | Record<string, any>
label?: string | any[] | Record<string, any>
}
// Action types supported by Zapier API
export type ZapierActionType =
| 'write'
| 'search'
| 'read'
| 'read_bulk'
| 'search_or_write'
| 'search_and_write'
// Execute Action params
export interface ZapierExecuteActionParams extends ZapierBaseParams {
actionId: string
instructions: string
params?: Record<string, ZapierParamConstraint>
previewOnly?: boolean
}
// List Actions params
export interface ZapierListActionsParams extends ZapierBaseParams {}
// Search Apps params
export interface ZapierSearchAppsParams extends ZapierBaseParams {
query?: string
}
// Guess Actions params (find actions based on natural language)
export interface ZapierGuessActionsParams extends ZapierBaseParams {
query: string
actionTypes?: ZapierActionType[]
count?: number
}
// Create AI Action params
export interface ZapierCreateAiActionParams extends ZapierBaseParams {
app: string
action: string
actionType?: ZapierActionType
params?: Record<string, string | string[]>
accountId?: number
authenticationId?: number
meta?: {
params?: Record<string, { label?: string }>
app_label?: string
action_label?: string
authentication_label?: string
app_needs_auth?: boolean
}
}
// Stateless Execute params
export interface ZapierStatelessExecuteParams extends ZapierBaseParams {
app: string
action: string
instructions: string
actionType?: ZapierActionType
params?: Record<string, ZapierParamConstraint>
previewOnly?: boolean
authenticationId?: number
accountId?: number
providerId?: string
tokenBudget?: number
skipParamGuessing?: boolean
}
// Search App Actions params
export interface ZapierSearchAppActionsParams extends ZapierBaseParams {
app: string
query?: string
actionTypes?: ZapierActionType[]
}
// Get Action Details params
export interface ZapierGetActionDetailsParams extends ZapierBaseParams {
app: string
action: string
actionType?: ZapierActionType
includeNeeds?: boolean
includeGives?: boolean
includeSample?: boolean
params?: Record<string, any>
accountId?: number
authenticationId?: number
}
// Update AI Action params
export interface ZapierUpdateAiActionParams extends ZapierBaseParams {
actionId: string
app: string
action: string
actionType?: ZapierActionType
params?: Record<string, string | string[]>
accountId?: number
authenticationId?: number
meta?: {
params?: Record<string, { label?: string }>
app_label?: string
action_label?: string
authentication_label?: string
app_needs_auth?: boolean
}
}
// Delete AI Action params
export interface ZapierDeleteAiActionParams extends ZapierBaseParams {
actionId: string
}
// Execute Action response
export interface ZapierExecuteActionResponse extends ToolResponse {
output: {
executionLogId: string
actionUsed: string
inputParams: Record<string, any>
resolvedParams: Record<string, any>
results: any[]
resultFieldLabels: Record<string, string>
status: 'success' | 'error' | 'empty' | 'preview' | 'halted'
error?: string
}
}
// List Actions response
export interface ZapierAiAction {
id: string
description: string
actionType: string
app: string
appLabel: string
action: string
actionLabel: string
params: Record<string, any>
accountId: number | null
authenticationId: number | null
needs: any[] | null
}
export interface ZapierListActionsResponse extends ToolResponse {
output: {
actions: ZapierAiAction[]
configurationLink: string
}
}
// Search Apps response
export interface ZapierAppActions {
write?: number
search?: number
read?: number
read_bulk?: number
search_or_write?: number
search_and_write?: number
}
export interface ZapierApp {
app: string
name: string
logoUrl: string
authType: string | null
actions: ZapierAppActions
actionCount: number
writeActionCount: number
searchActionCount: number
readActionCount: number
}
export interface ZapierSearchAppsResponse extends ToolResponse {
output: {
apps: ZapierApp[]
}
}
// Guess Actions response - matches exact API response structure
export interface ZapierGuessedAction {
app: string
action: string
actionType: string
name: string // Combined app and action name from API
description: string
image: string
score: number
}
export interface ZapierGuessActionsResponse extends ToolResponse {
output: {
actions: ZapierGuessedAction[]
}
}
// Create AI Action response - matches exact API response structure
export interface ZapierCreateAiActionResponse extends ToolResponse {
output: {
id: string
description: string
actionType: string
app: string
appLabel: string
action: string
actionLabel: string
params: Record<string, any>
accountId: number | null
authenticationId: number | null
}
}
// Stateless Execute response - same as Execute Action response
export interface ZapierStatelessExecuteResponse extends ToolResponse {
output: {
executionLogId: string
actionUsed: string
inputParams: Record<string, any>
resolvedParams: Record<string, any>
results: any[]
resultFieldLabels: Record<string, string>
status: 'success' | 'error' | 'empty' | 'preview' | 'halted'
error?: string
}
}
// Search App Actions response
export interface ZapierAppAction {
app: string
action: string
actionType: string
displayName: string
description: string
relevancyScore: number
appNeedsAuth: boolean
appInfo: {
app: string
name: string
logoUrl: string
authType: string
} | null
}
export interface ZapierSearchAppActionsResponse extends ToolResponse {
output: {
actions: ZapierAppAction[]
}
}
// Get Action Details response
export interface ZapierActionNeed {
key: string
type: string
label: string
required: boolean
helpText: string
defaultValue: any
choices: any[] | null
dependsOn: string[] | null
customField: boolean
}
export interface ZapierActionGive {
key: string
label: string
type: string
score: number | null
subscore: number | null
important: boolean
sample: any
}
export interface ZapierGetActionDetailsResponse extends ToolResponse {
output: {
action: {
type: string
key: string
name: string
noun: string
description: string
} | null
needs: ZapierActionNeed[]
gives: ZapierActionGive[]
sample: any
customNeedsProbability: number
}
}
// Update AI Action response - same as Create AI Action response
export interface ZapierUpdateAiActionResponse extends ToolResponse {
output: {
id: string
description: string
actionType: string
app: string
appLabel: string
action: string
actionLabel: string
params: Record<string, any>
accountId: number | null
authenticationId: number | null
}
}
// Delete AI Action response
export interface ZapierDeleteAiActionResponse extends ToolResponse {
output: {
deleted: boolean
message: string
}
}
// Union type for all Zapier responses
export type ZapierResponse =
| ZapierExecuteActionResponse
| ZapierListActionsResponse
| ZapierSearchAppsResponse
| ZapierGuessActionsResponse
| ZapierCreateAiActionResponse
| ZapierStatelessExecuteResponse
| ZapierSearchAppActionsResponse
| ZapierGetActionDetailsResponse
| ZapierUpdateAiActionResponse
| ZapierDeleteAiActionResponse

View File

@@ -0,0 +1,174 @@
import type { ToolConfig } from '@/tools/types'
import type { ZapierUpdateAiActionParams, ZapierUpdateAiActionResponse } from '@/tools/zapier/types'
export const zapierUpdateAiActionTool: ToolConfig<
ZapierUpdateAiActionParams,
ZapierUpdateAiActionResponse
> = {
id: 'zapier_update_action',
name: 'Zapier Update AI Action',
description: 'Update an existing stored AI Action configuration in Zapier.',
version: '1.0.0',
oauth: {
required: true,
provider: 'zapier',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Access token for Zapier AI Actions API',
},
actionId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'The ID of the AI Action to update',
},
app: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'The app identifier (e.g., "SlackAPI", "GmailV2API")',
},
action: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'The action identifier (e.g., "send_channel_message", "send_email")',
},
actionType: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'Type of action: write, search, read, read_bulk, search_or_write, search_and_write',
},
params: {
type: 'json',
required: false,
visibility: 'user-or-llm',
description: 'Pre-configured parameter values for the action',
},
accountId: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Zapier account ID',
},
authenticationId: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Authentication ID for the app connection',
},
meta: {
type: 'json',
required: false,
visibility: 'user-only',
description:
'Metadata object with params labels, app_label, action_label, authentication_label, app_needs_auth',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.accountId !== undefined) {
queryParams.append('account_id', String(params.accountId))
}
if (params.authenticationId !== undefined) {
queryParams.append('authentication_id', String(params.authenticationId))
}
const query = queryParams.toString()
return `https://actions.zapier.com/api/v2/ai-actions/${encodeURIComponent(params.actionId)}/${query ? `?${query}` : ''}`
},
method: 'PUT',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => ({
app: params.app,
action: params.action,
action_type: params.actionType || 'write',
params: params.params || {},
meta: params.meta || { params: {} },
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(data.error || data.detail || `Zapier API error: ${response.status}`)
}
const appLabel = data.meta?.app_label || ''
const actionLabel = data.meta?.action_label || ''
return {
success: true,
output: {
id: data.id || '',
description: data.description || '',
actionType: data.action_type || '',
app: data.app || '',
appLabel,
action: data.action || '',
actionLabel,
params: data.params || {},
accountId: data.account_id ?? null,
authenticationId: data.authentication_id ?? null,
},
}
},
outputs: {
id: {
type: 'string',
description: 'The ID of the updated AI Action',
},
description: {
type: 'string',
description: 'Description of the action',
},
actionType: {
type: 'string',
description: 'Type of action',
},
app: {
type: 'string',
description: 'App identifier',
},
appLabel: {
type: 'string',
description: 'Human-readable app label',
},
action: {
type: 'string',
description: 'Action identifier',
},
actionLabel: {
type: 'string',
description: 'Human-readable action label',
},
params: {
type: 'json',
description: 'Configured parameter values',
},
accountId: {
type: 'number',
description: 'Zapier account ID',
optional: true,
},
authenticationId: {
type: 'number',
description: 'Authentication ID used for the app',
optional: true,
},
},
}