@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 CHANGED
@@ -36,7 +36,13 @@ __export(index_exports, {
36
36
  AiToolNodeFunction: () => AiToolNodeFunction,
37
37
  AiToolNodeSchema: () => AiToolNodeSchema,
38
38
  BodyFieldSchema: () => BodyFieldSchema,
39
+ ChatLogNode: () => ChatLogNode,
40
+ ChatLogNodeFunction: () => ChatLogNodeFunction,
41
+ ChatLogSchema: () => ChatLogSchema,
39
42
  CustomToolSchema: () => CustomToolSchema,
43
+ GetOrCreateThreadNode: () => GetOrCreateThreadNode,
44
+ GetOrCreateThreadNodeFunction: () => GetOrCreateThreadNodeFunction,
45
+ GetOrCreateThreadSchema: () => GetOrCreateThreadSchema,
40
46
  HTTP_METHODS: () => HTTP_METHODS,
41
47
  HTTP_NODE_TYPES: () => HTTP_NODE_TYPES,
42
48
  HeaderSchema: () => HeaderSchema,
@@ -61,8 +67,13 @@ __export(index_exports, {
61
67
  IaMessageNode: () => IaMessageNode,
62
68
  IaMessageNodeFunction: () => IaMessageNodeFunction,
63
69
  IaMessageNodeSchema: () => IaMessageNodeSchema,
70
+ IsHumanActiveData: () => IsHumanActiveData,
64
71
  QueryParamSchema: () => QueryParamSchema,
65
72
  RouteSchema: () => RouteSchema,
73
+ SwitchNode: () => SwitchNode,
74
+ SwitchNodeFunction: () => SwitchNodeFunction,
75
+ VarNode: () => VarNode,
76
+ VarNodeFunction: () => VarNodeFunction,
66
77
  WhatsappMessageTriggerNode: () => WhatsappMessageTriggerNode,
67
78
  WhatsappSendMessageFunction: () => WhatsappSendMessageFunction,
68
79
  WhatsappSendMessageNode: () => WhatsappSendMessageNode,
@@ -82,6 +93,7 @@ __export(index_exports, {
82
93
  isHttpInputFriendlyId: () => isHttpInputFriendlyId,
83
94
  isHttpInputNode: () => isHttpInputNode,
84
95
  isHttpMethodNode: () => isHttpMethodNode,
96
+ isHumanActiveFunc: () => isHumanActiveFunc,
85
97
  nodeFunctions: () => node_functions_default,
86
98
  nodes: () => nodes_default,
87
99
  schemas: () => schemas
@@ -333,7 +345,11 @@ var ChatInputNodeFunction = (params) => {
333
345
  const { message: configMessage, chatId: configChatId } = fieldValues || {};
334
346
  const actualData = {
335
347
  message: request?.message ?? configMessage ?? "",
336
- chatId: request?.chatId ?? configChatId ?? null
348
+ chatId: request?.chatId ?? configChatId ?? null,
349
+ roomId: request?.sessionId ?? request?.chatId ?? configChatId ?? null,
350
+ // Room = Session/Chat
351
+ source: "chat"
352
+ // Hardcoded source for web chat
337
353
  };
338
354
  if (!actualData.message || typeof actualData.message !== "string") {
339
355
  throw new Error("Message is required for ChatInputNode");
@@ -376,6 +392,33 @@ var ChatInputNode = {
376
392
  name: "chatId",
377
393
  fieldType: "string"
378
394
  }
395
+ },
396
+ {
397
+ id: "roomId",
398
+ label: "Room ID",
399
+ type: "string",
400
+ required: false,
401
+ typeable: false,
402
+ handle: {
403
+ type: "output",
404
+ label: "Room ID",
405
+ name: "roomId",
406
+ fieldType: "string"
407
+ }
408
+ },
409
+ {
410
+ id: "source",
411
+ label: "Source",
412
+ type: "string",
413
+ required: false,
414
+ typeable: false,
415
+ defaultValue: "chat",
416
+ handle: {
417
+ type: "output",
418
+ label: "Source",
419
+ name: "source",
420
+ fieldType: "string"
421
+ }
379
422
  }
380
423
  ]
381
424
  };
@@ -1098,7 +1141,7 @@ async function createLLMFromModel(modelConfig, authToken, streaming = false) {
1098
1141
  case "gemini":
1099
1142
  return new import_google_gauth.ChatGoogle({
1100
1143
  model: "gemini-flash-latest",
1101
- apiKey: "AIzaSyAWj0Al2sVJ8vqaRN4UY7c6imAg7a3NbEc",
1144
+ apiKey: "AIzaSyBLeXr43XWg1lOQfsUTZQ85IX-IYYpZIW0",
1102
1145
  streaming
1103
1146
  });
1104
1147
  case "openai":
@@ -1124,6 +1167,18 @@ async function createLLMFromModel(modelConfig, authToken, streaming = false) {
1124
1167
  }
1125
1168
 
1126
1169
  // src/utils/guardrail-executor.ts
1170
+ function emitGuardrailEvent(context, name, passed, action, details) {
1171
+ if (context?.emitter?.emitThought) {
1172
+ context.emitter.emitThought({
1173
+ content: `guardrail:${passed ? "passed" : "failed"}:${name}`,
1174
+ type: "guardrail",
1175
+ name,
1176
+ passed,
1177
+ action: action || "evaluate",
1178
+ details
1179
+ });
1180
+ }
1181
+ }
1127
1182
  async function loadChatHistory(context) {
1128
1183
  const checkpointer = context?.checkpointer;
1129
1184
  const sessionId = context?.sessionId;
@@ -1218,6 +1273,7 @@ async function executeGuardrails(guardrails, content, mode = "fail-first", conte
1218
1273
  if (!guardPassed && actionInstruction) {
1219
1274
  violationMessage = actionInstruction;
1220
1275
  }
1276
+ emitGuardrailEvent(context, guard.name, guardPassed, guard.action, violationMessage || "Rule passed");
1221
1277
  } else if (guard.type === "function") {
1222
1278
  const { nodeFunction, name, actionInstruction } = guard;
1223
1279
  if (typeof nodeFunction === "function") {
@@ -1250,6 +1306,7 @@ async function executeGuardrails(guardrails, content, mode = "fail-first", conte
1250
1306
  guardPassed = false;
1251
1307
  violationMessage = `Erro na fun\xE7\xE3o guardrail: ${error instanceof Error ? error.message : String(error)}`;
1252
1308
  }
1309
+ emitGuardrailEvent(context, name, guardPassed, guard.action, violationMessage || "Function passed");
1253
1310
  }
1254
1311
  } else if (guard.type === "model") {
1255
1312
  const { model, evaluationPrompt, name, actionInstruction } = guard;
@@ -1317,6 +1374,7 @@ Reescreva o conte\xFAdo corrigindo a viola\xE7\xE3o. Retorne APENAS o texto corr
1317
1374
  message: violationMessage,
1318
1375
  action: "fix"
1319
1376
  });
1377
+ emitGuardrailEvent(context, name, false, "fix", `Content fixed: ${fixedContent.slice(0, 100)}...`);
1320
1378
  } catch (fixError) {
1321
1379
  console.error(`[GUARDRAIL LLM] Erro ao corrigir conte\xFAdo:`, fixError);
1322
1380
  }
@@ -1328,8 +1386,10 @@ Reescreva o conte\xFAdo corrigindo a viola\xE7\xE3o. Retorne APENAS o texto corr
1328
1386
  guardPassed = false;
1329
1387
  violationMessage = actionInstruction || `Modelo de avalia\xE7\xE3o "${name}" detectou viola\xE7\xE3o de seguran\xE7a/pol\xEDtica.`;
1330
1388
  console.log(`[GUARDRAIL LLM] Resultado: UNSAFE - Bloqueado`);
1389
+ emitGuardrailEvent(context, name, false, guard.action, violationMessage);
1331
1390
  } else {
1332
1391
  console.log(`[GUARDRAIL LLM] Resultado: SAFE - Aprovado`);
1392
+ emitGuardrailEvent(context, name, true, "approve", "Content passed evaluation");
1333
1393
  }
1334
1394
  }
1335
1395
  } catch (error) {
@@ -2034,7 +2094,8 @@ var import_tools = require("@langchain/core/tools");
2034
2094
  // src/nodes/memory/postgres/data.ts
2035
2095
  var import_zod8 = require("zod");
2036
2096
  var PostgresMemoryNodeSchema = import_zod8.z.object({
2037
- connectionString: import_zod8.z.string().describe("PostgreSQL connection string")
2097
+ connectionString: import_zod8.z.string().describe("PostgreSQL connection string"),
2098
+ threadId: import_zod8.z.string().optional().describe("Thread ID for conversation isolation")
2038
2099
  });
2039
2100
  var PostgresMemoryNode = {
2040
2101
  label: "Postgres Memory",
@@ -2056,6 +2117,20 @@ var PostgresMemoryNode = {
2056
2117
  defaultValue: "postgresql://yugabyte:yugabyte@localhost:5433/workflows",
2057
2118
  placeholder: "postgresql://user:pass@host:5432/database"
2058
2119
  },
2120
+ {
2121
+ id: "threadId",
2122
+ label: "Thread ID",
2123
+ type: "string",
2124
+ required: false,
2125
+ typeable: true,
2126
+ placeholder: "Thread/Session ID for conversation isolation",
2127
+ handle: {
2128
+ type: "input",
2129
+ label: "Thread ID",
2130
+ name: "threadId",
2131
+ fieldType: "string"
2132
+ }
2133
+ },
2059
2134
  {
2060
2135
  id: "checkpointer",
2061
2136
  label: "Checkpointer",
@@ -2078,12 +2153,15 @@ var PostgresMemoryNodeFunction = async (inputs) => {
2078
2153
  const { $field: _$field, $req: _$req, $inputs: _$inputs, $vars: _$vars } = inputs;
2079
2154
  const fieldValues = inputs.fieldValues || {};
2080
2155
  const connectionString = fieldValues.connectionString || inputs.connectionString || "postgresql://yugabyte:yugabyte@localhost:5433/workflows";
2156
+ const threadId = inputs.threadId ?? fieldValues.threadId;
2081
2157
  try {
2082
2158
  const checkpointer = import_langgraph_checkpoint_postgres.PostgresSaver.fromConnString(connectionString);
2083
2159
  await checkpointer.setup();
2084
- console.log("\u2705 PostgresMemory: Checkpointer initialized");
2160
+ console.log(`\u2705 PostgresMemory: Checkpointer initialized${threadId ? ` with threadId: ${threadId}` : ""}`);
2085
2161
  return {
2086
2162
  checkpointer,
2163
+ threadId,
2164
+ // Pass threadId to agent for conversation isolation
2087
2165
  type: "PostgresMemoryNode",
2088
2166
  connectionString: connectionString.replace(/:[^:@]+@/, ":***@")
2089
2167
  // Hide password in output
@@ -2487,6 +2565,20 @@ var WhatsappMessageTriggerNode = {
2487
2565
  name: "message",
2488
2566
  fieldType: "string"
2489
2567
  }
2568
+ },
2569
+ {
2570
+ id: "source",
2571
+ label: "Source",
2572
+ type: "string",
2573
+ required: false,
2574
+ typeable: false,
2575
+ defaultValue: "whatsapp",
2576
+ handle: {
2577
+ type: "output",
2578
+ label: "Source",
2579
+ name: "source",
2580
+ fieldType: "string"
2581
+ }
2490
2582
  }
2491
2583
  ]
2492
2584
  };
@@ -3307,6 +3399,595 @@ var ModelGuardrailNodeFunction = async (inputs) => {
3307
3399
  };
3308
3400
  };
3309
3401
 
3402
+ // src/nodes/chat/getOrCreateThread/data.ts
3403
+ var import_zod17 = require("zod");
3404
+ var GetOrCreateThreadSchema = import_zod17.z.object({
3405
+ source: import_zod17.z.string().describe("Channel source: whatsapp, telegram, web, etc."),
3406
+ identifier: import_zod17.z.string().describe("User identifier: phone number, chat_id, userId"),
3407
+ timeoutMinutes: import_zod17.z.number().optional().describe("Inactivity timeout in minutes (default: 1440 = 24h)")
3408
+ });
3409
+ var GetOrCreateThreadNode = {
3410
+ label: "Get or Create Thread",
3411
+ type: "GetOrCreateThreadNode",
3412
+ category: "chat",
3413
+ description: "Generates or retrieves a threadId based on identifier + timeout. Ensures tenant isolation.",
3414
+ icon: "\u{1F9F5}",
3415
+ group: "Chat",
3416
+ tags: {
3417
+ execution: "async",
3418
+ group: "Chat"
3419
+ },
3420
+ fields: [
3421
+ {
3422
+ id: "source",
3423
+ label: "Source",
3424
+ type: "string",
3425
+ required: true,
3426
+ defaultValue: "whatsapp",
3427
+ placeholder: "whatsapp, telegram, web",
3428
+ handle: {
3429
+ type: "input",
3430
+ label: "Source",
3431
+ name: "source",
3432
+ fieldType: "string"
3433
+ }
3434
+ },
3435
+ {
3436
+ id: "identifier",
3437
+ label: "Identifier",
3438
+ type: "string",
3439
+ required: true,
3440
+ placeholder: "+5511999999999",
3441
+ handle: {
3442
+ type: "input",
3443
+ label: "Identifier",
3444
+ name: "identifier",
3445
+ fieldType: "string"
3446
+ }
3447
+ },
3448
+ {
3449
+ id: "timeoutMinutes",
3450
+ label: "Timeout (minutes)",
3451
+ type: "number",
3452
+ required: false,
3453
+ defaultValue: "1440",
3454
+ placeholder: "1440 (24 hours)"
3455
+ },
3456
+ {
3457
+ id: "threadId",
3458
+ label: "Thread ID",
3459
+ type: "string",
3460
+ required: true,
3461
+ typeable: false,
3462
+ handle: {
3463
+ type: "output",
3464
+ label: "Thread ID",
3465
+ name: "threadId",
3466
+ fieldType: "string"
3467
+ }
3468
+ },
3469
+ {
3470
+ id: "isNew",
3471
+ label: "Is New Thread",
3472
+ type: "boolean",
3473
+ required: true,
3474
+ typeable: false,
3475
+ handle: {
3476
+ type: "output",
3477
+ label: "Is New",
3478
+ name: "isNew",
3479
+ fieldType: "boolean"
3480
+ }
3481
+ }
3482
+ ]
3483
+ };
3484
+
3485
+ // src/nodes/chat/getOrCreateThread/function.ts
3486
+ var GetOrCreateThreadNodeFunction = async (inputs) => {
3487
+ const fieldValues = inputs.fieldValues || {};
3488
+ const context = inputs.context || {};
3489
+ const source = fieldValues.source;
3490
+ const identifier = fieldValues.identifier;
3491
+ const timeoutMinutes = Number(fieldValues.timeoutMinutes) || 1440;
3492
+ const companyId = context?.companyId;
3493
+ if (!companyId) {
3494
+ throw new Error("GetOrCreateThread requires companyId in context for tenant isolation");
3495
+ }
3496
+ if (!source || !identifier) {
3497
+ throw new Error("GetOrCreateThread requires source and identifier");
3498
+ }
3499
+ const timeoutMs = timeoutMinutes * 60 * 1e3;
3500
+ const thresholdDate = new Date(Date.now() - timeoutMs);
3501
+ const db = context?.db;
3502
+ if (!db) {
3503
+ throw new Error("GetOrCreateThread requires database connection in context");
3504
+ }
3505
+ try {
3506
+ const existingSessions = await db.query(`
3507
+ SELECT id, session_id, updated_at
3508
+ FROM chat_sessions
3509
+ WHERE company_id = $1
3510
+ AND metadata->>'source' = $2
3511
+ AND metadata->>'identifier' = $3
3512
+ AND updated_at > $4
3513
+ ORDER BY updated_at DESC
3514
+ LIMIT 1
3515
+ `, [companyId, source, identifier, thresholdDate]);
3516
+ if (existingSessions.rows && existingSessions.rows.length > 0) {
3517
+ const session = existingSessions.rows[0];
3518
+ await db.query(`
3519
+ UPDATE chat_sessions
3520
+ SET updated_at = NOW()
3521
+ WHERE id = $1 AND company_id = $2
3522
+ `, [session.id, companyId]);
3523
+ return {
3524
+ threadId: session.session_id,
3525
+ isNew: false
3526
+ };
3527
+ }
3528
+ const newSessionId = crypto.randomUUID();
3529
+ const workflowId = context?.workflowId;
3530
+ await db.query(`
3531
+ INSERT INTO chat_sessions (workflow_id, company_id, chat_id, session_id, metadata)
3532
+ VALUES ($1, $2, $3, $4, $5)
3533
+ `, [
3534
+ workflowId || companyId,
3535
+ // fallback to companyId if no workflowId
3536
+ companyId,
3537
+ `${source}:${identifier}`,
3538
+ // chatId as composite key
3539
+ newSessionId,
3540
+ JSON.stringify({ source, identifier })
3541
+ ]);
3542
+ return {
3543
+ threadId: newSessionId,
3544
+ isNew: true
3545
+ };
3546
+ } catch (error) {
3547
+ console.error("[GetOrCreateThread] Error:", error);
3548
+ throw error;
3549
+ }
3550
+ };
3551
+
3552
+ // src/nodes/chat/chatLog/data.ts
3553
+ var import_zod18 = require("zod");
3554
+ var ChatLogSchema = import_zod18.z.object({
3555
+ threadId: import_zod18.z.string().describe("Thread ID from GetOrCreateThread"),
3556
+ direction: import_zod18.z.enum(["inbound", "outbound"]).describe("Message direction"),
3557
+ content: import_zod18.z.string().describe("Message content"),
3558
+ source: import_zod18.z.string().optional().describe("Channel source"),
3559
+ identifier: import_zod18.z.string().optional().describe("User identifier"),
3560
+ metadata: import_zod18.z.record(import_zod18.z.string(), import_zod18.z.any()).optional().describe("Additional metadata")
3561
+ });
3562
+ var ChatLogNode = {
3563
+ label: "Chat Log",
3564
+ type: "ChatLogNode",
3565
+ category: "chat",
3566
+ description: "Saves a message to the chat history. Supports inbound (user) and outbound (assistant) messages.",
3567
+ icon: "\u{1F4AC}",
3568
+ group: "Chat",
3569
+ tags: {
3570
+ execution: "async",
3571
+ group: "Chat"
3572
+ },
3573
+ fields: [
3574
+ {
3575
+ id: "threadId",
3576
+ label: "Thread ID",
3577
+ type: "string",
3578
+ required: true,
3579
+ placeholder: "From GetOrCreateThread node",
3580
+ handle: {
3581
+ type: "input",
3582
+ label: "Thread ID",
3583
+ name: "threadId",
3584
+ fieldType: "string"
3585
+ }
3586
+ },
3587
+ {
3588
+ id: "direction",
3589
+ label: "Direction",
3590
+ type: "select",
3591
+ required: true,
3592
+ defaultValue: "inbound",
3593
+ options: [
3594
+ { label: "Inbound (User \u2192 System)", value: "inbound" },
3595
+ { label: "Outbound (System \u2192 User)", value: "outbound" }
3596
+ ]
3597
+ },
3598
+ {
3599
+ id: "content",
3600
+ label: "Content",
3601
+ type: "string",
3602
+ required: true,
3603
+ placeholder: "Message content",
3604
+ handle: {
3605
+ type: "input",
3606
+ label: "Content",
3607
+ name: "content",
3608
+ fieldType: "string"
3609
+ }
3610
+ },
3611
+ {
3612
+ id: "source",
3613
+ label: "Source",
3614
+ type: "string",
3615
+ required: false,
3616
+ defaultValue: "whatsapp",
3617
+ placeholder: "whatsapp, telegram, web",
3618
+ handle: {
3619
+ type: "input",
3620
+ label: "Source",
3621
+ name: "source",
3622
+ fieldType: "string"
3623
+ }
3624
+ },
3625
+ {
3626
+ id: "identifier",
3627
+ label: "Identifier",
3628
+ type: "string",
3629
+ required: false,
3630
+ placeholder: "+5511999999999",
3631
+ handle: {
3632
+ type: "input",
3633
+ label: "Identifier",
3634
+ name: "identifier",
3635
+ fieldType: "string"
3636
+ }
3637
+ },
3638
+ {
3639
+ id: "messageId",
3640
+ label: "Message ID",
3641
+ type: "string",
3642
+ required: true,
3643
+ typeable: false,
3644
+ handle: {
3645
+ type: "output",
3646
+ label: "Message ID",
3647
+ name: "messageId",
3648
+ fieldType: "string"
3649
+ }
3650
+ },
3651
+ {
3652
+ id: "success",
3653
+ label: "Success",
3654
+ type: "boolean",
3655
+ required: true,
3656
+ typeable: false,
3657
+ handle: {
3658
+ type: "output",
3659
+ label: "Success",
3660
+ name: "success",
3661
+ fieldType: "boolean"
3662
+ }
3663
+ }
3664
+ ]
3665
+ };
3666
+
3667
+ // src/nodes/chat/chatLog/function.ts
3668
+ var ChatLogNodeFunction = async (inputs) => {
3669
+ const fieldValues = inputs.fieldValues || {};
3670
+ const context = inputs.context || {};
3671
+ const threadId = fieldValues.threadId;
3672
+ const direction = fieldValues.direction;
3673
+ const content = fieldValues.content;
3674
+ const source = fieldValues.source;
3675
+ const identifier = fieldValues.identifier;
3676
+ const companyId = context?.companyId;
3677
+ if (!companyId) {
3678
+ throw new Error("ChatLog requires companyId in context for tenant isolation");
3679
+ }
3680
+ if (!threadId || !content) {
3681
+ throw new Error("ChatLog requires threadId and content");
3682
+ }
3683
+ const role = direction === "inbound" ? "user" : "assistant";
3684
+ const db = context?.db;
3685
+ if (!db) {
3686
+ throw new Error("ChatLog requires database connection in context");
3687
+ }
3688
+ try {
3689
+ const sessionResult = await db.query(`
3690
+ SELECT id FROM chat_sessions
3691
+ WHERE session_id = $1 AND company_id = $2
3692
+ LIMIT 1
3693
+ `, [threadId, companyId]);
3694
+ if (!sessionResult.rows || sessionResult.rows.length === 0) {
3695
+ throw new Error(`Session not found for threadId: ${threadId}`);
3696
+ }
3697
+ const sessionId = sessionResult.rows[0].id;
3698
+ const messageId = crypto.randomUUID();
3699
+ await db.query(`
3700
+ INSERT INTO chat_messages (id, session_id, role, content, metadata)
3701
+ VALUES ($1, $2, $3, $4, $5)
3702
+ `, [
3703
+ messageId,
3704
+ sessionId,
3705
+ role,
3706
+ content,
3707
+ JSON.stringify({
3708
+ direction,
3709
+ source: source || null,
3710
+ identifier: identifier || null
3711
+ })
3712
+ ]);
3713
+ await db.query(`
3714
+ UPDATE chat_sessions
3715
+ SET updated_at = NOW()
3716
+ WHERE id = $1 AND company_id = $2
3717
+ `, [sessionId, companyId]);
3718
+ return {
3719
+ messageId,
3720
+ success: true
3721
+ };
3722
+ } catch (error) {
3723
+ console.error("[ChatLog] Error:", error);
3724
+ return {
3725
+ messageId: null,
3726
+ success: false
3727
+ };
3728
+ }
3729
+ };
3730
+
3731
+ // src/nodes/chat/isHumanActive/data.ts
3732
+ var IsHumanActiveData = {
3733
+ label: "Is Human Active?",
3734
+ type: "isHumanActive",
3735
+ category: "chat",
3736
+ description: "Checks if a human agent is currently handling the conversation (handoff mode).",
3737
+ icon: "\u{1F464}",
3738
+ group: "Chat",
3739
+ tags: {
3740
+ execution: "async",
3741
+ group: "Chat"
3742
+ },
3743
+ fields: [
3744
+ {
3745
+ id: "threadId",
3746
+ label: "Thread ID",
3747
+ type: "string",
3748
+ required: false,
3749
+ typeable: true,
3750
+ placeholder: "Session/Thread ID (optional, uses context if empty)",
3751
+ handle: {
3752
+ type: "input",
3753
+ label: "Thread ID",
3754
+ name: "threadId",
3755
+ fieldType: "string"
3756
+ }
3757
+ },
3758
+ {
3759
+ id: "active",
3760
+ label: "Active",
3761
+ type: "boolean",
3762
+ required: true,
3763
+ typeable: false,
3764
+ handle: {
3765
+ type: "output",
3766
+ label: "Active",
3767
+ name: "active",
3768
+ fieldType: "continue"
3769
+ }
3770
+ },
3771
+ {
3772
+ id: "inactive",
3773
+ label: "Inactive",
3774
+ type: "boolean",
3775
+ required: true,
3776
+ typeable: false,
3777
+ handle: {
3778
+ type: "output",
3779
+ label: "Inactive",
3780
+ name: "inactive",
3781
+ fieldType: "continue"
3782
+ }
3783
+ }
3784
+ ]
3785
+ };
3786
+
3787
+ // src/nodes/chat/isHumanActive/function.ts
3788
+ var isHumanActiveFunc = async (inputs) => {
3789
+ const fieldValues = inputs.fieldValues || {};
3790
+ const context = inputs.context || {};
3791
+ const sessionId = inputs.threadId || fieldValues.threadId || context?.sessionId || context?.chatId;
3792
+ if (!sessionId) {
3793
+ console.warn("[IsHumanActive] No sessionId found in input or context.");
3794
+ return {
3795
+ active: false,
3796
+ inactive: true
3797
+ };
3798
+ }
3799
+ const db = context?.db;
3800
+ if (!db) {
3801
+ console.warn("[IsHumanActive] No database connection in context.");
3802
+ return { active: false, inactive: true };
3803
+ }
3804
+ try {
3805
+ const result = await db.query(`
3806
+ SELECT human_active_until
3807
+ FROM chat_sessions
3808
+ WHERE session_id = $1
3809
+ LIMIT 1
3810
+ `, [sessionId]);
3811
+ const session = result.rows?.[0];
3812
+ if (!session) {
3813
+ console.warn(`[IsHumanActive] Session not found: ${sessionId}`);
3814
+ return { active: false, inactive: true };
3815
+ }
3816
+ const now = /* @__PURE__ */ new Date();
3817
+ const isActive = session.human_active_until && new Date(session.human_active_until) > now;
3818
+ console.log(`[IsHumanActive] Session: ${sessionId}, Until: ${session.human_active_until}, Active: ${isActive}`);
3819
+ return {
3820
+ active: !!isActive,
3821
+ inactive: !isActive
3822
+ };
3823
+ } catch (error) {
3824
+ console.error("[IsHumanActive] Error querying session:", error);
3825
+ return { active: false, inactive: true };
3826
+ }
3827
+ };
3828
+
3829
+ // src/nodes/logic/varNode/data.ts
3830
+ var VarNode = {
3831
+ label: "Variable",
3832
+ type: "VarNode",
3833
+ category: "logic",
3834
+ description: "Stores a value from multiple inputs. Strategy: keep first or last value received.",
3835
+ icon: "\u{1F4E6}",
3836
+ group: "Control",
3837
+ tags: {
3838
+ execution: "sync",
3839
+ group: "Control"
3840
+ },
3841
+ fields: [
3842
+ {
3843
+ id: "strategy",
3844
+ label: "Strategy",
3845
+ type: "select",
3846
+ required: true,
3847
+ defaultValue: "first",
3848
+ options: [
3849
+ { label: "First Value", value: "first" },
3850
+ { label: "Last Value", value: "last" }
3851
+ ]
3852
+ },
3853
+ {
3854
+ id: "value",
3855
+ label: "Value",
3856
+ type: "any",
3857
+ required: false,
3858
+ typeable: true,
3859
+ handle: {
3860
+ type: "input",
3861
+ label: "Value",
3862
+ name: "value",
3863
+ fieldType: "any",
3864
+ maxConnections: 10
3865
+ // Allow multiple connections
3866
+ }
3867
+ },
3868
+ {
3869
+ id: "output",
3870
+ label: "Output",
3871
+ type: "any",
3872
+ required: true,
3873
+ typeable: false,
3874
+ handle: {
3875
+ type: "output",
3876
+ label: "Value",
3877
+ name: "output",
3878
+ fieldType: "any"
3879
+ }
3880
+ },
3881
+ // Continue handle (hidden by default)
3882
+ {
3883
+ id: "continue",
3884
+ label: "Continue",
3885
+ type: "continue",
3886
+ typeable: false,
3887
+ active: false,
3888
+ // Hidden by default
3889
+ handle: {
3890
+ type: "output",
3891
+ label: "Continue",
3892
+ name: "continue",
3893
+ fieldType: "continue"
3894
+ }
3895
+ }
3896
+ ]
3897
+ };
3898
+
3899
+ // src/nodes/logic/varNode/function.ts
3900
+ var VarNodeFunction = async (inputs) => {
3901
+ const fieldValues = inputs.fieldValues || {};
3902
+ const strategy = fieldValues.strategy || "first";
3903
+ let values = inputs.value ?? fieldValues.value;
3904
+ if (!Array.isArray(values)) {
3905
+ values = values !== void 0 ? [values] : [];
3906
+ }
3907
+ const validValues = values.filter((v) => v !== void 0 && v !== null);
3908
+ if (validValues.length === 0) {
3909
+ return { output: void 0, continue: true };
3910
+ }
3911
+ const result = strategy === "first" ? validValues[0] : validValues[validValues.length - 1];
3912
+ return {
3913
+ output: result,
3914
+ continue: true
3915
+ };
3916
+ };
3917
+
3918
+ // src/nodes/logic/switchNode/data.ts
3919
+ var SwitchNode = {
3920
+ label: "Switch",
3921
+ type: "SwitchNode",
3922
+ category: "logic",
3923
+ description: "Routes execution based on input value. Each case triggers its corresponding path.",
3924
+ icon: "\u{1F500}",
3925
+ group: "Control",
3926
+ tags: {
3927
+ execution: "sync",
3928
+ group: "Control"
3929
+ },
3930
+ fields: [
3931
+ {
3932
+ id: "value",
3933
+ label: "Value",
3934
+ type: "string",
3935
+ required: true,
3936
+ typeable: true,
3937
+ placeholder: "Value to match",
3938
+ handle: {
3939
+ type: "input",
3940
+ label: "Value",
3941
+ name: "value",
3942
+ fieldType: "string"
3943
+ }
3944
+ },
3945
+ {
3946
+ id: "cases",
3947
+ label: "Cases",
3948
+ type: "keyValue",
3949
+ required: true,
3950
+ defaultValue: [
3951
+ { key: "whatsapp", value: "WhatsApp" },
3952
+ { key: "chat", value: "Web Chat" }
3953
+ ],
3954
+ placeholder: "Add cases (key = match value, value = label)"
3955
+ },
3956
+ {
3957
+ id: "includeDefault",
3958
+ label: "Include Default Path",
3959
+ type: "boolean",
3960
+ required: false,
3961
+ defaultValue: true
3962
+ }
3963
+ // Note: Dynamic outputs are generated based on 'cases' at runtime
3964
+ // Each case.key becomes an output handle of type 'continue'
3965
+ // Plus optional 'default' output if includeDefault is true
3966
+ ]
3967
+ };
3968
+
3969
+ // src/nodes/logic/switchNode/function.ts
3970
+ var SwitchNodeFunction = async (inputs) => {
3971
+ const fieldValues = inputs.fieldValues || {};
3972
+ const inputValue = inputs.value ?? fieldValues.value;
3973
+ const cases = fieldValues.cases || [];
3974
+ const includeDefault = fieldValues.includeDefault ?? true;
3975
+ const outputs = {};
3976
+ for (const c of cases) {
3977
+ outputs[c.key] = false;
3978
+ }
3979
+ if (includeDefault) {
3980
+ outputs["default"] = false;
3981
+ }
3982
+ const matchedCase = cases.find((c) => c.key === inputValue);
3983
+ if (matchedCase) {
3984
+ outputs[matchedCase.key] = true;
3985
+ } else if (includeDefault) {
3986
+ outputs["default"] = true;
3987
+ }
3988
+ return outputs;
3989
+ };
3990
+
3310
3991
  // src/nodes/consts/nodes.ts
3311
3992
  var nodes = [
3312
3993
  ChatInputNode,
@@ -3333,7 +4014,12 @@ var nodes = [
3333
4014
  PromptGuardrailNode,
3334
4015
  RuleGuardrailNode,
3335
4016
  FunctionGuardrailNode,
3336
- ModelGuardrailNode
4017
+ ModelGuardrailNode,
4018
+ GetOrCreateThreadNode,
4019
+ ChatLogNode,
4020
+ IsHumanActiveData,
4021
+ VarNode,
4022
+ SwitchNode
3337
4023
  ];
3338
4024
  var nodes_default = nodes;
3339
4025
 
@@ -3455,7 +4141,12 @@ var nodeFunctions = {
3455
4141
  PromptGuardrailNode: PromptGuardrailNodeFunction,
3456
4142
  RuleGuardrailNode: RuleGuardrailNodeFunction,
3457
4143
  FunctionGuardrailNode: FunctionGuardrailNodeFunction,
3458
- ModelGuardrailNode: ModelGuardrailNodeFunction
4144
+ ModelGuardrailNode: ModelGuardrailNodeFunction,
4145
+ GetOrCreateThreadNode: GetOrCreateThreadNodeFunction,
4146
+ ChatLogNode: ChatLogNodeFunction,
4147
+ isHumanActive: isHumanActiveFunc,
4148
+ VarNode: VarNodeFunction,
4149
+ SwitchNode: SwitchNodeFunction
3459
4150
  };
3460
4151
  var node_functions_default = nodeFunctions;
3461
4152
 
@@ -3569,12 +4260,12 @@ var HttpPutInputNodeFunction = (params) => {
3569
4260
  };
3570
4261
 
3571
4262
  // src/nodes/inputs/http/put/schema.ts
3572
- var import_zod17 = require("zod");
3573
- var HttpPutInputNodeSchema = import_zod17.z.object({
4263
+ var import_zod19 = require("zod");
4264
+ var HttpPutInputNodeSchema = import_zod19.z.object({
3574
4265
  route: RouteSchema,
3575
- queryParams: import_zod17.z.array(QueryParamSchema).optional().describe("Query parameters configuration"),
3576
- headers: import_zod17.z.array(HeaderSchema).optional().describe("Headers configuration"),
3577
- body: import_zod17.z.array(BodyFieldSchema).optional().describe("Body fields configuration")
4266
+ queryParams: import_zod19.z.array(QueryParamSchema).optional().describe("Query parameters configuration"),
4267
+ headers: import_zod19.z.array(HeaderSchema).optional().describe("Headers configuration"),
4268
+ body: import_zod19.z.array(BodyFieldSchema).optional().describe("Body fields configuration")
3578
4269
  });
3579
4270
 
3580
4271
  // src/nodes/inputs/http/delete/data.ts
@@ -3666,11 +4357,11 @@ var HttpDeleteInputNodeFunction = async (params) => {
3666
4357
  };
3667
4358
 
3668
4359
  // src/nodes/inputs/http/delete/schema.ts
3669
- var import_zod18 = require("zod");
3670
- var HttpDeleteInputNodeSchema = import_zod18.z.object({
4360
+ var import_zod20 = require("zod");
4361
+ var HttpDeleteInputNodeSchema = import_zod20.z.object({
3671
4362
  route: RouteSchema,
3672
- queryParams: import_zod18.z.array(QueryParamSchema).optional().describe("Query parameters configuration"),
3673
- headers: import_zod18.z.array(HeaderSchema).optional().describe("Headers configuration")
4363
+ queryParams: import_zod20.z.array(QueryParamSchema).optional().describe("Query parameters configuration"),
4364
+ headers: import_zod20.z.array(HeaderSchema).optional().describe("Headers configuration")
3674
4365
  });
3675
4366
 
3676
4367
  // src/nodes/inputs/http/patch/data.ts
@@ -3783,12 +4474,12 @@ var HttpPatchInputNodeFunction = (params) => {
3783
4474
  };
3784
4475
 
3785
4476
  // src/nodes/inputs/http/patch/schema.ts
3786
- var import_zod19 = require("zod");
3787
- var HttpPatchInputNodeSchema = import_zod19.z.object({
4477
+ var import_zod21 = require("zod");
4478
+ var HttpPatchInputNodeSchema = import_zod21.z.object({
3788
4479
  route: RouteSchema,
3789
- queryParams: import_zod19.z.array(QueryParamSchema).optional().describe("Query parameters configuration"),
3790
- headers: import_zod19.z.array(HeaderSchema).optional().describe("Headers configuration"),
3791
- body: import_zod19.z.array(BodyFieldSchema).optional().describe("Body fields configuration")
4480
+ queryParams: import_zod21.z.array(QueryParamSchema).optional().describe("Query parameters configuration"),
4481
+ headers: import_zod21.z.array(HeaderSchema).optional().describe("Headers configuration"),
4482
+ body: import_zod21.z.array(BodyFieldSchema).optional().describe("Body fields configuration")
3792
4483
  });
3793
4484
 
3794
4485
  // src/nodes/inputs/http/utils.ts
@@ -3848,7 +4539,13 @@ var getHttpMethodFromFriendlyId = (friendlyId) => {
3848
4539
  AiToolNodeFunction,
3849
4540
  AiToolNodeSchema,
3850
4541
  BodyFieldSchema,
4542
+ ChatLogNode,
4543
+ ChatLogNodeFunction,
4544
+ ChatLogSchema,
3851
4545
  CustomToolSchema,
4546
+ GetOrCreateThreadNode,
4547
+ GetOrCreateThreadNodeFunction,
4548
+ GetOrCreateThreadSchema,
3852
4549
  HTTP_METHODS,
3853
4550
  HTTP_NODE_TYPES,
3854
4551
  HeaderSchema,
@@ -3873,8 +4570,13 @@ var getHttpMethodFromFriendlyId = (friendlyId) => {
3873
4570
  IaMessageNode,
3874
4571
  IaMessageNodeFunction,
3875
4572
  IaMessageNodeSchema,
4573
+ IsHumanActiveData,
3876
4574
  QueryParamSchema,
3877
4575
  RouteSchema,
4576
+ SwitchNode,
4577
+ SwitchNodeFunction,
4578
+ VarNode,
4579
+ VarNodeFunction,
3878
4580
  WhatsappMessageTriggerNode,
3879
4581
  WhatsappSendMessageFunction,
3880
4582
  WhatsappSendMessageNode,
@@ -3894,6 +4596,7 @@ var getHttpMethodFromFriendlyId = (friendlyId) => {
3894
4596
  isHttpInputFriendlyId,
3895
4597
  isHttpInputNode,
3896
4598
  isHttpMethodNode,
4599
+ isHumanActiveFunc,
3897
4600
  nodeFunctions,
3898
4601
  nodes,
3899
4602
  schemas