@jupyterlite/ai 0.8.1 → 0.9.0-a0

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.
Files changed (162) hide show
  1. package/lib/agent.d.ts +233 -0
  2. package/lib/agent.js +604 -0
  3. package/lib/chat-model.d.ts +195 -0
  4. package/lib/chat-model.js +590 -0
  5. package/lib/completion/completion-provider.d.ts +83 -0
  6. package/lib/completion/completion-provider.js +209 -0
  7. package/lib/completion/index.d.ts +1 -0
  8. package/lib/completion/index.js +1 -0
  9. package/lib/components/clear-button.d.ts +18 -0
  10. package/lib/components/clear-button.js +31 -0
  11. package/lib/components/index.d.ts +3 -0
  12. package/lib/components/index.js +3 -0
  13. package/lib/components/model-select.d.ts +19 -0
  14. package/lib/components/model-select.js +154 -0
  15. package/lib/components/stop-button.d.ts +3 -3
  16. package/lib/components/stop-button.js +8 -9
  17. package/lib/components/token-usage-display.d.ts +45 -0
  18. package/lib/components/token-usage-display.js +74 -0
  19. package/lib/components/tool-select.d.ts +27 -0
  20. package/lib/components/tool-select.js +130 -0
  21. package/lib/icons.d.ts +3 -1
  22. package/lib/icons.js +10 -13
  23. package/lib/index.d.ts +4 -5
  24. package/lib/index.js +322 -167
  25. package/lib/mcp/browser.d.ts +68 -0
  26. package/lib/mcp/browser.js +132 -0
  27. package/lib/models/settings-model.d.ts +69 -0
  28. package/lib/models/settings-model.js +295 -0
  29. package/lib/providers/built-in-providers.d.ts +9 -0
  30. package/lib/providers/built-in-providers.js +192 -0
  31. package/lib/providers/models.d.ts +37 -0
  32. package/lib/providers/models.js +28 -0
  33. package/lib/providers/provider-registry.d.ts +94 -0
  34. package/lib/providers/provider-registry.js +155 -0
  35. package/lib/tokens.d.ts +157 -86
  36. package/lib/tokens.js +16 -12
  37. package/lib/tools/commands.d.ts +11 -0
  38. package/lib/tools/commands.js +126 -0
  39. package/lib/tools/file.d.ts +27 -0
  40. package/lib/tools/file.js +262 -0
  41. package/lib/tools/notebook.d.ts +40 -0
  42. package/lib/tools/notebook.js +762 -0
  43. package/lib/tools/tool-registry.d.ts +35 -0
  44. package/lib/tools/tool-registry.js +55 -0
  45. package/lib/widgets/ai-settings.d.ts +39 -0
  46. package/lib/widgets/ai-settings.js +506 -0
  47. package/lib/widgets/chat-wrapper.d.ts +144 -0
  48. package/lib/widgets/chat-wrapper.js +390 -0
  49. package/lib/widgets/provider-config-dialog.d.ts +13 -0
  50. package/lib/widgets/provider-config-dialog.js +104 -0
  51. package/package.json +150 -41
  52. package/schema/settings-model.json +153 -0
  53. package/src/agent.ts +800 -0
  54. package/src/chat-model.ts +770 -0
  55. package/src/completion/completion-provider.ts +308 -0
  56. package/src/completion/index.ts +1 -0
  57. package/src/components/clear-button.tsx +56 -0
  58. package/src/components/index.ts +3 -0
  59. package/src/components/model-select.tsx +245 -0
  60. package/src/components/stop-button.tsx +11 -11
  61. package/src/components/token-usage-display.tsx +130 -0
  62. package/src/components/tool-select.tsx +218 -0
  63. package/src/icons.ts +12 -14
  64. package/src/index.ts +468 -238
  65. package/src/mcp/browser.ts +213 -0
  66. package/src/models/settings-model.ts +409 -0
  67. package/src/providers/built-in-providers.ts +216 -0
  68. package/src/providers/models.ts +79 -0
  69. package/src/providers/provider-registry.ts +189 -0
  70. package/src/tokens.ts +203 -90
  71. package/src/tools/commands.ts +151 -0
  72. package/src/tools/file.ts +307 -0
  73. package/src/tools/notebook.ts +964 -0
  74. package/src/tools/tool-registry.ts +63 -0
  75. package/src/types.d.ts +4 -0
  76. package/src/widgets/ai-settings.tsx +1100 -0
  77. package/src/widgets/chat-wrapper.tsx +543 -0
  78. package/src/widgets/provider-config-dialog.tsx +256 -0
  79. package/style/base.css +335 -14
  80. package/style/icons/jupyternaut-lite.svg +1 -1
  81. package/lib/base-completer.d.ts +0 -49
  82. package/lib/base-completer.js +0 -14
  83. package/lib/chat-handler.d.ts +0 -56
  84. package/lib/chat-handler.js +0 -201
  85. package/lib/completion-provider.d.ts +0 -34
  86. package/lib/completion-provider.js +0 -32
  87. package/lib/default-prompts.d.ts +0 -2
  88. package/lib/default-prompts.js +0 -31
  89. package/lib/default-providers/Anthropic/completer.d.ts +0 -12
  90. package/lib/default-providers/Anthropic/completer.js +0 -46
  91. package/lib/default-providers/Anthropic/settings-schema.json +0 -70
  92. package/lib/default-providers/ChromeAI/completer.d.ts +0 -12
  93. package/lib/default-providers/ChromeAI/completer.js +0 -56
  94. package/lib/default-providers/ChromeAI/instructions.d.ts +0 -6
  95. package/lib/default-providers/ChromeAI/instructions.js +0 -42
  96. package/lib/default-providers/ChromeAI/settings-schema.json +0 -18
  97. package/lib/default-providers/Gemini/completer.d.ts +0 -12
  98. package/lib/default-providers/Gemini/completer.js +0 -48
  99. package/lib/default-providers/Gemini/instructions.d.ts +0 -2
  100. package/lib/default-providers/Gemini/instructions.js +0 -9
  101. package/lib/default-providers/Gemini/settings-schema.json +0 -64
  102. package/lib/default-providers/MistralAI/completer.d.ts +0 -13
  103. package/lib/default-providers/MistralAI/completer.js +0 -52
  104. package/lib/default-providers/MistralAI/instructions.d.ts +0 -2
  105. package/lib/default-providers/MistralAI/instructions.js +0 -18
  106. package/lib/default-providers/MistralAI/settings-schema.json +0 -75
  107. package/lib/default-providers/Ollama/completer.d.ts +0 -12
  108. package/lib/default-providers/Ollama/completer.js +0 -43
  109. package/lib/default-providers/Ollama/instructions.d.ts +0 -2
  110. package/lib/default-providers/Ollama/instructions.js +0 -70
  111. package/lib/default-providers/Ollama/settings-schema.json +0 -143
  112. package/lib/default-providers/OpenAI/completer.d.ts +0 -12
  113. package/lib/default-providers/OpenAI/completer.js +0 -43
  114. package/lib/default-providers/OpenAI/settings-schema.json +0 -628
  115. package/lib/default-providers/WebLLM/completer.d.ts +0 -21
  116. package/lib/default-providers/WebLLM/completer.js +0 -127
  117. package/lib/default-providers/WebLLM/instructions.d.ts +0 -6
  118. package/lib/default-providers/WebLLM/instructions.js +0 -32
  119. package/lib/default-providers/WebLLM/settings-schema.json +0 -19
  120. package/lib/default-providers/index.d.ts +0 -2
  121. package/lib/default-providers/index.js +0 -179
  122. package/lib/provider.d.ts +0 -144
  123. package/lib/provider.js +0 -412
  124. package/lib/settings/base.json +0 -7
  125. package/lib/settings/index.d.ts +0 -3
  126. package/lib/settings/index.js +0 -3
  127. package/lib/settings/panel.d.ts +0 -226
  128. package/lib/settings/panel.js +0 -510
  129. package/lib/settings/textarea.d.ts +0 -2
  130. package/lib/settings/textarea.js +0 -18
  131. package/lib/settings/utils.d.ts +0 -2
  132. package/lib/settings/utils.js +0 -4
  133. package/lib/types/ai-model.d.ts +0 -24
  134. package/lib/types/ai-model.js +0 -5
  135. package/schema/chat.json +0 -28
  136. package/schema/provider-registry.json +0 -29
  137. package/schema/system-prompts.json +0 -22
  138. package/src/base-completer.ts +0 -75
  139. package/src/chat-handler.ts +0 -262
  140. package/src/completion-provider.ts +0 -64
  141. package/src/default-prompts.ts +0 -33
  142. package/src/default-providers/Anthropic/completer.ts +0 -59
  143. package/src/default-providers/ChromeAI/completer.ts +0 -73
  144. package/src/default-providers/ChromeAI/instructions.ts +0 -45
  145. package/src/default-providers/Gemini/completer.ts +0 -61
  146. package/src/default-providers/Gemini/instructions.ts +0 -9
  147. package/src/default-providers/MistralAI/completer.ts +0 -69
  148. package/src/default-providers/MistralAI/instructions.ts +0 -18
  149. package/src/default-providers/Ollama/completer.ts +0 -54
  150. package/src/default-providers/Ollama/instructions.ts +0 -70
  151. package/src/default-providers/OpenAI/completer.ts +0 -54
  152. package/src/default-providers/WebLLM/completer.ts +0 -151
  153. package/src/default-providers/WebLLM/instructions.ts +0 -33
  154. package/src/default-providers/index.ts +0 -211
  155. package/src/global.d.ts +0 -9
  156. package/src/provider.ts +0 -514
  157. package/src/settings/index.ts +0 -3
  158. package/src/settings/panel.tsx +0 -773
  159. package/src/settings/textarea.tsx +0 -33
  160. package/src/settings/utils.ts +0 -5
  161. package/src/types/ai-model.ts +0 -37
  162. package/src/types/service-worker.d.ts +0 -6
package/lib/index.js CHANGED
@@ -1,83 +1,145 @@
1
- import { ActiveCellManager, buildChatSidebar, buildErrorWidget, ChatCommandRegistry, IChatCommandRegistry, InputToolbarRegistry } from '@jupyter/chat';
2
- import { ILayoutRestorer } from '@jupyterlab/application';
3
- import { IThemeManager } from '@jupyterlab/apputils';
1
+ import { ILabShell, ILayoutRestorer } from '@jupyterlab/application';
2
+ import { ActiveCellManager, AttachmentOpenerRegistry, ChatWidget, InputToolbarRegistry } from '@jupyter/chat';
3
+ import { ICommandPalette, IThemeManager } from '@jupyterlab/apputils';
4
4
  import { ICompletionProviderManager } from '@jupyterlab/completer';
5
+ import { IDocumentManager } from '@jupyterlab/docmanager';
5
6
  import { INotebookTracker } from '@jupyterlab/notebook';
6
7
  import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
8
+ import { IKernelSpecManager } from '@jupyterlab/services';
7
9
  import { ISettingRegistry } from '@jupyterlab/settingregistry';
8
- import { IFormRendererRegistry } from '@jupyterlab/ui-components';
9
- import { ISecretsManager, SecretsManager } from 'jupyter-secrets-manager';
10
- import { ChatHandler, welcomeMessage } from './chat-handler';
11
- import { CompletionProvider } from './completion-provider';
12
- import { defaultProviderPlugins } from './default-providers';
13
- import { AIProviderRegistry } from './provider';
14
- import { aiSettingsRenderer, textArea } from './settings';
15
- import { IAIProviderRegistry, PLUGIN_IDS } from './tokens';
10
+ import { settingsIcon } from '@jupyterlab/ui-components';
11
+ import { AgentManager } from './agent';
12
+ import { AIChatModel } from './chat-model';
13
+ import { ChatProviderRegistry, CompletionProviderRegistry } from './providers/provider-registry';
14
+ import { IChatProviderRegistry, ICompletionProviderRegistry, IAISettingsModel, IToolRegistry } from './tokens';
15
+ import { registerBuiltInChatProviders, registerBuiltInCompletionProviders } from './providers/built-in-providers';
16
+ import { AICompletionProvider } from './completion';
17
+ import { clearItem } from './components/clear-button';
18
+ import { createModelSelectItem } from './components/model-select';
16
19
  import { stopItem } from './components/stop-button';
17
- const chatCommandRegistryPlugin = {
18
- id: PLUGIN_IDS.chatCommandRegistry,
19
- description: 'Autocompletion registry',
20
+ import { createToolSelectItem } from './components/tool-select';
21
+ import { AISettingsModel } from './models/settings-model';
22
+ import { ToolRegistry } from './tools/tool-registry';
23
+ import { createAddCellTool, createDeleteCellTool, createExecuteActiveCellTool, createGetCellInfoTool, createGetNotebookInfoTool, createNotebookCreationTool, createRunCellTool, createSaveNotebookTool, createSetCellContentTool } from './tools/notebook';
24
+ import { createCopyFileTool, createDeleteFileTool, createNavigateToDirectoryTool, createNewFileTool, createOpenFileTool, createRenameFileTool } from './tools/file';
25
+ import { createDiscoverCommandsTool, createExecuteCommandTool } from './tools/commands';
26
+ import { AISettingsWidget } from './widgets/ai-settings';
27
+ import { ChatWrapperWidget } from './widgets/chat-wrapper';
28
+ /**
29
+ * Command IDs namespace
30
+ */
31
+ var CommandIds;
32
+ (function (CommandIds) {
33
+ CommandIds.openSettings = '@jupyterlite/ai:open-settings';
34
+ CommandIds.reposition = '@jupyterlite/ai:reposition';
35
+ })(CommandIds || (CommandIds = {}));
36
+ /**
37
+ * Chat provider registry plugin
38
+ */
39
+ const chatProviderRegistryPlugin = {
40
+ id: '@jupyterlite/ai:chat-provider-registry',
41
+ description: 'Chat AI provider registry',
20
42
  autoStart: true,
21
- provides: IChatCommandRegistry,
43
+ provides: IChatProviderRegistry,
22
44
  activate: () => {
23
- const registry = new ChatCommandRegistry();
24
- registry.addProvider(new ChatHandler.ClearCommandProvider());
25
- return registry;
45
+ return new ChatProviderRegistry();
26
46
  }
27
47
  };
28
- const chatPlugin = {
29
- id: PLUGIN_IDS.chat,
30
- description: 'LLM chat extension',
48
+ /**
49
+ * Completion provider registry plugin
50
+ */
51
+ const completionProviderRegistryPlugin = {
52
+ id: '@jupyterlite/ai:completion-provider-registry',
53
+ description: 'Completion provider registry',
31
54
  autoStart: true,
32
- requires: [IAIProviderRegistry, IRenderMimeRegistry, IChatCommandRegistry],
55
+ provides: ICompletionProviderRegistry,
56
+ activate: () => {
57
+ return new CompletionProviderRegistry();
58
+ }
59
+ };
60
+ /**
61
+ * Built-in chat providers plugin
62
+ */
63
+ const builtInChatProvidersPlugin = {
64
+ id: '@jupyterlite/ai:built-in-chat-providers',
65
+ description: 'Register built-in chat AI providers',
66
+ autoStart: true,
67
+ requires: [IChatProviderRegistry],
68
+ activate: (app, chatRegistry) => {
69
+ registerBuiltInChatProviders(chatRegistry);
70
+ }
71
+ };
72
+ /**
73
+ * Built-in completion providers plugin
74
+ */
75
+ const builtInCompletionProvidersPlugin = {
76
+ id: '@jupyterlite/ai:built-in-completion-providers',
77
+ description: 'Register built-in completion providers',
78
+ autoStart: true,
79
+ requires: [ICompletionProviderRegistry],
80
+ activate: (app, completionRegistry) => {
81
+ registerBuiltInCompletionProviders(completionRegistry);
82
+ }
83
+ };
84
+ /**
85
+ * Initialization data for the extension.
86
+ */
87
+ const plugin = {
88
+ id: '@jupyterlite/ai:plugin',
89
+ description: 'AI in JupyterLab',
90
+ autoStart: true,
91
+ requires: [
92
+ IAISettingsModel,
93
+ IToolRegistry,
94
+ IRenderMimeRegistry,
95
+ IDocumentManager,
96
+ IChatProviderRegistry
97
+ ],
33
98
  optional: [
34
- INotebookTracker,
35
- ISettingRegistry,
36
99
  IThemeManager,
37
- ILayoutRestorer
100
+ ICommandPalette,
101
+ INotebookTracker,
102
+ ILayoutRestorer,
103
+ ILabShell
38
104
  ],
39
- activate: async (app, providerRegistry, rmRegistry, chatCommandRegistry, notebookTracker, settingsRegistry, themeManager, restorer) => {
40
- let activeCellManager = null;
105
+ activate: (app, settingsModel, toolRegistry, rmRegistry, docManager, chatProviderRegistry, themeManager, palette, notebookTracker, restorer, labShell) => {
106
+ // Create ActiveCellManager if notebook tracker is available
107
+ let activeCellManager;
41
108
  if (notebookTracker) {
42
109
  activeCellManager = new ActiveCellManager({
43
110
  tracker: notebookTracker,
44
111
  shell: app.shell
45
112
  });
46
113
  }
47
- const chatHandler = new ChatHandler({
48
- providerRegistry,
49
- activeCellManager
114
+ // Create Agent Manager first so it can be shared
115
+ const agentManager = new AgentManager({
116
+ settingsModel,
117
+ toolRegistry,
118
+ chatProviderRegistry: chatProviderRegistry
50
119
  });
51
- let sendWithShiftEnter = false;
52
- let enableCodeToolbar = true;
53
- let personaName = 'AI';
54
- function loadSetting(setting) {
55
- sendWithShiftEnter = setting.get('sendWithShiftEnter')
56
- .composite;
57
- enableCodeToolbar = setting.get('enableCodeToolbar').composite;
58
- personaName = setting.get('personaName').composite;
59
- // set the properties
60
- chatHandler.config = { sendWithShiftEnter, enableCodeToolbar };
61
- chatHandler.personaName = personaName;
62
- }
63
- Promise.all([app.restored, settingsRegistry?.load(chatPlugin.id)])
64
- .then(([, settings]) => {
65
- if (!settings) {
66
- console.warn('The SettingsRegistry is not loaded for the chat extension');
67
- return;
68
- }
69
- loadSetting(settings);
70
- settings.changed.connect(loadSetting);
71
- })
72
- .catch(reason => {
73
- console.error(`Something went wrong when reading the settings.\n${reason}`);
120
+ // Create AI chat model
121
+ const chatModel = new AIChatModel({
122
+ user: { username: 'user', display_name: 'User' },
123
+ settingsModel,
124
+ agentManager,
125
+ activeCellManager,
126
+ documentManager: docManager
74
127
  });
75
- let chatWidget = null;
128
+ // Create input toolbar registry with all buttons
76
129
  const inputToolbarRegistry = InputToolbarRegistry.defaultToolbarRegistry();
77
- const stopButton = stopItem(() => chatHandler.stopStreaming());
130
+ const stopButton = stopItem();
131
+ const clearButton = clearItem();
132
+ const toolSelectButton = createToolSelectItem(toolRegistry, settingsModel.config.toolsEnabled);
133
+ const modelSelectButton = createModelSelectItem(settingsModel);
78
134
  inputToolbarRegistry.addItem('stop', stopButton);
79
- chatHandler.writersChanged.connect((_, writers) => {
80
- if (writers.filter(writer => writer.user.username === chatHandler.personaName).length) {
135
+ inputToolbarRegistry.addItem('clear', clearButton);
136
+ inputToolbarRegistry.addItem('model', modelSelectButton);
137
+ inputToolbarRegistry.addItem('tools', toolSelectButton);
138
+ // Listen to writers changes to show/hide stop button
139
+ chatModel.writersChanged.connect((_, writers) => {
140
+ // Check if AI is currently writing (streaming)
141
+ const aiWriting = writers.some(writer => writer.user.username === 'ai-assistant');
142
+ if (aiWriting) {
81
143
  inputToolbarRegistry.hide('send');
82
144
  inputToolbarRegistry.show('stop');
83
145
  }
@@ -86,131 +148,224 @@ const chatPlugin = {
86
148
  inputToolbarRegistry.show('send');
87
149
  }
88
150
  });
89
- try {
90
- chatWidget = buildChatSidebar({
91
- model: chatHandler,
92
- themeManager,
93
- rmRegistry,
94
- chatCommandRegistry,
95
- inputToolbarRegistry,
96
- welcomeMessage: welcomeMessage(providerRegistry.providers)
97
- });
98
- }
99
- catch (e) {
100
- chatWidget = buildErrorWidget(themeManager);
101
- }
102
- chatWidget.title.caption = 'Jupyterlite AI Chat';
103
- chatWidget.id = '@jupyterlite/ai:chat-widget';
104
- app.shell.add(chatWidget, 'left', { rank: 2000 });
151
+ // Listen for settings changes to update tool availability
152
+ settingsModel.stateChanged.connect(() => {
153
+ const config = settingsModel.config;
154
+ if (!config.toolsEnabled) {
155
+ inputToolbarRegistry.hide('tools');
156
+ }
157
+ else {
158
+ inputToolbarRegistry.show('tools');
159
+ }
160
+ });
161
+ // Create attachment opener registry to handle file attachments
162
+ const attachmentOpenerRegistry = new AttachmentOpenerRegistry();
163
+ attachmentOpenerRegistry.set('file', attachment => {
164
+ app.commands.execute('docmanager:open', { path: attachment.value });
165
+ });
166
+ attachmentOpenerRegistry.set('notebook', attachment => {
167
+ app.commands.execute('docmanager:open', { path: attachment.value });
168
+ });
169
+ // Create chat panel with drag/drop functionality
170
+ const chatPanel = new ChatWidget({
171
+ model: chatModel,
172
+ rmRegistry,
173
+ themeManager,
174
+ inputToolbarRegistry,
175
+ attachmentOpenerRegistry
176
+ });
177
+ // Create wrapper widget with a toolbar
178
+ const chatWrapper = new ChatWrapperWidget({
179
+ chatPanel,
180
+ commands: app.commands,
181
+ chatModel,
182
+ settingsModel
183
+ });
184
+ app.shell.add(chatWrapper, 'left', { rank: 1000 });
185
+ const settingsWidget = new AISettingsWidget({
186
+ settingsModel,
187
+ agentManager,
188
+ themeManager,
189
+ chatProviderRegistry
190
+ });
191
+ settingsWidget.id = 'jupyterlite-ai-settings';
192
+ settingsWidget.title.icon = settingsIcon;
105
193
  if (restorer) {
106
- restorer.add(chatWidget, chatWidget.id);
194
+ restorer.add(chatWrapper, chatWrapper.id);
195
+ restorer.add(settingsWidget, settingsWidget.id);
107
196
  }
197
+ registerCommands(app, palette, settingsWidget, labShell);
108
198
  }
109
199
  };
110
- const completerPlugin = {
111
- id: PLUGIN_IDS.completer,
112
- autoStart: true,
113
- requires: [IAIProviderRegistry, ICompletionProviderManager],
114
- activate: (app, providerRegistry, manager) => {
115
- const completer = new CompletionProvider({
116
- providerRegistry,
117
- requestCompletion: () => app.commands.execute('inline-completer:invoke')
118
- });
119
- manager.registerInlineProvider(completer);
120
- }
121
- };
122
- const providerRegistryPlugin = SecretsManager.sign(PLUGIN_IDS.providerRegistry, token => ({
123
- id: PLUGIN_IDS.providerRegistry,
124
- autoStart: true,
125
- requires: [IFormRendererRegistry, ISettingRegistry],
126
- optional: [IRenderMimeRegistry, ISecretsManager],
127
- provides: IAIProviderRegistry,
128
- activate: (app, editorRegistry, settingRegistry, rmRegistry, secretsManager) => {
129
- const providerRegistry = new AIProviderRegistry({
130
- token,
131
- secretsManager
132
- });
133
- editorRegistry.addRenderer(`${PLUGIN_IDS.providerRegistry}.AIproviders`, aiSettingsRenderer({
134
- providerRegistry,
135
- secretsToken: token,
136
- rmRegistry,
137
- secretsManager
138
- }));
139
- settingRegistry
140
- .load(providerRegistryPlugin.id)
141
- .then(settings => {
142
- if (!secretsManager) {
143
- delete settings.schema.properties?.['UseSecretsManager'];
200
+ function registerCommands(app, palette, settingsWidget, labShell) {
201
+ const { commands } = app;
202
+ commands.addCommand(CommandIds.openSettings, {
203
+ label: 'AI Settings',
204
+ caption: 'Configure AI providers and behavior',
205
+ icon: settingsIcon,
206
+ execute: () => {
207
+ // Check if the widget already exists in shell
208
+ let widget = Array.from(app.shell.widgets('main')).find(w => w.id === 'jupyterlite-ai-settings');
209
+ if (!widget && settingsWidget) {
210
+ // Use the pre-created widget
211
+ widget = settingsWidget;
212
+ app.shell.add(widget, 'main');
213
+ }
214
+ if (widget) {
215
+ app.shell.activateById(widget.id);
144
216
  }
145
- const updateProvider = () => {
146
- // Get the Ai provider settings.
147
- const providerSettings = settings.get('AIproviders')
148
- .composite;
149
- // Update completer provider.
150
- if (Object.keys(providerSettings).includes('completer')) {
151
- providerRegistry.setCompleterProvider(providerSettings['completer']);
217
+ },
218
+ describedBy: {
219
+ args: {}
220
+ }
221
+ });
222
+ if (labShell) {
223
+ commands.addCommand(CommandIds.reposition, {
224
+ label: 'Reposition Widget',
225
+ execute: (args) => {
226
+ const { widgetId, area, mode } = args;
227
+ const widget = widgetId
228
+ ? Array.from(labShell.widgets('main')).find(w => w.id === widgetId) ||
229
+ labShell.currentWidget
230
+ : labShell.currentWidget;
231
+ if (!widget) {
232
+ return;
152
233
  }
153
- else {
154
- providerRegistry.setCompleterProvider({});
234
+ if (area && area !== 'main') {
235
+ // Move to different area
236
+ labShell.move(widget, area);
237
+ labShell.activateById(widget.id);
155
238
  }
156
- // Update chat provider.
157
- if (Object.keys(providerSettings).includes('chat')) {
158
- providerRegistry.setChatProvider(providerSettings['chat']);
239
+ else if (mode) {
240
+ // Reposition within main area using split mode
241
+ labShell.add(widget, 'main', { mode, activate: true });
159
242
  }
160
- else {
161
- providerRegistry.setChatProvider({});
243
+ },
244
+ describedBy: {
245
+ args: {
246
+ type: 'object',
247
+ properties: {
248
+ widgetId: {
249
+ type: 'string',
250
+ description: 'The widget ID to reposition in the application shell'
251
+ },
252
+ area: {
253
+ type: 'string',
254
+ description: 'The name of the area to reposition the widget to'
255
+ },
256
+ mode: {
257
+ type: 'string',
258
+ enum: ['split-left', 'split-right', 'split-top', 'split-bottom'],
259
+ description: 'The mode to use when repositioning the widget'
260
+ }
261
+ }
162
262
  }
163
- };
164
- settings.changed.connect(() => updateProvider());
165
- updateProvider();
166
- })
167
- .catch(reason => {
168
- console.error(`Failed to load settings for ${providerRegistryPlugin.id}`, reason);
263
+ }
264
+ });
265
+ }
266
+ // Add to command palette if available
267
+ if (palette) {
268
+ palette.addItem({
269
+ command: CommandIds.openSettings,
270
+ category: 'AI Assistant'
169
271
  });
170
- return providerRegistry;
171
272
  }
172
- }));
173
- const systemPromptsPlugin = {
174
- id: PLUGIN_IDS.systemPrompts,
273
+ }
274
+ /**
275
+ * A plugin to provide AI-powered code completion.
276
+ */
277
+ const completionPlugin = {
278
+ id: '@jupyterlite/ai:completion',
279
+ description: 'AI-powered code completion',
175
280
  autoStart: true,
176
- requires: [IAIProviderRegistry, ISettingRegistry],
177
- optional: [IFormRendererRegistry],
178
- activate: (app, providerRegistry, settingsRegistry, editorRegistry) => {
179
- // Set textarea renderer for the prompt setting.
180
- editorRegistry?.addRenderer(`${PLUGIN_IDS.systemPrompts}.chatSystemPrompt`, textArea);
181
- editorRegistry?.addRenderer(`${PLUGIN_IDS.systemPrompts}.completionSystemPrompt`, textArea);
182
- /**
183
- * Update the prompts in the provider registry.
184
- */
185
- function loadSetting(setting) {
186
- providerRegistry.chatSystemPrompt = setting.get('chatSystemPrompt')
187
- .composite;
188
- providerRegistry.completerSystemPrompt = setting.get('completionSystemPrompt').composite;
281
+ requires: [IAISettingsModel, ICompletionProviderRegistry],
282
+ optional: [ICompletionProviderManager],
283
+ activate: (app, settingsModel, completionProviderRegistry, manager) => {
284
+ if (!manager) {
285
+ console.info('Completion provider manager not available, skipping AI completion setup');
286
+ return;
189
287
  }
190
- Promise.all([
191
- app.restored,
192
- settingsRegistry?.load(PLUGIN_IDS.systemPrompts)
193
- ])
194
- .then(([, settings]) => {
195
- if (!settings) {
196
- console.warn('The SettingsRegistry is not loaded for the chat extension');
197
- return;
198
- }
199
- loadSetting(settings);
200
- settings.changed.connect(loadSetting);
201
- })
202
- .catch(reason => {
203
- console.error(`Something went wrong when reading the settings.\n${reason}`);
288
+ const completionProvider = new AICompletionProvider({
289
+ settingsModel,
290
+ completionProviderRegistry: completionProviderRegistry
204
291
  });
292
+ manager.registerInlineProvider(completionProvider);
293
+ }
294
+ };
295
+ /**
296
+ * A plugin to provide the settings model.
297
+ */
298
+ const settingsModel = {
299
+ id: '@jupyterlite/ai:settings-model',
300
+ description: 'Provide the AI settings model',
301
+ autoStart: true,
302
+ provides: IAISettingsModel,
303
+ requires: [ISettingRegistry],
304
+ activate: (app, settingRegistry) => {
305
+ return new AISettingsModel({ settingRegistry });
306
+ }
307
+ };
308
+ /**
309
+ * A plugin to provide the tool registry.
310
+ */
311
+ const toolRegistry = {
312
+ id: '@jupyterlite/ai:tool-registry',
313
+ description: 'Provide the AI tool registry',
314
+ autoStart: true,
315
+ requires: [IAISettingsModel, IDocumentManager, IKernelSpecManager],
316
+ optional: [INotebookTracker],
317
+ provides: IToolRegistry,
318
+ activate: (app, settingsModel, docManager, kernelSpecManager, notebookTracker) => {
319
+ const toolRegistry = new ToolRegistry();
320
+ const notebookCreationTool = createNotebookCreationTool(docManager, kernelSpecManager);
321
+ toolRegistry.add('create_notebook', notebookCreationTool);
322
+ // Add high-level notebook operation tools
323
+ const addCellTool = createAddCellTool(docManager, notebookTracker);
324
+ const getNotebookInfoTool = createGetNotebookInfoTool(docManager, notebookTracker);
325
+ const getCellInfoTool = createGetCellInfoTool(docManager, notebookTracker);
326
+ const setCellContentTool = createSetCellContentTool(docManager, notebookTracker);
327
+ const runCellTool = createRunCellTool(docManager, notebookTracker);
328
+ const deleteCellTool = createDeleteCellTool(docManager, notebookTracker);
329
+ const saveNotebookTool = createSaveNotebookTool(docManager, notebookTracker);
330
+ const executeActiveCellTool = createExecuteActiveCellTool(docManager, notebookTracker);
331
+ toolRegistry.add('add_cell', addCellTool);
332
+ toolRegistry.add('get_notebook_info', getNotebookInfoTool);
333
+ toolRegistry.add('get_cell_info', getCellInfoTool);
334
+ toolRegistry.add('set_cell_content', setCellContentTool);
335
+ toolRegistry.add('run_cell', runCellTool);
336
+ toolRegistry.add('delete_cell', deleteCellTool);
337
+ toolRegistry.add('save_notebook', saveNotebookTool);
338
+ toolRegistry.add('execute_active_cell', executeActiveCellTool);
339
+ // Add file operation tools
340
+ const newFileTool = createNewFileTool(docManager);
341
+ const openFileTool = createOpenFileTool(docManager);
342
+ const deleteFileTool = createDeleteFileTool(docManager);
343
+ const renameFileTool = createRenameFileTool(docManager);
344
+ const copyFileTool = createCopyFileTool(docManager);
345
+ const navigateToDirectoryTool = createNavigateToDirectoryTool(app.commands);
346
+ toolRegistry.add('create_file', newFileTool);
347
+ toolRegistry.add('open_file', openFileTool);
348
+ toolRegistry.add('delete_file', deleteFileTool);
349
+ toolRegistry.add('rename_file', renameFileTool);
350
+ toolRegistry.add('copy_file', copyFileTool);
351
+ toolRegistry.add('navigate_to_directory', navigateToDirectoryTool);
352
+ // Add command operation tools
353
+ const discoverCommandsTool = createDiscoverCommandsTool(app.commands);
354
+ const executeCommandTool = createExecuteCommandTool(app.commands, settingsModel);
355
+ toolRegistry.add('discover_commands', discoverCommandsTool);
356
+ toolRegistry.add('execute_command', executeCommandTool);
357
+ return toolRegistry;
205
358
  }
206
359
  };
207
360
  export default [
208
- providerRegistryPlugin,
209
- chatCommandRegistryPlugin,
210
- chatPlugin,
211
- completerPlugin,
212
- systemPromptsPlugin,
213
- ...defaultProviderPlugins
361
+ chatProviderRegistryPlugin,
362
+ completionProviderRegistryPlugin,
363
+ builtInChatProvidersPlugin,
364
+ builtInCompletionProvidersPlugin,
365
+ plugin,
366
+ completionPlugin,
367
+ settingsModel,
368
+ toolRegistry
214
369
  ];
215
- export { IAIProviderRegistry } from './tokens';
216
- export * from './base-completer';
370
+ // Export extension points for other extensions to use
371
+ export * from './tokens';
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Browser-compatible MCP Server implementation
3
+ *
4
+ * This is a custom implementation that works around the limitation in
5
+ * @openai/agents where MCPServerStreamableHttp doesn't work in browsers
6
+ */
7
+ interface MCPServer {
8
+ cacheToolsList: boolean;
9
+ toolFilter?: any;
10
+ connect(): Promise<void>;
11
+ readonly name: string;
12
+ close(): Promise<void>;
13
+ listTools(): Promise<MCPTool[]>;
14
+ callTool(toolName: string, args: Record<string, unknown> | null): Promise<CallToolResultContent>;
15
+ invalidateToolsCache(): Promise<void>;
16
+ }
17
+ interface MCPTool {
18
+ name: string;
19
+ description?: string;
20
+ inputSchema: {
21
+ type: 'object';
22
+ properties: Record<string, any>;
23
+ required: string[];
24
+ additionalProperties: boolean;
25
+ };
26
+ }
27
+ type CallToolResultContent = Array<{
28
+ type: string;
29
+ text: string;
30
+ }>;
31
+ interface MCPServerStreamableHttpOptions {
32
+ url: string;
33
+ cacheToolsList?: boolean;
34
+ clientSessionTimeoutSeconds?: number;
35
+ name?: string;
36
+ logger?: any;
37
+ toolFilter?: any;
38
+ timeout?: number;
39
+ authProvider?: any;
40
+ requestInit?: any;
41
+ fetch?: any;
42
+ reconnectionOptions?: any;
43
+ sessionId?: string;
44
+ }
45
+ /**
46
+ * Browser-compatible MCP Server implementation that works around limitations
47
+ * in @openai/agents where MCPServerStreamableHttp doesn't work in browsers.
48
+ *
49
+ * This class provides a streamable HTTP client transport for MCP (Model Context Protocol)
50
+ * servers that can be used in browser environments.
51
+ */
52
+ export declare class BrowserMCPServerStreamableHttp implements MCPServer {
53
+ readonly name: string;
54
+ readonly cacheToolsList: boolean;
55
+ readonly toolFilter: any;
56
+ constructor(options: MCPServerStreamableHttpOptions);
57
+ connect(): Promise<void>;
58
+ close(): Promise<void>;
59
+ listTools(): Promise<MCPTool[]>;
60
+ callTool(toolName: string, args: Record<string, unknown> | null): Promise<CallToolResultContent>;
61
+ invalidateToolsCache(): Promise<void>;
62
+ private _session;
63
+ private _toolsList;
64
+ private _cacheDirty;
65
+ private _transport;
66
+ private _options;
67
+ }
68
+ export {};