@atomoz/workflows-nodes 0.1.25 → 0.1.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +415 -44
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +405 -44
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
7
|
var __export = (target, all) => {
|
|
6
8
|
for (var name in all)
|
|
@@ -14,6 +16,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
14
16
|
}
|
|
15
17
|
return to;
|
|
16
18
|
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
17
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
28
|
|
|
19
29
|
// index.ts
|
|
@@ -1088,7 +1098,7 @@ async function createLLMFromModel(modelConfig, authToken, streaming = false) {
|
|
|
1088
1098
|
case "gemini":
|
|
1089
1099
|
return new import_google_gauth.ChatGoogle({
|
|
1090
1100
|
model: "gemini-flash-latest",
|
|
1091
|
-
apiKey: "
|
|
1101
|
+
apiKey: "AIzaSyAWj0Al2sVJ8vqaRN4UY7c6imAg7a3NbEc",
|
|
1092
1102
|
streaming
|
|
1093
1103
|
});
|
|
1094
1104
|
case "openai":
|
|
@@ -1114,6 +1124,50 @@ async function createLLMFromModel(modelConfig, authToken, streaming = false) {
|
|
|
1114
1124
|
}
|
|
1115
1125
|
|
|
1116
1126
|
// src/utils/guardrail-executor.ts
|
|
1127
|
+
async function loadChatHistory(context) {
|
|
1128
|
+
const checkpointer = context?.checkpointer;
|
|
1129
|
+
const sessionId = context?.sessionId;
|
|
1130
|
+
if (!checkpointer || !sessionId) {
|
|
1131
|
+
console.log(`[GUARDRAIL] checkpointer=${!!checkpointer}, sessionId=${sessionId}`);
|
|
1132
|
+
return null;
|
|
1133
|
+
}
|
|
1134
|
+
try {
|
|
1135
|
+
console.log(`[GUARDRAIL] Carregando hist\xF3rico da mem\xF3ria (session: ${sessionId})`);
|
|
1136
|
+
if (typeof checkpointer.setup === "function" && !checkpointer.isSetup) {
|
|
1137
|
+
await checkpointer.setup();
|
|
1138
|
+
}
|
|
1139
|
+
let checkpoint = null;
|
|
1140
|
+
if (typeof checkpointer.getTuple === "function") {
|
|
1141
|
+
const tuple = await checkpointer.getTuple({ configurable: { thread_id: sessionId } });
|
|
1142
|
+
checkpoint = tuple?.checkpoint;
|
|
1143
|
+
console.log(`[GUARDRAIL] getTuple result:`, tuple ? "found" : "null");
|
|
1144
|
+
}
|
|
1145
|
+
if (!checkpoint && typeof checkpointer.get === "function") {
|
|
1146
|
+
checkpoint = await checkpointer.get({ configurable: { thread_id: sessionId } });
|
|
1147
|
+
console.log(`[GUARDRAIL] get result:`, checkpoint ? "found" : "null");
|
|
1148
|
+
}
|
|
1149
|
+
if (!checkpoint) {
|
|
1150
|
+
console.log(`[GUARDRAIL] Nenhum checkpoint encontrado`);
|
|
1151
|
+
return null;
|
|
1152
|
+
}
|
|
1153
|
+
console.log(`[GUARDRAIL] Checkpoint keys:`, Object.keys(checkpoint));
|
|
1154
|
+
const messages = checkpoint?.channel_values?.messages || checkpoint?.values?.messages || checkpoint?.messages || [];
|
|
1155
|
+
if (!messages || messages.length === 0) {
|
|
1156
|
+
console.log(`[GUARDRAIL] Nenhuma mensagem no checkpoint`);
|
|
1157
|
+
return null;
|
|
1158
|
+
}
|
|
1159
|
+
const historyLines = messages.map((m) => {
|
|
1160
|
+
const role = m._getType?.() === "human" || m.type === "human" ? "Usu\xE1rio" : "Assistente";
|
|
1161
|
+
const content = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
|
|
1162
|
+
return `${role}: ${content.slice(0, 200)}${content.length > 200 ? "..." : ""}`;
|
|
1163
|
+
});
|
|
1164
|
+
console.log(`[GUARDRAIL] Hist\xF3rico carregado: ${messages.length} mensagens`);
|
|
1165
|
+
return historyLines.join("\n");
|
|
1166
|
+
} catch (error) {
|
|
1167
|
+
console.error(`[GUARDRAIL] Erro ao carregar hist\xF3rico:`, error);
|
|
1168
|
+
return null;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1117
1171
|
async function executeGuardrails(guardrails, content, mode = "fail-first", context = {}) {
|
|
1118
1172
|
const list = Array.isArray(guardrails) ? guardrails : [guardrails];
|
|
1119
1173
|
const result = {
|
|
@@ -1199,44 +1253,90 @@ async function executeGuardrails(guardrails, content, mode = "fail-first", conte
|
|
|
1199
1253
|
}
|
|
1200
1254
|
} else if (guard.type === "model") {
|
|
1201
1255
|
const { model, evaluationPrompt, name, actionInstruction } = guard;
|
|
1256
|
+
console.log(`[GUARDRAIL LLM] Iniciando guardrail "${name}"`);
|
|
1257
|
+
console.log(`[GUARDRAIL LLM] Conte\xFAdo a avaliar (${content.length} chars):`, content.slice(0, 200) + (content.length > 200 ? "..." : ""));
|
|
1258
|
+
console.log(`[GUARDRAIL LLM] Action: ${guard.action}, Model dispon\xEDvel: ${!!model}`);
|
|
1259
|
+
const chatHistory = await loadChatHistory(context);
|
|
1260
|
+
if (chatHistory) {
|
|
1261
|
+
console.log(`[GUARDRAIL LLM] Hist\xF3rico inclu\xEDdo no contexto`);
|
|
1262
|
+
}
|
|
1202
1263
|
if (model && typeof model.invoke === "function") {
|
|
1203
1264
|
try {
|
|
1204
1265
|
let prompt = evaluationPrompt;
|
|
1266
|
+
console.log(`[GUARDRAIL LLM] Evaluation prompt base:`, (prompt || "").slice(0, 200));
|
|
1205
1267
|
if (actionInstruction) {
|
|
1206
1268
|
prompt += `
|
|
1207
1269
|
|
|
1208
1270
|
INSTRU\xC7\xC3O ADICIONAL DE A\xC7\xC3O:
|
|
1209
1271
|
${actionInstruction}`;
|
|
1272
|
+
}
|
|
1273
|
+
if (chatHistory) {
|
|
1274
|
+
prompt += `
|
|
1275
|
+
|
|
1276
|
+
HIST\xD3RICO DA CONVERSA:
|
|
1277
|
+
${chatHistory}`;
|
|
1210
1278
|
}
|
|
1211
1279
|
if (prompt.includes("{{content}}")) {
|
|
1212
1280
|
prompt = prompt.replace("{{content}}", content);
|
|
1213
1281
|
} else {
|
|
1214
1282
|
prompt = `${prompt}
|
|
1215
1283
|
|
|
1216
|
-
CONTE\xDADO
|
|
1284
|
+
CONTE\xDADO A AVALIAR (resposta atual):
|
|
1217
1285
|
${content}`;
|
|
1218
1286
|
}
|
|
1287
|
+
console.log(`[GUARDRAIL LLM] Chamando modelo...`);
|
|
1219
1288
|
const response = await model.invoke(prompt);
|
|
1220
1289
|
const resultText = typeof response.content === "string" ? response.content : String(response.content);
|
|
1290
|
+
console.log(`[GUARDRAIL LLM] Resposta do modelo:`, resultText.slice(0, 300));
|
|
1291
|
+
const isUnsafe = resultText.toUpperCase().includes("UNSAFE");
|
|
1292
|
+
const isSafe = resultText.toUpperCase().startsWith("SAFE") || resultText.toUpperCase().includes("SAFE") && !isUnsafe;
|
|
1221
1293
|
if (guard.action === "fix") {
|
|
1222
|
-
if (
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1294
|
+
if (isUnsafe) {
|
|
1295
|
+
console.log(`[GUARDRAIL LLM] Modo FIX - Detectado UNSAFE, chamando modelo para corrigir...`);
|
|
1296
|
+
const fixPrompt = `Voc\xEA \xE9 um corretor de conte\xFAdo. O texto abaixo foi marcado como UNSAFE por violar uma regra.
|
|
1297
|
+
|
|
1298
|
+
REGRA VIOLADA:
|
|
1299
|
+
${evaluationPrompt}
|
|
1300
|
+
|
|
1301
|
+
${actionInstruction ? `INSTRU\xC7\xC3O DE CORRE\xC7\xC3O:
|
|
1302
|
+
${actionInstruction}
|
|
1303
|
+
` : ""}
|
|
1304
|
+
|
|
1305
|
+
CONTE\xDADO ORIGINAL:
|
|
1306
|
+
${content}
|
|
1307
|
+
|
|
1308
|
+
Reescreva o conte\xFAdo corrigindo a viola\xE7\xE3o. Retorne APENAS o texto corrigido, sem explica\xE7\xF5es ou prefixos.`;
|
|
1309
|
+
try {
|
|
1310
|
+
const fixResponse = await model.invoke(fixPrompt);
|
|
1311
|
+
const fixedContent = typeof fixResponse.content === "string" ? fixResponse.content : String(fixResponse.content);
|
|
1312
|
+
console.log(`[GUARDRAIL LLM] Conte\xFAdo corrigido:`, fixedContent.slice(0, 300));
|
|
1313
|
+
result.modifiedContent = fixedContent;
|
|
1314
|
+
violationMessage = `Conte\xFAdo reescrito pelo guardrail "${name}".`;
|
|
1315
|
+
result.violations.push({
|
|
1316
|
+
name: guard.name,
|
|
1317
|
+
message: violationMessage,
|
|
1318
|
+
action: "fix"
|
|
1319
|
+
});
|
|
1320
|
+
} catch (fixError) {
|
|
1321
|
+
console.error(`[GUARDRAIL LLM] Erro ao corrigir conte\xFAdo:`, fixError);
|
|
1322
|
+
}
|
|
1323
|
+
} else {
|
|
1324
|
+
console.log(`[GUARDRAIL LLM] Modo FIX - Conte\xFAdo aprovado (SAFE)`);
|
|
1230
1325
|
}
|
|
1231
1326
|
} else {
|
|
1232
|
-
if (
|
|
1327
|
+
if (isUnsafe) {
|
|
1233
1328
|
guardPassed = false;
|
|
1234
1329
|
violationMessage = actionInstruction || `Modelo de avalia\xE7\xE3o "${name}" detectou viola\xE7\xE3o de seguran\xE7a/pol\xEDtica.`;
|
|
1330
|
+
console.log(`[GUARDRAIL LLM] Resultado: UNSAFE - Bloqueado`);
|
|
1331
|
+
} else {
|
|
1332
|
+
console.log(`[GUARDRAIL LLM] Resultado: SAFE - Aprovado`);
|
|
1235
1333
|
}
|
|
1236
1334
|
}
|
|
1237
1335
|
} catch (error) {
|
|
1238
|
-
console.error(`
|
|
1336
|
+
console.error(`[GUARDRAIL LLM] Erro ao executar guardrail "${name}":`, error);
|
|
1239
1337
|
}
|
|
1338
|
+
} else {
|
|
1339
|
+
console.log(`[GUARDRAIL LLM] Model n\xE3o dispon\xEDvel ou n\xE3o \xE9 invoc\xE1vel para guardrail "${name}"`);
|
|
1240
1340
|
}
|
|
1241
1341
|
}
|
|
1242
1342
|
if (!guardPassed) {
|
|
@@ -1300,7 +1400,7 @@ var IaAgentNodeFunction = async (inputs) => {
|
|
|
1300
1400
|
let guardrailViolations = [];
|
|
1301
1401
|
if (message && beforeGuardrails) {
|
|
1302
1402
|
const preparedBefore = await prepareGuardrails(beforeGuardrails);
|
|
1303
|
-
const context = { ...inputs, input: message };
|
|
1403
|
+
const context = { ...inputs, input: message, checkpointer, sessionId };
|
|
1304
1404
|
const beforeResults = await executeGuardrails(preparedBefore, message, guardrailMode, context);
|
|
1305
1405
|
if (beforeResults.blocked) {
|
|
1306
1406
|
console.log(`\u{1F6E1}\uFE0F IaAgentNode "${name}": Blocked by before-agent guardrail:`, beforeResults.message);
|
|
@@ -1502,7 +1602,7 @@ IMPORTANT: You must base your response on the last message in the conversation h
|
|
|
1502
1602
|
}
|
|
1503
1603
|
if (output && afterGuardrails) {
|
|
1504
1604
|
const preparedAfter = await prepareGuardrails(afterGuardrails);
|
|
1505
|
-
const context = { ...inputs, input: output };
|
|
1605
|
+
const context = { ...inputs, input: output, checkpointer, sessionId };
|
|
1506
1606
|
const afterResults = await executeGuardrails(preparedAfter, output, guardrailMode, context);
|
|
1507
1607
|
if (afterResults.blocked) {
|
|
1508
1608
|
console.log(`\u{1F6E1}\uFE0F IaAgentNode "${name}": Response blocked by after-agent guardrail:`, afterResults.message);
|
|
@@ -2391,8 +2491,271 @@ var WhatsappMessageTriggerNode = {
|
|
|
2391
2491
|
]
|
|
2392
2492
|
};
|
|
2393
2493
|
|
|
2494
|
+
// src/utils/sandbox-executor.ts
|
|
2495
|
+
var ivmModule = null;
|
|
2496
|
+
async function getIVM() {
|
|
2497
|
+
if (ivmModule !== null) return ivmModule;
|
|
2498
|
+
try {
|
|
2499
|
+
const mod = await import("isolated-vm");
|
|
2500
|
+
ivmModule = {
|
|
2501
|
+
Isolate: mod.Isolate || mod.default?.Isolate,
|
|
2502
|
+
ExternalCopy: mod.ExternalCopy || mod.default?.ExternalCopy,
|
|
2503
|
+
Reference: mod.Reference || mod.default?.Reference
|
|
2504
|
+
};
|
|
2505
|
+
if (!ivmModule.Isolate) {
|
|
2506
|
+
console.warn("[Sandbox] isolated-vm Isolate n\xE3o encontrado");
|
|
2507
|
+
return null;
|
|
2508
|
+
}
|
|
2509
|
+
return ivmModule;
|
|
2510
|
+
} catch (e) {
|
|
2511
|
+
console.warn("[Sandbox] isolated-vm n\xE3o dispon\xEDvel, usando fallback inseguro");
|
|
2512
|
+
return null;
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
var DEFAULT_OPTIONS = {
|
|
2516
|
+
timeout: 1e4,
|
|
2517
|
+
memoryLimit: 128,
|
|
2518
|
+
allowFetch: true
|
|
2519
|
+
};
|
|
2520
|
+
async function executeSandboxed(code, sandboxContext, options = {}) {
|
|
2521
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
2522
|
+
const ivm = await getIVM();
|
|
2523
|
+
if (!ivm) {
|
|
2524
|
+
return executeFallback(code, sandboxContext);
|
|
2525
|
+
}
|
|
2526
|
+
let isolate = null;
|
|
2527
|
+
let context = null;
|
|
2528
|
+
try {
|
|
2529
|
+
isolate = new ivm.Isolate({ memoryLimit: opts.memoryLimit });
|
|
2530
|
+
context = await isolate.createContext();
|
|
2531
|
+
const jail = context.global;
|
|
2532
|
+
await jail.set("globalThis", jail.derefInto());
|
|
2533
|
+
await injectContextVariables(jail, sandboxContext, ivm);
|
|
2534
|
+
await jail.set("__logRef", new ivm.Reference(function(...args) {
|
|
2535
|
+
console.log("[Sandbox]", ...args);
|
|
2536
|
+
}));
|
|
2537
|
+
if (opts.allowFetch) {
|
|
2538
|
+
await jail.set("__fetchRef", new ivm.Reference(async function(url, optionsJson) {
|
|
2539
|
+
try {
|
|
2540
|
+
const options2 = optionsJson ? JSON.parse(optionsJson) : {};
|
|
2541
|
+
const res = await fetch(url, {
|
|
2542
|
+
method: options2?.method || "GET",
|
|
2543
|
+
headers: options2?.headers,
|
|
2544
|
+
body: options2?.body
|
|
2545
|
+
});
|
|
2546
|
+
const contentType = res.headers.get("content-type") || "";
|
|
2547
|
+
let data;
|
|
2548
|
+
if (contentType.includes("application/json")) {
|
|
2549
|
+
data = await res.json();
|
|
2550
|
+
} else {
|
|
2551
|
+
data = await res.text();
|
|
2552
|
+
}
|
|
2553
|
+
return JSON.stringify({
|
|
2554
|
+
ok: res.ok,
|
|
2555
|
+
status: res.status,
|
|
2556
|
+
statusText: res.statusText,
|
|
2557
|
+
data
|
|
2558
|
+
});
|
|
2559
|
+
} catch (error) {
|
|
2560
|
+
return JSON.stringify({
|
|
2561
|
+
ok: false,
|
|
2562
|
+
status: 0,
|
|
2563
|
+
statusText: "Network Error",
|
|
2564
|
+
error: error.message
|
|
2565
|
+
});
|
|
2566
|
+
}
|
|
2567
|
+
}));
|
|
2568
|
+
}
|
|
2569
|
+
const bootstrapCode = `
|
|
2570
|
+
// Console
|
|
2571
|
+
const console = {
|
|
2572
|
+
log: (...args) => __logRef.applySync(undefined, args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a))),
|
|
2573
|
+
warn: (...args) => __logRef.applySync(undefined, ['[WARN]', ...args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a))]),
|
|
2574
|
+
error: (...args) => __logRef.applySync(undefined, ['[ERROR]', ...args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a))]),
|
|
2575
|
+
info: (...args) => __logRef.applySync(undefined, args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a))),
|
|
2576
|
+
};
|
|
2577
|
+
globalThis.console = console;
|
|
2578
|
+
|
|
2579
|
+
${opts.allowFetch ? `
|
|
2580
|
+
// Fetch
|
|
2581
|
+
globalThis.fetch = async (url, options = {}) => {
|
|
2582
|
+
const optionsJson = JSON.stringify(options);
|
|
2583
|
+
const resultJson = await __fetchRef.apply(undefined, [url, optionsJson], { result: { promise: true } });
|
|
2584
|
+
const result = JSON.parse(resultJson);
|
|
2585
|
+
|
|
2586
|
+
if (!result.ok && result.error) {
|
|
2587
|
+
throw new Error(result.error);
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
return {
|
|
2591
|
+
ok: result.ok,
|
|
2592
|
+
status: result.status,
|
|
2593
|
+
statusText: result.statusText,
|
|
2594
|
+
json: async () => result.data,
|
|
2595
|
+
text: async () => typeof result.data === 'string' ? result.data : JSON.stringify(result.data),
|
|
2596
|
+
};
|
|
2597
|
+
};
|
|
2598
|
+
` : ""}
|
|
2599
|
+
|
|
2600
|
+
// Base64
|
|
2601
|
+
globalThis.atob = (str) => {
|
|
2602
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
|
2603
|
+
let output = '';
|
|
2604
|
+
str = String(str).replace(/=+$/, '');
|
|
2605
|
+
for (let i = 0; i < str.length; i += 4) {
|
|
2606
|
+
const enc1 = chars.indexOf(str.charAt(i));
|
|
2607
|
+
const enc2 = chars.indexOf(str.charAt(i + 1));
|
|
2608
|
+
const enc3 = chars.indexOf(str.charAt(i + 2));
|
|
2609
|
+
const enc4 = chars.indexOf(str.charAt(i + 3));
|
|
2610
|
+
const chr1 = (enc1 << 2) | (enc2 >> 4);
|
|
2611
|
+
const chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
|
2612
|
+
const chr3 = ((enc3 & 3) << 6) | enc4;
|
|
2613
|
+
output += String.fromCharCode(chr1);
|
|
2614
|
+
if (enc3 !== 64) output += String.fromCharCode(chr2);
|
|
2615
|
+
if (enc4 !== 64) output += String.fromCharCode(chr3);
|
|
2616
|
+
}
|
|
2617
|
+
return output;
|
|
2618
|
+
};
|
|
2619
|
+
|
|
2620
|
+
globalThis.btoa = (str) => {
|
|
2621
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
|
2622
|
+
str = String(str);
|
|
2623
|
+
let output = '';
|
|
2624
|
+
for (let i = 0; i < str.length; i += 3) {
|
|
2625
|
+
const chr1 = str.charCodeAt(i);
|
|
2626
|
+
const chr2 = str.charCodeAt(i + 1);
|
|
2627
|
+
const chr3 = str.charCodeAt(i + 2);
|
|
2628
|
+
const enc1 = chr1 >> 2;
|
|
2629
|
+
const enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
|
2630
|
+
const enc3 = isNaN(chr2) ? 64 : ((chr2 & 15) << 2) | (chr3 >> 6);
|
|
2631
|
+
const enc4 = isNaN(chr3) ? 64 : chr3 & 63;
|
|
2632
|
+
output += chars.charAt(enc1) + chars.charAt(enc2) + chars.charAt(enc3) + chars.charAt(enc4);
|
|
2633
|
+
}
|
|
2634
|
+
return output;
|
|
2635
|
+
};
|
|
2636
|
+
`;
|
|
2637
|
+
const bootstrapScript = await isolate.compileScript(bootstrapCode);
|
|
2638
|
+
await bootstrapScript.run(context);
|
|
2639
|
+
const wrappedCode = wrapUserCode(code);
|
|
2640
|
+
const finalCode = `
|
|
2641
|
+
(async () => {
|
|
2642
|
+
const __userResult = await (${wrappedCode});
|
|
2643
|
+
// Serializa o resultado para poder transferir
|
|
2644
|
+
if (__userResult === undefined) return '__UNDEFINED__';
|
|
2645
|
+
if (__userResult === null) return 'null';
|
|
2646
|
+
if (typeof __userResult === 'object') {
|
|
2647
|
+
return JSON.stringify({ __type: 'object', value: __userResult });
|
|
2648
|
+
}
|
|
2649
|
+
return JSON.stringify({ __type: typeof __userResult, value: __userResult });
|
|
2650
|
+
})()
|
|
2651
|
+
`;
|
|
2652
|
+
const script = await isolate.compileScript(finalCode);
|
|
2653
|
+
const rawResult = await script.run(context, {
|
|
2654
|
+
timeout: opts.timeout,
|
|
2655
|
+
promise: true
|
|
2656
|
+
});
|
|
2657
|
+
if (rawResult === "__UNDEFINED__") return void 0;
|
|
2658
|
+
if (rawResult === "null") return null;
|
|
2659
|
+
try {
|
|
2660
|
+
const parsed = JSON.parse(rawResult);
|
|
2661
|
+
return parsed.value;
|
|
2662
|
+
} catch {
|
|
2663
|
+
return rawResult;
|
|
2664
|
+
}
|
|
2665
|
+
} catch (error) {
|
|
2666
|
+
if (error.message?.includes("Script execution timed out")) {
|
|
2667
|
+
throw new Error("Tempo de execu\xE7\xE3o excedido (timeout)");
|
|
2668
|
+
}
|
|
2669
|
+
if (error.message?.includes("Isolate was disposed")) {
|
|
2670
|
+
throw new Error("Execu\xE7\xE3o cancelada: limite de mem\xF3ria excedido");
|
|
2671
|
+
}
|
|
2672
|
+
throw new Error(`Erro na execu\xE7\xE3o do c\xF3digo: ${error.message || "Erro desconhecido"}`);
|
|
2673
|
+
} finally {
|
|
2674
|
+
if (context) {
|
|
2675
|
+
try {
|
|
2676
|
+
context.release();
|
|
2677
|
+
} catch {
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
if (isolate) {
|
|
2681
|
+
try {
|
|
2682
|
+
isolate.dispose();
|
|
2683
|
+
} catch {
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
async function injectContextVariables(jail, ctx, ivm) {
|
|
2689
|
+
const safeClone = (value) => {
|
|
2690
|
+
if (value === void 0 || value === null) {
|
|
2691
|
+
return value;
|
|
2692
|
+
}
|
|
2693
|
+
try {
|
|
2694
|
+
if (typeof value !== "object") {
|
|
2695
|
+
return value;
|
|
2696
|
+
}
|
|
2697
|
+
return new ivm.ExternalCopy(value).copyInto();
|
|
2698
|
+
} catch {
|
|
2699
|
+
try {
|
|
2700
|
+
return JSON.parse(JSON.stringify(value));
|
|
2701
|
+
} catch {
|
|
2702
|
+
return void 0;
|
|
2703
|
+
}
|
|
2704
|
+
}
|
|
2705
|
+
};
|
|
2706
|
+
await jail.set("input", safeClone(ctx.input));
|
|
2707
|
+
await jail.set("context", safeClone(ctx.context ?? {}));
|
|
2708
|
+
await jail.set("$inputs", safeClone(ctx.$inputs ?? {}));
|
|
2709
|
+
await jail.set("$vars", safeClone(ctx.$vars ?? {}));
|
|
2710
|
+
await jail.set("$field", safeClone(ctx.$field ?? {}));
|
|
2711
|
+
await jail.set("request", safeClone(ctx.request));
|
|
2712
|
+
await jail.set("params", safeClone(ctx.params));
|
|
2713
|
+
await jail.set("__placeholders", safeClone(ctx.__placeholders ?? {}));
|
|
2714
|
+
}
|
|
2715
|
+
function wrapUserCode(code) {
|
|
2716
|
+
const trimmed = code.trim();
|
|
2717
|
+
if (trimmed.startsWith("return ")) {
|
|
2718
|
+
return `(async function() { ${code} })()`;
|
|
2719
|
+
}
|
|
2720
|
+
const isSimpleExpression = !trimmed.includes("{") && !trimmed.includes("if ") && !trimmed.includes("for ") && !trimmed.includes("while ") && !trimmed.includes("function ") && !trimmed.includes("const ") && !trimmed.includes("let ") && !trimmed.includes("var ");
|
|
2721
|
+
if (isSimpleExpression) {
|
|
2722
|
+
return `(async function() { return ${code} })()`;
|
|
2723
|
+
}
|
|
2724
|
+
return `(async function() { ${code} })()`;
|
|
2725
|
+
}
|
|
2726
|
+
function executeFallback(code, ctx) {
|
|
2727
|
+
console.warn("[Sandbox] Usando execu\xE7\xE3o INSEGURA (new Function). Instale isolated-vm para seguran\xE7a.");
|
|
2728
|
+
const customFunction = new Function(
|
|
2729
|
+
"input",
|
|
2730
|
+
"context",
|
|
2731
|
+
"request",
|
|
2732
|
+
"params",
|
|
2733
|
+
"$inputs",
|
|
2734
|
+
"$vars",
|
|
2735
|
+
"$field",
|
|
2736
|
+
"__placeholders",
|
|
2737
|
+
code
|
|
2738
|
+
);
|
|
2739
|
+
return customFunction(
|
|
2740
|
+
ctx.input,
|
|
2741
|
+
ctx.context,
|
|
2742
|
+
ctx.request,
|
|
2743
|
+
ctx.params,
|
|
2744
|
+
ctx.$inputs,
|
|
2745
|
+
ctx.$vars,
|
|
2746
|
+
ctx.$field,
|
|
2747
|
+
ctx.__placeholders
|
|
2748
|
+
);
|
|
2749
|
+
}
|
|
2750
|
+
function looksLikeCode(code) {
|
|
2751
|
+
if (typeof code !== "string") return false;
|
|
2752
|
+
const c = code.trim();
|
|
2753
|
+
if (c.length < 3) return false;
|
|
2754
|
+
return /(return\s+|=>|function\s*\(|;|\n|\{|\})/.test(c);
|
|
2755
|
+
}
|
|
2756
|
+
|
|
2394
2757
|
// src/nodes/processors/custom-code.ts
|
|
2395
|
-
var NodeFunction = (params) => {
|
|
2758
|
+
var NodeFunction = async (params) => {
|
|
2396
2759
|
let input = params?.inputValue ?? params?.input;
|
|
2397
2760
|
const context = params && params.fieldValues ? params.fieldValues : params || {};
|
|
2398
2761
|
let customCode = context?.customCode ?? params?.customCode;
|
|
@@ -2405,12 +2768,6 @@ var NodeFunction = (params) => {
|
|
|
2405
2768
|
else if (firstInputField.value !== void 0) input = firstInputField.value;
|
|
2406
2769
|
}
|
|
2407
2770
|
}
|
|
2408
|
-
const looksLikeCode = (code) => {
|
|
2409
|
-
if (typeof code !== "string") return false;
|
|
2410
|
-
const c = code.trim();
|
|
2411
|
-
if (c.length < 3) return false;
|
|
2412
|
-
return /(return\s+|=>|function\s*\(|;|\n|\{|\})/.test(c);
|
|
2413
|
-
};
|
|
2414
2771
|
if (typeof customCode === "string" && !looksLikeCode(customCode)) {
|
|
2415
2772
|
if (input === void 0) input = customCode;
|
|
2416
2773
|
customCode = "";
|
|
@@ -2418,18 +2775,25 @@ var NodeFunction = (params) => {
|
|
|
2418
2775
|
if (!customCode || typeof customCode === "string" && customCode.trim() === "") {
|
|
2419
2776
|
return input;
|
|
2420
2777
|
}
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2778
|
+
const sandboxContext = {
|
|
2779
|
+
input,
|
|
2780
|
+
context,
|
|
2781
|
+
$inputs: params?.results || {},
|
|
2782
|
+
$vars: context && context.variables || params?.variables || void 0,
|
|
2783
|
+
request: params?.request,
|
|
2784
|
+
params,
|
|
2785
|
+
__placeholders: params?.__codePlaceholders ?? context?.__codePlaceholders
|
|
2786
|
+
};
|
|
2787
|
+
const result = await executeSandboxed(customCode, sandboxContext, {
|
|
2788
|
+
timeout: 3e4,
|
|
2789
|
+
// 30 segundos
|
|
2790
|
+
memoryLimit: 128,
|
|
2791
|
+
// 128MB
|
|
2792
|
+
allowFetch: true
|
|
2793
|
+
});
|
|
2794
|
+
return result;
|
|
2431
2795
|
};
|
|
2432
|
-
var CustomNodeFunction = (params) => {
|
|
2796
|
+
var CustomNodeFunction = async (params) => {
|
|
2433
2797
|
const context = params && params.fieldValues ? params.fieldValues : params || {};
|
|
2434
2798
|
const customCode = context?.customCode;
|
|
2435
2799
|
if (!customCode || typeof customCode === "string" && customCode.trim() === "") {
|
|
@@ -2452,29 +2816,36 @@ var CustomNodeFunction = (params) => {
|
|
|
2452
2816
|
}
|
|
2453
2817
|
$field[fieldId] = value;
|
|
2454
2818
|
});
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2819
|
+
const sandboxContext = {
|
|
2820
|
+
$field,
|
|
2821
|
+
context,
|
|
2822
|
+
$inputs: params?.results || {},
|
|
2823
|
+
$vars: context && context.variables || params?.variables || void 0,
|
|
2824
|
+
request: params?.request,
|
|
2825
|
+
params
|
|
2826
|
+
};
|
|
2827
|
+
const result = await executeSandboxed(customCode, sandboxContext, {
|
|
2828
|
+
timeout: 3e4,
|
|
2829
|
+
// 30 segundos
|
|
2830
|
+
memoryLimit: 128,
|
|
2831
|
+
// 128MB
|
|
2832
|
+
allowFetch: true
|
|
2833
|
+
});
|
|
2834
|
+
return result;
|
|
2464
2835
|
};
|
|
2465
2836
|
var CustomCodeNode = {
|
|
2466
2837
|
label: "Custom Code",
|
|
2467
2838
|
type: "CustomCodeNode",
|
|
2468
2839
|
category: "step",
|
|
2469
2840
|
icon: "\u{1F4BB}",
|
|
2470
|
-
description: "Node para executar c\xF3digo JavaScript customizado",
|
|
2841
|
+
description: "Node para executar c\xF3digo JavaScript customizado (sandbox segura)",
|
|
2471
2842
|
fields: [
|
|
2472
2843
|
{
|
|
2473
2844
|
id: "customCode",
|
|
2474
2845
|
label: "C\xF3digo Customizado",
|
|
2475
2846
|
type: "code",
|
|
2476
2847
|
required: false,
|
|
2477
|
-
placeholder: '// Seu c\xF3digo JavaScript aqui\n// Use "input" para acessar o valor de entrada\n// Use "context" para acessar os dados do n\xF3\nreturn input;'
|
|
2848
|
+
placeholder: '// Seu c\xF3digo JavaScript aqui\n// Use "input" para acessar o valor de entrada\n// Use "context" para acessar os dados do n\xF3\n// fetch(), JSON, Math, Date est\xE3o dispon\xEDveis\nreturn input;'
|
|
2478
2849
|
},
|
|
2479
2850
|
{
|
|
2480
2851
|
id: "input",
|
|
@@ -2751,7 +3122,7 @@ var FunctionGuardrailNode = {
|
|
|
2751
3122
|
label: "Fun\xE7\xE3o",
|
|
2752
3123
|
name: "function",
|
|
2753
3124
|
fieldType: "function",
|
|
2754
|
-
acceptTypes: ["code", "http", "any"],
|
|
3125
|
+
acceptTypes: ["function", "code", "http", "any"],
|
|
2755
3126
|
maxConnections: 1
|
|
2756
3127
|
}
|
|
2757
3128
|
},
|
package/dist/index.d.cts
CHANGED
|
@@ -183,8 +183,8 @@ declare const nodeFunctions: {
|
|
|
183
183
|
AiSupervisorNode: (params: any) => Promise<any>;
|
|
184
184
|
WhatsappNode: (fieldValues: any) => Promise<any>;
|
|
185
185
|
WhatsappSendMessageNode: (fieldValues: any) => Promise<any>;
|
|
186
|
-
CustomCodeNode: (params: any) => any
|
|
187
|
-
CustomNode: (params: any) => any
|
|
186
|
+
CustomCodeNode: (params: any) => Promise<any>;
|
|
187
|
+
CustomNode: (params: any) => Promise<any>;
|
|
188
188
|
PostgresMemoryNode: (inputs: any) => Promise<any>;
|
|
189
189
|
RedisMemoryNode: (inputs: any) => Promise<any>;
|
|
190
190
|
PromptGuardrailNode: (inputs: any) => Promise<any>;
|
package/dist/index.d.ts
CHANGED
|
@@ -183,8 +183,8 @@ declare const nodeFunctions: {
|
|
|
183
183
|
AiSupervisorNode: (params: any) => Promise<any>;
|
|
184
184
|
WhatsappNode: (fieldValues: any) => Promise<any>;
|
|
185
185
|
WhatsappSendMessageNode: (fieldValues: any) => Promise<any>;
|
|
186
|
-
CustomCodeNode: (params: any) => any
|
|
187
|
-
CustomNode: (params: any) => any
|
|
186
|
+
CustomCodeNode: (params: any) => Promise<any>;
|
|
187
|
+
CustomNode: (params: any) => Promise<any>;
|
|
188
188
|
PostgresMemoryNode: (inputs: any) => Promise<any>;
|
|
189
189
|
RedisMemoryNode: (inputs: any) => Promise<any>;
|
|
190
190
|
PromptGuardrailNode: (inputs: any) => Promise<any>;
|
package/dist/index.js
CHANGED
|
@@ -1008,7 +1008,7 @@ async function createLLMFromModel(modelConfig, authToken, streaming = false) {
|
|
|
1008
1008
|
case "gemini":
|
|
1009
1009
|
return new ChatGoogle({
|
|
1010
1010
|
model: "gemini-flash-latest",
|
|
1011
|
-
apiKey: "
|
|
1011
|
+
apiKey: "AIzaSyAWj0Al2sVJ8vqaRN4UY7c6imAg7a3NbEc",
|
|
1012
1012
|
streaming
|
|
1013
1013
|
});
|
|
1014
1014
|
case "openai":
|
|
@@ -1034,6 +1034,50 @@ async function createLLMFromModel(modelConfig, authToken, streaming = false) {
|
|
|
1034
1034
|
}
|
|
1035
1035
|
|
|
1036
1036
|
// src/utils/guardrail-executor.ts
|
|
1037
|
+
async function loadChatHistory(context) {
|
|
1038
|
+
const checkpointer = context?.checkpointer;
|
|
1039
|
+
const sessionId = context?.sessionId;
|
|
1040
|
+
if (!checkpointer || !sessionId) {
|
|
1041
|
+
console.log(`[GUARDRAIL] checkpointer=${!!checkpointer}, sessionId=${sessionId}`);
|
|
1042
|
+
return null;
|
|
1043
|
+
}
|
|
1044
|
+
try {
|
|
1045
|
+
console.log(`[GUARDRAIL] Carregando hist\xF3rico da mem\xF3ria (session: ${sessionId})`);
|
|
1046
|
+
if (typeof checkpointer.setup === "function" && !checkpointer.isSetup) {
|
|
1047
|
+
await checkpointer.setup();
|
|
1048
|
+
}
|
|
1049
|
+
let checkpoint = null;
|
|
1050
|
+
if (typeof checkpointer.getTuple === "function") {
|
|
1051
|
+
const tuple = await checkpointer.getTuple({ configurable: { thread_id: sessionId } });
|
|
1052
|
+
checkpoint = tuple?.checkpoint;
|
|
1053
|
+
console.log(`[GUARDRAIL] getTuple result:`, tuple ? "found" : "null");
|
|
1054
|
+
}
|
|
1055
|
+
if (!checkpoint && typeof checkpointer.get === "function") {
|
|
1056
|
+
checkpoint = await checkpointer.get({ configurable: { thread_id: sessionId } });
|
|
1057
|
+
console.log(`[GUARDRAIL] get result:`, checkpoint ? "found" : "null");
|
|
1058
|
+
}
|
|
1059
|
+
if (!checkpoint) {
|
|
1060
|
+
console.log(`[GUARDRAIL] Nenhum checkpoint encontrado`);
|
|
1061
|
+
return null;
|
|
1062
|
+
}
|
|
1063
|
+
console.log(`[GUARDRAIL] Checkpoint keys:`, Object.keys(checkpoint));
|
|
1064
|
+
const messages = checkpoint?.channel_values?.messages || checkpoint?.values?.messages || checkpoint?.messages || [];
|
|
1065
|
+
if (!messages || messages.length === 0) {
|
|
1066
|
+
console.log(`[GUARDRAIL] Nenhuma mensagem no checkpoint`);
|
|
1067
|
+
return null;
|
|
1068
|
+
}
|
|
1069
|
+
const historyLines = messages.map((m) => {
|
|
1070
|
+
const role = m._getType?.() === "human" || m.type === "human" ? "Usu\xE1rio" : "Assistente";
|
|
1071
|
+
const content = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
|
|
1072
|
+
return `${role}: ${content.slice(0, 200)}${content.length > 200 ? "..." : ""}`;
|
|
1073
|
+
});
|
|
1074
|
+
console.log(`[GUARDRAIL] Hist\xF3rico carregado: ${messages.length} mensagens`);
|
|
1075
|
+
return historyLines.join("\n");
|
|
1076
|
+
} catch (error) {
|
|
1077
|
+
console.error(`[GUARDRAIL] Erro ao carregar hist\xF3rico:`, error);
|
|
1078
|
+
return null;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1037
1081
|
async function executeGuardrails(guardrails, content, mode = "fail-first", context = {}) {
|
|
1038
1082
|
const list = Array.isArray(guardrails) ? guardrails : [guardrails];
|
|
1039
1083
|
const result = {
|
|
@@ -1119,44 +1163,90 @@ async function executeGuardrails(guardrails, content, mode = "fail-first", conte
|
|
|
1119
1163
|
}
|
|
1120
1164
|
} else if (guard.type === "model") {
|
|
1121
1165
|
const { model, evaluationPrompt, name, actionInstruction } = guard;
|
|
1166
|
+
console.log(`[GUARDRAIL LLM] Iniciando guardrail "${name}"`);
|
|
1167
|
+
console.log(`[GUARDRAIL LLM] Conte\xFAdo a avaliar (${content.length} chars):`, content.slice(0, 200) + (content.length > 200 ? "..." : ""));
|
|
1168
|
+
console.log(`[GUARDRAIL LLM] Action: ${guard.action}, Model dispon\xEDvel: ${!!model}`);
|
|
1169
|
+
const chatHistory = await loadChatHistory(context);
|
|
1170
|
+
if (chatHistory) {
|
|
1171
|
+
console.log(`[GUARDRAIL LLM] Hist\xF3rico inclu\xEDdo no contexto`);
|
|
1172
|
+
}
|
|
1122
1173
|
if (model && typeof model.invoke === "function") {
|
|
1123
1174
|
try {
|
|
1124
1175
|
let prompt = evaluationPrompt;
|
|
1176
|
+
console.log(`[GUARDRAIL LLM] Evaluation prompt base:`, (prompt || "").slice(0, 200));
|
|
1125
1177
|
if (actionInstruction) {
|
|
1126
1178
|
prompt += `
|
|
1127
1179
|
|
|
1128
1180
|
INSTRU\xC7\xC3O ADICIONAL DE A\xC7\xC3O:
|
|
1129
1181
|
${actionInstruction}`;
|
|
1182
|
+
}
|
|
1183
|
+
if (chatHistory) {
|
|
1184
|
+
prompt += `
|
|
1185
|
+
|
|
1186
|
+
HIST\xD3RICO DA CONVERSA:
|
|
1187
|
+
${chatHistory}`;
|
|
1130
1188
|
}
|
|
1131
1189
|
if (prompt.includes("{{content}}")) {
|
|
1132
1190
|
prompt = prompt.replace("{{content}}", content);
|
|
1133
1191
|
} else {
|
|
1134
1192
|
prompt = `${prompt}
|
|
1135
1193
|
|
|
1136
|
-
CONTE\xDADO
|
|
1194
|
+
CONTE\xDADO A AVALIAR (resposta atual):
|
|
1137
1195
|
${content}`;
|
|
1138
1196
|
}
|
|
1197
|
+
console.log(`[GUARDRAIL LLM] Chamando modelo...`);
|
|
1139
1198
|
const response = await model.invoke(prompt);
|
|
1140
1199
|
const resultText = typeof response.content === "string" ? response.content : String(response.content);
|
|
1200
|
+
console.log(`[GUARDRAIL LLM] Resposta do modelo:`, resultText.slice(0, 300));
|
|
1201
|
+
const isUnsafe = resultText.toUpperCase().includes("UNSAFE");
|
|
1202
|
+
const isSafe = resultText.toUpperCase().startsWith("SAFE") || resultText.toUpperCase().includes("SAFE") && !isUnsafe;
|
|
1141
1203
|
if (guard.action === "fix") {
|
|
1142
|
-
if (
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1204
|
+
if (isUnsafe) {
|
|
1205
|
+
console.log(`[GUARDRAIL LLM] Modo FIX - Detectado UNSAFE, chamando modelo para corrigir...`);
|
|
1206
|
+
const fixPrompt = `Voc\xEA \xE9 um corretor de conte\xFAdo. O texto abaixo foi marcado como UNSAFE por violar uma regra.
|
|
1207
|
+
|
|
1208
|
+
REGRA VIOLADA:
|
|
1209
|
+
${evaluationPrompt}
|
|
1210
|
+
|
|
1211
|
+
${actionInstruction ? `INSTRU\xC7\xC3O DE CORRE\xC7\xC3O:
|
|
1212
|
+
${actionInstruction}
|
|
1213
|
+
` : ""}
|
|
1214
|
+
|
|
1215
|
+
CONTE\xDADO ORIGINAL:
|
|
1216
|
+
${content}
|
|
1217
|
+
|
|
1218
|
+
Reescreva o conte\xFAdo corrigindo a viola\xE7\xE3o. Retorne APENAS o texto corrigido, sem explica\xE7\xF5es ou prefixos.`;
|
|
1219
|
+
try {
|
|
1220
|
+
const fixResponse = await model.invoke(fixPrompt);
|
|
1221
|
+
const fixedContent = typeof fixResponse.content === "string" ? fixResponse.content : String(fixResponse.content);
|
|
1222
|
+
console.log(`[GUARDRAIL LLM] Conte\xFAdo corrigido:`, fixedContent.slice(0, 300));
|
|
1223
|
+
result.modifiedContent = fixedContent;
|
|
1224
|
+
violationMessage = `Conte\xFAdo reescrito pelo guardrail "${name}".`;
|
|
1225
|
+
result.violations.push({
|
|
1226
|
+
name: guard.name,
|
|
1227
|
+
message: violationMessage,
|
|
1228
|
+
action: "fix"
|
|
1229
|
+
});
|
|
1230
|
+
} catch (fixError) {
|
|
1231
|
+
console.error(`[GUARDRAIL LLM] Erro ao corrigir conte\xFAdo:`, fixError);
|
|
1232
|
+
}
|
|
1233
|
+
} else {
|
|
1234
|
+
console.log(`[GUARDRAIL LLM] Modo FIX - Conte\xFAdo aprovado (SAFE)`);
|
|
1150
1235
|
}
|
|
1151
1236
|
} else {
|
|
1152
|
-
if (
|
|
1237
|
+
if (isUnsafe) {
|
|
1153
1238
|
guardPassed = false;
|
|
1154
1239
|
violationMessage = actionInstruction || `Modelo de avalia\xE7\xE3o "${name}" detectou viola\xE7\xE3o de seguran\xE7a/pol\xEDtica.`;
|
|
1240
|
+
console.log(`[GUARDRAIL LLM] Resultado: UNSAFE - Bloqueado`);
|
|
1241
|
+
} else {
|
|
1242
|
+
console.log(`[GUARDRAIL LLM] Resultado: SAFE - Aprovado`);
|
|
1155
1243
|
}
|
|
1156
1244
|
}
|
|
1157
1245
|
} catch (error) {
|
|
1158
|
-
console.error(`
|
|
1246
|
+
console.error(`[GUARDRAIL LLM] Erro ao executar guardrail "${name}":`, error);
|
|
1159
1247
|
}
|
|
1248
|
+
} else {
|
|
1249
|
+
console.log(`[GUARDRAIL LLM] Model n\xE3o dispon\xEDvel ou n\xE3o \xE9 invoc\xE1vel para guardrail "${name}"`);
|
|
1160
1250
|
}
|
|
1161
1251
|
}
|
|
1162
1252
|
if (!guardPassed) {
|
|
@@ -1220,7 +1310,7 @@ var IaAgentNodeFunction = async (inputs) => {
|
|
|
1220
1310
|
let guardrailViolations = [];
|
|
1221
1311
|
if (message && beforeGuardrails) {
|
|
1222
1312
|
const preparedBefore = await prepareGuardrails(beforeGuardrails);
|
|
1223
|
-
const context = { ...inputs, input: message };
|
|
1313
|
+
const context = { ...inputs, input: message, checkpointer, sessionId };
|
|
1224
1314
|
const beforeResults = await executeGuardrails(preparedBefore, message, guardrailMode, context);
|
|
1225
1315
|
if (beforeResults.blocked) {
|
|
1226
1316
|
console.log(`\u{1F6E1}\uFE0F IaAgentNode "${name}": Blocked by before-agent guardrail:`, beforeResults.message);
|
|
@@ -1422,7 +1512,7 @@ IMPORTANT: You must base your response on the last message in the conversation h
|
|
|
1422
1512
|
}
|
|
1423
1513
|
if (output && afterGuardrails) {
|
|
1424
1514
|
const preparedAfter = await prepareGuardrails(afterGuardrails);
|
|
1425
|
-
const context = { ...inputs, input: output };
|
|
1515
|
+
const context = { ...inputs, input: output, checkpointer, sessionId };
|
|
1426
1516
|
const afterResults = await executeGuardrails(preparedAfter, output, guardrailMode, context);
|
|
1427
1517
|
if (afterResults.blocked) {
|
|
1428
1518
|
console.log(`\u{1F6E1}\uFE0F IaAgentNode "${name}": Response blocked by after-agent guardrail:`, afterResults.message);
|
|
@@ -2311,8 +2401,271 @@ var WhatsappMessageTriggerNode = {
|
|
|
2311
2401
|
]
|
|
2312
2402
|
};
|
|
2313
2403
|
|
|
2404
|
+
// src/utils/sandbox-executor.ts
|
|
2405
|
+
var ivmModule = null;
|
|
2406
|
+
async function getIVM() {
|
|
2407
|
+
if (ivmModule !== null) return ivmModule;
|
|
2408
|
+
try {
|
|
2409
|
+
const mod = await import("isolated-vm");
|
|
2410
|
+
ivmModule = {
|
|
2411
|
+
Isolate: mod.Isolate || mod.default?.Isolate,
|
|
2412
|
+
ExternalCopy: mod.ExternalCopy || mod.default?.ExternalCopy,
|
|
2413
|
+
Reference: mod.Reference || mod.default?.Reference
|
|
2414
|
+
};
|
|
2415
|
+
if (!ivmModule.Isolate) {
|
|
2416
|
+
console.warn("[Sandbox] isolated-vm Isolate n\xE3o encontrado");
|
|
2417
|
+
return null;
|
|
2418
|
+
}
|
|
2419
|
+
return ivmModule;
|
|
2420
|
+
} catch (e) {
|
|
2421
|
+
console.warn("[Sandbox] isolated-vm n\xE3o dispon\xEDvel, usando fallback inseguro");
|
|
2422
|
+
return null;
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
var DEFAULT_OPTIONS = {
|
|
2426
|
+
timeout: 1e4,
|
|
2427
|
+
memoryLimit: 128,
|
|
2428
|
+
allowFetch: true
|
|
2429
|
+
};
|
|
2430
|
+
async function executeSandboxed(code, sandboxContext, options = {}) {
|
|
2431
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
2432
|
+
const ivm = await getIVM();
|
|
2433
|
+
if (!ivm) {
|
|
2434
|
+
return executeFallback(code, sandboxContext);
|
|
2435
|
+
}
|
|
2436
|
+
let isolate = null;
|
|
2437
|
+
let context = null;
|
|
2438
|
+
try {
|
|
2439
|
+
isolate = new ivm.Isolate({ memoryLimit: opts.memoryLimit });
|
|
2440
|
+
context = await isolate.createContext();
|
|
2441
|
+
const jail = context.global;
|
|
2442
|
+
await jail.set("globalThis", jail.derefInto());
|
|
2443
|
+
await injectContextVariables(jail, sandboxContext, ivm);
|
|
2444
|
+
await jail.set("__logRef", new ivm.Reference(function(...args) {
|
|
2445
|
+
console.log("[Sandbox]", ...args);
|
|
2446
|
+
}));
|
|
2447
|
+
if (opts.allowFetch) {
|
|
2448
|
+
await jail.set("__fetchRef", new ivm.Reference(async function(url, optionsJson) {
|
|
2449
|
+
try {
|
|
2450
|
+
const options2 = optionsJson ? JSON.parse(optionsJson) : {};
|
|
2451
|
+
const res = await fetch(url, {
|
|
2452
|
+
method: options2?.method || "GET",
|
|
2453
|
+
headers: options2?.headers,
|
|
2454
|
+
body: options2?.body
|
|
2455
|
+
});
|
|
2456
|
+
const contentType = res.headers.get("content-type") || "";
|
|
2457
|
+
let data;
|
|
2458
|
+
if (contentType.includes("application/json")) {
|
|
2459
|
+
data = await res.json();
|
|
2460
|
+
} else {
|
|
2461
|
+
data = await res.text();
|
|
2462
|
+
}
|
|
2463
|
+
return JSON.stringify({
|
|
2464
|
+
ok: res.ok,
|
|
2465
|
+
status: res.status,
|
|
2466
|
+
statusText: res.statusText,
|
|
2467
|
+
data
|
|
2468
|
+
});
|
|
2469
|
+
} catch (error) {
|
|
2470
|
+
return JSON.stringify({
|
|
2471
|
+
ok: false,
|
|
2472
|
+
status: 0,
|
|
2473
|
+
statusText: "Network Error",
|
|
2474
|
+
error: error.message
|
|
2475
|
+
});
|
|
2476
|
+
}
|
|
2477
|
+
}));
|
|
2478
|
+
}
|
|
2479
|
+
const bootstrapCode = `
|
|
2480
|
+
// Console
|
|
2481
|
+
const console = {
|
|
2482
|
+
log: (...args) => __logRef.applySync(undefined, args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a))),
|
|
2483
|
+
warn: (...args) => __logRef.applySync(undefined, ['[WARN]', ...args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a))]),
|
|
2484
|
+
error: (...args) => __logRef.applySync(undefined, ['[ERROR]', ...args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a))]),
|
|
2485
|
+
info: (...args) => __logRef.applySync(undefined, args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a))),
|
|
2486
|
+
};
|
|
2487
|
+
globalThis.console = console;
|
|
2488
|
+
|
|
2489
|
+
${opts.allowFetch ? `
|
|
2490
|
+
// Fetch
|
|
2491
|
+
globalThis.fetch = async (url, options = {}) => {
|
|
2492
|
+
const optionsJson = JSON.stringify(options);
|
|
2493
|
+
const resultJson = await __fetchRef.apply(undefined, [url, optionsJson], { result: { promise: true } });
|
|
2494
|
+
const result = JSON.parse(resultJson);
|
|
2495
|
+
|
|
2496
|
+
if (!result.ok && result.error) {
|
|
2497
|
+
throw new Error(result.error);
|
|
2498
|
+
}
|
|
2499
|
+
|
|
2500
|
+
return {
|
|
2501
|
+
ok: result.ok,
|
|
2502
|
+
status: result.status,
|
|
2503
|
+
statusText: result.statusText,
|
|
2504
|
+
json: async () => result.data,
|
|
2505
|
+
text: async () => typeof result.data === 'string' ? result.data : JSON.stringify(result.data),
|
|
2506
|
+
};
|
|
2507
|
+
};
|
|
2508
|
+
` : ""}
|
|
2509
|
+
|
|
2510
|
+
// Base64
|
|
2511
|
+
globalThis.atob = (str) => {
|
|
2512
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
|
2513
|
+
let output = '';
|
|
2514
|
+
str = String(str).replace(/=+$/, '');
|
|
2515
|
+
for (let i = 0; i < str.length; i += 4) {
|
|
2516
|
+
const enc1 = chars.indexOf(str.charAt(i));
|
|
2517
|
+
const enc2 = chars.indexOf(str.charAt(i + 1));
|
|
2518
|
+
const enc3 = chars.indexOf(str.charAt(i + 2));
|
|
2519
|
+
const enc4 = chars.indexOf(str.charAt(i + 3));
|
|
2520
|
+
const chr1 = (enc1 << 2) | (enc2 >> 4);
|
|
2521
|
+
const chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
|
2522
|
+
const chr3 = ((enc3 & 3) << 6) | enc4;
|
|
2523
|
+
output += String.fromCharCode(chr1);
|
|
2524
|
+
if (enc3 !== 64) output += String.fromCharCode(chr2);
|
|
2525
|
+
if (enc4 !== 64) output += String.fromCharCode(chr3);
|
|
2526
|
+
}
|
|
2527
|
+
return output;
|
|
2528
|
+
};
|
|
2529
|
+
|
|
2530
|
+
globalThis.btoa = (str) => {
|
|
2531
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
|
2532
|
+
str = String(str);
|
|
2533
|
+
let output = '';
|
|
2534
|
+
for (let i = 0; i < str.length; i += 3) {
|
|
2535
|
+
const chr1 = str.charCodeAt(i);
|
|
2536
|
+
const chr2 = str.charCodeAt(i + 1);
|
|
2537
|
+
const chr3 = str.charCodeAt(i + 2);
|
|
2538
|
+
const enc1 = chr1 >> 2;
|
|
2539
|
+
const enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
|
2540
|
+
const enc3 = isNaN(chr2) ? 64 : ((chr2 & 15) << 2) | (chr3 >> 6);
|
|
2541
|
+
const enc4 = isNaN(chr3) ? 64 : chr3 & 63;
|
|
2542
|
+
output += chars.charAt(enc1) + chars.charAt(enc2) + chars.charAt(enc3) + chars.charAt(enc4);
|
|
2543
|
+
}
|
|
2544
|
+
return output;
|
|
2545
|
+
};
|
|
2546
|
+
`;
|
|
2547
|
+
const bootstrapScript = await isolate.compileScript(bootstrapCode);
|
|
2548
|
+
await bootstrapScript.run(context);
|
|
2549
|
+
const wrappedCode = wrapUserCode(code);
|
|
2550
|
+
const finalCode = `
|
|
2551
|
+
(async () => {
|
|
2552
|
+
const __userResult = await (${wrappedCode});
|
|
2553
|
+
// Serializa o resultado para poder transferir
|
|
2554
|
+
if (__userResult === undefined) return '__UNDEFINED__';
|
|
2555
|
+
if (__userResult === null) return 'null';
|
|
2556
|
+
if (typeof __userResult === 'object') {
|
|
2557
|
+
return JSON.stringify({ __type: 'object', value: __userResult });
|
|
2558
|
+
}
|
|
2559
|
+
return JSON.stringify({ __type: typeof __userResult, value: __userResult });
|
|
2560
|
+
})()
|
|
2561
|
+
`;
|
|
2562
|
+
const script = await isolate.compileScript(finalCode);
|
|
2563
|
+
const rawResult = await script.run(context, {
|
|
2564
|
+
timeout: opts.timeout,
|
|
2565
|
+
promise: true
|
|
2566
|
+
});
|
|
2567
|
+
if (rawResult === "__UNDEFINED__") return void 0;
|
|
2568
|
+
if (rawResult === "null") return null;
|
|
2569
|
+
try {
|
|
2570
|
+
const parsed = JSON.parse(rawResult);
|
|
2571
|
+
return parsed.value;
|
|
2572
|
+
} catch {
|
|
2573
|
+
return rawResult;
|
|
2574
|
+
}
|
|
2575
|
+
} catch (error) {
|
|
2576
|
+
if (error.message?.includes("Script execution timed out")) {
|
|
2577
|
+
throw new Error("Tempo de execu\xE7\xE3o excedido (timeout)");
|
|
2578
|
+
}
|
|
2579
|
+
if (error.message?.includes("Isolate was disposed")) {
|
|
2580
|
+
throw new Error("Execu\xE7\xE3o cancelada: limite de mem\xF3ria excedido");
|
|
2581
|
+
}
|
|
2582
|
+
throw new Error(`Erro na execu\xE7\xE3o do c\xF3digo: ${error.message || "Erro desconhecido"}`);
|
|
2583
|
+
} finally {
|
|
2584
|
+
if (context) {
|
|
2585
|
+
try {
|
|
2586
|
+
context.release();
|
|
2587
|
+
} catch {
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
if (isolate) {
|
|
2591
|
+
try {
|
|
2592
|
+
isolate.dispose();
|
|
2593
|
+
} catch {
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
async function injectContextVariables(jail, ctx, ivm) {
|
|
2599
|
+
const safeClone = (value) => {
|
|
2600
|
+
if (value === void 0 || value === null) {
|
|
2601
|
+
return value;
|
|
2602
|
+
}
|
|
2603
|
+
try {
|
|
2604
|
+
if (typeof value !== "object") {
|
|
2605
|
+
return value;
|
|
2606
|
+
}
|
|
2607
|
+
return new ivm.ExternalCopy(value).copyInto();
|
|
2608
|
+
} catch {
|
|
2609
|
+
try {
|
|
2610
|
+
return JSON.parse(JSON.stringify(value));
|
|
2611
|
+
} catch {
|
|
2612
|
+
return void 0;
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
};
|
|
2616
|
+
await jail.set("input", safeClone(ctx.input));
|
|
2617
|
+
await jail.set("context", safeClone(ctx.context ?? {}));
|
|
2618
|
+
await jail.set("$inputs", safeClone(ctx.$inputs ?? {}));
|
|
2619
|
+
await jail.set("$vars", safeClone(ctx.$vars ?? {}));
|
|
2620
|
+
await jail.set("$field", safeClone(ctx.$field ?? {}));
|
|
2621
|
+
await jail.set("request", safeClone(ctx.request));
|
|
2622
|
+
await jail.set("params", safeClone(ctx.params));
|
|
2623
|
+
await jail.set("__placeholders", safeClone(ctx.__placeholders ?? {}));
|
|
2624
|
+
}
|
|
2625
|
+
function wrapUserCode(code) {
|
|
2626
|
+
const trimmed = code.trim();
|
|
2627
|
+
if (trimmed.startsWith("return ")) {
|
|
2628
|
+
return `(async function() { ${code} })()`;
|
|
2629
|
+
}
|
|
2630
|
+
const isSimpleExpression = !trimmed.includes("{") && !trimmed.includes("if ") && !trimmed.includes("for ") && !trimmed.includes("while ") && !trimmed.includes("function ") && !trimmed.includes("const ") && !trimmed.includes("let ") && !trimmed.includes("var ");
|
|
2631
|
+
if (isSimpleExpression) {
|
|
2632
|
+
return `(async function() { return ${code} })()`;
|
|
2633
|
+
}
|
|
2634
|
+
return `(async function() { ${code} })()`;
|
|
2635
|
+
}
|
|
2636
|
+
function executeFallback(code, ctx) {
|
|
2637
|
+
console.warn("[Sandbox] Usando execu\xE7\xE3o INSEGURA (new Function). Instale isolated-vm para seguran\xE7a.");
|
|
2638
|
+
const customFunction = new Function(
|
|
2639
|
+
"input",
|
|
2640
|
+
"context",
|
|
2641
|
+
"request",
|
|
2642
|
+
"params",
|
|
2643
|
+
"$inputs",
|
|
2644
|
+
"$vars",
|
|
2645
|
+
"$field",
|
|
2646
|
+
"__placeholders",
|
|
2647
|
+
code
|
|
2648
|
+
);
|
|
2649
|
+
return customFunction(
|
|
2650
|
+
ctx.input,
|
|
2651
|
+
ctx.context,
|
|
2652
|
+
ctx.request,
|
|
2653
|
+
ctx.params,
|
|
2654
|
+
ctx.$inputs,
|
|
2655
|
+
ctx.$vars,
|
|
2656
|
+
ctx.$field,
|
|
2657
|
+
ctx.__placeholders
|
|
2658
|
+
);
|
|
2659
|
+
}
|
|
2660
|
+
function looksLikeCode(code) {
|
|
2661
|
+
if (typeof code !== "string") return false;
|
|
2662
|
+
const c = code.trim();
|
|
2663
|
+
if (c.length < 3) return false;
|
|
2664
|
+
return /(return\s+|=>|function\s*\(|;|\n|\{|\})/.test(c);
|
|
2665
|
+
}
|
|
2666
|
+
|
|
2314
2667
|
// src/nodes/processors/custom-code.ts
|
|
2315
|
-
var NodeFunction = (params) => {
|
|
2668
|
+
var NodeFunction = async (params) => {
|
|
2316
2669
|
let input = params?.inputValue ?? params?.input;
|
|
2317
2670
|
const context = params && params.fieldValues ? params.fieldValues : params || {};
|
|
2318
2671
|
let customCode = context?.customCode ?? params?.customCode;
|
|
@@ -2325,12 +2678,6 @@ var NodeFunction = (params) => {
|
|
|
2325
2678
|
else if (firstInputField.value !== void 0) input = firstInputField.value;
|
|
2326
2679
|
}
|
|
2327
2680
|
}
|
|
2328
|
-
const looksLikeCode = (code) => {
|
|
2329
|
-
if (typeof code !== "string") return false;
|
|
2330
|
-
const c = code.trim();
|
|
2331
|
-
if (c.length < 3) return false;
|
|
2332
|
-
return /(return\s+|=>|function\s*\(|;|\n|\{|\})/.test(c);
|
|
2333
|
-
};
|
|
2334
2681
|
if (typeof customCode === "string" && !looksLikeCode(customCode)) {
|
|
2335
2682
|
if (input === void 0) input = customCode;
|
|
2336
2683
|
customCode = "";
|
|
@@ -2338,18 +2685,25 @@ var NodeFunction = (params) => {
|
|
|
2338
2685
|
if (!customCode || typeof customCode === "string" && customCode.trim() === "") {
|
|
2339
2686
|
return input;
|
|
2340
2687
|
}
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2688
|
+
const sandboxContext = {
|
|
2689
|
+
input,
|
|
2690
|
+
context,
|
|
2691
|
+
$inputs: params?.results || {},
|
|
2692
|
+
$vars: context && context.variables || params?.variables || void 0,
|
|
2693
|
+
request: params?.request,
|
|
2694
|
+
params,
|
|
2695
|
+
__placeholders: params?.__codePlaceholders ?? context?.__codePlaceholders
|
|
2696
|
+
};
|
|
2697
|
+
const result = await executeSandboxed(customCode, sandboxContext, {
|
|
2698
|
+
timeout: 3e4,
|
|
2699
|
+
// 30 segundos
|
|
2700
|
+
memoryLimit: 128,
|
|
2701
|
+
// 128MB
|
|
2702
|
+
allowFetch: true
|
|
2703
|
+
});
|
|
2704
|
+
return result;
|
|
2351
2705
|
};
|
|
2352
|
-
var CustomNodeFunction = (params) => {
|
|
2706
|
+
var CustomNodeFunction = async (params) => {
|
|
2353
2707
|
const context = params && params.fieldValues ? params.fieldValues : params || {};
|
|
2354
2708
|
const customCode = context?.customCode;
|
|
2355
2709
|
if (!customCode || typeof customCode === "string" && customCode.trim() === "") {
|
|
@@ -2372,29 +2726,36 @@ var CustomNodeFunction = (params) => {
|
|
|
2372
2726
|
}
|
|
2373
2727
|
$field[fieldId] = value;
|
|
2374
2728
|
});
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2729
|
+
const sandboxContext = {
|
|
2730
|
+
$field,
|
|
2731
|
+
context,
|
|
2732
|
+
$inputs: params?.results || {},
|
|
2733
|
+
$vars: context && context.variables || params?.variables || void 0,
|
|
2734
|
+
request: params?.request,
|
|
2735
|
+
params
|
|
2736
|
+
};
|
|
2737
|
+
const result = await executeSandboxed(customCode, sandboxContext, {
|
|
2738
|
+
timeout: 3e4,
|
|
2739
|
+
// 30 segundos
|
|
2740
|
+
memoryLimit: 128,
|
|
2741
|
+
// 128MB
|
|
2742
|
+
allowFetch: true
|
|
2743
|
+
});
|
|
2744
|
+
return result;
|
|
2384
2745
|
};
|
|
2385
2746
|
var CustomCodeNode = {
|
|
2386
2747
|
label: "Custom Code",
|
|
2387
2748
|
type: "CustomCodeNode",
|
|
2388
2749
|
category: "step",
|
|
2389
2750
|
icon: "\u{1F4BB}",
|
|
2390
|
-
description: "Node para executar c\xF3digo JavaScript customizado",
|
|
2751
|
+
description: "Node para executar c\xF3digo JavaScript customizado (sandbox segura)",
|
|
2391
2752
|
fields: [
|
|
2392
2753
|
{
|
|
2393
2754
|
id: "customCode",
|
|
2394
2755
|
label: "C\xF3digo Customizado",
|
|
2395
2756
|
type: "code",
|
|
2396
2757
|
required: false,
|
|
2397
|
-
placeholder: '// Seu c\xF3digo JavaScript aqui\n// Use "input" para acessar o valor de entrada\n// Use "context" para acessar os dados do n\xF3\nreturn input;'
|
|
2758
|
+
placeholder: '// Seu c\xF3digo JavaScript aqui\n// Use "input" para acessar o valor de entrada\n// Use "context" para acessar os dados do n\xF3\n// fetch(), JSON, Math, Date est\xE3o dispon\xEDveis\nreturn input;'
|
|
2398
2759
|
},
|
|
2399
2760
|
{
|
|
2400
2761
|
id: "input",
|
|
@@ -2671,7 +3032,7 @@ var FunctionGuardrailNode = {
|
|
|
2671
3032
|
label: "Fun\xE7\xE3o",
|
|
2672
3033
|
name: "function",
|
|
2673
3034
|
fieldType: "function",
|
|
2674
|
-
acceptTypes: ["code", "http", "any"],
|
|
3035
|
+
acceptTypes: ["function", "code", "http", "any"],
|
|
2675
3036
|
maxConnections: 1
|
|
2676
3037
|
}
|
|
2677
3038
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atomoz/workflows-nodes",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.27",
|
|
4
4
|
"description": "Atomoz Workflows - Node Library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@langchain/core": "^0.3.66",
|
|
43
|
+
"isolated-vm": "^6.0.2",
|
|
43
44
|
"@langchain/google-gauth": "^0.2.16",
|
|
44
45
|
"@langchain/langgraph": "^0.4.3",
|
|
45
46
|
"@langchain/langgraph-checkpoint-postgres": "^1.0.0",
|