@notebook-intelligence/notebook-intelligence 1.3.5 → 2.1.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 +366 -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 +640 -19
- package/src/index.ts +252 -1
- package/src/tokens.ts +15 -0
- package/style/base.css +196 -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,25 @@ 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("div", { className: `checkbox-item checkbox-item-indent-${indent} ${props.header ? 'checkbox-item-header' : ''}`, title: props.title, onClick: event => props.onClick(event) },
|
|
322
|
+
React.createElement("div", { className: "checkbox-item-toggle" },
|
|
323
|
+
props.checked ? (React.createElement(MdCheckBox, { className: "checkbox-icon" })) : (React.createElement(MdOutlineCheckBoxOutlineBlank, { className: "checkbox-icon" })),
|
|
324
|
+
props.label),
|
|
325
|
+
props.title && (React.createElement("div", { className: "checkbox-item-description" }, props.title))));
|
|
326
|
+
}
|
|
316
327
|
function SidebarComponent(props) {
|
|
317
328
|
const [chatMessages, setChatMessages] = useState([]);
|
|
318
329
|
const [prompt, setPrompt] = useState('');
|
|
@@ -336,8 +347,274 @@ function SidebarComponent(props) {
|
|
|
336
347
|
const [activeDocumentInfo, setActiveDocumentInfo] = useState(null);
|
|
337
348
|
const [currentFileContextTitle, setCurrentFileContextTitle] = useState('');
|
|
338
349
|
const telemetryEmitter = props.getTelemetryEmitter();
|
|
350
|
+
const [chatMode, setChatMode] = useState('ask');
|
|
351
|
+
const [toolSelectionTitle, setToolSelectionTitle] = useState('Tool selection');
|
|
352
|
+
const [selectedToolCount, setSelectedToolCount] = useState(0);
|
|
353
|
+
const [notebookExecuteToolSelected, setNotebookExecuteToolSelected] = useState(false);
|
|
354
|
+
const [toolConfig, setToolConfig] = useState({
|
|
355
|
+
builtinToolsets: [
|
|
356
|
+
{ id: BuiltinToolsetType.NotebookEdit, name: 'Notebook edit' },
|
|
357
|
+
{ id: BuiltinToolsetType.NotebookExecute, name: 'Notebook execute' }
|
|
358
|
+
],
|
|
359
|
+
mcpServers: [],
|
|
360
|
+
extensions: []
|
|
361
|
+
});
|
|
362
|
+
const [showModeTools, setShowModeTools] = useState(false);
|
|
363
|
+
const toolSelectionsInitial = {
|
|
364
|
+
builtinToolsets: [BuiltinToolsetType.NotebookEdit],
|
|
365
|
+
mcpServers: {},
|
|
366
|
+
extensions: {}
|
|
367
|
+
};
|
|
368
|
+
const toolSelectionsEmpty = {
|
|
369
|
+
builtinToolsets: [],
|
|
370
|
+
mcpServers: {},
|
|
371
|
+
extensions: {}
|
|
372
|
+
};
|
|
373
|
+
const [toolSelections, setToolSelections] = useState(toolSelectionsInitial);
|
|
374
|
+
const [hasExtensionTools, setHasExtensionTools] = useState(false);
|
|
375
|
+
NBIAPI.configChanged.connect(() => {
|
|
376
|
+
setToolConfig(NBIAPI.config.toolConfig);
|
|
377
|
+
});
|
|
378
|
+
useEffect(() => {
|
|
379
|
+
let hasTools = false;
|
|
380
|
+
for (const extension of toolConfig.extensions) {
|
|
381
|
+
if (extension.toolsets.length > 0) {
|
|
382
|
+
hasTools = true;
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
setHasExtensionTools(hasTools);
|
|
387
|
+
}, [toolConfig]);
|
|
388
|
+
useEffect(() => {
|
|
389
|
+
const builtinToolSelCount = toolSelections.builtinToolsets.length;
|
|
390
|
+
let mcpServerToolSelCount = 0;
|
|
391
|
+
let extensionToolSelCount = 0;
|
|
392
|
+
for (const serverId in toolSelections.mcpServers) {
|
|
393
|
+
const mcpServerTools = toolSelections.mcpServers[serverId];
|
|
394
|
+
mcpServerToolSelCount += mcpServerTools.length;
|
|
395
|
+
}
|
|
396
|
+
for (const extensionId in toolSelections.extensions) {
|
|
397
|
+
const extensionToolsets = toolSelections.extensions[extensionId];
|
|
398
|
+
for (const toolsetId in extensionToolsets) {
|
|
399
|
+
const toolsetTools = extensionToolsets[toolsetId];
|
|
400
|
+
extensionToolSelCount += toolsetTools.length;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
const typeCounts = [];
|
|
404
|
+
if (builtinToolSelCount > 0) {
|
|
405
|
+
typeCounts.push(`${builtinToolSelCount} built-in`);
|
|
406
|
+
}
|
|
407
|
+
if (mcpServerToolSelCount > 0) {
|
|
408
|
+
typeCounts.push(`${mcpServerToolSelCount} mcp`);
|
|
409
|
+
}
|
|
410
|
+
if (extensionToolSelCount > 0) {
|
|
411
|
+
typeCounts.push(`${extensionToolSelCount} ext`);
|
|
412
|
+
}
|
|
413
|
+
setSelectedToolCount(builtinToolSelCount + mcpServerToolSelCount + extensionToolSelCount);
|
|
414
|
+
setNotebookExecuteToolSelected(toolSelections.builtinToolsets.includes(BuiltinToolsetType.NotebookExecute));
|
|
415
|
+
setToolSelectionTitle(typeCounts.length === 0
|
|
416
|
+
? 'Tool selection'
|
|
417
|
+
: `Tool selection (${typeCounts.join(', ')})`);
|
|
418
|
+
}, [toolSelections]);
|
|
419
|
+
const onClearToolsButtonClicked = () => {
|
|
420
|
+
setToolSelections(toolSelectionsEmpty);
|
|
421
|
+
};
|
|
422
|
+
const getBuiltinToolsetState = (toolsetName) => {
|
|
423
|
+
return toolSelections.builtinToolsets.includes(toolsetName);
|
|
424
|
+
};
|
|
425
|
+
const setBuiltinToolsetState = (toolsetName, enabled) => {
|
|
426
|
+
const newConfig = { ...toolSelections };
|
|
427
|
+
if (enabled) {
|
|
428
|
+
if (!toolSelections.builtinToolsets.includes(toolsetName)) {
|
|
429
|
+
newConfig.builtinToolsets.push(toolsetName);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
const index = newConfig.builtinToolsets.indexOf(toolsetName);
|
|
434
|
+
if (index !== -1) {
|
|
435
|
+
newConfig.builtinToolsets.splice(index, 1);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
setToolSelections(newConfig);
|
|
439
|
+
};
|
|
440
|
+
const anyMCPServerToolSelected = (id) => {
|
|
441
|
+
if (!(id in toolSelections.mcpServers)) {
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
return toolSelections.mcpServers[id].length > 0;
|
|
445
|
+
};
|
|
446
|
+
const getMCPServerState = (id) => {
|
|
447
|
+
if (!(id in toolSelections.mcpServers)) {
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
const mcpServer = toolConfig.mcpServers.find(server => server.id === id);
|
|
451
|
+
const selectedServerTools = toolSelections.mcpServers[id];
|
|
452
|
+
for (const tool of mcpServer.tools) {
|
|
453
|
+
if (!selectedServerTools.includes(tool.name)) {
|
|
454
|
+
return false;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
return true;
|
|
458
|
+
};
|
|
459
|
+
const onMCPServerClicked = (id) => {
|
|
460
|
+
if (anyMCPServerToolSelected(id)) {
|
|
461
|
+
const newConfig = { ...toolSelections };
|
|
462
|
+
delete newConfig.mcpServers[id];
|
|
463
|
+
setToolSelections(newConfig);
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
const mcpServer = toolConfig.mcpServers.find(server => server.id === id);
|
|
467
|
+
const newConfig = { ...toolSelections };
|
|
468
|
+
newConfig.mcpServers[id] = structuredClone(mcpServer.tools.map((tool) => tool.name));
|
|
469
|
+
setToolSelections(newConfig);
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
const getMCPServerToolState = (serverId, toolId) => {
|
|
473
|
+
if (!(serverId in toolSelections.mcpServers)) {
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
const selectedServerTools = toolSelections.mcpServers[serverId];
|
|
477
|
+
return selectedServerTools.includes(toolId);
|
|
478
|
+
};
|
|
479
|
+
const setMCPServerToolState = (serverId, toolId, checked) => {
|
|
480
|
+
const newConfig = { ...toolSelections };
|
|
481
|
+
if (checked && !(serverId in newConfig.mcpServers)) {
|
|
482
|
+
newConfig.mcpServers[serverId] = [];
|
|
483
|
+
}
|
|
484
|
+
const selectedServerTools = newConfig.mcpServers[serverId];
|
|
485
|
+
if (checked) {
|
|
486
|
+
selectedServerTools.push(toolId);
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
const index = selectedServerTools.indexOf(toolId);
|
|
490
|
+
if (index !== -1) {
|
|
491
|
+
selectedServerTools.splice(index, 1);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
setToolSelections(newConfig);
|
|
495
|
+
};
|
|
496
|
+
// all toolsets and tools of the extension are selected
|
|
497
|
+
const getExtensionState = (extensionId) => {
|
|
498
|
+
if (!(extensionId in toolSelections.extensions)) {
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
const extension = toolConfig.extensions.find(extension => extension.id === extensionId);
|
|
502
|
+
for (const toolset of extension.toolsets) {
|
|
503
|
+
if (!getExtensionToolsetState(extensionId, toolset.id)) {
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return true;
|
|
508
|
+
};
|
|
509
|
+
const getExtensionToolsetState = (extensionId, toolsetId) => {
|
|
510
|
+
if (!(extensionId in toolSelections.extensions)) {
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
513
|
+
if (!(toolsetId in toolSelections.extensions[extensionId])) {
|
|
514
|
+
return false;
|
|
515
|
+
}
|
|
516
|
+
const extension = toolConfig.extensions.find(ext => ext.id === extensionId);
|
|
517
|
+
const extensionToolset = extension.toolsets.find((toolset) => toolset.id === toolsetId);
|
|
518
|
+
const selectedToolsetTools = toolSelections.extensions[extensionId][toolsetId];
|
|
519
|
+
for (const tool of extensionToolset.tools) {
|
|
520
|
+
if (!selectedToolsetTools.includes(tool)) {
|
|
521
|
+
return false;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return true;
|
|
525
|
+
};
|
|
526
|
+
const anyExtensionToolsetSelected = (extensionId) => {
|
|
527
|
+
if (!(extensionId in toolSelections.extensions)) {
|
|
528
|
+
return false;
|
|
529
|
+
}
|
|
530
|
+
return Object.keys(toolSelections.extensions[extensionId]).length > 0;
|
|
531
|
+
};
|
|
532
|
+
const onExtensionClicked = (extensionId) => {
|
|
533
|
+
if (anyExtensionToolsetSelected(extensionId)) {
|
|
534
|
+
const newConfig = { ...toolSelections };
|
|
535
|
+
delete newConfig.extensions[extensionId];
|
|
536
|
+
setToolSelections(newConfig);
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
const newConfig = { ...toolSelections };
|
|
540
|
+
const extension = toolConfig.extensions.find(ext => ext.id === extensionId);
|
|
541
|
+
if (extensionId in newConfig.extensions) {
|
|
542
|
+
delete newConfig.extensions[extensionId];
|
|
543
|
+
}
|
|
544
|
+
newConfig.extensions[extensionId] = {};
|
|
545
|
+
for (const toolset of extension.toolsets) {
|
|
546
|
+
newConfig.extensions[extensionId][toolset.id] = structuredClone(toolset.tools);
|
|
547
|
+
}
|
|
548
|
+
setToolSelections(newConfig);
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
const anyExtensionToolsetToolSelected = (extensionId, toolsetId) => {
|
|
552
|
+
if (!(extensionId in toolSelections.extensions)) {
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
555
|
+
if (!(toolsetId in toolSelections.extensions[extensionId])) {
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
return toolSelections.extensions[extensionId][toolsetId].length > 0;
|
|
559
|
+
};
|
|
560
|
+
const onExtensionToolsetClicked = (extensionId, toolsetId) => {
|
|
561
|
+
if (anyExtensionToolsetToolSelected(extensionId, toolsetId)) {
|
|
562
|
+
const newConfig = { ...toolSelections };
|
|
563
|
+
if (toolsetId in newConfig.extensions[extensionId]) {
|
|
564
|
+
delete newConfig.extensions[extensionId][toolsetId];
|
|
565
|
+
}
|
|
566
|
+
setToolSelections(newConfig);
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
const extension = toolConfig.extensions.find(ext => ext.id === extensionId);
|
|
570
|
+
const extensionToolset = extension.toolsets.find((toolset) => toolset.id === toolsetId);
|
|
571
|
+
const newConfig = { ...toolSelections };
|
|
572
|
+
if (!(extensionId in newConfig.extensions)) {
|
|
573
|
+
newConfig.extensions[extensionId] = {};
|
|
574
|
+
}
|
|
575
|
+
newConfig.extensions[extensionId][toolsetId] = structuredClone(extensionToolset.tools);
|
|
576
|
+
setToolSelections(newConfig);
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
const getExtensionToolsetToolState = (extensionId, toolsetId, toolId) => {
|
|
580
|
+
if (!(extensionId in toolSelections.extensions)) {
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
583
|
+
const selectedExtensionToolsets = toolSelections.extensions[extensionId];
|
|
584
|
+
if (!(toolsetId in selectedExtensionToolsets)) {
|
|
585
|
+
return false;
|
|
586
|
+
}
|
|
587
|
+
const selectedServerTools = selectedExtensionToolsets[toolsetId];
|
|
588
|
+
return selectedServerTools.includes(toolId);
|
|
589
|
+
};
|
|
590
|
+
const setExtensionToolsetToolState = (extensionId, toolsetId, toolId, checked) => {
|
|
591
|
+
const newConfig = { ...toolSelections };
|
|
592
|
+
if (checked && !(extensionId in newConfig.extensions)) {
|
|
593
|
+
newConfig.extensions[extensionId] = {};
|
|
594
|
+
}
|
|
595
|
+
if (checked && !(toolsetId in newConfig.extensions[extensionId])) {
|
|
596
|
+
newConfig.extensions[extensionId][toolsetId] = [];
|
|
597
|
+
}
|
|
598
|
+
const selectedTools = newConfig.extensions[extensionId][toolsetId];
|
|
599
|
+
if (checked) {
|
|
600
|
+
selectedTools.push(toolId);
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
const index = selectedTools.indexOf(toolId);
|
|
604
|
+
if (index !== -1) {
|
|
605
|
+
selectedTools.splice(index, 1);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
setToolSelections(newConfig);
|
|
609
|
+
};
|
|
339
610
|
useEffect(() => {
|
|
340
611
|
const prefixes = [];
|
|
612
|
+
if (chatMode !== 'ask') {
|
|
613
|
+
prefixes.push('/clear');
|
|
614
|
+
setOriginalPrefixes(prefixes);
|
|
615
|
+
setPrefixSuggestions(prefixes);
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
341
618
|
const chatParticipants = NBIAPI.config.chatParticipants;
|
|
342
619
|
for (const participant of chatParticipants) {
|
|
343
620
|
const id = participant.id;
|
|
@@ -353,7 +630,7 @@ function SidebarComponent(props) {
|
|
|
353
630
|
}
|
|
354
631
|
setOriginalPrefixes(prefixes);
|
|
355
632
|
setPrefixSuggestions(prefixes);
|
|
356
|
-
}, []);
|
|
633
|
+
}, [chatMode]);
|
|
357
634
|
useEffect(() => {
|
|
358
635
|
const fetchData = () => {
|
|
359
636
|
setGHLoginStatus(NBIAPI.getLoginStatus());
|
|
@@ -399,6 +676,7 @@ function SidebarComponent(props) {
|
|
|
399
676
|
applyPrefixSuggestion(prefix);
|
|
400
677
|
};
|
|
401
678
|
const handleSubmitStopChatButtonClick = async () => {
|
|
679
|
+
setShowModeTools(false);
|
|
402
680
|
if (!copilotRequestInProgress) {
|
|
403
681
|
handleUserInputSubmit();
|
|
404
682
|
}
|
|
@@ -406,6 +684,18 @@ function SidebarComponent(props) {
|
|
|
406
684
|
handleUserInputCancel();
|
|
407
685
|
}
|
|
408
686
|
};
|
|
687
|
+
const handleSettingsButtonClick = async () => {
|
|
688
|
+
setShowModeTools(false);
|
|
689
|
+
props
|
|
690
|
+
.getApp()
|
|
691
|
+
.commands.execute('notebook-intelligence:open-configuration-dialog');
|
|
692
|
+
};
|
|
693
|
+
const handleChatToolsButtonClick = async () => {
|
|
694
|
+
if (!showModeTools) {
|
|
695
|
+
NBIAPI.fetchCapabilities();
|
|
696
|
+
}
|
|
697
|
+
setShowModeTools(!showModeTools);
|
|
698
|
+
};
|
|
409
699
|
const handleUserInputSubmit = async () => {
|
|
410
700
|
setPromptHistoryIndex(promptHistory.length + 1);
|
|
411
701
|
setPromptHistory([...promptHistory, prompt]);
|
|
@@ -480,7 +770,9 @@ function SidebarComponent(props) {
|
|
|
480
770
|
content: extractedPrompt,
|
|
481
771
|
language: activeDocInfo.language,
|
|
482
772
|
filename: activeDocInfo.filename,
|
|
483
|
-
additionalContext
|
|
773
|
+
additionalContext,
|
|
774
|
+
chatMode,
|
|
775
|
+
toolSelections: toolSelections
|
|
484
776
|
}, {
|
|
485
777
|
emit: async (response) => {
|
|
486
778
|
var _a, _b, _c, _d, _e;
|
|
@@ -617,6 +909,7 @@ function SidebarComponent(props) {
|
|
|
617
909
|
event.stopPropagation();
|
|
618
910
|
event.preventDefault();
|
|
619
911
|
setShowPopover(false);
|
|
912
|
+
setShowModeTools(false);
|
|
620
913
|
setSelectedPrefixSuggestionIndex(0);
|
|
621
914
|
}
|
|
622
915
|
else if (event.key === 'ArrowUp') {
|
|
@@ -831,7 +1124,9 @@ function SidebarComponent(props) {
|
|
|
831
1124
|
}, [ghLoginStatus]);
|
|
832
1125
|
return (React.createElement("div", { className: "sidebar" },
|
|
833
1126
|
React.createElement("div", { className: "sidebar-header" },
|
|
834
|
-
React.createElement("div", { className: "sidebar-title" }, "Notebook Intelligence")
|
|
1127
|
+
React.createElement("div", { className: "sidebar-title" }, "Notebook Intelligence"),
|
|
1128
|
+
React.createElement("div", { className: "user-input-footer-button", onClick: () => handleSettingsButtonClick() },
|
|
1129
|
+
React.createElement(VscSettingsGear, null))),
|
|
835
1130
|
!chatEnabled && !ghLoginRequired && (React.createElement("div", { className: "sidebar-login-info" },
|
|
836
1131
|
"Chat is disabled as you don't have a model configured.",
|
|
837
1132
|
React.createElement("button", { className: "jp-Dialog-button jp-mod-accept jp-mod-styled", onClick: handleConfigurationClick },
|
|
@@ -851,7 +1146,7 @@ function SidebarComponent(props) {
|
|
|
851
1146
|
copilotRequestInProgress }))),
|
|
852
1147
|
React.createElement("div", { ref: messagesEndRef })))),
|
|
853
1148
|
chatEnabled && (React.createElement("div", { className: `sidebar-user-input ${copilotRequestInProgress ? 'generating' : ''}` },
|
|
854
|
-
React.createElement("textarea", { ref: promptInputRef, rows: 3, onChange: onPromptChange, onKeyDown: onPromptKeyDown, placeholder: "Ask
|
|
1149
|
+
React.createElement("textarea", { ref: promptInputRef, rows: 3, onChange: onPromptChange, onKeyDown: onPromptKeyDown, placeholder: "Ask Notebook Intelligence...", spellCheck: false, value: prompt }),
|
|
855
1150
|
(activeDocumentInfo === null || activeDocumentInfo === void 0 ? void 0 : activeDocumentInfo.filename) && (React.createElement("div", { className: "user-input-context-row" },
|
|
856
1151
|
React.createElement("div", { className: `user-input-context user-input-context-active-file ${contextOn ? 'on' : 'off'}` },
|
|
857
1152
|
React.createElement("div", null, currentFileContextTitle),
|
|
@@ -859,16 +1154,72 @@ function SidebarComponent(props) {
|
|
|
859
1154
|
React.createElement(VscEye, { title: "Use as context" }))) : (React.createElement("div", { className: "user-input-context-toggle", onClick: () => setContextOn(!contextOn) },
|
|
860
1155
|
React.createElement(VscEyeClosed, { title: "Don't use as context" })))))),
|
|
861
1156
|
React.createElement("div", { className: "user-input-footer" },
|
|
862
|
-
React.createElement("div", null,
|
|
1157
|
+
chatMode === 'ask' && (React.createElement("div", null,
|
|
863
1158
|
React.createElement("a", { href: "javascript:void(0)", onClick: () => {
|
|
864
1159
|
var _a;
|
|
865
1160
|
setShowPopover(true);
|
|
866
1161
|
(_a = promptInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
867
|
-
}, title: "Select chat participant" }, "@")),
|
|
1162
|
+
}, title: "Select chat participant" }, "@"))),
|
|
868
1163
|
React.createElement("div", { style: { flexGrow: 1 } }),
|
|
1164
|
+
React.createElement("div", { className: "chat-mode-widgets-container" },
|
|
1165
|
+
React.createElement("div", null,
|
|
1166
|
+
React.createElement("select", { className: "chat-mode-select", title: "Chat mode", value: chatMode, onChange: event => {
|
|
1167
|
+
if (event.target.value === 'ask') {
|
|
1168
|
+
setToolSelections(toolSelectionsEmpty);
|
|
1169
|
+
}
|
|
1170
|
+
else if (event.target.value === 'agent') {
|
|
1171
|
+
setToolSelections(toolSelectionsInitial);
|
|
1172
|
+
}
|
|
1173
|
+
setShowModeTools(false);
|
|
1174
|
+
setChatMode(event.target.value);
|
|
1175
|
+
} },
|
|
1176
|
+
React.createElement("option", { value: "ask" }, "Ask"),
|
|
1177
|
+
React.createElement("option", { value: "agent" }, "Agent"))),
|
|
1178
|
+
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
|
|
1179
|
+
? `Notebook execute tool selected!\n${toolSelectionTitle}`
|
|
1180
|
+
: toolSelectionTitle },
|
|
1181
|
+
React.createElement(VscTools, null),
|
|
1182
|
+
selectedToolCount > 0 && React.createElement(React.Fragment, null, selectedToolCount)))),
|
|
869
1183
|
React.createElement("div", null,
|
|
870
1184
|
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)))))
|
|
1185
|
+
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))))),
|
|
1186
|
+
showModeTools && (React.createElement("div", { className: "mode-tools-popover", tabIndex: 1, autoFocus: true, onKeyDown: (event) => {
|
|
1187
|
+
if (event.key === 'Escape' || event.key === 'Enter') {
|
|
1188
|
+
event.stopPropagation();
|
|
1189
|
+
event.preventDefault();
|
|
1190
|
+
setShowModeTools(false);
|
|
1191
|
+
}
|
|
1192
|
+
} },
|
|
1193
|
+
React.createElement("div", { className: "mode-tools-popover-header" },
|
|
1194
|
+
React.createElement("div", { className: "mode-tools-popover-header-icon" },
|
|
1195
|
+
React.createElement(VscTools, null)),
|
|
1196
|
+
React.createElement("div", { className: "mode-tools-popover-title" }, toolSelectionTitle),
|
|
1197
|
+
React.createElement("div", { className: "mode-tools-popover-clear-tools-button", style: {
|
|
1198
|
+
visibility: selectedToolCount > 0 ? 'visible' : 'hidden'
|
|
1199
|
+
} },
|
|
1200
|
+
React.createElement("div", null,
|
|
1201
|
+
React.createElement(VscTrash, null)),
|
|
1202
|
+
React.createElement("div", null,
|
|
1203
|
+
React.createElement("a", { href: "javascript:void(0);", onClick: onClearToolsButtonClicked }, "clear"))),
|
|
1204
|
+
React.createElement("div", { className: "mode-tools-popover-close-button", onClick: () => setShowModeTools(false) },
|
|
1205
|
+
React.createElement("div", null,
|
|
1206
|
+
React.createElement(VscPassFilled, null)),
|
|
1207
|
+
React.createElement("div", null, "Done"))),
|
|
1208
|
+
React.createElement("div", { className: "mode-tools-popover-tool-list" },
|
|
1209
|
+
React.createElement("div", { className: "mode-tools-group-header" }, "Built-in"),
|
|
1210
|
+
React.createElement("div", { className: "mode-tools-group mode-tools-group-built-in" }, toolConfig.builtinToolsets.map((toolset) => (React.createElement(CheckBoxItem, { key: toolset.id, label: toolset.name, checked: getBuiltinToolsetState(toolset.id), header: true, onClick: () => {
|
|
1211
|
+
setBuiltinToolsetState(toolset.id, !getBuiltinToolsetState(toolset.id));
|
|
1212
|
+
} })))),
|
|
1213
|
+
toolConfig.mcpServers.length > 0 && (React.createElement("div", { className: "mode-tools-group-header" }, "MCP Servers")),
|
|
1214
|
+
toolConfig.mcpServers.map((mcpServer, index) => (React.createElement("div", { className: "mode-tools-group" },
|
|
1215
|
+
React.createElement(CheckBoxItem, { label: mcpServer.id, header: true, checked: getMCPServerState(mcpServer.id), onClick: () => onMCPServerClicked(mcpServer.id) }),
|
|
1216
|
+
mcpServer.tools.map((tool, index) => (React.createElement(CheckBoxItem, { label: tool.name, title: tool.description, indent: 1, checked: getMCPServerToolState(mcpServer.id, tool.name), onClick: () => setMCPServerToolState(mcpServer.id, tool.name, !getMCPServerToolState(mcpServer.id, tool.name)) })))))),
|
|
1217
|
+
hasExtensionTools && (React.createElement("div", { className: "mode-tools-group-header" }, "Extension tools")),
|
|
1218
|
+
toolConfig.extensions.map((extension, index) => (React.createElement("div", { className: "mode-tools-group" },
|
|
1219
|
+
React.createElement(CheckBoxItem, { label: `${extension.name} (${extension.id})`, header: true, checked: getExtensionState(extension.id), onClick: () => onExtensionClicked(extension.id) }),
|
|
1220
|
+
extension.toolsets.map((toolset, index) => (React.createElement(React.Fragment, null,
|
|
1221
|
+
React.createElement(CheckBoxItem, { label: `${toolset.name} (${toolset.id})`, indent: 1, checked: getExtensionToolsetState(extension.id, toolset.id), onClick: () => onExtensionToolsetClicked(extension.id, toolset.id) }),
|
|
1222
|
+
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
1223
|
}
|
|
873
1224
|
function InlinePopoverComponent(props) {
|
|
874
1225
|
const [modifiedCode, setModifiedCode] = useState('');
|
|
@@ -964,7 +1315,8 @@ function InlinePromptComponent(props) {
|
|
|
964
1315
|
filename: undefined,
|
|
965
1316
|
prefix: props.prefix,
|
|
966
1317
|
suffix: props.suffix,
|
|
967
|
-
existingCode: props.existingCode
|
|
1318
|
+
existingCode: props.existingCode,
|
|
1319
|
+
chatMode: 'ask'
|
|
968
1320
|
}, {
|
|
969
1321
|
emit: async (response) => {
|
|
970
1322
|
props.onResponseEmit(response);
|
|
@@ -999,7 +1351,7 @@ function InlinePromptComponent(props) {
|
|
|
999
1351
|
}
|
|
1000
1352
|
}, []);
|
|
1001
1353
|
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
|
|
1354
|
+
React.createElement("textarea", { ref: promptInputRef, rows: 3, onChange: onPromptChange, onKeyDown: onPromptKeyDown, placeholder: "Ask Notebook Intelligence to generate Python code...", spellCheck: false, value: prompt })));
|
|
1003
1355
|
}
|
|
1004
1356
|
function GitHubCopilotStatusComponent(props) {
|
|
1005
1357
|
const [ghLoginStatus, setGHLoginStatus] = useState(GitHubCopilotLoginStatus.NotLoggedIn);
|