@atomoz/workflows-nodes 0.1.22 → 0.1.23

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.
Files changed (3) hide show
  1. package/dist/index.cjs +243 -95
  2. package/dist/index.js +243 -95
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -993,39 +993,50 @@ var IaAgentNode = {
993
993
  typeable: false,
994
994
  handle: {
995
995
  type: "output",
996
- label: "response",
996
+ label: "Response",
997
997
  name: "response",
998
998
  fieldType: "string"
999
999
  }
1000
1000
  },
1001
1001
  {
1002
- id: "beforeGuardrails",
1003
- label: "Before Guardrails",
1004
- type: "guardrail",
1002
+ id: "blocked",
1003
+ label: "Is Blocked",
1004
+ type: "boolean",
1005
1005
  required: false,
1006
1006
  typeable: false,
1007
1007
  handle: {
1008
- type: "input",
1009
- label: "Before Guardrails",
1010
- name: "beforeGuardrails",
1011
- fieldType: "guardrail",
1012
- acceptTypes: ["guardrail"],
1013
- maxConnections: 10
1008
+ type: "output",
1009
+ label: "Blocked",
1010
+ name: "blocked",
1011
+ fieldType: "boolean"
1014
1012
  }
1015
1013
  },
1016
1014
  {
1017
- id: "afterGuardrails",
1018
- label: "After Guardrails",
1015
+ id: "violations",
1016
+ label: "Violations",
1017
+ type: "json",
1018
+ required: false,
1019
+ typeable: false,
1020
+ handle: {
1021
+ type: "output",
1022
+ label: "Violations",
1023
+ name: "violations",
1024
+ fieldType: "json"
1025
+ }
1026
+ },
1027
+ {
1028
+ id: "guardrails",
1029
+ label: "Guardrails (Todas as Fases)",
1019
1030
  type: "guardrail",
1020
1031
  required: false,
1021
1032
  typeable: false,
1022
1033
  handle: {
1023
1034
  type: "input",
1024
- label: "After Guardrails",
1025
- name: "afterGuardrails",
1035
+ label: "Guardrails",
1036
+ name: "guardrails",
1026
1037
  fieldType: "guardrail",
1027
1038
  acceptTypes: ["guardrail"],
1028
- maxConnections: 10
1039
+ maxConnections: 20
1029
1040
  }
1030
1041
  },
1031
1042
  {
@@ -1103,7 +1114,7 @@ async function createLLMFromModel(modelConfig, authToken, streaming = false) {
1103
1114
  }
1104
1115
 
1105
1116
  // src/utils/guardrail-executor.ts
1106
- async function executeGuardrails(guardrails, content, mode = "fail-first") {
1117
+ async function executeGuardrails(guardrails, content, mode = "fail-first", context = {}) {
1107
1118
  const list = Array.isArray(guardrails) ? guardrails : [guardrails];
1108
1119
  const result = {
1109
1120
  passed: true,
@@ -1116,7 +1127,7 @@ async function executeGuardrails(guardrails, content, mode = "fail-first") {
1116
1127
  let guardPassed = true;
1117
1128
  let violationMessage = "";
1118
1129
  if (guard.type === "rule") {
1119
- const { ruleType, config, action } = guard;
1130
+ const { ruleType, config, action, actionInstruction } = guard;
1120
1131
  if (ruleType === "keywords" && config) {
1121
1132
  const keywords = config.split(",").map((k) => k.trim().toLowerCase());
1122
1133
  const lowerContent = content.toLowerCase();
@@ -1150,18 +1161,33 @@ async function executeGuardrails(guardrails, content, mode = "fail-first") {
1150
1161
  violationMessage = `Valor ${val} \xE9 menor que o m\xEDnimo permitido de ${min}.`;
1151
1162
  }
1152
1163
  }
1164
+ if (!guardPassed && actionInstruction) {
1165
+ violationMessage = actionInstruction;
1166
+ }
1153
1167
  } else if (guard.type === "function") {
1154
- const { nodeFunction, name } = guard;
1168
+ const { nodeFunction, name, actionInstruction } = guard;
1155
1169
  if (typeof nodeFunction === "function") {
1156
1170
  try {
1171
+ const executionContext = {
1172
+ input: content,
1173
+ ...context
1174
+ };
1157
1175
  const result2 = await nodeFunction({
1158
1176
  input: content,
1159
- fieldValues: { input: content },
1160
- originalNodeData: guard.originalNodeData
1177
+ fieldValues: { input: content, ...executionContext },
1178
+ // Envia contexto como fieldValues
1179
+ originalNodeData: guard.originalNodeData,
1180
+ $req: context?.$req,
1181
+ // Pass request context explicitly
1182
+ $vars: context?.$vars
1183
+ // Pass variables explicitly
1161
1184
  });
1162
1185
  if (result2 === false || typeof result2 === "object" && result2?.passed === false) {
1163
1186
  guardPassed = false;
1164
1187
  violationMessage = typeof result2?.message === "string" ? result2.message : `Fun\xE7\xE3o guardrail "${name}" reprovou o conte\xFAdo.`;
1188
+ if (actionInstruction) {
1189
+ violationMessage = actionInstruction;
1190
+ }
1165
1191
  } else if (typeof result2 === "object" && result2?.modifiedContent) {
1166
1192
  result2.modifiedContent = result2.modifiedContent;
1167
1193
  }
@@ -1172,15 +1198,41 @@ async function executeGuardrails(guardrails, content, mode = "fail-first") {
1172
1198
  }
1173
1199
  }
1174
1200
  } else if (guard.type === "model") {
1175
- const { model, evaluationPrompt, name } = guard;
1201
+ const { model, evaluationPrompt, name, actionInstruction } = guard;
1176
1202
  if (model && typeof model.invoke === "function") {
1177
1203
  try {
1178
- const prompt = evaluationPrompt.replace("{{content}}", content);
1204
+ let prompt = evaluationPrompt;
1205
+ if (actionInstruction) {
1206
+ prompt += `
1207
+
1208
+ INSTRU\xC7\xC3O ADICIONAL DE A\xC7\xC3O:
1209
+ ${actionInstruction}`;
1210
+ }
1211
+ if (prompt.includes("{{content}}")) {
1212
+ prompt = prompt.replace("{{content}}", content);
1213
+ } else {
1214
+ prompt = `${prompt}
1215
+
1216
+ CONTE\xDADO PARA AVALIAR:
1217
+ ${content}`;
1218
+ }
1179
1219
  const response = await model.invoke(prompt);
1180
1220
  const resultText = typeof response.content === "string" ? response.content : String(response.content);
1181
- if (resultText.toUpperCase().includes("UNSAFE")) {
1182
- guardPassed = false;
1183
- violationMessage = `Modelo de avalia\xE7\xE3o "${name}" detectou viola\xE7\xE3o de seguran\xE7a/pol\xEDtica.`;
1221
+ 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
+ });
1230
+ }
1231
+ } else {
1232
+ if (resultText.toUpperCase().includes("UNSAFE")) {
1233
+ guardPassed = false;
1234
+ violationMessage = actionInstruction || `Modelo de avalia\xE7\xE3o "${name}" detectou viola\xE7\xE3o de seguran\xE7a/pol\xEDtica.`;
1235
+ }
1184
1236
  }
1185
1237
  } catch (error) {
1186
1238
  console.error(`Error executing model guardrail "${name}":`, error);
@@ -1196,7 +1248,7 @@ async function executeGuardrails(guardrails, content, mode = "fail-first") {
1196
1248
  });
1197
1249
  if (guard.action === "block") {
1198
1250
  result.blocked = true;
1199
- result.message = violationMessage;
1251
+ result.message = `GUARDRAILS ATIVADO: ${violationMessage}`;
1200
1252
  if (mode === "fail-first") break;
1201
1253
  }
1202
1254
  }
@@ -1220,7 +1272,10 @@ GUARDRAIL [${guard.name}]: ${guard.prompt}`;
1220
1272
  var IaAgentNodeFunction = async (inputs) => {
1221
1273
  const { $field: _$field, $req: _$req, $inputs: _$inputs, $vars: _$vars } = inputs;
1222
1274
  const fieldValues = inputs.fieldValues || {};
1223
- const { model, tools, systemMessage, name, message, beforeGuardrails, afterGuardrails, guardrailMode } = fieldValues;
1275
+ const { model, tools, systemMessage, name, message, guardrails, guardrailMode } = fieldValues;
1276
+ const guardrailsList = Array.isArray(guardrails) ? guardrails : guardrails ? [guardrails] : [];
1277
+ const beforeGuardrails = guardrailsList.filter((g) => g?.phase === "before");
1278
+ const afterGuardrails = guardrailsList.filter((g) => !g?.phase || g?.phase === "after");
1224
1279
  const authToken = inputs.authToken;
1225
1280
  const stream = Boolean(inputs?.stream);
1226
1281
  const emitter = inputs?.emitter;
@@ -1231,8 +1286,8 @@ var IaAgentNodeFunction = async (inputs) => {
1231
1286
  throw new Error("Agent 'name' is required. Please provide a unique name for the agent in the node properties.");
1232
1287
  }
1233
1288
  const prepareGuardrails = async (list) => {
1234
- const guardrailsList = Array.isArray(list) ? list : [list];
1235
- return await Promise.all(guardrailsList.map(async (g) => {
1289
+ const guardrailsList2 = Array.isArray(list) ? list : [list];
1290
+ return await Promise.all(guardrailsList2.map(async (g) => {
1236
1291
  if (g?.type === "model" && g.model && !g.model.invoke) {
1237
1292
  if (!authToken) throw new Error("Auth token required for model guardrail");
1238
1293
  const modelInstance = await createLLMFromModel(g.model, authToken, false);
@@ -1241,9 +1296,12 @@ var IaAgentNodeFunction = async (inputs) => {
1241
1296
  return g;
1242
1297
  }));
1243
1298
  };
1299
+ let isBlocked = false;
1300
+ let guardrailViolations = [];
1244
1301
  if (message && beforeGuardrails) {
1245
1302
  const preparedBefore = await prepareGuardrails(beforeGuardrails);
1246
- const beforeResults = await executeGuardrails(preparedBefore, message, guardrailMode);
1303
+ const context = { ...inputs, input: message };
1304
+ const beforeResults = await executeGuardrails(preparedBefore, message, guardrailMode, context);
1247
1305
  if (beforeResults.blocked) {
1248
1306
  console.log(`\u{1F6E1}\uFE0F IaAgentNode "${name}": Blocked by before-agent guardrail:`, beforeResults.message);
1249
1307
  if (stream && emitter?.emitDelta) {
@@ -1256,9 +1314,9 @@ var IaAgentNodeFunction = async (inputs) => {
1256
1314
  }
1257
1315
  return {
1258
1316
  agent: null,
1259
- output: beforeResults.message || "Requisi\xE7\xE3o bloqueada por pol\xEDtica de seguran\xE7a.",
1317
+ output: beforeResults.message || "GUARDRAILS ATIVADO: Requisi\xE7\xE3o bloqueada por pol\xEDtica de seguran\xE7a.",
1260
1318
  blocked: true,
1261
- violations: beforeResults.violations
1319
+ violations: beforeResults.violations || []
1262
1320
  };
1263
1321
  }
1264
1322
  }
@@ -1278,17 +1336,46 @@ IMPORTANT: You must base your response on the last message in the conversation h
1278
1336
  finalSystemMessageContent = applyPromptGuardrails(finalSystemMessageContent, afterGuardrails);
1279
1337
  }
1280
1338
  const finalSystemMessage = new import_messages.SystemMessage(finalSystemMessageContent);
1339
+ const defaultModel = {
1340
+ model: "gemini-flash-latest",
1341
+ integrationId: "default-gemini"
1342
+ };
1343
+ const finalModel = model?.integrationId || typeof model?.bindTools === "function" ? model : defaultModel;
1344
+ console.log(`\u{1F916} IaAgentNode "${name}": Using model:`, finalModel === defaultModel ? "DEFAULT (Gemini)" : finalModel?.model || "instance");
1345
+ const callbacks = stream && emitter ? [
1346
+ {
1347
+ handleLLMNewToken: (token) => {
1348
+ if (emitter?.emitDelta) {
1349
+ emitter.emitDelta({
1350
+ content: token,
1351
+ actor: name,
1352
+ isAgent: true,
1353
+ isTool: false
1354
+ });
1355
+ }
1356
+ }
1357
+ }
1358
+ ] : [];
1281
1359
  let llmInstance;
1282
- if (model?.integrationId) {
1360
+ if (finalModel?.integrationId) {
1283
1361
  if (!authToken) {
1284
1362
  throw new Error("Auth token is required to instantiate LLM from integration");
1285
1363
  }
1286
- llmInstance = await createLLMFromModel(model, authToken, stream);
1287
- } else if (typeof model?.bindTools === "function") {
1288
- llmInstance = model;
1364
+ llmInstance = await createLLMFromModel(finalModel, authToken, stream);
1365
+ } else if (typeof finalModel?.bindTools === "function") {
1366
+ llmInstance = finalModel;
1289
1367
  } else {
1290
1368
  throw new Error("Invalid model: must have integrationId or be a valid LLM instance with bindTools method");
1291
1369
  }
1370
+ if (stream && callbacks.length > 0) {
1371
+ if (llmInstance.callbacks) {
1372
+ if (Array.isArray(llmInstance.callbacks)) {
1373
+ llmInstance.callbacks.push(...callbacks);
1374
+ }
1375
+ } else {
1376
+ llmInstance.callbacks = callbacks;
1377
+ }
1378
+ }
1292
1379
  const agent = (0, import_prebuilt.createReactAgent)({
1293
1380
  llm: llmInstance,
1294
1381
  tools: toolsArray,
@@ -1305,14 +1392,17 @@ IMPORTANT: You must base your response on the last message in the conversation h
1305
1392
  let output = "";
1306
1393
  if (message) {
1307
1394
  try {
1308
- const invokeConfig = checkpointer ? { configurable: { thread_id: sessionId } } : {};
1395
+ const invokeConfig = {
1396
+ ...checkpointer ? { configurable: { thread_id: sessionId } } : {},
1397
+ callbacks
1398
+ // Also pass here as backup
1399
+ };
1309
1400
  if (stream && emitter) {
1310
1401
  const streamIterator = await agent.stream(
1311
1402
  { messages: [new import_messages.HumanMessage(message)] },
1312
1403
  invokeConfig
1313
1404
  );
1314
1405
  let lastMessages = [];
1315
- const sentContents = /* @__PURE__ */ new Set();
1316
1406
  for await (const step of streamIterator) {
1317
1407
  if (step && typeof step === "object") {
1318
1408
  for (const [key, value] of Object.entries(step)) {
@@ -1320,21 +1410,6 @@ IMPORTANT: You must base your response on the last message in the conversation h
1320
1410
  const messages = value.messages;
1321
1411
  if (Array.isArray(messages)) {
1322
1412
  lastMessages = messages;
1323
- for (const msg of messages) {
1324
- const content = msg?.content;
1325
- const contentStr = typeof content === "string" ? content : Array.isArray(content) ? content.map((p) => p.type === "text" ? p.text : "").filter(Boolean).join("") : "";
1326
- if (contentStr && !sentContents.has(contentStr)) {
1327
- sentContents.add(contentStr);
1328
- if (emitter?.emitDelta) {
1329
- emitter.emitDelta({
1330
- content: contentStr,
1331
- actor: name,
1332
- isAgent: true,
1333
- isTool: false
1334
- });
1335
- }
1336
- }
1337
- }
1338
1413
  }
1339
1414
  }
1340
1415
  }
@@ -1376,22 +1451,42 @@ IMPORTANT: You must base your response on the last message in the conversation h
1376
1451
  }
1377
1452
  if (output && afterGuardrails) {
1378
1453
  const preparedAfter = await prepareGuardrails(afterGuardrails);
1379
- const afterResults = await executeGuardrails(preparedAfter, output, guardrailMode);
1454
+ const context = { ...inputs, input: output };
1455
+ const afterResults = await executeGuardrails(preparedAfter, output, guardrailMode, context);
1380
1456
  if (afterResults.blocked) {
1381
1457
  console.log(`\u{1F6E1}\uFE0F IaAgentNode "${name}": Response blocked by after-agent guardrail:`, afterResults.message);
1458
+ isBlocked = true;
1459
+ guardrailViolations = afterResults.violations || [];
1382
1460
  if (stream && emitter?.emitDelta) {
1383
1461
  emitter.emitDelta({
1384
1462
  content: `
1385
1463
 
1386
- \u26A0\uFE0F RESPOSTA BLOQUEADA: ${afterResults.message}`,
1464
+ ${afterResults.message}`,
1387
1465
  actor: name,
1388
1466
  isAgent: true,
1389
1467
  isError: true
1390
1468
  });
1391
1469
  }
1392
- output = afterResults.message || "Resposta bloqueada por pol\xEDtica de seguran\xE7a.";
1393
- } else if (afterResults.modifiedContent) {
1394
- output = afterResults.modifiedContent;
1470
+ output = afterResults.message || "GUARDRAILS ATIVADO: Resposta bloqueada por pol\xEDtica de seguran\xE7a.";
1471
+ } else {
1472
+ if (afterResults.modifiedContent) {
1473
+ output = afterResults.modifiedContent;
1474
+ }
1475
+ const warnings = afterResults.violations.filter((v) => v.action === "warn");
1476
+ if (warnings.length > 0) {
1477
+ const warningText = warnings.map((w) => `
1478
+
1479
+ \u26A0\uFE0F GUARDRAILS ATIVADO: ${w.message}`).join("");
1480
+ output += warningText;
1481
+ if (stream && emitter?.emitDelta) {
1482
+ emitter.emitDelta({
1483
+ content: warningText,
1484
+ actor: name,
1485
+ isAgent: true,
1486
+ isError: false
1487
+ });
1488
+ }
1489
+ }
1395
1490
  }
1396
1491
  }
1397
1492
  } catch (error) {
@@ -1401,7 +1496,11 @@ IMPORTANT: You must base your response on the last message in the conversation h
1401
1496
  }
1402
1497
  return {
1403
1498
  agent,
1404
- output: output || ""
1499
+ response: output || "",
1500
+ output: output || "",
1501
+ // Keep both for safety
1502
+ blocked: isBlocked,
1503
+ violations: guardrailViolations
1405
1504
  };
1406
1505
  };
1407
1506
 
@@ -2399,12 +2498,14 @@ var PromptGuardrailNode = {
2399
2498
 
2400
2499
  // src/nodes/guardrails/prompt/function.ts
2401
2500
  var PromptGuardrailNodeFunction = async (inputs) => {
2402
- const { fieldValues = {} } = inputs;
2403
- const { name, prompt } = fieldValues;
2501
+ const values = inputs.fieldValues || inputs;
2502
+ const { name, prompt } = values;
2404
2503
  return {
2405
- type: "prompt",
2406
- name: name || "Prompt Guardrail",
2407
- prompt: prompt || ""
2504
+ guardrail: {
2505
+ type: "prompt",
2506
+ name: name || "Prompt Guardrail",
2507
+ prompt: prompt || ""
2508
+ }
2408
2509
  };
2409
2510
  };
2410
2511
 
@@ -2415,7 +2516,8 @@ var RuleGuardrailNodeSchema = import_zod14.z.object({
2415
2516
  phase: import_zod14.z.enum(["before", "after"]).describe("Fase de execu\xE7\xE3o"),
2416
2517
  ruleType: import_zod14.z.enum(["maxValue", "minValue", "regex", "keywords", "pii"]).describe("Tipo de regra"),
2417
2518
  config: import_zod14.z.any().describe("Configura\xE7\xE3o da regra"),
2418
- action: import_zod14.z.enum(["block", "warn", "modify"]).describe("A\xE7\xE3o em caso de viola\xE7\xE3o")
2519
+ action: import_zod14.z.enum(["block", "warn", "modify"]).describe("A\xE7\xE3o em caso de viola\xE7\xE3o"),
2520
+ actionInstruction: import_zod14.z.string().optional().describe("Instru\xE7\xE3o adicional para a a\xE7\xE3o")
2419
2521
  });
2420
2522
  var RuleGuardrailNode = {
2421
2523
  label: "Rule Guardrail",
@@ -2479,6 +2581,13 @@ var RuleGuardrailNode = {
2479
2581
  { label: "Modificar/Ocultar", value: "modify" }
2480
2582
  ]
2481
2583
  },
2584
+ {
2585
+ id: "actionInstruction",
2586
+ label: "Instru\xE7\xE3o da A\xE7\xE3o",
2587
+ type: "textarea",
2588
+ required: false,
2589
+ placeholder: "Ex: Bloquear: 'N\xE3o posso falar sobre isso'. Warn: 'Aten\xE7\xE3o...'"
2590
+ },
2482
2591
  {
2483
2592
  id: "guardrail",
2484
2593
  label: "Guardrail",
@@ -2497,15 +2606,21 @@ var RuleGuardrailNode = {
2497
2606
 
2498
2607
  // src/nodes/guardrails/rule/function.ts
2499
2608
  var RuleGuardrailNodeFunction = async (inputs) => {
2500
- const { fieldValues = {} } = inputs;
2501
- const { name, phase, ruleType, config, action } = fieldValues;
2609
+ const values = inputs.fieldValues || inputs;
2610
+ const {
2611
+ name,
2612
+ ruleType,
2613
+ config,
2614
+ action
2615
+ } = values;
2502
2616
  return {
2503
- type: "rule",
2504
- name: name || "Rule Guardrail",
2505
- phase: phase || "after",
2506
- ruleType: ruleType || "keywords",
2507
- config: config || "",
2508
- action: action || "block"
2617
+ guardrail: {
2618
+ type: "rule",
2619
+ name: name || "Rule Guardrail",
2620
+ ruleType: ruleType || "keywords",
2621
+ config: config || "",
2622
+ action: action || "block"
2623
+ }
2509
2624
  };
2510
2625
  };
2511
2626
 
@@ -2515,7 +2630,8 @@ var FunctionGuardrailNodeSchema = import_zod15.z.object({
2515
2630
  name: import_zod15.z.string().describe("Nome do guardrail"),
2516
2631
  phase: import_zod15.z.enum(["before", "after"]).describe("Fase de execu\xE7\xE3o"),
2517
2632
  description: import_zod15.z.string().optional().describe("Descri\xE7\xE3o do que a fun\xE7\xE3o valida"),
2518
- action: import_zod15.z.enum(["block", "warn", "modify", "escalate"]).describe("A\xE7\xE3o em caso de viola\xE7\xE3o")
2633
+ action: import_zod15.z.enum(["block", "warn", "modify", "escalate"]).describe("A\xE7\xE3o em caso de viola\xE7\xE3o"),
2634
+ actionInstruction: import_zod15.z.string().optional().describe("Instru\xE7\xE3o adicional para a a\xE7\xE3o")
2519
2635
  });
2520
2636
  var FunctionGuardrailNode = {
2521
2637
  label: "Function Guardrail",
@@ -2582,6 +2698,13 @@ var FunctionGuardrailNode = {
2582
2698
  { label: "Escalar (Human-in-the-loop)", value: "escalate" }
2583
2699
  ]
2584
2700
  },
2701
+ {
2702
+ id: "actionInstruction",
2703
+ label: "Instru\xE7\xE3o da A\xE7\xE3o",
2704
+ type: "textarea",
2705
+ required: false,
2706
+ placeholder: "Ex: Instru\xE7\xE3o para a modifica\xE7\xE3o ou mensagem de bloqueio"
2707
+ },
2585
2708
  {
2586
2709
  id: "guardrail",
2587
2710
  label: "Guardrail",
@@ -2600,26 +2723,24 @@ var FunctionGuardrailNode = {
2600
2723
 
2601
2724
  // src/nodes/guardrails/function/function.ts
2602
2725
  var FunctionGuardrailNodeFunction = async (inputs) => {
2603
- const { fieldValues = {} } = inputs;
2726
+ const values = inputs.fieldValues || inputs;
2604
2727
  const {
2605
2728
  name,
2606
- phase,
2607
2729
  description,
2608
2730
  action,
2609
2731
  nodeFunction,
2610
- nodeType,
2611
2732
  originalNodeData
2612
- } = fieldValues;
2733
+ } = values;
2613
2734
  return {
2614
- type: "function",
2615
- name: name || "Function Guardrail",
2616
- phase: phase || "after",
2617
- description: description || "",
2618
- action: action || "block",
2619
- // Injected by executeWorkflow.ts
2620
- nodeFunction,
2621
- nodeType,
2622
- originalNodeData
2735
+ guardrail: {
2736
+ type: "function",
2737
+ name: name || "Function Guardrail",
2738
+ description,
2739
+ action: action || "block",
2740
+ // Injected by executeWorkflow.ts
2741
+ nodeFunction,
2742
+ originalNodeData
2743
+ }
2623
2744
  };
2624
2745
  };
2625
2746
 
@@ -2629,7 +2750,9 @@ var ModelGuardrailNodeSchema = import_zod16.z.object({
2629
2750
  name: import_zod16.z.string().describe("Nome do guardrail"),
2630
2751
  evaluationPrompt: import_zod16.z.string().describe("Prompt de avalia\xE7\xE3o"),
2631
2752
  model: import_zod16.z.any().describe("Modelo LLM para avalia\xE7\xE3o"),
2632
- action: import_zod16.z.enum(["block", "warn", "escalate"]).describe("A\xE7\xE3o em caso de viola\xE7\xE3o")
2753
+ action: import_zod16.z.enum(["block", "warn", "fix", "escalate"]).describe("A\xE7\xE3o em caso de viola\xE7\xE3o"),
2754
+ phase: import_zod16.z.enum(["before", "after"]).describe("Fase de execu\xE7\xE3o"),
2755
+ actionInstruction: import_zod16.z.string().optional().describe("Instru\xE7\xE3o adicional para a a\xE7\xE3o")
2633
2756
  });
2634
2757
  var ModelGuardrailNode = {
2635
2758
  label: "Model Guardrail",
@@ -2680,10 +2803,29 @@ var ModelGuardrailNode = {
2680
2803
  defaultValue: "block",
2681
2804
  options: [
2682
2805
  { label: "Bloquear Resposta", value: "block" },
2806
+ { label: "Corrigir/Reescrever (Fix)", value: "fix" },
2683
2807
  { label: "Avisar (Warning)", value: "warn" },
2684
2808
  { label: "Escalar (Human-in-the-loop)", value: "escalate" }
2685
2809
  ]
2686
2810
  },
2811
+ {
2812
+ id: "actionInstruction",
2813
+ label: "Instru\xE7\xE3o da A\xE7\xE3o",
2814
+ type: "textarea",
2815
+ required: false,
2816
+ placeholder: "Ex: Se bloquear, diga 'Pol\xEDtica violada'. Se corrigir, 'Reescreva com...'"
2817
+ },
2818
+ {
2819
+ id: "phase",
2820
+ label: "Fase de Execu\xE7\xE3o",
2821
+ type: "select",
2822
+ required: true,
2823
+ defaultValue: "after",
2824
+ options: [
2825
+ { label: "Antes do Agente (Input)", value: "before" },
2826
+ { label: "Depois do Agente (Output)", value: "after" }
2827
+ ]
2828
+ },
2687
2829
  {
2688
2830
  id: "guardrail",
2689
2831
  label: "Guardrail",
@@ -2702,19 +2844,25 @@ var ModelGuardrailNode = {
2702
2844
 
2703
2845
  // src/nodes/guardrails/model/function.ts
2704
2846
  var ModelGuardrailNodeFunction = async (inputs) => {
2705
- const { fieldValues = {} } = inputs;
2847
+ const values = inputs.fieldValues || inputs;
2706
2848
  const {
2707
2849
  name,
2708
2850
  evaluationPrompt,
2709
2851
  model,
2710
2852
  action
2711
- } = fieldValues;
2853
+ } = values;
2854
+ const defaultModel = {
2855
+ model: "gemini-flash-latest",
2856
+ integrationId: "default-gemini"
2857
+ };
2712
2858
  return {
2713
- type: "model",
2714
- name: name || "Model Guardrail",
2715
- evaluationPrompt: evaluationPrompt || "Avalie se este conte\xFAdo \xE9 seguro. Responda apenas SAFE ou UNSAFE.",
2716
- model,
2717
- action: action || "block"
2859
+ guardrail: {
2860
+ type: "model",
2861
+ name: name || "Model Guardrail",
2862
+ evaluationPrompt: evaluationPrompt || "Analise se o conte\xFAdo a seguir \xE9 apropriado, seguro e segue as pol\xEDticas de \xE9tica. Responda 'SAFE' se estiver tudo bem ou 'UNSAFE' caso contr\xE1rio.\n\nCONTE\xDADO:\n{{content}}",
2863
+ model: model || defaultModel,
2864
+ action: action || "block"
2865
+ }
2718
2866
  };
2719
2867
  };
2720
2868
 
package/dist/index.js CHANGED
@@ -913,39 +913,50 @@ var IaAgentNode = {
913
913
  typeable: false,
914
914
  handle: {
915
915
  type: "output",
916
- label: "response",
916
+ label: "Response",
917
917
  name: "response",
918
918
  fieldType: "string"
919
919
  }
920
920
  },
921
921
  {
922
- id: "beforeGuardrails",
923
- label: "Before Guardrails",
924
- type: "guardrail",
922
+ id: "blocked",
923
+ label: "Is Blocked",
924
+ type: "boolean",
925
925
  required: false,
926
926
  typeable: false,
927
927
  handle: {
928
- type: "input",
929
- label: "Before Guardrails",
930
- name: "beforeGuardrails",
931
- fieldType: "guardrail",
932
- acceptTypes: ["guardrail"],
933
- maxConnections: 10
928
+ type: "output",
929
+ label: "Blocked",
930
+ name: "blocked",
931
+ fieldType: "boolean"
934
932
  }
935
933
  },
936
934
  {
937
- id: "afterGuardrails",
938
- label: "After Guardrails",
935
+ id: "violations",
936
+ label: "Violations",
937
+ type: "json",
938
+ required: false,
939
+ typeable: false,
940
+ handle: {
941
+ type: "output",
942
+ label: "Violations",
943
+ name: "violations",
944
+ fieldType: "json"
945
+ }
946
+ },
947
+ {
948
+ id: "guardrails",
949
+ label: "Guardrails (Todas as Fases)",
939
950
  type: "guardrail",
940
951
  required: false,
941
952
  typeable: false,
942
953
  handle: {
943
954
  type: "input",
944
- label: "After Guardrails",
945
- name: "afterGuardrails",
955
+ label: "Guardrails",
956
+ name: "guardrails",
946
957
  fieldType: "guardrail",
947
958
  acceptTypes: ["guardrail"],
948
- maxConnections: 10
959
+ maxConnections: 20
949
960
  }
950
961
  },
951
962
  {
@@ -1023,7 +1034,7 @@ async function createLLMFromModel(modelConfig, authToken, streaming = false) {
1023
1034
  }
1024
1035
 
1025
1036
  // src/utils/guardrail-executor.ts
1026
- async function executeGuardrails(guardrails, content, mode = "fail-first") {
1037
+ async function executeGuardrails(guardrails, content, mode = "fail-first", context = {}) {
1027
1038
  const list = Array.isArray(guardrails) ? guardrails : [guardrails];
1028
1039
  const result = {
1029
1040
  passed: true,
@@ -1036,7 +1047,7 @@ async function executeGuardrails(guardrails, content, mode = "fail-first") {
1036
1047
  let guardPassed = true;
1037
1048
  let violationMessage = "";
1038
1049
  if (guard.type === "rule") {
1039
- const { ruleType, config, action } = guard;
1050
+ const { ruleType, config, action, actionInstruction } = guard;
1040
1051
  if (ruleType === "keywords" && config) {
1041
1052
  const keywords = config.split(",").map((k) => k.trim().toLowerCase());
1042
1053
  const lowerContent = content.toLowerCase();
@@ -1070,18 +1081,33 @@ async function executeGuardrails(guardrails, content, mode = "fail-first") {
1070
1081
  violationMessage = `Valor ${val} \xE9 menor que o m\xEDnimo permitido de ${min}.`;
1071
1082
  }
1072
1083
  }
1084
+ if (!guardPassed && actionInstruction) {
1085
+ violationMessage = actionInstruction;
1086
+ }
1073
1087
  } else if (guard.type === "function") {
1074
- const { nodeFunction, name } = guard;
1088
+ const { nodeFunction, name, actionInstruction } = guard;
1075
1089
  if (typeof nodeFunction === "function") {
1076
1090
  try {
1091
+ const executionContext = {
1092
+ input: content,
1093
+ ...context
1094
+ };
1077
1095
  const result2 = await nodeFunction({
1078
1096
  input: content,
1079
- fieldValues: { input: content },
1080
- originalNodeData: guard.originalNodeData
1097
+ fieldValues: { input: content, ...executionContext },
1098
+ // Envia contexto como fieldValues
1099
+ originalNodeData: guard.originalNodeData,
1100
+ $req: context?.$req,
1101
+ // Pass request context explicitly
1102
+ $vars: context?.$vars
1103
+ // Pass variables explicitly
1081
1104
  });
1082
1105
  if (result2 === false || typeof result2 === "object" && result2?.passed === false) {
1083
1106
  guardPassed = false;
1084
1107
  violationMessage = typeof result2?.message === "string" ? result2.message : `Fun\xE7\xE3o guardrail "${name}" reprovou o conte\xFAdo.`;
1108
+ if (actionInstruction) {
1109
+ violationMessage = actionInstruction;
1110
+ }
1085
1111
  } else if (typeof result2 === "object" && result2?.modifiedContent) {
1086
1112
  result2.modifiedContent = result2.modifiedContent;
1087
1113
  }
@@ -1092,15 +1118,41 @@ async function executeGuardrails(guardrails, content, mode = "fail-first") {
1092
1118
  }
1093
1119
  }
1094
1120
  } else if (guard.type === "model") {
1095
- const { model, evaluationPrompt, name } = guard;
1121
+ const { model, evaluationPrompt, name, actionInstruction } = guard;
1096
1122
  if (model && typeof model.invoke === "function") {
1097
1123
  try {
1098
- const prompt = evaluationPrompt.replace("{{content}}", content);
1124
+ let prompt = evaluationPrompt;
1125
+ if (actionInstruction) {
1126
+ prompt += `
1127
+
1128
+ INSTRU\xC7\xC3O ADICIONAL DE A\xC7\xC3O:
1129
+ ${actionInstruction}`;
1130
+ }
1131
+ if (prompt.includes("{{content}}")) {
1132
+ prompt = prompt.replace("{{content}}", content);
1133
+ } else {
1134
+ prompt = `${prompt}
1135
+
1136
+ CONTE\xDADO PARA AVALIAR:
1137
+ ${content}`;
1138
+ }
1099
1139
  const response = await model.invoke(prompt);
1100
1140
  const resultText = typeof response.content === "string" ? response.content : String(response.content);
1101
- if (resultText.toUpperCase().includes("UNSAFE")) {
1102
- guardPassed = false;
1103
- violationMessage = `Modelo de avalia\xE7\xE3o "${name}" detectou viola\xE7\xE3o de seguran\xE7a/pol\xEDtica.`;
1141
+ if (guard.action === "fix") {
1142
+ if (resultText && resultText.trim() !== content.trim() && !resultText.includes("SAFE")) {
1143
+ result.modifiedContent = resultText;
1144
+ violationMessage = `Conte\xFAdo reescrito pelo guardrail "${name}".`;
1145
+ result.violations.push({
1146
+ name: guard.name,
1147
+ message: violationMessage,
1148
+ action: "fix"
1149
+ });
1150
+ }
1151
+ } else {
1152
+ if (resultText.toUpperCase().includes("UNSAFE")) {
1153
+ guardPassed = false;
1154
+ violationMessage = actionInstruction || `Modelo de avalia\xE7\xE3o "${name}" detectou viola\xE7\xE3o de seguran\xE7a/pol\xEDtica.`;
1155
+ }
1104
1156
  }
1105
1157
  } catch (error) {
1106
1158
  console.error(`Error executing model guardrail "${name}":`, error);
@@ -1116,7 +1168,7 @@ async function executeGuardrails(guardrails, content, mode = "fail-first") {
1116
1168
  });
1117
1169
  if (guard.action === "block") {
1118
1170
  result.blocked = true;
1119
- result.message = violationMessage;
1171
+ result.message = `GUARDRAILS ATIVADO: ${violationMessage}`;
1120
1172
  if (mode === "fail-first") break;
1121
1173
  }
1122
1174
  }
@@ -1140,7 +1192,10 @@ GUARDRAIL [${guard.name}]: ${guard.prompt}`;
1140
1192
  var IaAgentNodeFunction = async (inputs) => {
1141
1193
  const { $field: _$field, $req: _$req, $inputs: _$inputs, $vars: _$vars } = inputs;
1142
1194
  const fieldValues = inputs.fieldValues || {};
1143
- const { model, tools, systemMessage, name, message, beforeGuardrails, afterGuardrails, guardrailMode } = fieldValues;
1195
+ const { model, tools, systemMessage, name, message, guardrails, guardrailMode } = fieldValues;
1196
+ const guardrailsList = Array.isArray(guardrails) ? guardrails : guardrails ? [guardrails] : [];
1197
+ const beforeGuardrails = guardrailsList.filter((g) => g?.phase === "before");
1198
+ const afterGuardrails = guardrailsList.filter((g) => !g?.phase || g?.phase === "after");
1144
1199
  const authToken = inputs.authToken;
1145
1200
  const stream = Boolean(inputs?.stream);
1146
1201
  const emitter = inputs?.emitter;
@@ -1151,8 +1206,8 @@ var IaAgentNodeFunction = async (inputs) => {
1151
1206
  throw new Error("Agent 'name' is required. Please provide a unique name for the agent in the node properties.");
1152
1207
  }
1153
1208
  const prepareGuardrails = async (list) => {
1154
- const guardrailsList = Array.isArray(list) ? list : [list];
1155
- return await Promise.all(guardrailsList.map(async (g) => {
1209
+ const guardrailsList2 = Array.isArray(list) ? list : [list];
1210
+ return await Promise.all(guardrailsList2.map(async (g) => {
1156
1211
  if (g?.type === "model" && g.model && !g.model.invoke) {
1157
1212
  if (!authToken) throw new Error("Auth token required for model guardrail");
1158
1213
  const modelInstance = await createLLMFromModel(g.model, authToken, false);
@@ -1161,9 +1216,12 @@ var IaAgentNodeFunction = async (inputs) => {
1161
1216
  return g;
1162
1217
  }));
1163
1218
  };
1219
+ let isBlocked = false;
1220
+ let guardrailViolations = [];
1164
1221
  if (message && beforeGuardrails) {
1165
1222
  const preparedBefore = await prepareGuardrails(beforeGuardrails);
1166
- const beforeResults = await executeGuardrails(preparedBefore, message, guardrailMode);
1223
+ const context = { ...inputs, input: message };
1224
+ const beforeResults = await executeGuardrails(preparedBefore, message, guardrailMode, context);
1167
1225
  if (beforeResults.blocked) {
1168
1226
  console.log(`\u{1F6E1}\uFE0F IaAgentNode "${name}": Blocked by before-agent guardrail:`, beforeResults.message);
1169
1227
  if (stream && emitter?.emitDelta) {
@@ -1176,9 +1234,9 @@ var IaAgentNodeFunction = async (inputs) => {
1176
1234
  }
1177
1235
  return {
1178
1236
  agent: null,
1179
- output: beforeResults.message || "Requisi\xE7\xE3o bloqueada por pol\xEDtica de seguran\xE7a.",
1237
+ output: beforeResults.message || "GUARDRAILS ATIVADO: Requisi\xE7\xE3o bloqueada por pol\xEDtica de seguran\xE7a.",
1180
1238
  blocked: true,
1181
- violations: beforeResults.violations
1239
+ violations: beforeResults.violations || []
1182
1240
  };
1183
1241
  }
1184
1242
  }
@@ -1198,17 +1256,46 @@ IMPORTANT: You must base your response on the last message in the conversation h
1198
1256
  finalSystemMessageContent = applyPromptGuardrails(finalSystemMessageContent, afterGuardrails);
1199
1257
  }
1200
1258
  const finalSystemMessage = new SystemMessage(finalSystemMessageContent);
1259
+ const defaultModel = {
1260
+ model: "gemini-flash-latest",
1261
+ integrationId: "default-gemini"
1262
+ };
1263
+ const finalModel = model?.integrationId || typeof model?.bindTools === "function" ? model : defaultModel;
1264
+ console.log(`\u{1F916} IaAgentNode "${name}": Using model:`, finalModel === defaultModel ? "DEFAULT (Gemini)" : finalModel?.model || "instance");
1265
+ const callbacks = stream && emitter ? [
1266
+ {
1267
+ handleLLMNewToken: (token) => {
1268
+ if (emitter?.emitDelta) {
1269
+ emitter.emitDelta({
1270
+ content: token,
1271
+ actor: name,
1272
+ isAgent: true,
1273
+ isTool: false
1274
+ });
1275
+ }
1276
+ }
1277
+ }
1278
+ ] : [];
1201
1279
  let llmInstance;
1202
- if (model?.integrationId) {
1280
+ if (finalModel?.integrationId) {
1203
1281
  if (!authToken) {
1204
1282
  throw new Error("Auth token is required to instantiate LLM from integration");
1205
1283
  }
1206
- llmInstance = await createLLMFromModel(model, authToken, stream);
1207
- } else if (typeof model?.bindTools === "function") {
1208
- llmInstance = model;
1284
+ llmInstance = await createLLMFromModel(finalModel, authToken, stream);
1285
+ } else if (typeof finalModel?.bindTools === "function") {
1286
+ llmInstance = finalModel;
1209
1287
  } else {
1210
1288
  throw new Error("Invalid model: must have integrationId or be a valid LLM instance with bindTools method");
1211
1289
  }
1290
+ if (stream && callbacks.length > 0) {
1291
+ if (llmInstance.callbacks) {
1292
+ if (Array.isArray(llmInstance.callbacks)) {
1293
+ llmInstance.callbacks.push(...callbacks);
1294
+ }
1295
+ } else {
1296
+ llmInstance.callbacks = callbacks;
1297
+ }
1298
+ }
1212
1299
  const agent = createReactAgent({
1213
1300
  llm: llmInstance,
1214
1301
  tools: toolsArray,
@@ -1225,14 +1312,17 @@ IMPORTANT: You must base your response on the last message in the conversation h
1225
1312
  let output = "";
1226
1313
  if (message) {
1227
1314
  try {
1228
- const invokeConfig = checkpointer ? { configurable: { thread_id: sessionId } } : {};
1315
+ const invokeConfig = {
1316
+ ...checkpointer ? { configurable: { thread_id: sessionId } } : {},
1317
+ callbacks
1318
+ // Also pass here as backup
1319
+ };
1229
1320
  if (stream && emitter) {
1230
1321
  const streamIterator = await agent.stream(
1231
1322
  { messages: [new HumanMessage(message)] },
1232
1323
  invokeConfig
1233
1324
  );
1234
1325
  let lastMessages = [];
1235
- const sentContents = /* @__PURE__ */ new Set();
1236
1326
  for await (const step of streamIterator) {
1237
1327
  if (step && typeof step === "object") {
1238
1328
  for (const [key, value] of Object.entries(step)) {
@@ -1240,21 +1330,6 @@ IMPORTANT: You must base your response on the last message in the conversation h
1240
1330
  const messages = value.messages;
1241
1331
  if (Array.isArray(messages)) {
1242
1332
  lastMessages = messages;
1243
- for (const msg of messages) {
1244
- const content = msg?.content;
1245
- const contentStr = typeof content === "string" ? content : Array.isArray(content) ? content.map((p) => p.type === "text" ? p.text : "").filter(Boolean).join("") : "";
1246
- if (contentStr && !sentContents.has(contentStr)) {
1247
- sentContents.add(contentStr);
1248
- if (emitter?.emitDelta) {
1249
- emitter.emitDelta({
1250
- content: contentStr,
1251
- actor: name,
1252
- isAgent: true,
1253
- isTool: false
1254
- });
1255
- }
1256
- }
1257
- }
1258
1333
  }
1259
1334
  }
1260
1335
  }
@@ -1296,22 +1371,42 @@ IMPORTANT: You must base your response on the last message in the conversation h
1296
1371
  }
1297
1372
  if (output && afterGuardrails) {
1298
1373
  const preparedAfter = await prepareGuardrails(afterGuardrails);
1299
- const afterResults = await executeGuardrails(preparedAfter, output, guardrailMode);
1374
+ const context = { ...inputs, input: output };
1375
+ const afterResults = await executeGuardrails(preparedAfter, output, guardrailMode, context);
1300
1376
  if (afterResults.blocked) {
1301
1377
  console.log(`\u{1F6E1}\uFE0F IaAgentNode "${name}": Response blocked by after-agent guardrail:`, afterResults.message);
1378
+ isBlocked = true;
1379
+ guardrailViolations = afterResults.violations || [];
1302
1380
  if (stream && emitter?.emitDelta) {
1303
1381
  emitter.emitDelta({
1304
1382
  content: `
1305
1383
 
1306
- \u26A0\uFE0F RESPOSTA BLOQUEADA: ${afterResults.message}`,
1384
+ ${afterResults.message}`,
1307
1385
  actor: name,
1308
1386
  isAgent: true,
1309
1387
  isError: true
1310
1388
  });
1311
1389
  }
1312
- output = afterResults.message || "Resposta bloqueada por pol\xEDtica de seguran\xE7a.";
1313
- } else if (afterResults.modifiedContent) {
1314
- output = afterResults.modifiedContent;
1390
+ output = afterResults.message || "GUARDRAILS ATIVADO: Resposta bloqueada por pol\xEDtica de seguran\xE7a.";
1391
+ } else {
1392
+ if (afterResults.modifiedContent) {
1393
+ output = afterResults.modifiedContent;
1394
+ }
1395
+ const warnings = afterResults.violations.filter((v) => v.action === "warn");
1396
+ if (warnings.length > 0) {
1397
+ const warningText = warnings.map((w) => `
1398
+
1399
+ \u26A0\uFE0F GUARDRAILS ATIVADO: ${w.message}`).join("");
1400
+ output += warningText;
1401
+ if (stream && emitter?.emitDelta) {
1402
+ emitter.emitDelta({
1403
+ content: warningText,
1404
+ actor: name,
1405
+ isAgent: true,
1406
+ isError: false
1407
+ });
1408
+ }
1409
+ }
1315
1410
  }
1316
1411
  }
1317
1412
  } catch (error) {
@@ -1321,7 +1416,11 @@ IMPORTANT: You must base your response on the last message in the conversation h
1321
1416
  }
1322
1417
  return {
1323
1418
  agent,
1324
- output: output || ""
1419
+ response: output || "",
1420
+ output: output || "",
1421
+ // Keep both for safety
1422
+ blocked: isBlocked,
1423
+ violations: guardrailViolations
1325
1424
  };
1326
1425
  };
1327
1426
 
@@ -2319,12 +2418,14 @@ var PromptGuardrailNode = {
2319
2418
 
2320
2419
  // src/nodes/guardrails/prompt/function.ts
2321
2420
  var PromptGuardrailNodeFunction = async (inputs) => {
2322
- const { fieldValues = {} } = inputs;
2323
- const { name, prompt } = fieldValues;
2421
+ const values = inputs.fieldValues || inputs;
2422
+ const { name, prompt } = values;
2324
2423
  return {
2325
- type: "prompt",
2326
- name: name || "Prompt Guardrail",
2327
- prompt: prompt || ""
2424
+ guardrail: {
2425
+ type: "prompt",
2426
+ name: name || "Prompt Guardrail",
2427
+ prompt: prompt || ""
2428
+ }
2328
2429
  };
2329
2430
  };
2330
2431
 
@@ -2335,7 +2436,8 @@ var RuleGuardrailNodeSchema = z14.object({
2335
2436
  phase: z14.enum(["before", "after"]).describe("Fase de execu\xE7\xE3o"),
2336
2437
  ruleType: z14.enum(["maxValue", "minValue", "regex", "keywords", "pii"]).describe("Tipo de regra"),
2337
2438
  config: z14.any().describe("Configura\xE7\xE3o da regra"),
2338
- action: z14.enum(["block", "warn", "modify"]).describe("A\xE7\xE3o em caso de viola\xE7\xE3o")
2439
+ action: z14.enum(["block", "warn", "modify"]).describe("A\xE7\xE3o em caso de viola\xE7\xE3o"),
2440
+ actionInstruction: z14.string().optional().describe("Instru\xE7\xE3o adicional para a a\xE7\xE3o")
2339
2441
  });
2340
2442
  var RuleGuardrailNode = {
2341
2443
  label: "Rule Guardrail",
@@ -2399,6 +2501,13 @@ var RuleGuardrailNode = {
2399
2501
  { label: "Modificar/Ocultar", value: "modify" }
2400
2502
  ]
2401
2503
  },
2504
+ {
2505
+ id: "actionInstruction",
2506
+ label: "Instru\xE7\xE3o da A\xE7\xE3o",
2507
+ type: "textarea",
2508
+ required: false,
2509
+ placeholder: "Ex: Bloquear: 'N\xE3o posso falar sobre isso'. Warn: 'Aten\xE7\xE3o...'"
2510
+ },
2402
2511
  {
2403
2512
  id: "guardrail",
2404
2513
  label: "Guardrail",
@@ -2417,15 +2526,21 @@ var RuleGuardrailNode = {
2417
2526
 
2418
2527
  // src/nodes/guardrails/rule/function.ts
2419
2528
  var RuleGuardrailNodeFunction = async (inputs) => {
2420
- const { fieldValues = {} } = inputs;
2421
- const { name, phase, ruleType, config, action } = fieldValues;
2529
+ const values = inputs.fieldValues || inputs;
2530
+ const {
2531
+ name,
2532
+ ruleType,
2533
+ config,
2534
+ action
2535
+ } = values;
2422
2536
  return {
2423
- type: "rule",
2424
- name: name || "Rule Guardrail",
2425
- phase: phase || "after",
2426
- ruleType: ruleType || "keywords",
2427
- config: config || "",
2428
- action: action || "block"
2537
+ guardrail: {
2538
+ type: "rule",
2539
+ name: name || "Rule Guardrail",
2540
+ ruleType: ruleType || "keywords",
2541
+ config: config || "",
2542
+ action: action || "block"
2543
+ }
2429
2544
  };
2430
2545
  };
2431
2546
 
@@ -2435,7 +2550,8 @@ var FunctionGuardrailNodeSchema = z15.object({
2435
2550
  name: z15.string().describe("Nome do guardrail"),
2436
2551
  phase: z15.enum(["before", "after"]).describe("Fase de execu\xE7\xE3o"),
2437
2552
  description: z15.string().optional().describe("Descri\xE7\xE3o do que a fun\xE7\xE3o valida"),
2438
- action: z15.enum(["block", "warn", "modify", "escalate"]).describe("A\xE7\xE3o em caso de viola\xE7\xE3o")
2553
+ action: z15.enum(["block", "warn", "modify", "escalate"]).describe("A\xE7\xE3o em caso de viola\xE7\xE3o"),
2554
+ actionInstruction: z15.string().optional().describe("Instru\xE7\xE3o adicional para a a\xE7\xE3o")
2439
2555
  });
2440
2556
  var FunctionGuardrailNode = {
2441
2557
  label: "Function Guardrail",
@@ -2502,6 +2618,13 @@ var FunctionGuardrailNode = {
2502
2618
  { label: "Escalar (Human-in-the-loop)", value: "escalate" }
2503
2619
  ]
2504
2620
  },
2621
+ {
2622
+ id: "actionInstruction",
2623
+ label: "Instru\xE7\xE3o da A\xE7\xE3o",
2624
+ type: "textarea",
2625
+ required: false,
2626
+ placeholder: "Ex: Instru\xE7\xE3o para a modifica\xE7\xE3o ou mensagem de bloqueio"
2627
+ },
2505
2628
  {
2506
2629
  id: "guardrail",
2507
2630
  label: "Guardrail",
@@ -2520,26 +2643,24 @@ var FunctionGuardrailNode = {
2520
2643
 
2521
2644
  // src/nodes/guardrails/function/function.ts
2522
2645
  var FunctionGuardrailNodeFunction = async (inputs) => {
2523
- const { fieldValues = {} } = inputs;
2646
+ const values = inputs.fieldValues || inputs;
2524
2647
  const {
2525
2648
  name,
2526
- phase,
2527
2649
  description,
2528
2650
  action,
2529
2651
  nodeFunction,
2530
- nodeType,
2531
2652
  originalNodeData
2532
- } = fieldValues;
2653
+ } = values;
2533
2654
  return {
2534
- type: "function",
2535
- name: name || "Function Guardrail",
2536
- phase: phase || "after",
2537
- description: description || "",
2538
- action: action || "block",
2539
- // Injected by executeWorkflow.ts
2540
- nodeFunction,
2541
- nodeType,
2542
- originalNodeData
2655
+ guardrail: {
2656
+ type: "function",
2657
+ name: name || "Function Guardrail",
2658
+ description,
2659
+ action: action || "block",
2660
+ // Injected by executeWorkflow.ts
2661
+ nodeFunction,
2662
+ originalNodeData
2663
+ }
2543
2664
  };
2544
2665
  };
2545
2666
 
@@ -2549,7 +2670,9 @@ var ModelGuardrailNodeSchema = z16.object({
2549
2670
  name: z16.string().describe("Nome do guardrail"),
2550
2671
  evaluationPrompt: z16.string().describe("Prompt de avalia\xE7\xE3o"),
2551
2672
  model: z16.any().describe("Modelo LLM para avalia\xE7\xE3o"),
2552
- action: z16.enum(["block", "warn", "escalate"]).describe("A\xE7\xE3o em caso de viola\xE7\xE3o")
2673
+ action: z16.enum(["block", "warn", "fix", "escalate"]).describe("A\xE7\xE3o em caso de viola\xE7\xE3o"),
2674
+ phase: z16.enum(["before", "after"]).describe("Fase de execu\xE7\xE3o"),
2675
+ actionInstruction: z16.string().optional().describe("Instru\xE7\xE3o adicional para a a\xE7\xE3o")
2553
2676
  });
2554
2677
  var ModelGuardrailNode = {
2555
2678
  label: "Model Guardrail",
@@ -2600,10 +2723,29 @@ var ModelGuardrailNode = {
2600
2723
  defaultValue: "block",
2601
2724
  options: [
2602
2725
  { label: "Bloquear Resposta", value: "block" },
2726
+ { label: "Corrigir/Reescrever (Fix)", value: "fix" },
2603
2727
  { label: "Avisar (Warning)", value: "warn" },
2604
2728
  { label: "Escalar (Human-in-the-loop)", value: "escalate" }
2605
2729
  ]
2606
2730
  },
2731
+ {
2732
+ id: "actionInstruction",
2733
+ label: "Instru\xE7\xE3o da A\xE7\xE3o",
2734
+ type: "textarea",
2735
+ required: false,
2736
+ placeholder: "Ex: Se bloquear, diga 'Pol\xEDtica violada'. Se corrigir, 'Reescreva com...'"
2737
+ },
2738
+ {
2739
+ id: "phase",
2740
+ label: "Fase de Execu\xE7\xE3o",
2741
+ type: "select",
2742
+ required: true,
2743
+ defaultValue: "after",
2744
+ options: [
2745
+ { label: "Antes do Agente (Input)", value: "before" },
2746
+ { label: "Depois do Agente (Output)", value: "after" }
2747
+ ]
2748
+ },
2607
2749
  {
2608
2750
  id: "guardrail",
2609
2751
  label: "Guardrail",
@@ -2622,19 +2764,25 @@ var ModelGuardrailNode = {
2622
2764
 
2623
2765
  // src/nodes/guardrails/model/function.ts
2624
2766
  var ModelGuardrailNodeFunction = async (inputs) => {
2625
- const { fieldValues = {} } = inputs;
2767
+ const values = inputs.fieldValues || inputs;
2626
2768
  const {
2627
2769
  name,
2628
2770
  evaluationPrompt,
2629
2771
  model,
2630
2772
  action
2631
- } = fieldValues;
2773
+ } = values;
2774
+ const defaultModel = {
2775
+ model: "gemini-flash-latest",
2776
+ integrationId: "default-gemini"
2777
+ };
2632
2778
  return {
2633
- type: "model",
2634
- name: name || "Model Guardrail",
2635
- evaluationPrompt: evaluationPrompt || "Avalie se este conte\xFAdo \xE9 seguro. Responda apenas SAFE ou UNSAFE.",
2636
- model,
2637
- action: action || "block"
2779
+ guardrail: {
2780
+ type: "model",
2781
+ name: name || "Model Guardrail",
2782
+ evaluationPrompt: evaluationPrompt || "Analise se o conte\xFAdo a seguir \xE9 apropriado, seguro e segue as pol\xEDticas de \xE9tica. Responda 'SAFE' se estiver tudo bem ou 'UNSAFE' caso contr\xE1rio.\n\nCONTE\xDADO:\n{{content}}",
2783
+ model: model || defaultModel,
2784
+ action: action || "block"
2785
+ }
2638
2786
  };
2639
2787
  };
2640
2788
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomoz/workflows-nodes",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "description": "Atomoz Workflows - Node Library",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",