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,31 @@
{
"GuideLite is a platform that helps organizations build and utilize AI assistants": "GuideLite is a platform that helps organizations build and utilize AI assistants",
"\nTo get your API key:\n1. Sign in to your GuideLite dashboard\n2. Click on your account in the left panel\n3. Select \"Profile\" from the dropdown menu\n4. Navigate to the API Keys tab and click \"Generate API Key\"\n5. Copy your unique API key (you won't be able to view it again unless you delete and create a new one)\n\nFor more information, visit: https://docs.guidelite.ai/reference/quickstart\n": "\nTo get your API key:\n1. Sign in to your GuideLite dashboard\n2. Click on your account in the left panel\n3. Select \"Profile\" from the dropdown menu\n4. Navigate to the API Keys tab and click \"Generate API Key\"\n5. Copy your unique API key (you won't be able to view it again unless you delete and create a new one)\n\nFor more information, visit: https://docs.guidelite.ai/reference/quickstart\n",
"Send a Prompt": "Send a Prompt",
"Custom API Call": "Custom API Call",
"Send a message to a Guidelite Assistant": "Send a message to a Guidelite Assistant",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Assistant": "Assistant",
"Message": "Message",
"Conversation ID": "Conversation ID",
"Method": "Method",
"Headers": "Headers",
"Query Parameters": "Query Parameters",
"Body": "Body",
"Response is Binary ?": "Response is Binary ?",
"No Error on Failure": "No Error on Failure",
"Timeout (in seconds)": "Timeout (in seconds)",
"Please select assistant": "Please select assistant",
"The input message to be processed by the assistant": "The input message to be processed by the assistant",
"The Conversation ID of the previous conversation. If empty, a new conversation will be created": "The Conversation ID of the previous conversation. If empty, a new conversation will be created",
"Authorization headers are injected automatically from your connection.": "Authorization headers are injected automatically from your connection.",
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"new lead submission": "new lead submission",
"Trigger when a new lead is captured through the assistant conversation": "Trigger when a new lead is captured through the assistant conversation"
}

View File

@@ -0,0 +1,31 @@
import { createPiece, PieceAuth } from '@activepieces/pieces-framework';
import { sendAPrompt } from './lib/actions/send-a-prompt';
import { newLeadSubmission } from './lib/triggers/new-lead-submission';
import { createCustomApiCallAction } from '@activepieces/pieces-common';
import { guideliteAuth } from './lib/common/auth';
import { BASE_URL } from './lib/common/client';
import { PieceCategory } from '@activepieces/shared';
export const guidelite = createPiece({
displayName: 'GuideLite',
auth: guideliteAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: 'https://cdn.activepieces.com/pieces/guidelite.png',
authors: ['sanket-a11y'],
description:
'GuideLite is a platform that helps organizations build and utilize AI assistants',
categories: [PieceCategory.ARTIFICIAL_INTELLIGENCE],
actions: [
sendAPrompt,
createCustomApiCallAction({
auth: guideliteAuth,
baseUrl: () => BASE_URL,
authMapping: async (auth) => {
return {
authorization: `Bearer ${auth.secret_text}`,
};
},
}),
],
triggers: [newLeadSubmission],
});

View File

@@ -0,0 +1,46 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { guideliteAuth } from '../common/auth';
import { HttpMethod } from '@activepieces/pieces-common';
import { makeRequest } from '../common/client';
import { assistantIdDropdown } from '../common/props';
export const sendAPrompt = createAction({
auth: guideliteAuth,
name: 'sendAPrompt',
displayName: 'Send a Prompt',
description: 'Send a message to a Guidelite Assistant',
props: {
assistantId: assistantIdDropdown,
message: Property.LongText({
displayName: 'Message',
description: 'The input message to be processed by the assistant',
required: true,
}),
conversationId: Property.ShortText({
displayName: 'Conversation ID',
description:
'The Conversation ID of the previous conversation. If empty, a new conversation will be created',
required: false,
}),
},
async run(context) {
const { assistantId, message, conversationId } = context.propsValue;
const body: any = {
assistantId,
message,
};
if (conversationId) {
body.conversationId = conversationId;
}
const response = await makeRequest(
context.auth,
HttpMethod.POST,
`/interface-assistant/chat`,
body
);
return response.body;
},
});

View File

@@ -0,0 +1,38 @@
import { HttpMethod } from '@activepieces/pieces-common';
import { PieceAuth } from '@activepieces/pieces-framework';
import { makeRequest } from './client';
import { AppConnectionType } from '@activepieces/shared';
export const guideliteAuth = PieceAuth.SecretText({
displayName: 'Guidelite API Key',
description: `
To get your API key:
1. Sign in to your GuideLite dashboard
2. Click on your account in the left panel
3. Select "Profile" from the dropdown menu
4. Navigate to the API Keys tab and click "Generate API Key"
5. Copy your unique API key (you won't be able to view it again unless you delete and create a new one)
For more information, visit: https://docs.guidelite.ai/reference/quickstart
`,
required: true,
validate: async ({ auth }) => {
if (auth) {
try {
await makeRequest({secret_text: auth, type: AppConnectionType.SECRET_TEXT}, HttpMethod.GET, '/assistant/list');
return {
valid: true,
};
} catch (error) {
return {
valid: false,
error: 'Invalid API Key',
};
}
}
return {
valid: false,
error: 'Invalid API Key',
};
},
});

View File

@@ -0,0 +1,27 @@
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
import { AppConnectionValueForAuthProperty } from '@activepieces/pieces-framework';
import { guideliteAuth } from '../common/auth';
export const BASE_URL = `https://api.guidelite.ai/external-api/v1`;
export async function makeRequest(
{secret_text}: AppConnectionValueForAuthProperty<typeof guideliteAuth>,
method: HttpMethod,
path: string,
body?: unknown
) {
try {
const response = await httpClient.sendRequest({
method,
url: `${BASE_URL}${path}`,
headers: {
authorization: `Bearer ${secret_text}`,
'Content-Type': 'application/json',
},
body,
});
return response.body;
} catch (error: any) {
throw new Error(`Unexpected error: ${error.message || String(error)}`);
}
}

View File

@@ -0,0 +1,44 @@
import { Property } from '@activepieces/pieces-framework';
import { makeRequest } from './client';
import { HttpMethod } from '@activepieces/pieces-common';
import { guideliteAuth } from './auth';
export const assistantIdDropdown = Property.Dropdown({
displayName: 'Assistant',
description: 'Please select assistant',
refreshers: [],
auth: guideliteAuth,
required: true,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Please connect your Guidelite account first.',
options: [],
};
}
try {
const response = await makeRequest(
auth,
HttpMethod.GET,
'/assistant/list'
);
return {
disabled: false,
options: response.map((model: any) => {
return {
label: model.assistantName,
value: model.assistantId,
};
}),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: "Couldn't load assistants, API key is invalid",
};
}
},
});

View File

@@ -0,0 +1,84 @@
import {
createTrigger,
TriggerStrategy,
StaticPropsValue,
AppConnectionValueForAuthProperty,
} from '@activepieces/pieces-framework';
import {
DedupeStrategy,
Polling,
pollingHelper,
HttpMethod,
} from '@activepieces/pieces-common';
import dayjs from 'dayjs';
import { guideliteAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { assistantIdDropdown } from '../common/props';
const props = {
assistantId: assistantIdDropdown,
};
const polling: Polling<AppConnectionValueForAuthProperty<typeof guideliteAuth>, StaticPropsValue<typeof props>> = {
strategy: DedupeStrategy.TIMEBASED,
items: async ({ propsValue, auth, lastFetchEpochMS }) => {
const { assistantId } = propsValue;
const fromDate = dayjs(lastFetchEpochMS).format('YYYY-MM-DD HH:mm:ss.SSS');
const toDate = dayjs(Date.now()).format('YYYY-MM-DD HH:mm:ss.SSS');
const leads = await makeRequest(
auth,
HttpMethod.POST,
'/manage-assistant/lead',
{
assistantId,
from: fromDate,
to: toDate,
country: 'all',
}
);
return leads.map((lead: { createdDate: string }) => ({
epochMilliSeconds: dayjs(lead.createdDate).valueOf(),
data: lead,
}));
},
};
export const newLeadSubmission = createTrigger({
auth: guideliteAuth,
name: 'newLeadSubmission',
displayName: 'new lead submission',
description:
'Trigger when a new lead is captured through the assistant conversation',
props,
sampleData: {
createdDate: '2024-04-25T10:13:12.504Z',
conversationId: '<YOUR-CONVERSATION-ID>',
assistantId: '<YOUR-ASSISTANT-ID>',
country: 'USA',
emailId: 'user@gmail.com',
phoneNumber: 1234567890,
ipAddress: '192.168.1.1',
city: 'New York',
countryCode: 'US',
},
type: TriggerStrategy.POLLING,
async test(context) {
return await pollingHelper.test(polling, context);
},
async onEnable(context) {
const { store, auth, propsValue } = context;
await pollingHelper.onEnable(polling, { store, auth, propsValue });
},
async onDisable(context) {
const { store, auth, propsValue } = context;
await pollingHelper.onDisable(polling, { store, auth, propsValue });
},
async run(context) {
return await pollingHelper.poll(polling, context);
},
});