@jupyterlite/ai 0.6.0 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jupyterlite/ai",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "AI code completions and chat for JupyterLite",
5
5
  "keywords": [
6
6
  "jupyter",
@@ -57,13 +57,14 @@
57
57
  },
58
58
  "dependencies": {
59
59
  "@jupyter/chat": "^0.9.0",
60
- "@jupyterlab/application": "^4.4.0-alpha.0",
61
- "@jupyterlab/apputils": "^4.5.0-alpha.0",
62
- "@jupyterlab/completer": "^4.4.0-alpha.0",
63
- "@jupyterlab/notebook": "^4.4.0-alpha.0",
64
- "@jupyterlab/rendermime": "^4.4.0-alpha.0",
65
- "@jupyterlab/settingregistry": "^4.4.0-beta.1",
66
- "@jupyterlab/ui-components": "^4.4.0-alpha.0",
60
+ "@jupyterlab/application": "^4.4.0",
61
+ "@jupyterlab/apputils": "^4.5.0",
62
+ "@jupyterlab/completer": "^4.4.0",
63
+ "@jupyterlab/coreutils": "^6.4.0",
64
+ "@jupyterlab/notebook": "^4.4.0",
65
+ "@jupyterlab/rendermime": "^4.4.0",
66
+ "@jupyterlab/settingregistry": "^4.4.0",
67
+ "@jupyterlab/ui-components": "^4.4.0",
67
68
  "@langchain/anthropic": "^0.3.9",
68
69
  "@langchain/community": "^0.3.31",
69
70
  "@langchain/core": "^0.3.40",
@@ -74,16 +75,16 @@
74
75
  "@lumino/signaling": "^2.1.2",
75
76
  "@mui/icons-material": "^5.11.0",
76
77
  "@mui/material": "^5.11.0",
77
- "@rjsf/core": "^4.2.0",
78
+ "@rjsf/core": "^5.18.4",
78
79
  "@rjsf/utils": "^5.18.4",
79
80
  "@rjsf/validator-ajv8": "^5.18.4",
80
81
  "json5": "^2.2.3",
81
- "jupyter-secrets-manager": "^0.2.0",
82
+ "jupyter-secrets-manager": "^0.3.0",
82
83
  "react": "^18.2.0",
83
84
  "react-dom": "^18.2.0"
84
85
  },
85
86
  "devDependencies": {
86
- "@jupyterlab/builder": "^4.0.0",
87
+ "@jupyterlab/builder": "^4.4.0",
87
88
  "@stylistic/eslint-plugin": "^3.0.1",
88
89
  "@types/json-schema": "^7.0.11",
89
90
  "@types/react": "^18.0.26",
@@ -11,6 +11,12 @@
11
11
  "description": "Whether to use or not the secrets manager. If not, secrets will be stored in the browser (local storage)",
12
12
  "default": true
13
13
  },
14
+ "HideSecretFields": {
15
+ "type": "boolean",
16
+ "title": "Hide secret fields",
17
+ "description": "Whether to hide the secret fields in the UI or not",
18
+ "default": true
19
+ },
14
20
  "AIprovider": {
15
21
  "type": "object",
16
22
  "title": "AI provider",
@@ -9,7 +9,7 @@ export interface IBaseCompleter {
9
9
  /**
10
10
  * The LLM completer.
11
11
  */
12
- provider: BaseLanguageModel;
12
+ completer: BaseLanguageModel;
13
13
 
14
14
  /**
15
15
  * The completion prompt.
@@ -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._anthropicProvider = new ChatAnthropic({ ...options.settings });
14
+ this._completer = new ChatAnthropic({ ...options.settings });
15
15
  }
16
16
 
17
- get provider(): BaseChatModel {
18
- return this._anthropicProvider;
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._anthropicProvider.invoke(messages);
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 _anthropicProvider: ChatAnthropic;
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._chromeProvider = new ChromeAI({ ...options.settings });
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 provider(): LLM {
49
- return this._chromeProvider;
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._chromeProvider.invoke(messages);
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 _chromeProvider: ChromeAI;
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._mistralProvider = new ChatMistralAI({ ...options.settings });
24
+ this._completer = new ChatMistralAI({ ...options.settings });
25
25
  this._throttler = new Throttler(
26
26
  async (messages: BaseMessage[]) => {
27
- const response = await this._mistralProvider.invoke(messages);
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 provider(): BaseChatModel {
51
- return this._mistralProvider;
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 _mistralProvider: ChatMistralAI;
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._openAIProvider = new ChatOpenAI({ ...options.settings });
14
+ this._completer = new ChatOpenAI({ ...options.settings });
15
15
  }
16
16
 
17
- get provider(): BaseChatModel {
18
- return this._openAIProvider;
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._openAIProvider.invoke(messages);
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 _openAIProvider: ChatOpenAI;
65
+ private _completer: ChatOpenAI;
66
66
  private _prompt: string = COMPLETION_SYSTEM_PROMPT;
67
67
  }
package/src/index.ts CHANGED
@@ -21,18 +21,18 @@ import {
21
21
  } from '@jupyterlab/settingregistry';
22
22
  import { IFormRendererRegistry } from '@jupyterlab/ui-components';
23
23
  import { ReadonlyPartialJSONObject } from '@lumino/coreutils';
24
- import { ISecretsManager } from 'jupyter-secrets-manager';
24
+ import { ISecretsManager, SecretsManager } from 'jupyter-secrets-manager';
25
25
 
26
26
  import { ChatHandler } from './chat-handler';
27
27
  import { CompletionProvider } from './completion-provider';
28
28
  import { defaultProviderPlugins } from './default-providers';
29
29
  import { AIProviderRegistry } from './provider';
30
30
  import { aiSettingsRenderer, SettingConnector } from './settings';
31
- import { IAIProviderRegistry } from './tokens';
31
+ import { IAIProviderRegistry, PLUGIN_IDS } from './tokens';
32
32
  import { stopItem } from './components/stop-button';
33
33
 
34
34
  const chatCommandRegistryPlugin: JupyterFrontEndPlugin<IChatCommandRegistry> = {
35
- id: '@jupyterlite/ai:autocompletion-registry',
35
+ id: PLUGIN_IDS.chatCommandRegistry,
36
36
  description: 'Autocompletion registry',
37
37
  autoStart: true,
38
38
  provides: IChatCommandRegistry,
@@ -44,7 +44,7 @@ const chatCommandRegistryPlugin: JupyterFrontEndPlugin<IChatCommandRegistry> = {
44
44
  };
45
45
 
46
46
  const chatPlugin: JupyterFrontEndPlugin<void> = {
47
- id: '@jupyterlite/ai:chat',
47
+ id: PLUGIN_IDS.chat,
48
48
  description: 'LLM chat extension',
49
49
  autoStart: true,
50
50
  requires: [IAIProviderRegistry, IRenderMimeRegistry, IChatCommandRegistry],
@@ -141,7 +141,7 @@ const chatPlugin: JupyterFrontEndPlugin<void> = {
141
141
  };
142
142
 
143
143
  const completerPlugin: JupyterFrontEndPlugin<void> = {
144
- id: '@jupyterlite/ai:completer',
144
+ id: PLUGIN_IDS.completer,
145
145
  autoStart: true,
146
146
  requires: [IAIProviderRegistry, ICompletionProviderManager],
147
147
  activate: (
@@ -157,59 +157,64 @@ const completerPlugin: JupyterFrontEndPlugin<void> = {
157
157
  }
158
158
  };
159
159
 
160
- const providerRegistryPlugin: JupyterFrontEndPlugin<IAIProviderRegistry> = {
161
- id: '@jupyterlite/ai:provider-registry',
162
- autoStart: true,
163
- requires: [IFormRendererRegistry, ISettingRegistry],
164
- optional: [IRenderMimeRegistry, ISecretsManager, ISettingConnector],
165
- provides: IAIProviderRegistry,
166
- activate: (
167
- app: JupyterFrontEnd,
168
- editorRegistry: IFormRendererRegistry,
169
- settingRegistry: ISettingRegistry,
170
- rmRegistry?: IRenderMimeRegistry,
171
- secretsManager?: ISecretsManager,
172
- settingConnector?: ISettingConnector
173
- ): IAIProviderRegistry => {
174
- const providerRegistry = new AIProviderRegistry({ secretsManager });
175
-
176
- editorRegistry.addRenderer(
177
- '@jupyterlite/ai:provider-registry.AIprovider',
178
- aiSettingsRenderer({
179
- providerRegistry,
180
- rmRegistry,
181
- secretsManager,
182
- settingConnector
183
- })
184
- );
185
-
186
- settingRegistry
187
- .load(providerRegistryPlugin.id)
188
- .then(settings => {
189
- const updateProvider = () => {
190
- // Update the settings to the AI providers.
191
- const providerSettings = (settings.get('AIprovider').composite ?? {
192
- provider: 'None'
193
- }) as ReadonlyPartialJSONObject;
194
- providerRegistry.setProvider({
195
- name: providerSettings.provider as string,
196
- settings: providerSettings
197
- });
198
- };
199
-
200
- settings.changed.connect(() => updateProvider());
201
- updateProvider();
202
- })
203
- .catch(reason => {
204
- console.error(
205
- `Failed to load settings for ${providerRegistryPlugin.id}`,
206
- reason
207
- );
160
+ const providerRegistryPlugin: JupyterFrontEndPlugin<IAIProviderRegistry> =
161
+ SecretsManager.sign(PLUGIN_IDS.providerRegistry, token => ({
162
+ id: PLUGIN_IDS.providerRegistry,
163
+ autoStart: true,
164
+ requires: [IFormRendererRegistry, ISettingRegistry],
165
+ optional: [IRenderMimeRegistry, ISecretsManager, ISettingConnector],
166
+ provides: IAIProviderRegistry,
167
+ activate: (
168
+ app: JupyterFrontEnd,
169
+ editorRegistry: IFormRendererRegistry,
170
+ settingRegistry: ISettingRegistry,
171
+ rmRegistry?: IRenderMimeRegistry,
172
+ secretsManager?: ISecretsManager,
173
+ settingConnector?: ISettingConnector
174
+ ): IAIProviderRegistry => {
175
+ const providerRegistry = new AIProviderRegistry({
176
+ token,
177
+ secretsManager
208
178
  });
209
179
 
210
- return providerRegistry;
211
- }
212
- };
180
+ editorRegistry.addRenderer(
181
+ `${PLUGIN_IDS.providerRegistry}.AIprovider`,
182
+ aiSettingsRenderer({
183
+ providerRegistry,
184
+ secretsToken: token,
185
+ rmRegistry,
186
+ secretsManager,
187
+ settingConnector
188
+ })
189
+ );
190
+
191
+ settingRegistry
192
+ .load(providerRegistryPlugin.id)
193
+ .then(settings => {
194
+ const updateProvider = () => {
195
+ // Update the settings to the AI providers.
196
+ const providerSettings = (settings.get('AIprovider').composite ?? {
197
+ provider: 'None'
198
+ }) as ReadonlyPartialJSONObject;
199
+ providerRegistry.setProvider({
200
+ name: providerSettings.provider as string,
201
+ settings: providerSettings
202
+ });
203
+ };
204
+
205
+ settings.changed.connect(() => updateProvider());
206
+ updateProvider();
207
+ })
208
+ .catch(reason => {
209
+ console.error(
210
+ `Failed to load settings for ${providerRegistryPlugin.id}`,
211
+ reason
212
+ );
213
+ });
214
+
215
+ return providerRegistry;
216
+ }
217
+ }));
213
218
 
214
219
  /**
215
220
  * Provides the settings connector as a separate plugin to allow for alternative
@@ -217,7 +222,7 @@ const providerRegistryPlugin: JupyterFrontEndPlugin<IAIProviderRegistry> = {
217
222
  * endpoint.
218
223
  */
219
224
  const settingsConnector: JupyterFrontEndPlugin<ISettingConnector> = {
220
- id: '@jupyterlite/ai:settings-connector',
225
+ id: PLUGIN_IDS.settingsConnector,
221
226
  description: 'Provides a settings connector which does not save passwords.',
222
227
  autoStart: true,
223
228
  provides: ISettingConnector,
package/src/provider.ts CHANGED
@@ -6,18 +6,17 @@ import { JSONSchema7 } from 'json-schema';
6
6
  import { ISecretsManager } from 'jupyter-secrets-manager';
7
7
 
8
8
  import { IBaseCompleter } from './base-completer';
9
- import {
10
- getSecretId,
11
- SECRETS_NAMESPACE,
12
- SECRETS_REPLACEMENT
13
- } from './settings';
9
+ import { getSecretId, SECRETS_REPLACEMENT } from './settings';
14
10
  import {
15
11
  IAIProvider,
16
12
  IAIProviderRegistry,
17
13
  IDict,
18
- ISetProviderOptions
14
+ ISetProviderOptions,
15
+ PLUGIN_IDS
19
16
  } from './tokens';
20
17
 
18
+ const SECRETS_NAMESPACE = PLUGIN_IDS.providerRegistry;
19
+
21
20
  export const chatSystemPrompt = (
22
21
  options: AIProviderRegistry.IPromptOptions
23
22
  ) => `
@@ -54,6 +53,7 @@ export class AIProviderRegistry implements IAIProviderRegistry {
54
53
  */
55
54
  constructor(options: AIProviderRegistry.IOptions) {
56
55
  this._secretsManager = options.secretsManager || null;
56
+ Private.setToken(options.token);
57
57
  }
58
58
 
59
59
  /**
@@ -171,8 +171,14 @@ export class AIProviderRegistry implements IAIProviderRegistry {
171
171
  for (const key of Object.keys(settings)) {
172
172
  if (settings[key] === SECRETS_REPLACEMENT) {
173
173
  const id = getSecretId(name, key);
174
- const secrets = await this._secretsManager?.get(SECRETS_NAMESPACE, id);
175
- fullSettings[key] = secrets?.value || settings[key];
174
+ const secrets = await this._secretsManager?.get(
175
+ Private.getToken(),
176
+ SECRETS_NAMESPACE,
177
+ id
178
+ );
179
+ if (secrets !== undefined) {
180
+ fullSettings[key] = secrets.value;
181
+ }
176
182
  continue;
177
183
  }
178
184
  fullSettings[key] = settings[key];
@@ -181,7 +187,7 @@ export class AIProviderRegistry implements IAIProviderRegistry {
181
187
  if (this._currentProvider?.completer !== undefined) {
182
188
  try {
183
189
  this._completer = new this._currentProvider.completer({
184
- ...fullSettings
190
+ settings: fullSettings
185
191
  });
186
192
  this._completerError = '';
187
193
  } catch (e: any) {
@@ -236,6 +242,10 @@ export namespace AIProviderRegistry {
236
242
  * The secrets manager used in the application.
237
243
  */
238
244
  secretsManager?: ISecretsManager;
245
+ /**
246
+ * The token used to request the secrets manager.
247
+ */
248
+ token: symbol;
239
249
  }
240
250
 
241
251
  /**
@@ -290,3 +300,24 @@ export namespace AIProviderRegistry {
290
300
  });
291
301
  }
292
302
  }
303
+
304
+ namespace Private {
305
+ /**
306
+ * The token to use with the secrets manager.
307
+ */
308
+ let secretsToken: symbol;
309
+
310
+ /**
311
+ * Set of the token.
312
+ */
313
+ export function setToken(value: symbol): void {
314
+ secretsToken = value;
315
+ }
316
+
317
+ /**
318
+ * get the token.
319
+ */
320
+ export function getToken(): symbol {
321
+ return secretsToken;
322
+ }
323
+ }