@botonic/plugin-flow-builder 0.36.0 → 0.37.0-alpha.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.
Files changed (124) hide show
  1. package/lib/cjs/action/ai-agent.js +6 -10
  2. package/lib/cjs/action/ai-agent.js.map +1 -1
  3. package/lib/cjs/action/index.js +4 -0
  4. package/lib/cjs/action/index.js.map +1 -1
  5. package/lib/cjs/action/payload.d.ts +1 -1
  6. package/lib/cjs/action/payload.js +46 -3
  7. package/lib/cjs/action/payload.js.map +1 -1
  8. package/lib/cjs/api.d.ts +3 -1
  9. package/lib/cjs/api.js +15 -0
  10. package/lib/cjs/api.js.map +1 -1
  11. package/lib/cjs/constants.d.ts +1 -0
  12. package/lib/cjs/constants.js +4 -1
  13. package/lib/cjs/constants.js.map +1 -1
  14. package/lib/cjs/content-fields/flow-ai-agent.d.ts +2 -1
  15. package/lib/cjs/content-fields/flow-ai-agent.js +15 -2
  16. package/lib/cjs/content-fields/flow-ai-agent.js.map +1 -1
  17. package/lib/cjs/content-fields/flow-button.d.ts +8 -0
  18. package/lib/cjs/content-fields/flow-button.js +15 -0
  19. package/lib/cjs/content-fields/flow-button.js.map +1 -1
  20. package/lib/cjs/content-fields/flow-element.d.ts +9 -0
  21. package/lib/cjs/content-fields/flow-element.js +12 -0
  22. package/lib/cjs/content-fields/flow-element.js.map +1 -1
  23. package/lib/cjs/content-fields/flow-rating.d.ts +15 -0
  24. package/lib/cjs/content-fields/flow-rating.js +56 -0
  25. package/lib/cjs/content-fields/flow-rating.js.map +1 -0
  26. package/lib/cjs/content-fields/hubtype-fields/index.d.ts +1 -0
  27. package/lib/cjs/content-fields/hubtype-fields/index.js +1 -0
  28. package/lib/cjs/content-fields/hubtype-fields/index.js.map +1 -1
  29. package/lib/cjs/content-fields/hubtype-fields/node-types.d.ts +2 -1
  30. package/lib/cjs/content-fields/hubtype-fields/node-types.js +1 -0
  31. package/lib/cjs/content-fields/hubtype-fields/node-types.js.map +1 -1
  32. package/lib/cjs/content-fields/hubtype-fields/nodes.d.ts +2 -1
  33. package/lib/cjs/content-fields/hubtype-fields/rating.d.ts +23 -0
  34. package/lib/cjs/content-fields/hubtype-fields/rating.js +9 -0
  35. package/lib/cjs/content-fields/hubtype-fields/rating.js.map +1 -0
  36. package/lib/cjs/content-fields/index.d.ts +3 -2
  37. package/lib/cjs/content-fields/index.js +3 -1
  38. package/lib/cjs/content-fields/index.js.map +1 -1
  39. package/lib/cjs/content-fields/whatsapp-button-list/flow-whatsapp-button-list-section.d.ts +1 -1
  40. package/lib/cjs/content-fields/whatsapp-button-list/flow-whatsapp-button-list-section.js +1 -1
  41. package/lib/cjs/content-fields/whatsapp-button-list/flow-whatsapp-button-list-section.js.map +1 -1
  42. package/lib/cjs/content-fields/whatsapp-button-list/flow-whatsapp-button-list.d.ts +1 -1
  43. package/lib/cjs/content-fields/whatsapp-button-list/flow-whatsapp-button-list.js +1 -1
  44. package/lib/cjs/content-fields/whatsapp-button-list/flow-whatsapp-button-list.js.map +1 -1
  45. package/lib/cjs/index.d.ts +1 -0
  46. package/lib/cjs/index.js +4 -0
  47. package/lib/cjs/index.js.map +1 -1
  48. package/lib/cjs/tracking.d.ts +2 -1
  49. package/lib/cjs/tracking.js +1 -0
  50. package/lib/cjs/tracking.js.map +1 -1
  51. package/lib/cjs/types.d.ts +36 -7
  52. package/lib/cjs/types.js.map +1 -1
  53. package/lib/esm/action/ai-agent.js +5 -9
  54. package/lib/esm/action/ai-agent.js.map +1 -1
  55. package/lib/esm/action/index.js +4 -0
  56. package/lib/esm/action/index.js.map +1 -1
  57. package/lib/esm/action/payload.d.ts +1 -1
  58. package/lib/esm/action/payload.js +46 -3
  59. package/lib/esm/action/payload.js.map +1 -1
  60. package/lib/esm/api.d.ts +3 -1
  61. package/lib/esm/api.js +15 -0
  62. package/lib/esm/api.js.map +1 -1
  63. package/lib/esm/constants.d.ts +1 -0
  64. package/lib/esm/constants.js +3 -0
  65. package/lib/esm/constants.js.map +1 -1
  66. package/lib/esm/content-fields/flow-ai-agent.d.ts +2 -1
  67. package/lib/esm/content-fields/flow-ai-agent.js +17 -4
  68. package/lib/esm/content-fields/flow-ai-agent.js.map +1 -1
  69. package/lib/esm/content-fields/flow-button.d.ts +8 -0
  70. package/lib/esm/content-fields/flow-button.js +15 -0
  71. package/lib/esm/content-fields/flow-button.js.map +1 -1
  72. package/lib/esm/content-fields/flow-element.d.ts +9 -0
  73. package/lib/esm/content-fields/flow-element.js +12 -0
  74. package/lib/esm/content-fields/flow-element.js.map +1 -1
  75. package/lib/esm/content-fields/flow-rating.d.ts +15 -0
  76. package/lib/esm/content-fields/flow-rating.js +52 -0
  77. package/lib/esm/content-fields/flow-rating.js.map +1 -0
  78. package/lib/esm/content-fields/hubtype-fields/index.d.ts +1 -0
  79. package/lib/esm/content-fields/hubtype-fields/index.js +1 -0
  80. package/lib/esm/content-fields/hubtype-fields/index.js.map +1 -1
  81. package/lib/esm/content-fields/hubtype-fields/node-types.d.ts +2 -1
  82. package/lib/esm/content-fields/hubtype-fields/node-types.js +1 -0
  83. package/lib/esm/content-fields/hubtype-fields/node-types.js.map +1 -1
  84. package/lib/esm/content-fields/hubtype-fields/nodes.d.ts +2 -1
  85. package/lib/esm/content-fields/hubtype-fields/rating.d.ts +23 -0
  86. package/lib/esm/content-fields/hubtype-fields/rating.js +6 -0
  87. package/lib/esm/content-fields/hubtype-fields/rating.js.map +1 -0
  88. package/lib/esm/content-fields/index.d.ts +3 -2
  89. package/lib/esm/content-fields/index.js +2 -1
  90. package/lib/esm/content-fields/index.js.map +1 -1
  91. package/lib/esm/content-fields/whatsapp-button-list/flow-whatsapp-button-list-section.d.ts +1 -1
  92. package/lib/esm/content-fields/whatsapp-button-list/flow-whatsapp-button-list-section.js +1 -1
  93. package/lib/esm/content-fields/whatsapp-button-list/flow-whatsapp-button-list-section.js.map +1 -1
  94. package/lib/esm/content-fields/whatsapp-button-list/flow-whatsapp-button-list.d.ts +1 -1
  95. package/lib/esm/content-fields/whatsapp-button-list/flow-whatsapp-button-list.js +1 -1
  96. package/lib/esm/content-fields/whatsapp-button-list/flow-whatsapp-button-list.js.map +1 -1
  97. package/lib/esm/index.d.ts +1 -0
  98. package/lib/esm/index.js +5 -1
  99. package/lib/esm/index.js.map +1 -1
  100. package/lib/esm/tracking.d.ts +2 -1
  101. package/lib/esm/tracking.js +1 -0
  102. package/lib/esm/tracking.js.map +1 -1
  103. package/lib/esm/types.d.ts +36 -7
  104. package/lib/esm/types.js.map +1 -1
  105. package/package.json +2 -2
  106. package/src/action/ai-agent.ts +7 -14
  107. package/src/action/index.tsx +4 -0
  108. package/src/action/payload.ts +56 -6
  109. package/src/api.ts +28 -0
  110. package/src/constants.ts +4 -0
  111. package/src/content-fields/flow-ai-agent.tsx +43 -3
  112. package/src/content-fields/flow-button.tsx +22 -0
  113. package/src/content-fields/flow-element.tsx +21 -0
  114. package/src/content-fields/flow-rating.tsx +92 -0
  115. package/src/content-fields/hubtype-fields/index.ts +1 -0
  116. package/src/content-fields/hubtype-fields/node-types.ts +1 -0
  117. package/src/content-fields/hubtype-fields/nodes.ts +2 -0
  118. package/src/content-fields/hubtype-fields/rating.ts +26 -0
  119. package/src/content-fields/index.ts +4 -0
  120. package/src/content-fields/whatsapp-button-list/flow-whatsapp-button-list-section.tsx +1 -1
  121. package/src/content-fields/whatsapp-button-list/flow-whatsapp-button-list.tsx +1 -1
  122. package/src/index.ts +7 -0
  123. package/src/tracking.ts +1 -0
  124. package/src/types.ts +43 -8
@@ -1,6 +1,5 @@
1
1
  import { FlowContent } from '../content-fields'
2
2
  import { FlowAiAgent } from '../content-fields/flow-ai-agent'
3
- import { AiAgentResponse } from '../types'
4
3
  import { FlowBuilderContext } from './index'
5
4
 
6
5
  export async function getContentsByAiAgent({
@@ -16,6 +15,7 @@ export async function getContentsByAiAgent({
16
15
 
17
16
  const contents =
18
17
  await flowBuilderPlugin.getContentsByNode(startNodeAiAgentFlow)
18
+
19
19
  const aiAgentContent = contents.find(
20
20
  content => content instanceof FlowAiAgent
21
21
  ) as FlowAiAgent
@@ -33,22 +33,15 @@ export async function getContentsByAiAgent({
33
33
  }
34
34
  )
35
35
 
36
- if (!aiAgentResponse || aiAgentResponse.role === 'exit') {
36
+ if (!aiAgentResponse) {
37
37
  return []
38
38
  }
39
39
 
40
- return updateContentsWithAiAgentResponse(contents, aiAgentResponse)
41
- }
40
+ if (aiAgentResponse.length === 1 && aiAgentResponse[0].type === 'exit') {
41
+ return []
42
+ }
42
43
 
43
- function updateContentsWithAiAgentResponse(
44
- contents: FlowContent[],
45
- aiAgentResponse: AiAgentResponse
46
- ): FlowContent[] {
47
- return contents.map(content => {
48
- if (content instanceof FlowAiAgent) {
49
- content.text = aiAgentResponse.content || ''
50
- }
44
+ aiAgentContent.responses = aiAgentResponse
51
45
 
52
- return content
53
- })
46
+ return contents
54
47
  }
@@ -125,6 +125,10 @@ async function getContents(
125
125
  return []
126
126
  }
127
127
 
128
+ if (request.input.payload?.startsWith('do-nothing')) {
129
+ request.input.payload = undefined
130
+ }
131
+
128
132
  if (request.input.payload || contentID) {
129
133
  const contentsByPayload = await getContentsByPayload(context)
130
134
  if (contentsByPayload.length > 0) {
@@ -1,13 +1,20 @@
1
+ import { storeCaseRating } from '@botonic/core'
2
+ import { v7 as uuid } from 'uuid'
3
+
4
+ import { AGENT_RATING_PAYLOAD, SEPARATOR } from '../constants'
1
5
  import { FlowContent } from '../content-fields'
2
6
  import { HtNodeWithContent } from '../content-fields/hubtype-fields'
7
+ import { EventAction, trackEvent } from '../tracking'
3
8
  import { FlowBuilderContext } from './index'
4
9
 
5
- export async function getContentsByPayload({
6
- cmsApi,
7
- flowBuilderPlugin,
8
- request,
9
- contentID,
10
- }: FlowBuilderContext): Promise<FlowContent[]> {
10
+ export async function getContentsByPayload(
11
+ context: FlowBuilderContext
12
+ ): Promise<FlowContent[]> {
13
+ const { cmsApi, flowBuilderPlugin, request, contentID } = context
14
+ if (request.input.payload?.startsWith(AGENT_RATING_PAYLOAD)) {
15
+ return await resolveRatingPayload(context)
16
+ }
17
+
11
18
  const id = contentID
12
19
  ? cmsApi.getNodeByContentID(contentID)?.id
13
20
  : request.input.payload
@@ -19,3 +26,46 @@ export async function getContentsByPayload({
19
26
 
20
27
  return []
21
28
  }
29
+
30
+ async function resolveRatingPayload(
31
+ context: FlowBuilderContext
32
+ ): Promise<FlowContent[]> {
33
+ const { cmsApi, flowBuilderPlugin, request } = context
34
+
35
+ if (!request.input.payload) {
36
+ return []
37
+ }
38
+
39
+ const id = request.input.payload
40
+ const buttonId = id?.split(SEPARATOR)[1]
41
+ const ratingNode = cmsApi.getRatingNodeByButtonId(buttonId)
42
+ const ratingButton = cmsApi.getRatingButtonById(ratingNode, buttonId)
43
+ const { target, text, value } = ratingButton
44
+ const possibleOptions = ratingNode.content.buttons.map(button => button.text)
45
+ const possibleValues = ratingNode.content.buttons.map(button => button.value)
46
+
47
+ if (request.session._hubtype_case_id) {
48
+ const event = {
49
+ action: EventAction.FeedbackCase,
50
+ feedbackTargetId: request.session._hubtype_case_id,
51
+ feedbackGroupId: uuid().toString(),
52
+ possibleOptions,
53
+ possibleValues,
54
+ option: text,
55
+ value,
56
+ }
57
+
58
+ await storeCaseRating(request.session, value)
59
+ await trackEvent(request, EventAction.FeedbackCase, event)
60
+ }
61
+
62
+ const targetNode = target
63
+ ? cmsApi.getNodeById<HtNodeWithContent>(target.id)
64
+ : undefined
65
+
66
+ if (targetNode) {
67
+ return await flowBuilderPlugin.getContentsByNode(targetNode)
68
+ }
69
+
70
+ return []
71
+ }
package/src/api.ts CHANGED
@@ -19,6 +19,8 @@ import {
19
19
  HtNodeWithContentType,
20
20
  HtNodeWithoutContentType,
21
21
  HtPayloadNode,
22
+ HtRatingButton,
23
+ HtRatingNode,
22
24
  } from './content-fields/hubtype-fields'
23
25
  import { HtSmartIntentNode } from './content-fields/hubtype-fields/smart-intent'
24
26
  import { FlowBuilderApiOptions, ProcessEnvNodeEnvs } from './types'
@@ -80,6 +82,32 @@ export class FlowBuilderApi {
80
82
  return node as T
81
83
  }
82
84
 
85
+ getRatingNodeByButtonId(id: string): HtRatingNode {
86
+ const ratingNodes = this.flow.nodes.filter(
87
+ node => node.type === HtNodeWithContentType.RATING
88
+ ) as HtRatingNode[]
89
+ const ratingNode = ratingNodes.find(node =>
90
+ node.content.buttons.some(button => button.id === id)
91
+ ) as HtRatingNode | undefined
92
+
93
+ if (!ratingNode) {
94
+ throw Error(`Rating node with button id: '${id}' not found`)
95
+ }
96
+
97
+ return ratingNode
98
+ }
99
+
100
+ getRatingButtonById(ratingNode: HtRatingNode, id: string): HtRatingButton {
101
+ const ratingButton = ratingNode.content.buttons.find(
102
+ button => button.id === id
103
+ ) as HtRatingButton | undefined
104
+ if (!ratingButton) {
105
+ throw Error(`Rating button with id: '${id}' not found`)
106
+ }
107
+
108
+ return ratingButton
109
+ }
110
+
83
111
  getNodeByContentID(contentID: string): HtNodeComponent {
84
112
  const content = this.flow.nodes.find(node =>
85
113
  'code' in node ? node.code === contentID : false
package/src/constants.ts CHANGED
@@ -8,6 +8,10 @@ export const REG_EXP_PATTERN = /^\/(.*)\/([gimyus]*)$/
8
8
  export const UUID_REGEXP =
9
9
  /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
10
10
 
11
+ /* ********** PAYLOADS ********** */
12
+ export const AGENT_RATING_PAYLOAD = 'agent-rating'
13
+
14
+ /* ********** FLOW NAMES ********** */
11
15
  export const MAIN_FLOW_NAME = 'Main'
12
16
  export const KNOWLEDGE_BASE_FLOW_NAME = 'Knowledge base'
13
17
  export const AI_AGENTS_FLOW_NAME = 'AI Agents'
@@ -1,6 +1,9 @@
1
- import { Text } from '@botonic/react'
1
+ import { Button, Carousel, Text } from '@botonic/react'
2
2
 
3
+ import { SOURCE_INFO_SEPARATOR } from '../constants'
4
+ import { AgenticOutputMessage } from '../types'
3
5
  import { ContentFieldsBase } from './content-fields-base'
6
+ import { FlowElement } from './flow-element'
4
7
  import { HtAiAgentNode } from './hubtype-fields/ai-agent'
5
8
 
6
9
  export class FlowAiAgent extends ContentFieldsBase {
@@ -8,7 +11,8 @@ export class FlowAiAgent extends ContentFieldsBase {
8
11
  public name: string = ''
9
12
  public instructions: string = ''
10
13
  public activeTools?: { name: string }[]
11
- public text: string = ''
14
+
15
+ public responses: AgenticOutputMessage[] = []
12
16
 
13
17
  static fromHubtypeCMS(component: HtAiAgentNode): FlowAiAgent {
14
18
  const newAiAgent = new FlowAiAgent(component.id)
@@ -20,6 +24,42 @@ export class FlowAiAgent extends ContentFieldsBase {
20
24
  }
21
25
 
22
26
  toBotonic(id: string): JSX.Element {
23
- return <Text key={id}>{this.text}</Text>
27
+ return (
28
+ <>
29
+ {this.responses.map(response => {
30
+ if (response.type === 'text') {
31
+ return <Text key={id}>{response.content.text}</Text>
32
+ }
33
+
34
+ if (response.type === 'textWithButtons') {
35
+ return (
36
+ <Text key={id}>
37
+ {response.content.text}
38
+ {response.content.buttons.map((button, buttonIndex) => (
39
+ <Button
40
+ key={buttonIndex}
41
+ payload={`do-nothing${SOURCE_INFO_SEPARATOR}${buttonIndex}`}
42
+ >
43
+ {button}
44
+ </Button>
45
+ ))}
46
+ </Text>
47
+ )
48
+ }
49
+
50
+ if (response.type === 'carousel') {
51
+ return (
52
+ <Carousel key={id}>
53
+ {response.content.elements.map(element =>
54
+ FlowElement.fromAIAgent(id, element).toBotonic(id)
55
+ )}
56
+ </Carousel>
57
+ )
58
+ }
59
+
60
+ return <></>
61
+ })}
62
+ </>
63
+ )
24
64
  }
25
65
  }
@@ -5,6 +5,7 @@ import { FlowBuilderApi } from '../api'
5
5
  import { SOURCE_INFO_SEPARATOR } from '../constants'
6
6
  import { ContentFieldsBase } from './content-fields-base'
7
7
  import { HtButton, HtButtonStyle, HtUrlNode } from './hubtype-fields'
8
+ import { HtRatingButton } from './hubtype-fields/rating'
8
9
 
9
10
  export class FlowButton extends ContentFieldsBase {
10
11
  public text = ''
@@ -34,6 +35,27 @@ export class FlowButton extends ContentFieldsBase {
34
35
  return newButton
35
36
  }
36
37
 
38
+ static fromAIAgent(button: {
39
+ id: string
40
+ text: string
41
+ payload?: string
42
+ url?: string
43
+ }): FlowButton {
44
+ const newButton = new FlowButton(button.id)
45
+ newButton.text = button.text
46
+ newButton.payload = button.payload
47
+ newButton.url = button.url
48
+ return newButton
49
+ }
50
+
51
+ static fromRating(button: HtRatingButton): FlowButton {
52
+ const newButton = new FlowButton(button.id)
53
+ newButton.text = button.text
54
+ newButton.payload = button.payload
55
+ newButton.target = button.target?.id
56
+ return newButton
57
+ }
58
+
37
59
  static getUrlId(cmsButton: HtButton, locale: string): string | undefined {
38
60
  return cmsButton.url.find(url => url.locale === locale)?.id
39
61
  }
@@ -30,6 +30,27 @@ export class FlowElement extends ContentFieldsBase {
30
30
  return newElement
31
31
  }
32
32
 
33
+ static fromAIAgent(
34
+ id: string,
35
+ element: {
36
+ title: string
37
+ subtitle: string
38
+ image: string
39
+ button: { text: string; url: string }
40
+ }
41
+ ) {
42
+ const newElement = new FlowElement(id)
43
+ newElement.title = element.title
44
+ newElement.subtitle = element.subtitle
45
+ newElement.image = element.image
46
+ newElement.button = FlowButton.fromAIAgent({
47
+ id: '',
48
+ text: element.button.text,
49
+ url: element.button.url,
50
+ })
51
+ return newElement
52
+ }
53
+
33
54
  toBotonic(parentId: string): JSX.Element {
34
55
  return (
35
56
  <Element key={`${parentId}-${this.id}`}>
@@ -0,0 +1,92 @@
1
+ import { isDev, isWebchat, isWhatsapp } from '@botonic/core'
2
+ import {
3
+ ActionRequest,
4
+ CustomRatingMessage,
5
+ Text,
6
+ WhatsappButtonList,
7
+ } from '@botonic/react'
8
+
9
+ import { getFlowBuilderPlugin } from '../helpers'
10
+ import { ContentFieldsBase } from './content-fields-base'
11
+ import { FlowButton } from './flow-button'
12
+ import { HtRatingNode, RatingType } from './hubtype-fields'
13
+
14
+ export class FlowRating extends ContentFieldsBase {
15
+ public code = ''
16
+ public text = ''
17
+ public sendButtonText = ''
18
+ public ratingType = RatingType.Stars
19
+ public buttons: FlowButton[] = []
20
+ public openListButtonText = ''
21
+
22
+ static fromHubtypeCMS(cmsText: HtRatingNode, locale: string): FlowRating {
23
+ const newRating = new FlowRating(cmsText.id)
24
+ newRating.code = cmsText.code
25
+ newRating.text = this.getTextByLocale(locale, cmsText.content.text)
26
+ newRating.sendButtonText = this.getTextByLocale(
27
+ locale,
28
+ cmsText.content.send_button_text
29
+ )
30
+ newRating.ratingType = cmsText.content.rating_type
31
+ newRating.buttons = cmsText.content.buttons.map(button =>
32
+ FlowButton.fromRating(button)
33
+ )
34
+ newRating.openListButtonText = this.getTextByLocale(
35
+ locale,
36
+ cmsText.content.open_list_button_text
37
+ )
38
+
39
+ return newRating
40
+ }
41
+
42
+ toBotonic(id: string, request: ActionRequest): JSX.Element {
43
+ const flowBuilderPlugin = getFlowBuilderPlugin(request.plugins)
44
+ const customRatingMessageEnabled =
45
+ flowBuilderPlugin.customRatingMessageEnabled
46
+
47
+ if (isWhatsapp(request.session)) {
48
+ return (
49
+ <WhatsappButtonList
50
+ body={this.text}
51
+ button={this.openListButtonText}
52
+ sections={[
53
+ {
54
+ rows: this.buttons.map(button => ({
55
+ id: button.payload as string,
56
+ title: button.text,
57
+ })),
58
+ },
59
+ ]}
60
+ />
61
+ )
62
+ }
63
+
64
+ if (
65
+ (isWebchat(request.session) || isDev(request.session)) &&
66
+ customRatingMessageEnabled
67
+ ) {
68
+ const payloads = this.buttons
69
+ .map(button => button.payload)
70
+ .slice()
71
+ .reverse()
72
+
73
+ return (
74
+ <CustomRatingMessage
75
+ payloads={payloads}
76
+ messageText={this.text}
77
+ buttonText={this.sendButtonText}
78
+ ratingType={this.ratingType}
79
+ />
80
+ )
81
+ }
82
+
83
+ return (
84
+ <Text key={id}>
85
+ {this.text}
86
+ {this.buttons.map((button, buttonIndex) =>
87
+ button.renderButton(buttonIndex)
88
+ )}
89
+ </Text>
90
+ )
91
+ }
92
+ }
@@ -12,6 +12,7 @@ export * from './knowledge-base'
12
12
  export * from './node-types'
13
13
  export * from './nodes'
14
14
  export * from './payload'
15
+ export * from './rating'
15
16
  export * from './smart-intent'
16
17
  export * from './text'
17
18
  export * from './url'
@@ -13,6 +13,7 @@ export enum HtNodeWithContentType {
13
13
  KNOWLEDGE_BASE = 'knowledge-base',
14
14
  BOT_ACTION = 'bot-action',
15
15
  AI_AGENT = 'ai-agent',
16
+ RATING = 'rating',
16
17
  }
17
18
 
18
19
  export enum HtNodeWithoutContentType {
@@ -9,6 +9,7 @@ import { HtImageNode } from './image'
9
9
  import { HtKeywordNode } from './keyword'
10
10
  import { HtKnowledgeBaseNode } from './knowledge-base'
11
11
  import { HtPayloadNode } from './payload'
12
+ import { HtRatingNode } from './rating'
12
13
  import { HtSmartIntentNode } from './smart-intent'
13
14
  import { HtTextNode } from './text'
14
15
  import { HtUrlNode } from './url'
@@ -31,6 +32,7 @@ export type HtNodeWithContent =
31
32
  | HtKnowledgeBaseNode
32
33
  | HtBotActionNode
33
34
  | HtAiAgentNode
35
+ | HtRatingNode
34
36
 
35
37
  export type HtNodeWithoutContent = HtUrlNode | HtPayloadNode | HtGoToFlow
36
38
 
@@ -0,0 +1,26 @@
1
+ import { HtBaseNode, HtNodeLink, HtTextLocale } from './common'
2
+ import { HtNodeWithContentType } from './node-types'
3
+
4
+ export enum RatingType {
5
+ Stars = 'stars',
6
+ Smileys = 'smileys',
7
+ }
8
+
9
+ export interface HtRatingButton {
10
+ id: string
11
+ text: string
12
+ payload: string
13
+ value: number
14
+ target?: HtNodeLink
15
+ }
16
+
17
+ export interface HtRatingNode extends HtBaseNode {
18
+ type: HtNodeWithContentType.RATING
19
+ content: {
20
+ text: HtTextLocale[]
21
+ buttons: HtRatingButton[]
22
+ rating_type: RatingType
23
+ send_button_text: HtTextLocale[]
24
+ open_list_button_text: HtTextLocale[]
25
+ }
26
+ }
@@ -7,10 +7,12 @@ import {
7
7
  DISABLED_MEMORY_LENGTH,
8
8
  FlowKnowledgeBase,
9
9
  } from './flow-knowledge-base'
10
+ import { FlowRating } from './flow-rating'
10
11
  import { FlowText } from './flow-text'
11
12
  import { FlowVideo } from './flow-video'
12
13
  import { FlowWhatsappCtaUrlButtonNode } from './flow-whatsapp-cta-url-button'
13
14
  import { FlowWhatsappButtonList } from './whatsapp-button-list/flow-whatsapp-button-list'
15
+
14
16
  export { ContentFieldsBase } from './content-fields-base'
15
17
  export { FlowButton } from './flow-button'
16
18
  export { FlowElement } from './flow-element'
@@ -21,6 +23,7 @@ export {
21
23
  FlowHandoff,
22
24
  FlowImage,
23
25
  FlowKnowledgeBase,
26
+ FlowRating,
24
27
  FlowText,
25
28
  FlowVideo,
26
29
  FlowWhatsappButtonList,
@@ -38,5 +41,6 @@ export type FlowContent =
38
41
  | FlowKnowledgeBase
39
42
  | FlowBotAction
40
43
  | FlowAiAgent
44
+ | FlowRating
41
45
 
42
46
  export { DISABLED_MEMORY_LENGTH }
@@ -4,8 +4,8 @@ import {
4
4
  } from '@botonic/react'
5
5
 
6
6
  import { FlowBuilderApi } from '../../api'
7
+ import { ContentFieldsBase } from '../content-fields-base'
7
8
  import { HtWhatsappButtonListSection } from '../hubtype-fields'
8
- import { ContentFieldsBase } from './../content-fields-base'
9
9
  import { FlowWhatsappButtonListRow } from './flow-whatsapp-button-list-row'
10
10
 
11
11
  export class FlowWhatsappButtonListSection extends ContentFieldsBase {
@@ -2,8 +2,8 @@ import { WhatsappButtonList } from '@botonic/react'
2
2
  import React from 'react'
3
3
 
4
4
  import { FlowBuilderApi } from '../../api'
5
+ import { ContentFieldsBase } from '../content-fields-base'
5
6
  import { HtWhatsappButtonListNode } from '../hubtype-fields'
6
- import { ContentFieldsBase } from './../content-fields-base'
7
7
  import { FlowWhatsappButtonListSection } from './flow-whatsapp-button-list-section'
8
8
 
9
9
  export class FlowWhatsappButtonList extends ContentFieldsBase {
package/src/index.ts CHANGED
@@ -21,6 +21,7 @@ import {
21
21
  FlowHandoff,
22
22
  FlowImage,
23
23
  FlowKnowledgeBase,
24
+ FlowRating,
24
25
  FlowText,
25
26
  FlowVideo,
26
27
  FlowWhatsappButtonList,
@@ -69,6 +70,7 @@ export default class BotonicPluginFlowBuilder implements Plugin {
69
70
  // TODO: Rethink how we construct FlowBuilderApi to be simpler
70
71
  public jsonVersion: FlowBuilderJSONVersion
71
72
  public apiUrl: string
73
+ public customRatingMessageEnabled: boolean
72
74
 
73
75
  constructor(options: BotonicPluginFlowBuilderOptions<ResolvedPlugins, any>) {
74
76
  this.apiUrl = options.apiUrl || FLOW_BUILDER_API_URL_PROD
@@ -90,6 +92,8 @@ export default class BotonicPluginFlowBuilder implements Plugin {
90
92
  allowKnowledgeBases: options.inShadowing?.allowKnowledgeBases || false,
91
93
  }
92
94
  this.contentFilters = options.contentFilters || []
95
+ this.customRatingMessageEnabled =
96
+ options.customRatingMessageEnabled || false
93
97
  }
94
98
 
95
99
  resolveFlowUrl(request: PluginPreRequest): string {
@@ -240,6 +244,9 @@ export default class BotonicPluginFlowBuilder implements Plugin {
240
244
  case HtNodeWithContentType.AI_AGENT:
241
245
  return FlowAiAgent.fromHubtypeCMS(hubtypeContent)
242
246
 
247
+ case HtNodeWithContentType.RATING:
248
+ return FlowRating.fromHubtypeCMS(hubtypeContent, locale)
249
+
243
250
  case HtNodeWithContentType.BOT_ACTION:
244
251
  return FlowBotAction.fromHubtypeCMS(hubtypeContent, locale, this.cmsApi)
245
252
 
package/src/tracking.ts CHANGED
@@ -14,6 +14,7 @@ export enum EventAction {
14
14
  IntentSmart = 'nlu_intent_smart',
15
15
  Knowledgebase = 'knowledgebase',
16
16
  Fallback = 'fallback',
17
+ FeedbackCase = 'feedback_case',
17
18
  }
18
19
 
19
20
  export enum KnowledgebaseFailReason {
package/src/types.ts CHANGED
@@ -24,6 +24,7 @@ export interface BotonicPluginFlowBuilderOptions<
24
24
  smartIntentsConfig?: { numSmartIntentsToUse: number }
25
25
  inShadowing?: Partial<InShadowingConfig>
26
26
  contentFilters?: ContentFilter<TPlugins, TExtraData>[]
27
+ customRatingMessageEnabled?: boolean
27
28
  }
28
29
 
29
30
  export type TrackEventFunction<
@@ -52,7 +53,7 @@ export type AiAgentFunction<
52
53
  > = (
53
54
  request: BotContext<TPlugins, TExtraData>,
54
55
  aiAgentArgs: AiAgentArgs
55
- ) => Promise<AiAgentResponse | undefined>
56
+ ) => Promise<AgenticOutputMessage[] | undefined>
56
57
 
57
58
  export interface AiAgentArgs {
58
59
  name: string
@@ -93,13 +94,6 @@ export interface KnowledgeBaseResponse {
93
94
  answer: string
94
95
  }
95
96
 
96
- export interface AiAgentResponse {
97
- role: string
98
- content?: string
99
- toolName?: string
100
- toolOutput?: string | null
101
- }
102
-
103
97
  export interface SmartIntentResponse {
104
98
  data: {
105
99
  smart_intent_title: string
@@ -114,3 +108,44 @@ export interface SmartIntentResponse {
114
108
  export interface PayloadParamsBase {
115
109
  followUpContentID?: string
116
110
  }
111
+
112
+ export interface OutputBaseMessage {
113
+ type: 'text' | 'textWithButtons' | 'carousel' | 'exit'
114
+ }
115
+
116
+ export interface TextMessage extends OutputBaseMessage {
117
+ type: 'text'
118
+ content: {
119
+ text: string
120
+ }
121
+ }
122
+
123
+ export interface TextWithButtonsMessage extends OutputBaseMessage {
124
+ type: 'textWithButtons'
125
+ content: {
126
+ text: string
127
+ buttons: string[]
128
+ }
129
+ }
130
+
131
+ export interface CarouselMessage extends OutputBaseMessage {
132
+ type: 'carousel'
133
+ content: {
134
+ elements: {
135
+ title: string
136
+ subtitle: string
137
+ image: string
138
+ button: { text: string; url: string }
139
+ }[]
140
+ }
141
+ }
142
+
143
+ export interface ExitMessage extends OutputBaseMessage {
144
+ type: 'exit'
145
+ }
146
+
147
+ export type AgenticOutputMessage =
148
+ | TextMessage
149
+ | TextWithButtonsMessage
150
+ | CarouselMessage
151
+ | ExitMessage