@jupyterlite/ai 0.7.0 → 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/lib/base-completer.d.ts +23 -1
- package/lib/base-completer.js +14 -1
- package/lib/chat-handler.d.ts +4 -6
- package/lib/chat-handler.js +22 -22
- package/lib/completion-provider.js +1 -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 -9
- package/lib/default-providers/Anthropic/completer.js +4 -13
- package/lib/default-providers/ChromeAI/completer.d.ts +4 -9
- package/lib/default-providers/ChromeAI/completer.js +4 -13
- 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 -11
- package/lib/default-providers/MistralAI/completer.js +41 -50
- 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 +4 -9
- package/lib/default-providers/Ollama/completer.js +7 -13
- package/lib/default-providers/Ollama/settings-schema.json +1 -4
- package/lib/default-providers/OpenAI/completer.d.ts +4 -9
- package/lib/default-providers/OpenAI/completer.js +7 -13
- package/lib/default-providers/OpenAI/settings-schema.json +88 -128
- package/lib/default-providers/WebLLM/completer.d.ts +3 -9
- package/lib/default-providers/WebLLM/completer.js +4 -13
- package/lib/default-providers/WebLLM/settings-schema.json +1 -3
- package/lib/default-providers/index.js +23 -19
- package/lib/index.d.ts +1 -0
- package/lib/index.js +68 -14
- package/lib/provider.d.ts +39 -11
- package/lib/provider.js +166 -81
- package/lib/settings/index.d.ts +1 -0
- package/lib/settings/index.js +1 -0
- package/lib/settings/panel.d.ts +116 -8
- package/lib/settings/panel.js +117 -22
- package/lib/settings/textarea.d.ts +2 -0
- package/lib/settings/textarea.js +18 -0
- package/lib/tokens.d.ts +24 -20
- package/lib/tokens.js +2 -1
- package/package.json +10 -9
- package/schema/chat.json +1 -1
- package/schema/provider-registry.json +11 -5
- package/schema/system-prompts.json +22 -0
- package/src/base-completer.ts +39 -1
- package/src/chat-handler.ts +23 -25
- package/src/completion-provider.ts +1 -1
- package/src/default-prompts.ts +33 -0
- package/src/default-providers/Anthropic/completer.ts +5 -16
- package/src/default-providers/ChromeAI/completer.ts +5 -16
- 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 -60
- package/src/default-providers/MistralAI/instructions.ts +2 -0
- package/src/default-providers/Ollama/completer.ts +8 -16
- package/src/default-providers/OpenAI/completer.ts +8 -16
- package/src/default-providers/WebLLM/completer.ts +5 -16
- package/src/default-providers/index.ts +23 -20
- package/src/index.ts +95 -15
- package/src/provider.ts +198 -94
- package/src/settings/index.ts +1 -0
- package/src/settings/panel.tsx +262 -34
- package/src/settings/textarea.tsx +33 -0
- package/src/tokens.ts +26 -22
- package/style/base.css +29 -0
package/src/settings/panel.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
FormComponent,
|
|
6
6
|
IFormRenderer
|
|
7
7
|
} from '@jupyterlab/ui-components';
|
|
8
|
-
import { JSONExt } from '@lumino/coreutils';
|
|
8
|
+
import { JSONExt, ReadonlyPartialJSONObject } from '@lumino/coreutils';
|
|
9
9
|
import { IChangeEvent } from '@rjsf/core';
|
|
10
10
|
import type { FieldProps } from '@rjsf/utils';
|
|
11
11
|
import validator from '@rjsf/validator-ajv8';
|
|
@@ -15,13 +15,16 @@ import React from 'react';
|
|
|
15
15
|
|
|
16
16
|
import { getSecretId, SECRETS_REPLACEMENT } from '.';
|
|
17
17
|
import baseSettings from './base.json';
|
|
18
|
-
import { IAIProviderRegistry, IDict, PLUGIN_IDS } from '../tokens';
|
|
18
|
+
import { IAIProviderRegistry, IDict, ModelRole, PLUGIN_IDS } from '../tokens';
|
|
19
19
|
|
|
20
20
|
const MD_MIME_TYPE = 'text/markdown';
|
|
21
|
-
const STORAGE_NAME = '@jupyterlite/ai:settings';
|
|
22
21
|
const INSTRUCTION_CLASS = 'jp-AISettingsInstructions';
|
|
23
22
|
const ERROR_CLASS = 'jp-AISettingsError';
|
|
24
23
|
const SECRETS_NAMESPACE = PLUGIN_IDS.providerRegistry;
|
|
24
|
+
const STORAGE_KEYS = {
|
|
25
|
+
chat: '@jupyterlite/ai:chat-settings',
|
|
26
|
+
completer: '@jupyterlite/ai:completer-settings'
|
|
27
|
+
};
|
|
25
28
|
|
|
26
29
|
export const aiSettingsRenderer = (options: {
|
|
27
30
|
providerRegistry: IAIProviderRegistry;
|
|
@@ -42,28 +45,196 @@ export const aiSettingsRenderer = (options: {
|
|
|
42
45
|
};
|
|
43
46
|
};
|
|
44
47
|
|
|
45
|
-
export interface ISettingsFormStates {
|
|
46
|
-
schema: JSONSchema7;
|
|
47
|
-
instruction: HTMLElement | null;
|
|
48
|
-
compatibilityError: string | null;
|
|
49
|
-
isModified?: boolean;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
48
|
const WrappedFormComponent = (props: any): JSX.Element => {
|
|
53
49
|
return <FormComponent {...props} validator={validator} />;
|
|
54
50
|
};
|
|
55
51
|
|
|
56
|
-
export
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
export interface IAiSettings {
|
|
53
|
+
/**
|
|
54
|
+
* Get the local storage settings for a specific role (chat or completer).
|
|
55
|
+
*/
|
|
56
|
+
getLocalStorage(role: ModelRole): IDict<any>;
|
|
57
|
+
/**
|
|
58
|
+
* Set the local storage item for a specific role (chat or completer).
|
|
59
|
+
* If the key is not provider (null) we assume the value should replace the whole
|
|
60
|
+
* local storage for this role.
|
|
61
|
+
*/
|
|
62
|
+
setLocalStorageItem(role: ModelRole, key: string | null, value: any): void;
|
|
63
|
+
/**
|
|
64
|
+
* Get the settings from the registry (jupyterlab settings system) for a given role.
|
|
65
|
+
*/
|
|
66
|
+
getSettingsFromRegistry(role: ModelRole): IDict<any>;
|
|
67
|
+
/**
|
|
68
|
+
* Save the settings to the setting registry.
|
|
69
|
+
*/
|
|
70
|
+
saveSettingsToRegistry(role: ModelRole, settings: IDict<any>): void;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export class AiSettings
|
|
74
|
+
extends React.Component<FieldProps, AiSettings.states>
|
|
75
|
+
implements IAiSettings
|
|
76
|
+
{
|
|
60
77
|
constructor(props: FieldProps) {
|
|
78
|
+
super(props);
|
|
79
|
+
this._settings = props.formContext.settings;
|
|
80
|
+
const uniqueProvider =
|
|
81
|
+
(this._settings.get('UniqueProvider').composite as boolean) ?? true;
|
|
82
|
+
|
|
83
|
+
this.state = { uniqueProvider };
|
|
84
|
+
|
|
85
|
+
this._settings.changed.connect(this._settingsChanged);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private _settingsChanged = () => {
|
|
89
|
+
const uniqueProvider =
|
|
90
|
+
(this._settings.get('UniqueProvider').composite as boolean) ?? true;
|
|
91
|
+
if (this.state.uniqueProvider === uniqueProvider) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (uniqueProvider) {
|
|
95
|
+
// Copy chat settings to the completer settings if there should be a unique
|
|
96
|
+
// provider for both.
|
|
97
|
+
this.setLocalStorageItem('completer', null, this.getLocalStorage('chat'));
|
|
98
|
+
this.saveSettingsToRegistry(
|
|
99
|
+
'completer',
|
|
100
|
+
this.getSettingsFromRegistry('chat')
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
this.setState({ uniqueProvider });
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Get the local storage settings for a specific role (chat or completer).
|
|
108
|
+
*/
|
|
109
|
+
getLocalStorage = (role: ModelRole): IDict<any> => {
|
|
110
|
+
const storageKey = STORAGE_KEYS[role];
|
|
111
|
+
return JSON.parse(localStorage.getItem(storageKey) ?? '{}');
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Set the local storage item for a specific role (chat or completer).
|
|
116
|
+
* If the key is not provider (null) we assume the value should replace the whole
|
|
117
|
+
* local storage for this role.
|
|
118
|
+
*/
|
|
119
|
+
setLocalStorageItem = (
|
|
120
|
+
role: ModelRole,
|
|
121
|
+
key: string | null,
|
|
122
|
+
value: any
|
|
123
|
+
): void => {
|
|
124
|
+
const storageKey = STORAGE_KEYS[role];
|
|
125
|
+
let settings: IDict<any>;
|
|
126
|
+
|
|
127
|
+
if (key !== null) {
|
|
128
|
+
settings = JSON.parse(localStorage.getItem(storageKey) ?? '{}');
|
|
129
|
+
settings[key] = value;
|
|
130
|
+
} else {
|
|
131
|
+
settings = value;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
localStorage.setItem(storageKey, JSON.stringify(settings));
|
|
135
|
+
|
|
136
|
+
// If both chat and completer use the same settings, only the chat settings should
|
|
137
|
+
// be editable for user, so we should duplicate its values to the completer
|
|
138
|
+
// local storage.
|
|
139
|
+
if (this.state.uniqueProvider && role === 'chat') {
|
|
140
|
+
const storageKeyCompleter = STORAGE_KEYS['completer'];
|
|
141
|
+
localStorage.setItem(storageKeyCompleter, JSON.stringify(settings));
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get the settings from the registry (jupyterlab settings system) for a given role.
|
|
147
|
+
*/
|
|
148
|
+
getSettingsFromRegistry = (role: ModelRole): IDict<any> => {
|
|
149
|
+
const settings = this._settings.get('AIproviders')
|
|
150
|
+
.composite as ReadonlyPartialJSONObject;
|
|
151
|
+
return settings && Object.keys(settings).includes(role)
|
|
152
|
+
? (settings[role] as IDict<any>)
|
|
153
|
+
: { provider: 'None' };
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Save the settings to the setting registry.
|
|
158
|
+
*/
|
|
159
|
+
saveSettingsToRegistry = (role: ModelRole, settings: IDict<any>): void => {
|
|
160
|
+
const fullSettings = this._settings.get('AIproviders')
|
|
161
|
+
.composite as IDict<any>;
|
|
162
|
+
fullSettings[role] = { ...settings };
|
|
163
|
+
|
|
164
|
+
// If both chat and completer use the same settings, only the chat settings should
|
|
165
|
+
// be editable for user, so we should duplicate its values to the completer
|
|
166
|
+
// settings.
|
|
167
|
+
if (this.state.uniqueProvider && role === 'chat') {
|
|
168
|
+
fullSettings['completer'] = { ...settings };
|
|
169
|
+
}
|
|
170
|
+
this._settings.set('AIproviders', { ...fullSettings }).catch(console.error);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
render(): JSX.Element {
|
|
174
|
+
return (
|
|
175
|
+
<div>
|
|
176
|
+
<h3>
|
|
177
|
+
{this.state.uniqueProvider
|
|
178
|
+
? 'Chat and completer provider'
|
|
179
|
+
: 'Chat provider'}
|
|
180
|
+
</h3>
|
|
181
|
+
<AiProviderSettings {...this.props} role={'chat'} aiSettings={this} />
|
|
182
|
+
{!this.state.uniqueProvider && (
|
|
183
|
+
<>
|
|
184
|
+
<h3>Completer provider</h3>
|
|
185
|
+
<AiProviderSettings
|
|
186
|
+
{...this.props}
|
|
187
|
+
role={'completer'}
|
|
188
|
+
aiSettings={this}
|
|
189
|
+
/>
|
|
190
|
+
</>
|
|
191
|
+
)}
|
|
192
|
+
</div>
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private _settings: ISettingRegistry.ISettings;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* The AI settings component namespace.
|
|
201
|
+
*/
|
|
202
|
+
namespace AiSettings {
|
|
203
|
+
/**
|
|
204
|
+
* The AI settings component states.
|
|
205
|
+
*/
|
|
206
|
+
export type states = {
|
|
207
|
+
/**
|
|
208
|
+
* Whether there is only one provider for chat and completion.
|
|
209
|
+
*/
|
|
210
|
+
uniqueProvider: boolean;
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* The provider names object.
|
|
214
|
+
*/
|
|
215
|
+
export type providers = {
|
|
216
|
+
[key in ModelRole]: string;
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* The provider schemas object.
|
|
220
|
+
*/
|
|
221
|
+
export type schemas = {
|
|
222
|
+
[key in ModelRole]: JSONSchema7;
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export class AiProviderSettings extends React.Component<
|
|
227
|
+
AiProviderSettings.props,
|
|
228
|
+
AiProviderSettings.states
|
|
229
|
+
> {
|
|
230
|
+
constructor(props: AiProviderSettings.props) {
|
|
61
231
|
super(props);
|
|
62
232
|
if (!props.formContext.providerRegistry) {
|
|
63
233
|
throw new Error(
|
|
64
234
|
'The provider registry is needed to enable the jupyterlite-ai settings panel'
|
|
65
235
|
);
|
|
66
236
|
}
|
|
237
|
+
this._role = props.role;
|
|
67
238
|
this._providerRegistry = props.formContext.providerRegistry;
|
|
68
239
|
this._rmRegistry = props.formContext.rmRegistry ?? null;
|
|
69
240
|
this._secretsManager = props.formContext.secretsManager ?? null;
|
|
@@ -87,10 +258,13 @@ export class AiSettings extends React.Component<
|
|
|
87
258
|
|
|
88
259
|
// Check if there is saved values in local storage, otherwise use the settings from
|
|
89
260
|
// the setting registry (leads to default if there are no user settings).
|
|
90
|
-
const
|
|
261
|
+
const storageKey = STORAGE_KEYS[this._role];
|
|
262
|
+
const storageSettings = localStorage.getItem(storageKey);
|
|
91
263
|
if (storageSettings === null) {
|
|
92
|
-
const labSettings = this.
|
|
93
|
-
|
|
264
|
+
const labSettings = this.props.aiSettings.getSettingsFromRegistry(
|
|
265
|
+
this._role
|
|
266
|
+
);
|
|
267
|
+
if (Object.keys(labSettings).includes('provider')) {
|
|
94
268
|
// Get the provider name.
|
|
95
269
|
const provider = Object.entries(labSettings).find(
|
|
96
270
|
v => v[0] === 'provider'
|
|
@@ -100,7 +274,7 @@ export class AiSettings extends React.Component<
|
|
|
100
274
|
_current: provider
|
|
101
275
|
};
|
|
102
276
|
settings[provider] = labSettings;
|
|
103
|
-
|
|
277
|
+
this.props.aiSettings.setLocalStorageItem(this._role, null, settings);
|
|
104
278
|
}
|
|
105
279
|
}
|
|
106
280
|
|
|
@@ -135,6 +309,10 @@ export class AiSettings extends React.Component<
|
|
|
135
309
|
this._settings.changed.connect(this._settingsChanged);
|
|
136
310
|
}
|
|
137
311
|
|
|
312
|
+
componentDidMount(): void {
|
|
313
|
+
this.componentDidUpdate();
|
|
314
|
+
}
|
|
315
|
+
|
|
138
316
|
async componentDidUpdate(): Promise<void> {
|
|
139
317
|
if (!this._secretsManager || !this._useSecretsManager) {
|
|
140
318
|
return;
|
|
@@ -175,7 +353,7 @@ export class AiSettings extends React.Component<
|
|
|
175
353
|
* Get the current provider from the local storage.
|
|
176
354
|
*/
|
|
177
355
|
getCurrentProvider(): string {
|
|
178
|
-
const settings =
|
|
356
|
+
const settings = this.props.aiSettings.getLocalStorage(this._role);
|
|
179
357
|
return settings['_current'] ?? 'None';
|
|
180
358
|
}
|
|
181
359
|
|
|
@@ -183,16 +361,18 @@ export class AiSettings extends React.Component<
|
|
|
183
361
|
* Save the current provider to the local storage.
|
|
184
362
|
*/
|
|
185
363
|
saveCurrentProvider(): void {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
364
|
+
this.props.aiSettings.setLocalStorageItem(
|
|
365
|
+
this._role,
|
|
366
|
+
'_current',
|
|
367
|
+
this._provider
|
|
368
|
+
);
|
|
189
369
|
}
|
|
190
370
|
|
|
191
371
|
/**
|
|
192
|
-
* Get settings from local storage for
|
|
372
|
+
* Get settings from local storage for the current provider provider.
|
|
193
373
|
*/
|
|
194
374
|
getSettingsFromLocalStorage(): IDict<any> {
|
|
195
|
-
const settings =
|
|
375
|
+
const settings = this.props.aiSettings.getLocalStorage(this._role);
|
|
196
376
|
return settings[this._provider] ?? { provider: this._provider };
|
|
197
377
|
}
|
|
198
378
|
|
|
@@ -201,13 +381,15 @@ export class AiSettings extends React.Component<
|
|
|
201
381
|
*/
|
|
202
382
|
saveSettingsToLocalStorage() {
|
|
203
383
|
const currentSettings = { ...this._currentSettings };
|
|
204
|
-
const settings = JSON.parse(localStorage.getItem(STORAGE_NAME) ?? '{}');
|
|
205
384
|
// Do not save secrets in local storage if using the secrets manager.
|
|
206
385
|
if (this._useSecretsManager) {
|
|
207
386
|
this._secretFields.forEach(field => delete currentSettings[field]);
|
|
208
387
|
}
|
|
209
|
-
|
|
210
|
-
|
|
388
|
+
this.props.aiSettings.setLocalStorageItem(
|
|
389
|
+
this._role,
|
|
390
|
+
this._provider,
|
|
391
|
+
currentSettings
|
|
392
|
+
);
|
|
211
393
|
}
|
|
212
394
|
|
|
213
395
|
/**
|
|
@@ -220,9 +402,11 @@ export class AiSettings extends React.Component<
|
|
|
220
402
|
sanitizedSettings[field] = SECRETS_REPLACEMENT;
|
|
221
403
|
});
|
|
222
404
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
.
|
|
405
|
+
|
|
406
|
+
this.props.aiSettings.saveSettingsToRegistry(this._role, {
|
|
407
|
+
provider: this._provider,
|
|
408
|
+
...sanitizedSettings
|
|
409
|
+
});
|
|
226
410
|
}
|
|
227
411
|
|
|
228
412
|
/**
|
|
@@ -265,7 +449,7 @@ export class AiSettings extends React.Component<
|
|
|
265
449
|
this._secretsManager.detachAll(Private.getToken(), SECRETS_NAMESPACE);
|
|
266
450
|
} else {
|
|
267
451
|
// Remove all the keys stored locally.
|
|
268
|
-
const settings =
|
|
452
|
+
const settings = this.props.aiSettings.getLocalStorage(this._role);
|
|
269
453
|
Object.keys(settings).forEach(provider => {
|
|
270
454
|
Object.keys(settings[provider])
|
|
271
455
|
.filter(key => key.toLowerCase().includes('key'))
|
|
@@ -273,7 +457,7 @@ export class AiSettings extends React.Component<
|
|
|
273
457
|
delete settings[provider][key];
|
|
274
458
|
});
|
|
275
459
|
});
|
|
276
|
-
|
|
460
|
+
this.props.aiSettings.setLocalStorageItem(this._role, null, settings);
|
|
277
461
|
}
|
|
278
462
|
this._updateSchema();
|
|
279
463
|
this.saveSettingsToLocalStorage();
|
|
@@ -297,7 +481,7 @@ export class AiSettings extends React.Component<
|
|
|
297
481
|
if (key.toLowerCase().includes('key')) {
|
|
298
482
|
this._secretFields.push(key);
|
|
299
483
|
|
|
300
|
-
// If the secrets manager is not used,
|
|
484
|
+
// If the secrets manager is not used, show the secrets fields.
|
|
301
485
|
// If the secrets manager is used, check if the fields should be visible.
|
|
302
486
|
const showSecretFields =
|
|
303
487
|
!this._useSecretsManager ||
|
|
@@ -467,6 +651,7 @@ export class AiSettings extends React.Component<
|
|
|
467
651
|
formData={{ provider: this._provider }}
|
|
468
652
|
schema={this._providerSchema}
|
|
469
653
|
onChange={this._onProviderChanged}
|
|
654
|
+
idPrefix={`jp-SettingsEditor-${PLUGIN_IDS.providerRegistry}-${this._role}`}
|
|
470
655
|
/>
|
|
471
656
|
{this.state.compatibilityError !== null && (
|
|
472
657
|
<div className={ERROR_CLASS}>
|
|
@@ -499,7 +684,7 @@ export class AiSettings extends React.Component<
|
|
|
499
684
|
schema={this.state.schema}
|
|
500
685
|
onChange={this._onFormChanged}
|
|
501
686
|
uiSchema={this._uiSchema}
|
|
502
|
-
idPrefix={`jp-SettingsEditor-${PLUGIN_IDS.providerRegistry}`}
|
|
687
|
+
idPrefix={`jp-SettingsEditor-${PLUGIN_IDS.providerRegistry}-${this._role}`}
|
|
503
688
|
formContext={{
|
|
504
689
|
...this.props.formContext,
|
|
505
690
|
defaultFormData: this._defaultFormData
|
|
@@ -509,6 +694,7 @@ export class AiSettings extends React.Component<
|
|
|
509
694
|
);
|
|
510
695
|
}
|
|
511
696
|
|
|
697
|
+
private _role: ModelRole;
|
|
512
698
|
private _providerRegistry: IAIProviderRegistry;
|
|
513
699
|
private _provider: string;
|
|
514
700
|
private _providerSchema: JSONSchema7;
|
|
@@ -523,6 +709,48 @@ export class AiSettings extends React.Component<
|
|
|
523
709
|
private _defaultFormData: IDict<any> = {};
|
|
524
710
|
}
|
|
525
711
|
|
|
712
|
+
/**
|
|
713
|
+
* The AI provider settings component namespace.
|
|
714
|
+
*/
|
|
715
|
+
export namespace AiProviderSettings {
|
|
716
|
+
/**
|
|
717
|
+
* The AI provider settings component props.
|
|
718
|
+
*/
|
|
719
|
+
export type props = FieldProps & {
|
|
720
|
+
/**
|
|
721
|
+
* Why this model is used for (chat or completion).
|
|
722
|
+
*/
|
|
723
|
+
role: ModelRole;
|
|
724
|
+
/**
|
|
725
|
+
* The parent component which should handle:
|
|
726
|
+
* - the get/set functions for local storage
|
|
727
|
+
* - save settings using jupyter settings system
|
|
728
|
+
*/
|
|
729
|
+
aiSettings: IAiSettings;
|
|
730
|
+
};
|
|
731
|
+
/**
|
|
732
|
+
* The AI provider settings component states.
|
|
733
|
+
*/
|
|
734
|
+
export type states = {
|
|
735
|
+
/**
|
|
736
|
+
* The schema of the settings.
|
|
737
|
+
*/
|
|
738
|
+
schema: JSONSchema7;
|
|
739
|
+
/**
|
|
740
|
+
* The instructions for this provider.
|
|
741
|
+
*/
|
|
742
|
+
instruction: HTMLElement | null;
|
|
743
|
+
/**
|
|
744
|
+
* An error if the model in not compatible with the current environment.
|
|
745
|
+
*/
|
|
746
|
+
compatibilityError: string | null;
|
|
747
|
+
/**
|
|
748
|
+
* Whether the settings are modified from default or not.
|
|
749
|
+
*/
|
|
750
|
+
isModified?: boolean;
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
|
|
526
754
|
namespace Private {
|
|
527
755
|
/**
|
|
528
756
|
* The token to use with the secrets manager.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
2
|
+
import { IFormRenderer } from '@jupyterlab/ui-components';
|
|
3
|
+
import { FieldProps } from '@rjsf/utils';
|
|
4
|
+
import React, { useState } from 'react';
|
|
5
|
+
|
|
6
|
+
const TEXTAREA_CLASS = 'jp-AISettingsTextArea';
|
|
7
|
+
|
|
8
|
+
export const textArea: IFormRenderer = {
|
|
9
|
+
fieldRenderer: (props: FieldProps) => {
|
|
10
|
+
const settings: ISettingRegistry.ISettings = props.formContext.settings;
|
|
11
|
+
const schema = settings.schema.properties?.[props.name];
|
|
12
|
+
const [formData, setFormData] = useState<string>(props.formData);
|
|
13
|
+
settings.changed.connect(() => {
|
|
14
|
+
setFormData(settings.get(props.name).composite as string);
|
|
15
|
+
});
|
|
16
|
+
const onChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
|
17
|
+
settings.set(props.name, event.target.value);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
{schema?.title && (
|
|
23
|
+
<h3 className="jp-FormGroup-fieldLabel jp-FormGroup-contentItem">
|
|
24
|
+
{schema.title}
|
|
25
|
+
</h3>
|
|
26
|
+
)}
|
|
27
|
+
<textarea className={TEXTAREA_CLASS} onChange={onChange}>
|
|
28
|
+
{formData}
|
|
29
|
+
</textarea>
|
|
30
|
+
</>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
};
|
package/src/tokens.ts
CHANGED
|
@@ -11,9 +11,12 @@ export const PLUGIN_IDS = {
|
|
|
11
11
|
chatCommandRegistry: '@jupyterlite/ai:autocompletion-registry',
|
|
12
12
|
completer: '@jupyterlite/ai:completer',
|
|
13
13
|
providerRegistry: '@jupyterlite/ai:provider-registry',
|
|
14
|
-
settingsConnector: '@jupyterlite/ai:settings-connector'
|
|
14
|
+
settingsConnector: '@jupyterlite/ai:settings-connector',
|
|
15
|
+
systemPrompts: '@jupyterlite/ai:system-prompts'
|
|
15
16
|
};
|
|
16
17
|
|
|
18
|
+
export type ModelRole = 'chat' | 'completer';
|
|
19
|
+
|
|
17
20
|
export interface IDict<T = any> {
|
|
18
21
|
[key: string]: T;
|
|
19
22
|
}
|
|
@@ -33,7 +36,7 @@ export interface IAIProvider {
|
|
|
33
36
|
/**
|
|
34
37
|
* The chat model class to use.
|
|
35
38
|
*/
|
|
36
|
-
|
|
39
|
+
chat?: IType<BaseChatModel>;
|
|
37
40
|
/**
|
|
38
41
|
* The completer class to use.
|
|
39
42
|
*/
|
|
@@ -83,15 +86,23 @@ export interface IAIProviderRegistry {
|
|
|
83
86
|
/**
|
|
84
87
|
* Get the current provider name.
|
|
85
88
|
*/
|
|
86
|
-
currentName: string;
|
|
89
|
+
currentName(role: ModelRole): string;
|
|
87
90
|
/**
|
|
88
91
|
* Get the current completer of the completion provider.
|
|
89
92
|
*/
|
|
90
93
|
currentCompleter: AICompleter | null;
|
|
94
|
+
/**
|
|
95
|
+
* Getter/setter for the completer system prompt.
|
|
96
|
+
*/
|
|
97
|
+
completerSystemPrompt: string;
|
|
91
98
|
/**
|
|
92
99
|
* Get the current llm chat model.
|
|
93
100
|
*/
|
|
94
101
|
currentChatModel: AIChatModel | null;
|
|
102
|
+
/**
|
|
103
|
+
* Getter/setter for the chat system prompt.
|
|
104
|
+
*/
|
|
105
|
+
chatSystemPrompt: string;
|
|
95
106
|
/**
|
|
96
107
|
* Get the settings schema of a given provider.
|
|
97
108
|
*/
|
|
@@ -111,16 +122,23 @@ export interface IAIProviderRegistry {
|
|
|
111
122
|
*/
|
|
112
123
|
formatErrorMessage(error: any): string;
|
|
113
124
|
/**
|
|
114
|
-
* Set the
|
|
115
|
-
* Creates the
|
|
125
|
+
* Set the completer provider.
|
|
126
|
+
* Creates the provider if the name has changed, otherwise only updates its config.
|
|
116
127
|
*
|
|
117
|
-
* @param options -
|
|
128
|
+
* @param options - An object with the name and the settings of the provider to use.
|
|
118
129
|
*/
|
|
119
|
-
|
|
130
|
+
setCompleterProvider(settings: ReadonlyPartialJSONObject): void;
|
|
131
|
+
/**
|
|
132
|
+
* Set the chat provider.
|
|
133
|
+
* Creates the provider if the name has changed, otherwise only updates its config.
|
|
134
|
+
*
|
|
135
|
+
* @param options - An object with the name and the settings of the provider to use.
|
|
136
|
+
*/
|
|
137
|
+
setChatProvider(settings: ReadonlyPartialJSONObject): void;
|
|
120
138
|
/**
|
|
121
139
|
* A signal emitting when the provider or its settings has changed.
|
|
122
140
|
*/
|
|
123
|
-
readonly providerChanged: ISignal<IAIProviderRegistry,
|
|
141
|
+
readonly providerChanged: ISignal<IAIProviderRegistry, ModelRole>;
|
|
124
142
|
/**
|
|
125
143
|
* Get the current chat error;
|
|
126
144
|
*/
|
|
@@ -131,20 +149,6 @@ export interface IAIProviderRegistry {
|
|
|
131
149
|
readonly completerError: string;
|
|
132
150
|
}
|
|
133
151
|
|
|
134
|
-
/**
|
|
135
|
-
* The set provider options.
|
|
136
|
-
*/
|
|
137
|
-
export interface ISetProviderOptions {
|
|
138
|
-
/**
|
|
139
|
-
* The name of the provider.
|
|
140
|
-
*/
|
|
141
|
-
name: string;
|
|
142
|
-
/**
|
|
143
|
-
* The settings of the provider.
|
|
144
|
-
*/
|
|
145
|
-
settings: ReadonlyPartialJSONObject;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
152
|
/**
|
|
149
153
|
* The provider registry token.
|
|
150
154
|
*/
|
package/style/base.css
CHANGED
|
@@ -14,3 +14,32 @@
|
|
|
14
14
|
color: var(--jp-error-color1);
|
|
15
15
|
font-size: var(--jp-content-font-size1);
|
|
16
16
|
}
|
|
17
|
+
|
|
18
|
+
.jp-AISettingsTextArea {
|
|
19
|
+
min-width: 400px;
|
|
20
|
+
min-height: 300px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.jp-chat-welcome-message {
|
|
24
|
+
text-align: center;
|
|
25
|
+
max-width: 350px;
|
|
26
|
+
margin: 0 auto;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.jp-chat-welcome-message button[data-commandLinker-command] {
|
|
30
|
+
background: var(--jp-layout-color2);
|
|
31
|
+
border: 1px solid var(--jp-border-color1);
|
|
32
|
+
color: var(--jp-ui-font-color1);
|
|
33
|
+
border-radius: var(--jp-border-radius);
|
|
34
|
+
cursor: pointer;
|
|
35
|
+
font-size: inherit;
|
|
36
|
+
font-family: inherit;
|
|
37
|
+
padding: 2px 6px;
|
|
38
|
+
transition: all 0.2s ease;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.jp-chat-welcome-message button[data-commandLinker-command]:hover {
|
|
42
|
+
background: var(--jp-layout-color3);
|
|
43
|
+
border-color: var(--jp-brand-color1);
|
|
44
|
+
color: var(--jp-brand-color1);
|
|
45
|
+
}
|