@botonic/plugin-flow-builder 0.34.0 → 0.34.2-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 (58) hide show
  1. package/lib/cjs/action/first-interaction.d.ts +1 -1
  2. package/lib/cjs/action/first-interaction.js +26 -28
  3. package/lib/cjs/action/first-interaction.js.map +1 -1
  4. package/lib/cjs/action/index.d.ts +1 -4
  5. package/lib/cjs/action/knowledge-bases.js +19 -17
  6. package/lib/cjs/action/knowledge-bases.js.map +1 -1
  7. package/lib/cjs/index.d.ts +2 -2
  8. package/lib/cjs/index.js +7 -4
  9. package/lib/cjs/index.js.map +1 -1
  10. package/lib/cjs/tracking.js.map +1 -1
  11. package/lib/cjs/types.d.ts +6 -0
  12. package/lib/cjs/types.js.map +1 -1
  13. package/lib/cjs/user-input/index.js +22 -15
  14. package/lib/cjs/user-input/index.js.map +1 -1
  15. package/lib/cjs/user-input/intent.js +7 -0
  16. package/lib/cjs/user-input/intent.js.map +1 -1
  17. package/lib/cjs/user-input/keyword.js +2 -0
  18. package/lib/cjs/user-input/keyword.js.map +1 -1
  19. package/lib/cjs/user-input/smart-intent.js +2 -0
  20. package/lib/cjs/user-input/smart-intent.js.map +1 -1
  21. package/lib/cjs/utils.d.ts +3 -0
  22. package/lib/cjs/utils.js +19 -1
  23. package/lib/cjs/utils.js.map +1 -1
  24. package/lib/esm/action/first-interaction.d.ts +1 -1
  25. package/lib/esm/action/first-interaction.js +26 -28
  26. package/lib/esm/action/first-interaction.js.map +1 -1
  27. package/lib/esm/action/index.d.ts +1 -4
  28. package/lib/esm/action/knowledge-bases.js +20 -18
  29. package/lib/esm/action/knowledge-bases.js.map +1 -1
  30. package/lib/esm/index.d.ts +2 -2
  31. package/lib/esm/index.js +7 -4
  32. package/lib/esm/index.js.map +1 -1
  33. package/lib/esm/tracking.js.map +1 -1
  34. package/lib/esm/types.d.ts +6 -0
  35. package/lib/esm/types.js.map +1 -1
  36. package/lib/esm/user-input/index.js +23 -16
  37. package/lib/esm/user-input/index.js.map +1 -1
  38. package/lib/esm/user-input/intent.js +7 -0
  39. package/lib/esm/user-input/intent.js.map +1 -1
  40. package/lib/esm/user-input/keyword.js +2 -0
  41. package/lib/esm/user-input/keyword.js.map +1 -1
  42. package/lib/esm/user-input/smart-intent.js +2 -0
  43. package/lib/esm/user-input/smart-intent.js.map +1 -1
  44. package/lib/esm/utils.d.ts +3 -0
  45. package/lib/esm/utils.js +16 -1
  46. package/lib/esm/utils.js.map +1 -1
  47. package/package.json +1 -1
  48. package/src/action/first-interaction.ts +31 -42
  49. package/src/action/knowledge-bases.ts +38 -36
  50. package/src/content-fields/hubtype-fields/intent.ts +1 -0
  51. package/src/index.ts +9 -4
  52. package/src/tracking.ts +0 -1
  53. package/src/types.ts +7 -0
  54. package/src/user-input/index.ts +33 -21
  55. package/src/user-input/intent.ts +8 -0
  56. package/src/user-input/keyword.ts +3 -0
  57. package/src/user-input/smart-intent.ts +5 -0
  58. package/src/utils.ts +27 -1
@@ -8,7 +8,7 @@ import {
8
8
  import { HtNodeWithContent } from '../content-fields/hubtype-fields/nodes'
9
9
  import { EventAction, KnowledgebaseFailReason, trackEvent } from '../tracking'
10
10
  import { KnowledgeBaseFunction, KnowledgeBaseResponse } from '../types'
11
- import { inputHasTextData } from '../utils'
11
+ import { inputHasTextData, isKnowledgeBasesAllowed } from '../utils'
12
12
  import { FlowBuilderContext } from './index'
13
13
 
14
14
  export async function getContentsByKnowledgeBase({
@@ -17,46 +17,48 @@ export async function getContentsByKnowledgeBase({
17
17
  request,
18
18
  resolvedLocale,
19
19
  }: FlowBuilderContext): Promise<FlowContent[]> {
20
- const startNodeKnowledgeBaseFlow = cmsApi.getStartNodeKnowledgeBaseFlow()
20
+ if (isKnowledgeBasesAllowed(request)) {
21
+ const startNodeKnowledgeBaseFlow = cmsApi.getStartNodeKnowledgeBaseFlow()
21
22
 
22
- if (!startNodeKnowledgeBaseFlow) {
23
- return []
24
- }
25
-
26
- const contents = await flowBuilderPlugin.getContentsByNode(
27
- startNodeKnowledgeBaseFlow,
28
- resolvedLocale
29
- )
23
+ if (!startNodeKnowledgeBaseFlow) {
24
+ return []
25
+ }
30
26
 
31
- const knowledgeBaseContent = contents.find(
32
- content => content instanceof FlowKnowledgeBase
33
- ) as FlowKnowledgeBase
27
+ const contents = await flowBuilderPlugin.getContentsByNode(
28
+ startNodeKnowledgeBaseFlow,
29
+ resolvedLocale
30
+ )
34
31
 
35
- if (!knowledgeBaseContent) {
36
- return contents
37
- }
32
+ const knowledgeBaseContent = contents.find(
33
+ content => content instanceof FlowKnowledgeBase
34
+ ) as FlowKnowledgeBase
38
35
 
39
- const sourceIds = knowledgeBaseContent.sourcesData.map(source => source.id)
40
- const flowId = cmsApi.getNodeById<HtNodeWithContent>(
41
- knowledgeBaseContent.id
42
- ).flow_id
36
+ if (!knowledgeBaseContent) {
37
+ return contents
38
+ }
43
39
 
44
- if (
45
- flowBuilderPlugin.getKnowledgeBaseResponse &&
46
- inputHasTextData(request.input) &&
47
- sourceIds.length > 0
48
- ) {
49
- const contentsWithKnowledgeResponse =
50
- await getContentsWithKnowledgeResponse(
51
- flowBuilderPlugin.getKnowledgeBaseResponse,
52
- request,
53
- contents,
54
- knowledgeBaseContent,
55
- flowId
56
- )
57
-
58
- if (contentsWithKnowledgeResponse) {
59
- return contentsWithKnowledgeResponse
40
+ const sourceIds = knowledgeBaseContent.sourcesData.map(source => source.id)
41
+ const flowId = cmsApi.getNodeById<HtNodeWithContent>(
42
+ knowledgeBaseContent.id
43
+ ).flow_id
44
+
45
+ if (
46
+ flowBuilderPlugin.getKnowledgeBaseResponse &&
47
+ inputHasTextData(request.input) &&
48
+ sourceIds.length > 0
49
+ ) {
50
+ const contentsWithKnowledgeResponse =
51
+ await getContentsWithKnowledgeResponse(
52
+ flowBuilderPlugin.getKnowledgeBaseResponse,
53
+ request,
54
+ contents,
55
+ knowledgeBaseContent,
56
+ flowId
57
+ )
58
+
59
+ if (contentsWithKnowledgeResponse) {
60
+ return contentsWithKnowledgeResponse
61
+ }
60
62
  }
61
63
  }
62
64
 
@@ -1,6 +1,7 @@
1
1
  import { HtBaseNode, HtInputLocale, HtTextLocale } from './common'
2
2
  import { HtNodeWithContentType } from './node-types'
3
3
 
4
+ // TODO: Remove this because frontend no allow create intents babel
4
5
  export interface HtIntentNode extends HtBaseNode {
5
6
  type: HtNodeWithContentType.INTENT
6
7
  content: {
package/src/index.ts CHANGED
@@ -34,6 +34,7 @@ import { DEFAULT_FUNCTIONS } from './functions'
34
34
  import {
35
35
  BotonicPluginFlowBuilderOptions,
36
36
  FlowBuilderJSONVersion,
37
+ InShadowingConfig,
37
38
  KnowledgeBaseFunction,
38
39
  PayloadParamsBase,
39
40
  TrackEventFunction,
@@ -54,12 +55,13 @@ export default class BotonicPluginFlowBuilder implements Plugin {
54
55
  public trackEvent?: TrackEventFunction
55
56
  public getKnowledgeBaseResponse?: KnowledgeBaseFunction
56
57
  public smartIntentsConfig: SmartIntentsInferenceConfig
58
+ public inShadowing: InShadowingConfig
57
59
 
58
60
  // TODO: Rethink how we construct FlowBuilderApi to be simpler
59
61
  public jsonVersion: FlowBuilderJSONVersion
60
62
  public apiUrl: string
61
63
 
62
- constructor(readonly options: BotonicPluginFlowBuilderOptions) {
64
+ constructor(options: BotonicPluginFlowBuilderOptions) {
63
65
  this.apiUrl = options.apiUrl || FLOW_BUILDER_API_URL_PROD
64
66
  this.jsonVersion = options.jsonVersion || FlowBuilderJSONVersion.LATEST
65
67
  this.flow = options.flow
@@ -73,6 +75,11 @@ export default class BotonicPluginFlowBuilder implements Plugin {
73
75
  }
74
76
  const customFunctions = options.customFunctions || {}
75
77
  this.functions = { ...DEFAULT_FUNCTIONS, ...customFunctions }
78
+ this.inShadowing = {
79
+ allowKeywords: options.inShadowing?.allowKeywords || false,
80
+ allowSmartIntents: options.inShadowing?.allowSmartIntents || false,
81
+ allowKnowledgeBases: options.inShadowing?.allowKnowledgeBases || false,
82
+ }
76
83
  }
77
84
 
78
85
  resolveFlowUrl(request: PluginPreRequest): string {
@@ -93,9 +100,7 @@ export default class BotonicPluginFlowBuilder implements Plugin {
93
100
  })
94
101
 
95
102
  const checkUserTextInput =
96
- inputHasTextData(request.input) &&
97
- !request.input.payload &&
98
- !request.session.is_first_interaction
103
+ inputHasTextData(request.input) && !request.input.payload
99
104
 
100
105
  if (checkUserTextInput) {
101
106
  const locale = this.getLocale(request.session)
package/src/tracking.ts CHANGED
@@ -5,7 +5,6 @@ import { FlowContent } from './content-fields'
5
5
  import {
6
6
  HtNodeWithContent,
7
7
  HtNodeWithContentType,
8
- HtNodeWithoutContentType,
9
8
  } from './content-fields/hubtype-fields'
10
9
  import { getFlowBuilderPlugin } from './helpers'
11
10
 
package/src/types.ts CHANGED
@@ -3,6 +3,12 @@ import { ActionRequest } from '@botonic/react'
3
3
 
4
4
  import { HtFlowBuilderData } from './content-fields/hubtype-fields'
5
5
 
6
+ export interface InShadowingConfig {
7
+ allowKeywords: boolean
8
+ allowSmartIntents: boolean
9
+ allowKnowledgeBases: boolean
10
+ }
11
+
6
12
  export interface BotonicPluginFlowBuilderOptions {
7
13
  apiUrl?: string
8
14
  jsonVersion?: FlowBuilderJSONVersion
@@ -13,6 +19,7 @@ export interface BotonicPluginFlowBuilderOptions {
13
19
  trackEvent?: TrackEventFunction
14
20
  getKnowledgeBaseResponse?: KnowledgeBaseFunction
15
21
  smartIntentsConfig?: { numSmartIntentsToUse: number }
22
+ inShadowing?: Partial<InShadowingConfig>
16
23
  }
17
24
 
18
25
  export type TrackEventFunction = (
@@ -1,4 +1,3 @@
1
- import { INPUT } from '@botonic/core'
2
1
  import { ActionRequest } from '@botonic/react'
3
2
 
4
3
  import { FlowBuilderApi } from '../api'
@@ -7,7 +6,11 @@ import {
7
6
  HtKeywordNode,
8
7
  HtSmartIntentNode,
9
8
  } from '../content-fields/hubtype-fields'
10
- import { inputHasTextData } from '../utils'
9
+ import {
10
+ inputHasTextData,
11
+ isKeywordsAllowed,
12
+ isSmartIntentsAllowed,
13
+ } from '../utils'
11
14
  import { getIntentNodeByInput } from './intent'
12
15
  import { KeywordMatcher } from './keyword'
13
16
  import { SmartIntentsApi, SmartIntentsInferenceConfig } from './smart-intent'
@@ -19,29 +22,38 @@ export async function getNodeByUserInput(
19
22
  smartIntentsConfig: SmartIntentsInferenceConfig
20
23
  ): Promise<HtSmartIntentNode | HtIntentNode | HtKeywordNode | undefined> {
21
24
  if (inputHasTextData(request.input)) {
22
- const keywordMatcher = new KeywordMatcher({
23
- cmsApi,
24
- locale,
25
- request,
26
- })
27
- const keywordNode = await keywordMatcher.getNodeByInput(request.input.data!)
28
- if (keywordNode) {
29
- return keywordNode
25
+ if (isKeywordsAllowed(request)) {
26
+ const keywordMatcher = new KeywordMatcher({
27
+ cmsApi,
28
+ locale,
29
+ request,
30
+ })
31
+ const keywordNode = await keywordMatcher.getNodeByInput(
32
+ request.input.data!
33
+ )
34
+ if (keywordNode) {
35
+ return keywordNode
36
+ }
30
37
  }
31
38
 
32
- const smartIntentsApi = new SmartIntentsApi(
33
- cmsApi,
34
- request,
35
- smartIntentsConfig
36
- )
37
- const smartIntentNode = await smartIntentsApi.getNodeByInput()
38
- if (smartIntentNode) {
39
- return smartIntentNode
39
+ if (isSmartIntentsAllowed(request)) {
40
+ const smartIntentsApi = new SmartIntentsApi(
41
+ cmsApi,
42
+ request,
43
+ smartIntentsConfig
44
+ )
45
+ const smartIntentNode = await smartIntentsApi.getNodeByInput()
46
+ if (smartIntentNode) {
47
+ return smartIntentNode
48
+ }
40
49
  }
41
50
 
42
- const intentNode = await getIntentNodeByInput(cmsApi, locale, request)
43
- if (intentNode) {
44
- return intentNode
51
+ // TODO: Remove this because frontend no allow create intents babel
52
+ if (isSmartIntentsAllowed(request)) {
53
+ const intentNode = await getIntentNodeByInput(cmsApi, locale, request)
54
+ if (intentNode) {
55
+ return intentNode
56
+ }
45
57
  }
46
58
  }
47
59
 
@@ -1,3 +1,4 @@
1
+ import { NluType } from '@botonic/core'
1
2
  import { ActionRequest } from '@botonic/react'
2
3
 
3
4
  import { FlowBuilderApi } from '../api'
@@ -15,6 +16,13 @@ export async function getIntentNodeByInput(
15
16
  await trackIntentEvent(request, intentNode)
16
17
 
17
18
  if (isIntentValid(intentNode, request, cmsApi)) {
19
+ const targetPayload = cmsApi.getPayload(intentNode.target)
20
+
21
+ request.input.nluResolution = {
22
+ type: NluType.Keyword,
23
+ matchedValue: intentNode.content.title,
24
+ payload: targetPayload,
25
+ }
18
26
  return intentNode
19
27
  }
20
28
  }
@@ -36,9 +36,12 @@ export class KeywordMatcher {
36
36
  if (!keywordNode || !this.matchedKeyword) {
37
37
  return undefined
38
38
  }
39
+ const targetPayload = this.cmsApi.getPayload(keywordNode.target)
40
+
39
41
  this.request.input.nluResolution = {
40
42
  type: NluType.Keyword,
41
43
  matchedValue: this.matchedKeyword,
44
+ payload: targetPayload,
42
45
  }
43
46
  await this.trackKeywordEvent()
44
47
  return keywordNode
@@ -46,11 +46,15 @@ export class SmartIntentsApi {
46
46
  smartIntentNode =>
47
47
  smartIntentNode.content.title === response.data.smart_intent_title
48
48
  )
49
+
49
50
  if (smartIntentNode) {
51
+ const targetPayload = this.cmsApi.getPayload(smartIntentNode.target)
50
52
  this.currentRequest.input.nluResolution = {
51
53
  type: NluType.SmartIntent,
52
54
  matchedValue: smartIntentNode.content.title,
55
+ payload: targetPayload,
53
56
  }
57
+
54
58
  await trackEvent(this.currentRequest, EventAction.IntentSmart, {
55
59
  nluIntentSmartTitle: response.data.smart_intent_title,
56
60
  nluIntentSmartNumUsed: response.data.smart_intents_used.length,
@@ -60,6 +64,7 @@ export class SmartIntentsApi {
60
64
  flowId: smartIntentNode.flow_id,
61
65
  flowNodeId: smartIntentNode.id,
62
66
  })
67
+
63
68
  return smartIntentNode
64
69
  }
65
70
  } catch (e) {
package/src/utils.ts CHANGED
@@ -1,7 +1,12 @@
1
1
  import { INPUT, Input, Session } from '@botonic/core'
2
2
  import { ActionRequest } from '@botonic/react'
3
3
 
4
- import { BotonicPluginFlowBuilderOptions, ProcessEnvNodeEnvs } from './types'
4
+ import { getFlowBuilderPlugin } from './helpers'
5
+ import {
6
+ BotonicPluginFlowBuilderOptions,
7
+ InShadowingConfig,
8
+ ProcessEnvNodeEnvs,
9
+ } from './types'
5
10
 
6
11
  function getAccessTokenFromSession(session: Session): string {
7
12
  if (!session._access_token) {
@@ -51,3 +56,24 @@ function resolveObjectKey(object: any, key: string): any {
51
56
  export function inputHasTextData(input: Input): boolean {
52
57
  return input.data !== undefined && input.type === INPUT.TEXT
53
58
  }
59
+
60
+ function isNluAllowed(
61
+ request: ActionRequest,
62
+ nluFlag: keyof InShadowingConfig
63
+ ): boolean {
64
+ const shadowing = Boolean(request.session._shadowing)
65
+ const flowBuilderPlugin = getFlowBuilderPlugin(request.plugins)
66
+ return !shadowing || (shadowing && flowBuilderPlugin.inShadowing[nluFlag])
67
+ }
68
+
69
+ export function isKeywordsAllowed(request: ActionRequest): boolean {
70
+ return isNluAllowed(request, 'allowKeywords')
71
+ }
72
+
73
+ export function isSmartIntentsAllowed(request: ActionRequest): boolean {
74
+ return isNluAllowed(request, 'allowSmartIntents')
75
+ }
76
+
77
+ export function isKnowledgeBasesAllowed(request: ActionRequest): boolean {
78
+ return isNluAllowed(request, 'allowKnowledgeBases')
79
+ }