Update n8n Skyvern.node.ts to include webhook_callback_url option in … (#2230)

This commit is contained in:
dd36
2025-04-30 11:10:14 -07:00
committed by GitHub
parent c069ebe6f9
commit 3af35bc428

View File

@@ -10,7 +10,7 @@ async function makeRequest(url: string, options: any = {}): Promise<any> {
const requestOptions = {
hostname: parsedUrl.hostname,
path: parsedUrl.pathname + parsedUrl.search,
port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
method: options.method || 'GET',
headers: options.headers || {},
};
@@ -83,7 +83,7 @@ export class Skyvern implements INodeType {
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
noDataExpression: true,
options: [
{
name: 'Task',
@@ -93,7 +93,6 @@ export class Skyvern implements INodeType {
name: 'Workflow',
value: 'workflow',
},
],
default: 'task',
},
@@ -135,18 +134,31 @@ export class Skyvern implements INodeType {
const taskOptions: IDataObject = this.getNodeParameter('taskOptions') as IDataObject;
if (taskOptions["engine"] !== "v1") return requestOptions;
// trigger the generate task v1 logic
const credentials = await this.getCredentials('skyvernApi');
const userPrompt = this.getNodeParameter('userPrompt');
// *** capture optional webhook URL ***
let webhookUrl: string | undefined;
try {
webhookUrl = this.getNodeParameter('webhookUrl') as string;
} catch (e) {
webhookUrl = undefined;
}
const generateBody: IDataObject = {
prompt: userPrompt,
};
if (webhookUrl) {
generateBody['webhook_callback_url'] = webhookUrl; // include for TaskV1 generation
}
const response = await makeRequest(credentials['baseUrl'] + '/api/v1/generate/task', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': credentials['apiKey'],
},
body: JSON.stringify({
prompt: userPrompt,
}),
body: JSON.stringify(generateBody),
});
if (!response.ok) {
throw new Error('Request to generate Task V1 failed'); // eslint-disable-line
@@ -159,7 +171,11 @@ export class Skyvern implements INodeType {
navigation_payload: data.navigation_payload,
data_extraction_goal: data.data_extraction_goal,
extracted_information_schema: data.extracted_information_schema,
};
} as IDataObject;
if (webhookUrl) {
(requestOptions.body as IDataObject)['webhook_callback_url'] = webhookUrl;
}
return requestOptions;
},
],
@@ -209,6 +225,28 @@ export class Skyvern implements INodeType {
},
},
},
// *** New property: optional webhook URL for Task dispatch ***
{
displayName: 'Webhook Callback URL',
description: 'Optional URL that Skyvern will call when the task finishes',
name: 'webhookUrl',
type: 'string',
default: '',
placeholder: 'https://example.com/webhook',
displayOptions: {
show: {
resource: ['task'],
taskOperation: ['dispatch'],
},
},
routing: {
request: {
body: {
webhook_callback_url: '={{$value ? $value : undefined}}',
},
},
},
},
{
displayName: 'Task ID',
description: 'The ID of the task',
@@ -365,6 +403,28 @@ export class Skyvern implements INodeType {
},
},
},
// *** New property: optional webhook URL for Workflow dispatch ***
{
displayName: 'Webhook Callback URL',
description: 'Optional URL that Skyvern will call when the workflow run finishes',
name: 'webhookCallbackUrl',
type: 'string',
default: '',
placeholder: 'https://example.com/webhook',
displayOptions: {
show: {
resource: ['workflow'],
workflowOperation: ['dispatch'],
},
},
routing: {
request: {
body: {
webhook_callback_url: '={{$value ? $value : undefined}}',
},
},
},
},
],
version: 1,
};
@@ -415,48 +475,49 @@ export class Skyvern implements INodeType {
const parameters: any[] = workflow.workflow_definition.parameters;
const fields: ResourceMapperField[] = await Promise.all(
parameters.filter((parameter: any) => parameter.parameter_type === 'workflow' || parameter.parameter_type === 'credential')
.map(async (parameter: any) => {
let options: INodePropertyOptions[] | undefined = undefined;
let parameterType: FieldType | undefined = undefined;
if (parameter.parameter_type === 'credential') {
const response = await makeRequest(credentials['baseUrl'] + '/api/v1/credentials', {
headers: {
'x-api-key': credentials['apiKey'],
},
});
if (!response.ok) {
throw new Error('Request to get credentials failed'); // eslint-disable-line
parameters
.filter((parameter: any) => parameter.parameter_type === 'workflow' || parameter.parameter_type === 'credential')
.map(async (parameter: any) => {
let options: INodePropertyOptions[] | undefined = undefined;
let parameterType: FieldType | undefined = undefined;
if (parameter.parameter_type === 'credential') {
const credResponse = await makeRequest(credentials['baseUrl'] + '/api/v1/credentials', {
headers: {
'x-api-key': credentials['apiKey'],
},
});
if (!credResponse.ok) {
throw new Error('Request to get credentials failed');
}
const credData = await credResponse.json();
options = credData.map((credential: any) => ({
name: credential.name,
value: credential.credential_id,
}));
parameterType = 'options';
} else {
const parameter_type_map: Record<string, FieldType> = {
string: 'string',
integer: 'number',
float: 'number',
boolean: 'boolean',
json: 'json',
file_url: 'url',
}
parameterType = parameter_type_map[parameter.workflow_parameter_type];
}
const data = await response.json();
options = data.map((credential: any) => ({
name: credential.name,
value: credential.credential_id,
}));
parameterType = 'options';
}else{
const parameter_type_map: Record<string, string> = {
'string': 'string',
'integer': 'number',
'float': 'number',
'boolean': 'boolean',
'json': 'json',
'file_url': 'url',
}
parameterType = parameter_type_map[parameter.workflow_parameter_type] as FieldType;
}
return {
id: parameter.key,
displayName: parameter.key,
defaultMatch: true,
canBeUsedToMatch: false,
required: parameter.default_value === undefined || parameter.default_value === null,
display: true,
type: parameterType,
options: options,
};
})
return {
id: parameter.key,
displayName: parameter.key,
defaultMatch: true,
canBeUsedToMatch: false,
required: parameter.default_value === undefined || parameter.default_value === null,
display: true,
type: parameterType,
options: options,
};
})
);