1
+ import { Notification } from '@jupyterlab/apputils' ;
1
2
import {
2
3
CompletionHandler ,
3
4
IInlineCompletionContext
4
5
} from '@jupyterlab/completer' ;
5
6
import { BaseLanguageModel } from '@langchain/core/language_models/base' ;
6
7
import { BaseChatModel } from '@langchain/core/language_models/chat_models' ;
7
- import { ISignal , Signal } from '@lumino/signaling' ;
8
8
import { ReadonlyPartialJSONObject } from '@lumino/coreutils' ;
9
+ import { Debouncer } from '@lumino/polling' ;
10
+ import { ISignal , Signal } from '@lumino/signaling' ;
9
11
import { JSONSchema7 } from 'json-schema' ;
10
12
import { ISecretsManager } from 'jupyter-secrets-manager' ;
11
13
@@ -21,37 +23,7 @@ import {
21
23
import { AIChatModel , AICompleter } from './types/ai-model' ;
22
24
23
25
const SECRETS_NAMESPACE = PLUGIN_IDS . providerRegistry ;
24
-
25
- export const chatSystemPrompt = (
26
- options : AIProviderRegistry . IPromptOptions
27
- ) => `
28
- You are Jupyternaut, a conversational assistant living in JupyterLab to help users.
29
- You are not a language model, but rather an application built on a foundation model from ${ options . provider_name } .
30
- You are talkative and you provide lots of specific details from the foundation model's context.
31
- You may use Markdown to format your response.
32
- If your response includes code, they must be enclosed in Markdown fenced code blocks (with triple backticks before and after).
33
- If your response includes mathematical notation, they must be expressed in LaTeX markup and enclosed in LaTeX delimiters.
34
- All dollar quantities (of USD) must be formatted in LaTeX, with the \`$\` symbol escaped by a single backslash \`\\\`.
35
- - Example prompt: \`If I have \\\\$100 and spend \\\\$20, how much money do I have left?\`
36
- - **Correct** response: \`You have \\(\\$80\\) remaining.\`
37
- - **Incorrect** response: \`You have $80 remaining.\`
38
- If you do not know the answer to a question, answer truthfully by responding that you do not know.
39
- The following is a friendly conversation between you and a human.
40
- ` ;
41
-
42
- export const COMPLETION_SYSTEM_PROMPT = `
43
- You are an application built to provide helpful code completion suggestions.
44
- You should only produce code. Keep comments to minimum, use the
45
- programming language comment syntax. Produce clean code.
46
- The code is written in JupyterLab, a data analysis and code development
47
- environment which can execute code extended with additional syntax for
48
- interactive features, such as magics.
49
- Only give raw strings back, do not format the response using backticks.
50
- The output should be a single string, and should only contain the code that will complete the
51
- give code passed as input, no explanation whatsoever.
52
- Do not include the prompt in the output, only the string that should be appended to the current input.
53
- Here is the code to complete:
54
- ` ;
26
+ const NOTIFICATION_DELAY = 2000 ;
55
27
56
28
export class AIProviderRegistry implements IAIProviderRegistry {
57
29
/**
@@ -60,6 +32,11 @@ export class AIProviderRegistry implements IAIProviderRegistry {
60
32
constructor ( options : AIProviderRegistry . IOptions ) {
61
33
this . _secretsManager = options . secretsManager || null ;
62
34
Private . setToken ( options . token ) ;
35
+
36
+ this . _notifications = {
37
+ chat : new Debouncer ( this . _emitErrorNotification , NOTIFICATION_DELAY ) ,
38
+ completer : new Debouncer ( this . _emitErrorNotification , NOTIFICATION_DELAY )
39
+ } ;
63
40
}
64
41
65
42
/**
@@ -206,18 +183,39 @@ export class AIProviderRegistry implements IAIProviderRegistry {
206
183
}
207
184
208
185
/**
209
- * Get the current chat error;
186
+ * Get/set the current chat error;
210
187
*/
211
188
get chatError ( ) : string {
212
189
return this . _chatError ;
213
190
}
191
+ private set chatError ( error : string ) {
192
+ this . _chatError = error ;
193
+ if ( error !== '' ) {
194
+ this . _notifications . chat . invoke ( `Chat: ${ error } ` ) ;
195
+ }
196
+ }
214
197
215
198
/**
216
- * Get the current completer error.
199
+ * Get/set the current completer error.
217
200
*/
218
201
get completerError ( ) : string {
219
202
return this . _completerError ;
220
203
}
204
+ private set completerError ( error : string ) {
205
+ this . _completerError = error ;
206
+ if ( error !== '' ) {
207
+ this . _notifications . completer . invoke ( `Completer: ${ error } ` ) ;
208
+ }
209
+ }
210
+
211
+ /**
212
+ * A function to emit a notification error.
213
+ */
214
+ private _emitErrorNotification ( error : string ) {
215
+ Notification . emit ( error , 'error' , {
216
+ autoClose : NOTIFICATION_DELAY
217
+ } ) ;
218
+ }
221
219
222
220
/**
223
221
* Set the completer provider.
@@ -228,11 +226,11 @@ export class AIProviderRegistry implements IAIProviderRegistry {
228
226
async setCompleterProvider (
229
227
settings : ReadonlyPartialJSONObject
230
228
) : Promise < void > {
231
- this . _completerError = '' ;
229
+ this . completerError = '' ;
232
230
if ( ! Object . keys ( settings ) . includes ( 'provider' ) ) {
233
231
Private . setName ( 'completer' , 'None' ) ;
234
232
Private . setCompleter ( null ) ;
235
- this . _completerError =
233
+ this . completerError =
236
234
'The provider is missing from the completer settings' ;
237
235
return ;
238
236
}
@@ -253,7 +251,7 @@ export class AIProviderRegistry implements IAIProviderRegistry {
253
251
if ( compatibilityCheck !== undefined ) {
254
252
const error = await compatibilityCheck ( ) ;
255
253
if ( error !== null ) {
256
- this . _completerError = error . trim ( ) ;
254
+ this . completerError = error . trim ( ) ;
257
255
Private . setName ( 'completer' , 'None' ) ;
258
256
this . _providerChanged . emit ( 'completer' ) ;
259
257
return ;
@@ -272,7 +270,7 @@ export class AIProviderRegistry implements IAIProviderRegistry {
272
270
} )
273
271
) ;
274
272
} catch ( e : any ) {
275
- this . _completerError = e . message ;
273
+ this . completerError = e . message ;
276
274
}
277
275
} else {
278
276
Private . setCompleter ( null ) ;
@@ -288,11 +286,11 @@ export class AIProviderRegistry implements IAIProviderRegistry {
288
286
* @param options - An object with the name and the settings of the provider to use.
289
287
*/
290
288
async setChatProvider ( settings : ReadonlyPartialJSONObject ) : Promise < void > {
291
- this . _chatError = '' ;
289
+ this . chatError = '' ;
292
290
if ( ! Object . keys ( settings ) . includes ( 'provider' ) ) {
293
- Private . setName ( 'completer ' , 'None' ) ;
294
- Private . setCompleter ( null ) ;
295
- this . _chatError = 'The provider is missing from the chat settings' ;
291
+ Private . setName ( 'chat ' , 'None' ) ;
292
+ Private . setChatModel ( null ) ;
293
+ this . chatError = 'The provider is missing from the chat settings' ;
296
294
return ;
297
295
}
298
296
const provider = settings [ 'provider' ] as string ;
@@ -312,7 +310,7 @@ export class AIProviderRegistry implements IAIProviderRegistry {
312
310
if ( compatibilityCheck !== undefined ) {
313
311
const error = await compatibilityCheck ( ) ;
314
312
if ( error !== null ) {
315
- this . _chatError = error . trim ( ) ;
313
+ this . chatError = error . trim ( ) ;
316
314
Private . setName ( 'chat' , 'None' ) ;
317
315
this . _providerChanged . emit ( 'chat' ) ;
318
316
return ;
@@ -330,7 +328,7 @@ export class AIProviderRegistry implements IAIProviderRegistry {
330
328
} )
331
329
) ;
332
330
} catch ( e : any ) {
333
- this . _chatError = e . message ;
331
+ this . chatError = e . message ;
334
332
Private . setChatModel ( null ) ;
335
333
}
336
334
} else {
@@ -378,6 +376,9 @@ export class AIProviderRegistry implements IAIProviderRegistry {
378
376
private _providerChanged = new Signal < IAIProviderRegistry , ModelRole > ( this ) ;
379
377
private _chatError : string = '' ;
380
378
private _completerError : string = '' ;
379
+ private _notifications : {
380
+ [ key in ModelRole ] : Debouncer ;
381
+ } ;
381
382
private _deferredProvider : {
382
383
[ key in ModelRole ] : ReadonlyPartialJSONObject | null ;
383
384
} = {
0 commit comments