@jupyterlite/ai 0.4.0 → 0.6.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/chat-handler.d.ts +9 -1
- package/lib/chat-handler.js +37 -1
- package/lib/completion-provider.d.ts +8 -1
- package/lib/components/stop-button.d.ts +19 -0
- package/lib/components/stop-button.js +32 -0
- package/lib/{llm-models/anthropic-completer.d.ts → default-providers/Anthropic/completer.d.ts} +1 -1
- package/lib/{llm-models/anthropic-completer.js → default-providers/Anthropic/completer.js} +1 -1
- package/lib/{llm-models/chrome-completer.d.ts → default-providers/ChromeAI/completer.d.ts} +1 -1
- package/lib/{llm-models/chrome-completer.js → default-providers/ChromeAI/completer.js} +1 -1
- package/lib/default-providers/ChromeAI/instructions.d.ts +2 -0
- package/lib/default-providers/ChromeAI/instructions.js +24 -0
- package/lib/{llm-models/codestral-completer.d.ts → default-providers/MistralAI/completer.d.ts} +1 -1
- package/lib/{llm-models/codestral-completer.js → default-providers/MistralAI/completer.js} +1 -1
- package/lib/default-providers/MistralAI/instructions.d.ts +2 -0
- package/lib/default-providers/MistralAI/instructions.js +16 -0
- package/lib/{llm-models/openai-completer.d.ts → default-providers/OpenAI/completer.d.ts} +1 -1
- package/lib/{llm-models/openai-completer.js → default-providers/OpenAI/completer.js} +1 -1
- package/lib/default-providers/index.d.ts +2 -0
- package/lib/default-providers/index.js +60 -0
- package/lib/index.d.ts +3 -2
- package/lib/index.js +57 -36
- package/lib/provider.d.ts +13 -12
- package/lib/provider.js +43 -9
- package/lib/settings/index.d.ts +3 -0
- package/lib/settings/index.js +3 -0
- package/lib/settings/panel.d.ts +17 -0
- package/lib/settings/panel.js +92 -5
- package/lib/settings/settings-connector.d.ts +31 -0
- package/lib/settings/settings-connector.js +61 -0
- package/lib/settings/utils.d.ts +3 -0
- package/lib/settings/utils.js +5 -0
- package/lib/tokens.d.ts +16 -4
- package/package.json +14 -7
- package/schema/provider-registry.json +6 -0
- package/src/chat-handler.ts +43 -1
- package/src/completion-provider.ts +8 -1
- package/src/components/stop-button.tsx +56 -0
- package/src/{llm-models/anthropic-completer.ts → default-providers/Anthropic/completer.ts} +2 -2
- package/src/{llm-models/chrome-completer.ts → default-providers/ChromeAI/completer.ts} +3 -2
- package/src/default-providers/ChromeAI/instructions.ts +24 -0
- package/src/{llm-models/codestral-completer.ts → default-providers/MistralAI/completer.ts} +2 -2
- package/src/default-providers/MistralAI/instructions.ts +16 -0
- package/src/{llm-models/openai-completer.ts → default-providers/OpenAI/completer.ts} +2 -2
- package/src/default-providers/index.ts +71 -0
- package/src/index.ts +77 -49
- package/src/provider.ts +58 -15
- package/src/settings/index.ts +3 -0
- package/src/settings/panel.tsx +109 -5
- package/src/settings/settings-connector.ts +89 -0
- package/src/settings/utils.ts +6 -0
- package/src/tokens.ts +17 -4
- package/lib/llm-models/index.d.ts +0 -4
- package/lib/llm-models/index.js +0 -43
- package/lib/settings/instructions.d.ts +0 -2
- package/lib/settings/instructions.js +0 -44
- package/lib/settings/schemas/index.d.ts +0 -3
- package/lib/settings/schemas/index.js +0 -11
- package/lib/slash-commands.d.ts +0 -16
- package/lib/slash-commands.js +0 -25
- package/src/llm-models/index.ts +0 -50
- package/src/settings/instructions.ts +0 -48
- package/src/settings/schemas/index.ts +0 -15
- package/src/slash-commands.tsx +0 -55
- /package/lib/{llm-models/base-completer.d.ts → base-completer.d.ts} +0 -0
- /package/lib/{llm-models/base-completer.js → base-completer.js} +0 -0
- /package/lib/{settings/schemas/_generated/Anthropic.json → default-providers/Anthropic/settings-schema.json} +0 -0
- /package/lib/{settings/schemas/_generated/ChromeAI.json → default-providers/ChromeAI/settings-schema.json} +0 -0
- /package/lib/{settings/schemas/_generated/MistralAI.json → default-providers/MistralAI/settings-schema.json} +0 -0
- /package/lib/{settings/schemas/_generated/OpenAI.json → default-providers/OpenAI/settings-schema.json} +0 -0
- /package/lib/settings/{schemas/base.json → base.json} +0 -0
- /package/src/{llm-models/base-completer.ts → base-completer.ts} +0 -0
- /package/src/{llm-models/svg.d.ts → global.d.ts} +0 -0
package/src/settings/panel.tsx
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
ISettingConnector,
|
|
4
|
+
ISettingRegistry
|
|
5
|
+
} from '@jupyterlab/settingregistry';
|
|
3
6
|
import { FormComponent, IFormRenderer } from '@jupyterlab/ui-components';
|
|
7
|
+
import { ArrayExt } from '@lumino/algorithm';
|
|
4
8
|
import { JSONExt } from '@lumino/coreutils';
|
|
5
9
|
import { IChangeEvent } from '@rjsf/core';
|
|
6
10
|
import type { FieldProps } from '@rjsf/utils';
|
|
7
11
|
import validator from '@rjsf/validator-ajv8';
|
|
8
12
|
import { JSONSchema7 } from 'json-schema';
|
|
13
|
+
import { ISecretsManager } from 'jupyter-secrets-manager';
|
|
9
14
|
import React from 'react';
|
|
10
15
|
|
|
11
|
-
import
|
|
16
|
+
import { getSecretId, SECRETS_NAMESPACE, SettingConnector } from '.';
|
|
17
|
+
import baseSettings from './base.json';
|
|
12
18
|
import { IAIProviderRegistry, IDict } from '../tokens';
|
|
13
19
|
|
|
14
20
|
const MD_MIME_TYPE = 'text/markdown';
|
|
@@ -18,6 +24,8 @@ const INSTRUCTION_CLASS = 'jp-AISettingsInstructions';
|
|
|
18
24
|
export const aiSettingsRenderer = (options: {
|
|
19
25
|
providerRegistry: IAIProviderRegistry;
|
|
20
26
|
rmRegistry?: IRenderMimeRegistry;
|
|
27
|
+
secretsManager?: ISecretsManager;
|
|
28
|
+
settingConnector?: ISettingConnector;
|
|
21
29
|
}): IFormRenderer => {
|
|
22
30
|
return {
|
|
23
31
|
fieldRenderer: (props: FieldProps) => {
|
|
@@ -49,8 +57,13 @@ export class AiSettings extends React.Component<
|
|
|
49
57
|
}
|
|
50
58
|
this._providerRegistry = props.formContext.providerRegistry;
|
|
51
59
|
this._rmRegistry = props.formContext.rmRegistry ?? null;
|
|
60
|
+
this._secretsManager = props.formContext.secretsManager ?? null;
|
|
61
|
+
this._settingConnector = props.formContext.settingConnector ?? null;
|
|
52
62
|
this._settings = props.formContext.settings;
|
|
53
63
|
|
|
64
|
+
this._useSecretsManager =
|
|
65
|
+
(this._settings.get('UseSecretsManager').composite as boolean) ?? true;
|
|
66
|
+
|
|
54
67
|
// Initialize the providers schema.
|
|
55
68
|
const providerSchema = JSONExt.deepCopy(baseSettings) as any;
|
|
56
69
|
providerSchema.properties.provider = {
|
|
@@ -95,6 +108,47 @@ export class AiSettings extends React.Component<
|
|
|
95
108
|
this._settings
|
|
96
109
|
.set('AIprovider', this._currentSettings)
|
|
97
110
|
.catch(console.error);
|
|
111
|
+
|
|
112
|
+
this._settings.changed.connect(() => {
|
|
113
|
+
const useSecretsManager =
|
|
114
|
+
(this._settings.get('UseSecretsManager').composite as boolean) ?? true;
|
|
115
|
+
if (useSecretsManager !== this._useSecretsManager) {
|
|
116
|
+
this.updateUseSecretsManager(useSecretsManager);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async componentDidUpdate(): Promise<void> {
|
|
122
|
+
if (!this._secretsManager || !this._useSecretsManager) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// Attach the password inputs to the secrets manager only if they have changed.
|
|
126
|
+
const inputs = this._formRef.current?.getElementsByTagName('input') || [];
|
|
127
|
+
if (ArrayExt.shallowEqual(inputs, this._formInputs)) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
await this._secretsManager.detachAll(SECRETS_NAMESPACE);
|
|
132
|
+
this._formInputs = [...inputs];
|
|
133
|
+
this._unsavedFields = [];
|
|
134
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
135
|
+
if (inputs[i].type.toLowerCase() === 'password') {
|
|
136
|
+
const label = inputs[i].getAttribute('label');
|
|
137
|
+
if (label) {
|
|
138
|
+
const id = getSecretId(this._provider, label);
|
|
139
|
+
this._secretsManager.attach(
|
|
140
|
+
SECRETS_NAMESPACE,
|
|
141
|
+
id,
|
|
142
|
+
inputs[i],
|
|
143
|
+
(value: string) => this._onPasswordUpdated(label, value)
|
|
144
|
+
);
|
|
145
|
+
this._unsavedFields.push(label);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (this._settingConnector instanceof SettingConnector) {
|
|
150
|
+
this._settingConnector.doNotSave = this._unsavedFields;
|
|
151
|
+
}
|
|
98
152
|
}
|
|
99
153
|
|
|
100
154
|
/**
|
|
@@ -126,11 +180,44 @@ export class AiSettings extends React.Component<
|
|
|
126
180
|
* Save settings in local storage for a given provider.
|
|
127
181
|
*/
|
|
128
182
|
saveSettings(value: IDict<any>) {
|
|
183
|
+
const currentSettings = { ...value };
|
|
129
184
|
const settings = JSON.parse(localStorage.getItem(STORAGE_NAME) ?? '{}');
|
|
130
|
-
|
|
185
|
+
this._unsavedFields.forEach(field => delete currentSettings[field]);
|
|
186
|
+
settings[this._provider] = currentSettings;
|
|
131
187
|
localStorage.setItem(STORAGE_NAME, JSON.stringify(settings));
|
|
132
188
|
}
|
|
133
189
|
|
|
190
|
+
private updateUseSecretsManager = (value: boolean) => {
|
|
191
|
+
this._useSecretsManager = value;
|
|
192
|
+
if (!value) {
|
|
193
|
+
// Detach all the password inputs attached to the secrets manager, and save the
|
|
194
|
+
// current settings to the local storage to save the password.
|
|
195
|
+
this._secretsManager?.detachAll(SECRETS_NAMESPACE);
|
|
196
|
+
this._formInputs = [];
|
|
197
|
+
this._unsavedFields = [];
|
|
198
|
+
if (this._settingConnector instanceof SettingConnector) {
|
|
199
|
+
this._settingConnector.doNotSave = [];
|
|
200
|
+
}
|
|
201
|
+
this.saveSettings(this._currentSettings);
|
|
202
|
+
} else {
|
|
203
|
+
// Remove all the keys stored locally and attach the password inputs to the
|
|
204
|
+
// secrets manager.
|
|
205
|
+
const settings = JSON.parse(localStorage.getItem(STORAGE_NAME) || '{}');
|
|
206
|
+
Object.keys(settings).forEach(provider => {
|
|
207
|
+
Object.keys(settings[provider])
|
|
208
|
+
.filter(key => key.toLowerCase().includes('key'))
|
|
209
|
+
.forEach(key => {
|
|
210
|
+
delete settings[provider][key];
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
localStorage.setItem(STORAGE_NAME, JSON.stringify(settings));
|
|
214
|
+
this.componentDidUpdate();
|
|
215
|
+
}
|
|
216
|
+
this._settings
|
|
217
|
+
.set('AIprovider', { provider: this._provider, ...this._currentSettings })
|
|
218
|
+
.catch(console.error);
|
|
219
|
+
};
|
|
220
|
+
|
|
134
221
|
/**
|
|
135
222
|
* Update the UI schema of the form.
|
|
136
223
|
* Currently use to hide API keys.
|
|
@@ -206,6 +293,17 @@ export class AiSettings extends React.Component<
|
|
|
206
293
|
.catch(console.error);
|
|
207
294
|
};
|
|
208
295
|
|
|
296
|
+
/**
|
|
297
|
+
* Callback function called when the password input has been programmatically updated
|
|
298
|
+
* with the secret manager.
|
|
299
|
+
*/
|
|
300
|
+
private _onPasswordUpdated = (fieldName: string, value: string) => {
|
|
301
|
+
this._currentSettings[fieldName] = value;
|
|
302
|
+
this._settings
|
|
303
|
+
.set('AIprovider', { provider: this._provider, ...this._currentSettings })
|
|
304
|
+
.catch(console.error);
|
|
305
|
+
};
|
|
306
|
+
|
|
209
307
|
/**
|
|
210
308
|
* Triggered when the form value has changed, to update the current settings and save
|
|
211
309
|
* it in local storage.
|
|
@@ -221,7 +319,7 @@ export class AiSettings extends React.Component<
|
|
|
221
319
|
|
|
222
320
|
render(): JSX.Element {
|
|
223
321
|
return (
|
|
224
|
-
|
|
322
|
+
<div ref={this._formRef}>
|
|
225
323
|
<WrappedFormComponent
|
|
226
324
|
formData={{ provider: this._provider }}
|
|
227
325
|
schema={this._providerSchema}
|
|
@@ -243,15 +341,21 @@ export class AiSettings extends React.Component<
|
|
|
243
341
|
onChange={this._onFormChange}
|
|
244
342
|
uiSchema={this._uiSchema}
|
|
245
343
|
/>
|
|
246
|
-
|
|
344
|
+
</div>
|
|
247
345
|
);
|
|
248
346
|
}
|
|
249
347
|
|
|
250
348
|
private _providerRegistry: IAIProviderRegistry;
|
|
251
349
|
private _provider: string;
|
|
252
350
|
private _providerSchema: JSONSchema7;
|
|
351
|
+
private _useSecretsManager: boolean;
|
|
253
352
|
private _rmRegistry: IRenderMimeRegistry | null;
|
|
353
|
+
private _secretsManager: ISecretsManager | null;
|
|
354
|
+
private _settingConnector: ISettingConnector | null;
|
|
254
355
|
private _currentSettings: IDict<any> = { provider: 'None' };
|
|
255
356
|
private _uiSchema: IDict<any> = {};
|
|
256
357
|
private _settings: ISettingRegistry.ISettings;
|
|
358
|
+
private _formRef = React.createRef<HTMLDivElement>();
|
|
359
|
+
private _unsavedFields: string[] = [];
|
|
360
|
+
private _formInputs: HTMLInputElement[] = [];
|
|
257
361
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { PageConfig } from '@jupyterlab/coreutils';
|
|
2
|
+
import {
|
|
3
|
+
ISettingConnector,
|
|
4
|
+
ISettingRegistry
|
|
5
|
+
} from '@jupyterlab/settingregistry';
|
|
6
|
+
import { DataConnector, IDataConnector } from '@jupyterlab/statedb';
|
|
7
|
+
import { Throttler } from '@lumino/polling';
|
|
8
|
+
import * as json5 from 'json5';
|
|
9
|
+
|
|
10
|
+
import { SECRETS_REPLACEMENT } from '.';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A data connector for fetching settings.
|
|
14
|
+
*
|
|
15
|
+
* #### Notes
|
|
16
|
+
* This connector adds a query parameter to the base services setting manager.
|
|
17
|
+
*/
|
|
18
|
+
export class SettingConnector
|
|
19
|
+
extends DataConnector<ISettingRegistry.IPlugin, string>
|
|
20
|
+
implements ISettingConnector
|
|
21
|
+
{
|
|
22
|
+
constructor(connector: IDataConnector<ISettingRegistry.IPlugin, string>) {
|
|
23
|
+
super();
|
|
24
|
+
this._connector = connector;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
set doNotSave(fields: string[]) {
|
|
28
|
+
this._doNotSave = [...fields];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Fetch settings for a plugin.
|
|
33
|
+
* @param id - The plugin ID
|
|
34
|
+
*
|
|
35
|
+
* #### Notes
|
|
36
|
+
* The REST API requests are throttled at one request per plugin per 100ms.
|
|
37
|
+
*/
|
|
38
|
+
fetch(id: string): Promise<ISettingRegistry.IPlugin | undefined> {
|
|
39
|
+
const throttlers = this._throttlers;
|
|
40
|
+
if (!(id in throttlers)) {
|
|
41
|
+
throttlers[id] = new Throttler(() => this._connector.fetch(id), 100);
|
|
42
|
+
}
|
|
43
|
+
return throttlers[id].invoke();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async list(query: 'ids'): Promise<{ ids: string[] }>;
|
|
47
|
+
async list(
|
|
48
|
+
query: 'active' | 'all'
|
|
49
|
+
): Promise<{ ids: string[]; values: ISettingRegistry.IPlugin[] }>;
|
|
50
|
+
async list(
|
|
51
|
+
query: 'active' | 'all' | 'ids' = 'all'
|
|
52
|
+
): Promise<{ ids: string[]; values?: ISettingRegistry.IPlugin[] }> {
|
|
53
|
+
const { isDisabled } = PageConfig.Extension;
|
|
54
|
+
const { ids, values } = await this._connector.list(
|
|
55
|
+
query === 'ids' ? 'ids' : undefined
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
if (query === 'all') {
|
|
59
|
+
return { ids, values };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (query === 'ids') {
|
|
63
|
+
return { ids };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
ids: ids.filter(id => !isDisabled(id)),
|
|
68
|
+
values: values.filter(({ id }) => !isDisabled(id))
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async save(id: string, raw: string): Promise<void> {
|
|
73
|
+
const settings = json5.parse(raw);
|
|
74
|
+
this._doNotSave.forEach(field => {
|
|
75
|
+
if (
|
|
76
|
+
settings['AIprovider'] !== undefined &&
|
|
77
|
+
settings['AIprovider'][field] !== undefined &&
|
|
78
|
+
settings['AIprovider'][field] !== ''
|
|
79
|
+
) {
|
|
80
|
+
settings['AIprovider'][field] = SECRETS_REPLACEMENT;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
await this._connector.save(id, json5.stringify(settings, null, 2));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private _connector: IDataConnector<ISettingRegistry.IPlugin, string>;
|
|
87
|
+
private _doNotSave: string[] = [];
|
|
88
|
+
private _throttlers: { [key: string]: Throttler } = Object.create(null);
|
|
89
|
+
}
|
package/src/tokens.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { ReadonlyPartialJSONObject, Token } from '@lumino/coreutils';
|
|
|
3
3
|
import { ISignal } from '@lumino/signaling';
|
|
4
4
|
import { JSONSchema7 } from 'json-schema';
|
|
5
5
|
|
|
6
|
-
import { IBaseCompleter } from './
|
|
6
|
+
import { IBaseCompleter } from './base-completer';
|
|
7
7
|
|
|
8
8
|
export interface IDict<T = any> {
|
|
9
9
|
[key: string]: T;
|
|
@@ -85,10 +85,9 @@ export interface IAIProviderRegistry {
|
|
|
85
85
|
* Set the providers (chat model and completer).
|
|
86
86
|
* Creates the providers if the name has changed, otherwise only updates their config.
|
|
87
87
|
*
|
|
88
|
-
* @param
|
|
89
|
-
* @param settings - the settings for the models.
|
|
88
|
+
* @param options - an object with the name and the settings of the provider to use.
|
|
90
89
|
*/
|
|
91
|
-
setProvider(
|
|
90
|
+
setProvider(options: ISetProviderOptions): void;
|
|
92
91
|
/**
|
|
93
92
|
* A signal emitting when the provider or its settings has changed.
|
|
94
93
|
*/
|
|
@@ -103,6 +102,20 @@ export interface IAIProviderRegistry {
|
|
|
103
102
|
readonly completerError: string;
|
|
104
103
|
}
|
|
105
104
|
|
|
105
|
+
/**
|
|
106
|
+
* The set provider options.
|
|
107
|
+
*/
|
|
108
|
+
export interface ISetProviderOptions {
|
|
109
|
+
/**
|
|
110
|
+
* The name of the provider.
|
|
111
|
+
*/
|
|
112
|
+
name: string;
|
|
113
|
+
/**
|
|
114
|
+
* The settings of the provider.
|
|
115
|
+
*/
|
|
116
|
+
settings: ReadonlyPartialJSONObject;
|
|
117
|
+
}
|
|
118
|
+
|
|
106
119
|
/**
|
|
107
120
|
* The provider registry token.
|
|
108
121
|
*/
|
package/lib/llm-models/index.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { ChatAnthropic } from '@langchain/anthropic';
|
|
2
|
-
import { ChromeAI } from '@langchain/community/experimental/llms/chrome_ai';
|
|
3
|
-
import { ChatMistralAI } from '@langchain/mistralai';
|
|
4
|
-
import { ChatOpenAI } from '@langchain/openai';
|
|
5
|
-
import { AnthropicCompleter } from './anthropic-completer';
|
|
6
|
-
import { CodestralCompleter } from './codestral-completer';
|
|
7
|
-
import { ChromeCompleter } from './chrome-completer';
|
|
8
|
-
import { OpenAICompleter } from './openai-completer';
|
|
9
|
-
import { instructions } from '../settings/instructions';
|
|
10
|
-
import { ProviderSettings } from '../settings/schemas';
|
|
11
|
-
export * from './base-completer';
|
|
12
|
-
const AIProviders = [
|
|
13
|
-
{
|
|
14
|
-
name: 'Anthropic',
|
|
15
|
-
chatModel: ChatAnthropic,
|
|
16
|
-
completer: AnthropicCompleter,
|
|
17
|
-
settingsSchema: ProviderSettings.Anthropic,
|
|
18
|
-
errorMessage: (error) => error.error.error.message
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
name: 'ChromeAI',
|
|
22
|
-
// TODO: fix
|
|
23
|
-
// @ts-expect-error: missing properties
|
|
24
|
-
chatModel: ChromeAI,
|
|
25
|
-
completer: ChromeCompleter,
|
|
26
|
-
instructions: instructions.ChromeAI,
|
|
27
|
-
settingsSchema: ProviderSettings.ChromeAI
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: 'MistralAI',
|
|
31
|
-
chatModel: ChatMistralAI,
|
|
32
|
-
completer: CodestralCompleter,
|
|
33
|
-
instructions: instructions.MistralAI,
|
|
34
|
-
settingsSchema: ProviderSettings.MistralAI
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
name: 'OpenAI',
|
|
38
|
-
chatModel: ChatOpenAI,
|
|
39
|
-
completer: OpenAICompleter,
|
|
40
|
-
settingsSchema: ProviderSettings.OpenAI
|
|
41
|
-
}
|
|
42
|
-
];
|
|
43
|
-
export { AIProviders };
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
const chromeAiInstructions = `
|
|
2
|
-
<i class="fas fa-exclamation-triangle"></i> Support for ChromeAI is still experimental and only available in Google Chrome.
|
|
3
|
-
|
|
4
|
-
You can test ChromeAI is enabled in your browser by going to the following URL: https://chromeai.org/
|
|
5
|
-
|
|
6
|
-
Enable the proper flags in Google Chrome.
|
|
7
|
-
|
|
8
|
-
- chrome://flags/#prompt-api-for-gemini-nano
|
|
9
|
-
- Select: \`Enabled\`
|
|
10
|
-
- chrome://flags/#optimization-guide-on-device-model
|
|
11
|
-
- Select: \`Enabled BypassPrefRequirement\`
|
|
12
|
-
- chrome://components
|
|
13
|
-
- Click \`Check for Update\` on Optimization Guide On Device Model to download the model
|
|
14
|
-
- [Optional] chrome://flags/#text-safety-classifier
|
|
15
|
-
|
|
16
|
-
<img src="https://github.com/user-attachments/assets/d48f46cc-52ee-4ce5-9eaf-c763cdbee04c" alt="A screenshot showing how to enable the ChromeAI flag in Google Chrome" width="500px">
|
|
17
|
-
|
|
18
|
-
Then restart Chrome for these changes to take effect.
|
|
19
|
-
|
|
20
|
-
<i class="fas fa-exclamation-triangle"></i> On first use, Chrome will download the on-device model, which can be as large as 22GB (according to their docs and at the time of writing).
|
|
21
|
-
During the download, ChromeAI may not be available via the extension.
|
|
22
|
-
|
|
23
|
-
<i class="fa fa-info-circle" aria-hidden="true"></i> For more information about Chrome Built-in AI: https://developer.chrome.com/docs/ai/get-started
|
|
24
|
-
`;
|
|
25
|
-
const mistralAIInstructions = `
|
|
26
|
-
<i class="fas fa-exclamation-triangle"></i> This extension is still very much experimental. It is not an official MistralAI extension.
|
|
27
|
-
|
|
28
|
-
1. Go to https://console.mistral.ai/api-keys/ and create an API key.
|
|
29
|
-
|
|
30
|
-
<img src="https://raw.githubusercontent.com/jupyterlite/ai/refs/heads/main/img/1-api-key.png" alt="Screenshot showing how to create an API key" width="500px">
|
|
31
|
-
|
|
32
|
-
2. Open the JupyterLab settings and go to the **Ai providers** section to select the \`MistralAI\`
|
|
33
|
-
provider and the API key (required).
|
|
34
|
-
|
|
35
|
-
<img src="https://raw.githubusercontent.com/jupyterlite/ai/refs/heads/main/img/2-jupyterlab-settings.png" alt="Screenshot showing how to add the API key to the settings" width="500px">
|
|
36
|
-
|
|
37
|
-
3. Open the chat, or use the inline completer
|
|
38
|
-
|
|
39
|
-
<img src="https://raw.githubusercontent.com/jupyterlite/ai/refs/heads/main/img/3-usage.png" alt="Screenshot showing how to use the chat" width="500px">
|
|
40
|
-
`;
|
|
41
|
-
export const instructions = {
|
|
42
|
-
ChromeAI: chromeAiInstructions,
|
|
43
|
-
MistralAI: mistralAIInstructions
|
|
44
|
-
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import ChromeAI from './_generated/ChromeAI.json';
|
|
2
|
-
import MistralAI from './_generated/MistralAI.json';
|
|
3
|
-
import Anthropic from './_generated/Anthropic.json';
|
|
4
|
-
import OpenAI from './_generated/OpenAI.json';
|
|
5
|
-
const ProviderSettings = {
|
|
6
|
-
ChromeAI,
|
|
7
|
-
MistralAI,
|
|
8
|
-
Anthropic,
|
|
9
|
-
OpenAI
|
|
10
|
-
};
|
|
11
|
-
export { ProviderSettings };
|
package/lib/slash-commands.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TODO: reuse from Jupyter AI instead of copying?
|
|
3
|
-
* https://github.com/jupyterlab/jupyter-ai/blob/main/packages/jupyter-ai/src/slash-autocompletion.tsx
|
|
4
|
-
*/
|
|
5
|
-
/// <reference types="react-addons-linked-state-mixin" />
|
|
6
|
-
import { AutocompleteCommand } from '@jupyter/chat';
|
|
7
|
-
import React from 'react';
|
|
8
|
-
type SlashCommandOption = AutocompleteCommand & {
|
|
9
|
-
id: string;
|
|
10
|
-
description: string;
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* Renders an option shown in the slash command autocomplete.
|
|
14
|
-
*/
|
|
15
|
-
export declare function renderSlashCommandOption(optionProps: React.HTMLAttributes<HTMLLIElement>, option: SlashCommandOption): JSX.Element;
|
|
16
|
-
export {};
|
package/lib/slash-commands.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TODO: reuse from Jupyter AI instead of copying?
|
|
3
|
-
* https://github.com/jupyterlab/jupyter-ai/blob/main/packages/jupyter-ai/src/slash-autocompletion.tsx
|
|
4
|
-
*/
|
|
5
|
-
import { Box, Typography } from '@mui/material';
|
|
6
|
-
import HideSource from '@mui/icons-material/HideSource';
|
|
7
|
-
import React from 'react';
|
|
8
|
-
const DEFAULT_SLASH_COMMAND_ICONS = {
|
|
9
|
-
clear: React.createElement(HideSource, null)
|
|
10
|
-
};
|
|
11
|
-
/**
|
|
12
|
-
* Renders an option shown in the slash command autocomplete.
|
|
13
|
-
*/
|
|
14
|
-
export function renderSlashCommandOption(optionProps, option) {
|
|
15
|
-
const icon = option.id in DEFAULT_SLASH_COMMAND_ICONS
|
|
16
|
-
? DEFAULT_SLASH_COMMAND_ICONS[option.id]
|
|
17
|
-
: DEFAULT_SLASH_COMMAND_ICONS.unknown;
|
|
18
|
-
return (React.createElement("li", { ...optionProps },
|
|
19
|
-
React.createElement(Box, { sx: { lineHeight: 0, marginRight: 4, opacity: 0.618 } }, icon),
|
|
20
|
-
React.createElement(Box, { sx: { flexGrow: 1 } },
|
|
21
|
-
React.createElement(Typography, { component: "span", sx: {
|
|
22
|
-
fontSize: 'var(--jp-ui-font-size1)'
|
|
23
|
-
} }, option.label),
|
|
24
|
-
React.createElement(Typography, { component: "span", sx: { opacity: 0.618, fontSize: 'var(--jp-ui-font-size0)' } }, ' — ' + option.description))));
|
|
25
|
-
}
|
package/src/llm-models/index.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { ChatAnthropic } from '@langchain/anthropic';
|
|
2
|
-
import { ChromeAI } from '@langchain/community/experimental/llms/chrome_ai';
|
|
3
|
-
import { ChatMistralAI } from '@langchain/mistralai';
|
|
4
|
-
import { ChatOpenAI } from '@langchain/openai';
|
|
5
|
-
|
|
6
|
-
import { AnthropicCompleter } from './anthropic-completer';
|
|
7
|
-
import { CodestralCompleter } from './codestral-completer';
|
|
8
|
-
import { ChromeCompleter } from './chrome-completer';
|
|
9
|
-
import { OpenAICompleter } from './openai-completer';
|
|
10
|
-
|
|
11
|
-
import { instructions } from '../settings/instructions';
|
|
12
|
-
import { ProviderSettings } from '../settings/schemas';
|
|
13
|
-
|
|
14
|
-
import { IAIProvider } from '../tokens';
|
|
15
|
-
|
|
16
|
-
export * from './base-completer';
|
|
17
|
-
|
|
18
|
-
const AIProviders: IAIProvider[] = [
|
|
19
|
-
{
|
|
20
|
-
name: 'Anthropic',
|
|
21
|
-
chatModel: ChatAnthropic,
|
|
22
|
-
completer: AnthropicCompleter,
|
|
23
|
-
settingsSchema: ProviderSettings.Anthropic,
|
|
24
|
-
errorMessage: (error: any) => error.error.error.message
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
name: 'ChromeAI',
|
|
28
|
-
// TODO: fix
|
|
29
|
-
// @ts-expect-error: missing properties
|
|
30
|
-
chatModel: ChromeAI,
|
|
31
|
-
completer: ChromeCompleter,
|
|
32
|
-
instructions: instructions.ChromeAI,
|
|
33
|
-
settingsSchema: ProviderSettings.ChromeAI
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
name: 'MistralAI',
|
|
37
|
-
chatModel: ChatMistralAI,
|
|
38
|
-
completer: CodestralCompleter,
|
|
39
|
-
instructions: instructions.MistralAI,
|
|
40
|
-
settingsSchema: ProviderSettings.MistralAI
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
name: 'OpenAI',
|
|
44
|
-
chatModel: ChatOpenAI,
|
|
45
|
-
completer: OpenAICompleter,
|
|
46
|
-
settingsSchema: ProviderSettings.OpenAI
|
|
47
|
-
}
|
|
48
|
-
];
|
|
49
|
-
|
|
50
|
-
export { AIProviders };
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { IDict } from '../tokens';
|
|
2
|
-
|
|
3
|
-
const chromeAiInstructions = `
|
|
4
|
-
<i class="fas fa-exclamation-triangle"></i> Support for ChromeAI is still experimental and only available in Google Chrome.
|
|
5
|
-
|
|
6
|
-
You can test ChromeAI is enabled in your browser by going to the following URL: https://chromeai.org/
|
|
7
|
-
|
|
8
|
-
Enable the proper flags in Google Chrome.
|
|
9
|
-
|
|
10
|
-
- chrome://flags/#prompt-api-for-gemini-nano
|
|
11
|
-
- Select: \`Enabled\`
|
|
12
|
-
- chrome://flags/#optimization-guide-on-device-model
|
|
13
|
-
- Select: \`Enabled BypassPrefRequirement\`
|
|
14
|
-
- chrome://components
|
|
15
|
-
- Click \`Check for Update\` on Optimization Guide On Device Model to download the model
|
|
16
|
-
- [Optional] chrome://flags/#text-safety-classifier
|
|
17
|
-
|
|
18
|
-
<img src="https://github.com/user-attachments/assets/d48f46cc-52ee-4ce5-9eaf-c763cdbee04c" alt="A screenshot showing how to enable the ChromeAI flag in Google Chrome" width="500px">
|
|
19
|
-
|
|
20
|
-
Then restart Chrome for these changes to take effect.
|
|
21
|
-
|
|
22
|
-
<i class="fas fa-exclamation-triangle"></i> On first use, Chrome will download the on-device model, which can be as large as 22GB (according to their docs and at the time of writing).
|
|
23
|
-
During the download, ChromeAI may not be available via the extension.
|
|
24
|
-
|
|
25
|
-
<i class="fa fa-info-circle" aria-hidden="true"></i> For more information about Chrome Built-in AI: https://developer.chrome.com/docs/ai/get-started
|
|
26
|
-
`;
|
|
27
|
-
|
|
28
|
-
const mistralAIInstructions = `
|
|
29
|
-
<i class="fas fa-exclamation-triangle"></i> This extension is still very much experimental. It is not an official MistralAI extension.
|
|
30
|
-
|
|
31
|
-
1. Go to https://console.mistral.ai/api-keys/ and create an API key.
|
|
32
|
-
|
|
33
|
-
<img src="https://raw.githubusercontent.com/jupyterlite/ai/refs/heads/main/img/1-api-key.png" alt="Screenshot showing how to create an API key" width="500px">
|
|
34
|
-
|
|
35
|
-
2. Open the JupyterLab settings and go to the **Ai providers** section to select the \`MistralAI\`
|
|
36
|
-
provider and the API key (required).
|
|
37
|
-
|
|
38
|
-
<img src="https://raw.githubusercontent.com/jupyterlite/ai/refs/heads/main/img/2-jupyterlab-settings.png" alt="Screenshot showing how to add the API key to the settings" width="500px">
|
|
39
|
-
|
|
40
|
-
3. Open the chat, or use the inline completer
|
|
41
|
-
|
|
42
|
-
<img src="https://raw.githubusercontent.com/jupyterlite/ai/refs/heads/main/img/3-usage.png" alt="Screenshot showing how to use the chat" width="500px">
|
|
43
|
-
`;
|
|
44
|
-
|
|
45
|
-
export const instructions: IDict = {
|
|
46
|
-
ChromeAI: chromeAiInstructions,
|
|
47
|
-
MistralAI: mistralAIInstructions
|
|
48
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { IDict } from '../../tokens';
|
|
2
|
-
|
|
3
|
-
import ChromeAI from './_generated/ChromeAI.json';
|
|
4
|
-
import MistralAI from './_generated/MistralAI.json';
|
|
5
|
-
import Anthropic from './_generated/Anthropic.json';
|
|
6
|
-
import OpenAI from './_generated/OpenAI.json';
|
|
7
|
-
|
|
8
|
-
const ProviderSettings: IDict<any> = {
|
|
9
|
-
ChromeAI,
|
|
10
|
-
MistralAI,
|
|
11
|
-
Anthropic,
|
|
12
|
-
OpenAI
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export { ProviderSettings };
|
package/src/slash-commands.tsx
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TODO: reuse from Jupyter AI instead of copying?
|
|
3
|
-
* https://github.com/jupyterlab/jupyter-ai/blob/main/packages/jupyter-ai/src/slash-autocompletion.tsx
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Box, Typography } from '@mui/material';
|
|
7
|
-
import { AutocompleteCommand } from '@jupyter/chat';
|
|
8
|
-
|
|
9
|
-
import HideSource from '@mui/icons-material/HideSource';
|
|
10
|
-
|
|
11
|
-
import React from 'react';
|
|
12
|
-
|
|
13
|
-
const DEFAULT_SLASH_COMMAND_ICONS: Record<string, JSX.Element> = {
|
|
14
|
-
clear: <HideSource />
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
type SlashCommandOption = AutocompleteCommand & {
|
|
18
|
-
id: string;
|
|
19
|
-
description: string;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Renders an option shown in the slash command autocomplete.
|
|
24
|
-
*/
|
|
25
|
-
export function renderSlashCommandOption(
|
|
26
|
-
optionProps: React.HTMLAttributes<HTMLLIElement>,
|
|
27
|
-
option: SlashCommandOption
|
|
28
|
-
): JSX.Element {
|
|
29
|
-
const icon =
|
|
30
|
-
option.id in DEFAULT_SLASH_COMMAND_ICONS
|
|
31
|
-
? DEFAULT_SLASH_COMMAND_ICONS[option.id]
|
|
32
|
-
: DEFAULT_SLASH_COMMAND_ICONS.unknown;
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<li {...optionProps}>
|
|
36
|
-
<Box sx={{ lineHeight: 0, marginRight: 4, opacity: 0.618 }}>{icon}</Box>
|
|
37
|
-
<Box sx={{ flexGrow: 1 }}>
|
|
38
|
-
<Typography
|
|
39
|
-
component="span"
|
|
40
|
-
sx={{
|
|
41
|
-
fontSize: 'var(--jp-ui-font-size1)'
|
|
42
|
-
}}
|
|
43
|
-
>
|
|
44
|
-
{option.label}
|
|
45
|
-
</Typography>
|
|
46
|
-
<Typography
|
|
47
|
-
component="span"
|
|
48
|
-
sx={{ opacity: 0.618, fontSize: 'var(--jp-ui-font-size0)' }}
|
|
49
|
-
>
|
|
50
|
-
{' — ' + option.description}
|
|
51
|
-
</Typography>
|
|
52
|
-
</Box>
|
|
53
|
-
</li>
|
|
54
|
-
);
|
|
55
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|