@notebook-intelligence/notebook-intelligence 1.2.2

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/src/api.ts ADDED
@@ -0,0 +1,333 @@
1
+ // Copyright (c) Mehmet Bektas <mbektasgh@outlook.com>
2
+
3
+ import { ServerConnection } from '@jupyterlab/services';
4
+ import { requestAPI } from './handler';
5
+ import { URLExt } from '@jupyterlab/coreutils';
6
+ import { UUID } from '@lumino/coreutils';
7
+ import { Signal } from '@lumino/signaling';
8
+ import {
9
+ GITHUB_COPILOT_PROVIDER_ID,
10
+ IChatCompletionResponseEmitter,
11
+ IChatParticipant,
12
+ IContextItem,
13
+ ITelemetryEvent,
14
+ RequestDataType
15
+ } from './tokens';
16
+
17
+ const LOGIN_STATUS_UPDATE_INTERVAL = 2000;
18
+
19
+ export enum GitHubCopilotLoginStatus {
20
+ NotLoggedIn = 'NOT_LOGGED_IN',
21
+ ActivatingDevice = 'ACTIVATING_DEVICE',
22
+ LoggingIn = 'LOGGING_IN',
23
+ LoggedIn = 'LOGGED_IN'
24
+ }
25
+
26
+ export interface IDeviceVerificationInfo {
27
+ verificationURI: string;
28
+ userCode: string;
29
+ }
30
+
31
+ export class NBIConfig {
32
+ get llmProviders(): [any] {
33
+ return this.capabilities.llm_providers;
34
+ }
35
+
36
+ get chatModels(): [any] {
37
+ return this.capabilities.chat_models;
38
+ }
39
+
40
+ get inlineCompletionModels(): [any] {
41
+ return this.capabilities.inline_completion_models;
42
+ }
43
+
44
+ get chatModel(): any {
45
+ return this.capabilities.chat_model;
46
+ }
47
+
48
+ get inlineCompletionModel(): any {
49
+ return this.capabilities.inline_completion_model;
50
+ }
51
+
52
+ get usingGitHubCopilotModel(): boolean {
53
+ return (
54
+ this.chatModel.provider === GITHUB_COPILOT_PROVIDER_ID ||
55
+ this.inlineCompletionModel.provider === GITHUB_COPILOT_PROVIDER_ID
56
+ );
57
+ }
58
+
59
+ capabilities: any = {};
60
+ chatParticipants: IChatParticipant[] = [];
61
+
62
+ changed = new Signal<this, void>(this);
63
+ }
64
+
65
+ export class NBIAPI {
66
+ static _loginStatus = GitHubCopilotLoginStatus.NotLoggedIn;
67
+ static _deviceVerificationInfo: IDeviceVerificationInfo = {
68
+ verificationURI: '',
69
+ userCode: ''
70
+ };
71
+ static _webSocket: WebSocket;
72
+ static _messageReceived = new Signal<unknown, any>(this);
73
+ static config = new NBIConfig();
74
+ static configChanged = this.config.changed;
75
+
76
+ static async initialize() {
77
+ await this.fetchCapabilities();
78
+ this.updateGitHubLoginStatus();
79
+
80
+ setInterval(() => {
81
+ this.updateGitHubLoginStatus();
82
+ }, LOGIN_STATUS_UPDATE_INTERVAL);
83
+
84
+ NBIAPI.initializeWebsocket();
85
+ }
86
+
87
+ static async initializeWebsocket() {
88
+ const serverSettings = ServerConnection.makeSettings();
89
+ const wsUrl = URLExt.join(
90
+ serverSettings.wsUrl,
91
+ 'notebook-intelligence',
92
+ 'copilot'
93
+ );
94
+
95
+ this._webSocket = new WebSocket(wsUrl);
96
+ this._webSocket.onmessage = msg => {
97
+ this._messageReceived.emit(msg.data);
98
+ };
99
+ }
100
+
101
+ static getLoginStatus(): GitHubCopilotLoginStatus {
102
+ return this._loginStatus;
103
+ }
104
+
105
+ static getDeviceVerificationInfo(): IDeviceVerificationInfo {
106
+ return this._deviceVerificationInfo;
107
+ }
108
+
109
+ static async loginToGitHub() {
110
+ this._loginStatus = GitHubCopilotLoginStatus.ActivatingDevice;
111
+ return new Promise((resolve, reject) => {
112
+ requestAPI<any>('gh-login', { method: 'POST' })
113
+ .then(data => {
114
+ resolve({
115
+ verificationURI: data.verification_uri,
116
+ userCode: data.user_code
117
+ });
118
+ this.updateGitHubLoginStatus();
119
+ })
120
+ .catch(reason => {
121
+ console.error(`Failed to login to GitHub Copilot.\n${reason}`);
122
+ reject(reason);
123
+ });
124
+ });
125
+ }
126
+
127
+ static async logoutFromGitHub() {
128
+ this._loginStatus = GitHubCopilotLoginStatus.ActivatingDevice;
129
+ return new Promise((resolve, reject) => {
130
+ requestAPI<any>('gh-logout', { method: 'GET' })
131
+ .then(data => {
132
+ this.updateGitHubLoginStatus().then(() => {
133
+ resolve(data);
134
+ });
135
+ })
136
+ .catch(reason => {
137
+ console.error(`Failed to logout from GitHub Copilot.\n${reason}`);
138
+ reject(reason);
139
+ });
140
+ });
141
+ }
142
+
143
+ static async updateGitHubLoginStatus() {
144
+ return new Promise<void>((resolve, reject) => {
145
+ requestAPI<any>('gh-login-status')
146
+ .then(response => {
147
+ this._loginStatus = response.status;
148
+ this._deviceVerificationInfo.verificationURI =
149
+ response.verification_uri || '';
150
+ this._deviceVerificationInfo.userCode = response.user_code || '';
151
+ resolve();
152
+ })
153
+ .catch(reason => {
154
+ console.error(
155
+ `Failed to fetch GitHub Copilot login status.\n${reason}`
156
+ );
157
+ reject(reason);
158
+ });
159
+ });
160
+ }
161
+
162
+ static async fetchCapabilities(): Promise<void> {
163
+ return new Promise<void>((resolve, reject) => {
164
+ requestAPI<any>('capabilities', { method: 'GET' })
165
+ .then(data => {
166
+ this.config.capabilities = structuredClone(data);
167
+ this.config.chatParticipants = structuredClone(
168
+ data.chat_participants
169
+ );
170
+ this.configChanged.emit();
171
+ resolve();
172
+ })
173
+ .catch(reason => {
174
+ console.error(`Failed to get extension capabilities.\n${reason}`);
175
+ reject(reason);
176
+ });
177
+ });
178
+ }
179
+
180
+ static async setConfig(config: any) {
181
+ requestAPI<any>('config', {
182
+ method: 'POST',
183
+ body: JSON.stringify(config)
184
+ })
185
+ .then(data => {
186
+ NBIAPI.fetchCapabilities();
187
+ })
188
+ .catch(reason => {
189
+ console.error(`Failed to set NBI config.\n${reason}`);
190
+ });
191
+ }
192
+
193
+ static async updateOllamaModelList(): Promise<void> {
194
+ return new Promise<void>((resolve, reject) => {
195
+ requestAPI<any>('update-provider-models', {
196
+ method: 'POST',
197
+ body: JSON.stringify({ provider: 'ollama' })
198
+ })
199
+ .then(async data => {
200
+ await NBIAPI.fetchCapabilities();
201
+ resolve();
202
+ })
203
+ .catch(reason => {
204
+ console.error(`Failed to update ollama model list.\n${reason}`);
205
+ reject(reason);
206
+ });
207
+ });
208
+ }
209
+
210
+ static async chatRequest(
211
+ messageId: string,
212
+ chatId: string,
213
+ prompt: string,
214
+ language: string,
215
+ filename: string,
216
+ additionalContext: IContextItem[],
217
+ responseEmitter: IChatCompletionResponseEmitter
218
+ ) {
219
+ this._messageReceived.connect((_, msg) => {
220
+ msg = JSON.parse(msg);
221
+ if (msg.id === messageId) {
222
+ responseEmitter.emit(msg);
223
+ }
224
+ });
225
+ this._webSocket.send(
226
+ JSON.stringify({
227
+ id: messageId,
228
+ type: RequestDataType.ChatRequest,
229
+ data: { chatId, prompt, language, filename, additionalContext }
230
+ })
231
+ );
232
+ }
233
+
234
+ static async generateCode(
235
+ chatId: string,
236
+ prompt: string,
237
+ prefix: string,
238
+ suffix: string,
239
+ existingCode: string,
240
+ language: string,
241
+ filename: string,
242
+ responseEmitter: IChatCompletionResponseEmitter
243
+ ) {
244
+ const messageId = UUID.uuid4();
245
+ this._messageReceived.connect((_, msg) => {
246
+ msg = JSON.parse(msg);
247
+ if (msg.id === messageId) {
248
+ responseEmitter.emit(msg);
249
+ }
250
+ });
251
+ this._webSocket.send(
252
+ JSON.stringify({
253
+ id: messageId,
254
+ type: RequestDataType.GenerateCode,
255
+ data: {
256
+ chatId,
257
+ prompt,
258
+ prefix,
259
+ suffix,
260
+ existingCode,
261
+ language,
262
+ filename
263
+ }
264
+ })
265
+ );
266
+ }
267
+
268
+ static async sendChatUserInput(messageId: string, data: any) {
269
+ this._webSocket.send(
270
+ JSON.stringify({
271
+ id: messageId,
272
+ type: RequestDataType.ChatUserInput,
273
+ data
274
+ })
275
+ );
276
+ }
277
+
278
+ static async sendWebSocketMessage(
279
+ messageId: string,
280
+ messageType: RequestDataType,
281
+ data: any
282
+ ) {
283
+ this._webSocket.send(
284
+ JSON.stringify({ id: messageId, type: messageType, data })
285
+ );
286
+ }
287
+
288
+ static async inlineCompletionsRequest(
289
+ chatId: string,
290
+ messageId: string,
291
+ prefix: string,
292
+ suffix: string,
293
+ language: string,
294
+ filename: string,
295
+ responseEmitter: IChatCompletionResponseEmitter
296
+ ) {
297
+ this._messageReceived.connect((_, msg) => {
298
+ msg = JSON.parse(msg);
299
+ if (msg.id === messageId) {
300
+ responseEmitter.emit(msg);
301
+ }
302
+ });
303
+ this._webSocket.send(
304
+ JSON.stringify({
305
+ id: messageId,
306
+ type: RequestDataType.InlineCompletionRequest,
307
+ data: {
308
+ chatId,
309
+ prefix,
310
+ suffix,
311
+ language,
312
+ filename
313
+ }
314
+ })
315
+ );
316
+ }
317
+
318
+ static async emitTelemetryEvent(event: ITelemetryEvent): Promise<void> {
319
+ return new Promise<void>((resolve, reject) => {
320
+ requestAPI<any>('emit-telemetry-event', {
321
+ method: 'POST',
322
+ body: JSON.stringify(event)
323
+ })
324
+ .then(async data => {
325
+ resolve();
326
+ })
327
+ .catch(reason => {
328
+ console.error(`Failed to emit telemetry event.\n${reason}`);
329
+ reject(reason);
330
+ });
331
+ });
332
+ }
333
+ }