@jupyterlite/ai 0.6.2 → 0.8.0
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 +1 -1
- package/lib/base-completer.d.ts +22 -5
- package/lib/base-completer.js +14 -1
- package/lib/chat-handler.d.ts +23 -11
- package/lib/chat-handler.js +66 -45
- package/lib/completion-provider.d.ts +2 -2
- package/lib/completion-provider.js +5 -4
- package/lib/components/stop-button.d.ts +0 -1
- package/lib/default-prompts.d.ts +2 -0
- package/lib/default-prompts.js +31 -0
- package/lib/default-providers/Anthropic/completer.d.ts +4 -11
- package/lib/default-providers/Anthropic/completer.js +5 -16
- package/lib/default-providers/ChromeAI/completer.d.ts +4 -11
- package/lib/default-providers/ChromeAI/completer.js +5 -16
- package/lib/default-providers/ChromeAI/instructions.d.ts +4 -0
- package/lib/default-providers/ChromeAI/instructions.js +18 -0
- package/lib/default-providers/ChromeAI/settings-schema.json +0 -3
- package/lib/default-providers/Gemini/completer.d.ts +12 -0
- package/lib/default-providers/Gemini/completer.js +48 -0
- package/lib/default-providers/Gemini/instructions.d.ts +2 -0
- package/lib/default-providers/Gemini/instructions.js +9 -0
- package/lib/default-providers/Gemini/settings-schema.json +64 -0
- package/lib/default-providers/MistralAI/completer.d.ts +10 -13
- package/lib/default-providers/MistralAI/completer.js +42 -52
- package/lib/default-providers/MistralAI/instructions.d.ts +1 -1
- package/lib/default-providers/MistralAI/instructions.js +2 -0
- package/lib/default-providers/Ollama/completer.d.ts +12 -0
- package/lib/default-providers/Ollama/completer.js +43 -0
- package/lib/default-providers/Ollama/instructions.d.ts +2 -0
- package/lib/default-providers/Ollama/instructions.js +70 -0
- package/lib/default-providers/Ollama/settings-schema.json +143 -0
- package/lib/default-providers/OpenAI/completer.d.ts +4 -11
- package/lib/default-providers/OpenAI/completer.js +8 -16
- package/lib/default-providers/OpenAI/settings-schema.json +88 -128
- package/lib/default-providers/WebLLM/completer.d.ts +21 -0
- package/lib/default-providers/WebLLM/completer.js +127 -0
- package/lib/default-providers/WebLLM/instructions.d.ts +6 -0
- package/lib/default-providers/WebLLM/instructions.js +32 -0
- package/lib/default-providers/WebLLM/settings-schema.json +19 -0
- package/lib/default-providers/index.js +127 -8
- package/lib/index.d.ts +3 -2
- package/lib/index.js +80 -36
- package/lib/provider.d.ts +48 -22
- package/lib/provider.js +254 -101
- package/lib/settings/index.d.ts +1 -1
- package/lib/settings/index.js +1 -1
- package/lib/settings/panel.d.ts +151 -14
- package/lib/settings/panel.js +334 -145
- package/lib/settings/textarea.d.ts +2 -0
- package/lib/settings/textarea.js +18 -0
- package/lib/tokens.d.ts +45 -22
- package/lib/tokens.js +2 -1
- package/lib/types/ai-model.d.ts +24 -0
- package/lib/types/ai-model.js +5 -0
- package/package.json +19 -15
- package/schema/chat.json +1 -1
- package/schema/provider-registry.json +8 -8
- package/schema/system-prompts.json +22 -0
- package/src/base-completer.ts +38 -6
- package/src/chat-handler.ts +62 -31
- package/src/completion-provider.ts +3 -3
- package/src/default-prompts.ts +33 -0
- package/src/default-providers/Anthropic/completer.ts +5 -21
- package/src/default-providers/ChromeAI/completer.ts +5 -21
- package/src/default-providers/ChromeAI/instructions.ts +21 -0
- package/src/default-providers/Gemini/completer.ts +61 -0
- package/src/default-providers/Gemini/instructions.ts +9 -0
- package/src/default-providers/MistralAI/completer.ts +47 -65
- package/src/default-providers/MistralAI/instructions.ts +2 -0
- package/src/default-providers/Ollama/completer.ts +54 -0
- package/src/default-providers/Ollama/instructions.ts +70 -0
- package/src/default-providers/OpenAI/completer.ts +8 -21
- package/src/default-providers/WebLLM/completer.ts +151 -0
- package/src/default-providers/WebLLM/instructions.ts +33 -0
- package/src/default-providers/index.ts +158 -18
- package/src/index.ts +108 -40
- package/src/provider.ts +300 -109
- package/src/settings/index.ts +1 -1
- package/src/settings/panel.tsx +463 -101
- package/src/settings/textarea.tsx +33 -0
- package/src/tokens.ts +49 -24
- package/src/types/ai-model.ts +37 -0
- package/src/types/service-worker.d.ts +6 -0
- package/style/base.css +34 -0
- package/lib/settings/settings-connector.d.ts +0 -31
- package/lib/settings/settings-connector.js +0 -61
- package/src/settings/settings-connector.ts +0 -88
package/src/provider.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
import { Notification } from '@jupyterlab/apputils';
|
|
2
|
+
import {
|
|
3
|
+
CompletionHandler,
|
|
4
|
+
IInlineCompletionContext
|
|
5
|
+
} from '@jupyterlab/completer';
|
|
1
6
|
import { BaseLanguageModel } from '@langchain/core/language_models/base';
|
|
2
7
|
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
3
|
-
import { ISignal, Signal } from '@lumino/signaling';
|
|
4
8
|
import { ReadonlyPartialJSONObject } from '@lumino/coreutils';
|
|
9
|
+
import { Debouncer } from '@lumino/polling';
|
|
10
|
+
import { ISignal, Signal } from '@lumino/signaling';
|
|
5
11
|
import { JSONSchema7 } from 'json-schema';
|
|
6
12
|
import { ISecretsManager } from 'jupyter-secrets-manager';
|
|
7
13
|
|
|
@@ -11,41 +17,13 @@ import {
|
|
|
11
17
|
IAIProvider,
|
|
12
18
|
IAIProviderRegistry,
|
|
13
19
|
IDict,
|
|
14
|
-
|
|
20
|
+
ModelRole,
|
|
15
21
|
PLUGIN_IDS
|
|
16
22
|
} from './tokens';
|
|
23
|
+
import { AIChatModel, AICompleter } from './types/ai-model';
|
|
17
24
|
|
|
18
25
|
const SECRETS_NAMESPACE = PLUGIN_IDS.providerRegistry;
|
|
19
|
-
|
|
20
|
-
export const chatSystemPrompt = (
|
|
21
|
-
options: AIProviderRegistry.IPromptOptions
|
|
22
|
-
) => `
|
|
23
|
-
You are Jupyternaut, a conversational assistant living in JupyterLab to help users.
|
|
24
|
-
You are not a language model, but rather an application built on a foundation model from ${options.provider_name}.
|
|
25
|
-
You are talkative and you provide lots of specific details from the foundation model's context.
|
|
26
|
-
You may use Markdown to format your response.
|
|
27
|
-
If your response includes code, they must be enclosed in Markdown fenced code blocks (with triple backticks before and after).
|
|
28
|
-
If your response includes mathematical notation, they must be expressed in LaTeX markup and enclosed in LaTeX delimiters.
|
|
29
|
-
All dollar quantities (of USD) must be formatted in LaTeX, with the \`$\` symbol escaped by a single backslash \`\\\`.
|
|
30
|
-
- Example prompt: \`If I have \\\\$100 and spend \\\\$20, how much money do I have left?\`
|
|
31
|
-
- **Correct** response: \`You have \\(\\$80\\) remaining.\`
|
|
32
|
-
- **Incorrect** response: \`You have $80 remaining.\`
|
|
33
|
-
If you do not know the answer to a question, answer truthfully by responding that you do not know.
|
|
34
|
-
The following is a friendly conversation between you and a human.
|
|
35
|
-
`;
|
|
36
|
-
|
|
37
|
-
export const COMPLETION_SYSTEM_PROMPT = `
|
|
38
|
-
You are an application built to provide helpful code completion suggestions.
|
|
39
|
-
You should only produce code. Keep comments to minimum, use the
|
|
40
|
-
programming language comment syntax. Produce clean code.
|
|
41
|
-
The code is written in JupyterLab, a data analysis and code development
|
|
42
|
-
environment which can execute code extended with additional syntax for
|
|
43
|
-
interactive features, such as magics.
|
|
44
|
-
Only give raw strings back, do not format the response using backticks.
|
|
45
|
-
The output should be a single string, and should correspond to what a human users
|
|
46
|
-
would write.
|
|
47
|
-
Do not include the prompt in the output, only the string that should be appended to the current input.
|
|
48
|
-
`;
|
|
26
|
+
const NOTIFICATION_DELAY = 2000;
|
|
49
27
|
|
|
50
28
|
export class AIProviderRegistry implements IAIProviderRegistry {
|
|
51
29
|
/**
|
|
@@ -54,64 +32,122 @@ export class AIProviderRegistry implements IAIProviderRegistry {
|
|
|
54
32
|
constructor(options: AIProviderRegistry.IOptions) {
|
|
55
33
|
this._secretsManager = options.secretsManager || null;
|
|
56
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
|
+
};
|
|
57
40
|
}
|
|
58
41
|
|
|
59
42
|
/**
|
|
60
43
|
* Get the list of provider names.
|
|
61
44
|
*/
|
|
62
45
|
get providers(): string[] {
|
|
63
|
-
return Array.from(
|
|
46
|
+
return Array.from(Private.providers.keys());
|
|
64
47
|
}
|
|
65
48
|
|
|
66
49
|
/**
|
|
67
50
|
* Add a new provider.
|
|
68
51
|
*/
|
|
69
52
|
add(provider: IAIProvider): void {
|
|
70
|
-
if (
|
|
53
|
+
if (Private.providers.has(provider.name)) {
|
|
71
54
|
throw new Error(
|
|
72
55
|
`A AI provider named '${provider.name}' is already registered`
|
|
73
56
|
);
|
|
74
57
|
}
|
|
75
|
-
|
|
58
|
+
Private.providers.set(provider.name, provider);
|
|
76
59
|
|
|
77
|
-
// Set the
|
|
78
|
-
if (provider.name === this._deferredProvider?.name) {
|
|
79
|
-
this.
|
|
60
|
+
// Set the providers if the loading has been deferred.
|
|
61
|
+
if (provider.name === this._deferredProvider.completer?.name) {
|
|
62
|
+
this.setCompleterProvider(this._deferredProvider.completer);
|
|
63
|
+
}
|
|
64
|
+
if (provider.name === this._deferredProvider.chat?.name) {
|
|
65
|
+
this.setChatProvider(this._deferredProvider.chat);
|
|
80
66
|
}
|
|
81
67
|
}
|
|
82
68
|
|
|
83
69
|
/**
|
|
84
70
|
* Get the current provider name.
|
|
85
71
|
*/
|
|
86
|
-
|
|
87
|
-
return
|
|
72
|
+
currentName(role: ModelRole): string {
|
|
73
|
+
return Private.getName(role);
|
|
88
74
|
}
|
|
89
75
|
|
|
90
76
|
/**
|
|
91
|
-
* Get the current
|
|
77
|
+
* Get the current AICompleter.
|
|
92
78
|
*/
|
|
93
|
-
get currentCompleter():
|
|
94
|
-
if (
|
|
79
|
+
get currentCompleter(): AICompleter | null {
|
|
80
|
+
if (Private.getName('completer') === 'None') {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const completer = Private.getCompleter();
|
|
84
|
+
if (completer === null) {
|
|
95
85
|
return null;
|
|
96
86
|
}
|
|
97
|
-
return
|
|
87
|
+
return {
|
|
88
|
+
fetch: (
|
|
89
|
+
request: CompletionHandler.IRequest,
|
|
90
|
+
context: IInlineCompletionContext
|
|
91
|
+
) => completer.fetch(request, context)
|
|
92
|
+
};
|
|
98
93
|
}
|
|
99
94
|
|
|
100
95
|
/**
|
|
101
|
-
*
|
|
96
|
+
* Getter/setter for the completer system prompt.
|
|
102
97
|
*/
|
|
103
|
-
get
|
|
104
|
-
|
|
98
|
+
get completerSystemPrompt(): string {
|
|
99
|
+
return this._completerPrompt.replaceAll(
|
|
100
|
+
'$provider_name$',
|
|
101
|
+
this.currentName('completer')
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
set completerSystemPrompt(value: string) {
|
|
105
|
+
this._completerPrompt = value;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Get the current AIChatModel.
|
|
110
|
+
*/
|
|
111
|
+
get currentChatModel(): AIChatModel | null {
|
|
112
|
+
if (Private.getName('chat') === 'None') {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
const currentProvider =
|
|
116
|
+
Private.providers.get(Private.getName('chat')) ?? null;
|
|
117
|
+
|
|
118
|
+
const chatModel = Private.getChatModel();
|
|
119
|
+
if (chatModel === null) {
|
|
105
120
|
return null;
|
|
106
121
|
}
|
|
107
|
-
|
|
122
|
+
if (currentProvider?.exposeChatModel ?? false) {
|
|
123
|
+
// Expose the full chat model if expected.
|
|
124
|
+
return chatModel as AIChatModel;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Otherwise, we create a reduced AIChatModel interface.
|
|
128
|
+
return {
|
|
129
|
+
stream: (input: any, options?: any) => chatModel.stream(input, options)
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Getter/setter for the chat system prompt.
|
|
135
|
+
*/
|
|
136
|
+
get chatSystemPrompt(): string {
|
|
137
|
+
return this._chatPrompt.replaceAll(
|
|
138
|
+
'$provider_name$',
|
|
139
|
+
this.currentName('chat')
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
set chatSystemPrompt(value: string) {
|
|
143
|
+
this._chatPrompt = value;
|
|
108
144
|
}
|
|
109
145
|
|
|
110
146
|
/**
|
|
111
147
|
* Get the settings schema of a given provider.
|
|
112
148
|
*/
|
|
113
149
|
getSettingsSchema(provider: string): JSONSchema7 {
|
|
114
|
-
return (
|
|
150
|
+
return (Private.providers.get(provider)?.settingsSchema?.properties ||
|
|
115
151
|
{}) as JSONSchema7;
|
|
116
152
|
}
|
|
117
153
|
|
|
@@ -119,15 +155,26 @@ export class AIProviderRegistry implements IAIProviderRegistry {
|
|
|
119
155
|
* Get the instructions of a given provider.
|
|
120
156
|
*/
|
|
121
157
|
getInstructions(provider: string): string | undefined {
|
|
122
|
-
return
|
|
158
|
+
return Private.providers.get(provider)?.instructions;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Get the compatibility check function of a given provider.
|
|
163
|
+
*/
|
|
164
|
+
getCompatibilityCheck(
|
|
165
|
+
provider: string
|
|
166
|
+
): (() => Promise<string | null>) | undefined {
|
|
167
|
+
return Private.providers.get(provider)?.compatibilityCheck;
|
|
123
168
|
}
|
|
124
169
|
|
|
125
170
|
/**
|
|
126
171
|
* Format an error message from the current provider.
|
|
127
172
|
*/
|
|
128
173
|
formatErrorMessage(error: any): string {
|
|
129
|
-
|
|
130
|
-
|
|
174
|
+
const currentProvider =
|
|
175
|
+
Private.providers.get(Private.getName('chat')) ?? null;
|
|
176
|
+
if (currentProvider?.errorMessage) {
|
|
177
|
+
return currentProvider?.errorMessage(error);
|
|
131
178
|
}
|
|
132
179
|
if (error.message) {
|
|
133
180
|
return error.message;
|
|
@@ -136,101 +183,210 @@ export class AIProviderRegistry implements IAIProviderRegistry {
|
|
|
136
183
|
}
|
|
137
184
|
|
|
138
185
|
/**
|
|
139
|
-
* Get the current chat error;
|
|
186
|
+
* Get/set the current chat error;
|
|
140
187
|
*/
|
|
141
188
|
get chatError(): string {
|
|
142
189
|
return this._chatError;
|
|
143
190
|
}
|
|
191
|
+
private set chatError(error: string) {
|
|
192
|
+
this._chatError = error;
|
|
193
|
+
if (error !== '') {
|
|
194
|
+
this._notifications.chat.invoke(`Chat: ${error}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
144
197
|
|
|
145
198
|
/**
|
|
146
|
-
*
|
|
199
|
+
* Get/set the current completer error.
|
|
147
200
|
*/
|
|
148
201
|
get completerError(): string {
|
|
149
202
|
return this._completerError;
|
|
150
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
|
+
}
|
|
151
219
|
|
|
152
220
|
/**
|
|
153
|
-
* Set the
|
|
154
|
-
* Creates the
|
|
221
|
+
* Set the completer provider.
|
|
222
|
+
* Creates the provider if the name has changed, otherwise only updates its config.
|
|
155
223
|
*
|
|
156
224
|
* @param options - An object with the name and the settings of the provider to use.
|
|
157
225
|
*/
|
|
158
|
-
async
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
226
|
+
async setCompleterProvider(
|
|
227
|
+
settings: ReadonlyPartialJSONObject
|
|
228
|
+
): Promise<void> {
|
|
229
|
+
this.completerError = '';
|
|
230
|
+
if (!Object.keys(settings).includes('provider')) {
|
|
231
|
+
Private.setName('completer', 'None');
|
|
232
|
+
Private.setCompleter(null);
|
|
233
|
+
this.completerError =
|
|
234
|
+
'The provider is missing from the completer settings';
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const provider = settings['provider'] as string;
|
|
238
|
+
const currentProvider = Private.providers.get(provider) ?? null;
|
|
239
|
+
if (currentProvider === null) {
|
|
162
240
|
// The current provider may not be loaded when the settings are first loaded.
|
|
163
241
|
// Let's defer the provider loading.
|
|
164
|
-
this._deferredProvider =
|
|
242
|
+
this._deferredProvider.completer = settings;
|
|
243
|
+
Private.setName('completer', provider);
|
|
244
|
+
Private.setCompleter(null);
|
|
245
|
+
return;
|
|
165
246
|
} else {
|
|
166
|
-
this._deferredProvider = null;
|
|
247
|
+
this._deferredProvider.completer = null;
|
|
167
248
|
}
|
|
168
249
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
id
|
|
178
|
-
);
|
|
179
|
-
if (secrets !== undefined) {
|
|
180
|
-
fullSettings[key] = secrets.value;
|
|
181
|
-
}
|
|
182
|
-
continue;
|
|
250
|
+
const compatibilityCheck = this.getCompatibilityCheck(provider);
|
|
251
|
+
if (compatibilityCheck !== undefined) {
|
|
252
|
+
const error = await compatibilityCheck();
|
|
253
|
+
if (error !== null) {
|
|
254
|
+
this.completerError = error.trim();
|
|
255
|
+
Private.setName('completer', 'None');
|
|
256
|
+
this._providerChanged.emit('completer');
|
|
257
|
+
return;
|
|
183
258
|
}
|
|
184
|
-
fullSettings[key] = settings[key];
|
|
185
259
|
}
|
|
186
260
|
|
|
187
|
-
|
|
261
|
+
// Get the settings including the secrets.
|
|
262
|
+
const fullSettings = await this._buildFullSettings(provider, settings);
|
|
263
|
+
|
|
264
|
+
if (currentProvider?.completer !== undefined) {
|
|
188
265
|
try {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
266
|
+
Private.setCompleter(
|
|
267
|
+
new currentProvider.completer({
|
|
268
|
+
providerRegistry: this,
|
|
269
|
+
settings: fullSettings
|
|
270
|
+
})
|
|
271
|
+
);
|
|
193
272
|
} catch (e: any) {
|
|
194
|
-
this.
|
|
273
|
+
this.completerError = e.message;
|
|
195
274
|
}
|
|
196
275
|
} else {
|
|
197
|
-
|
|
276
|
+
Private.setCompleter(null);
|
|
277
|
+
}
|
|
278
|
+
Private.setName('completer', provider);
|
|
279
|
+
this._providerChanged.emit('completer');
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Set the chat provider.
|
|
284
|
+
* Creates the provider if the name has changed, otherwise only updates its config.
|
|
285
|
+
*
|
|
286
|
+
* @param options - An object with the name and the settings of the provider to use.
|
|
287
|
+
*/
|
|
288
|
+
async setChatProvider(settings: ReadonlyPartialJSONObject): Promise<void> {
|
|
289
|
+
this.chatError = '';
|
|
290
|
+
if (!Object.keys(settings).includes('provider')) {
|
|
291
|
+
Private.setName('chat', 'None');
|
|
292
|
+
Private.setChatModel(null);
|
|
293
|
+
this.chatError = 'The provider is missing from the chat settings';
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const provider = settings['provider'] as string;
|
|
297
|
+
const currentProvider = Private.providers.get(provider) ?? null;
|
|
298
|
+
if (currentProvider === null) {
|
|
299
|
+
// The current provider may not be loaded when the settings are first loaded.
|
|
300
|
+
// Let's defer the provider loading.
|
|
301
|
+
this._deferredProvider.chat = settings;
|
|
302
|
+
Private.setName('chat', provider);
|
|
303
|
+
Private.setChatModel(null);
|
|
304
|
+
return;
|
|
305
|
+
} else {
|
|
306
|
+
this._deferredProvider.chat = null;
|
|
198
307
|
}
|
|
199
308
|
|
|
200
|
-
|
|
309
|
+
const compatibilityCheck = this.getCompatibilityCheck(provider);
|
|
310
|
+
if (compatibilityCheck !== undefined) {
|
|
311
|
+
const error = await compatibilityCheck();
|
|
312
|
+
if (error !== null) {
|
|
313
|
+
this.chatError = error.trim();
|
|
314
|
+
Private.setName('chat', 'None');
|
|
315
|
+
this._providerChanged.emit('chat');
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Get the settings including the secrets.
|
|
321
|
+
const fullSettings = await this._buildFullSettings(provider, settings);
|
|
322
|
+
|
|
323
|
+
if (currentProvider?.chat !== undefined) {
|
|
201
324
|
try {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
325
|
+
Private.setChatModel(
|
|
326
|
+
new currentProvider.chat({
|
|
327
|
+
...fullSettings
|
|
328
|
+
})
|
|
329
|
+
);
|
|
206
330
|
} catch (e: any) {
|
|
207
|
-
this.
|
|
208
|
-
|
|
331
|
+
this.chatError = e.message;
|
|
332
|
+
Private.setChatModel(null);
|
|
209
333
|
}
|
|
210
334
|
} else {
|
|
211
|
-
|
|
335
|
+
Private.setChatModel(null);
|
|
212
336
|
}
|
|
213
|
-
|
|
214
|
-
this._providerChanged.emit();
|
|
337
|
+
Private.setName('chat', provider);
|
|
338
|
+
this._providerChanged.emit('chat');
|
|
215
339
|
}
|
|
216
340
|
|
|
217
341
|
/**
|
|
218
342
|
* A signal emitting when the provider or its settings has changed.
|
|
219
343
|
*/
|
|
220
|
-
get providerChanged(): ISignal<IAIProviderRegistry,
|
|
344
|
+
get providerChanged(): ISignal<IAIProviderRegistry, ModelRole> {
|
|
221
345
|
return this._providerChanged;
|
|
222
346
|
}
|
|
223
347
|
|
|
348
|
+
/**
|
|
349
|
+
* Build a new settings object containing the secrets.
|
|
350
|
+
*/
|
|
351
|
+
private async _buildFullSettings(
|
|
352
|
+
name: string,
|
|
353
|
+
settings: IDict<any>
|
|
354
|
+
): Promise<IDict<any>> {
|
|
355
|
+
// Build a new settings object containing the secrets.
|
|
356
|
+
const fullSettings: IDict = {};
|
|
357
|
+
for (const key of Object.keys(settings)) {
|
|
358
|
+
if (settings[key] === SECRETS_REPLACEMENT) {
|
|
359
|
+
const id = getSecretId(name, key);
|
|
360
|
+
const secrets = await this._secretsManager?.get(
|
|
361
|
+
Private.getToken(),
|
|
362
|
+
SECRETS_NAMESPACE,
|
|
363
|
+
id
|
|
364
|
+
);
|
|
365
|
+
if (secrets !== undefined) {
|
|
366
|
+
fullSettings[key] = secrets.value;
|
|
367
|
+
}
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
fullSettings[key] = settings[key];
|
|
371
|
+
}
|
|
372
|
+
return fullSettings;
|
|
373
|
+
}
|
|
374
|
+
|
|
224
375
|
private _secretsManager: ISecretsManager | null;
|
|
225
|
-
private
|
|
226
|
-
private _completer: IBaseCompleter | null = null;
|
|
227
|
-
private _chatModel: BaseChatModel | null = null;
|
|
228
|
-
private _name: string = 'None';
|
|
229
|
-
private _providerChanged = new Signal<IAIProviderRegistry, void>(this);
|
|
376
|
+
private _providerChanged = new Signal<IAIProviderRegistry, ModelRole>(this);
|
|
230
377
|
private _chatError: string = '';
|
|
231
378
|
private _completerError: string = '';
|
|
232
|
-
private
|
|
233
|
-
|
|
379
|
+
private _notifications: {
|
|
380
|
+
[key in ModelRole]: Debouncer;
|
|
381
|
+
};
|
|
382
|
+
private _deferredProvider: {
|
|
383
|
+
[key in ModelRole]: ReadonlyPartialJSONObject | null;
|
|
384
|
+
} = {
|
|
385
|
+
chat: null,
|
|
386
|
+
completer: null
|
|
387
|
+
};
|
|
388
|
+
private _chatPrompt: string = '';
|
|
389
|
+
private _completerPrompt: string = '';
|
|
234
390
|
}
|
|
235
391
|
|
|
236
392
|
export namespace AIProviderRegistry {
|
|
@@ -303,21 +459,56 @@ export namespace AIProviderRegistry {
|
|
|
303
459
|
|
|
304
460
|
namespace Private {
|
|
305
461
|
/**
|
|
306
|
-
* The token to use with the secrets manager.
|
|
462
|
+
* The token to use with the secrets manager, setter and getter.
|
|
307
463
|
*/
|
|
308
464
|
let secretsToken: symbol;
|
|
465
|
+
export function setToken(value: symbol): void {
|
|
466
|
+
secretsToken = value;
|
|
467
|
+
}
|
|
468
|
+
export function getToken(): symbol {
|
|
469
|
+
return secretsToken;
|
|
470
|
+
}
|
|
309
471
|
|
|
310
472
|
/**
|
|
311
|
-
*
|
|
473
|
+
* The providers map, in private namespace to prevent updating the 'exposeChatModel'
|
|
474
|
+
* flag.
|
|
312
475
|
*/
|
|
313
|
-
export
|
|
314
|
-
|
|
476
|
+
export const providers = new Map<string, IAIProvider>();
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* The name of the current provider, setter and getter.
|
|
480
|
+
* It is in a private namespace to prevent updating it without updating the models.
|
|
481
|
+
*/
|
|
482
|
+
const names: { [key in ModelRole]: string } = {
|
|
483
|
+
chat: 'None',
|
|
484
|
+
completer: 'None'
|
|
485
|
+
};
|
|
486
|
+
export function setName(role: ModelRole, value: string): void {
|
|
487
|
+
names[role] = value;
|
|
488
|
+
}
|
|
489
|
+
export function getName(role: ModelRole): string {
|
|
490
|
+
return names[role];
|
|
315
491
|
}
|
|
316
492
|
|
|
317
493
|
/**
|
|
318
|
-
*
|
|
494
|
+
* The chat model setter and getter.
|
|
319
495
|
*/
|
|
320
|
-
|
|
321
|
-
|
|
496
|
+
let chatModel: BaseChatModel | null = null;
|
|
497
|
+
export function setChatModel(model: BaseChatModel | null): void {
|
|
498
|
+
chatModel = model;
|
|
499
|
+
}
|
|
500
|
+
export function getChatModel(): BaseChatModel | null {
|
|
501
|
+
return chatModel;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* The completer setter and getter.
|
|
506
|
+
*/
|
|
507
|
+
let completer: IBaseCompleter | null = null;
|
|
508
|
+
export function setCompleter(model: IBaseCompleter | null): void {
|
|
509
|
+
completer = model;
|
|
510
|
+
}
|
|
511
|
+
export function getCompleter(): IBaseCompleter | null {
|
|
512
|
+
return completer;
|
|
322
513
|
}
|
|
323
514
|
}
|
package/src/settings/index.ts
CHANGED