@jupyterlite/ai 0.14.0 → 0.15.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/agent.d.ts +28 -114
- package/lib/agent.js +140 -100
- package/lib/chat-model-handler.d.ts +9 -11
- package/lib/chat-model-handler.js +9 -4
- package/lib/chat-model.d.ts +84 -13
- package/lib/chat-model.js +208 -136
- package/lib/completion/completion-provider.d.ts +2 -3
- package/lib/components/completion-status.d.ts +2 -2
- package/lib/components/model-select.d.ts +3 -3
- package/lib/components/save-button.d.ts +31 -0
- package/lib/components/save-button.js +41 -0
- package/lib/components/token-usage-display.d.ts +2 -3
- package/lib/components/tool-select.d.ts +3 -4
- package/lib/diff-manager.d.ts +2 -3
- package/lib/index.d.ts +2 -4
- package/lib/index.js +181 -23
- package/lib/models/settings-model.d.ts +11 -53
- package/lib/models/settings-model.js +37 -22
- package/lib/providers/built-in-providers.js +17 -36
- package/lib/tokens.d.ts +340 -36
- package/lib/tokens.js +11 -6
- package/lib/tools/commands.d.ts +2 -3
- package/lib/widgets/ai-settings.d.ts +3 -5
- package/lib/widgets/ai-settings.js +3 -0
- package/lib/widgets/main-area-chat.d.ts +2 -3
- package/lib/widgets/main-area-chat.js +9 -9
- package/lib/widgets/provider-config-dialog.d.ts +1 -2
- package/lib/widgets/provider-config-dialog.js +16 -29
- package/package.json +15 -9
- package/schema/settings-model.json +7 -1
- package/src/agent.ts +197 -242
- package/src/chat-model-handler.ts +25 -21
- package/src/chat-model.ts +304 -196
- package/src/completion/completion-provider.ts +7 -4
- package/src/components/completion-status.tsx +3 -3
- package/src/components/model-select.tsx +4 -3
- package/src/components/save-button.tsx +84 -0
- package/src/components/token-usage-display.tsx +2 -3
- package/src/components/tool-select.tsx +10 -4
- package/src/diff-manager.ts +4 -4
- package/src/index.ts +245 -49
- package/src/models/settings-model.ts +45 -88
- package/src/providers/built-in-providers.ts +17 -36
- package/src/tokens.ts +406 -52
- package/src/tools/commands.ts +2 -3
- package/src/widgets/ai-settings.tsx +27 -15
- package/src/widgets/main-area-chat.ts +15 -12
- package/src/widgets/provider-config-dialog.tsx +51 -56
- package/style/base.css +17 -195
- package/lib/approval-buttons.d.ts +0 -49
- package/lib/approval-buttons.js +0 -79
- package/src/approval-buttons.ts +0 -115
|
@@ -1,74 +1,16 @@
|
|
|
1
1
|
import { VDomModel } from '@jupyterlab/ui-components';
|
|
2
2
|
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
supportsFillInMiddle?: boolean;
|
|
11
|
-
useFilterText?: boolean;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface IProviderConfig {
|
|
15
|
-
id: string;
|
|
16
|
-
name: string;
|
|
17
|
-
provider: string;
|
|
18
|
-
model: string;
|
|
19
|
-
apiKey?: string;
|
|
20
|
-
baseURL?: string;
|
|
21
|
-
headers?: Record<string, string>;
|
|
22
|
-
parameters?: IProviderParameters;
|
|
23
|
-
customSettings?: Record<string, any>;
|
|
24
|
-
[key: string]: any; // Index signature for JupyterLab settings compatibility
|
|
25
|
-
}
|
|
4
|
+
import {
|
|
5
|
+
IAIConfig,
|
|
6
|
+
IAISettingsModel,
|
|
7
|
+
IMCPServerConfig,
|
|
8
|
+
IProviderConfig
|
|
9
|
+
} from '../tokens';
|
|
26
10
|
|
|
27
|
-
|
|
28
|
-
id: string;
|
|
29
|
-
name: string;
|
|
30
|
-
url: string;
|
|
31
|
-
enabled: boolean;
|
|
32
|
-
[key: string]: any; // Index signature for JupyterLab settings compatibility
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface IAIConfig {
|
|
36
|
-
// Whether to use the secrets manager
|
|
37
|
-
useSecretsManager: boolean;
|
|
38
|
-
// List of configured providers
|
|
39
|
-
providers: IProviderConfig[];
|
|
40
|
-
// Active provider IDs for different use cases
|
|
41
|
-
defaultProvider: string; // Default provider for chat
|
|
42
|
-
activeCompleterProvider?: string; // Provider for completions (if different)
|
|
43
|
-
// When true, use the same provider for chat and completions
|
|
44
|
-
useSameProviderForChatAndCompleter: boolean;
|
|
45
|
-
// MCP servers configuration
|
|
46
|
-
mcpServers: IMCPServerConfig[];
|
|
47
|
-
// Global settings
|
|
48
|
-
contextAwareness: boolean;
|
|
49
|
-
codeExecution: boolean;
|
|
50
|
-
systemPrompt: string;
|
|
51
|
-
completionSystemPrompt: string;
|
|
52
|
-
toolsEnabled: boolean;
|
|
53
|
-
// Chat behavior settings
|
|
54
|
-
sendWithShiftEnter: boolean;
|
|
55
|
-
// Token usage display setting
|
|
56
|
-
showTokenUsage: boolean;
|
|
57
|
-
// Commands that require approval before execution
|
|
58
|
-
commandsRequiringApproval: string[];
|
|
59
|
-
// Commands whose execute_command outputs may auto-render MIME bundles in chat
|
|
60
|
-
commandsAutoRenderMimeBundles: string[];
|
|
61
|
-
// MIME types that are trusted when auto-rendering execute_command outputs
|
|
62
|
-
trustedMimeTypesForAutoRender: string[];
|
|
63
|
-
// Diff display settings
|
|
64
|
-
showCellDiff: boolean;
|
|
65
|
-
showFileDiff: boolean;
|
|
66
|
-
diffDisplayMode: 'split' | 'unified';
|
|
67
|
-
// Paths to directories containing agent skills
|
|
68
|
-
skillsPaths: string[];
|
|
69
|
-
}
|
|
11
|
+
const PLUGIN_ID = '@jupyterlite/ai:settings-model';
|
|
70
12
|
|
|
71
|
-
export class AISettingsModel extends VDomModel {
|
|
13
|
+
export class AISettingsModel extends VDomModel implements IAISettingsModel {
|
|
72
14
|
private _config: IAIConfig = {
|
|
73
15
|
useSecretsManager: true,
|
|
74
16
|
providers: [],
|
|
@@ -85,6 +27,7 @@ export class AISettingsModel extends VDomModel {
|
|
|
85
27
|
showFileDiff: true,
|
|
86
28
|
diffDisplayMode: 'split',
|
|
87
29
|
skillsPaths: ['.agents/skills', '_agents/skills'],
|
|
30
|
+
chatBackupDirectory: '',
|
|
88
31
|
commandsRequiringApproval: [
|
|
89
32
|
'notebook:restart-run-all',
|
|
90
33
|
'notebook:run-cell',
|
|
@@ -166,6 +109,15 @@ When asked to run code or perform computations, choose the most appropriate appr
|
|
|
166
109
|
|
|
167
110
|
This means if the user asks you to "calculate the factorial of 100" or "check what library version is installed", run that directly with the jupyterlab-ai-commands kernel execution command rather than creating a new notebook file.
|
|
168
111
|
|
|
112
|
+
## Notebook State and Cell Identity
|
|
113
|
+
When working with an existing notebook, use the notebook's current structure and kernel state as the source of truth.
|
|
114
|
+
- Before changing notebook content or structure, inspect the notebook and any target cells with the relevant notebook commands you have discovered.
|
|
115
|
+
- If the user may have edited the notebook, or if a previous command could have changed it, refresh your view before continuing rather than relying on earlier results.
|
|
116
|
+
- Treat variables from previously executed cells as part of the active kernel state. When the user asks you to work with existing data or variables, use them by name instead of recreating them unless the user asks you to redefine them or the kernel state is unavailable.
|
|
117
|
+
- Be explicit about the kind of cell reference you are using. A visible execution count (for example In [6]), a notebook position, and an internal cell ID or UUID are different identifiers and may not match.
|
|
118
|
+
- When the user identifies a cell by execution count, relative position, or content, verify the target cell from the current notebook contents before editing it or inserting cells relative to it.
|
|
119
|
+
- For relative insertions, anchor the change to the confirmed target cell rather than to empty placeholder or trailing cells unless the user explicitly refers to those cells.
|
|
120
|
+
|
|
169
121
|
## Your Approach
|
|
170
122
|
- **Context-aware**: You understand the user is working in a data science/research environment
|
|
171
123
|
- **Practical**: You focus on actionable solutions that work in the user's current setup
|
|
@@ -209,7 +161,7 @@ Guidelines:
|
|
|
209
161
|
|
|
210
162
|
## Multi-Step Task Handling
|
|
211
163
|
When users request complex tasks, you use the command system to accomplish them:
|
|
212
|
-
- For file and notebook operations, use discover_commands with query 'jupyterlab-ai-commands' to find the curated set of AI commands (~
|
|
164
|
+
- For file and notebook operations, use discover_commands with query 'jupyterlab-ai-commands' to find the curated set of AI commands (~22 commands)
|
|
213
165
|
- For other JupyterLab operations (terminal, launcher, UI), use specific keywords like 'terminal', 'launcher', etc.
|
|
214
166
|
- IMPORTANT: Always use 'jupyterlab-ai-commands' as the query for file/notebook tasks - this returns a focused set instead of 100+ generic commands
|
|
215
167
|
- For example, to create a notebook with cells:
|
|
@@ -251,16 +203,16 @@ Rules:
|
|
|
251
203
|
constructor(options: AISettingsModel.IOptions) {
|
|
252
204
|
super();
|
|
253
205
|
this._settingRegistry = options.settingRegistry;
|
|
254
|
-
this.
|
|
206
|
+
this._initializeSettings();
|
|
255
207
|
}
|
|
256
208
|
|
|
257
|
-
private async
|
|
209
|
+
private async _initializeSettings(): Promise<void> {
|
|
258
210
|
try {
|
|
259
211
|
this._settings = await this._settingRegistry.load(PLUGIN_ID);
|
|
260
|
-
this.
|
|
212
|
+
this._loadFromSettings();
|
|
261
213
|
|
|
262
214
|
// Listen for settings changes
|
|
263
|
-
this._settings.changed.connect(this.
|
|
215
|
+
this._settings.changed.connect(this._onSettingsChanged, this);
|
|
264
216
|
|
|
265
217
|
this.stateChanged.emit(void 0);
|
|
266
218
|
} catch (error) {
|
|
@@ -269,12 +221,12 @@ Rules:
|
|
|
269
221
|
}
|
|
270
222
|
}
|
|
271
223
|
|
|
272
|
-
private
|
|
273
|
-
this.
|
|
224
|
+
private _onSettingsChanged(): void {
|
|
225
|
+
this._loadFromSettings();
|
|
274
226
|
this.stateChanged.emit(void 0);
|
|
275
227
|
}
|
|
276
228
|
|
|
277
|
-
private
|
|
229
|
+
private _loadFromSettings(): void {
|
|
278
230
|
if (!this._settings) {
|
|
279
231
|
return;
|
|
280
232
|
}
|
|
@@ -334,12 +286,12 @@ Rules:
|
|
|
334
286
|
// If this is the first provider, make it active
|
|
335
287
|
if (this._config.providers.length === 1) {
|
|
336
288
|
// Save both providers and defaultProvider
|
|
337
|
-
await this.
|
|
289
|
+
await this._saveSetting('providers', this._config.providers);
|
|
338
290
|
this._config.defaultProvider = id;
|
|
339
|
-
await this.
|
|
291
|
+
await this._saveSetting('defaultProvider', this._config.defaultProvider);
|
|
340
292
|
} else {
|
|
341
293
|
// Only save providers
|
|
342
|
-
await this.
|
|
294
|
+
await this._saveSetting('providers', this._config.providers);
|
|
343
295
|
}
|
|
344
296
|
|
|
345
297
|
return id;
|
|
@@ -352,18 +304,18 @@ Rules:
|
|
|
352
304
|
}
|
|
353
305
|
|
|
354
306
|
this._config.providers.splice(index, 1);
|
|
355
|
-
await this.
|
|
307
|
+
await this._saveSetting('providers', this._config.providers);
|
|
356
308
|
|
|
357
309
|
// If this was the active provider, select a new one
|
|
358
310
|
if (this._config.defaultProvider === id) {
|
|
359
311
|
this._config.defaultProvider =
|
|
360
312
|
this._config.providers.length > 0 ? this._config.providers[0].id : '';
|
|
361
|
-
await this.
|
|
313
|
+
await this._saveSetting('defaultProvider', this._config.defaultProvider);
|
|
362
314
|
}
|
|
363
315
|
|
|
364
316
|
if (this._config.activeCompleterProvider === id) {
|
|
365
317
|
this._config.activeCompleterProvider = undefined;
|
|
366
|
-
await this.
|
|
318
|
+
await this._saveSetting(
|
|
367
319
|
'activeCompleterProvider',
|
|
368
320
|
this._config.activeCompleterProvider
|
|
369
321
|
);
|
|
@@ -385,19 +337,19 @@ Rules:
|
|
|
385
337
|
delete provider[key];
|
|
386
338
|
}
|
|
387
339
|
});
|
|
388
|
-
await this.
|
|
340
|
+
await this._saveSetting('providers', this._config.providers);
|
|
389
341
|
}
|
|
390
342
|
|
|
391
343
|
async setActiveProvider(id: string): Promise<void> {
|
|
392
344
|
if (this.getProvider(id)) {
|
|
393
345
|
this._config.defaultProvider = id;
|
|
394
|
-
await this.
|
|
346
|
+
await this._saveSetting('defaultProvider', this._config.defaultProvider);
|
|
395
347
|
}
|
|
396
348
|
}
|
|
397
349
|
|
|
398
350
|
async setActiveCompleterProvider(id: string | undefined): Promise<void> {
|
|
399
351
|
this._config.activeCompleterProvider = id;
|
|
400
|
-
await this.
|
|
352
|
+
await this._saveSetting(
|
|
401
353
|
'activeCompleterProvider',
|
|
402
354
|
this._config.activeCompleterProvider
|
|
403
355
|
);
|
|
@@ -423,7 +375,7 @@ Rules:
|
|
|
423
375
|
};
|
|
424
376
|
|
|
425
377
|
this._config.mcpServers.push(newServer);
|
|
426
|
-
await this.
|
|
378
|
+
await this._saveSetting('mcpServers', this._config.mcpServers);
|
|
427
379
|
return id;
|
|
428
380
|
}
|
|
429
381
|
|
|
@@ -434,7 +386,7 @@ Rules:
|
|
|
434
386
|
}
|
|
435
387
|
|
|
436
388
|
this._config.mcpServers.splice(index, 1);
|
|
437
|
-
await this.
|
|
389
|
+
await this._saveSetting('mcpServers', this._config.mcpServers);
|
|
438
390
|
}
|
|
439
391
|
|
|
440
392
|
async updateMCPServer(
|
|
@@ -447,7 +399,7 @@ Rules:
|
|
|
447
399
|
}
|
|
448
400
|
|
|
449
401
|
Object.assign(server, updates);
|
|
450
|
-
await this.
|
|
402
|
+
await this._saveSetting('mcpServers', this._config.mcpServers);
|
|
451
403
|
}
|
|
452
404
|
|
|
453
405
|
async updateConfig(updates: Partial<IAIConfig>): Promise<void> {
|
|
@@ -460,7 +412,7 @@ Rules:
|
|
|
460
412
|
this._config[key as keyof IAIConfig] !== value
|
|
461
413
|
) {
|
|
462
414
|
(this._config as any)[key] = value;
|
|
463
|
-
promises.push(this.
|
|
415
|
+
promises.push(this._saveSetting(key as keyof IAIConfig, value));
|
|
464
416
|
}
|
|
465
417
|
}
|
|
466
418
|
|
|
@@ -468,6 +420,11 @@ Rules:
|
|
|
468
420
|
await Promise.all(promises);
|
|
469
421
|
}
|
|
470
422
|
|
|
423
|
+
/**
|
|
424
|
+
* Get the API key saved in the settings file for a given provider.
|
|
425
|
+
*
|
|
426
|
+
* @param id - the id of the provider.
|
|
427
|
+
*/
|
|
471
428
|
getApiKey(id: string): string {
|
|
472
429
|
// First check the active completer provider
|
|
473
430
|
const activeCompleterProvider = this.getCompleterProvider();
|
|
@@ -484,7 +441,7 @@ Rules:
|
|
|
484
441
|
return '';
|
|
485
442
|
}
|
|
486
443
|
|
|
487
|
-
private async
|
|
444
|
+
private async _saveSetting(key: keyof IAIConfig, value: any): Promise<void> {
|
|
488
445
|
try {
|
|
489
446
|
if (this._settings) {
|
|
490
447
|
// Only save the specific setting that changed
|
|
@@ -28,8 +28,7 @@ export const anthropicProvider: IProviderInfo = {
|
|
|
28
28
|
'claude-opus-4-0',
|
|
29
29
|
'claude-opus-4-20250514',
|
|
30
30
|
'claude-sonnet-4-0',
|
|
31
|
-
'claude-sonnet-4-20250514'
|
|
32
|
-
'claude-3-haiku-20240307'
|
|
31
|
+
'claude-sonnet-4-20250514'
|
|
33
32
|
],
|
|
34
33
|
supportsBaseURL: true,
|
|
35
34
|
supportsHeaders: true,
|
|
@@ -65,29 +64,18 @@ export const googleProvider: IProviderInfo = {
|
|
|
65
64
|
'gemini-3.1-pro-preview',
|
|
66
65
|
'gemini-3.1-pro-preview-customtools',
|
|
67
66
|
'gemini-3.1-flash-image-preview',
|
|
68
|
-
'gemini-3-
|
|
67
|
+
'gemini-3.1-flash-lite-preview',
|
|
69
68
|
'gemini-3-pro-image-preview',
|
|
70
69
|
'gemini-3-flash-preview',
|
|
71
70
|
'gemini-2.5-pro',
|
|
72
71
|
'gemini-2.5-flash',
|
|
73
72
|
'gemini-2.5-flash-image',
|
|
74
73
|
'gemini-2.5-flash-lite',
|
|
75
|
-
'gemini-2.5-flash-lite-preview-09-2025',
|
|
76
74
|
'gemini-2.5-computer-use-preview-10-2025',
|
|
77
|
-
'
|
|
78
|
-
'gemini-2.0-flash-001',
|
|
79
|
-
'gemini-2.0-flash-lite',
|
|
80
|
-
'gemini-2.0-flash-lite-001',
|
|
75
|
+
'deep-research-pro-preview-12-2025',
|
|
81
76
|
'gemini-pro-latest',
|
|
82
77
|
'gemini-flash-latest',
|
|
83
|
-
'gemini-flash-lite-latest'
|
|
84
|
-
'deep-research-pro-preview-12-2025',
|
|
85
|
-
'gemma-3-27b-it',
|
|
86
|
-
'gemma-3-12b-it',
|
|
87
|
-
'gemma-3-4b-it',
|
|
88
|
-
'gemma-3-1b-it',
|
|
89
|
-
'gemma-3n-e4b-it',
|
|
90
|
-
'gemma-3n-e2b-it'
|
|
78
|
+
'gemini-flash-lite-latest'
|
|
91
79
|
],
|
|
92
80
|
supportsBaseURL: true,
|
|
93
81
|
factory: (options: IModelOptions) => {
|
|
@@ -111,23 +99,19 @@ export const mistralProvider: IProviderInfo = {
|
|
|
111
99
|
name: 'Mistral AI',
|
|
112
100
|
apiKeyRequirement: 'required',
|
|
113
101
|
defaultModels: [
|
|
114
|
-
'ministral-3b-latest',
|
|
115
|
-
'ministral-8b-latest',
|
|
116
102
|
'mistral-large-latest',
|
|
117
103
|
'mistral-medium-latest',
|
|
118
104
|
'mistral-medium-2508',
|
|
119
|
-
'mistral-medium-2505',
|
|
120
105
|
'mistral-small-latest',
|
|
121
|
-
'
|
|
106
|
+
'mistral-small-2506',
|
|
107
|
+
'ministral-3b-latest',
|
|
108
|
+
'ministral-8b-latest',
|
|
109
|
+
'ministral-14b-latest',
|
|
110
|
+
'magistral-small-latest',
|
|
111
|
+
'magistral-medium-latest',
|
|
122
112
|
'pixtral-large-latest',
|
|
123
|
-
'
|
|
124
|
-
'
|
|
125
|
-
'magistral-small-2506',
|
|
126
|
-
'magistral-medium-2506',
|
|
127
|
-
'pixtral-12b-2409',
|
|
128
|
-
'open-mistral-7b',
|
|
129
|
-
'open-mixtral-8x7b',
|
|
130
|
-
'open-mixtral-8x22b'
|
|
113
|
+
'codestral-latest',
|
|
114
|
+
'devstral-latest'
|
|
131
115
|
],
|
|
132
116
|
supportsBaseURL: true,
|
|
133
117
|
factory: (options: IModelOptions) => {
|
|
@@ -151,6 +135,9 @@ export const openaiProvider: IProviderInfo = {
|
|
|
151
135
|
name: 'OpenAI',
|
|
152
136
|
apiKeyRequirement: 'required',
|
|
153
137
|
defaultModels: [
|
|
138
|
+
'gpt-5.4',
|
|
139
|
+
'gpt-5.4-mini',
|
|
140
|
+
'gpt-5.4-nano',
|
|
154
141
|
'gpt-5.2',
|
|
155
142
|
'gpt-5.2-2025-12-11',
|
|
156
143
|
'gpt-5.2-chat-latest',
|
|
@@ -169,6 +156,7 @@ export const openaiProvider: IProviderInfo = {
|
|
|
169
156
|
'gpt-5-nano-2025-08-07',
|
|
170
157
|
'o4-mini',
|
|
171
158
|
'o4-mini-2025-04-16',
|
|
159
|
+
'o3-pro',
|
|
172
160
|
'o3',
|
|
173
161
|
'o3-2025-04-16',
|
|
174
162
|
'o3-mini',
|
|
@@ -185,21 +173,14 @@ export const openaiProvider: IProviderInfo = {
|
|
|
185
173
|
'gpt-4o-2024-05-13',
|
|
186
174
|
'gpt-4o-2024-08-06',
|
|
187
175
|
'gpt-4o-2024-11-20',
|
|
188
|
-
'gpt-4o-audio-preview',
|
|
189
|
-
'gpt-4o-audio-preview-2024-12-17',
|
|
190
|
-
'gpt-4o-audio-preview-2025-06-03',
|
|
191
176
|
'gpt-4o-mini',
|
|
192
177
|
'gpt-4o-mini-2024-07-18',
|
|
193
|
-
'gpt-4o-mini-audio-preview',
|
|
194
|
-
'gpt-4o-mini-audio-preview-2024-12-17',
|
|
195
178
|
'gpt-4o-search-preview',
|
|
196
179
|
'gpt-4o-search-preview-2025-03-11',
|
|
197
180
|
'gpt-4o-mini-search-preview',
|
|
198
181
|
'gpt-4o-mini-search-preview-2025-03-11',
|
|
199
182
|
'gpt-3.5-turbo',
|
|
200
|
-
'gpt-3.5-turbo-0125'
|
|
201
|
-
'gpt-3.5-turbo-1106',
|
|
202
|
-
'gpt-3.5-turbo-16k'
|
|
183
|
+
'gpt-3.5-turbo-0125'
|
|
203
184
|
],
|
|
204
185
|
supportsBaseURL: true,
|
|
205
186
|
supportsHeaders: true,
|