@atomoz/workflows-nodes 0.1.26 → 0.1.28

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 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
@@ -26,7 +36,13 @@ __export(index_exports, {
26
36
  AiToolNodeFunction: () => AiToolNodeFunction,
27
37
  AiToolNodeSchema: () => AiToolNodeSchema,
28
38
  BodyFieldSchema: () => BodyFieldSchema,
39
+ ChatLogNode: () => ChatLogNode,
40
+ ChatLogNodeFunction: () => ChatLogNodeFunction,
41
+ ChatLogSchema: () => ChatLogSchema,
29
42
  CustomToolSchema: () => CustomToolSchema,
43
+ GetOrCreateThreadNode: () => GetOrCreateThreadNode,
44
+ GetOrCreateThreadNodeFunction: () => GetOrCreateThreadNodeFunction,
45
+ GetOrCreateThreadSchema: () => GetOrCreateThreadSchema,
30
46
  HTTP_METHODS: () => HTTP_METHODS,
31
47
  HTTP_NODE_TYPES: () => HTTP_NODE_TYPES,
32
48
  HeaderSchema: () => HeaderSchema,
@@ -1088,7 +1104,7 @@ async function createLLMFromModel(modelConfig, authToken, streaming = false) {
1088
1104
  case "gemini":
1089
1105
  return new import_google_gauth.ChatGoogle({
1090
1106
  model: "gemini-flash-latest",
1091
- apiKey: "AIzaSyBzrL8Hx6dHhXgwc2HfLlQsf5Y-9pdtc9M",
1107
+ apiKey: "AIzaSyAWj0Al2sVJ8vqaRN4UY7c6imAg7a3NbEc",
1092
1108
  streaming
1093
1109
  });
1094
1110
  case "openai":
@@ -1114,6 +1130,62 @@ async function createLLMFromModel(modelConfig, authToken, streaming = false) {
1114
1130
  }
1115
1131
 
1116
1132
  // src/utils/guardrail-executor.ts
1133
+ function emitGuardrailEvent(context, name, passed, action, details) {
1134
+ if (context?.emitter?.emitThought) {
1135
+ context.emitter.emitThought({
1136
+ content: `guardrail:${passed ? "passed" : "failed"}:${name}`,
1137
+ type: "guardrail",
1138
+ name,
1139
+ passed,
1140
+ action: action || "evaluate",
1141
+ details
1142
+ });
1143
+ }
1144
+ }
1145
+ async function loadChatHistory(context) {
1146
+ const checkpointer = context?.checkpointer;
1147
+ const sessionId = context?.sessionId;
1148
+ if (!checkpointer || !sessionId) {
1149
+ console.log(`[GUARDRAIL] checkpointer=${!!checkpointer}, sessionId=${sessionId}`);
1150
+ return null;
1151
+ }
1152
+ try {
1153
+ console.log(`[GUARDRAIL] Carregando hist\xF3rico da mem\xF3ria (session: ${sessionId})`);
1154
+ if (typeof checkpointer.setup === "function" && !checkpointer.isSetup) {
1155
+ await checkpointer.setup();
1156
+ }
1157
+ let checkpoint = null;
1158
+ if (typeof checkpointer.getTuple === "function") {
1159
+ const tuple = await checkpointer.getTuple({ configurable: { thread_id: sessionId } });
1160
+ checkpoint = tuple?.checkpoint;
1161
+ console.log(`[GUARDRAIL] getTuple result:`, tuple ? "found" : "null");
1162
+ }
1163
+ if (!checkpoint && typeof checkpointer.get === "function") {
1164
+ checkpoint = await checkpointer.get({ configurable: { thread_id: sessionId } });
1165
+ console.log(`[GUARDRAIL] get result:`, checkpoint ? "found" : "null");
1166
+ }
1167
+ if (!checkpoint) {
1168
+ console.log(`[GUARDRAIL] Nenhum checkpoint encontrado`);
1169
+ return null;
1170
+ }
1171
+ console.log(`[GUARDRAIL] Checkpoint keys:`, Object.keys(checkpoint));
1172
+ const messages = checkpoint?.channel_values?.messages || checkpoint?.values?.messages || checkpoint?.messages || [];
1173
+ if (!messages || messages.length === 0) {
1174
+ console.log(`[GUARDRAIL] Nenhuma mensagem no checkpoint`);
1175
+ return null;
1176
+ }
1177
+ const historyLines = messages.map((m) => {
1178
+ const role = m._getType?.() === "human" || m.type === "human" ? "Usu\xE1rio" : "Assistente";
1179
+ const content = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
1180
+ return `${role}: ${content.slice(0, 200)}${content.length > 200 ? "..." : ""}`;
1181
+ });
1182
+ console.log(`[GUARDRAIL] Hist\xF3rico carregado: ${messages.length} mensagens`);
1183
+ return historyLines.join("\n");
1184
+ } catch (error) {
1185
+ console.error(`[GUARDRAIL] Erro ao carregar hist\xF3rico:`, error);
1186
+ return null;
1187
+ }
1188
+ }
1117
1189
  async function executeGuardrails(guardrails, content, mode = "fail-first", context = {}) {
1118
1190
  const list = Array.isArray(guardrails) ? guardrails : [guardrails];
1119
1191
  const result = {
@@ -1164,6 +1236,7 @@ async function executeGuardrails(guardrails, content, mode = "fail-first", conte
1164
1236
  if (!guardPassed && actionInstruction) {
1165
1237
  violationMessage = actionInstruction;
1166
1238
  }
1239
+ emitGuardrailEvent(context, guard.name, guardPassed, guard.action, violationMessage || "Rule passed");
1167
1240
  } else if (guard.type === "function") {
1168
1241
  const { nodeFunction, name, actionInstruction } = guard;
1169
1242
  if (typeof nodeFunction === "function") {
@@ -1196,47 +1269,97 @@ async function executeGuardrails(guardrails, content, mode = "fail-first", conte
1196
1269
  guardPassed = false;
1197
1270
  violationMessage = `Erro na fun\xE7\xE3o guardrail: ${error instanceof Error ? error.message : String(error)}`;
1198
1271
  }
1272
+ emitGuardrailEvent(context, name, guardPassed, guard.action, violationMessage || "Function passed");
1199
1273
  }
1200
1274
  } else if (guard.type === "model") {
1201
1275
  const { model, evaluationPrompt, name, actionInstruction } = guard;
1276
+ console.log(`[GUARDRAIL LLM] Iniciando guardrail "${name}"`);
1277
+ console.log(`[GUARDRAIL LLM] Conte\xFAdo a avaliar (${content.length} chars):`, content.slice(0, 200) + (content.length > 200 ? "..." : ""));
1278
+ console.log(`[GUARDRAIL LLM] Action: ${guard.action}, Model dispon\xEDvel: ${!!model}`);
1279
+ const chatHistory = await loadChatHistory(context);
1280
+ if (chatHistory) {
1281
+ console.log(`[GUARDRAIL LLM] Hist\xF3rico inclu\xEDdo no contexto`);
1282
+ }
1202
1283
  if (model && typeof model.invoke === "function") {
1203
1284
  try {
1204
1285
  let prompt = evaluationPrompt;
1286
+ console.log(`[GUARDRAIL LLM] Evaluation prompt base:`, (prompt || "").slice(0, 200));
1205
1287
  if (actionInstruction) {
1206
1288
  prompt += `
1207
1289
 
1208
1290
  INSTRU\xC7\xC3O ADICIONAL DE A\xC7\xC3O:
1209
1291
  ${actionInstruction}`;
1292
+ }
1293
+ if (chatHistory) {
1294
+ prompt += `
1295
+
1296
+ HIST\xD3RICO DA CONVERSA:
1297
+ ${chatHistory}`;
1210
1298
  }
1211
1299
  if (prompt.includes("{{content}}")) {
1212
1300
  prompt = prompt.replace("{{content}}", content);
1213
1301
  } else {
1214
1302
  prompt = `${prompt}
1215
1303
 
1216
- CONTE\xDADO PARA AVALIAR:
1304
+ CONTE\xDADO A AVALIAR (resposta atual):
1217
1305
  ${content}`;
1218
1306
  }
1307
+ console.log(`[GUARDRAIL LLM] Chamando modelo...`);
1219
1308
  const response = await model.invoke(prompt);
1220
1309
  const resultText = typeof response.content === "string" ? response.content : String(response.content);
1310
+ console.log(`[GUARDRAIL LLM] Resposta do modelo:`, resultText.slice(0, 300));
1311
+ const isUnsafe = resultText.toUpperCase().includes("UNSAFE");
1312
+ const isSafe = resultText.toUpperCase().startsWith("SAFE") || resultText.toUpperCase().includes("SAFE") && !isUnsafe;
1221
1313
  if (guard.action === "fix") {
1222
- if (resultText && resultText.trim() !== content.trim() && !resultText.includes("SAFE")) {
1223
- result.modifiedContent = resultText;
1224
- violationMessage = `Conte\xFAdo reescrito pelo guardrail "${name}".`;
1225
- result.violations.push({
1226
- name: guard.name,
1227
- message: violationMessage,
1228
- action: "fix"
1229
- });
1314
+ if (isUnsafe) {
1315
+ console.log(`[GUARDRAIL LLM] Modo FIX - Detectado UNSAFE, chamando modelo para corrigir...`);
1316
+ const fixPrompt = `Voc\xEA \xE9 um corretor de conte\xFAdo. O texto abaixo foi marcado como UNSAFE por violar uma regra.
1317
+
1318
+ REGRA VIOLADA:
1319
+ ${evaluationPrompt}
1320
+
1321
+ ${actionInstruction ? `INSTRU\xC7\xC3O DE CORRE\xC7\xC3O:
1322
+ ${actionInstruction}
1323
+ ` : ""}
1324
+
1325
+ CONTE\xDADO ORIGINAL:
1326
+ ${content}
1327
+
1328
+ Reescreva o conte\xFAdo corrigindo a viola\xE7\xE3o. Retorne APENAS o texto corrigido, sem explica\xE7\xF5es ou prefixos.`;
1329
+ try {
1330
+ const fixResponse = await model.invoke(fixPrompt);
1331
+ const fixedContent = typeof fixResponse.content === "string" ? fixResponse.content : String(fixResponse.content);
1332
+ console.log(`[GUARDRAIL LLM] Conte\xFAdo corrigido:`, fixedContent.slice(0, 300));
1333
+ result.modifiedContent = fixedContent;
1334
+ violationMessage = `Conte\xFAdo reescrito pelo guardrail "${name}".`;
1335
+ result.violations.push({
1336
+ name: guard.name,
1337
+ message: violationMessage,
1338
+ action: "fix"
1339
+ });
1340
+ emitGuardrailEvent(context, name, false, "fix", `Content fixed: ${fixedContent.slice(0, 100)}...`);
1341
+ } catch (fixError) {
1342
+ console.error(`[GUARDRAIL LLM] Erro ao corrigir conte\xFAdo:`, fixError);
1343
+ }
1344
+ } else {
1345
+ console.log(`[GUARDRAIL LLM] Modo FIX - Conte\xFAdo aprovado (SAFE)`);
1230
1346
  }
1231
1347
  } else {
1232
- if (resultText.toUpperCase().includes("UNSAFE")) {
1348
+ if (isUnsafe) {
1233
1349
  guardPassed = false;
1234
1350
  violationMessage = actionInstruction || `Modelo de avalia\xE7\xE3o "${name}" detectou viola\xE7\xE3o de seguran\xE7a/pol\xEDtica.`;
1351
+ console.log(`[GUARDRAIL LLM] Resultado: UNSAFE - Bloqueado`);
1352
+ emitGuardrailEvent(context, name, false, guard.action, violationMessage);
1353
+ } else {
1354
+ console.log(`[GUARDRAIL LLM] Resultado: SAFE - Aprovado`);
1355
+ emitGuardrailEvent(context, name, true, "approve", "Content passed evaluation");
1235
1356
  }
1236
1357
  }
1237
1358
  } catch (error) {
1238
- console.error(`Error executing model guardrail "${name}":`, error);
1359
+ console.error(`[GUARDRAIL LLM] Erro ao executar guardrail "${name}":`, error);
1239
1360
  }
1361
+ } else {
1362
+ console.log(`[GUARDRAIL LLM] Model n\xE3o dispon\xEDvel ou n\xE3o \xE9 invoc\xE1vel para guardrail "${name}"`);
1240
1363
  }
1241
1364
  }
1242
1365
  if (!guardPassed) {
@@ -1300,7 +1423,7 @@ var IaAgentNodeFunction = async (inputs) => {
1300
1423
  let guardrailViolations = [];
1301
1424
  if (message && beforeGuardrails) {
1302
1425
  const preparedBefore = await prepareGuardrails(beforeGuardrails);
1303
- const context = { ...inputs, input: message };
1426
+ const context = { ...inputs, input: message, checkpointer, sessionId };
1304
1427
  const beforeResults = await executeGuardrails(preparedBefore, message, guardrailMode, context);
1305
1428
  if (beforeResults.blocked) {
1306
1429
  console.log(`\u{1F6E1}\uFE0F IaAgentNode "${name}": Blocked by before-agent guardrail:`, beforeResults.message);
@@ -1502,7 +1625,7 @@ IMPORTANT: You must base your response on the last message in the conversation h
1502
1625
  }
1503
1626
  if (output && afterGuardrails) {
1504
1627
  const preparedAfter = await prepareGuardrails(afterGuardrails);
1505
- const context = { ...inputs, input: output };
1628
+ const context = { ...inputs, input: output, checkpointer, sessionId };
1506
1629
  const afterResults = await executeGuardrails(preparedAfter, output, guardrailMode, context);
1507
1630
  if (afterResults.blocked) {
1508
1631
  console.log(`\u{1F6E1}\uFE0F IaAgentNode "${name}": Response blocked by after-agent guardrail:`, afterResults.message);
@@ -2391,8 +2514,271 @@ var WhatsappMessageTriggerNode = {
2391
2514
  ]
2392
2515
  };
2393
2516
 
2517
+ // src/utils/sandbox-executor.ts
2518
+ var ivmModule = null;
2519
+ async function getIVM() {
2520
+ if (ivmModule !== null) return ivmModule;
2521
+ try {
2522
+ const mod = await import("isolated-vm");
2523
+ ivmModule = {
2524
+ Isolate: mod.Isolate || mod.default?.Isolate,
2525
+ ExternalCopy: mod.ExternalCopy || mod.default?.ExternalCopy,
2526
+ Reference: mod.Reference || mod.default?.Reference
2527
+ };
2528
+ if (!ivmModule.Isolate) {
2529
+ console.warn("[Sandbox] isolated-vm Isolate n\xE3o encontrado");
2530
+ return null;
2531
+ }
2532
+ return ivmModule;
2533
+ } catch (e) {
2534
+ console.warn("[Sandbox] isolated-vm n\xE3o dispon\xEDvel, usando fallback inseguro");
2535
+ return null;
2536
+ }
2537
+ }
2538
+ var DEFAULT_OPTIONS = {
2539
+ timeout: 1e4,
2540
+ memoryLimit: 128,
2541
+ allowFetch: true
2542
+ };
2543
+ async function executeSandboxed(code, sandboxContext, options = {}) {
2544
+ const opts = { ...DEFAULT_OPTIONS, ...options };
2545
+ const ivm = await getIVM();
2546
+ if (!ivm) {
2547
+ return executeFallback(code, sandboxContext);
2548
+ }
2549
+ let isolate = null;
2550
+ let context = null;
2551
+ try {
2552
+ isolate = new ivm.Isolate({ memoryLimit: opts.memoryLimit });
2553
+ context = await isolate.createContext();
2554
+ const jail = context.global;
2555
+ await jail.set("globalThis", jail.derefInto());
2556
+ await injectContextVariables(jail, sandboxContext, ivm);
2557
+ await jail.set("__logRef", new ivm.Reference(function(...args) {
2558
+ console.log("[Sandbox]", ...args);
2559
+ }));
2560
+ if (opts.allowFetch) {
2561
+ await jail.set("__fetchRef", new ivm.Reference(async function(url, optionsJson) {
2562
+ try {
2563
+ const options2 = optionsJson ? JSON.parse(optionsJson) : {};
2564
+ const res = await fetch(url, {
2565
+ method: options2?.method || "GET",
2566
+ headers: options2?.headers,
2567
+ body: options2?.body
2568
+ });
2569
+ const contentType = res.headers.get("content-type") || "";
2570
+ let data;
2571
+ if (contentType.includes("application/json")) {
2572
+ data = await res.json();
2573
+ } else {
2574
+ data = await res.text();
2575
+ }
2576
+ return JSON.stringify({
2577
+ ok: res.ok,
2578
+ status: res.status,
2579
+ statusText: res.statusText,
2580
+ data
2581
+ });
2582
+ } catch (error) {
2583
+ return JSON.stringify({
2584
+ ok: false,
2585
+ status: 0,
2586
+ statusText: "Network Error",
2587
+ error: error.message
2588
+ });
2589
+ }
2590
+ }));
2591
+ }
2592
+ const bootstrapCode = `
2593
+ // Console
2594
+ const console = {
2595
+ log: (...args) => __logRef.applySync(undefined, args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a))),
2596
+ warn: (...args) => __logRef.applySync(undefined, ['[WARN]', ...args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a))]),
2597
+ error: (...args) => __logRef.applySync(undefined, ['[ERROR]', ...args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a))]),
2598
+ info: (...args) => __logRef.applySync(undefined, args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a))),
2599
+ };
2600
+ globalThis.console = console;
2601
+
2602
+ ${opts.allowFetch ? `
2603
+ // Fetch
2604
+ globalThis.fetch = async (url, options = {}) => {
2605
+ const optionsJson = JSON.stringify(options);
2606
+ const resultJson = await __fetchRef.apply(undefined, [url, optionsJson], { result: { promise: true } });
2607
+ const result = JSON.parse(resultJson);
2608
+
2609
+ if (!result.ok && result.error) {
2610
+ throw new Error(result.error);
2611
+ }
2612
+
2613
+ return {
2614
+ ok: result.ok,
2615
+ status: result.status,
2616
+ statusText: result.statusText,
2617
+ json: async () => result.data,
2618
+ text: async () => typeof result.data === 'string' ? result.data : JSON.stringify(result.data),
2619
+ };
2620
+ };
2621
+ ` : ""}
2622
+
2623
+ // Base64
2624
+ globalThis.atob = (str) => {
2625
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
2626
+ let output = '';
2627
+ str = String(str).replace(/=+$/, '');
2628
+ for (let i = 0; i < str.length; i += 4) {
2629
+ const enc1 = chars.indexOf(str.charAt(i));
2630
+ const enc2 = chars.indexOf(str.charAt(i + 1));
2631
+ const enc3 = chars.indexOf(str.charAt(i + 2));
2632
+ const enc4 = chars.indexOf(str.charAt(i + 3));
2633
+ const chr1 = (enc1 << 2) | (enc2 >> 4);
2634
+ const chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
2635
+ const chr3 = ((enc3 & 3) << 6) | enc4;
2636
+ output += String.fromCharCode(chr1);
2637
+ if (enc3 !== 64) output += String.fromCharCode(chr2);
2638
+ if (enc4 !== 64) output += String.fromCharCode(chr3);
2639
+ }
2640
+ return output;
2641
+ };
2642
+
2643
+ globalThis.btoa = (str) => {
2644
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
2645
+ str = String(str);
2646
+ let output = '';
2647
+ for (let i = 0; i < str.length; i += 3) {
2648
+ const chr1 = str.charCodeAt(i);
2649
+ const chr2 = str.charCodeAt(i + 1);
2650
+ const chr3 = str.charCodeAt(i + 2);
2651
+ const enc1 = chr1 >> 2;
2652
+ const enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
2653
+ const enc3 = isNaN(chr2) ? 64 : ((chr2 & 15) << 2) | (chr3 >> 6);
2654
+ const enc4 = isNaN(chr3) ? 64 : chr3 & 63;
2655
+ output += chars.charAt(enc1) + chars.charAt(enc2) + chars.charAt(enc3) + chars.charAt(enc4);
2656
+ }
2657
+ return output;
2658
+ };
2659
+ `;
2660
+ const bootstrapScript = await isolate.compileScript(bootstrapCode);
2661
+ await bootstrapScript.run(context);
2662
+ const wrappedCode = wrapUserCode(code);
2663
+ const finalCode = `
2664
+ (async () => {
2665
+ const __userResult = await (${wrappedCode});
2666
+ // Serializa o resultado para poder transferir
2667
+ if (__userResult === undefined) return '__UNDEFINED__';
2668
+ if (__userResult === null) return 'null';
2669
+ if (typeof __userResult === 'object') {
2670
+ return JSON.stringify({ __type: 'object', value: __userResult });
2671
+ }
2672
+ return JSON.stringify({ __type: typeof __userResult, value: __userResult });
2673
+ })()
2674
+ `;
2675
+ const script = await isolate.compileScript(finalCode);
2676
+ const rawResult = await script.run(context, {
2677
+ timeout: opts.timeout,
2678
+ promise: true
2679
+ });
2680
+ if (rawResult === "__UNDEFINED__") return void 0;
2681
+ if (rawResult === "null") return null;
2682
+ try {
2683
+ const parsed = JSON.parse(rawResult);
2684
+ return parsed.value;
2685
+ } catch {
2686
+ return rawResult;
2687
+ }
2688
+ } catch (error) {
2689
+ if (error.message?.includes("Script execution timed out")) {
2690
+ throw new Error("Tempo de execu\xE7\xE3o excedido (timeout)");
2691
+ }
2692
+ if (error.message?.includes("Isolate was disposed")) {
2693
+ throw new Error("Execu\xE7\xE3o cancelada: limite de mem\xF3ria excedido");
2694
+ }
2695
+ throw new Error(`Erro na execu\xE7\xE3o do c\xF3digo: ${error.message || "Erro desconhecido"}`);
2696
+ } finally {
2697
+ if (context) {
2698
+ try {
2699
+ context.release();
2700
+ } catch {
2701
+ }
2702
+ }
2703
+ if (isolate) {
2704
+ try {
2705
+ isolate.dispose();
2706
+ } catch {
2707
+ }
2708
+ }
2709
+ }
2710
+ }
2711
+ async function injectContextVariables(jail, ctx, ivm) {
2712
+ const safeClone = (value) => {
2713
+ if (value === void 0 || value === null) {
2714
+ return value;
2715
+ }
2716
+ try {
2717
+ if (typeof value !== "object") {
2718
+ return value;
2719
+ }
2720
+ return new ivm.ExternalCopy(value).copyInto();
2721
+ } catch {
2722
+ try {
2723
+ return JSON.parse(JSON.stringify(value));
2724
+ } catch {
2725
+ return void 0;
2726
+ }
2727
+ }
2728
+ };
2729
+ await jail.set("input", safeClone(ctx.input));
2730
+ await jail.set("context", safeClone(ctx.context ?? {}));
2731
+ await jail.set("$inputs", safeClone(ctx.$inputs ?? {}));
2732
+ await jail.set("$vars", safeClone(ctx.$vars ?? {}));
2733
+ await jail.set("$field", safeClone(ctx.$field ?? {}));
2734
+ await jail.set("request", safeClone(ctx.request));
2735
+ await jail.set("params", safeClone(ctx.params));
2736
+ await jail.set("__placeholders", safeClone(ctx.__placeholders ?? {}));
2737
+ }
2738
+ function wrapUserCode(code) {
2739
+ const trimmed = code.trim();
2740
+ if (trimmed.startsWith("return ")) {
2741
+ return `(async function() { ${code} })()`;
2742
+ }
2743
+ 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 ");
2744
+ if (isSimpleExpression) {
2745
+ return `(async function() { return ${code} })()`;
2746
+ }
2747
+ return `(async function() { ${code} })()`;
2748
+ }
2749
+ function executeFallback(code, ctx) {
2750
+ console.warn("[Sandbox] Usando execu\xE7\xE3o INSEGURA (new Function). Instale isolated-vm para seguran\xE7a.");
2751
+ const customFunction = new Function(
2752
+ "input",
2753
+ "context",
2754
+ "request",
2755
+ "params",
2756
+ "$inputs",
2757
+ "$vars",
2758
+ "$field",
2759
+ "__placeholders",
2760
+ code
2761
+ );
2762
+ return customFunction(
2763
+ ctx.input,
2764
+ ctx.context,
2765
+ ctx.request,
2766
+ ctx.params,
2767
+ ctx.$inputs,
2768
+ ctx.$vars,
2769
+ ctx.$field,
2770
+ ctx.__placeholders
2771
+ );
2772
+ }
2773
+ function looksLikeCode(code) {
2774
+ if (typeof code !== "string") return false;
2775
+ const c = code.trim();
2776
+ if (c.length < 3) return false;
2777
+ return /(return\s+|=>|function\s*\(|;|\n|\{|\})/.test(c);
2778
+ }
2779
+
2394
2780
  // src/nodes/processors/custom-code.ts
2395
- var NodeFunction = (params) => {
2781
+ var NodeFunction = async (params) => {
2396
2782
  let input = params?.inputValue ?? params?.input;
2397
2783
  const context = params && params.fieldValues ? params.fieldValues : params || {};
2398
2784
  let customCode = context?.customCode ?? params?.customCode;
@@ -2405,12 +2791,6 @@ var NodeFunction = (params) => {
2405
2791
  else if (firstInputField.value !== void 0) input = firstInputField.value;
2406
2792
  }
2407
2793
  }
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
2794
  if (typeof customCode === "string" && !looksLikeCode(customCode)) {
2415
2795
  if (input === void 0) input = customCode;
2416
2796
  customCode = "";
@@ -2418,18 +2798,25 @@ var NodeFunction = (params) => {
2418
2798
  if (!customCode || typeof customCode === "string" && customCode.trim() === "") {
2419
2799
  return input;
2420
2800
  }
2421
- try {
2422
- const $inputs = params?.results || {};
2423
- const $vars = context && context.variables || params?.variables || void 0;
2424
- const __placeholders = params?.__codePlaceholders ?? context?.__codePlaceholders;
2425
- const customFunction = new Function("input", "context", "request", "params", "$inputs", "$vars", "__placeholders", customCode);
2426
- const result = customFunction(input, context, params?.request, params, $inputs, $vars, __placeholders);
2427
- return result;
2428
- } catch (error) {
2429
- throw new Error(`Erro ao executar c\xF3digo customizado: ${error instanceof Error ? error.message : "Erro desconhecido"}`);
2430
- }
2801
+ const sandboxContext = {
2802
+ input,
2803
+ context,
2804
+ $inputs: params?.results || {},
2805
+ $vars: context && context.variables || params?.variables || void 0,
2806
+ request: params?.request,
2807
+ params,
2808
+ __placeholders: params?.__codePlaceholders ?? context?.__codePlaceholders
2809
+ };
2810
+ const result = await executeSandboxed(customCode, sandboxContext, {
2811
+ timeout: 3e4,
2812
+ // 30 segundos
2813
+ memoryLimit: 128,
2814
+ // 128MB
2815
+ allowFetch: true
2816
+ });
2817
+ return result;
2431
2818
  };
2432
- var CustomNodeFunction = (params) => {
2819
+ var CustomNodeFunction = async (params) => {
2433
2820
  const context = params && params.fieldValues ? params.fieldValues : params || {};
2434
2821
  const customCode = context?.customCode;
2435
2822
  if (!customCode || typeof customCode === "string" && customCode.trim() === "") {
@@ -2452,29 +2839,36 @@ var CustomNodeFunction = (params) => {
2452
2839
  }
2453
2840
  $field[fieldId] = value;
2454
2841
  });
2455
- try {
2456
- const $inputs = params?.results || {};
2457
- const $vars = context && context.variables || params?.variables || void 0;
2458
- const customFunction = new Function("$field", "context", "request", "params", "$inputs", "$vars", customCode);
2459
- const result = customFunction($field, context, params?.request, params, $inputs, $vars);
2460
- return result;
2461
- } catch (error) {
2462
- throw new Error(`Erro ao executar CustomNode: ${error instanceof Error ? error.message : "Erro desconhecido"}`);
2463
- }
2842
+ const sandboxContext = {
2843
+ $field,
2844
+ context,
2845
+ $inputs: params?.results || {},
2846
+ $vars: context && context.variables || params?.variables || void 0,
2847
+ request: params?.request,
2848
+ params
2849
+ };
2850
+ const result = await executeSandboxed(customCode, sandboxContext, {
2851
+ timeout: 3e4,
2852
+ // 30 segundos
2853
+ memoryLimit: 128,
2854
+ // 128MB
2855
+ allowFetch: true
2856
+ });
2857
+ return result;
2464
2858
  };
2465
2859
  var CustomCodeNode = {
2466
2860
  label: "Custom Code",
2467
2861
  type: "CustomCodeNode",
2468
2862
  category: "step",
2469
2863
  icon: "\u{1F4BB}",
2470
- description: "Node para executar c\xF3digo JavaScript customizado",
2864
+ description: "Node para executar c\xF3digo JavaScript customizado (sandbox segura)",
2471
2865
  fields: [
2472
2866
  {
2473
2867
  id: "customCode",
2474
2868
  label: "C\xF3digo Customizado",
2475
2869
  type: "code",
2476
2870
  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;'
2871
+ 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
2872
  },
2479
2873
  {
2480
2874
  id: "input",
@@ -2936,6 +3330,335 @@ var ModelGuardrailNodeFunction = async (inputs) => {
2936
3330
  };
2937
3331
  };
2938
3332
 
3333
+ // src/nodes/chat/getOrCreateThread/data.ts
3334
+ var import_zod17 = require("zod");
3335
+ var GetOrCreateThreadSchema = import_zod17.z.object({
3336
+ source: import_zod17.z.string().describe("Channel source: whatsapp, telegram, web, etc."),
3337
+ identifier: import_zod17.z.string().describe("User identifier: phone number, chat_id, userId"),
3338
+ timeoutMinutes: import_zod17.z.number().optional().describe("Inactivity timeout in minutes (default: 1440 = 24h)")
3339
+ });
3340
+ var GetOrCreateThreadNode = {
3341
+ label: "Get or Create Thread",
3342
+ type: "GetOrCreateThreadNode",
3343
+ category: "chat",
3344
+ description: "Generates or retrieves a threadId based on identifier + timeout. Ensures tenant isolation.",
3345
+ icon: "\u{1F9F5}",
3346
+ group: "Chat",
3347
+ tags: {
3348
+ execution: "async",
3349
+ group: "Chat"
3350
+ },
3351
+ fields: [
3352
+ {
3353
+ id: "source",
3354
+ label: "Source",
3355
+ type: "string",
3356
+ required: true,
3357
+ defaultValue: "whatsapp",
3358
+ placeholder: "whatsapp, telegram, web",
3359
+ handle: {
3360
+ type: "input",
3361
+ label: "Source",
3362
+ name: "source",
3363
+ fieldType: "string"
3364
+ }
3365
+ },
3366
+ {
3367
+ id: "identifier",
3368
+ label: "Identifier",
3369
+ type: "string",
3370
+ required: true,
3371
+ placeholder: "+5511999999999",
3372
+ handle: {
3373
+ type: "input",
3374
+ label: "Identifier",
3375
+ name: "identifier",
3376
+ fieldType: "string"
3377
+ }
3378
+ },
3379
+ {
3380
+ id: "timeoutMinutes",
3381
+ label: "Timeout (minutes)",
3382
+ type: "number",
3383
+ required: false,
3384
+ defaultValue: "1440",
3385
+ placeholder: "1440 (24 hours)"
3386
+ },
3387
+ {
3388
+ id: "threadId",
3389
+ label: "Thread ID",
3390
+ type: "string",
3391
+ required: true,
3392
+ typeable: false,
3393
+ handle: {
3394
+ type: "output",
3395
+ label: "Thread ID",
3396
+ name: "threadId",
3397
+ fieldType: "string"
3398
+ }
3399
+ },
3400
+ {
3401
+ id: "isNew",
3402
+ label: "Is New Thread",
3403
+ type: "boolean",
3404
+ required: true,
3405
+ typeable: false,
3406
+ handle: {
3407
+ type: "output",
3408
+ label: "Is New",
3409
+ name: "isNew",
3410
+ fieldType: "boolean"
3411
+ }
3412
+ }
3413
+ ]
3414
+ };
3415
+
3416
+ // src/nodes/chat/getOrCreateThread/function.ts
3417
+ var GetOrCreateThreadNodeFunction = async (inputs) => {
3418
+ const fieldValues = inputs.fieldValues || {};
3419
+ const context = inputs.context || {};
3420
+ const source = fieldValues.source;
3421
+ const identifier = fieldValues.identifier;
3422
+ const timeoutMinutes = Number(fieldValues.timeoutMinutes) || 1440;
3423
+ const companyId = context?.companyId;
3424
+ if (!companyId) {
3425
+ throw new Error("GetOrCreateThread requires companyId in context for tenant isolation");
3426
+ }
3427
+ if (!source || !identifier) {
3428
+ throw new Error("GetOrCreateThread requires source and identifier");
3429
+ }
3430
+ const timeoutMs = timeoutMinutes * 60 * 1e3;
3431
+ const thresholdDate = new Date(Date.now() - timeoutMs);
3432
+ const db = context?.db;
3433
+ if (!db) {
3434
+ throw new Error("GetOrCreateThread requires database connection in context");
3435
+ }
3436
+ try {
3437
+ const existingSessions = await db.query(`
3438
+ SELECT id, session_id, updated_at
3439
+ FROM chat_sessions
3440
+ WHERE company_id = $1
3441
+ AND metadata->>'source' = $2
3442
+ AND metadata->>'identifier' = $3
3443
+ AND updated_at > $4
3444
+ ORDER BY updated_at DESC
3445
+ LIMIT 1
3446
+ `, [companyId, source, identifier, thresholdDate]);
3447
+ if (existingSessions.rows && existingSessions.rows.length > 0) {
3448
+ const session = existingSessions.rows[0];
3449
+ await db.query(`
3450
+ UPDATE chat_sessions
3451
+ SET updated_at = NOW()
3452
+ WHERE id = $1 AND company_id = $2
3453
+ `, [session.id, companyId]);
3454
+ return {
3455
+ threadId: session.session_id,
3456
+ isNew: false
3457
+ };
3458
+ }
3459
+ const newSessionId = crypto.randomUUID();
3460
+ const workflowId = context?.workflowId;
3461
+ await db.query(`
3462
+ INSERT INTO chat_sessions (workflow_id, company_id, chat_id, session_id, metadata)
3463
+ VALUES ($1, $2, $3, $4, $5)
3464
+ `, [
3465
+ workflowId || companyId,
3466
+ // fallback to companyId if no workflowId
3467
+ companyId,
3468
+ `${source}:${identifier}`,
3469
+ // chatId as composite key
3470
+ newSessionId,
3471
+ JSON.stringify({ source, identifier })
3472
+ ]);
3473
+ return {
3474
+ threadId: newSessionId,
3475
+ isNew: true
3476
+ };
3477
+ } catch (error) {
3478
+ console.error("[GetOrCreateThread] Error:", error);
3479
+ throw error;
3480
+ }
3481
+ };
3482
+
3483
+ // src/nodes/chat/chatLog/data.ts
3484
+ var import_zod18 = require("zod");
3485
+ var ChatLogSchema = import_zod18.z.object({
3486
+ threadId: import_zod18.z.string().describe("Thread ID from GetOrCreateThread"),
3487
+ direction: import_zod18.z.enum(["inbound", "outbound"]).describe("Message direction"),
3488
+ content: import_zod18.z.string().describe("Message content"),
3489
+ source: import_zod18.z.string().optional().describe("Channel source"),
3490
+ identifier: import_zod18.z.string().optional().describe("User identifier"),
3491
+ metadata: import_zod18.z.record(import_zod18.z.string(), import_zod18.z.any()).optional().describe("Additional metadata")
3492
+ });
3493
+ var ChatLogNode = {
3494
+ label: "Chat Log",
3495
+ type: "ChatLogNode",
3496
+ category: "chat",
3497
+ description: "Saves a message to the chat history. Supports inbound (user) and outbound (assistant) messages.",
3498
+ icon: "\u{1F4AC}",
3499
+ group: "Chat",
3500
+ tags: {
3501
+ execution: "async",
3502
+ group: "Chat"
3503
+ },
3504
+ fields: [
3505
+ {
3506
+ id: "threadId",
3507
+ label: "Thread ID",
3508
+ type: "string",
3509
+ required: true,
3510
+ placeholder: "From GetOrCreateThread node",
3511
+ handle: {
3512
+ type: "input",
3513
+ label: "Thread ID",
3514
+ name: "threadId",
3515
+ fieldType: "string"
3516
+ }
3517
+ },
3518
+ {
3519
+ id: "direction",
3520
+ label: "Direction",
3521
+ type: "select",
3522
+ required: true,
3523
+ defaultValue: "inbound",
3524
+ options: [
3525
+ { label: "Inbound (User \u2192 System)", value: "inbound" },
3526
+ { label: "Outbound (System \u2192 User)", value: "outbound" }
3527
+ ]
3528
+ },
3529
+ {
3530
+ id: "content",
3531
+ label: "Content",
3532
+ type: "string",
3533
+ required: true,
3534
+ placeholder: "Message content",
3535
+ handle: {
3536
+ type: "input",
3537
+ label: "Content",
3538
+ name: "content",
3539
+ fieldType: "string"
3540
+ }
3541
+ },
3542
+ {
3543
+ id: "source",
3544
+ label: "Source",
3545
+ type: "string",
3546
+ required: false,
3547
+ defaultValue: "whatsapp",
3548
+ placeholder: "whatsapp, telegram, web",
3549
+ handle: {
3550
+ type: "input",
3551
+ label: "Source",
3552
+ name: "source",
3553
+ fieldType: "string"
3554
+ }
3555
+ },
3556
+ {
3557
+ id: "identifier",
3558
+ label: "Identifier",
3559
+ type: "string",
3560
+ required: false,
3561
+ placeholder: "+5511999999999",
3562
+ handle: {
3563
+ type: "input",
3564
+ label: "Identifier",
3565
+ name: "identifier",
3566
+ fieldType: "string"
3567
+ }
3568
+ },
3569
+ {
3570
+ id: "messageId",
3571
+ label: "Message ID",
3572
+ type: "string",
3573
+ required: true,
3574
+ typeable: false,
3575
+ handle: {
3576
+ type: "output",
3577
+ label: "Message ID",
3578
+ name: "messageId",
3579
+ fieldType: "string"
3580
+ }
3581
+ },
3582
+ {
3583
+ id: "success",
3584
+ label: "Success",
3585
+ type: "boolean",
3586
+ required: true,
3587
+ typeable: false,
3588
+ handle: {
3589
+ type: "output",
3590
+ label: "Success",
3591
+ name: "success",
3592
+ fieldType: "boolean"
3593
+ }
3594
+ }
3595
+ ]
3596
+ };
3597
+
3598
+ // src/nodes/chat/chatLog/function.ts
3599
+ var ChatLogNodeFunction = async (inputs) => {
3600
+ const fieldValues = inputs.fieldValues || {};
3601
+ const context = inputs.context || {};
3602
+ const threadId = fieldValues.threadId;
3603
+ const direction = fieldValues.direction;
3604
+ const content = fieldValues.content;
3605
+ const source = fieldValues.source;
3606
+ const identifier = fieldValues.identifier;
3607
+ const companyId = context?.companyId;
3608
+ if (!companyId) {
3609
+ throw new Error("ChatLog requires companyId in context for tenant isolation");
3610
+ }
3611
+ if (!threadId || !content) {
3612
+ throw new Error("ChatLog requires threadId and content");
3613
+ }
3614
+ const role = direction === "inbound" ? "user" : "assistant";
3615
+ const db = context?.db;
3616
+ if (!db) {
3617
+ throw new Error("ChatLog requires database connection in context");
3618
+ }
3619
+ try {
3620
+ const sessionResult = await db.query(`
3621
+ SELECT id FROM chat_sessions
3622
+ WHERE session_id = $1 AND company_id = $2
3623
+ LIMIT 1
3624
+ `, [threadId, companyId]);
3625
+ if (!sessionResult.rows || sessionResult.rows.length === 0) {
3626
+ throw new Error(`Session not found for threadId: ${threadId}`);
3627
+ }
3628
+ const sessionId = sessionResult.rows[0].id;
3629
+ const messageId = crypto.randomUUID();
3630
+ await db.query(`
3631
+ INSERT INTO chat_messages (id, session_id, role, content, metadata)
3632
+ VALUES ($1, $2, $3, $4, $5)
3633
+ `, [
3634
+ messageId,
3635
+ sessionId,
3636
+ role,
3637
+ content,
3638
+ JSON.stringify({
3639
+ direction,
3640
+ source: source || null,
3641
+ identifier: identifier || null
3642
+ })
3643
+ ]);
3644
+ await db.query(`
3645
+ UPDATE chat_sessions
3646
+ SET updated_at = NOW()
3647
+ WHERE id = $1 AND company_id = $2
3648
+ `, [sessionId, companyId]);
3649
+ return {
3650
+ messageId,
3651
+ success: true
3652
+ };
3653
+ } catch (error) {
3654
+ console.error("[ChatLog] Error:", error);
3655
+ return {
3656
+ messageId: null,
3657
+ success: false
3658
+ };
3659
+ }
3660
+ };
3661
+
2939
3662
  // src/nodes/consts/nodes.ts
2940
3663
  var nodes = [
2941
3664
  ChatInputNode,
@@ -2962,7 +3685,9 @@ var nodes = [
2962
3685
  PromptGuardrailNode,
2963
3686
  RuleGuardrailNode,
2964
3687
  FunctionGuardrailNode,
2965
- ModelGuardrailNode
3688
+ ModelGuardrailNode,
3689
+ GetOrCreateThreadNode,
3690
+ ChatLogNode
2966
3691
  ];
2967
3692
  var nodes_default = nodes;
2968
3693
 
@@ -3084,7 +3809,9 @@ var nodeFunctions = {
3084
3809
  PromptGuardrailNode: PromptGuardrailNodeFunction,
3085
3810
  RuleGuardrailNode: RuleGuardrailNodeFunction,
3086
3811
  FunctionGuardrailNode: FunctionGuardrailNodeFunction,
3087
- ModelGuardrailNode: ModelGuardrailNodeFunction
3812
+ ModelGuardrailNode: ModelGuardrailNodeFunction,
3813
+ GetOrCreateThreadNode: GetOrCreateThreadNodeFunction,
3814
+ ChatLogNode: ChatLogNodeFunction
3088
3815
  };
3089
3816
  var node_functions_default = nodeFunctions;
3090
3817
 
@@ -3198,12 +3925,12 @@ var HttpPutInputNodeFunction = (params) => {
3198
3925
  };
3199
3926
 
3200
3927
  // src/nodes/inputs/http/put/schema.ts
3201
- var import_zod17 = require("zod");
3202
- var HttpPutInputNodeSchema = import_zod17.z.object({
3928
+ var import_zod19 = require("zod");
3929
+ var HttpPutInputNodeSchema = import_zod19.z.object({
3203
3930
  route: RouteSchema,
3204
- queryParams: import_zod17.z.array(QueryParamSchema).optional().describe("Query parameters configuration"),
3205
- headers: import_zod17.z.array(HeaderSchema).optional().describe("Headers configuration"),
3206
- body: import_zod17.z.array(BodyFieldSchema).optional().describe("Body fields configuration")
3931
+ queryParams: import_zod19.z.array(QueryParamSchema).optional().describe("Query parameters configuration"),
3932
+ headers: import_zod19.z.array(HeaderSchema).optional().describe("Headers configuration"),
3933
+ body: import_zod19.z.array(BodyFieldSchema).optional().describe("Body fields configuration")
3207
3934
  });
3208
3935
 
3209
3936
  // src/nodes/inputs/http/delete/data.ts
@@ -3295,11 +4022,11 @@ var HttpDeleteInputNodeFunction = async (params) => {
3295
4022
  };
3296
4023
 
3297
4024
  // src/nodes/inputs/http/delete/schema.ts
3298
- var import_zod18 = require("zod");
3299
- var HttpDeleteInputNodeSchema = import_zod18.z.object({
4025
+ var import_zod20 = require("zod");
4026
+ var HttpDeleteInputNodeSchema = import_zod20.z.object({
3300
4027
  route: RouteSchema,
3301
- queryParams: import_zod18.z.array(QueryParamSchema).optional().describe("Query parameters configuration"),
3302
- headers: import_zod18.z.array(HeaderSchema).optional().describe("Headers configuration")
4028
+ queryParams: import_zod20.z.array(QueryParamSchema).optional().describe("Query parameters configuration"),
4029
+ headers: import_zod20.z.array(HeaderSchema).optional().describe("Headers configuration")
3303
4030
  });
3304
4031
 
3305
4032
  // src/nodes/inputs/http/patch/data.ts
@@ -3412,12 +4139,12 @@ var HttpPatchInputNodeFunction = (params) => {
3412
4139
  };
3413
4140
 
3414
4141
  // src/nodes/inputs/http/patch/schema.ts
3415
- var import_zod19 = require("zod");
3416
- var HttpPatchInputNodeSchema = import_zod19.z.object({
4142
+ var import_zod21 = require("zod");
4143
+ var HttpPatchInputNodeSchema = import_zod21.z.object({
3417
4144
  route: RouteSchema,
3418
- queryParams: import_zod19.z.array(QueryParamSchema).optional().describe("Query parameters configuration"),
3419
- headers: import_zod19.z.array(HeaderSchema).optional().describe("Headers configuration"),
3420
- body: import_zod19.z.array(BodyFieldSchema).optional().describe("Body fields configuration")
4145
+ queryParams: import_zod21.z.array(QueryParamSchema).optional().describe("Query parameters configuration"),
4146
+ headers: import_zod21.z.array(HeaderSchema).optional().describe("Headers configuration"),
4147
+ body: import_zod21.z.array(BodyFieldSchema).optional().describe("Body fields configuration")
3421
4148
  });
3422
4149
 
3423
4150
  // src/nodes/inputs/http/utils.ts
@@ -3477,7 +4204,13 @@ var getHttpMethodFromFriendlyId = (friendlyId) => {
3477
4204
  AiToolNodeFunction,
3478
4205
  AiToolNodeSchema,
3479
4206
  BodyFieldSchema,
4207
+ ChatLogNode,
4208
+ ChatLogNodeFunction,
4209
+ ChatLogSchema,
3480
4210
  CustomToolSchema,
4211
+ GetOrCreateThreadNode,
4212
+ GetOrCreateThreadNodeFunction,
4213
+ GetOrCreateThreadSchema,
3481
4214
  HTTP_METHODS,
3482
4215
  HTTP_NODE_TYPES,
3483
4216
  HeaderSchema,