@onereach/step-voice 4.0.28 → 4.0.31

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/dst/Cancel.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import VoiceStep from './voice';
2
2
  export default class VoiceCancel extends VoiceStep {
3
- get useQueue(): boolean;
4
3
  runStep(): Promise<void>;
5
4
  }
package/dst/Cancel.js CHANGED
@@ -3,14 +3,33 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const voice_1 = tslib_1.__importDefault(require("./voice"));
5
5
  class VoiceCancel extends voice_1.default {
6
- get useQueue() {
7
- return false;
8
- }
9
6
  async runStep() {
7
+ const conv = await this.getConversation();
8
+ if (conv.lcl.length <= 1) {
9
+ this.log.debug('nothing to cancel');
10
+ this.exitStep('next');
11
+ return;
12
+ }
10
13
  const channel = await this.fetchData();
11
- await this.cancel();
12
- await this.sendCommands(channel, [{ name: 'cancel' }]);
13
- this.exitStep('next');
14
+ this.triggers.once(`in/voice/${channel.id}/event`, async (event) => {
15
+ switch (event.params.type) {
16
+ case 'hangup':
17
+ await this.handleHangup(channel);
18
+ return await this.waitConvEnd();
19
+ case 'error':
20
+ return this.throwError(event.params.error);
21
+ case 'cancel': {
22
+ await this.popConvStep(); // pop current command (cancel)
23
+ await this.cancel(); // cancel previous command
24
+ return this.exitStep('next');
25
+ }
26
+ default:
27
+ return this.exitFlow();
28
+ }
29
+ });
30
+ this.triggers.otherwise(async () => {
31
+ await this.sendCommands(channel, [{ name: 'cancel' }]);
32
+ });
14
33
  }
15
34
  }
16
35
  exports.default = VoiceCancel;
package/dst/Choice.d.ts CHANGED
@@ -14,6 +14,7 @@ interface INPUT {
14
14
  noReplyDelay: number;
15
15
  promptsTriggers: TODO[];
16
16
  usePromptsTriggers: boolean;
17
+ recognitionModel?: string;
17
18
  }
18
19
  interface EVENT extends VoiceEvent {
19
20
  callRecording?: TODO;
package/dst/Choice.js CHANGED
@@ -34,7 +34,7 @@ const getPhrasesForSpeechRec = (choices) => {
34
34
  }
35
35
  return texts;
36
36
  };
37
- const getAsrSettings = (settings, choices) => {
37
+ const getAsrSettings = (settings, choices, recognitionModel) => {
38
38
  if (settings.engine === 'google' || settings.engine === 'google_beta') {
39
39
  return {
40
40
  ...settings,
@@ -43,7 +43,8 @@ const getAsrSettings = (settings, choices) => {
43
43
  {
44
44
  phrases: getPhrasesForSpeechRec(choices)
45
45
  }
46
- ]
46
+ ],
47
+ recognitionModel
47
48
  }
48
49
  };
49
50
  }
@@ -68,13 +69,13 @@ const isRepromptTrigger = (recogResult, promptsTriggers) => {
68
69
  class Choice extends voice_1.default {
69
70
  async runStep() {
70
71
  const channel = await this.fetchData();
71
- const { textType, asr, tts, sensitiveData, noReplyDelay, usePromptsTriggers } = this.data;
72
+ const { textType, asr, tts, sensitiveData, noReplyDelay, usePromptsTriggers, recognitionModel } = this.data;
72
73
  const exitExists = (exitId) => {
73
74
  return lodash_1.default.some(choices, (choice) => choice.exitId === exitId);
74
75
  };
75
76
  const choices = this.buildChoices({ choices: this.data.choices });
76
77
  const ttsSettings = tts.getSettings(channel.tts);
77
- const asrSettings = getAsrSettings(asr.getSettings(channel.asr), choices);
78
+ const asrSettings = getAsrSettings(asr.getSettings(channel.asr), choices, recognitionModel);
78
79
  const repromptsList = this.buildReprompts({ prompts: this.data.prompts });
79
80
  const speechSections = this.buildSections({ sections: this.data.audio, textType, ttsSettings });
80
81
  const grammar = {
@@ -229,11 +230,11 @@ class Choice extends voice_1.default {
229
230
  }
230
231
  case 'hangup': {
231
232
  await this.handleHangup(channel);
232
- return this.end();
233
- }
234
- case 'cancel': {
235
- return this.exitStep('cancel');
233
+ return await this.waitConvEnd();
236
234
  }
235
+ // case 'cancel': {
236
+ // return this.data.handleCancel === true && this.exitStep('cancel')
237
+ // }
237
238
  case 'error':
238
239
  return this.throwError(event.params.error);
239
240
  default:
@@ -11,7 +11,7 @@ class ConferenceDial extends voice_1.default {
11
11
  switch (event.params.type) {
12
12
  case 'hangup':
13
13
  await this.handleHangup(channel);
14
- return this.end();
14
+ return await this.waitConvEnd();
15
15
  case 'conference-start':
16
16
  if (this.data.stayInConference) {
17
17
  return this.exitFlow();
@@ -2,7 +2,7 @@ import { ITypedEvent } from '@onereach/flow-sdk/dst/types';
2
2
  import VoiceStep, { IVoiceChannel, TODO, VoiceEvent } from './voice';
3
3
  interface INPUT {
4
4
  asr: TODO;
5
- processHangUp: 'user' | 'bot' | 'both' | 'none';
5
+ processHangUp: 'user' | 'bot' | 'both' | 'none' | string;
6
6
  recordAfterTransfer: boolean;
7
7
  recordCall: boolean;
8
8
  choices: TODO[];
@@ -27,7 +27,6 @@ interface EVENT extends VoiceEvent {
27
27
  }
28
28
  export default class GlobalCommand extends VoiceStep<Partial<INPUT>, OUTPUT, EVENT> {
29
29
  get isGlobal(): boolean;
30
- get autoCancel(): boolean | undefined;
31
30
  runStep(): Promise<void>;
32
31
  initThread(): Promise<void>;
33
32
  globThread(): Promise<void>;
@@ -9,9 +9,6 @@ class GlobalCommand extends voice_1.default {
9
9
  get isGlobal() {
10
10
  return true;
11
11
  }
12
- get autoCancel() {
13
- return undefined;
14
- }
15
12
  async runStep() {
16
13
  this._clearCache();
17
14
  await this.process.runThread({
@@ -27,10 +24,6 @@ class GlobalCommand extends voice_1.default {
27
24
  }
28
25
  async initThread() {
29
26
  const channel = await this.fetchData();
30
- // if (recordCall || _.includes(['bot', 'both'], processHangUp)) {
31
- // // prevent delete of session by "End" step
32
- // this.session.set('keepAlive', true);
33
- // }
34
27
  const choices = this.buildChoices({ choices: this.data.choices });
35
28
  const grammar = await this.buildGrammar(channel, choices);
36
29
  // set grammar into voice conversation
@@ -62,10 +55,9 @@ class GlobalCommand extends voice_1.default {
62
55
  }
63
56
  async globThread() {
64
57
  const channel = await this.fetchData();
65
- const choices = this.buildChoices({ choices: this.data.choices });
66
- function exitExists(exitId) {
67
- return lodash_1.default.some(choices, (choice) => choice.exitId === exitId);
68
- }
58
+ const findExit = (exitId) => {
59
+ return lodash_1.default.find(this.step.exits, (exit) => exitId === exit.stepId);
60
+ };
69
61
  // if (channel.autoHangup) {
70
62
  // this.triggers.local('thread/end/main', async () => {
71
63
  // delete this.thread.waits['thread/end/main']
@@ -85,7 +77,7 @@ class GlobalCommand extends voice_1.default {
85
77
  switch (event.params.type) {
86
78
  case 'hangup': {
87
79
  await this.hangup(channel);
88
- await this.sendEventToStep({ toGlobal: false, event: { ...this.event, processed: undefined, action: 'local' } });
80
+ await this.notifyConvEnd();
89
81
  return this.end();
90
82
  }
91
83
  case 'avm-detected':
@@ -95,7 +87,7 @@ class GlobalCommand extends voice_1.default {
95
87
  case 'digits': {
96
88
  const params = event.params;
97
89
  const exitId = params.exitId ?? '';
98
- if (exitExists(exitId)) {
90
+ if (findExit(exitId)) {
99
91
  await this.transcript(channel, {
100
92
  previousTranscriptId: channel.lastTranscriptId,
101
93
  keyPress: params.digit,
@@ -111,7 +103,7 @@ class GlobalCommand extends voice_1.default {
111
103
  case 'recognition': {
112
104
  const params = event.params;
113
105
  const exitId = params.exitId ?? '';
114
- if (exitExists(exitId)) {
106
+ if (findExit(exitId)) {
115
107
  const voiceProcessResult = lodash_1.default.chain(params.phrases)
116
108
  .map((p) => p.lexical)
117
109
  .join(' | ')
@@ -137,10 +129,6 @@ class GlobalCommand extends voice_1.default {
137
129
  }
138
130
  async hangup(channel) {
139
131
  await this.handleHangup(channel);
140
- // if (channel.recordCall || _.includes(['bot', 'both'], processHangUp)) {
141
- // // turn off protection of session deletion by "End" step
142
- // this.session.unset('keepAlive');
143
- // }
144
132
  const isHangedUpByBot = channel.sessionEndedBy === 'Bot';
145
133
  const hangUpType = isHangedUpByBot ? 'bot hang up' : 'user hang up';
146
134
  // process call recording in hangup event
@@ -160,7 +148,7 @@ class GlobalCommand extends voice_1.default {
160
148
  return await this.exitThread(this.event, hangUpType, 'hang up');
161
149
  case 'none':
162
150
  default:
163
- return this.exitFlow();
151
+ return this.end();
164
152
  }
165
153
  }
166
154
  async exitThread(event, type, stepExit) {
@@ -192,16 +180,18 @@ class GlobalCommand extends voice_1.default {
192
180
  // params: {}
193
181
  // }])
194
182
  // channel.global = null;
195
- await this.updateData();
183
+ // await this.updateData()
184
+ const exitLabel = this.getExitStepLabel(stepExit) ?? stepExit;
196
185
  await this.process.runThread({
197
- id: `${stepExit}_${(0, nanoid_1.nanoid)(8)}`,
186
+ id: `${exitLabel}_${(0, nanoid_1.nanoid)(8)}`,
198
187
  state: {
199
188
  name: 'exitToThread',
189
+ direct: true,
200
190
  result: {
201
191
  conversation: this.conversation,
202
192
  conversationThreadId: this.dataThreadId
203
193
  },
204
- exitStep: this.getExitStepId(stepExit),
194
+ exitStep: stepExit,
205
195
  step: this.currentStepId
206
196
  }
207
197
  });
@@ -210,7 +200,7 @@ class GlobalCommand extends voice_1.default {
210
200
  // this.gotoState(this.state, { name: 'exiting' })
211
201
  }
212
202
  exitToThread() {
213
- this.thread.jumpTo(this.state.exitStep, this.state.result);
203
+ this.thread.exitStep(this.state.exitStep, this.state.result);
214
204
  }
215
205
  async buildGrammar(channel, choices) {
216
206
  const { asr } = this.data;
package/dst/Hangup.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import VoiceStep from './voice';
2
2
  export default class Hangup extends VoiceStep {
3
3
  runStep(): Promise<void>;
4
+ onConvEnd(): Promise<void>;
4
5
  }
package/dst/Hangup.js CHANGED
@@ -12,9 +12,9 @@ class Hangup extends voice_1.default {
12
12
  return this.exitStep('next');
13
13
  case 'error':
14
14
  return this.throwError(event.params.error);
15
- case 'cancel': {
16
- return this.exitStep('cancel');
17
- }
15
+ // case 'cancel': {
16
+ // return this.data.handleCancel === true && this.exitStep('cancel')
17
+ // }
18
18
  default:
19
19
  return this.exitFlow();
20
20
  }
@@ -32,5 +32,8 @@ class Hangup extends voice_1.default {
32
32
  return this.exitFlow();
33
33
  });
34
34
  }
35
+ async onConvEnd() {
36
+ this.exitStep('next');
37
+ }
35
38
  }
36
39
  exports.default = Hangup;
@@ -21,7 +21,6 @@ interface INPUT {
21
21
  }
22
22
  export default class InitiateCall extends VoiceStep<INPUT, TODO, CallStartEvent> {
23
23
  get conversation(): string | import("@onereach/flow-sdk/dst/types").IMergeField;
24
- get autoCancel(): undefined;
25
24
  runStep(): Promise<void>;
26
25
  waitForCall(): Promise<void>;
27
26
  }
@@ -17,9 +17,6 @@ class InitiateCall extends voice_1.default {
17
17
  throw new Error('missing conversation');
18
18
  return this.step.dataOut;
19
19
  }
20
- get autoCancel() {
21
- return undefined;
22
- }
23
20
  async runStep() {
24
21
  const { channelId = uuid.v4() } = this.data;
25
22
  if (!this.session.key) {
@@ -11,7 +11,7 @@ class JoinConference extends voice_1.default {
11
11
  switch (event.params.type) {
12
12
  case 'hangup':
13
13
  await this.handleHangup(channel);
14
- return this.end();
14
+ return await this.waitConvEnd();
15
15
  case 'conference-start':
16
16
  await this.transcript(channel, {
17
17
  conferenceId: conferenceName,
@@ -19,6 +19,7 @@ interface INPUT {
19
19
  expectedNumberOfDigits: number;
20
20
  regExToValidate: string;
21
21
  mfVersion: string;
22
+ recognitionModel?: string;
22
23
  }
23
24
  interface EVENT extends VoiceEvent {
24
25
  callRecording?: TODO;
@@ -26,7 +26,7 @@ const validateInput = ({ input = '', type, regex, expectedLength }) => {
26
26
  class KeypadInput extends voice_1.default {
27
27
  async runStep() {
28
28
  const channel = await this.fetchData();
29
- const { interTimeout, asr, tts, noReplyDelay, textType, keypadBargeIn, endInput, terminationKey, endUserInputValidationOther, expectedNumberOfDigits, regExToValidate, mfVersion, sensitiveData } = this.data;
29
+ const { interTimeout, asr, tts, noReplyDelay, textType, keypadBargeIn, endInput, terminationKey, endUserInputValidationOther, expectedNumberOfDigits, regExToValidate, mfVersion, sensitiveData, recognitionModel } = this.data;
30
30
  const interDigitTimeout = Number(interTimeout) * 1000;
31
31
  const ttsSettings = tts.getSettings(channel.tts);
32
32
  const asrSettings = asr.getSettings(channel.asr);
@@ -35,7 +35,8 @@ class KeypadInput extends voice_1.default {
35
35
  asr: {
36
36
  ...asrSettings,
37
37
  config: {
38
- version: 'v1beta'
38
+ version: 'v1beta',
39
+ recognitionModel
39
40
  }
40
41
  }
41
42
  };
@@ -151,11 +152,11 @@ class KeypadInput extends voice_1.default {
151
152
  }
152
153
  case 'hangup': {
153
154
  await this.handleHangup(channel);
154
- return this.end();
155
- }
156
- case 'cancel': {
157
- return this.exitStep('cancel');
155
+ return await this.waitConvEnd();
158
156
  }
157
+ // case 'cancel': {
158
+ // return this.data.handleCancel === true && this.exitStep('cancel')
159
+ // }
159
160
  case 'error':
160
161
  return this.throwError(event.params.error);
161
162
  default:
@@ -11,7 +11,7 @@ class KickFromConference extends voice_1.default {
11
11
  switch (event.params.type) {
12
12
  case 'hangup':
13
13
  await this.handleHangup(channel);
14
- return this.end();
14
+ return await this.waitConvEnd();
15
15
  case 'conference-end':
16
16
  await this.transcript(channel, {
17
17
  conferenceId: room,
@@ -21,14 +21,15 @@ class SayMessage extends voice_1.default {
21
21
  switch (event.params.type) {
22
22
  case 'hangup':
23
23
  await this.handleHangup(channel);
24
- return this.end();
24
+ return await this.waitConvEnd();
25
25
  case 'playback':
26
26
  return this.exitStep('next');
27
27
  case 'error':
28
28
  return this.throwError(event.params.error);
29
- case 'cancel': {
30
- return this.exitStep('cancel');
31
- }
29
+ //
30
+ // case 'cancel': {
31
+ // return this.data.handleCancel === true && this.exitStep('cancel')
32
+ // }
32
33
  default:
33
34
  return this.exitFlow();
34
35
  }
package/dst/Transfer.js CHANGED
@@ -40,7 +40,7 @@ class Transfer extends voice_1.default {
40
40
  }
41
41
  case 'hangup': {
42
42
  await this.handleHangup(channel);
43
- return this.end();
43
+ return await this.waitConvEnd();
44
44
  }
45
45
  case 'error':
46
46
  return this.throwError(event.params.error);
@@ -39,7 +39,7 @@ class Recording extends voice_1.default {
39
39
  // TODO do we need zombie?
40
40
  this.state.zombie = true;
41
41
  await this.handleHangup(channel);
42
- return this.exitFlow();
42
+ return await this.waitConvEnd();
43
43
  case 'record':
44
44
  if (!lodash_1.default.isEmpty(url)) {
45
45
  await this.transcript(channel, {
@@ -2,7 +2,6 @@ import VoiceStep, { CallStartEvent, TODO } from './voice';
2
2
  import { ITypedEvent } from '@onereach/flow-sdk/dst/types';
3
3
  export default class WaitForCall extends VoiceStep<TODO, TODO, TODO> {
4
4
  get conversation(): string | import("@onereach/flow-sdk/dst/types").IMergeField;
5
- get autoCancel(): boolean;
6
5
  runStep(): Promise<void>;
7
6
  onCall(event: ITypedEvent<CallStartEvent>): Promise<unknown>;
8
7
  }
@@ -15,9 +15,6 @@ class WaitForCall extends voice_1.default {
15
15
  throw new Error('missing conversation');
16
16
  return this.step.dataOut;
17
17
  }
18
- get autoCancel() {
19
- return false;
20
- }
21
18
  async runStep() {
22
19
  const selectedNumbers = this.data.selectedNumbers;
23
20
  lodash_1.default.forEach(selectedNumbers, number => {
package/dst/step.d.ts CHANGED
@@ -10,10 +10,10 @@ export default class ConvStep<TData = unknown, TIn = unknown, TOut = unknown, TP
10
10
  get conversation(): IMergeFieldKey | IMergeField;
11
11
  /** id of the thread where conversation data is stored */
12
12
  get dataThreadId(): IThreadId;
13
- get autoCancel(): boolean | undefined;
14
13
  get isGlobal(): boolean;
15
14
  get useQueue(): boolean;
16
15
  fetchData(): Promise<TData & IConversationData>;
16
+ getConversation(): Promise<IConversation>;
17
17
  updateData(): Promise<void>;
18
18
  hasConversation(): Promise<boolean>;
19
19
  runBefore(): Promise<void>;
@@ -24,7 +24,14 @@ export default class ConvStep<TData = unknown, TIn = unknown, TOut = unknown, TP
24
24
  onSkipEvent(): Promise<void>;
25
25
  cancel(): Promise<void>;
26
26
  onCancel(): Promise<void>;
27
- waitCancelEnd(): Promise<void>;
27
+ onSleep(): Promise<void>;
28
+ onAwake(): Promise<void>;
29
+ onPause(): Promise<void>;
30
+ onResume(): Promise<void>;
31
+ notifyConvEnd(): Promise<void>;
32
+ waitConvEnd(): Promise<void>;
33
+ waitGlobEnd(): Promise<void>;
34
+ onConvEnd(): Promise<void>;
28
35
  pause(): Promise<void>;
29
36
  resume(): Promise<void>;
30
37
  sendEventToStep({ toGlobal, toStep, action, event }: {
@@ -37,13 +44,11 @@ export default class ConvStep<TData = unknown, TIn = unknown, TOut = unknown, TP
37
44
  /** @returns true if current conv is active */
38
45
  pushConvStep(): Promise<boolean>;
39
46
  /** @returns true if current conv was active */
40
- popConvStep(): Promise<boolean>;
41
- startConversation(data: TData, { autoCancel, events }: {
42
- autoCancel?: boolean;
47
+ popConvStep(popStep?: IConversationStep): Promise<boolean>;
48
+ startConversation(data: TData, { events }: {
43
49
  events: Record<string, {}>;
44
50
  thread?: IThreadId;
45
51
  }): Promise<void>;
46
52
  _fetchData(): Promise<(TData & IConversationData) | undefined>;
47
- _getConversation(): Promise<IConversation>;
48
53
  _clearCache(): void;
49
54
  }
package/dst/step.js CHANGED
@@ -3,7 +3,6 @@
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const tslib_1 = require("tslib");
5
5
  const step_1 = tslib_1.__importDefault(require("@onereach/flow-sdk/dst/step"));
6
- const event_1 = tslib_1.__importDefault(require("@onereach/flow-sdk/dst/event"));
7
6
  class ConvStep extends step_1.default {
8
7
  get conversation() {
9
8
  if (this.data.conversation == null)
@@ -15,9 +14,6 @@ class ConvStep extends step_1.default {
15
14
  const dataThreadId = this.state.thread ?? this.data.conversationThread;
16
15
  return dataThreadId || this.thread.id;
17
16
  }
18
- get autoCancel() {
19
- return undefined;
20
- }
21
17
  get isGlobal() {
22
18
  return false;
23
19
  }
@@ -30,6 +26,9 @@ class ConvStep extends step_1.default {
30
26
  throw new Error(`missing conversation data in state ${this.state.name}`);
31
27
  return data;
32
28
  }
29
+ async getConversation() {
30
+ return (await this.fetchData())._conv;
31
+ }
33
32
  async updateData() {
34
33
  if (this.convDataCache == null)
35
34
  throw new Error(`missing conversation cache in state ${this.state.name}`);
@@ -42,6 +41,8 @@ class ConvStep extends step_1.default {
42
41
  }
43
42
  async runBefore() {
44
43
  await super.runBefore();
44
+ if (this.state.ending)
45
+ return;
45
46
  // ensure cache is reset between step runs, just in case
46
47
  this._clearCache();
47
48
  this.triggers.local('_conv');
@@ -50,14 +51,15 @@ class ConvStep extends step_1.default {
50
51
  this.log.debug('conv.runBefore', { state: this.state, conv: this.convDataCache?._conv });
51
52
  if (this.state.direct)
52
53
  return;
53
- if (this.event.action === 'cancel') {
54
- this.state.name = 'onCancel';
54
+ if (!this.event.processed && this.event.action && typeof this[this.event.action] === 'function') {
55
+ this.event.processed = true;
56
+ this.state.name = this.event.action;
55
57
  return;
56
58
  }
57
59
  if (this.useQueue && !await this.pushConvStep()) {
58
60
  return await this.waitForConversation();
59
61
  }
60
- if (this.event.action == null && this.event.processed !== true && this.convDataCache?._conv?.trg?.[this.event.name] != null) {
62
+ if (this.event.action == null && !this.event.processed && this.convDataCache?._conv?.trg?.[this.event.name] != null) {
61
63
  if (this.isGlobal)
62
64
  return;
63
65
  const hasGlobal = await this.sendEventToStep({ event: { ...this.event, action: 'global' }, toGlobal: true }); // redirect to global (1)
@@ -77,17 +79,18 @@ class ConvStep extends step_1.default {
77
79
  if (!await this.hasConversation())
78
80
  return await super.runAfter();
79
81
  if (this.thread.hasControlAction()) {
80
- if (await this.popConvStep()) {
81
- await this.sendEventToStep({ toGlobal: this.isGlobal, action: 'activate' });
82
- }
82
+ await this.popConvStep();
83
+ // if (await this.popConvStep()) {
84
+ // await this.sendEventToStep({ toGlobal: this.isGlobal, action: 'onAwake' })
85
+ // }
83
86
  }
84
- if (this.isGlobal && !event_1.default.isProcessed(this.event)) {
87
+ if (this.isGlobal && !this.event.processed) {
85
88
  await this.sendEventToStep({ toGlobal: false, event: { ...this.event, processed: undefined, action: 'local' } });
86
89
  }
87
90
  await super.runAfter();
88
91
  }
89
92
  async hasActiveGlobal() {
90
- const globalLength = (await this._getConversation())?.glb?.length ?? 0;
93
+ const globalLength = (await this.getConversation())?.glb?.length ?? 0;
91
94
  return globalLength > 0;
92
95
  }
93
96
  async setLocalTriggers() {
@@ -119,60 +122,88 @@ class ConvStep extends step_1.default {
119
122
  this.log.debug('conv.cannot cancel global');
120
123
  return;
121
124
  }
122
- const conv = await this._getConversation();
123
- const activeStep = await this.activeStep(false);
124
- if (activeStep != null) {
125
- this.log.debug('conv.cancel', activeStep);
126
- conv.lcl.splice(0);
127
- await this.updateData();
128
- await this.sendEventToStep({ toGlobal: false, action: 'cancel', toStep: activeStep });
129
- }
130
- else {
131
- this.log.debug('conv.nothing to cancel');
132
- }
125
+ const activeStep = await this.activeStep();
126
+ await this.sendEventToStep({ event: { name: '_conv', action: 'onCancel', params: { byStep: this.step.label } }, toStep: activeStep });
133
127
  }
134
128
  async onCancel() {
129
+ await this.popConvStep();
135
130
  if (this.getExitStepId('cancel')) {
136
131
  this.log.debug('conv.cancel exit');
137
132
  this.exitStep('cancel');
138
133
  }
139
134
  else {
140
- const conversationThread = this.state.thread ?? this.thread.id;
141
- if (conversationThread === this.thread.id) {
142
- this.log.debug('conv.cancel wait for end', this.conversation);
143
- this.gotoState({ ...this.state, name: 'waitCancelEnd', direct: true });
135
+ return await this.waitConvEnd();
136
+ }
137
+ }
138
+ async onSleep() {
139
+ // sleep
140
+ }
141
+ async onAwake() {
142
+ // wakeup
143
+ }
144
+ async onPause() {
145
+ // return await this.waitConvEnd()
146
+ }
147
+ async onResume() {
148
+ // resume
149
+ }
150
+ async notifyConvEnd() {
151
+ await this.popConvStep();
152
+ const conv = await this.getConversation();
153
+ const lcl = conv.lcl.splice(0);
154
+ const glb = conv.glb.splice(0);
155
+ if (lcl.length > 0 || glb.length > 0) {
156
+ await this.updateData();
157
+ for (const step of lcl) {
158
+ await this.sendEventToStep({ toStep: step, action: 'onConvEnd' });
144
159
  }
145
- else {
146
- this.log.debug('conv.cancel end', this.conversation);
147
- this.end();
160
+ for (const step of glb) {
161
+ await this.sendEventToStep({ toStep: step, action: 'onConvEnd' });
148
162
  }
149
163
  }
150
164
  }
151
- async waitCancelEnd() {
152
- this.local.background = true;
153
- this.exitFlow();
154
- }
155
- async pause() {
156
- const conv = await this._getConversation();
157
- const activeStep = await this.activeStep(false);
158
- if (activeStep != null) {
159
- this.log.debug('conv.pause', activeStep);
160
- conv.stk.push(conv.lcl.splice(0)); // save que to stk
161
- await this.sendEventToStep({ toGlobal: false, action: 'pause', toStep: activeStep });
165
+ async waitConvEnd() {
166
+ const conversationThread = this.state.thread ?? this.thread.id;
167
+ if (!this.isGlobal && conversationThread === this.thread.id && this.thread.id !== 'main') {
168
+ this.log.debug('conv.wait for end', this.conversation);
169
+ this.gotoState({ ...this.state, name: 'waitGlobEnd', direct: true });
162
170
  }
163
171
  else {
164
- this.log.debug('conv.nothing to pause');
172
+ this.log.debug('conv.end', this.conversation);
173
+ await this.onConvEnd();
165
174
  }
166
175
  }
176
+ async waitGlobEnd() {
177
+ const gcThreadId = `G:${this.thread.id}`;
178
+ // wait for glob thread end (if exists)
179
+ this.triggers.local(`thread/end/${gcThreadId}`, async () => await this.onConvEnd());
180
+ if (!this.process.getThread(gcThreadId))
181
+ await this.onConvEnd();
182
+ }
183
+ async onConvEnd() {
184
+ this.end();
185
+ }
186
+ async pause() {
187
+ // const conv = await this._getConversation()
188
+ // const activeStep = await this.activeStep(false)
189
+ // if (activeStep != null) {
190
+ // this.log.debug('conv.pause', activeStep)
191
+ // conv.stk.push(conv.lcl.splice(0)) // save que to stk
192
+ // await this.updateData()
193
+ // await this.sendEventToStep({ action: 'onPause', toStep: activeStep })
194
+ // } else {
195
+ // this.log.debug('conv.nothing to pause')
196
+ // }
197
+ }
167
198
  async resume() {
168
- const conv = await this._getConversation();
169
- if (conv.stk.length > 0) {
170
- conv.lcl.unshift(...(conv.stk.pop() ?? [])); // restore que from stk
171
- await this.sendEventToStep({ toGlobal: false, action: 'resume' });
172
- }
173
- else {
174
- this.log.debug('conv.nothing to resume');
175
- }
199
+ // const conv = await this._getConversation()
200
+ // if (conv.stk.length > 0) {
201
+ // conv.lcl.unshift(...(conv.stk.pop() ?? [])) // restore que from stk
202
+ // await this.updateData()
203
+ // await this.sendEventToStep({ toGlobal: false, action: 'onResume' })
204
+ // } else {
205
+ // this.log.debug('conv.nothing to resume')
206
+ // }
176
207
  }
177
208
  async sendEventToStep({ toGlobal, toStep, action, event = { name: '_conv', action } }) {
178
209
  toStep || (toStep = await this.activeStep(toGlobal));
@@ -183,63 +214,59 @@ class ConvStep extends step_1.default {
183
214
  return undefined;
184
215
  }
185
216
  async activeStep(isGlobal = this.isGlobal) {
186
- const conv = await this._getConversation();
187
- return isGlobal ? conv.glb[conv.glb.length - 1] : conv.lcl[0];
217
+ const conv = await this.getConversation();
218
+ return isGlobal ? conv.glb[conv.glb.length - 1] : conv.lcl[conv.lcl.length - 1];
188
219
  }
189
220
  /** @returns true if current conv is active */
190
221
  async pushConvStep() {
191
- const conv = await this._getConversation();
222
+ const conv = await this.getConversation();
192
223
  const sessionKey = this.session.key;
193
224
  if (sessionKey == null)
194
225
  throw new Error('session is required');
195
226
  const que = this.isGlobal ? conv.glb : conv.lcl;
196
227
  const queIndex = que.findIndex(stp => stp.key === sessionKey && this.thread.id === stp.thread);
197
228
  if (queIndex < 0) {
198
- if (que.length > 0 && !this.isGlobal && (this.autoCancel ?? conv.acl ?? false))
199
- await this.cancel();
200
- que.push({ key: sessionKey, thread: this.thread.id });
229
+ await this.sendEventToStep({ toGlobal: false, event: { name: '_conv', action: 'onPause', params: { byStep: this.step.label } } });
230
+ que.push({ key: sessionKey, thread: this.thread.id, name: this.constructor.name, label: this.label, step: this.id });
201
231
  await this.updateData();
202
- return this.isGlobal ? true : que.length === 1;
232
+ return true;
203
233
  }
204
- return queIndex === (this.isGlobal ? que.length - 1 : 0);
234
+ return queIndex === que.length - 1;
205
235
  }
206
236
  /** @returns true if current conv was active */
207
- async popConvStep() {
208
- const conv = await this._getConversation();
237
+ async popConvStep(popStep) {
238
+ const conv = await this.getConversation();
209
239
  const sessionKey = this.session.key;
210
240
  if (sessionKey == null)
211
241
  throw new Error('session is required');
242
+ popStep || (popStep = { key: sessionKey, thread: this.thread.id });
212
243
  const que = this.isGlobal ? conv.glb : conv.lcl;
213
- const queIndex = que.findIndex(stp => stp.key === sessionKey && this.thread.id === stp.thread);
244
+ const queIndex = que.findIndex(stp => stp.key === popStep?.key && stp.thread === popStep.thread);
214
245
  if (queIndex >= 0) {
215
246
  // console.log('SPLICE1', this.thread.id, this.step.label, que)
216
247
  que.splice(queIndex, 1);
217
248
  await this.updateData();
218
- return this.isGlobal ? queIndex === que.length : queIndex === 0;
249
+ return queIndex === que.length;
219
250
  }
220
- let updated = false;
221
- conv.stk.forEach((steps, stepsIdx) => {
222
- const stpIdx = steps.findIndex(stp => stp.key === sessionKey && this.thread.id === stp.thread);
223
- if (stpIdx >= 0) {
224
- if (steps.length > 1)
225
- steps.splice(stpIdx, 1);
226
- else
227
- conv.stk.splice(stepsIdx, 1);
228
- updated = true;
229
- }
230
- });
231
- if (updated)
232
- await this.updateData();
251
+ // let updated = false
252
+ // conv.stk.forEach((steps, stepsIdx) => {
253
+ // const stpIdx = steps.findIndex(stp => stp.key === sessionKey && this.thread.id === stp.thread)
254
+ // if (stpIdx >= 0) {
255
+ // if (steps.length > 1) steps.splice(stpIdx, 1)
256
+ // else conv.stk.splice(stepsIdx, 1)
257
+ // updated = true
258
+ // }
259
+ // })
260
+ // if (updated) await this.updateData()
233
261
  return false;
234
262
  }
235
- async startConversation(data, { autoCancel = false, events }) {
263
+ async startConversation(data, { events }) {
236
264
  this.convDataCache = {
237
265
  ...data,
238
266
  _conv: {
239
- acl: (autoCancel ? 1 : undefined),
240
267
  trg: events,
241
268
  glb: [],
242
- stk: [],
269
+ // stk: [],
243
270
  lcl: []
244
271
  }
245
272
  };
@@ -254,9 +281,6 @@ class ConvStep extends step_1.default {
254
281
  // console.log('FETCH', this.conversation, this.thread.id, this.step.label, this.convDataCache?._conv.que)
255
282
  return this.convDataCache;
256
283
  }
257
- async _getConversation() {
258
- return (await this.fetchData())._conv;
259
- }
260
284
  _clearCache() {
261
285
  this.convDataCache = undefined;
262
286
  }
package/dst/voice.d.ts CHANGED
@@ -34,7 +34,6 @@ export interface CallStartEvent extends VoiceEvent {
34
34
  export default class VoiceStep<TIn = unknown, TOut = unknown, TParams = VoiceEvent> extends ConvStep<IVoiceChannel, TIn & {
35
35
  handleCancel?: boolean;
36
36
  }, TOut, TParams> {
37
- get autoCancel(): boolean | undefined;
38
37
  sendCommands({ id, type, callback }: IVoiceChannel, commands: TODO[]): Promise<unknown>;
39
38
  extractSectionMessages(sections: IPromtpSection[]): string;
40
39
  extractSectionFiles(sections: IPromtpSection[]): Array<{
package/dst/voice.js CHANGED
@@ -13,9 +13,6 @@ class VoiceStepError extends base_1.default {
13
13
  exports.VoiceStepError = VoiceStepError;
14
14
  class VoiceStep extends step_1.default {
15
15
  // static Error = VoiceStepError
16
- get autoCancel() {
17
- return true;
18
- }
19
16
  async sendCommands({ id, type, callback }, commands) {
20
17
  if (lodash_1.default.isEmpty(commands))
21
18
  return;
@@ -24,7 +21,7 @@ class VoiceStep extends step_1.default {
24
21
  name: `out/voice/${type}`,
25
22
  params: {
26
23
  id,
27
- cancel: this.autoCancel,
24
+ cancel: this.isGlobal ? undefined : true,
28
25
  commands
29
26
  },
30
27
  reporting: this.session.getSessionRef()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onereach/step-voice",
3
- "version": "4.0.28",
3
+ "version": "4.0.31",
4
4
  "author": "Roman Zolotarov <roman.zolotarov@onereach.com>",
5
5
  "contributors": [
6
6
  "Roman Zolotarov",
@@ -18,19 +18,19 @@
18
18
  "uuid": "^8.3.2"
19
19
  },
20
20
  "devDependencies": {
21
- "@onereach/flow-sdk": "^3.1.37",
21
+ "@onereach/flow-sdk": "^3.1.54",
22
22
  "@swc/cli": "^0.1.57",
23
- "@swc/core": "^1.2.205",
23
+ "@swc/core": "^1.2.210",
24
24
  "@swc/jest": "^0.2.21",
25
- "@types/jest": "^28.1.3",
25
+ "@types/jest": "^28.1.4",
26
26
  "@types/lodash": "^4.14.182",
27
27
  "@types/timestring": "^6.0.2",
28
28
  "@types/uuid": "^8.3.4",
29
- "aws-sdk": "^2.1164.0",
29
+ "aws-sdk": "^2.1168.0",
30
30
  "babel-runtime": "^6.26.0",
31
31
  "docdash": "^1.2.0",
32
32
  "husky": "^8.0.1",
33
- "jest": "^28.1.1",
33
+ "jest": "^28.1.2",
34
34
  "pinst": "^3.0.0",
35
35
  "ts-standard": "^11.0.0",
36
36
  "typescript": "^4.7.4"