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,57 @@
{
"Create Assistant Run": "Create Assistant Run",
"Create Structure Run": "Create Structure Run",
"Get Assistant Run": "Get Assistant Run",
"Get Structure Run": "Get Structure Run",
"Custom API Call": "Custom API Call",
"Create a run for an assistant with optional additional resources": "Create a run for an assistant with optional additional resources",
"Create a run for a structure and wait for completion": "Create a run for a structure and wait for completion",
"Get details of a specific assistant run": "Get details of a specific assistant run",
"Get details of a specific structure run": "Get details of a specific structure run",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Assistant": "Assistant",
"Input": "Input",
"Knowledge Bases": "Knowledge Bases",
"Rulesets": "Rulesets",
"Structures": "Structures",
"Tools": "Tools",
"Thread": "Thread",
"Create New Thread": "Create New Thread",
"Structure": "Structure",
"Input Arguments": "Input Arguments",
"Assistant Run": "Assistant Run",
"Structure Run": "Structure Run",
"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)",
"Select the assistant": "Select the assistant",
"Input to provide to the assistant": "Input to provide to the assistant",
"Select knowledge bases to use": "Select knowledge bases to use",
"Select rulesets to apply": "Select rulesets to apply",
"Select structures to use": "Select structures to use",
"Select tools to use": "Select tools to use",
"Select the thread": "Select the thread",
"Create a new thread for this run": "Create a new thread for this run",
"Select the structure": "Select the structure",
"Input arguments for the structure run": "Input arguments for the structure run",
"Select the assistant run": "Select the assistant run",
"Select the structure run": "Select the structure run",
"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",
"Assistant Run Completes": "Assistant Run Completes",
"Assistant Run Succeeds": "Assistant Run Succeeds",
"Structure Run Completes": "Structure Run Completes",
"Structure Run Succeeds": "Structure Run Succeeds",
"Trigger when an assistant run is completed (succeeded, failed, or cancelled)": "Trigger when an assistant run is completed (succeeded, failed, or cancelled)",
"Trigger when an assistant run succeeds": "Trigger when an assistant run succeeds"
}

View File

@@ -0,0 +1,46 @@
import { createPiece, PieceAuth } from '@activepieces/pieces-framework';
import { griptapeAuth } from './lib/common/auth';
import { PieceCategory } from '@activepieces/shared';
import { createAssistantRun } from './lib/actions/create-assistant-run';
import { createStructureRun } from './lib/actions/create-structure-run';
import { getAssistantRun } from './lib/actions/get-assistant-run';
import { getStructureRun } from './lib/actions/get-structure-run';
import { createCustomApiCallAction } from '@activepieces/pieces-common';
import { BASE_URL } from './lib/common/client';
import { assistantRunCompletes } from './lib/triggers/assistant-run-completes';
import { assistantRunSucceedes } from './lib/triggers/assistant-run-succeedes';
import { structureRunCompletes } from './lib/triggers/structure-run-completes';
import { structureRunSucceeds } from './lib/triggers/structure-run-succeeds';
export const griptape = createPiece({
displayName: 'Griptape Cloud',
auth: griptapeAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: 'https://cdn.activepieces.com/pieces/griptape.png',
categories: [
PieceCategory.ARTIFICIAL_INTELLIGENCE,
PieceCategory.DEVELOPER_TOOLS,
],
authors: ['sanket-a11y'],
actions: [
createAssistantRun,
createStructureRun,
getAssistantRun,
getStructureRun,
createCustomApiCallAction({
auth: griptapeAuth,
baseUrl: () => BASE_URL,
authMapping: async (auth) => {
return {
Authorization: `Bearer ${auth.secret_text}`,
};
},
}),
],
triggers: [
assistantRunCompletes,
assistantRunSucceedes,
structureRunCompletes,
structureRunSucceeds,
],
});

View File

@@ -0,0 +1,103 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { griptapeAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import {
assistantIdDropdown,
knowledgeBaseIdsDropdown,
rulesetIdsDropdown,
structuresIdsDropdown,
threadIdsDropdown,
toolsIdsDropdown,
} from '../common/props';
export const createAssistantRun = createAction({
auth: griptapeAuth,
name: 'createAssistantRun',
displayName: 'Create Assistant Run',
description:
'Create a run for an assistant with optional additional resources',
props: {
assistant_id: assistantIdDropdown,
input: Property.LongText({
displayName: 'Input',
description: 'Input to provide to the assistant',
required: true,
}),
knowledgeBaseIds: knowledgeBaseIdsDropdown,
rulesets: rulesetIdsDropdown,
structures: structuresIdsDropdown,
tools: toolsIdsDropdown,
thread: threadIdsDropdown,
create_new_thread: Property.Checkbox({
displayName: 'Create New Thread',
description: 'Create a new thread for this run',
required: false,
defaultValue: false,
}),
},
async run(context) {
const {
assistant_id,
input,
knowledgeBaseIds,
rulesets,
structures,
tools,
thread,
create_new_thread,
} = context.propsValue;
const requestBody: Record<string, unknown> = {
input,
};
if (knowledgeBaseIds && knowledgeBaseIds.length > 0) {
requestBody['additional_knowledge_base_ids'] = knowledgeBaseIds;
}
if (rulesets && rulesets.length > 0) {
requestBody['additional_ruleset_ids'] = rulesets;
}
if (structures && structures.length > 0) {
requestBody['additional_structure_ids'] = structures;
}
if (tools && tools.length > 0) {
requestBody['additional_tool_ids'] = tools;
}
requestBody['create_new_thread'] = create_new_thread;
if (thread && thread.length > 0) {
requestBody['thread_id'] = Array.isArray(thread) ? thread[0] : thread;
}
const response = await makeRequest(
context.auth.secret_text,
HttpMethod.POST,
`/assistants/${assistant_id}/runs`,
requestBody
);
const assistantRunId = response.assistant_run_id;
let runStatus = response.status;
let runData = response;
while (runStatus !== 'SUCCEEDED') {
await new Promise((resolve) => setTimeout(resolve, 2000));
runData = await makeRequest(
context.auth.secret_text,
HttpMethod.GET,
`/assistant-runs/${assistantRunId}`
);
runStatus = runData.status;
}
return runData;
},
});

View File

@@ -0,0 +1,53 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { griptapeAuth } from '../common/auth';
import { structureIdDropdown } from '../common/props';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const createStructureRun = createAction({
auth: griptapeAuth,
name: 'createStructureRun',
displayName: 'Create Structure Run',
description: 'Create a run for a structure and wait for completion',
props: {
structure_id: structureIdDropdown,
input_args: Property.Array({
displayName: 'Input Arguments',
description: 'Input arguments for the structure run',
required: true,
}),
},
async run(context) {
const { structure_id, input_args } = context.propsValue;
const requestBody: Record<string, unknown> = {
args: input_args,
};
const response = await makeRequest(
context.auth.secret_text,
HttpMethod.POST,
`/structures/${structure_id}/runs`,
requestBody
);
const structureRunId = response.structure_run_id;
let runStatus = response.status;
let runData = response;
while (runStatus !== 'SUCCEEDED') {
await new Promise((resolve) => setTimeout(resolve, 2000));
runData = await makeRequest(
context.auth.secret_text,
HttpMethod.GET,
`/structure-runs/${structureRunId}`
);
runStatus = runData.status;
}
return runData;
},
});

View File

@@ -0,0 +1,27 @@
import { createAction } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { griptapeAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { assistantIdDropdown, assistantRunsDropdown } from '../common/props';
export const getAssistantRun = createAction({
auth: griptapeAuth,
name: 'getAssistantRun',
displayName: 'Get Assistant Run',
description: 'Get details of a specific assistant run',
props: {
assistant_id: assistantIdDropdown,
assistant_run_id: assistantRunsDropdown,
},
async run(context) {
const { assistant_run_id } = context.propsValue;
const response = await makeRequest(
context.auth.secret_text,
HttpMethod.GET,
`/assistant-runs/${assistant_run_id}`
);
return response;
},
});

View File

@@ -0,0 +1,27 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { griptapeAuth } from '../common/auth';
import { structureIdDropdown, structureRunsDropdown } from '../common/props';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const getStructureRun = createAction({
auth: griptapeAuth,
name: 'getStructureRun',
displayName: 'Get Structure Run',
description: 'Get details of a specific structure run',
props: {
structure_id: structureIdDropdown,
structure_run_id: structureRunsDropdown,
},
async run(context) {
const { structure_run_id } = context.propsValue;
const response = await makeRequest(
context.auth.secret_text,
HttpMethod.GET,
`/structure-runs/${structure_run_id}`
);
return response;
},
});

View File

@@ -0,0 +1,22 @@
import { HttpMethod } from '@activepieces/pieces-common';
import { PieceAuth } from '@activepieces/pieces-framework';
import { makeRequest } from './client';
export const griptapeAuth = PieceAuth.SecretText({
displayName: 'API Key',
description: '',
required: true,
validate: async ({ auth }) => {
try {
await makeRequest(auth, HttpMethod.GET, `/organizations`);
return {
valid: true,
};
} catch (error) {
return {
valid: false,
error: 'Invalid API key. Please check your Griptape Cloud API key.',
};
}
},
});

View File

@@ -0,0 +1,25 @@
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
export const BASE_URL = `https://cloud.griptape.ai/api`;
export async function makeRequest(
api_key: string,
method: HttpMethod,
path: string,
body?: unknown
) {
try {
const response = await httpClient.sendRequest({
method,
url: `${BASE_URL}${path}`,
headers: {
Authorization: `Bearer ${api_key}`,
'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,357 @@
import { Property } from '@activepieces/pieces-framework';
import { makeRequest } from './client';
import { HttpMethod } from '@activepieces/pieces-common';
import { griptapeAuth } from './auth';
export const assistantIdDropdown = Property.Dropdown({
displayName: 'Assistant',
description: 'Select the assistant',
required: true,
refreshers: [],
auth: griptapeAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first',
};
}
try {
const response = await makeRequest(
auth.secret_text,
HttpMethod.GET,
'/assistants'
);
return {
disabled: false,
options: response.assistants.map((assistant: any) => ({
label: assistant.name,
value: assistant.assistant_id,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Could not fetch assistants',
};
}
},
});
export const knowledgeBaseIdsDropdown = Property.MultiSelectDropdown({
displayName: 'Knowledge Bases',
description: 'Select knowledge bases to use',
required: false,
refreshers: [],
auth: griptapeAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first',
};
}
try {
const response = await makeRequest(
auth.secret_text,
HttpMethod.GET,
'/knowledge-bases'
);
return {
disabled: false,
options: response.knowledge_bases.map((kb: any) => ({
label: kb.name,
value: kb.knowledge_base_id,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Could not fetch knowledge bases',
};
}
},
});
export const rulesetIdsDropdown = Property.MultiSelectDropdown({
displayName: 'Rulesets',
description: 'Select rulesets to apply',
required: false,
refreshers: [],
auth: griptapeAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first',
};
}
try {
const response = await makeRequest(
auth.secret_text,
HttpMethod.GET,
'/rulesets'
);
return {
disabled: false,
options: response.rulesets.map((rs: any) => ({
label: rs.name,
value: rs.ruleset_id,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Could not fetch rulesets',
};
}
},
});
export const structuresIdsDropdown = Property.MultiSelectDropdown({
displayName: 'Structures',
description: 'Select structures to use',
required: false,
refreshers: [],
auth: griptapeAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first',
};
}
try {
const response = await makeRequest(
auth.secret_text,
HttpMethod.GET,
'/structures'
);
return {
disabled: false,
options: response.structures.map((structure: any) => ({
label: structure.name,
value: structure.structure_id,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Could not fetch structures',
};
}
},
});
export const toolsIdsDropdown = Property.MultiSelectDropdown({
displayName: 'Tools',
description: 'Select tools to use',
required: false,
refreshers: [],
auth: griptapeAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first',
};
}
try {
const response = await makeRequest(
auth.secret_text,
HttpMethod.GET,
'/tools'
);
return {
disabled: false,
options: response.tools.map((tool: any) => ({
label: tool.name,
value: tool.tool_id,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Could not fetch tools',
};
}
},
});
export const threadIdsDropdown = Property.MultiSelectDropdown({
displayName: 'Thread',
description: 'Select the thread',
required: false,
refreshers: [],
auth: griptapeAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first',
};
}
try {
const response = await makeRequest(
auth.secret_text,
HttpMethod.GET,
`/threads`
);
return {
disabled: false,
options: response.threads.map((thread: any) => ({
label: thread.name,
value: thread.thread_id,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Could not fetch threads',
};
}
},
});
export const structureIdDropdown = Property.Dropdown({
displayName: 'Structure',
description: 'Select the structure',
required: true,
refreshers: [],
auth: griptapeAuth,
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first',
};
}
try {
const response = await makeRequest(
auth.secret_text,
HttpMethod.GET,
`/structures`
);
return {
disabled: false,
options: response.structures.map((structure: any) => ({
label: structure.name,
value: structure.structure_id,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Could not fetch structures',
};
}
},
});
export const assistantRunsDropdown = Property.Dropdown({
displayName: 'Assistant Run',
description: 'Select the assistant run',
required: true,
refreshers: ['assistant_id'],
auth: griptapeAuth,
options: async ({ auth, assistant_id }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first',
};
}
if (!assistant_id) {
return {
disabled: true,
options: [],
placeholder: 'Please select an assistant first',
};
}
try {
const response = await makeRequest(
auth.secret_text,
HttpMethod.GET,
`/assistants/${assistant_id}/runs`
);
return {
disabled: false,
options: response.assistant_runs.map((run: any) => ({
label: `${run.assistant_run_id} - ${run.status}`,
value: run.assistant_run_id,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Could not fetch assistant runs',
};
}
},
});
export const structureRunsDropdown = Property.Dropdown({
displayName: 'Structure Run',
description: 'Select the structure run',
required: true,
refreshers: ['structure_id'],
auth: griptapeAuth,
options: async ({ auth, structure_id }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please connect your account first',
};
}
if (!structure_id) {
return {
disabled: true,
options: [],
placeholder: 'Please select a structure first',
};
}
try {
const response = await makeRequest(
auth.secret_text,
HttpMethod.GET,
`/structures/${structure_id}/runs`
);
return {
disabled: false,
options: response.runs.map((run: any) => ({
label: `${run.structure_run_id} - ${run.status}`,
value: run.structure_run_id,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: 'Could not fetch structure runs',
};
}
},
});

View File

@@ -0,0 +1,83 @@
import {
createTrigger,
TriggerStrategy,
StaticPropsValue,
AppConnectionValueForAuthProperty,
} from '@activepieces/pieces-framework';
import {
DedupeStrategy,
Polling,
pollingHelper,
HttpMethod,
} from '@activepieces/pieces-common';
import dayjs from 'dayjs';
import { griptapeAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { assistantIdDropdown } from '../common/props';
const props = {
assistant_id: assistantIdDropdown,
};
const polling: Polling<AppConnectionValueForAuthProperty<typeof griptapeAuth>, StaticPropsValue<typeof props>> = {
strategy: DedupeStrategy.TIMEBASED,
items: async ({ propsValue, auth, lastFetchEpochMS }) => {
const { assistant_id } = propsValue;
try {
const response = await makeRequest(
auth.secret_text,
HttpMethod.GET,
`/assistants/${assistant_id}/runs?status=SUCCEEDED,FAILED,ERROR,CANCELLED&page_size=100`
);
const items = response.assistant_runs || [];
const completedRuns = items.filter(
(run: any) =>
['SUCCEEDED', 'FAILED', 'ERROR', 'CANCELLED'].includes(run.status) &&
dayjs(run.completed_at || run.updated_at).valueOf() > lastFetchEpochMS
);
return completedRuns.map((run: any) => ({
epochMilliSeconds: dayjs(run.completed_at || run.updated_at).valueOf(),
data: run,
}));
} catch (error) {
console.error('Error fetching assistant runs:', error);
return [];
}
},
};
export const assistantRunCompletes = createTrigger({
auth: griptapeAuth,
name: 'assistantRunCompletes',
displayName: 'Assistant Run Completes',
description:
'Trigger when an assistant run is completed (succeeded, failed, or cancelled)',
props,
sampleData: {
assistant_run_id: 'sample-run-id',
assistant_id: 'sample-assistant-id',
status: 'SUCCEEDED',
output: 'Sample output from assistant run',
created_at: new Date().toISOString(),
completed_at: new Date().toISOString(),
},
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);
},
});

View File

@@ -0,0 +1,83 @@
import {
createTrigger,
TriggerStrategy,
PiecePropValueSchema,
StaticPropsValue,
AppConnectionValueForAuthProperty,
} from '@activepieces/pieces-framework';
import {
DedupeStrategy,
Polling,
pollingHelper,
HttpMethod,
} from '@activepieces/pieces-common';
import dayjs from 'dayjs';
import { griptapeAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { assistantIdDropdown } from '../common/props';
const props = {
assistant_id: assistantIdDropdown,
};
const polling: Polling<AppConnectionValueForAuthProperty<typeof griptapeAuth>, StaticPropsValue<typeof props>> = {
strategy: DedupeStrategy.TIMEBASED,
items: async ({ propsValue, auth, lastFetchEpochMS }) => {
const { assistant_id } = propsValue;
try {
const response = await makeRequest(
auth.secret_text,
HttpMethod.GET,
`/assistants/${assistant_id}/runs?status=SUCCEEDED&page_size=100`
);
const items = response.assistant_runs || [];
const succeededRuns = items.filter(
(run: any) =>
run.status === 'SUCCEEDED' &&
dayjs(run.completed_at || run.updated_at).valueOf() > lastFetchEpochMS
);
return succeededRuns.map((run: any) => ({
epochMilliSeconds: dayjs(run.completed_at || run.updated_at).valueOf(),
data: run,
}));
} catch (error) {
console.error('Error fetching assistant runs:', error);
return [];
}
},
};
export const assistantRunSucceedes = createTrigger({
auth: griptapeAuth,
name: 'assistantRunSucceedes',
displayName: 'Assistant Run Succeeds',
description: 'Trigger when an assistant run succeeds',
props,
sampleData: {
assistant_run_id: 'sample-run-id',
assistant_id: 'sample-assistant-id',
status: 'SUCCEEDED',
output: 'Sample output from assistant run',
created_at: new Date().toISOString(),
completed_at: new Date().toISOString(),
},
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);
},
});

View File

@@ -0,0 +1,77 @@
import {
createTrigger,
TriggerStrategy,
PiecePropValueSchema,
StaticPropsValue,
AppConnectionValueForAuthProperty,
} from '@activepieces/pieces-framework';
import {
DedupeStrategy,
HttpMethod,
Polling,
pollingHelper,
} from '@activepieces/pieces-common';
import dayjs from 'dayjs';
import { structureIdDropdown } from '../common/props';
import { griptapeAuth } from '../common/auth';
import { makeRequest } from '../common/client';
const props = {
structure_id: structureIdDropdown,
};
const polling: Polling<AppConnectionValueForAuthProperty<typeof griptapeAuth>, StaticPropsValue<typeof props>> = {
strategy: DedupeStrategy.TIMEBASED,
items: async ({ propsValue, auth, lastFetchEpochMS }) => {
const { structure_id } = propsValue;
try {
const response = await makeRequest(
auth.secret_text,
HttpMethod.GET,
`/structures/${structure_id}/runs?status=SUCCEEDED,FAILED,ERROR,CANCELLED&page_size=100`
);
const items = response.structure_runs || [];
const completedRuns = items.filter(
(run: any) =>
['SUCCEEDED', 'FAILED', 'ERROR', 'CANCELLED'].includes(run.status) &&
dayjs(run.completed_at || run.updated_at).valueOf() > lastFetchEpochMS
);
return completedRuns.map((run: any) => ({
epochMilliSeconds: dayjs(run.completed_at || run.updated_at).valueOf(),
data: run,
}));
} catch (error) {
console.error('Error fetching assistant runs:', error);
return [];
}
},
};
export const structureRunCompletes = createTrigger({
auth: griptapeAuth,
name: 'structureRunCompletes',
displayName: 'Structure Run Completes',
description: '',
props,
sampleData: {},
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);
},
});

View File

@@ -0,0 +1,78 @@
import {
createTrigger,
TriggerStrategy,
PiecePropValueSchema,
StaticPropsValue,
AppConnectionValueForAuthProperty,
} from '@activepieces/pieces-framework';
import {
DedupeStrategy,
HttpMethod,
Polling,
pollingHelper,
} from '@activepieces/pieces-common';
import dayjs from 'dayjs';
import { structureIdDropdown } from '../common/props';
import { griptapeAuth } from '../common/auth';
import { makeRequest } from '../common/client';
const props = {
structure_id: structureIdDropdown,
};
const polling: Polling<AppConnectionValueForAuthProperty<typeof griptapeAuth>, StaticPropsValue<typeof props>> = {
strategy: DedupeStrategy.TIMEBASED,
items: async ({ auth, propsValue, lastFetchEpochMS }) => {
const { structure_id } = propsValue;
try {
const response = await makeRequest(
auth.secret_text,
HttpMethod.GET,
`/structures/${structure_id}/runs?status=SUCCEEDED&page_size=100`
);
const items = response.structure_runs || [];
const succeededRuns = items.filter(
(run: any) =>
run.status === 'SUCCEEDED' &&
dayjs(run.completed_at || run.updated_at).valueOf() > lastFetchEpochMS
);
return succeededRuns.map((run: any) => ({
epochMilliSeconds: dayjs(run.completed_at || run.updated_at).valueOf(),
data: run,
}));
} catch (error) {
console.error('Error fetching assistant runs:', error);
return [];
}
},
};
export const structureRunSucceeds = createTrigger({
auth: griptapeAuth,
name: 'structureRunSucceeds',
displayName: 'Structure Run Succeeds',
description: '',
props,
sampleData: {},
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);
},
});