@jupyterlite/ai 0.8.1 → 0.9.0-a1

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 +243 -0
  2. package/lib/agent.js +627 -0
  3. package/lib/chat-model.d.ts +195 -0
  4. package/lib/chat-model.js +591 -0
  5. package/lib/completion/completion-provider.d.ts +93 -0
  6. package/lib/completion/completion-provider.js +235 -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 +5 -5
  24. package/lib/index.js +341 -169
  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 +70 -0
  28. package/lib/models/settings-model.js +296 -0
  29. package/lib/providers/built-in-providers.d.ts +9 -0
  30. package/lib/providers/built-in-providers.js +266 -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 +167 -86
  36. package/lib/tokens.js +25 -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 +41 -0
  42. package/lib/tools/notebook.js +779 -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 +49 -0
  46. package/lib/widgets/ai-settings.js +580 -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 +14 -0
  50. package/lib/widgets/provider-config-dialog.js +112 -0
  51. package/package.json +151 -40
  52. package/schema/settings-model.json +159 -0
  53. package/src/agent.ts +836 -0
  54. package/src/chat-model.ts +771 -0
  55. package/src/completion/completion-provider.ts +346 -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 +485 -232
  65. package/src/mcp/browser.ts +213 -0
  66. package/src/models/settings-model.ts +413 -0
  67. package/src/providers/built-in-providers.ts +294 -0
  68. package/src/providers/models.ts +79 -0
  69. package/src/providers/provider-registry.ts +189 -0
  70. package/src/tokens.ts +217 -90
  71. package/src/tools/commands.ts +151 -0
  72. package/src/tools/file.ts +307 -0
  73. package/src/tools/notebook.ts +987 -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 +1233 -0
  77. package/src/widgets/chat-wrapper.tsx +543 -0
  78. package/src/widgets/provider-config-dialog.tsx +272 -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,134 @@
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';
10
+ import { settingsIcon } from '@jupyterlab/ui-components';
9
11
  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';
12
+ import { AgentManager } from './agent';
13
+ import { AIChatModel } from './chat-model';
14
+ import { ChatProviderRegistry, CompletionProviderRegistry } from './providers/provider-registry';
15
+ import { IAgentManager, IChatProviderRegistry, ICompletionProviderRegistry, IToolRegistry, SECRETS_NAMESPACE, IAISettingsModel } from './tokens';
16
+ import { registerBuiltInChatProviders, registerBuiltInCompletionProviders } from './providers/built-in-providers';
17
+ import { AICompletionProvider } from './completion';
18
+ import { clearItem } from './components/clear-button';
19
+ import { createModelSelectItem } from './components/model-select';
16
20
  import { stopItem } from './components/stop-button';
17
- const chatCommandRegistryPlugin = {
18
- id: PLUGIN_IDS.chatCommandRegistry,
19
- description: 'Autocompletion registry',
21
+ import { createToolSelectItem } from './components/tool-select';
22
+ import { AISettingsModel } from './models/settings-model';
23
+ import { ToolRegistry } from './tools/tool-registry';
24
+ import { createAddCellTool, createDeleteCellTool, createExecuteActiveCellTool, createGetCellInfoTool, createGetNotebookInfoTool, createNotebookCreationTool, createRunCellTool, createSaveNotebookTool, createSetCellContentTool } from './tools/notebook';
25
+ import { createCopyFileTool, createDeleteFileTool, createNavigateToDirectoryTool, createNewFileTool, createOpenFileTool, createRenameFileTool } from './tools/file';
26
+ import { createDiscoverCommandsTool, createExecuteCommandTool } from './tools/commands';
27
+ import { AISettingsWidget } from './widgets/ai-settings';
28
+ import { ChatWrapperWidget } from './widgets/chat-wrapper';
29
+ /**
30
+ * Command IDs namespace
31
+ */
32
+ var CommandIds;
33
+ (function (CommandIds) {
34
+ CommandIds.openSettings = '@jupyterlite/ai:open-settings';
35
+ CommandIds.reposition = '@jupyterlite/ai:reposition';
36
+ })(CommandIds || (CommandIds = {}));
37
+ /**
38
+ * Chat provider registry plugin
39
+ */
40
+ const chatProviderRegistryPlugin = {
41
+ id: '@jupyterlite/ai:chat-provider-registry',
42
+ description: 'Chat AI provider registry',
20
43
  autoStart: true,
21
- provides: IChatCommandRegistry,
44
+ provides: IChatProviderRegistry,
22
45
  activate: () => {
23
- const registry = new ChatCommandRegistry();
24
- registry.addProvider(new ChatHandler.ClearCommandProvider());
25
- return registry;
46
+ return new ChatProviderRegistry();
26
47
  }
27
48
  };
28
- const chatPlugin = {
29
- id: PLUGIN_IDS.chat,
30
- description: 'LLM chat extension',
49
+ /**
50
+ * Completion provider registry plugin
51
+ */
52
+ const completionProviderRegistryPlugin = {
53
+ id: '@jupyterlite/ai:completion-provider-registry',
54
+ description: 'Completion provider registry',
31
55
  autoStart: true,
32
- requires: [IAIProviderRegistry, IRenderMimeRegistry, IChatCommandRegistry],
33
- optional: [
34
- INotebookTracker,
35
- ISettingRegistry,
36
- IThemeManager,
37
- ILayoutRestorer
56
+ provides: ICompletionProviderRegistry,
57
+ activate: () => {
58
+ return new CompletionProviderRegistry();
59
+ }
60
+ };
61
+ /**
62
+ * Built-in chat providers plugin
63
+ */
64
+ const builtInChatProvidersPlugin = {
65
+ id: '@jupyterlite/ai:built-in-chat-providers',
66
+ description: 'Register built-in chat AI providers',
67
+ autoStart: true,
68
+ requires: [IChatProviderRegistry],
69
+ activate: (app, chatRegistry) => {
70
+ registerBuiltInChatProviders(chatRegistry);
71
+ }
72
+ };
73
+ /**
74
+ * Built-in completion providers plugin
75
+ */
76
+ const builtInCompletionProvidersPlugin = {
77
+ id: '@jupyterlite/ai:built-in-completion-providers',
78
+ description: 'Register built-in completion providers',
79
+ autoStart: true,
80
+ requires: [ICompletionProviderRegistry],
81
+ activate: (app, completionRegistry) => {
82
+ registerBuiltInCompletionProviders(completionRegistry);
83
+ }
84
+ };
85
+ /**
86
+ * Initialization data for the extension.
87
+ */
88
+ const plugin = {
89
+ id: '@jupyterlite/ai:plugin',
90
+ description: 'AI in JupyterLab',
91
+ autoStart: true,
92
+ requires: [
93
+ IAISettingsModel,
94
+ IAgentManager,
95
+ IToolRegistry,
96
+ IRenderMimeRegistry,
97
+ IDocumentManager
38
98
  ],
39
- activate: async (app, providerRegistry, rmRegistry, chatCommandRegistry, notebookTracker, settingsRegistry, themeManager, restorer) => {
40
- let activeCellManager = null;
99
+ optional: [IThemeManager, INotebookTracker, ILayoutRestorer, ILabShell],
100
+ activate: (app, settingsModel, agentManager, toolRegistry, rmRegistry, docManager, themeManager, notebookTracker, restorer, labShell) => {
101
+ // Create ActiveCellManager if notebook tracker is available
102
+ let activeCellManager;
41
103
  if (notebookTracker) {
42
104
  activeCellManager = new ActiveCellManager({
43
105
  tracker: notebookTracker,
44
106
  shell: app.shell
45
107
  });
46
108
  }
47
- const chatHandler = new ChatHandler({
48
- providerRegistry,
49
- activeCellManager
50
- });
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}`);
109
+ // Create AI chat model
110
+ const chatModel = new AIChatModel({
111
+ user: { username: 'user', display_name: 'User' },
112
+ settingsModel,
113
+ agentManager,
114
+ activeCellManager,
115
+ documentManager: docManager
74
116
  });
75
- let chatWidget = null;
117
+ // Create input toolbar registry with all buttons
76
118
  const inputToolbarRegistry = InputToolbarRegistry.defaultToolbarRegistry();
77
- const stopButton = stopItem(() => chatHandler.stopStreaming());
119
+ const stopButton = stopItem();
120
+ const clearButton = clearItem();
121
+ const toolSelectButton = createToolSelectItem(toolRegistry, settingsModel.config.toolsEnabled);
122
+ const modelSelectButton = createModelSelectItem(settingsModel);
78
123
  inputToolbarRegistry.addItem('stop', stopButton);
79
- chatHandler.writersChanged.connect((_, writers) => {
80
- if (writers.filter(writer => writer.user.username === chatHandler.personaName).length) {
124
+ inputToolbarRegistry.addItem('clear', clearButton);
125
+ inputToolbarRegistry.addItem('model', modelSelectButton);
126
+ inputToolbarRegistry.addItem('tools', toolSelectButton);
127
+ // Listen to writers changes to show/hide stop button
128
+ chatModel.writersChanged.connect((_, writers) => {
129
+ // Check if AI is currently writing (streaming)
130
+ const aiWriting = writers.some(writer => writer.user.username === 'ai-assistant');
131
+ if (aiWriting) {
81
132
  inputToolbarRegistry.hide('send');
82
133
  inputToolbarRegistry.show('stop');
83
134
  }
@@ -86,131 +137,252 @@ const chatPlugin = {
86
137
  inputToolbarRegistry.show('send');
87
138
  }
88
139
  });
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 });
140
+ // Listen for settings changes to update tool availability
141
+ settingsModel.stateChanged.connect(() => {
142
+ const config = settingsModel.config;
143
+ if (!config.toolsEnabled) {
144
+ inputToolbarRegistry.hide('tools');
145
+ }
146
+ else {
147
+ inputToolbarRegistry.show('tools');
148
+ }
149
+ });
150
+ // Create attachment opener registry to handle file attachments
151
+ const attachmentOpenerRegistry = new AttachmentOpenerRegistry();
152
+ attachmentOpenerRegistry.set('file', attachment => {
153
+ app.commands.execute('docmanager:open', { path: attachment.value });
154
+ });
155
+ attachmentOpenerRegistry.set('notebook', attachment => {
156
+ app.commands.execute('docmanager:open', { path: attachment.value });
157
+ });
158
+ // Create chat panel with drag/drop functionality
159
+ const chatPanel = new ChatWidget({
160
+ model: chatModel,
161
+ rmRegistry,
162
+ themeManager,
163
+ inputToolbarRegistry,
164
+ attachmentOpenerRegistry
165
+ });
166
+ // Create wrapper widget with a toolbar
167
+ const chatWrapper = new ChatWrapperWidget({
168
+ chatPanel,
169
+ commands: app.commands,
170
+ chatModel,
171
+ settingsModel
172
+ });
173
+ app.shell.add(chatWrapper, 'left', { rank: 1000 });
105
174
  if (restorer) {
106
- restorer.add(chatWidget, chatWidget.id);
175
+ restorer.add(chatWrapper, chatWrapper.id);
107
176
  }
177
+ registerCommands(app, labShell);
108
178
  }
109
179
  };
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'];
144
- }
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']);
180
+ function registerCommands(app, labShell) {
181
+ const { commands } = app;
182
+ if (labShell) {
183
+ commands.addCommand(CommandIds.reposition, {
184
+ label: 'Reposition Widget',
185
+ execute: (args) => {
186
+ const { widgetId, area, mode } = args;
187
+ const widget = widgetId
188
+ ? Array.from(labShell.widgets('main')).find(w => w.id === widgetId) ||
189
+ labShell.currentWidget
190
+ : labShell.currentWidget;
191
+ if (!widget) {
192
+ return;
152
193
  }
153
- else {
154
- providerRegistry.setCompleterProvider({});
194
+ if (area && area !== 'main') {
195
+ // Move to different area
196
+ labShell.move(widget, area);
197
+ labShell.activateById(widget.id);
155
198
  }
156
- // Update chat provider.
157
- if (Object.keys(providerSettings).includes('chat')) {
158
- providerRegistry.setChatProvider(providerSettings['chat']);
199
+ else if (mode) {
200
+ // Reposition within main area using split mode
201
+ labShell.add(widget, 'main', { mode, activate: true });
159
202
  }
160
- else {
161
- providerRegistry.setChatProvider({});
203
+ },
204
+ describedBy: {
205
+ args: {
206
+ type: 'object',
207
+ properties: {
208
+ widgetId: {
209
+ type: 'string',
210
+ description: 'The widget ID to reposition in the application shell'
211
+ },
212
+ area: {
213
+ type: 'string',
214
+ description: 'The name of the area to reposition the widget to'
215
+ },
216
+ mode: {
217
+ type: 'string',
218
+ enum: ['split-left', 'split-right', 'split-top', 'split-bottom'],
219
+ description: 'The mode to use when repositioning the widget'
220
+ }
221
+ }
162
222
  }
163
- };
164
- settings.changed.connect(() => updateProvider());
165
- updateProvider();
166
- })
167
- .catch(reason => {
168
- console.error(`Failed to load settings for ${providerRegistryPlugin.id}`, reason);
223
+ }
169
224
  });
170
- return providerRegistry;
171
225
  }
172
- }));
173
- const systemPromptsPlugin = {
174
- id: PLUGIN_IDS.systemPrompts,
226
+ }
227
+ /**
228
+ * A plugin to provide the settings model.
229
+ */
230
+ const agentManager = SecretsManager.sign(SECRETS_NAMESPACE, token => ({
231
+ id: SECRETS_NAMESPACE,
232
+ description: 'Provide the AI agent manager',
175
233
  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;
234
+ provides: IAgentManager,
235
+ requires: [IAISettingsModel, IChatProviderRegistry],
236
+ optional: [
237
+ ICommandPalette,
238
+ ICompletionProviderManager,
239
+ ICompletionProviderRegistry,
240
+ ILayoutRestorer,
241
+ ISecretsManager,
242
+ IThemeManager,
243
+ IToolRegistry
244
+ ],
245
+ activate: (app, settingsModel, chatProviderRegistry, palette, completionManager, completionProviderRegistry, restorer, secretsManager, themeManager, toolRegistry) => {
246
+ // Build the agent manager
247
+ const agentManager = new AgentManager({
248
+ settingsModel,
249
+ toolRegistry,
250
+ chatProviderRegistry,
251
+ secretsManager,
252
+ token
253
+ });
254
+ // Build the settings panel
255
+ const settingsWidget = new AISettingsWidget({
256
+ settingsModel,
257
+ agentManager,
258
+ themeManager,
259
+ chatProviderRegistry,
260
+ secretsManager,
261
+ token
262
+ });
263
+ settingsWidget.id = 'jupyterlite-ai-settings';
264
+ settingsWidget.title.icon = settingsIcon;
265
+ // Build the completion provider
266
+ if (completionManager && completionProviderRegistry) {
267
+ const completionProvider = new AICompletionProvider({
268
+ settingsModel,
269
+ completionProviderRegistry: completionProviderRegistry,
270
+ secretsManager,
271
+ token
272
+ });
273
+ completionManager.registerInlineProvider(completionProvider);
274
+ }
275
+ else {
276
+ console.info('Completion provider manager not available, skipping AI completion setup');
277
+ }
278
+ if (restorer) {
279
+ restorer.add(settingsWidget, settingsWidget.id);
189
280
  }
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;
281
+ app.commands.addCommand(CommandIds.openSettings, {
282
+ label: 'AI Settings',
283
+ caption: 'Configure AI providers and behavior',
284
+ icon: settingsIcon,
285
+ execute: () => {
286
+ // Check if the widget already exists in shell
287
+ let widget = Array.from(app.shell.widgets('main')).find(w => w.id === 'jupyterlite-ai-settings');
288
+ if (!widget && settingsWidget) {
289
+ // Use the pre-created widget
290
+ widget = settingsWidget;
291
+ app.shell.add(widget, 'main');
292
+ }
293
+ if (widget) {
294
+ app.shell.activateById(widget.id);
295
+ }
296
+ },
297
+ describedBy: {
298
+ args: {}
198
299
  }
199
- loadSetting(settings);
200
- settings.changed.connect(loadSetting);
201
- })
202
- .catch(reason => {
203
- console.error(`Something went wrong when reading the settings.\n${reason}`);
204
300
  });
301
+ // Add to command palette if available
302
+ if (palette) {
303
+ palette.addItem({
304
+ command: CommandIds.openSettings,
305
+ category: 'AI Assistant'
306
+ });
307
+ }
308
+ return agentManager;
309
+ }
310
+ }));
311
+ /**
312
+ * A plugin to provide the settings model.
313
+ */
314
+ const settingsModel = {
315
+ id: '@jupyterlite/ai:settings-model',
316
+ description: 'Provide the AI settings model',
317
+ autoStart: true,
318
+ provides: IAISettingsModel,
319
+ requires: [ISettingRegistry],
320
+ activate: (app, settingRegistry) => {
321
+ return new AISettingsModel({ settingRegistry });
322
+ }
323
+ };
324
+ /**
325
+ * A plugin to provide the tool registry.
326
+ */
327
+ const toolRegistry = {
328
+ id: '@jupyterlite/ai:tool-registry',
329
+ description: 'Provide the AI tool registry',
330
+ autoStart: true,
331
+ requires: [IAISettingsModel, IDocumentManager, IKernelSpecManager],
332
+ optional: [INotebookTracker],
333
+ provides: IToolRegistry,
334
+ activate: (app, settingsModel, docManager, kernelSpecManager, notebookTracker) => {
335
+ const { commands } = app;
336
+ const toolRegistry = new ToolRegistry();
337
+ const notebookCreationTool = createNotebookCreationTool(docManager, kernelSpecManager);
338
+ toolRegistry.add('create_notebook', notebookCreationTool);
339
+ // Add high-level notebook operation tools
340
+ const addCellTool = createAddCellTool(docManager, notebookTracker);
341
+ const getNotebookInfoTool = createGetNotebookInfoTool(docManager, notebookTracker);
342
+ const getCellInfoTool = createGetCellInfoTool(docManager, notebookTracker);
343
+ const setCellContentTool = createSetCellContentTool(docManager, commands, notebookTracker);
344
+ const runCellTool = createRunCellTool(docManager, notebookTracker);
345
+ const deleteCellTool = createDeleteCellTool(docManager, notebookTracker);
346
+ const saveNotebookTool = createSaveNotebookTool(docManager, notebookTracker);
347
+ const executeActiveCellTool = createExecuteActiveCellTool(docManager, notebookTracker);
348
+ toolRegistry.add('add_cell', addCellTool);
349
+ toolRegistry.add('get_notebook_info', getNotebookInfoTool);
350
+ toolRegistry.add('get_cell_info', getCellInfoTool);
351
+ toolRegistry.add('set_cell_content', setCellContentTool);
352
+ toolRegistry.add('run_cell', runCellTool);
353
+ toolRegistry.add('delete_cell', deleteCellTool);
354
+ toolRegistry.add('save_notebook', saveNotebookTool);
355
+ toolRegistry.add('execute_active_cell', executeActiveCellTool);
356
+ // Add file operation tools
357
+ const newFileTool = createNewFileTool(docManager);
358
+ const openFileTool = createOpenFileTool(docManager);
359
+ const deleteFileTool = createDeleteFileTool(docManager);
360
+ const renameFileTool = createRenameFileTool(docManager);
361
+ const copyFileTool = createCopyFileTool(docManager);
362
+ const navigateToDirectoryTool = createNavigateToDirectoryTool(app.commands);
363
+ toolRegistry.add('create_file', newFileTool);
364
+ toolRegistry.add('open_file', openFileTool);
365
+ toolRegistry.add('delete_file', deleteFileTool);
366
+ toolRegistry.add('rename_file', renameFileTool);
367
+ toolRegistry.add('copy_file', copyFileTool);
368
+ toolRegistry.add('navigate_to_directory', navigateToDirectoryTool);
369
+ // Add command operation tools
370
+ const discoverCommandsTool = createDiscoverCommandsTool(app.commands);
371
+ const executeCommandTool = createExecuteCommandTool(app.commands, settingsModel);
372
+ toolRegistry.add('discover_commands', discoverCommandsTool);
373
+ toolRegistry.add('execute_command', executeCommandTool);
374
+ return toolRegistry;
205
375
  }
206
376
  };
207
377
  export default [
208
- providerRegistryPlugin,
209
- chatCommandRegistryPlugin,
210
- chatPlugin,
211
- completerPlugin,
212
- systemPromptsPlugin,
213
- ...defaultProviderPlugins
378
+ chatProviderRegistryPlugin,
379
+ completionProviderRegistryPlugin,
380
+ builtInChatProvidersPlugin,
381
+ builtInCompletionProvidersPlugin,
382
+ plugin,
383
+ settingsModel,
384
+ agentManager,
385
+ toolRegistry
214
386
  ];
215
- export { IAIProviderRegistry } from './tokens';
216
- export * from './base-completer';
387
+ // Export extension points for other extensions to use
388
+ 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 {};