@jupyterlite/ai 0.8.0 → 0.9.0-a0
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/agent.d.ts +233 -0
- package/lib/agent.js +604 -0
- package/lib/chat-model.d.ts +195 -0
- package/lib/chat-model.js +590 -0
- package/lib/completion/completion-provider.d.ts +83 -0
- package/lib/completion/completion-provider.js +209 -0
- package/lib/completion/index.d.ts +1 -0
- package/lib/completion/index.js +1 -0
- package/lib/components/clear-button.d.ts +18 -0
- package/lib/components/clear-button.js +31 -0
- package/lib/components/index.d.ts +3 -0
- package/lib/components/index.js +3 -0
- package/lib/components/model-select.d.ts +19 -0
- package/lib/components/model-select.js +154 -0
- package/lib/components/stop-button.d.ts +3 -3
- package/lib/components/stop-button.js +8 -9
- package/lib/components/token-usage-display.d.ts +45 -0
- package/lib/components/token-usage-display.js +74 -0
- package/lib/components/tool-select.d.ts +27 -0
- package/lib/components/tool-select.js +130 -0
- package/lib/icons.d.ts +3 -1
- package/lib/icons.js +10 -13
- package/lib/index.d.ts +4 -5
- package/lib/index.js +322 -167
- package/lib/mcp/browser.d.ts +68 -0
- package/lib/mcp/browser.js +132 -0
- package/lib/models/settings-model.d.ts +69 -0
- package/lib/models/settings-model.js +295 -0
- package/lib/providers/built-in-providers.d.ts +9 -0
- package/lib/providers/built-in-providers.js +192 -0
- package/lib/providers/models.d.ts +37 -0
- package/lib/providers/models.js +28 -0
- package/lib/providers/provider-registry.d.ts +94 -0
- package/lib/providers/provider-registry.js +155 -0
- package/lib/tokens.d.ts +157 -86
- package/lib/tokens.js +16 -12
- package/lib/tools/commands.d.ts +11 -0
- package/lib/tools/commands.js +126 -0
- package/lib/tools/file.d.ts +27 -0
- package/lib/tools/file.js +262 -0
- package/lib/tools/notebook.d.ts +40 -0
- package/lib/tools/notebook.js +762 -0
- package/lib/tools/tool-registry.d.ts +35 -0
- package/lib/tools/tool-registry.js +55 -0
- package/lib/widgets/ai-settings.d.ts +39 -0
- package/lib/widgets/ai-settings.js +506 -0
- package/lib/widgets/chat-wrapper.d.ts +144 -0
- package/lib/widgets/chat-wrapper.js +390 -0
- package/lib/widgets/provider-config-dialog.d.ts +13 -0
- package/lib/widgets/provider-config-dialog.js +104 -0
- package/package.json +150 -41
- package/schema/settings-model.json +153 -0
- package/src/agent.ts +800 -0
- package/src/chat-model.ts +770 -0
- package/src/completion/completion-provider.ts +308 -0
- package/src/completion/index.ts +1 -0
- package/src/components/clear-button.tsx +56 -0
- package/src/components/index.ts +3 -0
- package/src/components/model-select.tsx +245 -0
- package/src/components/stop-button.tsx +11 -11
- package/src/components/token-usage-display.tsx +130 -0
- package/src/components/tool-select.tsx +218 -0
- package/src/icons.ts +12 -14
- package/src/index.ts +468 -238
- package/src/mcp/browser.ts +213 -0
- package/src/models/settings-model.ts +409 -0
- package/src/providers/built-in-providers.ts +216 -0
- package/src/providers/models.ts +79 -0
- package/src/providers/provider-registry.ts +189 -0
- package/src/tokens.ts +203 -90
- package/src/tools/commands.ts +151 -0
- package/src/tools/file.ts +307 -0
- package/src/tools/notebook.ts +964 -0
- package/src/tools/tool-registry.ts +63 -0
- package/src/types.d.ts +4 -0
- package/src/widgets/ai-settings.tsx +1100 -0
- package/src/widgets/chat-wrapper.tsx +543 -0
- package/src/widgets/provider-config-dialog.tsx +256 -0
- package/style/base.css +335 -14
- package/style/icons/jupyternaut-lite.svg +1 -1
- package/lib/base-completer.d.ts +0 -49
- package/lib/base-completer.js +0 -14
- package/lib/chat-handler.d.ts +0 -56
- package/lib/chat-handler.js +0 -201
- package/lib/completion-provider.d.ts +0 -34
- package/lib/completion-provider.js +0 -32
- package/lib/default-prompts.d.ts +0 -2
- package/lib/default-prompts.js +0 -31
- package/lib/default-providers/Anthropic/completer.d.ts +0 -12
- package/lib/default-providers/Anthropic/completer.js +0 -46
- package/lib/default-providers/Anthropic/settings-schema.json +0 -70
- package/lib/default-providers/ChromeAI/completer.d.ts +0 -12
- package/lib/default-providers/ChromeAI/completer.js +0 -56
- package/lib/default-providers/ChromeAI/instructions.d.ts +0 -6
- package/lib/default-providers/ChromeAI/instructions.js +0 -42
- package/lib/default-providers/ChromeAI/settings-schema.json +0 -18
- package/lib/default-providers/Gemini/completer.d.ts +0 -12
- package/lib/default-providers/Gemini/completer.js +0 -48
- package/lib/default-providers/Gemini/instructions.d.ts +0 -2
- package/lib/default-providers/Gemini/instructions.js +0 -9
- package/lib/default-providers/Gemini/settings-schema.json +0 -64
- package/lib/default-providers/MistralAI/completer.d.ts +0 -13
- package/lib/default-providers/MistralAI/completer.js +0 -52
- package/lib/default-providers/MistralAI/instructions.d.ts +0 -2
- package/lib/default-providers/MistralAI/instructions.js +0 -18
- package/lib/default-providers/MistralAI/settings-schema.json +0 -75
- package/lib/default-providers/Ollama/completer.d.ts +0 -12
- package/lib/default-providers/Ollama/completer.js +0 -43
- package/lib/default-providers/Ollama/instructions.d.ts +0 -2
- package/lib/default-providers/Ollama/instructions.js +0 -70
- package/lib/default-providers/Ollama/settings-schema.json +0 -143
- package/lib/default-providers/OpenAI/completer.d.ts +0 -12
- package/lib/default-providers/OpenAI/completer.js +0 -43
- package/lib/default-providers/OpenAI/settings-schema.json +0 -628
- package/lib/default-providers/WebLLM/completer.d.ts +0 -21
- package/lib/default-providers/WebLLM/completer.js +0 -127
- package/lib/default-providers/WebLLM/instructions.d.ts +0 -6
- package/lib/default-providers/WebLLM/instructions.js +0 -32
- package/lib/default-providers/WebLLM/settings-schema.json +0 -19
- package/lib/default-providers/index.d.ts +0 -2
- package/lib/default-providers/index.js +0 -179
- package/lib/provider.d.ts +0 -144
- package/lib/provider.js +0 -412
- package/lib/settings/base.json +0 -7
- package/lib/settings/index.d.ts +0 -3
- package/lib/settings/index.js +0 -3
- package/lib/settings/panel.d.ts +0 -226
- package/lib/settings/panel.js +0 -510
- package/lib/settings/textarea.d.ts +0 -2
- package/lib/settings/textarea.js +0 -18
- package/lib/settings/utils.d.ts +0 -2
- package/lib/settings/utils.js +0 -4
- package/lib/types/ai-model.d.ts +0 -24
- package/lib/types/ai-model.js +0 -5
- package/schema/chat.json +0 -28
- package/schema/provider-registry.json +0 -29
- package/schema/system-prompts.json +0 -22
- package/src/base-completer.ts +0 -75
- package/src/chat-handler.ts +0 -262
- package/src/completion-provider.ts +0 -64
- package/src/default-prompts.ts +0 -33
- package/src/default-providers/Anthropic/completer.ts +0 -59
- package/src/default-providers/ChromeAI/completer.ts +0 -73
- package/src/default-providers/ChromeAI/instructions.ts +0 -45
- package/src/default-providers/Gemini/completer.ts +0 -61
- package/src/default-providers/Gemini/instructions.ts +0 -9
- package/src/default-providers/MistralAI/completer.ts +0 -69
- package/src/default-providers/MistralAI/instructions.ts +0 -18
- package/src/default-providers/Ollama/completer.ts +0 -54
- package/src/default-providers/Ollama/instructions.ts +0 -70
- package/src/default-providers/OpenAI/completer.ts +0 -54
- package/src/default-providers/WebLLM/completer.ts +0 -151
- package/src/default-providers/WebLLM/instructions.ts +0 -33
- package/src/default-providers/index.ts +0 -211
- package/src/global.d.ts +0 -9
- package/src/provider.ts +0 -514
- package/src/settings/index.ts +0 -3
- package/src/settings/panel.tsx +0 -773
- package/src/settings/textarea.tsx +0 -33
- package/src/settings/utils.ts +0 -5
- package/src/types/ai-model.ts +0 -37
- package/src/types/service-worker.d.ts +0 -6
package/lib/settings/panel.js
DELETED
|
@@ -1,510 +0,0 @@
|
|
|
1
|
-
import { Button, FormComponent } from '@jupyterlab/ui-components';
|
|
2
|
-
import { JSONExt } from '@lumino/coreutils';
|
|
3
|
-
import validator from '@rjsf/validator-ajv8';
|
|
4
|
-
import React from 'react';
|
|
5
|
-
import { getSecretId, SECRETS_REPLACEMENT } from '.';
|
|
6
|
-
import baseSettings from './base.json';
|
|
7
|
-
import { PLUGIN_IDS } from '../tokens';
|
|
8
|
-
const MD_MIME_TYPE = 'text/markdown';
|
|
9
|
-
const INSTRUCTION_CLASS = 'jp-AISettingsInstructions';
|
|
10
|
-
const ERROR_CLASS = 'jp-AISettingsError';
|
|
11
|
-
const SECRETS_NAMESPACE = PLUGIN_IDS.providerRegistry;
|
|
12
|
-
const STORAGE_KEYS = {
|
|
13
|
-
chat: '@jupyterlite/ai:chat-settings',
|
|
14
|
-
completer: '@jupyterlite/ai:completer-settings'
|
|
15
|
-
};
|
|
16
|
-
export const aiSettingsRenderer = (options) => {
|
|
17
|
-
const { secretsToken } = options;
|
|
18
|
-
delete options.secretsToken;
|
|
19
|
-
if (secretsToken) {
|
|
20
|
-
Private.setToken(secretsToken);
|
|
21
|
-
}
|
|
22
|
-
return {
|
|
23
|
-
fieldRenderer: (props) => {
|
|
24
|
-
props.formContext = { ...props.formContext, ...options };
|
|
25
|
-
return React.createElement(AiSettings, { ...props });
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
};
|
|
29
|
-
const WrappedFormComponent = (props) => {
|
|
30
|
-
return React.createElement(FormComponent, { ...props, validator: validator });
|
|
31
|
-
};
|
|
32
|
-
export class AiSettings extends React.Component {
|
|
33
|
-
constructor(props) {
|
|
34
|
-
super(props);
|
|
35
|
-
this._settings = props.formContext.settings;
|
|
36
|
-
const uniqueProvider = this._settings.get('UniqueProvider').composite ?? true;
|
|
37
|
-
this.state = { uniqueProvider };
|
|
38
|
-
this._settings.changed.connect(this._settingsChanged);
|
|
39
|
-
}
|
|
40
|
-
_settingsChanged = () => {
|
|
41
|
-
const uniqueProvider = this._settings.get('UniqueProvider').composite ?? true;
|
|
42
|
-
if (this.state.uniqueProvider === uniqueProvider) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
if (uniqueProvider) {
|
|
46
|
-
// Copy chat settings to the completer settings if there should be a unique
|
|
47
|
-
// provider for both.
|
|
48
|
-
this.setLocalStorageItem('completer', null, this.getLocalStorage('chat'));
|
|
49
|
-
this.saveSettingsToRegistry('completer', this.getSettingsFromRegistry('chat'));
|
|
50
|
-
}
|
|
51
|
-
this.setState({ uniqueProvider });
|
|
52
|
-
};
|
|
53
|
-
/**
|
|
54
|
-
* Get the local storage settings for a specific role (chat or completer).
|
|
55
|
-
*/
|
|
56
|
-
getLocalStorage = (role) => {
|
|
57
|
-
const storageKey = STORAGE_KEYS[role];
|
|
58
|
-
return JSON.parse(localStorage.getItem(storageKey) ?? '{}');
|
|
59
|
-
};
|
|
60
|
-
/**
|
|
61
|
-
* Set the local storage item for a specific role (chat or completer).
|
|
62
|
-
* If the key is not provider (null) we assume the value should replace the whole
|
|
63
|
-
* local storage for this role.
|
|
64
|
-
*/
|
|
65
|
-
setLocalStorageItem = (role, key, value) => {
|
|
66
|
-
const storageKey = STORAGE_KEYS[role];
|
|
67
|
-
let settings;
|
|
68
|
-
if (key !== null) {
|
|
69
|
-
settings = JSON.parse(localStorage.getItem(storageKey) ?? '{}');
|
|
70
|
-
settings[key] = value;
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
settings = value;
|
|
74
|
-
}
|
|
75
|
-
localStorage.setItem(storageKey, JSON.stringify(settings));
|
|
76
|
-
// If both chat and completer use the same settings, only the chat settings should
|
|
77
|
-
// be editable for user, so we should duplicate its values to the completer
|
|
78
|
-
// local storage.
|
|
79
|
-
if (this.state.uniqueProvider && role === 'chat') {
|
|
80
|
-
const storageKeyCompleter = STORAGE_KEYS['completer'];
|
|
81
|
-
localStorage.setItem(storageKeyCompleter, JSON.stringify(settings));
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
/**
|
|
85
|
-
* Get the settings from the registry (jupyterlab settings system) for a given role.
|
|
86
|
-
*/
|
|
87
|
-
getSettingsFromRegistry = (role) => {
|
|
88
|
-
const settings = this._settings.get('AIproviders')
|
|
89
|
-
.composite;
|
|
90
|
-
return settings && Object.keys(settings).includes(role)
|
|
91
|
-
? settings[role]
|
|
92
|
-
: { provider: 'None' };
|
|
93
|
-
};
|
|
94
|
-
/**
|
|
95
|
-
* Save the settings to the setting registry.
|
|
96
|
-
*/
|
|
97
|
-
saveSettingsToRegistry = (role, settings) => {
|
|
98
|
-
const fullSettings = this._settings.get('AIproviders')
|
|
99
|
-
.composite;
|
|
100
|
-
fullSettings[role] = { ...settings };
|
|
101
|
-
// If both chat and completer use the same settings, only the chat settings should
|
|
102
|
-
// be editable for user, so we should duplicate its values to the completer
|
|
103
|
-
// settings.
|
|
104
|
-
if (this.state.uniqueProvider && role === 'chat') {
|
|
105
|
-
fullSettings['completer'] = { ...settings };
|
|
106
|
-
}
|
|
107
|
-
this._settings.set('AIproviders', { ...fullSettings }).catch(console.error);
|
|
108
|
-
};
|
|
109
|
-
render() {
|
|
110
|
-
return (React.createElement("div", null,
|
|
111
|
-
React.createElement("h3", null, this.state.uniqueProvider
|
|
112
|
-
? 'Chat and completer provider'
|
|
113
|
-
: 'Chat provider'),
|
|
114
|
-
React.createElement(AiProviderSettings, { ...this.props, role: 'chat', aiSettings: this }),
|
|
115
|
-
!this.state.uniqueProvider && (React.createElement(React.Fragment, null,
|
|
116
|
-
React.createElement("h3", null, "Completer provider"),
|
|
117
|
-
React.createElement(AiProviderSettings, { ...this.props, role: 'completer', aiSettings: this })))));
|
|
118
|
-
}
|
|
119
|
-
_settings;
|
|
120
|
-
}
|
|
121
|
-
export class AiProviderSettings extends React.Component {
|
|
122
|
-
constructor(props) {
|
|
123
|
-
super(props);
|
|
124
|
-
if (!props.formContext.providerRegistry) {
|
|
125
|
-
throw new Error('The provider registry is needed to enable the jupyterlite-ai settings panel');
|
|
126
|
-
}
|
|
127
|
-
this._role = props.role;
|
|
128
|
-
this._providerRegistry = props.formContext.providerRegistry;
|
|
129
|
-
this._rmRegistry = props.formContext.rmRegistry ?? null;
|
|
130
|
-
this._secretsManager = props.formContext.secretsManager ?? null;
|
|
131
|
-
this._settings = props.formContext.settings;
|
|
132
|
-
const useSecretsManagerSetting = this._settings.get('UseSecretsManager').composite ?? true;
|
|
133
|
-
this._useSecretsManager =
|
|
134
|
-
useSecretsManagerSetting && this._secretsManager !== null;
|
|
135
|
-
// Initialize the providers schema.
|
|
136
|
-
const providerSchema = JSONExt.deepCopy(baseSettings);
|
|
137
|
-
providerSchema.properties.provider = {
|
|
138
|
-
type: 'string',
|
|
139
|
-
title: 'Provider',
|
|
140
|
-
description: 'The AI provider to use for chat and completion',
|
|
141
|
-
default: 'None',
|
|
142
|
-
enum: ['None'].concat(this._providerRegistry.providers)
|
|
143
|
-
};
|
|
144
|
-
this._providerSchema = providerSchema;
|
|
145
|
-
// Check if there is saved values in local storage, otherwise use the settings from
|
|
146
|
-
// the setting registry (leads to default if there are no user settings).
|
|
147
|
-
const storageKey = STORAGE_KEYS[this._role];
|
|
148
|
-
const storageSettings = localStorage.getItem(storageKey);
|
|
149
|
-
if (storageSettings === null) {
|
|
150
|
-
const labSettings = this.props.aiSettings.getSettingsFromRegistry(this._role);
|
|
151
|
-
if (Object.keys(labSettings).includes('provider')) {
|
|
152
|
-
// Get the provider name.
|
|
153
|
-
const provider = Object.entries(labSettings).find(v => v[0] === 'provider')?.[1];
|
|
154
|
-
// Save the settings.
|
|
155
|
-
const settings = {
|
|
156
|
-
_current: provider
|
|
157
|
-
};
|
|
158
|
-
settings[provider] = labSettings;
|
|
159
|
-
this.props.aiSettings.setLocalStorageItem(this._role, null, settings);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
// Initialize the settings from the saved ones.
|
|
163
|
-
this._provider = this.getCurrentProvider();
|
|
164
|
-
// Initialize the schema.
|
|
165
|
-
const schema = this._buildSchema();
|
|
166
|
-
// Initialize the current settings.
|
|
167
|
-
const isModified = this._updatedFormData(this.getSettingsFromLocalStorage());
|
|
168
|
-
this.state = {
|
|
169
|
-
schema,
|
|
170
|
-
instruction: null,
|
|
171
|
-
compatibilityError: null,
|
|
172
|
-
isModified: isModified
|
|
173
|
-
};
|
|
174
|
-
this._renderInstruction();
|
|
175
|
-
this._checkProviderCompatibility();
|
|
176
|
-
// Update the setting registry.
|
|
177
|
-
this.saveSettingsToRegistry();
|
|
178
|
-
this._secretsManager?.fieldVisibilityChanged.connect(this._fieldVisibilityChanged);
|
|
179
|
-
this._settings.changed.connect(this._settingsChanged);
|
|
180
|
-
}
|
|
181
|
-
componentDidMount() {
|
|
182
|
-
this.componentDidUpdate();
|
|
183
|
-
}
|
|
184
|
-
async componentDidUpdate() {
|
|
185
|
-
if (!this._secretsManager || !this._useSecretsManager) {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
// Attach the password inputs to the secrets manager.
|
|
189
|
-
await this._secretsManager.detachAll(Private.getToken(), SECRETS_NAMESPACE);
|
|
190
|
-
const inputs = this._formRef.current?.getElementsByTagName('input') || [];
|
|
191
|
-
for (let i = 0; i < inputs.length; i++) {
|
|
192
|
-
if (inputs[i].type.toLowerCase() === 'password') {
|
|
193
|
-
const label = inputs[i].getAttribute('label');
|
|
194
|
-
if (label) {
|
|
195
|
-
const id = getSecretId(this._provider, label);
|
|
196
|
-
this._secretsManager.attach(Private.getToken(), SECRETS_NAMESPACE, id, inputs[i], (value) => this._onPasswordUpdated(label, value));
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
componentWillUnmount() {
|
|
202
|
-
this._settings.changed.disconnect(this._settingsChanged);
|
|
203
|
-
this._secretsManager?.fieldVisibilityChanged.disconnect(this._fieldVisibilityChanged);
|
|
204
|
-
if (!this._secretsManager || !this._useSecretsManager) {
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
this._secretsManager.detachAll(Private.getToken(), SECRETS_NAMESPACE);
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Get the current provider from the local storage.
|
|
211
|
-
*/
|
|
212
|
-
getCurrentProvider() {
|
|
213
|
-
const settings = this.props.aiSettings.getLocalStorage(this._role);
|
|
214
|
-
return settings['_current'] ?? 'None';
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Save the current provider to the local storage.
|
|
218
|
-
*/
|
|
219
|
-
saveCurrentProvider() {
|
|
220
|
-
this.props.aiSettings.setLocalStorageItem(this._role, '_current', this._provider);
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* Get settings from local storage for the current provider provider.
|
|
224
|
-
*/
|
|
225
|
-
getSettingsFromLocalStorage() {
|
|
226
|
-
const settings = this.props.aiSettings.getLocalStorage(this._role);
|
|
227
|
-
return settings[this._provider] ?? { provider: this._provider };
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* Save settings in local storage for a given provider.
|
|
231
|
-
*/
|
|
232
|
-
saveSettingsToLocalStorage() {
|
|
233
|
-
const currentSettings = { ...this._currentSettings };
|
|
234
|
-
// Do not save secrets in local storage if using the secrets manager.
|
|
235
|
-
if (this._useSecretsManager) {
|
|
236
|
-
this._secretFields.forEach(field => delete currentSettings[field]);
|
|
237
|
-
}
|
|
238
|
-
this.props.aiSettings.setLocalStorageItem(this._role, this._provider, currentSettings);
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Save the settings to the setting registry.
|
|
242
|
-
*/
|
|
243
|
-
saveSettingsToRegistry() {
|
|
244
|
-
const sanitizedSettings = { ...this._currentSettings };
|
|
245
|
-
if (this._useSecretsManager) {
|
|
246
|
-
this._secretFields.forEach(field => {
|
|
247
|
-
sanitizedSettings[field] = SECRETS_REPLACEMENT;
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
this.props.aiSettings.saveSettingsToRegistry(this._role, {
|
|
251
|
-
provider: this._provider,
|
|
252
|
-
...sanitizedSettings
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Triggered when the settings has changed.
|
|
257
|
-
*/
|
|
258
|
-
_settingsChanged = (settings) => {
|
|
259
|
-
this._updateUseSecretsManager(this._settings.get('UseSecretsManager').composite ?? true);
|
|
260
|
-
};
|
|
261
|
-
/**
|
|
262
|
-
* Triggered when the secret fields visibility has changed.
|
|
263
|
-
*/
|
|
264
|
-
_fieldVisibilityChanged = (_, value) => {
|
|
265
|
-
if (this._useSecretsManager) {
|
|
266
|
-
this._updateSchema();
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
/**
|
|
270
|
-
* Update the settings whether the secrets manager is used or not.
|
|
271
|
-
*
|
|
272
|
-
* @param value - whether to use the secrets manager or not.
|
|
273
|
-
*/
|
|
274
|
-
_updateUseSecretsManager = (value) => {
|
|
275
|
-
// No-op if the value did not change or the secrets manager has not been provided.
|
|
276
|
-
if (value === this._useSecretsManager || this._secretsManager === null) {
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
// Update the secrets manager.
|
|
280
|
-
this._useSecretsManager = value;
|
|
281
|
-
if (!value) {
|
|
282
|
-
// Detach all the password inputs attached to the secrets manager, and save the
|
|
283
|
-
// current settings to the local storage to save the password.
|
|
284
|
-
this._secretsManager.detachAll(Private.getToken(), SECRETS_NAMESPACE);
|
|
285
|
-
}
|
|
286
|
-
else {
|
|
287
|
-
// Remove all the keys stored locally.
|
|
288
|
-
const settings = this.props.aiSettings.getLocalStorage(this._role);
|
|
289
|
-
Object.keys(settings).forEach(provider => {
|
|
290
|
-
Object.keys(settings[provider])
|
|
291
|
-
.filter(key => key.toLowerCase().includes('key'))
|
|
292
|
-
.forEach(key => {
|
|
293
|
-
delete settings[provider][key];
|
|
294
|
-
});
|
|
295
|
-
});
|
|
296
|
-
this.props.aiSettings.setLocalStorageItem(this._role, null, settings);
|
|
297
|
-
}
|
|
298
|
-
this._updateSchema();
|
|
299
|
-
this.saveSettingsToLocalStorage();
|
|
300
|
-
this.saveSettingsToRegistry();
|
|
301
|
-
};
|
|
302
|
-
/**
|
|
303
|
-
* Build the schema for a given provider.
|
|
304
|
-
*/
|
|
305
|
-
_buildSchema() {
|
|
306
|
-
const schema = JSONExt.deepCopy(baseSettings);
|
|
307
|
-
this._uiSchema = {};
|
|
308
|
-
const settingsSchema = this._providerRegistry.getSettingsSchema(this._provider);
|
|
309
|
-
this._secretFields = [];
|
|
310
|
-
this._defaultFormData = {};
|
|
311
|
-
if (settingsSchema) {
|
|
312
|
-
Object.entries(settingsSchema).forEach(([key, value]) => {
|
|
313
|
-
if (key.toLowerCase().includes('key')) {
|
|
314
|
-
this._secretFields.push(key);
|
|
315
|
-
// If the secrets manager is not used, show the secrets fields.
|
|
316
|
-
// If the secrets manager is used, check if the fields should be visible.
|
|
317
|
-
const showSecretFields = !this._useSecretsManager ||
|
|
318
|
-
(this._secretsManager?.secretFieldsVisibility ?? true);
|
|
319
|
-
if (!showSecretFields) {
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
this._uiSchema[key] = { 'ui:widget': 'password' };
|
|
323
|
-
}
|
|
324
|
-
schema.properties[key] = value;
|
|
325
|
-
if (value.default !== undefined) {
|
|
326
|
-
this._defaultFormData[key] = value.default;
|
|
327
|
-
}
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
return schema;
|
|
331
|
-
}
|
|
332
|
-
/**
|
|
333
|
-
* Update the schema state for the given provider, that trigger the re-rendering of
|
|
334
|
-
* the component.
|
|
335
|
-
*/
|
|
336
|
-
_updateSchema() {
|
|
337
|
-
const schema = this._buildSchema();
|
|
338
|
-
this.setState({ schema });
|
|
339
|
-
}
|
|
340
|
-
/**
|
|
341
|
-
* Render the markdown instructions for the current provider.
|
|
342
|
-
*/
|
|
343
|
-
async _renderInstruction() {
|
|
344
|
-
let instructions = this._providerRegistry.getInstructions(this._provider);
|
|
345
|
-
if (!this._rmRegistry || !instructions) {
|
|
346
|
-
this.setState({ instruction: null });
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
instructions = `---\n\n${instructions}\n\n---`;
|
|
350
|
-
const renderer = this._rmRegistry.createRenderer(MD_MIME_TYPE);
|
|
351
|
-
const model = this._rmRegistry.createModel({
|
|
352
|
-
data: { [MD_MIME_TYPE]: instructions }
|
|
353
|
-
});
|
|
354
|
-
await renderer.renderModel(model);
|
|
355
|
-
this.setState({ instruction: renderer.node });
|
|
356
|
-
}
|
|
357
|
-
/**
|
|
358
|
-
* Check for compatibility of the provider with the current environment.
|
|
359
|
-
* If the provider is not compatible, display an error message.
|
|
360
|
-
*/
|
|
361
|
-
async _checkProviderCompatibility() {
|
|
362
|
-
const compatibilityCheck = this._providerRegistry.getCompatibilityCheck(this._provider);
|
|
363
|
-
if (!compatibilityCheck) {
|
|
364
|
-
this.setState({ compatibilityError: null });
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
|
-
const error = await compatibilityCheck();
|
|
368
|
-
if (!error) {
|
|
369
|
-
this.setState({ compatibilityError: null });
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
const errorDiv = document.createElement('div');
|
|
373
|
-
errorDiv.className = ERROR_CLASS;
|
|
374
|
-
errorDiv.innerHTML = error;
|
|
375
|
-
this.setState({ compatibilityError: error });
|
|
376
|
-
}
|
|
377
|
-
/**
|
|
378
|
-
* Triggered when the provider has changed, to update the schema and values.
|
|
379
|
-
* Update the Jupyterlab settings accordingly.
|
|
380
|
-
*/
|
|
381
|
-
_onProviderChanged = (e) => {
|
|
382
|
-
const provider = e.formData.provider;
|
|
383
|
-
if (provider === this._currentSettings.provider) {
|
|
384
|
-
return;
|
|
385
|
-
}
|
|
386
|
-
this._provider = provider;
|
|
387
|
-
this.saveCurrentProvider();
|
|
388
|
-
this._updateSchema();
|
|
389
|
-
this._renderInstruction();
|
|
390
|
-
this._checkProviderCompatibility();
|
|
391
|
-
// Initialize the current settings.
|
|
392
|
-
const isModified = this._updatedFormData(this.getSettingsFromLocalStorage());
|
|
393
|
-
if (isModified !== this.state.isModified) {
|
|
394
|
-
this.setState({ isModified });
|
|
395
|
-
}
|
|
396
|
-
this.saveSettingsToRegistry();
|
|
397
|
-
};
|
|
398
|
-
/**
|
|
399
|
-
* Callback function called when the password input has been programmatically updated
|
|
400
|
-
* with the secret manager.
|
|
401
|
-
*/
|
|
402
|
-
_onPasswordUpdated = (fieldName, value) => {
|
|
403
|
-
this._currentSettings[fieldName] = value;
|
|
404
|
-
this.saveSettingsToRegistry();
|
|
405
|
-
};
|
|
406
|
-
/**
|
|
407
|
-
* Update the current settings with the new values from the form.
|
|
408
|
-
*
|
|
409
|
-
* @param data - The form data to update.
|
|
410
|
-
* @returns - Boolean whether the form is not the default one.
|
|
411
|
-
*/
|
|
412
|
-
_updatedFormData(data) {
|
|
413
|
-
let isModified = false;
|
|
414
|
-
Object.entries(data).forEach(([key, value]) => {
|
|
415
|
-
if (this._defaultFormData[key] !== undefined) {
|
|
416
|
-
if (value === undefined) {
|
|
417
|
-
const schemaProperty = this.state.schema.properties?.[key];
|
|
418
|
-
if (schemaProperty.type === 'string') {
|
|
419
|
-
data[key] = '';
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
if (value !== this._defaultFormData[key]) {
|
|
423
|
-
isModified = true;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
});
|
|
427
|
-
this._currentSettings = JSONExt.deepCopy(data);
|
|
428
|
-
return isModified;
|
|
429
|
-
}
|
|
430
|
-
/**
|
|
431
|
-
* Triggered when the form value has changed, to update the current settings and save
|
|
432
|
-
* it in local storage.
|
|
433
|
-
* Update the Jupyterlab settings accordingly.
|
|
434
|
-
*/
|
|
435
|
-
_onFormChanged = (e) => {
|
|
436
|
-
const { formData } = e;
|
|
437
|
-
const isModified = this._updatedFormData(formData);
|
|
438
|
-
this.saveSettingsToLocalStorage();
|
|
439
|
-
this.saveSettingsToRegistry();
|
|
440
|
-
if (isModified !== this.state.isModified) {
|
|
441
|
-
this.setState({ isModified });
|
|
442
|
-
}
|
|
443
|
-
};
|
|
444
|
-
/**
|
|
445
|
-
* Handler for the "Restore to defaults" button - clears all
|
|
446
|
-
* modified settings then calls `setFormData` to restore the
|
|
447
|
-
* values.
|
|
448
|
-
*/
|
|
449
|
-
_reset = async (event) => {
|
|
450
|
-
event.stopPropagation();
|
|
451
|
-
this._currentSettings = {
|
|
452
|
-
...this._currentSettings,
|
|
453
|
-
...this._defaultFormData
|
|
454
|
-
};
|
|
455
|
-
this.saveSettingsToLocalStorage();
|
|
456
|
-
this.saveSettingsToRegistry();
|
|
457
|
-
this.setState({ isModified: false });
|
|
458
|
-
};
|
|
459
|
-
render() {
|
|
460
|
-
return (React.createElement("div", { ref: this._formRef },
|
|
461
|
-
React.createElement(WrappedFormComponent, { formData: { provider: this._provider }, schema: this._providerSchema, onChange: this._onProviderChanged, idPrefix: `jp-SettingsEditor-${PLUGIN_IDS.providerRegistry}-${this._role}` }),
|
|
462
|
-
this.state.compatibilityError !== null && (React.createElement("div", { className: ERROR_CLASS },
|
|
463
|
-
React.createElement("i", { className: 'fas fa-exclamation-triangle' }),
|
|
464
|
-
React.createElement("span", null, this.state.compatibilityError))),
|
|
465
|
-
this.state.instruction !== null && (React.createElement("details", null,
|
|
466
|
-
React.createElement("summary", { className: INSTRUCTION_CLASS }, "Instructions"),
|
|
467
|
-
React.createElement("span", { ref: node => node && node.replaceChildren(this.state.instruction) }))),
|
|
468
|
-
React.createElement("div", { className: "jp-SettingsHeader" },
|
|
469
|
-
React.createElement("h3", { title: this._provider }, this._provider),
|
|
470
|
-
React.createElement("div", { className: "jp-SettingsHeader-buttonbar" }, this.state.isModified && (React.createElement(Button, { className: "jp-RestoreButton", onClick: this._reset }, "Restore to Defaults")))),
|
|
471
|
-
React.createElement(WrappedFormComponent, { formData: this._currentSettings, schema: this.state.schema, onChange: this._onFormChanged, uiSchema: this._uiSchema, idPrefix: `jp-SettingsEditor-${PLUGIN_IDS.providerRegistry}-${this._role}`, formContext: {
|
|
472
|
-
...this.props.formContext,
|
|
473
|
-
defaultFormData: this._defaultFormData
|
|
474
|
-
} })));
|
|
475
|
-
}
|
|
476
|
-
_role;
|
|
477
|
-
_providerRegistry;
|
|
478
|
-
_provider;
|
|
479
|
-
_providerSchema;
|
|
480
|
-
_useSecretsManager;
|
|
481
|
-
_rmRegistry;
|
|
482
|
-
_secretsManager;
|
|
483
|
-
_currentSettings = { provider: 'None' };
|
|
484
|
-
_uiSchema = {};
|
|
485
|
-
_settings;
|
|
486
|
-
_formRef = React.createRef();
|
|
487
|
-
_secretFields = [];
|
|
488
|
-
_defaultFormData = {};
|
|
489
|
-
}
|
|
490
|
-
var Private;
|
|
491
|
-
(function (Private) {
|
|
492
|
-
/**
|
|
493
|
-
* The token to use with the secrets manager.
|
|
494
|
-
*/
|
|
495
|
-
let secretsToken;
|
|
496
|
-
/**
|
|
497
|
-
* Set of the token.
|
|
498
|
-
*/
|
|
499
|
-
function setToken(value) {
|
|
500
|
-
secretsToken = value;
|
|
501
|
-
}
|
|
502
|
-
Private.setToken = setToken;
|
|
503
|
-
/**
|
|
504
|
-
* get the token.
|
|
505
|
-
*/
|
|
506
|
-
function getToken() {
|
|
507
|
-
return secretsToken;
|
|
508
|
-
}
|
|
509
|
-
Private.getToken = getToken;
|
|
510
|
-
})(Private || (Private = {}));
|
package/lib/settings/textarea.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
const TEXTAREA_CLASS = 'jp-AISettingsTextArea';
|
|
3
|
-
export const textArea = {
|
|
4
|
-
fieldRenderer: (props) => {
|
|
5
|
-
const settings = props.formContext.settings;
|
|
6
|
-
const schema = settings.schema.properties?.[props.name];
|
|
7
|
-
const [formData, setFormData] = useState(props.formData);
|
|
8
|
-
settings.changed.connect(() => {
|
|
9
|
-
setFormData(settings.get(props.name).composite);
|
|
10
|
-
});
|
|
11
|
-
const onChange = (event) => {
|
|
12
|
-
settings.set(props.name, event.target.value);
|
|
13
|
-
};
|
|
14
|
-
return (React.createElement(React.Fragment, null,
|
|
15
|
-
schema?.title && (React.createElement("h3", { className: "jp-FormGroup-fieldLabel jp-FormGroup-contentItem" }, schema.title)),
|
|
16
|
-
React.createElement("textarea", { className: TEXTAREA_CLASS, onChange: onChange }, formData)));
|
|
17
|
-
}
|
|
18
|
-
};
|
package/lib/settings/utils.d.ts
DELETED
package/lib/settings/utils.js
DELETED
package/lib/types/ai-model.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { CompletionHandler, IInlineCompletionContext } from '@jupyterlab/completer';
|
|
2
|
-
import { IterableReadableStream } from '@langchain/core/utils/stream';
|
|
3
|
-
/**
|
|
4
|
-
* The reduced AI chat model interface.
|
|
5
|
-
*/
|
|
6
|
-
export type AIChatModel = {
|
|
7
|
-
/**
|
|
8
|
-
* The stream function of the chat model.
|
|
9
|
-
*/
|
|
10
|
-
stream: (input: any, options?: any) => Promise<IterableReadableStream<any>>;
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* The reduced AI completer interface.
|
|
14
|
-
*/
|
|
15
|
-
export type AICompleter = {
|
|
16
|
-
/**
|
|
17
|
-
* The fetch function of the completer.
|
|
18
|
-
*/
|
|
19
|
-
fetch: (request: CompletionHandler.IRequest, context: IInlineCompletionContext) => Promise<any>;
|
|
20
|
-
/**
|
|
21
|
-
* The optional request completion function of the completer.
|
|
22
|
-
*/
|
|
23
|
-
requestCompletion?: () => void;
|
|
24
|
-
};
|
package/lib/types/ai-model.js
DELETED
package/schema/chat.json
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"title": "Chat Configuration",
|
|
3
|
-
"description": "Configuration for the chat panel",
|
|
4
|
-
"jupyter.lab.setting-icon": "jupyter-chat::chat",
|
|
5
|
-
"jupyter.lab.setting-icon-label": "Jupyter Chat",
|
|
6
|
-
"type": "object",
|
|
7
|
-
"properties": {
|
|
8
|
-
"sendWithShiftEnter": {
|
|
9
|
-
"description": "Whether to send a message via Shift-Enter instead of Enter.",
|
|
10
|
-
"type": "boolean",
|
|
11
|
-
"default": false,
|
|
12
|
-
"readOnly": false
|
|
13
|
-
},
|
|
14
|
-
"enableCodeToolbar": {
|
|
15
|
-
"description": "Whether to enable or not the code toolbar.",
|
|
16
|
-
"type": "boolean",
|
|
17
|
-
"default": true,
|
|
18
|
-
"readOnly": false
|
|
19
|
-
},
|
|
20
|
-
"personaName": {
|
|
21
|
-
"type": "string",
|
|
22
|
-
"title": "AI persona name",
|
|
23
|
-
"description": "The name of the AI persona",
|
|
24
|
-
"default": "Jupyternaut"
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
"additionalProperties": false
|
|
28
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"title": "AI providers",
|
|
3
|
-
"description": "Provider registry settings",
|
|
4
|
-
"jupyter.lab.setting-icon": "@jupyterlite/ai:jupyternaut-lite",
|
|
5
|
-
"jupyter.lab.setting-icon-label": "JupyterLite AI provider",
|
|
6
|
-
"type": "object",
|
|
7
|
-
"properties": {
|
|
8
|
-
"UseSecretsManager": {
|
|
9
|
-
"type": "boolean",
|
|
10
|
-
"title": "Use secrets manager",
|
|
11
|
-
"description": "Whether to use or not the secrets manager. If not, secrets will be stored in the browser (local storage)",
|
|
12
|
-
"default": true
|
|
13
|
-
},
|
|
14
|
-
"UniqueProvider": {
|
|
15
|
-
"type": "boolean",
|
|
16
|
-
"title": "Use the same provider for chat and completer",
|
|
17
|
-
"description": "Whether to use only one provider for the chat and the completer.\nThis will overwrite all the settings for the completer, and copy the ones from the chat.",
|
|
18
|
-
"default": true
|
|
19
|
-
},
|
|
20
|
-
"AIproviders": {
|
|
21
|
-
"type": "object",
|
|
22
|
-
"title": "AI providers",
|
|
23
|
-
"description": "The AI providers configuration",
|
|
24
|
-
"default": {},
|
|
25
|
-
"additionalProperties": true
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
"additionalProperties": false
|
|
29
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"title": "AI system prompts",
|
|
3
|
-
"description": "System prompts",
|
|
4
|
-
"jupyter.lab.setting-icon": "@jupyterlite/ai:jupyternaut-lite",
|
|
5
|
-
"jupyter.lab.setting-icon-label": "JupyterLite AI Chat",
|
|
6
|
-
"type": "object",
|
|
7
|
-
"properties": {
|
|
8
|
-
"chatSystemPrompt": {
|
|
9
|
-
"type": "string",
|
|
10
|
-
"title": "Chat message system prompt",
|
|
11
|
-
"description": "The system prompt for the chat messages",
|
|
12
|
-
"default": "You are Jupyternaut, a conversational assistant living in JupyterLab to help users.\nYou are not a language model, but rather an application built on a foundation model from $provider_name$.\nYou are talkative and you provide lots of specific details from the foundation model's context.\nYou may use Markdown to format your response.\nIf your response includes code, they must be enclosed in Markdown fenced code blocks (with triple backticks before and after).\nIf your response includes mathematical notation, they must be expressed in LaTeX markup and enclosed in LaTeX delimiters.\nAll dollar quantities (of USD) must be formatted in LaTeX, with the `$` symbol escaped by a single backslash `\\`.\n- Example prompt: `If I have \\\\$100 and spend \\\\$20, how much money do I have left?`\n- **Correct** response: `You have \\(\\$80\\) remaining.`\n- **Incorrect** response: `You have $80 remaining.`\nIf you do not know the answer to a question, answer truthfully by responding that you do not know.\nThe following is a friendly conversation between you and a human."
|
|
13
|
-
},
|
|
14
|
-
"completionSystemPrompt": {
|
|
15
|
-
"type": "string",
|
|
16
|
-
"title": "Completion system prompt",
|
|
17
|
-
"description": "The system prompt for the completion",
|
|
18
|
-
"default": "You are an application built to provide helpful code completion suggestions.\nYou should only produce code. Keep comments to minimum, use the programming language comment syntax. Produce clean code.\nThe code is written in JupyterLab, a data analysis and code development environment which can execute code extended with additional syntax for interactive features, such as magics.\nOnly give raw strings back, do not format the response using backticks.\nThe output should be a single string, and should only contain the code that will complete the give code passed as input, no explanation whatsoever. Do not include the prompt in the output, only the string that should be appended to the current input. Here is the code to complete:"
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
"additionalProperties": false
|
|
22
|
-
}
|