@jupyterlite/ai 0.9.0-a3 → 0.9.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/README.md +20 -89
- package/lib/agent.d.ts +10 -4
- package/lib/agent.js +30 -17
- package/lib/chat-model.d.ts +6 -0
- package/lib/chat-model.js +144 -17
- package/lib/completion/completion-provider.js +1 -13
- package/lib/components/completion-status.d.ts +20 -0
- package/lib/components/completion-status.js +51 -0
- package/lib/components/index.d.ts +1 -0
- package/lib/components/index.js +1 -0
- package/lib/components/model-select.js +1 -2
- package/lib/diff-manager.d.ts +25 -0
- package/lib/diff-manager.js +60 -0
- package/lib/icons.d.ts +0 -1
- package/lib/icons.js +2 -6
- package/lib/index.d.ts +2 -2
- package/lib/index.js +54 -23
- package/lib/models/settings-model.d.ts +4 -0
- package/lib/models/settings-model.js +24 -2
- package/lib/providers/built-in-providers.d.ts +0 -4
- package/lib/providers/built-in-providers.js +17 -23
- package/lib/tokens.d.ts +74 -0
- package/lib/tokens.js +4 -0
- package/lib/tools/commands.js +36 -35
- package/lib/tools/file.d.ts +10 -1
- package/lib/tools/file.js +235 -146
- package/lib/tools/notebook.d.ts +2 -3
- package/lib/tools/notebook.js +11 -11
- package/lib/widgets/ai-settings.js +78 -13
- package/lib/widgets/provider-config-dialog.js +15 -8
- package/package.json +5 -3
- package/schema/settings-model.json +25 -0
- package/src/agent.ts +35 -20
- package/src/chat-model.ts +182 -19
- package/src/completion/completion-provider.ts +1 -14
- package/src/components/completion-status.tsx +79 -0
- package/src/components/index.ts +1 -0
- package/src/components/model-select.tsx +0 -3
- package/src/diff-manager.ts +81 -0
- package/src/icons.ts +2 -7
- package/src/index.ts +74 -24
- package/src/models/settings-model.ts +28 -2
- package/src/providers/built-in-providers.ts +17 -24
- package/src/tokens.ts +78 -0
- package/src/tools/commands.ts +45 -40
- package/src/tools/file.ts +295 -164
- package/src/tools/notebook.ts +13 -14
- package/src/widgets/ai-settings.tsx +184 -35
- package/src/widgets/provider-config-dialog.tsx +43 -16
- package/style/base.css +14 -0
|
@@ -2,7 +2,6 @@ import { TooltippedButton } from '@jupyter/chat';
|
|
|
2
2
|
import CheckIcon from '@mui/icons-material/Check';
|
|
3
3
|
import { Menu, MenuItem, Typography } from '@mui/material';
|
|
4
4
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
5
|
-
const SELECT_ITEM_CLASS = 'labai-model-select-item';
|
|
6
5
|
/**
|
|
7
6
|
* The model select component for choosing AI models.
|
|
8
7
|
*/
|
|
@@ -114,7 +113,7 @@ export function ModelSelect(props) {
|
|
|
114
113
|
paddingRight: '2em',
|
|
115
114
|
minWidth: '200px'
|
|
116
115
|
}
|
|
117
|
-
} }, availableModels.map(({ provider, providerLabel, isSelected }) => (React.createElement(MenuItem, { key: provider,
|
|
116
|
+
} }, availableModels.map(({ provider, providerLabel, isSelected }) => (React.createElement(MenuItem, { key: provider, onClick: async (e) => {
|
|
118
117
|
await selectModel(provider);
|
|
119
118
|
// Prevent sending message on model selection
|
|
120
119
|
e.stopPropagation();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { CommandRegistry } from '@lumino/commands';
|
|
2
|
+
import { AISettingsModel } from './models/settings-model';
|
|
3
|
+
import { IDiffManager, IShowCellDiffParams, IShowFileDiffParams } from './tokens';
|
|
4
|
+
/**
|
|
5
|
+
* Implementation of the diff manager
|
|
6
|
+
*/
|
|
7
|
+
export declare class DiffManager implements IDiffManager {
|
|
8
|
+
/**
|
|
9
|
+
* Construct a new DiffManager
|
|
10
|
+
*/
|
|
11
|
+
constructor(options: {
|
|
12
|
+
commands: CommandRegistry;
|
|
13
|
+
settingsModel: AISettingsModel;
|
|
14
|
+
});
|
|
15
|
+
/**
|
|
16
|
+
* Show diff between original and modified cell content
|
|
17
|
+
*/
|
|
18
|
+
showCellDiff(params: IShowCellDiffParams): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Show diff between original and modified file content
|
|
21
|
+
*/
|
|
22
|
+
showFileDiff(params: IShowFileDiffParams): Promise<void>;
|
|
23
|
+
private _commands;
|
|
24
|
+
private _settingsModel;
|
|
25
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command IDs for unified cell diffs
|
|
3
|
+
*/
|
|
4
|
+
const UNIFIED_DIFF_COMMAND_ID = 'jupyterlab-diff:unified-cell-diff';
|
|
5
|
+
/**
|
|
6
|
+
* Command IDs for split cell diffs
|
|
7
|
+
*/
|
|
8
|
+
const SPLIT_DIFF_COMMAND_ID = 'jupyterlab-diff:split-cell-diff';
|
|
9
|
+
/**
|
|
10
|
+
* Command ID for unified file diffs
|
|
11
|
+
*/
|
|
12
|
+
const UNIFIED_FILE_DIFF_COMMAND_ID = 'jupyterlab-diff:unified-file-diff';
|
|
13
|
+
/**
|
|
14
|
+
* Implementation of the diff manager
|
|
15
|
+
*/
|
|
16
|
+
export class DiffManager {
|
|
17
|
+
/**
|
|
18
|
+
* Construct a new DiffManager
|
|
19
|
+
*/
|
|
20
|
+
constructor(options) {
|
|
21
|
+
this._commands = options.commands;
|
|
22
|
+
this._settingsModel = options.settingsModel;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Show diff between original and modified cell content
|
|
26
|
+
*/
|
|
27
|
+
async showCellDiff(params) {
|
|
28
|
+
if (!this._settingsModel.config.showCellDiff) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const showDiffCommandId = this._settingsModel.config.diffDisplayMode === 'unified'
|
|
32
|
+
? UNIFIED_DIFF_COMMAND_ID
|
|
33
|
+
: SPLIT_DIFF_COMMAND_ID;
|
|
34
|
+
await this._commands.execute(showDiffCommandId, {
|
|
35
|
+
originalSource: params.original,
|
|
36
|
+
newSource: params.modified,
|
|
37
|
+
cellId: params.cellId,
|
|
38
|
+
showActionButtons: params.showActionButtons ?? true,
|
|
39
|
+
openDiff: params.openDiff ?? true,
|
|
40
|
+
notebookPath: params.notebookPath
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Show diff between original and modified file content
|
|
45
|
+
*/
|
|
46
|
+
async showFileDiff(params) {
|
|
47
|
+
if (!this._settingsModel.config.showFileDiff) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// File diffs only support unified view
|
|
51
|
+
await this._commands.execute(UNIFIED_FILE_DIFF_COMMAND_ID, {
|
|
52
|
+
originalSource: params.original,
|
|
53
|
+
newSource: params.modified,
|
|
54
|
+
filePath: params.filePath,
|
|
55
|
+
showActionButtons: params.showActionButtons ?? true
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
_commands;
|
|
59
|
+
_settingsModel;
|
|
60
|
+
}
|
package/lib/icons.d.ts
CHANGED
package/lib/icons.js
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { LabIcon } from '@jupyterlab/ui-components';
|
|
2
|
-
import
|
|
3
|
-
export const labaiIcon = new LabIcon({
|
|
4
|
-
name: '@jupyterlite/ai:icon',
|
|
5
|
-
svgstr: labaiIconSvg
|
|
6
|
-
});
|
|
2
|
+
import jupyternautSvg from '../style/icons/jupyternaut-lite.svg';
|
|
7
3
|
export const jupyternautIcon = new LabIcon({
|
|
8
4
|
name: '@jupyterlite/ai:jupyternaut',
|
|
9
|
-
svgstr:
|
|
5
|
+
svgstr: jupyternautSvg
|
|
10
6
|
});
|
|
11
7
|
const AI_AVATAR_BASE64 = btoa(jupyternautIcon.svgstr);
|
|
12
8
|
export const AI_AVATAR = `data:image/svg+xml;base64,${AI_AVATAR_BASE64}`;
|
package/lib/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { JupyterFrontEndPlugin } from '@jupyterlab/application';
|
|
2
2
|
import { IInputToolbarRegistryFactory } from '@jupyter/chat';
|
|
3
3
|
import { AgentManagerFactory } from './agent';
|
|
4
|
-
import { IProviderRegistry, IToolRegistry, IChatModelRegistry } from './tokens';
|
|
4
|
+
import { IProviderRegistry, IToolRegistry, IChatModelRegistry, IDiffManager } from './tokens';
|
|
5
5
|
import { AISettingsModel } from './models/settings-model';
|
|
6
|
-
declare const _default: (JupyterFrontEndPlugin<IProviderRegistry> | JupyterFrontEndPlugin<void> | JupyterFrontEndPlugin<IChatModelRegistry> | JupyterFrontEndPlugin<AgentManagerFactory> | JupyterFrontEndPlugin<AISettingsModel> | JupyterFrontEndPlugin<IToolRegistry> | JupyterFrontEndPlugin<IInputToolbarRegistryFactory>)[];
|
|
6
|
+
declare const _default: (JupyterFrontEndPlugin<IProviderRegistry> | JupyterFrontEndPlugin<void> | JupyterFrontEndPlugin<IChatModelRegistry> | JupyterFrontEndPlugin<AgentManagerFactory> | JupyterFrontEndPlugin<AISettingsModel> | JupyterFrontEndPlugin<IDiffManager> | JupyterFrontEndPlugin<IToolRegistry> | JupyterFrontEndPlugin<IInputToolbarRegistryFactory>)[];
|
|
7
7
|
export default _default;
|
|
8
8
|
export * from './tokens';
|
package/lib/index.js
CHANGED
|
@@ -3,10 +3,12 @@ import { ActiveCellManager, AttachmentOpenerRegistry, chatIcon, ChatWidget, IInp
|
|
|
3
3
|
import { ICommandPalette, IThemeManager, WidgetTracker } from '@jupyterlab/apputils';
|
|
4
4
|
import { ICompletionProviderManager } from '@jupyterlab/completer';
|
|
5
5
|
import { IDocumentManager } from '@jupyterlab/docmanager';
|
|
6
|
+
import { IEditorTracker } from '@jupyterlab/fileeditor';
|
|
6
7
|
import { INotebookTracker } from '@jupyterlab/notebook';
|
|
7
8
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
8
9
|
import { IKernelSpecManager } from '@jupyterlab/services';
|
|
9
10
|
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
11
|
+
import { IStatusBar } from '@jupyterlab/statusbar';
|
|
10
12
|
import { settingsIcon, Toolbar, ToolbarButton } from '@jupyterlab/ui-components';
|
|
11
13
|
import { ISecretsManager, SecretsManager } from 'jupyter-secrets-manager';
|
|
12
14
|
import { PromiseDelegate, UUID } from '@lumino/coreutils';
|
|
@@ -14,14 +16,15 @@ import { AgentManagerFactory } from './agent';
|
|
|
14
16
|
import { ProviderRegistry } from './providers/provider-registry';
|
|
15
17
|
import { ApprovalButtons } from './approval-buttons';
|
|
16
18
|
import { ChatModelRegistry } from './chat-model-registry';
|
|
17
|
-
import { CommandIds, IAgentManagerFactory, IProviderRegistry, IToolRegistry, SECRETS_NAMESPACE, IAISettingsModel, IChatModelRegistry } from './tokens';
|
|
18
|
-
import { anthropicProvider, googleProvider, mistralProvider, openaiProvider,
|
|
19
|
+
import { CommandIds, IAgentManagerFactory, IProviderRegistry, IToolRegistry, SECRETS_NAMESPACE, IAISettingsModel, IChatModelRegistry, IDiffManager } from './tokens';
|
|
20
|
+
import { anthropicProvider, googleProvider, mistralProvider, openaiProvider, genericProvider } from './providers/built-in-providers';
|
|
19
21
|
import { AICompletionProvider } from './completion';
|
|
20
|
-
import { clearItem, createModelSelectItem, createToolSelectItem, stopItem, TokenUsageWidget } from './components';
|
|
22
|
+
import { clearItem, createModelSelectItem, createToolSelectItem, stopItem, CompletionStatusWidget, TokenUsageWidget } from './components';
|
|
21
23
|
import { AISettingsModel } from './models/settings-model';
|
|
24
|
+
import { DiffManager } from './diff-manager';
|
|
22
25
|
import { ToolRegistry } from './tools/tool-registry';
|
|
23
26
|
import { createAddCellTool, createDeleteCellTool, createExecuteActiveCellTool, createGetCellInfoTool, createGetNotebookInfoTool, createNotebookCreationTool, createRunCellTool, createSaveNotebookTool, createSetCellContentTool } from './tools/notebook';
|
|
24
|
-
import { createCopyFileTool, createDeleteFileTool, createNavigateToDirectoryTool, createNewFileTool, createOpenFileTool, createRenameFileTool } from './tools/file';
|
|
27
|
+
import { createCopyFileTool, createDeleteFileTool, createGetFileInfoTool, createNavigateToDirectoryTool, createNewFileTool, createOpenFileTool, createRenameFileTool, createSetFileContentTool } from './tools/file';
|
|
25
28
|
import { createDiscoverCommandsTool, createExecuteCommandTool } from './tools/commands';
|
|
26
29
|
import { AISettingsWidget } from './widgets/ai-settings';
|
|
27
30
|
import { MainAreaChat } from './widgets/main-area-chat';
|
|
@@ -85,18 +88,6 @@ const openaiProviderPlugin = {
|
|
|
85
88
|
providerRegistry.registerProvider(openaiProvider);
|
|
86
89
|
}
|
|
87
90
|
};
|
|
88
|
-
/**
|
|
89
|
-
* Ollama provider plugin
|
|
90
|
-
*/
|
|
91
|
-
const ollamaProviderPlugin = {
|
|
92
|
-
id: '@jupyterlite/ai:ollama-provider',
|
|
93
|
-
description: 'Register Ollama provider',
|
|
94
|
-
autoStart: true,
|
|
95
|
-
requires: [IProviderRegistry],
|
|
96
|
-
activate: (app, providerRegistry) => {
|
|
97
|
-
providerRegistry.registerProvider(ollamaProvider);
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
91
|
/**
|
|
101
92
|
* Generic provider plugin
|
|
102
93
|
*/
|
|
@@ -478,6 +469,7 @@ const agentManagerFactory = SecretsManager.sign(SECRETS_NAMESPACE, token => ({
|
|
|
478
469
|
});
|
|
479
470
|
settingsWidget.id = 'jupyterlite-ai-settings';
|
|
480
471
|
settingsWidget.title.icon = settingsIcon;
|
|
472
|
+
settingsWidget.title.iconClass = 'jp-ai-settings-icon';
|
|
481
473
|
// Build the completion provider
|
|
482
474
|
if (completionManager) {
|
|
483
475
|
const completionProvider = new AICompletionProvider({
|
|
@@ -498,6 +490,7 @@ const agentManagerFactory = SecretsManager.sign(SECRETS_NAMESPACE, token => ({
|
|
|
498
490
|
label: 'AI Settings',
|
|
499
491
|
caption: 'Configure AI providers and behavior',
|
|
500
492
|
icon: settingsIcon,
|
|
493
|
+
iconClass: 'jp-ai-settings-icon',
|
|
501
494
|
execute: () => {
|
|
502
495
|
// Check if the widget already exists in shell
|
|
503
496
|
let widget = Array.from(app.shell.widgets('main')).find(w => w.id === 'jupyterlite-ai-settings');
|
|
@@ -537,15 +530,30 @@ const settingsModel = {
|
|
|
537
530
|
return new AISettingsModel({ settingRegistry });
|
|
538
531
|
}
|
|
539
532
|
};
|
|
533
|
+
/**
|
|
534
|
+
* Diff manager plugin
|
|
535
|
+
*/
|
|
536
|
+
const diffManager = {
|
|
537
|
+
id: '@jupyterlite/ai:diff-manager',
|
|
538
|
+
description: 'Provide the diff manager for notebook cell diffs',
|
|
539
|
+
autoStart: true,
|
|
540
|
+
provides: IDiffManager,
|
|
541
|
+
requires: [IAISettingsModel],
|
|
542
|
+
activate: (app, settingsModel) => {
|
|
543
|
+
return new DiffManager({
|
|
544
|
+
commands: app.commands,
|
|
545
|
+
settingsModel
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
};
|
|
540
549
|
const toolRegistry = {
|
|
541
550
|
id: '@jupyterlite/ai:tool-registry',
|
|
542
551
|
description: 'Provide the AI tool registry',
|
|
543
552
|
autoStart: true,
|
|
544
553
|
requires: [IAISettingsModel, IDocumentManager, IKernelSpecManager],
|
|
545
|
-
optional: [INotebookTracker],
|
|
554
|
+
optional: [INotebookTracker, IDiffManager, IEditorTracker],
|
|
546
555
|
provides: IToolRegistry,
|
|
547
|
-
activate: (app, settingsModel, docManager, kernelSpecManager, notebookTracker) => {
|
|
548
|
-
const { commands } = app;
|
|
556
|
+
activate: (app, settingsModel, docManager, kernelSpecManager, notebookTracker, diffManager, editorTracker) => {
|
|
549
557
|
const toolRegistry = new ToolRegistry();
|
|
550
558
|
const notebookCreationTool = createNotebookCreationTool(docManager, kernelSpecManager);
|
|
551
559
|
toolRegistry.add('create_notebook', notebookCreationTool);
|
|
@@ -553,7 +561,7 @@ const toolRegistry = {
|
|
|
553
561
|
const addCellTool = createAddCellTool(docManager, notebookTracker);
|
|
554
562
|
const getNotebookInfoTool = createGetNotebookInfoTool(docManager, notebookTracker);
|
|
555
563
|
const getCellInfoTool = createGetCellInfoTool(docManager, notebookTracker);
|
|
556
|
-
const setCellContentTool = createSetCellContentTool(docManager,
|
|
564
|
+
const setCellContentTool = createSetCellContentTool(docManager, notebookTracker, diffManager);
|
|
557
565
|
const runCellTool = createRunCellTool(docManager, notebookTracker);
|
|
558
566
|
const deleteCellTool = createDeleteCellTool(docManager, notebookTracker);
|
|
559
567
|
const saveNotebookTool = createSaveNotebookTool(docManager, notebookTracker);
|
|
@@ -573,12 +581,16 @@ const toolRegistry = {
|
|
|
573
581
|
const renameFileTool = createRenameFileTool(docManager);
|
|
574
582
|
const copyFileTool = createCopyFileTool(docManager);
|
|
575
583
|
const navigateToDirectoryTool = createNavigateToDirectoryTool(app.commands);
|
|
584
|
+
const getFileInfoTool = createGetFileInfoTool(docManager, editorTracker);
|
|
585
|
+
const setFileContentTool = createSetFileContentTool(docManager, diffManager);
|
|
576
586
|
toolRegistry.add('create_file', newFileTool);
|
|
577
587
|
toolRegistry.add('open_file', openFileTool);
|
|
578
588
|
toolRegistry.add('delete_file', deleteFileTool);
|
|
579
589
|
toolRegistry.add('rename_file', renameFileTool);
|
|
580
590
|
toolRegistry.add('copy_file', copyFileTool);
|
|
581
591
|
toolRegistry.add('navigate_to_directory', navigateToDirectoryTool);
|
|
592
|
+
toolRegistry.add('get_file_info', getFileInfoTool);
|
|
593
|
+
toolRegistry.add('set_file_content', setFileContentTool);
|
|
582
594
|
// Add command operation tools
|
|
583
595
|
const discoverCommandsTool = createDiscoverCommandsTool(app.commands);
|
|
584
596
|
const executeCommandTool = createExecuteCommandTool(app.commands, settingsModel);
|
|
@@ -591,7 +603,7 @@ const toolRegistry = {
|
|
|
591
603
|
* Extension providing the input toolbar registry.
|
|
592
604
|
*/
|
|
593
605
|
const inputToolbarFactory = {
|
|
594
|
-
id: '
|
|
606
|
+
id: '@jupyterlite/ai:input-toolbar-factory',
|
|
595
607
|
description: 'The input toolbar registry plugin.',
|
|
596
608
|
autoStart: true,
|
|
597
609
|
provides: IInputToolbarRegistryFactory,
|
|
@@ -623,20 +635,39 @@ const inputToolbarFactory = {
|
|
|
623
635
|
};
|
|
624
636
|
}
|
|
625
637
|
};
|
|
638
|
+
const completionStatus = {
|
|
639
|
+
id: '@jupyterlite/ai:completion-status',
|
|
640
|
+
description: 'The completion status displayed in the status bar',
|
|
641
|
+
autoStart: true,
|
|
642
|
+
requires: [IAISettingsModel],
|
|
643
|
+
optional: [IStatusBar],
|
|
644
|
+
activate: (app, settingsModel, statusBar) => {
|
|
645
|
+
if (!statusBar) {
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
const item = new CompletionStatusWidget({ settingsModel });
|
|
649
|
+
statusBar?.registerStatusItem('completionState', {
|
|
650
|
+
item,
|
|
651
|
+
align: 'right',
|
|
652
|
+
rank: 10
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
};
|
|
626
656
|
export default [
|
|
627
657
|
providerRegistryPlugin,
|
|
628
658
|
anthropicProviderPlugin,
|
|
629
659
|
googleProviderPlugin,
|
|
630
660
|
mistralProviderPlugin,
|
|
631
661
|
openaiProviderPlugin,
|
|
632
|
-
ollamaProviderPlugin,
|
|
633
662
|
genericProviderPlugin,
|
|
634
663
|
settingsModel,
|
|
664
|
+
diffManager,
|
|
635
665
|
chatModelRegistry,
|
|
636
666
|
plugin,
|
|
637
667
|
toolRegistry,
|
|
638
668
|
agentManagerFactory,
|
|
639
|
-
inputToolbarFactory
|
|
669
|
+
inputToolbarFactory,
|
|
670
|
+
completionStatus
|
|
640
671
|
];
|
|
641
672
|
// Export extension points for other extensions to use
|
|
642
673
|
export * from './tokens';
|
|
@@ -36,10 +36,14 @@ export interface IAIConfig {
|
|
|
36
36
|
contextAwareness: boolean;
|
|
37
37
|
codeExecution: boolean;
|
|
38
38
|
systemPrompt: string;
|
|
39
|
+
completionSystemPrompt: string;
|
|
39
40
|
toolsEnabled: boolean;
|
|
40
41
|
sendWithShiftEnter: boolean;
|
|
41
42
|
showTokenUsage: boolean;
|
|
42
43
|
commandsRequiringApproval: string[];
|
|
44
|
+
showCellDiff: boolean;
|
|
45
|
+
showFileDiff: boolean;
|
|
46
|
+
diffDisplayMode: 'split' | 'unified';
|
|
43
47
|
}
|
|
44
48
|
export declare class AISettingsModel extends VDomModel {
|
|
45
49
|
private _config;
|
|
@@ -13,6 +13,9 @@ export class AISettingsModel extends VDomModel {
|
|
|
13
13
|
toolsEnabled: true,
|
|
14
14
|
sendWithShiftEnter: false,
|
|
15
15
|
showTokenUsage: false,
|
|
16
|
+
showCellDiff: true,
|
|
17
|
+
showFileDiff: true,
|
|
18
|
+
diffDisplayMode: 'split',
|
|
16
19
|
commandsRequiringApproval: [
|
|
17
20
|
'notebook:restart-run-all',
|
|
18
21
|
'notebook:run-cell',
|
|
@@ -97,7 +100,18 @@ When users request complex tasks that require multiple steps (like "create a not
|
|
|
97
100
|
|
|
98
101
|
Always think through multi-step tasks and use tools to fully complete the user's request rather than stopping after just one action.
|
|
99
102
|
|
|
100
|
-
Ready to help you build something great! What are you working on
|
|
103
|
+
Ready to help you build something great! What are you working on?`,
|
|
104
|
+
// Completion system prompt - also defined in schema/settings-model.json
|
|
105
|
+
// This serves as a fallback if settings fail to load or are not available
|
|
106
|
+
completionSystemPrompt: `You are an AI code completion assistant. Complete the given code fragment with appropriate code.
|
|
107
|
+
Rules:
|
|
108
|
+
- Return only the completion text, no explanations or comments
|
|
109
|
+
- Do not include code block markers (\`\`\` or similar)
|
|
110
|
+
- Make completions contextually relevant to the surrounding code and notebook context
|
|
111
|
+
- Follow the language-specific conventions and style guidelines for the detected programming language
|
|
112
|
+
- Keep completions concise but functional
|
|
113
|
+
- Do not repeat the existing code that comes before the cursor
|
|
114
|
+
- Use variables, imports, functions, and other definitions from previous notebook cells when relevant`
|
|
101
115
|
};
|
|
102
116
|
_settingRegistry;
|
|
103
117
|
_settings = null;
|
|
@@ -152,7 +166,7 @@ Ready to help you build something great! What are you working on?`
|
|
|
152
166
|
}
|
|
153
167
|
return this._config.activeCompleterProvider
|
|
154
168
|
? this.getProvider(this._config.activeCompleterProvider)
|
|
155
|
-
:
|
|
169
|
+
: undefined;
|
|
156
170
|
}
|
|
157
171
|
async addProvider(providerConfig) {
|
|
158
172
|
const id = `${providerConfig.provider}-${Date.now()}`;
|
|
@@ -205,6 +219,11 @@ Ready to help you build something great! What are you working on?`
|
|
|
205
219
|
return;
|
|
206
220
|
}
|
|
207
221
|
Object.assign(provider, updates);
|
|
222
|
+
Object.keys(provider).forEach(key => {
|
|
223
|
+
if (key !== 'id' && updates[key] === undefined) {
|
|
224
|
+
delete provider[key];
|
|
225
|
+
}
|
|
226
|
+
});
|
|
208
227
|
await this.saveSetting('providers', this._config.providers);
|
|
209
228
|
}
|
|
210
229
|
async setActiveProvider(id) {
|
|
@@ -284,6 +303,9 @@ Ready to help you build something great! What are you working on?`
|
|
|
284
303
|
if (value !== undefined) {
|
|
285
304
|
await this._settings.set(key, value);
|
|
286
305
|
}
|
|
306
|
+
else {
|
|
307
|
+
await this._settings.remove(key);
|
|
308
|
+
}
|
|
287
309
|
}
|
|
288
310
|
}
|
|
289
311
|
catch (error) {
|
|
@@ -15,10 +15,6 @@ export declare const mistralProvider: IProviderInfo;
|
|
|
15
15
|
* OpenAI provider
|
|
16
16
|
*/
|
|
17
17
|
export declare const openaiProvider: IProviderInfo;
|
|
18
|
-
/**
|
|
19
|
-
* Ollama provider
|
|
20
|
-
*/
|
|
21
|
-
export declare const ollamaProvider: IProviderInfo;
|
|
22
18
|
/**
|
|
23
19
|
* Generic OpenAI-compatible provider
|
|
24
20
|
*/
|
|
@@ -2,7 +2,7 @@ import { createAnthropic } from '@ai-sdk/anthropic';
|
|
|
2
2
|
import { createGoogleGenerativeAI } from '@ai-sdk/google';
|
|
3
3
|
import { createMistral } from '@ai-sdk/mistral';
|
|
4
4
|
import { createOpenAI } from '@ai-sdk/openai';
|
|
5
|
-
import {
|
|
5
|
+
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
|
|
6
6
|
/**
|
|
7
7
|
* Anthropic provider
|
|
8
8
|
*/
|
|
@@ -13,6 +13,8 @@ export const anthropicProvider = {
|
|
|
13
13
|
defaultModels: [
|
|
14
14
|
'claude-sonnet-4-5',
|
|
15
15
|
'claude-sonnet-4-5-20250929',
|
|
16
|
+
'claude-haiku-4-5',
|
|
17
|
+
'claude-haiku-4-5-20251001',
|
|
16
18
|
'claude-opus-4-1',
|
|
17
19
|
'claude-opus-4-0',
|
|
18
20
|
'claude-sonnet-4-0',
|
|
@@ -192,25 +194,6 @@ export const openaiProvider = {
|
|
|
192
194
|
return openai(modelName);
|
|
193
195
|
}
|
|
194
196
|
};
|
|
195
|
-
/**
|
|
196
|
-
* Ollama provider
|
|
197
|
-
*/
|
|
198
|
-
export const ollamaProvider = {
|
|
199
|
-
id: 'ollama',
|
|
200
|
-
name: 'Ollama',
|
|
201
|
-
apiKeyRequirement: 'none',
|
|
202
|
-
defaultModels: [],
|
|
203
|
-
supportsBaseURL: true,
|
|
204
|
-
supportsHeaders: true,
|
|
205
|
-
factory: (options) => {
|
|
206
|
-
const ollama = createOllama({
|
|
207
|
-
baseURL: options.baseURL || 'http://localhost:11434/api',
|
|
208
|
-
...(options.headers && { headers: options.headers })
|
|
209
|
-
});
|
|
210
|
-
const modelName = options.model || 'phi3';
|
|
211
|
-
return ollama(modelName);
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
197
|
/**
|
|
215
198
|
* Generic OpenAI-compatible provider
|
|
216
199
|
*/
|
|
@@ -223,13 +206,24 @@ export const genericProvider = {
|
|
|
223
206
|
supportsHeaders: true,
|
|
224
207
|
supportsToolCalling: true,
|
|
225
208
|
description: 'Uses /chat/completions endpoint',
|
|
209
|
+
baseUrls: [
|
|
210
|
+
{
|
|
211
|
+
url: 'http://localhost:4000',
|
|
212
|
+
description: 'Default for local LiteLLM server'
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
url: 'http://localhost:11434/v1',
|
|
216
|
+
description: 'Default for local Ollama server'
|
|
217
|
+
}
|
|
218
|
+
],
|
|
226
219
|
factory: (options) => {
|
|
227
|
-
const
|
|
220
|
+
const openaiCompatible = createOpenAICompatible({
|
|
221
|
+
name: options.provider,
|
|
228
222
|
apiKey: options.apiKey || 'dummy',
|
|
229
|
-
|
|
223
|
+
baseURL: options.baseURL ?? '',
|
|
230
224
|
...(options.headers && { headers: options.headers })
|
|
231
225
|
});
|
|
232
226
|
const modelName = options.model || 'gpt-4o';
|
|
233
|
-
return
|
|
227
|
+
return openaiCompatible(modelName);
|
|
234
228
|
}
|
|
235
229
|
};
|
package/lib/tokens.d.ts
CHANGED
|
@@ -130,6 +130,13 @@ export interface IProviderInfo {
|
|
|
130
130
|
* Optional description shown in the UI
|
|
131
131
|
*/
|
|
132
132
|
description?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Optional URL suggestions
|
|
135
|
+
*/
|
|
136
|
+
baseUrls?: {
|
|
137
|
+
url: string;
|
|
138
|
+
description?: string;
|
|
139
|
+
}[];
|
|
133
140
|
/**
|
|
134
141
|
* Factory function for creating language models
|
|
135
142
|
*/
|
|
@@ -190,3 +197,70 @@ export interface IChatModelRegistry {
|
|
|
190
197
|
createModel(name?: string, activeProvider?: string, tokenUsage?: ITokenUsage): AIChatModel;
|
|
191
198
|
}
|
|
192
199
|
export declare const IChatModelRegistry: Token<IChatModelRegistry>;
|
|
200
|
+
/**
|
|
201
|
+
* Parameters for showing cell diff
|
|
202
|
+
*/
|
|
203
|
+
export interface IShowCellDiffParams {
|
|
204
|
+
/**
|
|
205
|
+
* Original cell content
|
|
206
|
+
*/
|
|
207
|
+
original: string;
|
|
208
|
+
/**
|
|
209
|
+
* Modified cell content
|
|
210
|
+
*/
|
|
211
|
+
modified: string;
|
|
212
|
+
/**
|
|
213
|
+
* Optional cell ID
|
|
214
|
+
*/
|
|
215
|
+
cellId?: string;
|
|
216
|
+
/**
|
|
217
|
+
* Whether to show action buttons in the diff view
|
|
218
|
+
*/
|
|
219
|
+
showActionButtons?: boolean;
|
|
220
|
+
/**
|
|
221
|
+
* Whether to open the diff view
|
|
222
|
+
*/
|
|
223
|
+
openDiff?: boolean;
|
|
224
|
+
/**
|
|
225
|
+
* Optional path to the notebook
|
|
226
|
+
*/
|
|
227
|
+
notebookPath?: string;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Parameters for showing file diff
|
|
231
|
+
*/
|
|
232
|
+
export interface IShowFileDiffParams {
|
|
233
|
+
/**
|
|
234
|
+
* Original file content
|
|
235
|
+
*/
|
|
236
|
+
original: string;
|
|
237
|
+
/**
|
|
238
|
+
* Modified file content
|
|
239
|
+
*/
|
|
240
|
+
modified: string;
|
|
241
|
+
/**
|
|
242
|
+
* Optional file path
|
|
243
|
+
*/
|
|
244
|
+
filePath?: string;
|
|
245
|
+
/**
|
|
246
|
+
* Whether to show action buttons in the diff view
|
|
247
|
+
*/
|
|
248
|
+
showActionButtons?: boolean;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Interface for managing diff operations
|
|
252
|
+
*/
|
|
253
|
+
export interface IDiffManager {
|
|
254
|
+
/**
|
|
255
|
+
* Show diff between original and modified cell content
|
|
256
|
+
*/
|
|
257
|
+
showCellDiff(params: IShowCellDiffParams): Promise<void>;
|
|
258
|
+
/**
|
|
259
|
+
* Show diff between original and modified file content
|
|
260
|
+
*/
|
|
261
|
+
showFileDiff(params: IShowFileDiffParams): Promise<void>;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Token for the diff manager.
|
|
265
|
+
*/
|
|
266
|
+
export declare const IDiffManager: Token<IDiffManager>;
|
package/lib/tokens.js
CHANGED
|
@@ -35,3 +35,7 @@ export const SECRETS_REPLACEMENT = '***';
|
|
|
35
35
|
*/
|
|
36
36
|
export const IAgentManagerFactory = new Token('@jupyterlite/ai:agent-manager-factory');
|
|
37
37
|
export const IChatModelRegistry = new Token('@jupyterlite/ai:chat-model-registry');
|
|
38
|
+
/**
|
|
39
|
+
* Token for the diff manager.
|
|
40
|
+
*/
|
|
41
|
+
export const IDiffManager = new Token('@jupyterlite/ai:diff-manager');
|
package/lib/tools/commands.js
CHANGED
|
@@ -15,43 +15,44 @@ export function createDiscoverCommandsTool(commands) {
|
|
|
15
15
|
.nullable()
|
|
16
16
|
.describe('Optional search query to filter commands')
|
|
17
17
|
}),
|
|
18
|
-
execute: async () => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
18
|
+
execute: async (input) => {
|
|
19
|
+
const { query } = input;
|
|
20
|
+
const commandList = [];
|
|
21
|
+
// Get all command IDs
|
|
22
|
+
const commandIds = commands.listCommands();
|
|
23
|
+
for (const id of commandIds) {
|
|
24
|
+
// Get command metadata using various CommandRegistry methods
|
|
25
|
+
const description = await commands.describedBy(id);
|
|
26
|
+
const label = commands.label(id);
|
|
27
|
+
const caption = commands.caption(id);
|
|
28
|
+
const usage = commands.usage(id);
|
|
29
|
+
const command = {
|
|
30
|
+
id,
|
|
31
|
+
label: label || undefined,
|
|
32
|
+
caption: caption || undefined,
|
|
33
|
+
description: usage || undefined,
|
|
34
|
+
args: description?.args || undefined
|
|
35
|
+
};
|
|
36
|
+
// Filter by query if provided
|
|
37
|
+
if (query) {
|
|
38
|
+
const searchTerm = query.toLowerCase();
|
|
39
|
+
const matchesQuery = id.toLowerCase().includes(searchTerm) ||
|
|
40
|
+
label?.toLowerCase().includes(searchTerm) ||
|
|
41
|
+
caption?.toLowerCase().includes(searchTerm) ||
|
|
42
|
+
usage?.toLowerCase().includes(searchTerm);
|
|
43
|
+
if (matchesQuery) {
|
|
44
|
+
commandList.push(command);
|
|
41
45
|
}
|
|
42
46
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
commands: commandList
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
catch (error) {
|
|
50
|
-
return {
|
|
51
|
-
success: false,
|
|
52
|
-
error: `Failed to discover commands: ${error instanceof Error ? error.message : String(error)}`
|
|
53
|
-
};
|
|
47
|
+
else {
|
|
48
|
+
commandList.push(command);
|
|
49
|
+
}
|
|
54
50
|
}
|
|
51
|
+
return {
|
|
52
|
+
success: true,
|
|
53
|
+
commandCount: commandList.length,
|
|
54
|
+
commands: commandList
|
|
55
|
+
};
|
|
55
56
|
}
|
|
56
57
|
});
|
|
57
58
|
}
|
|
@@ -69,7 +70,7 @@ export function createExecuteCommandTool(commands, settingsModel) {
|
|
|
69
70
|
.optional()
|
|
70
71
|
.describe('Optional arguments to pass to the command')
|
|
71
72
|
}),
|
|
72
|
-
needsApproval: async (
|
|
73
|
+
needsApproval: async (context, { commandId }) => {
|
|
73
74
|
// Use configurable list of commands requiring approval
|
|
74
75
|
const commandsRequiringApproval = settingsModel.config.commandsRequiringApproval;
|
|
75
76
|
return commandsRequiringApproval.some(cmd => commandId.includes(cmd) || cmd.includes(commandId));
|