From 47e36386aa307b009455d184db00c56627ae9f96 Mon Sep 17 00:00:00 2001 From: AntonyDevs Date: Tue, 10 Dec 2024 21:23:39 -0500 Subject: [PATCH 1/5] feat(tools): add Zapier Webhook tool for seamless integration with Zapier's webhook service --- packages/tools/package.json | 4 + packages/tools/rollup.config.mjs | 1 + packages/tools/src/index.js | 1 + packages/tools/src/zapier-webhook/README.md | 48 ++++ packages/tools/src/zapier-webhook/index.js | 92 +++++++ .../tools/src/zapier-webhook/tool.stories.jsx | 93 +++++++ .../tools/src/zapier-webhook/tool.test.js | 246 ++++++++++++++++++ 7 files changed, 485 insertions(+) create mode 100644 packages/tools/src/zapier-webhook/README.md create mode 100644 packages/tools/src/zapier-webhook/index.js create mode 100644 packages/tools/src/zapier-webhook/tool.stories.jsx create mode 100644 packages/tools/src/zapier-webhook/tool.test.js diff --git a/packages/tools/package.json b/packages/tools/package.json index e15829b..a5b3c26 100644 --- a/packages/tools/package.json +++ b/packages/tools/package.json @@ -45,6 +45,10 @@ "./textfile-search": { "import": "./dist/textfile-search/index.esm.js", "require": "./dist/textfile-search/index.cjs.js" + }, + "./zapier-webhook": { + "import": "./dist/zapier-webhook/index.esm.js", + "require": "./dist/zapier-webhook/index.cjs.js" } }, "files": [ diff --git a/packages/tools/rollup.config.mjs b/packages/tools/rollup.config.mjs index 264dcb6..cfb9f30 100644 --- a/packages/tools/rollup.config.mjs +++ b/packages/tools/rollup.config.mjs @@ -18,6 +18,7 @@ const toolFolders = [ 'website-search', 'pdf-search', 'textfile-search', + 'zapier-webhook', ]; // Add more folder names as needed const toolConfigs = toolFolders.map((tool) => { diff --git a/packages/tools/src/index.js b/packages/tools/src/index.js index f77c74e..f0d7fdf 100644 --- a/packages/tools/src/index.js +++ b/packages/tools/src/index.js @@ -8,3 +8,4 @@ export * from './simple-rag/index.js'; export * from './website-search/index.js'; export * from './pdf-search/index.js'; export * from './textfile-search/index.js'; +export * from './zapier-webhook/index.js'; diff --git a/packages/tools/src/zapier-webhook/README.md b/packages/tools/src/zapier-webhook/README.md new file mode 100644 index 0000000..6bd42d6 --- /dev/null +++ b/packages/tools/src/zapier-webhook/README.md @@ -0,0 +1,48 @@ +# Zapier Webhook Tool + +The Zapier Webhook Tool allows AI agents to interact with Zapier's webhook service, enabling seamless integration with thousands of apps and services supported by Zapier. + +## Purpose + +The Zapier Webhook Tool is designed to extend the capabilities of AI agents by allowing them to trigger workflows and automate tasks across various applications using Zapier's webhook functionality. This tool is ideal for scenarios where agents need to interact with multiple services and automate complex workflows. + +## Features + +- Easy integration with Zapier's webhook service +- Trigger workflows and automate tasks across thousands of apps +- Configurable options for webhook events and payloads + +## Usage + +To use the Zapier Webhook Tool, follow these steps: + +**Configure the Tool**: Create an instance of the `ZapierWebhook` tool with the required configuration. + +```javascript +import { z } from 'zod'; + +const zapierTool = new ZapierWebhook({ + url: 'https://hooks.zapier.com/hooks/catch/4716958/2sdvyu2', // Set your Zapier webhook URL here + schema: z.object({ + emailSubject: z.string().describe('The subject of the email.'), + issuesSummary: z.string().describe('The summary of the issues.'), + }), +}); +``` + +**Use the Tool**: Integrate the tool into your workflow or agent. + +```javascript +const response = await zapierTool._call({ + emailSubject: 'Weekly GitHub Issues Report', + issuesSummary: 'Summary of the issues found in the repository.', +}); + +console.log(response); +``` + +For questions or discussions, join our [Discord](https://kaibanjs.com/discord). + +## License + +MIT License diff --git a/packages/tools/src/zapier-webhook/index.js b/packages/tools/src/zapier-webhook/index.js new file mode 100644 index 0000000..1a34525 --- /dev/null +++ b/packages/tools/src/zapier-webhook/index.js @@ -0,0 +1,92 @@ +/** + * Zapier Webhook Tool + * + * This tool allows integration with Zapier's webhook service, enabling seamless + * interaction with thousands of apps and services supported by Zapier. It is + * designed to trigger workflows and automate tasks across various applications + * using Zapier's webhook functionality. + * + * Key features of Zapier Webhook Tool: + * - Easy integration with Zapier's webhook service + * - Trigger workflows and automate tasks across thousands of apps + * - Configurable options for webhook events and payloads + * + * Usage: + * const zapierTool = new ZapierWebhook({ + * url: 'https://hooks.zapier.com/hooks/catch/4716958/2sdvyu2', // Set your Zapier webhook URL here + * schema: z.object({ + * emailSubject: z.string().describe('The subject of the email.'), + * issuesSummary: z.string().describe('The summary of the issues.'), + * }), + * }); + * const response = await zapierTool._call({ + * emailSubject: 'Weekly GitHub Issues Report', + * issuesSummary: 'Summary of the issues found in the repository.', + * }); + * + * For more information about Zapier, visit: https://zapier.com/ + */ + +import { Tool } from '@langchain/core/tools'; +import ky from 'ky'; +import { HTTPError } from 'ky'; + +/** + * Class representing a Zapier Webhook tool. + * @extends Tool + */ +export class ZapierWebhook extends Tool { + /** + * Create a ZapierWebhook tool. + * @param {Object} fields - The configuration fields for the tool. + * @param {string} fields.url - The Zapier webhook URL. + * @param {Object} fields.schema - The schema for the input data using Zod. + */ + constructor(fields) { + super(fields); + this.url = fields.url; + this.name = 'zapier_webhook'; + this.description = + 'A tool for triggering Zapier webhooks to integrate with various services. Input should be a JSON object with the necessary data for the webhook.'; + + this.httpClient = ky; + this.schema = fields.schema; + } + + /** + * Call the Zapier webhook with the provided input data. + * @param {Object} input - The input data for the webhook. + * @returns {Promise} The response from the webhook as a JSON string. + */ + async _call(input) { + try { + const jsonData = await this.httpClient + .post(this.url, { + json: input, + headers: { + 'Content-Type': 'application/json', + }, + }) + .json(); + + if (!jsonData || typeof jsonData !== 'object') { + return 'Could not parse Zapier webhook response. Please try again.'; + } + + return JSON.stringify(jsonData); + } catch (error) { + if (error instanceof HTTPError) { + const statusCode = error.response.status; + let errorType = 'Unknown'; + if (statusCode >= 400 && statusCode < 500) { + errorType = 'Client Error'; + } else if (statusCode >= 500) { + errorType = 'Server Error'; + } + return `API request failed: ${errorType} (${statusCode})`; + } else { + return `An unexpected error occurred: ${error.message}`; + } + } + } +} diff --git a/packages/tools/src/zapier-webhook/tool.stories.jsx b/packages/tools/src/zapier-webhook/tool.stories.jsx new file mode 100644 index 0000000..0792a65 --- /dev/null +++ b/packages/tools/src/zapier-webhook/tool.stories.jsx @@ -0,0 +1,93 @@ +import { z } from 'zod'; +import { ToolPreviewer } from '../_utils/ToolPreviewer.jsx'; +import { AgentWithToolPreviewer } from '../_utils/AgentWithToolPreviewer.jsx'; +import { GithubIssues } from '../github-issues/index.js'; +import { ZapierWebhook } from './index.js'; +import { Agent, Task, Team } from '../../../../src/index'; +import React from 'react'; + +export default { + title: 'Tools/Zapier Webhook', + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: {}, +}; + +const githubTool = new GithubIssues({ + token: import.meta.env.VITE_GITHUB_TOKEN, + limit: 5, +}); + +const zapierTool = new ZapierWebhook({ + url: 'https://hooks.zapier.com/hooks/catch/4716958/2sdvyu2', // Set your Zapier webhook URL here + schema: z.object({ + emailSubject: z.string().describe('The subject of the email.'), + issuesSummary: z.string().describe('The summary of the issues.'), + }), +}); + +export const Default = { + render: (args) => , + args: { + toolInstance: zapierTool, + callParams: { + emailSubject: 'Weekly GitHub Issues Report', + issuesSummary: 'Summary of the issues found in the repository.', + }, + }, +}; + +// Create an agent with the GitHub tool +const issueAnalyzer = new Agent({ + name: 'Issue Analyzer', + role: 'GitHub Repository Inspector', + goal: 'Analyze and summarize GitHub repository issues', + tools: [githubTool], +}); + +// Create an agent with the Zapier webhook tool +const emailSender = new Agent({ + name: 'Email Sender', + role: 'Email Reporter', + goal: 'Send summarized issues via email using Zapier webhook', + tools: [zapierTool], +}); + +// Create an analysis task +const issueAnalysisTask = new Task({ + description: + 'Fetch and analyze issues from the following repository: {repoUrl}', + agent: issueAnalyzer, + expectedOutput: 'A structured summary of repository issues', +}); + +// Create a task to send the summary via Zapier webhook +const sendEmailTask = new Task({ + description: 'Send the summarized issues via Zapier webhook', + agent: emailSender, + expectedOutput: 'A confirmation that the email was sent successfully', +}); + +// Create the team +const team = new Team({ + name: 'Issue Reporting Team', + description: + 'Team to fetch GitHub issues and send them via email using Zapier webhook', + agents: [issueAnalyzer, emailSender], + tasks: [issueAnalysisTask, sendEmailTask], + inputs: { + repoUrl: 'https://github.com/facebook/react', + }, + env: { + OPENAI_API_KEY: import.meta.env.VITE_OPENAI_API_KEY, + }, +}); + +export const withAgent = { + render: (args) => , + args: { + team: team, + }, +}; diff --git a/packages/tools/src/zapier-webhook/tool.test.js b/packages/tools/src/zapier-webhook/tool.test.js new file mode 100644 index 0000000..fd535f9 --- /dev/null +++ b/packages/tools/src/zapier-webhook/tool.test.js @@ -0,0 +1,246 @@ +const { ZapierWebhook } = require('../../dist/zapier-webhook/index.cjs.js'); + +describe('ZapierWebhook', () => { + test('ZapierWebhook sends correct parameters and receives response', async () => { + const tool = new ZapierWebhook({ + url: 'https://hooks.zapier.com/hooks/catch/123456/abcdef', + schema: { + data: { + type: 'object', + properties: { + issues: { + type: 'array', + items: { + type: 'object', + properties: { + title: { type: 'string' }, + url: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + let capturedRequest; + tool.httpClient = tool.httpClient.extend({ + hooks: { + beforeRequest: [ + (request) => { + capturedRequest = request; + return new Response( + JSON.stringify({ + status: 'success', + message: 'Webhook received', + }), + { + status: 200, + headers: { 'Content-Type': 'application/json' }, + } + ); + }, + ], + }, + }); + + const result = await tool._call({ + data: { + issues: [ + { title: 'Issue 1', url: 'https://github.com/owner/repo/issues/1' }, + { title: 'Issue 2', url: 'https://github.com/owner/repo/issues/2' }, + ], + }, + }); + + // Check request + expect(capturedRequest.url).toBe( + 'https://hooks.zapier.com/hooks/catch/123456/abcdef' + ); + expect(capturedRequest.method).toBe('POST'); + expect(capturedRequest.headers.get('Content-Type')).toBe( + 'application/json' + ); + const body = await capturedRequest.json(); + expect(body).toEqual({ + data: { + issues: [ + { title: 'Issue 1', url: 'https://github.com/owner/repo/issues/1' }, + { title: 'Issue 2', url: 'https://github.com/owner/repo/issues/2' }, + ], + }, + }); + + // Check response + expect(result).toBe( + JSON.stringify({ status: 'success', message: 'Webhook received' }) + ); + }); + + test('ZapierWebhook handles client error (4xx)', async () => { + const tool = new ZapierWebhook({ + url: 'https://hooks.zapier.com/hooks/catch/123456/abcdef', + schema: { + data: { + type: 'object', + properties: { + issues: { + type: 'array', + items: { + type: 'object', + properties: { + title: { type: 'string' }, + url: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + tool.httpClient = tool.httpClient.extend({ + hooks: { + beforeRequest: [ + () => { + return new Response( + JSON.stringify({ + status: 'error', + message: 'Invalid request', + }), + { + status: 400, + headers: { 'Content-Type': 'application/json' }, + } + ); + }, + ], + }, + }); + + const result = await tool._call({ + data: { + issues: [ + { title: 'Issue 1', url: 'https://github.com/owner/repo/issues/1' }, + { title: 'Issue 2', url: 'https://github.com/owner/repo/issues/2' }, + ], + }, + }); + + expect(result).toBe('API request failed: Client Error (400)'); + }); + + test('ZapierWebhook handles server error (5xx)', async () => { + const tool = new ZapierWebhook({ + url: 'https://hooks.zapier.com/hooks/catch/123456/abcdef', + schema: { + data: { + type: 'object', + properties: { + issues: { + type: 'array', + items: { + type: 'object', + properties: { + title: { type: 'string' }, + url: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + tool.httpClient = tool.httpClient.extend({ + hooks: { + beforeRequest: [ + () => { + return new Response( + JSON.stringify({ + status: 'error', + message: 'Internal Server Error', + }), + { + status: 500, + headers: { 'Content-Type': 'application/json' }, + } + ); + }, + ], + }, + }); + + const result = await tool._call({ + data: { + issues: [ + { title: 'Issue 1', url: 'https://github.com/owner/repo/issues/1' }, + { title: 'Issue 2', url: 'https://github.com/owner/repo/issues/2' }, + ], + }, + }); + + expect(result).toBe('API request failed: Server Error (500)'); + }); + + test('ZapierWebhook handles unexpected errors', async () => { + const tool = new ZapierWebhook({ + url: 'https://hooks.zapier.com/hooks/catch/123456/abcdef', + schema: { + data: { + type: 'object', + properties: { + issues: { + type: 'array', + items: { + type: 'object', + properties: { + title: { type: 'string' }, + url: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + tool.httpClient = tool.httpClient.extend({ + hooks: { + beforeRequest: [ + () => { + throw new Error('Network Error'); + }, + ], + }, + }); + + const result = await tool._call({ + data: { + issues: [ + { title: 'Issue 1', url: 'https://github.com/owner/repo/issues/1' }, + { title: 'Issue 2', url: 'https://github.com/owner/repo/issues/2' }, + ], + }, + }); + + expect(result).toBe('An unexpected error occurred: Network Error'); + }); + + test('ZapierWebhook is exported correctly in both paths', () => { + const { ZapierWebhook } = require('../../dist/zapier-webhook/index.cjs.js'); + const { + ZapierWebhook: ZapierWebhookMain, + } = require('../../dist/index.cjs.js'); + + // Check that both imports are constructor functions + expect(typeof ZapierWebhook).toBe('function'); + expect(typeof ZapierWebhookMain).toBe('function'); + + // Check they have the same name and properties + expect(ZapierWebhook.name).toBe(ZapierWebhookMain.name); + expect(Object.keys(ZapierWebhook.prototype)).toEqual( + Object.keys(ZapierWebhookMain.prototype) + ); + }); +}); From 8dd6142f3593ce05670086d77491e0916d816110 Mon Sep 17 00:00:00 2001 From: AntonyDevs Date: Wed, 11 Dec 2024 14:51:13 -0500 Subject: [PATCH 2/5] feat(tools): add Make Webhook tool for seamless integration with Make's webhook service --- packages/tools/package.json | 4 + packages/tools/rollup.config.mjs | 1 + packages/tools/src/index.js | 1 + packages/tools/src/make-webhook/README.md | 48 ++++ packages/tools/src/make-webhook/index.js | 90 +++++++ .../tools/src/make-webhook/tool.stories.jsx | 93 +++++++ packages/tools/src/make-webhook/tool.test.js | 242 ++++++++++++++++++ 7 files changed, 479 insertions(+) create mode 100644 packages/tools/src/make-webhook/README.md create mode 100644 packages/tools/src/make-webhook/index.js create mode 100644 packages/tools/src/make-webhook/tool.stories.jsx create mode 100644 packages/tools/src/make-webhook/tool.test.js diff --git a/packages/tools/package.json b/packages/tools/package.json index a5b3c26..4393207 100644 --- a/packages/tools/package.json +++ b/packages/tools/package.json @@ -49,6 +49,10 @@ "./zapier-webhook": { "import": "./dist/zapier-webhook/index.esm.js", "require": "./dist/zapier-webhook/index.cjs.js" + }, + "./make-webhook": { + "import": "./dist/make-webhook/index.esm.js", + "require": "./dist/make-webhook/index.cjs.js" } }, "files": [ diff --git a/packages/tools/rollup.config.mjs b/packages/tools/rollup.config.mjs index cfb9f30..ee8d01f 100644 --- a/packages/tools/rollup.config.mjs +++ b/packages/tools/rollup.config.mjs @@ -19,6 +19,7 @@ const toolFolders = [ 'pdf-search', 'textfile-search', 'zapier-webhook', + 'make-webhook', ]; // Add more folder names as needed const toolConfigs = toolFolders.map((tool) => { diff --git a/packages/tools/src/index.js b/packages/tools/src/index.js index f0d7fdf..e876e17 100644 --- a/packages/tools/src/index.js +++ b/packages/tools/src/index.js @@ -9,3 +9,4 @@ export * from './website-search/index.js'; export * from './pdf-search/index.js'; export * from './textfile-search/index.js'; export * from './zapier-webhook/index.js'; +export * from './make-webhook/index.js'; diff --git a/packages/tools/src/make-webhook/README.md b/packages/tools/src/make-webhook/README.md new file mode 100644 index 0000000..938d09c --- /dev/null +++ b/packages/tools/src/make-webhook/README.md @@ -0,0 +1,48 @@ +# Make Webhook Tool + +The Make Webhook Tool allows AI agents to interact with Make's webhook service, enabling seamless integration with thousands of apps and services supported by Make. + +## Purpose + +The Make Webhook Tool is designed to extend the capabilities of AI agents by allowing them to trigger workflows and automate tasks across various applications using Make's webhook functionality. This tool is ideal for scenarios where agents need to interact with multiple services and automate complex workflows. + +## Features + +- Easy integration with Make's webhook service +- Trigger workflows and automate tasks across thousands of apps +- Configurable options for webhook events and payloads + +## Usage + +To use the Make Webhook Tool, follow these steps: + +**Configure the Tool**: Create an instance of the `MakeWebhook` tool with the required configuration. + +```javascript +import { z } from 'zod'; + +const MakeTool = new MakeWebhook({ + url: 'https://hooks.Make.com/hooks/catch/4716958/2sdvyu2', // Set your Make webhook URL here + schema: z.object({ + emailSubject: z.string().describe('The subject of the email.'), + issuesSummary: z.string().describe('The summary of the issues.'), + }), +}); +``` + +**Use the Tool**: Integrate the tool into your workflow or agent. + +```javascript +const response = await MakeTool._call({ + emailSubject: 'Weekly GitHub Issues Report', + issuesSummary: 'Summary of the issues found in the repository.', +}); + +console.log(response); +``` + +For questions or discussions, join our [Discord](https://kaibanjs.com/discord). + +## License + +MIT License diff --git a/packages/tools/src/make-webhook/index.js b/packages/tools/src/make-webhook/index.js new file mode 100644 index 0000000..7d0c9c9 --- /dev/null +++ b/packages/tools/src/make-webhook/index.js @@ -0,0 +1,90 @@ +/** + * Make Webhook Tool + * + * This tool allows integration with Make's webhook service, enabling seamless + * interaction with thousands of apps and services supported by Make. It is + * designed to trigger workflows and automate tasks across various applications + * using Make's webhook functionality. + * + * Key features of Make Webhook Tool: + * - Easy integration with Make's webhook service + * - Trigger workflows and automate tasks across thousands of apps + * - Configurable options for webhook events and payloads + * + * Usage: + * const MakeTool = new MakeWebhook({ + * url: 'https://hooks.Make.com/hooks/catch/4716958/2sdvyu2', // Set your Make webhook URL here + * schema: z.object({ + * emailSubject: z.string().describe('The subject of the email.'), + * issuesSummary: z.string().describe('The summary of the issues.'), + * }), + * }); + * const response = await MakeTool._call({ + * emailSubject: 'Weekly GitHub Issues Report', + * issuesSummary: 'Summary of the issues found in the repository.', + * }); + * + * For more information about Make, visit: https://Make.com/ + */ + +import { Tool } from '@langchain/core/tools'; +import ky from 'ky'; +import { HTTPError } from 'ky'; + +/** + * Class representing a Make Webhook tool. + * @extends Tool + */ +export class MakeWebhook extends Tool { + /** + * Create a MakeWebhook tool. + * @param {Object} fields - The configuration fields for the tool. + * @param {string} fields.url - The Make webhook URL. + * @param {Object} fields.schema - The schema for the input data using Zod. + */ + constructor(fields) { + super(fields); + this.url = fields.url; + this.name = 'make_webhook'; + this.description = + 'A tool for triggering Make webhooks to integrate with various services. Input should be a JSON object with the necessary data for the webhook.'; + + this.httpClient = ky; + this.schema = fields.schema; + } + + /** + * Call the Make webhook with the provided input data. + * @param {Object} input - The input data for the webhook. + * @returns {Promise} The response from the webhook as a JSON string. + */ + async _call(input) { + try { + const response = await this.httpClient.post(this.url, { + json: input, + headers: { + 'Content-Type': 'application/json', + }, + }); + + if (!response.ok) { + return 'Could not parse Make webhook response. Please try again.'; + } + + return 'Webhook response success'; + } catch (error) { + if (error instanceof HTTPError) { + const statusCode = error.response.status; + let errorType = 'Unknown'; + if (statusCode >= 400 && statusCode < 500) { + errorType = 'Client Error'; + } else if (statusCode >= 500) { + errorType = 'Server Error'; + } + return `API request failed: ${errorType} (${statusCode})`; + } else { + return `An unexpected error occurred: ${error.message}`; + } + } + } +} diff --git a/packages/tools/src/make-webhook/tool.stories.jsx b/packages/tools/src/make-webhook/tool.stories.jsx new file mode 100644 index 0000000..41a5d9b --- /dev/null +++ b/packages/tools/src/make-webhook/tool.stories.jsx @@ -0,0 +1,93 @@ +import { z } from 'zod'; +import { ToolPreviewer } from '../_utils/ToolPreviewer.jsx'; +import { AgentWithToolPreviewer } from '../_utils/AgentWithToolPreviewer.jsx'; +import { GithubIssues } from '../github-issues/index.js'; +import { MakeWebhook } from './index.js'; +import { Agent, Task, Team } from '../../../../src/index'; +import React from 'react'; + +export default { + title: 'Tools/Make Webhook', + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: {}, +}; + +const githubTool = new GithubIssues({ + token: import.meta.env.VITE_GITHUB_TOKEN, + limit: 5, +}); + +const makeTool = new MakeWebhook({ + url: 'https://hook.us2.make.com/fwxq61cn8k5f6143rsomlk3plcupsypp', // Set your Make webhook URL here + schema: z.object({ + emailSubject: z.string().describe('The subject of the email.'), + issuesSummary: z.string().describe('The summary of the issues.'), + }), +}); + +export const Default = { + render: (args) => , + args: { + toolInstance: makeTool, + callParams: { + emailSubject: 'Weekly GitHub Issues Report', + issuesSummary: 'Summary of the issues found in the repository.', + }, + }, +}; + +// Create an agent with the GitHub tool +const issueAnalyzer = new Agent({ + name: 'Issue Analyzer', + role: 'GitHub Repository Inspector', + goal: 'Analyze and summarize GitHub repository issues', + tools: [githubTool], +}); + +// Create an agent with the Make webhook tool +const emailSender = new Agent({ + name: 'Email Sender', + role: 'Email Reporter', + goal: 'Send summarized issues via email using Make webhook', + tools: [makeTool], +}); + +// Create an analysis task +const issueAnalysisTask = new Task({ + description: + 'Fetch and analyze issues from the following repository: {repoUrl}', + agent: issueAnalyzer, + expectedOutput: 'A structured summary of repository issues', +}); + +// Create a task to send the summary via Make webhook +const sendEmailTask = new Task({ + description: 'Send the summarized issues via Make webhook', + agent: emailSender, + expectedOutput: 'A confirmation that the email was sent successfully', +}); + +// Create the team +const team = new Team({ + name: 'Issue Reporting Team', + description: + 'Team to fetch GitHub issues and send them via email using Make webhook', + agents: [issueAnalyzer, emailSender], + tasks: [issueAnalysisTask, sendEmailTask], + inputs: { + repoUrl: 'https://github.com/facebook/react', + }, + env: { + OPENAI_API_KEY: import.meta.env.VITE_OPENAI_API_KEY, + }, +}); + +export const withAgent = { + render: (args) => , + args: { + team: team, + }, +}; diff --git a/packages/tools/src/make-webhook/tool.test.js b/packages/tools/src/make-webhook/tool.test.js new file mode 100644 index 0000000..5b803ef --- /dev/null +++ b/packages/tools/src/make-webhook/tool.test.js @@ -0,0 +1,242 @@ +const { MakeWebhook } = require('../../dist/Make-webhook/index.cjs.js'); + +describe('MakeWebhook', () => { + test('MakeWebhook sends correct parameters and receives response', async () => { + const tool = new MakeWebhook({ + url: 'https://hook.us2.make.com/fwxq61cn8k5f6143rsomlk3plcupsypp', + schema: { + data: { + type: 'object', + properties: { + issues: { + type: 'array', + items: { + type: 'object', + properties: { + title: { type: 'string' }, + url: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + let capturedRequest; + tool.httpClient = tool.httpClient.extend({ + hooks: { + beforeRequest: [ + (request) => { + capturedRequest = request; + return new Response( + JSON.stringify({ + status: 'success', + message: 'Webhook received', + }), + { + status: 200, + headers: { 'Content-Type': 'application/json' }, + } + ); + }, + ], + }, + }); + + const result = await tool._call({ + data: { + issues: [ + { title: 'Issue 1', url: 'https://github.com/owner/repo/issues/1' }, + { title: 'Issue 2', url: 'https://github.com/owner/repo/issues/2' }, + ], + }, + }); + + // Check request + expect(capturedRequest.url).toBe( + 'https://hook.us2.make.com/fwxq61cn8k5f6143rsomlk3plcupsypp' + ); + expect(capturedRequest.method).toBe('POST'); + expect(capturedRequest.headers.get('Content-Type')).toBe( + 'application/json' + ); + const body = await capturedRequest.json(); + expect(body).toEqual({ + data: { + issues: [ + { title: 'Issue 1', url: 'https://github.com/owner/repo/issues/1' }, + { title: 'Issue 2', url: 'https://github.com/owner/repo/issues/2' }, + ], + }, + }); + + // Check response + expect(result).toBe('Webhook response success'); + }); + + test('MakeWebhook handles client error (4xx)', async () => { + const tool = new MakeWebhook({ + url: 'https://hook.us2.make.com/fwxq61cn8k5f6143rsomlk3plcupsypp', + schema: { + data: { + type: 'object', + properties: { + issues: { + type: 'array', + items: { + type: 'object', + properties: { + title: { type: 'string' }, + url: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + tool.httpClient = tool.httpClient.extend({ + hooks: { + beforeRequest: [ + () => { + return new Response( + JSON.stringify({ + status: 'error', + message: 'Invalid request', + }), + { + status: 400, + headers: { 'Content-Type': 'application/json' }, + } + ); + }, + ], + }, + }); + + const result = await tool._call({ + data: { + issues: [ + { title: 'Issue 1', url: 'https://github.com/owner/repo/issues/1' }, + { title: 'Issue 2', url: 'https://github.com/owner/repo/issues/2' }, + ], + }, + }); + + expect(result).toBe('API request failed: Client Error (400)'); + }); + + test('MakeWebhook handles server error (5xx)', async () => { + const tool = new MakeWebhook({ + url: 'https://hook.us2.make.com/fwxq61cn8k5f6143rsomlk3plcupsypp', + schema: { + data: { + type: 'object', + properties: { + issues: { + type: 'array', + items: { + type: 'object', + properties: { + title: { type: 'string' }, + url: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + tool.httpClient = tool.httpClient.extend({ + hooks: { + beforeRequest: [ + () => { + return new Response( + JSON.stringify({ + status: 'error', + message: 'Internal Server Error', + }), + { + status: 500, + headers: { 'Content-Type': 'application/json' }, + } + ); + }, + ], + }, + }); + + const result = await tool._call({ + data: { + issues: [ + { title: 'Issue 1', url: 'https://github.com/owner/repo/issues/1' }, + { title: 'Issue 2', url: 'https://github.com/owner/repo/issues/2' }, + ], + }, + }); + + expect(result).toBe('API request failed: Server Error (500)'); + }); + + test('MakeWebhook handles unexpected errors', async () => { + const tool = new MakeWebhook({ + url: 'https://hook.us2.make.com/fwxq61cn8k5f6143rsomlk3plcupsypp', + schema: { + data: { + type: 'object', + properties: { + issues: { + type: 'array', + items: { + type: 'object', + properties: { + title: { type: 'string' }, + url: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }); + + tool.httpClient = tool.httpClient.extend({ + hooks: { + beforeRequest: [ + () => { + throw new Error('Network Error'); + }, + ], + }, + }); + + const result = await tool._call({ + data: { + issues: [ + { title: 'Issue 1', url: 'https://github.com/owner/repo/issues/1' }, + { title: 'Issue 2', url: 'https://github.com/owner/repo/issues/2' }, + ], + }, + }); + + expect(result).toBe('An unexpected error occurred: Network Error'); + }); + + test('MakeWebhook is exported correctly in both paths', () => { + const { MakeWebhook } = require('../../dist/make-webhook/index.cjs.js'); + const { MakeWebhook: MakeWebhookMain } = require('../../dist/index.cjs.js'); + + // Check that both imports are constructor functions + expect(typeof MakeWebhook).toBe('function'); + expect(typeof MakeWebhookMain).toBe('function'); + + // Check they have the same name and properties + expect(MakeWebhook.name).toBe(MakeWebhookMain.name); + expect(Object.keys(MakeWebhook.prototype)).toEqual( + Object.keys(MakeWebhookMain.prototype) + ); + }); +}); From 87022361ae71ad05625433379b981b4ce4713dc0 Mon Sep 17 00:00:00 2001 From: AntonyDevs Date: Wed, 11 Dec 2024 21:39:08 -0500 Subject: [PATCH 3/5] fix typo --- packages/tools/src/make-webhook/tool.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tools/src/make-webhook/tool.test.js b/packages/tools/src/make-webhook/tool.test.js index 5b803ef..4e3b2b0 100644 --- a/packages/tools/src/make-webhook/tool.test.js +++ b/packages/tools/src/make-webhook/tool.test.js @@ -1,4 +1,4 @@ -const { MakeWebhook } = require('../../dist/Make-webhook/index.cjs.js'); +const { MakeWebhook } = require('../../dist/make-webhook/index.cjs.js'); describe('MakeWebhook', () => { test('MakeWebhook sends correct parameters and receives response', async () => { From d2dfa76db7abed44c99ec44d071ae8e58c76323d Mon Sep 17 00:00:00 2001 From: AntonyDevs Date: Mon, 16 Dec 2024 11:21:04 -0500 Subject: [PATCH 4/5] fix cors error in zapier webhook --- packages/tools/src/zapier-webhook/index.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/tools/src/zapier-webhook/index.js b/packages/tools/src/zapier-webhook/index.js index 1a34525..744a7ff 100644 --- a/packages/tools/src/zapier-webhook/index.js +++ b/packages/tools/src/zapier-webhook/index.js @@ -62,10 +62,7 @@ export class ZapierWebhook extends Tool { try { const jsonData = await this.httpClient .post(this.url, { - json: input, - headers: { - 'Content-Type': 'application/json', - }, + body: JSON.stringify(input), }) .json(); From f065f2582d1c19758ff9b3fa8c40817ea35d9b8f Mon Sep 17 00:00:00 2001 From: AntonyDevs Date: Mon, 16 Dec 2024 11:25:42 -0500 Subject: [PATCH 5/5] fix test in zapier webhook tool --- packages/tools/src/zapier-webhook/tool.test.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/tools/src/zapier-webhook/tool.test.js b/packages/tools/src/zapier-webhook/tool.test.js index fd535f9..40c34ad 100644 --- a/packages/tools/src/zapier-webhook/tool.test.js +++ b/packages/tools/src/zapier-webhook/tool.test.js @@ -58,9 +58,6 @@ describe('ZapierWebhook', () => { 'https://hooks.zapier.com/hooks/catch/123456/abcdef' ); expect(capturedRequest.method).toBe('POST'); - expect(capturedRequest.headers.get('Content-Type')).toBe( - 'application/json' - ); const body = await capturedRequest.json(); expect(body).toEqual({ data: {