@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
package/src/approval-buttons.ts
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { ChatWidget } from '@jupyter/chat';
|
|
2
2
|
import { IDisposable } from '@lumino/disposable';
|
|
3
|
-
import {
|
|
3
|
+
import type { AgentManager } from './agent';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Handles click events for approval buttons in the chat panel.
|
|
7
|
+
*/
|
|
5
8
|
export class ApprovalButtons implements IDisposable {
|
|
6
9
|
constructor(options: ApprovalButtons.IOptions) {
|
|
7
10
|
this._chatPanel = options.chatPanel;
|
|
8
|
-
this.
|
|
9
|
-
|
|
10
|
-
// Set up approval button event handling
|
|
11
|
-
this._setupApprovalHandlers();
|
|
11
|
+
this._agentManager = options.agentManager;
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
this._setupMessageProcessing();
|
|
13
|
+
this._chatPanel.node.addEventListener('click', this._handleClick);
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
get isDisposed(): boolean {
|
|
@@ -27,435 +26,90 @@ export class ApprovalButtons implements IDisposable {
|
|
|
27
26
|
}
|
|
28
27
|
this._isDisposed = true;
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
if (this._mutationObserver) {
|
|
32
|
-
this._mutationObserver.disconnect();
|
|
33
|
-
this._mutationObserver = undefined;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Remove all listener on existing buttons.
|
|
37
|
-
const existingButtons = this._chatPanel.node.querySelectorAll(
|
|
38
|
-
'.jp-ai-approval-btn'
|
|
39
|
-
);
|
|
40
|
-
existingButtons.forEach(button => {
|
|
41
|
-
button.removeEventListener('click', this._handleButtonClick);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
const existingGroupButtons = this._chatPanel.node.querySelectorAll(
|
|
45
|
-
'.jp-ai-group-approval-buttons button'
|
|
46
|
-
);
|
|
47
|
-
existingGroupButtons.forEach(button => {
|
|
48
|
-
button.removeEventListener('click', this._handleGroupedButtonClick);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// Clean the references.
|
|
52
|
-
this._chatModel = null!;
|
|
29
|
+
this._chatPanel.node.removeEventListener('click', this._handleClick);
|
|
53
30
|
this._chatPanel = null!;
|
|
54
31
|
}
|
|
55
32
|
|
|
56
33
|
/**
|
|
57
|
-
*
|
|
58
|
-
|
|
59
|
-
private _setupApprovalHandlers() {
|
|
60
|
-
// This method will be called to add handlers to existing buttons
|
|
61
|
-
// New buttons get handlers added in _processApprovalButtons
|
|
62
|
-
const existingButtons = this._chatPanel.node.querySelectorAll(
|
|
63
|
-
'.jp-ai-approval-btn'
|
|
64
|
-
);
|
|
65
|
-
existingButtons.forEach(button => {
|
|
66
|
-
this._addButtonHandler(button as HTMLButtonElement);
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Adds click event handler to an approval button.
|
|
72
|
-
*
|
|
73
|
-
* @param button - The button element to add handler to
|
|
74
|
-
*/
|
|
75
|
-
private _addButtonHandler(button: HTMLButtonElement) {
|
|
76
|
-
// Remove any existing listeners to avoid duplicates
|
|
77
|
-
button.removeEventListener('click', this._handleButtonClick);
|
|
78
|
-
button.addEventListener('click', this._handleButtonClick);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Handles click events for individual approval buttons.
|
|
83
|
-
*
|
|
84
|
-
* @param event - The click event
|
|
34
|
+
* Handles click events using event delegation.
|
|
35
|
+
* Detects clicks on approval buttons and calls the appropriate handler.
|
|
85
36
|
*/
|
|
86
|
-
private
|
|
37
|
+
private _handleClick = (event: Event): void => {
|
|
87
38
|
const target = event.target as HTMLElement;
|
|
88
|
-
event.preventDefault();
|
|
89
|
-
event.stopPropagation();
|
|
90
|
-
|
|
91
|
-
const buttonsContainer = target.closest('.jp-ai-tool-approval-buttons');
|
|
92
|
-
if (!buttonsContainer) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
39
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
);
|
|
99
|
-
if (!interruptionId) {
|
|
40
|
+
// Check if the click target is an approval button
|
|
41
|
+
if (!target.classList.contains('jp-ai-approval-btn')) {
|
|
100
42
|
return;
|
|
101
43
|
}
|
|
102
44
|
|
|
103
|
-
|
|
104
|
-
|
|
45
|
+
event.preventDefault();
|
|
46
|
+
event.stopPropagation();
|
|
105
47
|
|
|
106
|
-
// Hide buttons immediately and show status
|
|
107
48
|
const isApprove = target.classList.contains('jp-ai-approval-approve');
|
|
108
|
-
this.
|
|
109
|
-
|
|
110
|
-
if (isApprove) {
|
|
111
|
-
// Execute approval with message ID for updating the tool call box
|
|
112
|
-
await this._chatModel.approveToolCall(
|
|
113
|
-
interruptionId,
|
|
114
|
-
messageId || undefined
|
|
115
|
-
);
|
|
116
|
-
} else if (target.classList.contains('jp-ai-approval-reject')) {
|
|
117
|
-
// Execute rejection with message ID for updating the tool call box
|
|
118
|
-
await this._chatModel.rejectToolCall(
|
|
119
|
-
interruptionId,
|
|
120
|
-
messageId || undefined
|
|
121
|
-
);
|
|
122
|
-
}
|
|
49
|
+
this._handleApproval(target, isApprove);
|
|
123
50
|
};
|
|
124
51
|
|
|
125
52
|
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
* @param button - The button element to add handler to
|
|
129
|
-
*/
|
|
130
|
-
private _addGroupedButtonHandler(button: HTMLButtonElement) {
|
|
131
|
-
// Remove any existing listeners to avoid duplicates
|
|
132
|
-
button.removeEventListener('click', this._handleGroupedButtonClick);
|
|
133
|
-
button.addEventListener('click', this._handleGroupedButtonClick);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Handles click events for grouped approval buttons.
|
|
138
|
-
*
|
|
139
|
-
* @param event - The click event
|
|
53
|
+
* Handles approval/rejection of a tool call.
|
|
140
54
|
*/
|
|
141
|
-
private
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
event.stopPropagation();
|
|
145
|
-
|
|
146
|
-
const buttonsContainer = target.closest('.jp-ai-group-approval-buttons');
|
|
147
|
-
if (!buttonsContainer) {
|
|
55
|
+
private _handleApproval(target: HTMLElement, isApprove: boolean): void {
|
|
56
|
+
const container = target.closest('.jp-ai-tool-approval-buttons');
|
|
57
|
+
if (!container) {
|
|
148
58
|
return;
|
|
149
59
|
}
|
|
150
60
|
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (!groupId || !interruptionIdsStr) {
|
|
61
|
+
// Extract approval ID from class name (encoded as jp-ai-approval-id--{id})
|
|
62
|
+
const approvalId = this._extractApprovalId(container);
|
|
63
|
+
if (!approvalId) {
|
|
64
|
+
console.warn('No approval ID found for button');
|
|
156
65
|
return;
|
|
157
66
|
}
|
|
158
67
|
|
|
159
|
-
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
// Hide buttons immediately and show status
|
|
163
|
-
const isApprove = target.classList.contains('jp-ai-group-approve-all');
|
|
164
|
-
this._showGroupApprovalStatus(buttonsContainer, isApprove);
|
|
68
|
+
// Disable buttons to prevent double-clicks
|
|
69
|
+
const buttons = container.querySelectorAll('button');
|
|
70
|
+
buttons.forEach(btn => btn.setAttribute('disabled', 'true'));
|
|
165
71
|
|
|
166
72
|
if (isApprove) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
interruptionIds,
|
|
171
|
-
messageId || undefined
|
|
172
|
-
);
|
|
173
|
-
} else if (target.classList.contains('jp-ai-group-reject-all')) {
|
|
174
|
-
// Execute grouped rejection
|
|
175
|
-
await this._chatModel.rejectGroupedToolCalls(
|
|
176
|
-
groupId,
|
|
177
|
-
interruptionIds,
|
|
178
|
-
messageId || undefined
|
|
179
|
-
);
|
|
73
|
+
this._agentManager.approveToolCall(approvalId);
|
|
74
|
+
} else {
|
|
75
|
+
this._agentManager.rejectToolCall(approvalId);
|
|
180
76
|
}
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Shows approval status by replacing buttons with status indicator.
|
|
185
|
-
*
|
|
186
|
-
* @param buttonsContainer - The container element holding the buttons
|
|
187
|
-
* @param isApprove - Whether the action was approval or rejection
|
|
188
|
-
*/
|
|
189
|
-
private _showApprovalStatus(
|
|
190
|
-
buttonsContainer: Element,
|
|
191
|
-
isApprove: boolean
|
|
192
|
-
): void {
|
|
193
|
-
// Clear the container and add status indicator
|
|
194
|
-
buttonsContainer.innerHTML = '';
|
|
195
|
-
|
|
196
|
-
const statusDiv = document.createElement('div');
|
|
197
|
-
statusDiv.className = `jp-ai-approval-status ${isApprove ? 'jp-ai-approval-status-approved' : 'jp-ai-approval-status-rejected'}`;
|
|
198
|
-
|
|
199
|
-
const icon = document.createElement('span');
|
|
200
|
-
icon.className = 'jp-ai-approval-icon';
|
|
201
|
-
icon.textContent = isApprove ? '✅' : '❌';
|
|
202
|
-
|
|
203
|
-
const text = document.createElement('span');
|
|
204
|
-
text.textContent = isApprove ? 'Tools approved' : 'Tools rejected';
|
|
205
|
-
|
|
206
|
-
statusDiv.appendChild(icon);
|
|
207
|
-
statusDiv.appendChild(text);
|
|
208
|
-
buttonsContainer.appendChild(statusDiv);
|
|
209
77
|
}
|
|
210
78
|
|
|
211
79
|
/**
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
* @param buttonsContainer - The container element holding the buttons
|
|
215
|
-
* @param isApprove - Whether the action was approval or rejection
|
|
216
|
-
* @param toolCount - The number of tools that were approved/rejected
|
|
80
|
+
* Extracts the approval ID from an element's class list.
|
|
81
|
+
* The ID is encoded in a class name like "jp-ai-approval-id--{id}".
|
|
217
82
|
*/
|
|
218
|
-
private
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
buttonsContainer.innerHTML = '';
|
|
224
|
-
|
|
225
|
-
const statusDiv = document.createElement('div');
|
|
226
|
-
statusDiv.className = `jp-ai-group-approval-status ${isApprove ? 'jp-ai-group-approval-status-approved' : 'jp-ai-group-approval-status-rejected'}`;
|
|
227
|
-
|
|
228
|
-
const icon = document.createElement('span');
|
|
229
|
-
icon.className = 'jp-ai-approval-icon';
|
|
230
|
-
icon.textContent = isApprove ? '✅' : '❌';
|
|
231
|
-
|
|
232
|
-
const text = document.createElement('span');
|
|
233
|
-
text.textContent = isApprove ? 'Tools approved' : 'Tools rejected';
|
|
234
|
-
|
|
235
|
-
statusDiv.appendChild(icon);
|
|
236
|
-
statusDiv.appendChild(text);
|
|
237
|
-
buttonsContainer.appendChild(statusDiv);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Sets up mutation observer to watch for new messages and process approval buttons.
|
|
242
|
-
*/
|
|
243
|
-
private _setupMessageProcessing() {
|
|
244
|
-
// Use a MutationObserver to watch for new messages and process approval buttons
|
|
245
|
-
this._mutationObserver = new MutationObserver(mutations => {
|
|
246
|
-
if (this._isDisposed) {
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
mutations.forEach(mutation => {
|
|
250
|
-
mutation.addedNodes.forEach(node => {
|
|
251
|
-
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
252
|
-
const element = node as Element;
|
|
253
|
-
this._processApprovalButtons(element);
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
this._mutationObserver.observe(this._chatPanel.node, {
|
|
260
|
-
childList: true,
|
|
261
|
-
subtree: true
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Processes text nodes to replace approval button placeholders with actual button elements.
|
|
267
|
-
*
|
|
268
|
-
* @param element - The element to search for approval button placeholders
|
|
269
|
-
*/
|
|
270
|
-
private _processApprovalButtons(element: Element) {
|
|
271
|
-
// Find all text nodes that contain approval buttons and replace them with actual buttons
|
|
272
|
-
const walker = document.createTreeWalker(
|
|
273
|
-
element,
|
|
274
|
-
NodeFilter.SHOW_TEXT,
|
|
275
|
-
null
|
|
276
|
-
);
|
|
277
|
-
|
|
278
|
-
const textNodes: Text[] = [];
|
|
279
|
-
let node;
|
|
280
|
-
while ((node = walker.nextNode())) {
|
|
281
|
-
textNodes.push(node as Text);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
textNodes.forEach(textNode => {
|
|
285
|
-
const text = textNode.textContent || '';
|
|
286
|
-
|
|
287
|
-
// Handle single tool approval buttons [APPROVAL_BUTTONS:id]
|
|
288
|
-
const singleMatch = text.match(/\[APPROVAL_BUTTONS:([^\]]+)\]/);
|
|
289
|
-
if (singleMatch) {
|
|
290
|
-
this._createSingleApprovalButtons(textNode, singleMatch[1]);
|
|
291
|
-
return;
|
|
83
|
+
private _extractApprovalId(element: Element): string | null {
|
|
84
|
+
const prefix = 'jp-ai-approval-id--';
|
|
85
|
+
for (const className of element.classList) {
|
|
86
|
+
if (className.startsWith(prefix)) {
|
|
87
|
+
return className.slice(prefix.length);
|
|
292
88
|
}
|
|
293
|
-
|
|
294
|
-
// Handle grouped tool approval buttons [GROUP_APPROVAL_BUTTONS:groupId:id1,id2,id3]
|
|
295
|
-
const groupMatch = text.match(
|
|
296
|
-
/\[GROUP_APPROVAL_BUTTONS:([^:]+):([^\]]+)\]/
|
|
297
|
-
);
|
|
298
|
-
if (groupMatch) {
|
|
299
|
-
this._createGroupedApprovalButtons(
|
|
300
|
-
textNode,
|
|
301
|
-
groupMatch[1],
|
|
302
|
-
groupMatch[2]
|
|
303
|
-
);
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Creates an approval button element with appropriate styling and classes.
|
|
311
|
-
*
|
|
312
|
-
* @param text - The button text
|
|
313
|
-
* @param isApprove - Whether this is an approve or reject button
|
|
314
|
-
* @param additionalClasses - Additional CSS classes to add
|
|
315
|
-
* @returns The created button element
|
|
316
|
-
*/
|
|
317
|
-
private _createApprovalButton(
|
|
318
|
-
text: string,
|
|
319
|
-
isApprove: boolean,
|
|
320
|
-
additionalClasses: string = ''
|
|
321
|
-
): HTMLButtonElement {
|
|
322
|
-
const button = document.createElement('button');
|
|
323
|
-
const baseClass = isApprove
|
|
324
|
-
? 'jp-ai-approval-approve'
|
|
325
|
-
: 'jp-ai-approval-reject';
|
|
326
|
-
button.className = `jp-ai-approval-btn ${baseClass}${additionalClasses ? ' ' + additionalClasses : ''}`;
|
|
327
|
-
button.textContent = text;
|
|
328
|
-
return button;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* Creates and inserts approval buttons for a single tool call.
|
|
333
|
-
*
|
|
334
|
-
* @param textNode - The text node to replace with buttons
|
|
335
|
-
* @param interruptionId - The interruption ID for the tool call
|
|
336
|
-
*/
|
|
337
|
-
private _createSingleApprovalButtons(textNode: Text, interruptionId: string) {
|
|
338
|
-
// Create approval buttons for single tool
|
|
339
|
-
const buttonContainer = document.createElement('div');
|
|
340
|
-
buttonContainer.className = 'jp-ai-tool-approval-buttons';
|
|
341
|
-
buttonContainer.setAttribute('data-interruption-id', interruptionId);
|
|
342
|
-
|
|
343
|
-
// Try to find the message ID from the closest message container
|
|
344
|
-
const messageId = this._findMessageId(textNode);
|
|
345
|
-
if (messageId) {
|
|
346
|
-
buttonContainer.setAttribute('data-message-id', messageId);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
const approveBtn = this._createApprovalButton('Approve', true);
|
|
350
|
-
const rejectBtn = this._createApprovalButton('Reject', false);
|
|
351
|
-
|
|
352
|
-
// Add click handlers directly to the buttons
|
|
353
|
-
this._addButtonHandler(approveBtn);
|
|
354
|
-
this._addButtonHandler(rejectBtn);
|
|
355
|
-
|
|
356
|
-
buttonContainer.appendChild(approveBtn);
|
|
357
|
-
buttonContainer.appendChild(rejectBtn);
|
|
358
|
-
|
|
359
|
-
// Replace the text node with the button container
|
|
360
|
-
const parent = textNode.parentNode;
|
|
361
|
-
if (parent) {
|
|
362
|
-
parent.replaceChild(buttonContainer, textNode);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Creates and inserts approval buttons for grouped tool calls.
|
|
368
|
-
*
|
|
369
|
-
* @param textNode - The text node to replace with buttons
|
|
370
|
-
* @param groupId - The group ID for the tool calls
|
|
371
|
-
* @param interruptionIds - Comma-separated interruption IDs
|
|
372
|
-
*/
|
|
373
|
-
private _createGroupedApprovalButtons(
|
|
374
|
-
textNode: Text,
|
|
375
|
-
groupId: string,
|
|
376
|
-
interruptionIds: string
|
|
377
|
-
) {
|
|
378
|
-
// Create approval buttons for grouped tools
|
|
379
|
-
const buttonContainer = document.createElement('div');
|
|
380
|
-
buttonContainer.className = 'jp-ai-group-approval-buttons';
|
|
381
|
-
buttonContainer.setAttribute('data-group-id', groupId);
|
|
382
|
-
buttonContainer.setAttribute('data-interruption-ids', interruptionIds);
|
|
383
|
-
|
|
384
|
-
// Try to find the message ID from the closest message container
|
|
385
|
-
const messageId = this._findMessageId(textNode);
|
|
386
|
-
if (messageId) {
|
|
387
|
-
buttonContainer.setAttribute('data-message-id', messageId);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
const approveBtn = this._createApprovalButton(
|
|
391
|
-
'Approve',
|
|
392
|
-
true,
|
|
393
|
-
'jp-ai-group-approve-all'
|
|
394
|
-
);
|
|
395
|
-
const rejectBtn = this._createApprovalButton(
|
|
396
|
-
'Reject',
|
|
397
|
-
false,
|
|
398
|
-
'jp-ai-group-reject-all'
|
|
399
|
-
);
|
|
400
|
-
|
|
401
|
-
// Add click handlers for grouped approvals
|
|
402
|
-
this._addGroupedButtonHandler(approveBtn);
|
|
403
|
-
this._addGroupedButtonHandler(rejectBtn);
|
|
404
|
-
|
|
405
|
-
buttonContainer.appendChild(approveBtn);
|
|
406
|
-
buttonContainer.appendChild(rejectBtn);
|
|
407
|
-
|
|
408
|
-
// Replace the text node with the button container
|
|
409
|
-
const parent = textNode.parentNode;
|
|
410
|
-
if (parent) {
|
|
411
|
-
parent.replaceChild(buttonContainer, textNode);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* Finds the message ID by traversing up the DOM tree from a text node.
|
|
417
|
-
*
|
|
418
|
-
* @param textNode - The text node to start searching from
|
|
419
|
-
* @returns The message ID if found, null otherwise
|
|
420
|
-
*/
|
|
421
|
-
private _findMessageId(textNode: Text): string | null {
|
|
422
|
-
let messageElement = textNode.parentNode;
|
|
423
|
-
while (messageElement && messageElement !== document.body) {
|
|
424
|
-
if (messageElement.nodeType === Node.ELEMENT_NODE) {
|
|
425
|
-
const element = messageElement as Element;
|
|
426
|
-
// Look for common message container attributes or classes
|
|
427
|
-
const messageId =
|
|
428
|
-
element.getAttribute('data-message-id') ||
|
|
429
|
-
element.getAttribute('id') ||
|
|
430
|
-
element
|
|
431
|
-
.querySelector('[data-message-id]')
|
|
432
|
-
?.getAttribute('data-message-id');
|
|
433
|
-
if (messageId) {
|
|
434
|
-
return messageId;
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
messageElement = messageElement.parentNode;
|
|
438
89
|
}
|
|
439
90
|
return null;
|
|
440
91
|
}
|
|
441
92
|
|
|
442
93
|
private _chatPanel: ChatWidget;
|
|
443
|
-
private _chatModel: AIChatModel;
|
|
444
94
|
private _isDisposed: boolean = false;
|
|
445
|
-
private
|
|
95
|
+
private _agentManager: AgentManager;
|
|
446
96
|
}
|
|
447
97
|
|
|
448
98
|
/**
|
|
449
|
-
* Namespace for
|
|
99
|
+
* Namespace for ApprovalButtons statics.
|
|
450
100
|
*/
|
|
451
101
|
export namespace ApprovalButtons {
|
|
452
102
|
/**
|
|
453
|
-
* The options for the constructor of the
|
|
103
|
+
* The options for the constructor of the approval buttons.
|
|
454
104
|
*/
|
|
455
105
|
export interface IOptions {
|
|
456
106
|
/**
|
|
457
107
|
* The chat panel widget to wrap.
|
|
458
108
|
*/
|
|
459
109
|
chatPanel: ChatWidget;
|
|
110
|
+
/**
|
|
111
|
+
* The agent manager for handling approvals.
|
|
112
|
+
*/
|
|
113
|
+
agentManager: AgentManager;
|
|
460
114
|
}
|
|
461
115
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ActiveCellManager } from '@jupyter/chat';
|
|
2
|
+
import { TranslationBundle } from '@jupyterlab/translation';
|
|
2
3
|
import { AgentManagerFactory } from './agent';
|
|
3
4
|
import { AIChatModel } from './chat-model';
|
|
4
5
|
import { AISettingsModel } from './models/settings-model';
|
|
@@ -22,6 +23,7 @@ export class ChatModelRegistry implements IChatModelRegistry {
|
|
|
22
23
|
this._toolRegistry = options.toolRegistry;
|
|
23
24
|
this._providerRegistry = options.providerRegistry;
|
|
24
25
|
this._activeCellManager = options.activeCellManager;
|
|
26
|
+
this._trans = options.trans;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
createModel(
|
|
@@ -44,7 +46,8 @@ export class ChatModelRegistry implements IChatModelRegistry {
|
|
|
44
46
|
settingsModel: this._settingsModel,
|
|
45
47
|
agentManager,
|
|
46
48
|
activeCellManager: this._activeCellManager,
|
|
47
|
-
documentManager: this._docManager
|
|
49
|
+
documentManager: this._docManager,
|
|
50
|
+
trans: this._trans
|
|
48
51
|
});
|
|
49
52
|
|
|
50
53
|
// Set the name of the chat if not provided.
|
|
@@ -97,6 +100,7 @@ export class ChatModelRegistry implements IChatModelRegistry {
|
|
|
97
100
|
private _toolRegistry?: IToolRegistry;
|
|
98
101
|
private _providerRegistry?: IProviderRegistry;
|
|
99
102
|
private _activeCellManager?: ActiveCellManager;
|
|
103
|
+
private _trans: TranslationBundle;
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
export namespace ChatModelRegistry {
|
|
@@ -125,5 +129,9 @@ export namespace ChatModelRegistry {
|
|
|
125
129
|
* The active cell manager.
|
|
126
130
|
*/
|
|
127
131
|
activeCellManager: ActiveCellManager | undefined;
|
|
132
|
+
/**
|
|
133
|
+
* The application language translation bundle.
|
|
134
|
+
*/
|
|
135
|
+
trans: TranslationBundle;
|
|
128
136
|
}
|
|
129
137
|
}
|