mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-09 23:17:59 -05:00
Compare commits
3 Commits
v0.5.47
...
feat/zapie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3696658b03 | ||
|
|
4d9ae94047 | ||
|
|
ce72880935 |
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
"wordpress",
|
||||
"x",
|
||||
"youtube",
|
||||
"zapier",
|
||||
"zendesk",
|
||||
"zep",
|
||||
"zoom"
|
||||
|
||||
275
apps/docs/content/docs/en/tools/zapier.mdx
Normal file
275
apps/docs/content/docs/en/tools/zapier.mdx
Normal 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 Zapier’s 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 Zapier’s 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`
|
||||
@@ -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 {
|
||||
|
||||
808
apps/sim/blocks/blocks/zapier.ts
Normal file
808
apps/sim/blocks/blocks/zapier.ts
Normal 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',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}`)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
172
apps/sim/tools/zapier/create_action.ts
Normal file
172
apps/sim/tools/zapier/create_action.ts
Normal 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,
|
||||
},
|
||||
},
|
||||
}
|
||||
73
apps/sim/tools/zapier/delete_action.ts
Normal file
73
apps/sim/tools/zapier/delete_action.ts
Normal 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',
|
||||
},
|
||||
},
|
||||
}
|
||||
136
apps/sim/tools/zapier/execute_action.ts
Normal file
136
apps/sim/tools/zapier/execute_action.ts
Normal 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,
|
||||
},
|
||||
},
|
||||
}
|
||||
202
apps/sim/tools/zapier/get_action_details.ts
Normal file
202
apps/sim/tools/zapier/get_action_details.ts
Normal 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',
|
||||
},
|
||||
},
|
||||
}
|
||||
103
apps/sim/tools/zapier/guess_actions.ts
Normal file
103
apps/sim/tools/zapier/guess_actions.ts
Normal 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',
|
||||
},
|
||||
},
|
||||
}
|
||||
23
apps/sim/tools/zapier/index.ts
Normal file
23
apps/sim/tools/zapier/index.ts
Normal 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,
|
||||
}
|
||||
78
apps/sim/tools/zapier/list_actions.ts
Normal file
78
apps/sim/tools/zapier/list_actions.ts
Normal 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',
|
||||
},
|
||||
},
|
||||
}
|
||||
111
apps/sim/tools/zapier/search_app_actions.ts
Normal file
111
apps/sim/tools/zapier/search_app_actions.ts
Normal 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',
|
||||
},
|
||||
},
|
||||
}
|
||||
106
apps/sim/tools/zapier/search_apps.ts
Normal file
106
apps/sim/tools/zapier/search_apps.ts
Normal 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',
|
||||
},
|
||||
},
|
||||
}
|
||||
207
apps/sim/tools/zapier/stateless_execute.ts
Normal file
207
apps/sim/tools/zapier/stateless_execute.ts
Normal 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,
|
||||
},
|
||||
},
|
||||
}
|
||||
330
apps/sim/tools/zapier/types.ts
Normal file
330
apps/sim/tools/zapier/types.ts
Normal 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
|
||||
174
apps/sim/tools/zapier/update_action.ts
Normal file
174
apps/sim/tools/zapier/update_action.ts
Normal 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,
|
||||
},
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user