@nlxai/core 1.2.3 → 1.2.4-alpha.10
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/README.md +358 -16
- package/docs/README.md +1930 -0
- package/lib/index.cjs +315 -76
- package/lib/index.d.ts +195 -10
- package/lib/index.esm.js +315 -77
- package/lib/index.umd.js +2 -2
- package/package.json +10 -3
package/lib/index.cjs
CHANGED
|
@@ -6,7 +6,7 @@ var ReconnectingWebSocket = require('reconnecting-websocket');
|
|
|
6
6
|
var uuid = require('uuid');
|
|
7
7
|
|
|
8
8
|
var name = "@nlxai/core";
|
|
9
|
-
var version$1 = "1.2.
|
|
9
|
+
var version$1 = "1.2.4-alpha.10";
|
|
10
10
|
var description = "Low-level SDK for building NLX experiences";
|
|
11
11
|
var type = "module";
|
|
12
12
|
var main = "lib/index.cjs";
|
|
@@ -34,14 +34,21 @@ var scripts = {
|
|
|
34
34
|
var author = "Peter Szerzo <peter@nlx.ai>";
|
|
35
35
|
var license = "MIT";
|
|
36
36
|
var devDependencies = {
|
|
37
|
+
"@rollup/plugin-commonjs": "^25.0.7",
|
|
38
|
+
"@rollup/plugin-json": "^6.0.1",
|
|
39
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
40
|
+
"@rollup/plugin-replace": "^5.0.5",
|
|
41
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
42
|
+
"@rollup/plugin-typescript": "^11.1.5",
|
|
37
43
|
"@types/isomorphic-fetch": "^0.0.39",
|
|
38
44
|
"@types/node": "^24.10.1",
|
|
39
45
|
"@types/ramda": "0.31.1",
|
|
40
46
|
"@types/uuid": "^9.0.7",
|
|
41
|
-
"concat-md": "^0.5.1",
|
|
42
47
|
"eslint-config-nlx": "*",
|
|
43
48
|
prettier: "^3.1.0",
|
|
49
|
+
rollup: "^4.3.0",
|
|
44
50
|
"rollup-config-nlx": "*",
|
|
51
|
+
"rollup-plugin-node-polyfills": "^0.2.1",
|
|
45
52
|
typedoc: "^0.28.14",
|
|
46
53
|
"typedoc-plugin-markdown": "^4.9.0",
|
|
47
54
|
typescript: "^5.5.4"
|
|
@@ -55,7 +62,7 @@ var dependencies = {
|
|
|
55
62
|
var publishConfig = {
|
|
56
63
|
access: "public"
|
|
57
64
|
};
|
|
58
|
-
var gitHead = "
|
|
65
|
+
var gitHead = "9a1bfacce5cc21ca2d64e79c86805dab37568de3";
|
|
59
66
|
var packageJson = {
|
|
60
67
|
name: name,
|
|
61
68
|
version: version$1,
|
|
@@ -81,6 +88,24 @@ var packageJson = {
|
|
|
81
88
|
const version = packageJson.version;
|
|
82
89
|
// use a custom Console to indicate we really want to log to the console and it's not incidental. `console.log` causes an eslint error
|
|
83
90
|
const Console = console;
|
|
91
|
+
/**
|
|
92
|
+
* The protocol used to communicate with the application
|
|
93
|
+
*/
|
|
94
|
+
exports.Protocol = void 0;
|
|
95
|
+
(function (Protocol) {
|
|
96
|
+
/**
|
|
97
|
+
* Regular encrypted HTTPS, without support for post-escalation message handling, interim messages and other streaming features.
|
|
98
|
+
*/
|
|
99
|
+
Protocol["Https"] = "https";
|
|
100
|
+
/**
|
|
101
|
+
* Encrypted HTTPS with streaming enabled. This is the default setting and supports interim messages. Does not support post-escalation message handling.
|
|
102
|
+
*/
|
|
103
|
+
Protocol["HttpsWithStreaming"] = "httpsWithStreaming";
|
|
104
|
+
/**
|
|
105
|
+
* Websocket, with support for post-escalation message handling.
|
|
106
|
+
*/
|
|
107
|
+
Protocol["Websocket"] = "websocket";
|
|
108
|
+
})(exports.Protocol || (exports.Protocol = {}));
|
|
84
109
|
/**
|
|
85
110
|
* Response type
|
|
86
111
|
*/
|
|
@@ -127,42 +152,181 @@ const safeJsonParse = (val) => {
|
|
|
127
152
|
return null;
|
|
128
153
|
}
|
|
129
154
|
};
|
|
130
|
-
const
|
|
155
|
+
const getHost = (url) => url.match(/(bots\.dev\.studio\.nlx\.ai|bots\.studio\.nlx\.ai|apps\.nlx\.ai|dev\.apps\.nlx\.ai)/g)?.[0] ?? "apps.nlx.ai";
|
|
131
156
|
/**
|
|
132
|
-
*
|
|
133
|
-
* @param
|
|
134
|
-
* @returns
|
|
157
|
+
* Parse configuration into structured connection information, taking into account `applicationUrl`-based configs.
|
|
158
|
+
* @param config - client configuration.
|
|
159
|
+
* @returns connection - connection information, or `null` if the configuration is invalid.
|
|
135
160
|
*/
|
|
136
|
-
const
|
|
161
|
+
const parseConnection = (config) => {
|
|
162
|
+
const applicationUrl = config.applicationUrl ?? "";
|
|
163
|
+
const apiKey = config.apiKey ?? config.headers?.["nlx-api-key"] ?? "";
|
|
164
|
+
const protocol = config.protocol ??
|
|
165
|
+
/**
|
|
166
|
+
* Backwards-compatibility: if a websocket URL was specified, assume it's websocket. Otherwise, look at the legacy experimental streamsetting
|
|
167
|
+
* and only assume non-streaming if it's explicitly set to false.
|
|
168
|
+
*/
|
|
169
|
+
(isWebsocketUrl(applicationUrl)
|
|
170
|
+
? exports.Protocol.Websocket
|
|
171
|
+
: config.experimental?.streamHttp === false
|
|
172
|
+
? exports.Protocol.Https
|
|
173
|
+
: exports.Protocol.HttpsWithStreaming);
|
|
174
|
+
if (config.host != null &&
|
|
175
|
+
config.channelKey != null &&
|
|
176
|
+
config.deploymentKey != null) {
|
|
177
|
+
return {
|
|
178
|
+
protocol,
|
|
179
|
+
apiKey,
|
|
180
|
+
host: config.host,
|
|
181
|
+
channelKey: config.channelKey,
|
|
182
|
+
deploymentKey: config.deploymentKey,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
// `applicationUrl`-based definition: websocket case
|
|
137
186
|
if (isWebsocketUrl(applicationUrl)) {
|
|
138
|
-
|
|
187
|
+
const host = getHost(applicationUrl);
|
|
188
|
+
const url = new URL(applicationUrl);
|
|
189
|
+
const params = new URLSearchParams(url.search);
|
|
190
|
+
const channelKey = params.get("channelKey");
|
|
191
|
+
const deploymentKey = params.get("deploymentKey");
|
|
192
|
+
if (channelKey != null && deploymentKey != null) {
|
|
193
|
+
return { protocol, channelKey, deploymentKey, host, apiKey };
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
139
196
|
}
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return applicationUrl;
|
|
197
|
+
// `applicationUrl`-based definition: http case
|
|
198
|
+
const host = getHost(applicationUrl);
|
|
199
|
+
const parseResult = new URLPattern({
|
|
200
|
+
pathname: "/c/:deploymentKey/:channelKey",
|
|
201
|
+
}).exec(applicationUrl);
|
|
202
|
+
if (parseResult?.pathname.groups.channelKey != null &&
|
|
203
|
+
parseResult?.pathname.groups.deploymentKey != null) {
|
|
204
|
+
return {
|
|
205
|
+
protocol,
|
|
206
|
+
channelKey: parseResult.pathname.groups.channelKey,
|
|
207
|
+
deploymentKey: parseResult.pathname.groups.deploymentKey,
|
|
208
|
+
host,
|
|
209
|
+
apiKey,
|
|
210
|
+
};
|
|
155
211
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
212
|
+
return null;
|
|
213
|
+
};
|
|
214
|
+
const toWebsocketUrl = (connection) => {
|
|
215
|
+
return `wss://us-east-1-ws.${connection.host}?deploymentKey=${connection.deploymentKey}&channelKey=${connection.channelKey}&apiKey=${connection.apiKey}`;
|
|
216
|
+
};
|
|
217
|
+
const toHttpUrl = (connection) => {
|
|
218
|
+
return `https://${connection.host}/c/${connection.deploymentKey}/${connection.channelKey}`;
|
|
162
219
|
};
|
|
163
220
|
const isWebsocketUrl = (url) => {
|
|
164
221
|
return url.indexOf("wss://") === 0;
|
|
165
222
|
};
|
|
223
|
+
const fetchUserMessage = async ({ fullApplicationUrl, apiKey, headers, body, stream, eventListeners, }) => {
|
|
224
|
+
const streamRequest = async (body) => {
|
|
225
|
+
const response = await fetch(fullApplicationUrl, {
|
|
226
|
+
method: "POST",
|
|
227
|
+
headers: {
|
|
228
|
+
...headers,
|
|
229
|
+
"nlx-api-key": apiKey,
|
|
230
|
+
"Content-Type": "application/json",
|
|
231
|
+
// Legacy header
|
|
232
|
+
"nlx-sdk-version": packageJson.version,
|
|
233
|
+
"nlx-core-version": packageJson.version,
|
|
234
|
+
},
|
|
235
|
+
body: JSON.stringify({ ...body, stream: true }),
|
|
236
|
+
});
|
|
237
|
+
if (!response.ok || response.body == null)
|
|
238
|
+
throw new Error(`HTTP Error: ${response.status}`);
|
|
239
|
+
const reader = response.body.getReader();
|
|
240
|
+
const decoder = new TextDecoder();
|
|
241
|
+
let buffer = "";
|
|
242
|
+
const messages = [];
|
|
243
|
+
let finalResponse = {};
|
|
244
|
+
while (true) {
|
|
245
|
+
const { done, value } = await reader.read();
|
|
246
|
+
if (done)
|
|
247
|
+
break;
|
|
248
|
+
buffer += decoder.decode(value, { stream: true });
|
|
249
|
+
while (true) {
|
|
250
|
+
const openBrace = buffer.indexOf("{");
|
|
251
|
+
if (openBrace === -1)
|
|
252
|
+
break;
|
|
253
|
+
let foundObject = false;
|
|
254
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
255
|
+
if (buffer[i] === "}") {
|
|
256
|
+
const candidate = buffer.substring(openBrace, i + 1);
|
|
257
|
+
try {
|
|
258
|
+
const json = JSON.parse(candidate);
|
|
259
|
+
if (json.type === "interim") {
|
|
260
|
+
const text = json.text;
|
|
261
|
+
if (typeof text === "string") {
|
|
262
|
+
eventListeners.interimMessage.forEach((listener) => {
|
|
263
|
+
listener(text);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
else if (json.type === "message") {
|
|
268
|
+
messages.push({
|
|
269
|
+
text: json.text,
|
|
270
|
+
choices: json.choices ?? [],
|
|
271
|
+
messageId: json.messageId,
|
|
272
|
+
metadata: json.metadata,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
else if (json.type === "final_response") {
|
|
276
|
+
finalResponse = json.data;
|
|
277
|
+
}
|
|
278
|
+
buffer = buffer.substring(i + 1);
|
|
279
|
+
foundObject = true;
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
catch (e) {
|
|
283
|
+
/* keep scanning */
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (!foundObject)
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
eventListeners.interimMessage.forEach((listener) => {
|
|
292
|
+
listener(undefined);
|
|
293
|
+
});
|
|
294
|
+
return {
|
|
295
|
+
...finalResponse,
|
|
296
|
+
messages: [
|
|
297
|
+
...messages,
|
|
298
|
+
...(finalResponse.messages ?? []).map((json) => ({
|
|
299
|
+
text: json.text,
|
|
300
|
+
choices: json.choices ?? [],
|
|
301
|
+
messageId: json.messageId,
|
|
302
|
+
metadata: json.metadata,
|
|
303
|
+
})),
|
|
304
|
+
],
|
|
305
|
+
};
|
|
306
|
+
};
|
|
307
|
+
if (stream) {
|
|
308
|
+
return await streamRequest(body);
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
const response = await fetch(fullApplicationUrl, {
|
|
312
|
+
method: "POST",
|
|
313
|
+
headers: {
|
|
314
|
+
...(headers ?? {}),
|
|
315
|
+
"nlx-api-key": apiKey,
|
|
316
|
+
Accept: "application/json",
|
|
317
|
+
"Content-Type": "application/json",
|
|
318
|
+
// Legacy header
|
|
319
|
+
"nlx-sdk-version": packageJson.version,
|
|
320
|
+
"nlx-core-version": packageJson.version,
|
|
321
|
+
},
|
|
322
|
+
body: JSON.stringify(body),
|
|
323
|
+
});
|
|
324
|
+
if (!response.ok || response.body == null)
|
|
325
|
+
throw new Error(`HTTP Error: ${response.status}`);
|
|
326
|
+
const json = await response.json();
|
|
327
|
+
return json;
|
|
328
|
+
}
|
|
329
|
+
};
|
|
166
330
|
/**
|
|
167
331
|
* Call this to create a conversation handler.
|
|
168
332
|
* @param configuration - The necessary configuration to create the conversation.
|
|
@@ -188,12 +352,21 @@ function createConversation(configuration) {
|
|
|
188
352
|
let voicePlusSocket;
|
|
189
353
|
let voicePlusSocketMessageQueue = [];
|
|
190
354
|
let voicePlusSocketMessageQueueCheckInterval = null;
|
|
191
|
-
const
|
|
355
|
+
const connection = parseConnection(configuration);
|
|
356
|
+
const websocketApplicationUrl = connection != null
|
|
357
|
+
? toWebsocketUrl(connection)
|
|
358
|
+
: configuration.applicationUrl ?? "";
|
|
359
|
+
const httpApplicationUrl = connection != null
|
|
360
|
+
? toHttpUrl(connection)
|
|
361
|
+
: configuration.applicationUrl ?? "";
|
|
192
362
|
// Check if the application URL has a language code appended to it
|
|
193
|
-
if (/[-|_][a-z]{2,}[-|_][A-Z]{2,}$/.test(
|
|
363
|
+
if (/[-|_][a-z]{2,}[-|_][A-Z]{2,}$/.test(httpApplicationUrl)) {
|
|
194
364
|
Console.warn("Since v1.0.0, the language code is no longer added at the end of the application URL. Please remove the modifier (e.g. '-en-US') from the URL, and specify it in the `languageCode` parameter instead.");
|
|
195
365
|
}
|
|
196
|
-
const eventListeners = {
|
|
366
|
+
const eventListeners = {
|
|
367
|
+
voicePlusCommand: [],
|
|
368
|
+
interimMessage: [],
|
|
369
|
+
};
|
|
197
370
|
const initialConversationId = configuration.conversationId ?? uuid.v4();
|
|
198
371
|
let state = {
|
|
199
372
|
responses: configuration.responses ?? [],
|
|
@@ -201,7 +374,7 @@ function createConversation(configuration) {
|
|
|
201
374
|
userId: configuration.userId,
|
|
202
375
|
conversationId: initialConversationId,
|
|
203
376
|
};
|
|
204
|
-
const fullApplicationHttpUrl = () => `${
|
|
377
|
+
const fullApplicationHttpUrl = () => `${httpApplicationUrl}${configuration.experimental?.completeApplicationUrl === true
|
|
205
378
|
? ""
|
|
206
379
|
: `-${state.languageCode}`}`;
|
|
207
380
|
const setState = (change,
|
|
@@ -295,7 +468,7 @@ function createConversation(configuration) {
|
|
|
295
468
|
channelType: configuration.experimental?.channelType,
|
|
296
469
|
environment: configuration.environment,
|
|
297
470
|
};
|
|
298
|
-
if (
|
|
471
|
+
if (connection?.protocol === exports.Protocol.Websocket) {
|
|
299
472
|
if (socket?.readyState === 1) {
|
|
300
473
|
socket.send(JSON.stringify(bodyWithContext));
|
|
301
474
|
}
|
|
@@ -305,20 +478,14 @@ function createConversation(configuration) {
|
|
|
305
478
|
}
|
|
306
479
|
else {
|
|
307
480
|
try {
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
},
|
|
316
|
-
body: JSON.stringify(bodyWithContext),
|
|
481
|
+
const json = await fetchUserMessage({
|
|
482
|
+
fullApplicationUrl: fullApplicationHttpUrl(),
|
|
483
|
+
apiKey: connection?.apiKey ?? "",
|
|
484
|
+
headers: configuration.headers ?? {},
|
|
485
|
+
stream: connection?.protocol === exports.Protocol.HttpsWithStreaming,
|
|
486
|
+
eventListeners,
|
|
487
|
+
body: bodyWithContext,
|
|
317
488
|
});
|
|
318
|
-
if (res.status >= 400) {
|
|
319
|
-
throw new Error(`Responded with ${res.status}`);
|
|
320
|
-
}
|
|
321
|
-
const json = await res.json();
|
|
322
489
|
messageResponseHandler(json);
|
|
323
490
|
}
|
|
324
491
|
catch (err) {
|
|
@@ -344,7 +511,7 @@ function createConversation(configuration) {
|
|
|
344
511
|
const setupWebsocket = () => {
|
|
345
512
|
// If the socket is already set up, tear it down first
|
|
346
513
|
teardownWebsocket();
|
|
347
|
-
const url = new URL(
|
|
514
|
+
const url = new URL(websocketApplicationUrl);
|
|
348
515
|
if (configuration.experimental?.completeApplicationUrl !== true) {
|
|
349
516
|
url.searchParams.set("languageCode", state.languageCode);
|
|
350
517
|
url.searchParams.set("channelKey", `${url.searchParams.get("channelKey") ?? ""}-${state.languageCode}`);
|
|
@@ -359,21 +526,6 @@ function createConversation(configuration) {
|
|
|
359
526
|
messageResponseHandler(safeJsonParse(e.data));
|
|
360
527
|
}
|
|
361
528
|
};
|
|
362
|
-
url.searchParams.set("voice-plus", "true");
|
|
363
|
-
voicePlusSocket = new ReconnectingWebSocket(url.href);
|
|
364
|
-
voicePlusSocketMessageQueueCheckInterval = setInterval(() => {
|
|
365
|
-
checkVoicePlusSocketQueue();
|
|
366
|
-
}, 500);
|
|
367
|
-
voicePlusSocket.onmessage = (e) => {
|
|
368
|
-
if (typeof e?.data === "string") {
|
|
369
|
-
const command = safeJsonParse(e.data);
|
|
370
|
-
if (command != null) {
|
|
371
|
-
eventListeners.voicePlusCommand.forEach((listener) => {
|
|
372
|
-
listener(command);
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
};
|
|
377
529
|
};
|
|
378
530
|
const setupCommandWebsocket = () => {
|
|
379
531
|
// If the socket is already set up, tear it down first
|
|
@@ -381,16 +533,15 @@ function createConversation(configuration) {
|
|
|
381
533
|
if (configuration.bidirectional !== true) {
|
|
382
534
|
return;
|
|
383
535
|
}
|
|
384
|
-
const url = new URL(
|
|
536
|
+
const url = new URL(websocketApplicationUrl);
|
|
385
537
|
if (configuration.experimental?.completeApplicationUrl !== true) {
|
|
386
538
|
url.searchParams.set("languageCode", state.languageCode);
|
|
387
539
|
url.searchParams.set("channelKey", `${url.searchParams.get("channelKey") ?? ""}-${state.languageCode}`);
|
|
388
540
|
}
|
|
389
541
|
url.searchParams.set("conversationId", state.conversationId);
|
|
390
542
|
url.searchParams.set("type", "voice-plus");
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
url.searchParams.set("apiKey", apiKey);
|
|
543
|
+
if (connection?.apiKey != null) {
|
|
544
|
+
url.searchParams.set("apiKey", connection.apiKey);
|
|
394
545
|
}
|
|
395
546
|
voicePlusSocket = new ReconnectingWebSocket(url.href);
|
|
396
547
|
voicePlusSocketMessageQueueCheckInterval = setInterval(() => {
|
|
@@ -427,7 +578,7 @@ function createConversation(configuration) {
|
|
|
427
578
|
voicePlusSocket = undefined;
|
|
428
579
|
}
|
|
429
580
|
};
|
|
430
|
-
if (
|
|
581
|
+
if (connection?.protocol === exports.Protocol.Websocket) {
|
|
431
582
|
setupWebsocket();
|
|
432
583
|
}
|
|
433
584
|
setupCommandWebsocket();
|
|
@@ -533,10 +684,13 @@ function createConversation(configuration) {
|
|
|
533
684
|
method: "POST",
|
|
534
685
|
headers: {
|
|
535
686
|
...(configuration.headers ?? {}),
|
|
687
|
+
"nlx-api-key": connection?.apiKey ?? "",
|
|
536
688
|
Accept: "application/json",
|
|
537
689
|
"Content-Type": "application/json",
|
|
538
690
|
"nlx-conversation-id": state.conversationId,
|
|
691
|
+
// Legacy header
|
|
539
692
|
"nlx-sdk-version": packageJson.version,
|
|
693
|
+
"nlx-core-version": packageJson.version,
|
|
540
694
|
},
|
|
541
695
|
body: JSON.stringify({
|
|
542
696
|
languageCode: state.languageCode,
|
|
@@ -591,6 +745,23 @@ function createConversation(configuration) {
|
|
|
591
745
|
sendFlow(welcomeIntent, context);
|
|
592
746
|
},
|
|
593
747
|
sendChoice,
|
|
748
|
+
submitFeedback: async (feedbackUrl, feedback) => {
|
|
749
|
+
const res = await fetch(feedbackUrl, {
|
|
750
|
+
method: "POST",
|
|
751
|
+
headers: {
|
|
752
|
+
"Content-Type": "application/json",
|
|
753
|
+
},
|
|
754
|
+
body: JSON.stringify({
|
|
755
|
+
languageCode: state.languageCode,
|
|
756
|
+
conversationId: state.conversationId,
|
|
757
|
+
userId: state.userId,
|
|
758
|
+
...feedback,
|
|
759
|
+
}),
|
|
760
|
+
});
|
|
761
|
+
if (res.status >= 400) {
|
|
762
|
+
throw new Error(`Responded with ${res.status}`);
|
|
763
|
+
}
|
|
764
|
+
},
|
|
594
765
|
currentConversationId: () => {
|
|
595
766
|
return state.conversationId;
|
|
596
767
|
},
|
|
@@ -599,7 +770,7 @@ function createConversation(configuration) {
|
|
|
599
770
|
Console.warn("Attempted to set language code to the one already active.");
|
|
600
771
|
return;
|
|
601
772
|
}
|
|
602
|
-
if (
|
|
773
|
+
if (connection?.protocol === exports.Protocol.Websocket) {
|
|
603
774
|
setupWebsocket();
|
|
604
775
|
}
|
|
605
776
|
setupCommandWebsocket();
|
|
@@ -609,15 +780,17 @@ function createConversation(configuration) {
|
|
|
609
780
|
return state.languageCode;
|
|
610
781
|
},
|
|
611
782
|
getVoiceCredentials: async (context, options) => {
|
|
612
|
-
const
|
|
613
|
-
const res = await fetch(`${url}-${state.languageCode}/requestToken`, {
|
|
783
|
+
const res = await fetch(`${httpApplicationUrl}-${state.languageCode}/requestToken`, {
|
|
614
784
|
method: "POST",
|
|
615
785
|
headers: {
|
|
616
786
|
...(configuration.headers ?? {}),
|
|
787
|
+
"nlx-api-key": connection?.apiKey ?? "",
|
|
617
788
|
Accept: "application/json",
|
|
618
789
|
"Content-Type": "application/json",
|
|
619
790
|
"nlx-conversation-id": state.conversationId,
|
|
791
|
+
// Legacy header
|
|
620
792
|
"nlx-sdk-version": packageJson.version,
|
|
793
|
+
"nlx-core-version": packageJson.version,
|
|
621
794
|
},
|
|
622
795
|
body: JSON.stringify({
|
|
623
796
|
languageCode: state.languageCode,
|
|
@@ -647,14 +820,14 @@ function createConversation(configuration) {
|
|
|
647
820
|
conversationId: uuid.v4(),
|
|
648
821
|
responses: options?.clearResponses === true ? [] : state.responses,
|
|
649
822
|
});
|
|
650
|
-
if (
|
|
823
|
+
if (connection?.protocol === exports.Protocol.Websocket) {
|
|
651
824
|
setupWebsocket();
|
|
652
825
|
}
|
|
653
826
|
setupCommandWebsocket();
|
|
654
827
|
},
|
|
655
828
|
destroy: () => {
|
|
656
829
|
subscribers = [];
|
|
657
|
-
if (
|
|
830
|
+
if (connection?.protocol === exports.Protocol.Websocket) {
|
|
658
831
|
teardownWebsocket();
|
|
659
832
|
}
|
|
660
833
|
teardownCommandWebsocket();
|
|
@@ -679,8 +852,7 @@ function createConversation(configuration) {
|
|
|
679
852
|
* @returns Whether the configuration is valid?
|
|
680
853
|
*/
|
|
681
854
|
const isConfigValid = (configuration) => {
|
|
682
|
-
|
|
683
|
-
return applicationUrl.length > 0;
|
|
855
|
+
return parseConnection(configuration) != null;
|
|
684
856
|
};
|
|
685
857
|
/**
|
|
686
858
|
* Helper method to decide when a new {@link Config} requires creating a new {@link ConversationHandler} or whether the old `Config`'s
|
|
@@ -773,10 +945,77 @@ function promisify(fn, convo, timeout = 10000) {
|
|
|
773
945
|
});
|
|
774
946
|
};
|
|
775
947
|
}
|
|
948
|
+
/**
|
|
949
|
+
* Use this function when using **Voice+ scripts** to advance the conversation to the step specified.
|
|
950
|
+
*
|
|
951
|
+
* This functionality is orthogonal from other usage of the core SDK, as it may be used either using standard SDK communication channels or it can be used to provide a Voice+ script experience with for instance a telephony based channel.
|
|
952
|
+
* @example
|
|
953
|
+
* ```typescript
|
|
954
|
+
* import { sendVoicePlusStep } from "@nlxai/core";
|
|
955
|
+
*
|
|
956
|
+
* await sendVoicePlusStep({
|
|
957
|
+
* // hard-coded params
|
|
958
|
+
* apiKey: "REPLACE_WITH_API_KEY",
|
|
959
|
+
* workspaceId: "REPLACE_WITH_WORKSPACE_ID",
|
|
960
|
+
* scriptId: "REPLACE_WITH_SCRIPT_ID",
|
|
961
|
+
* step: "REPLACE_WITH_STEP_ID",
|
|
962
|
+
* // dynamic params
|
|
963
|
+
* conversationId: "REPLACE_WITH_CONVERSATION_ID",
|
|
964
|
+
* languageCode: "en-US",
|
|
965
|
+
* });
|
|
966
|
+
* ```
|
|
967
|
+
* @param configuration - Configuration for sending the step. Many of the values can be found on the deployment modal of the Voice+ script.
|
|
968
|
+
*/
|
|
969
|
+
const sendVoicePlusStep = async ({ apiKey, workspaceId, conversationId, scriptId, languageCode, step, context, debug = false, dev = false, }) => {
|
|
970
|
+
if (scriptId == null) {
|
|
971
|
+
throw new Error("Voice+ scriptId is not defined.");
|
|
972
|
+
}
|
|
973
|
+
if (typeof conversationId !== "string" || conversationId.length === 0) {
|
|
974
|
+
throw new Error("Voice+ conversationId is not defined.");
|
|
975
|
+
}
|
|
976
|
+
const [stepId, stepTriggerDescription] = typeof step === "string"
|
|
977
|
+
? [step, undefined]
|
|
978
|
+
: [step.stepId, step.stepTriggerDescription];
|
|
979
|
+
if (!stepIdRegex.test(stepId)) {
|
|
980
|
+
throw new Error("Invalid stepId. It should be formatted as a UUID.");
|
|
981
|
+
}
|
|
982
|
+
const payload = {
|
|
983
|
+
stepId,
|
|
984
|
+
context,
|
|
985
|
+
conversationId,
|
|
986
|
+
journeyId: scriptId,
|
|
987
|
+
languageCode,
|
|
988
|
+
stepTriggerDescription,
|
|
989
|
+
};
|
|
990
|
+
try {
|
|
991
|
+
await fetch(`https://${dev ? "dev." : ""}mm.nlx.ai/v1/track`, {
|
|
992
|
+
method: "POST",
|
|
993
|
+
headers: {
|
|
994
|
+
"x-api-key": apiKey,
|
|
995
|
+
"x-nlx-id": workspaceId,
|
|
996
|
+
"Content-Type": "application/json",
|
|
997
|
+
"nlx-sdk-version": packageJson.version,
|
|
998
|
+
"nlx-core-version": packageJson.version,
|
|
999
|
+
},
|
|
1000
|
+
body: JSON.stringify(payload),
|
|
1001
|
+
});
|
|
1002
|
+
if (debug) {
|
|
1003
|
+
Console.info(`✓ step: ${stepId}`, payload);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
catch (err) {
|
|
1007
|
+
if (debug) {
|
|
1008
|
+
Console.error(`× step: ${stepId}`, err, payload);
|
|
1009
|
+
}
|
|
1010
|
+
throw err;
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
const stepIdRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
776
1014
|
|
|
777
1015
|
exports.createConversation = createConversation;
|
|
778
1016
|
exports.getCurrentExpirationTimestamp = getCurrentExpirationTimestamp;
|
|
779
1017
|
exports.isConfigValid = isConfigValid;
|
|
780
1018
|
exports.promisify = promisify;
|
|
1019
|
+
exports.sendVoicePlusStep = sendVoicePlusStep;
|
|
781
1020
|
exports.shouldReinitialize = shouldReinitialize;
|
|
782
1021
|
exports.version = version;
|