@jupyterlite/ai 0.9.1 → 0.10.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.
Files changed (66) hide show
  1. package/README.md +5 -214
  2. package/lib/agent.d.ts +58 -66
  3. package/lib/agent.js +274 -300
  4. package/lib/approval-buttons.d.ts +19 -82
  5. package/lib/approval-buttons.js +36 -289
  6. package/lib/chat-model-registry.d.ts +6 -0
  7. package/lib/chat-model-registry.js +4 -1
  8. package/lib/chat-model.d.ts +19 -54
  9. package/lib/chat-model.js +243 -303
  10. package/lib/components/clear-button.d.ts +6 -1
  11. package/lib/components/clear-button.js +8 -3
  12. package/lib/components/completion-status.d.ts +5 -0
  13. package/lib/components/completion-status.js +5 -4
  14. package/lib/components/model-select.d.ts +6 -1
  15. package/lib/components/model-select.js +9 -8
  16. package/lib/components/stop-button.d.ts +6 -1
  17. package/lib/components/stop-button.js +8 -3
  18. package/lib/components/token-usage-display.d.ts +5 -0
  19. package/lib/components/token-usage-display.js +2 -2
  20. package/lib/components/tool-select.d.ts +6 -1
  21. package/lib/components/tool-select.js +6 -5
  22. package/lib/index.js +58 -38
  23. package/lib/models/settings-model.d.ts +1 -1
  24. package/lib/providers/built-in-providers.js +38 -19
  25. package/lib/providers/models.d.ts +3 -3
  26. package/lib/providers/provider-registry.d.ts +3 -4
  27. package/lib/providers/provider-registry.js +1 -4
  28. package/lib/tokens.d.ts +5 -6
  29. package/lib/tools/commands.d.ts +2 -1
  30. package/lib/tools/commands.js +37 -46
  31. package/lib/tools/file.js +49 -73
  32. package/lib/tools/notebook.js +370 -445
  33. package/lib/widgets/ai-settings.d.ts +6 -0
  34. package/lib/widgets/ai-settings.js +72 -71
  35. package/lib/widgets/main-area-chat.d.ts +2 -0
  36. package/lib/widgets/main-area-chat.js +5 -2
  37. package/lib/widgets/provider-config-dialog.d.ts +2 -0
  38. package/lib/widgets/provider-config-dialog.js +34 -34
  39. package/package.json +12 -12
  40. package/src/agent.ts +342 -361
  41. package/src/approval-buttons.ts +43 -389
  42. package/src/chat-model-registry.ts +9 -1
  43. package/src/chat-model.ts +355 -370
  44. package/src/completion/completion-provider.ts +2 -3
  45. package/src/components/clear-button.tsx +16 -3
  46. package/src/components/completion-status.tsx +18 -4
  47. package/src/components/model-select.tsx +21 -8
  48. package/src/components/stop-button.tsx +16 -3
  49. package/src/components/token-usage-display.tsx +14 -2
  50. package/src/components/tool-select.tsx +23 -5
  51. package/src/index.ts +75 -36
  52. package/src/models/settings-model.ts +1 -1
  53. package/src/providers/built-in-providers.ts +38 -19
  54. package/src/providers/models.ts +3 -3
  55. package/src/providers/provider-registry.ts +4 -8
  56. package/src/tokens.ts +5 -6
  57. package/src/tools/commands.ts +39 -50
  58. package/src/tools/file.ts +49 -75
  59. package/src/tools/notebook.ts +451 -510
  60. package/src/widgets/ai-settings.tsx +153 -84
  61. package/src/widgets/main-area-chat.ts +8 -2
  62. package/src/widgets/provider-config-dialog.tsx +54 -41
  63. package/style/base.css +13 -73
  64. package/lib/mcp/browser.d.ts +0 -68
  65. package/lib/mcp/browser.js +0 -138
  66. package/src/mcp/browser.ts +0 -220
package/src/index.ts CHANGED
@@ -38,6 +38,12 @@ import { ISettingRegistry } from '@jupyterlab/settingregistry';
38
38
 
39
39
  import { IStatusBar } from '@jupyterlab/statusbar';
40
40
 
41
+ import {
42
+ ITranslator,
43
+ nullTranslator,
44
+ TranslationBundle
45
+ } from '@jupyterlab/translation';
46
+
41
47
  import {
42
48
  settingsIcon,
43
49
  Toolbar,
@@ -212,7 +218,7 @@ const chatModelRegistry: JupyterFrontEndPlugin<IChatModelRegistry> = {
212
218
  description: 'Registry for the current chat model',
213
219
  autoStart: true,
214
220
  requires: [IAISettingsModel, IAgentManagerFactory, IDocumentManager],
215
- optional: [IProviderRegistry, INotebookTracker, IToolRegistry],
221
+ optional: [IProviderRegistry, INotebookTracker, IToolRegistry, ITranslator],
216
222
  provides: IChatModelRegistry,
217
223
  activate: (
218
224
  app: JupyterFrontEnd,
@@ -221,8 +227,11 @@ const chatModelRegistry: JupyterFrontEndPlugin<IChatModelRegistry> = {
221
227
  docManager: IDocumentManager,
222
228
  providerRegistry?: IProviderRegistry,
223
229
  notebookTracker?: INotebookTracker,
224
- toolRegistry?: IToolRegistry
230
+ toolRegistry?: IToolRegistry,
231
+ translator?: ITranslator
225
232
  ): IChatModelRegistry => {
233
+ const trans = (translator ?? nullTranslator).load('jupyterlite_ai');
234
+
226
235
  // Create ActiveCellManager if notebook tracker is available
227
236
  let activeCellManager: ActiveCellManager | undefined;
228
237
  if (notebookTracker) {
@@ -237,7 +246,8 @@ const chatModelRegistry: JupyterFrontEndPlugin<IChatModelRegistry> = {
237
246
  agentManagerFactory,
238
247
  docManager,
239
248
  providerRegistry,
240
- toolRegistry
249
+ toolRegistry,
250
+ trans
241
251
  });
242
252
  }
243
253
  };
@@ -255,7 +265,7 @@ const plugin: JupyterFrontEndPlugin<void> = {
255
265
  IChatModelRegistry,
256
266
  IAISettingsModel
257
267
  ],
258
- optional: [IThemeManager, ILayoutRestorer, ILabShell],
268
+ optional: [IThemeManager, ILayoutRestorer, ILabShell, ITranslator],
259
269
  activate: (
260
270
  app: JupyterFrontEnd,
261
271
  rmRegistry: IRenderMimeRegistry,
@@ -264,8 +274,10 @@ const plugin: JupyterFrontEndPlugin<void> = {
264
274
  settingsModel: AISettingsModel,
265
275
  themeManager?: IThemeManager,
266
276
  restorer?: ILayoutRestorer,
267
- labShell?: ILabShell
277
+ labShell?: ILabShell,
278
+ translator?: ITranslator
268
279
  ): void => {
280
+ const trans = (translator ?? nullTranslator).load('jupyterlite_ai');
269
281
  // Create attachment opener registry to handle file attachments
270
282
  const attachmentOpenerRegistry = new AttachmentOpenerRegistry();
271
283
  attachmentOpenerRegistry.set('file', attachment => {
@@ -304,7 +316,7 @@ const plugin: JupyterFrontEndPlugin<void> = {
304
316
 
305
317
  chatPanel.id = '@jupyterlite/ai:chat-panel';
306
318
  chatPanel.title.icon = chatIcon;
307
- chatPanel.title.caption = 'Chat with AI assistant'; // TODO: i18n/
319
+ chatPanel.title.caption = trans.__('Chat with AI assistant');
308
320
 
309
321
  chatPanel.toolbar.addItem('spacer', Toolbar.createSpacerItem());
310
322
  chatPanel.toolbar.addItem(
@@ -314,7 +326,7 @@ const plugin: JupyterFrontEndPlugin<void> = {
314
326
  onClick: () => {
315
327
  app.commands.execute('@jupyterlite/ai:open-settings');
316
328
  },
317
- tooltip: 'Open AI Settings'
329
+ tooltip: trans.__('Open AI Settings')
318
330
  })
319
331
  );
320
332
 
@@ -335,7 +347,8 @@ const plugin: JupyterFrontEndPlugin<void> = {
335
347
  const tokenUsageWidget = new TokenUsageWidget({
336
348
  tokenUsageChanged: model.tokenUsageChanged,
337
349
  settingsModel,
338
- initialTokenUsage: model.agentManager.tokenUsage
350
+ initialTokenUsage: model.agentManager.tokenUsage,
351
+ translator: trans
339
352
  });
340
353
  section.toolbar.insertBefore('markRead', 'token-usage', tokenUsageWidget);
341
354
  model.writersChanged?.connect((_, writers) => {
@@ -355,7 +368,8 @@ const plugin: JupyterFrontEndPlugin<void> = {
355
368
 
356
369
  // Associate an approval buttons object to the chat.
357
370
  const approvalButton = new ApprovalButtons({
358
- chatPanel: widget
371
+ chatPanel: widget,
372
+ agentManager: model.agentManager
359
373
  });
360
374
 
361
375
  widget.disposed.connect(() => {
@@ -407,6 +421,7 @@ const plugin: JupyterFrontEndPlugin<void> = {
407
421
  settingsModel,
408
422
  tracker,
409
423
  modelRegistry,
424
+ trans,
410
425
  themeManager,
411
426
  labShell
412
427
  );
@@ -422,6 +437,7 @@ function registerCommands(
422
437
  settingsModel: AISettingsModel,
423
438
  tracker: WidgetTracker<MainAreaChat | ChatWidget>,
424
439
  modelRegistry: IChatModelRegistry,
440
+ trans: TranslationBundle,
425
441
  themeManager?: IThemeManager,
426
442
  labShell?: ILabShell
427
443
  ) {
@@ -429,7 +445,7 @@ function registerCommands(
429
445
 
430
446
  if (labShell) {
431
447
  commands.addCommand(CommandIds.reposition, {
432
- label: 'Reposition Widget',
448
+ label: trans.__('Reposition Widget'),
433
449
  execute: (args: any) => {
434
450
  const { widgetId, area, mode } = args;
435
451
  const widget = widgetId
@@ -456,17 +472,22 @@ function registerCommands(
456
472
  properties: {
457
473
  widgetId: {
458
474
  type: 'string',
459
- description:
475
+ description: trans.__(
460
476
  'The widget ID to reposition in the application shell'
477
+ )
461
478
  },
462
479
  area: {
463
480
  type: 'string',
464
- description: 'The name of the area to reposition the widget to'
481
+ description: trans.__(
482
+ 'The name of the area to reposition the widget to'
483
+ )
465
484
  },
466
485
  mode: {
467
486
  type: 'string',
468
487
  enum: ['split-left', 'split-right', 'split-top', 'split-bottom'],
469
- description: 'The mode to use when repositioning the widget'
488
+ description: trans.__(
489
+ 'The mode to use when repositioning the widget'
490
+ )
470
491
  }
471
492
  }
472
493
  }
@@ -481,7 +502,12 @@ function registerCommands(
481
502
  inputToolbarRegistry: inputToolbarFactory.create(),
482
503
  attachmentOpenerRegistry
483
504
  });
484
- const widget = new MainAreaChat({ content, commands, settingsModel });
505
+ const widget = new MainAreaChat({
506
+ content,
507
+ commands,
508
+ settingsModel,
509
+ trans
510
+ });
485
511
  app.shell.add(widget, 'main');
486
512
 
487
513
  // Add the widget to the tracker.
@@ -501,7 +527,7 @@ function registerCommands(
501
527
  };
502
528
 
503
529
  commands.addCommand(CommandIds.openChat, {
504
- label: 'Open a chat',
530
+ label: trans.__('Open a chat'),
505
531
  execute: async (args): Promise<boolean> => {
506
532
  const area = (args.area as string) === 'main' ? 'main' : 'side';
507
533
  const provider = (args.provider as string) ?? undefined;
@@ -532,15 +558,15 @@ function registerCommands(
532
558
  area: {
533
559
  type: 'string',
534
560
  enum: ['main', 'side'],
535
- description: 'The name of the area to open the chat to'
561
+ description: trans.__('The name of the area to open the chat to')
536
562
  },
537
563
  name: {
538
564
  type: 'string',
539
- description: 'The name of the chat'
565
+ description: trans.__('The name of the chat')
540
566
  },
541
567
  provider: {
542
568
  type: 'string',
543
- description: 'The provider/model to use with this chat'
569
+ description: trans.__('The provider/model to use with this chat')
544
570
  }
545
571
  }
546
572
  }
@@ -548,7 +574,7 @@ function registerCommands(
548
574
  });
549
575
 
550
576
  commands.addCommand(CommandIds.moveChat, {
551
- caption: 'Move chat between area',
577
+ caption: trans.__('Move chat between area'),
552
578
  execute: async (args): Promise<boolean> => {
553
579
  const area = args.area as string;
554
580
  if (!['side', 'main'].includes(area)) {
@@ -601,7 +627,7 @@ function registerCommands(
601
627
  trackerUpdated.promise,
602
628
  new Promise<boolean>(r =>
603
629
  setTimeout(() => {
604
- return false;
630
+ r(false);
605
631
  }, 2000)
606
632
  )
607
633
  ]);
@@ -634,11 +660,11 @@ function registerCommands(
634
660
  area: {
635
661
  type: 'string',
636
662
  enum: ['main', 'side'],
637
- description: 'The name of the area to move the chat to'
663
+ description: trans.__('The name of the area to move the chat to')
638
664
  },
639
665
  name: {
640
666
  type: 'string',
641
- description: 'The name of the chat to move'
667
+ description: trans.__('The name of the chat to move')
642
668
  }
643
669
  },
644
670
  requires: ['area', 'name']
@@ -663,7 +689,8 @@ const agentManagerFactory: JupyterFrontEndPlugin<AgentManagerFactory> =
663
689
  ICompletionProviderManager,
664
690
  ILayoutRestorer,
665
691
  ISecretsManager,
666
- IThemeManager
692
+ IThemeManager,
693
+ ITranslator
667
694
  ],
668
695
  activate: (
669
696
  app: JupyterFrontEnd,
@@ -673,8 +700,10 @@ const agentManagerFactory: JupyterFrontEndPlugin<AgentManagerFactory> =
673
700
  completionManager?: ICompletionProviderManager,
674
701
  restorer?: ILayoutRestorer,
675
702
  secretsManager?: ISecretsManager,
676
- themeManager?: IThemeManager
703
+ themeManager?: IThemeManager,
704
+ translator?: ITranslator
677
705
  ): AgentManagerFactory => {
706
+ const trans = (translator ?? nullTranslator).load('jupyterlite_ai');
678
707
  const agentManagerFactory = new AgentManagerFactory({
679
708
  settingsModel,
680
709
  secretsManager,
@@ -688,7 +717,8 @@ const agentManagerFactory: JupyterFrontEndPlugin<AgentManagerFactory> =
688
717
  themeManager,
689
718
  providerRegistry,
690
719
  secretsManager,
691
- token
720
+ token,
721
+ trans
692
722
  });
693
723
  settingsWidget.id = 'jupyterlite-ai-settings';
694
724
  settingsWidget.title.icon = settingsIcon;
@@ -715,8 +745,8 @@ const agentManagerFactory: JupyterFrontEndPlugin<AgentManagerFactory> =
715
745
  }
716
746
 
717
747
  app.commands.addCommand(CommandIds.openSettings, {
718
- label: 'AI Settings',
719
- caption: 'Configure AI providers and behavior',
748
+ label: trans.__('AI Settings'),
749
+ caption: trans.__('Configure AI providers and behavior'),
720
750
  icon: settingsIcon,
721
751
  iconClass: 'jp-ai-settings-icon',
722
752
  execute: () => {
@@ -744,7 +774,7 @@ const agentManagerFactory: JupyterFrontEndPlugin<AgentManagerFactory> =
744
774
  if (palette) {
745
775
  palette.addItem({
746
776
  command: CommandIds.openSettings,
747
- category: 'AI Assistant'
777
+ category: trans.__('AI Assistant')
748
778
  });
749
779
  }
750
780
 
@@ -888,18 +918,22 @@ const inputToolbarFactory: JupyterFrontEndPlugin<IInputToolbarRegistryFactory> =
888
918
  autoStart: true,
889
919
  provides: IInputToolbarRegistryFactory,
890
920
  requires: [IAISettingsModel, IToolRegistry],
921
+ optional: [ITranslator],
891
922
  activate: (
892
923
  app: JupyterFrontEnd,
893
924
  settingsModel: AISettingsModel,
894
- toolRegistry: IToolRegistry
925
+ toolRegistry: IToolRegistry,
926
+ translator?: ITranslator
895
927
  ): IInputToolbarRegistryFactory => {
896
- const stopButton = stopItem();
897
- const clearButton = clearItem();
928
+ const trans = (translator ?? nullTranslator).load('jupyterlite_ai');
929
+ const stopButton = stopItem(trans);
930
+ const clearButton = clearItem(trans);
898
931
  const toolSelectButton = createToolSelectItem(
899
932
  toolRegistry,
900
- settingsModel.config.toolsEnabled
933
+ settingsModel.config.toolsEnabled,
934
+ trans
901
935
  );
902
- const modelSelectButton = createModelSelectItem(settingsModel);
936
+ const modelSelectButton = createModelSelectItem(settingsModel, trans);
903
937
 
904
938
  return {
905
939
  create() {
@@ -931,16 +965,21 @@ const completionStatus: JupyterFrontEndPlugin<void> = {
931
965
  description: 'The completion status displayed in the status bar',
932
966
  autoStart: true,
933
967
  requires: [IAISettingsModel],
934
- optional: [IStatusBar],
968
+ optional: [IStatusBar, ITranslator],
935
969
  activate: (
936
970
  app: JupyterFrontEnd,
937
971
  settingsModel: AISettingsModel,
938
- statusBar: IStatusBar | null
972
+ statusBar: IStatusBar | null,
973
+ translator?: ITranslator
939
974
  ) => {
940
975
  if (!statusBar) {
941
976
  return;
942
977
  }
943
- const item = new CompletionStatusWidget({ settingsModel });
978
+ const trans = (translator ?? nullTranslator).load('jupyterlite_ai');
979
+ const item = new CompletionStatusWidget({
980
+ settingsModel,
981
+ translator: trans
982
+ });
944
983
  statusBar?.registerStatusItem('completionState', {
945
984
  item,
946
985
  align: 'right',
@@ -5,7 +5,7 @@ const PLUGIN_ID = '@jupyterlite/ai:settings-model';
5
5
 
6
6
  export interface IProviderParameters {
7
7
  temperature?: number;
8
- maxTokens?: number;
8
+ maxOutputTokens?: number;
9
9
  maxTurns?: number;
10
10
  supportsFillInMiddle?: boolean;
11
11
  useFilterText?: boolean;
@@ -15,15 +15,17 @@ export const anthropicProvider: IProviderInfo = {
15
15
  name: 'Anthropic Claude',
16
16
  apiKeyRequirement: 'required',
17
17
  defaultModels: [
18
+ 'claude-opus-4-5',
19
+ 'claude-opus-4-5-20251101',
18
20
  'claude-sonnet-4-5',
19
21
  'claude-sonnet-4-5-20250929',
20
22
  'claude-haiku-4-5',
21
23
  'claude-haiku-4-5-20251001',
22
24
  'claude-opus-4-1',
23
- 'claude-opus-4-0',
24
- 'claude-sonnet-4-0',
25
25
  'claude-opus-4-1-20250805',
26
+ 'claude-opus-4-0',
26
27
  'claude-opus-4-20250514',
28
+ 'claude-sonnet-4-0',
27
29
  'claude-sonnet-4-20250514',
28
30
  'claude-3-7-sonnet-latest',
29
31
  'claude-3-7-sonnet-20250219',
@@ -58,8 +60,11 @@ export const googleProvider: IProviderInfo = {
58
60
  name: 'Google Generative AI',
59
61
  apiKeyRequirement: 'required',
60
62
  defaultModels: [
61
- 'gemini-2.5-flash',
63
+ 'gemini-3-pro-preview',
64
+ 'gemini-3-pro-image-preview',
65
+ 'gemini-3-flash-preview',
62
66
  'gemini-2.5-pro',
67
+ 'gemini-2.5-flash',
63
68
  'gemini-2.5-flash-image-preview',
64
69
  'gemini-2.5-flash-lite',
65
70
  'gemini-2.5-flash-lite-preview-09-2025',
@@ -84,6 +89,9 @@ export const googleProvider: IProviderInfo = {
84
89
  'gemini-1.5-pro-latest',
85
90
  'gemini-1.5-pro-001',
86
91
  'gemini-1.5-pro-002',
92
+ 'gemini-pro-latest',
93
+ 'gemini-flash-latest',
94
+ 'gemini-flash-lite-latest',
87
95
  'gemini-exp-1206',
88
96
  'gemma-3-12b-it',
89
97
  'gemma-3-27b-it'
@@ -150,12 +158,32 @@ export const openaiProvider: IProviderInfo = {
150
158
  name: 'OpenAI',
151
159
  apiKeyRequirement: 'required',
152
160
  defaultModels: [
153
- 'o1',
154
- 'o1-2024-12-17',
155
- 'o3-mini',
156
- 'o3-mini-2025-01-31',
161
+ 'gpt-5.2',
162
+ 'gpt-5.2-chat-latest',
163
+ 'gpt-5.2-pro',
164
+ 'gpt-5.1',
165
+ 'gpt-5.1-chat-latest',
166
+ 'gpt-5.1-codex',
167
+ 'gpt-5.1-codex-mini',
168
+ 'gpt-5.1-codex-max',
169
+ 'gpt-5',
170
+ 'gpt-5-2025-08-07',
171
+ 'gpt-5-chat-latest',
172
+ 'gpt-5-codex',
173
+ 'gpt-5-pro',
174
+ 'gpt-5-pro-2025-10-06',
175
+ 'gpt-5-mini',
176
+ 'gpt-5-mini-2025-08-07',
177
+ 'gpt-5-nano',
178
+ 'gpt-5-nano-2025-08-07',
157
179
  'o3',
158
180
  'o3-2025-04-16',
181
+ 'o3-mini',
182
+ 'o3-mini-2025-01-31',
183
+ 'o1',
184
+ 'o1-2024-12-17',
185
+ 'gpt-4.5-preview',
186
+ 'gpt-4.5-preview-2025-02-27',
159
187
  'gpt-4.1',
160
188
  'gpt-4.1-2025-04-14',
161
189
  'gpt-4.1-mini',
@@ -168,23 +196,14 @@ export const openaiProvider: IProviderInfo = {
168
196
  'gpt-4o-2024-11-20',
169
197
  'gpt-4o-mini',
170
198
  'gpt-4o-mini-2024-07-18',
199
+ 'chatgpt-4o-latest',
171
200
  'gpt-4-turbo',
172
201
  'gpt-4-turbo-2024-04-09',
173
202
  'gpt-4',
174
203
  'gpt-4-0613',
175
- 'gpt-4.5-preview',
176
- 'gpt-4.5-preview-2025-02-27',
177
- 'gpt-3.5-turbo-0125',
178
204
  'gpt-3.5-turbo',
179
- 'gpt-3.5-turbo-1106',
180
- 'chatgpt-4o-latest',
181
- 'gpt-5',
182
- 'gpt-5-2025-08-07',
183
- 'gpt-5-mini',
184
- 'gpt-5-mini-2025-08-07',
185
- 'gpt-5-nano',
186
- 'gpt-5-nano-2025-08-07',
187
- 'gpt-5-chat-latest'
205
+ 'gpt-3.5-turbo-0125',
206
+ 'gpt-3.5-turbo-1106'
188
207
  ],
189
208
  supportsBaseURL: true,
190
209
  supportsHeaders: true,
@@ -1,4 +1,4 @@
1
- import type { LanguageModelV2 } from '@ai-sdk/provider';
1
+ import type { LanguageModel } from 'ai';
2
2
  import type { IProviderRegistry } from '../tokens';
3
3
 
4
4
  /**
@@ -38,7 +38,7 @@ export interface IModelOptions {
38
38
  export function createCompletionModel(
39
39
  options: IModelOptions,
40
40
  registry?: IProviderRegistry
41
- ): LanguageModelV2 {
41
+ ): LanguageModel {
42
42
  if (!registry) {
43
43
  throw new Error('Provider registry not available');
44
44
  }
@@ -60,7 +60,7 @@ export function createCompletionModel(
60
60
  export function createModel(
61
61
  options: IModelOptions,
62
62
  registry?: IProviderRegistry
63
- ) {
63
+ ): LanguageModel {
64
64
  if (!registry) {
65
65
  throw new Error('Provider registry not available');
66
66
  }
@@ -1,7 +1,5 @@
1
1
  import { ISignal, Signal } from '@lumino/signaling';
2
- import type { LanguageModelV2 } from '@ai-sdk/provider';
3
- import type { Model } from '@openai/agents';
4
- import { aisdk } from '@openai/agents-extensions';
2
+ import type { LanguageModel } from 'ai';
5
3
  import type { IModelOptions } from './models';
6
4
  import { IProviderInfo, IProviderRegistry } from '../tokens';
7
5
 
@@ -50,15 +48,13 @@ export class ProviderRegistry implements IProviderRegistry {
50
48
  * @param options Model configuration options
51
49
  * @returns Chat model instance or null if creation fails
52
50
  */
53
- createChatModel(id: string, options: IModelOptions): Model | null {
51
+ createChatModel(id: string, options: IModelOptions): LanguageModel | null {
54
52
  const provider = this._providers[id];
55
53
  if (!provider) {
56
54
  return null;
57
55
  }
58
56
 
59
- const languageModel = provider.factory(options);
60
- // wrap with aisdk for compatibility with the agent framework
61
- return aisdk(languageModel);
57
+ return provider.factory(options);
62
58
  }
63
59
 
64
60
  /**
@@ -70,7 +66,7 @@ export class ProviderRegistry implements IProviderRegistry {
70
66
  createCompletionModel(
71
67
  id: string,
72
68
  options: IModelOptions
73
- ): LanguageModelV2 | null {
69
+ ): LanguageModel | null {
74
70
  const provider = this._providers[id];
75
71
  if (!provider) {
76
72
  return null;
package/src/tokens.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Token } from '@lumino/coreutils';
2
2
  import { ISignal } from '@lumino/signaling';
3
- import { FunctionTool, Model } from '@openai/agents';
4
- import { LanguageModelV2 } from '@ai-sdk/provider';
3
+ import type { Tool, LanguageModel } from 'ai';
5
4
  import { AgentManager } from './agent';
6
5
  import type { AISettingsModel } from './models/settings-model';
7
6
  import type { IModelOptions } from './providers/models';
@@ -21,7 +20,7 @@ export namespace CommandIds {
21
20
  /**
22
21
  * Type definition for a tool
23
22
  */
24
- export type ITool = FunctionTool<any, any, any>;
23
+ export type ITool = Tool;
25
24
 
26
25
  /**
27
26
  * Interface for token usage statistics from AI model interactions
@@ -109,7 +108,7 @@ export const IProviderRegistry = new Token<IProviderRegistry>(
109
108
  * Interface for a provider factory function that creates language models
110
109
  */
111
110
  export interface IProviderFactory {
112
- (options: IModelOptions): LanguageModelV2;
111
+ (options: IModelOptions): LanguageModel;
113
112
  }
114
113
 
115
114
  /**
@@ -197,7 +196,7 @@ export interface IProviderRegistry {
197
196
  /**
198
197
  * Create a chat model instance for the given provider.
199
198
  */
200
- createChatModel(id: string, options: IModelOptions): Model | null;
199
+ createChatModel(id: string, options: IModelOptions): LanguageModel | null;
201
200
 
202
201
  /**
203
202
  * Create a completion model instance for the given provider.
@@ -205,7 +204,7 @@ export interface IProviderRegistry {
205
204
  createCompletionModel(
206
205
  id: string,
207
206
  options: IModelOptions
208
- ): LanguageModelV2 | null;
207
+ ): LanguageModel | null;
209
208
 
210
209
  /**
211
210
  * Get all available provider IDs.
@@ -1,5 +1,5 @@
1
1
  import { CommandRegistry } from '@lumino/commands';
2
- import { tool } from '@openai/agents';
2
+ import { tool } from 'ai';
3
3
  import { z } from 'zod';
4
4
  import { ITool } from '../tokens';
5
5
  import { AISettingsModel } from '../models/settings-model';
@@ -9,11 +9,10 @@ import { AISettingsModel } from '../models/settings-model';
9
9
  */
10
10
  export function createDiscoverCommandsTool(commands: CommandRegistry): ITool {
11
11
  return tool({
12
- name: 'discover_commands',
12
+ title: 'Discover Commands',
13
13
  description:
14
14
  'Discover all available JupyterLab commands with their metadata, arguments, and descriptions',
15
- parameters: z.object({
16
- // currently unused, but could be used to filter commands by a search term
15
+ inputSchema: z.object({
17
16
  query: z
18
17
  .string()
19
18
  .optional()
@@ -75,31 +74,28 @@ export function createDiscoverCommandsTool(commands: CommandRegistry): ITool {
75
74
  }
76
75
 
77
76
  /**
78
- * Create a tool to execute a specific JupyterLab command
77
+ * Create a tool to execute a specific JupyterLab command.
78
+ * Commands in the settings' commandsRequiringApproval list will need approval.
79
79
  */
80
80
  export function createExecuteCommandTool(
81
81
  commands: CommandRegistry,
82
82
  settingsModel: AISettingsModel
83
83
  ): ITool {
84
84
  return tool({
85
- name: 'execute_command',
85
+ title: 'Execute Command',
86
86
  description:
87
87
  'Execute a specific JupyterLab command with optional arguments',
88
- parameters: z.object({
88
+ inputSchema: z.object({
89
89
  commandId: z.string().describe('The ID of the command to execute'),
90
90
  args: z
91
91
  .any()
92
92
  .optional()
93
93
  .describe('Optional arguments to pass to the command')
94
94
  }),
95
- needsApproval: async (context, { commandId }) => {
96
- // Use configurable list of commands requiring approval
95
+ needsApproval: (input: { commandId: string; args?: any }) => {
97
96
  const commandsRequiringApproval =
98
- settingsModel.config.commandsRequiringApproval;
99
-
100
- return commandsRequiringApproval.some(
101
- cmd => commandId.includes(cmd) || cmd.includes(commandId)
102
- );
97
+ settingsModel.config.commandsRequiringApproval || [];
98
+ return commandsRequiringApproval.includes(input.commandId);
103
99
  },
104
100
  execute: async (input: { commandId: string; args?: any }) => {
105
101
  const { commandId, args } = input;
@@ -112,45 +108,38 @@ export function createExecuteCommandTool(
112
108
  };
113
109
  }
114
110
 
115
- try {
116
- // Execute the command
117
- const result = await commands.execute(commandId, args);
111
+ // Execute the command
112
+ const result = await commands.execute(commandId, args);
118
113
 
119
- // Handle Widget objects specially (including subclasses like DocumentWidget)
120
- let serializedResult;
121
- if (
122
- result &&
123
- typeof result === 'object' &&
124
- (result.constructor?.name?.includes('Widget') || result.id)
125
- ) {
126
- serializedResult = {
127
- type: result.constructor?.name || 'Widget',
128
- id: result.id,
129
- title: result.title?.label || result.title,
130
- className: result.className
131
- };
132
- } else {
133
- // For other objects, try JSON serialization with fallback
134
- try {
135
- serializedResult = JSON.parse(JSON.stringify(result));
136
- } catch {
137
- serializedResult = result
138
- ? '[Complex object - cannot serialize]'
139
- : 'Command executed successfully';
140
- }
141
- }
142
-
143
- return {
144
- success: true,
145
- commandId,
146
- result: serializedResult
147
- };
148
- } catch (error) {
149
- return {
150
- success: false,
151
- error: `Failed to execute command '${commandId}': ${error instanceof Error ? error.message : String(error)}`
114
+ // Handle Widget objects specially (including subclasses like DocumentWidget)
115
+ let serializedResult;
116
+ if (
117
+ result &&
118
+ typeof result === 'object' &&
119
+ (result.constructor?.name?.includes('Widget') || result.id)
120
+ ) {
121
+ serializedResult = {
122
+ type: result.constructor?.name || 'Widget',
123
+ id: result.id,
124
+ title: result.title?.label || result.title,
125
+ className: result.className
152
126
  };
127
+ } else {
128
+ // For other objects, try JSON serialization with fallback
129
+ try {
130
+ serializedResult = JSON.parse(JSON.stringify(result));
131
+ } catch {
132
+ serializedResult = result
133
+ ? '[Complex object - cannot serialize]'
134
+ : 'Command executed successfully';
135
+ }
153
136
  }
137
+
138
+ return {
139
+ success: true,
140
+ commandId,
141
+ result: serializedResult
142
+ };
154
143
  }
155
144
  });
156
145
  }