@atomoz/workflows-nodes 0.1.27 → 0.1.29
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 +723 -20
- package/dist/index.d.cts +70 -3
- package/dist/index.d.ts +70 -3
- package/dist/index.js +711 -20
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -243,7 +243,11 @@ var ChatInputNodeFunction = (params) => {
|
|
|
243
243
|
const { message: configMessage, chatId: configChatId } = fieldValues || {};
|
|
244
244
|
const actualData = {
|
|
245
245
|
message: request?.message ?? configMessage ?? "",
|
|
246
|
-
chatId: request?.chatId ?? configChatId ?? null
|
|
246
|
+
chatId: request?.chatId ?? configChatId ?? null,
|
|
247
|
+
roomId: request?.sessionId ?? request?.chatId ?? configChatId ?? null,
|
|
248
|
+
// Room = Session/Chat
|
|
249
|
+
source: "chat"
|
|
250
|
+
// Hardcoded source for web chat
|
|
247
251
|
};
|
|
248
252
|
if (!actualData.message || typeof actualData.message !== "string") {
|
|
249
253
|
throw new Error("Message is required for ChatInputNode");
|
|
@@ -286,6 +290,33 @@ var ChatInputNode = {
|
|
|
286
290
|
name: "chatId",
|
|
287
291
|
fieldType: "string"
|
|
288
292
|
}
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
id: "roomId",
|
|
296
|
+
label: "Room ID",
|
|
297
|
+
type: "string",
|
|
298
|
+
required: false,
|
|
299
|
+
typeable: false,
|
|
300
|
+
handle: {
|
|
301
|
+
type: "output",
|
|
302
|
+
label: "Room ID",
|
|
303
|
+
name: "roomId",
|
|
304
|
+
fieldType: "string"
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
id: "source",
|
|
309
|
+
label: "Source",
|
|
310
|
+
type: "string",
|
|
311
|
+
required: false,
|
|
312
|
+
typeable: false,
|
|
313
|
+
defaultValue: "chat",
|
|
314
|
+
handle: {
|
|
315
|
+
type: "output",
|
|
316
|
+
label: "Source",
|
|
317
|
+
name: "source",
|
|
318
|
+
fieldType: "string"
|
|
319
|
+
}
|
|
289
320
|
}
|
|
290
321
|
]
|
|
291
322
|
};
|
|
@@ -1008,7 +1039,7 @@ async function createLLMFromModel(modelConfig, authToken, streaming = false) {
|
|
|
1008
1039
|
case "gemini":
|
|
1009
1040
|
return new ChatGoogle({
|
|
1010
1041
|
model: "gemini-flash-latest",
|
|
1011
|
-
apiKey: "
|
|
1042
|
+
apiKey: "AIzaSyBLeXr43XWg1lOQfsUTZQ85IX-IYYpZIW0",
|
|
1012
1043
|
streaming
|
|
1013
1044
|
});
|
|
1014
1045
|
case "openai":
|
|
@@ -1034,6 +1065,18 @@ async function createLLMFromModel(modelConfig, authToken, streaming = false) {
|
|
|
1034
1065
|
}
|
|
1035
1066
|
|
|
1036
1067
|
// src/utils/guardrail-executor.ts
|
|
1068
|
+
function emitGuardrailEvent(context, name, passed, action, details) {
|
|
1069
|
+
if (context?.emitter?.emitThought) {
|
|
1070
|
+
context.emitter.emitThought({
|
|
1071
|
+
content: `guardrail:${passed ? "passed" : "failed"}:${name}`,
|
|
1072
|
+
type: "guardrail",
|
|
1073
|
+
name,
|
|
1074
|
+
passed,
|
|
1075
|
+
action: action || "evaluate",
|
|
1076
|
+
details
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1037
1080
|
async function loadChatHistory(context) {
|
|
1038
1081
|
const checkpointer = context?.checkpointer;
|
|
1039
1082
|
const sessionId = context?.sessionId;
|
|
@@ -1128,6 +1171,7 @@ async function executeGuardrails(guardrails, content, mode = "fail-first", conte
|
|
|
1128
1171
|
if (!guardPassed && actionInstruction) {
|
|
1129
1172
|
violationMessage = actionInstruction;
|
|
1130
1173
|
}
|
|
1174
|
+
emitGuardrailEvent(context, guard.name, guardPassed, guard.action, violationMessage || "Rule passed");
|
|
1131
1175
|
} else if (guard.type === "function") {
|
|
1132
1176
|
const { nodeFunction, name, actionInstruction } = guard;
|
|
1133
1177
|
if (typeof nodeFunction === "function") {
|
|
@@ -1160,6 +1204,7 @@ async function executeGuardrails(guardrails, content, mode = "fail-first", conte
|
|
|
1160
1204
|
guardPassed = false;
|
|
1161
1205
|
violationMessage = `Erro na fun\xE7\xE3o guardrail: ${error instanceof Error ? error.message : String(error)}`;
|
|
1162
1206
|
}
|
|
1207
|
+
emitGuardrailEvent(context, name, guardPassed, guard.action, violationMessage || "Function passed");
|
|
1163
1208
|
}
|
|
1164
1209
|
} else if (guard.type === "model") {
|
|
1165
1210
|
const { model, evaluationPrompt, name, actionInstruction } = guard;
|
|
@@ -1227,6 +1272,7 @@ Reescreva o conte\xFAdo corrigindo a viola\xE7\xE3o. Retorne APENAS o texto corr
|
|
|
1227
1272
|
message: violationMessage,
|
|
1228
1273
|
action: "fix"
|
|
1229
1274
|
});
|
|
1275
|
+
emitGuardrailEvent(context, name, false, "fix", `Content fixed: ${fixedContent.slice(0, 100)}...`);
|
|
1230
1276
|
} catch (fixError) {
|
|
1231
1277
|
console.error(`[GUARDRAIL LLM] Erro ao corrigir conte\xFAdo:`, fixError);
|
|
1232
1278
|
}
|
|
@@ -1238,8 +1284,10 @@ Reescreva o conte\xFAdo corrigindo a viola\xE7\xE3o. Retorne APENAS o texto corr
|
|
|
1238
1284
|
guardPassed = false;
|
|
1239
1285
|
violationMessage = actionInstruction || `Modelo de avalia\xE7\xE3o "${name}" detectou viola\xE7\xE3o de seguran\xE7a/pol\xEDtica.`;
|
|
1240
1286
|
console.log(`[GUARDRAIL LLM] Resultado: UNSAFE - Bloqueado`);
|
|
1287
|
+
emitGuardrailEvent(context, name, false, guard.action, violationMessage);
|
|
1241
1288
|
} else {
|
|
1242
1289
|
console.log(`[GUARDRAIL LLM] Resultado: SAFE - Aprovado`);
|
|
1290
|
+
emitGuardrailEvent(context, name, true, "approve", "Content passed evaluation");
|
|
1243
1291
|
}
|
|
1244
1292
|
}
|
|
1245
1293
|
} catch (error) {
|
|
@@ -1944,7 +1992,8 @@ import { tool } from "@langchain/core/tools";
|
|
|
1944
1992
|
// src/nodes/memory/postgres/data.ts
|
|
1945
1993
|
import { z as z8 } from "zod";
|
|
1946
1994
|
var PostgresMemoryNodeSchema = z8.object({
|
|
1947
|
-
connectionString: z8.string().describe("PostgreSQL connection string")
|
|
1995
|
+
connectionString: z8.string().describe("PostgreSQL connection string"),
|
|
1996
|
+
threadId: z8.string().optional().describe("Thread ID for conversation isolation")
|
|
1948
1997
|
});
|
|
1949
1998
|
var PostgresMemoryNode = {
|
|
1950
1999
|
label: "Postgres Memory",
|
|
@@ -1966,6 +2015,20 @@ var PostgresMemoryNode = {
|
|
|
1966
2015
|
defaultValue: "postgresql://yugabyte:yugabyte@localhost:5433/workflows",
|
|
1967
2016
|
placeholder: "postgresql://user:pass@host:5432/database"
|
|
1968
2017
|
},
|
|
2018
|
+
{
|
|
2019
|
+
id: "threadId",
|
|
2020
|
+
label: "Thread ID",
|
|
2021
|
+
type: "string",
|
|
2022
|
+
required: false,
|
|
2023
|
+
typeable: true,
|
|
2024
|
+
placeholder: "Thread/Session ID for conversation isolation",
|
|
2025
|
+
handle: {
|
|
2026
|
+
type: "input",
|
|
2027
|
+
label: "Thread ID",
|
|
2028
|
+
name: "threadId",
|
|
2029
|
+
fieldType: "string"
|
|
2030
|
+
}
|
|
2031
|
+
},
|
|
1969
2032
|
{
|
|
1970
2033
|
id: "checkpointer",
|
|
1971
2034
|
label: "Checkpointer",
|
|
@@ -1988,12 +2051,15 @@ var PostgresMemoryNodeFunction = async (inputs) => {
|
|
|
1988
2051
|
const { $field: _$field, $req: _$req, $inputs: _$inputs, $vars: _$vars } = inputs;
|
|
1989
2052
|
const fieldValues = inputs.fieldValues || {};
|
|
1990
2053
|
const connectionString = fieldValues.connectionString || inputs.connectionString || "postgresql://yugabyte:yugabyte@localhost:5433/workflows";
|
|
2054
|
+
const threadId = inputs.threadId ?? fieldValues.threadId;
|
|
1991
2055
|
try {
|
|
1992
2056
|
const checkpointer = PostgresSaver.fromConnString(connectionString);
|
|
1993
2057
|
await checkpointer.setup();
|
|
1994
|
-
console.log(
|
|
2058
|
+
console.log(`\u2705 PostgresMemory: Checkpointer initialized${threadId ? ` with threadId: ${threadId}` : ""}`);
|
|
1995
2059
|
return {
|
|
1996
2060
|
checkpointer,
|
|
2061
|
+
threadId,
|
|
2062
|
+
// Pass threadId to agent for conversation isolation
|
|
1997
2063
|
type: "PostgresMemoryNode",
|
|
1998
2064
|
connectionString: connectionString.replace(/:[^:@]+@/, ":***@")
|
|
1999
2065
|
// Hide password in output
|
|
@@ -2397,6 +2463,20 @@ var WhatsappMessageTriggerNode = {
|
|
|
2397
2463
|
name: "message",
|
|
2398
2464
|
fieldType: "string"
|
|
2399
2465
|
}
|
|
2466
|
+
},
|
|
2467
|
+
{
|
|
2468
|
+
id: "source",
|
|
2469
|
+
label: "Source",
|
|
2470
|
+
type: "string",
|
|
2471
|
+
required: false,
|
|
2472
|
+
typeable: false,
|
|
2473
|
+
defaultValue: "whatsapp",
|
|
2474
|
+
handle: {
|
|
2475
|
+
type: "output",
|
|
2476
|
+
label: "Source",
|
|
2477
|
+
name: "source",
|
|
2478
|
+
fieldType: "string"
|
|
2479
|
+
}
|
|
2400
2480
|
}
|
|
2401
2481
|
]
|
|
2402
2482
|
};
|
|
@@ -3217,6 +3297,595 @@ var ModelGuardrailNodeFunction = async (inputs) => {
|
|
|
3217
3297
|
};
|
|
3218
3298
|
};
|
|
3219
3299
|
|
|
3300
|
+
// src/nodes/chat/getOrCreateThread/data.ts
|
|
3301
|
+
import { z as z17 } from "zod";
|
|
3302
|
+
var GetOrCreateThreadSchema = z17.object({
|
|
3303
|
+
source: z17.string().describe("Channel source: whatsapp, telegram, web, etc."),
|
|
3304
|
+
identifier: z17.string().describe("User identifier: phone number, chat_id, userId"),
|
|
3305
|
+
timeoutMinutes: z17.number().optional().describe("Inactivity timeout in minutes (default: 1440 = 24h)")
|
|
3306
|
+
});
|
|
3307
|
+
var GetOrCreateThreadNode = {
|
|
3308
|
+
label: "Get or Create Thread",
|
|
3309
|
+
type: "GetOrCreateThreadNode",
|
|
3310
|
+
category: "chat",
|
|
3311
|
+
description: "Generates or retrieves a threadId based on identifier + timeout. Ensures tenant isolation.",
|
|
3312
|
+
icon: "\u{1F9F5}",
|
|
3313
|
+
group: "Chat",
|
|
3314
|
+
tags: {
|
|
3315
|
+
execution: "async",
|
|
3316
|
+
group: "Chat"
|
|
3317
|
+
},
|
|
3318
|
+
fields: [
|
|
3319
|
+
{
|
|
3320
|
+
id: "source",
|
|
3321
|
+
label: "Source",
|
|
3322
|
+
type: "string",
|
|
3323
|
+
required: true,
|
|
3324
|
+
defaultValue: "whatsapp",
|
|
3325
|
+
placeholder: "whatsapp, telegram, web",
|
|
3326
|
+
handle: {
|
|
3327
|
+
type: "input",
|
|
3328
|
+
label: "Source",
|
|
3329
|
+
name: "source",
|
|
3330
|
+
fieldType: "string"
|
|
3331
|
+
}
|
|
3332
|
+
},
|
|
3333
|
+
{
|
|
3334
|
+
id: "identifier",
|
|
3335
|
+
label: "Identifier",
|
|
3336
|
+
type: "string",
|
|
3337
|
+
required: true,
|
|
3338
|
+
placeholder: "+5511999999999",
|
|
3339
|
+
handle: {
|
|
3340
|
+
type: "input",
|
|
3341
|
+
label: "Identifier",
|
|
3342
|
+
name: "identifier",
|
|
3343
|
+
fieldType: "string"
|
|
3344
|
+
}
|
|
3345
|
+
},
|
|
3346
|
+
{
|
|
3347
|
+
id: "timeoutMinutes",
|
|
3348
|
+
label: "Timeout (minutes)",
|
|
3349
|
+
type: "number",
|
|
3350
|
+
required: false,
|
|
3351
|
+
defaultValue: "1440",
|
|
3352
|
+
placeholder: "1440 (24 hours)"
|
|
3353
|
+
},
|
|
3354
|
+
{
|
|
3355
|
+
id: "threadId",
|
|
3356
|
+
label: "Thread ID",
|
|
3357
|
+
type: "string",
|
|
3358
|
+
required: true,
|
|
3359
|
+
typeable: false,
|
|
3360
|
+
handle: {
|
|
3361
|
+
type: "output",
|
|
3362
|
+
label: "Thread ID",
|
|
3363
|
+
name: "threadId",
|
|
3364
|
+
fieldType: "string"
|
|
3365
|
+
}
|
|
3366
|
+
},
|
|
3367
|
+
{
|
|
3368
|
+
id: "isNew",
|
|
3369
|
+
label: "Is New Thread",
|
|
3370
|
+
type: "boolean",
|
|
3371
|
+
required: true,
|
|
3372
|
+
typeable: false,
|
|
3373
|
+
handle: {
|
|
3374
|
+
type: "output",
|
|
3375
|
+
label: "Is New",
|
|
3376
|
+
name: "isNew",
|
|
3377
|
+
fieldType: "boolean"
|
|
3378
|
+
}
|
|
3379
|
+
}
|
|
3380
|
+
]
|
|
3381
|
+
};
|
|
3382
|
+
|
|
3383
|
+
// src/nodes/chat/getOrCreateThread/function.ts
|
|
3384
|
+
var GetOrCreateThreadNodeFunction = async (inputs) => {
|
|
3385
|
+
const fieldValues = inputs.fieldValues || {};
|
|
3386
|
+
const context = inputs.context || {};
|
|
3387
|
+
const source = fieldValues.source;
|
|
3388
|
+
const identifier = fieldValues.identifier;
|
|
3389
|
+
const timeoutMinutes = Number(fieldValues.timeoutMinutes) || 1440;
|
|
3390
|
+
const companyId = context?.companyId;
|
|
3391
|
+
if (!companyId) {
|
|
3392
|
+
throw new Error("GetOrCreateThread requires companyId in context for tenant isolation");
|
|
3393
|
+
}
|
|
3394
|
+
if (!source || !identifier) {
|
|
3395
|
+
throw new Error("GetOrCreateThread requires source and identifier");
|
|
3396
|
+
}
|
|
3397
|
+
const timeoutMs = timeoutMinutes * 60 * 1e3;
|
|
3398
|
+
const thresholdDate = new Date(Date.now() - timeoutMs);
|
|
3399
|
+
const db = context?.db;
|
|
3400
|
+
if (!db) {
|
|
3401
|
+
throw new Error("GetOrCreateThread requires database connection in context");
|
|
3402
|
+
}
|
|
3403
|
+
try {
|
|
3404
|
+
const existingSessions = await db.query(`
|
|
3405
|
+
SELECT id, session_id, updated_at
|
|
3406
|
+
FROM chat_sessions
|
|
3407
|
+
WHERE company_id = $1
|
|
3408
|
+
AND metadata->>'source' = $2
|
|
3409
|
+
AND metadata->>'identifier' = $3
|
|
3410
|
+
AND updated_at > $4
|
|
3411
|
+
ORDER BY updated_at DESC
|
|
3412
|
+
LIMIT 1
|
|
3413
|
+
`, [companyId, source, identifier, thresholdDate]);
|
|
3414
|
+
if (existingSessions.rows && existingSessions.rows.length > 0) {
|
|
3415
|
+
const session = existingSessions.rows[0];
|
|
3416
|
+
await db.query(`
|
|
3417
|
+
UPDATE chat_sessions
|
|
3418
|
+
SET updated_at = NOW()
|
|
3419
|
+
WHERE id = $1 AND company_id = $2
|
|
3420
|
+
`, [session.id, companyId]);
|
|
3421
|
+
return {
|
|
3422
|
+
threadId: session.session_id,
|
|
3423
|
+
isNew: false
|
|
3424
|
+
};
|
|
3425
|
+
}
|
|
3426
|
+
const newSessionId = crypto.randomUUID();
|
|
3427
|
+
const workflowId = context?.workflowId;
|
|
3428
|
+
await db.query(`
|
|
3429
|
+
INSERT INTO chat_sessions (workflow_id, company_id, chat_id, session_id, metadata)
|
|
3430
|
+
VALUES ($1, $2, $3, $4, $5)
|
|
3431
|
+
`, [
|
|
3432
|
+
workflowId || companyId,
|
|
3433
|
+
// fallback to companyId if no workflowId
|
|
3434
|
+
companyId,
|
|
3435
|
+
`${source}:${identifier}`,
|
|
3436
|
+
// chatId as composite key
|
|
3437
|
+
newSessionId,
|
|
3438
|
+
JSON.stringify({ source, identifier })
|
|
3439
|
+
]);
|
|
3440
|
+
return {
|
|
3441
|
+
threadId: newSessionId,
|
|
3442
|
+
isNew: true
|
|
3443
|
+
};
|
|
3444
|
+
} catch (error) {
|
|
3445
|
+
console.error("[GetOrCreateThread] Error:", error);
|
|
3446
|
+
throw error;
|
|
3447
|
+
}
|
|
3448
|
+
};
|
|
3449
|
+
|
|
3450
|
+
// src/nodes/chat/chatLog/data.ts
|
|
3451
|
+
import { z as z18 } from "zod";
|
|
3452
|
+
var ChatLogSchema = z18.object({
|
|
3453
|
+
threadId: z18.string().describe("Thread ID from GetOrCreateThread"),
|
|
3454
|
+
direction: z18.enum(["inbound", "outbound"]).describe("Message direction"),
|
|
3455
|
+
content: z18.string().describe("Message content"),
|
|
3456
|
+
source: z18.string().optional().describe("Channel source"),
|
|
3457
|
+
identifier: z18.string().optional().describe("User identifier"),
|
|
3458
|
+
metadata: z18.record(z18.string(), z18.any()).optional().describe("Additional metadata")
|
|
3459
|
+
});
|
|
3460
|
+
var ChatLogNode = {
|
|
3461
|
+
label: "Chat Log",
|
|
3462
|
+
type: "ChatLogNode",
|
|
3463
|
+
category: "chat",
|
|
3464
|
+
description: "Saves a message to the chat history. Supports inbound (user) and outbound (assistant) messages.",
|
|
3465
|
+
icon: "\u{1F4AC}",
|
|
3466
|
+
group: "Chat",
|
|
3467
|
+
tags: {
|
|
3468
|
+
execution: "async",
|
|
3469
|
+
group: "Chat"
|
|
3470
|
+
},
|
|
3471
|
+
fields: [
|
|
3472
|
+
{
|
|
3473
|
+
id: "threadId",
|
|
3474
|
+
label: "Thread ID",
|
|
3475
|
+
type: "string",
|
|
3476
|
+
required: true,
|
|
3477
|
+
placeholder: "From GetOrCreateThread node",
|
|
3478
|
+
handle: {
|
|
3479
|
+
type: "input",
|
|
3480
|
+
label: "Thread ID",
|
|
3481
|
+
name: "threadId",
|
|
3482
|
+
fieldType: "string"
|
|
3483
|
+
}
|
|
3484
|
+
},
|
|
3485
|
+
{
|
|
3486
|
+
id: "direction",
|
|
3487
|
+
label: "Direction",
|
|
3488
|
+
type: "select",
|
|
3489
|
+
required: true,
|
|
3490
|
+
defaultValue: "inbound",
|
|
3491
|
+
options: [
|
|
3492
|
+
{ label: "Inbound (User \u2192 System)", value: "inbound" },
|
|
3493
|
+
{ label: "Outbound (System \u2192 User)", value: "outbound" }
|
|
3494
|
+
]
|
|
3495
|
+
},
|
|
3496
|
+
{
|
|
3497
|
+
id: "content",
|
|
3498
|
+
label: "Content",
|
|
3499
|
+
type: "string",
|
|
3500
|
+
required: true,
|
|
3501
|
+
placeholder: "Message content",
|
|
3502
|
+
handle: {
|
|
3503
|
+
type: "input",
|
|
3504
|
+
label: "Content",
|
|
3505
|
+
name: "content",
|
|
3506
|
+
fieldType: "string"
|
|
3507
|
+
}
|
|
3508
|
+
},
|
|
3509
|
+
{
|
|
3510
|
+
id: "source",
|
|
3511
|
+
label: "Source",
|
|
3512
|
+
type: "string",
|
|
3513
|
+
required: false,
|
|
3514
|
+
defaultValue: "whatsapp",
|
|
3515
|
+
placeholder: "whatsapp, telegram, web",
|
|
3516
|
+
handle: {
|
|
3517
|
+
type: "input",
|
|
3518
|
+
label: "Source",
|
|
3519
|
+
name: "source",
|
|
3520
|
+
fieldType: "string"
|
|
3521
|
+
}
|
|
3522
|
+
},
|
|
3523
|
+
{
|
|
3524
|
+
id: "identifier",
|
|
3525
|
+
label: "Identifier",
|
|
3526
|
+
type: "string",
|
|
3527
|
+
required: false,
|
|
3528
|
+
placeholder: "+5511999999999",
|
|
3529
|
+
handle: {
|
|
3530
|
+
type: "input",
|
|
3531
|
+
label: "Identifier",
|
|
3532
|
+
name: "identifier",
|
|
3533
|
+
fieldType: "string"
|
|
3534
|
+
}
|
|
3535
|
+
},
|
|
3536
|
+
{
|
|
3537
|
+
id: "messageId",
|
|
3538
|
+
label: "Message ID",
|
|
3539
|
+
type: "string",
|
|
3540
|
+
required: true,
|
|
3541
|
+
typeable: false,
|
|
3542
|
+
handle: {
|
|
3543
|
+
type: "output",
|
|
3544
|
+
label: "Message ID",
|
|
3545
|
+
name: "messageId",
|
|
3546
|
+
fieldType: "string"
|
|
3547
|
+
}
|
|
3548
|
+
},
|
|
3549
|
+
{
|
|
3550
|
+
id: "success",
|
|
3551
|
+
label: "Success",
|
|
3552
|
+
type: "boolean",
|
|
3553
|
+
required: true,
|
|
3554
|
+
typeable: false,
|
|
3555
|
+
handle: {
|
|
3556
|
+
type: "output",
|
|
3557
|
+
label: "Success",
|
|
3558
|
+
name: "success",
|
|
3559
|
+
fieldType: "boolean"
|
|
3560
|
+
}
|
|
3561
|
+
}
|
|
3562
|
+
]
|
|
3563
|
+
};
|
|
3564
|
+
|
|
3565
|
+
// src/nodes/chat/chatLog/function.ts
|
|
3566
|
+
var ChatLogNodeFunction = async (inputs) => {
|
|
3567
|
+
const fieldValues = inputs.fieldValues || {};
|
|
3568
|
+
const context = inputs.context || {};
|
|
3569
|
+
const threadId = fieldValues.threadId;
|
|
3570
|
+
const direction = fieldValues.direction;
|
|
3571
|
+
const content = fieldValues.content;
|
|
3572
|
+
const source = fieldValues.source;
|
|
3573
|
+
const identifier = fieldValues.identifier;
|
|
3574
|
+
const companyId = context?.companyId;
|
|
3575
|
+
if (!companyId) {
|
|
3576
|
+
throw new Error("ChatLog requires companyId in context for tenant isolation");
|
|
3577
|
+
}
|
|
3578
|
+
if (!threadId || !content) {
|
|
3579
|
+
throw new Error("ChatLog requires threadId and content");
|
|
3580
|
+
}
|
|
3581
|
+
const role = direction === "inbound" ? "user" : "assistant";
|
|
3582
|
+
const db = context?.db;
|
|
3583
|
+
if (!db) {
|
|
3584
|
+
throw new Error("ChatLog requires database connection in context");
|
|
3585
|
+
}
|
|
3586
|
+
try {
|
|
3587
|
+
const sessionResult = await db.query(`
|
|
3588
|
+
SELECT id FROM chat_sessions
|
|
3589
|
+
WHERE session_id = $1 AND company_id = $2
|
|
3590
|
+
LIMIT 1
|
|
3591
|
+
`, [threadId, companyId]);
|
|
3592
|
+
if (!sessionResult.rows || sessionResult.rows.length === 0) {
|
|
3593
|
+
throw new Error(`Session not found for threadId: ${threadId}`);
|
|
3594
|
+
}
|
|
3595
|
+
const sessionId = sessionResult.rows[0].id;
|
|
3596
|
+
const messageId = crypto.randomUUID();
|
|
3597
|
+
await db.query(`
|
|
3598
|
+
INSERT INTO chat_messages (id, session_id, role, content, metadata)
|
|
3599
|
+
VALUES ($1, $2, $3, $4, $5)
|
|
3600
|
+
`, [
|
|
3601
|
+
messageId,
|
|
3602
|
+
sessionId,
|
|
3603
|
+
role,
|
|
3604
|
+
content,
|
|
3605
|
+
JSON.stringify({
|
|
3606
|
+
direction,
|
|
3607
|
+
source: source || null,
|
|
3608
|
+
identifier: identifier || null
|
|
3609
|
+
})
|
|
3610
|
+
]);
|
|
3611
|
+
await db.query(`
|
|
3612
|
+
UPDATE chat_sessions
|
|
3613
|
+
SET updated_at = NOW()
|
|
3614
|
+
WHERE id = $1 AND company_id = $2
|
|
3615
|
+
`, [sessionId, companyId]);
|
|
3616
|
+
return {
|
|
3617
|
+
messageId,
|
|
3618
|
+
success: true
|
|
3619
|
+
};
|
|
3620
|
+
} catch (error) {
|
|
3621
|
+
console.error("[ChatLog] Error:", error);
|
|
3622
|
+
return {
|
|
3623
|
+
messageId: null,
|
|
3624
|
+
success: false
|
|
3625
|
+
};
|
|
3626
|
+
}
|
|
3627
|
+
};
|
|
3628
|
+
|
|
3629
|
+
// src/nodes/chat/isHumanActive/data.ts
|
|
3630
|
+
var IsHumanActiveData = {
|
|
3631
|
+
label: "Is Human Active?",
|
|
3632
|
+
type: "isHumanActive",
|
|
3633
|
+
category: "chat",
|
|
3634
|
+
description: "Checks if a human agent is currently handling the conversation (handoff mode).",
|
|
3635
|
+
icon: "\u{1F464}",
|
|
3636
|
+
group: "Chat",
|
|
3637
|
+
tags: {
|
|
3638
|
+
execution: "async",
|
|
3639
|
+
group: "Chat"
|
|
3640
|
+
},
|
|
3641
|
+
fields: [
|
|
3642
|
+
{
|
|
3643
|
+
id: "threadId",
|
|
3644
|
+
label: "Thread ID",
|
|
3645
|
+
type: "string",
|
|
3646
|
+
required: false,
|
|
3647
|
+
typeable: true,
|
|
3648
|
+
placeholder: "Session/Thread ID (optional, uses context if empty)",
|
|
3649
|
+
handle: {
|
|
3650
|
+
type: "input",
|
|
3651
|
+
label: "Thread ID",
|
|
3652
|
+
name: "threadId",
|
|
3653
|
+
fieldType: "string"
|
|
3654
|
+
}
|
|
3655
|
+
},
|
|
3656
|
+
{
|
|
3657
|
+
id: "active",
|
|
3658
|
+
label: "Active",
|
|
3659
|
+
type: "boolean",
|
|
3660
|
+
required: true,
|
|
3661
|
+
typeable: false,
|
|
3662
|
+
handle: {
|
|
3663
|
+
type: "output",
|
|
3664
|
+
label: "Active",
|
|
3665
|
+
name: "active",
|
|
3666
|
+
fieldType: "continue"
|
|
3667
|
+
}
|
|
3668
|
+
},
|
|
3669
|
+
{
|
|
3670
|
+
id: "inactive",
|
|
3671
|
+
label: "Inactive",
|
|
3672
|
+
type: "boolean",
|
|
3673
|
+
required: true,
|
|
3674
|
+
typeable: false,
|
|
3675
|
+
handle: {
|
|
3676
|
+
type: "output",
|
|
3677
|
+
label: "Inactive",
|
|
3678
|
+
name: "inactive",
|
|
3679
|
+
fieldType: "continue"
|
|
3680
|
+
}
|
|
3681
|
+
}
|
|
3682
|
+
]
|
|
3683
|
+
};
|
|
3684
|
+
|
|
3685
|
+
// src/nodes/chat/isHumanActive/function.ts
|
|
3686
|
+
var isHumanActiveFunc = async (inputs) => {
|
|
3687
|
+
const fieldValues = inputs.fieldValues || {};
|
|
3688
|
+
const context = inputs.context || {};
|
|
3689
|
+
const sessionId = inputs.threadId || fieldValues.threadId || context?.sessionId || context?.chatId;
|
|
3690
|
+
if (!sessionId) {
|
|
3691
|
+
console.warn("[IsHumanActive] No sessionId found in input or context.");
|
|
3692
|
+
return {
|
|
3693
|
+
active: false,
|
|
3694
|
+
inactive: true
|
|
3695
|
+
};
|
|
3696
|
+
}
|
|
3697
|
+
const db = context?.db;
|
|
3698
|
+
if (!db) {
|
|
3699
|
+
console.warn("[IsHumanActive] No database connection in context.");
|
|
3700
|
+
return { active: false, inactive: true };
|
|
3701
|
+
}
|
|
3702
|
+
try {
|
|
3703
|
+
const result = await db.query(`
|
|
3704
|
+
SELECT human_active_until
|
|
3705
|
+
FROM chat_sessions
|
|
3706
|
+
WHERE session_id = $1
|
|
3707
|
+
LIMIT 1
|
|
3708
|
+
`, [sessionId]);
|
|
3709
|
+
const session = result.rows?.[0];
|
|
3710
|
+
if (!session) {
|
|
3711
|
+
console.warn(`[IsHumanActive] Session not found: ${sessionId}`);
|
|
3712
|
+
return { active: false, inactive: true };
|
|
3713
|
+
}
|
|
3714
|
+
const now = /* @__PURE__ */ new Date();
|
|
3715
|
+
const isActive = session.human_active_until && new Date(session.human_active_until) > now;
|
|
3716
|
+
console.log(`[IsHumanActive] Session: ${sessionId}, Until: ${session.human_active_until}, Active: ${isActive}`);
|
|
3717
|
+
return {
|
|
3718
|
+
active: !!isActive,
|
|
3719
|
+
inactive: !isActive
|
|
3720
|
+
};
|
|
3721
|
+
} catch (error) {
|
|
3722
|
+
console.error("[IsHumanActive] Error querying session:", error);
|
|
3723
|
+
return { active: false, inactive: true };
|
|
3724
|
+
}
|
|
3725
|
+
};
|
|
3726
|
+
|
|
3727
|
+
// src/nodes/logic/varNode/data.ts
|
|
3728
|
+
var VarNode = {
|
|
3729
|
+
label: "Variable",
|
|
3730
|
+
type: "VarNode",
|
|
3731
|
+
category: "logic",
|
|
3732
|
+
description: "Stores a value from multiple inputs. Strategy: keep first or last value received.",
|
|
3733
|
+
icon: "\u{1F4E6}",
|
|
3734
|
+
group: "Control",
|
|
3735
|
+
tags: {
|
|
3736
|
+
execution: "sync",
|
|
3737
|
+
group: "Control"
|
|
3738
|
+
},
|
|
3739
|
+
fields: [
|
|
3740
|
+
{
|
|
3741
|
+
id: "strategy",
|
|
3742
|
+
label: "Strategy",
|
|
3743
|
+
type: "select",
|
|
3744
|
+
required: true,
|
|
3745
|
+
defaultValue: "first",
|
|
3746
|
+
options: [
|
|
3747
|
+
{ label: "First Value", value: "first" },
|
|
3748
|
+
{ label: "Last Value", value: "last" }
|
|
3749
|
+
]
|
|
3750
|
+
},
|
|
3751
|
+
{
|
|
3752
|
+
id: "value",
|
|
3753
|
+
label: "Value",
|
|
3754
|
+
type: "any",
|
|
3755
|
+
required: false,
|
|
3756
|
+
typeable: true,
|
|
3757
|
+
handle: {
|
|
3758
|
+
type: "input",
|
|
3759
|
+
label: "Value",
|
|
3760
|
+
name: "value",
|
|
3761
|
+
fieldType: "any",
|
|
3762
|
+
maxConnections: 10
|
|
3763
|
+
// Allow multiple connections
|
|
3764
|
+
}
|
|
3765
|
+
},
|
|
3766
|
+
{
|
|
3767
|
+
id: "output",
|
|
3768
|
+
label: "Output",
|
|
3769
|
+
type: "any",
|
|
3770
|
+
required: true,
|
|
3771
|
+
typeable: false,
|
|
3772
|
+
handle: {
|
|
3773
|
+
type: "output",
|
|
3774
|
+
label: "Value",
|
|
3775
|
+
name: "output",
|
|
3776
|
+
fieldType: "any"
|
|
3777
|
+
}
|
|
3778
|
+
},
|
|
3779
|
+
// Continue handle (hidden by default)
|
|
3780
|
+
{
|
|
3781
|
+
id: "continue",
|
|
3782
|
+
label: "Continue",
|
|
3783
|
+
type: "continue",
|
|
3784
|
+
typeable: false,
|
|
3785
|
+
active: false,
|
|
3786
|
+
// Hidden by default
|
|
3787
|
+
handle: {
|
|
3788
|
+
type: "output",
|
|
3789
|
+
label: "Continue",
|
|
3790
|
+
name: "continue",
|
|
3791
|
+
fieldType: "continue"
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
]
|
|
3795
|
+
};
|
|
3796
|
+
|
|
3797
|
+
// src/nodes/logic/varNode/function.ts
|
|
3798
|
+
var VarNodeFunction = async (inputs) => {
|
|
3799
|
+
const fieldValues = inputs.fieldValues || {};
|
|
3800
|
+
const strategy = fieldValues.strategy || "first";
|
|
3801
|
+
let values = inputs.value ?? fieldValues.value;
|
|
3802
|
+
if (!Array.isArray(values)) {
|
|
3803
|
+
values = values !== void 0 ? [values] : [];
|
|
3804
|
+
}
|
|
3805
|
+
const validValues = values.filter((v) => v !== void 0 && v !== null);
|
|
3806
|
+
if (validValues.length === 0) {
|
|
3807
|
+
return { output: void 0, continue: true };
|
|
3808
|
+
}
|
|
3809
|
+
const result = strategy === "first" ? validValues[0] : validValues[validValues.length - 1];
|
|
3810
|
+
return {
|
|
3811
|
+
output: result,
|
|
3812
|
+
continue: true
|
|
3813
|
+
};
|
|
3814
|
+
};
|
|
3815
|
+
|
|
3816
|
+
// src/nodes/logic/switchNode/data.ts
|
|
3817
|
+
var SwitchNode = {
|
|
3818
|
+
label: "Switch",
|
|
3819
|
+
type: "SwitchNode",
|
|
3820
|
+
category: "logic",
|
|
3821
|
+
description: "Routes execution based on input value. Each case triggers its corresponding path.",
|
|
3822
|
+
icon: "\u{1F500}",
|
|
3823
|
+
group: "Control",
|
|
3824
|
+
tags: {
|
|
3825
|
+
execution: "sync",
|
|
3826
|
+
group: "Control"
|
|
3827
|
+
},
|
|
3828
|
+
fields: [
|
|
3829
|
+
{
|
|
3830
|
+
id: "value",
|
|
3831
|
+
label: "Value",
|
|
3832
|
+
type: "string",
|
|
3833
|
+
required: true,
|
|
3834
|
+
typeable: true,
|
|
3835
|
+
placeholder: "Value to match",
|
|
3836
|
+
handle: {
|
|
3837
|
+
type: "input",
|
|
3838
|
+
label: "Value",
|
|
3839
|
+
name: "value",
|
|
3840
|
+
fieldType: "string"
|
|
3841
|
+
}
|
|
3842
|
+
},
|
|
3843
|
+
{
|
|
3844
|
+
id: "cases",
|
|
3845
|
+
label: "Cases",
|
|
3846
|
+
type: "keyValue",
|
|
3847
|
+
required: true,
|
|
3848
|
+
defaultValue: [
|
|
3849
|
+
{ key: "whatsapp", value: "WhatsApp" },
|
|
3850
|
+
{ key: "chat", value: "Web Chat" }
|
|
3851
|
+
],
|
|
3852
|
+
placeholder: "Add cases (key = match value, value = label)"
|
|
3853
|
+
},
|
|
3854
|
+
{
|
|
3855
|
+
id: "includeDefault",
|
|
3856
|
+
label: "Include Default Path",
|
|
3857
|
+
type: "boolean",
|
|
3858
|
+
required: false,
|
|
3859
|
+
defaultValue: true
|
|
3860
|
+
}
|
|
3861
|
+
// Note: Dynamic outputs are generated based on 'cases' at runtime
|
|
3862
|
+
// Each case.key becomes an output handle of type 'continue'
|
|
3863
|
+
// Plus optional 'default' output if includeDefault is true
|
|
3864
|
+
]
|
|
3865
|
+
};
|
|
3866
|
+
|
|
3867
|
+
// src/nodes/logic/switchNode/function.ts
|
|
3868
|
+
var SwitchNodeFunction = async (inputs) => {
|
|
3869
|
+
const fieldValues = inputs.fieldValues || {};
|
|
3870
|
+
const inputValue = inputs.value ?? fieldValues.value;
|
|
3871
|
+
const cases = fieldValues.cases || [];
|
|
3872
|
+
const includeDefault = fieldValues.includeDefault ?? true;
|
|
3873
|
+
const outputs = {};
|
|
3874
|
+
for (const c of cases) {
|
|
3875
|
+
outputs[c.key] = false;
|
|
3876
|
+
}
|
|
3877
|
+
if (includeDefault) {
|
|
3878
|
+
outputs["default"] = false;
|
|
3879
|
+
}
|
|
3880
|
+
const matchedCase = cases.find((c) => c.key === inputValue);
|
|
3881
|
+
if (matchedCase) {
|
|
3882
|
+
outputs[matchedCase.key] = true;
|
|
3883
|
+
} else if (includeDefault) {
|
|
3884
|
+
outputs["default"] = true;
|
|
3885
|
+
}
|
|
3886
|
+
return outputs;
|
|
3887
|
+
};
|
|
3888
|
+
|
|
3220
3889
|
// src/nodes/consts/nodes.ts
|
|
3221
3890
|
var nodes = [
|
|
3222
3891
|
ChatInputNode,
|
|
@@ -3243,7 +3912,12 @@ var nodes = [
|
|
|
3243
3912
|
PromptGuardrailNode,
|
|
3244
3913
|
RuleGuardrailNode,
|
|
3245
3914
|
FunctionGuardrailNode,
|
|
3246
|
-
ModelGuardrailNode
|
|
3915
|
+
ModelGuardrailNode,
|
|
3916
|
+
GetOrCreateThreadNode,
|
|
3917
|
+
ChatLogNode,
|
|
3918
|
+
IsHumanActiveData,
|
|
3919
|
+
VarNode,
|
|
3920
|
+
SwitchNode
|
|
3247
3921
|
];
|
|
3248
3922
|
var nodes_default = nodes;
|
|
3249
3923
|
|
|
@@ -3365,7 +4039,12 @@ var nodeFunctions = {
|
|
|
3365
4039
|
PromptGuardrailNode: PromptGuardrailNodeFunction,
|
|
3366
4040
|
RuleGuardrailNode: RuleGuardrailNodeFunction,
|
|
3367
4041
|
FunctionGuardrailNode: FunctionGuardrailNodeFunction,
|
|
3368
|
-
ModelGuardrailNode: ModelGuardrailNodeFunction
|
|
4042
|
+
ModelGuardrailNode: ModelGuardrailNodeFunction,
|
|
4043
|
+
GetOrCreateThreadNode: GetOrCreateThreadNodeFunction,
|
|
4044
|
+
ChatLogNode: ChatLogNodeFunction,
|
|
4045
|
+
isHumanActive: isHumanActiveFunc,
|
|
4046
|
+
VarNode: VarNodeFunction,
|
|
4047
|
+
SwitchNode: SwitchNodeFunction
|
|
3369
4048
|
};
|
|
3370
4049
|
var node_functions_default = nodeFunctions;
|
|
3371
4050
|
|
|
@@ -3479,12 +4158,12 @@ var HttpPutInputNodeFunction = (params) => {
|
|
|
3479
4158
|
};
|
|
3480
4159
|
|
|
3481
4160
|
// src/nodes/inputs/http/put/schema.ts
|
|
3482
|
-
import { z as
|
|
3483
|
-
var HttpPutInputNodeSchema =
|
|
4161
|
+
import { z as z19 } from "zod";
|
|
4162
|
+
var HttpPutInputNodeSchema = z19.object({
|
|
3484
4163
|
route: RouteSchema,
|
|
3485
|
-
queryParams:
|
|
3486
|
-
headers:
|
|
3487
|
-
body:
|
|
4164
|
+
queryParams: z19.array(QueryParamSchema).optional().describe("Query parameters configuration"),
|
|
4165
|
+
headers: z19.array(HeaderSchema).optional().describe("Headers configuration"),
|
|
4166
|
+
body: z19.array(BodyFieldSchema).optional().describe("Body fields configuration")
|
|
3488
4167
|
});
|
|
3489
4168
|
|
|
3490
4169
|
// src/nodes/inputs/http/delete/data.ts
|
|
@@ -3576,11 +4255,11 @@ var HttpDeleteInputNodeFunction = async (params) => {
|
|
|
3576
4255
|
};
|
|
3577
4256
|
|
|
3578
4257
|
// src/nodes/inputs/http/delete/schema.ts
|
|
3579
|
-
import { z as
|
|
3580
|
-
var HttpDeleteInputNodeSchema =
|
|
4258
|
+
import { z as z20 } from "zod";
|
|
4259
|
+
var HttpDeleteInputNodeSchema = z20.object({
|
|
3581
4260
|
route: RouteSchema,
|
|
3582
|
-
queryParams:
|
|
3583
|
-
headers:
|
|
4261
|
+
queryParams: z20.array(QueryParamSchema).optional().describe("Query parameters configuration"),
|
|
4262
|
+
headers: z20.array(HeaderSchema).optional().describe("Headers configuration")
|
|
3584
4263
|
});
|
|
3585
4264
|
|
|
3586
4265
|
// src/nodes/inputs/http/patch/data.ts
|
|
@@ -3693,12 +4372,12 @@ var HttpPatchInputNodeFunction = (params) => {
|
|
|
3693
4372
|
};
|
|
3694
4373
|
|
|
3695
4374
|
// src/nodes/inputs/http/patch/schema.ts
|
|
3696
|
-
import { z as
|
|
3697
|
-
var HttpPatchInputNodeSchema =
|
|
4375
|
+
import { z as z21 } from "zod";
|
|
4376
|
+
var HttpPatchInputNodeSchema = z21.object({
|
|
3698
4377
|
route: RouteSchema,
|
|
3699
|
-
queryParams:
|
|
3700
|
-
headers:
|
|
3701
|
-
body:
|
|
4378
|
+
queryParams: z21.array(QueryParamSchema).optional().describe("Query parameters configuration"),
|
|
4379
|
+
headers: z21.array(HeaderSchema).optional().describe("Headers configuration"),
|
|
4380
|
+
body: z21.array(BodyFieldSchema).optional().describe("Body fields configuration")
|
|
3702
4381
|
});
|
|
3703
4382
|
|
|
3704
4383
|
// src/nodes/inputs/http/utils.ts
|
|
@@ -3757,7 +4436,13 @@ export {
|
|
|
3757
4436
|
AiToolNodeFunction,
|
|
3758
4437
|
AiToolNodeSchema,
|
|
3759
4438
|
BodyFieldSchema,
|
|
4439
|
+
ChatLogNode,
|
|
4440
|
+
ChatLogNodeFunction,
|
|
4441
|
+
ChatLogSchema,
|
|
3760
4442
|
CustomToolSchema,
|
|
4443
|
+
GetOrCreateThreadNode,
|
|
4444
|
+
GetOrCreateThreadNodeFunction,
|
|
4445
|
+
GetOrCreateThreadSchema,
|
|
3761
4446
|
HTTP_METHODS,
|
|
3762
4447
|
HTTP_NODE_TYPES,
|
|
3763
4448
|
HeaderSchema,
|
|
@@ -3782,8 +4467,13 @@ export {
|
|
|
3782
4467
|
IaMessageNode,
|
|
3783
4468
|
IaMessageNodeFunction,
|
|
3784
4469
|
IaMessageNodeSchema,
|
|
4470
|
+
IsHumanActiveData,
|
|
3785
4471
|
QueryParamSchema,
|
|
3786
4472
|
RouteSchema,
|
|
4473
|
+
SwitchNode,
|
|
4474
|
+
SwitchNodeFunction,
|
|
4475
|
+
VarNode,
|
|
4476
|
+
VarNodeFunction,
|
|
3787
4477
|
WhatsappMessageTriggerNode,
|
|
3788
4478
|
WhatsappSendMessageFunction,
|
|
3789
4479
|
WhatsappSendMessageNode,
|
|
@@ -3803,6 +4493,7 @@ export {
|
|
|
3803
4493
|
isHttpInputFriendlyId,
|
|
3804
4494
|
isHttpInputNode,
|
|
3805
4495
|
isHttpMethodNode,
|
|
4496
|
+
isHumanActiveFunc,
|
|
3806
4497
|
node_functions_default as nodeFunctions,
|
|
3807
4498
|
nodes_default as nodes,
|
|
3808
4499
|
schemas
|