@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
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { BotContext } from '@botonic/core'
|
|
2
|
+
|
|
3
|
+
import { trackOneContent } from '../tracking'
|
|
4
|
+
import { ContentFieldsBase } from './content-fields-base'
|
|
5
|
+
import type { HtDoNothingNode } from './hubtype-fields'
|
|
6
|
+
|
|
7
|
+
export class FlowDoNothing extends ContentFieldsBase {
|
|
8
|
+
static fromHubtypeCMS(cmsDoNothing: HtDoNothingNode): FlowDoNothing {
|
|
9
|
+
const newDoNothing = new FlowDoNothing(cmsDoNothing.id)
|
|
10
|
+
newDoNothing.code = cmsDoNothing.code
|
|
11
|
+
newDoNothing.followUp = cmsDoNothing.follow_up
|
|
12
|
+
|
|
13
|
+
return newDoNothing
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async trackFlow(botContext: BotContext): Promise<void> {
|
|
17
|
+
await trackOneContent(botContext, this)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async processContent(botContext: BotContext): Promise<void> {
|
|
21
|
+
await this.filterContent(botContext, this)
|
|
22
|
+
await this.trackFlow(botContext)
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
toBotonic(): JSX.Element {
|
|
27
|
+
return <></>
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -6,17 +6,27 @@ import {
|
|
|
6
6
|
isWebchat,
|
|
7
7
|
} from '@botonic/core'
|
|
8
8
|
import { WebchatSettings } from '@botonic/react'
|
|
9
|
-
|
|
10
9
|
import type { FlowBuilderApi } from '../api'
|
|
10
|
+
import { ON_CLOSE_HANDOFF_PAYLOAD, SEPARATOR } from '../constants'
|
|
11
11
|
import { getCommonFlowContentEventArgsForContentId } from '../tracking'
|
|
12
12
|
import { ContentFieldsBase } from './content-fields-base'
|
|
13
|
-
import
|
|
13
|
+
import {
|
|
14
|
+
DiscardType,
|
|
15
|
+
type HtHandoffNode,
|
|
16
|
+
type HtNodeLink,
|
|
17
|
+
type HtQueueLocale,
|
|
18
|
+
} from './hubtype-fields'
|
|
14
19
|
|
|
15
20
|
export class FlowHandoff extends ContentFieldsBase {
|
|
16
21
|
public queue?: HtQueueLocale
|
|
17
22
|
public onFinishPayload?: string
|
|
18
23
|
public handoffAutoAssign: boolean
|
|
19
24
|
public hasQueuePositionChangedNotificationsEnabled: boolean
|
|
25
|
+
public hasDifferentiatedCloseTypes: boolean
|
|
26
|
+
public resolvedByAgent?: HtNodeLink
|
|
27
|
+
public discardedByAgent?: HtNodeLink
|
|
28
|
+
public discardedByUser?: HtNodeLink
|
|
29
|
+
public discardedBySystem?: HtNodeLink
|
|
20
30
|
public isTestIntegration: boolean
|
|
21
31
|
|
|
22
32
|
static fromHubtypeCMS(
|
|
@@ -30,14 +40,21 @@ export class FlowHandoff extends ContentFieldsBase {
|
|
|
30
40
|
locale,
|
|
31
41
|
cmsHandoff.content.queue
|
|
32
42
|
)
|
|
43
|
+
newHandoff.hasDifferentiatedCloseTypes =
|
|
44
|
+
cmsHandoff.content.has_differentiated_close_types
|
|
45
|
+
newHandoff.resolvedByAgent = cmsHandoff.content.resolved_by_agent
|
|
46
|
+
newHandoff.discardedByAgent = cmsHandoff.content.discarded_by_agent
|
|
47
|
+
newHandoff.discardedByUser = cmsHandoff.content.discarded_by_user
|
|
48
|
+
newHandoff.discardedBySystem = cmsHandoff.content.discarded_by_system
|
|
49
|
+
newHandoff.handoffAutoAssign = cmsHandoff.content.has_auto_assign
|
|
50
|
+
newHandoff.hasQueuePositionChangedNotificationsEnabled =
|
|
51
|
+
cmsHandoff.content.has_queue_position_changed_notifications_enabled
|
|
52
|
+
|
|
33
53
|
newHandoff.onFinishPayload = FlowHandoff.getOnFinishPayload(
|
|
34
54
|
cmsHandoff,
|
|
35
55
|
cmsApi
|
|
36
56
|
)
|
|
37
|
-
newHandoff.
|
|
38
|
-
newHandoff.hasQueuePositionChangedNotificationsEnabled =
|
|
39
|
-
cmsHandoff.content.has_queue_position_changed_notifications_enabled
|
|
40
|
-
newHandoff.followUp = cmsHandoff.follow_up
|
|
57
|
+
newHandoff.followUp = undefined
|
|
41
58
|
|
|
42
59
|
return newHandoff
|
|
43
60
|
}
|
|
@@ -46,13 +63,43 @@ export class FlowHandoff extends ContentFieldsBase {
|
|
|
46
63
|
cmsHandoff: HtHandoffNode,
|
|
47
64
|
cmsApi: FlowBuilderApi
|
|
48
65
|
): string | undefined {
|
|
49
|
-
if (cmsHandoff.
|
|
66
|
+
if (cmsHandoff.content.has_differentiated_close_types) {
|
|
67
|
+
return `${ON_CLOSE_HANDOFF_PAYLOAD}${SEPARATOR}${cmsHandoff.id}`
|
|
68
|
+
} else if (cmsHandoff.target?.id) {
|
|
50
69
|
return cmsApi.getPayload(cmsHandoff.target)
|
|
51
70
|
}
|
|
52
71
|
|
|
53
72
|
return undefined
|
|
54
73
|
}
|
|
55
74
|
|
|
75
|
+
resolveOnClosePayload(botContext: BotContext): string {
|
|
76
|
+
const contactReasons =
|
|
77
|
+
botContext.session._hubtype_case_contact_reasons || []
|
|
78
|
+
|
|
79
|
+
if (contactReasons.some(reason => reason.name === DiscardType.ByAgent)) {
|
|
80
|
+
if (this.discardedByAgent?.id) {
|
|
81
|
+
return this.discardedByAgent.id
|
|
82
|
+
}
|
|
83
|
+
console.error('No discarded by agent target found')
|
|
84
|
+
}
|
|
85
|
+
if (contactReasons.some(reason => reason.name === DiscardType.ByUser)) {
|
|
86
|
+
if (this.discardedByUser?.id) {
|
|
87
|
+
return this.discardedByUser.id
|
|
88
|
+
}
|
|
89
|
+
console.error('No discarded by user target found')
|
|
90
|
+
}
|
|
91
|
+
if (contactReasons.some(reason => reason.name === DiscardType.BySystem)) {
|
|
92
|
+
if (this.discardedBySystem?.id) {
|
|
93
|
+
return this.discardedBySystem.id
|
|
94
|
+
}
|
|
95
|
+
console.error('No discarded by system target found')
|
|
96
|
+
}
|
|
97
|
+
if (this.resolvedByAgent?.id) {
|
|
98
|
+
return this.resolvedByAgent.id
|
|
99
|
+
}
|
|
100
|
+
throw new Error('No resolved by agent target found')
|
|
101
|
+
}
|
|
102
|
+
|
|
56
103
|
async doHandoff(botContext: BotContext): Promise<void> {
|
|
57
104
|
const handOffBuilder = new HandOffBuilder(botContext.session)
|
|
58
105
|
handOffBuilder.withAutoAssignOnWaiting(this.handoffAutoAssign)
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type BotContext,
|
|
3
|
+
isWhatsapp,
|
|
4
|
+
type RequestContactInfoMessage,
|
|
5
|
+
} from '@botonic/core'
|
|
2
6
|
import { Text, WhatsappRequestContactInfo } from '@botonic/react'
|
|
3
7
|
|
|
4
8
|
import { trackOneContent } from '../tracking'
|
|
@@ -26,6 +30,20 @@ export class FlowWhatsappRequestContactInfoNode extends ContentFieldsBase {
|
|
|
26
30
|
return requestContactInfo
|
|
27
31
|
}
|
|
28
32
|
|
|
33
|
+
static fromAIAgent(
|
|
34
|
+
id: string,
|
|
35
|
+
message: RequestContactInfoMessage,
|
|
36
|
+
botContext: BotContext
|
|
37
|
+
): JSX.Element {
|
|
38
|
+
botContext.session.whatsapp_request_contact = undefined
|
|
39
|
+
|
|
40
|
+
if (!isWhatsapp(botContext.session)) {
|
|
41
|
+
return <Text key={id}>{message.content.text}</Text>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return <WhatsappRequestContactInfo key={id} body={message.content.text} />
|
|
45
|
+
}
|
|
46
|
+
|
|
29
47
|
async trackFlow(botContext: BotContext): Promise<void> {
|
|
30
48
|
await trackOneContent(botContext, this)
|
|
31
49
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { HtBaseNode, HtNodeLink } from './common'
|
|
2
|
+
import type { HtNodeWithContentType } from './node-types'
|
|
3
|
+
|
|
4
|
+
export interface HtContactReasonBranch {
|
|
5
|
+
id: string
|
|
6
|
+
name: string
|
|
7
|
+
project_id: string
|
|
8
|
+
project_name: string
|
|
9
|
+
target: HtNodeLink
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface HtContactReasonsNode extends HtBaseNode {
|
|
13
|
+
type: HtNodeWithContentType.CONTACT_REASONS_CONDITION
|
|
14
|
+
content: {
|
|
15
|
+
contact_reasons: HtContactReasonBranch[]
|
|
16
|
+
default_target: HtNodeLink
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
HtBaseNode,
|
|
3
|
+
HtNodeLink,
|
|
4
|
+
HtPayloadLocale,
|
|
5
|
+
HtQueueLocale,
|
|
6
|
+
} from './common'
|
|
2
7
|
import type { HtNodeWithContentType } from './node-types'
|
|
3
8
|
|
|
9
|
+
export enum DiscardType {
|
|
10
|
+
ByAgent = 'discarded',
|
|
11
|
+
ByUser = 'discarded_by_user',
|
|
12
|
+
BySystem = 'discarded_by_system',
|
|
13
|
+
}
|
|
14
|
+
|
|
4
15
|
export interface HtHandoffNode extends HtBaseNode {
|
|
5
16
|
type: HtNodeWithContentType.HANDOFF
|
|
6
17
|
content: {
|
|
@@ -8,5 +19,10 @@ export interface HtHandoffNode extends HtBaseNode {
|
|
|
8
19
|
payload: HtPayloadLocale[]
|
|
9
20
|
has_auto_assign: boolean
|
|
10
21
|
has_queue_position_changed_notifications_enabled: boolean
|
|
22
|
+
has_differentiated_close_types: boolean
|
|
23
|
+
resolved_by_agent?: HtNodeLink
|
|
24
|
+
discarded_by_agent?: HtNodeLink
|
|
25
|
+
discarded_by_user?: HtNodeLink
|
|
26
|
+
discarded_by_system?: HtNodeLink
|
|
11
27
|
}
|
|
12
28
|
}
|
|
@@ -20,6 +20,8 @@ export enum HtNodeWithContentType {
|
|
|
20
20
|
GO_TO_FLOW = 'go-to-flow',
|
|
21
21
|
CAPTURE_USER_INPUT = 'capture-user-input',
|
|
22
22
|
CUSTOM_CONDITION = 'custom-condition',
|
|
23
|
+
DO_NOTHING = 'do-nothing',
|
|
24
|
+
CONTACT_REASONS_CONDITION = 'contact-reasons-condition',
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
export enum HtNodeWithoutContentType {
|
|
@@ -3,7 +3,9 @@ import type { HtAiAgentRouterNode } from './ai-agent-router'
|
|
|
3
3
|
import type { HtBotActionNode } from './bot-action'
|
|
4
4
|
import type { HtCaptureUserInputNode } from './capture-user-input'
|
|
5
5
|
import type { HtCarouselNode } from './carousel'
|
|
6
|
+
import type { HtContactReasonsNode } from './contact-reasons-conditional'
|
|
6
7
|
import type { HtCustomConditionalV2Node } from './custom-conditional-v2'
|
|
8
|
+
import type { HtDoNothingNode } from './do-nothing'
|
|
7
9
|
// import { HtChannelConditionalNode } from './channel-conditional'
|
|
8
10
|
// import { HtCountryConditionalNode } from './country-conditional'
|
|
9
11
|
// import { HtCustomConditionalNode } from './custom-conditional'
|
|
@@ -48,6 +50,8 @@ export type HtNodeWithContent =
|
|
|
48
50
|
| HtWhatsappTemplateNode
|
|
49
51
|
| HtCaptureUserInputNode
|
|
50
52
|
| HtCustomConditionalV2Node
|
|
53
|
+
| HtDoNothingNode
|
|
54
|
+
| HtContactReasonsNode
|
|
51
55
|
// | HtChannelConditionalNode
|
|
52
56
|
// | HtCountryConditionalNode
|
|
53
57
|
// | HtCustomConditionalNode
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { HtButton } from './button'
|
|
1
2
|
import type { HtBaseNode, HtTextLocale } from './common'
|
|
2
3
|
import type { HtNodeWithContentType } from './node-types'
|
|
3
4
|
|
|
@@ -5,5 +6,6 @@ export interface HtWhatsappRequestContactInfoNode extends HtBaseNode {
|
|
|
5
6
|
type: HtNodeWithContentType.WHATSAPP_REQUEST_CONTACT_INFO
|
|
6
7
|
content: {
|
|
7
8
|
text: HtTextLocale[]
|
|
9
|
+
button: HtButton
|
|
8
10
|
}
|
|
9
11
|
}
|
|
@@ -5,8 +5,10 @@ import { FlowBotAction } from './flow-bot-action'
|
|
|
5
5
|
import { FlowCaptureUserInput } from './flow-capture-user-input'
|
|
6
6
|
import { FlowCarousel } from './flow-carousel'
|
|
7
7
|
import { FlowChannelConditional } from './flow-channel-conditional'
|
|
8
|
+
import { FlowContactReasonsConditional } from './flow-contact-reasons-conditional'
|
|
8
9
|
import { FlowCountryConditional } from './flow-country-conditional'
|
|
9
10
|
import { FlowCustomConditional } from './flow-custom-conditional'
|
|
11
|
+
import { FlowDoNothing } from './flow-do-nothing'
|
|
10
12
|
import { FlowGoToFlow } from './flow-go-to-flow'
|
|
11
13
|
import { FlowHandoff } from './flow-handoff'
|
|
12
14
|
import { FlowImage } from './flow-image'
|
|
@@ -33,9 +35,11 @@ export {
|
|
|
33
35
|
FlowCaptureUserInput,
|
|
34
36
|
FlowCarousel,
|
|
35
37
|
FlowChannelConditional,
|
|
38
|
+
FlowContactReasonsConditional,
|
|
36
39
|
FlowCountryConditional,
|
|
37
40
|
FlowCustomConditional,
|
|
38
41
|
FlowCustomConditionalV2,
|
|
42
|
+
FlowDoNothing,
|
|
39
43
|
FlowGoToFlow,
|
|
40
44
|
FlowHandoff,
|
|
41
45
|
FlowImage,
|
|
@@ -72,3 +76,5 @@ export type FlowContent =
|
|
|
72
76
|
| FlowCaptureUserInput
|
|
73
77
|
| FlowAiAgentRouter
|
|
74
78
|
| FlowCustomConditionalV2
|
|
79
|
+
| FlowDoNothing
|
|
80
|
+
| FlowContactReasonsConditional
|
package/src/flow-factory.ts
CHANGED
|
@@ -7,10 +7,12 @@ import {
|
|
|
7
7
|
FlowBotAction,
|
|
8
8
|
FlowCarousel,
|
|
9
9
|
FlowChannelConditional,
|
|
10
|
+
FlowContactReasonsConditional,
|
|
10
11
|
type FlowContent,
|
|
11
12
|
FlowCountryConditional,
|
|
12
13
|
FlowCustomConditional,
|
|
13
14
|
FlowCustomConditionalV2,
|
|
15
|
+
FlowDoNothing,
|
|
14
16
|
FlowGoToFlow,
|
|
15
17
|
FlowHandoff,
|
|
16
18
|
FlowImage,
|
|
@@ -118,6 +120,15 @@ export class FlowFactory {
|
|
|
118
120
|
this.botContext
|
|
119
121
|
)
|
|
120
122
|
|
|
123
|
+
case HtNodeWithContentType.DO_NOTHING:
|
|
124
|
+
return FlowDoNothing.fromHubtypeCMS(hubtypeContent)
|
|
125
|
+
|
|
126
|
+
case HtNodeWithContentType.CONTACT_REASONS_CONDITION:
|
|
127
|
+
return FlowContactReasonsConditional.fromHubtypeCMS(
|
|
128
|
+
hubtypeContent,
|
|
129
|
+
this.botContext
|
|
130
|
+
)
|
|
131
|
+
|
|
121
132
|
default:
|
|
122
133
|
return undefined
|
|
123
134
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,24 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
type ResolvedPlugins,
|
|
7
|
-
type Session,
|
|
1
|
+
import type {
|
|
2
|
+
BotContext,
|
|
3
|
+
Plugin,
|
|
4
|
+
ResolvedPlugins,
|
|
5
|
+
Session,
|
|
8
6
|
} from '@botonic/core'
|
|
9
|
-
import type { ActionRequest } from '@botonic/react'
|
|
10
7
|
import { v7 as uuidv7 } from 'uuid'
|
|
11
8
|
|
|
12
9
|
import { FlowBuilderApi } from './api'
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
FLOW_BUILDER_API_URL_PROD,
|
|
16
|
-
SEPARATOR,
|
|
17
|
-
SOURCE_INFO_SEPARATOR,
|
|
18
|
-
} from './constants'
|
|
10
|
+
import { BotContextManager } from './bot-context-manager'
|
|
11
|
+
import { FLOW_BUILDER_API_URL_PROD, SEPARATOR } from './constants'
|
|
19
12
|
import type { FlowContent } from './content-fields'
|
|
20
13
|
import {
|
|
21
|
-
type HtBotActionNode,
|
|
22
14
|
type HtFlowBuilderData,
|
|
23
15
|
type HtNodeWithContent,
|
|
24
16
|
HtNodeWithContentType,
|
|
@@ -35,10 +27,8 @@ import {
|
|
|
35
27
|
type RatingSubmittedInfo,
|
|
36
28
|
type TrackEventFunction,
|
|
37
29
|
} from './types'
|
|
38
|
-
import { getNextPayloadByUserInput } from './user-input'
|
|
39
30
|
import type { SmartIntentsInferenceConfig } from './user-input/smart-intent'
|
|
40
31
|
import { resolveGetAccessToken } from './utils/authentication'
|
|
41
|
-
import { inputHasTextOrTranscript } from './utils/input'
|
|
42
32
|
|
|
43
33
|
// TODO: Create a proper service to wrap all calls and allow api versioning
|
|
44
34
|
|
|
@@ -46,7 +36,7 @@ export default class BotonicPluginFlowBuilder implements Plugin {
|
|
|
46
36
|
public cmsApi: FlowBuilderApi
|
|
47
37
|
private flow?: HtFlowBuilderData
|
|
48
38
|
private functions: Record<any, any>
|
|
49
|
-
private
|
|
39
|
+
private botContext: BotContext
|
|
50
40
|
public getAccessToken: (session: Session) => string
|
|
51
41
|
public trackEvent?: TrackEventFunction
|
|
52
42
|
public getAiAgentResponse?: AiAgentFunction
|
|
@@ -85,85 +75,33 @@ export default class BotonicPluginFlowBuilder implements Plugin {
|
|
|
85
75
|
options.disableAIAgentInFirstInteraction || false
|
|
86
76
|
}
|
|
87
77
|
|
|
88
|
-
resolveFlowUrl(
|
|
89
|
-
if (
|
|
78
|
+
resolveFlowUrl(botContext: BotContext): string {
|
|
79
|
+
if (botContext.session.is_test_integration) {
|
|
90
80
|
return `${this.apiUrl}/v1/bot_flows/{bot_id}/versions/${FlowBuilderJSONVersion.DRAFT}/`
|
|
91
81
|
}
|
|
92
82
|
return `${this.apiUrl}/v1/bot_flows/{bot_id}/versions/${this.jsonVersion}/`
|
|
93
83
|
}
|
|
94
84
|
|
|
95
|
-
async pre(
|
|
96
|
-
|
|
97
|
-
this.convertWhatsappAiAgentEmptyPayloads(request)
|
|
98
|
-
|
|
99
|
-
this.currentRequest = request
|
|
85
|
+
async pre(botContext: BotContext): Promise<void> {
|
|
86
|
+
this.botContext = botContext
|
|
100
87
|
this.cmsApi = await FlowBuilderApi.create({
|
|
101
|
-
flowUrl: this.resolveFlowUrl(
|
|
88
|
+
flowUrl: this.resolveFlowUrl(botContext),
|
|
102
89
|
url: this.apiUrl,
|
|
103
90
|
flow: this.flow,
|
|
104
|
-
accessToken: this.getAccessToken(
|
|
105
|
-
|
|
91
|
+
accessToken: this.getAccessToken(botContext.session),
|
|
92
|
+
botContext: this.botContext,
|
|
106
93
|
})
|
|
107
94
|
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const nextPayload = await getNextPayloadByUserInput(
|
|
114
|
-
this.cmsApi,
|
|
115
|
-
resolvedLocale,
|
|
116
|
-
request as unknown as ActionRequest,
|
|
117
|
-
this.smartIntentsConfig
|
|
118
|
-
)
|
|
119
|
-
request.input.payload = nextPayload
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
await this.updateRequestBeforeRoutes(request)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
private convertWhatsappAiAgentEmptyPayloads(request: PluginPreRequest): void {
|
|
126
|
-
if (request.session.user.provider === PROVIDER.WHATSAPP) {
|
|
127
|
-
const shouldUseReferral =
|
|
128
|
-
request.input.referral &&
|
|
129
|
-
request.input.payload?.startsWith(EMPTY_PAYLOAD)
|
|
130
|
-
|
|
131
|
-
if (shouldUseReferral) {
|
|
132
|
-
request.input.type = INPUT.TEXT
|
|
133
|
-
request.input.data = request.input.referral
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
private async updateRequestBeforeRoutes(
|
|
139
|
-
request: PluginPreRequest
|
|
140
|
-
): Promise<void> {
|
|
141
|
-
this.cmsApi.removeCaptureUserInputId()
|
|
142
|
-
if (request.input.payload) {
|
|
143
|
-
request.input.payload = this.removeSourceSuffix(request.input.payload)
|
|
144
|
-
|
|
145
|
-
if (this.cmsApi.isBotAction(request.input.payload)) {
|
|
146
|
-
const cmsBotAction = this.cmsApi.getNodeById<HtBotActionNode>(
|
|
147
|
-
request.input.payload
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
request.input.payload =
|
|
151
|
-
this.cmsApi.createPayloadWithParams(cmsBotAction)
|
|
152
|
-
|
|
153
|
-
// Re-execute convertWhatsappAiAgentEmptyPayloads function to handle
|
|
154
|
-
// the case that a BotAction has a payload equals to EMPTY_PAYLOAD
|
|
155
|
-
this.convertWhatsappAiAgentEmptyPayloads(request)
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
private removeSourceSuffix(payload: string): string {
|
|
161
|
-
return payload.split(SOURCE_INFO_SEPARATOR)[0]
|
|
95
|
+
const botContextManager = new BotContextManager(
|
|
96
|
+
this.cmsApi,
|
|
97
|
+
this.smartIntentsConfig
|
|
98
|
+
)
|
|
99
|
+
await botContextManager.prepareInputForRoutes(botContext)
|
|
162
100
|
}
|
|
163
101
|
|
|
164
|
-
post(
|
|
165
|
-
|
|
166
|
-
delete
|
|
102
|
+
post(botContext: BotContext): void {
|
|
103
|
+
botContext.input.nluResolution = undefined
|
|
104
|
+
delete botContext.session.user.system_locale_updated
|
|
167
105
|
}
|
|
168
106
|
|
|
169
107
|
async getContentsByContentID(
|
|
@@ -189,7 +127,7 @@ export default class BotonicPluginFlowBuilder implements Plugin {
|
|
|
189
127
|
|
|
190
128
|
async getStartContents(): Promise<FlowContent[]> {
|
|
191
129
|
const startNode = this.cmsApi.getStartNode()
|
|
192
|
-
this.
|
|
130
|
+
this.botContext.session.flow_thread_id = uuidv7()
|
|
193
131
|
return await this.getContentsByNode(startNode)
|
|
194
132
|
}
|
|
195
133
|
|
|
@@ -206,7 +144,7 @@ export default class BotonicPluginFlowBuilder implements Plugin {
|
|
|
206
144
|
) {
|
|
207
145
|
const customFunctionResolver = new CustomFunction(
|
|
208
146
|
this.functions,
|
|
209
|
-
this.
|
|
147
|
+
this.botContext,
|
|
210
148
|
resolvedLocale
|
|
211
149
|
)
|
|
212
150
|
const targetId = await customFunctionResolver.call(node)
|
|
@@ -214,7 +152,7 @@ export default class BotonicPluginFlowBuilder implements Plugin {
|
|
|
214
152
|
}
|
|
215
153
|
|
|
216
154
|
const flowFactory = new FlowFactory(
|
|
217
|
-
this.
|
|
155
|
+
this.botContext,
|
|
218
156
|
this.cmsApi,
|
|
219
157
|
resolvedLocale
|
|
220
158
|
)
|
package/src/types.ts
CHANGED
|
@@ -3,7 +3,6 @@ import type {
|
|
|
3
3
|
BotContext,
|
|
4
4
|
GuardrailRule,
|
|
5
5
|
InferenceResponse,
|
|
6
|
-
PluginPreRequest,
|
|
7
6
|
ResolvedPlugins,
|
|
8
7
|
} from '@botonic/core'
|
|
9
8
|
import type { FlowContent } from './content-fields'
|
|
@@ -67,7 +66,7 @@ export interface FlowBuilderApiOptions {
|
|
|
67
66
|
flowUrl: string
|
|
68
67
|
flow?: HtFlowBuilderData
|
|
69
68
|
accessToken: string
|
|
70
|
-
|
|
69
|
+
botContext: BotContext
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
export enum ProcessEnvNodeEnvs {
|
|
@@ -6,6 +6,7 @@ import { FlowImage } from '../content-fields/flow-image'
|
|
|
6
6
|
import { FlowText } from '../content-fields/flow-text'
|
|
7
7
|
import { FlowVideo } from '../content-fields/flow-video'
|
|
8
8
|
import { FlowWhatsappCtaUrlButtonNode } from '../content-fields/flow-whatsapp-cta-url-button'
|
|
9
|
+
import { FlowWhatsappRequestContactInfoNode } from '../content-fields/flow-whatsapp-request-contact-info'
|
|
9
10
|
import { FlowWhatsappTemplate } from '../content-fields/flow-whatsapp-template'
|
|
10
11
|
import { HtButtonStyle } from '../content-fields/hubtype-fields'
|
|
11
12
|
import { FlowWhatsappButtonList } from '../content-fields/whatsapp-button-list/flow-whatsapp-button-list'
|
|
@@ -34,6 +35,9 @@ export class HubtypeAssistantContent {
|
|
|
34
35
|
if (content instanceof FlowWhatsappTemplate) {
|
|
35
36
|
return HubtypeAssistantContent.formatWhatsappTemplateContent(content)
|
|
36
37
|
}
|
|
38
|
+
if (content instanceof FlowWhatsappRequestContactInfoNode) {
|
|
39
|
+
return HubtypeAssistantContent.formatRequestContactInfoContent(content)
|
|
40
|
+
}
|
|
37
41
|
return ''
|
|
38
42
|
}
|
|
39
43
|
|
|
@@ -205,4 +209,14 @@ export class HubtypeAssistantContent {
|
|
|
205
209
|
const { name, language } = template.htWhatsappTemplate
|
|
206
210
|
return `WhatsApp Template: ${name} (${language})`
|
|
207
211
|
}
|
|
212
|
+
|
|
213
|
+
private static formatRequestContactInfoContent(
|
|
214
|
+
requestContactInfo: FlowWhatsappRequestContactInfoNode
|
|
215
|
+
): string {
|
|
216
|
+
const body = requestContactInfo.text?.trim() ?? ''
|
|
217
|
+
if (!body) {
|
|
218
|
+
return '[WhatsApp Request Contact Info]'
|
|
219
|
+
}
|
|
220
|
+
return requestContactInfo.text
|
|
221
|
+
}
|
|
208
222
|
}
|