@nlxai/core 1.2.3-alpha.1 → 1.2.3
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 +1877 -34
- package/lib/index.cjs +100 -55
- package/lib/index.d.ts +255 -201
- package/lib/index.esm.js +100 -55
- package/lib/index.umd.js +2 -2
- package/package.json +12 -12
- package/typedoc.cjs +9 -2
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.3
|
|
9
|
+
var version$1 = "1.2.3";
|
|
10
10
|
var description = "Low-level SDK for building NLX experiences";
|
|
11
11
|
var type = "module";
|
|
12
12
|
var main = "lib/index.cjs";
|
|
@@ -22,40 +22,40 @@ var exports$1 = {
|
|
|
22
22
|
};
|
|
23
23
|
var scripts = {
|
|
24
24
|
build: "rm -rf lib && rollup -c --configPlugin typescript --configImportAttributesKey with",
|
|
25
|
-
docs: "rm -rf docs/ && typedoc && concat-md --decrease-title-levels --dir-name-as-title docs/ > docs/index.md",
|
|
26
25
|
"lint:check": "eslint src/ --ext .ts,.tsx,.js,.jsx --max-warnings 0",
|
|
27
26
|
lint: "eslint src/ --ext .ts,.tsx,.js,.jsx --fix",
|
|
28
27
|
prepublish: "npm run build",
|
|
29
|
-
"preview-docs": "npm run docs && comrak --unsafe --gfm -o docs/index.html docs/index.md && open docs/index.html",
|
|
30
|
-
"publish-docs": "npm run docs && mv docs/index.md ../website/src/content/headless-api-reference.md",
|
|
31
28
|
test: "typedoc --emit none",
|
|
32
|
-
tsc: "tsc"
|
|
29
|
+
tsc: "tsc",
|
|
30
|
+
"update-readme:docs": "rm -rf docs/ && typedoc",
|
|
31
|
+
"update-readme:merge": "../../scripts/transclude-markdown.js",
|
|
32
|
+
"update-readme": "npm run update-readme:docs && npm run update-readme:merge"
|
|
33
33
|
};
|
|
34
34
|
var author = "Peter Szerzo <peter@nlx.ai>";
|
|
35
35
|
var license = "MIT";
|
|
36
36
|
var devDependencies = {
|
|
37
|
-
"@types/isomorphic-fetch": "^0.0.
|
|
38
|
-
"@types/node": "^
|
|
39
|
-
"@types/ramda": "0.
|
|
37
|
+
"@types/isomorphic-fetch": "^0.0.39",
|
|
38
|
+
"@types/node": "^24.10.1",
|
|
39
|
+
"@types/ramda": "0.31.1",
|
|
40
40
|
"@types/uuid": "^9.0.7",
|
|
41
41
|
"concat-md": "^0.5.1",
|
|
42
42
|
"eslint-config-nlx": "*",
|
|
43
43
|
prettier: "^3.1.0",
|
|
44
44
|
"rollup-config-nlx": "*",
|
|
45
|
-
typedoc: "^0.
|
|
46
|
-
"typedoc-plugin-markdown": "^
|
|
45
|
+
typedoc: "^0.28.14",
|
|
46
|
+
"typedoc-plugin-markdown": "^4.9.0",
|
|
47
47
|
typescript: "^5.5.4"
|
|
48
48
|
};
|
|
49
49
|
var dependencies = {
|
|
50
50
|
"isomorphic-fetch": "^3.0.0",
|
|
51
|
-
ramda: "^0.
|
|
51
|
+
ramda: "^0.32.0",
|
|
52
52
|
"reconnecting-websocket": "^4.4.0",
|
|
53
53
|
uuid: "^9.0.1"
|
|
54
54
|
};
|
|
55
55
|
var publishConfig = {
|
|
56
56
|
access: "public"
|
|
57
57
|
};
|
|
58
|
-
var gitHead = "
|
|
58
|
+
var gitHead = "3902161e95745dd4a9cfb68bb469755a62b421f5";
|
|
59
59
|
var packageJson = {
|
|
60
60
|
name: name,
|
|
61
61
|
version: version$1,
|
|
@@ -127,18 +127,6 @@ const safeJsonParse = (val) => {
|
|
|
127
127
|
return null;
|
|
128
128
|
}
|
|
129
129
|
};
|
|
130
|
-
/**
|
|
131
|
-
* Helper method to decide when a new {@link Config} requires creating a new {@link ConversationHandler} or whether the old `Config`'s
|
|
132
|
-
* `ConversationHandler` can be used.
|
|
133
|
-
*
|
|
134
|
-
* The order of configs doesn't matter.
|
|
135
|
-
* @param config1 -
|
|
136
|
-
* @param config2 -
|
|
137
|
-
* @returns true if `createConversation` should be called again
|
|
138
|
-
*/
|
|
139
|
-
const shouldReinitialize = (config1, config2) => {
|
|
140
|
-
return !ramda.equals(config1, config2);
|
|
141
|
-
};
|
|
142
130
|
const getBaseDomain = (url) => url.match(/(bots\.dev\.studio\.nlx\.ai|bots\.studio\.nlx\.ai|apps\.nlx\.ai|dev\.apps\.nlx\.ai)/g)?.[0] ?? "apps.nlx.ai";
|
|
143
131
|
/**
|
|
144
132
|
* When a HTTP URL is provided, deduce the websocket URL. Otherwise, return the argument.
|
|
@@ -175,41 +163,45 @@ const normalizeToHttp = (applicationUrl) => {
|
|
|
175
163
|
const isWebsocketUrl = (url) => {
|
|
176
164
|
return url.indexOf("wss://") === 0;
|
|
177
165
|
};
|
|
178
|
-
/**
|
|
179
|
-
* Check whether a configuration is value.
|
|
180
|
-
* @param config - Chat configuration
|
|
181
|
-
* @returns isValid - Whether the configuration is valid
|
|
182
|
-
*/
|
|
183
|
-
const isConfigValid = (config) => {
|
|
184
|
-
const applicationUrl = config.applicationUrl ?? "";
|
|
185
|
-
return applicationUrl.length > 0;
|
|
186
|
-
};
|
|
187
166
|
/**
|
|
188
167
|
* Call this to create a conversation handler.
|
|
189
|
-
* @param
|
|
168
|
+
* @param configuration - The necessary configuration to create the conversation.
|
|
190
169
|
* @returns The {@link ConversationHandler} is a bundle of functions to interact with the conversation.
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* import { createConversation } from "@nlx/core";
|
|
173
|
+
*
|
|
174
|
+
* const conversation = createConversation({
|
|
175
|
+
* applicationUrl: "https://apps.nlx.ai/c/cfab3-243ad-232dc",
|
|
176
|
+
* headers: {
|
|
177
|
+
* "nlx-api-key": "4393029032-dwsd",
|
|
178
|
+
* },
|
|
179
|
+
* userId: "abcd-1234",
|
|
180
|
+
* languageCode: "en-US",
|
|
181
|
+
* });
|
|
182
|
+
* ```
|
|
191
183
|
*/
|
|
192
|
-
function createConversation(
|
|
184
|
+
function createConversation(configuration) {
|
|
193
185
|
let socket;
|
|
194
186
|
let socketMessageQueue = [];
|
|
195
187
|
let socketMessageQueueCheckInterval = null;
|
|
196
188
|
let voicePlusSocket;
|
|
197
189
|
let voicePlusSocketMessageQueue = [];
|
|
198
190
|
let voicePlusSocketMessageQueueCheckInterval = null;
|
|
199
|
-
const applicationUrl =
|
|
191
|
+
const applicationUrl = configuration.applicationUrl ?? "";
|
|
200
192
|
// Check if the application URL has a language code appended to it
|
|
201
193
|
if (/[-|_][a-z]{2,}[-|_][A-Z]{2,}$/.test(applicationUrl)) {
|
|
202
194
|
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.");
|
|
203
195
|
}
|
|
204
196
|
const eventListeners = { voicePlusCommand: [] };
|
|
205
|
-
const initialConversationId =
|
|
197
|
+
const initialConversationId = configuration.conversationId ?? uuid.v4();
|
|
206
198
|
let state = {
|
|
207
|
-
responses:
|
|
208
|
-
languageCode:
|
|
209
|
-
userId:
|
|
199
|
+
responses: configuration.responses ?? [],
|
|
200
|
+
languageCode: configuration.languageCode,
|
|
201
|
+
userId: configuration.userId,
|
|
210
202
|
conversationId: initialConversationId,
|
|
211
203
|
};
|
|
212
|
-
const fullApplicationHttpUrl = () => `${normalizeToHttp(applicationUrl)}${
|
|
204
|
+
const fullApplicationHttpUrl = () => `${normalizeToHttp(applicationUrl)}${configuration.experimental?.completeApplicationUrl === true
|
|
213
205
|
? ""
|
|
214
206
|
: `-${state.languageCode}`}`;
|
|
215
207
|
const setState = (change,
|
|
@@ -228,7 +220,7 @@ function createConversation(config) {
|
|
|
228
220
|
type: exports.ResponseType.Failure,
|
|
229
221
|
receivedAt: new Date().getTime(),
|
|
230
222
|
payload: {
|
|
231
|
-
text:
|
|
223
|
+
text: configuration.failureMessage ?? defaultFailureMessage,
|
|
232
224
|
},
|
|
233
225
|
};
|
|
234
226
|
setState({
|
|
@@ -283,6 +275,7 @@ function createConversation(config) {
|
|
|
283
275
|
const sendToApplication = async (body) => {
|
|
284
276
|
if (requestOverride != null) {
|
|
285
277
|
requestOverride(body, (payload) => {
|
|
278
|
+
Console.warn("Using the second argument in `setRequestOverride` is deprecated. Use `conversationHandler.appendMessageToTranscript` instead.");
|
|
286
279
|
const newResponse = {
|
|
287
280
|
type: exports.ResponseType.Application,
|
|
288
281
|
receivedAt: new Date().getTime(),
|
|
@@ -299,8 +292,8 @@ function createConversation(config) {
|
|
|
299
292
|
conversationId: state.conversationId,
|
|
300
293
|
...body,
|
|
301
294
|
languageCode: state.languageCode,
|
|
302
|
-
channelType:
|
|
303
|
-
environment:
|
|
295
|
+
channelType: configuration.experimental?.channelType,
|
|
296
|
+
environment: configuration.environment,
|
|
304
297
|
};
|
|
305
298
|
if (isWebsocketUrl(applicationUrl)) {
|
|
306
299
|
if (socket?.readyState === 1) {
|
|
@@ -315,7 +308,7 @@ function createConversation(config) {
|
|
|
315
308
|
const res = await fetch(fullApplicationHttpUrl(), {
|
|
316
309
|
method: "POST",
|
|
317
310
|
headers: {
|
|
318
|
-
...(
|
|
311
|
+
...(configuration.headers ?? {}),
|
|
319
312
|
Accept: "application/json",
|
|
320
313
|
"Content-Type": "application/json",
|
|
321
314
|
"nlx-sdk-version": packageJson.version,
|
|
@@ -352,7 +345,7 @@ function createConversation(config) {
|
|
|
352
345
|
// If the socket is already set up, tear it down first
|
|
353
346
|
teardownWebsocket();
|
|
354
347
|
const url = new URL(applicationUrl);
|
|
355
|
-
if (
|
|
348
|
+
if (configuration.experimental?.completeApplicationUrl !== true) {
|
|
356
349
|
url.searchParams.set("languageCode", state.languageCode);
|
|
357
350
|
url.searchParams.set("channelKey", `${url.searchParams.get("channelKey") ?? ""}-${state.languageCode}`);
|
|
358
351
|
}
|
|
@@ -385,17 +378,17 @@ function createConversation(config) {
|
|
|
385
378
|
const setupCommandWebsocket = () => {
|
|
386
379
|
// If the socket is already set up, tear it down first
|
|
387
380
|
teardownCommandWebsocket();
|
|
388
|
-
if (
|
|
381
|
+
if (configuration.bidirectional !== true) {
|
|
389
382
|
return;
|
|
390
383
|
}
|
|
391
384
|
const url = new URL(normalizeToWebsocket(applicationUrl));
|
|
392
|
-
if (
|
|
385
|
+
if (configuration.experimental?.completeApplicationUrl !== true) {
|
|
393
386
|
url.searchParams.set("languageCode", state.languageCode);
|
|
394
387
|
url.searchParams.set("channelKey", `${url.searchParams.get("channelKey") ?? ""}-${state.languageCode}`);
|
|
395
388
|
}
|
|
396
389
|
url.searchParams.set("conversationId", state.conversationId);
|
|
397
390
|
url.searchParams.set("type", "voice-plus");
|
|
398
|
-
const apiKey =
|
|
391
|
+
const apiKey = configuration.headers["nlx-api-key"];
|
|
399
392
|
if (!isWebsocketUrl(applicationUrl) && apiKey != null) {
|
|
400
393
|
url.searchParams.set("apiKey", apiKey);
|
|
401
394
|
}
|
|
@@ -539,7 +532,7 @@ function createConversation(config) {
|
|
|
539
532
|
const res = await fetch(`${fullApplicationHttpUrl()}/context`, {
|
|
540
533
|
method: "POST",
|
|
541
534
|
headers: {
|
|
542
|
-
...(
|
|
535
|
+
...(configuration.headers ?? {}),
|
|
543
536
|
Accept: "application/json",
|
|
544
537
|
"Content-Type": "application/json",
|
|
545
538
|
"nlx-conversation-id": state.conversationId,
|
|
@@ -556,6 +549,15 @@ function createConversation(config) {
|
|
|
556
549
|
throw new Error(`Responded with ${res.status}`);
|
|
557
550
|
}
|
|
558
551
|
},
|
|
552
|
+
appendMessageToTranscript: (newResponse) => {
|
|
553
|
+
const newResponseWithTimestamp = {
|
|
554
|
+
...newResponse,
|
|
555
|
+
receivedAt: newResponse.receivedAt ?? new Date().getTime(),
|
|
556
|
+
};
|
|
557
|
+
setState({
|
|
558
|
+
responses: [...state.responses, newResponseWithTimestamp],
|
|
559
|
+
}, newResponseWithTimestamp);
|
|
560
|
+
},
|
|
559
561
|
sendStructured: (structured, context) => {
|
|
560
562
|
appendStructuredUserResponse(structured, context);
|
|
561
563
|
void sendToApplication({
|
|
@@ -611,7 +613,7 @@ function createConversation(config) {
|
|
|
611
613
|
const res = await fetch(`${url}-${state.languageCode}/requestToken`, {
|
|
612
614
|
method: "POST",
|
|
613
615
|
headers: {
|
|
614
|
-
...(
|
|
616
|
+
...(configuration.headers ?? {}),
|
|
615
617
|
Accept: "application/json",
|
|
616
618
|
"Content-Type": "application/json",
|
|
617
619
|
"nlx-conversation-id": state.conversationId,
|
|
@@ -672,9 +674,52 @@ function createConversation(config) {
|
|
|
672
674
|
};
|
|
673
675
|
}
|
|
674
676
|
/**
|
|
675
|
-
*
|
|
676
|
-
* @param
|
|
677
|
-
* @returns
|
|
677
|
+
* Check whether a configuration is valid.
|
|
678
|
+
* @param configuration - Conversation configuration
|
|
679
|
+
* @returns Whether the configuration is valid?
|
|
680
|
+
*/
|
|
681
|
+
const isConfigValid = (configuration) => {
|
|
682
|
+
const applicationUrl = configuration.applicationUrl ?? "";
|
|
683
|
+
return applicationUrl.length > 0;
|
|
684
|
+
};
|
|
685
|
+
/**
|
|
686
|
+
* Helper method to decide when a new {@link Config} requires creating a new {@link ConversationHandler} or whether the old `Config`'s
|
|
687
|
+
* `ConversationHandler` can be used.
|
|
688
|
+
*
|
|
689
|
+
* The order of configs doesn't matter.
|
|
690
|
+
* @param config1 -
|
|
691
|
+
* @param config2 -
|
|
692
|
+
* @returns true if `createConversation` should be called again
|
|
693
|
+
*/
|
|
694
|
+
const shouldReinitialize = (config1, config2) => {
|
|
695
|
+
return !ramda.equals(config1, config2);
|
|
696
|
+
};
|
|
697
|
+
/**
|
|
698
|
+
* Get current expiration timestamp from a list of responses. Can be used to determine if a conversation has timed out.
|
|
699
|
+
* @example
|
|
700
|
+
* ```typescript
|
|
701
|
+
* import { useState } from "react";
|
|
702
|
+
* import { getCurrentExpirationTimestamp } from "@nlxai/core";
|
|
703
|
+
*
|
|
704
|
+
* const [isTimedOut, setIsTimedOut] = useState(false);
|
|
705
|
+
*
|
|
706
|
+
* conversation.subscribe((responses) => {
|
|
707
|
+
* const expirationTimestamp = getCurrentExpirationTimestamp(responses);
|
|
708
|
+
* if (expirationTimestamp != null && expirationTimestamp < new Date().getTime()) {
|
|
709
|
+
* setIsTimedOut(true);
|
|
710
|
+
* }
|
|
711
|
+
* });
|
|
712
|
+
*
|
|
713
|
+
* return (<div>
|
|
714
|
+
* {isTimedOut ? (
|
|
715
|
+
* <p>Your session has timed out. Please start a new conversation.</p>
|
|
716
|
+
* ) : (
|
|
717
|
+
* <p>Your session is active.</p>
|
|
718
|
+
* )}
|
|
719
|
+
* </div>
|
|
720
|
+
* ```
|
|
721
|
+
* @param responses - The current list of user and application responses (first argument in the subscribe callback)
|
|
722
|
+
* @returns An expiration timestamp in Unix Epoch (`new Date().getTime()`), or `null` if this is not known (typically occurs if the application has not responded yet)
|
|
678
723
|
*/
|
|
679
724
|
const getCurrentExpirationTimestamp = (responses) => {
|
|
680
725
|
let expirationTimestamp = null;
|
|
@@ -702,7 +747,7 @@ const getCurrentExpirationTimestamp = (responses) => {
|
|
|
702
747
|
* console.log(response);
|
|
703
748
|
* });
|
|
704
749
|
* ```
|
|
705
|
-
* @typeParam
|
|
750
|
+
* @typeParam Params - the type of the function's params, e.g. for `sendText` it's `text: string, context?: Context`
|
|
706
751
|
* @param fn - the function to wrap (e.g. `convo.sendText`, `convo.sendChoice`, etc.)
|
|
707
752
|
* @param convo - the `ConversationHandler` (from {@link createConversation})
|
|
708
753
|
* @param timeout - the timeout in milliseconds
|