@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.
- package/lib/chat-commands/clear.d.ts +1 -0
- package/lib/chat-commands/index.d.ts +1 -0
- package/lib/chat-commands/skills.d.ts +2 -1
- package/lib/chat-model-handler.d.ts +4 -3
- package/lib/chat-model-handler.js +2 -1
- package/lib/chat-model.d.ts +148 -8
- package/lib/chat-model.js +368 -79
- package/lib/completion/completion-provider.d.ts +3 -1
- package/lib/completion/completion-provider.js +1 -2
- package/lib/completion/index.d.ts +1 -0
- package/lib/components/clear-button.d.ts +1 -0
- package/lib/components/clear-button.js +3 -4
- package/lib/components/completion-status.d.ts +1 -0
- package/lib/components/completion-status.js +5 -4
- package/lib/components/index.d.ts +1 -0
- package/lib/components/model-select.d.ts +1 -0
- package/lib/components/model-select.js +62 -67
- package/lib/components/save-button.d.ts +3 -2
- package/lib/components/save-button.js +4 -5
- package/lib/components/stop-button.d.ts +1 -0
- package/lib/components/stop-button.js +3 -4
- package/lib/components/tool-select.d.ts +3 -1
- package/lib/components/tool-select.js +47 -60
- package/lib/components/usage-display.d.ts +4 -2
- package/lib/components/usage-display.js +50 -61
- package/lib/diff-manager.d.ts +3 -1
- package/lib/index.d.ts +3 -2
- package/lib/index.js +50 -59
- package/lib/models/settings-model.d.ts +3 -1
- package/lib/models/settings-model.js +1 -0
- package/lib/rendered-message-outputarea.d.ts +1 -0
- package/lib/tokens.d.ts +48 -597
- package/lib/tokens.js +2 -31
- package/lib/widgets/ai-settings.d.ts +3 -1
- package/lib/widgets/ai-settings.js +185 -344
- package/lib/widgets/main-area-chat.d.ts +3 -3
- package/lib/widgets/main-area-chat.js +2 -4
- package/lib/widgets/provider-config-dialog.d.ts +2 -1
- package/lib/widgets/provider-config-dialog.js +102 -167
- package/package.json +111 -258
- package/schema/settings-model.json +6 -0
- package/src/chat-commands/skills.ts +2 -2
- package/src/chat-model-handler.ts +10 -6
- package/src/chat-model.ts +488 -96
- package/src/completion/completion-provider.ts +6 -6
- package/src/components/clear-button.tsx +0 -2
- package/src/components/completion-status.tsx +2 -2
- package/src/components/model-select.tsx +1 -1
- package/src/components/save-button.tsx +3 -3
- package/src/components/stop-button.tsx +0 -2
- package/src/components/tool-select.tsx +10 -9
- package/src/components/usage-display.tsx +4 -2
- package/src/diff-manager.ts +4 -3
- package/src/index.ts +103 -107
- package/src/models/settings-model.ts +7 -6
- package/src/tokens.ts +54 -744
- package/src/widgets/ai-settings.tsx +40 -11
- package/src/widgets/main-area-chat.ts +5 -8
- package/src/widgets/provider-config-dialog.tsx +8 -8
- package/LICENSE +0 -30
- package/README.md +0 -49
- package/lib/agent.d.ts +0 -277
- package/lib/agent.js +0 -1116
- package/lib/icons.d.ts +0 -3
- package/lib/icons.js +0 -8
- package/lib/providers/built-in-providers.d.ts +0 -21
- package/lib/providers/built-in-providers.js +0 -233
- package/lib/providers/generated-context-windows.d.ts +0 -8
- package/lib/providers/generated-context-windows.js +0 -96
- package/lib/providers/model-info.d.ts +0 -3
- package/lib/providers/model-info.js +0 -58
- package/lib/providers/models.d.ts +0 -37
- package/lib/providers/models.js +0 -28
- package/lib/providers/provider-registry.d.ts +0 -49
- package/lib/providers/provider-registry.js +0 -72
- package/lib/providers/provider-tools.d.ts +0 -36
- package/lib/providers/provider-tools.js +0 -93
- package/lib/skills/index.d.ts +0 -4
- package/lib/skills/index.js +0 -7
- package/lib/skills/parse-skill.d.ts +0 -25
- package/lib/skills/parse-skill.js +0 -69
- package/lib/skills/skill-loader.d.ts +0 -25
- package/lib/skills/skill-loader.js +0 -133
- package/lib/skills/skill-registry.d.ts +0 -31
- package/lib/skills/skill-registry.js +0 -100
- package/lib/skills/types.d.ts +0 -29
- package/lib/skills/types.js +0 -5
- package/lib/tools/commands.d.ts +0 -11
- package/lib/tools/commands.js +0 -154
- package/lib/tools/skills.d.ts +0 -9
- package/lib/tools/skills.js +0 -73
- package/lib/tools/tool-registry.d.ts +0 -35
- package/lib/tools/tool-registry.js +0 -55
- package/lib/tools/web.d.ts +0 -8
- package/lib/tools/web.js +0 -196
- package/src/agent.ts +0 -1441
- package/src/icons.ts +0 -11
- package/src/providers/built-in-providers.ts +0 -241
- package/src/providers/generated-context-windows.ts +0 -102
- package/src/providers/model-info.ts +0 -88
- package/src/providers/models.ts +0 -76
- package/src/providers/provider-registry.ts +0 -88
- package/src/providers/provider-tools.ts +0 -179
- package/src/skills/index.ts +0 -14
- package/src/skills/parse-skill.ts +0 -91
- package/src/skills/skill-loader.ts +0 -175
- package/src/skills/skill-registry.ts +0 -137
- package/src/skills/types.ts +0 -37
- package/src/tools/commands.ts +0 -210
- package/src/tools/skills.ts +0 -84
- package/src/tools/tool-registry.ts +0 -63
- package/src/tools/web.ts +0 -238
- package/src/types.d.ts +0 -4
- package/style/icons/jupyternaut-lite.svg +0 -7
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { getEffectiveContextWindow, SECRETS_REPLACEMENT } from '@jupyternaut/agent';
|
|
1
3
|
import { ReactWidget } from '@jupyterlab/ui-components';
|
|
2
4
|
import { Debouncer } from '@lumino/polling';
|
|
3
5
|
import Add from '@mui/icons-material/Add';
|
|
@@ -13,8 +15,6 @@ import MoreVert from '@mui/icons-material/MoreVert';
|
|
|
13
15
|
import Settings from '@mui/icons-material/Settings';
|
|
14
16
|
import { Alert, Box, Button, Card, CardContent, Chip, Dialog, DialogActions, DialogContent, DialogTitle, Divider, FormControl, FormControlLabel, IconButton, InputLabel, List, ListItem, ListItemText, Menu, MenuItem, Select, Switch, Tab, Tabs, TextField, ThemeProvider, Tooltip, Typography, createTheme } from '@mui/material';
|
|
15
17
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
16
|
-
import { getEffectiveContextWindow } from '../providers/model-info';
|
|
17
|
-
import { SECRETS_REPLACEMENT } from '../tokens';
|
|
18
18
|
import { ProviderConfigDialog } from './provider-config-dialog';
|
|
19
19
|
/**
|
|
20
20
|
* Create a theme that uses IThemeManager to detect theme
|
|
@@ -63,7 +63,7 @@ export class AISettingsWidget extends ReactWidget {
|
|
|
63
63
|
* @returns A React element containing the AI settings interface
|
|
64
64
|
*/
|
|
65
65
|
render() {
|
|
66
|
-
return (
|
|
66
|
+
return (_jsx(AISettingsComponent, { model: this._settingsModel, agentManagerFactory: this._agentManagerFactory, themeManager: this._themeManager, providerRegistry: this._providerRegistry, secretsAccess: this._secretsAccess, trans: this._trans }));
|
|
67
67
|
}
|
|
68
68
|
_settingsModel;
|
|
69
69
|
_agentManagerFactory;
|
|
@@ -79,7 +79,7 @@ export class AISettingsWidget extends ReactWidget {
|
|
|
79
79
|
*/
|
|
80
80
|
const AISettingsComponent = ({ model, agentManagerFactory, themeManager, providerRegistry, secretsAccess, trans }) => {
|
|
81
81
|
if (!model) {
|
|
82
|
-
return
|
|
82
|
+
return _jsx("div", { children: trans.__('Settings model not available') });
|
|
83
83
|
}
|
|
84
84
|
const [config, setConfig] = useState(model.config || {});
|
|
85
85
|
const [theme, setTheme] = useState(() => createJupyterLabTheme(themeManager));
|
|
@@ -356,8 +356,7 @@ const AISettingsComponent = ({ model, agentManagerFactory, themeManager, provide
|
|
|
356
356
|
setMcpMenuAnchor(null);
|
|
357
357
|
setMcpMenuServerId('');
|
|
358
358
|
};
|
|
359
|
-
return (
|
|
360
|
-
React.createElement(Box, { sx: {
|
|
359
|
+
return (_jsx(ThemeProvider, { theme: theme, children: _jsxs(Box, { sx: {
|
|
361
360
|
height: '100%',
|
|
362
361
|
maxHeight: '100vh',
|
|
363
362
|
overflow: 'auto',
|
|
@@ -365,334 +364,185 @@ const AISettingsComponent = ({ model, agentManagerFactory, themeManager, provide
|
|
|
365
364
|
pb: 4,
|
|
366
365
|
boxSizing: 'border-box',
|
|
367
366
|
fontSize: '0.9rem'
|
|
368
|
-
} },
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
alignItems: 'center',
|
|
523
|
-
gap: 1
|
|
524
|
-
} },
|
|
525
|
-
trans.__('Skills Paths'),
|
|
526
|
-
React.createElement(Tooltip, { title: trans.__('Directories containing agent skills, relative to the server root. Skills are loaded from all paths; the first occurrence of a skill name takes priority.') },
|
|
527
|
-
React.createElement(InfoOutlined, { sx: { fontSize: 16 } }))),
|
|
528
|
-
React.createElement(List, { sx: { mb: 2, maxHeight: 200, overflow: 'auto' } }, (config.skillsPaths ?? []).map((skillPath, index) => (React.createElement(ListItem, { key: index, divider: true, secondaryAction: React.createElement(IconButton, { onClick: () => {
|
|
529
|
-
const newPaths = [...config.skillsPaths];
|
|
530
|
-
newPaths.splice(index, 1);
|
|
531
|
-
handleConfigUpdate({ skillsPaths: newPaths });
|
|
532
|
-
}, size: "small" },
|
|
533
|
-
React.createElement(Delete, null)) },
|
|
534
|
-
React.createElement(ListItemText, { primary: skillPath }))))),
|
|
535
|
-
React.createElement(TextField, { fullWidth: true, label: trans.__('Add Skills Path'), placeholder: trans.__('e.g., .claude/skills'), onKeyDown: e => {
|
|
536
|
-
if (e.key === 'Enter') {
|
|
537
|
-
const value = e.target.value.trim();
|
|
538
|
-
if (value &&
|
|
539
|
-
!(config.skillsPaths ?? []).includes(value)) {
|
|
540
|
-
const newPaths = [
|
|
541
|
-
...(config.skillsPaths ?? []),
|
|
542
|
-
value
|
|
543
|
-
];
|
|
544
|
-
handleConfigUpdate({ skillsPaths: newPaths });
|
|
545
|
-
e.target.value = '';
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
}, helperText: trans.__('Press Enter to add a path. Defaults: .agents/skills, _agents/skills') })),
|
|
549
|
-
React.createElement(Divider, { sx: { my: 2 } }),
|
|
550
|
-
React.createElement(Box, null,
|
|
551
|
-
React.createElement(Typography, { variant: "body1", gutterBottom: true }, trans.__('Commands Requiring Approval')),
|
|
552
|
-
React.createElement(Typography, { variant: "caption", color: "text.secondary", gutterBottom: true, sx: { display: 'block' } }, trans.__('Commands that require user approval before AI can execute them')),
|
|
553
|
-
React.createElement(List, { sx: { mb: 2, maxHeight: 200, overflow: 'auto' } }, config.commandsRequiringApproval.map((command, index) => (React.createElement(ListItem, { key: index, divider: true, secondaryAction: React.createElement(IconButton, { onClick: () => {
|
|
554
|
-
const newCommands = [
|
|
555
|
-
...config.commandsRequiringApproval
|
|
556
|
-
];
|
|
557
|
-
newCommands.splice(index, 1);
|
|
558
|
-
handleConfigUpdate({
|
|
559
|
-
commandsRequiringApproval: newCommands
|
|
560
|
-
});
|
|
561
|
-
}, size: "small" },
|
|
562
|
-
React.createElement(Delete, null)) },
|
|
563
|
-
React.createElement(ListItemText, { primary: command }))))),
|
|
564
|
-
React.createElement(TextField, { fullWidth: true, label: trans.__('Add New Command'), placeholder: trans.__('e.g., notebook:run-cell'), onKeyDown: e => {
|
|
565
|
-
if (e.key === 'Enter') {
|
|
566
|
-
const value = e.target.value.trim();
|
|
567
|
-
if (value &&
|
|
568
|
-
!config.commandsRequiringApproval.includes(value)) {
|
|
569
|
-
const newCommands = [
|
|
570
|
-
...config.commandsRequiringApproval,
|
|
571
|
-
value
|
|
572
|
-
];
|
|
573
|
-
handleConfigUpdate({
|
|
574
|
-
commandsRequiringApproval: newCommands
|
|
575
|
-
});
|
|
576
|
-
e.target.value = '';
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
}, helperText: trans.__('Press Enter to add a command. Common commands: notebook:run-cell, console:execute, fileeditor:run-code') })),
|
|
580
|
-
React.createElement(Divider, { sx: { my: 2 } }),
|
|
581
|
-
React.createElement(Box, null,
|
|
582
|
-
React.createElement(Typography, { variant: "body1", gutterBottom: true }, trans.__('Commands Auto-Rendering MIME Bundles')),
|
|
583
|
-
React.createElement(Typography, { variant: "caption", color: "text.secondary", gutterBottom: true, sx: { display: 'block' } }, trans.__('Only these execute_command command IDs can auto-render MIME bundle outputs in chat')),
|
|
584
|
-
React.createElement(List, { sx: { mb: 2, maxHeight: 200, overflow: 'auto' } }, (config.commandsAutoRenderMimeBundles ?? []).map((command, index) => (React.createElement(ListItem, { key: index, divider: true, secondaryAction: React.createElement(IconButton, { onClick: () => {
|
|
585
|
-
const newCommands = [
|
|
586
|
-
...(config.commandsAutoRenderMimeBundles ??
|
|
587
|
-
[])
|
|
588
|
-
];
|
|
589
|
-
newCommands.splice(index, 1);
|
|
590
|
-
handleConfigUpdate({
|
|
591
|
-
commandsAutoRenderMimeBundles: newCommands
|
|
592
|
-
});
|
|
593
|
-
}, size: "small" },
|
|
594
|
-
React.createElement(Delete, null)) },
|
|
595
|
-
React.createElement(ListItemText, { primary: command }))))),
|
|
596
|
-
React.createElement(TextField, { fullWidth: true, label: trans.__('Add Auto-Render Command'), placeholder: trans.__('e.g., jupyterlab-ai-commands:execute-in-kernel'), onKeyDown: e => {
|
|
597
|
-
if (e.key === 'Enter') {
|
|
598
|
-
const value = e.target.value.trim();
|
|
599
|
-
const existingCommands = config.commandsAutoRenderMimeBundles ?? [];
|
|
600
|
-
if (value && !existingCommands.includes(value)) {
|
|
601
|
-
const newCommands = [...existingCommands, value];
|
|
602
|
-
handleConfigUpdate({
|
|
603
|
-
commandsAutoRenderMimeBundles: newCommands
|
|
604
|
-
});
|
|
605
|
-
e.target.value = '';
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
}, helperText: trans.__('Press Enter to add a command. Default: jupyterlab-ai-commands:execute-in-kernel') })),
|
|
609
|
-
React.createElement(Divider, { sx: { my: 2 } }),
|
|
610
|
-
React.createElement(Box, null,
|
|
611
|
-
React.createElement(Typography, { variant: "body1", gutterBottom: true }, trans.__('Trusted MIME Types for Auto-Render')),
|
|
612
|
-
React.createElement(Typography, { variant: "caption", color: "text.secondary", gutterBottom: true, sx: { display: 'block' } }, trans.__('When auto-rendering command outputs, these MIME types are marked trusted in chat')),
|
|
613
|
-
React.createElement(List, { sx: { mb: 2, maxHeight: 200, overflow: 'auto' } }, (config.trustedMimeTypesForAutoRender ?? []).map((mimeType, index) => (React.createElement(ListItem, { key: index, divider: true, secondaryAction: React.createElement(IconButton, { onClick: () => {
|
|
614
|
-
const newMimeTypes = [
|
|
615
|
-
...(config.trustedMimeTypesForAutoRender ??
|
|
616
|
-
[])
|
|
617
|
-
];
|
|
618
|
-
newMimeTypes.splice(index, 1);
|
|
619
|
-
handleConfigUpdate({
|
|
620
|
-
trustedMimeTypesForAutoRender: newMimeTypes
|
|
621
|
-
});
|
|
622
|
-
}, size: "small" },
|
|
623
|
-
React.createElement(Delete, null)) },
|
|
624
|
-
React.createElement(ListItemText, { primary: mimeType }))))),
|
|
625
|
-
React.createElement(TextField, { fullWidth: true, label: trans.__('Add Trusted MIME Type'), placeholder: trans.__('e.g., text/html'), onKeyDown: e => {
|
|
626
|
-
if (e.key === 'Enter') {
|
|
627
|
-
const value = e.target.value.trim();
|
|
628
|
-
const existingMimeTypes = config.trustedMimeTypesForAutoRender ?? [];
|
|
629
|
-
if (value && !existingMimeTypes.includes(value)) {
|
|
630
|
-
const newMimeTypes = [...existingMimeTypes, value];
|
|
631
|
-
handleConfigUpdate({
|
|
632
|
-
trustedMimeTypesForAutoRender: newMimeTypes
|
|
633
|
-
});
|
|
634
|
-
e.target.value = '';
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
}, helperText: trans.__('Press Enter to add a MIME type. Default: text/html') })))))),
|
|
638
|
-
activeTab === 2 && (React.createElement(Card, { elevation: 2 },
|
|
639
|
-
React.createElement(CardContent, null,
|
|
640
|
-
React.createElement(Box, { sx: {
|
|
641
|
-
display: 'flex',
|
|
642
|
-
alignItems: 'center',
|
|
643
|
-
justifyContent: 'space-between',
|
|
644
|
-
mb: 2
|
|
645
|
-
} },
|
|
646
|
-
React.createElement(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
647
|
-
React.createElement(Cable, { color: "primary" }),
|
|
648
|
-
React.createElement(Typography, { variant: "h6", component: "h2" }, trans.__('Remote MCP Servers'))),
|
|
649
|
-
React.createElement(Button, { variant: "contained", startIcon: React.createElement(Add, null), onClick: openAddMCPDialog, size: "small" }, trans.__('Add Server'))),
|
|
650
|
-
React.createElement(Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 } }, trans.__("Configure remote Model Context Protocol (MCP) servers to extend the AI's capabilities with external tools and data sources.")),
|
|
651
|
-
config.mcpServers.length === 0 ? (React.createElement(Alert, { severity: "info" }, trans.__('No MCP servers configured yet. Click "Add Server" to connect to remote MCP services.'))) : (React.createElement(List, null, config.mcpServers.map(server => (React.createElement(ListItem, { key: server.id, divider: true, secondaryAction: React.createElement(IconButton, { onClick: e => handleMCPMenuClick(e, server.id), size: "small" },
|
|
652
|
-
React.createElement(MoreVert, null)) },
|
|
653
|
-
React.createElement(ListItemText, { primary: React.createElement(Box, { sx: {
|
|
367
|
+
}, children: [_jsxs(Box, { sx: { mb: 2, display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Settings, { color: "primary", sx: { fontSize: 24 } }), _jsx(Typography, { variant: "h5", component: "h1", sx: { fontWeight: 600 }, children: trans.__('AI Settings') })] }), _jsx(Box, { sx: { borderBottom: 1, borderColor: 'divider', mb: 2 }, children: _jsxs(Tabs, { value: activeTab, onChange: (_, newValue) => setActiveTab(newValue), children: [_jsx(Tab, { label: trans.__('Providers') }), _jsx(Tab, { label: trans.__('Behavior') }), _jsx(Tab, { label: trans.__('MCP Servers') })] }) }), activeTab === 0 && (_jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [config.providers.length > 0 && (_jsx(Card, { elevation: 2, children: _jsxs(CardContent, { children: [_jsx(Typography, { variant: "h6", component: "h2", gutterBottom: true, children: trans.__('Default Providers') }), _jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsxs(FormControl, { fullWidth: true, children: [_jsx(InputLabel, { children: trans.__('Chat Provider') }), _jsx(Select, { value: config.defaultProvider, label: trans.__('Chat Provider'), onChange: e => model.setActiveProvider(e.target.value), children: config.providers.map(provider => (_jsx(MenuItem, { value: provider.id, children: provider.name }, provider.id))) })] }), _jsx(FormControlLabel, { control: _jsx(Switch, { checked: config.useSameProviderForChatAndCompleter, onChange: e => handleConfigUpdate({
|
|
368
|
+
useSameProviderForChatAndCompleter: e.target.checked
|
|
369
|
+
}), color: "primary" }), label: trans.__('Use same provider for chat and completions') }), !config.useSameProviderForChatAndCompleter && (_jsxs(FormControl, { fullWidth: true, children: [_jsx(InputLabel, { children: trans.__('Completion Provider') }), _jsxs(Select, { value: config.activeCompleterProvider || '', label: trans.__('Completion Provider'), className: "jp-ai-completion-provider-select", onChange: e => model.setActiveCompleterProvider(e.target.value || undefined), children: [_jsx(MenuItem, { value: "", children: _jsx("em", { children: trans.__('No completion') }) }), config.providers.map(provider => (_jsx(MenuItem, { value: provider.id, children: provider.name }, provider.id)))] })] }))] })] }) })), _jsx(Card, { elevation: 2, children: _jsxs(CardContent, { children: [_jsxs(Box, { sx: {
|
|
370
|
+
display: 'flex',
|
|
371
|
+
alignItems: 'center',
|
|
372
|
+
justifyContent: 'space-between',
|
|
373
|
+
mb: 2
|
|
374
|
+
}, children: [_jsx(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: _jsx(Typography, { variant: "h6", component: "h2", children: trans.__('Configured Providers') }) }), _jsx(Button, { variant: "contained", startIcon: _jsx(Add, {}), onClick: openAddDialog, size: "small", children: trans.__('Add Provider') })] }), config.providers.length === 0 ? (_jsx(Alert, { severity: "info", children: trans.__('No providers configured yet. Click "Add Provider" to get started.') })) : (_jsx(List, { children: config.providers.map(provider => {
|
|
375
|
+
const isActive = config.defaultProvider === provider.id;
|
|
376
|
+
const isActiveCompleter = config.useSameProviderForChatAndCompleter
|
|
377
|
+
? isActive
|
|
378
|
+
: config.activeCompleterProvider === provider.id;
|
|
379
|
+
const providerInfo = providerRegistry.getProviderInfo(provider.provider);
|
|
380
|
+
const providerToolCapabilities = providerInfo?.providerToolCapabilities;
|
|
381
|
+
const params = provider.parameters;
|
|
382
|
+
const effectiveContextWindow = getEffectiveContextWindow(provider, providerRegistry);
|
|
383
|
+
const webSearchEnabled = !!providerToolCapabilities?.webSearch &&
|
|
384
|
+
provider.customSettings?.webSearch?.enabled === true;
|
|
385
|
+
const webFetchEnabled = !!providerToolCapabilities?.webFetch &&
|
|
386
|
+
provider.customSettings?.webFetch?.enabled === true;
|
|
387
|
+
return (_jsx(ListItem, { sx: {
|
|
388
|
+
flexDirection: 'column',
|
|
389
|
+
alignItems: 'stretch',
|
|
390
|
+
py: 2
|
|
391
|
+
}, children: _jsxs(Box, { sx: {
|
|
392
|
+
display: 'flex',
|
|
393
|
+
justifyContent: 'space-between',
|
|
394
|
+
alignItems: 'flex-start',
|
|
395
|
+
width: '100%',
|
|
396
|
+
mb: 1
|
|
397
|
+
}, children: [_jsxs(Box, { sx: { flex: 1 }, children: [_jsxs(Box, { sx: {
|
|
398
|
+
display: 'flex',
|
|
399
|
+
alignItems: 'center',
|
|
400
|
+
gap: 1,
|
|
401
|
+
mb: 0.5
|
|
402
|
+
}, children: [_jsx(Typography, { variant: "subtitle1", fontWeight: "medium", children: provider.name }), isActive && (_jsx(Chip, { label: trans.__('Chat'), size: "small", color: "primary", icon: _jsx(CheckCircle, {}) })), isActiveCompleter && (_jsx(Chip, { label: trans.__('Completion'), size: "small", color: "secondary", icon: _jsx(CheckCircle, {}) }))] }), _jsxs(Typography, { variant: "body2", color: "text.secondary", gutterBottom: true, children: [provider.provider, " \u2022 ", provider.model, provider.description &&
|
|
403
|
+
` • ${provider.description}`] }), (params?.temperature !== undefined ||
|
|
404
|
+
params?.maxOutputTokens !== undefined ||
|
|
405
|
+
params?.maxTurns !== undefined ||
|
|
406
|
+
effectiveContextWindow !== undefined ||
|
|
407
|
+
webSearchEnabled ||
|
|
408
|
+
webFetchEnabled) && (_jsxs(Box, { sx: {
|
|
409
|
+
display: 'flex',
|
|
410
|
+
flexWrap: 'wrap',
|
|
411
|
+
gap: 1,
|
|
412
|
+
mt: 1
|
|
413
|
+
}, children: [params?.temperature !== undefined && (_jsx(Chip, { label: trans.__('Temp: %1', params.temperature), size: "small", variant: "outlined" })), params?.maxOutputTokens !== undefined && (_jsx(Chip, { label: trans.__('Tokens: %1', params.maxOutputTokens), size: "small", variant: "outlined" })), params?.maxTurns !== undefined && (_jsx(Chip, { label: trans.__('Turns: %1', params.maxTurns), size: "small", variant: "outlined" })), effectiveContextWindow !== undefined && (_jsx(Chip, { label: trans.__('Context: %1', effectiveContextWindow), size: "small", variant: "outlined" })), webSearchEnabled && (_jsx(Chip, { label: trans.__('Web Search'), size: "small", variant: "outlined", color: "info" })), webFetchEnabled && (_jsx(Chip, { label: trans.__('Web Fetch'), size: "small", variant: "outlined", color: "info" }))] }))] }), _jsx(IconButton, { onClick: e => handleMenuClick(e, provider.id), size: "small", children: _jsx(MoreVert, {}) })] }) }, provider.id));
|
|
414
|
+
}) }))] }) }), secretsAccess?.isAvailable && (_jsx(FormControlLabel, { control: _jsx(Switch, { checked: config.useSecretsManager, onChange: e => handleConfigUpdate({
|
|
415
|
+
useSecretsManager: e.target.checked
|
|
416
|
+
}), color: "primary", sx: { alignSelf: 'flex-start' } }), label: _jsxs("div", { children: [_jsx("span", { children: trans.__('Use the secrets manager to manage API keys') }), !config.useSecretsManager && (_jsx(Alert, { severity: "warning", icon: _jsx(Error, {}), sx: { mb: 2 }, children: trans.__('The secrets are stored in plain text in settings') }))] }) }))] })), activeTab === 1 && (_jsx(Card, { elevation: 2, children: _jsxs(CardContent, { children: [_jsx(Typography, { variant: "h6", component: "h2", gutterBottom: true, children: trans.__('Behavior Settings') }), _jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsx(FormControlLabel, { control: _jsx(Switch, { checked: config.toolsEnabled, onChange: e => handleConfigUpdate({
|
|
417
|
+
toolsEnabled: e.target.checked
|
|
418
|
+
}), color: "primary" }), label: _jsxs(Box, { children: [_jsx(Typography, { variant: "body1", children: trans.__('Enable Tools') }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: trans.__('Allow the AI to use tools like notebook operations, code execution, and file management') })] }) }), _jsx(FormControlLabel, { control: _jsx(Switch, { checked: config.sendWithShiftEnter, onChange: e => handleConfigUpdate({
|
|
419
|
+
sendWithShiftEnter: e.target.checked
|
|
420
|
+
}), color: "primary" }), label: _jsxs(Box, { children: [_jsx(Typography, { variant: "body1", children: trans.__('Send with Shift+Enter') }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: trans.__('Use Shift+Enter to send messages (Enter creates new line)') })] }) }), _jsx(FormControlLabel, { control: _jsx(Switch, { checked: config.autoTitle, onChange: e => handleConfigUpdate({
|
|
421
|
+
autoTitle: e.target.checked
|
|
422
|
+
}), color: "primary" }), label: _jsxs(Box, { children: [_jsx(Typography, { variant: "body1", children: trans.__('Auto Title') }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: trans.__('Automatically generate a chat title from the model for every message until there are 5 messages') })] }) }), _jsx(FormControlLabel, { control: _jsx(Switch, { checked: config.showTokenUsage, onChange: e => handleConfigUpdate({
|
|
423
|
+
showTokenUsage: e.target.checked
|
|
424
|
+
}), color: "primary" }), label: _jsxs(Box, { children: [_jsx(Typography, { variant: "body1", children: trans.__('Show Token Usage') }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: trans.__('Display token usage information in the chat toolbar') })] }) }), _jsx(FormControlLabel, { control: _jsx(Switch, { checked: config.showContextUsage, onChange: e => handleConfigUpdate({
|
|
425
|
+
showContextUsage: e.target.checked
|
|
426
|
+
}), color: "primary" }), label: _jsxs(Box, { children: [_jsx(Typography, { variant: "body1", children: trans.__('Show Context Usage') }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: trans.__('Display estimated context usage in the chat toolbar') })] }) }), _jsx(FormControlLabel, { control: _jsx(Switch, { checked: config.showCellDiff, onChange: e => handleConfigUpdate({
|
|
427
|
+
showCellDiff: e.target.checked
|
|
428
|
+
}), color: "primary" }), label: _jsxs(Box, { children: [_jsx(Typography, { variant: "body1", children: trans.__('Show Cell Diff') }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: trans.__('Show diff view when AI modifies cell content') })] }) }), config.showCellDiff && (_jsxs(FormControl, { sx: { ml: 4 }, children: [_jsx(InputLabel, { children: trans.__('Diff Display Mode') }), _jsxs(Select, { value: config.diffDisplayMode, label: trans.__('Diff Display Mode'), onChange: e => handleConfigUpdate({
|
|
429
|
+
diffDisplayMode: e.target.value
|
|
430
|
+
}), children: [_jsx(MenuItem, { value: "split", children: trans.__('Split View') }), _jsx(MenuItem, { value: "unified", children: trans.__('Unified View') })] })] })), _jsx(FormControlLabel, { control: _jsx(Switch, { checked: config.showFileDiff, onChange: e => handleConfigUpdate({
|
|
431
|
+
showFileDiff: e.target.checked
|
|
432
|
+
}), color: "primary" }), label: _jsxs(Box, { children: [_jsx(Typography, { variant: "body1", children: trans.__('Show File Diff') }), _jsx(Typography, { variant: "caption", color: "text.secondary", children: trans.__('Show diff view when AI modifies file content') })] }) }), _jsx(TextField, { fullWidth: true, label: trans.__('Chat Backup Directory'), value: config.chatBackupDirectory, onChange: e => handleConfigUpdate({
|
|
433
|
+
chatBackupDirectory: e.target.value
|
|
434
|
+
}), helperText: trans.__('Directory where chat history backups are saved (relative to the server root)') }), _jsx(Divider, { sx: { my: 1 } }), _jsx(TextField, { fullWidth: true, multiline: true, rows: 3, label: trans.__('System Prompt'), value: systemPromptValue, onChange: e => handleSystemPromptChange(e.target.value), placeholder: trans.__("Define the AI's behavior and personality..."), helperText: trans.__('Instructions that define how the AI should behave and respond') }), _jsx(TextField, { fullWidth: true, multiline: true, rows: 3, label: trans.__('Completion System Prompt'), value: completionPromptValue, onChange: e => handleCompletionPromptChange(e.target.value), placeholder: trans.__('Define how the AI should generate code completions...'), helperText: trans.__('Instructions that define how the AI should generate code completions') }), _jsx(Divider, { sx: { my: 2 } }), _jsxs(Box, { children: [_jsxs(Typography, { variant: "body1", gutterBottom: true, sx: {
|
|
435
|
+
display: 'inline-flex',
|
|
436
|
+
alignItems: 'center',
|
|
437
|
+
gap: 1
|
|
438
|
+
}, children: [trans.__('Skills Paths'), _jsx(Tooltip, { title: trans.__('Directories containing agent skills, relative to the server root. Skills are loaded from all paths; the first occurrence of a skill name takes priority.'), children: _jsx(InfoOutlined, { sx: { fontSize: 16 } }) })] }), _jsx(List, { sx: { mb: 2, maxHeight: 200, overflow: 'auto' }, children: (config.skillsPaths ?? []).map((skillPath, index) => (_jsx(ListItem, { divider: true, secondaryAction: _jsx(IconButton, { onClick: () => {
|
|
439
|
+
const newPaths = [...config.skillsPaths];
|
|
440
|
+
newPaths.splice(index, 1);
|
|
441
|
+
handleConfigUpdate({ skillsPaths: newPaths });
|
|
442
|
+
}, size: "small", children: _jsx(Delete, {}) }), children: _jsx(ListItemText, { primary: skillPath }) }, index))) }), _jsx(TextField, { fullWidth: true, label: trans.__('Add Skills Path'), placeholder: trans.__('e.g., .claude/skills'), onKeyDown: e => {
|
|
443
|
+
if (e.key === 'Enter') {
|
|
444
|
+
const value = e.target.value.trim();
|
|
445
|
+
if (value &&
|
|
446
|
+
!(config.skillsPaths ?? []).includes(value)) {
|
|
447
|
+
const newPaths = [
|
|
448
|
+
...(config.skillsPaths ?? []),
|
|
449
|
+
value
|
|
450
|
+
];
|
|
451
|
+
handleConfigUpdate({ skillsPaths: newPaths });
|
|
452
|
+
e.target.value = '';
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}, helperText: trans.__('Press Enter to add a path. Defaults: .agents/skills, _agents/skills') })] }), _jsx(Divider, { sx: { my: 2 } }), _jsxs(Box, { children: [_jsx(Typography, { variant: "body1", gutterBottom: true, children: trans.__('Commands Requiring Approval') }), _jsx(Typography, { variant: "caption", color: "text.secondary", gutterBottom: true, sx: { display: 'block' }, children: trans.__('Commands that require user approval before AI can execute them') }), _jsx(List, { sx: { mb: 2, maxHeight: 200, overflow: 'auto' }, children: config.commandsRequiringApproval.map((command, index) => (_jsx(ListItem, { divider: true, secondaryAction: _jsx(IconButton, { onClick: () => {
|
|
456
|
+
const newCommands = [
|
|
457
|
+
...config.commandsRequiringApproval
|
|
458
|
+
];
|
|
459
|
+
newCommands.splice(index, 1);
|
|
460
|
+
handleConfigUpdate({
|
|
461
|
+
commandsRequiringApproval: newCommands
|
|
462
|
+
});
|
|
463
|
+
}, size: "small", children: _jsx(Delete, {}) }), children: _jsx(ListItemText, { primary: command }) }, index))) }), _jsx(TextField, { fullWidth: true, label: trans.__('Add New Command'), placeholder: trans.__('e.g., notebook:run-cell'), onKeyDown: e => {
|
|
464
|
+
if (e.key === 'Enter') {
|
|
465
|
+
const value = e.target.value.trim();
|
|
466
|
+
if (value &&
|
|
467
|
+
!config.commandsRequiringApproval.includes(value)) {
|
|
468
|
+
const newCommands = [
|
|
469
|
+
...config.commandsRequiringApproval,
|
|
470
|
+
value
|
|
471
|
+
];
|
|
472
|
+
handleConfigUpdate({
|
|
473
|
+
commandsRequiringApproval: newCommands
|
|
474
|
+
});
|
|
475
|
+
e.target.value = '';
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}, helperText: trans.__('Press Enter to add a command. Common commands: notebook:run-cell, console:execute, fileeditor:run-code') })] }), _jsx(Divider, { sx: { my: 2 } }), _jsxs(Box, { children: [_jsx(Typography, { variant: "body1", gutterBottom: true, children: trans.__('Commands Auto-Rendering MIME Bundles') }), _jsx(Typography, { variant: "caption", color: "text.secondary", gutterBottom: true, sx: { display: 'block' }, children: trans.__('Only these execute_command command IDs can auto-render MIME bundle outputs in chat') }), _jsx(List, { sx: { mb: 2, maxHeight: 200, overflow: 'auto' }, children: (config.commandsAutoRenderMimeBundles ?? []).map((command, index) => (_jsx(ListItem, { divider: true, secondaryAction: _jsx(IconButton, { onClick: () => {
|
|
479
|
+
const newCommands = [
|
|
480
|
+
...(config.commandsAutoRenderMimeBundles ??
|
|
481
|
+
[])
|
|
482
|
+
];
|
|
483
|
+
newCommands.splice(index, 1);
|
|
484
|
+
handleConfigUpdate({
|
|
485
|
+
commandsAutoRenderMimeBundles: newCommands
|
|
486
|
+
});
|
|
487
|
+
}, size: "small", children: _jsx(Delete, {}) }), children: _jsx(ListItemText, { primary: command }) }, index))) }), _jsx(TextField, { fullWidth: true, label: trans.__('Add Auto-Render Command'), placeholder: trans.__('e.g., jupyterlab-ai-commands:execute-in-kernel'), onKeyDown: e => {
|
|
488
|
+
if (e.key === 'Enter') {
|
|
489
|
+
const value = e.target.value.trim();
|
|
490
|
+
const existingCommands = config.commandsAutoRenderMimeBundles ?? [];
|
|
491
|
+
if (value && !existingCommands.includes(value)) {
|
|
492
|
+
const newCommands = [...existingCommands, value];
|
|
493
|
+
handleConfigUpdate({
|
|
494
|
+
commandsAutoRenderMimeBundles: newCommands
|
|
495
|
+
});
|
|
496
|
+
e.target.value = '';
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}, helperText: trans.__('Press Enter to add a command. Default: jupyterlab-ai-commands:execute-in-kernel') })] }), _jsx(Divider, { sx: { my: 2 } }), _jsxs(Box, { children: [_jsx(Typography, { variant: "body1", gutterBottom: true, children: trans.__('Trusted MIME Types for Auto-Render') }), _jsx(Typography, { variant: "caption", color: "text.secondary", gutterBottom: true, sx: { display: 'block' }, children: trans.__('When auto-rendering command outputs, these MIME types are marked trusted in chat') }), _jsx(List, { sx: { mb: 2, maxHeight: 200, overflow: 'auto' }, children: (config.trustedMimeTypesForAutoRender ?? []).map((mimeType, index) => (_jsx(ListItem, { divider: true, secondaryAction: _jsx(IconButton, { onClick: () => {
|
|
500
|
+
const newMimeTypes = [
|
|
501
|
+
...(config.trustedMimeTypesForAutoRender ??
|
|
502
|
+
[])
|
|
503
|
+
];
|
|
504
|
+
newMimeTypes.splice(index, 1);
|
|
505
|
+
handleConfigUpdate({
|
|
506
|
+
trustedMimeTypesForAutoRender: newMimeTypes
|
|
507
|
+
});
|
|
508
|
+
}, size: "small", children: _jsx(Delete, {}) }), children: _jsx(ListItemText, { primary: mimeType }) }, index))) }), _jsx(TextField, { fullWidth: true, label: trans.__('Add Trusted MIME Type'), placeholder: trans.__('e.g., text/html'), onKeyDown: e => {
|
|
509
|
+
if (e.key === 'Enter') {
|
|
510
|
+
const value = e.target.value.trim();
|
|
511
|
+
const existingMimeTypes = config.trustedMimeTypesForAutoRender ?? [];
|
|
512
|
+
if (value && !existingMimeTypes.includes(value)) {
|
|
513
|
+
const newMimeTypes = [...existingMimeTypes, value];
|
|
514
|
+
handleConfigUpdate({
|
|
515
|
+
trustedMimeTypesForAutoRender: newMimeTypes
|
|
516
|
+
});
|
|
517
|
+
e.target.value = '';
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}, helperText: trans.__('Press Enter to add a MIME type. Default: text/html') })] })] })] }) })), activeTab === 2 && (_jsx(Card, { elevation: 2, children: _jsxs(CardContent, { children: [_jsxs(Box, { sx: {
|
|
654
521
|
display: 'flex',
|
|
655
522
|
alignItems: 'center',
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
trans.__('Edit')),
|
|
680
|
-
React.createElement(MenuItem, { onClick: () => handleDeleteProvider(menuProviderId), sx: { color: 'error.main' } },
|
|
681
|
-
React.createElement(Delete, { sx: { mr: 1 } }),
|
|
682
|
-
trans.__('Delete'))),
|
|
683
|
-
React.createElement(MCPServerDialog, { open: mcpDialogOpen, onClose: () => setMcpDialogOpen(false), onSave: editingMCPServer ? handleEditMCPServer : handleAddMCPServer, initialConfig: editingMCPServer, mode: editingMCPServer ? 'edit' : 'add', trans: trans }),
|
|
684
|
-
React.createElement(Menu, { anchorEl: mcpMenuAnchor, open: Boolean(mcpMenuAnchor), onClose: handleMCPMenuClose },
|
|
685
|
-
React.createElement(MenuItem, { onClick: () => {
|
|
686
|
-
const server = config.mcpServers.find(s => s.id === mcpMenuServerId);
|
|
687
|
-
if (server) {
|
|
688
|
-
openEditMCPDialog(server);
|
|
689
|
-
}
|
|
690
|
-
} },
|
|
691
|
-
React.createElement(Edit, { sx: { mr: 1 } }),
|
|
692
|
-
trans.__('Edit')),
|
|
693
|
-
React.createElement(MenuItem, { onClick: () => handleDeleteMCPServer(mcpMenuServerId), sx: { color: 'error.main' } },
|
|
694
|
-
React.createElement(Delete, { sx: { mr: 1 } }),
|
|
695
|
-
trans.__('Delete'))))));
|
|
523
|
+
justifyContent: 'space-between',
|
|
524
|
+
mb: 2
|
|
525
|
+
}, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [_jsx(Cable, { color: "primary" }), _jsx(Typography, { variant: "h6", component: "h2", children: trans.__('Remote MCP Servers') })] }), _jsx(Button, { variant: "contained", startIcon: _jsx(Add, {}), onClick: openAddMCPDialog, size: "small", children: trans.__('Add Server') })] }), _jsx(Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: trans.__("Configure remote Model Context Protocol (MCP) servers to extend the AI's capabilities with external tools and data sources.") }), config.mcpServers.length === 0 ? (_jsx(Alert, { severity: "info", children: trans.__('No MCP servers configured yet. Click "Add Server" to connect to remote MCP services.') })) : (_jsx(List, { children: config.mcpServers.map(server => (_jsx(ListItem, { divider: true, secondaryAction: _jsx(IconButton, { onClick: e => handleMCPMenuClick(e, server.id), size: "small", children: _jsx(MoreVert, {}) }), children: _jsx(ListItemText, { primary: _jsxs(Box, { sx: {
|
|
526
|
+
display: 'flex',
|
|
527
|
+
alignItems: 'center',
|
|
528
|
+
gap: 1
|
|
529
|
+
}, children: [_jsx(Typography, { variant: "body1", children: server.name }), server.enabled &&
|
|
530
|
+
agentManagerFactory?.isMCPServerConnected(server.name) && (_jsx(CheckCircleOutline, { sx: { color: 'success.main', fontSize: 16 } })), server.enabled &&
|
|
531
|
+
!agentManagerFactory?.isMCPServerConnected(server.name) && (_jsx(ErrorOutline, { sx: { color: 'error.main', fontSize: 16 } })), _jsx(Switch, { checked: server.enabled, onChange: e => model.updateMCPServer(server.id, {
|
|
532
|
+
enabled: e.target.checked
|
|
533
|
+
}), size: "small", color: "primary" })] }), secondary: _jsxs(Box, { children: [_jsx(Typography, { variant: "body2", color: "text.secondary", children: server.url }), server.enabled && agentManagerFactory && (_jsx(Typography, { variant: "caption", color: "text.secondary", children: trans.__('Status: %1', agentManagerFactory.isMCPServerConnected(server.name)
|
|
534
|
+
? trans.__('Connected')
|
|
535
|
+
: trans.__('Connection failed')) }))] }) }) }, server.id))) }))] }) })), _jsx(ProviderConfigDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSave: editingProvider ? handleEditProvider : handleAddProvider, initialConfig: editingProvider, mode: editingProvider ? 'edit' : 'add', providerRegistry: providerRegistry, handleSecretField: handleSecretField, trans: trans }), _jsxs(Menu, { anchorEl: menuAnchor, open: Boolean(menuAnchor), onClose: handleMenuClose, children: [_jsxs(MenuItem, { onClick: () => {
|
|
536
|
+
const provider = config.providers.find(p => p.id === menuProviderId);
|
|
537
|
+
if (provider) {
|
|
538
|
+
openEditDialog(provider);
|
|
539
|
+
}
|
|
540
|
+
}, children: [_jsx(Edit, { sx: { mr: 1 } }), trans.__('Edit')] }), _jsxs(MenuItem, { onClick: () => handleDeleteProvider(menuProviderId), sx: { color: 'error.main' }, children: [_jsx(Delete, { sx: { mr: 1 } }), trans.__('Delete')] })] }), _jsx(MCPServerDialog, { open: mcpDialogOpen, onClose: () => setMcpDialogOpen(false), onSave: editingMCPServer ? handleEditMCPServer : handleAddMCPServer, initialConfig: editingMCPServer, mode: editingMCPServer ? 'edit' : 'add', trans: trans }), _jsxs(Menu, { anchorEl: mcpMenuAnchor, open: Boolean(mcpMenuAnchor), onClose: handleMCPMenuClose, children: [_jsxs(MenuItem, { onClick: () => {
|
|
541
|
+
const server = config.mcpServers.find(s => s.id === mcpMenuServerId);
|
|
542
|
+
if (server) {
|
|
543
|
+
openEditMCPDialog(server);
|
|
544
|
+
}
|
|
545
|
+
}, children: [_jsx(Edit, { sx: { mr: 1 } }), trans.__('Edit')] }), _jsxs(MenuItem, { onClick: () => handleDeleteMCPServer(mcpMenuServerId), sx: { color: 'error.main' }, children: [_jsx(Delete, { sx: { mr: 1 } }), trans.__('Delete')] })] })] }) }));
|
|
696
546
|
};
|
|
697
547
|
/**
|
|
698
548
|
* Dialog component for adding/editing MCP server configurations
|
|
@@ -742,16 +592,7 @@ const MCPServerDialog = ({ open, onClose, onSave, initialConfig, mode, trans })
|
|
|
742
592
|
}
|
|
743
593
|
};
|
|
744
594
|
const canSave = name.trim() && url.trim() && _isValidUrl(url.trim());
|
|
745
|
-
return (
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
: trans.__('Edit MCP Server')),
|
|
749
|
-
React.createElement(DialogContent, null,
|
|
750
|
-
React.createElement(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2, pt: 1 } },
|
|
751
|
-
React.createElement(TextField, { autoFocus: true, fullWidth: true, label: trans.__('Server Name'), value: name, onChange: e => setName(e.target.value), placeholder: trans.__('My MCP Server'), helperText: trans.__('A friendly name to identify this MCP server') }),
|
|
752
|
-
React.createElement(TextField, { fullWidth: true, label: trans.__('Server URL'), value: url, onChange: e => setUrl(e.target.value), placeholder: trans.__('https://example.com/mcp'), helperText: trans.__('The HTTP/HTTPS URL of the MCP server'), error: Boolean(url.trim() && !_isValidUrl(url.trim())) }),
|
|
753
|
-
React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: enabled, onChange: e => setEnabled(e.target.checked), color: "primary" }), label: trans.__('Enable this server') }))),
|
|
754
|
-
React.createElement(DialogActions, null,
|
|
755
|
-
React.createElement(Button, { onClick: onClose }, trans.__('Cancel')),
|
|
756
|
-
React.createElement(Button, { onClick: handleSave, variant: "contained", disabled: !canSave }, mode === 'add' ? trans.__('Add') : trans.__('Save')))));
|
|
595
|
+
return (_jsxs(Dialog, { open: open, onClose: onClose, maxWidth: "sm", fullWidth: true, children: [_jsx(DialogTitle, { children: mode === 'add'
|
|
596
|
+
? trans.__('Add MCP Server')
|
|
597
|
+
: trans.__('Edit MCP Server') }), _jsx(DialogContent, { children: _jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2, pt: 1 }, children: [_jsx(TextField, { autoFocus: true, fullWidth: true, label: trans.__('Server Name'), value: name, onChange: e => setName(e.target.value), placeholder: trans.__('My MCP Server'), helperText: trans.__('A friendly name to identify this MCP server') }), _jsx(TextField, { fullWidth: true, label: trans.__('Server URL'), value: url, onChange: e => setUrl(e.target.value), placeholder: trans.__('https://example.com/mcp'), helperText: trans.__('The HTTP/HTTPS URL of the MCP server'), error: Boolean(url.trim() && !_isValidUrl(url.trim())) }), _jsx(FormControlLabel, { control: _jsx(Switch, { checked: enabled, onChange: e => setEnabled(e.target.checked), color: "primary" }), label: trans.__('Enable this server') })] }) }), _jsxs(DialogActions, { children: [_jsx(Button, { onClick: onClose, children: trans.__('Cancel') }), _jsx(Button, { onClick: handleSave, variant: "contained", disabled: !canSave, children: mode === 'add' ? trans.__('Add') : trans.__('Save') })] })] }));
|
|
757
598
|
};
|