n8n-nodes-handit
Version:
n8n community nodes for Handit tracing and prompt management
261 lines • 13.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.HanditTracing = void 0;
const n8n_workflow_1 = require("n8n-workflow");
class HanditTracing {
constructor() {
this.description = {
displayName: 'Handit Tracing',
name: 'handitTracing',
icon: 'file:handit.svg',
group: ['transform'],
version: 1,
description: 'Collect workflow data and send to Handit API for tracing with enhanced node type support',
defaults: {
name: 'Handit Tracing',
},
inputs: ["main"],
outputs: ["main"],
credentials: [
{
name: 'handitApi',
required: true,
},
],
properties: [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
options: [
{
name: 'Trace Workflow',
value: 'trace',
description: 'Collect and send workflow data to Handit API',
action: 'Trace workflow data',
},
],
default: 'trace',
noDataExpression: true,
},
{
displayName: 'Agent Name',
name: 'agentName',
type: 'string',
default: 'demo agent',
required: true,
description: 'Name of the agent for tracing',
displayOptions: {
show: {
operation: ['trace'],
},
},
},
{
displayName: 'Workflow Structure',
name: 'workflowStructure',
type: 'json',
default: '{\n "Edit Fields": {\n "type": "tool",\n "inputs": []\n },\n "AI Agent": {\n "type": "llm",\n "inputs": ["Edit Fields"]\n }\n}',
required: true,
description: 'JSON object defining the workflow structure with node types and dependencies (parameters will be auto-captured)',
displayOptions: {
show: {
operation: ['trace'],
},
},
},
{
displayName: 'API URL',
name: 'apiUrl',
type: 'string',
default: 'https://handit-api-oss-299768392189.us-central1.run.app/api/track/bulk',
description: 'Custom API endpoint URL (leave empty to use the default Handit API endpoint)',
displayOptions: {
show: {
operation: ['trace'],
},
},
},
],
};
}
async execute() {
const items = this.getInputData();
const returnData = [];
const operation = this.getNodeParameter('operation', 0);
if (operation === 'trace') {
for (let i = 0; i < items.length; i++) {
try {
const agentName = this.getNodeParameter('agentName', i);
const workflowStructureInput = this.getNodeParameter('workflowStructure', i);
const apiUrl = this.getNodeParameter('apiUrl', i);
const credentials = await this.getCredentials('handitApi');
if (!(credentials === null || credentials === void 0 ? void 0 : credentials.apiToken)) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Handit API credentials are required');
}
let workflowStructure;
try {
workflowStructure = JSON.parse(workflowStructureInput);
}
catch (error) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid JSON in workflow structure: ${error.message}`);
}
let workflowDataArray = [];
try {
function getAllNodes() {
const allNodes = new Set();
Object.keys(workflowStructure).forEach(node => allNodes.add(node));
Object.values(workflowStructure).forEach(nodeConfig => {
if (nodeConfig.inputs && Array.isArray(nodeConfig.inputs)) {
nodeConfig.inputs.forEach(inputNode => allNodes.add(inputNode));
}
});
return Array.from(allNodes);
}
const nodes = getAllNodes();
function resolveAllExpressions(value, inputData, allNodesData) {
if (typeof value === 'string') {
const regex = /{{\s*(.*?)\s*}}/g;
return value.replace(regex, (_, code) => {
try {
const $json = inputData || {};
const $node = (nodeName) => ({ json: allNodesData[nodeName] || {} });
const contextFunction = new Function('$json', '$node', `return ${code}`);
return contextFunction($json, $node);
}
catch (e) {
return `{{ ${code} }}`;
}
});
}
else if (Array.isArray(value)) {
return value.map((item) => resolveAllExpressions(item, inputData, allNodesData));
}
else if (value !== null && typeof value === 'object') {
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, resolveAllExpressions(v, inputData, allNodesData)]));
}
return value;
}
function findInputSource(currentNode, allNodesData) {
const nodeConfig = workflowStructure[currentNode];
const possibleSources = (nodeConfig === null || nodeConfig === void 0 ? void 0 : nodeConfig.inputs) || [];
for (const sourceNode of possibleSources) {
if (allNodesData[sourceNode] && Object.keys(allNodesData[sourceNode]).length > 0) {
return allNodesData[sourceNode];
}
}
return {};
}
const allNodesData = {};
const inputData = this.getInputData();
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
try {
allNodesData[node] = inputData && inputData.length > 0 ? inputData[0].json || {} : {};
}
catch (e) {
allNodesData[node] = {};
}
}
for (let j = 0; j < nodes.length; j++) {
const node = nodes[j];
const nodeConfig = workflowStructure[node];
const nodeType = nodeConfig ? nodeConfig.type : 'tool';
let output = {};
let previousSteps = {};
try {
const inputData = this.getInputData();
if (inputData && inputData.length > 0) {
output = inputData[0].json || {};
if (output['intermediateSteps']) {
previousSteps = output['intermediateSteps'];
delete output['intermediateSteps'];
}
}
}
catch (e) {
}
let nodeParameters = {};
let captureMethod = 'unknown';
try {
const workflowProxy = this.getWorkflowDataProxy(0);
if (workflowProxy && workflowProxy.$ && typeof workflowProxy.$ === 'function') {
try {
const nodeProxy = workflowProxy.$(node);
if (nodeProxy && nodeProxy.params) {
const rawParameters = JSON.parse(JSON.stringify(nodeProxy.params)) || {};
const inputData = findInputSource(node, allNodesData);
nodeParameters = resolveAllExpressions(rawParameters, inputData, allNodesData);
captureMethod = 'node_params_via_proxy_resolved';
}
}
catch (nodeError) {
}
}
}
catch (e) {
}
if (Object.keys(nodeParameters).length === 0) {
const inputData = this.getInputData();
if (inputData && inputData.length > 0) {
nodeParameters = inputData[0].json || {};
captureMethod = 'input_data_fallback';
}
}
const input = {
...nodeParameters,
_captured_at: new Date().toISOString(),
_node_type: nodeType,
_input_sources: (nodeConfig === null || nodeConfig === void 0 ? void 0 : nodeConfig.inputs) || [],
_capture_method: captureMethod,
previousSteps,
};
workflowDataArray.push({
nodeName: node,
input: input,
nodeType: nodeType,
output: output || {},
});
}
}
catch (error) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Error processing workflow data: ${error.message}`);
}
const dataToSend = {
workflowData: workflowDataArray.filter((item) => item.output &&
typeof item.output === 'object' &&
Object.keys(item.output).length > 0),
agentName: agentName,
};
const requestOptions = {
method: 'POST',
url: apiUrl || 'https://handit-api-oss-299768392189.us-central1.run.app/api/track/bulk',
body: dataToSend,
json: true,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${credentials.apiToken}`,
},
};
const response = await this.helpers.httpRequest(requestOptions);
returnData.push({
success: true,
message: 'Data sent successfully',
response: response,
data: dataToSend,
});
}
catch (error) {
returnData.push({
success: false,
error: error.message,
data: {},
});
}
}
}
return [this.helpers.returnJsonArray(returnData)];
}
}
exports.HanditTracing = HanditTracing;
//# sourceMappingURL=HanditTracing.node.js.map