-
Notifications
You must be signed in to change notification settings - Fork 404
Expand file tree
/
Copy pathllm-plugin.ts
More file actions
131 lines (115 loc) · 4.16 KB
/
Copy pathllm-plugin.ts
File metadata and controls
131 lines (115 loc) · 4.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/* eslint-disable require-jsdoc */
import {WebexPlugin} from '@webex/webex-core';
import LLMChannel, {config} from './llm';
import {DATA_CHANNEL_WITH_JWT_TOKEN} from './constants';
/**
* LLMPlugin — registered as `webex.internal.llm`.
*
* Factory for creating LLMChannel instances. Each Meeting creates and owns
* its own LLMChannel(s), allowing multiple independent connections without
* the need for session IDs or ownership tracking.
*
* This is a breaking API change from the previous design where the plugin
* maintained a Map of sessions and exposed session-keyed methods.
*
* Old usage (no longer supported):
* webex.internal.llm.isConnected()
* webex.internal.llm.registerAndConnect(url, dcUrl, token, sessionId)
*
* New usage:
* const llm = webex.internal.llm.createConnection();
* await llm.registerAndConnect(url, dcUrl, token);
* llm.isConnected();
* // When done:
* await llm.disconnect();
*/
export class LLMPlugin extends (WebexPlugin as any) {
namespace = 'llm';
/**
* Registry of active LLM channels for interceptor lookup.
* Channels are registered when created and unregistered on disconnect.
*/
private channels = new Set<LLMChannel>();
/**
* Creates a new LLMChannel instance. The caller owns the channel and is
* responsible for connecting, disconnecting, and cleaning it up.
*
* @example
* const llm = webex.internal.llm.createConnection();
* llm.setRefreshHandler(() => meeting.refreshDataChannelToken());
* await llm.registerAndConnect(locusUrl, datachannelUrl, token);
*
* // Subscribe to events directly on the channel
* llm.on('event:relay.event', handler);
* llm.on('online', onlineHandler);
*
* // When done
* await llm.disconnect();
*
* @returns {LLMChannel} A new LLM connection instance
*/
public createConnection(): LLMChannel {
// @ts-ignore — WebexPlugin children require {parent: this.webex}
const channel = new LLMChannel({parent: this.webex});
this.channels.add(channel);
// Auto-unregister when disconnected
channel.on('offline', () => {
this.channels.delete(channel);
});
return channel;
}
/**
* Returns true if the data channel token feature flag is enabled.
* This is a global check, not per-connection.
* @returns {Promise<boolean>}
*/
public isDataChannelTokenEnabled(): Promise<boolean> {
// @ts-ignore
return this.webex.internal.feature.getFeature('developer', DATA_CHANNEL_WITH_JWT_TOKEN);
}
/**
* Find a connection by its datachannel URL. Used by the interceptor to
* route token refresh requests to the correct channel.
* @param {string} url - The request URL to match
* @returns {LLMChannel | undefined}
*/
public getConnectionByDatachannelUrl(url: string): LLMChannel | undefined {
for (const channel of this.channels) {
const datachannelUrl = channel.getDatachannelUrl();
if (datachannelUrl && LLMChannel.matchesDatachannelRequestUrl(url, datachannelUrl)) {
return channel;
}
}
return undefined;
}
/**
* Find a locus URL by matching a request URL to an active connection's
* datachannel URL. Used by the interceptor.
* @param {string} requestUrl - The request URL to match
* @returns {string | undefined}
*/
public getLocusUrlByDatachannelUrl(requestUrl: string): string | undefined {
const channel = this.getConnectionByDatachannelUrl(requestUrl);
return channel?.getLocusUrl();
}
/**
* Get all active connections. Useful for diagnostics/debugging.
* @returns {Set<LLMChannel>}
*/
public getAllConnections(): Set<LLMChannel> {
return new Set(this.channels);
}
/**
* Disconnect all active connections. Useful for cleanup on logout.
* @param {object} [options] - Disconnect options
* @param {number} [options.code] - WebSocket close code
* @param {string} [options.reason] - WebSocket close reason
* @returns {Promise<void>}
*/
public async disconnectAll(options?: {code: number; reason: string}): Promise<void> {
const promises = Array.from(this.channels).map((channel) => channel.disconnect(options));
await Promise.all(promises);
}
}
export {config};
export default LLMPlugin;