@jupyterlite/ai 0.9.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -214
- package/lib/agent.d.ts +58 -66
- package/lib/agent.js +274 -300
- 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 +19 -54
- package/lib/chat-model.js +243 -303
- package/lib/components/clear-button.d.ts +6 -1
- package/lib/components/clear-button.js +8 -3
- 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 +9 -8
- package/lib/components/stop-button.d.ts +6 -1
- package/lib/components/stop-button.js +8 -3
- 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 +6 -5
- package/lib/index.js +58 -38
- package/lib/models/settings-model.d.ts +1 -1
- 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 +37 -46
- package/lib/tools/file.js +49 -73
- package/lib/tools/notebook.js +370 -445
- 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 +12 -12
- package/src/agent.ts +342 -361
- package/src/approval-buttons.ts +43 -389
- package/src/chat-model-registry.ts +9 -1
- package/src/chat-model.ts +355 -370
- package/src/completion/completion-provider.ts +2 -3
- package/src/components/clear-button.tsx +16 -3
- package/src/components/completion-status.tsx +18 -4
- package/src/components/model-select.tsx +21 -8
- package/src/components/stop-button.tsx +16 -3
- package/src/components/token-usage-display.tsx +14 -2
- package/src/components/tool-select.tsx +23 -5
- package/src/index.ts +75 -36
- package/src/models/settings-model.ts +1 -1
- 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 +39 -50
- package/src/tools/file.ts +49 -75
- package/src/tools/notebook.ts +451 -510
- 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 +13 -73
- package/lib/mcp/browser.d.ts +0 -68
- package/lib/mcp/browser.js +0 -138
- package/src/mcp/browser.ts +0 -220
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { InputToolbarRegistry } from '@jupyter/chat';
|
|
2
|
+
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
2
3
|
/**
|
|
3
4
|
* Properties of the clear button.
|
|
4
5
|
*/
|
|
@@ -7,6 +8,10 @@ export interface IClearButtonProps extends InputToolbarRegistry.IToolbarItemProp
|
|
|
7
8
|
* The function to clear messages.
|
|
8
9
|
*/
|
|
9
10
|
clearMessages: () => void;
|
|
11
|
+
/**
|
|
12
|
+
* The application language translator.
|
|
13
|
+
*/
|
|
14
|
+
translator: TranslationBundle;
|
|
10
15
|
}
|
|
11
16
|
/**
|
|
12
17
|
* The clear button component.
|
|
@@ -15,4 +20,4 @@ export declare function ClearButton(props: IClearButtonProps): JSX.Element;
|
|
|
15
20
|
/**
|
|
16
21
|
* Factory returning the clear button toolbar item.
|
|
17
22
|
*/
|
|
18
|
-
export declare function clearItem(): InputToolbarRegistry.IToolbarItem;
|
|
23
|
+
export declare function clearItem(translator: TranslationBundle): InputToolbarRegistry.IToolbarItem;
|
|
@@ -5,7 +5,8 @@ import React from 'react';
|
|
|
5
5
|
* The clear button component.
|
|
6
6
|
*/
|
|
7
7
|
export function ClearButton(props) {
|
|
8
|
-
const
|
|
8
|
+
const { translator: trans } = props;
|
|
9
|
+
const tooltip = trans.__('Clear chat');
|
|
9
10
|
return (React.createElement(TooltippedButton, { onClick: props.clearMessages, tooltip: tooltip, buttonProps: {
|
|
10
11
|
size: 'small',
|
|
11
12
|
variant: 'outlined',
|
|
@@ -17,12 +18,16 @@ export function ClearButton(props) {
|
|
|
17
18
|
/**
|
|
18
19
|
* Factory returning the clear button toolbar item.
|
|
19
20
|
*/
|
|
20
|
-
export function clearItem() {
|
|
21
|
+
export function clearItem(translator) {
|
|
21
22
|
return {
|
|
22
23
|
element: (props) => {
|
|
23
24
|
const { model } = props;
|
|
24
25
|
const clearMessages = () => model.chatContext.clearMessages();
|
|
25
|
-
const clearProps = {
|
|
26
|
+
const clearProps = {
|
|
27
|
+
...props,
|
|
28
|
+
clearMessages,
|
|
29
|
+
translator
|
|
30
|
+
};
|
|
26
31
|
return ClearButton(clearProps);
|
|
27
32
|
},
|
|
28
33
|
position: 0,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AISettingsModel } from '../models/settings-model';
|
|
2
2
|
import { ReactWidget } from '@jupyterlab/ui-components';
|
|
3
|
+
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
3
4
|
/**
|
|
4
5
|
* The completion status props.
|
|
5
6
|
*/
|
|
@@ -8,6 +9,10 @@ interface ICompletionStatusProps {
|
|
|
8
9
|
* The settings model.
|
|
9
10
|
*/
|
|
10
11
|
settingsModel: AISettingsModel;
|
|
12
|
+
/**
|
|
13
|
+
* The application language translator.
|
|
14
|
+
*/
|
|
15
|
+
translator: TranslationBundle;
|
|
11
16
|
}
|
|
12
17
|
/**
|
|
13
18
|
* The completion status widget that will be added to the status bar.
|
|
@@ -7,6 +7,7 @@ const COMPLETION_DISABLED_CLASS = 'jp-ai-completion-disabled';
|
|
|
7
7
|
* The completion status component.
|
|
8
8
|
*/
|
|
9
9
|
function CompletionStatus(props) {
|
|
10
|
+
const { translator: trans } = props;
|
|
10
11
|
const [disabled, setDisabled] = useState(true);
|
|
11
12
|
const [title, setTitle] = useState('');
|
|
12
13
|
/**
|
|
@@ -16,15 +17,15 @@ function CompletionStatus(props) {
|
|
|
16
17
|
const stateChanged = (model) => {
|
|
17
18
|
if (model.config.useSameProviderForChatAndCompleter) {
|
|
18
19
|
setDisabled(false);
|
|
19
|
-
setTitle(
|
|
20
|
+
setTitle(trans.__('Completion using %1', model.getDefaultProvider()?.model ?? ''));
|
|
20
21
|
}
|
|
21
22
|
else if (model.config.activeCompleterProvider) {
|
|
22
23
|
setDisabled(false);
|
|
23
|
-
setTitle(
|
|
24
|
+
setTitle(trans.__('Completion using %1', model.getProvider(model.config.activeCompleterProvider)?.model ?? ''));
|
|
24
25
|
}
|
|
25
26
|
else {
|
|
26
27
|
setDisabled(true);
|
|
27
|
-
setTitle('No completion');
|
|
28
|
+
setTitle(trans.__('No completion'));
|
|
28
29
|
}
|
|
29
30
|
};
|
|
30
31
|
props.settingsModel.stateChanged.connect(stateChanged);
|
|
@@ -32,7 +33,7 @@ function CompletionStatus(props) {
|
|
|
32
33
|
return () => {
|
|
33
34
|
props.settingsModel.stateChanged.disconnect(stateChanged);
|
|
34
35
|
};
|
|
35
|
-
}, [props.settingsModel]);
|
|
36
|
+
}, [props.settingsModel, trans]);
|
|
36
37
|
return (React.createElement(jupyternautIcon.react, { className: disabled ? COMPLETION_DISABLED_CLASS : '', top: '2px', width: '16px', stylesheet: 'statusBar', title: title }));
|
|
37
38
|
}
|
|
38
39
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { InputToolbarRegistry } from '@jupyter/chat';
|
|
2
|
+
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
2
3
|
import { AISettingsModel } from '../models/settings-model';
|
|
3
4
|
/**
|
|
4
5
|
* Properties for the model select component.
|
|
@@ -8,6 +9,10 @@ export interface IModelSelectProps extends InputToolbarRegistry.IToolbarItemProp
|
|
|
8
9
|
* The settings model to get available models and current selection from.
|
|
9
10
|
*/
|
|
10
11
|
settingsModel: AISettingsModel;
|
|
12
|
+
/**
|
|
13
|
+
* The application language translator.
|
|
14
|
+
*/
|
|
15
|
+
translator: TranslationBundle;
|
|
11
16
|
}
|
|
12
17
|
/**
|
|
13
18
|
* The model select component for choosing AI models.
|
|
@@ -16,4 +21,4 @@ export declare function ModelSelect(props: IModelSelectProps): JSX.Element;
|
|
|
16
21
|
/**
|
|
17
22
|
* Factory function returning the toolbar item for model selection.
|
|
18
23
|
*/
|
|
19
|
-
export declare function createModelSelectItem(settingsModel: AISettingsModel): InputToolbarRegistry.IToolbarItem;
|
|
24
|
+
export declare function createModelSelectItem(settingsModel: AISettingsModel, translator: TranslationBundle): InputToolbarRegistry.IToolbarItem;
|
|
@@ -6,7 +6,7 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|
|
6
6
|
* The model select component for choosing AI models.
|
|
7
7
|
*/
|
|
8
8
|
export function ModelSelect(props) {
|
|
9
|
-
const { settingsModel, model } = props;
|
|
9
|
+
const { settingsModel, model, translator: trans } = props;
|
|
10
10
|
const agentManager = model.chatContext
|
|
11
11
|
.agentManager;
|
|
12
12
|
const [currentProvider, setCurrentProvider] = useState(agentManager.activeProvider ?? '');
|
|
@@ -60,28 +60,28 @@ export function ModelSelect(props) {
|
|
|
60
60
|
}));
|
|
61
61
|
// Show a message if no providers are configured
|
|
62
62
|
if (availableModels.length === 0) {
|
|
63
|
-
return (React.createElement(TooltippedButton, { onClick: () => { }, tooltip:
|
|
63
|
+
return (React.createElement(TooltippedButton, { onClick: () => { }, tooltip: trans.__('No providers configured. Please go to AI Settings to add a provider.'), buttonProps: {
|
|
64
64
|
size: 'small',
|
|
65
65
|
variant: 'outlined',
|
|
66
66
|
color: 'warning',
|
|
67
67
|
disabled: true,
|
|
68
|
-
title: 'No Providers Available'
|
|
68
|
+
title: trans.__('No Providers Available')
|
|
69
69
|
}, sx: {
|
|
70
70
|
minWidth: 'auto',
|
|
71
71
|
display: 'flex',
|
|
72
72
|
alignItems: 'center',
|
|
73
73
|
height: '29px'
|
|
74
74
|
} },
|
|
75
|
-
React.createElement(Typography, { variant: "caption", sx: { fontSize: '0.7rem', fontWeight: 500 } },
|
|
75
|
+
React.createElement(Typography, { variant: "caption", sx: { fontSize: '0.7rem', fontWeight: 500 } }, trans.__('No Providers'))));
|
|
76
76
|
}
|
|
77
77
|
return (React.createElement(React.Fragment, null,
|
|
78
78
|
React.createElement(TooltippedButton, { onClick: e => {
|
|
79
79
|
openMenu(e.currentTarget);
|
|
80
|
-
}, tooltip:
|
|
80
|
+
}, tooltip: trans.__('Current Model: %1 - %2', currentProviderLabel, currentModel), buttonProps: {
|
|
81
81
|
size: 'small',
|
|
82
82
|
variant: 'contained',
|
|
83
83
|
color: 'primary',
|
|
84
|
-
title: 'Select AI Model',
|
|
84
|
+
title: trans.__('Select AI Model'),
|
|
85
85
|
onKeyDown: e => {
|
|
86
86
|
if (e.key !== 'Enter' && e.key !== ' ') {
|
|
87
87
|
return;
|
|
@@ -144,7 +144,7 @@ export function ModelSelect(props) {
|
|
|
144
144
|
/**
|
|
145
145
|
* Factory function returning the toolbar item for model selection.
|
|
146
146
|
*/
|
|
147
|
-
export function createModelSelectItem(settingsModel) {
|
|
147
|
+
export function createModelSelectItem(settingsModel, translator) {
|
|
148
148
|
return {
|
|
149
149
|
element: (props) => {
|
|
150
150
|
const chatContext = props.model.chatContext;
|
|
@@ -153,7 +153,8 @@ export function createModelSelectItem(settingsModel) {
|
|
|
153
153
|
}
|
|
154
154
|
const modelSelectProps = {
|
|
155
155
|
...props,
|
|
156
|
-
settingsModel
|
|
156
|
+
settingsModel,
|
|
157
|
+
translator
|
|
157
158
|
};
|
|
158
159
|
return React.createElement(ModelSelect, { ...modelSelectProps });
|
|
159
160
|
},
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { InputToolbarRegistry } from '@jupyter/chat';
|
|
2
|
+
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
2
3
|
/**
|
|
3
4
|
* Properties of the stop button.
|
|
4
5
|
*/
|
|
@@ -7,6 +8,10 @@ export interface IStopButtonProps extends InputToolbarRegistry.IToolbarItemProps
|
|
|
7
8
|
* The function to stop streaming.
|
|
8
9
|
*/
|
|
9
10
|
stopStreaming: () => void;
|
|
11
|
+
/**
|
|
12
|
+
* The application language translator.
|
|
13
|
+
*/
|
|
14
|
+
translator: TranslationBundle;
|
|
10
15
|
}
|
|
11
16
|
/**
|
|
12
17
|
* The stop button component.
|
|
@@ -15,4 +20,4 @@ export declare function StopButton(props: IStopButtonProps): JSX.Element;
|
|
|
15
20
|
/**
|
|
16
21
|
* Factory returning the stop button toolbar item.
|
|
17
22
|
*/
|
|
18
|
-
export declare function stopItem(): InputToolbarRegistry.IToolbarItem;
|
|
23
|
+
export declare function stopItem(translator: TranslationBundle): InputToolbarRegistry.IToolbarItem;
|
|
@@ -5,7 +5,8 @@ import React from 'react';
|
|
|
5
5
|
* The stop button component.
|
|
6
6
|
*/
|
|
7
7
|
export function StopButton(props) {
|
|
8
|
-
const
|
|
8
|
+
const { translator: trans } = props;
|
|
9
|
+
const tooltip = trans.__('Stop streaming');
|
|
9
10
|
return (React.createElement(TooltippedButton, { onClick: props.stopStreaming, tooltip: tooltip, buttonProps: {
|
|
10
11
|
size: 'small',
|
|
11
12
|
variant: 'contained',
|
|
@@ -17,12 +18,16 @@ export function StopButton(props) {
|
|
|
17
18
|
/**
|
|
18
19
|
* Factory returning the stop button toolbar item.
|
|
19
20
|
*/
|
|
20
|
-
export function stopItem() {
|
|
21
|
+
export function stopItem(translator) {
|
|
21
22
|
return {
|
|
22
23
|
element: (props) => {
|
|
23
24
|
const { model } = props;
|
|
24
25
|
const stopStreaming = () => model.chatContext.stopStreaming();
|
|
25
|
-
const stopProps = {
|
|
26
|
+
const stopProps = {
|
|
27
|
+
...props,
|
|
28
|
+
stopStreaming,
|
|
29
|
+
translator
|
|
30
|
+
};
|
|
26
31
|
return StopButton(stopProps);
|
|
27
32
|
},
|
|
28
33
|
position: 50,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ReactWidget } from '@jupyterlab/ui-components';
|
|
2
|
+
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
2
3
|
import React from 'react';
|
|
3
4
|
import { ISignal } from '@lumino/signaling';
|
|
4
5
|
import { AISettingsModel } from '../models/settings-model';
|
|
@@ -19,6 +20,10 @@ export interface ITokenUsageDisplayProps {
|
|
|
19
20
|
* Initial token usage.
|
|
20
21
|
*/
|
|
21
22
|
initialTokenUsage?: ITokenUsage;
|
|
23
|
+
/**
|
|
24
|
+
* The application language translator.
|
|
25
|
+
*/
|
|
26
|
+
translator: TranslationBundle;
|
|
22
27
|
}
|
|
23
28
|
/**
|
|
24
29
|
* React component that displays token usage information.
|
|
@@ -5,7 +5,7 @@ import React from 'react';
|
|
|
5
5
|
* Shows input/output token counts with up/down arrows.
|
|
6
6
|
* Only renders when token usage display is enabled in settings.
|
|
7
7
|
*/
|
|
8
|
-
export const TokenUsageDisplay = ({ tokenUsageChanged, settingsModel, initialTokenUsage }) => {
|
|
8
|
+
export const TokenUsageDisplay = ({ tokenUsageChanged, settingsModel, initialTokenUsage, translator: trans }) => {
|
|
9
9
|
return (React.createElement(UseSignal, { signal: settingsModel.stateChanged, initialArgs: undefined }, () => {
|
|
10
10
|
const config = settingsModel.config;
|
|
11
11
|
if (!config.showTokenUsage) {
|
|
@@ -30,7 +30,7 @@ export const TokenUsageDisplay = ({ tokenUsageChanged, settingsModel, initialTok
|
|
|
30
30
|
border: '1px solid var(--jp-border-color1)',
|
|
31
31
|
borderRadius: '4px',
|
|
32
32
|
whiteSpace: 'nowrap'
|
|
33
|
-
}, title:
|
|
33
|
+
}, title: trans.__('Token Usage - Sent: %1, Received: %2, Total: %3', tokenUsage.inputTokens.toLocaleString(), tokenUsage.outputTokens.toLocaleString(), total.toLocaleString()) },
|
|
34
34
|
React.createElement("span", { style: {
|
|
35
35
|
display: 'flex',
|
|
36
36
|
alignItems: 'center',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { InputToolbarRegistry } from '@jupyter/chat';
|
|
2
|
+
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
2
3
|
import { IToolRegistry } from '../tokens';
|
|
3
4
|
/**
|
|
4
5
|
* Properties for the tool select component.
|
|
@@ -16,6 +17,10 @@ export interface IToolSelectProps extends InputToolbarRegistry.IToolbarItemProps
|
|
|
16
17
|
* Function to handle tool selection changes.
|
|
17
18
|
*/
|
|
18
19
|
onToolSelectionChange: (selectedToolNames: string[]) => void;
|
|
20
|
+
/**
|
|
21
|
+
* The application language translator.
|
|
22
|
+
*/
|
|
23
|
+
translator: TranslationBundle;
|
|
19
24
|
}
|
|
20
25
|
/**
|
|
21
26
|
* The tool select component for choosing AI tools.
|
|
@@ -24,4 +29,4 @@ export declare function ToolSelect(props: IToolSelectProps): JSX.Element;
|
|
|
24
29
|
/**
|
|
25
30
|
* Factory function returning the toolbar item for tool selection.
|
|
26
31
|
*/
|
|
27
|
-
export declare function createToolSelectItem(toolRegistry: IToolRegistry, toolsEnabled
|
|
32
|
+
export declare function createToolSelectItem(toolRegistry: IToolRegistry, toolsEnabled: boolean | undefined, translator: TranslationBundle): InputToolbarRegistry.IToolbarItem;
|
|
@@ -8,7 +8,7 @@ const SELECT_ITEM_CLASS = 'jp-AIToolSelect-item';
|
|
|
8
8
|
* The tool select component for choosing AI tools.
|
|
9
9
|
*/
|
|
10
10
|
export function ToolSelect(props) {
|
|
11
|
-
const { toolRegistry, onToolSelectionChange, toolsEnabled } = props;
|
|
11
|
+
const { toolRegistry, onToolSelectionChange, toolsEnabled, translator: trans } = props;
|
|
12
12
|
const [selectedToolNames, setSelectedToolNames] = useState([]);
|
|
13
13
|
const [tools, setTools] = useState(toolRegistry?.namedTools || []);
|
|
14
14
|
const [menuAnchorEl, setMenuAnchorEl] = useState(null);
|
|
@@ -63,11 +63,11 @@ export function ToolSelect(props) {
|
|
|
63
63
|
return (React.createElement(React.Fragment, null,
|
|
64
64
|
React.createElement(TooltippedButton, { onClick: e => {
|
|
65
65
|
openMenu(e.currentTarget);
|
|
66
|
-
}, tooltip:
|
|
66
|
+
}, tooltip: trans.__('Tools (%1/%2 selected)', selectedToolNames.length.toString(), tools.length.toString()), buttonProps: {
|
|
67
67
|
size: 'small',
|
|
68
68
|
variant: selectedToolNames.length > 0 ? 'contained' : 'outlined',
|
|
69
69
|
color: 'primary',
|
|
70
|
-
title: 'Select AI Tools',
|
|
70
|
+
title: trans.__('Select AI Tools'),
|
|
71
71
|
onKeyDown: e => {
|
|
72
72
|
if (e.key !== 'Enter' && e.key !== ' ') {
|
|
73
73
|
return;
|
|
@@ -106,7 +106,7 @@ export function ToolSelect(props) {
|
|
|
106
106
|
/**
|
|
107
107
|
* Factory function returning the toolbar item for tool selection.
|
|
108
108
|
*/
|
|
109
|
-
export function createToolSelectItem(toolRegistry, toolsEnabled = true) {
|
|
109
|
+
export function createToolSelectItem(toolRegistry, toolsEnabled = true, translator) {
|
|
110
110
|
return {
|
|
111
111
|
element: (props) => {
|
|
112
112
|
const onToolSelectionChange = (tools) => {
|
|
@@ -121,7 +121,8 @@ export function createToolSelectItem(toolRegistry, toolsEnabled = true) {
|
|
|
121
121
|
...props,
|
|
122
122
|
toolRegistry,
|
|
123
123
|
onToolSelectionChange,
|
|
124
|
-
toolsEnabled
|
|
124
|
+
toolsEnabled,
|
|
125
|
+
translator
|
|
125
126
|
};
|
|
126
127
|
return React.createElement(ToolSelect, { ...toolSelectProps });
|
|
127
128
|
},
|
package/lib/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
|
9
9
|
import { IKernelSpecManager } from '@jupyterlab/services';
|
|
10
10
|
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
11
11
|
import { IStatusBar } from '@jupyterlab/statusbar';
|
|
12
|
+
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
|
12
13
|
import { settingsIcon, Toolbar, ToolbarButton } from '@jupyterlab/ui-components';
|
|
13
14
|
import { ISecretsManager, SecretsManager } from 'jupyter-secrets-manager';
|
|
14
15
|
import { PromiseDelegate, UUID } from '@lumino/coreutils';
|
|
@@ -108,9 +109,10 @@ const chatModelRegistry = {
|
|
|
108
109
|
description: 'Registry for the current chat model',
|
|
109
110
|
autoStart: true,
|
|
110
111
|
requires: [IAISettingsModel, IAgentManagerFactory, IDocumentManager],
|
|
111
|
-
optional: [IProviderRegistry, INotebookTracker, IToolRegistry],
|
|
112
|
+
optional: [IProviderRegistry, INotebookTracker, IToolRegistry, ITranslator],
|
|
112
113
|
provides: IChatModelRegistry,
|
|
113
|
-
activate: (app, settingsModel, agentManagerFactory, docManager, providerRegistry, notebookTracker, toolRegistry) => {
|
|
114
|
+
activate: (app, settingsModel, agentManagerFactory, docManager, providerRegistry, notebookTracker, toolRegistry, translator) => {
|
|
115
|
+
const trans = (translator ?? nullTranslator).load('jupyterlite_ai');
|
|
114
116
|
// Create ActiveCellManager if notebook tracker is available
|
|
115
117
|
let activeCellManager;
|
|
116
118
|
if (notebookTracker) {
|
|
@@ -125,7 +127,8 @@ const chatModelRegistry = {
|
|
|
125
127
|
agentManagerFactory,
|
|
126
128
|
docManager,
|
|
127
129
|
providerRegistry,
|
|
128
|
-
toolRegistry
|
|
130
|
+
toolRegistry,
|
|
131
|
+
trans
|
|
129
132
|
});
|
|
130
133
|
}
|
|
131
134
|
};
|
|
@@ -142,8 +145,9 @@ const plugin = {
|
|
|
142
145
|
IChatModelRegistry,
|
|
143
146
|
IAISettingsModel
|
|
144
147
|
],
|
|
145
|
-
optional: [IThemeManager, ILayoutRestorer, ILabShell],
|
|
146
|
-
activate: (app, rmRegistry, inputToolbarFactory, modelRegistry, settingsModel, themeManager, restorer, labShell) => {
|
|
148
|
+
optional: [IThemeManager, ILayoutRestorer, ILabShell, ITranslator],
|
|
149
|
+
activate: (app, rmRegistry, inputToolbarFactory, modelRegistry, settingsModel, themeManager, restorer, labShell, translator) => {
|
|
150
|
+
const trans = (translator ?? nullTranslator).load('jupyterlite_ai');
|
|
147
151
|
// Create attachment opener registry to handle file attachments
|
|
148
152
|
const attachmentOpenerRegistry = new AttachmentOpenerRegistry();
|
|
149
153
|
attachmentOpenerRegistry.set('file', attachment => {
|
|
@@ -178,14 +182,14 @@ const plugin = {
|
|
|
178
182
|
});
|
|
179
183
|
chatPanel.id = '@jupyterlite/ai:chat-panel';
|
|
180
184
|
chatPanel.title.icon = chatIcon;
|
|
181
|
-
chatPanel.title.caption = 'Chat with AI assistant';
|
|
185
|
+
chatPanel.title.caption = trans.__('Chat with AI assistant');
|
|
182
186
|
chatPanel.toolbar.addItem('spacer', Toolbar.createSpacerItem());
|
|
183
187
|
chatPanel.toolbar.addItem('settings', new ToolbarButton({
|
|
184
188
|
icon: settingsIcon,
|
|
185
189
|
onClick: () => {
|
|
186
190
|
app.commands.execute('@jupyterlite/ai:open-settings');
|
|
187
191
|
},
|
|
188
|
-
tooltip: 'Open AI Settings'
|
|
192
|
+
tooltip: trans.__('Open AI Settings')
|
|
189
193
|
}));
|
|
190
194
|
chatPanel.sectionAdded.connect((_, section) => {
|
|
191
195
|
const { widget } = section;
|
|
@@ -199,7 +203,8 @@ const plugin = {
|
|
|
199
203
|
const tokenUsageWidget = new TokenUsageWidget({
|
|
200
204
|
tokenUsageChanged: model.tokenUsageChanged,
|
|
201
205
|
settingsModel,
|
|
202
|
-
initialTokenUsage: model.agentManager.tokenUsage
|
|
206
|
+
initialTokenUsage: model.agentManager.tokenUsage,
|
|
207
|
+
translator: trans
|
|
203
208
|
});
|
|
204
209
|
section.toolbar.insertBefore('markRead', 'token-usage', tokenUsageWidget);
|
|
205
210
|
model.writersChanged?.connect((_, writers) => {
|
|
@@ -216,7 +221,8 @@ const plugin = {
|
|
|
216
221
|
});
|
|
217
222
|
// Associate an approval buttons object to the chat.
|
|
218
223
|
const approvalButton = new ApprovalButtons({
|
|
219
|
-
chatPanel: widget
|
|
224
|
+
chatPanel: widget,
|
|
225
|
+
agentManager: model.agentManager
|
|
220
226
|
});
|
|
221
227
|
widget.disposed.connect(() => {
|
|
222
228
|
// Dispose of the approval buttons widget when the chat is disposed.
|
|
@@ -251,14 +257,14 @@ const plugin = {
|
|
|
251
257
|
app.commands.execute(CommandIds.openChat);
|
|
252
258
|
}
|
|
253
259
|
});
|
|
254
|
-
registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry, inputToolbarFactory, settingsModel, tracker, modelRegistry, themeManager, labShell);
|
|
260
|
+
registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry, inputToolbarFactory, settingsModel, tracker, modelRegistry, trans, themeManager, labShell);
|
|
255
261
|
}
|
|
256
262
|
};
|
|
257
|
-
function registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry, inputToolbarFactory, settingsModel, tracker, modelRegistry, themeManager, labShell) {
|
|
263
|
+
function registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry, inputToolbarFactory, settingsModel, tracker, modelRegistry, trans, themeManager, labShell) {
|
|
258
264
|
const { commands } = app;
|
|
259
265
|
if (labShell) {
|
|
260
266
|
commands.addCommand(CommandIds.reposition, {
|
|
261
|
-
label: 'Reposition Widget',
|
|
267
|
+
label: trans.__('Reposition Widget'),
|
|
262
268
|
execute: (args) => {
|
|
263
269
|
const { widgetId, area, mode } = args;
|
|
264
270
|
const widget = widgetId
|
|
@@ -284,16 +290,16 @@ function registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry,
|
|
|
284
290
|
properties: {
|
|
285
291
|
widgetId: {
|
|
286
292
|
type: 'string',
|
|
287
|
-
description: 'The widget ID to reposition in the application shell'
|
|
293
|
+
description: trans.__('The widget ID to reposition in the application shell')
|
|
288
294
|
},
|
|
289
295
|
area: {
|
|
290
296
|
type: 'string',
|
|
291
|
-
description: 'The name of the area to reposition the widget to'
|
|
297
|
+
description: trans.__('The name of the area to reposition the widget to')
|
|
292
298
|
},
|
|
293
299
|
mode: {
|
|
294
300
|
type: 'string',
|
|
295
301
|
enum: ['split-left', 'split-right', 'split-top', 'split-bottom'],
|
|
296
|
-
description: 'The mode to use when repositioning the widget'
|
|
302
|
+
description: trans.__('The mode to use when repositioning the widget')
|
|
297
303
|
}
|
|
298
304
|
}
|
|
299
305
|
}
|
|
@@ -307,7 +313,12 @@ function registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry,
|
|
|
307
313
|
inputToolbarRegistry: inputToolbarFactory.create(),
|
|
308
314
|
attachmentOpenerRegistry
|
|
309
315
|
});
|
|
310
|
-
const widget = new MainAreaChat({
|
|
316
|
+
const widget = new MainAreaChat({
|
|
317
|
+
content,
|
|
318
|
+
commands,
|
|
319
|
+
settingsModel,
|
|
320
|
+
trans
|
|
321
|
+
});
|
|
311
322
|
app.shell.add(widget, 'main');
|
|
312
323
|
// Add the widget to the tracker.
|
|
313
324
|
tracker.add(widget);
|
|
@@ -321,7 +332,7 @@ function registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry,
|
|
|
321
332
|
});
|
|
322
333
|
};
|
|
323
334
|
commands.addCommand(CommandIds.openChat, {
|
|
324
|
-
label: 'Open a chat',
|
|
335
|
+
label: trans.__('Open a chat'),
|
|
325
336
|
execute: async (args) => {
|
|
326
337
|
const area = args.area === 'main' ? 'main' : 'side';
|
|
327
338
|
const provider = args.provider ?? undefined;
|
|
@@ -348,22 +359,22 @@ function registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry,
|
|
|
348
359
|
area: {
|
|
349
360
|
type: 'string',
|
|
350
361
|
enum: ['main', 'side'],
|
|
351
|
-
description: 'The name of the area to open the chat to'
|
|
362
|
+
description: trans.__('The name of the area to open the chat to')
|
|
352
363
|
},
|
|
353
364
|
name: {
|
|
354
365
|
type: 'string',
|
|
355
|
-
description: 'The name of the chat'
|
|
366
|
+
description: trans.__('The name of the chat')
|
|
356
367
|
},
|
|
357
368
|
provider: {
|
|
358
369
|
type: 'string',
|
|
359
|
-
description: 'The provider/model to use with this chat'
|
|
370
|
+
description: trans.__('The provider/model to use with this chat')
|
|
360
371
|
}
|
|
361
372
|
}
|
|
362
373
|
}
|
|
363
374
|
}
|
|
364
375
|
});
|
|
365
376
|
commands.addCommand(CommandIds.moveChat, {
|
|
366
|
-
caption: 'Move chat between area',
|
|
377
|
+
caption: trans.__('Move chat between area'),
|
|
367
378
|
execute: async (args) => {
|
|
368
379
|
const area = args.area;
|
|
369
380
|
if (!['side', 'main'].includes(area)) {
|
|
@@ -399,7 +410,7 @@ function registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry,
|
|
|
399
410
|
const status = await Promise.any([
|
|
400
411
|
trackerUpdated.promise,
|
|
401
412
|
new Promise(r => setTimeout(() => {
|
|
402
|
-
|
|
413
|
+
r(false);
|
|
403
414
|
}, 2000))
|
|
404
415
|
]);
|
|
405
416
|
tracker.widgetUpdated.disconnect(widgetUpdated);
|
|
@@ -427,11 +438,11 @@ function registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry,
|
|
|
427
438
|
area: {
|
|
428
439
|
type: 'string',
|
|
429
440
|
enum: ['main', 'side'],
|
|
430
|
-
description: 'The name of the area to move the chat to'
|
|
441
|
+
description: trans.__('The name of the area to move the chat to')
|
|
431
442
|
},
|
|
432
443
|
name: {
|
|
433
444
|
type: 'string',
|
|
434
|
-
description: 'The name of the chat to move'
|
|
445
|
+
description: trans.__('The name of the chat to move')
|
|
435
446
|
}
|
|
436
447
|
},
|
|
437
448
|
requires: ['area', 'name']
|
|
@@ -454,9 +465,11 @@ const agentManagerFactory = SecretsManager.sign(SECRETS_NAMESPACE, token => ({
|
|
|
454
465
|
ICompletionProviderManager,
|
|
455
466
|
ILayoutRestorer,
|
|
456
467
|
ISecretsManager,
|
|
457
|
-
IThemeManager
|
|
468
|
+
IThemeManager,
|
|
469
|
+
ITranslator
|
|
458
470
|
],
|
|
459
|
-
activate: (app, settingsModel, providerRegistry, palette, completionManager, restorer, secretsManager, themeManager) => {
|
|
471
|
+
activate: (app, settingsModel, providerRegistry, palette, completionManager, restorer, secretsManager, themeManager, translator) => {
|
|
472
|
+
const trans = (translator ?? nullTranslator).load('jupyterlite_ai');
|
|
460
473
|
const agentManagerFactory = new AgentManagerFactory({
|
|
461
474
|
settingsModel,
|
|
462
475
|
secretsManager,
|
|
@@ -469,7 +482,8 @@ const agentManagerFactory = SecretsManager.sign(SECRETS_NAMESPACE, token => ({
|
|
|
469
482
|
themeManager,
|
|
470
483
|
providerRegistry,
|
|
471
484
|
secretsManager,
|
|
472
|
-
token
|
|
485
|
+
token,
|
|
486
|
+
trans
|
|
473
487
|
});
|
|
474
488
|
settingsWidget.id = 'jupyterlite-ai-settings';
|
|
475
489
|
settingsWidget.title.icon = settingsIcon;
|
|
@@ -491,8 +505,8 @@ const agentManagerFactory = SecretsManager.sign(SECRETS_NAMESPACE, token => ({
|
|
|
491
505
|
restorer.add(settingsWidget, settingsWidget.id);
|
|
492
506
|
}
|
|
493
507
|
app.commands.addCommand(CommandIds.openSettings, {
|
|
494
|
-
label: 'AI Settings',
|
|
495
|
-
caption: 'Configure AI providers and behavior',
|
|
508
|
+
label: trans.__('AI Settings'),
|
|
509
|
+
caption: trans.__('Configure AI providers and behavior'),
|
|
496
510
|
icon: settingsIcon,
|
|
497
511
|
iconClass: 'jp-ai-settings-icon',
|
|
498
512
|
execute: () => {
|
|
@@ -515,7 +529,7 @@ const agentManagerFactory = SecretsManager.sign(SECRETS_NAMESPACE, token => ({
|
|
|
515
529
|
if (palette) {
|
|
516
530
|
palette.addItem({
|
|
517
531
|
command: CommandIds.openSettings,
|
|
518
|
-
category: 'AI Assistant'
|
|
532
|
+
category: trans.__('AI Assistant')
|
|
519
533
|
});
|
|
520
534
|
}
|
|
521
535
|
return agentManagerFactory;
|
|
@@ -612,11 +626,13 @@ const inputToolbarFactory = {
|
|
|
612
626
|
autoStart: true,
|
|
613
627
|
provides: IInputToolbarRegistryFactory,
|
|
614
628
|
requires: [IAISettingsModel, IToolRegistry],
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
const
|
|
618
|
-
const
|
|
619
|
-
const
|
|
629
|
+
optional: [ITranslator],
|
|
630
|
+
activate: (app, settingsModel, toolRegistry, translator) => {
|
|
631
|
+
const trans = (translator ?? nullTranslator).load('jupyterlite_ai');
|
|
632
|
+
const stopButton = stopItem(trans);
|
|
633
|
+
const clearButton = clearItem(trans);
|
|
634
|
+
const toolSelectButton = createToolSelectItem(toolRegistry, settingsModel.config.toolsEnabled, trans);
|
|
635
|
+
const modelSelectButton = createModelSelectItem(settingsModel, trans);
|
|
620
636
|
return {
|
|
621
637
|
create() {
|
|
622
638
|
const inputToolbarRegistry = InputToolbarRegistry.defaultToolbarRegistry();
|
|
@@ -644,12 +660,16 @@ const completionStatus = {
|
|
|
644
660
|
description: 'The completion status displayed in the status bar',
|
|
645
661
|
autoStart: true,
|
|
646
662
|
requires: [IAISettingsModel],
|
|
647
|
-
optional: [IStatusBar],
|
|
648
|
-
activate: (app, settingsModel, statusBar) => {
|
|
663
|
+
optional: [IStatusBar, ITranslator],
|
|
664
|
+
activate: (app, settingsModel, statusBar, translator) => {
|
|
649
665
|
if (!statusBar) {
|
|
650
666
|
return;
|
|
651
667
|
}
|
|
652
|
-
const
|
|
668
|
+
const trans = (translator ?? nullTranslator).load('jupyterlite_ai');
|
|
669
|
+
const item = new CompletionStatusWidget({
|
|
670
|
+
settingsModel,
|
|
671
|
+
translator: trans
|
|
672
|
+
});
|
|
653
673
|
statusBar?.registerStatusItem('completionState', {
|
|
654
674
|
item,
|
|
655
675
|
align: 'right',
|
|
@@ -2,7 +2,7 @@ import { VDomModel } from '@jupyterlab/ui-components';
|
|
|
2
2
|
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
3
3
|
export interface IProviderParameters {
|
|
4
4
|
temperature?: number;
|
|
5
|
-
|
|
5
|
+
maxOutputTokens?: number;
|
|
6
6
|
maxTurns?: number;
|
|
7
7
|
supportsFillInMiddle?: boolean;
|
|
8
8
|
useFilterText?: boolean;
|