From 2725f3506bbb6d9f1e595e9e8f1ee4bc68487d62 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Mon, 11 Nov 2024 11:51:24 -0300 Subject: [PATCH 1/4] skyvern init --- .../create-run-task/create-run-task.mjs | 33 ++++++ .../actions/get-workflow/get-workflow.mjs | 26 +++++ .../actions/run-workflow/run-workflow.mjs | 48 ++++++++ components/skyvern/package.json | 2 +- components/skyvern/skyvern.app.mjs | 108 +++++++++++++++++- .../new-or-updated-workflow.mjs | 87 ++++++++++++++ 6 files changed, 298 insertions(+), 6 deletions(-) create mode 100644 components/skyvern/actions/create-run-task/create-run-task.mjs create mode 100644 components/skyvern/actions/get-workflow/get-workflow.mjs create mode 100644 components/skyvern/actions/run-workflow/run-workflow.mjs create mode 100644 components/skyvern/sources/new-or-updated-workflow/new-or-updated-workflow.mjs diff --git a/components/skyvern/actions/create-run-task/create-run-task.mjs b/components/skyvern/actions/create-run-task/create-run-task.mjs new file mode 100644 index 0000000000000..7beecdcf41252 --- /dev/null +++ b/components/skyvern/actions/create-run-task/create-run-task.mjs @@ -0,0 +1,33 @@ +import skyvern from "../../skyvern.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "skyvern-create-run-task", + name: "Create and Run Task", + description: "Create a new task and run it instantly in Skyvern. Useful for one-off automations. [See the documentation](https://docs.skyvern.com/)", + version: "0.0.{{ts}}", + type: "action", + props: { + skyvern, + taskName: { + propDefinition: [ + skyvern, + "taskName", + ], + }, + taskGoal: { + propDefinition: [ + skyvern, + "taskGoal", + ], + }, + }, + async run({ $ }) { + const response = await this.skyvern.createAndRunTask({ + taskName: this.taskName, + taskGoal: this.taskGoal, + }); + $.export("$summary", `Created and ran task with ID ${response.task_id}`); + return response; + }, +}; diff --git a/components/skyvern/actions/get-workflow/get-workflow.mjs b/components/skyvern/actions/get-workflow/get-workflow.mjs new file mode 100644 index 0000000000000..9569836cd9e63 --- /dev/null +++ b/components/skyvern/actions/get-workflow/get-workflow.mjs @@ -0,0 +1,26 @@ +import skyvern from "../../skyvern.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "skyvern-get-workflow-run-details", + name: "Get Workflow Run Details", + description: "Retrieve details of a specific Skyvern workflow run. Useful for checking the status and result of a run. [See the documentation](https://docs.skyvern.com/workflows/getting-workflows)", + version: "0.0.1", + type: "action", + props: { + skyvern, + workflowId: { + propDefinition: [ + skyvern, + "workflowId", + ], + }, + }, + async run({ $ }) { + const response = await this.skyvern.getWorkflowRunDetails({ + workflowId: this.workflowId, + }); + $.export("$summary", `Successfully retrieved details for workflow run with ID: ${this.workflowId}`); + return response; + }, +}; diff --git a/components/skyvern/actions/run-workflow/run-workflow.mjs b/components/skyvern/actions/run-workflow/run-workflow.mjs new file mode 100644 index 0000000000000..d7d2d262284aa --- /dev/null +++ b/components/skyvern/actions/run-workflow/run-workflow.mjs @@ -0,0 +1,48 @@ +import skyvern from "../../skyvern.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "skyvern-run-workflow", + name: "Run Workflow", + description: "Trigger a predefined workflow in Skyvern, allowing the execution of complex routines from Pipedream. [See the documentation](https://docs.skyvern.com/workflows/running-workflows)", + version: "0.0.{{ts}}", + type: "action", + props: { + skyvern, + workflowId: { + propDefinition: [ + skyvern, + "workflowId", + ], + }, + data: { + type: "object", + label: "Data", + description: "The data field is used to pass in required and optional parameters that a workflow accepts", + optional: true, + }, + proxyLocation: { + type: "string", + label: "Proxy Location", + description: "Proxy location for the web browser. Please pass 'RESIDENTIAL'.", + optional: true, + }, + webhookCallbackUrl: { + type: "string", + label: "Webhook Callback URL", + description: "URL where system will send callback once it finishes executing the workflow run.", + optional: true, + }, + }, + async run({ $ }) { + const response = await this.skyvern.triggerWorkflow({ + workflowId: this.workflowId, + data: this.data, + proxyLocation: this.proxyLocation, + webhookCallbackUrl: this.webhookCallbackUrl, + }); + + $.export("$summary", `Successfully triggered workflow with ID ${response.workflow_id}`); + return response; + }, +}; diff --git a/components/skyvern/package.json b/components/skyvern/package.json index 116badecfbf6f..07a2b0d0d3435 100644 --- a/components/skyvern/package.json +++ b/components/skyvern/package.json @@ -12,4 +12,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/components/skyvern/skyvern.app.mjs b/components/skyvern/skyvern.app.mjs index 467d1dbc56a6e..05064e651fd9a 100644 --- a/components/skyvern/skyvern.app.mjs +++ b/components/skyvern/skyvern.app.mjs @@ -1,11 +1,109 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "skyvern", - propDefinitions: {}, + propDefinitions: { + workspace: { + type: "string", + label: "Workspace", + description: "The workspace scope for workflows", + async options() { + const workflows = await this.listWorkflows(); + return workflows.map((workflow) => ({ + label: workflow.title, + value: workflow.workspace_id, + })); + }, + }, + workflowId: { + type: "string", + label: "Workflow ID", + description: "The unique identifier for a workflow", + }, + taskName: { + type: "string", + label: "Task Name", + description: "The name of the task to be created and run", + }, + taskGoal: { + type: "string", + label: "Task Goal", + description: "The goal of the task to be created and run", + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://api.skyvern.com/api/v1"; + }, + async _makeRequest(opts = {}) { + const { + $ = this, method = "GET", path = "/", headers, ...otherOpts + } = opts; + return axios($, { + ...otherOpts, + method, + url: this._baseUrl() + path, + headers: { + ...headers, + "x-api-key": this.$auth.api_key, + }, + }); + }, + async listWorkflows(opts = {}) { + const params = { + only_workflows: true, + ...opts, + }; + return this._makeRequest({ + path: "/workflows", + params, + }); + }, + async emitNewWorkflowEvent({ + workspace, ...opts + }) { + const path = `/workflows/${workspace}/events`; + return this._makeRequest({ + path, + ...opts, + }); + }, + async getWorkflowRunDetails({ + workflowId, ...opts + }) { + const path = `/workflows/runs/${workflowId}`; + return this._makeRequest({ + path, + ...opts, + }); + }, + async triggerWorkflow({ + workflowId, data, proxyLocation, webhookCallbackUrl, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/workflows/${workflowId}/run`, + data: { + data, + proxy_location: proxyLocation, + webhook_callback_url: webhookCallbackUrl, + }, + ...opts, + }); + }, + async createAndRunTask({ + taskName, taskGoal, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: "/tasks", + data: { + name: taskName, + navigation_goal: taskGoal, + ...opts, + }, + }); }, }, -}; \ No newline at end of file +}; diff --git a/components/skyvern/sources/new-or-updated-workflow/new-or-updated-workflow.mjs b/components/skyvern/sources/new-or-updated-workflow/new-or-updated-workflow.mjs new file mode 100644 index 0000000000000..2aa51f1f15310 --- /dev/null +++ b/components/skyvern/sources/new-or-updated-workflow/new-or-updated-workflow.mjs @@ -0,0 +1,87 @@ +import skyvern from "../../skyvern.app.mjs"; +import { + axios, DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, +} from "@pipedream/platform"; + +export default { + key: "skyvern-new-or-updated-workflow", + name: "New or Updated Workflow", + description: "Emits a new event when a workflow is created or updated in Skyvern. [See the documentation](https://docs.skyvern.com/workflows/getting-workflows)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + skyvern, + db: "$.service.db", + workspace: { + propDefinition: [ + skyvern, + "workspace", + ], + }, + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + methods: { + _getLastWorkflowVersion() { + return this.db.get("lastWorkflowVersion") || {}; + }, + _setLastWorkflowVersion(workflows) { + const lastWorkflowVersion = workflows.reduce((acc, workflow) => { + acc[workflow.workflow_id] = workflow.version; + return acc; + }, {}); + this.db.set("lastWorkflowVersion", lastWorkflowVersion); + }, + }, + hooks: { + async deploy() { + const workflows = await this.skyvern.listWorkflows({ + workspace: this.workspace, + }); + const last50Workflows = workflows.slice(-50); + + for (const workflow of last50Workflows) { + this.$emit(workflow, { + id: workflow.workflow_id, + summary: `New or Updated Workflow: ${workflow.title}`, + ts: Date.now(), + }); + } + + this._setLastWorkflowVersion(last50Workflows); + }, + async activate() { + // Add any logic for when the component is activated + }, + async deactivate() { + // Add any logic for when the component is deactivated + }, + }, + async run() { + const lastWorkflowVersion = this._getLastWorkflowVersion(); + const workflows = await this.skyvern.listWorkflows({ + workspace: this.workspace, + }); + + for (const workflow of workflows) { + const previousVersion = lastWorkflowVersion[workflow.workflow_id]; + + if (!previousVersion || workflow.version > previousVersion) { + this.$emit(workflow, { + id: workflow.workflow_id, + summary: `New or Updated Workflow: ${workflow.title}`, + ts: Date.now(), + }); + + lastWorkflowVersion[workflow.workflow_id] = workflow.version; + } + } + + this._setLastWorkflowVersion(workflows); + }, +}; From 036fe9f2ae204705137efd3cf2663b617bc8f714 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Tue, 12 Nov 2024 11:09:03 -0300 Subject: [PATCH 2/4] [Components] skyvern #14566 Sources - New Or Updated Workflow Actions - Get Workflow - Run Workflow - Create Run Task --- .../create-run-task/create-run-task.mjs | 69 ++++++++-- .../actions/get-workflow/get-workflow.mjs | 6 +- .../actions/run-workflow/run-workflow.mjs | 28 ++-- components/skyvern/common/utils.mjs | 24 ++++ components/skyvern/package.json | 5 +- components/skyvern/skyvern.app.mjs | 123 +++++++++--------- .../new-or-updated-workflow.mjs | 94 ++++++------- .../new-or-updated-workflow/test-event.mjs | 27 ++++ 8 files changed, 229 insertions(+), 147 deletions(-) create mode 100644 components/skyvern/common/utils.mjs create mode 100644 components/skyvern/sources/new-or-updated-workflow/test-event.mjs diff --git a/components/skyvern/actions/create-run-task/create-run-task.mjs b/components/skyvern/actions/create-run-task/create-run-task.mjs index 7beecdcf41252..c8618f6846393 100644 --- a/components/skyvern/actions/create-run-task/create-run-task.mjs +++ b/components/skyvern/actions/create-run-task/create-run-task.mjs @@ -1,31 +1,78 @@ +import { parseObject } from "../../common/utils.mjs"; import skyvern from "../../skyvern.app.mjs"; -import { axios } from "@pipedream/platform"; export default { key: "skyvern-create-run-task", name: "Create and Run Task", description: "Create a new task and run it instantly in Skyvern. Useful for one-off automations. [See the documentation](https://docs.skyvern.com/)", - version: "0.0.{{ts}}", + version: "0.0.1", type: "action", props: { skyvern, - taskName: { - propDefinition: [ - skyvern, - "taskName", - ], + url: { + type: "string", + label: "URL", + description: "It must be a http or https URL.", + }, + navigationGoal: { + type: "string", + label: "Navigation Goal", + description: "The prompt that tells the agent what the user-facing goal is. This is the guiding light for the LLM as it navigates a particular website / sitemap to achieve this specified goal.", + optional: true, + }, + dataExtractionGoal: { + type: "string", + label: "Data Extraction Goal", + description: "The prompt that instructs the agent to extract information once the agent has achieved its **User Goal**.", + optional: true, }, - taskGoal: { + navigationPayload: { + type: "object", + label: "Navigation Payload", + description: "JSON-formatted payload with any \"facts\" or information that would help the agent perform its job. In the case of navigating an insurance quote, this payload would include any user information to help fill out the insurance flow such as date of birth, or age they got their license, and so on. This can include nested information, and the formatting isn't validated.", + optional: true, + }, + webhookCallbackUrl: { propDefinition: [ skyvern, - "taskGoal", + "webhookCallbackUrl", ], + description: "The callback URL once our system is finished processing this async task.", + optional: true, + }, + extractedInformationSchema: { + type: "object", + label: "Extracted Information Schema", + description: "Used to enforce a JSON schema spec to be enforced in the data_extraction_goal. Similar to [https://json-schema.org/](https://json-schema.org/) definition.", + optional: true, + }, + totpVerificationUrl: { + type: "string", + label: "TOTP Verification URL", + description: "The URL of your TOTP endpoint. If this field is provided, Skyvern will call the URL to fetch the TOTP/2FA/MFA code when needed.", + optional: true, + }, + totpIdentifier: { + type: "string", + label: "TOTP Identifier", + description: "The email address or the phone number which receives the TOTP/2FA/MFA code. If this field is provided, Skyvern will fetch the code that is pushed to [Skyvern's TOTP API](https://docs.skyvern.com/running-tasks/advanced-features#push-code-to-skyvern).", + optional: true, }, }, async run({ $ }) { const response = await this.skyvern.createAndRunTask({ - taskName: this.taskName, - taskGoal: this.taskGoal, + $, + data: { + url: this.url, + navigation_goal: this.navigationGoal, + data_extraction_goal: this.dataExtractionGoal, + navigation_payload: parseObject(this.navigationPayload), + webhook_callback_url: this.webhookCallbackUrl, + proxyLocation: "RESIDENTIAL", + extracted_information_schema: parseObject(this.extractedInformationSchema), + totp_verification_url: this.totpVerificationUrl, + totp_identifier: this.totpIdentifier, + }, }); $.export("$summary", `Created and ran task with ID ${response.task_id}`); return response; diff --git a/components/skyvern/actions/get-workflow/get-workflow.mjs b/components/skyvern/actions/get-workflow/get-workflow.mjs index 9569836cd9e63..9585b5520ec76 100644 --- a/components/skyvern/actions/get-workflow/get-workflow.mjs +++ b/components/skyvern/actions/get-workflow/get-workflow.mjs @@ -1,10 +1,9 @@ import skyvern from "../../skyvern.app.mjs"; -import { axios } from "@pipedream/platform"; export default { key: "skyvern-get-workflow-run-details", name: "Get Workflow Run Details", - description: "Retrieve details of a specific Skyvern workflow run. Useful for checking the status and result of a run. [See the documentation](https://docs.skyvern.com/workflows/getting-workflows)", + description: "Retrieve details of runs of a specific Skyvern workflow. Useful for checking the status and result of a run. [See the documentation](https://docs.skyvern.com/workflows/getting-workflows)", version: "0.0.1", type: "action", props: { @@ -18,9 +17,10 @@ export default { }, async run({ $ }) { const response = await this.skyvern.getWorkflowRunDetails({ + $, workflowId: this.workflowId, }); - $.export("$summary", `Successfully retrieved details for workflow run with ID: ${this.workflowId}`); + $.export("$summary", `Successfully retrieved run details for workflow: ${this.workflowId}`); return response; }, }; diff --git a/components/skyvern/actions/run-workflow/run-workflow.mjs b/components/skyvern/actions/run-workflow/run-workflow.mjs index d7d2d262284aa..f1bfe4fbc26bd 100644 --- a/components/skyvern/actions/run-workflow/run-workflow.mjs +++ b/components/skyvern/actions/run-workflow/run-workflow.mjs @@ -1,11 +1,11 @@ +import { parseObject } from "../../common/utils.mjs"; import skyvern from "../../skyvern.app.mjs"; -import { axios } from "@pipedream/platform"; export default { key: "skyvern-run-workflow", name: "Run Workflow", description: "Trigger a predefined workflow in Skyvern, allowing the execution of complex routines from Pipedream. [See the documentation](https://docs.skyvern.com/workflows/running-workflows)", - version: "0.0.{{ts}}", + version: "0.0.1", type: "action", props: { skyvern, @@ -18,28 +18,26 @@ export default { data: { type: "object", label: "Data", - description: "The data field is used to pass in required and optional parameters that a workflow accepts", - optional: true, - }, - proxyLocation: { - type: "string", - label: "Proxy Location", - description: "Proxy location for the web browser. Please pass 'RESIDENTIAL'.", + description: "The data field is used to pass in required and optional parameters that a workflow accepts. [See the documentation](https://docs.skyvern.com/workflows/running-workflows) for further information.", optional: true, }, webhookCallbackUrl: { - type: "string", - label: "Webhook Callback URL", - description: "URL where system will send callback once it finishes executing the workflow run.", + propDefinition: [ + skyvern, + "webhookCallbackUrl", + ], optional: true, }, }, async run({ $ }) { const response = await this.skyvern.triggerWorkflow({ + $, workflowId: this.workflowId, - data: this.data, - proxyLocation: this.proxyLocation, - webhookCallbackUrl: this.webhookCallbackUrl, + data: { + data: parseObject(this.data), + proxyLocation: "RESIDENTIAL", + webhookCallbackUrl: this.webhookCallbackUrl, + }, }); $.export("$summary", `Successfully triggered workflow with ID ${response.workflow_id}`); diff --git a/components/skyvern/common/utils.mjs b/components/skyvern/common/utils.mjs new file mode 100644 index 0000000000000..dcc9cc61f6f41 --- /dev/null +++ b/components/skyvern/common/utils.mjs @@ -0,0 +1,24 @@ +export const parseObject = (obj) => { + if (!obj) return undefined; + + if (Array.isArray(obj)) { + return obj.map((item) => { + if (typeof item === "string") { + try { + return JSON.parse(item); + } catch (e) { + return item; + } + } + return item; + }); + } + if (typeof obj === "string") { + try { + return JSON.parse(obj); + } catch (e) { + return obj; + } + } + return obj; +}; diff --git a/components/skyvern/package.json b/components/skyvern/package.json index 07a2b0d0d3435..62d24d3d820c7 100644 --- a/components/skyvern/package.json +++ b/components/skyvern/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/skyvern", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Skyvern Components", "main": "skyvern.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } } diff --git a/components/skyvern/skyvern.app.mjs b/components/skyvern/skyvern.app.mjs index 05064e651fd9a..98db90739188d 100644 --- a/components/skyvern/skyvern.app.mjs +++ b/components/skyvern/skyvern.app.mjs @@ -4,106 +4,109 @@ export default { type: "app", app: "skyvern", propDefinitions: { - workspace: { - type: "string", - label: "Workspace", - description: "The workspace scope for workflows", - async options() { - const workflows = await this.listWorkflows(); - return workflows.map((workflow) => ({ - label: workflow.title, - value: workflow.workspace_id, - })); - }, - }, workflowId: { type: "string", label: "Workflow ID", description: "The unique identifier for a workflow", + async options({ page }) { + const workflows = await this.listWorkflows({ + params: { + page: page + 1, + }, + }); + return workflows.map(({ + workflow_permanent_id: value, title: label, + }) => ({ + label, + value, + })); + }, }, - taskName: { - type: "string", - label: "Task Name", - description: "The name of the task to be created and run", - }, - taskGoal: { + webhookCallbackUrl: { type: "string", - label: "Task Goal", - description: "The goal of the task to be created and run", + label: "Webhook Callback URL", + description: "URL where system will send callback once it finishes executing the workflow run.", }, }, methods: { _baseUrl() { return "https://api.skyvern.com/api/v1"; }, - async _makeRequest(opts = {}) { - const { - $ = this, method = "GET", path = "/", headers, ...otherOpts - } = opts; + _headers() { + return { + "x-api-key": this.$auth.api_key, + }; + }, + _makeRequest({ + $ = this, path, ...opts + }) { return axios($, { - ...otherOpts, - method, url: this._baseUrl() + path, - headers: { - ...headers, - "x-api-key": this.$auth.api_key, - }, - }); - }, - async listWorkflows(opts = {}) { - const params = { - only_workflows: true, + headers: this._headers(), ...opts, - }; - return this._makeRequest({ - path: "/workflows", - params, }); }, - async emitNewWorkflowEvent({ - workspace, ...opts + listWorkflows({ + params, ...opts }) { - const path = `/workflows/${workspace}/events`; return this._makeRequest({ - path, + path: "/workflows", + params: { + ...params, + only_workflows: true, + }, ...opts, }); }, - async getWorkflowRunDetails({ + getWorkflowRunDetails({ workflowId, ...opts }) { - const path = `/workflows/runs/${workflowId}`; + const path = `/workflows/${workflowId}/runs`; return this._makeRequest({ path, ...opts, }); }, - async triggerWorkflow({ - workflowId, data, proxyLocation, webhookCallbackUrl, ...opts + triggerWorkflow({ + workflowId, ...opts }) { return this._makeRequest({ method: "POST", path: `/workflows/${workflowId}/run`, - data: { - data, - proxy_location: proxyLocation, - webhook_callback_url: webhookCallbackUrl, - }, ...opts, }); }, - async createAndRunTask({ - taskName, taskGoal, ...opts - }) { + createAndRunTask(opts = {}) { return this._makeRequest({ method: "POST", path: "/tasks", - data: { - name: taskName, - navigation_goal: taskGoal, - ...opts, - }, + ...opts, }); }, + async *paginate({ + fn, params = {}, maxResults = null, ...opts + }) { + let hasMore = false; + let count = 0; + let page = 0; + + do { + params.page = ++page; + const data = await fn({ + params, + ...opts, + }); + for (const d of data) { + yield d; + + if (maxResults && ++count === maxResults) { + return count; + } + } + + hasMore = data.length; + + } while (hasMore); + }, }, }; diff --git a/components/skyvern/sources/new-or-updated-workflow/new-or-updated-workflow.mjs b/components/skyvern/sources/new-or-updated-workflow/new-or-updated-workflow.mjs index 2aa51f1f15310..686b81f5ebebb 100644 --- a/components/skyvern/sources/new-or-updated-workflow/new-or-updated-workflow.mjs +++ b/components/skyvern/sources/new-or-updated-workflow/new-or-updated-workflow.mjs @@ -1,24 +1,17 @@ +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; import skyvern from "../../skyvern.app.mjs"; -import { - axios, DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, -} from "@pipedream/platform"; +import sampleEmit from "./test-event.mjs"; export default { key: "skyvern-new-or-updated-workflow", name: "New or Updated Workflow", - description: "Emits a new event when a workflow is created or updated in Skyvern. [See the documentation](https://docs.skyvern.com/workflows/getting-workflows)", - version: "0.0.{{ts}}", + description: "Emit new event when a workflow is created or updated in Skyvern.", + version: "0.0.1", type: "source", dedupe: "unique", props: { skyvern, db: "$.service.db", - workspace: { - propDefinition: [ - skyvern, - "workspace", - ], - }, timer: { type: "$.interface.timer", default: { @@ -27,61 +20,48 @@ export default { }, }, methods: { - _getLastWorkflowVersion() { - return this.db.get("lastWorkflowVersion") || {}; + _getLastDate() { + return this.db.get("lastDate") || 0; }, - _setLastWorkflowVersion(workflows) { - const lastWorkflowVersion = workflows.reduce((acc, workflow) => { - acc[workflow.workflow_id] = workflow.version; - return acc; - }, {}); - this.db.set("lastWorkflowVersion", lastWorkflowVersion); + _setLastDate(lastDate) { + this.db.set("lastDate", lastDate); }, - }, - hooks: { - async deploy() { - const workflows = await this.skyvern.listWorkflows({ - workspace: this.workspace, + async emitEvent(maxResults = false) { + const lastDate = this._getLastDate(); + + const response = this.skyvern.paginate({ + fn: this.skyvern.listWorkflows, + maxResults, }); - const last50Workflows = workflows.slice(-50); - for (const workflow of last50Workflows) { - this.$emit(workflow, { - id: workflow.workflow_id, - summary: `New or Updated Workflow: ${workflow.title}`, - ts: Date.now(), - }); + let responseArray = []; + for await (const item of response) { + if (Date.parse(item.modified_at) <= lastDate) break; + responseArray.push(item); } - this._setLastWorkflowVersion(last50Workflows); - }, - async activate() { - // Add any logic for when the component is activated + if (responseArray.length) { + this._setLastDate(responseArray[0].modified_at); + } + + for (const item of responseArray.reverse()) { + this.$emit(item, { + id: `${item.modified_at}-${item.workflow_permanent_id}`, + summary: `New Workflow ${item.version === 1 + ? "Created" + : "Updated"}: ${item.title}`, + ts: Date.parse(item.modified_at), + }); + } }, - async deactivate() { - // Add any logic for when the component is deactivated + }, + hooks: { + async deploy() { + await this.emitEvent(25); }, }, async run() { - const lastWorkflowVersion = this._getLastWorkflowVersion(); - const workflows = await this.skyvern.listWorkflows({ - workspace: this.workspace, - }); - - for (const workflow of workflows) { - const previousVersion = lastWorkflowVersion[workflow.workflow_id]; - - if (!previousVersion || workflow.version > previousVersion) { - this.$emit(workflow, { - id: workflow.workflow_id, - summary: `New or Updated Workflow: ${workflow.title}`, - ts: Date.now(), - }); - - lastWorkflowVersion[workflow.workflow_id] = workflow.version; - } - } - - this._setLastWorkflowVersion(workflows); + await this.emitEvent(); }, + sampleEmit, }; diff --git a/components/skyvern/sources/new-or-updated-workflow/test-event.mjs b/components/skyvern/sources/new-or-updated-workflow/test-event.mjs new file mode 100644 index 0000000000000..ef4fdef8db798 --- /dev/null +++ b/components/skyvern/sources/new-or-updated-workflow/test-event.mjs @@ -0,0 +1,27 @@ +export default { + "workflow_id": "string", + "organization_id": "string", + "title": "string", + "workflow_permanent_id": "string", + "version": "integer", + "is_saved_task": "boolean", + "description": "string", + "proxy_location": "string | null", + "webhook_callback_url": "string | null", + "totp_verification_url": "string | null", + "workflow_definition": { + "parameters": [ + { + "parameter_type": "string", + "key": "string", + "description": "string | null" + } + ], + "blocks": [ + { + "label": "string", + "block_type": "string" + } + ] + } +} \ No newline at end of file From c9229589133c99becd65277130a4e9ed1343c4ea Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Tue, 12 Nov 2024 11:09:44 -0300 Subject: [PATCH 3/4] pnpm update --- pnpm-lock.yaml | 107 +++++++++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 52 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 48e44a6b26ac2..29e6cdcc551fe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9430,7 +9430,10 @@ importers: specifiers: {} components/skyvern: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.3 + dependencies: + '@pipedream/platform': 3.0.3 components/slack: specifiers: @@ -13365,55 +13368,6 @@ packages: - aws-crt dev: false - /@aws-sdk/client-sso-oidc/3.600.0_tdq3komn4zwyd65w7klbptsu34: - resolution: {integrity: sha512-7+I8RWURGfzvChyNQSyj5/tKrqRbzRl7H+BnTOf/4Vsw1nFOi5ROhlhD4X/Y0QCTacxnaoNcIrqnY7uGGvVRzw==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sts': 3.600.0 - '@aws-sdk/core': 3.598.0 - '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 - '@aws-sdk/middleware-host-header': 3.598.0 - '@aws-sdk/middleware-logger': 3.598.0 - '@aws-sdk/middleware-recursion-detection': 3.598.0 - '@aws-sdk/middleware-user-agent': 3.598.0 - '@aws-sdk/region-config-resolver': 3.598.0 - '@aws-sdk/types': 3.598.0 - '@aws-sdk/util-endpoints': 3.598.0 - '@aws-sdk/util-user-agent-browser': 3.598.0 - '@aws-sdk/util-user-agent-node': 3.598.0 - '@smithy/config-resolver': 3.0.3 - '@smithy/core': 2.2.3 - '@smithy/fetch-http-handler': 3.2.1 - '@smithy/hash-node': 3.0.2 - '@smithy/invalid-dependency': 3.0.2 - '@smithy/middleware-content-length': 3.0.2 - '@smithy/middleware-endpoint': 3.0.4 - '@smithy/middleware-retry': 3.0.6 - '@smithy/middleware-serde': 3.0.3 - '@smithy/middleware-stack': 3.0.3 - '@smithy/node-config-provider': 3.1.3 - '@smithy/node-http-handler': 3.1.2 - '@smithy/protocol-http': 4.0.3 - '@smithy/smithy-client': 3.1.6 - '@smithy/types': 3.3.0 - '@smithy/url-parser': 3.0.3 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.6 - '@smithy/util-defaults-mode-node': 3.0.6 - '@smithy/util-endpoints': 2.0.3 - '@smithy/util-middleware': 3.0.3 - '@smithy/util-retry': 3.0.2 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 - transitivePeerDependencies: - - '@aws-sdk/client-sts' - - aws-crt - dev: false - /@aws-sdk/client-sso/3.423.0: resolution: {integrity: sha512-znIufHkwhCIePgaYciIs3x/+BpzR57CZzbCKHR9+oOvGyufEPPpUT5bFLvbwTgfiVkTjuk6sG/ES3U5Bc+xtrA==} engines: {node: '>=14.0.0'} @@ -13649,7 +13603,7 @@ packages: dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.600.0_tdq3komn4zwyd65w7klbptsu34 + '@aws-sdk/client-sso-oidc': 3.600.0 '@aws-sdk/core': 3.598.0 '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 '@aws-sdk/middleware-host-header': 3.598.0 @@ -13691,6 +13645,55 @@ packages: - aws-crt dev: false + /@aws-sdk/client-sts/3.600.0_dseaa2p5u2yk67qiepewcq3hkq: + resolution: {integrity: sha512-KQG97B7LvTtTiGmjlrG1LRAY8wUvCQzrmZVV5bjrJ/1oXAU7DITYwVbSJeX9NWg6hDuSk0VE3MFwIXS2SvfLIA==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sso-oidc': 3.600.0 + '@aws-sdk/core': 3.598.0 + '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 + '@aws-sdk/middleware-host-header': 3.598.0 + '@aws-sdk/middleware-logger': 3.598.0 + '@aws-sdk/middleware-recursion-detection': 3.598.0 + '@aws-sdk/middleware-user-agent': 3.598.0 + '@aws-sdk/region-config-resolver': 3.598.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@aws-sdk/util-user-agent-browser': 3.598.0 + '@aws-sdk/util-user-agent-node': 3.598.0 + '@smithy/config-resolver': 3.0.3 + '@smithy/core': 2.2.3 + '@smithy/fetch-http-handler': 3.2.1 + '@smithy/hash-node': 3.0.2 + '@smithy/invalid-dependency': 3.0.2 + '@smithy/middleware-content-length': 3.0.2 + '@smithy/middleware-endpoint': 3.0.4 + '@smithy/middleware-retry': 3.0.6 + '@smithy/middleware-serde': 3.0.3 + '@smithy/middleware-stack': 3.0.3 + '@smithy/node-config-provider': 3.1.3 + '@smithy/node-http-handler': 3.1.2 + '@smithy/protocol-http': 4.0.3 + '@smithy/smithy-client': 3.1.6 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.6 + '@smithy/util-defaults-mode-node': 3.0.6 + '@smithy/util-endpoints': 2.0.3 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-retry': 3.0.2 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt + dev: false + /@aws-sdk/core/3.556.0: resolution: {integrity: sha512-vJaSaHw2kPQlo11j/Rzuz0gk1tEaKdz+2ser0f0qZ5vwFlANjt08m/frU17ctnVKC1s58bxpctO/1P894fHLrA==} engines: {node: '>=14.0.0'} @@ -18034,7 +18037,7 @@ packages: '@aws-sdk/client-sns': 3.423.0 '@aws-sdk/client-sqs': 3.423.0 '@aws-sdk/client-ssm': 3.423.0 - '@aws-sdk/client-sts': 3.600.0 + '@aws-sdk/client-sts': 3.600.0_dseaa2p5u2yk67qiepewcq3hkq '@aws-sdk/s3-request-presigner': 3.609.0 '@pipedream/helper_functions': 0.3.12 '@pipedream/platform': 1.6.6 From 5b6eb6c9841657cb9377e20476accfd24e4d0769 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Tue, 12 Nov 2024 11:44:06 -0300 Subject: [PATCH 4/4] fix action key --- components/skyvern/actions/get-workflow/get-workflow.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/skyvern/actions/get-workflow/get-workflow.mjs b/components/skyvern/actions/get-workflow/get-workflow.mjs index 9585b5520ec76..530fde4c96ed6 100644 --- a/components/skyvern/actions/get-workflow/get-workflow.mjs +++ b/components/skyvern/actions/get-workflow/get-workflow.mjs @@ -1,7 +1,7 @@ import skyvern from "../../skyvern.app.mjs"; export default { - key: "skyvern-get-workflow-run-details", + key: "skyvern-get-workflow", name: "Get Workflow Run Details", description: "Retrieve details of runs of a specific Skyvern workflow. Useful for checking the status and result of a run. [See the documentation](https://docs.skyvern.com/workflows/getting-workflows)", version: "0.0.1",