@jupyterlite/ai 0.6.1 → 0.6.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/lib/base-completer.d.ts +1 -1
- package/lib/default-providers/Anthropic/completer.d.ts +2 -2
- package/lib/default-providers/Anthropic/completer.js +4 -4
- package/lib/default-providers/ChromeAI/completer.d.ts +2 -2
- package/lib/default-providers/ChromeAI/completer.js +4 -4
- package/lib/default-providers/MistralAI/completer.d.ts +2 -2
- package/lib/default-providers/MistralAI/completer.js +4 -4
- package/lib/default-providers/OpenAI/completer.d.ts +2 -2
- package/lib/default-providers/OpenAI/completer.js +4 -4
- package/lib/provider.js +4 -2
- package/lib/settings/panel.d.ts +7 -3
- package/lib/settings/panel.js +28 -21
- package/lib/settings/settings-connector.js +3 -3
- package/package.json +2 -2
- package/src/base-completer.ts +1 -1
- package/src/default-providers/Anthropic/completer.ts +5 -5
- package/src/default-providers/ChromeAI/completer.ts +5 -5
- package/src/default-providers/MistralAI/completer.ts +5 -5
- package/src/default-providers/OpenAI/completer.ts +5 -5
- package/src/provider.ts +4 -2
- package/src/settings/panel.tsx +31 -21
- package/src/settings/settings-connector.ts +4 -5
package/lib/base-completer.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
|
3
3
|
import { BaseCompleter, IBaseCompleter } from '../../base-completer';
|
|
4
4
|
export declare class AnthropicCompleter implements IBaseCompleter {
|
|
5
5
|
constructor(options: BaseCompleter.IOptions);
|
|
6
|
-
get
|
|
6
|
+
get completer(): BaseChatModel;
|
|
7
7
|
/**
|
|
8
8
|
* Getter and setter for the initial prompt.
|
|
9
9
|
*/
|
|
@@ -14,6 +14,6 @@ export declare class AnthropicCompleter implements IBaseCompleter {
|
|
|
14
14
|
insertText: string;
|
|
15
15
|
}[];
|
|
16
16
|
}>;
|
|
17
|
-
private
|
|
17
|
+
private _completer;
|
|
18
18
|
private _prompt;
|
|
19
19
|
}
|
|
@@ -4,10 +4,10 @@ import { COMPLETION_SYSTEM_PROMPT } from '../../provider';
|
|
|
4
4
|
export class AnthropicCompleter {
|
|
5
5
|
constructor(options) {
|
|
6
6
|
this._prompt = COMPLETION_SYSTEM_PROMPT;
|
|
7
|
-
this.
|
|
7
|
+
this._completer = new ChatAnthropic({ ...options.settings });
|
|
8
8
|
}
|
|
9
|
-
get
|
|
10
|
-
return this.
|
|
9
|
+
get completer() {
|
|
10
|
+
return this._completer;
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* Getter and setter for the initial prompt.
|
|
@@ -28,7 +28,7 @@ export class AnthropicCompleter {
|
|
|
28
28
|
new AIMessage(trimmedPrompt)
|
|
29
29
|
];
|
|
30
30
|
try {
|
|
31
|
-
const response = await this.
|
|
31
|
+
const response = await this._completer.invoke(messages);
|
|
32
32
|
const items = [];
|
|
33
33
|
// Anthropic can return string or complex content, a list of string/images/other.
|
|
34
34
|
if (typeof response.content === 'string') {
|
|
@@ -8,12 +8,12 @@ export declare class ChromeCompleter implements IBaseCompleter {
|
|
|
8
8
|
*/
|
|
9
9
|
get prompt(): string;
|
|
10
10
|
set prompt(value: string);
|
|
11
|
-
get
|
|
11
|
+
get completer(): LLM;
|
|
12
12
|
fetch(request: CompletionHandler.IRequest, context: IInlineCompletionContext): Promise<{
|
|
13
13
|
items: {
|
|
14
14
|
insertText: string;
|
|
15
15
|
}[];
|
|
16
16
|
}>;
|
|
17
|
-
private
|
|
17
|
+
private _completer;
|
|
18
18
|
private _prompt;
|
|
19
19
|
}
|
|
@@ -23,7 +23,7 @@ const CODE_BLOCK_END_REGEX = /```$/;
|
|
|
23
23
|
export class ChromeCompleter {
|
|
24
24
|
constructor(options) {
|
|
25
25
|
this._prompt = COMPLETION_SYSTEM_PROMPT;
|
|
26
|
-
this.
|
|
26
|
+
this._completer = new ChromeAI({ ...options.settings });
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
29
|
* Getter and setter for the initial prompt.
|
|
@@ -34,8 +34,8 @@ export class ChromeCompleter {
|
|
|
34
34
|
set prompt(value) {
|
|
35
35
|
this._prompt = value;
|
|
36
36
|
}
|
|
37
|
-
get
|
|
38
|
-
return this.
|
|
37
|
+
get completer() {
|
|
38
|
+
return this._completer;
|
|
39
39
|
}
|
|
40
40
|
async fetch(request, context) {
|
|
41
41
|
const { text, offset: cursorOffset } = request;
|
|
@@ -46,7 +46,7 @@ export class ChromeCompleter {
|
|
|
46
46
|
new HumanMessage(trimmedPrompt)
|
|
47
47
|
];
|
|
48
48
|
try {
|
|
49
|
-
let response = await this.
|
|
49
|
+
let response = await this._completer.invoke(messages);
|
|
50
50
|
// ChromeAI sometimes returns a string starting with '```',
|
|
51
51
|
// so process the response to remove the code block delimiters
|
|
52
52
|
if (CODE_BLOCK_START_REGEX.test(response)) {
|
|
@@ -3,7 +3,7 @@ import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
|
3
3
|
import { BaseCompleter, IBaseCompleter } from '../../base-completer';
|
|
4
4
|
export declare class CodestralCompleter implements IBaseCompleter {
|
|
5
5
|
constructor(options: BaseCompleter.IOptions);
|
|
6
|
-
get
|
|
6
|
+
get completer(): BaseChatModel;
|
|
7
7
|
/**
|
|
8
8
|
* Getter and setter for the initial prompt.
|
|
9
9
|
*/
|
|
@@ -11,6 +11,6 @@ export declare class CodestralCompleter implements IBaseCompleter {
|
|
|
11
11
|
set prompt(value: string);
|
|
12
12
|
fetch(request: CompletionHandler.IRequest, context: IInlineCompletionContext): Promise<any>;
|
|
13
13
|
private _throttler;
|
|
14
|
-
private
|
|
14
|
+
private _completer;
|
|
15
15
|
private _prompt;
|
|
16
16
|
}
|
|
@@ -9,9 +9,9 @@ const INTERVAL = 1000;
|
|
|
9
9
|
export class CodestralCompleter {
|
|
10
10
|
constructor(options) {
|
|
11
11
|
this._prompt = COMPLETION_SYSTEM_PROMPT;
|
|
12
|
-
this.
|
|
12
|
+
this._completer = new ChatMistralAI({ ...options.settings });
|
|
13
13
|
this._throttler = new Throttler(async (messages) => {
|
|
14
|
-
const response = await this.
|
|
14
|
+
const response = await this._completer.invoke(messages);
|
|
15
15
|
// Extract results of completion request.
|
|
16
16
|
const items = [];
|
|
17
17
|
if (typeof response.content === 'string') {
|
|
@@ -32,8 +32,8 @@ export class CodestralCompleter {
|
|
|
32
32
|
return { items };
|
|
33
33
|
}, { limit: INTERVAL });
|
|
34
34
|
}
|
|
35
|
-
get
|
|
36
|
-
return this.
|
|
35
|
+
get completer() {
|
|
36
|
+
return this._completer;
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
39
|
* Getter and setter for the initial prompt.
|
|
@@ -3,7 +3,7 @@ import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
|
3
3
|
import { BaseCompleter, IBaseCompleter } from '../../base-completer';
|
|
4
4
|
export declare class OpenAICompleter implements IBaseCompleter {
|
|
5
5
|
constructor(options: BaseCompleter.IOptions);
|
|
6
|
-
get
|
|
6
|
+
get completer(): BaseChatModel;
|
|
7
7
|
/**
|
|
8
8
|
* Getter and setter for the initial prompt.
|
|
9
9
|
*/
|
|
@@ -14,6 +14,6 @@ export declare class OpenAICompleter implements IBaseCompleter {
|
|
|
14
14
|
insertText: string;
|
|
15
15
|
}[];
|
|
16
16
|
}>;
|
|
17
|
-
private
|
|
17
|
+
private _completer;
|
|
18
18
|
private _prompt;
|
|
19
19
|
}
|
|
@@ -4,10 +4,10 @@ import { COMPLETION_SYSTEM_PROMPT } from '../../provider';
|
|
|
4
4
|
export class OpenAICompleter {
|
|
5
5
|
constructor(options) {
|
|
6
6
|
this._prompt = COMPLETION_SYSTEM_PROMPT;
|
|
7
|
-
this.
|
|
7
|
+
this._completer = new ChatOpenAI({ ...options.settings });
|
|
8
8
|
}
|
|
9
|
-
get
|
|
10
|
-
return this.
|
|
9
|
+
get completer() {
|
|
10
|
+
return this._completer;
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* Getter and setter for the initial prompt.
|
|
@@ -23,7 +23,7 @@ export class OpenAICompleter {
|
|
|
23
23
|
const prompt = text.slice(0, cursorOffset);
|
|
24
24
|
const messages = [new SystemMessage(this._prompt), new AIMessage(prompt)];
|
|
25
25
|
try {
|
|
26
|
-
const response = await this.
|
|
26
|
+
const response = await this._completer.invoke(messages);
|
|
27
27
|
const items = [];
|
|
28
28
|
if (typeof response.content === 'string') {
|
|
29
29
|
items.push({
|
package/lib/provider.js
CHANGED
|
@@ -153,7 +153,9 @@ export class AIProviderRegistry {
|
|
|
153
153
|
if (settings[key] === SECRETS_REPLACEMENT) {
|
|
154
154
|
const id = getSecretId(name, key);
|
|
155
155
|
const secrets = await ((_b = this._secretsManager) === null || _b === void 0 ? void 0 : _b.get(Private.getToken(), SECRETS_NAMESPACE, id));
|
|
156
|
-
|
|
156
|
+
if (secrets !== undefined) {
|
|
157
|
+
fullSettings[key] = secrets.value;
|
|
158
|
+
}
|
|
157
159
|
continue;
|
|
158
160
|
}
|
|
159
161
|
fullSettings[key] = settings[key];
|
|
@@ -161,7 +163,7 @@ export class AIProviderRegistry {
|
|
|
161
163
|
if (((_c = this._currentProvider) === null || _c === void 0 ? void 0 : _c.completer) !== undefined) {
|
|
162
164
|
try {
|
|
163
165
|
this._completer = new this._currentProvider.completer({
|
|
164
|
-
|
|
166
|
+
settings: fullSettings
|
|
165
167
|
});
|
|
166
168
|
this._completerError = '';
|
|
167
169
|
}
|
package/lib/settings/panel.d.ts
CHANGED
|
@@ -37,7 +37,12 @@ export declare class AiSettings extends React.Component<FieldProps, ISettingsFor
|
|
|
37
37
|
* Save settings in local storage for a given provider.
|
|
38
38
|
*/
|
|
39
39
|
saveSettings(value: IDict<any>): void;
|
|
40
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Update the settings whether the secrets manager is used or not.
|
|
42
|
+
*
|
|
43
|
+
* @param value - whether to use the secrets manager or not.
|
|
44
|
+
*/
|
|
45
|
+
private _updateUseSecretsManager;
|
|
41
46
|
/**
|
|
42
47
|
* Build the schema for a given provider.
|
|
43
48
|
*/
|
|
@@ -80,6 +85,5 @@ export declare class AiSettings extends React.Component<FieldProps, ISettingsFor
|
|
|
80
85
|
private _uiSchema;
|
|
81
86
|
private _settings;
|
|
82
87
|
private _formRef;
|
|
83
|
-
private
|
|
84
|
-
private _formInputs;
|
|
88
|
+
private _secretFields;
|
|
85
89
|
}
|
package/lib/settings/panel.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { FormComponent } from '@jupyterlab/ui-components';
|
|
2
|
-
import { ArrayExt } from '@lumino/algorithm';
|
|
3
2
|
import { JSONExt } from '@lumino/coreutils';
|
|
4
3
|
import validator from '@rjsf/validator-ajv8';
|
|
5
4
|
import React from 'react';
|
|
@@ -30,23 +29,25 @@ export class AiSettings extends React.Component {
|
|
|
30
29
|
constructor(props) {
|
|
31
30
|
var _a, _b, _c, _d, _e, _f;
|
|
32
31
|
super(props);
|
|
33
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Update the settings whether the secrets manager is used or not.
|
|
34
|
+
*
|
|
35
|
+
* @param value - whether to use the secrets manager or not.
|
|
36
|
+
*/
|
|
37
|
+
this._updateUseSecretsManager = (value) => {
|
|
34
38
|
var _a;
|
|
35
39
|
this._useSecretsManager = value;
|
|
36
40
|
if (!value) {
|
|
37
41
|
// Detach all the password inputs attached to the secrets manager, and save the
|
|
38
42
|
// current settings to the local storage to save the password.
|
|
39
43
|
(_a = this._secretsManager) === null || _a === void 0 ? void 0 : _a.detachAll(Private.getToken(), SECRETS_NAMESPACE);
|
|
40
|
-
this._formInputs = [];
|
|
41
|
-
this._unsavedFields = [];
|
|
42
44
|
if (this._settingConnector instanceof SettingConnector) {
|
|
43
45
|
this._settingConnector.doNotSave = [];
|
|
44
46
|
}
|
|
45
47
|
this.saveSettings(this._currentSettings);
|
|
46
48
|
}
|
|
47
49
|
else {
|
|
48
|
-
// Remove all the keys stored locally
|
|
49
|
-
// secrets manager.
|
|
50
|
+
// Remove all the keys stored locally.
|
|
50
51
|
const settings = JSON.parse(localStorage.getItem(STORAGE_NAME) || '{}');
|
|
51
52
|
Object.keys(settings).forEach(provider => {
|
|
52
53
|
Object.keys(settings[provider])
|
|
@@ -56,6 +57,11 @@ export class AiSettings extends React.Component {
|
|
|
56
57
|
});
|
|
57
58
|
});
|
|
58
59
|
localStorage.setItem(STORAGE_NAME, JSON.stringify(settings));
|
|
60
|
+
// Update the fields not to save in settings.
|
|
61
|
+
if (this._settingConnector instanceof SettingConnector) {
|
|
62
|
+
this._settingConnector.doNotSave = this._secretFields;
|
|
63
|
+
}
|
|
64
|
+
// Attach the password inputs to the secrets manager.
|
|
59
65
|
this.componentDidUpdate();
|
|
60
66
|
}
|
|
61
67
|
this._settings
|
|
@@ -105,8 +111,7 @@ export class AiSettings extends React.Component {
|
|
|
105
111
|
this._currentSettings = { provider: 'None' };
|
|
106
112
|
this._uiSchema = {};
|
|
107
113
|
this._formRef = React.createRef();
|
|
108
|
-
this.
|
|
109
|
-
this._formInputs = [];
|
|
114
|
+
this._secretFields = [];
|
|
110
115
|
if (!props.formContext.providerRegistry) {
|
|
111
116
|
throw new Error('The provider registry is needed to enable the jupyterlite-ai settings panel');
|
|
112
117
|
}
|
|
@@ -160,7 +165,7 @@ export class AiSettings extends React.Component {
|
|
|
160
165
|
var _a, _b;
|
|
161
166
|
const useSecretsManager = (_a = this._settings.get('UseSecretsManager').composite) !== null && _a !== void 0 ? _a : true;
|
|
162
167
|
if (useSecretsManager !== this._useSecretsManager) {
|
|
163
|
-
this.
|
|
168
|
+
this._updateUseSecretsManager(useSecretsManager);
|
|
164
169
|
}
|
|
165
170
|
const hideSecretFields = (_b = this._settings.get('HideSecretFields').composite) !== null && _b !== void 0 ? _b : true;
|
|
166
171
|
if (hideSecretFields !== this._hideSecretFields) {
|
|
@@ -174,27 +179,18 @@ export class AiSettings extends React.Component {
|
|
|
174
179
|
if (!this._secretsManager || !this._useSecretsManager) {
|
|
175
180
|
return;
|
|
176
181
|
}
|
|
177
|
-
// Attach the password inputs to the secrets manager
|
|
178
|
-
const inputs = ((_a = this._formRef.current) === null || _a === void 0 ? void 0 : _a.getElementsByTagName('input')) || [];
|
|
179
|
-
if (ArrayExt.shallowEqual(inputs, this._formInputs)) {
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
+
// Attach the password inputs to the secrets manager.
|
|
182
183
|
await this._secretsManager.detachAll(Private.getToken(), SECRETS_NAMESPACE);
|
|
183
|
-
this.
|
|
184
|
-
this._unsavedFields = [];
|
|
184
|
+
const inputs = ((_a = this._formRef.current) === null || _a === void 0 ? void 0 : _a.getElementsByTagName('input')) || [];
|
|
185
185
|
for (let i = 0; i < inputs.length; i++) {
|
|
186
186
|
if (inputs[i].type.toLowerCase() === 'password') {
|
|
187
187
|
const label = inputs[i].getAttribute('label');
|
|
188
188
|
if (label) {
|
|
189
189
|
const id = getSecretId(this._provider, label);
|
|
190
190
|
this._secretsManager.attach(Private.getToken(), SECRETS_NAMESPACE, id, inputs[i], (value) => this._onPasswordUpdated(label, value));
|
|
191
|
-
this._unsavedFields.push(label);
|
|
192
191
|
}
|
|
193
192
|
}
|
|
194
193
|
}
|
|
195
|
-
if (this._settingConnector instanceof SettingConnector) {
|
|
196
|
-
this._settingConnector.doNotSave = this._unsavedFields;
|
|
197
|
-
}
|
|
198
194
|
}
|
|
199
195
|
componentWillUnmount() {
|
|
200
196
|
if (!this._secretsManager || !this._useSecretsManager) {
|
|
@@ -233,7 +229,10 @@ export class AiSettings extends React.Component {
|
|
|
233
229
|
var _a;
|
|
234
230
|
const currentSettings = { ...value };
|
|
235
231
|
const settings = JSON.parse((_a = localStorage.getItem(STORAGE_NAME)) !== null && _a !== void 0 ? _a : '{}');
|
|
236
|
-
|
|
232
|
+
// Do not save secrets in local storage if using the secrets manager.
|
|
233
|
+
if (this._secretsManager && this._useSecretsManager) {
|
|
234
|
+
this._secretFields.forEach(field => delete currentSettings[field]);
|
|
235
|
+
}
|
|
237
236
|
settings[this._provider] = currentSettings;
|
|
238
237
|
localStorage.setItem(STORAGE_NAME, JSON.stringify(settings));
|
|
239
238
|
}
|
|
@@ -244,9 +243,11 @@ export class AiSettings extends React.Component {
|
|
|
244
243
|
const schema = JSONExt.deepCopy(baseSettings);
|
|
245
244
|
this._uiSchema = {};
|
|
246
245
|
const settingsSchema = this._providerRegistry.getSettingsSchema(this._provider);
|
|
246
|
+
this._secretFields = [];
|
|
247
247
|
if (settingsSchema) {
|
|
248
248
|
Object.entries(settingsSchema).forEach(([key, value]) => {
|
|
249
249
|
if (key.toLowerCase().includes('key')) {
|
|
250
|
+
this._secretFields.push(key);
|
|
250
251
|
if (this._hideSecretFields) {
|
|
251
252
|
return;
|
|
252
253
|
}
|
|
@@ -255,6 +256,12 @@ export class AiSettings extends React.Component {
|
|
|
255
256
|
schema.properties[key] = value;
|
|
256
257
|
});
|
|
257
258
|
}
|
|
259
|
+
// Do not save secrets in settings if using the secrets manager.
|
|
260
|
+
if (this._secretsManager &&
|
|
261
|
+
this._useSecretsManager &&
|
|
262
|
+
this._settingConnector instanceof SettingConnector) {
|
|
263
|
+
this._settingConnector.doNotSave = this._secretFields;
|
|
264
|
+
}
|
|
258
265
|
return schema;
|
|
259
266
|
}
|
|
260
267
|
/**
|
|
@@ -49,10 +49,10 @@ export class SettingConnector extends DataConnector {
|
|
|
49
49
|
}
|
|
50
50
|
async save(id, raw) {
|
|
51
51
|
const settings = json5.parse(raw);
|
|
52
|
+
// Replace secrets fields with the replacement string.
|
|
53
|
+
// Create the field if it does not exist in settings.
|
|
52
54
|
this._doNotSave.forEach(field => {
|
|
53
|
-
if (settings['AIprovider'] !== undefined
|
|
54
|
-
settings['AIprovider'][field] !== undefined &&
|
|
55
|
-
settings['AIprovider'][field] !== '') {
|
|
55
|
+
if (settings['AIprovider'] !== undefined) {
|
|
56
56
|
settings['AIprovider'][field] = SECRETS_REPLACEMENT;
|
|
57
57
|
}
|
|
58
58
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jupyterlite/ai",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "AI code completions and chat for JupyterLite",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"@lumino/signaling": "^2.1.2",
|
|
76
76
|
"@mui/icons-material": "^5.11.0",
|
|
77
77
|
"@mui/material": "^5.11.0",
|
|
78
|
-
"@rjsf/core": "^
|
|
78
|
+
"@rjsf/core": "^5.18.4",
|
|
79
79
|
"@rjsf/utils": "^5.18.4",
|
|
80
80
|
"@rjsf/validator-ajv8": "^5.18.4",
|
|
81
81
|
"json5": "^2.2.3",
|
package/src/base-completer.ts
CHANGED
|
@@ -11,11 +11,11 @@ import { COMPLETION_SYSTEM_PROMPT } from '../../provider';
|
|
|
11
11
|
|
|
12
12
|
export class AnthropicCompleter implements IBaseCompleter {
|
|
13
13
|
constructor(options: BaseCompleter.IOptions) {
|
|
14
|
-
this.
|
|
14
|
+
this._completer = new ChatAnthropic({ ...options.settings });
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
get
|
|
18
|
-
return this.
|
|
17
|
+
get completer(): BaseChatModel {
|
|
18
|
+
return this._completer;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -44,7 +44,7 @@ export class AnthropicCompleter implements IBaseCompleter {
|
|
|
44
44
|
];
|
|
45
45
|
|
|
46
46
|
try {
|
|
47
|
-
const response = await this.
|
|
47
|
+
const response = await this._completer.invoke(messages);
|
|
48
48
|
const items = [];
|
|
49
49
|
|
|
50
50
|
// Anthropic can return string or complex content, a list of string/images/other.
|
|
@@ -70,6 +70,6 @@ export class AnthropicCompleter implements IBaseCompleter {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
private
|
|
73
|
+
private _completer: ChatAnthropic;
|
|
74
74
|
private _prompt: string = COMPLETION_SYSTEM_PROMPT;
|
|
75
75
|
}
|
|
@@ -32,7 +32,7 @@ const CODE_BLOCK_END_REGEX = /```$/;
|
|
|
32
32
|
|
|
33
33
|
export class ChromeCompleter implements IBaseCompleter {
|
|
34
34
|
constructor(options: BaseCompleter.IOptions) {
|
|
35
|
-
this.
|
|
35
|
+
this._completer = new ChromeAI({ ...options.settings });
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -45,8 +45,8 @@ export class ChromeCompleter implements IBaseCompleter {
|
|
|
45
45
|
this._prompt = value;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
get
|
|
49
|
-
return this.
|
|
48
|
+
get completer(): LLM {
|
|
49
|
+
return this._completer;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
async fetch(
|
|
@@ -64,7 +64,7 @@ export class ChromeCompleter implements IBaseCompleter {
|
|
|
64
64
|
];
|
|
65
65
|
|
|
66
66
|
try {
|
|
67
|
-
let response = await this.
|
|
67
|
+
let response = await this._completer.invoke(messages);
|
|
68
68
|
|
|
69
69
|
// ChromeAI sometimes returns a string starting with '```',
|
|
70
70
|
// so process the response to remove the code block delimiters
|
|
@@ -84,6 +84,6 @@ export class ChromeCompleter implements IBaseCompleter {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
private
|
|
87
|
+
private _completer: ChromeAI;
|
|
88
88
|
private _prompt: string = COMPLETION_SYSTEM_PROMPT;
|
|
89
89
|
}
|
|
@@ -21,10 +21,10 @@ const INTERVAL = 1000;
|
|
|
21
21
|
|
|
22
22
|
export class CodestralCompleter implements IBaseCompleter {
|
|
23
23
|
constructor(options: BaseCompleter.IOptions) {
|
|
24
|
-
this.
|
|
24
|
+
this._completer = new ChatMistralAI({ ...options.settings });
|
|
25
25
|
this._throttler = new Throttler(
|
|
26
26
|
async (messages: BaseMessage[]) => {
|
|
27
|
-
const response = await this.
|
|
27
|
+
const response = await this._completer.invoke(messages);
|
|
28
28
|
// Extract results of completion request.
|
|
29
29
|
const items = [];
|
|
30
30
|
if (typeof response.content === 'string') {
|
|
@@ -47,8 +47,8 @@ export class CodestralCompleter implements IBaseCompleter {
|
|
|
47
47
|
);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
get
|
|
51
|
-
return this.
|
|
50
|
+
get completer(): BaseChatModel {
|
|
51
|
+
return this._completer;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
@@ -82,6 +82,6 @@ export class CodestralCompleter implements IBaseCompleter {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
private _throttler: Throttler;
|
|
85
|
-
private
|
|
85
|
+
private _completer: ChatMistralAI;
|
|
86
86
|
private _prompt: string = COMPLETION_SYSTEM_PROMPT;
|
|
87
87
|
}
|
|
@@ -11,11 +11,11 @@ import { COMPLETION_SYSTEM_PROMPT } from '../../provider';
|
|
|
11
11
|
|
|
12
12
|
export class OpenAICompleter implements IBaseCompleter {
|
|
13
13
|
constructor(options: BaseCompleter.IOptions) {
|
|
14
|
-
this.
|
|
14
|
+
this._completer = new ChatOpenAI({ ...options.settings });
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
get
|
|
18
|
-
return this.
|
|
17
|
+
get completer(): BaseChatModel {
|
|
18
|
+
return this._completer;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -38,7 +38,7 @@ export class OpenAICompleter implements IBaseCompleter {
|
|
|
38
38
|
const messages = [new SystemMessage(this._prompt), new AIMessage(prompt)];
|
|
39
39
|
|
|
40
40
|
try {
|
|
41
|
-
const response = await this.
|
|
41
|
+
const response = await this._completer.invoke(messages);
|
|
42
42
|
const items = [];
|
|
43
43
|
if (typeof response.content === 'string') {
|
|
44
44
|
items.push({
|
|
@@ -62,6 +62,6 @@ export class OpenAICompleter implements IBaseCompleter {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
private
|
|
65
|
+
private _completer: ChatOpenAI;
|
|
66
66
|
private _prompt: string = COMPLETION_SYSTEM_PROMPT;
|
|
67
67
|
}
|
package/src/provider.ts
CHANGED
|
@@ -176,7 +176,9 @@ export class AIProviderRegistry implements IAIProviderRegistry {
|
|
|
176
176
|
SECRETS_NAMESPACE,
|
|
177
177
|
id
|
|
178
178
|
);
|
|
179
|
-
|
|
179
|
+
if (secrets !== undefined) {
|
|
180
|
+
fullSettings[key] = secrets.value;
|
|
181
|
+
}
|
|
180
182
|
continue;
|
|
181
183
|
}
|
|
182
184
|
fullSettings[key] = settings[key];
|
|
@@ -185,7 +187,7 @@ export class AIProviderRegistry implements IAIProviderRegistry {
|
|
|
185
187
|
if (this._currentProvider?.completer !== undefined) {
|
|
186
188
|
try {
|
|
187
189
|
this._completer = new this._currentProvider.completer({
|
|
188
|
-
|
|
190
|
+
settings: fullSettings
|
|
189
191
|
});
|
|
190
192
|
this._completerError = '';
|
|
191
193
|
} catch (e: any) {
|
package/src/settings/panel.tsx
CHANGED
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
ISettingRegistry
|
|
5
5
|
} from '@jupyterlab/settingregistry';
|
|
6
6
|
import { FormComponent, IFormRenderer } from '@jupyterlab/ui-components';
|
|
7
|
-
import { ArrayExt } from '@lumino/algorithm';
|
|
8
7
|
import { JSONExt } from '@lumino/coreutils';
|
|
9
8
|
import { IChangeEvent } from '@rjsf/core';
|
|
10
9
|
import type { FieldProps } from '@rjsf/utils';
|
|
@@ -122,7 +121,7 @@ export class AiSettings extends React.Component<
|
|
|
122
121
|
const useSecretsManager =
|
|
123
122
|
(this._settings.get('UseSecretsManager').composite as boolean) ?? true;
|
|
124
123
|
if (useSecretsManager !== this._useSecretsManager) {
|
|
125
|
-
this.
|
|
124
|
+
this._updateUseSecretsManager(useSecretsManager);
|
|
126
125
|
}
|
|
127
126
|
const hideSecretFields =
|
|
128
127
|
(this._settings.get('HideSecretFields').composite as boolean) ?? true;
|
|
@@ -137,15 +136,10 @@ export class AiSettings extends React.Component<
|
|
|
137
136
|
if (!this._secretsManager || !this._useSecretsManager) {
|
|
138
137
|
return;
|
|
139
138
|
}
|
|
140
|
-
// Attach the password inputs to the secrets manager only if they have changed.
|
|
141
|
-
const inputs = this._formRef.current?.getElementsByTagName('input') || [];
|
|
142
|
-
if (ArrayExt.shallowEqual(inputs, this._formInputs)) {
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
139
|
|
|
140
|
+
// Attach the password inputs to the secrets manager.
|
|
146
141
|
await this._secretsManager.detachAll(Private.getToken(), SECRETS_NAMESPACE);
|
|
147
|
-
this.
|
|
148
|
-
this._unsavedFields = [];
|
|
142
|
+
const inputs = this._formRef.current?.getElementsByTagName('input') || [];
|
|
149
143
|
for (let i = 0; i < inputs.length; i++) {
|
|
150
144
|
if (inputs[i].type.toLowerCase() === 'password') {
|
|
151
145
|
const label = inputs[i].getAttribute('label');
|
|
@@ -158,13 +152,9 @@ export class AiSettings extends React.Component<
|
|
|
158
152
|
inputs[i],
|
|
159
153
|
(value: string) => this._onPasswordUpdated(label, value)
|
|
160
154
|
);
|
|
161
|
-
this._unsavedFields.push(label);
|
|
162
155
|
}
|
|
163
156
|
}
|
|
164
157
|
}
|
|
165
|
-
if (this._settingConnector instanceof SettingConnector) {
|
|
166
|
-
this._settingConnector.doNotSave = this._unsavedFields;
|
|
167
|
-
}
|
|
168
158
|
}
|
|
169
159
|
|
|
170
160
|
componentWillUnmount(): void {
|
|
@@ -205,26 +195,31 @@ export class AiSettings extends React.Component<
|
|
|
205
195
|
saveSettings(value: IDict<any>) {
|
|
206
196
|
const currentSettings = { ...value };
|
|
207
197
|
const settings = JSON.parse(localStorage.getItem(STORAGE_NAME) ?? '{}');
|
|
208
|
-
|
|
198
|
+
// Do not save secrets in local storage if using the secrets manager.
|
|
199
|
+
if (this._secretsManager && this._useSecretsManager) {
|
|
200
|
+
this._secretFields.forEach(field => delete currentSettings[field]);
|
|
201
|
+
}
|
|
209
202
|
settings[this._provider] = currentSettings;
|
|
210
203
|
localStorage.setItem(STORAGE_NAME, JSON.stringify(settings));
|
|
211
204
|
}
|
|
212
205
|
|
|
213
|
-
|
|
206
|
+
/**
|
|
207
|
+
* Update the settings whether the secrets manager is used or not.
|
|
208
|
+
*
|
|
209
|
+
* @param value - whether to use the secrets manager or not.
|
|
210
|
+
*/
|
|
211
|
+
private _updateUseSecretsManager = (value: boolean) => {
|
|
214
212
|
this._useSecretsManager = value;
|
|
215
213
|
if (!value) {
|
|
216
214
|
// Detach all the password inputs attached to the secrets manager, and save the
|
|
217
215
|
// current settings to the local storage to save the password.
|
|
218
216
|
this._secretsManager?.detachAll(Private.getToken(), SECRETS_NAMESPACE);
|
|
219
|
-
this._formInputs = [];
|
|
220
|
-
this._unsavedFields = [];
|
|
221
217
|
if (this._settingConnector instanceof SettingConnector) {
|
|
222
218
|
this._settingConnector.doNotSave = [];
|
|
223
219
|
}
|
|
224
220
|
this.saveSettings(this._currentSettings);
|
|
225
221
|
} else {
|
|
226
|
-
// Remove all the keys stored locally
|
|
227
|
-
// secrets manager.
|
|
222
|
+
// Remove all the keys stored locally.
|
|
228
223
|
const settings = JSON.parse(localStorage.getItem(STORAGE_NAME) || '{}');
|
|
229
224
|
Object.keys(settings).forEach(provider => {
|
|
230
225
|
Object.keys(settings[provider])
|
|
@@ -234,6 +229,11 @@ export class AiSettings extends React.Component<
|
|
|
234
229
|
});
|
|
235
230
|
});
|
|
236
231
|
localStorage.setItem(STORAGE_NAME, JSON.stringify(settings));
|
|
232
|
+
// Update the fields not to save in settings.
|
|
233
|
+
if (this._settingConnector instanceof SettingConnector) {
|
|
234
|
+
this._settingConnector.doNotSave = this._secretFields;
|
|
235
|
+
}
|
|
236
|
+
// Attach the password inputs to the secrets manager.
|
|
237
237
|
this.componentDidUpdate();
|
|
238
238
|
}
|
|
239
239
|
this._settings
|
|
@@ -251,9 +251,11 @@ export class AiSettings extends React.Component<
|
|
|
251
251
|
this._provider
|
|
252
252
|
);
|
|
253
253
|
|
|
254
|
+
this._secretFields = [];
|
|
254
255
|
if (settingsSchema) {
|
|
255
256
|
Object.entries(settingsSchema).forEach(([key, value]) => {
|
|
256
257
|
if (key.toLowerCase().includes('key')) {
|
|
258
|
+
this._secretFields.push(key);
|
|
257
259
|
if (this._hideSecretFields) {
|
|
258
260
|
return;
|
|
259
261
|
}
|
|
@@ -262,6 +264,15 @@ export class AiSettings extends React.Component<
|
|
|
262
264
|
schema.properties[key] = value;
|
|
263
265
|
});
|
|
264
266
|
}
|
|
267
|
+
|
|
268
|
+
// Do not save secrets in settings if using the secrets manager.
|
|
269
|
+
if (
|
|
270
|
+
this._secretsManager &&
|
|
271
|
+
this._useSecretsManager &&
|
|
272
|
+
this._settingConnector instanceof SettingConnector
|
|
273
|
+
) {
|
|
274
|
+
this._settingConnector.doNotSave = this._secretFields;
|
|
275
|
+
}
|
|
265
276
|
return schema as JSONSchema7;
|
|
266
277
|
}
|
|
267
278
|
|
|
@@ -375,8 +386,7 @@ export class AiSettings extends React.Component<
|
|
|
375
386
|
private _uiSchema: IDict<any> = {};
|
|
376
387
|
private _settings: ISettingRegistry.ISettings;
|
|
377
388
|
private _formRef = React.createRef<HTMLDivElement>();
|
|
378
|
-
private
|
|
379
|
-
private _formInputs: HTMLInputElement[] = [];
|
|
389
|
+
private _secretFields: string[] = [];
|
|
380
390
|
}
|
|
381
391
|
|
|
382
392
|
namespace Private {
|
|
@@ -71,12 +71,11 @@ export class SettingConnector
|
|
|
71
71
|
|
|
72
72
|
async save(id: string, raw: string): Promise<void> {
|
|
73
73
|
const settings = json5.parse(raw);
|
|
74
|
+
|
|
75
|
+
// Replace secrets fields with the replacement string.
|
|
76
|
+
// Create the field if it does not exist in settings.
|
|
74
77
|
this._doNotSave.forEach(field => {
|
|
75
|
-
if (
|
|
76
|
-
settings['AIprovider'] !== undefined &&
|
|
77
|
-
settings['AIprovider'][field] !== undefined &&
|
|
78
|
-
settings['AIprovider'][field] !== ''
|
|
79
|
-
) {
|
|
78
|
+
if (settings['AIprovider'] !== undefined) {
|
|
80
79
|
settings['AIprovider'][field] = SECRETS_REPLACEMENT;
|
|
81
80
|
}
|
|
82
81
|
});
|