@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
package/src/index.ts
CHANGED
|
@@ -26,6 +26,8 @@ import { ICompletionProviderManager } from '@jupyterlab/completer';
|
|
|
26
26
|
|
|
27
27
|
import { IDocumentManager } from '@jupyterlab/docmanager';
|
|
28
28
|
|
|
29
|
+
import { IEditorTracker } from '@jupyterlab/fileeditor';
|
|
30
|
+
|
|
29
31
|
import { INotebookTracker } from '@jupyterlab/notebook';
|
|
30
32
|
|
|
31
33
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
@@ -34,6 +36,8 @@ import { IKernelSpecManager, KernelSpec } from '@jupyterlab/services';
|
|
|
34
36
|
|
|
35
37
|
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
36
38
|
|
|
39
|
+
import { IStatusBar } from '@jupyterlab/statusbar';
|
|
40
|
+
|
|
37
41
|
import {
|
|
38
42
|
settingsIcon,
|
|
39
43
|
Toolbar,
|
|
@@ -61,7 +65,8 @@ import {
|
|
|
61
65
|
IToolRegistry,
|
|
62
66
|
SECRETS_NAMESPACE,
|
|
63
67
|
IAISettingsModel,
|
|
64
|
-
IChatModelRegistry
|
|
68
|
+
IChatModelRegistry,
|
|
69
|
+
IDiffManager
|
|
65
70
|
} from './tokens';
|
|
66
71
|
|
|
67
72
|
import {
|
|
@@ -69,7 +74,6 @@ import {
|
|
|
69
74
|
googleProvider,
|
|
70
75
|
mistralProvider,
|
|
71
76
|
openaiProvider,
|
|
72
|
-
ollamaProvider,
|
|
73
77
|
genericProvider
|
|
74
78
|
} from './providers/built-in-providers';
|
|
75
79
|
|
|
@@ -80,11 +84,14 @@ import {
|
|
|
80
84
|
createModelSelectItem,
|
|
81
85
|
createToolSelectItem,
|
|
82
86
|
stopItem,
|
|
87
|
+
CompletionStatusWidget,
|
|
83
88
|
TokenUsageWidget
|
|
84
89
|
} from './components';
|
|
85
90
|
|
|
86
91
|
import { AISettingsModel } from './models/settings-model';
|
|
87
92
|
|
|
93
|
+
import { DiffManager } from './diff-manager';
|
|
94
|
+
|
|
88
95
|
import { ToolRegistry } from './tools/tool-registry';
|
|
89
96
|
|
|
90
97
|
import {
|
|
@@ -102,10 +109,12 @@ import {
|
|
|
102
109
|
import {
|
|
103
110
|
createCopyFileTool,
|
|
104
111
|
createDeleteFileTool,
|
|
112
|
+
createGetFileInfoTool,
|
|
105
113
|
createNavigateToDirectoryTool,
|
|
106
114
|
createNewFileTool,
|
|
107
115
|
createOpenFileTool,
|
|
108
|
-
createRenameFileTool
|
|
116
|
+
createRenameFileTool,
|
|
117
|
+
createSetFileContentTool
|
|
109
118
|
} from './tools/file';
|
|
110
119
|
|
|
111
120
|
import {
|
|
@@ -182,19 +191,6 @@ const openaiProviderPlugin: JupyterFrontEndPlugin<void> = {
|
|
|
182
191
|
}
|
|
183
192
|
};
|
|
184
193
|
|
|
185
|
-
/**
|
|
186
|
-
* Ollama provider plugin
|
|
187
|
-
*/
|
|
188
|
-
const ollamaProviderPlugin: JupyterFrontEndPlugin<void> = {
|
|
189
|
-
id: '@jupyterlite/ai:ollama-provider',
|
|
190
|
-
description: 'Register Ollama provider',
|
|
191
|
-
autoStart: true,
|
|
192
|
-
requires: [IProviderRegistry],
|
|
193
|
-
activate: (app: JupyterFrontEnd, providerRegistry: IProviderRegistry) => {
|
|
194
|
-
providerRegistry.registerProvider(ollamaProvider);
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
|
|
198
194
|
/**
|
|
199
195
|
* Generic provider plugin
|
|
200
196
|
*/
|
|
@@ -691,6 +687,7 @@ const agentManagerFactory: JupyterFrontEndPlugin<AgentManagerFactory> =
|
|
|
691
687
|
});
|
|
692
688
|
settingsWidget.id = 'jupyterlite-ai-settings';
|
|
693
689
|
settingsWidget.title.icon = settingsIcon;
|
|
690
|
+
settingsWidget.title.iconClass = 'jp-ai-settings-icon';
|
|
694
691
|
|
|
695
692
|
// Build the completion provider
|
|
696
693
|
if (completionManager) {
|
|
@@ -716,6 +713,7 @@ const agentManagerFactory: JupyterFrontEndPlugin<AgentManagerFactory> =
|
|
|
716
713
|
label: 'AI Settings',
|
|
717
714
|
caption: 'Configure AI providers and behavior',
|
|
718
715
|
icon: settingsIcon,
|
|
716
|
+
iconClass: 'jp-ai-settings-icon',
|
|
719
717
|
execute: () => {
|
|
720
718
|
// Check if the widget already exists in shell
|
|
721
719
|
let widget = Array.from(app.shell.widgets('main')).find(
|
|
@@ -763,21 +761,42 @@ const settingsModel: JupyterFrontEndPlugin<AISettingsModel> = {
|
|
|
763
761
|
}
|
|
764
762
|
};
|
|
765
763
|
|
|
764
|
+
/**
|
|
765
|
+
* Diff manager plugin
|
|
766
|
+
*/
|
|
767
|
+
const diffManager: JupyterFrontEndPlugin<IDiffManager> = {
|
|
768
|
+
id: '@jupyterlite/ai:diff-manager',
|
|
769
|
+
description: 'Provide the diff manager for notebook cell diffs',
|
|
770
|
+
autoStart: true,
|
|
771
|
+
provides: IDiffManager,
|
|
772
|
+
requires: [IAISettingsModel],
|
|
773
|
+
activate: (
|
|
774
|
+
app: JupyterFrontEnd,
|
|
775
|
+
settingsModel: AISettingsModel
|
|
776
|
+
): IDiffManager => {
|
|
777
|
+
return new DiffManager({
|
|
778
|
+
commands: app.commands,
|
|
779
|
+
settingsModel
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
};
|
|
783
|
+
|
|
766
784
|
const toolRegistry: JupyterFrontEndPlugin<IToolRegistry> = {
|
|
767
785
|
id: '@jupyterlite/ai:tool-registry',
|
|
768
786
|
description: 'Provide the AI tool registry',
|
|
769
787
|
autoStart: true,
|
|
770
788
|
requires: [IAISettingsModel, IDocumentManager, IKernelSpecManager],
|
|
771
|
-
optional: [INotebookTracker],
|
|
789
|
+
optional: [INotebookTracker, IDiffManager, IEditorTracker],
|
|
772
790
|
provides: IToolRegistry,
|
|
773
791
|
activate: (
|
|
774
792
|
app: JupyterFrontEnd,
|
|
775
793
|
settingsModel: AISettingsModel,
|
|
776
794
|
docManager: IDocumentManager,
|
|
777
795
|
kernelSpecManager: KernelSpec.IManager,
|
|
778
|
-
notebookTracker?: INotebookTracker
|
|
796
|
+
notebookTracker?: INotebookTracker,
|
|
797
|
+
diffManager?: IDiffManager,
|
|
798
|
+
editorTracker?: IEditorTracker
|
|
779
799
|
) => {
|
|
780
|
-
const { commands } = app;
|
|
781
800
|
const toolRegistry = new ToolRegistry();
|
|
782
801
|
|
|
783
802
|
const notebookCreationTool = createNotebookCreationTool(
|
|
@@ -795,8 +814,8 @@ const toolRegistry: JupyterFrontEndPlugin<IToolRegistry> = {
|
|
|
795
814
|
const getCellInfoTool = createGetCellInfoTool(docManager, notebookTracker);
|
|
796
815
|
const setCellContentTool = createSetCellContentTool(
|
|
797
816
|
docManager,
|
|
798
|
-
|
|
799
|
-
|
|
817
|
+
notebookTracker,
|
|
818
|
+
diffManager
|
|
800
819
|
);
|
|
801
820
|
const runCellTool = createRunCellTool(docManager, notebookTracker);
|
|
802
821
|
const deleteCellTool = createDeleteCellTool(docManager, notebookTracker);
|
|
@@ -825,6 +844,11 @@ const toolRegistry: JupyterFrontEndPlugin<IToolRegistry> = {
|
|
|
825
844
|
const renameFileTool = createRenameFileTool(docManager);
|
|
826
845
|
const copyFileTool = createCopyFileTool(docManager);
|
|
827
846
|
const navigateToDirectoryTool = createNavigateToDirectoryTool(app.commands);
|
|
847
|
+
const getFileInfoTool = createGetFileInfoTool(docManager, editorTracker);
|
|
848
|
+
const setFileContentTool = createSetFileContentTool(
|
|
849
|
+
docManager,
|
|
850
|
+
diffManager
|
|
851
|
+
);
|
|
828
852
|
|
|
829
853
|
toolRegistry.add('create_file', newFileTool);
|
|
830
854
|
toolRegistry.add('open_file', openFileTool);
|
|
@@ -832,6 +856,8 @@ const toolRegistry: JupyterFrontEndPlugin<IToolRegistry> = {
|
|
|
832
856
|
toolRegistry.add('rename_file', renameFileTool);
|
|
833
857
|
toolRegistry.add('copy_file', copyFileTool);
|
|
834
858
|
toolRegistry.add('navigate_to_directory', navigateToDirectoryTool);
|
|
859
|
+
toolRegistry.add('get_file_info', getFileInfoTool);
|
|
860
|
+
toolRegistry.add('set_file_content', setFileContentTool);
|
|
835
861
|
|
|
836
862
|
// Add command operation tools
|
|
837
863
|
const discoverCommandsTool = createDiscoverCommandsTool(app.commands);
|
|
@@ -852,7 +878,7 @@ const toolRegistry: JupyterFrontEndPlugin<IToolRegistry> = {
|
|
|
852
878
|
*/
|
|
853
879
|
const inputToolbarFactory: JupyterFrontEndPlugin<IInputToolbarRegistryFactory> =
|
|
854
880
|
{
|
|
855
|
-
id: '
|
|
881
|
+
id: '@jupyterlite/ai:input-toolbar-factory',
|
|
856
882
|
description: 'The input toolbar registry plugin.',
|
|
857
883
|
autoStart: true,
|
|
858
884
|
provides: IInputToolbarRegistryFactory,
|
|
@@ -895,20 +921,44 @@ const inputToolbarFactory: JupyterFrontEndPlugin<IInputToolbarRegistryFactory> =
|
|
|
895
921
|
}
|
|
896
922
|
};
|
|
897
923
|
|
|
924
|
+
const completionStatus: JupyterFrontEndPlugin<void> = {
|
|
925
|
+
id: '@jupyterlite/ai:completion-status',
|
|
926
|
+
description: 'The completion status displayed in the status bar',
|
|
927
|
+
autoStart: true,
|
|
928
|
+
requires: [IAISettingsModel],
|
|
929
|
+
optional: [IStatusBar],
|
|
930
|
+
activate: (
|
|
931
|
+
app: JupyterFrontEnd,
|
|
932
|
+
settingsModel: AISettingsModel,
|
|
933
|
+
statusBar: IStatusBar | null
|
|
934
|
+
) => {
|
|
935
|
+
if (!statusBar) {
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
const item = new CompletionStatusWidget({ settingsModel });
|
|
939
|
+
statusBar?.registerStatusItem('completionState', {
|
|
940
|
+
item,
|
|
941
|
+
align: 'right',
|
|
942
|
+
rank: 10
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
};
|
|
946
|
+
|
|
898
947
|
export default [
|
|
899
948
|
providerRegistryPlugin,
|
|
900
949
|
anthropicProviderPlugin,
|
|
901
950
|
googleProviderPlugin,
|
|
902
951
|
mistralProviderPlugin,
|
|
903
952
|
openaiProviderPlugin,
|
|
904
|
-
ollamaProviderPlugin,
|
|
905
953
|
genericProviderPlugin,
|
|
906
954
|
settingsModel,
|
|
955
|
+
diffManager,
|
|
907
956
|
chatModelRegistry,
|
|
908
957
|
plugin,
|
|
909
958
|
toolRegistry,
|
|
910
959
|
agentManagerFactory,
|
|
911
|
-
inputToolbarFactory
|
|
960
|
+
inputToolbarFactory,
|
|
961
|
+
completionStatus
|
|
912
962
|
];
|
|
913
963
|
|
|
914
964
|
// Export extension points for other extensions to use
|
|
@@ -48,6 +48,7 @@ export interface IAIConfig {
|
|
|
48
48
|
contextAwareness: boolean;
|
|
49
49
|
codeExecution: boolean;
|
|
50
50
|
systemPrompt: string;
|
|
51
|
+
completionSystemPrompt: string;
|
|
51
52
|
toolsEnabled: boolean;
|
|
52
53
|
// Chat behavior settings
|
|
53
54
|
sendWithShiftEnter: boolean;
|
|
@@ -55,6 +56,10 @@ export interface IAIConfig {
|
|
|
55
56
|
showTokenUsage: boolean;
|
|
56
57
|
// Commands that require approval before execution
|
|
57
58
|
commandsRequiringApproval: string[];
|
|
59
|
+
// Diff display settings
|
|
60
|
+
showCellDiff: boolean;
|
|
61
|
+
showFileDiff: boolean;
|
|
62
|
+
diffDisplayMode: 'split' | 'unified';
|
|
58
63
|
}
|
|
59
64
|
|
|
60
65
|
export class AISettingsModel extends VDomModel {
|
|
@@ -70,6 +75,9 @@ export class AISettingsModel extends VDomModel {
|
|
|
70
75
|
toolsEnabled: true,
|
|
71
76
|
sendWithShiftEnter: false,
|
|
72
77
|
showTokenUsage: false,
|
|
78
|
+
showCellDiff: true,
|
|
79
|
+
showFileDiff: true,
|
|
80
|
+
diffDisplayMode: 'split',
|
|
73
81
|
commandsRequiringApproval: [
|
|
74
82
|
'notebook:restart-run-all',
|
|
75
83
|
'notebook:run-cell',
|
|
@@ -154,7 +162,18 @@ When users request complex tasks that require multiple steps (like "create a not
|
|
|
154
162
|
|
|
155
163
|
Always think through multi-step tasks and use tools to fully complete the user's request rather than stopping after just one action.
|
|
156
164
|
|
|
157
|
-
Ready to help you build something great! What are you working on
|
|
165
|
+
Ready to help you build something great! What are you working on?`,
|
|
166
|
+
// Completion system prompt - also defined in schema/settings-model.json
|
|
167
|
+
// This serves as a fallback if settings fail to load or are not available
|
|
168
|
+
completionSystemPrompt: `You are an AI code completion assistant. Complete the given code fragment with appropriate code.
|
|
169
|
+
Rules:
|
|
170
|
+
- Return only the completion text, no explanations or comments
|
|
171
|
+
- Do not include code block markers (\`\`\` or similar)
|
|
172
|
+
- Make completions contextually relevant to the surrounding code and notebook context
|
|
173
|
+
- Follow the language-specific conventions and style guidelines for the detected programming language
|
|
174
|
+
- Keep completions concise but functional
|
|
175
|
+
- Do not repeat the existing code that comes before the cursor
|
|
176
|
+
- Use variables, imports, functions, and other definitions from previous notebook cells when relevant`
|
|
158
177
|
};
|
|
159
178
|
|
|
160
179
|
private _settingRegistry: ISettingRegistry;
|
|
@@ -222,7 +241,7 @@ Ready to help you build something great! What are you working on?`
|
|
|
222
241
|
}
|
|
223
242
|
return this._config.activeCompleterProvider
|
|
224
243
|
? this.getProvider(this._config.activeCompleterProvider)
|
|
225
|
-
:
|
|
244
|
+
: undefined;
|
|
226
245
|
}
|
|
227
246
|
|
|
228
247
|
async addProvider(
|
|
@@ -292,6 +311,11 @@ Ready to help you build something great! What are you working on?`
|
|
|
292
311
|
}
|
|
293
312
|
|
|
294
313
|
Object.assign(provider, updates);
|
|
314
|
+
Object.keys(provider).forEach(key => {
|
|
315
|
+
if (key !== 'id' && updates[key] === undefined) {
|
|
316
|
+
delete provider[key];
|
|
317
|
+
}
|
|
318
|
+
});
|
|
295
319
|
await this.saveSetting('providers', this._config.providers);
|
|
296
320
|
}
|
|
297
321
|
|
|
@@ -397,6 +421,8 @@ Ready to help you build something great! What are you working on?`
|
|
|
397
421
|
// Only save the specific setting that changed
|
|
398
422
|
if (value !== undefined) {
|
|
399
423
|
await this._settings.set(key, value as any);
|
|
424
|
+
} else {
|
|
425
|
+
await this._settings.remove(key);
|
|
400
426
|
}
|
|
401
427
|
}
|
|
402
428
|
} catch (error) {
|
|
@@ -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
|
import type { IProviderInfo } from '../tokens';
|
|
8
8
|
import type { IModelOptions } from './models';
|
|
@@ -17,6 +17,8 @@ export const anthropicProvider: IProviderInfo = {
|
|
|
17
17
|
defaultModels: [
|
|
18
18
|
'claude-sonnet-4-5',
|
|
19
19
|
'claude-sonnet-4-5-20250929',
|
|
20
|
+
'claude-haiku-4-5',
|
|
21
|
+
'claude-haiku-4-5-20251001',
|
|
20
22
|
'claude-opus-4-1',
|
|
21
23
|
'claude-opus-4-0',
|
|
22
24
|
'claude-sonnet-4-0',
|
|
@@ -200,26 +202,6 @@ export const openaiProvider: IProviderInfo = {
|
|
|
200
202
|
}
|
|
201
203
|
};
|
|
202
204
|
|
|
203
|
-
/**
|
|
204
|
-
* Ollama provider
|
|
205
|
-
*/
|
|
206
|
-
export const ollamaProvider: IProviderInfo = {
|
|
207
|
-
id: 'ollama',
|
|
208
|
-
name: 'Ollama',
|
|
209
|
-
apiKeyRequirement: 'none',
|
|
210
|
-
defaultModels: [],
|
|
211
|
-
supportsBaseURL: true,
|
|
212
|
-
supportsHeaders: true,
|
|
213
|
-
factory: (options: IModelOptions) => {
|
|
214
|
-
const ollama = createOllama({
|
|
215
|
-
baseURL: options.baseURL || 'http://localhost:11434/api',
|
|
216
|
-
...(options.headers && { headers: options.headers })
|
|
217
|
-
});
|
|
218
|
-
const modelName = options.model || 'phi3';
|
|
219
|
-
return ollama(modelName);
|
|
220
|
-
}
|
|
221
|
-
};
|
|
222
|
-
|
|
223
205
|
/**
|
|
224
206
|
* Generic OpenAI-compatible provider
|
|
225
207
|
*/
|
|
@@ -232,13 +214,24 @@ export const genericProvider: IProviderInfo = {
|
|
|
232
214
|
supportsHeaders: true,
|
|
233
215
|
supportsToolCalling: true,
|
|
234
216
|
description: 'Uses /chat/completions endpoint',
|
|
217
|
+
baseUrls: [
|
|
218
|
+
{
|
|
219
|
+
url: 'http://localhost:4000',
|
|
220
|
+
description: 'Default for local LiteLLM server'
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
url: 'http://localhost:11434/v1',
|
|
224
|
+
description: 'Default for local Ollama server'
|
|
225
|
+
}
|
|
226
|
+
],
|
|
235
227
|
factory: (options: IModelOptions) => {
|
|
236
|
-
const
|
|
228
|
+
const openaiCompatible = createOpenAICompatible({
|
|
229
|
+
name: options.provider,
|
|
237
230
|
apiKey: options.apiKey || 'dummy',
|
|
238
|
-
|
|
231
|
+
baseURL: options.baseURL ?? '',
|
|
239
232
|
...(options.headers && { headers: options.headers })
|
|
240
233
|
});
|
|
241
234
|
const modelName = options.model || 'gpt-4o';
|
|
242
|
-
return
|
|
235
|
+
return openaiCompatible(modelName);
|
|
243
236
|
}
|
|
244
237
|
};
|
package/src/tokens.ts
CHANGED
|
@@ -159,6 +159,11 @@ export interface IProviderInfo {
|
|
|
159
159
|
*/
|
|
160
160
|
description?: string;
|
|
161
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Optional URL suggestions
|
|
164
|
+
*/
|
|
165
|
+
baseUrls?: { url: string; description?: string }[];
|
|
166
|
+
|
|
162
167
|
/**
|
|
163
168
|
* Factory function for creating language models
|
|
164
169
|
*/
|
|
@@ -250,3 +255,76 @@ export interface IChatModelRegistry {
|
|
|
250
255
|
export const IChatModelRegistry = new Token<IChatModelRegistry>(
|
|
251
256
|
'@jupyterlite/ai:chat-model-registry'
|
|
252
257
|
);
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Parameters for showing cell diff
|
|
261
|
+
*/
|
|
262
|
+
export interface IShowCellDiffParams {
|
|
263
|
+
/**
|
|
264
|
+
* Original cell content
|
|
265
|
+
*/
|
|
266
|
+
original: string;
|
|
267
|
+
/**
|
|
268
|
+
* Modified cell content
|
|
269
|
+
*/
|
|
270
|
+
modified: string;
|
|
271
|
+
/**
|
|
272
|
+
* Optional cell ID
|
|
273
|
+
*/
|
|
274
|
+
cellId?: string;
|
|
275
|
+
/**
|
|
276
|
+
* Whether to show action buttons in the diff view
|
|
277
|
+
*/
|
|
278
|
+
showActionButtons?: boolean;
|
|
279
|
+
/**
|
|
280
|
+
* Whether to open the diff view
|
|
281
|
+
*/
|
|
282
|
+
openDiff?: boolean;
|
|
283
|
+
/**
|
|
284
|
+
* Optional path to the notebook
|
|
285
|
+
*/
|
|
286
|
+
notebookPath?: string;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Parameters for showing file diff
|
|
291
|
+
*/
|
|
292
|
+
export interface IShowFileDiffParams {
|
|
293
|
+
/**
|
|
294
|
+
* Original file content
|
|
295
|
+
*/
|
|
296
|
+
original: string;
|
|
297
|
+
/**
|
|
298
|
+
* Modified file content
|
|
299
|
+
*/
|
|
300
|
+
modified: string;
|
|
301
|
+
/**
|
|
302
|
+
* Optional file path
|
|
303
|
+
*/
|
|
304
|
+
filePath?: string;
|
|
305
|
+
/**
|
|
306
|
+
* Whether to show action buttons in the diff view
|
|
307
|
+
*/
|
|
308
|
+
showActionButtons?: boolean;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Interface for managing diff operations
|
|
313
|
+
*/
|
|
314
|
+
export interface IDiffManager {
|
|
315
|
+
/**
|
|
316
|
+
* Show diff between original and modified cell content
|
|
317
|
+
*/
|
|
318
|
+
showCellDiff(params: IShowCellDiffParams): Promise<void>;
|
|
319
|
+
/**
|
|
320
|
+
* Show diff between original and modified file content
|
|
321
|
+
*/
|
|
322
|
+
showFileDiff(params: IShowFileDiffParams): Promise<void>;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Token for the diff manager.
|
|
327
|
+
*/
|
|
328
|
+
export const IDiffManager = new Token<IDiffManager>(
|
|
329
|
+
'@jupyterlite/ai:diff-manager'
|
|
330
|
+
);
|
package/src/tools/commands.ts
CHANGED
|
@@ -20,51 +20,56 @@ export function createDiscoverCommandsTool(commands: CommandRegistry): ITool {
|
|
|
20
20
|
.nullable()
|
|
21
21
|
.describe('Optional search query to filter commands')
|
|
22
22
|
}),
|
|
23
|
-
execute: async () => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
execute: async (input: { query?: string | null }) => {
|
|
24
|
+
const { query } = input;
|
|
25
|
+
const commandList: Array<{
|
|
26
|
+
id: string;
|
|
27
|
+
label?: string;
|
|
28
|
+
caption?: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
args?: any;
|
|
31
|
+
}> = [];
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
// Get all command IDs
|
|
34
|
+
const commandIds = commands.listCommands();
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
for (const id of commandIds) {
|
|
37
|
+
// Get command metadata using various CommandRegistry methods
|
|
38
|
+
const description = await commands.describedBy(id);
|
|
39
|
+
const label = commands.label(id);
|
|
40
|
+
const caption = commands.caption(id);
|
|
41
|
+
const usage = commands.usage(id);
|
|
42
|
+
|
|
43
|
+
const command = {
|
|
44
|
+
id,
|
|
45
|
+
label: label || undefined,
|
|
46
|
+
caption: caption || undefined,
|
|
47
|
+
description: usage || undefined,
|
|
48
|
+
args: description?.args || undefined
|
|
49
|
+
};
|
|
43
50
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
// Filter by query if provided
|
|
52
|
+
if (query) {
|
|
53
|
+
const searchTerm = query.toLowerCase();
|
|
54
|
+
const matchesQuery =
|
|
55
|
+
id.toLowerCase().includes(searchTerm) ||
|
|
56
|
+
label?.toLowerCase().includes(searchTerm) ||
|
|
57
|
+
caption?.toLowerCase().includes(searchTerm) ||
|
|
58
|
+
usage?.toLowerCase().includes(searchTerm);
|
|
59
|
+
|
|
60
|
+
if (matchesQuery) {
|
|
61
|
+
commandList.push(command);
|
|
54
62
|
}
|
|
63
|
+
} else {
|
|
64
|
+
commandList.push(command);
|
|
55
65
|
}
|
|
56
|
-
|
|
57
|
-
return {
|
|
58
|
-
success: true,
|
|
59
|
-
commandCount: commandList.length,
|
|
60
|
-
commands: commandList
|
|
61
|
-
};
|
|
62
|
-
} catch (error) {
|
|
63
|
-
return {
|
|
64
|
-
success: false,
|
|
65
|
-
error: `Failed to discover commands: ${error instanceof Error ? error.message : String(error)}`
|
|
66
|
-
};
|
|
67
66
|
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
success: true,
|
|
70
|
+
commandCount: commandList.length,
|
|
71
|
+
commands: commandList
|
|
72
|
+
};
|
|
68
73
|
}
|
|
69
74
|
});
|
|
70
75
|
}
|
|
@@ -87,7 +92,7 @@ export function createExecuteCommandTool(
|
|
|
87
92
|
.optional()
|
|
88
93
|
.describe('Optional arguments to pass to the command')
|
|
89
94
|
}),
|
|
90
|
-
needsApproval: async (
|
|
95
|
+
needsApproval: async (context, { commandId }) => {
|
|
91
96
|
// Use configurable list of commands requiring approval
|
|
92
97
|
const commandsRequiringApproval =
|
|
93
98
|
settingsModel.config.commandsRequiringApproval;
|