Add Activepieces integration for workflow automation

- Add Activepieces fork with SmoothSchedule custom piece
- Create integrations app with Activepieces service layer
- Add embed token endpoint for iframe integration
- Create Automations page with embedded workflow builder
- Add sidebar visibility fix for embed mode
- Add list inactive customers endpoint to Public API
- Include SmoothSchedule triggers: event created/updated/cancelled
- Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
poduck
2025-12-18 22:59:37 -05:00
parent 9848268d34
commit 3aa7199503
16292 changed files with 1284892 additions and 4708 deletions

View File

@@ -0,0 +1,38 @@
import { HttpMethod } from '@activepieces/pieces-common';
import { createAction, Property } from '@activepieces/pieces-framework';
import { chatbaseAuth } from '../../index';
import { makeRequest } from '../common';
export const createChatbotAction = createAction({
auth: chatbaseAuth,
name: 'create_chatbot',
displayName: 'Create Chatbot',
description: 'Creates a new chatbot.',
props: {
chatbotName: Property.ShortText({
displayName: 'Chatbot Name',
required: true,
}),
sourceText: Property.LongText({
displayName: 'Source Text',
description: 'Optional text data for training the chatbot.',
required: false,
}),
},
async run(context) {
const { chatbotName, sourceText } = context.propsValue;
const apiKey = context.auth.secret_text;
const body: Record<string, unknown> = {
chatbotName,
};
if (sourceText) {
body['sourceText'] = sourceText;
}
const response = await makeRequest(apiKey, HttpMethod.POST, '/create-chatbot', body);
return response;
},
});

View File

@@ -0,0 +1,20 @@
import { HttpMethod } from '@activepieces/pieces-common';
import { createAction } from '@activepieces/pieces-framework';
import { chatbaseAuth } from '../../index';
import { makeRequest } from '../common';
export const listChatbotsAction = createAction({
auth: chatbaseAuth,
name: 'list_chatbots',
displayName: 'List All Chatbots',
description: 'Retrieves a list of all chatbots.',
props: {},
async run(context) {
const apiKey = context.auth.secret_text;
const response = await makeRequest(apiKey, HttpMethod.GET, '/get-chatbots');
return response;
},
});

View File

@@ -0,0 +1,83 @@
import { HttpMethod } from '@activepieces/pieces-common';
import { createAction, Property } from '@activepieces/pieces-framework';
import { chatbaseAuth } from '../../index';
import { makeRequest } from '../common';
import { chatbotIdDropdown } from '../common/props';
export const searchConversationsAction = createAction({
auth: chatbaseAuth,
name: 'search_conversations',
displayName: 'Search Conversations by Query',
description: 'Searches for conversations from a specific chatbot.',
props: {
chatbotId: chatbotIdDropdown,
filteredSources: Property.StaticMultiSelectDropdown({
displayName: 'Sources',
description: 'Filter by one or more conversation sources.',
required: false,
options: {
disabled: false,
options: [
{ label: 'API', value: 'API' },
{ label: 'Chatbase site', value: 'Chatbase site' },
{ label: 'Instagram', value: 'Instagram' },
{ label: 'Messenger', value: 'Messenger' },
{ label: 'Slack', value: 'Slack' },
{ label: 'Unspecified', value: 'Unspecified' },
{ label: 'WhatsApp', value: 'WhatsApp' },
{ label: 'Widget or Iframe', value: 'Widget or Iframe' },
],
},
}),
startDate: Property.DateTime({
displayName: 'Start Date',
required: false,
}),
endDate: Property.DateTime({
displayName: 'End Date',
required: false,
}),
page: Property.Number({
displayName: 'Page',
description: 'Pagination page number (default = 1)',
required: false,
}),
size: Property.Number({
displayName: 'Page Size',
description: 'Number of results per page (default = 10, max = 100)',
required: false,
}),
},
async run(context) {
const { chatbotId, filteredSources, startDate, endDate, page, size } = context.propsValue;
const apiKey = context.auth.secret_text;
const queryParams = new URLSearchParams({ chatbotId });
if (filteredSources?.length) {
queryParams.append('filteredSources', filteredSources.join(','));
}
if (startDate) {
queryParams.append('startDate', startDate.toString().split('T')[0]);
}
if (endDate) {
queryParams.append('endDate', endDate.toString().split('T')[0]);
}
if (page) {
queryParams.append('page', page.toString());
}
if (size) {
queryParams.append('size', size.toString());
}
const response = await makeRequest(
apiKey,
HttpMethod.GET,
`/get-conversations?${queryParams.toString()}`,
);
return response;
},
});

View File

@@ -0,0 +1,93 @@
import { HttpMethod } from '@activepieces/pieces-common';
import { createAction, Property } from '@activepieces/pieces-framework';
import { chatbaseAuth } from '../../index';
import { makeRequest } from '../common';
import { chatbotIdDropdown } from '../common/props';
export const sendPromptToChatbotAction = createAction({
auth: chatbaseAuth,
name: 'message_chatbot',
displayName: 'Send Prompt to Chatbot',
description: 'Sends a prompt to the chatbot to generate a response.',
props: {
chatbotId: chatbotIdDropdown,
message: Property.LongText({
displayName: 'Prompt',
required: true,
}),
temperature: Property.Number({
displayName: 'Temperature',
description: 'Higher values = more random output. Between 0 and 1.',
required: false,
defaultValue: 0,
}),
conversationId: Property.ShortText({
displayName: 'Conversation ID',
description: 'Unique ID for saving this conversation in Chatbase dashboard.',
required: false,
}),
model: Property.StaticDropdown({
displayName: 'Model (Optional)',
required: false,
options: {
options: [
{ label: 'o4-mini', value: 'o4-mini' },
{ label: 'o3', value: 'o3' },
{ label: 'gpt-4', value: 'gpt-4' },
{ label: 'gpt-4o', value: 'gpt-4o' },
{ label: 'gpt-4o-mini', value: 'gpt-4o-mini' },
{ label: 'gpt-4.1-mini', value: 'gpt-4.1-mini' },
{ label: 'gpt-4.1-nano', value: 'gpt-4.1-nano' },
{ label: 'gpt-4-turbo', value: 'gpt-4-turbo' },
{ label: 'o3-mini', value: 'o3-mini' },
{ label: 'gpt-4.1', value: 'gpt-4.1' },
{ label: 'gpt-4.5', value: 'gpt-4.5' },
{ label: 'claude-sonnet-4', value: 'claude-sonnet-4' },
{ label: 'claude-3-7-sonnet', value: 'claude-3-7-sonnet' },
{ label: 'claude-3-5-sonnet', value: 'claude-3-5-sonnet' },
{ label: 'claude-3-opus', value: 'claude-3-opus' },
{ label: 'claude-opus-4', value: 'claude-opus-4' },
{ label: 'claude-3-haiku', value: 'claude-3-haiku' },
{ label: 'gemini-2.0-flash', value: 'gemini-2.0-flash' },
{ label: 'gemini-1.5-flash', value: 'gemini-1.5-flash' },
{ label: 'gemini-1.5-pro', value: 'gemini-1.5-pro' },
{ label: 'gemini-2.0-pro', value: 'gemini-2.0-pro' },
{ label: 'command-r', value: 'command-r' },
{ label: 'command-r-plus', value: 'command-r-plus' },
{ label: 'DeepSeek-V3', value: 'DeepSeek-V3' },
{ label: 'DeepSeek-R1', value: 'DeepSeek-R1' },
{
label: 'Llama-4-Scout-17B-16E-Instruct',
value: 'Llama-4-Scout-17B-16E-Instruct',
},
{
label: 'Llama-4-Maverick-17B-128E-Instruct-FP8',
value: 'Llama-4-Maverick-17B-128E-Instruct-FP8',
},
{ label: 'grok-3', value: 'grok-3' },
{ label: 'grok-3-mini', value: 'grok-3-mini' },
],
},
}),
},
async run(context) {
const { chatbotId, message, temperature, model, conversationId } = context.propsValue;
const apiKey = context.auth.secret_text;
const payload: Record<string, any> = {
chatbotId,
messages: [{ content: message, role: 'user' }],
};
if (temperature !== undefined) payload['temperature'] = temperature;
if (conversationId) payload['conversationId'] = conversationId;
if (model) payload['model'] = model;
const response = await makeRequest(apiKey, HttpMethod.POST, '/chat', payload);
return response;
},
});

View File

@@ -0,0 +1,22 @@
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
export async function makeRequest(
apiKey: string,
method: HttpMethod,
path: string,
body?: unknown,
) {
const url = `https://www.chatbase.co/api/v1${path}`;
const response = await httpClient.sendRequest({
method,
url,
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body,
});
return response.body;
}

View File

@@ -0,0 +1,33 @@
import { HttpMethod } from '@activepieces/pieces-common';
import { DropdownOption, Property } from '@activepieces/pieces-framework';
import { makeRequest } from './index';
import { chatbaseAuth } from '../../index';
export const chatbotIdDropdown = Property.Dropdown({
auth: chatbaseAuth,
displayName: 'Chatbot',
required: true,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Please connect your account first.',
options: [],
};
}
const apiKey = auth.secret_text;
const response = await makeRequest(apiKey, HttpMethod.GET, '/get-chatbots');
const options: DropdownOption<string>[] = response.chatbots.map((chatbot: any) => ({
label: chatbot.chatbotName,
value: chatbot.chatbotId,
}));
return {
disabled: false,
options,
};
},
});