@jupyterlite/ai 0.9.1 → 0.11.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/README.md +5 -214
- package/lib/agent.d.ts +58 -66
- package/lib/agent.js +291 -310
- package/lib/approval-buttons.d.ts +19 -82
- package/lib/approval-buttons.js +36 -289
- package/lib/chat-model-registry.d.ts +6 -0
- package/lib/chat-model-registry.js +4 -1
- package/lib/chat-model.d.ts +26 -54
- package/lib/chat-model.js +277 -303
- package/lib/components/clear-button.d.ts +6 -1
- package/lib/components/clear-button.js +10 -6
- package/lib/components/completion-status.d.ts +5 -0
- package/lib/components/completion-status.js +5 -4
- package/lib/components/model-select.d.ts +6 -1
- package/lib/components/model-select.js +13 -16
- package/lib/components/stop-button.d.ts +6 -1
- package/lib/components/stop-button.js +12 -8
- package/lib/components/token-usage-display.d.ts +5 -0
- package/lib/components/token-usage-display.js +2 -2
- package/lib/components/tool-select.d.ts +6 -1
- package/lib/components/tool-select.js +10 -9
- package/lib/index.d.ts +1 -0
- package/lib/index.js +61 -81
- package/lib/models/settings-model.d.ts +1 -1
- package/lib/models/settings-model.js +40 -26
- package/lib/providers/built-in-providers.js +38 -19
- package/lib/providers/models.d.ts +3 -3
- package/lib/providers/provider-registry.d.ts +3 -4
- package/lib/providers/provider-registry.js +1 -4
- package/lib/tokens.d.ts +5 -6
- package/lib/tools/commands.d.ts +2 -1
- package/lib/tools/commands.js +36 -49
- package/lib/widgets/ai-settings.d.ts +6 -0
- package/lib/widgets/ai-settings.js +72 -71
- package/lib/widgets/main-area-chat.d.ts +2 -0
- package/lib/widgets/main-area-chat.js +5 -2
- package/lib/widgets/provider-config-dialog.d.ts +2 -0
- package/lib/widgets/provider-config-dialog.js +34 -34
- package/package.json +13 -13
- package/schema/settings-model.json +3 -2
- package/src/agent.ts +360 -372
- package/src/approval-buttons.ts +43 -389
- package/src/chat-model-registry.ts +9 -1
- package/src/chat-model.ts +399 -370
- package/src/completion/completion-provider.ts +2 -3
- package/src/components/clear-button.tsx +18 -6
- package/src/components/completion-status.tsx +18 -4
- package/src/components/model-select.tsx +25 -16
- package/src/components/stop-button.tsx +22 -9
- package/src/components/token-usage-display.tsx +14 -2
- package/src/components/tool-select.tsx +27 -9
- package/src/index.ts +78 -134
- package/src/models/settings-model.ts +41 -27
- package/src/providers/built-in-providers.ts +38 -19
- package/src/providers/models.ts +3 -3
- package/src/providers/provider-registry.ts +4 -8
- package/src/tokens.ts +5 -6
- package/src/tools/commands.ts +40 -53
- package/src/widgets/ai-settings.tsx +153 -84
- package/src/widgets/main-area-chat.ts +8 -2
- package/src/widgets/provider-config-dialog.tsx +54 -41
- package/style/base.css +24 -73
- package/lib/mcp/browser.d.ts +0 -68
- package/lib/mcp/browser.js +0 -138
- package/lib/tools/file.d.ts +0 -36
- package/lib/tools/file.js +0 -351
- package/lib/tools/notebook.d.ts +0 -40
- package/lib/tools/notebook.js +0 -779
- package/src/mcp/browser.ts +0 -220
- package/src/tools/file.ts +0 -438
- package/src/tools/notebook.ts +0 -986
package/lib/tokens.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Token } from '@lumino/coreutils';
|
|
2
2
|
import { ISignal } from '@lumino/signaling';
|
|
3
|
-
import {
|
|
4
|
-
import { LanguageModelV2 } from '@ai-sdk/provider';
|
|
3
|
+
import type { Tool, LanguageModel } from 'ai';
|
|
5
4
|
import { AgentManager } from './agent';
|
|
6
5
|
import type { AISettingsModel } from './models/settings-model';
|
|
7
6
|
import type { IModelOptions } from './providers/models';
|
|
@@ -19,7 +18,7 @@ export declare namespace CommandIds {
|
|
|
19
18
|
/**
|
|
20
19
|
* Type definition for a tool
|
|
21
20
|
*/
|
|
22
|
-
export type ITool =
|
|
21
|
+
export type ITool = Tool;
|
|
23
22
|
/**
|
|
24
23
|
* Interface for token usage statistics from AI model interactions
|
|
25
24
|
*/
|
|
@@ -89,7 +88,7 @@ export declare const IProviderRegistry: Token<IProviderRegistry>;
|
|
|
89
88
|
* Interface for a provider factory function that creates language models
|
|
90
89
|
*/
|
|
91
90
|
export interface IProviderFactory {
|
|
92
|
-
(options: IModelOptions):
|
|
91
|
+
(options: IModelOptions): LanguageModel;
|
|
93
92
|
}
|
|
94
93
|
/**
|
|
95
94
|
* Provider information
|
|
@@ -165,11 +164,11 @@ export interface IProviderRegistry {
|
|
|
165
164
|
/**
|
|
166
165
|
* Create a chat model instance for the given provider.
|
|
167
166
|
*/
|
|
168
|
-
createChatModel(id: string, options: IModelOptions):
|
|
167
|
+
createChatModel(id: string, options: IModelOptions): LanguageModel | null;
|
|
169
168
|
/**
|
|
170
169
|
* Create a completion model instance for the given provider.
|
|
171
170
|
*/
|
|
172
|
-
createCompletionModel(id: string, options: IModelOptions):
|
|
171
|
+
createCompletionModel(id: string, options: IModelOptions): LanguageModel | null;
|
|
173
172
|
/**
|
|
174
173
|
* Get all available provider IDs.
|
|
175
174
|
*/
|
package/lib/tools/commands.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { AISettingsModel } from '../models/settings-model';
|
|
|
6
6
|
*/
|
|
7
7
|
export declare function createDiscoverCommandsTool(commands: CommandRegistry): ITool;
|
|
8
8
|
/**
|
|
9
|
-
* Create a tool to execute a specific JupyterLab command
|
|
9
|
+
* Create a tool to execute a specific JupyterLab command.
|
|
10
|
+
* Commands in the settings' commandsRequiringApproval list will need approval.
|
|
10
11
|
*/
|
|
11
12
|
export declare function createExecuteCommandTool(commands: CommandRegistry, settingsModel: AISettingsModel): ITool;
|
package/lib/tools/commands.js
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
import { tool } from '
|
|
1
|
+
import { tool } from 'ai';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
/**
|
|
4
4
|
* Create a tool to discover all available commands and their metadata
|
|
5
5
|
*/
|
|
6
6
|
export function createDiscoverCommandsTool(commands) {
|
|
7
7
|
return tool({
|
|
8
|
-
|
|
8
|
+
title: 'Discover Commands',
|
|
9
9
|
description: 'Discover all available JupyterLab commands with their metadata, arguments, and descriptions',
|
|
10
|
-
|
|
11
|
-
// currently unused, but could be used to filter commands by a search term
|
|
10
|
+
inputSchema: z.object({
|
|
12
11
|
query: z
|
|
13
12
|
.string()
|
|
14
13
|
.optional()
|
|
15
14
|
.nullable()
|
|
16
|
-
.describe(
|
|
15
|
+
.describe("Optional search query to filter commands. It doesn't need to be provided to list all commands")
|
|
17
16
|
}),
|
|
18
17
|
execute: async (input) => {
|
|
19
18
|
const { query } = input;
|
|
@@ -57,23 +56,23 @@ export function createDiscoverCommandsTool(commands) {
|
|
|
57
56
|
});
|
|
58
57
|
}
|
|
59
58
|
/**
|
|
60
|
-
* Create a tool to execute a specific JupyterLab command
|
|
59
|
+
* Create a tool to execute a specific JupyterLab command.
|
|
60
|
+
* Commands in the settings' commandsRequiringApproval list will need approval.
|
|
61
61
|
*/
|
|
62
62
|
export function createExecuteCommandTool(commands, settingsModel) {
|
|
63
63
|
return tool({
|
|
64
|
-
|
|
64
|
+
title: 'Execute Command',
|
|
65
65
|
description: 'Execute a specific JupyterLab command with optional arguments',
|
|
66
|
-
|
|
66
|
+
inputSchema: z.object({
|
|
67
67
|
commandId: z.string().describe('The ID of the command to execute'),
|
|
68
68
|
args: z
|
|
69
|
-
.
|
|
69
|
+
.record(z.string(), z.unknown())
|
|
70
70
|
.optional()
|
|
71
|
-
.describe('Optional arguments to pass to the command')
|
|
71
|
+
.describe('Optional arguments object to pass to the command (must be an object, not a string)')
|
|
72
72
|
}),
|
|
73
|
-
needsApproval:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return commandsRequiringApproval.some(cmd => commandId.includes(cmd) || cmd.includes(commandId));
|
|
73
|
+
needsApproval: (input) => {
|
|
74
|
+
const commandsRequiringApproval = settingsModel.config.commandsRequiringApproval || [];
|
|
75
|
+
return commandsRequiringApproval.includes(input.commandId);
|
|
77
76
|
},
|
|
78
77
|
execute: async (input) => {
|
|
79
78
|
const { commandId, args } = input;
|
|
@@ -84,44 +83,32 @@ export function createExecuteCommandTool(commands, settingsModel) {
|
|
|
84
83
|
error: `Command '${commandId}' does not exist. Use 'discover_commands' to see available commands.`
|
|
85
84
|
};
|
|
86
85
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
serializedResult = {
|
|
96
|
-
type: result.constructor?.name || 'Widget',
|
|
97
|
-
id: result.id,
|
|
98
|
-
title: result.title?.label || result.title,
|
|
99
|
-
className: result.className
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
// For other objects, try JSON serialization with fallback
|
|
104
|
-
try {
|
|
105
|
-
serializedResult = JSON.parse(JSON.stringify(result));
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
serializedResult = result
|
|
109
|
-
? '[Complex object - cannot serialize]'
|
|
110
|
-
: 'Command executed successfully';
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return {
|
|
114
|
-
success: true,
|
|
115
|
-
commandId,
|
|
116
|
-
result: serializedResult
|
|
86
|
+
// Execute the command
|
|
87
|
+
const result = await commands.execute(commandId, args);
|
|
88
|
+
// Handle Widget objects specially by extracting id and title
|
|
89
|
+
let serializedResult;
|
|
90
|
+
if (result && typeof result === 'object' && result.id) {
|
|
91
|
+
serializedResult = {
|
|
92
|
+
id: result.id,
|
|
93
|
+
title: result.title?.label || result.title
|
|
117
94
|
};
|
|
118
95
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
96
|
+
else {
|
|
97
|
+
// For other objects, try JSON serialization with fallback
|
|
98
|
+
try {
|
|
99
|
+
serializedResult = JSON.parse(JSON.stringify(result));
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
serializedResult = result
|
|
103
|
+
? '[Complex object - cannot serialize]'
|
|
104
|
+
: 'Command executed successfully';
|
|
105
|
+
}
|
|
124
106
|
}
|
|
107
|
+
return {
|
|
108
|
+
success: true,
|
|
109
|
+
commandId,
|
|
110
|
+
result: serializedResult
|
|
111
|
+
};
|
|
125
112
|
}
|
|
126
113
|
});
|
|
127
114
|
}
|
|
@@ -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 { ISecretsManager } from 'jupyter-secrets-manager';
|
|
4
5
|
import React from 'react';
|
|
5
6
|
import { AgentManagerFactory } from '../agent';
|
|
@@ -24,6 +25,7 @@ export declare class AISettingsWidget extends ReactWidget {
|
|
|
24
25
|
private _themeManager?;
|
|
25
26
|
private _providerRegistry;
|
|
26
27
|
private _secretsManager?;
|
|
28
|
+
private _trans;
|
|
27
29
|
}
|
|
28
30
|
/**
|
|
29
31
|
* Namespace for AISettingsWidget types and interfaces
|
|
@@ -45,5 +47,9 @@ export declare namespace AISettingsWidget {
|
|
|
45
47
|
* The token used to request the secrets manager.
|
|
46
48
|
*/
|
|
47
49
|
token: symbol;
|
|
50
|
+
/**
|
|
51
|
+
* The application language translation bundle.
|
|
52
|
+
*/
|
|
53
|
+
trans: TranslationBundle;
|
|
48
54
|
}
|
|
49
55
|
}
|
|
@@ -46,9 +46,10 @@ export class AISettingsWidget extends ReactWidget {
|
|
|
46
46
|
this._themeManager = options.themeManager;
|
|
47
47
|
this._providerRegistry = options.providerRegistry;
|
|
48
48
|
this._secretsManager = options.secretsManager;
|
|
49
|
+
this._trans = options.trans;
|
|
49
50
|
this.id = 'jupyterlite-ai-settings';
|
|
50
|
-
this.title.label = 'AI Settings';
|
|
51
|
-
this.title.caption = 'Configure AI providers and behavior';
|
|
51
|
+
this.title.label = this._trans.__('AI Settings');
|
|
52
|
+
this.title.caption = this._trans.__('Configure AI providers and behavior');
|
|
52
53
|
this.title.closable = true;
|
|
53
54
|
}
|
|
54
55
|
/**
|
|
@@ -56,22 +57,23 @@ export class AISettingsWidget extends ReactWidget {
|
|
|
56
57
|
* @returns A React element containing the AI settings interface
|
|
57
58
|
*/
|
|
58
59
|
render() {
|
|
59
|
-
return (React.createElement(AISettingsComponent, { model: this._settingsModel, agentManagerFactory: this._agentManagerFactory, themeManager: this._themeManager, providerRegistry: this._providerRegistry, secretsManager: this._secretsManager }));
|
|
60
|
+
return (React.createElement(AISettingsComponent, { model: this._settingsModel, agentManagerFactory: this._agentManagerFactory, themeManager: this._themeManager, providerRegistry: this._providerRegistry, secretsManager: this._secretsManager, trans: this._trans }));
|
|
60
61
|
}
|
|
61
62
|
_settingsModel;
|
|
62
63
|
_agentManagerFactory;
|
|
63
64
|
_themeManager;
|
|
64
65
|
_providerRegistry;
|
|
65
66
|
_secretsManager;
|
|
67
|
+
_trans;
|
|
66
68
|
}
|
|
67
69
|
/**
|
|
68
70
|
* The main AI settings component that provides configuration UI
|
|
69
71
|
* @param props - Component props containing models and theme manager
|
|
70
72
|
* @returns A React component for AI settings configuration
|
|
71
73
|
*/
|
|
72
|
-
const AISettingsComponent = ({ model, agentManagerFactory, themeManager, providerRegistry, secretsManager }) => {
|
|
74
|
+
const AISettingsComponent = ({ model, agentManagerFactory, themeManager, providerRegistry, secretsManager, trans }) => {
|
|
73
75
|
if (!model) {
|
|
74
|
-
return React.createElement("div", null,
|
|
76
|
+
return React.createElement("div", null, trans.__('Settings model not available'));
|
|
75
77
|
}
|
|
76
78
|
const [config, setConfig] = useState(model.config || {});
|
|
77
79
|
const [theme, setTheme] = useState(() => createJupyterLabTheme(themeManager));
|
|
@@ -358,28 +360,28 @@ const AISettingsComponent = ({ model, agentManagerFactory, themeManager, provide
|
|
|
358
360
|
} },
|
|
359
361
|
React.createElement(Box, { sx: { mb: 2, display: 'flex', alignItems: 'center', gap: 2 } },
|
|
360
362
|
React.createElement(Settings, { color: "primary", sx: { fontSize: 24 } }),
|
|
361
|
-
React.createElement(Typography, { variant: "h5", component: "h1", sx: { fontWeight: 600 } },
|
|
363
|
+
React.createElement(Typography, { variant: "h5", component: "h1", sx: { fontWeight: 600 } }, trans.__('AI Settings'))),
|
|
362
364
|
React.createElement(Box, { sx: { borderBottom: 1, borderColor: 'divider', mb: 2 } },
|
|
363
365
|
React.createElement(Tabs, { value: activeTab, onChange: (_, newValue) => setActiveTab(newValue) },
|
|
364
|
-
React.createElement(Tab, { label:
|
|
365
|
-
React.createElement(Tab, { label:
|
|
366
|
-
React.createElement(Tab, { label:
|
|
366
|
+
React.createElement(Tab, { label: trans.__('Providers') }),
|
|
367
|
+
React.createElement(Tab, { label: trans.__('Behavior') }),
|
|
368
|
+
React.createElement(Tab, { label: trans.__('MCP Servers') }))),
|
|
367
369
|
activeTab === 0 && (React.createElement(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 } },
|
|
368
370
|
config.providers.length > 0 && (React.createElement(Card, { elevation: 2 },
|
|
369
371
|
React.createElement(CardContent, null,
|
|
370
|
-
React.createElement(Typography, { variant: "h6", component: "h2", gutterBottom: true },
|
|
372
|
+
React.createElement(Typography, { variant: "h6", component: "h2", gutterBottom: true }, trans.__('Default Providers')),
|
|
371
373
|
React.createElement(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 } },
|
|
372
374
|
React.createElement(FormControl, { fullWidth: true },
|
|
373
|
-
React.createElement(InputLabel, null,
|
|
374
|
-
React.createElement(Select, { value: config.defaultProvider, label:
|
|
375
|
+
React.createElement(InputLabel, null, trans.__('Chat Provider')),
|
|
376
|
+
React.createElement(Select, { value: config.defaultProvider, label: trans.__('Chat Provider'), onChange: e => model.setActiveProvider(e.target.value) }, config.providers.map(provider => (React.createElement(MenuItem, { key: provider.id, value: provider.id }, provider.name))))),
|
|
375
377
|
React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: config.useSameProviderForChatAndCompleter, onChange: e => handleConfigUpdate({
|
|
376
378
|
useSameProviderForChatAndCompleter: e.target.checked
|
|
377
|
-
}), color: "primary" }), label:
|
|
379
|
+
}), color: "primary" }), label: trans.__('Use same provider for chat and completions') }),
|
|
378
380
|
!config.useSameProviderForChatAndCompleter && (React.createElement(FormControl, { fullWidth: true },
|
|
379
|
-
React.createElement(InputLabel, null,
|
|
380
|
-
React.createElement(Select, { value: config.activeCompleterProvider || '', label:
|
|
381
|
+
React.createElement(InputLabel, null, trans.__('Completion Provider')),
|
|
382
|
+
React.createElement(Select, { value: config.activeCompleterProvider || '', label: trans.__('Completion Provider'), className: "jp-ai-completion-provider-select", onChange: e => model.setActiveCompleterProvider(e.target.value || undefined) },
|
|
381
383
|
React.createElement(MenuItem, { value: "" },
|
|
382
|
-
React.createElement("em", null,
|
|
384
|
+
React.createElement("em", null, trans.__('No completion'))),
|
|
383
385
|
config.providers.map(provider => (React.createElement(MenuItem, { key: provider.id, value: provider.id }, provider.name)))))))))),
|
|
384
386
|
React.createElement(Card, { elevation: 2 },
|
|
385
387
|
React.createElement(CardContent, null,
|
|
@@ -390,9 +392,9 @@ const AISettingsComponent = ({ model, agentManagerFactory, themeManager, provide
|
|
|
390
392
|
mb: 2
|
|
391
393
|
} },
|
|
392
394
|
React.createElement(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
393
|
-
React.createElement(Typography, { variant: "h6", component: "h2" },
|
|
394
|
-
React.createElement(Button, { variant: "contained", startIcon: React.createElement(Add, null), onClick: openAddDialog, size: "small" },
|
|
395
|
-
config.providers.length === 0 ? (React.createElement(Alert, { severity: "info" },
|
|
395
|
+
React.createElement(Typography, { variant: "h6", component: "h2" }, trans.__('Configured Providers'))),
|
|
396
|
+
React.createElement(Button, { variant: "contained", startIcon: React.createElement(Add, null), onClick: openAddDialog, size: "small" }, trans.__('Add Provider'))),
|
|
397
|
+
config.providers.length === 0 ? (React.createElement(Alert, { severity: "info" }, trans.__('No providers configured yet. Click "Add Provider" to get started.'))) : (React.createElement(List, null, config.providers.map(provider => {
|
|
396
398
|
const isActive = config.defaultProvider === provider.id;
|
|
397
399
|
const isActiveCompleter = config.useSameProviderForChatAndCompleter
|
|
398
400
|
? isActive
|
|
@@ -418,8 +420,8 @@ const AISettingsComponent = ({ model, agentManagerFactory, themeManager, provide
|
|
|
418
420
|
mb: 0.5
|
|
419
421
|
} },
|
|
420
422
|
React.createElement(Typography, { variant: "subtitle1", fontWeight: "medium" }, provider.name),
|
|
421
|
-
isActive && (React.createElement(Chip, { label:
|
|
422
|
-
isActiveCompleter && (React.createElement(Chip, { label:
|
|
423
|
+
isActive && (React.createElement(Chip, { label: trans.__('Chat'), size: "small", color: "primary", icon: React.createElement(CheckCircle, null) })),
|
|
424
|
+
isActiveCompleter && (React.createElement(Chip, { label: trans.__('Completion'), size: "small", color: "secondary", icon: React.createElement(CheckCircle, null) }))),
|
|
423
425
|
React.createElement(Typography, { variant: "body2", color: "text.secondary", gutterBottom: true },
|
|
424
426
|
provider.provider,
|
|
425
427
|
" \u2022 ",
|
|
@@ -428,67 +430,67 @@ const AISettingsComponent = ({ model, agentManagerFactory, themeManager, provide
|
|
|
428
430
|
` • ${provider.description}`),
|
|
429
431
|
params &&
|
|
430
432
|
(params.temperature !== undefined ||
|
|
431
|
-
params.
|
|
433
|
+
params.maxOutputTokens !== undefined ||
|
|
432
434
|
params.maxTurns !== undefined) && (React.createElement(Box, { sx: {
|
|
433
435
|
display: 'flex',
|
|
434
436
|
flexWrap: 'wrap',
|
|
435
437
|
gap: 1,
|
|
436
438
|
mt: 1
|
|
437
439
|
} },
|
|
438
|
-
params.temperature !== undefined && (React.createElement(Chip, { label:
|
|
439
|
-
params.
|
|
440
|
-
params.maxTurns !== undefined && (React.createElement(Chip, { label:
|
|
440
|
+
params.temperature !== undefined && (React.createElement(Chip, { label: trans.__('Temp: %1', params.temperature), size: "small", variant: "outlined" })),
|
|
441
|
+
params.maxOutputTokens !== undefined && (React.createElement(Chip, { label: trans.__('Tokens: %1', params.maxOutputTokens), size: "small", variant: "outlined" })),
|
|
442
|
+
params.maxTurns !== undefined && (React.createElement(Chip, { label: trans.__('Turns: %1', params.maxTurns), size: "small", variant: "outlined" }))))),
|
|
441
443
|
React.createElement(IconButton, { onClick: e => handleMenuClick(e, provider.id), size: "small" },
|
|
442
444
|
React.createElement(MoreVert, null)))));
|
|
443
445
|
}))))),
|
|
444
446
|
secretsManager !== undefined && (React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: config.useSecretsManager, onChange: e => handleConfigUpdate({
|
|
445
447
|
useSecretsManager: e.target.checked
|
|
446
448
|
}), color: "primary", sx: { alignSelf: 'flex-start' } }), label: React.createElement("div", null,
|
|
447
|
-
React.createElement("span", null,
|
|
448
|
-
!config.useSecretsManager && (React.createElement(Alert, { severity: "warning", icon: React.createElement(Error, null), sx: { mb: 2 } },
|
|
449
|
+
React.createElement("span", null, trans.__('Use the secrets manager to manage API keys')),
|
|
450
|
+
!config.useSecretsManager && (React.createElement(Alert, { severity: "warning", icon: React.createElement(Error, null), sx: { mb: 2 } }, trans.__('The secrets are stored in plain text in settings')))) })))),
|
|
449
451
|
activeTab === 1 && (React.createElement(Card, { elevation: 2 },
|
|
450
452
|
React.createElement(CardContent, null,
|
|
451
|
-
React.createElement(Typography, { variant: "h6", component: "h2", gutterBottom: true },
|
|
453
|
+
React.createElement(Typography, { variant: "h6", component: "h2", gutterBottom: true }, trans.__('Behavior Settings')),
|
|
452
454
|
React.createElement(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 } },
|
|
453
455
|
React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: config.toolsEnabled, onChange: e => handleConfigUpdate({
|
|
454
456
|
toolsEnabled: e.target.checked
|
|
455
457
|
}), color: "primary" }), label: React.createElement(Box, null,
|
|
456
|
-
React.createElement(Typography, { variant: "body1" },
|
|
457
|
-
React.createElement(Typography, { variant: "caption", color: "text.secondary" },
|
|
458
|
+
React.createElement(Typography, { variant: "body1" }, trans.__('Enable Tools')),
|
|
459
|
+
React.createElement(Typography, { variant: "caption", color: "text.secondary" }, trans.__('Allow the AI to use tools like notebook operations, code execution, and file management'))) }),
|
|
458
460
|
React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: config.sendWithShiftEnter, onChange: e => handleConfigUpdate({
|
|
459
461
|
sendWithShiftEnter: e.target.checked
|
|
460
462
|
}), color: "primary" }), label: React.createElement(Box, null,
|
|
461
|
-
React.createElement(Typography, { variant: "body1" },
|
|
462
|
-
React.createElement(Typography, { variant: "caption", color: "text.secondary" },
|
|
463
|
+
React.createElement(Typography, { variant: "body1" }, trans.__('Send with Shift+Enter')),
|
|
464
|
+
React.createElement(Typography, { variant: "caption", color: "text.secondary" }, trans.__('Use Shift+Enter to send messages (Enter creates new line)'))) }),
|
|
463
465
|
React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: config.showTokenUsage, onChange: e => handleConfigUpdate({
|
|
464
466
|
showTokenUsage: e.target.checked
|
|
465
467
|
}), color: "primary" }), label: React.createElement(Box, null,
|
|
466
|
-
React.createElement(Typography, { variant: "body1" },
|
|
467
|
-
React.createElement(Typography, { variant: "caption", color: "text.secondary" },
|
|
468
|
+
React.createElement(Typography, { variant: "body1" }, trans.__('Show Token Usage')),
|
|
469
|
+
React.createElement(Typography, { variant: "caption", color: "text.secondary" }, trans.__('Display token usage information in the chat toolbar'))) }),
|
|
468
470
|
React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: config.showCellDiff, onChange: e => handleConfigUpdate({
|
|
469
471
|
showCellDiff: e.target.checked
|
|
470
472
|
}), color: "primary" }), label: React.createElement(Box, null,
|
|
471
|
-
React.createElement(Typography, { variant: "body1" },
|
|
472
|
-
React.createElement(Typography, { variant: "caption", color: "text.secondary" },
|
|
473
|
+
React.createElement(Typography, { variant: "body1" }, trans.__('Show Cell Diff')),
|
|
474
|
+
React.createElement(Typography, { variant: "caption", color: "text.secondary" }, trans.__('Show diff view when AI modifies cell content'))) }),
|
|
473
475
|
config.showCellDiff && (React.createElement(FormControl, { sx: { ml: 4 } },
|
|
474
|
-
React.createElement(InputLabel, null,
|
|
475
|
-
React.createElement(Select, { value: config.diffDisplayMode, label:
|
|
476
|
+
React.createElement(InputLabel, null, trans.__('Diff Display Mode')),
|
|
477
|
+
React.createElement(Select, { value: config.diffDisplayMode, label: trans.__('Diff Display Mode'), onChange: e => handleConfigUpdate({
|
|
476
478
|
diffDisplayMode: e.target.value
|
|
477
479
|
}) },
|
|
478
|
-
React.createElement(MenuItem, { value: "split" },
|
|
479
|
-
React.createElement(MenuItem, { value: "unified" },
|
|
480
|
+
React.createElement(MenuItem, { value: "split" }, trans.__('Split View')),
|
|
481
|
+
React.createElement(MenuItem, { value: "unified" }, trans.__('Unified View'))))),
|
|
480
482
|
React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: config.showFileDiff, onChange: e => handleConfigUpdate({
|
|
481
483
|
showFileDiff: e.target.checked
|
|
482
484
|
}), color: "primary" }), label: React.createElement(Box, null,
|
|
483
|
-
React.createElement(Typography, { variant: "body1" },
|
|
484
|
-
React.createElement(Typography, { variant: "caption", color: "text.secondary" },
|
|
485
|
+
React.createElement(Typography, { variant: "body1" }, trans.__('Show File Diff')),
|
|
486
|
+
React.createElement(Typography, { variant: "caption", color: "text.secondary" }, trans.__('Show diff view when AI modifies file content'))) }),
|
|
485
487
|
React.createElement(Divider, { sx: { my: 1 } }),
|
|
486
|
-
React.createElement(TextField, { fullWidth: true, multiline: true, rows: 3, label:
|
|
487
|
-
React.createElement(TextField, { fullWidth: true, multiline: true, rows: 3, label:
|
|
488
|
+
React.createElement(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') }),
|
|
489
|
+
React.createElement(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') }),
|
|
488
490
|
React.createElement(Divider, { sx: { my: 2 } }),
|
|
489
491
|
React.createElement(Box, null,
|
|
490
|
-
React.createElement(Typography, { variant: "body1", gutterBottom: true },
|
|
491
|
-
React.createElement(Typography, { variant: "caption", color: "text.secondary", gutterBottom: true, sx: { display: 'block' } },
|
|
492
|
+
React.createElement(Typography, { variant: "body1", gutterBottom: true }, trans.__('Commands Requiring Approval')),
|
|
493
|
+
React.createElement(Typography, { variant: "caption", color: "text.secondary", gutterBottom: true, sx: { display: 'block' } }, trans.__('Commands that require user approval before AI can execute them')),
|
|
492
494
|
React.createElement(List, { sx: { mb: 2, maxHeight: 200, overflow: 'auto' } }, config.commandsRequiringApproval.map((command, index) => (React.createElement(ListItem, { key: index, divider: true },
|
|
493
495
|
React.createElement(ListItemText, { primary: command }),
|
|
494
496
|
React.createElement(ListItemSecondaryAction, null,
|
|
@@ -502,7 +504,7 @@ const AISettingsComponent = ({ model, agentManagerFactory, themeManager, provide
|
|
|
502
504
|
});
|
|
503
505
|
}, size: "small" },
|
|
504
506
|
React.createElement(Delete, null))))))),
|
|
505
|
-
React.createElement(TextField, { fullWidth: true, label:
|
|
507
|
+
React.createElement(TextField, { fullWidth: true, label: trans.__('Add New Command'), placeholder: trans.__('e.g., notebook:run-cell'), onKeyDown: e => {
|
|
506
508
|
if (e.key === 'Enter') {
|
|
507
509
|
const value = e.target.value.trim();
|
|
508
510
|
if (value &&
|
|
@@ -517,7 +519,7 @@ const AISettingsComponent = ({ model, agentManagerFactory, themeManager, provide
|
|
|
517
519
|
e.target.value = '';
|
|
518
520
|
}
|
|
519
521
|
}
|
|
520
|
-
}, helperText:
|
|
522
|
+
}, helperText: trans.__('Press Enter to add a command. Common commands: notebook:run-cell, console:execute, fileeditor:run-code') })))))),
|
|
521
523
|
activeTab === 2 && (React.createElement(Card, { elevation: 2 },
|
|
522
524
|
React.createElement(CardContent, null,
|
|
523
525
|
React.createElement(Box, { sx: {
|
|
@@ -528,10 +530,10 @@ const AISettingsComponent = ({ model, agentManagerFactory, themeManager, provide
|
|
|
528
530
|
} },
|
|
529
531
|
React.createElement(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
530
532
|
React.createElement(Cable, { color: "primary" }),
|
|
531
|
-
React.createElement(Typography, { variant: "h6", component: "h2" },
|
|
532
|
-
React.createElement(Button, { variant: "contained", startIcon: React.createElement(Add, null), onClick: openAddMCPDialog, size: "small" },
|
|
533
|
-
React.createElement(Typography, { variant: "body2", color: "text.secondary", sx: { mb: 2 } }, "Configure remote Model Context Protocol (MCP) servers to extend the AI's capabilities with external tools and data sources."),
|
|
534
|
-
config.mcpServers.length === 0 ? (React.createElement(Alert, { severity: "info" },
|
|
533
|
+
React.createElement(Typography, { variant: "h6", component: "h2" }, trans.__('Remote MCP Servers'))),
|
|
534
|
+
React.createElement(Button, { variant: "contained", startIcon: React.createElement(Add, null), onClick: openAddMCPDialog, size: "small" }, trans.__('Add Server'))),
|
|
535
|
+
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.")),
|
|
536
|
+
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 },
|
|
535
537
|
React.createElement(ListItemText, { primary: React.createElement(Box, { sx: {
|
|
536
538
|
display: 'flex',
|
|
537
539
|
alignItems: 'center',
|
|
@@ -546,16 +548,13 @@ const AISettingsComponent = ({ model, agentManagerFactory, themeManager, provide
|
|
|
546
548
|
enabled: e.target.checked
|
|
547
549
|
}), size: "small", color: "primary" })), secondary: React.createElement(Box, null,
|
|
548
550
|
React.createElement(Typography, { variant: "body2", color: "text.secondary" }, server.url),
|
|
549
|
-
server.enabled && agentManagerFactory && (React.createElement(Typography, { variant: "caption", color: "text.secondary" },
|
|
550
|
-
|
|
551
|
-
' ',
|
|
552
|
-
agentManagerFactory.isMCPServerConnected(server.name)
|
|
553
|
-
? 'Connected'
|
|
554
|
-
: 'Connection failed'))) }),
|
|
551
|
+
server.enabled && agentManagerFactory && (React.createElement(Typography, { variant: "caption", color: "text.secondary" }, trans.__('Status: %1', agentManagerFactory.isMCPServerConnected(server.name)
|
|
552
|
+
? trans.__('Connected')
|
|
553
|
+
: trans.__('Connection failed'))))) }),
|
|
555
554
|
React.createElement(ListItemSecondaryAction, null,
|
|
556
555
|
React.createElement(IconButton, { onClick: e => handleMCPMenuClick(e, server.id), size: "small" },
|
|
557
556
|
React.createElement(MoreVert, null))))))))))),
|
|
558
|
-
React.createElement(ProviderConfigDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSave: editingProvider ? handleEditProvider : handleAddProvider, initialConfig: editingProvider, mode: editingProvider ? 'edit' : 'add', providerRegistry: providerRegistry, handleSecretField: handleSecretField }),
|
|
557
|
+
React.createElement(ProviderConfigDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSave: editingProvider ? handleEditProvider : handleAddProvider, initialConfig: editingProvider, mode: editingProvider ? 'edit' : 'add', providerRegistry: providerRegistry, handleSecretField: handleSecretField, trans: trans }),
|
|
559
558
|
React.createElement(Menu, { anchorEl: menuAnchor, open: Boolean(menuAnchor), onClose: handleMenuClose },
|
|
560
559
|
React.createElement(MenuItem, { onClick: () => {
|
|
561
560
|
const provider = config.providers.find(p => p.id === menuProviderId);
|
|
@@ -564,11 +563,11 @@ const AISettingsComponent = ({ model, agentManagerFactory, themeManager, provide
|
|
|
564
563
|
}
|
|
565
564
|
} },
|
|
566
565
|
React.createElement(Edit, { sx: { mr: 1 } }),
|
|
567
|
-
|
|
566
|
+
trans.__('Edit')),
|
|
568
567
|
React.createElement(MenuItem, { onClick: () => handleDeleteProvider(menuProviderId), sx: { color: 'error.main' } },
|
|
569
568
|
React.createElement(Delete, { sx: { mr: 1 } }),
|
|
570
|
-
|
|
571
|
-
React.createElement(MCPServerDialog, { open: mcpDialogOpen, onClose: () => setMcpDialogOpen(false), onSave: editingMCPServer ? handleEditMCPServer : handleAddMCPServer, initialConfig: editingMCPServer, mode: editingMCPServer ? 'edit' : 'add' }),
|
|
569
|
+
trans.__('Delete'))),
|
|
570
|
+
React.createElement(MCPServerDialog, { open: mcpDialogOpen, onClose: () => setMcpDialogOpen(false), onSave: editingMCPServer ? handleEditMCPServer : handleAddMCPServer, initialConfig: editingMCPServer, mode: editingMCPServer ? 'edit' : 'add', trans: trans }),
|
|
572
571
|
React.createElement(Menu, { anchorEl: mcpMenuAnchor, open: Boolean(mcpMenuAnchor), onClose: handleMCPMenuClose },
|
|
573
572
|
React.createElement(MenuItem, { onClick: () => {
|
|
574
573
|
const server = config.mcpServers.find(s => s.id === mcpMenuServerId);
|
|
@@ -577,17 +576,17 @@ const AISettingsComponent = ({ model, agentManagerFactory, themeManager, provide
|
|
|
577
576
|
}
|
|
578
577
|
} },
|
|
579
578
|
React.createElement(Edit, { sx: { mr: 1 } }),
|
|
580
|
-
|
|
579
|
+
trans.__('Edit')),
|
|
581
580
|
React.createElement(MenuItem, { onClick: () => handleDeleteMCPServer(mcpMenuServerId), sx: { color: 'error.main' } },
|
|
582
581
|
React.createElement(Delete, { sx: { mr: 1 } }),
|
|
583
|
-
|
|
582
|
+
trans.__('Delete'))))));
|
|
584
583
|
};
|
|
585
584
|
/**
|
|
586
585
|
* Dialog component for adding/editing MCP server configurations
|
|
587
586
|
* @param props - Component props for the MCP server dialog
|
|
588
587
|
* @returns A React component for MCP server configuration
|
|
589
588
|
*/
|
|
590
|
-
const MCPServerDialog = ({ open, onClose, onSave, initialConfig, mode }) => {
|
|
589
|
+
const MCPServerDialog = ({ open, onClose, onSave, initialConfig, mode, trans }) => {
|
|
591
590
|
const [name, setName] = useState(initialConfig?.name || '');
|
|
592
591
|
const [url, setUrl] = useState(initialConfig?.url || '');
|
|
593
592
|
const [enabled, setEnabled] = useState(initialConfig?.enabled ?? true);
|
|
@@ -631,15 +630,17 @@ const MCPServerDialog = ({ open, onClose, onSave, initialConfig, mode }) => {
|
|
|
631
630
|
};
|
|
632
631
|
const canSave = name.trim() && url.trim() && _isValidUrl(url.trim());
|
|
633
632
|
return (React.createElement(Dialog, { open: open, onClose: onClose, maxWidth: "sm", fullWidth: true },
|
|
634
|
-
React.createElement(DialogTitle, null, mode === 'add'
|
|
633
|
+
React.createElement(DialogTitle, null, mode === 'add'
|
|
634
|
+
? trans.__('Add MCP Server')
|
|
635
|
+
: trans.__('Edit MCP Server')),
|
|
635
636
|
React.createElement(DialogContent, null,
|
|
636
637
|
React.createElement(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2, pt: 1 } },
|
|
637
|
-
React.createElement(TextField, { autoFocus: true, fullWidth: true, label:
|
|
638
|
-
React.createElement(TextField, { fullWidth: true, label:
|
|
639
|
-
React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: enabled, onChange: e => setEnabled(e.target.checked), color: "primary" }), label:
|
|
638
|
+
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') }),
|
|
639
|
+
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())) }),
|
|
640
|
+
React.createElement(FormControlLabel, { control: React.createElement(Switch, { checked: enabled, onChange: e => setEnabled(e.target.checked), color: "primary" }), label: trans.__('Enable this server') }))),
|
|
640
641
|
React.createElement(DialogActions, null,
|
|
641
|
-
React.createElement(Button, { onClick: onClose },
|
|
642
|
-
React.createElement(Button, { onClick: handleSave, variant: "contained", disabled: !canSave }, mode === 'add' ? 'Add' : 'Save'))));
|
|
642
|
+
React.createElement(Button, { onClick: onClose }, trans.__('Cancel')),
|
|
643
|
+
React.createElement(Button, { onClick: handleSave, variant: "contained", disabled: !canSave }, mode === 'add' ? trans.__('Add') : trans.__('Save')))));
|
|
643
644
|
};
|
|
644
645
|
var Private;
|
|
645
646
|
(function (Private) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ChatWidget } from '@jupyter/chat';
|
|
2
2
|
import { MainAreaWidget } from '@jupyterlab/apputils';
|
|
3
|
+
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
3
4
|
import { CommandRegistry } from '@lumino/commands';
|
|
4
5
|
import { AIChatModel } from '../chat-model';
|
|
5
6
|
import { AISettingsModel } from '../models/settings-model';
|
|
@@ -7,6 +8,7 @@ export declare namespace MainAreaChat {
|
|
|
7
8
|
interface IOptions extends MainAreaWidget.IOptions<ChatWidget> {
|
|
8
9
|
commands: CommandRegistry;
|
|
9
10
|
settingsModel: AISettingsModel;
|
|
11
|
+
trans: TranslationBundle;
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
14
|
/**
|
|
@@ -10,6 +10,7 @@ export class MainAreaChat extends MainAreaWidget {
|
|
|
10
10
|
constructor(options) {
|
|
11
11
|
super(options);
|
|
12
12
|
this.title.label = this.content.model.name;
|
|
13
|
+
const { trans } = options;
|
|
13
14
|
// add the move to side button.
|
|
14
15
|
this.toolbar.addItem('moveToSide', new CommandToolbarButton({
|
|
15
16
|
commands: options.commands,
|
|
@@ -24,12 +25,14 @@ export class MainAreaChat extends MainAreaWidget {
|
|
|
24
25
|
const tokenUsageWidget = new TokenUsageWidget({
|
|
25
26
|
tokenUsageChanged: this.model.tokenUsageChanged,
|
|
26
27
|
settingsModel: options.settingsModel,
|
|
27
|
-
initialTokenUsage: this.model.agentManager.tokenUsage
|
|
28
|
+
initialTokenUsage: this.model.agentManager.tokenUsage,
|
|
29
|
+
translator: trans
|
|
28
30
|
});
|
|
29
31
|
this.toolbar.addItem('token-usage', tokenUsageWidget);
|
|
30
32
|
// Add the approval button, tied to the chat widget.
|
|
31
33
|
this._approvalButtons = new ApprovalButtons({
|
|
32
|
-
chatPanel: this.content
|
|
34
|
+
chatPanel: this.content,
|
|
35
|
+
agentManager: this.model.agentManager
|
|
33
36
|
});
|
|
34
37
|
}
|
|
35
38
|
dispose() {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
1
2
|
import React from 'react';
|
|
2
3
|
import { IProviderConfig } from '../models/settings-model';
|
|
3
4
|
import type { IProviderRegistry } from '../tokens';
|
|
@@ -9,6 +10,7 @@ interface IProviderConfigDialogProps {
|
|
|
9
10
|
mode: 'add' | 'edit';
|
|
10
11
|
providerRegistry: IProviderRegistry;
|
|
11
12
|
handleSecretField: (input: HTMLInputElement, provider: string, fieldName: string) => Promise<void>;
|
|
13
|
+
trans: TranslationBundle;
|
|
12
14
|
}
|
|
13
15
|
export declare const ProviderConfigDialog: React.FC<IProviderConfigDialogProps>;
|
|
14
16
|
export {};
|