@atomoz/workflows-nodes 0.1.22 → 0.1.24
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 +302 -97
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +302 -97
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -913,39 +913,50 @@ var IaAgentNode = {
|
|
|
913
913
|
typeable: false,
|
|
914
914
|
handle: {
|
|
915
915
|
type: "output",
|
|
916
|
-
label: "
|
|
916
|
+
label: "Response",
|
|
917
917
|
name: "response",
|
|
918
918
|
fieldType: "string"
|
|
919
919
|
}
|
|
920
920
|
},
|
|
921
921
|
{
|
|
922
|
-
id: "
|
|
923
|
-
label: "
|
|
924
|
-
type: "
|
|
922
|
+
id: "blocked",
|
|
923
|
+
label: "Is Blocked",
|
|
924
|
+
type: "boolean",
|
|
925
925
|
required: false,
|
|
926
926
|
typeable: false,
|
|
927
927
|
handle: {
|
|
928
|
-
type: "
|
|
929
|
-
label: "
|
|
930
|
-
name: "
|
|
931
|
-
fieldType: "
|
|
932
|
-
|
|
933
|
-
|
|
928
|
+
type: "output",
|
|
929
|
+
label: "Blocked",
|
|
930
|
+
name: "blocked",
|
|
931
|
+
fieldType: "boolean"
|
|
932
|
+
}
|
|
933
|
+
},
|
|
934
|
+
{
|
|
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"
|
|
934
945
|
}
|
|
935
946
|
},
|
|
936
947
|
{
|
|
937
|
-
id: "
|
|
938
|
-
label: "
|
|
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: "
|
|
945
|
-
name: "
|
|
955
|
+
label: "Guardrails",
|
|
956
|
+
name: "guardrails",
|
|
946
957
|
fieldType: "guardrail",
|
|
947
958
|
acceptTypes: ["guardrail"],
|
|
948
|
-
maxConnections:
|
|
959
|
+
maxConnections: 20
|
|
949
960
|
}
|
|
950
961
|
},
|
|
951
962
|
{
|
|
@@ -997,7 +1008,7 @@ async function createLLMFromModel(modelConfig, authToken, streaming = false) {
|
|
|
997
1008
|
case "gemini":
|
|
998
1009
|
return new ChatGoogle({
|
|
999
1010
|
model: "gemini-flash-latest",
|
|
1000
|
-
apiKey: "
|
|
1011
|
+
apiKey: "AIzaSyBzrL8Hx6dHhXgwc2HfLlQsf5Y-9pdtc9M",
|
|
1001
1012
|
streaming
|
|
1002
1013
|
});
|
|
1003
1014
|
case "openai":
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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 (
|
|
1102
|
-
|
|
1103
|
-
|
|
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,
|
|
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
|
|
1155
|
-
return await Promise.all(
|
|
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
|
|
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,65 @@ 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 tokenUsage = { input: 0, output: 0, total: 0 };
|
|
1266
|
+
const callbacks = [
|
|
1267
|
+
{
|
|
1268
|
+
handleLLMEnd: (output2) => {
|
|
1269
|
+
let usage = output2.llmOutput?.tokenUsage || output2.llmOutput?.estimatedTokenUsage;
|
|
1270
|
+
if (!usage && output2.generations && Array.isArray(output2.generations) && output2.generations.length > 0) {
|
|
1271
|
+
const firstGen = output2.generations[0][0];
|
|
1272
|
+
if (firstGen?.generationInfo?.tokenUsage) {
|
|
1273
|
+
usage = firstGen.generationInfo.tokenUsage;
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
if (usage) {
|
|
1277
|
+
tokenUsage.input += usage.promptTokens || usage.input_tokens || 0;
|
|
1278
|
+
tokenUsage.output += usage.completionTokens || usage.output_tokens || 0;
|
|
1279
|
+
tokenUsage.total += usage.totalTokens || usage.total_tokens || 0;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
];
|
|
1284
|
+
if (stream && emitter) {
|
|
1285
|
+
callbacks.push({
|
|
1286
|
+
handleLLMNewToken: (token) => {
|
|
1287
|
+
if (emitter?.emitDelta) {
|
|
1288
|
+
emitter.emitDelta({
|
|
1289
|
+
content: token,
|
|
1290
|
+
actor: name,
|
|
1291
|
+
isAgent: true,
|
|
1292
|
+
isTool: false
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1201
1298
|
let llmInstance;
|
|
1202
|
-
if (
|
|
1299
|
+
if (finalModel?.integrationId) {
|
|
1203
1300
|
if (!authToken) {
|
|
1204
1301
|
throw new Error("Auth token is required to instantiate LLM from integration");
|
|
1205
1302
|
}
|
|
1206
|
-
llmInstance = await createLLMFromModel(
|
|
1207
|
-
} else if (typeof
|
|
1208
|
-
llmInstance =
|
|
1303
|
+
llmInstance = await createLLMFromModel(finalModel, authToken, stream);
|
|
1304
|
+
} else if (typeof finalModel?.bindTools === "function") {
|
|
1305
|
+
llmInstance = finalModel;
|
|
1209
1306
|
} else {
|
|
1210
1307
|
throw new Error("Invalid model: must have integrationId or be a valid LLM instance with bindTools method");
|
|
1211
1308
|
}
|
|
1309
|
+
if (callbacks.length > 0) {
|
|
1310
|
+
if (llmInstance.callbacks) {
|
|
1311
|
+
if (Array.isArray(llmInstance.callbacks)) {
|
|
1312
|
+
llmInstance.callbacks.push(...callbacks);
|
|
1313
|
+
}
|
|
1314
|
+
} else {
|
|
1315
|
+
llmInstance.callbacks = callbacks;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1212
1318
|
const agent = createReactAgent({
|
|
1213
1319
|
llm: llmInstance,
|
|
1214
1320
|
tools: toolsArray,
|
|
@@ -1225,14 +1331,17 @@ IMPORTANT: You must base your response on the last message in the conversation h
|
|
|
1225
1331
|
let output = "";
|
|
1226
1332
|
if (message) {
|
|
1227
1333
|
try {
|
|
1228
|
-
const invokeConfig =
|
|
1334
|
+
const invokeConfig = {
|
|
1335
|
+
...checkpointer ? { configurable: { thread_id: sessionId } } : {},
|
|
1336
|
+
callbacks
|
|
1337
|
+
// Also pass here as backup
|
|
1338
|
+
};
|
|
1229
1339
|
if (stream && emitter) {
|
|
1230
1340
|
const streamIterator = await agent.stream(
|
|
1231
1341
|
{ messages: [new HumanMessage(message)] },
|
|
1232
1342
|
invokeConfig
|
|
1233
1343
|
);
|
|
1234
1344
|
let lastMessages = [];
|
|
1235
|
-
const sentContents = /* @__PURE__ */ new Set();
|
|
1236
1345
|
for await (const step of streamIterator) {
|
|
1237
1346
|
if (step && typeof step === "object") {
|
|
1238
1347
|
for (const [key, value] of Object.entries(step)) {
|
|
@@ -1240,21 +1349,6 @@ IMPORTANT: You must base your response on the last message in the conversation h
|
|
|
1240
1349
|
const messages = value.messages;
|
|
1241
1350
|
if (Array.isArray(messages)) {
|
|
1242
1351
|
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
1352
|
}
|
|
1259
1353
|
}
|
|
1260
1354
|
}
|
|
@@ -1263,6 +1357,22 @@ IMPORTANT: You must base your response on the last message in the conversation h
|
|
|
1263
1357
|
if (lastMessages.length > 0) {
|
|
1264
1358
|
const lastMessage = lastMessages[lastMessages.length - 1];
|
|
1265
1359
|
const content = lastMessage?.content;
|
|
1360
|
+
const msg = lastMessage;
|
|
1361
|
+
const usageMetadata = msg?.response_metadata?.tokenUsage || msg?.response_metadata?.usage || msg?.usage_metadata;
|
|
1362
|
+
if (usageMetadata) {
|
|
1363
|
+
const input = usageMetadata.promptTokens || usageMetadata.input_tokens || 0;
|
|
1364
|
+
const output2 = usageMetadata.completionTokens || usageMetadata.output_tokens || 0;
|
|
1365
|
+
const total = usageMetadata.totalTokens || usageMetadata.total_tokens || 0;
|
|
1366
|
+
if (tokenUsage.total === 0) {
|
|
1367
|
+
if (input + output2 > 0) {
|
|
1368
|
+
tokenUsage.input = input;
|
|
1369
|
+
tokenUsage.output = output2;
|
|
1370
|
+
tokenUsage.total = input + output2;
|
|
1371
|
+
} else if (total > 0) {
|
|
1372
|
+
tokenUsage.total = total;
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1266
1376
|
if (typeof content === "string") {
|
|
1267
1377
|
output = content;
|
|
1268
1378
|
} else if (Array.isArray(content)) {
|
|
@@ -1281,6 +1391,22 @@ IMPORTANT: You must base your response on the last message in the conversation h
|
|
|
1281
1391
|
if (result?.messages && result.messages.length > 0) {
|
|
1282
1392
|
const lastMessage = result.messages[result.messages.length - 1];
|
|
1283
1393
|
const content = lastMessage?.content;
|
|
1394
|
+
const msg = lastMessage;
|
|
1395
|
+
const usageMetadata = msg?.response_metadata?.tokenUsage || msg?.response_metadata?.usage || msg?.usage_metadata;
|
|
1396
|
+
if (usageMetadata) {
|
|
1397
|
+
const input = usageMetadata.promptTokens || usageMetadata.input_tokens || 0;
|
|
1398
|
+
const output2 = usageMetadata.completionTokens || usageMetadata.output_tokens || 0;
|
|
1399
|
+
const total = usageMetadata.totalTokens || usageMetadata.total_tokens || 0;
|
|
1400
|
+
if (tokenUsage.total === 0) {
|
|
1401
|
+
if (input + output2 > 0) {
|
|
1402
|
+
tokenUsage.input = input;
|
|
1403
|
+
tokenUsage.output = output2;
|
|
1404
|
+
tokenUsage.total = input + output2;
|
|
1405
|
+
} else if (total > 0) {
|
|
1406
|
+
tokenUsage.total = total;
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1284
1410
|
if (typeof content === "string") {
|
|
1285
1411
|
output = content;
|
|
1286
1412
|
} else if (Array.isArray(content)) {
|
|
@@ -1296,22 +1422,42 @@ IMPORTANT: You must base your response on the last message in the conversation h
|
|
|
1296
1422
|
}
|
|
1297
1423
|
if (output && afterGuardrails) {
|
|
1298
1424
|
const preparedAfter = await prepareGuardrails(afterGuardrails);
|
|
1299
|
-
const
|
|
1425
|
+
const context = { ...inputs, input: output };
|
|
1426
|
+
const afterResults = await executeGuardrails(preparedAfter, output, guardrailMode, context);
|
|
1300
1427
|
if (afterResults.blocked) {
|
|
1301
1428
|
console.log(`\u{1F6E1}\uFE0F IaAgentNode "${name}": Response blocked by after-agent guardrail:`, afterResults.message);
|
|
1429
|
+
isBlocked = true;
|
|
1430
|
+
guardrailViolations = afterResults.violations || [];
|
|
1302
1431
|
if (stream && emitter?.emitDelta) {
|
|
1303
1432
|
emitter.emitDelta({
|
|
1304
1433
|
content: `
|
|
1305
1434
|
|
|
1306
|
-
|
|
1435
|
+
${afterResults.message}`,
|
|
1307
1436
|
actor: name,
|
|
1308
1437
|
isAgent: true,
|
|
1309
1438
|
isError: true
|
|
1310
1439
|
});
|
|
1311
1440
|
}
|
|
1312
|
-
output = afterResults.message || "Resposta bloqueada por pol\xEDtica de seguran\xE7a.";
|
|
1313
|
-
} else
|
|
1314
|
-
|
|
1441
|
+
output = afterResults.message || "GUARDRAILS ATIVADO: Resposta bloqueada por pol\xEDtica de seguran\xE7a.";
|
|
1442
|
+
} else {
|
|
1443
|
+
if (afterResults.modifiedContent) {
|
|
1444
|
+
output = afterResults.modifiedContent;
|
|
1445
|
+
}
|
|
1446
|
+
const warnings = afterResults.violations.filter((v) => v.action === "warn");
|
|
1447
|
+
if (warnings.length > 0) {
|
|
1448
|
+
const warningText = warnings.map((w) => `
|
|
1449
|
+
|
|
1450
|
+
\u26A0\uFE0F GUARDRAILS ATIVADO: ${w.message}`).join("");
|
|
1451
|
+
output += warningText;
|
|
1452
|
+
if (stream && emitter?.emitDelta) {
|
|
1453
|
+
emitter.emitDelta({
|
|
1454
|
+
content: warningText,
|
|
1455
|
+
actor: name,
|
|
1456
|
+
isAgent: true,
|
|
1457
|
+
isError: false
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1315
1461
|
}
|
|
1316
1462
|
}
|
|
1317
1463
|
} catch (error) {
|
|
@@ -1319,9 +1465,19 @@ IMPORTANT: You must base your response on the last message in the conversation h
|
|
|
1319
1465
|
output = `Error: ${error instanceof Error ? error.message : "Unknown error"}`;
|
|
1320
1466
|
}
|
|
1321
1467
|
}
|
|
1468
|
+
if (tokenUsage.total === 0 && (tokenUsage.input > 0 || tokenUsage.output > 0)) {
|
|
1469
|
+
tokenUsage.total = tokenUsage.input + tokenUsage.output;
|
|
1470
|
+
} else if (tokenUsage.total !== tokenUsage.input + tokenUsage.output) {
|
|
1471
|
+
tokenUsage.total = tokenUsage.input + tokenUsage.output;
|
|
1472
|
+
}
|
|
1473
|
+
console.log(`[TOKEN COUNT] Input: ${tokenUsage.input}, Output: ${tokenUsage.output}, Total: ${tokenUsage.total}`);
|
|
1322
1474
|
return {
|
|
1323
1475
|
agent,
|
|
1324
|
-
|
|
1476
|
+
response: output || "",
|
|
1477
|
+
output: output || "",
|
|
1478
|
+
// Keep both for safety
|
|
1479
|
+
blocked: isBlocked,
|
|
1480
|
+
violations: guardrailViolations
|
|
1325
1481
|
};
|
|
1326
1482
|
};
|
|
1327
1483
|
|
|
@@ -1741,7 +1897,7 @@ import { PostgresSaver } from "@langchain/langgraph-checkpoint-postgres";
|
|
|
1741
1897
|
var PostgresMemoryNodeFunction = async (inputs) => {
|
|
1742
1898
|
const { $field: _$field, $req: _$req, $inputs: _$inputs, $vars: _$vars } = inputs;
|
|
1743
1899
|
const fieldValues = inputs.fieldValues || {};
|
|
1744
|
-
const connectionString = fieldValues.connectionString || inputs.connectionString || "postgresql://
|
|
1900
|
+
const connectionString = fieldValues.connectionString || inputs.connectionString || "postgresql://yugabyte:yugabyte@localhost:5433/workflows";
|
|
1745
1901
|
try {
|
|
1746
1902
|
const checkpointer = PostgresSaver.fromConnString(connectionString);
|
|
1747
1903
|
await checkpointer.setup();
|
|
@@ -2319,12 +2475,14 @@ var PromptGuardrailNode = {
|
|
|
2319
2475
|
|
|
2320
2476
|
// src/nodes/guardrails/prompt/function.ts
|
|
2321
2477
|
var PromptGuardrailNodeFunction = async (inputs) => {
|
|
2322
|
-
const
|
|
2323
|
-
const { name, prompt } =
|
|
2478
|
+
const values = inputs.fieldValues || inputs;
|
|
2479
|
+
const { name, prompt } = values;
|
|
2324
2480
|
return {
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2481
|
+
guardrail: {
|
|
2482
|
+
type: "prompt",
|
|
2483
|
+
name: name || "Prompt Guardrail",
|
|
2484
|
+
prompt: prompt || ""
|
|
2485
|
+
}
|
|
2328
2486
|
};
|
|
2329
2487
|
};
|
|
2330
2488
|
|
|
@@ -2335,7 +2493,8 @@ var RuleGuardrailNodeSchema = z14.object({
|
|
|
2335
2493
|
phase: z14.enum(["before", "after"]).describe("Fase de execu\xE7\xE3o"),
|
|
2336
2494
|
ruleType: z14.enum(["maxValue", "minValue", "regex", "keywords", "pii"]).describe("Tipo de regra"),
|
|
2337
2495
|
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")
|
|
2496
|
+
action: z14.enum(["block", "warn", "modify"]).describe("A\xE7\xE3o em caso de viola\xE7\xE3o"),
|
|
2497
|
+
actionInstruction: z14.string().optional().describe("Instru\xE7\xE3o adicional para a a\xE7\xE3o")
|
|
2339
2498
|
});
|
|
2340
2499
|
var RuleGuardrailNode = {
|
|
2341
2500
|
label: "Rule Guardrail",
|
|
@@ -2399,6 +2558,13 @@ var RuleGuardrailNode = {
|
|
|
2399
2558
|
{ label: "Modificar/Ocultar", value: "modify" }
|
|
2400
2559
|
]
|
|
2401
2560
|
},
|
|
2561
|
+
{
|
|
2562
|
+
id: "actionInstruction",
|
|
2563
|
+
label: "Instru\xE7\xE3o da A\xE7\xE3o",
|
|
2564
|
+
type: "textarea",
|
|
2565
|
+
required: false,
|
|
2566
|
+
placeholder: "Ex: Bloquear: 'N\xE3o posso falar sobre isso'. Warn: 'Aten\xE7\xE3o...'"
|
|
2567
|
+
},
|
|
2402
2568
|
{
|
|
2403
2569
|
id: "guardrail",
|
|
2404
2570
|
label: "Guardrail",
|
|
@@ -2417,15 +2583,21 @@ var RuleGuardrailNode = {
|
|
|
2417
2583
|
|
|
2418
2584
|
// src/nodes/guardrails/rule/function.ts
|
|
2419
2585
|
var RuleGuardrailNodeFunction = async (inputs) => {
|
|
2420
|
-
const
|
|
2421
|
-
const {
|
|
2586
|
+
const values = inputs.fieldValues || inputs;
|
|
2587
|
+
const {
|
|
2588
|
+
name,
|
|
2589
|
+
ruleType,
|
|
2590
|
+
config,
|
|
2591
|
+
action
|
|
2592
|
+
} = values;
|
|
2422
2593
|
return {
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2594
|
+
guardrail: {
|
|
2595
|
+
type: "rule",
|
|
2596
|
+
name: name || "Rule Guardrail",
|
|
2597
|
+
ruleType: ruleType || "keywords",
|
|
2598
|
+
config: config || "",
|
|
2599
|
+
action: action || "block"
|
|
2600
|
+
}
|
|
2429
2601
|
};
|
|
2430
2602
|
};
|
|
2431
2603
|
|
|
@@ -2435,7 +2607,8 @@ var FunctionGuardrailNodeSchema = z15.object({
|
|
|
2435
2607
|
name: z15.string().describe("Nome do guardrail"),
|
|
2436
2608
|
phase: z15.enum(["before", "after"]).describe("Fase de execu\xE7\xE3o"),
|
|
2437
2609
|
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")
|
|
2610
|
+
action: z15.enum(["block", "warn", "modify", "escalate"]).describe("A\xE7\xE3o em caso de viola\xE7\xE3o"),
|
|
2611
|
+
actionInstruction: z15.string().optional().describe("Instru\xE7\xE3o adicional para a a\xE7\xE3o")
|
|
2439
2612
|
});
|
|
2440
2613
|
var FunctionGuardrailNode = {
|
|
2441
2614
|
label: "Function Guardrail",
|
|
@@ -2502,6 +2675,13 @@ var FunctionGuardrailNode = {
|
|
|
2502
2675
|
{ label: "Escalar (Human-in-the-loop)", value: "escalate" }
|
|
2503
2676
|
]
|
|
2504
2677
|
},
|
|
2678
|
+
{
|
|
2679
|
+
id: "actionInstruction",
|
|
2680
|
+
label: "Instru\xE7\xE3o da A\xE7\xE3o",
|
|
2681
|
+
type: "textarea",
|
|
2682
|
+
required: false,
|
|
2683
|
+
placeholder: "Ex: Instru\xE7\xE3o para a modifica\xE7\xE3o ou mensagem de bloqueio"
|
|
2684
|
+
},
|
|
2505
2685
|
{
|
|
2506
2686
|
id: "guardrail",
|
|
2507
2687
|
label: "Guardrail",
|
|
@@ -2520,26 +2700,24 @@ var FunctionGuardrailNode = {
|
|
|
2520
2700
|
|
|
2521
2701
|
// src/nodes/guardrails/function/function.ts
|
|
2522
2702
|
var FunctionGuardrailNodeFunction = async (inputs) => {
|
|
2523
|
-
const
|
|
2703
|
+
const values = inputs.fieldValues || inputs;
|
|
2524
2704
|
const {
|
|
2525
2705
|
name,
|
|
2526
|
-
phase,
|
|
2527
2706
|
description,
|
|
2528
2707
|
action,
|
|
2529
2708
|
nodeFunction,
|
|
2530
|
-
nodeType,
|
|
2531
2709
|
originalNodeData
|
|
2532
|
-
} =
|
|
2710
|
+
} = values;
|
|
2533
2711
|
return {
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2712
|
+
guardrail: {
|
|
2713
|
+
type: "function",
|
|
2714
|
+
name: name || "Function Guardrail",
|
|
2715
|
+
description,
|
|
2716
|
+
action: action || "block",
|
|
2717
|
+
// Injected by executeWorkflow.ts
|
|
2718
|
+
nodeFunction,
|
|
2719
|
+
originalNodeData
|
|
2720
|
+
}
|
|
2543
2721
|
};
|
|
2544
2722
|
};
|
|
2545
2723
|
|
|
@@ -2549,7 +2727,9 @@ var ModelGuardrailNodeSchema = z16.object({
|
|
|
2549
2727
|
name: z16.string().describe("Nome do guardrail"),
|
|
2550
2728
|
evaluationPrompt: z16.string().describe("Prompt de avalia\xE7\xE3o"),
|
|
2551
2729
|
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")
|
|
2730
|
+
action: z16.enum(["block", "warn", "fix", "escalate"]).describe("A\xE7\xE3o em caso de viola\xE7\xE3o"),
|
|
2731
|
+
phase: z16.enum(["before", "after"]).describe("Fase de execu\xE7\xE3o"),
|
|
2732
|
+
actionInstruction: z16.string().optional().describe("Instru\xE7\xE3o adicional para a a\xE7\xE3o")
|
|
2553
2733
|
});
|
|
2554
2734
|
var ModelGuardrailNode = {
|
|
2555
2735
|
label: "Model Guardrail",
|
|
@@ -2600,10 +2780,29 @@ var ModelGuardrailNode = {
|
|
|
2600
2780
|
defaultValue: "block",
|
|
2601
2781
|
options: [
|
|
2602
2782
|
{ label: "Bloquear Resposta", value: "block" },
|
|
2783
|
+
{ label: "Corrigir/Reescrever (Fix)", value: "fix" },
|
|
2603
2784
|
{ label: "Avisar (Warning)", value: "warn" },
|
|
2604
2785
|
{ label: "Escalar (Human-in-the-loop)", value: "escalate" }
|
|
2605
2786
|
]
|
|
2606
2787
|
},
|
|
2788
|
+
{
|
|
2789
|
+
id: "actionInstruction",
|
|
2790
|
+
label: "Instru\xE7\xE3o da A\xE7\xE3o",
|
|
2791
|
+
type: "textarea",
|
|
2792
|
+
required: false,
|
|
2793
|
+
placeholder: "Ex: Se bloquear, diga 'Pol\xEDtica violada'. Se corrigir, 'Reescreva com...'"
|
|
2794
|
+
},
|
|
2795
|
+
{
|
|
2796
|
+
id: "phase",
|
|
2797
|
+
label: "Fase de Execu\xE7\xE3o",
|
|
2798
|
+
type: "select",
|
|
2799
|
+
required: true,
|
|
2800
|
+
defaultValue: "after",
|
|
2801
|
+
options: [
|
|
2802
|
+
{ label: "Antes do Agente (Input)", value: "before" },
|
|
2803
|
+
{ label: "Depois do Agente (Output)", value: "after" }
|
|
2804
|
+
]
|
|
2805
|
+
},
|
|
2607
2806
|
{
|
|
2608
2807
|
id: "guardrail",
|
|
2609
2808
|
label: "Guardrail",
|
|
@@ -2622,19 +2821,25 @@ var ModelGuardrailNode = {
|
|
|
2622
2821
|
|
|
2623
2822
|
// src/nodes/guardrails/model/function.ts
|
|
2624
2823
|
var ModelGuardrailNodeFunction = async (inputs) => {
|
|
2625
|
-
const
|
|
2824
|
+
const values = inputs.fieldValues || inputs;
|
|
2626
2825
|
const {
|
|
2627
2826
|
name,
|
|
2628
2827
|
evaluationPrompt,
|
|
2629
2828
|
model,
|
|
2630
2829
|
action
|
|
2631
|
-
} =
|
|
2830
|
+
} = values;
|
|
2831
|
+
const defaultModel = {
|
|
2832
|
+
model: "gemini-flash-latest",
|
|
2833
|
+
integrationId: "default-gemini"
|
|
2834
|
+
};
|
|
2632
2835
|
return {
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2836
|
+
guardrail: {
|
|
2837
|
+
type: "model",
|
|
2838
|
+
name: name || "Model Guardrail",
|
|
2839
|
+
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}}",
|
|
2840
|
+
model: model || defaultModel,
|
|
2841
|
+
action: action || "block"
|
|
2842
|
+
}
|
|
2638
2843
|
};
|
|
2639
2844
|
};
|
|
2640
2845
|
|