@notebook-intelligence/notebook-intelligence 1.3.5 → 2.0.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 +1 -1
- package/lib/api.d.ts +3 -2
- package/lib/api.js +13 -2
- package/lib/chat-sidebar.d.ts +3 -1
- package/lib/chat-sidebar.js +365 -14
- package/lib/index.js +199 -1
- package/lib/tokens.d.ts +13 -0
- package/lib/tokens.js +5 -0
- package/package.json +1 -1
- package/src/api.ts +16 -1
- package/src/chat-sidebar.tsx +630 -19
- package/src/index.ts +252 -1
- package/src/tokens.ts +15 -0
- package/style/base.css +167 -3
package/README.md
CHANGED
|
@@ -157,7 +157,7 @@ Below is an example of a server configuration with SSE transport. For SSE transp
|
|
|
157
157
|
}
|
|
158
158
|
```
|
|
159
159
|
|
|
160
|
-
If you have multiple servers configured but you would like to disable some for a while, you can do so by using the `disabled` key. `servername2` will be
|
|
160
|
+
If you have multiple servers configured but you would like to disable some for a while, you can do so by using the `disabled` key. `servername2` will be disabled and not available in `@mcp` chat participant.
|
|
161
161
|
|
|
162
162
|
```json
|
|
163
163
|
"mcpServers": {
|
package/lib/api.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Signal } from '@lumino/signaling';
|
|
2
|
-
import { IChatCompletionResponseEmitter, IChatParticipant, IContextItem, ITelemetryEvent, RequestDataType } from './tokens';
|
|
2
|
+
import { IChatCompletionResponseEmitter, IChatParticipant, IContextItem, ITelemetryEvent, IToolSelections, RequestDataType } from './tokens';
|
|
3
3
|
export declare enum GitHubCopilotLoginStatus {
|
|
4
4
|
NotLoggedIn = "NOT_LOGGED_IN",
|
|
5
5
|
ActivatingDevice = "ACTIVATING_DEVICE",
|
|
@@ -18,6 +18,7 @@ export declare class NBIConfig {
|
|
|
18
18
|
get inlineCompletionModel(): any;
|
|
19
19
|
get usingGitHubCopilotModel(): boolean;
|
|
20
20
|
get storeGitHubAccessToken(): boolean;
|
|
21
|
+
get toolConfig(): any;
|
|
21
22
|
capabilities: any;
|
|
22
23
|
chatParticipants: IChatParticipant[];
|
|
23
24
|
changed: Signal<this, void>;
|
|
@@ -39,7 +40,7 @@ export declare class NBIAPI {
|
|
|
39
40
|
static fetchCapabilities(): Promise<void>;
|
|
40
41
|
static setConfig(config: any): Promise<void>;
|
|
41
42
|
static updateOllamaModelList(): Promise<void>;
|
|
42
|
-
static chatRequest(messageId: string, chatId: string, prompt: string, language: string, filename: string, additionalContext: IContextItem[], responseEmitter: IChatCompletionResponseEmitter): Promise<void>;
|
|
43
|
+
static chatRequest(messageId: string, chatId: string, prompt: string, language: string, filename: string, additionalContext: IContextItem[], chatMode: string, toolSelections: IToolSelections, responseEmitter: IChatCompletionResponseEmitter): Promise<void>;
|
|
43
44
|
static generateCode(chatId: string, prompt: string, prefix: string, suffix: string, existingCode: string, language: string, filename: string, responseEmitter: IChatCompletionResponseEmitter): Promise<void>;
|
|
44
45
|
static sendChatUserInput(messageId: string, data: any): Promise<void>;
|
|
45
46
|
static sendWebSocketMessage(messageId: string, messageType: RequestDataType, data: any): Promise<void>;
|
package/lib/api.js
CHANGED
|
@@ -42,6 +42,9 @@ export class NBIConfig {
|
|
|
42
42
|
get storeGitHubAccessToken() {
|
|
43
43
|
return this.capabilities.store_github_access_token === true;
|
|
44
44
|
}
|
|
45
|
+
get toolConfig() {
|
|
46
|
+
return this.capabilities.tool_config;
|
|
47
|
+
}
|
|
45
48
|
}
|
|
46
49
|
class NBIAPI {
|
|
47
50
|
static async initialize() {
|
|
@@ -167,7 +170,7 @@ class NBIAPI {
|
|
|
167
170
|
});
|
|
168
171
|
});
|
|
169
172
|
}
|
|
170
|
-
static async chatRequest(messageId, chatId, prompt, language, filename, additionalContext, responseEmitter) {
|
|
173
|
+
static async chatRequest(messageId, chatId, prompt, language, filename, additionalContext, chatMode, toolSelections, responseEmitter) {
|
|
171
174
|
this._messageReceived.connect((_, msg) => {
|
|
172
175
|
msg = JSON.parse(msg);
|
|
173
176
|
if (msg.id === messageId) {
|
|
@@ -177,7 +180,15 @@ class NBIAPI {
|
|
|
177
180
|
this._webSocket.send(JSON.stringify({
|
|
178
181
|
id: messageId,
|
|
179
182
|
type: RequestDataType.ChatRequest,
|
|
180
|
-
data: {
|
|
183
|
+
data: {
|
|
184
|
+
chatId,
|
|
185
|
+
prompt,
|
|
186
|
+
language,
|
|
187
|
+
filename,
|
|
188
|
+
additionalContext,
|
|
189
|
+
chatMode,
|
|
190
|
+
toolSelections
|
|
191
|
+
}
|
|
181
192
|
}));
|
|
182
193
|
}
|
|
183
194
|
static async generateCode(chatId, prompt, prefix, suffix, existingCode, language, filename, responseEmitter) {
|
package/lib/chat-sidebar.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { ReactWidget } from '@jupyterlab/apputils';
|
|
3
|
-
import { IActiveDocumentInfo, ICellContents, IContextItem, ITelemetryEmitter } from './tokens';
|
|
3
|
+
import { IActiveDocumentInfo, ICellContents, IContextItem, ITelemetryEmitter, IToolSelections } from './tokens';
|
|
4
4
|
import { JupyterFrontEnd } from '@jupyterlab/application';
|
|
5
5
|
export declare enum RunChatCompletionType {
|
|
6
6
|
Chat = 0,
|
|
@@ -21,6 +21,8 @@ export interface IRunChatCompletionRequest {
|
|
|
21
21
|
suffix?: string;
|
|
22
22
|
existingCode?: string;
|
|
23
23
|
additionalContext?: IContextItem[];
|
|
24
|
+
chatMode: string;
|
|
25
|
+
toolSelections?: IToolSelections;
|
|
24
26
|
}
|
|
25
27
|
export interface IChatSidebarOptions {
|
|
26
28
|
getActiveDocumentInfo: () => IActiveDocumentInfo;
|
package/lib/chat-sidebar.js
CHANGED
|
@@ -4,12 +4,13 @@ import { ReactWidget } from '@jupyterlab/apputils';
|
|
|
4
4
|
import { UUID } from '@lumino/coreutils';
|
|
5
5
|
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';
|
|
6
6
|
import { NBIAPI, GitHubCopilotLoginStatus } from './api';
|
|
7
|
-
import { BackendMessageType, ContextType, GITHUB_COPILOT_PROVIDER_ID, RequestDataType, ResponseStreamDataType, TelemetryEventType } from './tokens';
|
|
7
|
+
import { BackendMessageType, BuiltinToolsetType, ContextType, GITHUB_COPILOT_PROVIDER_ID, RequestDataType, ResponseStreamDataType, TelemetryEventType } from './tokens';
|
|
8
8
|
import { MarkdownRenderer } from './markdown-renderer';
|
|
9
9
|
import copySvgstr from '../style/icons/copy.svg';
|
|
10
10
|
import copilotSvgstr from '../style/icons/copilot.svg';
|
|
11
11
|
import copilotWarningSvgstr from '../style/icons/copilot-warning.svg';
|
|
12
|
-
import { VscSend, VscStopCircle, VscEye, VscEyeClosed, VscTriangleRight, VscTriangleDown, VscWarning } from 'react-icons/vsc';
|
|
12
|
+
import { VscSend, VscStopCircle, VscEye, VscEyeClosed, VscTriangleRight, VscTriangleDown, VscWarning, VscSettingsGear, VscPassFilled, VscTools, VscTrash } from 'react-icons/vsc';
|
|
13
|
+
import { MdOutlineCheckBoxOutlineBlank, MdCheckBox } from 'react-icons/md';
|
|
13
14
|
import { extractLLMGeneratedCode, isDarkTheme } from './utils';
|
|
14
15
|
const OPENAI_COMPATIBLE_CHAT_MODEL_ID = 'openai-compatible-chat-model';
|
|
15
16
|
const LITELLM_COMPATIBLE_CHAT_MODEL_ID = 'litellm-compatible-chat-model';
|
|
@@ -239,7 +240,9 @@ function ChatResponse(props) {
|
|
|
239
240
|
React.createElement("div", { className: "chat-message-from" },
|
|
240
241
|
((_a = msg.participant) === null || _a === void 0 ? void 0 : _a.iconPath) && (React.createElement("div", { className: `chat-message-from-icon ${((_b = msg.participant) === null || _b === void 0 ? void 0 : _b.id) === 'default' ? 'chat-message-from-icon-default' : ''} ${isDarkTheme() ? 'dark' : ''}` },
|
|
241
242
|
React.createElement("img", { src: msg.participant.iconPath }))),
|
|
242
|
-
React.createElement("div", { className: "chat-message-from-title" }, msg.from === 'user'
|
|
243
|
+
React.createElement("div", { className: "chat-message-from-title" }, msg.from === 'user'
|
|
244
|
+
? 'User'
|
|
245
|
+
: ((_c = msg.participant) === null || _c === void 0 ? void 0 : _c.name) || 'AI Assistant'),
|
|
243
246
|
React.createElement("div", { className: "chat-message-from-progress", style: { display: `${props.showGenerating ? 'visible' : 'none'}` } },
|
|
244
247
|
React.createElement("div", { className: "loading-ellipsis" }, "Generating"))),
|
|
245
248
|
React.createElement("div", { className: "chat-message-timestamp" }, timestamp)),
|
|
@@ -302,17 +305,24 @@ function ChatResponse(props) {
|
|
|
302
305
|
async function submitCompletionRequest(request, responseEmitter) {
|
|
303
306
|
switch (request.type) {
|
|
304
307
|
case RunChatCompletionType.Chat:
|
|
305
|
-
return NBIAPI.chatRequest(request.messageId, request.chatId, request.content, request.language || 'python', request.filename || 'Untitled.ipynb', request.additionalContext || [], responseEmitter);
|
|
308
|
+
return NBIAPI.chatRequest(request.messageId, request.chatId, request.content, request.language || 'python', request.filename || 'Untitled.ipynb', request.additionalContext || [], request.chatMode, request.toolSelections || {}, responseEmitter);
|
|
306
309
|
case RunChatCompletionType.ExplainThis:
|
|
307
310
|
case RunChatCompletionType.FixThis:
|
|
308
311
|
case RunChatCompletionType.ExplainThisOutput:
|
|
309
312
|
case RunChatCompletionType.TroubleshootThisOutput: {
|
|
310
|
-
return NBIAPI.chatRequest(request.messageId, request.chatId, request.content, request.language || 'python', request.filename || 'Untitled.ipynb', [], responseEmitter);
|
|
313
|
+
return NBIAPI.chatRequest(request.messageId, request.chatId, request.content, request.language || 'python', request.filename || 'Untitled.ipynb', [], 'ask', {}, responseEmitter);
|
|
311
314
|
}
|
|
312
315
|
case RunChatCompletionType.GenerateCode:
|
|
313
316
|
return NBIAPI.generateCode(request.chatId, request.content, request.prefix || '', request.suffix || '', request.existingCode || '', request.language || 'python', request.filename || 'Untitled.ipynb', responseEmitter);
|
|
314
317
|
}
|
|
315
318
|
}
|
|
319
|
+
function CheckBoxItem(props) {
|
|
320
|
+
const indent = props.indent || 0;
|
|
321
|
+
return (React.createElement(React.Fragment, null,
|
|
322
|
+
React.createElement("div", { className: `checkbox-item checkbox-item-indent-${indent}`, onClick: event => props.onClick(event) },
|
|
323
|
+
props.checked ? (React.createElement(MdCheckBox, { className: "checkbox-icon" })) : (React.createElement(MdOutlineCheckBoxOutlineBlank, { className: "checkbox-icon" })),
|
|
324
|
+
props.label)));
|
|
325
|
+
}
|
|
316
326
|
function SidebarComponent(props) {
|
|
317
327
|
const [chatMessages, setChatMessages] = useState([]);
|
|
318
328
|
const [prompt, setPrompt] = useState('');
|
|
@@ -336,8 +346,274 @@ function SidebarComponent(props) {
|
|
|
336
346
|
const [activeDocumentInfo, setActiveDocumentInfo] = useState(null);
|
|
337
347
|
const [currentFileContextTitle, setCurrentFileContextTitle] = useState('');
|
|
338
348
|
const telemetryEmitter = props.getTelemetryEmitter();
|
|
349
|
+
const [chatMode, setChatMode] = useState('ask');
|
|
350
|
+
const [toolSelectionTitle, setToolSelectionTitle] = useState('Tool selection');
|
|
351
|
+
const [selectedToolCount, setSelectedToolCount] = useState(0);
|
|
352
|
+
const [notebookExecuteToolSelected, setNotebookExecuteToolSelected] = useState(false);
|
|
353
|
+
const [toolConfig, setToolConfig] = useState({
|
|
354
|
+
builtinToolsets: [
|
|
355
|
+
{ id: BuiltinToolsetType.NotebookEdit, name: 'Notebook edit' },
|
|
356
|
+
{ id: BuiltinToolsetType.NotebookExecute, name: 'Notebook execute' }
|
|
357
|
+
],
|
|
358
|
+
mcpServers: [],
|
|
359
|
+
extensions: []
|
|
360
|
+
});
|
|
361
|
+
const [showModeTools, setShowModeTools] = useState(false);
|
|
362
|
+
const toolSelectionsInitial = {
|
|
363
|
+
builtinToolsets: [BuiltinToolsetType.NotebookEdit],
|
|
364
|
+
mcpServers: {},
|
|
365
|
+
extensions: {}
|
|
366
|
+
};
|
|
367
|
+
const toolSelectionsEmpty = {
|
|
368
|
+
builtinToolsets: [],
|
|
369
|
+
mcpServers: {},
|
|
370
|
+
extensions: {}
|
|
371
|
+
};
|
|
372
|
+
const [toolSelections, setToolSelections] = useState(toolSelectionsInitial);
|
|
373
|
+
const [hasExtensionTools, setHasExtensionTools] = useState(false);
|
|
374
|
+
NBIAPI.configChanged.connect(() => {
|
|
375
|
+
setToolConfig(NBIAPI.config.toolConfig);
|
|
376
|
+
});
|
|
377
|
+
useEffect(() => {
|
|
378
|
+
let hasTools = false;
|
|
379
|
+
for (const extension of toolConfig.extensions) {
|
|
380
|
+
if (extension.toolsets.length > 0) {
|
|
381
|
+
hasTools = true;
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
setHasExtensionTools(hasTools);
|
|
386
|
+
}, [toolConfig]);
|
|
387
|
+
useEffect(() => {
|
|
388
|
+
const builtinToolSelCount = toolSelections.builtinToolsets.length;
|
|
389
|
+
let mcpServerToolSelCount = 0;
|
|
390
|
+
let extensionToolSelCount = 0;
|
|
391
|
+
for (const serverId in toolSelections.mcpServers) {
|
|
392
|
+
const mcpServerTools = toolSelections.mcpServers[serverId];
|
|
393
|
+
mcpServerToolSelCount += mcpServerTools.length;
|
|
394
|
+
}
|
|
395
|
+
for (const extensionId in toolSelections.extensions) {
|
|
396
|
+
const extensionToolsets = toolSelections.extensions[extensionId];
|
|
397
|
+
for (const toolsetId in extensionToolsets) {
|
|
398
|
+
const toolsetTools = extensionToolsets[toolsetId];
|
|
399
|
+
extensionToolSelCount += toolsetTools.length;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
const typeCounts = [];
|
|
403
|
+
if (builtinToolSelCount > 0) {
|
|
404
|
+
typeCounts.push(`${builtinToolSelCount} built-in`);
|
|
405
|
+
}
|
|
406
|
+
if (mcpServerToolSelCount > 0) {
|
|
407
|
+
typeCounts.push(`${mcpServerToolSelCount} mcp`);
|
|
408
|
+
}
|
|
409
|
+
if (extensionToolSelCount > 0) {
|
|
410
|
+
typeCounts.push(`${extensionToolSelCount} ext`);
|
|
411
|
+
}
|
|
412
|
+
setSelectedToolCount(builtinToolSelCount + mcpServerToolSelCount + extensionToolSelCount);
|
|
413
|
+
setNotebookExecuteToolSelected(toolSelections.builtinToolsets.includes(BuiltinToolsetType.NotebookExecute));
|
|
414
|
+
setToolSelectionTitle(typeCounts.length === 0
|
|
415
|
+
? 'Tool selection'
|
|
416
|
+
: `Tool selection (${typeCounts.join(', ')})`);
|
|
417
|
+
}, [toolSelections]);
|
|
418
|
+
const onClearToolsButtonClicked = () => {
|
|
419
|
+
setToolSelections(toolSelectionsEmpty);
|
|
420
|
+
};
|
|
421
|
+
const getBuiltinToolsetState = (toolsetName) => {
|
|
422
|
+
return toolSelections.builtinToolsets.includes(toolsetName);
|
|
423
|
+
};
|
|
424
|
+
const setBuiltinToolsetState = (toolsetName, enabled) => {
|
|
425
|
+
const newConfig = { ...toolSelections };
|
|
426
|
+
if (enabled) {
|
|
427
|
+
if (!toolSelections.builtinToolsets.includes(toolsetName)) {
|
|
428
|
+
newConfig.builtinToolsets.push(toolsetName);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
const index = newConfig.builtinToolsets.indexOf(toolsetName);
|
|
433
|
+
if (index !== -1) {
|
|
434
|
+
newConfig.builtinToolsets.splice(index, 1);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
setToolSelections(newConfig);
|
|
438
|
+
};
|
|
439
|
+
const anyMCPServerToolSelected = (id) => {
|
|
440
|
+
if (!(id in toolSelections.mcpServers)) {
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
return toolSelections.mcpServers[id].length > 0;
|
|
444
|
+
};
|
|
445
|
+
const getMCPServerState = (id) => {
|
|
446
|
+
if (!(id in toolSelections.mcpServers)) {
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
const mcpServer = toolConfig.mcpServers.find(server => server.id === id);
|
|
450
|
+
const selectedServerTools = toolSelections.mcpServers[id];
|
|
451
|
+
for (const tool of mcpServer.tools) {
|
|
452
|
+
if (!selectedServerTools.includes(tool)) {
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return true;
|
|
457
|
+
};
|
|
458
|
+
const onMCPServerClicked = (id) => {
|
|
459
|
+
if (anyMCPServerToolSelected(id)) {
|
|
460
|
+
const newConfig = { ...toolSelections };
|
|
461
|
+
delete newConfig.mcpServers[id];
|
|
462
|
+
setToolSelections(newConfig);
|
|
463
|
+
}
|
|
464
|
+
else {
|
|
465
|
+
const mcpServer = toolConfig.mcpServers.find(server => server.id === id);
|
|
466
|
+
const newConfig = { ...toolSelections };
|
|
467
|
+
newConfig.mcpServers[id] = structuredClone(mcpServer.tools);
|
|
468
|
+
setToolSelections(newConfig);
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
const getMCPServerToolState = (serverId, toolId) => {
|
|
472
|
+
if (!(serverId in toolSelections.mcpServers)) {
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
const selectedServerTools = toolSelections.mcpServers[serverId];
|
|
476
|
+
return selectedServerTools.includes(toolId);
|
|
477
|
+
};
|
|
478
|
+
const setMCPServerToolState = (serverId, toolId, checked) => {
|
|
479
|
+
const newConfig = { ...toolSelections };
|
|
480
|
+
if (checked && !(serverId in newConfig.mcpServers)) {
|
|
481
|
+
newConfig.mcpServers[serverId] = [];
|
|
482
|
+
}
|
|
483
|
+
const selectedServerTools = newConfig.mcpServers[serverId];
|
|
484
|
+
if (checked) {
|
|
485
|
+
selectedServerTools.push(toolId);
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
const index = selectedServerTools.indexOf(toolId);
|
|
489
|
+
if (index !== -1) {
|
|
490
|
+
selectedServerTools.splice(index, 1);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
setToolSelections(newConfig);
|
|
494
|
+
};
|
|
495
|
+
// all toolsets and tools of the extension are selected
|
|
496
|
+
const getExtensionState = (extensionId) => {
|
|
497
|
+
if (!(extensionId in toolSelections.extensions)) {
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
const extension = toolConfig.extensions.find(extension => extension.id === extensionId);
|
|
501
|
+
for (const toolset of extension.toolsets) {
|
|
502
|
+
if (!getExtensionToolsetState(extensionId, toolset.id)) {
|
|
503
|
+
return false;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
return true;
|
|
507
|
+
};
|
|
508
|
+
const getExtensionToolsetState = (extensionId, toolsetId) => {
|
|
509
|
+
if (!(extensionId in toolSelections.extensions)) {
|
|
510
|
+
return false;
|
|
511
|
+
}
|
|
512
|
+
if (!(toolsetId in toolSelections.extensions[extensionId])) {
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
const extension = toolConfig.extensions.find(ext => ext.id === extensionId);
|
|
516
|
+
const extensionToolset = extension.toolsets.find((toolset) => toolset.id === toolsetId);
|
|
517
|
+
const selectedToolsetTools = toolSelections.extensions[extensionId][toolsetId];
|
|
518
|
+
for (const tool of extensionToolset.tools) {
|
|
519
|
+
if (!selectedToolsetTools.includes(tool)) {
|
|
520
|
+
return false;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return true;
|
|
524
|
+
};
|
|
525
|
+
const anyExtensionToolsetSelected = (extensionId) => {
|
|
526
|
+
if (!(extensionId in toolSelections.extensions)) {
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
529
|
+
return Object.keys(toolSelections.extensions[extensionId]).length > 0;
|
|
530
|
+
};
|
|
531
|
+
const onExtensionClicked = (extensionId) => {
|
|
532
|
+
if (anyExtensionToolsetSelected(extensionId)) {
|
|
533
|
+
const newConfig = { ...toolSelections };
|
|
534
|
+
delete newConfig.extensions[extensionId];
|
|
535
|
+
setToolSelections(newConfig);
|
|
536
|
+
}
|
|
537
|
+
else {
|
|
538
|
+
const newConfig = { ...toolSelections };
|
|
539
|
+
const extension = toolConfig.extensions.find(ext => ext.id === extensionId);
|
|
540
|
+
if (extensionId in newConfig.extensions) {
|
|
541
|
+
delete newConfig.extensions[extensionId];
|
|
542
|
+
}
|
|
543
|
+
newConfig.extensions[extensionId] = {};
|
|
544
|
+
for (const toolset of extension.toolsets) {
|
|
545
|
+
newConfig.extensions[extensionId][toolset.id] = structuredClone(toolset.tools);
|
|
546
|
+
}
|
|
547
|
+
setToolSelections(newConfig);
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
const anyExtensionToolsetToolSelected = (extensionId, toolsetId) => {
|
|
551
|
+
if (!(extensionId in toolSelections.extensions)) {
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
if (!(toolsetId in toolSelections.extensions[extensionId])) {
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
return toolSelections.extensions[extensionId][toolsetId].length > 0;
|
|
558
|
+
};
|
|
559
|
+
const onExtensionToolsetClicked = (extensionId, toolsetId) => {
|
|
560
|
+
if (anyExtensionToolsetToolSelected(extensionId, toolsetId)) {
|
|
561
|
+
const newConfig = { ...toolSelections };
|
|
562
|
+
if (toolsetId in newConfig.extensions[extensionId]) {
|
|
563
|
+
delete newConfig.extensions[extensionId][toolsetId];
|
|
564
|
+
}
|
|
565
|
+
setToolSelections(newConfig);
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
const extension = toolConfig.extensions.find(ext => ext.id === extensionId);
|
|
569
|
+
const extensionToolset = extension.toolsets.find((toolset) => toolset.id === toolsetId);
|
|
570
|
+
const newConfig = { ...toolSelections };
|
|
571
|
+
if (!(extensionId in newConfig.extensions)) {
|
|
572
|
+
newConfig.extensions[extensionId] = {};
|
|
573
|
+
}
|
|
574
|
+
newConfig.extensions[extensionId][toolsetId] = structuredClone(extensionToolset.tools);
|
|
575
|
+
setToolSelections(newConfig);
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
const getExtensionToolsetToolState = (extensionId, toolsetId, toolId) => {
|
|
579
|
+
if (!(extensionId in toolSelections.extensions)) {
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
const selectedExtensionToolsets = toolSelections.extensions[extensionId];
|
|
583
|
+
if (!(toolsetId in selectedExtensionToolsets)) {
|
|
584
|
+
return false;
|
|
585
|
+
}
|
|
586
|
+
const selectedServerTools = selectedExtensionToolsets[toolsetId];
|
|
587
|
+
return selectedServerTools.includes(toolId);
|
|
588
|
+
};
|
|
589
|
+
const setExtensionToolsetToolState = (extensionId, toolsetId, toolId, checked) => {
|
|
590
|
+
const newConfig = { ...toolSelections };
|
|
591
|
+
if (checked && !(extensionId in newConfig.extensions)) {
|
|
592
|
+
newConfig.extensions[extensionId] = {};
|
|
593
|
+
}
|
|
594
|
+
if (checked && !(toolsetId in newConfig.extensions[extensionId])) {
|
|
595
|
+
newConfig.extensions[extensionId][toolsetId] = [];
|
|
596
|
+
}
|
|
597
|
+
const selectedTools = newConfig.extensions[extensionId][toolsetId];
|
|
598
|
+
if (checked) {
|
|
599
|
+
selectedTools.push(toolId);
|
|
600
|
+
}
|
|
601
|
+
else {
|
|
602
|
+
const index = selectedTools.indexOf(toolId);
|
|
603
|
+
if (index !== -1) {
|
|
604
|
+
selectedTools.splice(index, 1);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
setToolSelections(newConfig);
|
|
608
|
+
};
|
|
339
609
|
useEffect(() => {
|
|
340
610
|
const prefixes = [];
|
|
611
|
+
if (chatMode !== 'ask') {
|
|
612
|
+
prefixes.push('/clear');
|
|
613
|
+
setOriginalPrefixes(prefixes);
|
|
614
|
+
setPrefixSuggestions(prefixes);
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
341
617
|
const chatParticipants = NBIAPI.config.chatParticipants;
|
|
342
618
|
for (const participant of chatParticipants) {
|
|
343
619
|
const id = participant.id;
|
|
@@ -353,7 +629,7 @@ function SidebarComponent(props) {
|
|
|
353
629
|
}
|
|
354
630
|
setOriginalPrefixes(prefixes);
|
|
355
631
|
setPrefixSuggestions(prefixes);
|
|
356
|
-
}, []);
|
|
632
|
+
}, [chatMode]);
|
|
357
633
|
useEffect(() => {
|
|
358
634
|
const fetchData = () => {
|
|
359
635
|
setGHLoginStatus(NBIAPI.getLoginStatus());
|
|
@@ -399,6 +675,7 @@ function SidebarComponent(props) {
|
|
|
399
675
|
applyPrefixSuggestion(prefix);
|
|
400
676
|
};
|
|
401
677
|
const handleSubmitStopChatButtonClick = async () => {
|
|
678
|
+
setShowModeTools(false);
|
|
402
679
|
if (!copilotRequestInProgress) {
|
|
403
680
|
handleUserInputSubmit();
|
|
404
681
|
}
|
|
@@ -406,6 +683,18 @@ function SidebarComponent(props) {
|
|
|
406
683
|
handleUserInputCancel();
|
|
407
684
|
}
|
|
408
685
|
};
|
|
686
|
+
const handleSettingsButtonClick = async () => {
|
|
687
|
+
setShowModeTools(false);
|
|
688
|
+
props
|
|
689
|
+
.getApp()
|
|
690
|
+
.commands.execute('notebook-intelligence:open-configuration-dialog');
|
|
691
|
+
};
|
|
692
|
+
const handleChatToolsButtonClick = async () => {
|
|
693
|
+
if (!showModeTools) {
|
|
694
|
+
NBIAPI.fetchCapabilities();
|
|
695
|
+
}
|
|
696
|
+
setShowModeTools(!showModeTools);
|
|
697
|
+
};
|
|
409
698
|
const handleUserInputSubmit = async () => {
|
|
410
699
|
setPromptHistoryIndex(promptHistory.length + 1);
|
|
411
700
|
setPromptHistory([...promptHistory, prompt]);
|
|
@@ -480,7 +769,9 @@ function SidebarComponent(props) {
|
|
|
480
769
|
content: extractedPrompt,
|
|
481
770
|
language: activeDocInfo.language,
|
|
482
771
|
filename: activeDocInfo.filename,
|
|
483
|
-
additionalContext
|
|
772
|
+
additionalContext,
|
|
773
|
+
chatMode,
|
|
774
|
+
toolSelections: toolSelections
|
|
484
775
|
}, {
|
|
485
776
|
emit: async (response) => {
|
|
486
777
|
var _a, _b, _c, _d, _e;
|
|
@@ -617,6 +908,7 @@ function SidebarComponent(props) {
|
|
|
617
908
|
event.stopPropagation();
|
|
618
909
|
event.preventDefault();
|
|
619
910
|
setShowPopover(false);
|
|
911
|
+
setShowModeTools(false);
|
|
620
912
|
setSelectedPrefixSuggestionIndex(0);
|
|
621
913
|
}
|
|
622
914
|
else if (event.key === 'ArrowUp') {
|
|
@@ -831,7 +1123,9 @@ function SidebarComponent(props) {
|
|
|
831
1123
|
}, [ghLoginStatus]);
|
|
832
1124
|
return (React.createElement("div", { className: "sidebar" },
|
|
833
1125
|
React.createElement("div", { className: "sidebar-header" },
|
|
834
|
-
React.createElement("div", { className: "sidebar-title" }, "Notebook Intelligence")
|
|
1126
|
+
React.createElement("div", { className: "sidebar-title" }, "Notebook Intelligence"),
|
|
1127
|
+
React.createElement("div", { className: "user-input-footer-button", onClick: () => handleSettingsButtonClick() },
|
|
1128
|
+
React.createElement(VscSettingsGear, null))),
|
|
835
1129
|
!chatEnabled && !ghLoginRequired && (React.createElement("div", { className: "sidebar-login-info" },
|
|
836
1130
|
"Chat is disabled as you don't have a model configured.",
|
|
837
1131
|
React.createElement("button", { className: "jp-Dialog-button jp-mod-accept jp-mod-styled", onClick: handleConfigurationClick },
|
|
@@ -851,7 +1145,7 @@ function SidebarComponent(props) {
|
|
|
851
1145
|
copilotRequestInProgress }))),
|
|
852
1146
|
React.createElement("div", { ref: messagesEndRef })))),
|
|
853
1147
|
chatEnabled && (React.createElement("div", { className: `sidebar-user-input ${copilotRequestInProgress ? 'generating' : ''}` },
|
|
854
|
-
React.createElement("textarea", { ref: promptInputRef, rows: 3, onChange: onPromptChange, onKeyDown: onPromptKeyDown, placeholder: "Ask
|
|
1148
|
+
React.createElement("textarea", { ref: promptInputRef, rows: 3, onChange: onPromptChange, onKeyDown: onPromptKeyDown, placeholder: "Ask Notebook Intelligence...", spellCheck: false, value: prompt }),
|
|
855
1149
|
(activeDocumentInfo === null || activeDocumentInfo === void 0 ? void 0 : activeDocumentInfo.filename) && (React.createElement("div", { className: "user-input-context-row" },
|
|
856
1150
|
React.createElement("div", { className: `user-input-context user-input-context-active-file ${contextOn ? 'on' : 'off'}` },
|
|
857
1151
|
React.createElement("div", null, currentFileContextTitle),
|
|
@@ -859,16 +1153,72 @@ function SidebarComponent(props) {
|
|
|
859
1153
|
React.createElement(VscEye, { title: "Use as context" }))) : (React.createElement("div", { className: "user-input-context-toggle", onClick: () => setContextOn(!contextOn) },
|
|
860
1154
|
React.createElement(VscEyeClosed, { title: "Don't use as context" })))))),
|
|
861
1155
|
React.createElement("div", { className: "user-input-footer" },
|
|
862
|
-
React.createElement("div", null,
|
|
1156
|
+
chatMode === 'ask' && (React.createElement("div", null,
|
|
863
1157
|
React.createElement("a", { href: "javascript:void(0)", onClick: () => {
|
|
864
1158
|
var _a;
|
|
865
1159
|
setShowPopover(true);
|
|
866
1160
|
(_a = promptInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
867
|
-
}, title: "Select chat participant" }, "@")),
|
|
1161
|
+
}, title: "Select chat participant" }, "@"))),
|
|
868
1162
|
React.createElement("div", { style: { flexGrow: 1 } }),
|
|
1163
|
+
React.createElement("div", { className: "chat-mode-widgets-container" },
|
|
1164
|
+
React.createElement("div", null,
|
|
1165
|
+
React.createElement("select", { className: "chat-mode-select", title: "Chat mode", value: chatMode, onChange: event => {
|
|
1166
|
+
if (event.target.value === 'ask') {
|
|
1167
|
+
setToolSelections(toolSelectionsEmpty);
|
|
1168
|
+
}
|
|
1169
|
+
else if (event.target.value === 'agent') {
|
|
1170
|
+
setToolSelections(toolSelectionsInitial);
|
|
1171
|
+
}
|
|
1172
|
+
setShowModeTools(false);
|
|
1173
|
+
setChatMode(event.target.value);
|
|
1174
|
+
} },
|
|
1175
|
+
React.createElement("option", { value: "ask" }, "Ask"),
|
|
1176
|
+
React.createElement("option", { value: "agent" }, "Agent"))),
|
|
1177
|
+
chatMode !== 'ask' && (React.createElement("div", { className: `user-input-footer-button tools-button ${notebookExecuteToolSelected ? 'tools-button-warning' : selectedToolCount > 0 ? 'tools-button-active' : ''}`, onClick: () => handleChatToolsButtonClick(), title: notebookExecuteToolSelected
|
|
1178
|
+
? `Notebook execute tool selected!\n${toolSelectionTitle}`
|
|
1179
|
+
: toolSelectionTitle },
|
|
1180
|
+
React.createElement(VscTools, null),
|
|
1181
|
+
selectedToolCount > 0 && React.createElement(React.Fragment, null, selectedToolCount)))),
|
|
869
1182
|
React.createElement("div", null,
|
|
870
1183
|
React.createElement("button", { className: "jp-Dialog-button jp-mod-accept jp-mod-styled send-button", onClick: () => handleSubmitStopChatButtonClick(), disabled: prompt.length === 0 && !copilotRequestInProgress }, copilotRequestInProgress ? React.createElement(VscStopCircle, null) : React.createElement(VscSend, null)))),
|
|
871
|
-
showPopover && prefixSuggestions.length > 0 && (React.createElement("div", { className: "user-input-autocomplete" }, prefixSuggestions.map((prefix, index) => (React.createElement("div", { key: `key-${index}`, className: `user-input-autocomplete-item ${index === selectedPrefixSuggestionIndex ? 'selected' : ''}`, "data-value": prefix, onClick: event => prefixSuggestionSelected(event) }, prefix)))))
|
|
1184
|
+
showPopover && prefixSuggestions.length > 0 && (React.createElement("div", { className: "user-input-autocomplete" }, prefixSuggestions.map((prefix, index) => (React.createElement("div", { key: `key-${index}`, className: `user-input-autocomplete-item ${index === selectedPrefixSuggestionIndex ? 'selected' : ''}`, "data-value": prefix, onClick: event => prefixSuggestionSelected(event) }, prefix))))),
|
|
1185
|
+
showModeTools && (React.createElement("div", { className: "mode-tools-popover", tabIndex: 1, autoFocus: true, onKeyDown: (event) => {
|
|
1186
|
+
if (event.key === 'Escape' || event.key === 'Enter') {
|
|
1187
|
+
event.stopPropagation();
|
|
1188
|
+
event.preventDefault();
|
|
1189
|
+
setShowModeTools(false);
|
|
1190
|
+
}
|
|
1191
|
+
} },
|
|
1192
|
+
React.createElement("div", { className: "mode-tools-popover-header" },
|
|
1193
|
+
React.createElement("div", { className: "mode-tools-popover-header-icon" },
|
|
1194
|
+
React.createElement(VscTools, null)),
|
|
1195
|
+
React.createElement("div", { className: "mode-tools-popover-title" }, toolSelectionTitle),
|
|
1196
|
+
React.createElement("div", { className: "mode-tools-popover-clear-tools-button", style: {
|
|
1197
|
+
visibility: selectedToolCount > 0 ? 'visible' : 'hidden'
|
|
1198
|
+
} },
|
|
1199
|
+
React.createElement("div", null,
|
|
1200
|
+
React.createElement(VscTrash, null)),
|
|
1201
|
+
React.createElement("div", null,
|
|
1202
|
+
React.createElement("a", { href: "javascript:void(0);", onClick: onClearToolsButtonClicked }, "clear"))),
|
|
1203
|
+
React.createElement("div", { className: "mode-tools-popover-close-button", onClick: () => setShowModeTools(false) },
|
|
1204
|
+
React.createElement("div", null,
|
|
1205
|
+
React.createElement(VscPassFilled, null)),
|
|
1206
|
+
React.createElement("div", null, "Done"))),
|
|
1207
|
+
React.createElement("div", { className: "mode-tools-popover-tool-list" },
|
|
1208
|
+
React.createElement("div", { className: "mode-tools-group-header" }, "Built-in"),
|
|
1209
|
+
React.createElement("div", { className: "mode-tools-group" }, toolConfig.builtinToolsets.map((toolset) => (React.createElement(CheckBoxItem, { key: toolset.id, label: toolset.name, checked: getBuiltinToolsetState(toolset.id), onClick: () => {
|
|
1210
|
+
setBuiltinToolsetState(toolset.id, !getBuiltinToolsetState(toolset.id));
|
|
1211
|
+
} })))),
|
|
1212
|
+
toolConfig.mcpServers.length > 0 && (React.createElement("div", { className: "mode-tools-group-header" }, "MCP Servers")),
|
|
1213
|
+
toolConfig.mcpServers.map((mcpServer, index) => (React.createElement("div", { className: "mode-tools-group" },
|
|
1214
|
+
React.createElement(CheckBoxItem, { label: mcpServer.id, checked: getMCPServerState(mcpServer.id), onClick: () => onMCPServerClicked(mcpServer.id) }),
|
|
1215
|
+
mcpServer.tools.map((tool, index) => (React.createElement(CheckBoxItem, { label: tool, indent: 1, checked: getMCPServerToolState(mcpServer.id, tool), onClick: () => setMCPServerToolState(mcpServer.id, tool, !getMCPServerToolState(mcpServer.id, tool)) })))))),
|
|
1216
|
+
hasExtensionTools && (React.createElement("div", { className: "mode-tools-group-header" }, "Extension tools")),
|
|
1217
|
+
toolConfig.extensions.map((extension, index) => (React.createElement("div", { className: "mode-tools-group" },
|
|
1218
|
+
React.createElement(CheckBoxItem, { label: `${extension.name} (${extension.id})`, checked: getExtensionState(extension.id), onClick: () => onExtensionClicked(extension.id) }),
|
|
1219
|
+
extension.toolsets.map((toolset, index) => (React.createElement(React.Fragment, null,
|
|
1220
|
+
React.createElement(CheckBoxItem, { label: `${toolset.name} (${toolset.id})`, indent: 1, checked: getExtensionToolsetState(extension.id, toolset.id), onClick: () => onExtensionToolsetClicked(extension.id, toolset.id) }),
|
|
1221
|
+
toolset.tools.map((tool, index) => (React.createElement(CheckBoxItem, { label: tool, indent: 2, checked: getExtensionToolsetToolState(extension.id, toolset.id, tool), onClick: () => setExtensionToolsetToolState(extension.id, toolset.id, tool, !getExtensionToolsetToolState(extension.id, toolset.id, tool)) }))))))))))))))));
|
|
872
1222
|
}
|
|
873
1223
|
function InlinePopoverComponent(props) {
|
|
874
1224
|
const [modifiedCode, setModifiedCode] = useState('');
|
|
@@ -964,7 +1314,8 @@ function InlinePromptComponent(props) {
|
|
|
964
1314
|
filename: undefined,
|
|
965
1315
|
prefix: props.prefix,
|
|
966
1316
|
suffix: props.suffix,
|
|
967
|
-
existingCode: props.existingCode
|
|
1317
|
+
existingCode: props.existingCode,
|
|
1318
|
+
chatMode: 'ask'
|
|
968
1319
|
}, {
|
|
969
1320
|
emit: async (response) => {
|
|
970
1321
|
props.onResponseEmit(response);
|
|
@@ -999,7 +1350,7 @@ function InlinePromptComponent(props) {
|
|
|
999
1350
|
}
|
|
1000
1351
|
}, []);
|
|
1001
1352
|
return (React.createElement("div", { className: "inline-prompt-container", style: { height: props.limitHeight ? '40px' : '100%' } },
|
|
1002
|
-
React.createElement("textarea", { ref: promptInputRef, rows: 3, onChange: onPromptChange, onKeyDown: onPromptKeyDown, placeholder: "Ask
|
|
1353
|
+
React.createElement("textarea", { ref: promptInputRef, rows: 3, onChange: onPromptChange, onKeyDown: onPromptKeyDown, placeholder: "Ask Notebook Intelligence to generate Python code...", spellCheck: false, value: prompt })));
|
|
1003
1354
|
}
|
|
1004
1355
|
function GitHubCopilotStatusComponent(props) {
|
|
1005
1356
|
const [ghLoginStatus, setGHLoginStatus] = useState(GitHubCopilotLoginStatus.NotLoggedIn);
|