@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
@@ -1,5 +1,6 @@
1
1
  import { IThemeManager } from '@jupyterlab/apputils';
2
2
  import { ReactWidget } from '@jupyterlab/ui-components';
3
+ import type { TranslationBundle } from '@jupyterlab/translation';
3
4
  import { Debouncer } from '@lumino/polling';
4
5
  import Add from '@mui/icons-material/Add';
5
6
  import Cable from '@mui/icons-material/Cable';
@@ -92,9 +93,10 @@ export class AISettingsWidget extends ReactWidget {
92
93
  this._themeManager = options.themeManager;
93
94
  this._providerRegistry = options.providerRegistry;
94
95
  this._secretsManager = options.secretsManager;
96
+ this._trans = options.trans;
95
97
  this.id = 'jupyterlite-ai-settings';
96
- this.title.label = 'AI Settings';
97
- this.title.caption = 'Configure AI providers and behavior';
98
+ this.title.label = this._trans.__('AI Settings');
99
+ this.title.caption = this._trans.__('Configure AI providers and behavior');
98
100
  this.title.closable = true;
99
101
  }
100
102
 
@@ -110,6 +112,7 @@ export class AISettingsWidget extends ReactWidget {
110
112
  themeManager={this._themeManager}
111
113
  providerRegistry={this._providerRegistry}
112
114
  secretsManager={this._secretsManager}
115
+ trans={this._trans}
113
116
  />
114
117
  );
115
118
  }
@@ -119,6 +122,7 @@ export class AISettingsWidget extends ReactWidget {
119
122
  private _themeManager?: IThemeManager;
120
123
  private _providerRegistry: IProviderRegistry;
121
124
  private _secretsManager?: ISecretsManager;
125
+ private _trans: TranslationBundle;
122
126
  }
123
127
 
124
128
  /**
@@ -130,6 +134,7 @@ interface IAISettingsComponentProps {
130
134
  themeManager?: IThemeManager;
131
135
  providerRegistry: IProviderRegistry;
132
136
  secretsManager?: ISecretsManager;
137
+ trans: TranslationBundle;
133
138
  }
134
139
 
135
140
  /**
@@ -142,10 +147,11 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
142
147
  agentManagerFactory,
143
148
  themeManager,
144
149
  providerRegistry,
145
- secretsManager
150
+ secretsManager,
151
+ trans
146
152
  }) => {
147
153
  if (!model) {
148
- return <div>Settings model not available</div>;
154
+ return <div>{trans.__('Settings model not available')}</div>;
149
155
  }
150
156
 
151
157
  const [config, setConfig] = useState(model.config || {});
@@ -535,7 +541,7 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
535
541
  <Box sx={{ mb: 2, display: 'flex', alignItems: 'center', gap: 2 }}>
536
542
  <Settings color="primary" sx={{ fontSize: 24 }} />
537
543
  <Typography variant="h5" component="h1" sx={{ fontWeight: 600 }}>
538
- AI Settings
544
+ {trans.__('AI Settings')}
539
545
  </Typography>
540
546
  </Box>
541
547
  {/* Tabs */}
@@ -544,9 +550,9 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
544
550
  value={activeTab}
545
551
  onChange={(_, newValue) => setActiveTab(newValue)}
546
552
  >
547
- <Tab label="Providers" />
548
- <Tab label="Behavior" />
549
- <Tab label="MCP Servers" />
553
+ <Tab label={trans.__('Providers')} />
554
+ <Tab label={trans.__('Behavior')} />
555
+ <Tab label={trans.__('MCP Servers')} />
550
556
  </Tabs>
551
557
  </Box>
552
558
 
@@ -558,17 +564,17 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
558
564
  <Card elevation={2}>
559
565
  <CardContent>
560
566
  <Typography variant="h6" component="h2" gutterBottom>
561
- Default Providers
567
+ {trans.__('Default Providers')}
562
568
  </Typography>
563
569
 
564
570
  <Box
565
571
  sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}
566
572
  >
567
573
  <FormControl fullWidth>
568
- <InputLabel>Chat Provider</InputLabel>
574
+ <InputLabel>{trans.__('Chat Provider')}</InputLabel>
569
575
  <Select
570
576
  value={config.defaultProvider}
571
- label="Chat Provider"
577
+ label={trans.__('Chat Provider')}
572
578
  onChange={e => model.setActiveProvider(e.target.value)}
573
579
  >
574
580
  {config.providers.map(provider => (
@@ -592,15 +598,19 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
592
598
  color="primary"
593
599
  />
594
600
  }
595
- label="Use same provider for chat and completions"
601
+ label={trans.__(
602
+ 'Use same provider for chat and completions'
603
+ )}
596
604
  />
597
605
 
598
606
  {!config.useSameProviderForChatAndCompleter && (
599
607
  <FormControl fullWidth>
600
- <InputLabel>Completion Provider</InputLabel>
608
+ <InputLabel>
609
+ {trans.__('Completion Provider')}
610
+ </InputLabel>
601
611
  <Select
602
612
  value={config.activeCompleterProvider || ''}
603
- label="Completion Provider"
613
+ label={trans.__('Completion Provider')}
604
614
  className="jp-ai-completion-provider-select"
605
615
  onChange={e =>
606
616
  model.setActiveCompleterProvider(
@@ -609,7 +619,7 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
609
619
  }
610
620
  >
611
621
  <MenuItem value="">
612
- <em>No completion</em>
622
+ <em>{trans.__('No completion')}</em>
613
623
  </MenuItem>
614
624
  {config.providers.map(provider => (
615
625
  <MenuItem key={provider.id} value={provider.id}>
@@ -637,7 +647,7 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
637
647
  >
638
648
  <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
639
649
  <Typography variant="h6" component="h2">
640
- Configured Providers
650
+ {trans.__('Configured Providers')}
641
651
  </Typography>
642
652
  </Box>
643
653
  <Button
@@ -646,14 +656,15 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
646
656
  onClick={openAddDialog}
647
657
  size="small"
648
658
  >
649
- Add Provider
659
+ {trans.__('Add Provider')}
650
660
  </Button>
651
661
  </Box>
652
662
 
653
663
  {config.providers.length === 0 ? (
654
664
  <Alert severity="info">
655
- No providers configured yet. Click "Add Provider" to get
656
- started.
665
+ {trans.__(
666
+ 'No providers configured yet. Click "Add Provider" to get started.'
667
+ )}
657
668
  </Alert>
658
669
  ) : (
659
670
  <List>
@@ -700,7 +711,7 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
700
711
  </Typography>
701
712
  {isActive && (
702
713
  <Chip
703
- label="Chat"
714
+ label={trans.__('Chat')}
704
715
  size="small"
705
716
  color="primary"
706
717
  icon={<CheckCircle />}
@@ -708,7 +719,7 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
708
719
  )}
709
720
  {isActiveCompleter && (
710
721
  <Chip
711
- label="Completion"
722
+ label={trans.__('Completion')}
712
723
  size="small"
713
724
  color="secondary"
714
725
  icon={<CheckCircle />}
@@ -728,7 +739,7 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
728
739
  {/* Display parameters if set */}
729
740
  {params &&
730
741
  (params.temperature !== undefined ||
731
- params.maxTokens !== undefined ||
742
+ params.maxOutputTokens !== undefined ||
732
743
  params.maxTurns !== undefined) && (
733
744
  <Box
734
745
  sx={{
@@ -740,21 +751,30 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
740
751
  >
741
752
  {params.temperature !== undefined && (
742
753
  <Chip
743
- label={`Temp: ${params.temperature}`}
754
+ label={trans.__(
755
+ 'Temp: %1',
756
+ params.temperature
757
+ )}
744
758
  size="small"
745
759
  variant="outlined"
746
760
  />
747
761
  )}
748
- {params.maxTokens !== undefined && (
762
+ {params.maxOutputTokens !== undefined && (
749
763
  <Chip
750
- label={`Tokens: ${params.maxTokens}`}
764
+ label={trans.__(
765
+ 'Tokens: %1',
766
+ params.maxOutputTokens
767
+ )}
751
768
  size="small"
752
769
  variant="outlined"
753
770
  />
754
771
  )}
755
772
  {params.maxTurns !== undefined && (
756
773
  <Chip
757
- label={`Turns: ${params.maxTurns}`}
774
+ label={trans.__(
775
+ 'Turns: %1',
776
+ params.maxTurns
777
+ )}
758
778
  size="small"
759
779
  variant="outlined"
760
780
  />
@@ -794,10 +814,14 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
794
814
  }
795
815
  label={
796
816
  <div>
797
- <span>Use the secrets manager to manage API keys</span>
817
+ <span>
818
+ {trans.__('Use the secrets manager to manage API keys')}
819
+ </span>
798
820
  {!config.useSecretsManager && (
799
821
  <Alert severity="warning" icon={<Error />} sx={{ mb: 2 }}>
800
- The secrets are stored in plain text in settings
822
+ {trans.__(
823
+ 'The secrets are stored in plain text in settings'
824
+ )}
801
825
  </Alert>
802
826
  )}
803
827
  </div>
@@ -811,7 +835,7 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
811
835
  <Card elevation={2}>
812
836
  <CardContent>
813
837
  <Typography variant="h6" component="h2" gutterBottom>
814
- Behavior Settings
838
+ {trans.__('Behavior Settings')}
815
839
  </Typography>
816
840
 
817
841
  <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
@@ -829,10 +853,13 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
829
853
  }
830
854
  label={
831
855
  <Box>
832
- <Typography variant="body1">Enable Tools</Typography>
856
+ <Typography variant="body1">
857
+ {trans.__('Enable Tools')}
858
+ </Typography>
833
859
  <Typography variant="caption" color="text.secondary">
834
- Allow the AI to use tools like notebook operations, code
835
- execution, and file management
860
+ {trans.__(
861
+ 'Allow the AI to use tools like notebook operations, code execution, and file management'
862
+ )}
836
863
  </Typography>
837
864
  </Box>
838
865
  }
@@ -853,11 +880,12 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
853
880
  label={
854
881
  <Box>
855
882
  <Typography variant="body1">
856
- Send with Shift+Enter
883
+ {trans.__('Send with Shift+Enter')}
857
884
  </Typography>
858
885
  <Typography variant="caption" color="text.secondary">
859
- Use Shift+Enter to send messages (Enter creates new
860
- line)
886
+ {trans.__(
887
+ 'Use Shift+Enter to send messages (Enter creates new line)'
888
+ )}
861
889
  </Typography>
862
890
  </Box>
863
891
  }
@@ -877,9 +905,13 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
877
905
  }
878
906
  label={
879
907
  <Box>
880
- <Typography variant="body1">Show Token Usage</Typography>
908
+ <Typography variant="body1">
909
+ {trans.__('Show Token Usage')}
910
+ </Typography>
881
911
  <Typography variant="caption" color="text.secondary">
882
- Display token usage information in the chat toolbar
912
+ {trans.__(
913
+ 'Display token usage information in the chat toolbar'
914
+ )}
883
915
  </Typography>
884
916
  </Box>
885
917
  }
@@ -899,9 +931,13 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
899
931
  }
900
932
  label={
901
933
  <Box>
902
- <Typography variant="body1">Show Cell Diff</Typography>
934
+ <Typography variant="body1">
935
+ {trans.__('Show Cell Diff')}
936
+ </Typography>
903
937
  <Typography variant="caption" color="text.secondary">
904
- Show diff view when AI modifies cell content
938
+ {trans.__(
939
+ 'Show diff view when AI modifies cell content'
940
+ )}
905
941
  </Typography>
906
942
  </Box>
907
943
  }
@@ -909,18 +945,22 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
909
945
 
910
946
  {config.showCellDiff && (
911
947
  <FormControl sx={{ ml: 4 }}>
912
- <InputLabel>Diff Display Mode</InputLabel>
948
+ <InputLabel>{trans.__('Diff Display Mode')}</InputLabel>
913
949
  <Select
914
950
  value={config.diffDisplayMode}
915
- label="Diff Display Mode"
951
+ label={trans.__('Diff Display Mode')}
916
952
  onChange={e =>
917
953
  handleConfigUpdate({
918
954
  diffDisplayMode: e.target.value as 'split' | 'unified'
919
955
  })
920
956
  }
921
957
  >
922
- <MenuItem value="split">Split View</MenuItem>
923
- <MenuItem value="unified">Unified View</MenuItem>
958
+ <MenuItem value="split">
959
+ {trans.__('Split View')}
960
+ </MenuItem>
961
+ <MenuItem value="unified">
962
+ {trans.__('Unified View')}
963
+ </MenuItem>
924
964
  </Select>
925
965
  </FormControl>
926
966
  )}
@@ -939,9 +979,13 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
939
979
  }
940
980
  label={
941
981
  <Box>
942
- <Typography variant="body1">Show File Diff</Typography>
982
+ <Typography variant="body1">
983
+ {trans.__('Show File Diff')}
984
+ </Typography>
943
985
  <Typography variant="caption" color="text.secondary">
944
- Show diff view when AI modifies file content
986
+ {trans.__(
987
+ 'Show diff view when AI modifies file content'
988
+ )}
945
989
  </Typography>
946
990
  </Box>
947
991
  }
@@ -953,29 +997,37 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
953
997
  fullWidth
954
998
  multiline
955
999
  rows={3}
956
- label="System Prompt"
1000
+ label={trans.__('System Prompt')}
957
1001
  value={systemPromptValue}
958
1002
  onChange={e => handleSystemPromptChange(e.target.value)}
959
- placeholder="Define the AI's behavior and personality..."
960
- helperText="Instructions that define how the AI should behave and respond"
1003
+ placeholder={trans.__(
1004
+ "Define the AI's behavior and personality..."
1005
+ )}
1006
+ helperText={trans.__(
1007
+ 'Instructions that define how the AI should behave and respond'
1008
+ )}
961
1009
  />
962
1010
 
963
1011
  <TextField
964
1012
  fullWidth
965
1013
  multiline
966
1014
  rows={3}
967
- label="Completion System Prompt"
1015
+ label={trans.__('Completion System Prompt')}
968
1016
  value={completionPromptValue}
969
1017
  onChange={e => handleCompletionPromptChange(e.target.value)}
970
- placeholder="Define how the AI should generate code completions..."
971
- helperText="Instructions that define how the AI should generate code completions"
1018
+ placeholder={trans.__(
1019
+ 'Define how the AI should generate code completions...'
1020
+ )}
1021
+ helperText={trans.__(
1022
+ 'Instructions that define how the AI should generate code completions'
1023
+ )}
972
1024
  />
973
1025
 
974
1026
  <Divider sx={{ my: 2 }} />
975
1027
 
976
1028
  <Box>
977
1029
  <Typography variant="body1" gutterBottom>
978
- Commands Requiring Approval
1030
+ {trans.__('Commands Requiring Approval')}
979
1031
  </Typography>
980
1032
  <Typography
981
1033
  variant="caption"
@@ -983,8 +1035,9 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
983
1035
  gutterBottom
984
1036
  sx={{ display: 'block' }}
985
1037
  >
986
- Commands that require user approval before AI can execute
987
- them
1038
+ {trans.__(
1039
+ 'Commands that require user approval before AI can execute them'
1040
+ )}
988
1041
  </Typography>
989
1042
 
990
1043
  <List sx={{ mb: 2, maxHeight: 200, overflow: 'auto' }}>
@@ -1013,8 +1066,8 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
1013
1066
 
1014
1067
  <TextField
1015
1068
  fullWidth
1016
- label="Add New Command"
1017
- placeholder="e.g., notebook:run-cell"
1069
+ label={trans.__('Add New Command')}
1070
+ placeholder={trans.__('e.g., notebook:run-cell')}
1018
1071
  onKeyDown={e => {
1019
1072
  if (e.key === 'Enter') {
1020
1073
  const value = (
@@ -1035,7 +1088,9 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
1035
1088
  }
1036
1089
  }
1037
1090
  }}
1038
- helperText="Press Enter to add a command. Common commands: notebook:run-cell, console:execute, fileeditor:run-code"
1091
+ helperText={trans.__(
1092
+ 'Press Enter to add a command. Common commands: notebook:run-cell, console:execute, fileeditor:run-code'
1093
+ )}
1039
1094
  />
1040
1095
  </Box>
1041
1096
  </Box>
@@ -1057,7 +1112,7 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
1057
1112
  <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
1058
1113
  <Cable color="primary" />
1059
1114
  <Typography variant="h6" component="h2">
1060
- Remote MCP Servers
1115
+ {trans.__('Remote MCP Servers')}
1061
1116
  </Typography>
1062
1117
  </Box>
1063
1118
  <Button
@@ -1066,19 +1121,21 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
1066
1121
  onClick={openAddMCPDialog}
1067
1122
  size="small"
1068
1123
  >
1069
- Add Server
1124
+ {trans.__('Add Server')}
1070
1125
  </Button>
1071
1126
  </Box>
1072
1127
 
1073
1128
  <Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
1074
- Configure remote Model Context Protocol (MCP) servers to extend
1075
- the AI's capabilities with external tools and data sources.
1129
+ {trans.__(
1130
+ "Configure remote Model Context Protocol (MCP) servers to extend the AI's capabilities with external tools and data sources."
1131
+ )}
1076
1132
  </Typography>
1077
1133
 
1078
1134
  {config.mcpServers.length === 0 ? (
1079
1135
  <Alert severity="info">
1080
- No MCP servers configured yet. Click "Add Server" to connect
1081
- to remote MCP services.
1136
+ {trans.__(
1137
+ 'No MCP servers configured yet. Click "Add Server" to connect to remote MCP services.'
1138
+ )}
1082
1139
  </Alert>
1083
1140
  ) : (
1084
1141
  <List>
@@ -1134,12 +1191,14 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
1134
1191
  variant="caption"
1135
1192
  color="text.secondary"
1136
1193
  >
1137
- Status:{' '}
1138
- {agentManagerFactory.isMCPServerConnected(
1139
- server.name
1140
- )
1141
- ? 'Connected'
1142
- : 'Connection failed'}
1194
+ {trans.__(
1195
+ 'Status: %1',
1196
+ agentManagerFactory.isMCPServerConnected(
1197
+ server.name
1198
+ )
1199
+ ? trans.__('Connected')
1200
+ : trans.__('Connection failed')
1201
+ )}
1143
1202
  </Typography>
1144
1203
  )}
1145
1204
  </Box>
@@ -1170,6 +1229,7 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
1170
1229
  mode={editingProvider ? 'edit' : 'add'}
1171
1230
  providerRegistry={providerRegistry}
1172
1231
  handleSecretField={handleSecretField}
1232
+ trans={trans}
1173
1233
  />
1174
1234
 
1175
1235
  {/* Provider Menu */}
@@ -1189,14 +1249,14 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
1189
1249
  }}
1190
1250
  >
1191
1251
  <Edit sx={{ mr: 1 }} />
1192
- Edit
1252
+ {trans.__('Edit')}
1193
1253
  </MenuItem>
1194
1254
  <MenuItem
1195
1255
  onClick={() => handleDeleteProvider(menuProviderId)}
1196
1256
  sx={{ color: 'error.main' }}
1197
1257
  >
1198
1258
  <Delete sx={{ mr: 1 }} />
1199
- Delete
1259
+ {trans.__('Delete')}
1200
1260
  </MenuItem>
1201
1261
  </Menu>
1202
1262
 
@@ -1207,6 +1267,7 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
1207
1267
  onSave={editingMCPServer ? handleEditMCPServer : handleAddMCPServer}
1208
1268
  initialConfig={editingMCPServer}
1209
1269
  mode={editingMCPServer ? 'edit' : 'add'}
1270
+ trans={trans}
1210
1271
  />
1211
1272
 
1212
1273
  {/* MCP Server Menu */}
@@ -1226,14 +1287,14 @@ const AISettingsComponent: React.FC<IAISettingsComponentProps> = ({
1226
1287
  }}
1227
1288
  >
1228
1289
  <Edit sx={{ mr: 1 }} />
1229
- Edit
1290
+ {trans.__('Edit')}
1230
1291
  </MenuItem>
1231
1292
  <MenuItem
1232
1293
  onClick={() => handleDeleteMCPServer(mcpMenuServerId)}
1233
1294
  sx={{ color: 'error.main' }}
1234
1295
  >
1235
1296
  <Delete sx={{ mr: 1 }} />
1236
- Delete
1297
+ {trans.__('Delete')}
1237
1298
  </MenuItem>
1238
1299
  </Menu>
1239
1300
  </Box>
@@ -1250,6 +1311,7 @@ interface IMCPServerDialogProps {
1250
1311
  onSave: (config: Omit<IMCPServerConfig, 'id'>) => void;
1251
1312
  initialConfig?: IMCPServerConfig;
1252
1313
  mode: 'add' | 'edit';
1314
+ trans: TranslationBundle;
1253
1315
  }
1254
1316
 
1255
1317
  /**
@@ -1262,7 +1324,8 @@ const MCPServerDialog: React.FC<IMCPServerDialogProps> = ({
1262
1324
  onClose,
1263
1325
  onSave,
1264
1326
  initialConfig,
1265
- mode
1327
+ mode,
1328
+ trans
1266
1329
  }) => {
1267
1330
  const [name, setName] = useState(initialConfig?.name || '');
1268
1331
  const [url, setUrl] = useState(initialConfig?.url || '');
@@ -1314,26 +1377,28 @@ const MCPServerDialog: React.FC<IMCPServerDialogProps> = ({
1314
1377
  return (
1315
1378
  <Dialog open={open} onClose={onClose} maxWidth="sm" fullWidth>
1316
1379
  <DialogTitle>
1317
- {mode === 'add' ? 'Add MCP Server' : 'Edit MCP Server'}
1380
+ {mode === 'add'
1381
+ ? trans.__('Add MCP Server')
1382
+ : trans.__('Edit MCP Server')}
1318
1383
  </DialogTitle>
1319
1384
  <DialogContent>
1320
1385
  <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, pt: 1 }}>
1321
1386
  <TextField
1322
1387
  autoFocus
1323
1388
  fullWidth
1324
- label="Server Name"
1389
+ label={trans.__('Server Name')}
1325
1390
  value={name}
1326
1391
  onChange={e => setName(e.target.value)}
1327
- placeholder="My MCP Server"
1328
- helperText="A friendly name to identify this MCP server"
1392
+ placeholder={trans.__('My MCP Server')}
1393
+ helperText={trans.__('A friendly name to identify this MCP server')}
1329
1394
  />
1330
1395
  <TextField
1331
1396
  fullWidth
1332
- label="Server URL"
1397
+ label={trans.__('Server URL')}
1333
1398
  value={url}
1334
1399
  onChange={e => setUrl(e.target.value)}
1335
- placeholder="https://example.com/mcp"
1336
- helperText="The HTTP/HTTPS URL of the MCP server"
1400
+ placeholder={trans.__('https://example.com/mcp')}
1401
+ helperText={trans.__('The HTTP/HTTPS URL of the MCP server')}
1337
1402
  error={Boolean(url.trim() && !_isValidUrl(url.trim()))}
1338
1403
  />
1339
1404
  <FormControlLabel
@@ -1344,14 +1409,14 @@ const MCPServerDialog: React.FC<IMCPServerDialogProps> = ({
1344
1409
  color="primary"
1345
1410
  />
1346
1411
  }
1347
- label="Enable this server"
1412
+ label={trans.__('Enable this server')}
1348
1413
  />
1349
1414
  </Box>
1350
1415
  </DialogContent>
1351
1416
  <DialogActions>
1352
- <Button onClick={onClose}>Cancel</Button>
1417
+ <Button onClick={onClose}>{trans.__('Cancel')}</Button>
1353
1418
  <Button onClick={handleSave} variant="contained" disabled={!canSave}>
1354
- {mode === 'add' ? 'Add' : 'Save'}
1419
+ {mode === 'add' ? trans.__('Add') : trans.__('Save')}
1355
1420
  </Button>
1356
1421
  </DialogActions>
1357
1422
  </Dialog>
@@ -1378,6 +1443,10 @@ export namespace AISettingsWidget {
1378
1443
  * The token used to request the secrets manager.
1379
1444
  */
1380
1445
  token: symbol;
1446
+ /**
1447
+ * The application language translation bundle.
1448
+ */
1449
+ trans: TranslationBundle;
1381
1450
  }
1382
1451
  }
1383
1452
 
@@ -1,6 +1,7 @@
1
1
  import { ChatWidget } from '@jupyter/chat';
2
2
  import { CommandToolbarButton, MainAreaWidget } from '@jupyterlab/apputils';
3
3
  import { launchIcon } from '@jupyterlab/ui-components';
4
+ import type { TranslationBundle } from '@jupyterlab/translation';
4
5
  import { CommandRegistry } from '@lumino/commands';
5
6
 
6
7
  import { ApprovalButtons } from '../approval-buttons';
@@ -13,6 +14,7 @@ export namespace MainAreaChat {
13
14
  export interface IOptions extends MainAreaWidget.IOptions<ChatWidget> {
14
15
  commands: CommandRegistry;
15
16
  settingsModel: AISettingsModel;
17
+ trans: TranslationBundle;
16
18
  }
17
19
  }
18
20
 
@@ -24,6 +26,8 @@ export class MainAreaChat extends MainAreaWidget<ChatWidget> {
24
26
  super(options);
25
27
  this.title.label = this.content.model.name;
26
28
 
29
+ const { trans } = options;
30
+
27
31
  // add the move to side button.
28
32
  this.toolbar.addItem(
29
33
  'moveToSide',
@@ -42,13 +46,15 @@ export class MainAreaChat extends MainAreaWidget<ChatWidget> {
42
46
  const tokenUsageWidget = new TokenUsageWidget({
43
47
  tokenUsageChanged: this.model.tokenUsageChanged,
44
48
  settingsModel: options.settingsModel,
45
- initialTokenUsage: this.model.agentManager.tokenUsage
49
+ initialTokenUsage: this.model.agentManager.tokenUsage,
50
+ translator: trans
46
51
  });
47
52
  this.toolbar.addItem('token-usage', tokenUsageWidget);
48
53
 
49
54
  // Add the approval button, tied to the chat widget.
50
55
  this._approvalButtons = new ApprovalButtons({
51
- chatPanel: this.content
56
+ chatPanel: this.content,
57
+ agentManager: this.model.agentManager
52
58
  });
53
59
  }
54
60