@jupyterlite/ai 0.17.0 → 0.19.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 (114) hide show
  1. package/lib/chat-commands/clear.d.ts +1 -0
  2. package/lib/chat-commands/index.d.ts +1 -0
  3. package/lib/chat-commands/skills.d.ts +2 -1
  4. package/lib/chat-model-handler.d.ts +4 -3
  5. package/lib/chat-model-handler.js +2 -1
  6. package/lib/chat-model.d.ts +148 -8
  7. package/lib/chat-model.js +368 -79
  8. package/lib/completion/completion-provider.d.ts +3 -1
  9. package/lib/completion/completion-provider.js +1 -2
  10. package/lib/completion/index.d.ts +1 -0
  11. package/lib/components/clear-button.d.ts +1 -0
  12. package/lib/components/clear-button.js +3 -4
  13. package/lib/components/completion-status.d.ts +1 -0
  14. package/lib/components/completion-status.js +5 -4
  15. package/lib/components/index.d.ts +1 -0
  16. package/lib/components/model-select.d.ts +1 -0
  17. package/lib/components/model-select.js +62 -67
  18. package/lib/components/save-button.d.ts +3 -2
  19. package/lib/components/save-button.js +4 -5
  20. package/lib/components/stop-button.d.ts +1 -0
  21. package/lib/components/stop-button.js +3 -4
  22. package/lib/components/tool-select.d.ts +3 -1
  23. package/lib/components/tool-select.js +47 -60
  24. package/lib/components/usage-display.d.ts +4 -2
  25. package/lib/components/usage-display.js +50 -61
  26. package/lib/diff-manager.d.ts +3 -1
  27. package/lib/index.d.ts +3 -2
  28. package/lib/index.js +50 -59
  29. package/lib/models/settings-model.d.ts +3 -1
  30. package/lib/models/settings-model.js +1 -0
  31. package/lib/rendered-message-outputarea.d.ts +1 -0
  32. package/lib/tokens.d.ts +48 -597
  33. package/lib/tokens.js +2 -31
  34. package/lib/widgets/ai-settings.d.ts +3 -1
  35. package/lib/widgets/ai-settings.js +185 -344
  36. package/lib/widgets/main-area-chat.d.ts +3 -3
  37. package/lib/widgets/main-area-chat.js +2 -4
  38. package/lib/widgets/provider-config-dialog.d.ts +2 -1
  39. package/lib/widgets/provider-config-dialog.js +102 -167
  40. package/package.json +111 -258
  41. package/schema/settings-model.json +6 -0
  42. package/src/chat-commands/skills.ts +2 -2
  43. package/src/chat-model-handler.ts +10 -6
  44. package/src/chat-model.ts +488 -96
  45. package/src/completion/completion-provider.ts +6 -6
  46. package/src/components/clear-button.tsx +0 -2
  47. package/src/components/completion-status.tsx +2 -2
  48. package/src/components/model-select.tsx +1 -1
  49. package/src/components/save-button.tsx +3 -3
  50. package/src/components/stop-button.tsx +0 -2
  51. package/src/components/tool-select.tsx +10 -9
  52. package/src/components/usage-display.tsx +4 -2
  53. package/src/diff-manager.ts +4 -3
  54. package/src/index.ts +103 -107
  55. package/src/models/settings-model.ts +7 -6
  56. package/src/tokens.ts +54 -744
  57. package/src/widgets/ai-settings.tsx +40 -11
  58. package/src/widgets/main-area-chat.ts +5 -8
  59. package/src/widgets/provider-config-dialog.tsx +8 -8
  60. package/LICENSE +0 -30
  61. package/README.md +0 -49
  62. package/lib/agent.d.ts +0 -277
  63. package/lib/agent.js +0 -1116
  64. package/lib/icons.d.ts +0 -3
  65. package/lib/icons.js +0 -8
  66. package/lib/providers/built-in-providers.d.ts +0 -21
  67. package/lib/providers/built-in-providers.js +0 -233
  68. package/lib/providers/generated-context-windows.d.ts +0 -8
  69. package/lib/providers/generated-context-windows.js +0 -96
  70. package/lib/providers/model-info.d.ts +0 -3
  71. package/lib/providers/model-info.js +0 -58
  72. package/lib/providers/models.d.ts +0 -37
  73. package/lib/providers/models.js +0 -28
  74. package/lib/providers/provider-registry.d.ts +0 -49
  75. package/lib/providers/provider-registry.js +0 -72
  76. package/lib/providers/provider-tools.d.ts +0 -36
  77. package/lib/providers/provider-tools.js +0 -93
  78. package/lib/skills/index.d.ts +0 -4
  79. package/lib/skills/index.js +0 -7
  80. package/lib/skills/parse-skill.d.ts +0 -25
  81. package/lib/skills/parse-skill.js +0 -69
  82. package/lib/skills/skill-loader.d.ts +0 -25
  83. package/lib/skills/skill-loader.js +0 -133
  84. package/lib/skills/skill-registry.d.ts +0 -31
  85. package/lib/skills/skill-registry.js +0 -100
  86. package/lib/skills/types.d.ts +0 -29
  87. package/lib/skills/types.js +0 -5
  88. package/lib/tools/commands.d.ts +0 -11
  89. package/lib/tools/commands.js +0 -154
  90. package/lib/tools/skills.d.ts +0 -9
  91. package/lib/tools/skills.js +0 -73
  92. package/lib/tools/tool-registry.d.ts +0 -35
  93. package/lib/tools/tool-registry.js +0 -55
  94. package/lib/tools/web.d.ts +0 -8
  95. package/lib/tools/web.js +0 -196
  96. package/src/agent.ts +0 -1441
  97. package/src/icons.ts +0 -11
  98. package/src/providers/built-in-providers.ts +0 -241
  99. package/src/providers/generated-context-windows.ts +0 -102
  100. package/src/providers/model-info.ts +0 -88
  101. package/src/providers/models.ts +0 -76
  102. package/src/providers/provider-registry.ts +0 -88
  103. package/src/providers/provider-tools.ts +0 -179
  104. package/src/skills/index.ts +0 -14
  105. package/src/skills/parse-skill.ts +0 -91
  106. package/src/skills/skill-loader.ts +0 -175
  107. package/src/skills/skill-registry.ts +0 -137
  108. package/src/skills/types.ts +0 -37
  109. package/src/tools/commands.ts +0 -210
  110. package/src/tools/skills.ts +0 -84
  111. package/src/tools/tool-registry.ts +0 -63
  112. package/src/tools/web.ts +0 -238
  113. package/src/types.d.ts +0 -4
  114. package/style/icons/jupyternaut-lite.svg +0 -7
@@ -2,8 +2,7 @@ import { ChatWidget } from '@jupyter/chat';
2
2
  import { MainAreaWidget } from '@jupyterlab/apputils';
3
3
  import type { TranslationBundle } from '@jupyterlab/translation';
4
4
  import { CommandRegistry } from '@lumino/commands';
5
- import { AIChatModel } from '../chat-model';
6
- import { type IAISettingsModel } from '../tokens';
5
+ import { IAIChatModel, type IAISettingsModel } from '../tokens';
7
6
  export declare namespace MainAreaChat {
8
7
  interface IOptions extends MainAreaWidget.IOptions<ChatWidget> {
9
8
  commands: CommandRegistry;
@@ -20,7 +19,7 @@ export declare class MainAreaChat extends MainAreaWidget<ChatWidget> {
20
19
  /**
21
20
  * Get the model of the chat.
22
21
  */
23
- get model(): AIChatModel;
22
+ get model(): IAIChatModel;
24
23
  /**
25
24
  * Get the area of the chat.
26
25
  */
@@ -29,3 +28,4 @@ export declare class MainAreaChat extends MainAreaWidget<ChatWidget> {
29
28
  private _titleChanged;
30
29
  private _outputAreaCompat;
31
30
  }
31
+ //# sourceMappingURL=main-area-chat.d.ts.map
@@ -43,14 +43,14 @@ export class MainAreaChat extends MainAreaWidget {
43
43
  this._outputAreaCompat = new RenderedMessageOutputAreaCompat({
44
44
  chatPanel: this.content
45
45
  });
46
- this.model.writersChanged.connect(this._writersChanged);
46
+ this.model.writersChanged?.connect(this._writersChanged);
47
47
  this.model.titleChanged.connect(this._titleChanged);
48
48
  }
49
49
  dispose() {
50
50
  super.dispose();
51
51
  // Dispose of the approval buttons widget when the chat is disposed.
52
52
  this._outputAreaCompat.dispose();
53
- this.model.writersChanged.disconnect(this._writersChanged);
53
+ this.model.writersChanged?.disconnect(this._writersChanged);
54
54
  this.model.titleChanged.disconnect(this._titleChanged);
55
55
  }
56
56
  /**
@@ -69,12 +69,10 @@ export class MainAreaChat extends MainAreaWidget {
69
69
  // Check if AI is currently writing (streaming)
70
70
  const aiWriting = writers.some(writer => writer.user.username === 'ai-assistant');
71
71
  if (aiWriting) {
72
- this.content.inputToolbarRegistry?.hide('send');
73
72
  this.content.inputToolbarRegistry?.show('stop');
74
73
  }
75
74
  else {
76
75
  this.content.inputToolbarRegistry?.hide('stop');
77
- this.content.inputToolbarRegistry?.show('send');
78
76
  }
79
77
  };
80
78
  _titleChanged = () => {
@@ -1,6 +1,6 @@
1
+ import type { IProviderConfig, IProviderRegistry } from '@jupyternaut/agent';
1
2
  import type { TranslationBundle } from '@jupyterlab/translation';
2
3
  import React from 'react';
3
- import type { IProviderConfig, IProviderRegistry } from '../tokens';
4
4
  interface IProviderConfigDialogProps {
5
5
  open: boolean;
6
6
  onClose: () => void;
@@ -13,3 +13,4 @@ interface IProviderConfigDialogProps {
13
13
  }
14
14
  export declare const ProviderConfigDialog: React.FC<IProviderConfigDialogProps>;
15
15
  export {};
16
+ //# sourceMappingURL=provider-config-dialog.d.ts.map
@@ -1,10 +1,12 @@
1
+ import { createElement as _createElement } from "react";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { getProviderModelInfo } from '@jupyternaut/agent';
1
4
  import ExpandMore from '@mui/icons-material/ExpandMore';
2
5
  import Delete from '@mui/icons-material/Delete';
3
6
  import Visibility from '@mui/icons-material/Visibility';
4
7
  import VisibilityOff from '@mui/icons-material/VisibilityOff';
5
8
  import { Accordion, AccordionDetails, AccordionSummary, Autocomplete, Box, Button, Chip, Dialog, DialogActions, DialogContent, DialogTitle, FormControl, FormControlLabel, IconButton, InputAdornment, InputLabel, List, ListItem, ListItemText, MenuItem, Select, Slider, Switch, TextField, Typography } from '@mui/material';
6
9
  import React from 'react';
7
- import { getProviderModelInfo } from '../providers/model-info';
8
10
  /**
9
11
  * Default parameter values for provider configuration
10
12
  */
@@ -188,32 +190,26 @@ export const ProviderConfigDialog = ({ open, onClose, onSave, initialConfig, mod
188
190
  }, [customSettings, updateCustomSetting]);
189
191
  const renderDomainList = React.useCallback((fieldId, label, placeholder, values) => {
190
192
  const domainValues = toStringArray(values);
191
- return (React.createElement(Box, null,
192
- React.createElement(Typography, { variant: "body2", gutterBottom: true }, label),
193
- React.createElement(List, { dense: true, sx: {
194
- mb: 1,
195
- maxHeight: 160,
196
- overflow: 'auto',
197
- border: 1,
198
- borderColor: 'divider',
199
- borderRadius: 1
200
- } }, domainValues.length === 0 ? (React.createElement(ListItem, null,
201
- React.createElement(ListItemText, { secondary: trans.__('No domains added.'), slotProps: {
202
- secondary: {
203
- color: 'text.secondary'
193
+ return (_jsxs(Box, { children: [_jsx(Typography, { variant: "body2", gutterBottom: true, children: label }), _jsx(List, { dense: true, sx: {
194
+ mb: 1,
195
+ maxHeight: 160,
196
+ overflow: 'auto',
197
+ border: 1,
198
+ borderColor: 'divider',
199
+ borderRadius: 1
200
+ }, children: domainValues.length === 0 ? (_jsx(ListItem, { children: _jsx(ListItemText, { secondary: trans.__('No domains added.'), slotProps: {
201
+ secondary: {
202
+ color: 'text.secondary'
203
+ }
204
+ } }) })) : (domainValues.map(value => (_jsx(ListItem, { secondaryAction: _jsx(IconButton, { onClick: () => removeDomainValue(fieldId, value), size: "small", children: _jsx(Delete, { fontSize: "small" }) }), children: _jsx(ListItemText, { primary: value }) }, value)))) }), _jsx(TextField, { fullWidth: true, size: "small", label: trans.__('Add Domain'), value: domainInputs[fieldId], onChange: e => setDomainInputs(prev => ({
205
+ ...prev,
206
+ [fieldId]: e.target.value
207
+ })), onKeyDown: e => {
208
+ if (e.key === 'Enter') {
209
+ e.preventDefault();
210
+ addDomainValue(fieldId);
204
211
  }
205
- } }))) : (domainValues.map(value => (React.createElement(ListItem, { key: value, secondaryAction: React.createElement(IconButton, { onClick: () => removeDomainValue(fieldId, value), size: "small" },
206
- React.createElement(Delete, { fontSize: "small" })) },
207
- React.createElement(ListItemText, { primary: value })))))),
208
- React.createElement(TextField, { fullWidth: true, size: "small", label: trans.__('Add Domain'), value: domainInputs[fieldId], onChange: e => setDomainInputs(prev => ({
209
- ...prev,
210
- [fieldId]: e.target.value
211
- })), onKeyDown: e => {
212
- if (e.key === 'Enter') {
213
- e.preventDefault();
214
- addDomainValue(fieldId);
215
- }
216
- }, placeholder: placeholder, helperText: trans.__('Press Enter to add one domain.') })));
212
+ }, placeholder: placeholder, helperText: trans.__('Press Enter to add one domain.') })] }));
217
213
  }, [addDomainValue, domainInputs, removeDomainValue, trans]);
218
214
  const handleSave = () => {
219
215
  if (!name.trim() || !provider || !model) {
@@ -240,145 +236,84 @@ export const ProviderConfigDialog = ({ open, onClose, onSave, initialConfig, mod
240
236
  provider &&
241
237
  model &&
242
238
  (selectedProvider?.apiKeyRequirement !== 'required' || apiKey);
243
- return (React.createElement(Dialog, { open: open, onClose: onClose, maxWidth: "md", fullWidth: true },
244
- React.createElement(DialogTitle, null, mode === 'add'
245
- ? trans.__('Add New Provider')
246
- : trans.__('Edit Provider')),
247
- React.createElement(DialogContent, null,
248
- React.createElement(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2, pt: 1 } },
249
- React.createElement(TextField, { fullWidth: true, label: trans.__('Provider Name'), value: name, onChange: e => setName(e.target.value), placeholder: trans.__('e.g., My Anthropic Config, Work Provider'), helperText: trans.__('A friendly name to identify this provider configuration'), required: true }),
250
- React.createElement(FormControl, { fullWidth: true, required: true },
251
- React.createElement(InputLabel, null, trans.__('Provider Type')),
252
- React.createElement(Select, { value: provider, label: trans.__('Provider Type'), onChange: e => handleProviderChange(e.target.value) }, providerOptions.map(option => (React.createElement(MenuItem, { key: option.value, value: option.value },
253
- React.createElement(Box, null,
254
- React.createElement(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
255
- option.label,
256
- option.apiKeyRequirement === 'required' && (React.createElement(Chip, { size: "small", label: trans.__('API Key'), color: "default", variant: "outlined" }))),
257
- option.description && (React.createElement(Typography, { variant: "caption", color: "text.secondary" }, option.description)))))))),
258
- React.createElement(Autocomplete, { freeSolo: true, fullWidth: true, options: selectedProvider?.models ?? [], value: model, onChange: (_, value) => {
259
- setModel(typeof value === 'string' ? value : '');
260
- }, inputValue: model, onInputChange: (_, value) => {
261
- setModel(value);
262
- }, renderInput: params => (React.createElement(TextField, { ...params, fullWidth: true, label: trans.__('Model'), placeholder: trans.__('Select or type a model ID'), required: true, helperText: trans.__('Choose from the list or enter a custom model ID') })), clearOnBlur: false }),
263
- selectedProvider &&
264
- selectedProvider?.apiKeyRequirement !== 'none' && (React.createElement(TextField, { fullWidth: true, inputRef: handleRef, label: selectedProvider?.apiKeyRequirement === 'required'
265
- ? trans.__('API Key')
266
- : trans.__('API Key (Optional)'), type: showApiKey ? 'text' : 'password', value: apiKey, onChange: e => setApiKey(e.target.value), placeholder: trans.__('Enter your API key...'), required: selectedProvider?.apiKeyRequirement === 'required', InputProps: {
267
- endAdornment: (React.createElement(InputAdornment, { position: "end" },
268
- React.createElement(IconButton, { onClick: () => setShowApiKey(!showApiKey), edge: "end" }, showApiKey ? React.createElement(VisibilityOff, null) : React.createElement(Visibility, null))))
269
- } })),
270
- selectedProvider?.supportsBaseURL && (React.createElement(Autocomplete, { freeSolo: true, fullWidth: true, options: (selectedProvider.baseUrls ?? []).map(option => option.url), value: baseURL || '', onChange: (_, value) => {
271
- if (value && typeof value === 'string') {
272
- setBaseURL(value);
273
- }
274
- }, inputValue: baseURL || '', renderOption: (props, option) => {
275
- const urlOption = (selectedProvider.baseUrls ?? []).find(u => u.url === option);
276
- return (React.createElement(Box, { component: "li", ...props, key: option },
277
- React.createElement(Box, null,
278
- React.createElement(Typography, { variant: "body2" }, option),
279
- urlOption?.description && (React.createElement(Typography, { variant: "caption", color: "text.secondary" }, urlOption.description)))));
280
- }, renderInput: params => (React.createElement(TextField, { ...params, fullWidth: true, label: trans.__('Base URL'), placeholder: "https://api.example.com/v1", onChange: e => setBaseURL(e.target.value) })), clearOnBlur: false })),
281
- React.createElement(Accordion, { expanded: expandedAdvanced, onChange: (_, isExpanded) => setExpandedAdvanced(isExpanded), sx: {
282
- mt: 2,
283
- bgcolor: 'transparent',
284
- boxShadow: 'none',
285
- border: 1,
286
- borderColor: 'divider',
287
- borderRadius: 1
288
- } },
289
- React.createElement(AccordionSummary, { expandIcon: React.createElement(ExpandMore, null) },
290
- React.createElement(Typography, { variant: "subtitle1", fontWeight: "medium" }, trans.__('Advanced Settings'))),
291
- React.createElement(AccordionDetails, { sx: { bgcolor: 'transparent' } },
292
- React.createElement(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 } },
293
- React.createElement(Box, null,
294
- React.createElement(Typography, { gutterBottom: true }, trans.__('Temperature: %1', parameters.temperature ?? trans.__('Default'))),
295
- React.createElement(Slider, { value: parameters.temperature ?? DEFAULT_TEMPERATURE, onChange: (_, value) => setParameters({
296
- ...parameters,
297
- temperature: value
298
- }), min: 0, max: 2, step: 0.1, valueLabelDisplay: "auto" }),
299
- React.createElement(Typography, { variant: "caption", color: "text.secondary" }, trans.__('Temperature for the model (lower values are more deterministic)'))),
300
- React.createElement(TextField, { fullWidth: true, label: trans.__('Max Tokens (Optional)'), type: "number", value: parameters.maxOutputTokens ?? '', onChange: e => setParameters({
301
- ...parameters,
302
- maxOutputTokens: e.target.value
303
- ? Number(e.target.value)
304
- : undefined
305
- }), placeholder: trans.__('Leave empty for provider default'), helperText: trans.__('Maximum length of AI responses'), slotProps: { htmlInput: { min: 1 } } }),
306
- React.createElement(TextField, { fullWidth: true, label: trans.__('Max Turns (Optional)'), type: "number", value: parameters.maxTurns ?? '', onChange: e => setParameters({
307
- ...parameters,
308
- maxTurns: e.target.value
309
- ? Number(e.target.value)
310
- : undefined
311
- }), placeholder: trans.__('Default: %1', DEFAULT_MAX_TURNS), helperText: trans.__('Maximum number of tool execution turns'), slotProps: { htmlInput: { min: 1, max: 100 } } }),
312
- React.createElement(TextField, { fullWidth: true, label: trans.__('Context Window (Optional)'), type: "number", value: parameters.contextWindow ?? '', onChange: e => setParameters({
313
- ...parameters,
314
- contextWindow: e.target.value
315
- ? Number(e.target.value)
316
- : undefined
317
- }), placeholder: selectedModelInfo?.contextWindow !== undefined
318
- ? trans.__('Default: %1', selectedModelInfo.contextWindow.toLocaleString())
319
- : trans.__('e.g., 128000'), helperText: selectedModelInfo?.contextWindow !== undefined &&
320
- parameters.contextWindow === undefined
321
- ? trans.__('Using provider metadata default of %1 tokens for this model unless you override it here.', selectedModelInfo.contextWindow.toLocaleString())
322
- : trans.__('Model context window size in tokens (used for context usage estimation)'), slotProps: { htmlInput: { min: 1 } } }),
323
- React.createElement(Typography, { variant: "body2", color: "text.secondary", sx: { mt: 2, mb: 1 } }, trans.__('Completion Options')),
324
- React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: parameters.supportsFillInMiddle ?? false, onChange: e => setParameters({
325
- ...parameters,
326
- supportsFillInMiddle: e.target.checked
327
- }) }), label: trans.__('Fill-in-the-middle support') }),
328
- React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: parameters.useFilterText ?? false, onChange: e => setParameters({
329
- ...parameters,
330
- useFilterText: e.target.checked
331
- }) }), label: trans.__('Use filter text') }),
332
- (supportsWebSearch || supportsWebFetch) && (React.createElement(React.Fragment, null,
333
- React.createElement(Typography, { variant: "body2", color: "text.secondary", sx: { mt: 2, mb: 1 } }, trans.__('Provider Web Tools')),
334
- supportsWebSearch && (React.createElement(React.Fragment, null,
335
- React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: webSearchSettings.enabled === true, onChange: e => updateCustomSetting('webSearch', 'enabled', e.target.checked) }), label: trans.__('Enable Web Search') }),
336
- webSearchSettings.enabled === true && (React.createElement(Box, { sx: {
337
- pl: 2,
338
- borderLeft: 2,
339
- borderColor: 'divider',
340
- display: 'flex',
341
- flexDirection: 'column',
342
- gap: 1.5
343
- } },
344
- (webSearchImplementation === 'openai' ||
345
- webSearchImplementation === 'anthropic') &&
346
- renderDomainList('webSearch.allowedDomains', trans.__('Allowed Domains'), trans.__('example.com'), webSearchSettings.allowedDomains),
347
- webSearchImplementation === 'openai' && (React.createElement(React.Fragment, null,
348
- React.createElement(FormControl, { fullWidth: true },
349
- React.createElement(InputLabel, null, trans.__('Search Context Size')),
350
- React.createElement(Select, { value: webSearchSettings.searchContextSize ??
351
- 'medium', label: trans.__('Search Context Size'), onChange: e => updateCustomSetting('webSearch', 'searchContextSize', e.target.value) },
352
- React.createElement(MenuItem, { value: "low" }, trans.__('Low')),
353
- React.createElement(MenuItem, { value: "medium" }, trans.__('Medium')),
354
- React.createElement(MenuItem, { value: "high" }, trans.__('High')))),
355
- React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: webSearchSettings.externalWebAccess !==
356
- false, onChange: e => updateCustomSetting('webSearch', 'externalWebAccess', e.target.checked) }), label: trans.__('Use External Web Access') }))),
357
- webSearchImplementation === 'anthropic' && (React.createElement(React.Fragment, null,
358
- React.createElement(TextField, { fullWidth: true, label: trans.__('Web Search Max Uses'), type: "number", value: webSearchSettings.maxUses ?? '', onChange: e => updateCustomSetting('webSearch', 'maxUses', e.target.value
359
- ? Number(e.target.value)
360
- : undefined), slotProps: { htmlInput: { min: 1 } } }),
361
- renderDomainList('webSearch.blockedDomains', trans.__('Blocked Domains'), trans.__('spam.example.com'), webSearchSettings.blockedDomains))))))),
362
- supportsWebFetch && (React.createElement(React.Fragment, null,
363
- React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: webFetchSettings.enabled === true, onChange: e => updateCustomSetting('webFetch', 'enabled', e.target.checked) }), label: trans.__('Enable Web Fetch') }),
364
- webFetchSettings.enabled === true && (React.createElement(Box, { sx: {
365
- pl: 2,
366
- borderLeft: 2,
367
- borderColor: 'divider',
368
- display: 'flex',
369
- flexDirection: 'column',
370
- gap: 1.5
371
- } },
372
- React.createElement(TextField, { fullWidth: true, label: trans.__('Web Fetch Max Uses'), type: "number", value: webFetchSettings.maxUses ?? '', onChange: e => updateCustomSetting('webFetch', 'maxUses', e.target.value
373
- ? Number(e.target.value)
374
- : undefined), slotProps: { htmlInput: { min: 1 } } }),
375
- React.createElement(TextField, { fullWidth: true, label: trans.__('Web Fetch Max Content Tokens'), type: "number", value: webFetchSettings.maxContentTokens ?? '', onChange: e => updateCustomSetting('webFetch', 'maxContentTokens', e.target.value
376
- ? Number(e.target.value)
377
- : undefined), slotProps: { htmlInput: { min: 1 } } }),
378
- renderDomainList('webFetch.allowedDomains', trans.__('Allowed Domains'), trans.__('docs.example.com'), webFetchSettings.allowedDomains),
379
- renderDomainList('webFetch.blockedDomains', trans.__('Blocked Domains'), trans.__('spam.example.com'), webFetchSettings.blockedDomains),
380
- React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: webFetchSettings.citationsEnabled === true, onChange: e => updateCustomSetting('webFetch', 'citationsEnabled', e.target.checked) }), label: trans.__('Enable Citations') })))))))))))),
381
- React.createElement(DialogActions, null,
382
- React.createElement(Button, { onClick: onClose }, trans.__('Cancel')),
383
- React.createElement(Button, { onClick: handleSave, variant: "contained", disabled: !isValid }, mode === 'add' ? trans.__('Add Provider') : trans.__('Save Changes')))));
239
+ return (_jsxs(Dialog, { open: open, onClose: onClose, maxWidth: "md", fullWidth: true, children: [_jsx(DialogTitle, { children: mode === 'add'
240
+ ? trans.__('Add New Provider')
241
+ : trans.__('Edit Provider') }), _jsx(DialogContent, { children: _jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2, pt: 1 }, children: [_jsx(TextField, { fullWidth: true, label: trans.__('Provider Name'), value: name, onChange: e => setName(e.target.value), placeholder: trans.__('e.g., My Anthropic Config, Work Provider'), helperText: trans.__('A friendly name to identify this provider configuration'), required: true }), _jsxs(FormControl, { fullWidth: true, required: true, children: [_jsx(InputLabel, { children: trans.__('Provider Type') }), _jsx(Select, { value: provider, label: trans.__('Provider Type'), onChange: e => handleProviderChange(e.target.value), children: providerOptions.map(option => (_jsx(MenuItem, { value: option.value, children: _jsxs(Box, { children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [option.label, option.apiKeyRequirement === 'required' && (_jsx(Chip, { size: "small", label: trans.__('API Key'), color: "default", variant: "outlined" }))] }), option.description && (_jsx(Typography, { variant: "caption", color: "text.secondary", children: option.description }))] }) }, option.value))) })] }), _jsx(Autocomplete, { freeSolo: true, fullWidth: true, options: selectedProvider?.models ?? [], value: model, onChange: (_, value) => {
242
+ setModel(typeof value === 'string' ? value : '');
243
+ }, inputValue: model, onInputChange: (_, value) => {
244
+ setModel(value);
245
+ }, renderInput: params => (_jsx(TextField, { ...params, fullWidth: true, label: trans.__('Model'), placeholder: trans.__('Select or type a model ID'), required: true, helperText: trans.__('Choose from the list or enter a custom model ID') })), clearOnBlur: false }), selectedProvider &&
246
+ selectedProvider?.apiKeyRequirement !== 'none' && (_jsx(TextField, { fullWidth: true, inputRef: handleRef, label: selectedProvider?.apiKeyRequirement === 'required'
247
+ ? trans.__('API Key')
248
+ : trans.__('API Key (Optional)'), type: showApiKey ? 'text' : 'password', value: apiKey, onChange: e => setApiKey(e.target.value), placeholder: trans.__('Enter your API key...'), required: selectedProvider?.apiKeyRequirement === 'required', InputProps: {
249
+ endAdornment: (_jsx(InputAdornment, { position: "end", children: _jsx(IconButton, { onClick: () => setShowApiKey(!showApiKey), edge: "end", children: showApiKey ? _jsx(VisibilityOff, {}) : _jsx(Visibility, {}) }) }))
250
+ } })), selectedProvider?.supportsBaseURL && (_jsx(Autocomplete, { freeSolo: true, fullWidth: true, options: (selectedProvider.baseUrls ?? []).map(option => option.url), value: baseURL || '', onChange: (_, value) => {
251
+ if (value && typeof value === 'string') {
252
+ setBaseURL(value);
253
+ }
254
+ }, inputValue: baseURL || '', renderOption: (props, option) => {
255
+ const urlOption = (selectedProvider.baseUrls ?? []).find(u => u.url === option);
256
+ return (_createElement(Box, { component: "li", ...props, key: option },
257
+ _jsxs(Box, { children: [_jsx(Typography, { variant: "body2", children: option }), urlOption?.description && (_jsx(Typography, { variant: "caption", color: "text.secondary", children: urlOption.description }))] })));
258
+ }, renderInput: params => (_jsx(TextField, { ...params, fullWidth: true, label: trans.__('Base URL'), placeholder: "https://api.example.com/v1", onChange: e => setBaseURL(e.target.value) })), clearOnBlur: false })), _jsxs(Accordion, { expanded: expandedAdvanced, onChange: (_, isExpanded) => setExpandedAdvanced(isExpanded), sx: {
259
+ mt: 2,
260
+ bgcolor: 'transparent',
261
+ boxShadow: 'none',
262
+ border: 1,
263
+ borderColor: 'divider',
264
+ borderRadius: 1
265
+ }, children: [_jsx(AccordionSummary, { expandIcon: _jsx(ExpandMore, {}), children: _jsx(Typography, { variant: "subtitle1", fontWeight: "medium", children: trans.__('Advanced Settings') }) }), _jsx(AccordionDetails, { sx: { bgcolor: 'transparent' }, children: _jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsxs(Box, { children: [_jsx(Typography, { gutterBottom: true, children: trans.__('Temperature: %1', parameters.temperature ?? trans.__('Default')) }), _jsx(Slider, { value: parameters.temperature ?? DEFAULT_TEMPERATURE, onChange: (_, value) => setParameters({
266
+ ...parameters,
267
+ temperature: value
268
+ }), min: 0, max: 2, step: 0.1, valueLabelDisplay: "auto" }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: trans.__('Temperature for the model (lower values are more deterministic)') })] }), _jsx(TextField, { fullWidth: true, label: trans.__('Max Tokens (Optional)'), type: "number", value: parameters.maxOutputTokens ?? '', onChange: e => setParameters({
269
+ ...parameters,
270
+ maxOutputTokens: e.target.value
271
+ ? Number(e.target.value)
272
+ : undefined
273
+ }), placeholder: trans.__('Leave empty for provider default'), helperText: trans.__('Maximum length of AI responses'), slotProps: { htmlInput: { min: 1 } } }), _jsx(TextField, { fullWidth: true, label: trans.__('Max Turns (Optional)'), type: "number", value: parameters.maxTurns ?? '', onChange: e => setParameters({
274
+ ...parameters,
275
+ maxTurns: e.target.value
276
+ ? Number(e.target.value)
277
+ : undefined
278
+ }), placeholder: trans.__('Default: %1', DEFAULT_MAX_TURNS), helperText: trans.__('Maximum number of tool execution turns'), slotProps: { htmlInput: { min: 1, max: 100 } } }), _jsx(TextField, { fullWidth: true, label: trans.__('Context Window (Optional)'), type: "number", value: parameters.contextWindow ?? '', onChange: e => setParameters({
279
+ ...parameters,
280
+ contextWindow: e.target.value
281
+ ? Number(e.target.value)
282
+ : undefined
283
+ }), placeholder: selectedModelInfo?.contextWindow !== undefined
284
+ ? trans.__('Default: %1', selectedModelInfo.contextWindow.toLocaleString())
285
+ : trans.__('e.g., 128000'), helperText: selectedModelInfo?.contextWindow !== undefined &&
286
+ parameters.contextWindow === undefined
287
+ ? trans.__('Using provider metadata default of %1 tokens for this model unless you override it here.', selectedModelInfo.contextWindow.toLocaleString())
288
+ : trans.__('Model context window size in tokens (used for context usage estimation)'), slotProps: { htmlInput: { min: 1 } } }), _jsx(Typography, { variant: "body2", color: "text.secondary", sx: { mt: 2, mb: 1 }, children: trans.__('Completion Options') }), _jsx(FormControlLabel, { control: _jsx(Switch, { checked: parameters.supportsFillInMiddle ?? false, onChange: e => setParameters({
289
+ ...parameters,
290
+ supportsFillInMiddle: e.target.checked
291
+ }) }), label: trans.__('Fill-in-the-middle support') }), _jsx(FormControlLabel, { control: _jsx(Switch, { checked: parameters.useFilterText ?? false, onChange: e => setParameters({
292
+ ...parameters,
293
+ useFilterText: e.target.checked
294
+ }) }), label: trans.__('Use filter text') }), (supportsWebSearch || supportsWebFetch) && (_jsxs(_Fragment, { children: [_jsx(Typography, { variant: "body2", color: "text.secondary", sx: { mt: 2, mb: 1 }, children: trans.__('Provider Web Tools') }), supportsWebSearch && (_jsxs(_Fragment, { children: [_jsx(FormControlLabel, { control: _jsx(Switch, { checked: webSearchSettings.enabled === true, onChange: e => updateCustomSetting('webSearch', 'enabled', e.target.checked) }), label: trans.__('Enable Web Search') }), webSearchSettings.enabled === true && (_jsxs(Box, { sx: {
295
+ pl: 2,
296
+ borderLeft: 2,
297
+ borderColor: 'divider',
298
+ display: 'flex',
299
+ flexDirection: 'column',
300
+ gap: 1.5
301
+ }, children: [(webSearchImplementation === 'openai' ||
302
+ webSearchImplementation === 'anthropic') &&
303
+ renderDomainList('webSearch.allowedDomains', trans.__('Allowed Domains'), trans.__('example.com'), webSearchSettings.allowedDomains), webSearchImplementation === 'openai' && (_jsxs(_Fragment, { children: [_jsxs(FormControl, { fullWidth: true, children: [_jsx(InputLabel, { children: trans.__('Search Context Size') }), _jsxs(Select, { value: webSearchSettings.searchContextSize ??
304
+ 'medium', label: trans.__('Search Context Size'), onChange: e => updateCustomSetting('webSearch', 'searchContextSize', e.target.value), children: [_jsx(MenuItem, { value: "low", children: trans.__('Low') }), _jsx(MenuItem, { value: "medium", children: trans.__('Medium') }), _jsx(MenuItem, { value: "high", children: trans.__('High') })] })] }), _jsx(FormControlLabel, { control: _jsx(Switch, { checked: webSearchSettings.externalWebAccess !==
305
+ false, onChange: e => updateCustomSetting('webSearch', 'externalWebAccess', e.target.checked) }), label: trans.__('Use External Web Access') })] })), webSearchImplementation === 'anthropic' && (_jsxs(_Fragment, { children: [_jsx(TextField, { fullWidth: true, label: trans.__('Web Search Max Uses'), type: "number", value: webSearchSettings.maxUses ?? '', onChange: e => updateCustomSetting('webSearch', 'maxUses', e.target.value
306
+ ? Number(e.target.value)
307
+ : undefined), slotProps: { htmlInput: { min: 1 } } }), renderDomainList('webSearch.blockedDomains', trans.__('Blocked Domains'), trans.__('spam.example.com'), webSearchSettings.blockedDomains)] }))] }))] })), supportsWebFetch && (_jsxs(_Fragment, { children: [_jsx(FormControlLabel, { control: _jsx(Switch, { checked: webFetchSettings.enabled === true, onChange: e => updateCustomSetting('webFetch', 'enabled', e.target.checked) }), label: trans.__('Enable Web Fetch') }), webFetchSettings.enabled === true && (_jsxs(Box, { sx: {
308
+ pl: 2,
309
+ borderLeft: 2,
310
+ borderColor: 'divider',
311
+ display: 'flex',
312
+ flexDirection: 'column',
313
+ gap: 1.5
314
+ }, children: [_jsx(TextField, { fullWidth: true, label: trans.__('Web Fetch Max Uses'), type: "number", value: webFetchSettings.maxUses ?? '', onChange: e => updateCustomSetting('webFetch', 'maxUses', e.target.value
315
+ ? Number(e.target.value)
316
+ : undefined), slotProps: { htmlInput: { min: 1 } } }), _jsx(TextField, { fullWidth: true, label: trans.__('Web Fetch Max Content Tokens'), type: "number", value: webFetchSettings.maxContentTokens ?? '', onChange: e => updateCustomSetting('webFetch', 'maxContentTokens', e.target.value
317
+ ? Number(e.target.value)
318
+ : undefined), slotProps: { htmlInput: { min: 1 } } }), renderDomainList('webFetch.allowedDomains', trans.__('Allowed Domains'), trans.__('docs.example.com'), webFetchSettings.allowedDomains), renderDomainList('webFetch.blockedDomains', trans.__('Blocked Domains'), trans.__('spam.example.com'), webFetchSettings.blockedDomains), _jsx(FormControlLabel, { control: _jsx(Switch, { checked: webFetchSettings.citationsEnabled === true, onChange: e => updateCustomSetting('webFetch', 'citationsEnabled', e.target.checked) }), label: trans.__('Enable Citations') })] }))] }))] }))] }) })] })] }) }), _jsxs(DialogActions, { children: [_jsx(Button, { onClick: onClose, children: trans.__('Cancel') }), _jsx(Button, { onClick: handleSave, variant: "contained", disabled: !isValid, children: mode === 'add' ? trans.__('Add Provider') : trans.__('Save Changes') })] })] }));
384
319
  };