@botonic/plugin-flow-builder 0.57.0-rslib-esm.1 → 0.58.0-alpha-new-stack.0
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/lib/action/ai-agent-from-user-input.js +8 -0
- package/lib/action/ai-agent-from-user-input.js.map +1 -1
- package/lib/action/first-interaction.js +10 -0
- package/lib/action/first-interaction.js.map +1 -1
- package/lib/action/get-contents.js +5 -2
- package/lib/action/get-contents.js.map +1 -1
- package/lib/action/index.js +8 -1
- package/lib/action/index.js.map +1 -1
- package/lib/api.d.ts +8 -3
- package/lib/api.js +37 -13
- package/lib/api.js.map +1 -1
- package/lib/bot-context-manager.d.ts +17 -0
- package/lib/bot-context-manager.js +101 -0
- package/lib/bot-context-manager.js.map +1 -0
- package/lib/constants.d.ts +2 -1
- package/lib/constants.js +4 -3
- package/lib/constants.js.map +1 -1
- package/lib/content-fields/contact-reasons-conditional-matcher.d.ts +4 -0
- package/lib/content-fields/contact-reasons-conditional-matcher.js +10 -0
- package/lib/content-fields/contact-reasons-conditional-matcher.js.map +1 -0
- package/lib/content-fields/flow-ai-agent-base.js +7 -1
- package/lib/content-fields/flow-ai-agent-base.js.map +1 -1
- package/lib/content-fields/flow-ai-agent-router.js +2 -1
- package/lib/content-fields/flow-ai-agent-router.js.map +1 -1
- package/lib/content-fields/flow-ai-agent.js +2 -1
- package/lib/content-fields/flow-ai-agent.js.map +1 -1
- package/lib/content-fields/flow-contact-reasons-conditional.d.ts +14 -0
- package/lib/content-fields/flow-contact-reasons-conditional.js +68 -0
- package/lib/content-fields/flow-contact-reasons-conditional.js.map +1 -0
- package/lib/content-fields/flow-do-nothing.d.ts +9 -0
- package/lib/content-fields/flow-do-nothing.js +33 -0
- package/lib/content-fields/flow-do-nothing.js.map +1 -0
- package/lib/content-fields/flow-handoff.d.ts +7 -1
- package/lib/content-fields/flow-handoff.js +41 -3
- package/lib/content-fields/flow-handoff.js.map +1 -1
- package/lib/content-fields/flow-whatsapp-request-contact-info.d.ts +2 -1
- package/lib/content-fields/flow-whatsapp-request-contact-info.js +11 -0
- package/lib/content-fields/flow-whatsapp-request-contact-info.js.map +1 -1
- package/lib/content-fields/hubtype-fields/contact-reasons-conditional.d.ts +16 -0
- package/lib/content-fields/hubtype-fields/contact-reasons-conditional.js +4 -0
- package/lib/content-fields/hubtype-fields/contact-reasons-conditional.js.map +1 -0
- package/lib/content-fields/hubtype-fields/do-nothing.d.ts +6 -0
- package/lib/content-fields/hubtype-fields/do-nothing.js +4 -0
- package/lib/content-fields/hubtype-fields/do-nothing.js.map +1 -0
- package/lib/content-fields/hubtype-fields/handoff.d.ts +11 -1
- package/lib/content-fields/hubtype-fields/handoff.js +7 -1
- package/lib/content-fields/hubtype-fields/handoff.js.map +1 -1
- package/lib/content-fields/hubtype-fields/index.d.ts +1 -0
- package/lib/content-fields/hubtype-fields/index.js +2 -0
- package/lib/content-fields/hubtype-fields/index.js.map +1 -1
- package/lib/content-fields/hubtype-fields/node-types.d.ts +3 -1
- package/lib/content-fields/hubtype-fields/node-types.js +2 -0
- package/lib/content-fields/hubtype-fields/node-types.js.map +1 -1
- package/lib/content-fields/hubtype-fields/nodes.d.ts +3 -1
- package/lib/content-fields/hubtype-fields/nodes.js.map +1 -1
- package/lib/content-fields/hubtype-fields/whatsapp-request-contact-info.d.ts +2 -0
- package/lib/content-fields/hubtype-fields/whatsapp-request-contact-info.js.map +1 -1
- package/lib/content-fields/index.d.ts +4 -2
- package/lib/content-fields/index.js +6 -0
- package/lib/content-fields/index.js.map +1 -1
- package/lib/flow-factory.js +5 -1
- package/lib/flow-factory.js.map +1 -1
- package/lib/index.d.ts +5 -8
- package/lib/index.js +17 -55
- package/lib/index.js.map +1 -1
- package/lib/types.d.ts +2 -2
- package/lib/types.js.map +1 -1
- package/lib/utils/hubtype-assistant-content.d.ts +1 -0
- package/lib/utils/hubtype-assistant-content.js +13 -0
- package/lib/utils/hubtype-assistant-content.js.map +1 -1
- package/package.json +4 -4
- package/src/action/ai-agent-from-user-input.ts +7 -0
- package/src/action/first-interaction.ts +6 -0
- package/src/action/get-contents.ts +17 -2
- package/src/action/index.tsx +7 -0
- package/src/api.ts +52 -15
- package/src/bot-context-manager.ts +153 -0
- package/src/constants.ts +2 -1
- package/src/content-fields/contact-reasons-conditional-matcher.ts +24 -0
- package/src/content-fields/flow-ai-agent-base.tsx +12 -1
- package/src/content-fields/flow-ai-agent-router.tsx +1 -0
- package/src/content-fields/flow-ai-agent.tsx +1 -0
- package/src/content-fields/flow-contact-reasons-conditional.tsx +90 -0
- package/src/content-fields/flow-do-nothing.tsx +29 -0
- package/src/content-fields/flow-handoff.tsx +54 -7
- package/src/content-fields/flow-whatsapp-request-contact-info.tsx +19 -1
- package/src/content-fields/hubtype-fields/contact-reasons-conditional.ts +18 -0
- package/src/content-fields/hubtype-fields/do-nothing.ts +7 -0
- package/src/content-fields/hubtype-fields/handoff.ts +17 -1
- package/src/content-fields/hubtype-fields/index.ts +1 -0
- package/src/content-fields/hubtype-fields/node-types.ts +2 -0
- package/src/content-fields/hubtype-fields/nodes.ts +4 -0
- package/src/content-fields/hubtype-fields/whatsapp-request-contact-info.ts +2 -0
- package/src/content-fields/index.ts +6 -0
- package/src/flow-factory.ts +11 -0
- package/src/index.ts +26 -88
- package/src/types.ts +1 -2
- package/src/utils/hubtype-assistant-content.ts +14 -0
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { NluType } from "@botonic/core";
|
|
1
2
|
import { splitAiAgentContents } from "../utils/ai-agent.js";
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
|
|
6
|
+
|
|
7
|
+
|
|
5
8
|
async function getContentsByAiAgentFromUserInput({ cmsApi, flowBuilderPlugin, request }) {
|
|
6
9
|
const startNodeAiAgentFlow = cmsApi.getStartNodeAiAgentFlow();
|
|
7
10
|
const isAiAgentEnabled = cmsApi.isAiAgentEnabled();
|
|
@@ -27,6 +30,11 @@ async function getContentsByAiAgentFromUserInput({ cmsApi, flowBuilderPlugin, re
|
|
|
27
30
|
return [];
|
|
28
31
|
}
|
|
29
32
|
}
|
|
33
|
+
request.input.nluResolution = {
|
|
34
|
+
type: NluType.AiAgent,
|
|
35
|
+
matchedValue: 'ai-agent-from-user-input',
|
|
36
|
+
payload: undefined
|
|
37
|
+
};
|
|
30
38
|
return contents;
|
|
31
39
|
}
|
|
32
40
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action/ai-agent-from-user-input.js","sources":["../../src/action/ai-agent-from-user-input.ts"],"sourcesContent":["import type { FlowContent } from '../content-fields/index'\nimport { splitAiAgentContents } from '../utils/ai-agent'\nimport type { FlowBuilderContext } from './context'\n\nexport async function getContentsByAiAgentFromUserInput({\n cmsApi,\n flowBuilderPlugin,\n request,\n}: FlowBuilderContext): Promise<FlowContent[]> {\n const startNodeAiAgentFlow = cmsApi.getStartNodeAiAgentFlow()\n const isAiAgentEnabled = cmsApi.isAiAgentEnabled()\n if (!startNodeAiAgentFlow || !isAiAgentEnabled) {\n return []\n }\n\n const contents =\n await flowBuilderPlugin.getContentsByNode(startNodeAiAgentFlow)\n\n const splitContents = splitAiAgentContents(contents)\n\n if (!splitContents) {\n return []\n }\n\n if ('aiAgentRouterContent' in splitContents) {\n const { aiAgentRouterContent, contentsBeforeAiAgentRouter } = splitContents\n const aiAgentResponse = await aiAgentRouterContent.resolveAIAgentResponse(\n request,\n contentsBeforeAiAgentRouter\n )\n\n if (!aiAgentResponse || aiAgentResponse.exit) {\n return []\n }\n }\n\n if ('aiAgentWorkerContent' in splitContents) {\n const { aiAgentWorkerContent, contentsBeforeAiAgentWorker } = splitContents\n const aiAgentResponse = await aiAgentWorkerContent.resolveAIAgentResponse(\n request,\n contentsBeforeAiAgentWorker\n )\n\n if (!aiAgentResponse || aiAgentResponse.exit) {\n return []\n }\n }\n\n return contents\n}\n"],"names":["splitAiAgentContents","getContentsByAiAgentFromUserInput","cmsApi","flowBuilderPlugin","request","startNodeAiAgentFlow","isAiAgentEnabled","contents","splitContents","aiAgentRouterContent","contentsBeforeAiAgentRouter","aiAgentResponse","aiAgentWorkerContent","contentsBeforeAiAgentWorker"],"mappings":"
|
|
1
|
+
{"version":3,"file":"action/ai-agent-from-user-input.js","sources":["../../src/action/ai-agent-from-user-input.ts"],"sourcesContent":["import { NluType } from '@botonic/core'\nimport type { FlowContent } from '../content-fields/index'\nimport { splitAiAgentContents } from '../utils/ai-agent'\nimport type { FlowBuilderContext } from './context'\n\nexport async function getContentsByAiAgentFromUserInput({\n cmsApi,\n flowBuilderPlugin,\n request,\n}: FlowBuilderContext): Promise<FlowContent[]> {\n const startNodeAiAgentFlow = cmsApi.getStartNodeAiAgentFlow()\n const isAiAgentEnabled = cmsApi.isAiAgentEnabled()\n if (!startNodeAiAgentFlow || !isAiAgentEnabled) {\n return []\n }\n\n const contents =\n await flowBuilderPlugin.getContentsByNode(startNodeAiAgentFlow)\n\n const splitContents = splitAiAgentContents(contents)\n\n if (!splitContents) {\n return []\n }\n\n if ('aiAgentRouterContent' in splitContents) {\n const { aiAgentRouterContent, contentsBeforeAiAgentRouter } = splitContents\n const aiAgentResponse = await aiAgentRouterContent.resolveAIAgentResponse(\n request,\n contentsBeforeAiAgentRouter\n )\n\n if (!aiAgentResponse || aiAgentResponse.exit) {\n return []\n }\n }\n\n if ('aiAgentWorkerContent' in splitContents) {\n const { aiAgentWorkerContent, contentsBeforeAiAgentWorker } = splitContents\n const aiAgentResponse = await aiAgentWorkerContent.resolveAIAgentResponse(\n request,\n contentsBeforeAiAgentWorker\n )\n\n if (!aiAgentResponse || aiAgentResponse.exit) {\n return []\n }\n }\n\n request.input.nluResolution = {\n type: NluType.AiAgent,\n matchedValue: 'ai-agent-from-user-input',\n payload: undefined,\n }\n\n return contents\n}\n"],"names":["NluType","splitAiAgentContents","getContentsByAiAgentFromUserInput","cmsApi","flowBuilderPlugin","request","startNodeAiAgentFlow","isAiAgentEnabled","contents","splitContents","aiAgentRouterContent","contentsBeforeAiAgentRouter","aiAgentResponse","aiAgentWorkerContent","contentsBeforeAiAgentWorker","undefined"],"mappings":";;;;;AAAuC;AAEiB;AAGjD,eAAeE,iCAAiCA,CAAC,EACtDC,MAAM,EACNC,iBAAiB,EACjBC,OAAO,EACY;IACnB,MAAMC,uBAAuBH,OAAO,uBAAuB;IAC3D,MAAMI,mBAAmBJ,OAAO,gBAAgB;IAChD,IAAI,CAACG,wBAAwB,CAACC,kBAAkB;QAC9C,OAAO,EAAE;IACX;IAEA,MAAMC,WACJ,MAAMJ,kBAAkB,iBAAiB,CAACE;IAE5C,MAAMG,gBAAgBR,oBAAoBA,CAACO;IAE3C,IAAI,CAACC,eAAe;QAClB,OAAO,EAAE;IACX;IAEA,IAAI,0BAA0BA,eAAe;QAC3C,MAAM,EAAEC,oBAAoB,EAAEC,2BAA2B,EAAE,GAAGF;QAC9D,MAAMG,kBAAkB,MAAMF,qBAAqB,sBAAsB,CACvEL,SACAM;QAGF,IAAI,CAACC,mBAAmBA,gBAAgB,IAAI,EAAE;YAC5C,OAAO,EAAE;QACX;IACF;IAEA,IAAI,0BAA0BH,eAAe;QAC3C,MAAM,EAAEI,oBAAoB,EAAEC,2BAA2B,EAAE,GAAGL;QAC9D,MAAMG,kBAAkB,MAAMC,qBAAqB,sBAAsB,CACvER,SACAS;QAGF,IAAI,CAACF,mBAAmBA,gBAAgB,IAAI,EAAE;YAC5C,OAAO,EAAE;QACX;IACF;IAEAP,QAAQ,KAAK,CAAC,aAAa,GAAG;QAC5B,MAAML,eAAe;QACrB,cAAc;QACd,SAASe;IACX;IAEA,OAAOP;AACT"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { NluType } from "@botonic/core";
|
|
1
2
|
import { MAIN_FLOW_NAME } from "../constants.js";
|
|
2
3
|
import { FlowAiAgent, FlowAiAgentRouter, FlowBotAction } from "../content-fields/index.js";
|
|
3
4
|
import { inputHasTextOrTranscript } from "../utils/input.js";
|
|
@@ -14,6 +15,8 @@ import { getContentsByPayload } from "./payload.js";
|
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
|
|
18
|
+
|
|
19
|
+
|
|
17
20
|
async function getContentsByFirstInteraction(context) {
|
|
18
21
|
const { contentID, flowBuilderPlugin, request } = context;
|
|
19
22
|
/*
|
|
@@ -41,6 +44,13 @@ async function getContentsByFirstInteraction(context) {
|
|
|
41
44
|
}
|
|
42
45
|
if (request.input.nluResolution || inputHasTextOrTranscript(request.input)) {
|
|
43
46
|
const contentsByUserInput = await getContentsByUserInput(context);
|
|
47
|
+
if (request.input.nluResolution?.type === NluType.AiAgent) {
|
|
48
|
+
const startContents = await flowBuilderPlugin.getStartContents();
|
|
49
|
+
return [
|
|
50
|
+
...startContents,
|
|
51
|
+
...contentsByUserInput
|
|
52
|
+
];
|
|
53
|
+
}
|
|
44
54
|
return [
|
|
45
55
|
...firstInteractionContents,
|
|
46
56
|
...contentsByUserInput
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action/first-interaction.js","sources":["../../src/action/first-interaction.ts"],"sourcesContent":["import type { FlowBuilderApi } from '../api'\nimport { MAIN_FLOW_NAME } from '../constants'\nimport {\n FlowAiAgent,\n FlowAiAgentRouter,\n FlowBotAction,\n type FlowContent,\n} from '../content-fields'\nimport type BotonicPluginFlowBuilder from '../index'\nimport { inputHasTextOrTranscript } from '../utils/input'\nimport { getContentsByAiAgentFromUserInput } from './ai-agent-from-user-input'\nimport type { FlowBuilderContext } from './context'\nimport { getContentsByPayload } from './payload'\n\nexport async function getContentsByFirstInteraction(\n context: FlowBuilderContext\n): Promise<FlowContent[]> {\n const { contentID, flowBuilderPlugin, request } = context\n\n /*\n * If the contentID is provided, the firstInteractionContents are obtained even if they are not used\n * because when obtain this firstInteractionContents is when the session.flow_thread_id is updated.\n * This is needed for example when send a WhatsApp campaign is sent,\n * the bot not receives the message because this message is sent directly by the backend\n * we expect the bot to respond only with the contents of the contentID and not with the firstInteractionContents.\n */\n const firstInteractionContents = await flowBuilderPlugin.getStartContents()\n\n if (contentID) {\n try {\n const contentsByContentID =\n await flowBuilderPlugin.getContentsByContentID(contentID)\n\n if (contentsByContentID.length > 0) {\n return contentsByContentID\n }\n } catch (_error) {\n console.warn(\n `The contentID ${contentID} is not found. Returning the firstInteractionContents`\n )\n }\n }\n\n // Bot actions and AI agents already consume the user input. Matching\n // keywords/intents/KB/AI-agent-from-user-input on top would duplicate replies\n // (e.g. Main start → Go to flow → AI Agents).\n if (startContentsAlreadyHandleUserInput(firstInteractionContents)) {\n return firstInteractionContents\n }\n\n if (request.input.nluResolution || inputHasTextOrTranscript(request.input)) {\n const contentsByUserInput = await getContentsByUserInput(context)\n\n return [...firstInteractionContents, ...contentsByUserInput]\n }\n\n return firstInteractionContents\n}\n\nfunction startContentsAlreadyHandleUserInput(contents: FlowContent[]): boolean {\n if (contents.at(-1) instanceof FlowBotAction) {\n return true\n }\n\n // To avoid duplicated ai agent response, we check if there is an ai agent or ai agent router in the first interaction contents.\n return contents.some(\n content =>\n content instanceof FlowAiAgent || content instanceof FlowAiAgentRouter\n )\n}\n\nasync function getContentsByUserInput(\n context: FlowBuilderContext\n): Promise<FlowContent[]> {\n const { cmsApi, flowBuilderPlugin, request, resolvedLocale } = context\n const payloadByNlu = request.input.nluResolution?.payload\n\n if (payloadByNlu) {\n request.input.payload = payloadByNlu\n const conversationStartId = getConversationStartId(cmsApi)\n\n if (request.input.payload === conversationStartId) {\n return []\n }\n\n const contentsByKeywordsOrIntents = await getContentsByPayload({\n cmsApi,\n flowBuilderPlugin,\n request,\n resolvedLocale,\n })\n\n const hasRepeatedContent = await checkRepeatedContents(\n flowBuilderPlugin,\n contentsByKeywordsOrIntents\n )\n\n if (hasRepeatedContent) {\n return []\n }\n\n if (contentsByKeywordsOrIntents.length > 0) {\n return contentsByKeywordsOrIntents\n }\n }\n\n if (!flowBuilderPlugin.disableAIAgentInFirstInteraction) {\n const contentsByAiAgent = await getContentsByAiAgentFromUserInput(context)\n return contentsByAiAgent\n }\n\n return []\n}\n\nfunction getConversationStartId(cmsApi: FlowBuilderApi) {\n const conversationStartId = cmsApi.flow.flows.find(\n flow => flow.name === MAIN_FLOW_NAME\n )?.start_node_id\n\n return conversationStartId\n}\n\nasync function checkRepeatedContents(\n flowBuilderPlugin: BotonicPluginFlowBuilder,\n contentsByKeywordsOrIntents: FlowContent[]\n) {\n const startContents = await flowBuilderPlugin.getStartContents()\n const contentIds = new Set(\n contentsByKeywordsOrIntents.map(content => content.id)\n )\n const hasRepeatedContent = startContents.some(content =>\n contentIds.has(content.id)\n )\n\n return hasRepeatedContent\n}\n"],"names":["MAIN_FLOW_NAME","FlowAiAgent","FlowAiAgentRouter","FlowBotAction","inputHasTextOrTranscript","getContentsByAiAgentFromUserInput","getContentsByPayload","getContentsByFirstInteraction","context","contentID","flowBuilderPlugin","request","firstInteractionContents","contentsByContentID","_error","console","startContentsAlreadyHandleUserInput","contentsByUserInput","getContentsByUserInput","contents","content","cmsApi","resolvedLocale","payloadByNlu","conversationStartId","getConversationStartId","contentsByKeywordsOrIntents","hasRepeatedContent","checkRepeatedContents","contentsByAiAgent","flow","
|
|
1
|
+
{"version":3,"file":"action/first-interaction.js","sources":["../../src/action/first-interaction.ts"],"sourcesContent":["import { NluType } from '@botonic/core'\nimport type { FlowBuilderApi } from '../api'\nimport { MAIN_FLOW_NAME } from '../constants'\nimport {\n FlowAiAgent,\n FlowAiAgentRouter,\n FlowBotAction,\n type FlowContent,\n} from '../content-fields'\nimport type BotonicPluginFlowBuilder from '../index'\nimport { inputHasTextOrTranscript } from '../utils/input'\nimport { getContentsByAiAgentFromUserInput } from './ai-agent-from-user-input'\nimport type { FlowBuilderContext } from './context'\nimport { getContentsByPayload } from './payload'\n\nexport async function getContentsByFirstInteraction(\n context: FlowBuilderContext\n): Promise<FlowContent[]> {\n const { contentID, flowBuilderPlugin, request } = context\n\n /*\n * If the contentID is provided, the firstInteractionContents are obtained even if they are not used\n * because when obtain this firstInteractionContents is when the session.flow_thread_id is updated.\n * This is needed for example when send a WhatsApp campaign is sent,\n * the bot not receives the message because this message is sent directly by the backend\n * we expect the bot to respond only with the contents of the contentID and not with the firstInteractionContents.\n */\n const firstInteractionContents = await flowBuilderPlugin.getStartContents()\n\n if (contentID) {\n try {\n const contentsByContentID =\n await flowBuilderPlugin.getContentsByContentID(contentID)\n\n if (contentsByContentID.length > 0) {\n return contentsByContentID\n }\n } catch (_error) {\n console.warn(\n `The contentID ${contentID} is not found. Returning the firstInteractionContents`\n )\n }\n }\n\n // Bot actions and AI agents already consume the user input. Matching\n // keywords/intents/KB/AI-agent-from-user-input on top would duplicate replies\n // (e.g. Main start → Go to flow → AI Agents).\n if (startContentsAlreadyHandleUserInput(firstInteractionContents)) {\n return firstInteractionContents\n }\n\n if (request.input.nluResolution || inputHasTextOrTranscript(request.input)) {\n const contentsByUserInput = await getContentsByUserInput(context)\n\n if (request.input.nluResolution?.type === NluType.AiAgent) {\n const startContents = await flowBuilderPlugin.getStartContents()\n return [...startContents, ...contentsByUserInput]\n }\n\n return [...firstInteractionContents, ...contentsByUserInput]\n }\n\n return firstInteractionContents\n}\n\nfunction startContentsAlreadyHandleUserInput(contents: FlowContent[]): boolean {\n if (contents.at(-1) instanceof FlowBotAction) {\n return true\n }\n\n // To avoid duplicated ai agent response, we check if there is an ai agent or ai agent router in the first interaction contents.\n return contents.some(\n content =>\n content instanceof FlowAiAgent || content instanceof FlowAiAgentRouter\n )\n}\n\nasync function getContentsByUserInput(\n context: FlowBuilderContext\n): Promise<FlowContent[]> {\n const { cmsApi, flowBuilderPlugin, request, resolvedLocale } = context\n const payloadByNlu = request.input.nluResolution?.payload\n\n if (payloadByNlu) {\n request.input.payload = payloadByNlu\n const conversationStartId = getConversationStartId(cmsApi)\n\n if (request.input.payload === conversationStartId) {\n return []\n }\n\n const contentsByKeywordsOrIntents = await getContentsByPayload({\n cmsApi,\n flowBuilderPlugin,\n request,\n resolvedLocale,\n })\n\n const hasRepeatedContent = await checkRepeatedContents(\n flowBuilderPlugin,\n contentsByKeywordsOrIntents\n )\n\n if (hasRepeatedContent) {\n return []\n }\n\n if (contentsByKeywordsOrIntents.length > 0) {\n return contentsByKeywordsOrIntents\n }\n }\n\n if (!flowBuilderPlugin.disableAIAgentInFirstInteraction) {\n const contentsByAiAgent = await getContentsByAiAgentFromUserInput(context)\n return contentsByAiAgent\n }\n\n return []\n}\n\nfunction getConversationStartId(cmsApi: FlowBuilderApi) {\n const conversationStartId = cmsApi.flow.flows.find(\n flow => flow.name === MAIN_FLOW_NAME\n )?.start_node_id\n\n return conversationStartId\n}\n\nasync function checkRepeatedContents(\n flowBuilderPlugin: BotonicPluginFlowBuilder,\n contentsByKeywordsOrIntents: FlowContent[]\n) {\n const startContents = await flowBuilderPlugin.getStartContents()\n const contentIds = new Set(\n contentsByKeywordsOrIntents.map(content => content.id)\n )\n const hasRepeatedContent = startContents.some(content =>\n contentIds.has(content.id)\n )\n\n return hasRepeatedContent\n}\n"],"names":["NluType","MAIN_FLOW_NAME","FlowAiAgent","FlowAiAgentRouter","FlowBotAction","inputHasTextOrTranscript","getContentsByAiAgentFromUserInput","getContentsByPayload","getContentsByFirstInteraction","context","contentID","flowBuilderPlugin","request","firstInteractionContents","contentsByContentID","_error","console","startContentsAlreadyHandleUserInput","contentsByUserInput","getContentsByUserInput","startContents","contents","content","cmsApi","resolvedLocale","payloadByNlu","conversationStartId","getConversationStartId","contentsByKeywordsOrIntents","hasRepeatedContent","checkRepeatedContents","contentsByAiAgent","flow","contentIds","Set"],"mappings":";;;;;;;;;;;;;AAAuC;AAEM;AAMnB;AAE+B;AACqB;AAE9B;AAEzC,eAAeQ,6BAA6BA,CACjDC,OAA2B;IAE3B,MAAM,EAAEC,SAAS,EAAEC,iBAAiB,EAAEC,OAAO,EAAE,GAAGH;IAElD;;;;;;GAMC,GACD,MAAMI,2BAA2B,MAAMF,kBAAkB,gBAAgB;IAEzE,IAAID,WAAW;QACb,IAAI;YACF,MAAMI,sBACJ,MAAMH,kBAAkB,sBAAsB,CAACD;YAEjD,IAAII,oBAAoB,MAAM,GAAG,GAAG;gBAClC,OAAOA;YACT;QACF,EAAE,OAAOC,QAAQ;YACfC,QAAQ,IAAI,CACV,CAAC,cAAc,EAAEN,UAAU,qDAAqD,CAAC;QAErF;IACF;IAEA,qEAAqE;IACrE,8EAA8E;IAC9E,8CAA8C;IAC9C,IAAIO,mCAAmCA,CAACJ,2BAA2B;QACjE,OAAOA;IACT;IAEA,IAAID,QAAQ,KAAK,CAAC,aAAa,IAAIP,wBAAwBA,CAACO,QAAQ,KAAK,GAAG;QAC1E,MAAMM,sBAAsB,MAAMC,sBAAsBA,CAACV;QAEzD,IAAIG,QAAQ,KAAK,CAAC,aAAa,EAAE,SAASZ,eAAe,EAAE;YACzD,MAAMoB,gBAAgB,MAAMT,kBAAkB,gBAAgB;YAC9D,OAAO;mBAAIS;mBAAkBF;aAAoB;QACnD;QAEA,OAAO;eAAIL;eAA6BK;SAAoB;IAC9D;IAEA,OAAOL;AACT;AAEA,SAASI,mCAAmCA,CAACI,QAAuB;IAClE,IAAIA,SAAS,EAAE,CAAC,CAAC,cAAcjB,aAAaA,EAAE;QAC5C,OAAO;IACT;IAEA,gIAAgI;IAChI,OAAOiB,SAAS,IAAI,CAClBC,CAAAA,UACEA,mBAAmBpB,WAAWA,IAAIoB,mBAAmBnB,iBAAiBA;AAE5E;AAEA,eAAegB,sBAAsBA,CACnCV,OAA2B;IAE3B,MAAM,EAAEc,MAAM,EAAEZ,iBAAiB,EAAEC,OAAO,EAAEY,cAAc,EAAE,GAAGf;IAC/D,MAAMgB,eAAeb,QAAQ,KAAK,CAAC,aAAa,EAAE;IAElD,IAAIa,cAAc;QAChBb,QAAQ,KAAK,CAAC,OAAO,GAAGa;QACxB,MAAMC,sBAAsBC,sBAAsBA,CAACJ;QAEnD,IAAIX,QAAQ,KAAK,CAAC,OAAO,KAAKc,qBAAqB;YACjD,OAAO,EAAE;QACX;QAEA,MAAME,8BAA8B,MAAMrB,oBAAoBA,CAAC;YAC7DgB;YACAZ;YACAC;YACAY;QACF;QAEA,MAAMK,qBAAqB,MAAMC,qBAAqBA,CACpDnB,mBACAiB;QAGF,IAAIC,oBAAoB;YACtB,OAAO,EAAE;QACX;QAEA,IAAID,4BAA4B,MAAM,GAAG,GAAG;YAC1C,OAAOA;QACT;IACF;IAEA,IAAI,CAACjB,kBAAkB,gCAAgC,EAAE;QACvD,MAAMoB,oBAAoB,MAAMzB,iCAAiCA,CAACG;QAClE,OAAOsB;IACT;IAEA,OAAO,EAAE;AACX;AAEA,SAASJ,sBAAsBA,CAACJ,MAAsB;IACpD,MAAMG,sBAAsBH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAChDS,CAAAA,OAAQA,KAAK,IAAI,KAAK/B,cAAcA,GACnC;IAEH,OAAOyB;AACT;AAEA,eAAeI,qBAAqBA,CAClCnB,iBAA2C,EAC3CiB,2BAA0C;IAE1C,MAAMR,gBAAgB,MAAMT,kBAAkB,gBAAgB;IAC9D,MAAMsB,aAAa,IAAIC,IACrBN,4BAA4B,GAAG,CAACN,CAAAA,UAAWA,QAAQ,EAAE;IAEvD,MAAMO,qBAAqBT,cAAc,IAAI,CAACE,CAAAA,UAC5CW,WAAW,GAAG,CAACX,QAAQ,EAAE;IAG3B,OAAOO;AACT"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { INPUT } from "@botonic/core";
|
|
1
|
+
import { INPUT, WhatsappInputOrigin } from "@botonic/core";
|
|
2
2
|
import { EMPTY_PAYLOAD } from "../constants.js";
|
|
3
3
|
import { inputHasTextOrTranscript } from "../utils/input.js";
|
|
4
4
|
import { getContentsByAiAgentFromUserInput } from "./ai-agent-from-user-input.js";
|
|
@@ -42,7 +42,7 @@ async function getContents(botContext, contentID) {
|
|
|
42
42
|
}
|
|
43
43
|
return await getContentsByFallback(context);
|
|
44
44
|
}
|
|
45
|
-
if (inputHasTextOrTranscript(botContext.input)) {
|
|
45
|
+
if (inputHasTextOrTranscript(botContext.input) || isContactRequested(botContext.input)) {
|
|
46
46
|
const aiAgentContents = await getContentsByAiAgentFromUserInput(context);
|
|
47
47
|
if (aiAgentContents.length > 0) {
|
|
48
48
|
return aiAgentContents;
|
|
@@ -50,6 +50,9 @@ async function getContents(botContext, contentID) {
|
|
|
50
50
|
}
|
|
51
51
|
return await getContentsByFallback(context);
|
|
52
52
|
}
|
|
53
|
+
function isContactRequested(input) {
|
|
54
|
+
return input.type === INPUT.CONTACT && input.origin === WhatsappInputOrigin.ContactRequest;
|
|
55
|
+
}
|
|
53
56
|
|
|
54
57
|
export { getContents };
|
|
55
58
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action/get-contents.js","sources":["../../src/action/get-contents.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"action/get-contents.js","sources":["../../src/action/get-contents.ts"],"sourcesContent":["import {\n type BotContext,\n INPUT,\n type Input,\n WhatsappInputOrigin,\n} from '@botonic/core'\nimport { EMPTY_PAYLOAD } from '../constants'\nimport type { FlowContent } from '../content-fields'\nimport { inputHasTextOrTranscript } from '../utils/input'\nimport { getContentsByAiAgentFromUserInput } from './ai-agent-from-user-input'\nimport { getFlowBuilderActionContext } from './context'\nimport { getContentsByFallback } from './fallback'\nimport { getContentsByFirstInteraction } from './first-interaction'\nimport { getContentsByPayload } from './payload'\n\nexport async function getContents(\n botContext: BotContext,\n contentID?: string\n): Promise<FlowContent[]> {\n const context = getFlowBuilderActionContext(botContext, contentID)\n\n if (botContext.session.is_first_interaction) {\n return await getContentsByFirstInteraction(context)\n }\n // TODO: Add needed logic when we can define contents for multi locale queue position message\n if (botContext.input.type === INPUT.EVENT_QUEUE_POSITION_CHANGED) {\n return []\n }\n\n if (botContext.input.payload?.startsWith(EMPTY_PAYLOAD)) {\n botContext.input.payload = undefined\n }\n\n if (botContext.input.payload || contentID) {\n const contentsByPayload = await getContentsByPayload(context)\n if (contentsByPayload.length > 0) {\n return contentsByPayload\n }\n\n return await getContentsByFallback(context)\n }\n\n if (\n inputHasTextOrTranscript(botContext.input) ||\n isContactRequested(botContext.input)\n ) {\n const aiAgentContents = await getContentsByAiAgentFromUserInput(context)\n if (aiAgentContents.length > 0) {\n return aiAgentContents\n }\n }\n\n return await getContentsByFallback(context)\n}\n\nfunction isContactRequested(input: Input) {\n return (\n input.type === INPUT.CONTACT &&\n input.origin === WhatsappInputOrigin.ContactRequest\n )\n}\n"],"names":["INPUT","WhatsappInputOrigin","EMPTY_PAYLOAD","inputHasTextOrTranscript","getContentsByAiAgentFromUserInput","getFlowBuilderActionContext","getContentsByFallback","getContentsByFirstInteraction","getContentsByPayload","getContents","botContext","contentID","context","undefined","contentsByPayload","isContactRequested","aiAgentContents","input"],"mappings":";;;;;;;;;;;;;;;;;AAKsB;AACsB;AAEa;AACqB;AACvB;AACL;AACiB;AACnB;AAEzC,eAAeS,WAAWA,CAC/BC,UAAsB,EACtBC,SAAkB;IAElB,MAAMC,UAAUP,2BAA2BA,CAACK,YAAYC;IAExD,IAAID,WAAW,OAAO,CAAC,oBAAoB,EAAE;QAC3C,OAAO,MAAMH,6BAA6BA,CAACK;IAC7C;IACA,6FAA6F;IAC7F,IAAIF,WAAW,KAAK,CAAC,IAAI,KAAKV,kCAAkC,EAAE;QAChE,OAAO,EAAE;IACX;IAEA,IAAIU,WAAW,KAAK,CAAC,OAAO,EAAE,WAAWR,aAAaA,GAAG;QACvDQ,WAAW,KAAK,CAAC,OAAO,GAAGG;IAC7B;IAEA,IAAIH,WAAW,KAAK,CAAC,OAAO,IAAIC,WAAW;QACzC,MAAMG,oBAAoB,MAAMN,oBAAoBA,CAACI;QACrD,IAAIE,kBAAkB,MAAM,GAAG,GAAG;YAChC,OAAOA;QACT;QAEA,OAAO,MAAMR,qBAAqBA,CAACM;IACrC;IAEA,IACET,wBAAwBA,CAACO,WAAW,KAAK,KACzCK,kBAAkBA,CAACL,WAAW,KAAK,GACnC;QACA,MAAMM,kBAAkB,MAAMZ,iCAAiCA,CAACQ;QAChE,IAAII,gBAAgB,MAAM,GAAG,GAAG;YAC9B,OAAOA;QACT;IACF;IAEA,OAAO,MAAMV,qBAAqBA,CAACM;AACrC;AAEA,SAASG,kBAAkBA,CAACE,KAAY;IACtC,OACEA,MAAM,IAAI,KAAKjB,aAAa,IAC5BiB,MAAM,MAAM,KAAKhB,kCAAkC;AAEvD"}
|
package/lib/action/index.js
CHANGED
|
@@ -2,8 +2,9 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { isDev, isWebchat } from "@botonic/core";
|
|
3
3
|
import { Multichannel, RequestContext, WebchatSettings } from "@botonic/react";
|
|
4
4
|
import react from "react";
|
|
5
|
-
import { FlowAiAgent, FlowAiAgentRouter } from "../content-fields/index.js";
|
|
5
|
+
import { FlowAiAgent, FlowAiAgentRouter, FlowWhatsappRequestContactInfoNode } from "../content-fields/index.js";
|
|
6
6
|
import { splitAiAgentContents } from "../utils/ai-agent.js";
|
|
7
|
+
import { getFlowBuilderPlugin } from "../utils/get-flow-builder-plugin.js";
|
|
7
8
|
import { getFlowBuilderActionContext } from "./context.js";
|
|
8
9
|
import { getContentsByFirstInteraction } from "./first-interaction.js";
|
|
9
10
|
import { getContents } from "./get-contents.js";
|
|
@@ -25,6 +26,8 @@ import { getContents } from "./get-contents.js";
|
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
|
|
29
|
+
|
|
30
|
+
|
|
28
31
|
|
|
29
32
|
class FlowBuilderAction extends react.Component {
|
|
30
33
|
static async executeConversationStart(botContext) {
|
|
@@ -49,6 +52,10 @@ class FlowBuilderAction extends react.Component {
|
|
|
49
52
|
continue;
|
|
50
53
|
}
|
|
51
54
|
await content.processContent(botContext);
|
|
55
|
+
if (content instanceof FlowWhatsappRequestContactInfoNode) {
|
|
56
|
+
const flowBuilderPlugin = getFlowBuilderPlugin(botContext.plugins);
|
|
57
|
+
flowBuilderPlugin.cmsApi.setWhatsappRequestContactId(content.id);
|
|
58
|
+
}
|
|
52
59
|
}
|
|
53
60
|
return contents;
|
|
54
61
|
}
|
package/lib/action/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action/index.js","sources":["../../src/action/index.tsx"],"sourcesContent":["import { type BotContext, isDev, isWebchat } from '@botonic/core'\nimport {\n Multichannel,\n RequestContext,\n WebchatSettings,\n type WebchatSettingsProps,\n} from '@botonic/react'\nimport React from 'react'\n\nimport {\n FlowAiAgent,\n FlowAiAgentRouter,\n type FlowContent,\n} from '../content-fields'\nimport { splitAiAgentContents } from '../utils/ai-agent'\nimport { getFlowBuilderActionContext } from './context'\nimport { getContentsByFirstInteraction } from './first-interaction'\nimport { getContents } from './get-contents'\n\nexport type FlowBuilderActionProps = {\n contents: FlowContent[]\n webchatSettingsParams?: WebchatSettingsProps\n}\n\nexport class FlowBuilderAction extends React.Component<FlowBuilderActionProps> {\n static contextType = RequestContext\n declare context: React.ContextType<typeof RequestContext>\n\n static async executeConversationStart(\n botContext: BotContext\n ): Promise<FlowBuilderActionProps> {\n const context = getFlowBuilderActionContext(botContext)\n const contents = await getContentsByFirstInteraction(context)\n\n const filteredContents = await FlowBuilderAction.prepareContentsToRender(\n botContext,\n contents\n )\n\n return { contents: filteredContents }\n }\n\n static async botonicInit(\n botContext: BotContext,\n contentID?: string\n ): Promise<FlowBuilderActionProps> {\n const contents = await getContents(botContext, contentID)\n\n const contentsToRender = await FlowBuilderAction.prepareContentsToRender(\n botContext,\n contents\n )\n\n return { contents: contentsToRender }\n }\n\n static async prepareContentsToRender(\n botContext: BotContext,\n contents: FlowContent[]\n ) {\n for (const content of contents) {\n if (FlowBuilderAction.isAiAgentContent(content)) {\n await FlowBuilderAction.processAiAgentContent(botContext, contents)\n continue\n }\n\n await content.processContent(botContext)\n }\n\n return contents\n }\n\n private static isAiAgentContent(content: FlowContent): boolean {\n return (\n content instanceof FlowAiAgent || content instanceof FlowAiAgentRouter\n )\n }\n\n // TODO: Refactor this to be more generic and reusable\n private static async processAiAgentContent(\n botContext: BotContext,\n contents: FlowContent[]\n ) {\n const splitContents = splitAiAgentContents(contents)\n if (!splitContents) {\n return\n }\n\n if ('aiAgentRouterContent' in splitContents) {\n const { aiAgentRouterContent, contentsBeforeAiAgentRouter } =\n splitContents\n await aiAgentRouterContent.processContent(\n botContext,\n contentsBeforeAiAgentRouter\n )\n }\n\n if ('aiAgentWorkerContent' in splitContents) {\n const { aiAgentWorkerContent, contentsBeforeAiAgentWorker } =\n splitContents\n await aiAgentWorkerContent.processContent(\n botContext,\n contentsBeforeAiAgentWorker\n )\n }\n }\n\n protected getWebchatSettingsParams(botContext: BotContext): {\n shouldSendWebchatSettings: boolean\n webchatSettingsParams?: WebchatSettingsProps\n } {\n let { webchatSettingsParams } = this.props\n if (botContext.session.user.system_locale_updated) {\n webchatSettingsParams = {\n ...webchatSettingsParams,\n user: {\n ...webchatSettingsParams?.user,\n system_locale: botContext.session.user.system_locale,\n },\n }\n }\n const shouldSendWebchatSettings =\n (isWebchat(botContext.session) || isDev(botContext.session)) &&\n !!webchatSettingsParams\n\n return {\n shouldSendWebchatSettings,\n webchatSettingsParams,\n }\n }\n\n render(): JSX.Element | JSX.Element[] {\n const { contents } = this.props\n const botContext = this.context as BotContext\n const { shouldSendWebchatSettings, webchatSettingsParams } =\n this.getWebchatSettingsParams(botContext)\n\n return (\n <>\n {shouldSendWebchatSettings && (\n <WebchatSettings {...webchatSettingsParams} />\n )}\n {contents.map(content => content.toBotonic(botContext))}\n </>\n )\n }\n}\n\nexport class FlowBuilderMultichannelAction extends FlowBuilderAction {\n render(): JSX.Element | JSX.Element[] {\n const { contents } = this.props\n const botContext = this.context as BotContext\n const { shouldSendWebchatSettings, webchatSettingsParams } =\n this.getWebchatSettingsParams(botContext)\n\n return (\n <Multichannel text={{ buttonsAsText: false }}>\n {shouldSendWebchatSettings && (\n <WebchatSettings {...webchatSettingsParams} />\n )}\n {contents.map(content => content.toBotonic(botContext))}\n </Multichannel>\n )\n }\n}\n"],"names":["isDev","isWebchat","Multichannel","RequestContext","WebchatSettings","React","FlowAiAgent","FlowAiAgentRouter","splitAiAgentContents","getFlowBuilderActionContext","getContentsByFirstInteraction","getContents","FlowBuilderAction","botContext","context","contents","filteredContents","contentID","contentsToRender","content","splitContents","aiAgentRouterContent","contentsBeforeAiAgentRouter","aiAgentWorkerContent","contentsBeforeAiAgentWorker","webchatSettingsParams","shouldSendWebchatSettings","FlowBuilderMultichannelAction"],"mappings":"
|
|
1
|
+
{"version":3,"file":"action/index.js","sources":["../../src/action/index.tsx"],"sourcesContent":["import { type BotContext, isDev, isWebchat } from '@botonic/core'\nimport {\n Multichannel,\n RequestContext,\n WebchatSettings,\n type WebchatSettingsProps,\n} from '@botonic/react'\nimport React from 'react'\n\nimport {\n FlowAiAgent,\n FlowAiAgentRouter,\n type FlowContent,\n FlowWhatsappRequestContactInfoNode,\n} from '../content-fields'\nimport { splitAiAgentContents } from '../utils/ai-agent'\nimport { getFlowBuilderPlugin } from '../utils/get-flow-builder-plugin'\nimport { getFlowBuilderActionContext } from './context'\nimport { getContentsByFirstInteraction } from './first-interaction'\nimport { getContents } from './get-contents'\n\nexport type FlowBuilderActionProps = {\n contents: FlowContent[]\n webchatSettingsParams?: WebchatSettingsProps\n}\n\nexport class FlowBuilderAction extends React.Component<FlowBuilderActionProps> {\n static contextType = RequestContext\n declare context: React.ContextType<typeof RequestContext>\n\n static async executeConversationStart(\n botContext: BotContext\n ): Promise<FlowBuilderActionProps> {\n const context = getFlowBuilderActionContext(botContext)\n const contents = await getContentsByFirstInteraction(context)\n\n const filteredContents = await FlowBuilderAction.prepareContentsToRender(\n botContext,\n contents\n )\n\n return { contents: filteredContents }\n }\n\n static async botonicInit(\n botContext: BotContext,\n contentID?: string\n ): Promise<FlowBuilderActionProps> {\n const contents = await getContents(botContext, contentID)\n\n const contentsToRender = await FlowBuilderAction.prepareContentsToRender(\n botContext,\n contents\n )\n\n return { contents: contentsToRender }\n }\n\n static async prepareContentsToRender(\n botContext: BotContext,\n contents: FlowContent[]\n ) {\n for (const content of contents) {\n if (FlowBuilderAction.isAiAgentContent(content)) {\n await FlowBuilderAction.processAiAgentContent(botContext, contents)\n continue\n }\n\n await content.processContent(botContext)\n\n if (content instanceof FlowWhatsappRequestContactInfoNode) {\n const flowBuilderPlugin = getFlowBuilderPlugin(botContext.plugins)\n flowBuilderPlugin.cmsApi.setWhatsappRequestContactId(content.id)\n }\n }\n\n return contents\n }\n\n private static isAiAgentContent(content: FlowContent): boolean {\n return (\n content instanceof FlowAiAgent || content instanceof FlowAiAgentRouter\n )\n }\n\n // TODO: Refactor this to be more generic and reusable\n private static async processAiAgentContent(\n botContext: BotContext,\n contents: FlowContent[]\n ) {\n const splitContents = splitAiAgentContents(contents)\n if (!splitContents) {\n return\n }\n\n if ('aiAgentRouterContent' in splitContents) {\n const { aiAgentRouterContent, contentsBeforeAiAgentRouter } =\n splitContents\n await aiAgentRouterContent.processContent(\n botContext,\n contentsBeforeAiAgentRouter\n )\n }\n\n if ('aiAgentWorkerContent' in splitContents) {\n const { aiAgentWorkerContent, contentsBeforeAiAgentWorker } =\n splitContents\n await aiAgentWorkerContent.processContent(\n botContext,\n contentsBeforeAiAgentWorker\n )\n }\n }\n\n protected getWebchatSettingsParams(botContext: BotContext): {\n shouldSendWebchatSettings: boolean\n webchatSettingsParams?: WebchatSettingsProps\n } {\n let { webchatSettingsParams } = this.props\n if (botContext.session.user.system_locale_updated) {\n webchatSettingsParams = {\n ...webchatSettingsParams,\n user: {\n ...webchatSettingsParams?.user,\n system_locale: botContext.session.user.system_locale,\n },\n }\n }\n const shouldSendWebchatSettings =\n (isWebchat(botContext.session) || isDev(botContext.session)) &&\n !!webchatSettingsParams\n\n return {\n shouldSendWebchatSettings,\n webchatSettingsParams,\n }\n }\n\n render(): JSX.Element | JSX.Element[] {\n const { contents } = this.props\n const botContext = this.context as BotContext\n const { shouldSendWebchatSettings, webchatSettingsParams } =\n this.getWebchatSettingsParams(botContext)\n\n return (\n <>\n {shouldSendWebchatSettings && (\n <WebchatSettings {...webchatSettingsParams} />\n )}\n {contents.map(content => content.toBotonic(botContext))}\n </>\n )\n }\n}\n\nexport class FlowBuilderMultichannelAction extends FlowBuilderAction {\n render(): JSX.Element | JSX.Element[] {\n const { contents } = this.props\n const botContext = this.context as BotContext\n const { shouldSendWebchatSettings, webchatSettingsParams } =\n this.getWebchatSettingsParams(botContext)\n\n return (\n <Multichannel text={{ buttonsAsText: false }}>\n {shouldSendWebchatSettings && (\n <WebchatSettings {...webchatSettingsParams} />\n )}\n {contents.map(content => content.toBotonic(botContext))}\n </Multichannel>\n )\n }\n}\n"],"names":["isDev","isWebchat","Multichannel","RequestContext","WebchatSettings","React","FlowAiAgent","FlowAiAgentRouter","FlowWhatsappRequestContactInfoNode","splitAiAgentContents","getFlowBuilderPlugin","getFlowBuilderActionContext","getContentsByFirstInteraction","getContents","FlowBuilderAction","botContext","context","contents","filteredContents","contentID","contentsToRender","content","flowBuilderPlugin","splitContents","aiAgentRouterContent","contentsBeforeAiAgentRouter","aiAgentWorkerContent","contentsBeforeAiAgentWorker","webchatSettingsParams","shouldSendWebchatSettings","FlowBuilderMultichannelAction"],"mappings":"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"}
|
package/lib/api.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { type HtBotActionNode, type HtCaptureUserInputNode, type HtFlowBuilderData, type HtFlowWebview, type HtKeywordNode, type HtNodeComponent, type HtNodeLink, type HtNodeWithContent, type HtRatingButton, type HtRatingNode, type HtSmartIntentNode } from './content-fields/hubtype-fields/index.js';
|
|
1
|
+
import type { BotContext } from '@botonic/core';
|
|
2
|
+
import { type HtBotActionNode, type HtCaptureUserInputNode, type HtFlowBuilderData, type HtFlowWebview, type HtKeywordNode, type HtNodeComponent, type HtNodeLink, type HtNodeWithContent, type HtRatingButton, type HtRatingNode, type HtSmartIntentNode, type HtWhatsappRequestContactInfoNode } from './content-fields/hubtype-fields/index.js';
|
|
3
3
|
import { type FlowBuilderApiOptions } from './types.js';
|
|
4
4
|
export declare class FlowBuilderApi {
|
|
5
5
|
url: string;
|
|
6
6
|
flowUrl: string;
|
|
7
7
|
flow: HtFlowBuilderData;
|
|
8
|
-
|
|
8
|
+
botContext: BotContext;
|
|
9
9
|
private constructor();
|
|
10
10
|
static create(options: FlowBuilderApiOptions): Promise<FlowBuilderApi>;
|
|
11
11
|
private getFlow;
|
|
@@ -36,5 +36,10 @@ export declare class FlowBuilderApi {
|
|
|
36
36
|
removeCaptureUserInputId(): void;
|
|
37
37
|
setUserExtraDataVariable(key: string, value: string): void;
|
|
38
38
|
getCaptureUserInputNode(): HtCaptureUserInputNode | undefined;
|
|
39
|
+
getSessionWhatsappRequestContactId(): string | undefined;
|
|
40
|
+
setWhatsappRequestContactId(id: string): void;
|
|
41
|
+
removeWhatsappRequestContactId(): void;
|
|
42
|
+
getWhatsappRequestContactInfoNode(): HtWhatsappRequestContactInfoNode | undefined;
|
|
39
43
|
getResolvedLocale(): string;
|
|
44
|
+
isPushFlowPayload(payload?: string): boolean;
|
|
40
45
|
}
|
package/lib/api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
|
-
import { AI_AGENTS_FLOW_NAME, SEPARATOR, UUID_REGEXP } from "./constants.js";
|
|
2
|
+
import { AI_AGENTS_FLOW_NAME, PUSH_FLOW_PAYLOAD, SEPARATOR, UUID_REGEXP } from "./constants.js";
|
|
3
3
|
import { HtNodeWithContentType } from "./content-fields/hubtype-fields/index.js";
|
|
4
4
|
import { ProcessEnvNodeEnvs } from "./types.js";
|
|
5
5
|
import { FlowLocale } from "./utils/flow-locale.js";
|
|
@@ -18,12 +18,12 @@ class FlowBuilderApi {
|
|
|
18
18
|
static async create(options) {
|
|
19
19
|
const newApi = new FlowBuilderApi();
|
|
20
20
|
newApi.url = options.url;
|
|
21
|
-
newApi.
|
|
21
|
+
newApi.botContext = options.botContext;
|
|
22
22
|
// TODO: Refactor later to combine logic from `FlowBuilderApi.create`, `resolveFlowUrl` and `getAccessToken` to be in one place
|
|
23
23
|
if (process.env.NODE_ENV === ProcessEnvNodeEnvs.DEVELOPMENT) {
|
|
24
24
|
await newApi.updateSessionWithUserInfo(options.accessToken);
|
|
25
25
|
}
|
|
26
|
-
const updatedRequest = newApi.
|
|
26
|
+
const updatedRequest = newApi.botContext;
|
|
27
27
|
newApi.flowUrl = options.flowUrl.replace('{bot_id}', updatedRequest.session.bot.id);
|
|
28
28
|
newApi.flow = options.flow ?? await newApi.getFlow(options.accessToken);
|
|
29
29
|
return newApi;
|
|
@@ -43,8 +43,8 @@ class FlowBuilderApi {
|
|
|
43
43
|
Authorization: `Bearer ${token}`
|
|
44
44
|
}
|
|
45
45
|
});
|
|
46
|
-
this.
|
|
47
|
-
this.
|
|
46
|
+
this.botContext.session.organization_id = response.data.organization_id;
|
|
47
|
+
this.botContext.session.bot.id = response.data.bot_id;
|
|
48
48
|
}
|
|
49
49
|
getNodeByFlowId(id) {
|
|
50
50
|
const subFlow = this.flow.flows.find((subFlow)=>subFlow.id === id);
|
|
@@ -178,22 +178,22 @@ class FlowBuilderApi {
|
|
|
178
178
|
return !!this.getCaptureUserInputId();
|
|
179
179
|
}
|
|
180
180
|
getCaptureUserInputId() {
|
|
181
|
-
return this.
|
|
181
|
+
return this.botContext.session.capture_user_input?.node_id;
|
|
182
182
|
}
|
|
183
183
|
setCaptureUserInputId(id) {
|
|
184
|
-
if (this.
|
|
185
|
-
this.
|
|
184
|
+
if (this.botContext.session.capture_user_input) {
|
|
185
|
+
this.botContext.session.capture_user_input.node_id = id;
|
|
186
186
|
}
|
|
187
|
-
this.
|
|
187
|
+
this.botContext.session.capture_user_input = {
|
|
188
188
|
node_id: id
|
|
189
189
|
};
|
|
190
190
|
}
|
|
191
191
|
removeCaptureUserInputId() {
|
|
192
|
-
this.
|
|
192
|
+
this.botContext.session.capture_user_input = undefined;
|
|
193
193
|
}
|
|
194
194
|
setUserExtraDataVariable(key, value) {
|
|
195
|
-
if (this.
|
|
196
|
-
this.
|
|
195
|
+
if (this.botContext.session.user.extra_data) {
|
|
196
|
+
this.botContext.session.user.extra_data[key] = value;
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
199
|
getCaptureUserInputNode() {
|
|
@@ -203,10 +203,34 @@ class FlowBuilderApi {
|
|
|
203
203
|
}
|
|
204
204
|
return this.getNodeById(captureUserInputId);
|
|
205
205
|
}
|
|
206
|
+
getSessionWhatsappRequestContactId() {
|
|
207
|
+
return this.botContext.session.whatsapp_request_contact?.id;
|
|
208
|
+
}
|
|
209
|
+
setWhatsappRequestContactId(id) {
|
|
210
|
+
if (this.botContext.session.whatsapp_request_contact) {
|
|
211
|
+
this.botContext.session.whatsapp_request_contact.id = id;
|
|
212
|
+
}
|
|
213
|
+
this.botContext.session.whatsapp_request_contact = {
|
|
214
|
+
id
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
removeWhatsappRequestContactId() {
|
|
218
|
+
this.botContext.session.whatsapp_request_contact = undefined;
|
|
219
|
+
}
|
|
220
|
+
getWhatsappRequestContactInfoNode() {
|
|
221
|
+
const whatsappRequestContactId = this.getSessionWhatsappRequestContactId();
|
|
222
|
+
if (!whatsappRequestContactId) {
|
|
223
|
+
return undefined;
|
|
224
|
+
}
|
|
225
|
+
return this.getNodeById(whatsappRequestContactId);
|
|
226
|
+
}
|
|
206
227
|
getResolvedLocale() {
|
|
207
228
|
const flowLocales = this.flow.locales;
|
|
208
229
|
const defaultLocaleCode = this.flow.default_locale_code;
|
|
209
|
-
return new FlowLocale(this.
|
|
230
|
+
return new FlowLocale(this.botContext, flowLocales, defaultLocaleCode).resolve();
|
|
231
|
+
}
|
|
232
|
+
isPushFlowPayload(payload) {
|
|
233
|
+
return payload?.startsWith(PUSH_FLOW_PAYLOAD) ?? false;
|
|
210
234
|
}
|
|
211
235
|
constructor(){}
|
|
212
236
|
}
|
package/lib/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sources":["../src/api.ts"],"sourcesContent":["import type { PluginPreRequest } from '@botonic/core'\nimport axios from 'axios'\n\nimport { AI_AGENTS_FLOW_NAME, SEPARATOR, UUID_REGEXP } from './constants'\nimport {\n type HtBotActionNode,\n type HtCaptureUserInputNode,\n type HtFallbackNode,\n type HtFlowBuilderData,\n type HtFlowWebview,\n type HtGoToFlow,\n type HtKeywordNode,\n type HtNodeComponent,\n type HtNodeLink,\n type HtNodeWithContent,\n HtNodeWithContentType,\n type HtPayloadNode,\n type HtRatingButton,\n type HtRatingNode,\n type HtSmartIntentNode,\n} from './content-fields/hubtype-fields'\nimport {\n type FlowBuilderApiOptions,\n type PayloadParamsBase,\n ProcessEnvNodeEnvs,\n} from './types'\nimport { FlowLocale } from './utils/flow-locale'\n\nexport class FlowBuilderApi {\n url: string\n flowUrl: string\n flow: HtFlowBuilderData\n request: PluginPreRequest\n\n private constructor() {}\n\n static async create(options: FlowBuilderApiOptions): Promise<FlowBuilderApi> {\n const newApi = new FlowBuilderApi()\n\n newApi.url = options.url\n newApi.request = options.request\n // TODO: Refactor later to combine logic from `FlowBuilderApi.create`, `resolveFlowUrl` and `getAccessToken` to be in one place\n if (process.env.NODE_ENV === ProcessEnvNodeEnvs.DEVELOPMENT) {\n await newApi.updateSessionWithUserInfo(options.accessToken)\n }\n const updatedRequest = newApi.request\n newApi.flowUrl = options.flowUrl.replace(\n '{bot_id}',\n updatedRequest.session.bot.id\n )\n newApi.flow = options.flow ?? (await newApi.getFlow(options.accessToken))\n return newApi\n }\n\n private async getFlow(token: string): Promise<HtFlowBuilderData> {\n const { data } = await axios.get(this.flowUrl, {\n headers: { Authorization: `Bearer ${token}` },\n })\n return data as HtFlowBuilderData\n }\n\n private async updateSessionWithUserInfo(token: string) {\n const url = `${this.url}/v1/flow_builder/user_info/`\n const response = await axios.get(url, {\n headers: { Authorization: `Bearer ${token}` },\n })\n this.request.session.organization_id = response.data.organization_id\n this.request.session.bot.id = response.data.bot_id\n }\n\n getNodeByFlowId(id: string): HtNodeWithContent {\n const subFlow = this.flow.flows.find(subFlow => subFlow.id === id)\n if (!subFlow) {\n throw Error(`SubFlow with id: '${id}' not found`)\n }\n return this.getNodeById<HtNodeWithContent>(subFlow.start_node_id)\n }\n\n getNodeByCampaignId<T extends HtNodeComponent>(id: string): T {\n const campaign = this.flow.campaigns.find(campaign => campaign.id === id)\n if (!campaign) {\n throw Error(`Campaign with id: '${id}' not found`)\n }\n return this.getNodeById<T>(campaign.start_node_id)\n }\n\n getNodeById<T extends HtNodeComponent>(id: string): T {\n const node = this.flow.nodes.find(node => node.id === id)\n if (!node) {\n console.error(`Node with id: '${id}' not found`)\n }\n\n return node as T\n }\n\n getRatingNodeByButtonId(id: string): HtRatingNode {\n const ratingNodes = this.flow.nodes.filter(\n node => node.type === HtNodeWithContentType.RATING\n ) as HtRatingNode[]\n const ratingNode = ratingNodes.find(node =>\n node.content.buttons.some(button => button.id === id)\n ) as HtRatingNode | undefined\n\n if (!ratingNode) {\n throw Error(`Rating node with button id: '${id}' not found`)\n }\n\n return ratingNode\n }\n\n getRatingButtonById(ratingNode: HtRatingNode, id: string): HtRatingButton {\n const ratingButton = ratingNode.content.buttons.find(\n button => button.id === id\n ) as HtRatingButton | undefined\n if (!ratingButton) {\n throw Error(`Rating button with id: '${id}' not found`)\n }\n\n return ratingButton\n }\n\n getNodeByContentID(contentID: string): HtNodeComponent {\n const content = this.flow.nodes.find(node =>\n 'code' in node ? node.code === contentID : false\n )\n if (!content) {\n throw Error(`Node with contentID: '${contentID}' not found`)\n }\n return content\n }\n\n getStartNode(): HtNodeWithContent {\n const startNodeId = this.flow.start_node_id\n if (!startNodeId) {\n throw new Error('Start node id must be defined')\n }\n return this.getNodeById(startNodeId)\n }\n\n getFallbackNode(alternate: boolean): HtNodeWithContent {\n const fallbackNode = this.flow.nodes.find(\n node => node.type === HtNodeWithContentType.FALLBACK\n ) as HtFallbackNode | undefined\n if (!fallbackNode) {\n throw new Error('Fallback node must be defined')\n }\n const fallbackFirstMessage = fallbackNode.content.first_message\n if (!fallbackFirstMessage) {\n throw new Error('Fallback 1st message must be defined')\n }\n const fallbackSecondMessage = fallbackNode.content.second_message\n if (!fallbackSecondMessage) {\n return this.getNodeById(fallbackFirstMessage.id)\n }\n return alternate\n ? this.getNodeById(fallbackFirstMessage.id)\n : this.getNodeById(fallbackSecondMessage.id)\n }\n\n getSmartIntentNodes(): HtSmartIntentNode[] {\n return this.flow.nodes.filter(\n node => node.type === HtNodeWithContentType.SMART_INTENT\n ) as HtSmartIntentNode[]\n }\n\n getKeywordNodes(): HtKeywordNode[] {\n return this.flow.nodes.filter(\n node => node.type === HtNodeWithContentType.KEYWORD\n ) as HtKeywordNode[]\n }\n\n getPayload(target?: HtNodeLink): string | undefined {\n if (!target) {\n return undefined\n }\n\n return target.id\n }\n\n isBotAction(id: string): boolean {\n if (!this.isUUID(id)) {\n return false\n }\n const node = this.getNodeById(id)\n return node?.type === HtNodeWithContentType.BOT_ACTION\n }\n\n private isUUID(str: string): boolean {\n return UUID_REGEXP.test(str)\n }\n\n createPayloadWithParams(botActionNode: HtBotActionNode): string {\n const payloadId = botActionNode.content.payload_id\n const payloadNode = this.getNodeById<HtPayloadNode>(payloadId)\n const customParams = JSON.parse(\n botActionNode.content.payload_params || '{}'\n )\n\n const contentID = botActionNode.code\n\n const followUpContentID = this.getFollowUpContentID(\n botActionNode.follow_up?.id\n )\n\n const payloadParams: PayloadParamsBase = {\n contentID,\n followUpContentID,\n }\n\n const payloadJson = JSON.stringify({\n ...customParams,\n ...payloadParams,\n })\n return `${payloadNode.content.payload}${SEPARATOR}${payloadJson}`\n }\n\n private getFollowUpContentID(id?: string): string | undefined {\n const followUpNode = id\n ? this.getNodeById<HtNodeWithContent | HtGoToFlow>(id)\n : undefined\n\n return followUpNode?.code\n }\n\n getFlowName(flowId: string): string {\n const flow = this.flow.flows.find(flow => flow.id === flowId)\n return flow ? flow.name : this.getCampaignFlowName(flowId)\n }\n\n getCampaignFlowName(campaignId: string): string {\n const campaign = this.flow.campaigns.find(\n campaign => campaign.id === campaignId\n )\n return campaign ? campaign.name : ''\n }\n\n getStartNodeAiAgentFlow(): HtNodeWithContent | undefined {\n const aiAgentFlow = this.flow.flows.find(\n flow => flow.name === AI_AGENTS_FLOW_NAME\n )\n\n if (!aiAgentFlow) {\n return undefined\n }\n\n return this.getNodeById<HtNodeWithContent>(aiAgentFlow.start_node_id)\n }\n\n isAiAgentEnabled(): boolean {\n return this.flow.is_ai_agent_active || false\n }\n\n getWebviewById(id: string): HtFlowWebview | undefined {\n return this.flow.webviews.find(webview => webview.id === id)\n }\n\n shouldCaptureUserInput(): boolean {\n return !!this.getCaptureUserInputId()\n }\n\n getCaptureUserInputId(): string | undefined {\n return this.request.session.capture_user_input?.node_id\n }\n\n setCaptureUserInputId(id: string): void {\n if (this.request.session.capture_user_input) {\n this.request.session.capture_user_input.node_id = id\n }\n this.request.session.capture_user_input = { node_id: id }\n }\n\n removeCaptureUserInputId(): void {\n this.request.session.capture_user_input = undefined\n }\n\n setUserExtraDataVariable(key: string, value: string): void {\n if (this.request.session.user.extra_data) {\n this.request.session.user.extra_data[key] = value\n }\n }\n\n getCaptureUserInputNode(): HtCaptureUserInputNode | undefined {\n const captureUserInputId = this.getCaptureUserInputId()\n if (!captureUserInputId) {\n return undefined\n }\n return this.getNodeById<HtCaptureUserInputNode>(captureUserInputId)\n }\n\n getResolvedLocale(): string {\n const flowLocales = this.flow.locales\n const defaultLocaleCode = this.flow.default_locale_code\n\n return new FlowLocale(\n this.request,\n flowLocales,\n defaultLocaleCode\n ).resolve()\n }\n}\n"],"names":["axios","AI_AGENTS_FLOW_NAME","SEPARATOR","UUID_REGEXP","HtNodeWithContentType","ProcessEnvNodeEnvs","FlowLocale","FlowBuilderApi","options","newApi","process","updatedRequest","token","data","url","response","id","subFlow","Error","campaign","node","console","ratingNodes","ratingNode","button","ratingButton","contentID","content","startNodeId","alternate","fallbackNode","fallbackFirstMessage","fallbackSecondMessage","target","undefined","str","botActionNode","payloadId","payloadNode","customParams","JSON","followUpContentID","payloadParams","payloadJson","followUpNode","flowId","flow","campaignId","aiAgentFlow","webview","key","value","captureUserInputId","flowLocales","defaultLocaleCode"],"mappings":";;;;;;;;;;;AACyB;AAEgD;AAiBjC;AAKxB;AACgC;AAEzC,MAAMO,cAAcA;IAQzB,aAAa,OAAOC,OAA8B,EAA2B;QAC3E,MAAMC,SAAS,IAAIF,cAAcA;QAEjCE,OAAO,GAAG,GAAGD,QAAQ,GAAG;QACxBC,OAAO,OAAO,GAAGD,QAAQ,OAAO;QAChC,+HAA+H;QAC/H,IAAIE,oBAAoB,KAAKL,8BAA8B,EAAE;YAC3D,MAAMI,OAAO,yBAAyB,CAACD,QAAQ,WAAW;QAC5D;QACA,MAAMG,iBAAiBF,OAAO,OAAO;QACrCA,OAAO,OAAO,GAAGD,QAAQ,OAAO,CAAC,OAAO,CACtC,YACAG,eAAe,OAAO,CAAC,GAAG,CAAC,EAAE;QAE/BF,OAAO,IAAI,GAAGD,QAAQ,IAAI,IAAK,MAAMC,OAAO,OAAO,CAACD,QAAQ,WAAW;QACvE,OAAOC;IACT;IAEA,MAAc,QAAQG,KAAa,EAA8B;QAC/D,MAAM,EAAEC,IAAI,EAAE,GAAG,MAAMb,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE;YAC7C,SAAS;gBAAE,eAAe,CAAC,OAAO,EAAEY,OAAO;YAAC;QAC9C;QACA,OAAOC;IACT;IAEA,MAAc,0BAA0BD,KAAa,EAAE;QACrD,MAAME,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,2BAA2B,CAAC;QACpD,MAAMC,WAAW,MAAMf,SAAS,CAACc,KAAK;YACpC,SAAS;gBAAE,eAAe,CAAC,OAAO,EAAEF,OAAO;YAAC;QAC9C;QACA,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,GAAGG,SAAS,IAAI,CAAC,eAAe;QACpE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,GAAGA,SAAS,IAAI,CAAC,MAAM;IACpD;IAEA,gBAAgBC,EAAU,EAAqB;QAC7C,MAAMC,UAAU,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAACA,CAAAA,UAAWA,QAAQ,EAAE,KAAKD;QAC/D,IAAI,CAACC,SAAS;YACZ,MAAMC,MAAM,CAAC,kBAAkB,EAAEF,GAAG,WAAW,CAAC;QAClD;QACA,OAAO,IAAI,CAAC,WAAW,CAAoBC,QAAQ,aAAa;IAClE;IAEA,oBAA+CD,EAAU,EAAK;QAC5D,MAAMG,WAAW,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAACA,CAAAA,WAAYA,SAAS,EAAE,KAAKH;QACtE,IAAI,CAACG,UAAU;YACb,MAAMD,MAAM,CAAC,mBAAmB,EAAEF,GAAG,WAAW,CAAC;QACnD;QACA,OAAO,IAAI,CAAC,WAAW,CAAIG,SAAS,aAAa;IACnD;IAEA,YAAuCH,EAAU,EAAK;QACpD,MAAMI,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAACA,CAAAA,OAAQA,KAAK,EAAE,KAAKJ;QACtD,IAAI,CAACI,MAAM;YACTC,QAAQ,KAAK,CAAC,CAAC,eAAe,EAAEL,GAAG,WAAW,CAAC;QACjD;QAEA,OAAOI;IACT;IAEA,wBAAwBJ,EAAU,EAAgB;QAChD,MAAMM,cAAc,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CACxCF,CAAAA,OAAQA,KAAK,IAAI,KAAKhB,4BAA4B;QAEpD,MAAMmB,aAAaD,YAAY,IAAI,CAACF,CAAAA,OAClCA,KAAK,OAAO,CAAC,OAAO,CAAC,IAAI,CAACI,CAAAA,SAAUA,OAAO,EAAE,KAAKR;QAGpD,IAAI,CAACO,YAAY;YACf,MAAML,MAAM,CAAC,6BAA6B,EAAEF,GAAG,WAAW,CAAC;QAC7D;QAEA,OAAOO;IACT;IAEA,oBAAoBA,UAAwB,EAAEP,EAAU,EAAkB;QACxE,MAAMS,eAAeF,WAAW,OAAO,CAAC,OAAO,CAAC,IAAI,CAClDC,CAAAA,SAAUA,OAAO,EAAE,KAAKR;QAE1B,IAAI,CAACS,cAAc;YACjB,MAAMP,MAAM,CAAC,wBAAwB,EAAEF,GAAG,WAAW,CAAC;QACxD;QAEA,OAAOS;IACT;IAEA,mBAAmBC,SAAiB,EAAmB;QACrD,MAAMC,UAAU,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAACP,CAAAA,OACnC,UAAUA,OAAOA,KAAK,IAAI,KAAKM,YAAY;QAE7C,IAAI,CAACC,SAAS;YACZ,MAAMT,MAAM,CAAC,sBAAsB,EAAEQ,UAAU,WAAW,CAAC;QAC7D;QACA,OAAOC;IACT;IAEA,eAAkC;QAChC,MAAMC,cAAc,IAAI,CAAC,IAAI,CAAC,aAAa;QAC3C,IAAI,CAACA,aAAa;YAChB,MAAM,IAAIV,MAAM;QAClB;QACA,OAAO,IAAI,CAAC,WAAW,CAACU;IAC1B;IAEA,gBAAgBC,SAAkB,EAAqB;QACrD,MAAMC,eAAe,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CACvCV,CAAAA,OAAQA,KAAK,IAAI,KAAKhB,8BAA8B;QAEtD,IAAI,CAAC0B,cAAc;YACjB,MAAM,IAAIZ,MAAM;QAClB;QACA,MAAMa,uBAAuBD,aAAa,OAAO,CAAC,aAAa;QAC/D,IAAI,CAACC,sBAAsB;YACzB,MAAM,IAAIb,MAAM;QAClB;QACA,MAAMc,wBAAwBF,aAAa,OAAO,CAAC,cAAc;QACjE,IAAI,CAACE,uBAAuB;YAC1B,OAAO,IAAI,CAAC,WAAW,CAACD,qBAAqB,EAAE;QACjD;QACA,OAAOF,YACH,IAAI,CAAC,WAAW,CAACE,qBAAqB,EAAE,IACxC,IAAI,CAAC,WAAW,CAACC,sBAAsB,EAAE;IAC/C;IAEA,sBAA2C;QACzC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAC3BZ,CAAAA,OAAQA,KAAK,IAAI,KAAKhB,kCAAkC;IAE5D;IAEA,kBAAmC;QACjC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAC3BgB,CAAAA,OAAQA,KAAK,IAAI,KAAKhB,6BAA6B;IAEvD;IAEA,WAAW6B,MAAmB,EAAsB;QAClD,IAAI,CAACA,QAAQ;YACX,OAAOC;QACT;QAEA,OAAOD,OAAO,EAAE;IAClB;IAEA,YAAYjB,EAAU,EAAW;QAC/B,IAAI,CAAC,IAAI,CAAC,MAAM,CAACA,KAAK;YACpB,OAAO;QACT;QACA,MAAMI,OAAO,IAAI,CAAC,WAAW,CAACJ;QAC9B,OAAOI,MAAM,SAAShB,gCAAgC;IACxD;IAEQ,OAAO+B,GAAW,EAAW;QACnC,OAAOhC,gBAAgB,CAACgC;IAC1B;IAEA,wBAAwBC,aAA8B,EAAU;QAC9D,MAAMC,YAAYD,cAAc,OAAO,CAAC,UAAU;QAClD,MAAME,cAAc,IAAI,CAAC,WAAW,CAAgBD;QACpD,MAAME,eAAeC,KAAK,KAAK,CAC7BJ,cAAc,OAAO,CAAC,cAAc,IAAI;QAG1C,MAAMV,YAAYU,cAAc,IAAI;QAEpC,MAAMK,oBAAoB,IAAI,CAAC,oBAAoB,CACjDL,cAAc,SAAS,EAAE;QAG3B,MAAMM,gBAAmC;YACvChB;YACAe;QACF;QAEA,MAAME,cAAcH,KAAK,SAAS,CAAC;YACjC,GAAGD,YAAY;YACf,GAAGG,aAAa;QAClB;QACA,OAAO,GAAGJ,YAAY,OAAO,CAAC,OAAO,GAAGpC,SAASA,GAAGyC,aAAa;IACnE;IAEQ,qBAAqB3B,EAAW,EAAsB;QAC5D,MAAM4B,eAAe5B,KACjB,IAAI,CAAC,WAAW,CAAiCA,MACjDkB;QAEJ,OAAOU,cAAc;IACvB;IAEA,YAAYC,MAAc,EAAU;QAClC,MAAMC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAACA,CAAAA,OAAQA,KAAK,EAAE,KAAKD;QACtD,OAAOC,OAAOA,KAAK,IAAI,GAAG,IAAI,CAAC,mBAAmB,CAACD;IACrD;IAEA,oBAAoBE,UAAkB,EAAU;QAC9C,MAAM5B,WAAW,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CACvCA,CAAAA,WAAYA,SAAS,EAAE,KAAK4B;QAE9B,OAAO5B,WAAWA,SAAS,IAAI,GAAG;IACpC;IAEA,0BAAyD;QACvD,MAAM6B,cAAc,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CACtCF,CAAAA,OAAQA,KAAK,IAAI,KAAK7C,mBAAmBA;QAG3C,IAAI,CAAC+C,aAAa;YAChB,OAAOd;QACT;QAEA,OAAO,IAAI,CAAC,WAAW,CAAoBc,YAAY,aAAa;IACtE;IAEA,mBAA4B;QAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,kBAAkB,IAAI;IACzC;IAEA,eAAehC,EAAU,EAA6B;QACpD,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAACiC,CAAAA,UAAWA,QAAQ,EAAE,KAAKjC;IAC3D;IAEA,yBAAkC;QAChC,OAAO,CAAC,CAAC,IAAI,CAAC,qBAAqB;IACrC;IAEA,wBAA4C;QAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAkB,EAAE;IAClD;IAEA,sBAAsBA,EAAU,EAAQ;QACtC,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAkB,EAAE;YAC3C,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,OAAO,GAAGA;QACpD;QACA,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAkB,GAAG;YAAE,SAASA;QAAG;IAC1D;IAEA,2BAAiC;QAC/B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAkB,GAAGkB;IAC5C;IAEA,yBAAyBgB,GAAW,EAAEC,KAAa,EAAQ;QACzD,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE;YACxC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAACD,IAAI,GAAGC;QAC9C;IACF;IAEA,0BAA8D;QAC5D,MAAMC,qBAAqB,IAAI,CAAC,qBAAqB;QACrD,IAAI,CAACA,oBAAoB;YACvB,OAAOlB;QACT;QACA,OAAO,IAAI,CAAC,WAAW,CAAyBkB;IAClD;IAEA,oBAA4B;QAC1B,MAAMC,cAAc,IAAI,CAAC,IAAI,CAAC,OAAO;QACrC,MAAMC,oBAAoB,IAAI,CAAC,IAAI,CAAC,mBAAmB;QAEvD,OAAO,IAAIhD,UAAUA,CACnB,IAAI,CAAC,OAAO,EACZ+C,aACAC,mBACA,OAAO;IACX;IAxQA,aAAsB,CAAC;AAyQzB"}
|
|
1
|
+
{"version":3,"file":"api.js","sources":["../src/api.ts"],"sourcesContent":["import type { BotContext } from '@botonic/core'\nimport axios from 'axios'\n\nimport {\n AI_AGENTS_FLOW_NAME,\n PUSH_FLOW_PAYLOAD,\n SEPARATOR,\n UUID_REGEXP,\n} from './constants'\nimport {\n type HtBotActionNode,\n type HtCaptureUserInputNode,\n type HtFallbackNode,\n type HtFlowBuilderData,\n type HtFlowWebview,\n type HtGoToFlow,\n type HtKeywordNode,\n type HtNodeComponent,\n type HtNodeLink,\n type HtNodeWithContent,\n HtNodeWithContentType,\n type HtPayloadNode,\n type HtRatingButton,\n type HtRatingNode,\n type HtSmartIntentNode,\n type HtWhatsappRequestContactInfoNode,\n} from './content-fields/hubtype-fields'\nimport {\n type FlowBuilderApiOptions,\n type PayloadParamsBase,\n ProcessEnvNodeEnvs,\n} from './types'\nimport { FlowLocale } from './utils/flow-locale'\n\nexport class FlowBuilderApi {\n url: string\n flowUrl: string\n flow: HtFlowBuilderData\n botContext: BotContext\n\n private constructor() {}\n\n static async create(options: FlowBuilderApiOptions): Promise<FlowBuilderApi> {\n const newApi = new FlowBuilderApi()\n\n newApi.url = options.url\n newApi.botContext = options.botContext\n // TODO: Refactor later to combine logic from `FlowBuilderApi.create`, `resolveFlowUrl` and `getAccessToken` to be in one place\n if (process.env.NODE_ENV === ProcessEnvNodeEnvs.DEVELOPMENT) {\n await newApi.updateSessionWithUserInfo(options.accessToken)\n }\n const updatedRequest = newApi.botContext\n newApi.flowUrl = options.flowUrl.replace(\n '{bot_id}',\n updatedRequest.session.bot.id\n )\n newApi.flow = options.flow ?? (await newApi.getFlow(options.accessToken))\n return newApi\n }\n\n private async getFlow(token: string): Promise<HtFlowBuilderData> {\n const { data } = await axios.get(this.flowUrl, {\n headers: { Authorization: `Bearer ${token}` },\n })\n return data as HtFlowBuilderData\n }\n\n private async updateSessionWithUserInfo(token: string) {\n const url = `${this.url}/v1/flow_builder/user_info/`\n const response = await axios.get(url, {\n headers: { Authorization: `Bearer ${token}` },\n })\n this.botContext.session.organization_id = response.data.organization_id\n this.botContext.session.bot.id = response.data.bot_id\n }\n\n getNodeByFlowId(id: string): HtNodeWithContent {\n const subFlow = this.flow.flows.find(subFlow => subFlow.id === id)\n if (!subFlow) {\n throw Error(`SubFlow with id: '${id}' not found`)\n }\n return this.getNodeById<HtNodeWithContent>(subFlow.start_node_id)\n }\n\n getNodeByCampaignId<T extends HtNodeComponent>(id: string): T {\n const campaign = this.flow.campaigns.find(campaign => campaign.id === id)\n if (!campaign) {\n throw Error(`Campaign with id: '${id}' not found`)\n }\n return this.getNodeById<T>(campaign.start_node_id)\n }\n\n getNodeById<T extends HtNodeComponent>(id: string): T {\n const node = this.flow.nodes.find(node => node.id === id)\n if (!node) {\n console.error(`Node with id: '${id}' not found`)\n }\n\n return node as T\n }\n\n getRatingNodeByButtonId(id: string): HtRatingNode {\n const ratingNodes = this.flow.nodes.filter(\n node => node.type === HtNodeWithContentType.RATING\n ) as HtRatingNode[]\n const ratingNode = ratingNodes.find(node =>\n node.content.buttons.some(button => button.id === id)\n ) as HtRatingNode | undefined\n\n if (!ratingNode) {\n throw Error(`Rating node with button id: '${id}' not found`)\n }\n\n return ratingNode\n }\n\n getRatingButtonById(ratingNode: HtRatingNode, id: string): HtRatingButton {\n const ratingButton = ratingNode.content.buttons.find(\n button => button.id === id\n ) as HtRatingButton | undefined\n if (!ratingButton) {\n throw Error(`Rating button with id: '${id}' not found`)\n }\n\n return ratingButton\n }\n\n getNodeByContentID(contentID: string): HtNodeComponent {\n const content = this.flow.nodes.find(node =>\n 'code' in node ? node.code === contentID : false\n )\n if (!content) {\n throw Error(`Node with contentID: '${contentID}' not found`)\n }\n return content\n }\n\n getStartNode(): HtNodeWithContent {\n const startNodeId = this.flow.start_node_id\n if (!startNodeId) {\n throw new Error('Start node id must be defined')\n }\n return this.getNodeById(startNodeId)\n }\n\n getFallbackNode(alternate: boolean): HtNodeWithContent {\n const fallbackNode = this.flow.nodes.find(\n node => node.type === HtNodeWithContentType.FALLBACK\n ) as HtFallbackNode | undefined\n if (!fallbackNode) {\n throw new Error('Fallback node must be defined')\n }\n const fallbackFirstMessage = fallbackNode.content.first_message\n if (!fallbackFirstMessage) {\n throw new Error('Fallback 1st message must be defined')\n }\n const fallbackSecondMessage = fallbackNode.content.second_message\n if (!fallbackSecondMessage) {\n return this.getNodeById(fallbackFirstMessage.id)\n }\n return alternate\n ? this.getNodeById(fallbackFirstMessage.id)\n : this.getNodeById(fallbackSecondMessage.id)\n }\n\n getSmartIntentNodes(): HtSmartIntentNode[] {\n return this.flow.nodes.filter(\n node => node.type === HtNodeWithContentType.SMART_INTENT\n ) as HtSmartIntentNode[]\n }\n\n getKeywordNodes(): HtKeywordNode[] {\n return this.flow.nodes.filter(\n node => node.type === HtNodeWithContentType.KEYWORD\n ) as HtKeywordNode[]\n }\n\n getPayload(target?: HtNodeLink): string | undefined {\n if (!target) {\n return undefined\n }\n\n return target.id\n }\n\n isBotAction(id: string): boolean {\n if (!this.isUUID(id)) {\n return false\n }\n const node = this.getNodeById(id)\n return node?.type === HtNodeWithContentType.BOT_ACTION\n }\n\n private isUUID(str: string): boolean {\n return UUID_REGEXP.test(str)\n }\n\n createPayloadWithParams(botActionNode: HtBotActionNode): string {\n const payloadId = botActionNode.content.payload_id\n const payloadNode = this.getNodeById<HtPayloadNode>(payloadId)\n const customParams = JSON.parse(\n botActionNode.content.payload_params || '{}'\n )\n\n const contentID = botActionNode.code\n\n const followUpContentID = this.getFollowUpContentID(\n botActionNode.follow_up?.id\n )\n\n const payloadParams: PayloadParamsBase = {\n contentID,\n followUpContentID,\n }\n\n const payloadJson = JSON.stringify({\n ...customParams,\n ...payloadParams,\n })\n return `${payloadNode.content.payload}${SEPARATOR}${payloadJson}`\n }\n\n private getFollowUpContentID(id?: string): string | undefined {\n const followUpNode = id\n ? this.getNodeById<HtNodeWithContent | HtGoToFlow>(id)\n : undefined\n\n return followUpNode?.code\n }\n\n getFlowName(flowId: string): string {\n const flow = this.flow.flows.find(flow => flow.id === flowId)\n return flow ? flow.name : this.getCampaignFlowName(flowId)\n }\n\n getCampaignFlowName(campaignId: string): string {\n const campaign = this.flow.campaigns.find(\n campaign => campaign.id === campaignId\n )\n return campaign ? campaign.name : ''\n }\n\n getStartNodeAiAgentFlow(): HtNodeWithContent | undefined {\n const aiAgentFlow = this.flow.flows.find(\n flow => flow.name === AI_AGENTS_FLOW_NAME\n )\n\n if (!aiAgentFlow) {\n return undefined\n }\n\n return this.getNodeById<HtNodeWithContent>(aiAgentFlow.start_node_id)\n }\n\n isAiAgentEnabled(): boolean {\n return this.flow.is_ai_agent_active || false\n }\n\n getWebviewById(id: string): HtFlowWebview | undefined {\n return this.flow.webviews.find(webview => webview.id === id)\n }\n\n shouldCaptureUserInput(): boolean {\n return !!this.getCaptureUserInputId()\n }\n\n getCaptureUserInputId(): string | undefined {\n return this.botContext.session.capture_user_input?.node_id\n }\n\n setCaptureUserInputId(id: string): void {\n if (this.botContext.session.capture_user_input) {\n this.botContext.session.capture_user_input.node_id = id\n }\n this.botContext.session.capture_user_input = { node_id: id }\n }\n\n removeCaptureUserInputId(): void {\n this.botContext.session.capture_user_input = undefined\n }\n\n setUserExtraDataVariable(key: string, value: string): void {\n if (this.botContext.session.user.extra_data) {\n this.botContext.session.user.extra_data[key] = value\n }\n }\n\n getCaptureUserInputNode(): HtCaptureUserInputNode | undefined {\n const captureUserInputId = this.getCaptureUserInputId()\n if (!captureUserInputId) {\n return undefined\n }\n return this.getNodeById<HtCaptureUserInputNode>(captureUserInputId)\n }\n\n getSessionWhatsappRequestContactId(): string | undefined {\n return this.botContext.session.whatsapp_request_contact?.id\n }\n\n setWhatsappRequestContactId(id: string): void {\n if (this.botContext.session.whatsapp_request_contact) {\n this.botContext.session.whatsapp_request_contact.id = id\n }\n this.botContext.session.whatsapp_request_contact = { id }\n }\n\n removeWhatsappRequestContactId(): void {\n this.botContext.session.whatsapp_request_contact = undefined\n }\n\n getWhatsappRequestContactInfoNode():\n | HtWhatsappRequestContactInfoNode\n | undefined {\n const whatsappRequestContactId = this.getSessionWhatsappRequestContactId()\n if (!whatsappRequestContactId) {\n return undefined\n }\n return this.getNodeById<HtWhatsappRequestContactInfoNode>(\n whatsappRequestContactId\n )\n }\n\n getResolvedLocale(): string {\n const flowLocales = this.flow.locales\n const defaultLocaleCode = this.flow.default_locale_code\n\n return new FlowLocale(\n this.botContext,\n flowLocales,\n defaultLocaleCode\n ).resolve()\n }\n\n isPushFlowPayload(payload?: string): boolean {\n return payload?.startsWith(PUSH_FLOW_PAYLOAD) ?? false\n }\n}\n"],"names":["axios","AI_AGENTS_FLOW_NAME","PUSH_FLOW_PAYLOAD","SEPARATOR","UUID_REGEXP","HtNodeWithContentType","ProcessEnvNodeEnvs","FlowLocale","FlowBuilderApi","options","newApi","process","updatedRequest","token","data","url","response","id","subFlow","Error","campaign","node","console","ratingNodes","ratingNode","button","ratingButton","contentID","content","startNodeId","alternate","fallbackNode","fallbackFirstMessage","fallbackSecondMessage","target","undefined","str","botActionNode","payloadId","payloadNode","customParams","JSON","followUpContentID","payloadParams","payloadJson","followUpNode","flowId","flow","campaignId","aiAgentFlow","webview","key","value","captureUserInputId","whatsappRequestContactId","flowLocales","defaultLocaleCode","payload"],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type BotContext } from '@botonic/core';
|
|
2
|
+
import type { FlowBuilderApi } from './api.js';
|
|
3
|
+
import type { SmartIntentsInferenceConfig } from './user-input/smart-intent.js';
|
|
4
|
+
export declare class BotContextManager {
|
|
5
|
+
private readonly cmsApi;
|
|
6
|
+
private readonly smartIntentsConfig;
|
|
7
|
+
constructor(cmsApi: FlowBuilderApi, smartIntentsConfig: SmartIntentsInferenceConfig);
|
|
8
|
+
prepareInputForRoutes(botContext: BotContext): Promise<void>;
|
|
9
|
+
private updateFirstInteractionOnPushFlowPayload;
|
|
10
|
+
private resolvePayloadFromUserTextInput;
|
|
11
|
+
private resolveWhatsappContactRequestPayload;
|
|
12
|
+
private resolveOnCloseHandoffPayload;
|
|
13
|
+
private convertWhatsappAiAgentEmptyPayloads;
|
|
14
|
+
private removePayloadSourceSuffix;
|
|
15
|
+
private resolveBotActionPayload;
|
|
16
|
+
private removeSourceSuffix;
|
|
17
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { INPUT, PROVIDER, WhatsappInputOrigin } from "@botonic/core";
|
|
2
|
+
import { EMPTY_PAYLOAD, ON_CLOSE_HANDOFF_PAYLOAD, SEPARATOR, SOURCE_INFO_SEPARATOR } from "./constants.js";
|
|
3
|
+
import { FlowHandoff } from "./content-fields/index.js";
|
|
4
|
+
import { HtNodeWithContentType } from "./content-fields/hubtype-fields/index.js";
|
|
5
|
+
import { getNextPayloadByUserInput } from "./user-input/index.js";
|
|
6
|
+
import { inputHasTextOrTranscript } from "./utils/input.js";
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class BotContextManager {
|
|
21
|
+
async prepareInputForRoutes(botContext) {
|
|
22
|
+
// When AI Agent is executed in Whatsapp, button payloads come as referral and must be converted to text being processed by the agent.
|
|
23
|
+
this.convertWhatsappAiAgentEmptyPayloads(botContext);
|
|
24
|
+
// If the payload is a push-flow payload, set first interaction to false
|
|
25
|
+
this.updateFirstInteractionOnPushFlowPayload(botContext);
|
|
26
|
+
this.resolveWhatsappContactRequestPayload(botContext);
|
|
27
|
+
this.resolveOnCloseHandoffPayload(botContext);
|
|
28
|
+
await this.resolvePayloadFromUserTextInput(botContext);
|
|
29
|
+
this.cmsApi.removeCaptureUserInputId();
|
|
30
|
+
this.removePayloadSourceSuffix(botContext);
|
|
31
|
+
this.resolveBotActionPayload(botContext);
|
|
32
|
+
}
|
|
33
|
+
async updateFirstInteractionOnPushFlowPayload(botContext) {
|
|
34
|
+
if (this.cmsApi.isPushFlowPayload(botContext.input.payload)) {
|
|
35
|
+
botContext.session.is_first_interaction = false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async resolvePayloadFromUserTextInput(botContext) {
|
|
39
|
+
const checkUserTextInput = inputHasTextOrTranscript(botContext.input) && !botContext.input.payload;
|
|
40
|
+
if (!checkUserTextInput) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const resolvedLocale = this.cmsApi.getResolvedLocale();
|
|
44
|
+
const nextPayload = await getNextPayloadByUserInput(this.cmsApi, resolvedLocale, botContext, this.smartIntentsConfig);
|
|
45
|
+
botContext.input.payload = nextPayload;
|
|
46
|
+
}
|
|
47
|
+
resolveWhatsappContactRequestPayload(botContext) {
|
|
48
|
+
if (botContext.input.type !== INPUT.CONTACT || botContext.input.origin !== WhatsappInputOrigin.ContactRequest) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const whatsappRequestContactInfoNode = this.cmsApi.getWhatsappRequestContactInfoNode();
|
|
52
|
+
if (whatsappRequestContactInfoNode) {
|
|
53
|
+
botContext.input.payload = this.cmsApi.getPayload(whatsappRequestContactInfoNode.content.button.target);
|
|
54
|
+
}
|
|
55
|
+
this.cmsApi.removeWhatsappRequestContactId();
|
|
56
|
+
}
|
|
57
|
+
resolveOnCloseHandoffPayload(botContext) {
|
|
58
|
+
if (botContext.input.payload?.startsWith(ON_CLOSE_HANDOFF_PAYLOAD)) {
|
|
59
|
+
const handoffNodeId = botContext.input.payload.split(SEPARATOR)[1];
|
|
60
|
+
const handoffNode = this.cmsApi.getNodeById(handoffNodeId);
|
|
61
|
+
if (handoffNode && handoffNode.type === HtNodeWithContentType.HANDOFF) {
|
|
62
|
+
const flowHandoff = FlowHandoff.fromHubtypeCMS(handoffNode, this.cmsApi.getResolvedLocale(), this.cmsApi);
|
|
63
|
+
botContext.input.payload = flowHandoff.resolveOnClosePayload(botContext);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
convertWhatsappAiAgentEmptyPayloads(botContext) {
|
|
68
|
+
if (botContext.session.user.provider === PROVIDER.WHATSAPP) {
|
|
69
|
+
const shouldUseReferral = botContext.input.referral && botContext.input.payload?.startsWith(EMPTY_PAYLOAD);
|
|
70
|
+
if (shouldUseReferral) {
|
|
71
|
+
botContext.input.type = INPUT.TEXT;
|
|
72
|
+
botContext.input.data = botContext.input.referral;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
removePayloadSourceSuffix(botContext) {
|
|
77
|
+
if (botContext.input.payload) {
|
|
78
|
+
botContext.input.payload = this.removeSourceSuffix(botContext.input.payload);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
resolveBotActionPayload(botContext) {
|
|
82
|
+
if (botContext.input.payload && this.cmsApi.isBotAction(botContext.input.payload)) {
|
|
83
|
+
const cmsBotAction = this.cmsApi.getNodeById(botContext.input.payload);
|
|
84
|
+
botContext.input.payload = this.cmsApi.createPayloadWithParams(cmsBotAction);
|
|
85
|
+
// Re-execute convertWhatsappAiAgentEmptyPayloads function to handle
|
|
86
|
+
// the case that a BotAction has a payload equals to EMPTY_PAYLOAD
|
|
87
|
+
this.convertWhatsappAiAgentEmptyPayloads(botContext);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
removeSourceSuffix(payload) {
|
|
91
|
+
return payload.split(SOURCE_INFO_SEPARATOR)[0];
|
|
92
|
+
}
|
|
93
|
+
constructor(cmsApi, smartIntentsConfig){
|
|
94
|
+
this.cmsApi = cmsApi;
|
|
95
|
+
this.smartIntentsConfig = smartIntentsConfig;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export { BotContextManager };
|
|
100
|
+
|
|
101
|
+
//# sourceMappingURL=bot-context-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot-context-manager.js","sources":["../src/bot-context-manager.ts"],"sourcesContent":["import {\n type BotContext,\n INPUT,\n PROVIDER,\n WhatsappInputOrigin,\n} from '@botonic/core'\n\nimport type { FlowBuilderApi } from './api'\nimport {\n EMPTY_PAYLOAD,\n ON_CLOSE_HANDOFF_PAYLOAD,\n SEPARATOR,\n SOURCE_INFO_SEPARATOR,\n} from './constants'\nimport { FlowHandoff } from './content-fields'\nimport {\n type HtBotActionNode,\n type HtHandoffNode,\n HtNodeWithContentType,\n} from './content-fields/hubtype-fields'\nimport { getNextPayloadByUserInput } from './user-input'\nimport type { SmartIntentsInferenceConfig } from './user-input/smart-intent'\nimport { inputHasTextOrTranscript } from './utils/input'\n\nexport class BotContextManager {\n constructor(\n private readonly cmsApi: FlowBuilderApi,\n private readonly smartIntentsConfig: SmartIntentsInferenceConfig\n ) {}\n\n async prepareInputForRoutes(botContext: BotContext): Promise<void> {\n // When AI Agent is executed in Whatsapp, button payloads come as referral and must be converted to text being processed by the agent.\n this.convertWhatsappAiAgentEmptyPayloads(botContext)\n\n // If the payload is a push-flow payload, set first interaction to false\n this.updateFirstInteractionOnPushFlowPayload(botContext)\n\n this.resolveWhatsappContactRequestPayload(botContext)\n this.resolveOnCloseHandoffPayload(botContext)\n\n await this.resolvePayloadFromUserTextInput(botContext)\n\n this.cmsApi.removeCaptureUserInputId()\n this.removePayloadSourceSuffix(botContext)\n this.resolveBotActionPayload(botContext)\n }\n\n private async updateFirstInteractionOnPushFlowPayload(\n botContext: BotContext\n ): Promise<void> {\n if (this.cmsApi.isPushFlowPayload(botContext.input.payload)) {\n botContext.session.is_first_interaction = false\n }\n }\n\n private async resolvePayloadFromUserTextInput(\n botContext: BotContext\n ): Promise<void> {\n const checkUserTextInput =\n inputHasTextOrTranscript(botContext.input) && !botContext.input.payload\n\n if (!checkUserTextInput) {\n return\n }\n\n const resolvedLocale = this.cmsApi.getResolvedLocale()\n const nextPayload = await getNextPayloadByUserInput(\n this.cmsApi,\n resolvedLocale,\n botContext,\n this.smartIntentsConfig\n )\n botContext.input.payload = nextPayload\n }\n\n private resolveWhatsappContactRequestPayload(botContext: BotContext): void {\n if (\n botContext.input.type !== INPUT.CONTACT ||\n botContext.input.origin !== WhatsappInputOrigin.ContactRequest\n ) {\n return\n }\n\n const whatsappRequestContactInfoNode =\n this.cmsApi.getWhatsappRequestContactInfoNode()\n\n if (whatsappRequestContactInfoNode) {\n botContext.input.payload = this.cmsApi.getPayload(\n whatsappRequestContactInfoNode.content.button.target\n )\n }\n\n this.cmsApi.removeWhatsappRequestContactId()\n }\n\n private resolveOnCloseHandoffPayload(botContext: BotContext): void {\n if (botContext.input.payload?.startsWith(ON_CLOSE_HANDOFF_PAYLOAD)) {\n const handoffNodeId = botContext.input.payload.split(SEPARATOR)[1]\n const handoffNode = this.cmsApi.getNodeById<HtHandoffNode>(handoffNodeId)\n if (handoffNode && handoffNode.type === HtNodeWithContentType.HANDOFF) {\n const flowHandoff = FlowHandoff.fromHubtypeCMS(\n handoffNode,\n this.cmsApi.getResolvedLocale(),\n this.cmsApi\n )\n botContext.input.payload = flowHandoff.resolveOnClosePayload(botContext)\n }\n }\n }\n\n private convertWhatsappAiAgentEmptyPayloads(botContext: BotContext): void {\n if (botContext.session.user.provider === PROVIDER.WHATSAPP) {\n const shouldUseReferral =\n botContext.input.referral &&\n botContext.input.payload?.startsWith(EMPTY_PAYLOAD)\n\n if (shouldUseReferral) {\n botContext.input.type = INPUT.TEXT\n botContext.input.data = botContext.input.referral\n }\n }\n }\n\n private removePayloadSourceSuffix(botContext: BotContext): void {\n if (botContext.input.payload) {\n botContext.input.payload = this.removeSourceSuffix(\n botContext.input.payload\n )\n }\n }\n\n private resolveBotActionPayload(botContext: BotContext): void {\n if (\n botContext.input.payload &&\n this.cmsApi.isBotAction(botContext.input.payload)\n ) {\n const cmsBotAction = this.cmsApi.getNodeById<HtBotActionNode>(\n botContext.input.payload\n )\n\n botContext.input.payload =\n this.cmsApi.createPayloadWithParams(cmsBotAction)\n\n // Re-execute convertWhatsappAiAgentEmptyPayloads function to handle\n // the case that a BotAction has a payload equals to EMPTY_PAYLOAD\n this.convertWhatsappAiAgentEmptyPayloads(botContext)\n }\n }\n\n private removeSourceSuffix(payload: string): string {\n return payload.split(SOURCE_INFO_SEPARATOR)[0]\n }\n}\n"],"names":["INPUT","PROVIDER","WhatsappInputOrigin","EMPTY_PAYLOAD","ON_CLOSE_HANDOFF_PAYLOAD","SEPARATOR","SOURCE_INFO_SEPARATOR","FlowHandoff","HtNodeWithContentType","getNextPayloadByUserInput","inputHasTextOrTranscript","BotContextManager","botContext","checkUserTextInput","resolvedLocale","nextPayload","whatsappRequestContactInfoNode","handoffNodeId","handoffNode","flowHandoff","shouldUseReferral","cmsBotAction","payload","cmsApi","smartIntentsConfig"],"mappings":"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"}
|
package/lib/constants.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
export declare const FLOW_BUILDER_API_URL_PROD: string;
|
|
2
2
|
export declare const SEPARATOR = "|";
|
|
3
3
|
export declare const SOURCE_INFO_SEPARATOR = "|source_";
|
|
4
|
-
export declare const EMPTY_PAYLOAD = "fb-empty-payload";
|
|
5
4
|
export declare const VARIABLE_PATTERN_GLOBAL: RegExp;
|
|
6
5
|
export declare const ACCESS_TOKEN_VARIABLE_KEY = "_access_token";
|
|
7
6
|
export declare const REG_EXP_PATTERN: RegExp;
|
|
8
7
|
export declare const UUID_REGEXP: RegExp;
|
|
8
|
+
export declare const EMPTY_PAYLOAD = "fb-empty-payload";
|
|
9
|
+
export declare const ON_CLOSE_HANDOFF_PAYLOAD = "fb-on-close-handoff";
|
|
9
10
|
export declare const AGENT_RATING_PAYLOAD = "agent-rating";
|
|
10
11
|
export declare const PUSH_FLOW_PAYLOAD = "push-flow";
|
|
11
12
|
export declare const MAIN_FLOW_NAME = "Main";
|
package/lib/constants.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
const FLOW_BUILDER_API_URL_PROD = process.env.HUBTYPE_API_URL || 'https://api.hubtype.com';
|
|
2
2
|
const SEPARATOR = '|';
|
|
3
3
|
const SOURCE_INFO_SEPARATOR = `${SEPARATOR}source_`;
|
|
4
|
-
const EMPTY_PAYLOAD = 'fb-empty-payload';
|
|
5
4
|
const VARIABLE_PATTERN_GLOBAL = /{([^{}]+)}/g;
|
|
6
5
|
const ACCESS_TOKEN_VARIABLE_KEY = '_access_token';
|
|
7
6
|
const REG_EXP_PATTERN = /^\/(.*)\/([gimyus]*)$/;
|
|
8
7
|
const UUID_REGEXP = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
9
|
-
/* ********** PAYLOADS ********** */ const
|
|
8
|
+
/* ********** PAYLOADS ********** */ const EMPTY_PAYLOAD = 'fb-empty-payload';
|
|
9
|
+
const ON_CLOSE_HANDOFF_PAYLOAD = 'fb-on-close-handoff';
|
|
10
|
+
const AGENT_RATING_PAYLOAD = 'agent-rating';
|
|
10
11
|
const PUSH_FLOW_PAYLOAD = 'push-flow';
|
|
11
12
|
/* ********** FLOW NAMES ********** */ const MAIN_FLOW_NAME = 'Main';
|
|
12
13
|
const AI_AGENTS_FLOW_NAME = 'AI Agents';
|
|
13
14
|
const FALLBACK_FLOW_NAME = 'Fallback';
|
|
14
15
|
|
|
15
|
-
export { ACCESS_TOKEN_VARIABLE_KEY, AGENT_RATING_PAYLOAD, AI_AGENTS_FLOW_NAME, EMPTY_PAYLOAD, FALLBACK_FLOW_NAME, FLOW_BUILDER_API_URL_PROD, MAIN_FLOW_NAME, PUSH_FLOW_PAYLOAD, REG_EXP_PATTERN, SEPARATOR, SOURCE_INFO_SEPARATOR, UUID_REGEXP, VARIABLE_PATTERN_GLOBAL };
|
|
16
|
+
export { ACCESS_TOKEN_VARIABLE_KEY, AGENT_RATING_PAYLOAD, AI_AGENTS_FLOW_NAME, EMPTY_PAYLOAD, FALLBACK_FLOW_NAME, FLOW_BUILDER_API_URL_PROD, MAIN_FLOW_NAME, ON_CLOSE_HANDOFF_PAYLOAD, PUSH_FLOW_PAYLOAD, REG_EXP_PATTERN, SEPARATOR, SOURCE_INFO_SEPARATOR, UUID_REGEXP, VARIABLE_PATTERN_GLOBAL };
|
|
16
17
|
|
|
17
18
|
//# sourceMappingURL=constants.js.map
|