@jupyterlite/ai 0.14.0 → 0.15.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 (52) hide show
  1. package/lib/agent.d.ts +28 -114
  2. package/lib/agent.js +140 -100
  3. package/lib/chat-model-handler.d.ts +9 -11
  4. package/lib/chat-model-handler.js +9 -4
  5. package/lib/chat-model.d.ts +84 -13
  6. package/lib/chat-model.js +208 -136
  7. package/lib/completion/completion-provider.d.ts +2 -3
  8. package/lib/components/completion-status.d.ts +2 -2
  9. package/lib/components/model-select.d.ts +3 -3
  10. package/lib/components/save-button.d.ts +31 -0
  11. package/lib/components/save-button.js +41 -0
  12. package/lib/components/token-usage-display.d.ts +2 -3
  13. package/lib/components/tool-select.d.ts +3 -4
  14. package/lib/diff-manager.d.ts +2 -3
  15. package/lib/index.d.ts +2 -4
  16. package/lib/index.js +181 -23
  17. package/lib/models/settings-model.d.ts +11 -53
  18. package/lib/models/settings-model.js +37 -22
  19. package/lib/providers/built-in-providers.js +17 -36
  20. package/lib/tokens.d.ts +340 -36
  21. package/lib/tokens.js +11 -6
  22. package/lib/tools/commands.d.ts +2 -3
  23. package/lib/widgets/ai-settings.d.ts +3 -5
  24. package/lib/widgets/ai-settings.js +3 -0
  25. package/lib/widgets/main-area-chat.d.ts +2 -3
  26. package/lib/widgets/main-area-chat.js +9 -9
  27. package/lib/widgets/provider-config-dialog.d.ts +1 -2
  28. package/lib/widgets/provider-config-dialog.js +16 -29
  29. package/package.json +15 -9
  30. package/schema/settings-model.json +7 -1
  31. package/src/agent.ts +197 -242
  32. package/src/chat-model-handler.ts +25 -21
  33. package/src/chat-model.ts +304 -196
  34. package/src/completion/completion-provider.ts +7 -4
  35. package/src/components/completion-status.tsx +3 -3
  36. package/src/components/model-select.tsx +4 -3
  37. package/src/components/save-button.tsx +84 -0
  38. package/src/components/token-usage-display.tsx +2 -3
  39. package/src/components/tool-select.tsx +10 -4
  40. package/src/diff-manager.ts +4 -4
  41. package/src/index.ts +245 -49
  42. package/src/models/settings-model.ts +45 -88
  43. package/src/providers/built-in-providers.ts +17 -36
  44. package/src/tokens.ts +406 -52
  45. package/src/tools/commands.ts +2 -3
  46. package/src/widgets/ai-settings.tsx +27 -15
  47. package/src/widgets/main-area-chat.ts +15 -12
  48. package/src/widgets/provider-config-dialog.tsx +51 -56
  49. package/style/base.css +17 -195
  50. package/lib/approval-buttons.d.ts +0 -49
  51. package/lib/approval-buttons.js +0 -79
  52. package/src/approval-buttons.ts +0 -115
package/src/index.ts CHANGED
@@ -23,6 +23,7 @@ import {
23
23
  import {
24
24
  ICommandPalette,
25
25
  IThemeManager,
26
+ showDialog,
26
27
  showErrorMessage,
27
28
  WidgetTracker
28
29
  } from '@jupyterlab/apputils';
@@ -31,6 +32,8 @@ import { ICompletionProviderManager } from '@jupyterlab/completer';
31
32
 
32
33
  import { IDocumentManager } from '@jupyterlab/docmanager';
33
34
 
35
+ import { FileDialog } from '@jupyterlab/filebrowser';
36
+
34
37
  import { INotebookTracker } from '@jupyterlab/notebook';
35
38
 
36
39
  import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
@@ -48,28 +51,36 @@ import {
48
51
  } from '@jupyterlab/translation';
49
52
 
50
53
  import {
54
+ fileUploadIcon,
55
+ saveIcon,
51
56
  settingsIcon,
52
57
  Toolbar,
53
58
  ToolbarButton
54
59
  } from '@jupyterlab/ui-components';
55
60
 
56
- import { ISecretsManager, SecretsManager } from 'jupyter-secrets-manager';
57
-
58
61
  import { PromiseDelegate, UUID } from '@lumino/coreutils';
62
+
59
63
  import { DisposableSet } from '@lumino/disposable';
64
+
60
65
  import { CommandRegistry } from '@lumino/commands';
61
66
 
67
+ import { IComponentsRendererFactory } from 'jupyter-chat-components';
68
+
69
+ import { ISecretsManager, SecretsManager } from 'jupyter-secrets-manager';
70
+
62
71
  import { AgentManagerFactory } from './agent';
63
72
 
64
73
  import { AIChatModel } from './chat-model';
74
+
65
75
  import { RenderedMessageOutputAreaCompat } from './rendered-message-outputarea';
66
76
 
67
77
  import { ClearCommandProvider } from './chat-commands/clear';
78
+
68
79
  import { SkillsCommandProvider } from './chat-commands/skills';
69
80
 
70
81
  import { ProviderRegistry } from './providers/provider-registry';
71
82
 
72
- import { ApprovalButtons } from './approval-buttons';
83
+ import { SaveComponentWidget } from './components/save-button';
73
84
 
74
85
  import { ChatModelHandler } from './chat-model-handler';
75
86
 
@@ -77,13 +88,14 @@ import {
77
88
  CommandIds,
78
89
  IAgentManagerFactory,
79
90
  type IAISecretsAccess,
91
+ IAISettingsModel,
92
+ IChatModelHandler,
93
+ IDiffManager,
94
+ type IProviderConfig,
80
95
  IProviderRegistry,
81
96
  IToolRegistry,
82
97
  ISkillRegistry,
83
- SECRETS_NAMESPACE,
84
- IAISettingsModel,
85
- IChatModelHandler,
86
- IDiffManager
98
+ SECRETS_NAMESPACE
87
99
  } from './tokens';
88
100
 
89
101
  import {
@@ -105,7 +117,7 @@ import {
105
117
  TokenUsageWidget
106
118
  } from './components';
107
119
 
108
- import { AISettingsModel, IProviderConfig } from './models/settings-model';
120
+ import { AISettingsModel } from './models/settings-model';
109
121
 
110
122
  import { loadSkillsFromPaths, SkillRegistry } from './skills';
111
123
 
@@ -117,7 +129,9 @@ import {
117
129
  createDiscoverCommandsTool,
118
130
  createExecuteCommandTool
119
131
  } from './tools/commands';
132
+
120
133
  import { createDiscoverSkillsTool, createLoadSkillTool } from './tools/skills';
134
+
121
135
  import { createBrowserFetchTool } from './tools/web';
122
136
 
123
137
  import { AISettingsWidget } from './widgets/ai-settings';
@@ -320,17 +334,16 @@ const chatModelHandler: JupyterFrontEndPlugin<IChatModelHandler> = {
320
334
  ],
321
335
  optional: [IProviderRegistry, IToolRegistry, ITranslator],
322
336
  provides: IChatModelHandler,
323
- activate: (
337
+ activate: async (
324
338
  app: JupyterFrontEnd,
325
- settingsModel: AISettingsModel,
326
- agentManagerFactory: AgentManagerFactory,
339
+ settingsModel: IAISettingsModel,
340
+ agentManagerFactory: IAgentManagerFactory,
327
341
  docManager: IDocumentManager,
328
342
  rmRegistry: IRenderMimeRegistry,
329
343
  providerRegistry?: IProviderRegistry,
330
- toolRegistry?: IToolRegistry,
331
- translator?: ITranslator
332
- ): IChatModelHandler => {
333
- const trans = (translator ?? nullTranslator).load('jupyterlite_ai');
344
+ toolRegistry?: IToolRegistry
345
+ ): Promise<IChatModelHandler> => {
346
+ await app.serviceManager.ready;
334
347
 
335
348
  return new ChatModelHandler({
336
349
  settingsModel,
@@ -339,7 +352,7 @@ const chatModelHandler: JupyterFrontEndPlugin<IChatModelHandler> = {
339
352
  rmRegistry,
340
353
  providerRegistry,
341
354
  toolRegistry,
342
- trans
355
+ contentsManager: app.serviceManager.contents
343
356
  });
344
357
  }
345
358
  };
@@ -364,22 +377,29 @@ const plugin: JupyterFrontEndPlugin<IChatTracker> = {
364
377
  ILayoutRestorer,
365
378
  ILabShell,
366
379
  INotebookTracker,
367
- ITranslator
380
+ ITranslator,
381
+ IComponentsRendererFactory,
382
+ ICommandPalette,
383
+ IDocumentManager
368
384
  ],
369
385
  activate: (
370
386
  app: JupyterFrontEnd,
371
387
  rmRegistry: IRenderMimeRegistry,
372
388
  inputToolbarFactory: IInputToolbarRegistryFactory,
373
389
  modelHandler: IChatModelHandler,
374
- settingsModel: AISettingsModel,
390
+ settingsModel: IAISettingsModel,
375
391
  chatCommandRegistry: IChatCommandRegistry,
376
392
  themeManager?: IThemeManager,
377
393
  restorer?: ILayoutRestorer,
378
394
  labShell?: ILabShell,
379
395
  notebookTracker?: INotebookTracker,
380
- translator?: ITranslator
396
+ translator?: ITranslator,
397
+ chatComponentsFactory?: IComponentsRendererFactory,
398
+ palette?: ICommandPalette,
399
+ documentManager?: IDocumentManager
381
400
  ): IChatTracker => {
382
401
  const trans = (translator ?? nullTranslator).load('jupyterlite_ai');
402
+
383
403
  // Create attachment opener registry to handle file attachments
384
404
  const attachmentOpenerRegistry = new AttachmentOpenerRegistry();
385
405
  attachmentOpenerRegistry.set('file', attachment => {
@@ -436,7 +456,10 @@ const plugin: JupyterFrontEndPlugin<IChatTracker> = {
436
456
  name = `${modelName}-${i}`;
437
457
  i += 1;
438
458
  }
439
- const model = modelHandler.createModel(name, provider);
459
+ const model = modelHandler.createModel({
460
+ name,
461
+ activeProvider: provider
462
+ });
440
463
  return { model };
441
464
  },
442
465
  getChatNames: async () => {
@@ -525,6 +548,19 @@ const plugin: JupyterFrontEndPlugin<IChatTracker> = {
525
548
  tokenUsageWidget
526
549
  );
527
550
 
551
+ if (model.saveAvailable) {
552
+ const saveChatButton = new SaveComponentWidget({
553
+ model,
554
+ translator: trans
555
+ });
556
+
557
+ chatPanel.current?.toolbar.insertAfter(
558
+ 'markRead',
559
+ 'saveChat',
560
+ saveChatButton
561
+ );
562
+ }
563
+
528
564
  // Listen for writers change to display the stop button.
529
565
  function writersChanged(_: IChatModel, writers: IChatModel.IWriter[]) {
530
566
  // Check if AI is currently writing (streaming)
@@ -543,11 +579,6 @@ const plugin: JupyterFrontEndPlugin<IChatTracker> = {
543
579
 
544
580
  model.writersChanged?.connect(writersChanged);
545
581
 
546
- // Associate an approval buttons object to the chat.
547
- const approvalButton = new ApprovalButtons({
548
- chatPanel: widget,
549
- agentManager: model.agentManager
550
- });
551
582
  // Temporary compat: keep output-area CSS context for MIME renderers
552
583
  // until jupyter-chat provides it natively.
553
584
  const outputAreaCompat = new RenderedMessageOutputAreaCompat({
@@ -560,11 +591,17 @@ const plugin: JupyterFrontEndPlugin<IChatTracker> = {
560
591
  model.writersChanged?.disconnect(writersChanged);
561
592
 
562
593
  // Dispose of the approval buttons widget when the chat is disposed.
563
- approvalButton.dispose();
564
594
  outputAreaCompat.dispose();
565
595
  });
566
596
  });
567
597
 
598
+ /**
599
+ * Update the available chat list when settings config changed.
600
+ */
601
+ settingsModel.stateChanged.connect(() => {
602
+ chatPanel.updateChatList();
603
+ });
604
+
568
605
  app.shell.add(chatPanel, 'left', { rank: 1000 });
569
606
 
570
607
  if (restorer) {
@@ -602,9 +639,32 @@ const plugin: JupyterFrontEndPlugin<IChatTracker> = {
602
639
  modelHandler,
603
640
  trans,
604
641
  themeManager,
605
- labShell
642
+ labShell,
643
+ palette,
644
+ documentManager
606
645
  );
607
646
 
647
+ /**
648
+ * The callback to approve or reject a tool.
649
+ */
650
+ function toolCallApproval(
651
+ targetId: string,
652
+ approvalId: string,
653
+ isApproved: boolean
654
+ ) {
655
+ const model = tracker.find(chat => chat.model.name === targetId)?.model;
656
+ if (!model) {
657
+ return;
658
+ }
659
+ isApproved
660
+ ? (model as AIChatModel).agentManager.approveToolCall(approvalId)
661
+ : (model as AIChatModel).agentManager.rejectToolCall(approvalId);
662
+ }
663
+
664
+ if (chatComponentsFactory) {
665
+ chatComponentsFactory.toolCallApproval = toolCallApproval;
666
+ }
667
+
608
668
  return tracker;
609
669
  }
610
670
  };
@@ -615,13 +675,15 @@ function registerCommands(
615
675
  chatPanel: MultiChatPanel,
616
676
  attachmentOpenerRegistry: IAttachmentOpenerRegistry,
617
677
  inputToolbarFactory: IInputToolbarRegistryFactory,
618
- settingsModel: AISettingsModel,
678
+ settingsModel: IAISettingsModel,
619
679
  chatCommandRegistry: IChatCommandRegistry,
620
680
  tracker: WidgetTracker<MainAreaChat | ChatWidget>,
621
681
  modelRegistry: IChatModelHandler,
622
682
  trans: TranslationBundle,
623
683
  themeManager?: IThemeManager,
624
- labShell?: ILabShell
684
+ labShell?: ILabShell,
685
+ palette?: ICommandPalette,
686
+ documentManager?: IDocumentManager
625
687
  ) {
626
688
  const { commands } = app;
627
689
 
@@ -735,7 +797,10 @@ function registerCommands(
735
797
  name = providerConfig.name;
736
798
  }
737
799
 
738
- const model = modelRegistry.createModel(name, provider);
800
+ const model = modelRegistry.createModel({
801
+ name,
802
+ activeProvider: provider
803
+ });
739
804
  if (!model) {
740
805
  return false;
741
806
  }
@@ -817,13 +882,12 @@ function registerCommands(
817
882
  previousModel.name = UUID.uuid4();
818
883
 
819
884
  // Create a new model by duplicating the previous model attributes.
820
- const model = modelRegistry.createModel(
821
- args.name as string,
822
- previousModel.agentManager.activeProvider,
823
- previousModel.agentManager.tokenUsage
824
- );
825
- previousModel?.messages.forEach(message => {
826
- model?.messageAdded({ ...message.content });
885
+ const model = modelRegistry.createModel({
886
+ name: args.name as string,
887
+ activeProvider: previousModel.agentManager.activeProvider,
888
+ tokenUsage: previousModel.agentManager.tokenUsage,
889
+ messages: previousModel.messages,
890
+ autosave: previousModel.autosave
827
891
  });
828
892
 
829
893
  // Wait (with timeout) for the tracker to have updated the previous widget.
@@ -869,6 +933,135 @@ function registerCommands(
869
933
  }
870
934
  }
871
935
  });
936
+
937
+ commands.addCommand(CommandIds.saveChat, {
938
+ label: args => (args.isPalette ? trans.__('Save chat') : ''),
939
+ caption: trans.__('Save the chat as local file'),
940
+ icon: saveIcon,
941
+ execute: async (args): Promise<boolean> => {
942
+ let model: AIChatModel | null = null;
943
+ if (args.name) {
944
+ tracker.forEach(widget => {
945
+ if (widget.model.name === args.name) {
946
+ model = widget.model as AIChatModel;
947
+ }
948
+ });
949
+ } else {
950
+ model = (tracker.currentWidget?.model as AIChatModel) ?? null;
951
+ }
952
+ if (model === null) {
953
+ console.log('No chat to save');
954
+ return false;
955
+ }
956
+
957
+ model.save();
958
+ return true;
959
+ },
960
+ describedBy: {
961
+ args: {
962
+ type: 'object',
963
+ properties: {
964
+ isPalette: {
965
+ type: 'boolean',
966
+ description: trans.__('Whether the command is in palette')
967
+ },
968
+ name: {
969
+ type: 'string',
970
+ description: trans.__('The name of the chat to save')
971
+ }
972
+ }
973
+ }
974
+ }
975
+ });
976
+
977
+ commands.addCommand(CommandIds.restoreChat, {
978
+ label: args => (args.isPalette ? trans.__('Restore chat') : ''),
979
+ caption: trans.__('Restore the chat from a local file'),
980
+ icon: fileUploadIcon,
981
+ isVisible: () => !!documentManager,
982
+ execute: async (args): Promise<boolean> => {
983
+ if (!documentManager) {
984
+ console.warn('The restoration is not possible');
985
+ return false;
986
+ }
987
+ let model: AIChatModel | null = null;
988
+ if (args.name) {
989
+ tracker.forEach(widget => {
990
+ if (widget.model.name === args.name) {
991
+ model = widget.model as AIChatModel;
992
+ }
993
+ });
994
+ } else {
995
+ model = (tracker.currentWidget?.model as AIChatModel) ?? null;
996
+ }
997
+ if (model === null) {
998
+ console.warn('There is no chat to restore');
999
+ return false;
1000
+ }
1001
+
1002
+ let backupDirExists = false;
1003
+ await app.serviceManager.contents
1004
+ .get(settingsModel.config.chatBackupDirectory, { content: false })
1005
+ .then(() => (backupDirExists = true))
1006
+ .catch(() => (backupDirExists = false));
1007
+
1008
+ const selection = await FileDialog.getOpenFiles({
1009
+ title: trans.__('Select files to attach'),
1010
+ manager: documentManager,
1011
+ defaultPath: backupDirExists
1012
+ ? settingsModel.config.chatBackupDirectory
1013
+ : ''
1014
+ });
1015
+
1016
+ const filepath = selection.value?.[0].path;
1017
+
1018
+ if (!filepath) {
1019
+ return false;
1020
+ }
1021
+
1022
+ if (model.messages.length) {
1023
+ const result = await showDialog({
1024
+ body: trans.__('All the message will be deleted')
1025
+ });
1026
+ if (!result.button.accept) {
1027
+ return false;
1028
+ }
1029
+ }
1030
+ return model.restore(filepath);
1031
+ },
1032
+ describedBy: {
1033
+ args: {
1034
+ type: 'object',
1035
+ properties: {
1036
+ isPalette: {
1037
+ type: 'boolean',
1038
+ description: trans.__('Whether the command is in palette')
1039
+ },
1040
+ name: {
1041
+ type: 'string',
1042
+ description: trans.__('The name of the chat to save')
1043
+ }
1044
+ }
1045
+ }
1046
+ }
1047
+ });
1048
+
1049
+ if (palette) {
1050
+ palette.addItem({
1051
+ category: trans.__('AI Assistant'),
1052
+ command: CommandIds.saveChat,
1053
+ args: {
1054
+ isPalette: true
1055
+ }
1056
+ });
1057
+ palette.addItem({
1058
+ category: trans.__('AI Assistant'),
1059
+ command: CommandIds.restoreChat,
1060
+ args: {
1061
+ isPalette: true
1062
+ }
1063
+ });
1064
+ }
872
1065
  }
873
1066
  }
874
1067
 
@@ -876,7 +1069,7 @@ function registerCommands(
876
1069
  * A plugin to provide the agent manager factory and completion provider.
877
1070
  * These objects require the secrets manager token with the same namespace.
878
1071
  */
879
- const agentManagerFactory: JupyterFrontEndPlugin<AgentManagerFactory> =
1072
+ const agentManagerFactory: JupyterFrontEndPlugin<IAgentManagerFactory> =
880
1073
  SecretsManager.sign(SECRETS_NAMESPACE, token => {
881
1074
  Private.setAISecretsToken(token);
882
1075
 
@@ -889,12 +1082,12 @@ const agentManagerFactory: JupyterFrontEndPlugin<AgentManagerFactory> =
889
1082
  optional: [ISkillRegistry, ICompletionProviderManager, ISecretsManager],
890
1083
  activate: (
891
1084
  app: JupyterFrontEnd,
892
- settingsModel: AISettingsModel,
1085
+ settingsModel: IAISettingsModel,
893
1086
  providerRegistry: IProviderRegistry,
894
1087
  skillRegistry?: ISkillRegistry,
895
1088
  completionManager?: ICompletionProviderManager,
896
1089
  secretsManager?: ISecretsManager
897
- ): AgentManagerFactory => {
1090
+ ): IAgentManagerFactory => {
898
1091
  const agentManagerFactory = new AgentManagerFactory({
899
1092
  settingsModel,
900
1093
  skillRegistry,
@@ -940,8 +1133,8 @@ const settingsPanelPlugin: JupyterFrontEndPlugin<void> = {
940
1133
  ],
941
1134
  activate: (
942
1135
  app: JupyterFrontEnd,
943
- settingsModel: AISettingsModel,
944
- agentManagerFactory: AgentManagerFactory,
1136
+ settingsModel: IAISettingsModel,
1137
+ agentManagerFactory: IAgentManagerFactory,
945
1138
  providerRegistry: IProviderRegistry,
946
1139
  palette?: ICommandPalette,
947
1140
  restorer?: ILayoutRestorer,
@@ -1005,13 +1198,16 @@ const settingsPanelPlugin: JupyterFrontEndPlugin<void> = {
1005
1198
  /**
1006
1199
  * Built-in completion providers plugin
1007
1200
  */
1008
- const settingsModel: JupyterFrontEndPlugin<AISettingsModel> = {
1201
+ const settingsModel: JupyterFrontEndPlugin<IAISettingsModel> = {
1009
1202
  id: '@jupyterlite/ai:settings-model',
1010
1203
  description: 'Provide the AI settings model',
1011
1204
  autoStart: true,
1012
1205
  provides: IAISettingsModel,
1013
1206
  requires: [ISettingRegistry],
1014
- activate: (app: JupyterFrontEnd, settingRegistry: ISettingRegistry) => {
1207
+ activate: (
1208
+ app: JupyterFrontEnd,
1209
+ settingRegistry: ISettingRegistry
1210
+ ): IAISettingsModel => {
1015
1211
  return new AISettingsModel({ settingRegistry });
1016
1212
  }
1017
1213
  };
@@ -1027,7 +1223,7 @@ const diffManager: JupyterFrontEndPlugin<IDiffManager> = {
1027
1223
  requires: [IAISettingsModel],
1028
1224
  activate: (
1029
1225
  app: JupyterFrontEnd,
1030
- settingsModel: AISettingsModel
1226
+ settingsModel: IAISettingsModel
1031
1227
  ): IDiffManager => {
1032
1228
  return new DiffManager({
1033
1229
  commands: app.commands,
@@ -1058,7 +1254,7 @@ const toolRegistry: JupyterFrontEndPlugin<IToolRegistry> = {
1058
1254
  provides: IToolRegistry,
1059
1255
  activate: (
1060
1256
  app: JupyterFrontEnd,
1061
- settingsModel: AISettingsModel,
1257
+ settingsModel: IAISettingsModel,
1062
1258
  skillRegistry?: ISkillRegistry
1063
1259
  ) => {
1064
1260
  const toolRegistry = new ToolRegistry();
@@ -1098,7 +1294,7 @@ const inputToolbarFactory: JupyterFrontEndPlugin<IInputToolbarRegistryFactory> =
1098
1294
  optional: [ITranslator],
1099
1295
  activate: (
1100
1296
  app: JupyterFrontEnd,
1101
- settingsModel: AISettingsModel,
1297
+ settingsModel: IAISettingsModel,
1102
1298
  toolRegistry: IToolRegistry,
1103
1299
  providerRegistry: IProviderRegistry,
1104
1300
  translator?: ITranslator
@@ -1148,7 +1344,7 @@ const completionStatus: JupyterFrontEndPlugin<void> = {
1148
1344
  optional: [IStatusBar, ITranslator],
1149
1345
  activate: (
1150
1346
  app: JupyterFrontEnd,
1151
- settingsModel: AISettingsModel,
1347
+ settingsModel: IAISettingsModel,
1152
1348
  statusBar: IStatusBar | null,
1153
1349
  translator?: ITranslator
1154
1350
  ) => {
@@ -1179,7 +1375,7 @@ const skillsPlugin: JupyterFrontEndPlugin<void> = {
1179
1375
  optional: [ICommandPalette, ITranslator],
1180
1376
  activate: async (
1181
1377
  app: JupyterFrontEnd,
1182
- settingsModel: AISettingsModel,
1378
+ settingsModel: IAISettingsModel,
1183
1379
  docManager: IDocumentManager,
1184
1380
  skillRegistry: ISkillRegistry,
1185
1381
  palette?: ICommandPalette,