@notebook-intelligence/notebook-intelligence 2.4.1 → 2.5.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.
@@ -46,24 +46,15 @@ import {
46
46
  VscEyeClosed,
47
47
  VscTriangleRight,
48
48
  VscTriangleDown,
49
- VscWarning,
50
49
  VscSettingsGear,
51
50
  VscPassFilled,
52
51
  VscTools,
53
52
  VscTrash
54
53
  } from 'react-icons/vsc';
55
54
 
56
- import { MdOutlineCheckBoxOutlineBlank, MdCheckBox } from 'react-icons/md';
57
-
58
55
  import { extractLLMGeneratedCode, isDarkTheme } from './utils';
59
- import * as path from 'path';
60
-
61
- const OPENAI_COMPATIBLE_CHAT_MODEL_ID = 'openai-compatible-chat-model';
62
- const LITELLM_COMPATIBLE_CHAT_MODEL_ID = 'litellm-compatible-chat-model';
63
- const OPENAI_COMPATIBLE_INLINE_COMPLETION_MODEL_ID =
64
- 'openai-compatible-inline-completion-model';
65
- const LITELLM_COMPATIBLE_INLINE_COMPLETION_MODEL_ID =
66
- 'litellm-compatible-inline-completion-model';
56
+ import { CheckBoxItem } from './components/checkbox';
57
+ import { mcpServerSettingsToEnabledState } from './components/mcp-util';
67
58
 
68
59
  export enum RunChatCompletionType {
69
60
  Chat,
@@ -264,30 +255,6 @@ export class GitHubCopilotLoginDialogBody extends ReactWidget {
264
255
  private _onLoggedIn: () => void;
265
256
  }
266
257
 
267
- export class ConfigurationDialogBody extends ReactWidget {
268
- constructor(options: {
269
- onSave: () => void;
270
- onEditMCPConfigClicked: () => void;
271
- }) {
272
- super();
273
-
274
- this._onEditMCPConfigClicked = options.onEditMCPConfigClicked;
275
- this._onSave = options.onSave;
276
- }
277
-
278
- render(): JSX.Element {
279
- return (
280
- <ConfigurationDialogBodyComponent
281
- onEditMCPConfigClicked={this._onEditMCPConfigClicked}
282
- onSave={this._onSave}
283
- />
284
- );
285
- }
286
-
287
- private _onEditMCPConfigClicked: () => void;
288
- private _onSave: () => void;
289
- }
290
-
291
258
  interface IChatMessageContent {
292
259
  id: string;
293
260
  type: ResponseStreamDataType;
@@ -684,30 +651,6 @@ async function submitCompletionRequest(
684
651
  }
685
652
  }
686
653
 
687
- function CheckBoxItem(props: any) {
688
- const indent = props.indent || 0;
689
-
690
- return (
691
- <div
692
- className={`checkbox-item checkbox-item-indent-${indent} ${props.header ? 'checkbox-item-header' : ''}`}
693
- title={props.title}
694
- onClick={event => props.onClick(event)}
695
- >
696
- <div className="checkbox-item-toggle">
697
- {props.checked ? (
698
- <MdCheckBox className="checkbox-icon" />
699
- ) : (
700
- <MdOutlineCheckBoxOutlineBlank className="checkbox-icon" />
701
- )}
702
- {props.label}
703
- </div>
704
- {props.title && (
705
- <div className="checkbox-item-description">{props.title}</div>
706
- )}
707
- </div>
708
- );
709
- }
710
-
711
654
  function SidebarComponent(props: any) {
712
655
  const [chatMessages, setChatMessages] = useState<IChatMessage[]>([]);
713
656
  const [prompt, setPrompt] = useState<string>('');
@@ -743,7 +686,9 @@ function SidebarComponent(props: any) {
743
686
  const [selectedToolCount, setSelectedToolCount] = useState(0);
744
687
  const [notebookExecuteToolSelected, setNotebookExecuteToolSelected] =
745
688
  useState(false);
746
- const [toolConfig, setToolConfig] = useState({
689
+
690
+ const [renderCount, setRenderCount] = useState(1);
691
+ const toolConfigRef = useRef({
747
692
  builtinToolsets: [
748
693
  { id: BuiltinToolsetType.NotebookEdit, name: 'Notebook edit' },
749
694
  { id: BuiltinToolsetType.NotebookExecute, name: 'Notebook execute' }
@@ -751,6 +696,16 @@ function SidebarComponent(props: any) {
751
696
  mcpServers: [],
752
697
  extensions: []
753
698
  });
699
+ const mcpServerSettingsRef = useRef(NBIAPI.config.mcpServerSettings);
700
+ const [mcpServerEnabledState, setMCPServerEnabledState] = useState(
701
+ new Map<string, Set<string>>(
702
+ mcpServerSettingsToEnabledState(
703
+ toolConfigRef.current.mcpServers,
704
+ mcpServerSettingsRef.current
705
+ )
706
+ )
707
+ );
708
+
754
709
  const [showModeTools, setShowModeTools] = useState(false);
755
710
  const toolSelectionsInitial: any = {
756
711
  builtinToolsets: [BuiltinToolsetType.NotebookEdit],
@@ -762,25 +717,37 @@ function SidebarComponent(props: any) {
762
717
  mcpServers: {},
763
718
  extensions: {}
764
719
  };
765
- const [toolSelections, setToolSelections] = useState(toolSelectionsInitial);
720
+ const [toolSelections, setToolSelections] = useState(
721
+ structuredClone(toolSelectionsInitial)
722
+ );
766
723
  const [hasExtensionTools, setHasExtensionTools] = useState(false);
767
724
  const [lastScrollTime, setLastScrollTime] = useState(0);
768
725
  const [scrollPending, setScrollPending] = useState(false);
769
726
 
770
- NBIAPI.configChanged.connect(() => {
771
- setToolConfig(NBIAPI.config.toolConfig);
772
- });
727
+ useEffect(() => {
728
+ NBIAPI.configChanged.connect(() => {
729
+ toolConfigRef.current = NBIAPI.config.toolConfig;
730
+ mcpServerSettingsRef.current = NBIAPI.config.mcpServerSettings;
731
+ const newMcpServerEnabledState = mcpServerSettingsToEnabledState(
732
+ toolConfigRef.current.mcpServers,
733
+ mcpServerSettingsRef.current
734
+ );
735
+ setMCPServerEnabledState(newMcpServerEnabledState);
736
+ setToolSelections(structuredClone(toolSelectionsInitial));
737
+ setRenderCount(renderCount => renderCount + 1);
738
+ });
739
+ }, []);
773
740
 
774
741
  useEffect(() => {
775
742
  let hasTools = false;
776
- for (const extension of toolConfig.extensions) {
743
+ for (const extension of toolConfigRef.current.extensions) {
777
744
  if (extension.toolsets.length > 0) {
778
745
  hasTools = true;
779
746
  break;
780
747
  }
781
748
  }
782
749
  setHasExtensionTools(hasTools);
783
- }, [toolConfig]);
750
+ }, [toolConfigRef.current]);
784
751
 
785
752
  useEffect(() => {
786
753
  const builtinToolSelCount = toolSelections.builtinToolsets.length;
@@ -862,7 +829,9 @@ function SidebarComponent(props: any) {
862
829
  return false;
863
830
  }
864
831
 
865
- const mcpServer = toolConfig.mcpServers.find(server => server.id === id);
832
+ const mcpServer = toolConfigRef.current.mcpServers.find(
833
+ server => server.id === id
834
+ );
866
835
 
867
836
  const selectedServerTools: string[] = toolSelections.mcpServers[id];
868
837
 
@@ -881,10 +850,16 @@ function SidebarComponent(props: any) {
881
850
  delete newConfig.mcpServers[id];
882
851
  setToolSelections(newConfig);
883
852
  } else {
884
- const mcpServer = toolConfig.mcpServers.find(server => server.id === id);
853
+ const mcpServer = toolConfigRef.current.mcpServers.find(
854
+ server => server.id === id
855
+ );
885
856
  const newConfig = { ...toolSelections };
886
857
  newConfig.mcpServers[id] = structuredClone(
887
- mcpServer.tools.map((tool: any) => tool.name)
858
+ mcpServer.tools
859
+ .filter((tool: any) =>
860
+ mcpServerEnabledState.get(mcpServer.id).has(tool.name)
861
+ )
862
+ .map((tool: any) => tool.name)
888
863
  );
889
864
  setToolSelections(newConfig);
890
865
  }
@@ -931,7 +906,7 @@ function SidebarComponent(props: any) {
931
906
  return false;
932
907
  }
933
908
 
934
- const extension = toolConfig.extensions.find(
909
+ const extension = toolConfigRef.current.extensions.find(
935
910
  extension => extension.id === extensionId
936
911
  );
937
912
 
@@ -956,7 +931,9 @@ function SidebarComponent(props: any) {
956
931
  return false;
957
932
  }
958
933
 
959
- const extension = toolConfig.extensions.find(ext => ext.id === extensionId);
934
+ const extension = toolConfigRef.current.extensions.find(
935
+ ext => ext.id === extensionId
936
+ );
960
937
  const extensionToolset = extension.toolsets.find(
961
938
  (toolset: any) => toolset.id === toolsetId
962
939
  );
@@ -988,7 +965,7 @@ function SidebarComponent(props: any) {
988
965
  setToolSelections(newConfig);
989
966
  } else {
990
967
  const newConfig = { ...toolSelections };
991
- const extension = toolConfig.extensions.find(
968
+ const extension = toolConfigRef.current.extensions.find(
992
969
  ext => ext.id === extensionId
993
970
  );
994
971
  if (extensionId in newConfig.extensions) {
@@ -1030,7 +1007,7 @@ function SidebarComponent(props: any) {
1030
1007
  }
1031
1008
  setToolSelections(newConfig);
1032
1009
  } else {
1033
- const extension = toolConfig.extensions.find(
1010
+ const extension = toolConfigRef.current.extensions.find(
1034
1011
  ext => ext.id === extensionId
1035
1012
  );
1036
1013
  const extensionToolset = extension.toolsets.find(
@@ -1194,7 +1171,16 @@ function SidebarComponent(props: any) {
1194
1171
 
1195
1172
  const handleChatToolsButtonClick = async () => {
1196
1173
  if (!showModeTools) {
1197
- NBIAPI.fetchCapabilities();
1174
+ NBIAPI.fetchCapabilities().then(() => {
1175
+ toolConfigRef.current = NBIAPI.config.toolConfig;
1176
+ mcpServerSettingsRef.current = NBIAPI.config.mcpServerSettings;
1177
+ const newMcpServerEnabledState = mcpServerSettingsToEnabledState(
1178
+ toolConfigRef.current.mcpServers,
1179
+ mcpServerSettingsRef.current
1180
+ );
1181
+ setMCPServerEnabledState(newMcpServerEnabledState);
1182
+ setRenderCount(renderCount => renderCount + 1);
1183
+ });
1198
1184
  }
1199
1185
  setShowModeTools(!showModeTools);
1200
1186
  };
@@ -1729,10 +1715,12 @@ function SidebarComponent(props: any) {
1729
1715
  const [ghLoginRequired, setGHLoginRequired] = useState(getGHLoginRequired());
1730
1716
  const [chatEnabled, setChatEnabled] = useState(getChatEnabled());
1731
1717
 
1732
- NBIAPI.configChanged.connect(() => {
1733
- setGHLoginRequired(getGHLoginRequired());
1734
- setChatEnabled(getChatEnabled());
1735
- });
1718
+ useEffect(() => {
1719
+ NBIAPI.configChanged.connect(() => {
1720
+ setGHLoginRequired(getGHLoginRequired());
1721
+ setChatEnabled(getChatEnabled());
1722
+ });
1723
+ }, []);
1736
1724
 
1737
1725
  useEffect(() => {
1738
1726
  setGHLoginRequired(getGHLoginRequired());
@@ -1876,7 +1864,7 @@ function SidebarComponent(props: any) {
1876
1864
  if (event.target.value === 'ask') {
1877
1865
  setToolSelections(toolSelectionsEmpty);
1878
1866
  } else if (event.target.value === 'agent') {
1879
- setToolSelections(toolSelectionsInitial);
1867
+ setToolSelections(structuredClone(toolSelectionsInitial));
1880
1868
  }
1881
1869
  setShowModeTools(false);
1882
1870
  setChatMode(event.target.value);
@@ -1980,7 +1968,7 @@ function SidebarComponent(props: any) {
1980
1968
  <div className="mode-tools-popover-tool-list">
1981
1969
  <div className="mode-tools-group-header">Built-in</div>
1982
1970
  <div className="mode-tools-group mode-tools-group-built-in">
1983
- {toolConfig.builtinToolsets.map((toolset: any) => (
1971
+ {toolConfigRef.current.builtinToolsets.map((toolset: any) => (
1984
1972
  <CheckBoxItem
1985
1973
  key={toolset.id}
1986
1974
  label={toolset.name}
@@ -1995,87 +1983,111 @@ function SidebarComponent(props: any) {
1995
1983
  />
1996
1984
  ))}
1997
1985
  </div>
1998
- {toolConfig.mcpServers.length > 0 && (
1999
- <div className="mode-tools-group-header">MCP Servers</div>
2000
- )}
2001
- {toolConfig.mcpServers.map((mcpServer, index: number) => (
2002
- <div className="mode-tools-group">
2003
- <CheckBoxItem
2004
- label={mcpServer.id}
2005
- header={true}
2006
- checked={getMCPServerState(mcpServer.id)}
2007
- onClick={() => onMCPServerClicked(mcpServer.id)}
2008
- />
2009
- {mcpServer.tools.map((tool: any, index: number) => (
2010
- <CheckBoxItem
2011
- label={tool.name}
2012
- title={tool.description}
2013
- indent={1}
2014
- checked={getMCPServerToolState(mcpServer.id, tool.name)}
2015
- onClick={() =>
2016
- setMCPServerToolState(
2017
- mcpServer.id,
2018
- tool.name,
2019
- !getMCPServerToolState(mcpServer.id, tool.name)
1986
+ {renderCount > 0 &&
1987
+ mcpServerEnabledState.size > 0 &&
1988
+ toolConfigRef.current.mcpServers.length > 0 && (
1989
+ <div className="mode-tools-group-header">MCP Servers</div>
1990
+ )}
1991
+ {renderCount > 0 &&
1992
+ toolConfigRef.current.mcpServers
1993
+ .filter(mcpServer =>
1994
+ mcpServerEnabledState.has(mcpServer.id)
1995
+ )
1996
+ .map((mcpServer, index: number) => (
1997
+ <div className="mode-tools-group">
1998
+ <CheckBoxItem
1999
+ label={mcpServer.id}
2000
+ header={true}
2001
+ checked={getMCPServerState(mcpServer.id)}
2002
+ onClick={() => onMCPServerClicked(mcpServer.id)}
2003
+ />
2004
+ {mcpServer.tools
2005
+ .filter((tool: any) =>
2006
+ mcpServerEnabledState
2007
+ .get(mcpServer.id)
2008
+ .has(tool.name)
2020
2009
  )
2021
- }
2022
- />
2010
+ .map((tool: any, index: number) => (
2011
+ <CheckBoxItem
2012
+ label={tool.name}
2013
+ title={tool.description}
2014
+ indent={1}
2015
+ checked={getMCPServerToolState(
2016
+ mcpServer.id,
2017
+ tool.name
2018
+ )}
2019
+ onClick={() =>
2020
+ setMCPServerToolState(
2021
+ mcpServer.id,
2022
+ tool.name,
2023
+ !getMCPServerToolState(
2024
+ mcpServer.id,
2025
+ tool.name
2026
+ )
2027
+ )
2028
+ }
2029
+ />
2030
+ ))}
2031
+ </div>
2023
2032
  ))}
2024
- </div>
2025
- ))}
2026
2033
  {hasExtensionTools && (
2027
2034
  <div className="mode-tools-group-header">Extension tools</div>
2028
2035
  )}
2029
- {toolConfig.extensions.map((extension, index: number) => (
2030
- <div className="mode-tools-group">
2031
- <CheckBoxItem
2032
- label={`${extension.name} (${extension.id})`}
2033
- header={true}
2034
- checked={getExtensionState(extension.id)}
2035
- onClick={() => onExtensionClicked(extension.id)}
2036
- />
2037
- {extension.toolsets.map((toolset: any, index: number) => (
2038
- <>
2039
- <CheckBoxItem
2040
- label={`${toolset.name} (${toolset.id})`}
2041
- title={toolset.description}
2042
- indent={1}
2043
- checked={getExtensionToolsetState(
2044
- extension.id,
2045
- toolset.id
2046
- )}
2047
- onClick={() =>
2048
- onExtensionToolsetClicked(extension.id, toolset.id)
2049
- }
2050
- />
2051
- {toolset.tools.map((tool: any, index: number) => (
2036
+ {toolConfigRef.current.extensions.map(
2037
+ (extension, index: number) => (
2038
+ <div className="mode-tools-group">
2039
+ <CheckBoxItem
2040
+ label={`${extension.name} (${extension.id})`}
2041
+ header={true}
2042
+ checked={getExtensionState(extension.id)}
2043
+ onClick={() => onExtensionClicked(extension.id)}
2044
+ />
2045
+ {extension.toolsets.map((toolset: any, index: number) => (
2046
+ <>
2052
2047
  <CheckBoxItem
2053
- label={tool.name}
2054
- title={tool.description}
2055
- indent={2}
2056
- checked={getExtensionToolsetToolState(
2048
+ label={`${toolset.name} (${toolset.id})`}
2049
+ title={toolset.description}
2050
+ indent={1}
2051
+ checked={getExtensionToolsetState(
2057
2052
  extension.id,
2058
- toolset.id,
2059
- tool.name
2053
+ toolset.id
2060
2054
  )}
2061
2055
  onClick={() =>
2062
- setExtensionToolsetToolState(
2056
+ onExtensionToolsetClicked(
2057
+ extension.id,
2058
+ toolset.id
2059
+ )
2060
+ }
2061
+ />
2062
+ {toolset.tools.map((tool: any, index: number) => (
2063
+ <CheckBoxItem
2064
+ label={tool.name}
2065
+ title={tool.description}
2066
+ indent={2}
2067
+ checked={getExtensionToolsetToolState(
2063
2068
  extension.id,
2064
2069
  toolset.id,
2065
- tool.name,
2066
- !getExtensionToolsetToolState(
2070
+ tool.name
2071
+ )}
2072
+ onClick={() =>
2073
+ setExtensionToolsetToolState(
2067
2074
  extension.id,
2068
2075
  toolset.id,
2069
- tool.name
2076
+ tool.name,
2077
+ !getExtensionToolsetToolState(
2078
+ extension.id,
2079
+ toolset.id,
2080
+ tool.name
2081
+ )
2070
2082
  )
2071
- )
2072
- }
2073
- />
2074
- ))}
2075
- </>
2076
- ))}
2077
- </div>
2078
- ))}
2083
+ }
2084
+ />
2085
+ ))}
2086
+ </>
2087
+ ))}
2088
+ </div>
2089
+ )
2090
+ )}
2079
2091
  </div>
2080
2092
  </div>
2081
2093
  )}
@@ -2497,527 +2509,3 @@ function GitHubCopilotLoginDialogBodyComponent(props: any) {
2497
2509
  </div>
2498
2510
  );
2499
2511
  }
2500
-
2501
- function ConfigurationDialogBodyComponent(props: any) {
2502
- const nbiConfig = NBIAPI.config;
2503
- const llmProviders = nbiConfig.llmProviders;
2504
- const [chatModels, setChatModels] = useState([]);
2505
- const [inlineCompletionModels, setInlineCompletionModels] = useState([]);
2506
- const [mcpServerNames, setMcpServerNames] = useState(
2507
- nbiConfig.toolConfig.mcpServers?.map((server: any) => server.id) || []
2508
- );
2509
-
2510
- const handleSaveClick = async () => {
2511
- const config: any = {
2512
- default_chat_mode: defaultChatMode,
2513
- chat_model: {
2514
- provider: chatModelProvider,
2515
- model: chatModel,
2516
- properties: chatModelProperties
2517
- },
2518
- inline_completion_model: {
2519
- provider: inlineCompletionModelProvider,
2520
- model: inlineCompletionModel,
2521
- properties: inlineCompletionModelProperties
2522
- }
2523
- };
2524
-
2525
- if (
2526
- chatModelProvider === 'github-copilot' ||
2527
- inlineCompletionModelProvider === 'github-copilot'
2528
- ) {
2529
- config.store_github_access_token = storeGitHubAccessToken;
2530
- }
2531
-
2532
- await NBIAPI.setConfig(config);
2533
-
2534
- props.onSave();
2535
- };
2536
-
2537
- const handleRefreshOllamaModelListClick = async () => {
2538
- await NBIAPI.updateOllamaModelList();
2539
- updateModelOptionsForProvider(chatModelProvider, 'chat');
2540
- };
2541
-
2542
- const [chatModelProvider, setChatModelProvider] = useState(
2543
- nbiConfig.chatModel.provider || 'none'
2544
- );
2545
- const [inlineCompletionModelProvider, setInlineCompletionModelProvider] =
2546
- useState(nbiConfig.inlineCompletionModel.provider || 'none');
2547
- const [defaultChatMode, setDefaultChatMode] = useState<string>(
2548
- nbiConfig.defaultChatMode
2549
- );
2550
- const [chatModel, setChatModel] = useState<string>(nbiConfig.chatModel.model);
2551
- const [chatModelProperties, setChatModelProperties] = useState<any[]>([]);
2552
- const [inlineCompletionModelProperties, setInlineCompletionModelProperties] =
2553
- useState<any[]>([]);
2554
- const [inlineCompletionModel, setInlineCompletionModel] = useState(
2555
- nbiConfig.inlineCompletionModel.model
2556
- );
2557
- const [storeGitHubAccessToken, setStoreGitHubAccessToken] = useState(
2558
- nbiConfig.storeGitHubAccessToken
2559
- );
2560
-
2561
- const updateModelOptionsForProvider = (
2562
- providerId: string,
2563
- modelType: 'chat' | 'inline-completion'
2564
- ) => {
2565
- if (modelType === 'chat') {
2566
- setChatModelProvider(providerId);
2567
- } else {
2568
- setInlineCompletionModelProvider(providerId);
2569
- }
2570
- const models =
2571
- modelType === 'chat'
2572
- ? nbiConfig.chatModels
2573
- : nbiConfig.inlineCompletionModels;
2574
- const selectedModelId =
2575
- modelType === 'chat'
2576
- ? nbiConfig.chatModel.model
2577
- : nbiConfig.inlineCompletionModel.model;
2578
-
2579
- const providerModels = models.filter(
2580
- (model: any) => model.provider === providerId
2581
- );
2582
- if (modelType === 'chat') {
2583
- setChatModels(providerModels);
2584
- } else {
2585
- setInlineCompletionModels(providerModels);
2586
- }
2587
- let selectedModel = providerModels.find(
2588
- (model: any) => model.id === selectedModelId
2589
- );
2590
- if (!selectedModel) {
2591
- selectedModel = providerModels?.[0];
2592
- }
2593
- if (selectedModel) {
2594
- if (modelType === 'chat') {
2595
- setChatModel(selectedModel.id);
2596
- setChatModelProperties(selectedModel.properties);
2597
- } else {
2598
- setInlineCompletionModel(selectedModel.id);
2599
- setInlineCompletionModelProperties(selectedModel.properties);
2600
- }
2601
- } else {
2602
- if (modelType === 'chat') {
2603
- setChatModelProperties([]);
2604
- } else {
2605
- setInlineCompletionModelProperties([]);
2606
- }
2607
- }
2608
- };
2609
-
2610
- const onModelPropertyChange = (
2611
- modelType: 'chat' | 'inline-completion',
2612
- propertyId: string,
2613
- value: string
2614
- ) => {
2615
- const modelProperties =
2616
- modelType === 'chat'
2617
- ? chatModelProperties
2618
- : inlineCompletionModelProperties;
2619
- const updatedProperties = modelProperties.map((property: any) => {
2620
- if (property.id === propertyId) {
2621
- return { ...property, value };
2622
- }
2623
- return property;
2624
- });
2625
- if (modelType === 'chat') {
2626
- setChatModelProperties(updatedProperties);
2627
- } else {
2628
- setInlineCompletionModelProperties(updatedProperties);
2629
- }
2630
- };
2631
-
2632
- const handleReloadMCPServersClick = async () => {
2633
- const data = await NBIAPI.reloadMCPServerList();
2634
- setMcpServerNames(data.mcpServers?.map((server: any) => server.id) || []);
2635
- };
2636
-
2637
- useEffect(() => {
2638
- updateModelOptionsForProvider(chatModelProvider, 'chat');
2639
- updateModelOptionsForProvider(
2640
- inlineCompletionModelProvider,
2641
- 'inline-completion'
2642
- );
2643
- }, []);
2644
-
2645
- return (
2646
- <div className="config-dialog">
2647
- <div className="config-dialog-body">
2648
- <div className="model-config-section">
2649
- <div className="model-config-section-header">Default chat mode</div>
2650
- <div className="model-config-section-body">
2651
- <div className="model-config-section-row">
2652
- <div className="model-config-section-column">
2653
- <div>
2654
- <select
2655
- className="jp-mod-styled"
2656
- value={defaultChatMode}
2657
- onChange={event => setDefaultChatMode(event.target.value)}
2658
- >
2659
- <option value="ask">Ask</option>
2660
- <option value="agent">Agent</option>
2661
- </select>
2662
- </div>
2663
- </div>
2664
- <div className="model-config-section-column"> </div>
2665
- </div>
2666
- </div>
2667
- </div>
2668
-
2669
- <div className="model-config-section">
2670
- <div className="model-config-section-header">Chat model</div>
2671
- <div className="model-config-section-body">
2672
- <div className="model-config-section-row">
2673
- <div className="model-config-section-column">
2674
- <div>Provider</div>
2675
- <div>
2676
- <select
2677
- className="jp-mod-styled"
2678
- onChange={event =>
2679
- updateModelOptionsForProvider(event.target.value, 'chat')
2680
- }
2681
- >
2682
- {llmProviders.map((provider: any, index: number) => (
2683
- <option
2684
- key={index}
2685
- value={provider.id}
2686
- selected={provider.id === chatModelProvider}
2687
- >
2688
- {provider.name}
2689
- </option>
2690
- ))}
2691
- <option
2692
- key={-1}
2693
- value="none"
2694
- selected={
2695
- chatModelProvider === 'none' ||
2696
- !llmProviders.find(
2697
- provider => provider.id === chatModelProvider
2698
- )
2699
- }
2700
- >
2701
- None
2702
- </option>
2703
- </select>
2704
- </div>
2705
- </div>
2706
- {!['openai-compatible', 'litellm-compatible', 'none'].includes(
2707
- chatModelProvider
2708
- ) &&
2709
- chatModels.length > 0 && (
2710
- <div className="model-config-section-column">
2711
- <div>Model</div>
2712
- {![
2713
- OPENAI_COMPATIBLE_CHAT_MODEL_ID,
2714
- LITELLM_COMPATIBLE_CHAT_MODEL_ID
2715
- ].includes(chatModel) &&
2716
- chatModels.length > 0 && (
2717
- <div>
2718
- <select
2719
- className="jp-mod-styled"
2720
- onChange={event => setChatModel(event.target.value)}
2721
- >
2722
- {chatModels.map((model: any, index: number) => (
2723
- <option
2724
- key={index}
2725
- value={model.id}
2726
- selected={model.id === chatModel}
2727
- >
2728
- {model.name}
2729
- </option>
2730
- ))}
2731
- </select>
2732
- </div>
2733
- )}
2734
- </div>
2735
- )}
2736
- </div>
2737
-
2738
- <div className="model-config-section-row">
2739
- <div className="model-config-section-column">
2740
- {chatModelProvider === 'ollama' && chatModels.length === 0 && (
2741
- <div className="ollama-warning-message">
2742
- No Ollama models found! Make sure{' '}
2743
- <a href="https://ollama.com/" target="_blank">
2744
- Ollama
2745
- </a>{' '}
2746
- is running and models are downloaded to your computer.{' '}
2747
- <a
2748
- href="javascript:void(0)"
2749
- onClick={handleRefreshOllamaModelListClick}
2750
- >
2751
- Try again
2752
- </a>{' '}
2753
- once ready.
2754
- </div>
2755
- )}
2756
- </div>
2757
- </div>
2758
-
2759
- <div className="model-config-section-row">
2760
- <div className="model-config-section-column">
2761
- {chatModelProperties.map((property: any, index: number) => (
2762
- <div className="form-field-row" key={index}>
2763
- <div className="form-field-description">
2764
- {property.name} {property.optional ? '(optional)' : ''}
2765
- </div>
2766
- <input
2767
- name="chat-model-id-input"
2768
- placeholder={property.description}
2769
- className="jp-mod-styled"
2770
- spellCheck={false}
2771
- value={property.value}
2772
- onChange={event =>
2773
- onModelPropertyChange(
2774
- 'chat',
2775
- property.id,
2776
- event.target.value
2777
- )
2778
- }
2779
- />
2780
- </div>
2781
- ))}
2782
- </div>
2783
- </div>
2784
- </div>
2785
- </div>
2786
-
2787
- <div className="model-config-section">
2788
- <div className="model-config-section-header">Auto-complete model</div>
2789
- <div className="model-config-section-body">
2790
- <div className="model-config-section-row">
2791
- <div className="model-config-section-column">
2792
- <div>Provider</div>
2793
- <div>
2794
- <select
2795
- className="jp-mod-styled"
2796
- onChange={event =>
2797
- updateModelOptionsForProvider(
2798
- event.target.value,
2799
- 'inline-completion'
2800
- )
2801
- }
2802
- >
2803
- {llmProviders.map((provider: any, index: number) => (
2804
- <option
2805
- key={index}
2806
- value={provider.id}
2807
- selected={provider.id === inlineCompletionModelProvider}
2808
- >
2809
- {provider.name}
2810
- </option>
2811
- ))}
2812
- <option
2813
- key={-1}
2814
- value="none"
2815
- selected={
2816
- inlineCompletionModelProvider === 'none' ||
2817
- !llmProviders.find(
2818
- provider =>
2819
- provider.id === inlineCompletionModelProvider
2820
- )
2821
- }
2822
- >
2823
- None
2824
- </option>
2825
- </select>
2826
- </div>
2827
- </div>
2828
- {!['openai-compatible', 'litellm-compatible', 'none'].includes(
2829
- inlineCompletionModelProvider
2830
- ) && (
2831
- <div className="model-config-section-column">
2832
- <div>Model</div>
2833
- {![
2834
- OPENAI_COMPATIBLE_INLINE_COMPLETION_MODEL_ID,
2835
- LITELLM_COMPATIBLE_INLINE_COMPLETION_MODEL_ID
2836
- ].includes(inlineCompletionModel) && (
2837
- <div>
2838
- <select
2839
- className="jp-mod-styled"
2840
- onChange={event =>
2841
- setInlineCompletionModel(event.target.value)
2842
- }
2843
- >
2844
- {inlineCompletionModels.map(
2845
- (model: any, index: number) => (
2846
- <option
2847
- key={index}
2848
- value={model.id}
2849
- selected={model.id === inlineCompletionModel}
2850
- >
2851
- {model.name}
2852
- </option>
2853
- )
2854
- )}
2855
- </select>
2856
- </div>
2857
- )}
2858
- </div>
2859
- )}
2860
- </div>
2861
-
2862
- <div className="model-config-section-row">
2863
- <div className="model-config-section-column">
2864
- {inlineCompletionModelProperties.map(
2865
- (property: any, index: number) => (
2866
- <div className="form-field-row" key={index}>
2867
- <div className="form-field-description">
2868
- {property.name} {property.optional ? '(optional)' : ''}
2869
- </div>
2870
- <input
2871
- name="inline-completion-model-id-input"
2872
- placeholder={property.description}
2873
- className="jp-mod-styled"
2874
- spellCheck={false}
2875
- value={property.value}
2876
- onChange={event =>
2877
- onModelPropertyChange(
2878
- 'inline-completion',
2879
- property.id,
2880
- event.target.value
2881
- )
2882
- }
2883
- />
2884
- </div>
2885
- )
2886
- )}
2887
- </div>
2888
- </div>
2889
- </div>
2890
- </div>
2891
-
2892
- {(chatModelProvider === 'github-copilot' ||
2893
- inlineCompletionModelProvider === 'github-copilot') && (
2894
- <div className="model-config-section">
2895
- <div className="model-config-section-header access-token-config-header">
2896
- GitHub Copilot login{' '}
2897
- <a
2898
- href="https://github.com/notebook-intelligence/notebook-intelligence/blob/main/README.md#remembering-github-copilot-login"
2899
- target="_blank"
2900
- >
2901
- {' '}
2902
- <VscWarning
2903
- className="access-token-warning"
2904
- title="Click to learn more about security implications"
2905
- />
2906
- </a>
2907
- </div>
2908
- <div className="model-config-section-body">
2909
- <div className="model-config-section-row">
2910
- <div className="model-config-section-column">
2911
- <label>
2912
- <input
2913
- type="checkbox"
2914
- checked={storeGitHubAccessToken}
2915
- onChange={event => {
2916
- setStoreGitHubAccessToken(event.target.checked);
2917
- }}
2918
- />
2919
- Remember my GitHub Copilot access token
2920
- </label>
2921
- </div>
2922
- </div>
2923
- </div>
2924
- </div>
2925
- )}
2926
-
2927
- <div className="model-config-section">
2928
- <div className="model-config-section-header">
2929
- MCP Servers ({mcpServerNames.length}) [
2930
- <a href="javascript:void(0)" onClick={props.onEditMCPConfigClicked}>
2931
- edit
2932
- </a>
2933
- ]
2934
- </div>
2935
- <div className="model-config-section-body">
2936
- <div className="model-config-section-row">
2937
- <div className="model-config-section-column">
2938
- {mcpServerNames.length === 0 && (
2939
- <div>
2940
- No MCP servers found. Add MCP servers in the configuration
2941
- file.
2942
- </div>
2943
- )}
2944
- {mcpServerNames.length > 0 && (
2945
- <div>{mcpServerNames.sort().join(', ')}</div>
2946
- )}
2947
- </div>
2948
- <div
2949
- className="model-config-section-column"
2950
- style={{ flexGrow: 'initial' }}
2951
- >
2952
- <button
2953
- className="jp-Dialog-button jp-mod-reject jp-mod-styled"
2954
- onClick={handleReloadMCPServersClick}
2955
- >
2956
- <div className="jp-Dialog-buttonLabel">Reload</div>
2957
- </button>
2958
- </div>
2959
- </div>
2960
- </div>
2961
- </div>
2962
-
2963
- <div className="model-config-section">
2964
- <div className="model-config-section-header">Config file path</div>
2965
- <div className="model-config-section-body">
2966
- <div className="model-config-section-row">
2967
- <div className="model-config-section-column">
2968
- <span
2969
- className="user-code-span"
2970
- onClick={() => {
2971
- navigator.clipboard.writeText(
2972
- path.join(NBIAPI.config.userConfigDir, 'config.json')
2973
- );
2974
- return true;
2975
- }}
2976
- >
2977
- {path.join(NBIAPI.config.userConfigDir, 'config.json')}{' '}
2978
- <span
2979
- className="copy-icon"
2980
- dangerouslySetInnerHTML={{ __html: copySvgstr }}
2981
- ></span>
2982
- </span>
2983
- </div>
2984
- </div>
2985
- </div>
2986
- <div className="model-config-section-header">
2987
- MCP config file path
2988
- </div>
2989
- <div className="model-config-section-body">
2990
- <div className="model-config-section-row">
2991
- <div className="model-config-section-column">
2992
- <span
2993
- className="user-code-span"
2994
- onClick={() => {
2995
- navigator.clipboard.writeText(
2996
- path.join(NBIAPI.config.userConfigDir, 'mcp.json')
2997
- );
2998
- return true;
2999
- }}
3000
- >
3001
- {path.join(NBIAPI.config.userConfigDir, 'mcp.json')}{' '}
3002
- <span
3003
- className="copy-icon"
3004
- dangerouslySetInnerHTML={{ __html: copySvgstr }}
3005
- ></span>
3006
- </span>
3007
- </div>
3008
- </div>
3009
- </div>
3010
- </div>
3011
- </div>
3012
-
3013
- <div className="config-dialog-footer">
3014
- <button
3015
- className="jp-Dialog-button jp-mod-accept jp-mod-styled"
3016
- onClick={handleSaveClick}
3017
- >
3018
- <div className="jp-Dialog-buttonLabel">Save</div>
3019
- </button>
3020
- </div>
3021
- </div>
3022
- );
3023
- }