@botonic/plugin-flow-builder 0.45.0-alpha.1 → 0.46.0-alpha-3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/lib/cjs/action/ai-agent.js +2 -0
  2. package/lib/cjs/action/ai-agent.js.map +1 -1
  3. package/lib/cjs/action/first-interaction.js +1 -1
  4. package/lib/cjs/action/first-interaction.js.map +1 -1
  5. package/lib/cjs/action/index.js +1 -1
  6. package/lib/cjs/action/index.js.map +1 -1
  7. package/lib/cjs/action/knowledge-bases.js +1 -1
  8. package/lib/cjs/action/knowledge-bases.js.map +1 -1
  9. package/lib/cjs/api.d.ts +1 -0
  10. package/lib/cjs/api.js +4 -0
  11. package/lib/cjs/api.js.map +1 -1
  12. package/lib/cjs/content-fields/flow-ai-agent.d.ts +3 -1
  13. package/lib/cjs/content-fields/flow-ai-agent.js +5 -0
  14. package/lib/cjs/content-fields/flow-ai-agent.js.map +1 -1
  15. package/lib/cjs/content-fields/flow-go-to-flow.d.ts +1 -0
  16. package/lib/cjs/content-fields/flow-go-to-flow.js +8 -0
  17. package/lib/cjs/content-fields/flow-go-to-flow.js.map +1 -1
  18. package/lib/cjs/content-fields/flow-whatsapp-template.d.ts +2 -1
  19. package/lib/cjs/content-fields/flow-whatsapp-template.js +13 -5
  20. package/lib/cjs/content-fields/flow-whatsapp-template.js.map +1 -1
  21. package/lib/cjs/content-fields/hubtype-fields/ai-agent.d.ts +3 -0
  22. package/lib/cjs/content-fields/hubtype-fields/whatsapp-template.d.ts +11 -8
  23. package/lib/cjs/flow-factory.js +1 -1
  24. package/lib/cjs/flow-factory.js.map +1 -1
  25. package/lib/cjs/index.d.ts +1 -1
  26. package/lib/cjs/index.js +8 -3
  27. package/lib/cjs/index.js.map +1 -1
  28. package/lib/cjs/user-input/capture-user-input-api.d.ts +2 -1
  29. package/lib/cjs/user-input/capture-user-input-api.js +6 -5
  30. package/lib/cjs/user-input/capture-user-input-api.js.map +1 -1
  31. package/lib/cjs/user-input/index.js +6 -4
  32. package/lib/cjs/user-input/index.js.map +1 -1
  33. package/lib/cjs/user-input/keyword.d.ts +4 -2
  34. package/lib/cjs/user-input/keyword.js +5 -4
  35. package/lib/cjs/user-input/keyword.js.map +1 -1
  36. package/lib/cjs/user-input/smart-intent.d.ts +2 -2
  37. package/lib/cjs/user-input/smart-intent.js +5 -5
  38. package/lib/cjs/user-input/smart-intent.js.map +1 -1
  39. package/lib/cjs/utils.d.ts +2 -1
  40. package/lib/cjs/utils.js +16 -3
  41. package/lib/cjs/utils.js.map +1 -1
  42. package/lib/esm/action/ai-agent.js +2 -0
  43. package/lib/esm/action/ai-agent.js.map +1 -1
  44. package/lib/esm/action/first-interaction.js +1 -1
  45. package/lib/esm/action/first-interaction.js.map +1 -1
  46. package/lib/esm/action/index.js +1 -1
  47. package/lib/esm/action/index.js.map +1 -1
  48. package/lib/esm/action/knowledge-bases.js +1 -1
  49. package/lib/esm/action/knowledge-bases.js.map +1 -1
  50. package/lib/esm/api.d.ts +1 -0
  51. package/lib/esm/api.js +4 -0
  52. package/lib/esm/api.js.map +1 -1
  53. package/lib/esm/content-fields/flow-ai-agent.d.ts +3 -1
  54. package/lib/esm/content-fields/flow-ai-agent.js +5 -0
  55. package/lib/esm/content-fields/flow-ai-agent.js.map +1 -1
  56. package/lib/esm/content-fields/flow-go-to-flow.d.ts +1 -0
  57. package/lib/esm/content-fields/flow-go-to-flow.js +8 -0
  58. package/lib/esm/content-fields/flow-go-to-flow.js.map +1 -1
  59. package/lib/esm/content-fields/flow-whatsapp-template.d.ts +2 -1
  60. package/lib/esm/content-fields/flow-whatsapp-template.js +13 -5
  61. package/lib/esm/content-fields/flow-whatsapp-template.js.map +1 -1
  62. package/lib/esm/content-fields/hubtype-fields/ai-agent.d.ts +3 -0
  63. package/lib/esm/content-fields/hubtype-fields/whatsapp-template.d.ts +11 -8
  64. package/lib/esm/flow-factory.js +1 -1
  65. package/lib/esm/flow-factory.js.map +1 -1
  66. package/lib/esm/index.d.ts +1 -1
  67. package/lib/esm/index.js +8 -3
  68. package/lib/esm/index.js.map +1 -1
  69. package/lib/esm/user-input/capture-user-input-api.d.ts +2 -1
  70. package/lib/esm/user-input/capture-user-input-api.js +6 -5
  71. package/lib/esm/user-input/capture-user-input-api.js.map +1 -1
  72. package/lib/esm/user-input/index.js +6 -4
  73. package/lib/esm/user-input/index.js.map +1 -1
  74. package/lib/esm/user-input/keyword.d.ts +4 -2
  75. package/lib/esm/user-input/keyword.js +5 -4
  76. package/lib/esm/user-input/keyword.js.map +1 -1
  77. package/lib/esm/user-input/smart-intent.d.ts +2 -2
  78. package/lib/esm/user-input/smart-intent.js +5 -5
  79. package/lib/esm/user-input/smart-intent.js.map +1 -1
  80. package/lib/esm/utils.d.ts +2 -1
  81. package/lib/esm/utils.js +16 -3
  82. package/lib/esm/utils.js.map +1 -1
  83. package/package.json +3 -3
  84. package/src/action/ai-agent.ts +2 -0
  85. package/src/action/first-interaction.ts +2 -2
  86. package/src/action/index.tsx +2 -2
  87. package/src/action/knowledge-bases.ts +2 -2
  88. package/src/api.ts +5 -0
  89. package/src/content-fields/flow-ai-agent.tsx +5 -1
  90. package/src/content-fields/flow-go-to-flow.tsx +13 -1
  91. package/src/content-fields/flow-whatsapp-template.tsx +26 -5
  92. package/src/content-fields/hubtype-fields/ai-agent.ts +3 -0
  93. package/src/content-fields/hubtype-fields/whatsapp-template.ts +13 -9
  94. package/src/flow-factory.ts +1 -1
  95. package/src/index.ts +19 -5
  96. package/src/user-input/capture-user-input-api.ts +12 -6
  97. package/src/user-input/index.ts +9 -7
  98. package/src/user-input/keyword.ts +10 -4
  99. package/src/user-input/smart-intent.ts +4 -4
  100. package/src/utils.ts +18 -2
@@ -69,18 +69,22 @@ export interface HtWhatsAppTemplate {
69
69
  namespace: string
70
70
  parameter_format: string
71
71
  }
72
+
73
+ export interface HtWhatsappTemplateContentByLocale {
74
+ template: HtWhatsAppTemplate
75
+ header_variables?: {
76
+ type: WhatsAppTemplateParameterType
77
+ text?: Record<string, string>
78
+ media?: HtMediaFileLocale[]
79
+ }
80
+ variable_values: Record<string, string>
81
+ url_variable_values?: Record<string, string>
82
+ }
83
+
72
84
  export interface HtWhatsappTemplateNode extends HtBaseNode {
73
85
  type: HtNodeWithContentType.WHATSAPP_TEMPLATE
74
86
  content: {
75
- template: HtWhatsAppTemplate
76
- header_variables?: {
77
- type: WhatsAppTemplateParameterType
78
- text?: Record<string, string>
79
- media?: HtMediaFileLocale[]
80
- }
81
- variable_values: Record<string, string>
82
-
87
+ by_locale: Record<string, HtWhatsappTemplateContentByLocale>
83
88
  buttons: HtButton[]
84
- url_variable_values?: Record<string, string>
85
89
  }
86
90
  }
@@ -93,7 +93,7 @@ export class FlowFactory {
93
93
  return FlowGoToFlow.fromHubtypeCMS(hubtypeContent, this.cmsApi)
94
94
 
95
95
  case HtNodeWithContentType.WHATSAPP_TEMPLATE:
96
- return FlowWhatsappTemplate.fromHubtypeCMS(hubtypeContent)
96
+ return FlowWhatsappTemplate.fromHubtypeCMS(hubtypeContent, this.locale)
97
97
 
98
98
  case HtNodeWithContentType.CAPTURE_USER_INPUT:
99
99
  return FlowCaptureUserInput.fromHubtypeCMS(hubtypeContent)
package/src/index.ts CHANGED
@@ -16,10 +16,11 @@ import {
16
16
  SEPARATOR,
17
17
  SOURCE_INFO_SEPARATOR,
18
18
  } from './constants'
19
- import type { FlowContent } from './content-fields'
19
+ import { type FlowContent, FlowGoToFlow } from './content-fields'
20
20
  import {
21
21
  type HtBotActionNode,
22
22
  type HtFlowBuilderData,
23
+ type HtGoToFlow,
23
24
  type HtNodeWithContent,
24
25
  HtNodeWithContentType,
25
26
  } from './content-fields/hubtype-fields'
@@ -38,7 +39,7 @@ import {
38
39
  } from './types'
39
40
  import { getNextPayloadByUserInput } from './user-input'
40
41
  import type { SmartIntentsInferenceConfig } from './user-input/smart-intent'
41
- import { inputHasTextData, resolveGetAccessToken } from './utils'
42
+ import { inputHasTextOrTranscript, resolveGetAccessToken } from './utils'
42
43
 
43
44
  // TODO: Create a proper service to wrap all calls and allow api versioning
44
45
 
@@ -109,7 +110,7 @@ export default class BotonicPluginFlowBuilder implements Plugin {
109
110
  })
110
111
 
111
112
  const checkUserTextInput =
112
- inputHasTextData(request.input) && !request.input.payload
113
+ inputHasTextOrTranscript(request.input) && !request.input.payload
113
114
 
114
115
  if (checkUserTextInput) {
115
116
  const resolvedLocale = this.cmsApi.getResolvedLocale()
@@ -122,7 +123,7 @@ export default class BotonicPluginFlowBuilder implements Plugin {
122
123
  request.input.payload = nextPayload
123
124
  }
124
125
 
125
- this.updateRequestBeforeRoutes(request)
126
+ await this.updateRequestBeforeRoutes(request)
126
127
  }
127
128
 
128
129
  private convertWhatsappAiAgentEmptyPayloads(request: PluginPreRequest): void {
@@ -138,7 +139,9 @@ export default class BotonicPluginFlowBuilder implements Plugin {
138
139
  }
139
140
  }
140
141
 
141
- private updateRequestBeforeRoutes(request: PluginPreRequest): void {
142
+ private async updateRequestBeforeRoutes(
143
+ request: PluginPreRequest
144
+ ): Promise<void> {
142
145
  this.cmsApi.removeCaptureUserInputId()
143
146
  if (request.input.payload) {
144
147
  request.input.payload = this.removeSourceSuffix(request.input.payload)
@@ -155,6 +158,17 @@ export default class BotonicPluginFlowBuilder implements Plugin {
155
158
  // the case that a BotAction has a payload equals to EMPTY_PAYLOAD
156
159
  this.convertWhatsappAiAgentEmptyPayloads(request)
157
160
  }
161
+
162
+ if (this.cmsApi.isGoToFlow(request.input.payload)) {
163
+ const cmsGoToFlow = this.cmsApi.getNodeById<HtGoToFlow>(
164
+ request.input.payload
165
+ )
166
+ await FlowGoToFlow.resolveToAiAgentsFlow(
167
+ request,
168
+ cmsGoToFlow,
169
+ this.cmsApi
170
+ )
171
+ }
158
172
  }
159
173
  }
160
174
 
@@ -13,7 +13,7 @@ import {
13
13
  getCommonFlowContentEventArgsForContentId,
14
14
  trackEvent,
15
15
  } from '../tracking'
16
- import { inputHasTextData } from '../utils'
16
+ import { inputHasTextOrTranscript } from '../utils'
17
17
 
18
18
  interface AiCaptureResponseSuccess {
19
19
  success: true
@@ -29,19 +29,25 @@ type AiCaptureResponse = AiCaptureResponseSuccess | AiCaptureResponseFailure
29
29
  export class CaptureUserInputApi {
30
30
  private cmsApi: FlowBuilderApi
31
31
  private request: ActionRequest
32
+ private textOrTranscript: string
32
33
 
33
- constructor(cmsApi: FlowBuilderApi, request: ActionRequest) {
34
+ constructor(
35
+ cmsApi: FlowBuilderApi,
36
+ request: ActionRequest,
37
+ textOrTranscript: string
38
+ ) {
34
39
  this.cmsApi = cmsApi
35
40
  this.request = request
41
+ this.textOrTranscript = textOrTranscript
36
42
  }
37
43
 
38
44
  async getNextNodeId(): Promise<string | undefined> {
39
45
  if (
40
- inputHasTextData(this.request.input) &&
46
+ inputHasTextOrTranscript(this.request.input) &&
41
47
  this.cmsApi.shouldCaptureUserInput()
42
48
  ) {
43
49
  const captureUserInputNode = this.cmsApi.getCaptureUserInputNode()
44
- if (!captureUserInputNode) {
50
+ if (!captureUserInputNode || !this.textOrTranscript) {
45
51
  return undefined
46
52
  }
47
53
  const captureUserInput =
@@ -50,7 +56,7 @@ export class CaptureUserInputApi {
50
56
  if (captureUserInput.aiValidationType === HtAiValidationType.NONE) {
51
57
  this.cmsApi.setUserExtraDataVariable(
52
58
  captureUserInputNode.content.field_name,
53
- this.request.input.data as string
59
+ this.textOrTranscript
54
60
  )
55
61
  await this.trackUserInputCapture(captureUserInputNode, true)
56
62
  return captureUserInput.captureSuccessId
@@ -82,7 +88,7 @@ export class CaptureUserInputApi {
82
88
  field_name: captureUserInputNode.content.field_name,
83
89
  validation_instructions:
84
90
  captureUserInputNode.content.ai_validation_instructions,
85
- user_input: this.request.input.data,
91
+ user_input: this.textOrTranscript,
86
92
  }
87
93
  const pluginFlowBuilder = getFlowBuilderPlugin(this.request.plugins)
88
94
  const token = pluginFlowBuilder.getAccessToken(this.request.session)
@@ -2,7 +2,7 @@ import type { ActionRequest } from '@botonic/react'
2
2
 
3
3
  import type { FlowBuilderApi } from '../api'
4
4
  import {
5
- inputHasTextData,
5
+ getTextOrTranscript,
6
6
  isKeywordsAllowed,
7
7
  isSmartIntentsAllowed,
8
8
  } from '../utils'
@@ -19,11 +19,13 @@ export async function getNextPayloadByUserInput(
19
19
  request: ActionRequest,
20
20
  smartIntentsConfig: SmartIntentsInferenceConfig
21
21
  ): Promise<string | undefined> {
22
- if (inputHasTextData(request.input)) {
22
+ const userTextOrTranscript = getTextOrTranscript(request.input)
23
+ if (userTextOrTranscript) {
23
24
  if (cmsApi.shouldCaptureUserInput()) {
24
25
  const captureUserInputApi = new CaptureUserInputApi(
25
26
  cmsApi,
26
- request as unknown as ActionRequest
27
+ request,
28
+ userTextOrTranscript
27
29
  )
28
30
  return await captureUserInputApi.getNextNodeId()
29
31
  }
@@ -33,10 +35,9 @@ export async function getNextPayloadByUserInput(
33
35
  cmsApi,
34
36
  locale,
35
37
  request,
38
+ userTextOrTranscript,
36
39
  })
37
- const keywordNode = await keywordMatcher.getNodeByInput(
38
- request.input.data!
39
- )
40
+ const keywordNode = await keywordMatcher.getNodeByInput()
40
41
  if (keywordNode) {
41
42
  return cmsApi.getPayload(keywordNode.target)
42
43
  }
@@ -46,7 +47,8 @@ export async function getNextPayloadByUserInput(
46
47
  const smartIntentsApi = new SmartIntentsApi(
47
48
  cmsApi,
48
49
  request,
49
- smartIntentsConfig
50
+ smartIntentsConfig,
51
+ userTextOrTranscript
50
52
  )
51
53
  const smartIntentNode = await smartIntentsApi.getNodeByInput()
52
54
  if (smartIntentNode) {
@@ -16,6 +16,7 @@ interface KeywordProps {
16
16
  cmsApi: FlowBuilderApi
17
17
  locale: string
18
18
  request: ActionRequest
19
+ userTextOrTranscript: string
19
20
  }
20
21
  export class KeywordMatcher {
21
22
  public cmsApi: FlowBuilderApi
@@ -25,17 +26,22 @@ export class KeywordMatcher {
25
26
  public matchedKeyword?: string
26
27
  public keywordNodeId?: string
27
28
  public flowId?: string
29
+ public userTextOrTranscript: string
28
30
 
29
- constructor({ cmsApi, locale, request }: KeywordProps) {
31
+ constructor({ cmsApi, locale, request, userTextOrTranscript }: KeywordProps) {
30
32
  this.cmsApi = cmsApi
31
33
  this.locale = locale
32
34
  this.request = request
33
35
  this.isRegExp = false
36
+ this.userTextOrTranscript = userTextOrTranscript
34
37
  }
35
38
 
36
- async getNodeByInput(userInput: string): Promise<HtKeywordNode | undefined> {
39
+ async getNodeByInput(): Promise<HtKeywordNode | undefined> {
37
40
  const keywordNodes = this.cmsApi.getKeywordNodes()
38
- const keywordNode = this.getNodeByKeyword(userInput, keywordNodes)
41
+ const keywordNode = this.getNodeByKeyword(
42
+ this.userTextOrTranscript,
43
+ keywordNodes
44
+ )
39
45
  if (!keywordNode || !this.matchedKeyword) {
40
46
  return undefined
41
47
  }
@@ -120,7 +126,7 @@ export class KeywordMatcher {
120
126
  nluKeywordName: this.matchedKeyword as string,
121
127
  nluKeywordIsRegex: this.isRegExp,
122
128
  nluKeywordMessageId: this.request.input.message_id,
123
- userInput: this.request.input.data as string,
129
+ userInput: this.userTextOrTranscript,
124
130
  }
125
131
  const { action, ...eventArgs } = event
126
132
  await trackEvent(this.request, action, eventArgs)
@@ -28,11 +28,11 @@ export class SmartIntentsApi {
28
28
  public cmsApi: FlowBuilderApi,
29
29
  public currentRequest: ActionRequest,
30
30
  public smartIntentsConfig: SmartIntentsInferenceConfig,
31
- public flowId?: string
31
+ public userTextOrTranscript: string
32
32
  ) {}
33
33
 
34
34
  async getNodeByInput(): Promise<HtSmartIntentNode | undefined> {
35
- if (!this.currentRequest.input.data) {
35
+ if (!this.userTextOrTranscript) {
36
36
  return undefined
37
37
  }
38
38
  const smartIntentNodes = this.cmsApi.getSmartIntentNodes()
@@ -42,7 +42,7 @@ export class SmartIntentsApi {
42
42
 
43
43
  const params = {
44
44
  bot_id: this.currentRequest.session.bot.id,
45
- text: this.currentRequest.input.data,
45
+ text: this.userTextOrTranscript,
46
46
  num_smart_intents_to_use: this.smartIntentsConfig.numSmartIntentsToUse,
47
47
  use_latest: this.resolveUseLatest(),
48
48
  }
@@ -73,7 +73,7 @@ export class SmartIntentsApi {
73
73
  nluIntentSmartTitle: response.data.smart_intent_title,
74
74
  nluIntentSmartNumUsed: response.data.smart_intents_used.length,
75
75
  nluIntentSmartMessageId: this.currentRequest.input.message_id,
76
- userInput: this.currentRequest.input.data,
76
+ userInput: this.userTextOrTranscript,
77
77
  flowThreadId: this.currentRequest.session.flow_thread_id as string,
78
78
  flowId,
79
79
  flowName,
package/src/utils.ts CHANGED
@@ -24,8 +24,24 @@ export function resolveGetAccessToken(
24
24
  }
25
25
  }
26
26
 
27
- export function inputHasTextData(input: Input): boolean {
28
- return input.data !== undefined && input.type === INPUT.TEXT
27
+ export function inputHasTextOrTranscript(input: Input): boolean {
28
+ const isTextInput = Boolean(input.data) && input.type === INPUT.TEXT
29
+ const isTranscriptText =
30
+ Boolean(input.transcript) && input.type === INPUT.AUDIO
31
+
32
+ return isTextInput || isTranscriptText
33
+ }
34
+
35
+ export function getTextOrTranscript(input: Input): string | undefined {
36
+ if (input.type === INPUT.TEXT && input.data) {
37
+ return input.data
38
+ }
39
+ if (input.type === INPUT.AUDIO && input.transcript) {
40
+ return input.transcript
41
+ }
42
+
43
+ console.error('No text or transcript found in input', input)
44
+ return undefined
29
45
  }
30
46
 
31
47
  function isNluAllowed(