@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 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 diabled and not available in `@mcp` chat participant.
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: { chatId, prompt, language, filename, additionalContext }
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) {
@@ -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;
@@ -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' ? 'User' : ((_c = msg.participant) === null || _c === void 0 ? void 0 : _c.name) || 'Copilot'),
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 Copilot...", spellCheck: false, value: prompt }),
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 Copilot to generate Python code...", spellCheck: false, value: prompt })));
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);