@webex/internal-plugin-llm 3.12.0-next.9 → 3.12.0-task-refactor.1

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/package.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "node": ">=18"
14
14
  },
15
15
  "dependencies": {
16
- "@webex/internal-plugin-mercury": "3.12.0-next.8"
16
+ "@webex/internal-plugin-mercury": "3.12.0-task-refactor.1"
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.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",
30
+ "@webex/test-helper-chai": "3.12.0-task-refactor.1",
31
+ "@webex/test-helper-mocha": "3.12.0-task-refactor.1",
32
+ "@webex/test-helper-mock-webex": "3.12.0-task-refactor.1",
33
+ "@webex/test-helper-test-users": "3.12.0-task-refactor.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.12.0-next.9"
47
+ "version": "3.12.0-task-refactor.1"
48
48
  }
package/src/constants.ts CHANGED
@@ -1,14 +1,2 @@
1
1
  // eslint-disable-next-line import/prefer-default-export
2
2
  export const LLM = 'llm';
3
-
4
- export const LLM_DEFAULT_SESSION = 'llm-default-session';
5
-
6
- export const DATA_CHANNEL_WITH_JWT_TOKEN = 'data-channel-with-jwt-token';
7
-
8
- export const SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM = 'subscriptionAwareSubchannels';
9
-
10
- export const DATA_CHNANEL_TYPE = {
11
- TRANSCRIPTION: 'transcription',
12
- };
13
-
14
- export const AWARE_DATA_CHANNEL = [DATA_CHNANEL_TYPE.TRANSCRIPTION];
package/src/index.ts CHANGED
@@ -1,10 +1,8 @@
1
1
  import * as WebexCore from '@webex/webex-core';
2
2
  import LLMChannel, {config} from './llm';
3
- import {DataChannelTokenType} from './llm.types';
4
3
 
5
4
  WebexCore.registerInternalPlugin('llm', LLMChannel, {
6
5
  config,
7
6
  });
8
7
 
9
- export {DataChannelTokenType};
10
8
  export {default} from './llm';
package/src/llm.ts CHANGED
@@ -2,15 +2,9 @@
2
2
 
3
3
  import Mercury from '@webex/internal-plugin-mercury';
4
4
 
5
+ import {LLM} from './constants';
5
6
  // eslint-disable-next-line no-unused-vars
6
- import {
7
- LLM,
8
- DATA_CHANNEL_WITH_JWT_TOKEN,
9
- AWARE_DATA_CHANNEL,
10
- SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM,
11
- LLM_DEFAULT_SESSION,
12
- } from './constants';
13
- import {ILLMChannel, DataChannelTokenType} from './llm.types';
7
+ import {ILLMChannel} from './llm.types';
14
8
 
15
9
  export const config = {
16
10
  llm: {
@@ -48,287 +42,90 @@ export const config = {
48
42
  */
49
43
  export default class LLMChannel extends (Mercury as any) implements ILLMChannel {
50
44
  namespace = LLM;
51
- defaultSessionId = LLM_DEFAULT_SESSION;
45
+
52
46
  /**
53
- * Map to store connection-specific data for multiple LLM connections
54
- * @private
55
- * @type {Map<string, {webSocketUrl?: string; binding?: string; locusUrl?: string; datachannelUrl?: string}>}
47
+ * If the LLM plugin has been registered and listening
48
+ * @instance
49
+ * @type {Boolean}
50
+ * @public
56
51
  */
57
- private connections: Map<
58
- string,
59
- {
60
- webSocketUrl?: string;
61
- binding?: string;
62
- locusUrl?: string;
63
- datachannelUrl?: string;
64
- datachannelToken?: string;
65
- }
66
- > = new Map();
67
52
 
68
- private datachannelTokens: Record<DataChannelTokenType, string> = {
69
- [DataChannelTokenType.Default]: undefined,
70
- [DataChannelTokenType.PracticeSession]: undefined,
71
- };
53
+ private webSocketUrl?: string;
54
+
55
+ private binding?: string;
56
+
57
+ private locusUrl?: string;
72
58
 
73
- private refreshHandler?: () => Promise<{
74
- body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};
75
- }>;
59
+ private datachannelUrl?: string;
76
60
 
77
61
  /**
78
62
  * Register to the websocket
79
63
  * @param {string} llmSocketUrl
80
- * @param {string} datachannelToken
81
- * @param {string} sessionId - Connection identifier
82
64
  * @returns {Promise<void>}
83
65
  */
84
- private register = async (
85
- llmSocketUrl: string,
86
- datachannelToken?: string,
87
- sessionId: string = LLM_DEFAULT_SESSION
88
- ): Promise<void> => {
89
- const isDataChannelTokenEnabled = await this.isDataChannelTokenEnabled();
90
-
91
- return this.request({
66
+ private register = (llmSocketUrl: string): Promise<void> =>
67
+ this.request({
92
68
  method: 'POST',
93
69
  url: llmSocketUrl,
94
70
  body: {deviceUrl: this.webex.internal.device.url},
95
- headers:
96
- isDataChannelTokenEnabled && datachannelToken
97
- ? {'Data-Channel-Auth-Token': datachannelToken}
98
- : {},
99
71
  })
100
72
  .then((res: {body: {webSocketUrl: string; binding: string}}) => {
101
- // Get or create connection data
102
- const sessionData = this.connections.get(sessionId) || {};
103
- sessionData.webSocketUrl = res.body.webSocketUrl;
104
- sessionData.binding = res.body.binding;
105
- this.connections.set(sessionId, sessionData);
73
+ this.webSocketUrl = res.body.webSocketUrl;
74
+ this.binding = res.body.binding;
106
75
  })
107
76
  .catch((error: any) => {
108
- this.logger.error(`Error connecting to websocket for ${sessionId}: ${error}`);
77
+ this.logger.error(`Error connecting to websocket: ${error}`);
109
78
  throw error;
110
79
  });
111
- };
112
80
 
113
81
  /**
114
82
  * Register and connect to the websocket
115
83
  * @param {string} locusUrl
116
84
  * @param {string} datachannelUrl
117
- * @param {string} datachannelToken
118
- * @param {string} sessionId - Connection identifier
119
85
  * @returns {Promise<void>}
120
86
  */
121
- public registerAndConnect = (
122
- locusUrl: string,
123
- datachannelUrl: string,
124
- datachannelToken?: string,
125
- sessionId: string = LLM_DEFAULT_SESSION
126
- ): Promise<void> =>
127
- this.register(datachannelUrl, datachannelToken, sessionId).then(async () => {
87
+ public registerAndConnect = (locusUrl: string, datachannelUrl: string): Promise<void> =>
88
+ this.register(datachannelUrl).then(() => {
128
89
  if (!locusUrl || !datachannelUrl) return undefined;
129
-
130
- // Get or create connection data
131
- const sessionData = this.connections.get(sessionId) || {};
132
- sessionData.locusUrl = locusUrl;
133
- sessionData.datachannelUrl = datachannelUrl;
134
- sessionData.datachannelToken = datachannelToken;
135
- this.connections.set(sessionId, sessionData);
136
-
137
- const isDataChannelTokenEnabled = await this.isDataChannelTokenEnabled();
138
-
139
- const connectUrl = isDataChannelTokenEnabled
140
- ? LLMChannel.buildUrlWithAwareSubchannels(sessionData.webSocketUrl, AWARE_DATA_CHANNEL)
141
- : sessionData.webSocketUrl;
142
-
143
- return this.connect(connectUrl, sessionId);
90
+ this.locusUrl = locusUrl;
91
+ this.datachannelUrl = datachannelUrl;
92
+ this.connect(this.webSocketUrl);
144
93
  });
145
94
 
146
95
  /**
147
96
  * Tells if LLM socket is connected
148
- * @param {string} sessionId - Connection identifier
149
97
  * @returns {boolean} connected
150
98
  */
151
- public isConnected = (sessionId = LLM_DEFAULT_SESSION): boolean => {
152
- const socket = this.getSocket(sessionId);
153
-
154
- return socket ? socket.connected : false;
155
- };
99
+ public isConnected = (): boolean => this.connected;
156
100
 
157
101
  /**
158
102
  * Tells if LLM socket is binding
159
- * @param {string} sessionId - Connection identifier
160
103
  * @returns {string} binding
161
104
  */
162
- public getBinding = (sessionId = LLM_DEFAULT_SESSION): string => {
163
- const sessionData = this.connections.get(sessionId);
164
-
165
- return sessionData?.binding;
166
- };
105
+ public getBinding = (): string => this.binding;
167
106
 
168
107
  /**
169
108
  * Get Locus URL for the connection
170
- * @param {string} sessionId - Connection identifier
171
109
  * @returns {string} locus Url
172
110
  */
173
- public getLocusUrl = (sessionId = LLM_DEFAULT_SESSION): string => {
174
- const sessionData = this.connections.get(sessionId);
175
-
176
- return sessionData?.locusUrl;
177
- };
111
+ public getLocusUrl = (): string => this.locusUrl;
178
112
 
179
113
  /**
180
114
  * Get data channel URL for the connection
181
- * @param {string} sessionId - Connection identifier
182
115
  * @returns {string} data channel Url
183
116
  */
184
- public getDatachannelUrl = (sessionId = LLM_DEFAULT_SESSION): string => {
185
- const sessionData = this.connections.get(sessionId);
186
-
187
- return sessionData?.datachannelUrl;
188
- };
189
-
190
- /**
191
- * Get data channel token for the connection
192
- * @param {DataChannelTokenType} dataChannelTokenType
193
- * @returns {string} data channel token
194
- */
195
- public getDatachannelToken = (
196
- dataChannelTokenType: DataChannelTokenType = DataChannelTokenType.Default
197
- ): string => {
198
- return this.datachannelTokens[dataChannelTokenType];
199
- };
200
-
201
- /**
202
- * Set data channel token for the connection
203
- * @param {string} datachannelToken - data channel token
204
- * @param {DataChannelTokenType} dataChannelTokenType
205
- * @returns {void}
206
- */
207
- public setDatachannelToken = (
208
- datachannelToken: string,
209
- dataChannelTokenType: DataChannelTokenType = DataChannelTokenType.Default
210
- ): void => {
211
- this.datachannelTokens[dataChannelTokenType] = datachannelToken;
212
- };
213
-
214
- /**
215
- * Resets all data‑channel tokens to their initial undefined values.
216
- * Used when leaving or disconnecting from a meeting.
217
- * @returns {void}
218
- */
219
- public resetDatachannelTokens() {
220
- this.datachannelTokens = {
221
- [DataChannelTokenType.Default]: undefined,
222
- [DataChannelTokenType.PracticeSession]: undefined,
223
- };
224
- }
225
-
226
- /**
227
- * Set the handler used to refresh the DataChannel token
228
- *
229
- * @param {function} handler - Function that returns a refreshed token
230
- * @returns {void}
231
- */
232
- public setRefreshHandler(
233
- handler: () => Promise<{
234
- body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};
235
- }>
236
- ) {
237
- this.refreshHandler = handler;
238
- }
239
-
240
- /**
241
- * Refresh the data channel token using the injected handler.
242
- * Logs a descriptive error if the handler is missing or fails.
243
- *
244
- * @returns {Promise<string>} The refreshed token.
245
- */
246
- public async refreshDataChannelToken() {
247
- if (!this.refreshHandler) {
248
- this.logger.warn(
249
- 'llm#refreshDataChannelToken --> LLM refreshHandler is not set, skipping token refresh'
250
- );
251
-
252
- return null;
253
- }
254
-
255
- try {
256
- const res = await this.refreshHandler();
257
-
258
- return res;
259
- } catch (error: any) {
260
- this.logger.warn(
261
- `llm#refreshDataChannelToken --> DataChannel token refresh failed (likely locus changed or participant left): ${
262
- error?.message || error
263
- }`
264
- );
265
-
266
- return null;
267
- }
268
- }
117
+ public getDatachannelUrl = (): string => this.datachannelUrl;
269
118
 
270
119
  /**
271
120
  * Disconnects websocket connection
272
121
  * @param {{code: number, reason: string}} options - The disconnect option object with code and reason
273
- * @param {string} sessionId - Connection identifier
274
- * @returns {Promise<void>}
275
- */
276
- public disconnectLLM = (
277
- options: {code: number; reason: string},
278
- sessionId: string = LLM_DEFAULT_SESSION
279
- ): Promise<void> =>
280
- this.disconnect(options, sessionId).then(() => {
281
- // Clean up sessions data
282
- this.connections.delete(sessionId);
283
- });
284
-
285
- /**
286
- * Disconnects all LLM websocket connections
287
- * @param {{code: number, reason: string}} options - The disconnect option object with code and reason
288
122
  * @returns {Promise<void>}
289
123
  */
290
- public disconnectAllLLM = (options?: {code: number; reason: string}): Promise<void> =>
291
- this.disconnectAll(options).then(() => {
292
- // Clean up all connection data
293
- this.connections.clear();
124
+ public disconnectLLM = (options: object): Promise<void> =>
125
+ this.disconnect(options).then(() => {
126
+ this.locusUrl = undefined;
127
+ this.datachannelUrl = undefined;
128
+ this.binding = undefined;
129
+ this.webSocketUrl = undefined;
294
130
  });
295
-
296
- /**
297
- * Get all active LLM connections
298
- * @returns {Map} Map of sessionId to session data
299
- */
300
- public getAllConnections = (): Map<
301
- string,
302
- {
303
- webSocketUrl?: string;
304
- binding?: string;
305
- locusUrl?: string;
306
- datachannelUrl?: string;
307
- datachannelToken?: string;
308
- }
309
- > => new Map(this.connections);
310
-
311
- /**
312
- * Returns true if data channel token is enabled, false otherwise
313
- * @returns {Promise<boolean>} resolves with true if data channel token is enabled
314
- */
315
- public isDataChannelTokenEnabled(): Promise<boolean> {
316
- // @ts-ignore
317
- return this.webex.internal.feature.getFeature('developer', DATA_CHANNEL_WITH_JWT_TOKEN);
318
- }
319
-
320
- /**
321
- * Builds a WebSocket URL with the `subscriptionAwareSubchannels` query parameter.
322
- *
323
- * @param {string} baseUrl - The original WebSocket URL.
324
- * @param {string[]} subchannels - List of subchannels to declare as subscription-aware.
325
- * @returns {string} The final URL with updated query parameters.
326
- */
327
-
328
- public static buildUrlWithAwareSubchannels = (baseUrl: string, subchannels: string[]) => {
329
- const urlObj = new URL(baseUrl);
330
- urlObj.searchParams.set(SUBSCRIPTION_AWARE_SUBCHANNELS_PARAM, subchannels.join(','));
331
-
332
- return urlObj.toString();
333
- };
334
131
  }
package/src/llm.types.ts CHANGED
@@ -1,32 +1,9 @@
1
1
  interface ILLMChannel {
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
- >;
2
+ registerAndConnect: (locusUrl: string, datachannelUrl: string) => Promise<void>;
3
+ isConnected: () => boolean;
4
+ getBinding: () => string;
5
+ getLocusUrl: () => string;
6
+ disconnectLLM: (options: {code: number; reason: string}) => Promise<void>;
24
7
  }
25
-
26
- export enum DataChannelTokenType {
27
- Default = 'llm-default-session',
28
- PracticeSession = 'llm-practice-session',
29
- }
30
-
31
8
  // eslint-disable-next-line import/prefer-default-export
32
9
  export type {ILLMChannel};