@webex/internal-plugin-llm 3.10.0 → 3.11.0-next.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 +83 -12
- package/dist/constants.js +3 -1
- package/dist/constants.js.map +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/llm.js +206 -55
- package/dist/llm.js.map +1 -1
- package/dist/llm.types.js +6 -0
- package/dist/llm.types.js.map +1 -1
- package/package.json +6 -6
- package/src/constants.ts +4 -0
- package/src/index.ts +2 -0
- package/src/llm.ts +188 -33
- package/src/llm.types.ts +28 -5
- package/test/unit/spec/llm.js +201 -3
package/README.md
CHANGED
|
@@ -23,22 +23,93 @@ npm install --save @webex/internal-plugin-llm
|
|
|
23
23
|
|
|
24
24
|
```js
|
|
25
25
|
import '@webex/internal-plugin-llm';
|
|
26
|
-
|
|
27
26
|
import WebexCore from '@webex/webex-core';
|
|
27
|
+
// Optional: import enum from package internals if needed in your app setup
|
|
28
|
+
// import {DataChannelTokenType} from '@webex/internal-plugin-llm/src/llm.types';
|
|
28
29
|
|
|
29
30
|
const webex = new WebexCore();
|
|
30
|
-
// locusUrl is got from meeting.locusInfo.url;
|
|
31
|
-
// datachannelUrl is got from meeting.locusInfo.info.datachannelUrl;
|
|
32
|
-
webex.internal.llm.registerAndConnect(locusUrl, datachannelUrl);
|
|
33
|
-
|
|
34
|
-
// Checks if LLM is connected
|
|
35
|
-
webex.internal.llm.isConnected();
|
|
36
|
-
|
|
37
|
-
// Disconnect LLM connection
|
|
38
|
-
webex.internal.llm.disconnectLLM();
|
|
39
31
|
|
|
40
|
-
//
|
|
41
|
-
|
|
32
|
+
// locusUrl and datachannelUrl are from meeting.locusInfo
|
|
33
|
+
const locusUrl = meeting.locusInfo.url;
|
|
34
|
+
const datachannelUrl = meeting.locusInfo.info.datachannelUrl;
|
|
35
|
+
|
|
36
|
+
// Optional JWT token for data channel auth
|
|
37
|
+
const datachannelToken = '<jwt-token>';
|
|
38
|
+
|
|
39
|
+
// Default session (no token)
|
|
40
|
+
await webex.internal.llm.registerAndConnect(locusUrl, datachannelUrl);
|
|
41
|
+
|
|
42
|
+
// Default session (with JWT token)
|
|
43
|
+
await webex.internal.llm.registerAndConnect(locusUrl, datachannelUrl, datachannelToken);
|
|
44
|
+
|
|
45
|
+
// Multiple named sessions
|
|
46
|
+
await webex.internal.llm.registerAndConnect(locusUrlA, datachannelUrlA, undefined, 'session-a');
|
|
47
|
+
await webex.internal.llm.registerAndConnect(
|
|
48
|
+
locusUrlB,
|
|
49
|
+
datachannelUrlB,
|
|
50
|
+
datachannelToken,
|
|
51
|
+
'session-b'
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// Listen across multiple connections
|
|
55
|
+
const llm = webex.internal.llm;
|
|
56
|
+
const sessionA = 'session-a';
|
|
57
|
+
const sessionB = 'session-b';
|
|
58
|
+
|
|
59
|
+
// Default session events use the base event name.
|
|
60
|
+
llm.on('online', () => {
|
|
61
|
+
console.log('[default] connected');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
llm.on('event', (envelope) => {
|
|
65
|
+
console.log('[default] event', envelope.data?.eventType, envelope.sessionId);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Non-default sessions emit events with :<sessionId> suffix.
|
|
69
|
+
llm.on(`online:${sessionA}`, () => {
|
|
70
|
+
console.log(`[${sessionA}] connected`);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
llm.on(`event:${sessionA}`, (envelope) => {
|
|
74
|
+
console.log(`[${sessionA}] event`, envelope.data?.eventType, envelope.sessionId);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
llm.on(`event:${sessionB}`, (envelope) => {
|
|
78
|
+
console.log(`[${sessionB}] event`, envelope.data?.eventType, envelope.sessionId);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Optional: store/retrieve token by token type
|
|
82
|
+
webex.internal.llm.setDatachannelToken(datachannelToken, 'DEFAULT');
|
|
83
|
+
webex.internal.llm.getDatachannelToken('DEFAULT');
|
|
84
|
+
|
|
85
|
+
// Optional: inject token refresh handler
|
|
86
|
+
webex.internal.llm.setRefreshHandler(async () => {
|
|
87
|
+
// Return shape must match plugin expectation
|
|
88
|
+
return {
|
|
89
|
+
body: {
|
|
90
|
+
datachannelToken: '<refreshed-jwt-token>',
|
|
91
|
+
datachannelTokenType: 'DEFAULT',
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Optional: manually trigger refresh (if needed by your flow)
|
|
97
|
+
await webex.internal.llm.refreshDataChannelToken();
|
|
98
|
+
|
|
99
|
+
// Per-session status and metadata
|
|
100
|
+
webex.internal.llm.isConnected('session-a');
|
|
101
|
+
webex.internal.llm.getBinding('session-a');
|
|
102
|
+
webex.internal.llm.getLocusUrl('session-a');
|
|
103
|
+
webex.internal.llm.getDatachannelUrl('session-a');
|
|
104
|
+
|
|
105
|
+
// All active sessions
|
|
106
|
+
webex.internal.llm.getAllConnections();
|
|
107
|
+
|
|
108
|
+
// Disconnect one session
|
|
109
|
+
await webex.internal.llm.disconnectLLM({code: 1000, reason: 'done'}, 'session-a');
|
|
110
|
+
|
|
111
|
+
// Disconnect all sessions
|
|
112
|
+
await webex.internal.llm.disconnectAllLLM({code: 1000, reason: 'shutdown'});
|
|
42
113
|
```
|
|
43
114
|
|
|
44
115
|
## Maintainers
|
package/dist/constants.js
CHANGED
|
@@ -4,7 +4,9 @@ var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/defi
|
|
|
4
4
|
_Object$defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
-
exports.LLM = void 0;
|
|
7
|
+
exports.LLM_DEFAULT_SESSION = exports.LLM = exports.DATA_CHANNEL_WITH_JWT_TOKEN = void 0;
|
|
8
8
|
// eslint-disable-next-line import/prefer-default-export
|
|
9
9
|
var LLM = exports.LLM = 'llm';
|
|
10
|
+
var LLM_DEFAULT_SESSION = exports.LLM_DEFAULT_SESSION = 'llm-default-session';
|
|
11
|
+
var DATA_CHANNEL_WITH_JWT_TOKEN = exports.DATA_CHANNEL_WITH_JWT_TOKEN = 'data-channel-with-jwt-token';
|
|
10
12
|
//# sourceMappingURL=constants.js.map
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["LLM","exports"],"sources":["constants.ts"],"sourcesContent":["// eslint-disable-next-line import/prefer-default-export\nexport const LLM = 'llm';\n"],"mappings":";;;;;;;AAAA;AACO,IAAMA,GAAG,GAAAC,OAAA,CAAAD,GAAA,GAAG,KAAK"}
|
|
1
|
+
{"version":3,"names":["LLM","exports","LLM_DEFAULT_SESSION","DATA_CHANNEL_WITH_JWT_TOKEN"],"sources":["constants.ts"],"sourcesContent":["// eslint-disable-next-line import/prefer-default-export\nexport const LLM = 'llm';\n\nexport const LLM_DEFAULT_SESSION = 'llm-default-session';\n\nexport const DATA_CHANNEL_WITH_JWT_TOKEN = 'data-channel-with-jwt-token';\n"],"mappings":";;;;;;;AAAA;AACO,IAAMA,GAAG,GAAAC,OAAA,CAAAD,GAAA,GAAG,KAAK;AAEjB,IAAME,mBAAmB,GAAAD,OAAA,CAAAC,mBAAA,GAAG,qBAAqB;AAEjD,IAAMC,2BAA2B,GAAAF,OAAA,CAAAE,2BAAA,GAAG,6BAA6B","ignoreList":[]}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,12 @@ var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs2/core-js/o
|
|
|
7
7
|
_Object$defineProperty(exports, "__esModule", {
|
|
8
8
|
value: true
|
|
9
9
|
});
|
|
10
|
+
_Object$defineProperty(exports, "DataChannelTokenType", {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function get() {
|
|
13
|
+
return _llm2.DataChannelTokenType;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
10
16
|
_Object$defineProperty(exports, "default", {
|
|
11
17
|
enumerable: true,
|
|
12
18
|
get: function get() {
|
|
@@ -15,8 +21,8 @@ _Object$defineProperty(exports, "default", {
|
|
|
15
21
|
});
|
|
16
22
|
var WebexCore = _interopRequireWildcard(require("@webex/webex-core"));
|
|
17
23
|
var _llm = _interopRequireWildcard(require("./llm"));
|
|
18
|
-
|
|
19
|
-
function _interopRequireWildcard(e, r) { if (!
|
|
24
|
+
var _llm2 = require("./llm.types");
|
|
25
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof _WeakMap) var r = new _WeakMap(), n = new _WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = _Object$defineProperty) && _Object$getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
|
|
20
26
|
WebexCore.registerInternalPlugin('llm', _llm.default, {
|
|
21
27
|
config: _llm.config
|
|
22
28
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["WebexCore","_interopRequireWildcard","require","_llm","
|
|
1
|
+
{"version":3,"names":["WebexCore","_interopRequireWildcard","require","_llm","_llm2","e","t","_WeakMap","r","n","__esModule","o","i","f","__proto__","default","_typeof","has","get","set","_t","hasOwnProperty","call","_Object$defineProperty","_Object$getOwnPropertyDescriptor","registerInternalPlugin","LLMChannel","config"],"sources":["index.ts"],"sourcesContent":["import * as WebexCore from '@webex/webex-core';\nimport LLMChannel, {config} from './llm';\nimport {DataChannelTokenType} from './llm.types';\n\nWebexCore.registerInternalPlugin('llm', LLMChannel, {\n config,\n});\n\nexport {DataChannelTokenType};\nexport {default} from './llm';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,SAAA,GAAAC,uBAAA,CAAAC,OAAA;AACA,IAAAC,IAAA,GAAAF,uBAAA,CAAAC,OAAA;AACA,IAAAE,KAAA,GAAAF,OAAA;AAAiD,SAAAD,wBAAAI,CAAA,EAAAC,CAAA,6BAAAC,QAAA,MAAAC,CAAA,OAAAD,QAAA,IAAAE,CAAA,OAAAF,QAAA,YAAAN,uBAAA,YAAAA,wBAAAI,CAAA,EAAAC,CAAA,SAAAA,CAAA,IAAAD,CAAA,IAAAA,CAAA,CAAAK,UAAA,SAAAL,CAAA,MAAAM,CAAA,EAAAC,CAAA,EAAAC,CAAA,KAAAC,SAAA,QAAAC,OAAA,EAAAV,CAAA,iBAAAA,CAAA,gBAAAW,OAAA,CAAAX,CAAA,0BAAAA,CAAA,SAAAQ,CAAA,MAAAF,CAAA,GAAAL,CAAA,GAAAG,CAAA,GAAAD,CAAA,QAAAG,CAAA,CAAAM,GAAA,CAAAZ,CAAA,UAAAM,CAAA,CAAAO,GAAA,CAAAb,CAAA,GAAAM,CAAA,CAAAQ,GAAA,CAAAd,CAAA,EAAAQ,CAAA,cAAAO,EAAA,IAAAf,CAAA,gBAAAe,EAAA,OAAAC,cAAA,CAAAC,IAAA,CAAAjB,CAAA,EAAAe,EAAA,OAAAR,CAAA,IAAAD,CAAA,GAAAY,sBAAA,KAAAC,gCAAA,CAAAnB,CAAA,EAAAe,EAAA,OAAAR,CAAA,CAAAM,GAAA,IAAAN,CAAA,CAAAO,GAAA,IAAAR,CAAA,CAAAE,CAAA,EAAAO,EAAA,EAAAR,CAAA,IAAAC,CAAA,CAAAO,EAAA,IAAAf,CAAA,CAAAe,EAAA,WAAAP,CAAA,KAAAR,CAAA,EAAAC,CAAA;AAEjDN,SAAS,CAACyB,sBAAsB,CAAC,KAAK,EAAEC,YAAU,EAAE;EAClDC,MAAM,EAANA;AACF,CAAC,CAAC","ignoreList":[]}
|
package/dist/llm.js
CHANGED
|
@@ -7,19 +7,20 @@ _Object$defineProperty(exports, "__esModule", {
|
|
|
7
7
|
value: true
|
|
8
8
|
});
|
|
9
9
|
exports.default = exports.config = void 0;
|
|
10
|
-
var
|
|
10
|
+
var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs2/regenerator"));
|
|
11
|
+
var _map = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/map"));
|
|
12
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/asyncToGenerator"));
|
|
11
13
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));
|
|
12
|
-
var
|
|
13
|
-
var _inherits2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/inherits"));
|
|
14
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/createClass"));
|
|
14
15
|
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/possibleConstructorReturn"));
|
|
15
16
|
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/getPrototypeOf"));
|
|
16
|
-
var
|
|
17
|
+
var _inherits2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/inherits"));
|
|
18
|
+
var _defineProperty3 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
|
|
17
19
|
var _internalPluginMercury = _interopRequireDefault(require("@webex/internal-plugin-mercury"));
|
|
18
20
|
var _constants = require("./constants");
|
|
19
|
-
|
|
20
|
-
function
|
|
21
|
-
// eslint-disable-next-line no-unused-vars
|
|
22
|
-
|
|
21
|
+
var _llm = require("./llm.types");
|
|
22
|
+
function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? _Reflect$construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
|
|
23
|
+
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } /* eslint-disable consistent-return */ // eslint-disable-next-line no-unused-vars
|
|
23
24
|
var config = exports.config = {
|
|
24
25
|
llm: {
|
|
25
26
|
/**
|
|
@@ -55,103 +56,253 @@ var config = exports.config = {
|
|
|
55
56
|
* LLMChannel to provide socket connections
|
|
56
57
|
*/
|
|
57
58
|
var LLMChannel = exports.default = /*#__PURE__*/function (_ref) {
|
|
58
|
-
(0, _inherits2.default)(LLMChannel, _ref);
|
|
59
|
-
var _super = _createSuper(LLMChannel);
|
|
60
59
|
function LLMChannel() {
|
|
61
60
|
var _this;
|
|
62
61
|
(0, _classCallCheck2.default)(this, LLMChannel);
|
|
63
62
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
64
63
|
args[_key] = arguments[_key];
|
|
65
64
|
}
|
|
66
|
-
_this =
|
|
67
|
-
(0,
|
|
65
|
+
_this = _callSuper(this, LLMChannel, [].concat(args));
|
|
66
|
+
(0, _defineProperty3.default)(_this, "namespace", _constants.LLM);
|
|
67
|
+
(0, _defineProperty3.default)(_this, "defaultSessionId", _constants.LLM_DEFAULT_SESSION);
|
|
68
68
|
/**
|
|
69
|
-
*
|
|
70
|
-
* @
|
|
71
|
-
* @type {
|
|
72
|
-
* @public
|
|
69
|
+
* Map to store connection-specific data for multiple LLM connections
|
|
70
|
+
* @private
|
|
71
|
+
* @type {Map<string, {webSocketUrl?: string; binding?: string; locusUrl?: string; datachannelUrl?: string}>}
|
|
73
72
|
*/
|
|
74
|
-
(0,
|
|
75
|
-
(0,
|
|
76
|
-
(0,
|
|
77
|
-
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "datachannelUrl", void 0);
|
|
73
|
+
(0, _defineProperty3.default)(_this, "connections", new _map.default());
|
|
74
|
+
(0, _defineProperty3.default)(_this, "datachannelTokens", (0, _defineProperty3.default)((0, _defineProperty3.default)({}, _llm.DataChannelTokenType.Default, undefined), _llm.DataChannelTokenType.PracticeSession, undefined));
|
|
75
|
+
(0, _defineProperty3.default)(_this, "refreshHandler", void 0);
|
|
78
76
|
/**
|
|
79
77
|
* Register to the websocket
|
|
80
78
|
* @param {string} llmSocketUrl
|
|
79
|
+
* @param {string} datachannelToken
|
|
80
|
+
* @param {string} sessionId - Connection identifier
|
|
81
81
|
* @returns {Promise<void>}
|
|
82
82
|
*/
|
|
83
|
-
(0,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
83
|
+
(0, _defineProperty3.default)(_this, "register", /*#__PURE__*/function () {
|
|
84
|
+
var _ref2 = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee(llmSocketUrl, datachannelToken) {
|
|
85
|
+
var sessionId,
|
|
86
|
+
isDataChannelTokenEnabled,
|
|
87
|
+
_args = arguments;
|
|
88
|
+
return _regenerator.default.wrap(function (_context) {
|
|
89
|
+
while (1) switch (_context.prev = _context.next) {
|
|
90
|
+
case 0:
|
|
91
|
+
sessionId = _args.length > 2 && _args[2] !== undefined ? _args[2] : _constants.LLM_DEFAULT_SESSION;
|
|
92
|
+
_context.next = 1;
|
|
93
|
+
return _this.isDataChannelTokenEnabled();
|
|
94
|
+
case 1:
|
|
95
|
+
isDataChannelTokenEnabled = _context.sent;
|
|
96
|
+
return _context.abrupt("return", _this.request({
|
|
97
|
+
method: 'POST',
|
|
98
|
+
url: llmSocketUrl,
|
|
99
|
+
body: {
|
|
100
|
+
deviceUrl: _this.webex.internal.device.url
|
|
101
|
+
},
|
|
102
|
+
headers: isDataChannelTokenEnabled && datachannelToken ? {
|
|
103
|
+
'Data-Channel-Auth-Token': datachannelToken
|
|
104
|
+
} : {}
|
|
105
|
+
}).then(function (res) {
|
|
106
|
+
// Get or create connection data
|
|
107
|
+
var sessionData = _this.connections.get(sessionId) || {};
|
|
108
|
+
sessionData.webSocketUrl = res.body.webSocketUrl;
|
|
109
|
+
sessionData.binding = res.body.binding;
|
|
110
|
+
_this.connections.set(sessionId, sessionData);
|
|
111
|
+
}).catch(function (error) {
|
|
112
|
+
_this.logger.error("Error connecting to websocket for ".concat(sessionId, ": ").concat(error));
|
|
113
|
+
throw error;
|
|
114
|
+
}));
|
|
115
|
+
case 2:
|
|
116
|
+
case "end":
|
|
117
|
+
return _context.stop();
|
|
118
|
+
}
|
|
119
|
+
}, _callee);
|
|
120
|
+
}));
|
|
121
|
+
return function (_x, _x2) {
|
|
122
|
+
return _ref2.apply(this, arguments);
|
|
123
|
+
};
|
|
124
|
+
}());
|
|
98
125
|
/**
|
|
99
126
|
* Register and connect to the websocket
|
|
100
127
|
* @param {string} locusUrl
|
|
101
128
|
* @param {string} datachannelUrl
|
|
129
|
+
* @param {string} datachannelToken
|
|
130
|
+
* @param {string} sessionId - Connection identifier
|
|
102
131
|
* @returns {Promise<void>}
|
|
103
132
|
*/
|
|
104
|
-
(0,
|
|
105
|
-
|
|
133
|
+
(0, _defineProperty3.default)(_this, "registerAndConnect", function (locusUrl, datachannelUrl, datachannelToken) {
|
|
134
|
+
var sessionId = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : _constants.LLM_DEFAULT_SESSION;
|
|
135
|
+
return _this.register(datachannelUrl, datachannelToken, sessionId).then(function () {
|
|
106
136
|
if (!locusUrl || !datachannelUrl) return undefined;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
_this.
|
|
137
|
+
|
|
138
|
+
// Get or create connection data
|
|
139
|
+
var sessionData = _this.connections.get(sessionId) || {};
|
|
140
|
+
sessionData.locusUrl = locusUrl;
|
|
141
|
+
sessionData.datachannelUrl = datachannelUrl;
|
|
142
|
+
sessionData.datachannelToken = datachannelToken;
|
|
143
|
+
_this.connections.set(sessionId, sessionData);
|
|
144
|
+
return _this.connect(sessionData.webSocketUrl, sessionId);
|
|
110
145
|
});
|
|
111
146
|
});
|
|
112
147
|
/**
|
|
113
148
|
* Tells if LLM socket is connected
|
|
149
|
+
* @param {string} sessionId - Connection identifier
|
|
114
150
|
* @returns {boolean} connected
|
|
115
151
|
*/
|
|
116
|
-
(0,
|
|
117
|
-
|
|
152
|
+
(0, _defineProperty3.default)(_this, "isConnected", function () {
|
|
153
|
+
var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constants.LLM_DEFAULT_SESSION;
|
|
154
|
+
var socket = _this.getSocket(sessionId);
|
|
155
|
+
return socket ? socket.connected : false;
|
|
118
156
|
});
|
|
119
157
|
/**
|
|
120
158
|
* Tells if LLM socket is binding
|
|
159
|
+
* @param {string} sessionId - Connection identifier
|
|
121
160
|
* @returns {string} binding
|
|
122
161
|
*/
|
|
123
|
-
(0,
|
|
124
|
-
|
|
162
|
+
(0, _defineProperty3.default)(_this, "getBinding", function () {
|
|
163
|
+
var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constants.LLM_DEFAULT_SESSION;
|
|
164
|
+
var sessionData = _this.connections.get(sessionId);
|
|
165
|
+
return sessionData === null || sessionData === void 0 ? void 0 : sessionData.binding;
|
|
125
166
|
});
|
|
126
167
|
/**
|
|
127
168
|
* Get Locus URL for the connection
|
|
169
|
+
* @param {string} sessionId - Connection identifier
|
|
128
170
|
* @returns {string} locus Url
|
|
129
171
|
*/
|
|
130
|
-
(0,
|
|
131
|
-
|
|
172
|
+
(0, _defineProperty3.default)(_this, "getLocusUrl", function () {
|
|
173
|
+
var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constants.LLM_DEFAULT_SESSION;
|
|
174
|
+
var sessionData = _this.connections.get(sessionId);
|
|
175
|
+
return sessionData === null || sessionData === void 0 ? void 0 : sessionData.locusUrl;
|
|
132
176
|
});
|
|
133
177
|
/**
|
|
134
178
|
* Get data channel URL for the connection
|
|
179
|
+
* @param {string} sessionId - Connection identifier
|
|
135
180
|
* @returns {string} data channel Url
|
|
136
181
|
*/
|
|
137
|
-
(0,
|
|
138
|
-
|
|
182
|
+
(0, _defineProperty3.default)(_this, "getDatachannelUrl", function () {
|
|
183
|
+
var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constants.LLM_DEFAULT_SESSION;
|
|
184
|
+
var sessionData = _this.connections.get(sessionId);
|
|
185
|
+
return sessionData === null || sessionData === void 0 ? void 0 : sessionData.datachannelUrl;
|
|
186
|
+
});
|
|
187
|
+
/**
|
|
188
|
+
* Get data channel token for the connection
|
|
189
|
+
* @param {DataChannelTokenType} dataChannelTokenType
|
|
190
|
+
* @returns {string} data channel token
|
|
191
|
+
*/
|
|
192
|
+
(0, _defineProperty3.default)(_this, "getDatachannelToken", function (dataChannelTokenType) {
|
|
193
|
+
return _this.datachannelTokens[dataChannelTokenType];
|
|
194
|
+
});
|
|
195
|
+
/**
|
|
196
|
+
* Set data channel token for the connection
|
|
197
|
+
* @param {string} datachannelToken - data channel token
|
|
198
|
+
* @param {DataChannelTokenType} dataChannelTokenType
|
|
199
|
+
* @returns {void}
|
|
200
|
+
*/
|
|
201
|
+
(0, _defineProperty3.default)(_this, "setDatachannelToken", function (datachannelToken, dataChannelTokenType) {
|
|
202
|
+
_this.datachannelTokens[dataChannelTokenType] = datachannelToken;
|
|
139
203
|
});
|
|
140
204
|
/**
|
|
141
205
|
* Disconnects websocket connection
|
|
142
206
|
* @param {{code: number, reason: string}} options - The disconnect option object with code and reason
|
|
207
|
+
* @param {string} sessionId - Connection identifier
|
|
208
|
+
* @returns {Promise<void>}
|
|
209
|
+
*/
|
|
210
|
+
(0, _defineProperty3.default)(_this, "disconnectLLM", function (options) {
|
|
211
|
+
var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _constants.LLM_DEFAULT_SESSION;
|
|
212
|
+
return _this.disconnect(options, sessionId).then(function () {
|
|
213
|
+
// Clean up sessions data
|
|
214
|
+
_this.connections.delete(sessionId);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
/**
|
|
218
|
+
* Disconnects all LLM websocket connections
|
|
219
|
+
* @param {{code: number, reason: string}} options - The disconnect option object with code and reason
|
|
143
220
|
* @returns {Promise<void>}
|
|
144
221
|
*/
|
|
145
|
-
(0,
|
|
146
|
-
return _this.
|
|
147
|
-
|
|
148
|
-
_this.
|
|
149
|
-
_this.binding = undefined;
|
|
150
|
-
_this.webSocketUrl = undefined;
|
|
222
|
+
(0, _defineProperty3.default)(_this, "disconnectAllLLM", function (options) {
|
|
223
|
+
return _this.disconnectAll(options).then(function () {
|
|
224
|
+
// Clean up all connection data
|
|
225
|
+
_this.connections.clear();
|
|
151
226
|
});
|
|
152
227
|
});
|
|
228
|
+
/**
|
|
229
|
+
* Get all active LLM connections
|
|
230
|
+
* @returns {Map} Map of sessionId to session data
|
|
231
|
+
*/
|
|
232
|
+
(0, _defineProperty3.default)(_this, "getAllConnections", function () {
|
|
233
|
+
return new _map.default(_this.connections);
|
|
234
|
+
});
|
|
153
235
|
return _this;
|
|
154
236
|
}
|
|
155
|
-
|
|
237
|
+
(0, _inherits2.default)(LLMChannel, _ref);
|
|
238
|
+
return (0, _createClass2.default)(LLMChannel, [{
|
|
239
|
+
key: "setRefreshHandler",
|
|
240
|
+
value:
|
|
241
|
+
/**
|
|
242
|
+
* Set the handler used to refresh the DataChannel token
|
|
243
|
+
*
|
|
244
|
+
* @param {function} handler - Function that returns a refreshed token
|
|
245
|
+
* @returns {void}
|
|
246
|
+
*/
|
|
247
|
+
function setRefreshHandler(handler) {
|
|
248
|
+
this.refreshHandler = handler;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Refresh the data channel token using the injected handler.
|
|
253
|
+
* Logs a descriptive error if the handler is missing or fails.
|
|
254
|
+
*
|
|
255
|
+
* @returns {Promise<string>} The refreshed token.
|
|
256
|
+
*/
|
|
257
|
+
}, {
|
|
258
|
+
key: "refreshDataChannelToken",
|
|
259
|
+
value: (function () {
|
|
260
|
+
var _refreshDataChannelToken = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee2() {
|
|
261
|
+
var error, res, _t;
|
|
262
|
+
return _regenerator.default.wrap(function (_context2) {
|
|
263
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
264
|
+
case 0:
|
|
265
|
+
if (this.refreshHandler) {
|
|
266
|
+
_context2.next = 1;
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
error = new Error('LLM refreshHandler is not set');
|
|
270
|
+
this.logger.error("Error refreshing DataChannel token: ".concat(error.message));
|
|
271
|
+
throw error;
|
|
272
|
+
case 1:
|
|
273
|
+
_context2.prev = 1;
|
|
274
|
+
_context2.next = 2;
|
|
275
|
+
return this.refreshHandler();
|
|
276
|
+
case 2:
|
|
277
|
+
res = _context2.sent;
|
|
278
|
+
return _context2.abrupt("return", res);
|
|
279
|
+
case 3:
|
|
280
|
+
_context2.prev = 3;
|
|
281
|
+
_t = _context2["catch"](1);
|
|
282
|
+
this.logger.error("Error refreshing DataChannel token: ".concat(_t));
|
|
283
|
+
throw _t;
|
|
284
|
+
case 4:
|
|
285
|
+
case "end":
|
|
286
|
+
return _context2.stop();
|
|
287
|
+
}
|
|
288
|
+
}, _callee2, this, [[1, 3]]);
|
|
289
|
+
}));
|
|
290
|
+
function refreshDataChannelToken() {
|
|
291
|
+
return _refreshDataChannelToken.apply(this, arguments);
|
|
292
|
+
}
|
|
293
|
+
return refreshDataChannelToken;
|
|
294
|
+
}())
|
|
295
|
+
}, {
|
|
296
|
+
key: "isDataChannelTokenEnabled",
|
|
297
|
+
value:
|
|
298
|
+
/**
|
|
299
|
+
* Returns true if data channel token is enabled, false otherwise
|
|
300
|
+
* @returns {Promise<boolean>} resolves with true if data channel token is enabled
|
|
301
|
+
*/
|
|
302
|
+
function isDataChannelTokenEnabled() {
|
|
303
|
+
// @ts-ignore
|
|
304
|
+
return this.webex.internal.feature.getFeature('developer', _constants.DATA_CHANNEL_WITH_JWT_TOKEN);
|
|
305
|
+
}
|
|
306
|
+
}]);
|
|
156
307
|
}(_internalPluginMercury.default);
|
|
157
308
|
//# sourceMappingURL=llm.js.map
|
package/dist/llm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_internalPluginMercury","_interopRequireDefault","require","_constants","_createSuper","Derived","hasNativeReflectConstruct","_isNativeReflectConstruct","_createSuperInternal","Super","_getPrototypeOf2","default","result","NewTarget","constructor","_Reflect$construct","arguments","apply","_possibleConstructorReturn2","Reflect","sham","Proxy","Boolean","prototype","valueOf","call","e","config","exports","llm","pingInterval","process","env","MERCURY_PING_INTERVAL","pongTimeout","MERCURY_PONG_TIMEOUT","backoffTimeMax","MERCURY_BACKOFF_TIME_MAX","backoffTimeReset","MERCURY_BACKOFF_TIME_RESET","forceCloseDelay","MERCURY_FORCE_CLOSE_DELAY","LLMChannel","_ref","_inherits2","_super","_this","_classCallCheck2","_len","length","args","Array","_key","concat","_defineProperty2","_assertThisInitialized2","LLM","llmSocketUrl","request","method","url","body","deviceUrl","webex","internal","device","then","res","webSocketUrl","binding","catch","error","logger","locusUrl","datachannelUrl","register","undefined","connect","connected","options","disconnect","_createClass2","Mercury"],"sources":["llm.ts"],"sourcesContent":["/* eslint-disable consistent-return */\n\nimport Mercury from '@webex/internal-plugin-mercury';\n\nimport {LLM} from './constants';\n// eslint-disable-next-line no-unused-vars\nimport {ILLMChannel} from './llm.types';\n\nexport const config = {\n llm: {\n /**\n * Milliseconds between pings sent up the socket\n * @type {number}\n */\n pingInterval: process.env.MERCURY_PING_INTERVAL || 15000,\n /**\n * Milliseconds to wait for a pong before declaring the connection dead\n * @type {number}\n */\n pongTimeout: process.env.MERCURY_PONG_TIMEOUT || 14000,\n /**\n * Maximum milliseconds between connection attempts\n * @type {Number}\n */\n backoffTimeMax: process.env.MERCURY_BACKOFF_TIME_MAX || 32000,\n /**\n * Initial milliseconds between connection attempts\n * @type {Number}\n */\n backoffTimeReset: process.env.MERCURY_BACKOFF_TIME_RESET || 1000,\n /**\n * Milliseconds to wait for a close frame before declaring the socket dead and\n * discarding it\n * @type {[type]}\n */\n forceCloseDelay: process.env.MERCURY_FORCE_CLOSE_DELAY || 2000,\n },\n};\n\n/**\n * LLMChannel to provide socket connections\n */\nexport default class LLMChannel extends (Mercury as any) implements ILLMChannel {\n namespace = LLM;\n\n /**\n * If the LLM plugin has been registered and listening\n * @instance\n * @type {Boolean}\n * @public\n */\n\n private webSocketUrl?: string;\n\n private binding?: string;\n\n private locusUrl?: string;\n\n private datachannelUrl?: string;\n\n /**\n * Register to the websocket\n * @param {string} llmSocketUrl\n * @returns {Promise<void>}\n */\n private register = (llmSocketUrl: string): Promise<void> =>\n this.request({\n method: 'POST',\n url: llmSocketUrl,\n body: {deviceUrl: this.webex.internal.device.url},\n })\n .then((res: {body: {webSocketUrl: string; binding: string}}) => {\n this.webSocketUrl = res.body.webSocketUrl;\n this.binding = res.body.binding;\n })\n .catch((error: any) => {\n this.logger.error(`Error connecting to websocket: ${error}`);\n throw error;\n });\n\n /**\n * Register and connect to the websocket\n * @param {string} locusUrl\n * @param {string} datachannelUrl\n * @returns {Promise<void>}\n */\n public registerAndConnect = (locusUrl: string, datachannelUrl: string): Promise<void> =>\n this.register(datachannelUrl).then(() => {\n if (!locusUrl || !datachannelUrl) return undefined;\n this.locusUrl = locusUrl;\n this.datachannelUrl = datachannelUrl;\n this.connect(this.webSocketUrl);\n });\n\n /**\n * Tells if LLM socket is connected\n * @returns {boolean} connected\n */\n public isConnected = (): boolean => this.connected;\n\n /**\n * Tells if LLM socket is binding\n * @returns {string} binding\n */\n public getBinding = (): string => this.binding;\n\n /**\n * Get Locus URL for the connection\n * @returns {string} locus Url\n */\n public getLocusUrl = (): string => this.locusUrl;\n\n /**\n * Get data channel URL for the connection\n * @returns {string} data channel Url\n */\n public getDatachannelUrl = (): string => this.datachannelUrl;\n\n /**\n * Disconnects websocket connection\n * @param {{code: number, reason: string}} options - The disconnect option object with code and reason\n * @returns {Promise<void>}\n */\n public disconnectLLM = (options: object): Promise<void> =>\n this.disconnect(options).then(() => {\n this.locusUrl = undefined;\n this.datachannelUrl = undefined;\n this.binding = undefined;\n this.webSocketUrl = undefined;\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["_internalPluginMercury","_interopRequireDefault","require","_constants","_llm","_callSuper","t","o","e","_getPrototypeOf2","default","_possibleConstructorReturn2","_isNativeReflectConstruct","_Reflect$construct","constructor","apply","Boolean","prototype","valueOf","call","config","exports","llm","pingInterval","process","env","MERCURY_PING_INTERVAL","pongTimeout","MERCURY_PONG_TIMEOUT","backoffTimeMax","MERCURY_BACKOFF_TIME_MAX","backoffTimeReset","MERCURY_BACKOFF_TIME_RESET","forceCloseDelay","MERCURY_FORCE_CLOSE_DELAY","LLMChannel","_ref","_this","_classCallCheck2","_len","arguments","length","args","Array","_key","concat","_defineProperty3","LLM","LLM_DEFAULT_SESSION","_map","DataChannelTokenType","Default","undefined","PracticeSession","_ref2","_asyncToGenerator2","_regenerator","mark","_callee","llmSocketUrl","datachannelToken","sessionId","isDataChannelTokenEnabled","_args","wrap","_context","prev","next","sent","abrupt","request","method","url","body","deviceUrl","webex","internal","device","headers","then","res","sessionData","connections","get","webSocketUrl","binding","set","catch","error","logger","stop","_x","_x2","locusUrl","datachannelUrl","register","connect","socket","getSocket","connected","dataChannelTokenType","datachannelTokens","options","disconnect","delete","disconnectAll","clear","_inherits2","_createClass2","key","value","setRefreshHandler","handler","refreshHandler","_refreshDataChannelToken","_callee2","_t","_context2","Error","message","refreshDataChannelToken","feature","getFeature","DATA_CHANNEL_WITH_JWT_TOKEN","Mercury"],"sources":["llm.ts"],"sourcesContent":["/* eslint-disable consistent-return */\n\nimport Mercury from '@webex/internal-plugin-mercury';\n\nimport {LLM, DATA_CHANNEL_WITH_JWT_TOKEN, LLM_DEFAULT_SESSION} from './constants';\n// eslint-disable-next-line no-unused-vars\nimport {ILLMChannel, DataChannelTokenType} from './llm.types';\n\nexport const config = {\n llm: {\n /**\n * Milliseconds between pings sent up the socket\n * @type {number}\n */\n pingInterval: process.env.MERCURY_PING_INTERVAL || 15000,\n /**\n * Milliseconds to wait for a pong before declaring the connection dead\n * @type {number}\n */\n pongTimeout: process.env.MERCURY_PONG_TIMEOUT || 14000,\n /**\n * Maximum milliseconds between connection attempts\n * @type {Number}\n */\n backoffTimeMax: process.env.MERCURY_BACKOFF_TIME_MAX || 32000,\n /**\n * Initial milliseconds between connection attempts\n * @type {Number}\n */\n backoffTimeReset: process.env.MERCURY_BACKOFF_TIME_RESET || 1000,\n /**\n * Milliseconds to wait for a close frame before declaring the socket dead and\n * discarding it\n * @type {[type]}\n */\n forceCloseDelay: process.env.MERCURY_FORCE_CLOSE_DELAY || 2000,\n },\n};\n\n/**\n * LLMChannel to provide socket connections\n */\nexport default class LLMChannel extends (Mercury as any) implements ILLMChannel {\n namespace = LLM;\n defaultSessionId = LLM_DEFAULT_SESSION;\n /**\n * Map to store connection-specific data for multiple LLM connections\n * @private\n * @type {Map<string, {webSocketUrl?: string; binding?: string; locusUrl?: string; datachannelUrl?: string}>}\n */\n private connections: Map<\n string,\n {\n webSocketUrl?: string;\n binding?: string;\n locusUrl?: string;\n datachannelUrl?: string;\n datachannelToken?: string;\n }\n > = new Map();\n\n private datachannelTokens: Record<DataChannelTokenType, string> = {\n [DataChannelTokenType.Default]: undefined,\n [DataChannelTokenType.PracticeSession]: undefined,\n };\n\n private refreshHandler?: () => Promise<{\n body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};\n }>;\n\n /**\n * Register to the websocket\n * @param {string} llmSocketUrl\n * @param {string} datachannelToken\n * @param {string} sessionId - Connection identifier\n * @returns {Promise<void>}\n */\n private register = async (\n llmSocketUrl: string,\n datachannelToken?: string,\n sessionId: string = LLM_DEFAULT_SESSION\n ): Promise<void> => {\n const isDataChannelTokenEnabled = await this.isDataChannelTokenEnabled();\n\n return this.request({\n method: 'POST',\n url: llmSocketUrl,\n body: {deviceUrl: this.webex.internal.device.url},\n headers:\n isDataChannelTokenEnabled && datachannelToken\n ? {'Data-Channel-Auth-Token': datachannelToken}\n : {},\n })\n .then((res: {body: {webSocketUrl: string; binding: string}}) => {\n // Get or create connection data\n const sessionData = this.connections.get(sessionId) || {};\n sessionData.webSocketUrl = res.body.webSocketUrl;\n sessionData.binding = res.body.binding;\n this.connections.set(sessionId, sessionData);\n })\n .catch((error: any) => {\n this.logger.error(`Error connecting to websocket for ${sessionId}: ${error}`);\n throw error;\n });\n };\n\n /**\n * Register and connect to the websocket\n * @param {string} locusUrl\n * @param {string} datachannelUrl\n * @param {string} datachannelToken\n * @param {string} sessionId - Connection identifier\n * @returns {Promise<void>}\n */\n public registerAndConnect = (\n locusUrl: string,\n datachannelUrl: string,\n datachannelToken?: string,\n sessionId: string = LLM_DEFAULT_SESSION\n ): Promise<void> =>\n this.register(datachannelUrl, datachannelToken, sessionId).then(() => {\n if (!locusUrl || !datachannelUrl) return undefined;\n\n // Get or create connection data\n const sessionData = this.connections.get(sessionId) || {};\n sessionData.locusUrl = locusUrl;\n sessionData.datachannelUrl = datachannelUrl;\n sessionData.datachannelToken = datachannelToken;\n this.connections.set(sessionId, sessionData);\n\n return this.connect(sessionData.webSocketUrl, sessionId);\n });\n\n /**\n * Tells if LLM socket is connected\n * @param {string} sessionId - Connection identifier\n * @returns {boolean} connected\n */\n public isConnected = (sessionId = LLM_DEFAULT_SESSION): boolean => {\n const socket = this.getSocket(sessionId);\n\n return socket ? socket.connected : false;\n };\n\n /**\n * Tells if LLM socket is binding\n * @param {string} sessionId - Connection identifier\n * @returns {string} binding\n */\n public getBinding = (sessionId = LLM_DEFAULT_SESSION): string => {\n const sessionData = this.connections.get(sessionId);\n\n return sessionData?.binding;\n };\n\n /**\n * Get Locus URL for the connection\n * @param {string} sessionId - Connection identifier\n * @returns {string} locus Url\n */\n public getLocusUrl = (sessionId = LLM_DEFAULT_SESSION): string => {\n const sessionData = this.connections.get(sessionId);\n\n return sessionData?.locusUrl;\n };\n\n /**\n * Get data channel URL for the connection\n * @param {string} sessionId - Connection identifier\n * @returns {string} data channel Url\n */\n public getDatachannelUrl = (sessionId = LLM_DEFAULT_SESSION): string => {\n const sessionData = this.connections.get(sessionId);\n\n return sessionData?.datachannelUrl;\n };\n\n /**\n * Get data channel token for the connection\n * @param {DataChannelTokenType} dataChannelTokenType\n * @returns {string} data channel token\n */\n public getDatachannelToken = (dataChannelTokenType: DataChannelTokenType): string => {\n return this.datachannelTokens[dataChannelTokenType];\n };\n\n /**\n * Set data channel token for the connection\n * @param {string} datachannelToken - data channel token\n * @param {DataChannelTokenType} dataChannelTokenType\n * @returns {void}\n */\n public setDatachannelToken = (\n datachannelToken: string,\n dataChannelTokenType: DataChannelTokenType\n ): void => {\n this.datachannelTokens[dataChannelTokenType] = datachannelToken;\n };\n\n /**\n * Set the handler used to refresh the DataChannel token\n *\n * @param {function} handler - Function that returns a refreshed token\n * @returns {void}\n */\n public setRefreshHandler(\n handler: () => Promise<{\n body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};\n }>\n ) {\n this.refreshHandler = handler;\n }\n\n /**\n * Refresh the data channel token using the injected handler.\n * Logs a descriptive error if the handler is missing or fails.\n *\n * @returns {Promise<string>} The refreshed token.\n */\n public async refreshDataChannelToken() {\n if (!this.refreshHandler) {\n const error = new Error('LLM refreshHandler is not set');\n this.logger.error(`Error refreshing DataChannel token: ${error.message}`);\n throw error;\n }\n\n try {\n const res = await this.refreshHandler();\n\n return res;\n } catch (error: any) {\n this.logger.error(`Error refreshing DataChannel token: ${error}`);\n throw error;\n }\n }\n\n /**\n * Disconnects websocket connection\n * @param {{code: number, reason: string}} options - The disconnect option object with code and reason\n * @param {string} sessionId - Connection identifier\n * @returns {Promise<void>}\n */\n public disconnectLLM = (\n options: {code: number; reason: string},\n sessionId: string = LLM_DEFAULT_SESSION\n ): Promise<void> =>\n this.disconnect(options, sessionId).then(() => {\n // Clean up sessions data\n this.connections.delete(sessionId);\n });\n\n /**\n * Disconnects all LLM websocket connections\n * @param {{code: number, reason: string}} options - The disconnect option object with code and reason\n * @returns {Promise<void>}\n */\n public disconnectAllLLM = (options?: {code: number; reason: string}): Promise<void> =>\n this.disconnectAll(options).then(() => {\n // Clean up all connection data\n this.connections.clear();\n });\n\n /**\n * Get all active LLM connections\n * @returns {Map} Map of sessionId to session data\n */\n public getAllConnections = (): Map<\n string,\n {\n webSocketUrl?: string;\n binding?: string;\n locusUrl?: string;\n datachannelUrl?: string;\n datachannelToken?: string;\n }\n > => new Map(this.connections);\n\n /**\n * Returns true if data channel token is enabled, false otherwise\n * @returns {Promise<boolean>} resolves with true if data channel token is enabled\n */\n public isDataChannelTokenEnabled(): Promise<boolean> {\n // @ts-ignore\n return this.webex.internal.feature.getFeature('developer', DATA_CHANNEL_WITH_JWT_TOKEN);\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
package/dist/llm.types.js
CHANGED
|
@@ -4,4 +4,10 @@ var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/defi
|
|
|
4
4
|
_Object$defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
+
exports.DataChannelTokenType = void 0;
|
|
8
|
+
var DataChannelTokenType = exports.DataChannelTokenType = /*#__PURE__*/function (DataChannelTokenType) {
|
|
9
|
+
DataChannelTokenType["Default"] = "default";
|
|
10
|
+
DataChannelTokenType["PracticeSession"] = "practiceSession";
|
|
11
|
+
return DataChannelTokenType;
|
|
12
|
+
}({}); // eslint-disable-next-line import/prefer-default-export
|
|
7
13
|
//# sourceMappingURL=llm.types.js.map
|
package/dist/llm.types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["llm.types.ts"],"sourcesContent":["interface ILLMChannel {\n registerAndConnect: (locusUrl: string
|
|
1
|
+
{"version":3,"names":["DataChannelTokenType","exports"],"sources":["llm.types.ts"],"sourcesContent":["interface ILLMChannel {\n registerAndConnect: (\n locusUrl: string,\n datachannelUrl: string,\n datachannelToken?: string,\n sessionId?: string\n ) => Promise<void>;\n isConnected: (sessionId?: string) => boolean;\n getBinding: (sessionId?: string) => string;\n getLocusUrl: (sessionId?: string) => string;\n getDatachannelUrl: (sessionId?: string) => string;\n disconnectLLM: (options: {code: number; reason: string}, sessionId?: string) => Promise<void>;\n disconnectAllLLM: (options?: {code: number; reason: string}) => Promise<void>;\n getAllConnections: () => Map<\n string,\n {\n webSocketUrl?: string;\n binding?: string;\n locusUrl?: string;\n datachannelUrl?: string;\n datachannelToken?: string;\n }\n >;\n}\n\nexport enum DataChannelTokenType {\n Default = 'default',\n PracticeSession = 'practiceSession',\n}\n\n// eslint-disable-next-line import/prefer-default-export\nexport type {ILLMChannel};\n"],"mappings":";;;;;;;IAyBYA,oBAAoB,GAAAC,OAAA,CAAAD,oBAAA,0BAApBA,oBAAoB;EAApBA,oBAAoB;EAApBA,oBAAoB;EAAA,OAApBA,oBAAoB;AAAA,OAKhC","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"node": ">=18"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@webex/internal-plugin-mercury": "3.
|
|
16
|
+
"@webex/internal-plugin-mercury": "3.11.0-next.9"
|
|
17
17
|
},
|
|
18
18
|
"browserify": {
|
|
19
19
|
"transform": [
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"@webex/eslint-config-legacy": "0.0.0",
|
|
28
28
|
"@webex/jest-config-legacy": "0.0.0",
|
|
29
29
|
"@webex/legacy-tools": "0.0.0",
|
|
30
|
-
"@webex/test-helper-chai": "3.
|
|
31
|
-
"@webex/test-helper-mocha": "3.
|
|
32
|
-
"@webex/test-helper-mock-webex": "3.
|
|
33
|
-
"@webex/test-helper-test-users": "3.
|
|
30
|
+
"@webex/test-helper-chai": "3.11.0-next.1",
|
|
31
|
+
"@webex/test-helper-mocha": "3.11.0-next.1",
|
|
32
|
+
"@webex/test-helper-mock-webex": "3.11.0-next.1",
|
|
33
|
+
"@webex/test-helper-test-users": "3.11.0-next.1",
|
|
34
34
|
"eslint": "^8.24.0",
|
|
35
35
|
"prettier": "^2.7.1",
|
|
36
36
|
"sinon": "^9.2.4"
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
"test:style": "eslint ./src/**/*.*",
|
|
45
45
|
"test:unit": "webex-legacy-tools test --unit --runner jest"
|
|
46
46
|
},
|
|
47
|
-
"version": "3.
|
|
47
|
+
"version": "3.11.0-next.10"
|
|
48
48
|
}
|
package/src/constants.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as WebexCore from '@webex/webex-core';
|
|
2
2
|
import LLMChannel, {config} from './llm';
|
|
3
|
+
import {DataChannelTokenType} from './llm.types';
|
|
3
4
|
|
|
4
5
|
WebexCore.registerInternalPlugin('llm', LLMChannel, {
|
|
5
6
|
config,
|
|
6
7
|
});
|
|
7
8
|
|
|
9
|
+
export {DataChannelTokenType};
|
|
8
10
|
export {default} from './llm';
|
package/src/llm.ts
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import Mercury from '@webex/internal-plugin-mercury';
|
|
4
4
|
|
|
5
|
-
import {LLM} from './constants';
|
|
5
|
+
import {LLM, DATA_CHANNEL_WITH_JWT_TOKEN, LLM_DEFAULT_SESSION} from './constants';
|
|
6
6
|
// eslint-disable-next-line no-unused-vars
|
|
7
|
-
import {ILLMChannel} from './llm.types';
|
|
7
|
+
import {ILLMChannel, DataChannelTokenType} from './llm.types';
|
|
8
8
|
|
|
9
9
|
export const config = {
|
|
10
10
|
llm: {
|
|
@@ -42,90 +42,245 @@ export const config = {
|
|
|
42
42
|
*/
|
|
43
43
|
export default class LLMChannel extends (Mercury as any) implements ILLMChannel {
|
|
44
44
|
namespace = LLM;
|
|
45
|
-
|
|
45
|
+
defaultSessionId = LLM_DEFAULT_SESSION;
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
48
|
-
* @
|
|
49
|
-
* @type {
|
|
50
|
-
* @public
|
|
47
|
+
* Map to store connection-specific data for multiple LLM connections
|
|
48
|
+
* @private
|
|
49
|
+
* @type {Map<string, {webSocketUrl?: string; binding?: string; locusUrl?: string; datachannelUrl?: string}>}
|
|
51
50
|
*/
|
|
51
|
+
private connections: Map<
|
|
52
|
+
string,
|
|
53
|
+
{
|
|
54
|
+
webSocketUrl?: string;
|
|
55
|
+
binding?: string;
|
|
56
|
+
locusUrl?: string;
|
|
57
|
+
datachannelUrl?: string;
|
|
58
|
+
datachannelToken?: string;
|
|
59
|
+
}
|
|
60
|
+
> = new Map();
|
|
52
61
|
|
|
53
|
-
private
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
private locusUrl?: string;
|
|
62
|
+
private datachannelTokens: Record<DataChannelTokenType, string> = {
|
|
63
|
+
[DataChannelTokenType.Default]: undefined,
|
|
64
|
+
[DataChannelTokenType.PracticeSession]: undefined,
|
|
65
|
+
};
|
|
58
66
|
|
|
59
|
-
private
|
|
67
|
+
private refreshHandler?: () => Promise<{
|
|
68
|
+
body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};
|
|
69
|
+
}>;
|
|
60
70
|
|
|
61
71
|
/**
|
|
62
72
|
* Register to the websocket
|
|
63
73
|
* @param {string} llmSocketUrl
|
|
74
|
+
* @param {string} datachannelToken
|
|
75
|
+
* @param {string} sessionId - Connection identifier
|
|
64
76
|
* @returns {Promise<void>}
|
|
65
77
|
*/
|
|
66
|
-
private register = (
|
|
67
|
-
|
|
78
|
+
private register = async (
|
|
79
|
+
llmSocketUrl: string,
|
|
80
|
+
datachannelToken?: string,
|
|
81
|
+
sessionId: string = LLM_DEFAULT_SESSION
|
|
82
|
+
): Promise<void> => {
|
|
83
|
+
const isDataChannelTokenEnabled = await this.isDataChannelTokenEnabled();
|
|
84
|
+
|
|
85
|
+
return this.request({
|
|
68
86
|
method: 'POST',
|
|
69
87
|
url: llmSocketUrl,
|
|
70
88
|
body: {deviceUrl: this.webex.internal.device.url},
|
|
89
|
+
headers:
|
|
90
|
+
isDataChannelTokenEnabled && datachannelToken
|
|
91
|
+
? {'Data-Channel-Auth-Token': datachannelToken}
|
|
92
|
+
: {},
|
|
71
93
|
})
|
|
72
94
|
.then((res: {body: {webSocketUrl: string; binding: string}}) => {
|
|
73
|
-
|
|
74
|
-
|
|
95
|
+
// Get or create connection data
|
|
96
|
+
const sessionData = this.connections.get(sessionId) || {};
|
|
97
|
+
sessionData.webSocketUrl = res.body.webSocketUrl;
|
|
98
|
+
sessionData.binding = res.body.binding;
|
|
99
|
+
this.connections.set(sessionId, sessionData);
|
|
75
100
|
})
|
|
76
101
|
.catch((error: any) => {
|
|
77
|
-
this.logger.error(`Error connecting to websocket: ${error}`);
|
|
102
|
+
this.logger.error(`Error connecting to websocket for ${sessionId}: ${error}`);
|
|
78
103
|
throw error;
|
|
79
104
|
});
|
|
105
|
+
};
|
|
80
106
|
|
|
81
107
|
/**
|
|
82
108
|
* Register and connect to the websocket
|
|
83
109
|
* @param {string} locusUrl
|
|
84
110
|
* @param {string} datachannelUrl
|
|
111
|
+
* @param {string} datachannelToken
|
|
112
|
+
* @param {string} sessionId - Connection identifier
|
|
85
113
|
* @returns {Promise<void>}
|
|
86
114
|
*/
|
|
87
|
-
public registerAndConnect = (
|
|
88
|
-
|
|
115
|
+
public registerAndConnect = (
|
|
116
|
+
locusUrl: string,
|
|
117
|
+
datachannelUrl: string,
|
|
118
|
+
datachannelToken?: string,
|
|
119
|
+
sessionId: string = LLM_DEFAULT_SESSION
|
|
120
|
+
): Promise<void> =>
|
|
121
|
+
this.register(datachannelUrl, datachannelToken, sessionId).then(() => {
|
|
89
122
|
if (!locusUrl || !datachannelUrl) return undefined;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
this.
|
|
123
|
+
|
|
124
|
+
// Get or create connection data
|
|
125
|
+
const sessionData = this.connections.get(sessionId) || {};
|
|
126
|
+
sessionData.locusUrl = locusUrl;
|
|
127
|
+
sessionData.datachannelUrl = datachannelUrl;
|
|
128
|
+
sessionData.datachannelToken = datachannelToken;
|
|
129
|
+
this.connections.set(sessionId, sessionData);
|
|
130
|
+
|
|
131
|
+
return this.connect(sessionData.webSocketUrl, sessionId);
|
|
93
132
|
});
|
|
94
133
|
|
|
95
134
|
/**
|
|
96
135
|
* Tells if LLM socket is connected
|
|
136
|
+
* @param {string} sessionId - Connection identifier
|
|
97
137
|
* @returns {boolean} connected
|
|
98
138
|
*/
|
|
99
|
-
public isConnected = (): boolean =>
|
|
139
|
+
public isConnected = (sessionId = LLM_DEFAULT_SESSION): boolean => {
|
|
140
|
+
const socket = this.getSocket(sessionId);
|
|
141
|
+
|
|
142
|
+
return socket ? socket.connected : false;
|
|
143
|
+
};
|
|
100
144
|
|
|
101
145
|
/**
|
|
102
146
|
* Tells if LLM socket is binding
|
|
147
|
+
* @param {string} sessionId - Connection identifier
|
|
103
148
|
* @returns {string} binding
|
|
104
149
|
*/
|
|
105
|
-
public getBinding = (): string =>
|
|
150
|
+
public getBinding = (sessionId = LLM_DEFAULT_SESSION): string => {
|
|
151
|
+
const sessionData = this.connections.get(sessionId);
|
|
152
|
+
|
|
153
|
+
return sessionData?.binding;
|
|
154
|
+
};
|
|
106
155
|
|
|
107
156
|
/**
|
|
108
157
|
* Get Locus URL for the connection
|
|
158
|
+
* @param {string} sessionId - Connection identifier
|
|
109
159
|
* @returns {string} locus Url
|
|
110
160
|
*/
|
|
111
|
-
public getLocusUrl = (): string =>
|
|
161
|
+
public getLocusUrl = (sessionId = LLM_DEFAULT_SESSION): string => {
|
|
162
|
+
const sessionData = this.connections.get(sessionId);
|
|
163
|
+
|
|
164
|
+
return sessionData?.locusUrl;
|
|
165
|
+
};
|
|
112
166
|
|
|
113
167
|
/**
|
|
114
168
|
* Get data channel URL for the connection
|
|
169
|
+
* @param {string} sessionId - Connection identifier
|
|
115
170
|
* @returns {string} data channel Url
|
|
116
171
|
*/
|
|
117
|
-
public getDatachannelUrl = (): string =>
|
|
172
|
+
public getDatachannelUrl = (sessionId = LLM_DEFAULT_SESSION): string => {
|
|
173
|
+
const sessionData = this.connections.get(sessionId);
|
|
174
|
+
|
|
175
|
+
return sessionData?.datachannelUrl;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Get data channel token for the connection
|
|
180
|
+
* @param {DataChannelTokenType} dataChannelTokenType
|
|
181
|
+
* @returns {string} data channel token
|
|
182
|
+
*/
|
|
183
|
+
public getDatachannelToken = (dataChannelTokenType: DataChannelTokenType): string => {
|
|
184
|
+
return this.datachannelTokens[dataChannelTokenType];
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Set data channel token for the connection
|
|
189
|
+
* @param {string} datachannelToken - data channel token
|
|
190
|
+
* @param {DataChannelTokenType} dataChannelTokenType
|
|
191
|
+
* @returns {void}
|
|
192
|
+
*/
|
|
193
|
+
public setDatachannelToken = (
|
|
194
|
+
datachannelToken: string,
|
|
195
|
+
dataChannelTokenType: DataChannelTokenType
|
|
196
|
+
): void => {
|
|
197
|
+
this.datachannelTokens[dataChannelTokenType] = datachannelToken;
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Set the handler used to refresh the DataChannel token
|
|
202
|
+
*
|
|
203
|
+
* @param {function} handler - Function that returns a refreshed token
|
|
204
|
+
* @returns {void}
|
|
205
|
+
*/
|
|
206
|
+
public setRefreshHandler(
|
|
207
|
+
handler: () => Promise<{
|
|
208
|
+
body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};
|
|
209
|
+
}>
|
|
210
|
+
) {
|
|
211
|
+
this.refreshHandler = handler;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Refresh the data channel token using the injected handler.
|
|
216
|
+
* Logs a descriptive error if the handler is missing or fails.
|
|
217
|
+
*
|
|
218
|
+
* @returns {Promise<string>} The refreshed token.
|
|
219
|
+
*/
|
|
220
|
+
public async refreshDataChannelToken() {
|
|
221
|
+
if (!this.refreshHandler) {
|
|
222
|
+
const error = new Error('LLM refreshHandler is not set');
|
|
223
|
+
this.logger.error(`Error refreshing DataChannel token: ${error.message}`);
|
|
224
|
+
throw error;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
const res = await this.refreshHandler();
|
|
229
|
+
|
|
230
|
+
return res;
|
|
231
|
+
} catch (error: any) {
|
|
232
|
+
this.logger.error(`Error refreshing DataChannel token: ${error}`);
|
|
233
|
+
throw error;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
118
236
|
|
|
119
237
|
/**
|
|
120
238
|
* Disconnects websocket connection
|
|
121
239
|
* @param {{code: number, reason: string}} options - The disconnect option object with code and reason
|
|
240
|
+
* @param {string} sessionId - Connection identifier
|
|
241
|
+
* @returns {Promise<void>}
|
|
242
|
+
*/
|
|
243
|
+
public disconnectLLM = (
|
|
244
|
+
options: {code: number; reason: string},
|
|
245
|
+
sessionId: string = LLM_DEFAULT_SESSION
|
|
246
|
+
): Promise<void> =>
|
|
247
|
+
this.disconnect(options, sessionId).then(() => {
|
|
248
|
+
// Clean up sessions data
|
|
249
|
+
this.connections.delete(sessionId);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Disconnects all LLM websocket connections
|
|
254
|
+
* @param {{code: number, reason: string}} options - The disconnect option object with code and reason
|
|
122
255
|
* @returns {Promise<void>}
|
|
123
256
|
*/
|
|
124
|
-
public
|
|
125
|
-
this.
|
|
126
|
-
|
|
127
|
-
this.
|
|
128
|
-
this.binding = undefined;
|
|
129
|
-
this.webSocketUrl = undefined;
|
|
257
|
+
public disconnectAllLLM = (options?: {code: number; reason: string}): Promise<void> =>
|
|
258
|
+
this.disconnectAll(options).then(() => {
|
|
259
|
+
// Clean up all connection data
|
|
260
|
+
this.connections.clear();
|
|
130
261
|
});
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Get all active LLM connections
|
|
265
|
+
* @returns {Map} Map of sessionId to session data
|
|
266
|
+
*/
|
|
267
|
+
public getAllConnections = (): Map<
|
|
268
|
+
string,
|
|
269
|
+
{
|
|
270
|
+
webSocketUrl?: string;
|
|
271
|
+
binding?: string;
|
|
272
|
+
locusUrl?: string;
|
|
273
|
+
datachannelUrl?: string;
|
|
274
|
+
datachannelToken?: string;
|
|
275
|
+
}
|
|
276
|
+
> => new Map(this.connections);
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Returns true if data channel token is enabled, false otherwise
|
|
280
|
+
* @returns {Promise<boolean>} resolves with true if data channel token is enabled
|
|
281
|
+
*/
|
|
282
|
+
public isDataChannelTokenEnabled(): Promise<boolean> {
|
|
283
|
+
// @ts-ignore
|
|
284
|
+
return this.webex.internal.feature.getFeature('developer', DATA_CHANNEL_WITH_JWT_TOKEN);
|
|
285
|
+
}
|
|
131
286
|
}
|
package/src/llm.types.ts
CHANGED
|
@@ -1,9 +1,32 @@
|
|
|
1
1
|
interface ILLMChannel {
|
|
2
|
-
registerAndConnect: (
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
registerAndConnect: (
|
|
3
|
+
locusUrl: string,
|
|
4
|
+
datachannelUrl: string,
|
|
5
|
+
datachannelToken?: string,
|
|
6
|
+
sessionId?: string
|
|
7
|
+
) => Promise<void>;
|
|
8
|
+
isConnected: (sessionId?: string) => boolean;
|
|
9
|
+
getBinding: (sessionId?: string) => string;
|
|
10
|
+
getLocusUrl: (sessionId?: string) => string;
|
|
11
|
+
getDatachannelUrl: (sessionId?: string) => string;
|
|
12
|
+
disconnectLLM: (options: {code: number; reason: string}, sessionId?: string) => Promise<void>;
|
|
13
|
+
disconnectAllLLM: (options?: {code: number; reason: string}) => Promise<void>;
|
|
14
|
+
getAllConnections: () => Map<
|
|
15
|
+
string,
|
|
16
|
+
{
|
|
17
|
+
webSocketUrl?: string;
|
|
18
|
+
binding?: string;
|
|
19
|
+
locusUrl?: string;
|
|
20
|
+
datachannelUrl?: string;
|
|
21
|
+
datachannelToken?: string;
|
|
22
|
+
}
|
|
23
|
+
>;
|
|
7
24
|
}
|
|
25
|
+
|
|
26
|
+
export enum DataChannelTokenType {
|
|
27
|
+
Default = 'default',
|
|
28
|
+
PracticeSession = 'practiceSession',
|
|
29
|
+
}
|
|
30
|
+
|
|
8
31
|
// eslint-disable-next-line import/prefer-default-export
|
|
9
32
|
export type {ILLMChannel};
|
package/test/unit/spec/llm.js
CHANGED
|
@@ -19,9 +19,15 @@ describe('plugin-llm', () => {
|
|
|
19
19
|
},
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
+
webex.internal.feature = {
|
|
23
|
+
setFeature: sinon.stub().resolves({value: true}),
|
|
24
|
+
getFeature: sinon.stub().resolves(true),
|
|
25
|
+
};
|
|
26
|
+
|
|
22
27
|
llmService = webex.internal.llm;
|
|
23
28
|
llmService.connect = sinon.stub().callsFake(() => {
|
|
24
|
-
|
|
29
|
+
// Simulate a successful connection by stubbing getSocket to return connected: true
|
|
30
|
+
llmService.getSocket = sinon.stub().returns({connected: true});
|
|
25
31
|
});
|
|
26
32
|
llmService.disconnect = sinon.stub().resolves(true);
|
|
27
33
|
llmService.request = sinon.stub().resolves({
|
|
@@ -56,10 +62,51 @@ describe('plugin-llm', () => {
|
|
|
56
62
|
await llmService.registerAndConnect();
|
|
57
63
|
assert.equal(llmService.isConnected(), false);
|
|
58
64
|
});
|
|
65
|
+
|
|
66
|
+
it('registers connection with token', async () => {
|
|
67
|
+
llmService.register = sinon.stub().resolves({
|
|
68
|
+
body: {
|
|
69
|
+
binding: 'binding',
|
|
70
|
+
webSocketUrl: 'url',
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
assert.equal(llmService.isConnected(), false);
|
|
75
|
+
|
|
76
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl, 'abc123');
|
|
77
|
+
|
|
78
|
+
sinon.assert.calledOnceWithExactly(
|
|
79
|
+
llmService.register,
|
|
80
|
+
datachannelUrl,
|
|
81
|
+
'abc123',
|
|
82
|
+
'llm-default-session'
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
assert.equal(llmService.isConnected(), true);
|
|
86
|
+
});
|
|
59
87
|
});
|
|
60
88
|
|
|
61
89
|
describe('#register', () => {
|
|
62
|
-
|
|
90
|
+
beforeEach(() => {
|
|
91
|
+
llmService.isDataChannelTokenEnabled = sinon.stub();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('registers connection with token header', async () => {
|
|
95
|
+
llmService.isDataChannelTokenEnabled.resolves(true);
|
|
96
|
+
await llmService.register(datachannelUrl, 'abc123');
|
|
97
|
+
|
|
98
|
+
sinon.assert.calledOnceWithExactly(
|
|
99
|
+
llmService.request,
|
|
100
|
+
sinon.match({
|
|
101
|
+
method: 'POST',
|
|
102
|
+
url: `${datachannelUrl}`,
|
|
103
|
+
body: {deviceUrl: webex.internal.device.url},
|
|
104
|
+
headers: {'Data-Channel-Auth-Token': 'abc123'},
|
|
105
|
+
})
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('registers connection without token header when none provided', async () => {
|
|
63
110
|
await llmService.register(datachannelUrl);
|
|
64
111
|
|
|
65
112
|
sinon.assert.calledOnceWithExactly(
|
|
@@ -68,13 +115,28 @@ describe('plugin-llm', () => {
|
|
|
68
115
|
method: 'POST',
|
|
69
116
|
url: `${datachannelUrl}`,
|
|
70
117
|
body: {deviceUrl: webex.internal.device.url},
|
|
118
|
+
headers: {},
|
|
71
119
|
})
|
|
72
120
|
);
|
|
121
|
+
});
|
|
73
122
|
|
|
74
|
-
|
|
123
|
+
it('registers connection without token header when toggle disabled', async () => {
|
|
124
|
+
llmService.isDataChannelTokenEnabled.resolves(false);
|
|
125
|
+
|
|
126
|
+
await llmService.register(datachannelUrl,'abc123');
|
|
127
|
+
sinon.assert.calledOnceWithExactly(
|
|
128
|
+
llmService.request,
|
|
129
|
+
sinon.match({
|
|
130
|
+
method: 'POST',
|
|
131
|
+
url: `${datachannelUrl}`,
|
|
132
|
+
body: {deviceUrl: webex.internal.device.url},
|
|
133
|
+
headers: {},
|
|
134
|
+
})
|
|
135
|
+
);
|
|
75
136
|
});
|
|
76
137
|
});
|
|
77
138
|
|
|
139
|
+
|
|
78
140
|
describe('#getLocusUrl', () => {
|
|
79
141
|
it('gets LocusUrl', async () => {
|
|
80
142
|
llmService.register = sinon.stub().resolves({
|
|
@@ -149,5 +211,141 @@ describe('plugin-llm', () => {
|
|
|
149
211
|
await expect(instance.disconnectLLM({})).rejects.toThrow('Disconnect failed');
|
|
150
212
|
});
|
|
151
213
|
});
|
|
214
|
+
|
|
215
|
+
describe('#setRefreshHandler', () => {
|
|
216
|
+
it('stores the provided handler', () => {
|
|
217
|
+
const handler = sinon.stub().resolves({ body: { datachannelToken: 'newToken' } });
|
|
218
|
+
llmService.setRefreshHandler(handler);
|
|
219
|
+
|
|
220
|
+
// @ts-ignore
|
|
221
|
+
assert.equal(llmService.refreshHandler, handler);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
describe('#isDataChannelTokenEnabled', () => {
|
|
226
|
+
it('works correctly', async () => {
|
|
227
|
+
webex.internal.feature.getFeature.returns(true);
|
|
228
|
+
|
|
229
|
+
const result = await llmService.isDataChannelTokenEnabled();
|
|
230
|
+
|
|
231
|
+
sinon.assert.calledOnceWithExactly(
|
|
232
|
+
webex.internal.feature.getFeature,
|
|
233
|
+
'developer',
|
|
234
|
+
'data-channel-with-jwt-token'
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
assert.equal(result, true);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
describe('#refreshDataChannelToken', () => {
|
|
242
|
+
it('throws if no handler is set', async () => {
|
|
243
|
+
try {
|
|
244
|
+
await llmService.refreshDataChannelToken();
|
|
245
|
+
assert.fail('Should have thrown');
|
|
246
|
+
} catch (err) {
|
|
247
|
+
assert.match(err.message, 'LLM refreshHandler is not set');
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('returns token when handler resolves', async () => {
|
|
252
|
+
const mockToken = { body: { datachannelToken: 'newToken' ,isPracticeSession: false} }
|
|
253
|
+
const handler = sinon.stub().resolves(mockToken);
|
|
254
|
+
llmService.setRefreshHandler(handler);
|
|
255
|
+
|
|
256
|
+
const token = await llmService.refreshDataChannelToken();
|
|
257
|
+
assert.equal(token, mockToken);
|
|
258
|
+
sinon.assert.calledOnce(handler);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('logs and rethrows when handler rejects', async () => {
|
|
262
|
+
const handler = sinon.stub().rejects(new Error('throw error'));
|
|
263
|
+
|
|
264
|
+
const loggerSpy = llmService.logger.error;
|
|
265
|
+
|
|
266
|
+
llmService.setRefreshHandler(handler);
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
await llmService.refreshDataChannelToken();
|
|
270
|
+
assert.fail('Should have thrown');
|
|
271
|
+
} catch (err) {
|
|
272
|
+
assert.match(err.message, /throw error/);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
sinon.assert.calledOnce(loggerSpy);
|
|
276
|
+
sinon.assert.calledWithMatch(
|
|
277
|
+
loggerSpy,
|
|
278
|
+
sinon.match("Error refreshing DataChannel token: Error: throw error")
|
|
279
|
+
);
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
describe('#getDatachannelToken / #setDatachannelToken', () => {
|
|
284
|
+
it('sets and gets datachannel token', () => {
|
|
285
|
+
llmService.setDatachannelToken('abc123','default');
|
|
286
|
+
assert.equal(llmService.getDatachannelToken('default'), 'abc123');
|
|
287
|
+
llmService.setDatachannelToken('123abc','practiceSession');
|
|
288
|
+
assert.equal(llmService.getDatachannelToken('practiceSession'), '123abc');
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
describe('multi-connection logic', () => {
|
|
293
|
+
const locusUrl2 = 'locusUrl2';
|
|
294
|
+
const datachannelUrl2 = 'datachannelUrl2';
|
|
295
|
+
|
|
296
|
+
beforeEach(() => {
|
|
297
|
+
const sockets = new Map();
|
|
298
|
+
|
|
299
|
+
llmService.connect = sinon.stub().callsFake((url, sessionId) => {
|
|
300
|
+
sockets.set(sessionId, {connected: true});
|
|
301
|
+
llmService.getSocket = sinon.stub().callsFake((sid) => sockets.get(sid));
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('tracks multiple sessions independently', async () => {
|
|
306
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl, undefined, 's1');
|
|
307
|
+
await llmService.registerAndConnect(locusUrl2, datachannelUrl2, undefined, 's2');
|
|
308
|
+
|
|
309
|
+
assert.equal(llmService.isConnected('s1'), true);
|
|
310
|
+
assert.equal(llmService.isConnected('s2'), true);
|
|
311
|
+
assert.equal(llmService.getLocusUrl('s1'), locusUrl);
|
|
312
|
+
assert.equal(llmService.getLocusUrl('s2'), locusUrl2);
|
|
313
|
+
assert.equal(llmService.getDatachannelUrl('s1'), datachannelUrl);
|
|
314
|
+
assert.equal(llmService.getDatachannelUrl('s2'), datachannelUrl2);
|
|
315
|
+
|
|
316
|
+
const all = llmService.getAllConnections();
|
|
317
|
+
assert.equal(all.size, 2);
|
|
318
|
+
assert.equal(all.has('s1'), true);
|
|
319
|
+
assert.equal(all.has('s2'), true);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('disconnectLLM clears only the targeted session', async () => {
|
|
323
|
+
llmService.disconnect = sinon.stub().resolves(true);
|
|
324
|
+
|
|
325
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl, undefined, 's1');
|
|
326
|
+
await llmService.registerAndConnect(locusUrl2, datachannelUrl2, undefined, 's2');
|
|
327
|
+
|
|
328
|
+
const options = {code: 1000, reason: 'test'};
|
|
329
|
+
await llmService.disconnectLLM(options, 's1');
|
|
330
|
+
|
|
331
|
+
sinon.assert.calledOnceWithExactly(llmService.disconnect, options, 's1');
|
|
332
|
+
|
|
333
|
+
const all = llmService.getAllConnections();
|
|
334
|
+
assert.equal(all.has('s1'), false);
|
|
335
|
+
assert.equal(all.has('s2'), true);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('disconnectAllLLM clears all sessions', async () => {
|
|
339
|
+
llmService.disconnectAll = sinon.stub().resolves(true);
|
|
340
|
+
|
|
341
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl, undefined, 's1');
|
|
342
|
+
await llmService.registerAndConnect(locusUrl2, datachannelUrl2, undefined, 's2');
|
|
343
|
+
|
|
344
|
+
await llmService.disconnectAllLLM({code: 1000, reason: 'all'});
|
|
345
|
+
|
|
346
|
+
sinon.assert.calledOnce(llmService.disconnectAll);
|
|
347
|
+
assert.equal(llmService.getAllConnections().size, 0);
|
|
348
|
+
});
|
|
349
|
+
});
|
|
152
350
|
});
|
|
153
351
|
});
|