@jupyterlite/ai 0.14.0 → 0.15.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/agent.d.ts +28 -114
- package/lib/agent.js +140 -100
- package/lib/chat-model-handler.d.ts +9 -11
- package/lib/chat-model-handler.js +9 -4
- package/lib/chat-model.d.ts +84 -13
- package/lib/chat-model.js +208 -136
- package/lib/completion/completion-provider.d.ts +2 -3
- package/lib/components/completion-status.d.ts +2 -2
- package/lib/components/model-select.d.ts +3 -3
- package/lib/components/save-button.d.ts +31 -0
- package/lib/components/save-button.js +41 -0
- package/lib/components/token-usage-display.d.ts +2 -3
- package/lib/components/tool-select.d.ts +3 -4
- package/lib/diff-manager.d.ts +2 -3
- package/lib/index.d.ts +2 -4
- package/lib/index.js +181 -23
- package/lib/models/settings-model.d.ts +11 -53
- package/lib/models/settings-model.js +37 -22
- package/lib/providers/built-in-providers.js +17 -36
- package/lib/tokens.d.ts +340 -36
- package/lib/tokens.js +11 -6
- package/lib/tools/commands.d.ts +2 -3
- package/lib/widgets/ai-settings.d.ts +3 -5
- package/lib/widgets/ai-settings.js +3 -0
- package/lib/widgets/main-area-chat.d.ts +2 -3
- package/lib/widgets/main-area-chat.js +9 -9
- package/lib/widgets/provider-config-dialog.d.ts +1 -2
- package/lib/widgets/provider-config-dialog.js +16 -29
- package/package.json +15 -9
- package/schema/settings-model.json +7 -1
- package/src/agent.ts +197 -242
- package/src/chat-model-handler.ts +25 -21
- package/src/chat-model.ts +304 -196
- package/src/completion/completion-provider.ts +7 -4
- package/src/components/completion-status.tsx +3 -3
- package/src/components/model-select.tsx +4 -3
- package/src/components/save-button.tsx +84 -0
- package/src/components/token-usage-display.tsx +2 -3
- package/src/components/tool-select.tsx +10 -4
- package/src/diff-manager.ts +4 -4
- package/src/index.ts +245 -49
- package/src/models/settings-model.ts +45 -88
- package/src/providers/built-in-providers.ts +17 -36
- package/src/tokens.ts +406 -52
- package/src/tools/commands.ts +2 -3
- package/src/widgets/ai-settings.tsx +27 -15
- package/src/widgets/main-area-chat.ts +15 -12
- package/src/widgets/provider-config-dialog.tsx +51 -56
- package/style/base.css +17 -195
- package/lib/approval-buttons.d.ts +0 -49
- package/lib/approval-buttons.js +0 -79
- package/src/approval-buttons.ts +0 -115
|
@@ -4,17 +4,16 @@ import { launchIcon } from '@jupyterlab/ui-components';
|
|
|
4
4
|
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
5
5
|
import { CommandRegistry } from '@lumino/commands';
|
|
6
6
|
|
|
7
|
-
import { ApprovalButtons } from '../approval-buttons';
|
|
8
7
|
import { AIChatModel } from '../chat-model';
|
|
8
|
+
import { SaveComponentWidget } from '../components/save-button';
|
|
9
9
|
import { TokenUsageWidget } from '../components/token-usage-display';
|
|
10
|
-
import { AISettingsModel } from '../models/settings-model';
|
|
11
10
|
import { RenderedMessageOutputAreaCompat } from '../rendered-message-outputarea';
|
|
12
|
-
import { CommandIds } from '../tokens';
|
|
11
|
+
import { CommandIds, type IAISettingsModel } from '../tokens';
|
|
13
12
|
|
|
14
13
|
export namespace MainAreaChat {
|
|
15
14
|
export interface IOptions extends MainAreaWidget.IOptions<ChatWidget> {
|
|
16
15
|
commands: CommandRegistry;
|
|
17
|
-
settingsModel:
|
|
16
|
+
settingsModel: IAISettingsModel;
|
|
18
17
|
trans: TranslationBundle;
|
|
19
18
|
}
|
|
20
19
|
}
|
|
@@ -29,7 +28,7 @@ export class MainAreaChat extends MainAreaWidget<ChatWidget> {
|
|
|
29
28
|
|
|
30
29
|
const { trans } = options;
|
|
31
30
|
|
|
32
|
-
//
|
|
31
|
+
// Move to side button.
|
|
33
32
|
this.toolbar.addItem(
|
|
34
33
|
'moveToSide',
|
|
35
34
|
new CommandToolbarButton({
|
|
@@ -43,6 +42,17 @@ export class MainAreaChat extends MainAreaWidget<ChatWidget> {
|
|
|
43
42
|
})
|
|
44
43
|
);
|
|
45
44
|
|
|
45
|
+
if (this.model.saveAvailable) {
|
|
46
|
+
// Save chat component
|
|
47
|
+
this.toolbar.addItem(
|
|
48
|
+
'saveChat',
|
|
49
|
+
new SaveComponentWidget({
|
|
50
|
+
model: this.model,
|
|
51
|
+
translator: trans
|
|
52
|
+
})
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
46
56
|
// Add the token usage button.
|
|
47
57
|
const tokenUsageWidget = new TokenUsageWidget({
|
|
48
58
|
tokenUsageChanged: this.model.tokenUsageChanged,
|
|
@@ -52,11 +62,6 @@ export class MainAreaChat extends MainAreaWidget<ChatWidget> {
|
|
|
52
62
|
});
|
|
53
63
|
this.toolbar.addItem('token-usage', tokenUsageWidget);
|
|
54
64
|
|
|
55
|
-
// Add the approval button, tied to the chat widget.
|
|
56
|
-
this._approvalButtons = new ApprovalButtons({
|
|
57
|
-
chatPanel: this.content,
|
|
58
|
-
agentManager: this.model.agentManager
|
|
59
|
-
});
|
|
60
65
|
// Temporary compat: keep output-area CSS context for MIME renderers
|
|
61
66
|
// until jupyter-chat provides it natively.
|
|
62
67
|
this._outputAreaCompat = new RenderedMessageOutputAreaCompat({
|
|
@@ -69,7 +74,6 @@ export class MainAreaChat extends MainAreaWidget<ChatWidget> {
|
|
|
69
74
|
dispose(): void {
|
|
70
75
|
super.dispose();
|
|
71
76
|
// Dispose of the approval buttons widget when the chat is disposed.
|
|
72
|
-
this._approvalButtons.dispose();
|
|
73
77
|
this._outputAreaCompat.dispose();
|
|
74
78
|
this.model.writersChanged.disconnect(this._writersChanged);
|
|
75
79
|
}
|
|
@@ -103,6 +107,5 @@ export class MainAreaChat extends MainAreaWidget<ChatWidget> {
|
|
|
103
107
|
}
|
|
104
108
|
};
|
|
105
109
|
|
|
106
|
-
private _approvalButtons: ApprovalButtons;
|
|
107
110
|
private _outputAreaCompat: RenderedMessageOutputAreaCompat;
|
|
108
111
|
}
|
|
@@ -31,8 +31,12 @@ import {
|
|
|
31
31
|
} from '@mui/material';
|
|
32
32
|
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
33
33
|
import React from 'react';
|
|
34
|
-
import {
|
|
35
|
-
|
|
34
|
+
import type {
|
|
35
|
+
IProviderConfig,
|
|
36
|
+
IProviderParameters,
|
|
37
|
+
IProviderRegistry,
|
|
38
|
+
IProviderToolCapabilities
|
|
39
|
+
} from '../tokens';
|
|
36
40
|
|
|
37
41
|
/**
|
|
38
42
|
* Default parameter values for provider configuration
|
|
@@ -187,7 +191,6 @@ export const ProviderConfigDialog: React.FC<IProviderConfigDialogProps> = ({
|
|
|
187
191
|
label: info.name,
|
|
188
192
|
models: info.defaultModels,
|
|
189
193
|
apiKeyRequirement: info.apiKeyRequirement,
|
|
190
|
-
allowCustomModel: id === 'generic', // Generic allows custom models
|
|
191
194
|
supportsBaseURL: info.supportsBaseURL,
|
|
192
195
|
description: info.description,
|
|
193
196
|
baseUrls: info.baseUrls
|
|
@@ -200,9 +203,14 @@ export const ProviderConfigDialog: React.FC<IProviderConfigDialogProps> = ({
|
|
|
200
203
|
React.useEffect(() => {
|
|
201
204
|
if (open) {
|
|
202
205
|
// Reset form when dialog opens
|
|
206
|
+
const initialProvider = initialConfig?.provider || 'anthropic';
|
|
207
|
+
const initialProviderInfo =
|
|
208
|
+
providerRegistry.getProviderInfo(initialProvider);
|
|
203
209
|
setName(initialConfig?.name || '');
|
|
204
|
-
setProvider(
|
|
205
|
-
setModel(
|
|
210
|
+
setProvider(initialProvider);
|
|
211
|
+
setModel(
|
|
212
|
+
initialConfig?.model || initialProviderInfo?.defaultModels[0] || ''
|
|
213
|
+
);
|
|
206
214
|
setApiKey(initialConfig?.apiKey || '');
|
|
207
215
|
setBaseURL(initialConfig?.baseURL || '');
|
|
208
216
|
setParameters(initialConfig?.parameters || {});
|
|
@@ -215,14 +223,7 @@ export const ProviderConfigDialog: React.FC<IProviderConfigDialogProps> = ({
|
|
|
215
223
|
setDomainInputs(createEmptyDomainInputs());
|
|
216
224
|
setExpandedAdvanced(false);
|
|
217
225
|
}
|
|
218
|
-
}, [open, initialConfig]);
|
|
219
|
-
|
|
220
|
-
React.useEffect(() => {
|
|
221
|
-
// Auto-select first model when provider changes
|
|
222
|
-
if (selectedProvider && selectedProvider.models.length > 0 && !model) {
|
|
223
|
-
setModel(selectedProvider.models[0]);
|
|
224
|
-
}
|
|
225
|
-
}, [provider, selectedProvider, model]);
|
|
226
|
+
}, [open, initialConfig, providerRegistry]);
|
|
226
227
|
|
|
227
228
|
const handleRef = React.useCallback(
|
|
228
229
|
(node: HTMLInputElement | null) => {
|
|
@@ -233,6 +234,15 @@ export const ProviderConfigDialog: React.FC<IProviderConfigDialogProps> = ({
|
|
|
233
234
|
[provider, handleSecretField, open]
|
|
234
235
|
);
|
|
235
236
|
|
|
237
|
+
const handleProviderChange = React.useCallback(
|
|
238
|
+
(newProvider: IProviderConfig['provider']) => {
|
|
239
|
+
const newProviderInfo = providerRegistry.getProviderInfo(newProvider);
|
|
240
|
+
setProvider(newProvider);
|
|
241
|
+
setModel(newProviderInfo?.defaultModels[0] || '');
|
|
242
|
+
},
|
|
243
|
+
[providerRegistry]
|
|
244
|
+
);
|
|
245
|
+
|
|
236
246
|
const updateCustomSetting = React.useCallback(
|
|
237
247
|
(section: 'webSearch' | 'webFetch', key: string, value: unknown) => {
|
|
238
248
|
setCustomSettings(prev => {
|
|
@@ -450,7 +460,9 @@ export const ProviderConfigDialog: React.FC<IProviderConfigDialogProps> = ({
|
|
|
450
460
|
value={provider}
|
|
451
461
|
label={trans.__('Provider Type')}
|
|
452
462
|
onChange={e =>
|
|
453
|
-
|
|
463
|
+
handleProviderChange(
|
|
464
|
+
e.target.value as IProviderConfig['provider']
|
|
465
|
+
)
|
|
454
466
|
}
|
|
455
467
|
>
|
|
456
468
|
{providerOptions.map(option => (
|
|
@@ -478,49 +490,32 @@ export const ProviderConfigDialog: React.FC<IProviderConfigDialogProps> = ({
|
|
|
478
490
|
</Select>
|
|
479
491
|
</FormControl>
|
|
480
492
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
<
|
|
495
|
-
|
|
493
|
+
<Autocomplete
|
|
494
|
+
freeSolo
|
|
495
|
+
fullWidth
|
|
496
|
+
options={selectedProvider?.models ?? []}
|
|
497
|
+
value={model}
|
|
498
|
+
onChange={(_, value) => {
|
|
499
|
+
setModel(typeof value === 'string' ? value : '');
|
|
500
|
+
}}
|
|
501
|
+
inputValue={model}
|
|
502
|
+
onInputChange={(_, value) => {
|
|
503
|
+
setModel(value);
|
|
504
|
+
}}
|
|
505
|
+
renderInput={params => (
|
|
506
|
+
<TextField
|
|
507
|
+
{...params}
|
|
508
|
+
fullWidth
|
|
496
509
|
label={trans.__('Model')}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
{
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
: modelOption.includes('opus')
|
|
507
|
-
? trans.__('Advanced reasoning')
|
|
508
|
-
: modelOption.includes('haiku')
|
|
509
|
-
? trans.__('Fast and lightweight')
|
|
510
|
-
: modelOption.includes('large')
|
|
511
|
-
? trans.__('Most capable model')
|
|
512
|
-
: modelOption.includes('small')
|
|
513
|
-
? trans.__('Fast and efficient')
|
|
514
|
-
: modelOption.includes('codestral')
|
|
515
|
-
? trans.__('Code-specialized')
|
|
516
|
-
: trans.__('General purpose')}
|
|
517
|
-
</Typography>
|
|
518
|
-
</Box>
|
|
519
|
-
</MenuItem>
|
|
520
|
-
))}
|
|
521
|
-
</Select>
|
|
522
|
-
</FormControl>
|
|
523
|
-
)}
|
|
510
|
+
placeholder={trans.__('Select or type a model ID')}
|
|
511
|
+
required
|
|
512
|
+
helperText={trans.__(
|
|
513
|
+
'Choose from the list or enter a custom model ID'
|
|
514
|
+
)}
|
|
515
|
+
/>
|
|
516
|
+
)}
|
|
517
|
+
clearOnBlur={false}
|
|
518
|
+
/>
|
|
524
519
|
|
|
525
520
|
{selectedProvider &&
|
|
526
521
|
selectedProvider?.apiKeyRequirement !== 'none' && (
|
package/style/base.css
CHANGED
|
@@ -88,164 +88,6 @@
|
|
|
88
88
|
border-bottom: none;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
/* Modern Tool Call Card Styling */
|
|
92
|
-
.jp-ai-tool-call {
|
|
93
|
-
margin: 8px 0;
|
|
94
|
-
border: 1px solid var(--jp-border-color1);
|
|
95
|
-
border-radius: 6px;
|
|
96
|
-
background: var(--jp-layout-color0);
|
|
97
|
-
box-shadow: var(--jp-elevation-z2);
|
|
98
|
-
transition: all 0.2s ease;
|
|
99
|
-
overflow: hidden;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.jp-ai-tool-call:hover {
|
|
103
|
-
border-color: var(--jp-border-color2);
|
|
104
|
-
box-shadow: var(--jp-elevation-z4);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/* Tool Header - clickable summary */
|
|
108
|
-
.jp-ai-tool-header {
|
|
109
|
-
display: flex;
|
|
110
|
-
align-items: center;
|
|
111
|
-
padding: 4px 8px;
|
|
112
|
-
background: var(--jp-layout-color1);
|
|
113
|
-
cursor: pointer;
|
|
114
|
-
user-select: none;
|
|
115
|
-
gap: 8px;
|
|
116
|
-
transition: background-color 0.2s ease;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
.jp-ai-tool-header:hover {
|
|
120
|
-
background: var(--jp-layout-color2);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
.jp-ai-tool-header::marker {
|
|
124
|
-
content: '';
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
.jp-ai-tool-header::before {
|
|
128
|
-
content: '';
|
|
129
|
-
width: 0;
|
|
130
|
-
height: 0;
|
|
131
|
-
border-left: 5px solid var(--jp-ui-font-color2);
|
|
132
|
-
border-top: 3px solid transparent;
|
|
133
|
-
border-bottom: 3px solid transparent;
|
|
134
|
-
transition: transform 0.2s ease;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
.jp-ai-tool-call[open] .jp-ai-tool-header::before {
|
|
138
|
-
transform: rotate(90deg);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
.jp-ai-tool-icon {
|
|
142
|
-
font-size: 14px;
|
|
143
|
-
opacity: 0.8;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
.jp-ai-tool-title {
|
|
147
|
-
font-family: var(--jp-ui-font-family);
|
|
148
|
-
font-size: var(--jp-ui-font-size1);
|
|
149
|
-
font-weight: 500;
|
|
150
|
-
color: var(--jp-ui-font-color1);
|
|
151
|
-
flex: 1;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
.jp-ai-tool-summary {
|
|
155
|
-
font-weight: 400;
|
|
156
|
-
opacity: 0.7;
|
|
157
|
-
font-size: var(--jp-ui-font-size0);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
.jp-ai-tool-summary::before {
|
|
161
|
-
content: ' ';
|
|
162
|
-
white-space: pre;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
.jp-ai-tool-status {
|
|
166
|
-
font-size: var(--jp-ui-font-size0);
|
|
167
|
-
font-weight: 500;
|
|
168
|
-
padding: 2px 6px;
|
|
169
|
-
border-radius: 3px;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
.jp-ai-tool-status-pending {
|
|
173
|
-
background: rgb(var(--jp-warn-color1-rgb) / 15%);
|
|
174
|
-
color: var(--jp-warn-color1);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
.jp-ai-tool-status-completed {
|
|
178
|
-
background: rgb(var(--jp-success-color1-rgb) / 15%);
|
|
179
|
-
color: var(--jp-success-color1);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
.jp-ai-tool-status-error {
|
|
183
|
-
background: rgb(var(--jp-error-color1-rgb) / 15%);
|
|
184
|
-
color: var(--jp-error-color1);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
.jp-ai-tool-status-approval {
|
|
188
|
-
background: rgb(var(--jp-warn-color1-rgb) / 15%);
|
|
189
|
-
color: var(--jp-warn-color1);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/* Tool Body */
|
|
193
|
-
.jp-ai-tool-body {
|
|
194
|
-
padding: 8px 12px 12px;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
.jp-ai-tool-section {
|
|
198
|
-
margin-bottom: 8px;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
.jp-ai-tool-section:last-child {
|
|
202
|
-
margin-bottom: 0;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
.jp-ai-tool-label {
|
|
206
|
-
font-family: var(--jp-ui-font-family);
|
|
207
|
-
font-size: var(--jp-ui-font-size0);
|
|
208
|
-
font-weight: 600;
|
|
209
|
-
color: var(--jp-ui-font-color2);
|
|
210
|
-
margin-bottom: 4px;
|
|
211
|
-
text-transform: uppercase;
|
|
212
|
-
letter-spacing: 0.5px;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
.jp-ai-tool-code {
|
|
216
|
-
background: var(--jp-layout-color2);
|
|
217
|
-
border: 1px solid var(--jp-border-color1);
|
|
218
|
-
border-radius: 4px;
|
|
219
|
-
padding: 8px;
|
|
220
|
-
margin: 0;
|
|
221
|
-
font-family: var(--jp-code-font-family);
|
|
222
|
-
font-size: var(--jp-code-font-size);
|
|
223
|
-
line-height: 1.4;
|
|
224
|
-
overflow: auto auto;
|
|
225
|
-
max-height: 200px;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
.jp-ai-tool-code code {
|
|
229
|
-
background: none;
|
|
230
|
-
padding: 0;
|
|
231
|
-
border: none;
|
|
232
|
-
font-family: inherit;
|
|
233
|
-
font-size: inherit;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/* State-specific styling */
|
|
237
|
-
.jp-ai-tool-pending {
|
|
238
|
-
border-left: 4px solid var(--jp-warn-color1);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
.jp-ai-tool-completed {
|
|
242
|
-
border-left: 4px solid var(--jp-success-color1);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
.jp-ai-tool-error {
|
|
246
|
-
border-left: 4px solid var(--jp-error-color1);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
91
|
.jp-AIChatToolbar {
|
|
250
92
|
display: flex;
|
|
251
93
|
flex-shrink: 0;
|
|
@@ -267,53 +109,33 @@
|
|
|
267
109
|
padding: 0 0.4em;
|
|
268
110
|
}
|
|
269
111
|
|
|
270
|
-
/*
|
|
271
|
-
.jp-ai-
|
|
272
|
-
.jp-ai-group-approval-buttons {
|
|
112
|
+
/* Save button */
|
|
113
|
+
.jp-ai-SaveButton {
|
|
273
114
|
display: flex;
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
.jp-ai-approval-btn {
|
|
280
|
-
padding: 6px 12px;
|
|
281
|
-
border: none;
|
|
115
|
+
align-items: center;
|
|
116
|
+
background-color: var(--jp-layout-color1);
|
|
117
|
+
border: 1px solid var(--jp-border-color1);
|
|
282
118
|
border-radius: 4px;
|
|
283
|
-
|
|
284
|
-
font-size: var(--jp-ui-font-size0);
|
|
285
|
-
font-weight: 500;
|
|
286
|
-
cursor: pointer;
|
|
287
|
-
transition: all 0.2s ease;
|
|
288
|
-
min-width: 70px;
|
|
289
|
-
display: inline-block;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
.jp-ai-approval-approve {
|
|
293
|
-
background: var(--jp-success-color1);
|
|
294
|
-
color: var(--jp-ui-inverse-font-color1);
|
|
119
|
+
padding: 4px;
|
|
295
120
|
}
|
|
296
121
|
|
|
297
|
-
.jp-ai-
|
|
298
|
-
|
|
299
|
-
transform: translateY(-1px);
|
|
300
|
-
box-shadow: var(--jp-elevation-z4);
|
|
122
|
+
.jp-ai-SaveButton.lm-mod-toggled {
|
|
123
|
+
box-shadow: inset 0 0 2px 2px var(--neutral-fill-strong-active);
|
|
301
124
|
}
|
|
302
125
|
|
|
303
|
-
.jp-ai-
|
|
304
|
-
|
|
305
|
-
|
|
126
|
+
.jp-ai-SaveButton .jp-ToolbarButtonComponent {
|
|
127
|
+
margin: unset;
|
|
128
|
+
height: 18px;
|
|
306
129
|
}
|
|
307
130
|
|
|
308
|
-
.jp-ai-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
box-shadow: var(--jp-elevation-z4);
|
|
131
|
+
.jp-ai-SaveButton .jp-ai-AutoSaveButton {
|
|
132
|
+
min-width: unset;
|
|
133
|
+
width: 18px;
|
|
312
134
|
}
|
|
313
135
|
|
|
314
|
-
.jp-ai-
|
|
315
|
-
|
|
316
|
-
|
|
136
|
+
.jp-ai-SaveButton .jp-ai-AutoSaveButton svg {
|
|
137
|
+
width: 12px;
|
|
138
|
+
height: 12px;
|
|
317
139
|
}
|
|
318
140
|
|
|
319
141
|
.jp-MainAreaWidget
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { ChatWidget } from '@jupyter/chat';
|
|
2
|
-
import { IDisposable } from '@lumino/disposable';
|
|
3
|
-
import type { AgentManager } from './agent';
|
|
4
|
-
/**
|
|
5
|
-
* Handles click events for approval buttons in the chat panel.
|
|
6
|
-
*/
|
|
7
|
-
export declare class ApprovalButtons implements IDisposable {
|
|
8
|
-
constructor(options: ApprovalButtons.IOptions);
|
|
9
|
-
get isDisposed(): boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Dispose of the resources held by the object.
|
|
12
|
-
*/
|
|
13
|
-
dispose(): void;
|
|
14
|
-
/**
|
|
15
|
-
* Handles click events using event delegation.
|
|
16
|
-
* Detects clicks on approval buttons and calls the appropriate handler.
|
|
17
|
-
*/
|
|
18
|
-
private _handleClick;
|
|
19
|
-
/**
|
|
20
|
-
* Handles approval/rejection of a tool call.
|
|
21
|
-
*/
|
|
22
|
-
private _handleApproval;
|
|
23
|
-
/**
|
|
24
|
-
* Extracts the approval ID from an element's class list.
|
|
25
|
-
* The ID is encoded in a class name like "jp-ai-approval-id--{id}".
|
|
26
|
-
*/
|
|
27
|
-
private _extractApprovalId;
|
|
28
|
-
private _chatPanel;
|
|
29
|
-
private _isDisposed;
|
|
30
|
-
private _agentManager;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Namespace for ApprovalButtons statics.
|
|
34
|
-
*/
|
|
35
|
-
export declare namespace ApprovalButtons {
|
|
36
|
-
/**
|
|
37
|
-
* The options for the constructor of the approval buttons.
|
|
38
|
-
*/
|
|
39
|
-
interface IOptions {
|
|
40
|
-
/**
|
|
41
|
-
* The chat panel widget to wrap.
|
|
42
|
-
*/
|
|
43
|
-
chatPanel: ChatWidget;
|
|
44
|
-
/**
|
|
45
|
-
* The agent manager for handling approvals.
|
|
46
|
-
*/
|
|
47
|
-
agentManager: AgentManager;
|
|
48
|
-
}
|
|
49
|
-
}
|
package/lib/approval-buttons.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Handles click events for approval buttons in the chat panel.
|
|
3
|
-
*/
|
|
4
|
-
export class ApprovalButtons {
|
|
5
|
-
constructor(options) {
|
|
6
|
-
this._chatPanel = options.chatPanel;
|
|
7
|
-
this._agentManager = options.agentManager;
|
|
8
|
-
this._chatPanel.node.addEventListener('click', this._handleClick);
|
|
9
|
-
}
|
|
10
|
-
get isDisposed() {
|
|
11
|
-
return this._isDisposed;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Dispose of the resources held by the object.
|
|
15
|
-
*/
|
|
16
|
-
dispose() {
|
|
17
|
-
if (this._isDisposed) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
this._isDisposed = true;
|
|
21
|
-
this._chatPanel.node.removeEventListener('click', this._handleClick);
|
|
22
|
-
this._chatPanel = null;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Handles click events using event delegation.
|
|
26
|
-
* Detects clicks on approval buttons and calls the appropriate handler.
|
|
27
|
-
*/
|
|
28
|
-
_handleClick = (event) => {
|
|
29
|
-
const target = event.target;
|
|
30
|
-
// Check if the click target is an approval button
|
|
31
|
-
if (!target.classList.contains('jp-ai-approval-btn')) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
event.preventDefault();
|
|
35
|
-
event.stopPropagation();
|
|
36
|
-
const isApprove = target.classList.contains('jp-ai-approval-approve');
|
|
37
|
-
this._handleApproval(target, isApprove);
|
|
38
|
-
};
|
|
39
|
-
/**
|
|
40
|
-
* Handles approval/rejection of a tool call.
|
|
41
|
-
*/
|
|
42
|
-
_handleApproval(target, isApprove) {
|
|
43
|
-
const container = target.closest('.jp-ai-tool-approval-buttons');
|
|
44
|
-
if (!container) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
// Extract approval ID from class name (encoded as jp-ai-approval-id--{id})
|
|
48
|
-
const approvalId = this._extractApprovalId(container);
|
|
49
|
-
if (!approvalId) {
|
|
50
|
-
console.warn('No approval ID found for button');
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
// Disable buttons to prevent double-clicks
|
|
54
|
-
const buttons = container.querySelectorAll('button');
|
|
55
|
-
buttons.forEach(btn => btn.setAttribute('disabled', 'true'));
|
|
56
|
-
if (isApprove) {
|
|
57
|
-
this._agentManager.approveToolCall(approvalId);
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
this._agentManager.rejectToolCall(approvalId);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Extracts the approval ID from an element's class list.
|
|
65
|
-
* The ID is encoded in a class name like "jp-ai-approval-id--{id}".
|
|
66
|
-
*/
|
|
67
|
-
_extractApprovalId(element) {
|
|
68
|
-
const prefix = 'jp-ai-approval-id--';
|
|
69
|
-
for (const className of element.classList) {
|
|
70
|
-
if (className.startsWith(prefix)) {
|
|
71
|
-
return className.slice(prefix.length);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
76
|
-
_chatPanel;
|
|
77
|
-
_isDisposed = false;
|
|
78
|
-
_agentManager;
|
|
79
|
-
}
|