@notebook-intelligence/notebook-intelligence 4.2.1 → 4.3.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/lib/api.d.ts CHANGED
@@ -11,6 +11,8 @@ export interface IDeviceVerificationInfo {
11
11
  userCode: string;
12
12
  }
13
13
  export declare enum ClaudeModelType {
14
+ None = "none",
15
+ Inherit = "inherit",
14
16
  Default = "",
15
17
  ClaudeOpus45 = "claude-opus-4-5",
16
18
  ClaudeHaiku45 = "claude-haiku-4-5"
@@ -30,6 +32,7 @@ export declare class NBIConfig {
30
32
  get inlineCompletionModel(): any;
31
33
  get usingGitHubCopilotModel(): boolean;
32
34
  get storeGitHubAccessToken(): boolean;
35
+ get inlineCompletionDebouncerDelay(): number;
33
36
  get toolConfig(): any;
34
37
  get mcpServers(): any;
35
38
  getMCPServer(serverId: string): any;
package/lib/api.js CHANGED
@@ -15,6 +15,8 @@ export var GitHubCopilotLoginStatus;
15
15
  })(GitHubCopilotLoginStatus || (GitHubCopilotLoginStatus = {}));
16
16
  export var ClaudeModelType;
17
17
  (function (ClaudeModelType) {
18
+ ClaudeModelType["None"] = "none";
19
+ ClaudeModelType["Inherit"] = "inherit";
18
20
  ClaudeModelType["Default"] = "";
19
21
  ClaudeModelType["ClaudeOpus45"] = "claude-opus-4-5";
20
22
  ClaudeModelType["ClaudeHaiku45"] = "claude-haiku-4-5";
@@ -61,6 +63,11 @@ export class NBIConfig {
61
63
  get storeGitHubAccessToken() {
62
64
  return this.capabilities.store_github_access_token === true;
63
65
  }
66
+ get inlineCompletionDebouncerDelay() {
67
+ return Number.isInteger(this.capabilities.inline_completion_debouncer_delay)
68
+ ? this.capabilities.inline_completion_debouncer_delay
69
+ : 200;
70
+ }
64
71
  get toolConfig() {
65
72
  return this.capabilities.tool_config;
66
73
  }
@@ -38,6 +38,12 @@ function SettingsPanelComponent(props) {
38
38
  }
39
39
  function SettingsPanelTabsComponent(props) {
40
40
  const [activeTab, setActiveTab] = useState(props.activeTab);
41
+ const [isInClaudeCodeMode, setIsInClaudeCodeMode] = useState(NBIAPI.config.isInClaudeCodeMode);
42
+ useEffect(() => {
43
+ NBIAPI.configChanged.connect(() => {
44
+ setIsInClaudeCodeMode(NBIAPI.config.isInClaudeCodeMode);
45
+ });
46
+ }, []);
41
47
  return (React.createElement("div", null,
42
48
  React.createElement("div", { className: `nbi-settings-panel-tab ${activeTab === 'general' ? 'active' : ''}`, onClick: () => {
43
49
  setActiveTab('general');
@@ -49,16 +55,17 @@ function SettingsPanelTabsComponent(props) {
49
55
  } },
50
56
  React.createElement("span", { className: "claude-icon", dangerouslySetInnerHTML: { __html: claudeSvgStr } }),
51
57
  "Claude"),
52
- React.createElement("div", { className: `nbi-settings-panel-tab ${activeTab === 'mcp-servers' ? 'active' : ''}`, onClick: () => {
58
+ !isInClaudeCodeMode && (React.createElement("div", { className: `nbi-settings-panel-tab ${activeTab === 'mcp-servers' ? 'active' : ''}`, onClick: () => {
53
59
  setActiveTab('mcp-servers');
54
60
  props.onTabSelected('mcp-servers');
55
- } }, "MCP Servers")));
61
+ } }, "MCP Servers"))));
56
62
  }
57
63
  function SettingsPanelComponentGeneral(props) {
58
64
  const nbiConfig = NBIAPI.config;
59
65
  const llmProviders = nbiConfig.llmProviders;
60
66
  const [chatModels, setChatModels] = useState([]);
61
67
  const [inlineCompletionModels, setInlineCompletionModels] = useState([]);
68
+ const isInClaudeCodeMode = nbiConfig.isInClaudeCodeMode;
62
69
  const handleSaveSettings = async () => {
63
70
  const config = {
64
71
  default_chat_mode: defaultChatMode,
@@ -71,7 +78,8 @@ function SettingsPanelComponentGeneral(props) {
71
78
  provider: inlineCompletionModelProvider,
72
79
  model: inlineCompletionModel,
73
80
  properties: inlineCompletionModelProperties
74
- }
81
+ },
82
+ inline_completion_debouncer_delay: inlineCompletionDebouncerDelay
75
83
  };
76
84
  if (chatModelProvider === 'github-copilot' ||
77
85
  inlineCompletionModelProvider === 'github-copilot') {
@@ -92,6 +100,7 @@ function SettingsPanelComponentGeneral(props) {
92
100
  const [inlineCompletionModelProperties, setInlineCompletionModelProperties] = useState([]);
93
101
  const [inlineCompletionModel, setInlineCompletionModel] = useState(nbiConfig.inlineCompletionModel.model);
94
102
  const [storeGitHubAccessToken, setStoreGitHubAccessToken] = useState(nbiConfig.storeGitHubAccessToken);
103
+ const [inlineCompletionDebouncerDelay, setInlineCompletionDebouncerDelay] = useState(nbiConfig.inlineCompletionDebouncerDelay);
95
104
  const updateModelOptionsForProvider = (providerId, modelType) => {
96
105
  if (modelType === 'chat') {
97
106
  setChatModelProvider(providerId);
@@ -166,11 +175,12 @@ function SettingsPanelComponentGeneral(props) {
166
175
  inlineCompletionModelProvider,
167
176
  inlineCompletionModel,
168
177
  inlineCompletionModelProperties,
169
- storeGitHubAccessToken
178
+ storeGitHubAccessToken,
179
+ inlineCompletionDebouncerDelay
170
180
  ]);
171
181
  return (React.createElement("div", { className: "config-dialog" },
172
182
  React.createElement("div", { className: "config-dialog-body" },
173
- React.createElement("div", { className: "model-config-section" },
183
+ !isInClaudeCodeMode && (React.createElement("div", { className: "model-config-section" },
174
184
  React.createElement("div", { className: "model-config-section-header" }, "Default chat mode"),
175
185
  React.createElement("div", { className: "model-config-section-body" },
176
186
  React.createElement("div", { className: "model-config-section-row" },
@@ -179,8 +189,8 @@ function SettingsPanelComponentGeneral(props) {
179
189
  React.createElement("select", { className: "jp-mod-styled", value: defaultChatMode, onChange: event => setDefaultChatMode(event.target.value) },
180
190
  React.createElement("option", { value: "ask" }, "Ask"),
181
191
  React.createElement("option", { value: "agent" }, "Agent")))),
182
- React.createElement("div", { className: "model-config-section-column" }, " ")))),
183
- React.createElement("div", { className: "model-config-section" },
192
+ React.createElement("div", { className: "model-config-section-column" }, " "))))),
193
+ !isInClaudeCodeMode && (React.createElement("div", { className: "model-config-section" },
184
194
  React.createElement("div", { className: "model-config-section-header" }, "Chat model"),
185
195
  React.createElement("div", { className: "model-config-section-body" },
186
196
  React.createElement("div", { className: "model-config-section-row" },
@@ -201,7 +211,8 @@ function SettingsPanelComponentGeneral(props) {
201
211
  chatModels.length > 0 && (React.createElement("div", null,
202
212
  React.createElement("select", { className: "jp-mod-styled", onChange: event => setChatModel(event.target.value) }, chatModels.map((model, index) => (React.createElement("option", { key: index, value: model.id, selected: model.id === chatModel }, model.name))))))))),
203
213
  React.createElement("div", { className: "model-config-section-row" },
204
- React.createElement("div", { className: "model-config-section-column" }, chatModelProvider === 'ollama' && chatModels.length === 0 && (React.createElement("div", { className: "ollama-warning-message" },
214
+ React.createElement("div", { className: "model-config-section-column" }, chatModelProvider === 'ollama' &&
215
+ chatModels.length === 0 && (React.createElement("div", { className: "ollama-warning-message" },
205
216
  "No Ollama models found! Make sure",
206
217
  ' ',
207
218
  React.createElement("a", { href: "https://ollama.com/", target: "_blank" }, "Ollama"),
@@ -217,7 +228,7 @@ function SettingsPanelComponentGeneral(props) {
217
228
  property.name,
218
229
  " ",
219
230
  property.optional ? '(optional)' : ''),
220
- React.createElement("input", { name: "chat-model-id-input", placeholder: property.description, className: "jp-mod-styled", spellCheck: false, value: property.value, onChange: event => onModelPropertyChange('chat', property.id, event.target.value) })))))))),
231
+ React.createElement("input", { name: "chat-model-id-input", placeholder: property.description, className: "jp-mod-styled", spellCheck: false, value: property.value, onChange: event => onModelPropertyChange('chat', property.id, event.target.value) }))))))))),
221
232
  React.createElement("div", { className: "model-config-section" },
222
233
  React.createElement("div", { className: "model-config-section-header" }, "Auto-complete model"),
223
234
  React.createElement("div", { className: "model-config-section-body" },
@@ -243,8 +254,14 @@ function SettingsPanelComponentGeneral(props) {
243
254
  " ",
244
255
  property.optional ? '(optional)' : ''),
245
256
  React.createElement("input", { name: "inline-completion-model-id-input", placeholder: property.description, className: "jp-mod-styled", spellCheck: false, value: property.value, onChange: event => onModelPropertyChange('inline-completion', property.id, event.target.value) })))))))),
246
- (chatModelProvider === 'github-copilot' ||
247
- inlineCompletionModelProvider === 'github-copilot') && (React.createElement("div", { className: "model-config-section" },
257
+ React.createElement("div", { className: "model-config-section-row", style: { width: '50%' } },
258
+ React.createElement("div", { className: "model-config-section-column" },
259
+ React.createElement("div", { className: "form-field-row", style: { paddingLeft: '10px' } },
260
+ React.createElement("div", { className: "form-field-description" }, "Auto-complete debouncer delay (ms)"),
261
+ React.createElement("input", { name: "inline-completion-debouncer-delay-input", placeholder: "Auto-complete debouncer delay (milliseconds)", className: "jp-mod-styled", spellCheck: false, value: inlineCompletionDebouncerDelay, type: "number", onChange: event => setInlineCompletionDebouncerDelay(Number(event.target.value)) })))),
262
+ !isInClaudeCodeMode &&
263
+ (chatModelProvider === 'github-copilot' ||
264
+ inlineCompletionModelProvider === 'github-copilot') && (React.createElement("div", { className: "model-config-section" },
248
265
  React.createElement("div", { className: "model-config-section-header access-token-config-header" },
249
266
  "GitHub Copilot login",
250
267
  ' ',
@@ -387,7 +404,7 @@ function SettingsPanelComponentMCPServers(props) {
387
404
  React.createElement("div", { className: "jp-Dialog-buttonLabel" }, "Add / Edit")))))))));
388
405
  }
389
406
  function SettingsPanelComponentClaude(props) {
390
- var _a, _b, _c, _d, _e, _f;
407
+ var _a, _b, _c, _d, _e, _f, _g;
391
408
  const nbiConfig = NBIAPI.config;
392
409
  const claudeSettingsRef = useRef(nbiConfig.claudeSettings);
393
410
  const [_renderCount, setRenderCount] = useState(1);
@@ -401,6 +418,7 @@ function SettingsPanelComponentClaude(props) {
401
418
  ClaudeToolType.ClaudeCodeTools,
402
419
  ClaudeToolType.JupyterUITools
403
420
  ]);
421
+ const [continueConversation, setContinueConversation] = useState((_g = nbiConfig.claudeSettings.continue_conversation) !== null && _g !== void 0 ? _g : false);
404
422
  useEffect(() => {
405
423
  NBIAPI.configChanged.connect(() => {
406
424
  claudeSettingsRef.current = nbiConfig.claudeSettings;
@@ -416,7 +434,8 @@ function SettingsPanelComponentClaude(props) {
416
434
  api_key: apiKey,
417
435
  base_url: baseUrl,
418
436
  setting_sources: settingSources,
419
- tools: tools
437
+ tools: tools,
438
+ continue_conversation: continueConversation
420
439
  }
421
440
  });
422
441
  };
@@ -429,7 +448,8 @@ function SettingsPanelComponentClaude(props) {
429
448
  apiKey,
430
449
  baseUrl,
431
450
  settingSources,
432
- tools
451
+ tools,
452
+ continueConversation
433
453
  ]);
434
454
  return (React.createElement("div", { className: "config-dialog claude-mode-config-dialog" },
435
455
  React.createElement("div", { className: "config-dialog-body" },
@@ -468,6 +488,8 @@ function SettingsPanelComponentClaude(props) {
468
488
  React.createElement("div", null, "Auto-complete model"),
469
489
  React.createElement("div", null,
470
490
  React.createElement("select", { className: "jp-mod-styled", onChange: event => setInlineCompletionModel(event.target.value) },
491
+ React.createElement("option", { value: ClaudeModelType.None, selected: inlineCompletionModel === ClaudeModelType.None }, "None"),
492
+ React.createElement("option", { value: ClaudeModelType.Inherit, selected: inlineCompletionModel === ClaudeModelType.Inherit }, "Inherit from general settings"),
471
493
  React.createElement("option", { value: ClaudeModelType.Default, selected: inlineCompletionModel === ClaudeModelType.Default }, "Default (recommended)"),
472
494
  React.createElement("option", { value: ClaudeModelType.ClaudeOpus45, selected: inlineCompletionModel === ClaudeModelType.ClaudeOpus45 }, "Claude Opus 4.5"),
473
495
  React.createElement("option", { value: ClaudeModelType.ClaudeHaiku45, selected: inlineCompletionModel === ClaudeModelType.ClaudeHaiku45 }, "Claude Haiku 4.5"))))))),
@@ -507,6 +529,15 @@ function SettingsPanelComponentClaude(props) {
507
529
  ? tools.filter((tool) => tool !== ClaudeToolType.JupyterUITools)
508
530
  : [...tools, ClaudeToolType.JupyterUITools]);
509
531
  } })))))),
532
+ React.createElement("div", { className: "model-config-section" },
533
+ React.createElement("div", { className: "model-config-section-header" }, "Conversation History"),
534
+ React.createElement("div", { className: "model-config-section-body" },
535
+ React.createElement("div", { className: "model-config-section-row" },
536
+ React.createElement("div", { className: "model-config-section-column" },
537
+ React.createElement("div", null,
538
+ React.createElement(CheckBoxItem, { header: true, label: "Remember conversation history", checked: continueConversation, onClick: () => {
539
+ setContinueConversation(!continueConversation);
540
+ } })))))),
510
541
  React.createElement("div", { className: "model-config-section" },
511
542
  React.createElement("div", { className: "model-config-section-header" }, "Claude account"),
512
543
  React.createElement("div", { className: "model-config-section-body" },
package/lib/index.js CHANGED
@@ -239,7 +239,7 @@ class NBIInlineCompletionProvider {
239
239
  get schema() {
240
240
  return {
241
241
  default: {
242
- debouncerDelay: 200,
242
+ debouncerDelay: NBIAPI.config.inlineCompletionDebouncerDelay,
243
243
  timeout: 15000
244
244
  }
245
245
  };
@@ -344,7 +344,10 @@ class NBIInlineCompletionProvider {
344
344
  return '@notebook-intelligence/notebook-intelligence';
345
345
  }
346
346
  get icon() {
347
- return NBIAPI.config.isInClaudeCodeMode
347
+ const isClaudeModel = NBIAPI.config.isInClaudeCodeMode &&
348
+ NBIAPI.config.claudeSettings.inline_completion_model !== 'none' &&
349
+ NBIAPI.config.claudeSettings.inline_completion_model !== 'inherit';
350
+ return isClaudeModel
348
351
  ? claudeIcon
349
352
  : NBIAPI.config.usingGitHubCopilotModel
350
353
  ? githubCopilotIcon
@@ -550,7 +553,7 @@ const plugin = {
550
553
  }
551
554
  });
552
555
  panel.addWidget(sidebar);
553
- app.shell.add(panel, 'right', { rank: 1000 });
556
+ app.shell.add(panel, 'left', { rank: 1000 });
554
557
  app.shell.activateById(panel.id);
555
558
  const updateSidebarIcon = () => {
556
559
  if (NBIAPI.getChatEnabled()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notebook-intelligence/notebook-intelligence",
3
- "version": "4.2.1",
3
+ "version": "4.3.0",
4
4
  "description": "AI coding assistant for JupyterLab",
5
5
  "keywords": [
6
6
  "AI",
package/src/api.ts CHANGED
@@ -30,6 +30,8 @@ export interface IDeviceVerificationInfo {
30
30
  }
31
31
 
32
32
  export enum ClaudeModelType {
33
+ None = 'none',
34
+ Inherit = 'inherit',
33
35
  Default = '',
34
36
  ClaudeOpus45 = 'claude-opus-4-5',
35
37
  ClaudeHaiku45 = 'claude-haiku-4-5'
@@ -84,6 +86,12 @@ export class NBIConfig {
84
86
  return this.capabilities.store_github_access_token === true;
85
87
  }
86
88
 
89
+ get inlineCompletionDebouncerDelay(): number {
90
+ return Number.isInteger(this.capabilities.inline_completion_debouncer_delay)
91
+ ? this.capabilities.inline_completion_debouncer_delay
92
+ : 200;
93
+ }
94
+
87
95
  get toolConfig(): any {
88
96
  return this.capabilities.tool_config;
89
97
  }
@@ -82,6 +82,15 @@ function SettingsPanelComponent(props: any) {
82
82
 
83
83
  function SettingsPanelTabsComponent(props: any) {
84
84
  const [activeTab, setActiveTab] = useState(props.activeTab);
85
+ const [isInClaudeCodeMode, setIsInClaudeCodeMode] = useState(
86
+ NBIAPI.config.isInClaudeCodeMode
87
+ );
88
+
89
+ useEffect(() => {
90
+ NBIAPI.configChanged.connect(() => {
91
+ setIsInClaudeCodeMode(NBIAPI.config.isInClaudeCodeMode);
92
+ });
93
+ }, []);
85
94
 
86
95
  return (
87
96
  <div>
@@ -107,15 +116,17 @@ function SettingsPanelTabsComponent(props: any) {
107
116
  ></span>
108
117
  Claude
109
118
  </div>
110
- <div
111
- className={`nbi-settings-panel-tab ${activeTab === 'mcp-servers' ? 'active' : ''}`}
112
- onClick={() => {
113
- setActiveTab('mcp-servers');
114
- props.onTabSelected('mcp-servers');
115
- }}
116
- >
117
- MCP Servers
118
- </div>
119
+ {!isInClaudeCodeMode && (
120
+ <div
121
+ className={`nbi-settings-panel-tab ${activeTab === 'mcp-servers' ? 'active' : ''}`}
122
+ onClick={() => {
123
+ setActiveTab('mcp-servers');
124
+ props.onTabSelected('mcp-servers');
125
+ }}
126
+ >
127
+ MCP Servers
128
+ </div>
129
+ )}
119
130
  </div>
120
131
  );
121
132
  }
@@ -125,6 +136,7 @@ function SettingsPanelComponentGeneral(props: any) {
125
136
  const llmProviders = nbiConfig.llmProviders;
126
137
  const [chatModels, setChatModels] = useState([]);
127
138
  const [inlineCompletionModels, setInlineCompletionModels] = useState([]);
139
+ const isInClaudeCodeMode = nbiConfig.isInClaudeCodeMode;
128
140
 
129
141
  const handleSaveSettings = async () => {
130
142
  const config: any = {
@@ -138,7 +150,8 @@ function SettingsPanelComponentGeneral(props: any) {
138
150
  provider: inlineCompletionModelProvider,
139
151
  model: inlineCompletionModel,
140
152
  properties: inlineCompletionModelProperties
141
- }
153
+ },
154
+ inline_completion_debouncer_delay: inlineCompletionDebouncerDelay
142
155
  };
143
156
 
144
157
  if (
@@ -176,6 +189,8 @@ function SettingsPanelComponentGeneral(props: any) {
176
189
  const [storeGitHubAccessToken, setStoreGitHubAccessToken] = useState(
177
190
  nbiConfig.storeGitHubAccessToken
178
191
  );
192
+ const [inlineCompletionDebouncerDelay, setInlineCompletionDebouncerDelay] =
193
+ useState(nbiConfig.inlineCompletionDebouncerDelay);
179
194
 
180
195
  const updateModelOptionsForProvider = (
181
196
  providerId: string,
@@ -266,150 +281,161 @@ function SettingsPanelComponentGeneral(props: any) {
266
281
  inlineCompletionModelProvider,
267
282
  inlineCompletionModel,
268
283
  inlineCompletionModelProperties,
269
- storeGitHubAccessToken
284
+ storeGitHubAccessToken,
285
+ inlineCompletionDebouncerDelay
270
286
  ]);
271
287
 
272
288
  return (
273
289
  <div className="config-dialog">
274
290
  <div className="config-dialog-body">
275
- <div className="model-config-section">
276
- <div className="model-config-section-header">Default chat mode</div>
277
- <div className="model-config-section-body">
278
- <div className="model-config-section-row">
279
- <div className="model-config-section-column">
280
- <div>
281
- <select
282
- className="jp-mod-styled"
283
- value={defaultChatMode}
284
- onChange={event => setDefaultChatMode(event.target.value)}
285
- >
286
- <option value="ask">Ask</option>
287
- <option value="agent">Agent</option>
288
- </select>
291
+ {!isInClaudeCodeMode && (
292
+ <div className="model-config-section">
293
+ <div className="model-config-section-header">Default chat mode</div>
294
+ <div className="model-config-section-body">
295
+ <div className="model-config-section-row">
296
+ <div className="model-config-section-column">
297
+ <div>
298
+ <select
299
+ className="jp-mod-styled"
300
+ value={defaultChatMode}
301
+ onChange={event => setDefaultChatMode(event.target.value)}
302
+ >
303
+ <option value="ask">Ask</option>
304
+ <option value="agent">Agent</option>
305
+ </select>
306
+ </div>
289
307
  </div>
308
+ <div className="model-config-section-column"> </div>
290
309
  </div>
291
- <div className="model-config-section-column"> </div>
292
310
  </div>
293
311
  </div>
294
- </div>
312
+ )}
295
313
 
296
- <div className="model-config-section">
297
- <div className="model-config-section-header">Chat model</div>
298
- <div className="model-config-section-body">
299
- <div className="model-config-section-row">
300
- <div className="model-config-section-column">
301
- <div>Provider</div>
302
- <div>
303
- <select
304
- className="jp-mod-styled"
305
- onChange={event =>
306
- updateModelOptionsForProvider(event.target.value, 'chat')
307
- }
308
- >
309
- {llmProviders.map((provider: any, index: number) => (
310
- <option
311
- key={index}
312
- value={provider.id}
313
- selected={provider.id === chatModelProvider}
314
- >
315
- {provider.name}
316
- </option>
317
- ))}
318
- <option
319
- key={-1}
320
- value="none"
321
- selected={
322
- chatModelProvider === 'none' ||
323
- !llmProviders.find(
324
- provider => provider.id === chatModelProvider
314
+ {!isInClaudeCodeMode && (
315
+ <div className="model-config-section">
316
+ <div className="model-config-section-header">Chat model</div>
317
+ <div className="model-config-section-body">
318
+ <div className="model-config-section-row">
319
+ <div className="model-config-section-column">
320
+ <div>Provider</div>
321
+ <div>
322
+ <select
323
+ className="jp-mod-styled"
324
+ onChange={event =>
325
+ updateModelOptionsForProvider(
326
+ event.target.value,
327
+ 'chat'
325
328
  )
326
329
  }
327
330
  >
328
- None
329
- </option>
330
- </select>
331
+ {llmProviders.map((provider: any, index: number) => (
332
+ <option
333
+ key={index}
334
+ value={provider.id}
335
+ selected={provider.id === chatModelProvider}
336
+ >
337
+ {provider.name}
338
+ </option>
339
+ ))}
340
+ <option
341
+ key={-1}
342
+ value="none"
343
+ selected={
344
+ chatModelProvider === 'none' ||
345
+ !llmProviders.find(
346
+ provider => provider.id === chatModelProvider
347
+ )
348
+ }
349
+ >
350
+ None
351
+ </option>
352
+ </select>
353
+ </div>
331
354
  </div>
355
+ {!['openai-compatible', 'litellm-compatible', 'none'].includes(
356
+ chatModelProvider
357
+ ) &&
358
+ chatModels.length > 0 && (
359
+ <div className="model-config-section-column">
360
+ <div>Model</div>
361
+ {![
362
+ OPENAI_COMPATIBLE_CHAT_MODEL_ID,
363
+ LITELLM_COMPATIBLE_CHAT_MODEL_ID
364
+ ].includes(chatModel) &&
365
+ chatModels.length > 0 && (
366
+ <div>
367
+ <select
368
+ className="jp-mod-styled"
369
+ onChange={event =>
370
+ setChatModel(event.target.value)
371
+ }
372
+ >
373
+ {chatModels.map((model: any, index: number) => (
374
+ <option
375
+ key={index}
376
+ value={model.id}
377
+ selected={model.id === chatModel}
378
+ >
379
+ {model.name}
380
+ </option>
381
+ ))}
382
+ </select>
383
+ </div>
384
+ )}
385
+ </div>
386
+ )}
332
387
  </div>
333
- {!['openai-compatible', 'litellm-compatible', 'none'].includes(
334
- chatModelProvider
335
- ) &&
336
- chatModels.length > 0 && (
337
- <div className="model-config-section-column">
338
- <div>Model</div>
339
- {![
340
- OPENAI_COMPATIBLE_CHAT_MODEL_ID,
341
- LITELLM_COMPATIBLE_CHAT_MODEL_ID
342
- ].includes(chatModel) &&
343
- chatModels.length > 0 && (
344
- <div>
345
- <select
346
- className="jp-mod-styled"
347
- onChange={event => setChatModel(event.target.value)}
348
- >
349
- {chatModels.map((model: any, index: number) => (
350
- <option
351
- key={index}
352
- value={model.id}
353
- selected={model.id === chatModel}
354
- >
355
- {model.name}
356
- </option>
357
- ))}
358
- </select>
359
- </div>
360
- )}
361
- </div>
362
- )}
363
- </div>
364
388
 
365
- <div className="model-config-section-row">
366
- <div className="model-config-section-column">
367
- {chatModelProvider === 'ollama' && chatModels.length === 0 && (
368
- <div className="ollama-warning-message">
369
- No Ollama models found! Make sure{' '}
370
- <a href="https://ollama.com/" target="_blank">
371
- Ollama
372
- </a>{' '}
373
- is running and models are downloaded to your computer.{' '}
374
- <a
375
- href="javascript:void(0)"
376
- onClick={handleRefreshOllamaModelListClick}
377
- >
378
- Try again
379
- </a>{' '}
380
- once ready.
381
- </div>
382
- )}
389
+ <div className="model-config-section-row">
390
+ <div className="model-config-section-column">
391
+ {chatModelProvider === 'ollama' &&
392
+ chatModels.length === 0 && (
393
+ <div className="ollama-warning-message">
394
+ No Ollama models found! Make sure{' '}
395
+ <a href="https://ollama.com/" target="_blank">
396
+ Ollama
397
+ </a>{' '}
398
+ is running and models are downloaded to your computer.{' '}
399
+ <a
400
+ href="javascript:void(0)"
401
+ onClick={handleRefreshOllamaModelListClick}
402
+ >
403
+ Try again
404
+ </a>{' '}
405
+ once ready.
406
+ </div>
407
+ )}
408
+ </div>
383
409
  </div>
384
- </div>
385
410
 
386
- <div className="model-config-section-row">
387
- <div className="model-config-section-column">
388
- {chatModelProperties.map((property: any, index: number) => (
389
- <div className="form-field-row" key={index}>
390
- <div className="form-field-description">
391
- {property.name} {property.optional ? '(optional)' : ''}
411
+ <div className="model-config-section-row">
412
+ <div className="model-config-section-column">
413
+ {chatModelProperties.map((property: any, index: number) => (
414
+ <div className="form-field-row" key={index}>
415
+ <div className="form-field-description">
416
+ {property.name} {property.optional ? '(optional)' : ''}
417
+ </div>
418
+ <input
419
+ name="chat-model-id-input"
420
+ placeholder={property.description}
421
+ className="jp-mod-styled"
422
+ spellCheck={false}
423
+ value={property.value}
424
+ onChange={event =>
425
+ onModelPropertyChange(
426
+ 'chat',
427
+ property.id,
428
+ event.target.value
429
+ )
430
+ }
431
+ />
392
432
  </div>
393
- <input
394
- name="chat-model-id-input"
395
- placeholder={property.description}
396
- className="jp-mod-styled"
397
- spellCheck={false}
398
- value={property.value}
399
- onChange={event =>
400
- onModelPropertyChange(
401
- 'chat',
402
- property.id,
403
- event.target.value
404
- )
405
- }
406
- />
407
- </div>
408
- ))}
433
+ ))}
434
+ </div>
409
435
  </div>
410
436
  </div>
411
437
  </div>
412
- </div>
438
+ )}
413
439
 
414
440
  <div className="model-config-section">
415
441
  <div className="model-config-section-header">Auto-complete model</div>
@@ -516,40 +542,62 @@ function SettingsPanelComponentGeneral(props: any) {
516
542
  </div>
517
543
  </div>
518
544
 
519
- {(chatModelProvider === 'github-copilot' ||
520
- inlineCompletionModelProvider === 'github-copilot') && (
521
- <div className="model-config-section">
522
- <div className="model-config-section-header access-token-config-header">
523
- GitHub Copilot login{' '}
524
- <a
525
- href="https://github.com/notebook-intelligence/notebook-intelligence/blob/main/README.md#remembering-github-copilot-login"
526
- target="_blank"
527
- >
528
- {' '}
529
- <VscWarning
530
- className="access-token-warning"
531
- title="Click to learn more about security implications"
532
- />
533
- </a>
545
+ <div className="model-config-section-row" style={{ width: '50%' }}>
546
+ <div className="model-config-section-column">
547
+ <div className="form-field-row" style={{ paddingLeft: '10px' }}>
548
+ <div className="form-field-description">
549
+ Auto-complete debouncer delay (ms)
550
+ </div>
551
+ <input
552
+ name="inline-completion-debouncer-delay-input"
553
+ placeholder="Auto-complete debouncer delay (milliseconds)"
554
+ className="jp-mod-styled"
555
+ spellCheck={false}
556
+ value={inlineCompletionDebouncerDelay}
557
+ type="number"
558
+ onChange={event =>
559
+ setInlineCompletionDebouncerDelay(Number(event.target.value))
560
+ }
561
+ />
534
562
  </div>
535
- <div className="model-config-section-body">
536
- <div className="model-config-section-row">
537
- <div className="model-config-section-column">
538
- <label>
539
- <input
540
- type="checkbox"
541
- checked={storeGitHubAccessToken}
542
- onChange={event => {
543
- setStoreGitHubAccessToken(event.target.checked);
544
- }}
545
- />
546
- Remember my GitHub Copilot access token
547
- </label>
563
+ </div>
564
+ </div>
565
+
566
+ {!isInClaudeCodeMode &&
567
+ (chatModelProvider === 'github-copilot' ||
568
+ inlineCompletionModelProvider === 'github-copilot') && (
569
+ <div className="model-config-section">
570
+ <div className="model-config-section-header access-token-config-header">
571
+ GitHub Copilot login{' '}
572
+ <a
573
+ href="https://github.com/notebook-intelligence/notebook-intelligence/blob/main/README.md#remembering-github-copilot-login"
574
+ target="_blank"
575
+ >
576
+ {' '}
577
+ <VscWarning
578
+ className="access-token-warning"
579
+ title="Click to learn more about security implications"
580
+ />
581
+ </a>
582
+ </div>
583
+ <div className="model-config-section-body">
584
+ <div className="model-config-section-row">
585
+ <div className="model-config-section-column">
586
+ <label>
587
+ <input
588
+ type="checkbox"
589
+ checked={storeGitHubAccessToken}
590
+ onChange={event => {
591
+ setStoreGitHubAccessToken(event.target.checked);
592
+ }}
593
+ />
594
+ Remember my GitHub Copilot access token
595
+ </label>
596
+ </div>
548
597
  </div>
549
598
  </div>
550
599
  </div>
551
- </div>
552
- )}
600
+ )}
553
601
 
554
602
  <div className="model-config-section">
555
603
  <div className="model-config-section-header">Config file path</div>
@@ -842,6 +890,9 @@ function SettingsPanelComponentClaude(props: any) {
842
890
  ClaudeToolType.JupyterUITools
843
891
  ]
844
892
  );
893
+ const [continueConversation, setContinueConversation] = useState(
894
+ nbiConfig.claudeSettings.continue_conversation ?? false
895
+ );
845
896
 
846
897
  useEffect(() => {
847
898
  NBIAPI.configChanged.connect(() => {
@@ -859,7 +910,8 @@ function SettingsPanelComponentClaude(props: any) {
859
910
  api_key: apiKey,
860
911
  base_url: baseUrl,
861
912
  setting_sources: settingSources,
862
- tools: tools
913
+ tools: tools,
914
+ continue_conversation: continueConversation
863
915
  }
864
916
  });
865
917
  };
@@ -873,7 +925,8 @@ function SettingsPanelComponentClaude(props: any) {
873
925
  apiKey,
874
926
  baseUrl,
875
927
  settingSources,
876
- tools
928
+ tools,
929
+ continueConversation
877
930
  ]);
878
931
 
879
932
  return (
@@ -953,6 +1006,20 @@ function SettingsPanelComponentClaude(props: any) {
953
1006
  setInlineCompletionModel(event.target.value)
954
1007
  }
955
1008
  >
1009
+ <option
1010
+ value={ClaudeModelType.None}
1011
+ selected={inlineCompletionModel === ClaudeModelType.None}
1012
+ >
1013
+ None
1014
+ </option>
1015
+ <option
1016
+ value={ClaudeModelType.Inherit}
1017
+ selected={
1018
+ inlineCompletionModel === ClaudeModelType.Inherit
1019
+ }
1020
+ >
1021
+ Inherit from general settings
1022
+ </option>
956
1023
  <option
957
1024
  value={ClaudeModelType.Default}
958
1025
  selected={
@@ -1077,6 +1144,28 @@ function SettingsPanelComponentClaude(props: any) {
1077
1144
  </div>
1078
1145
  </div>
1079
1146
 
1147
+ <div className="model-config-section">
1148
+ <div className="model-config-section-header">
1149
+ Conversation History
1150
+ </div>
1151
+ <div className="model-config-section-body">
1152
+ <div className="model-config-section-row">
1153
+ <div className="model-config-section-column">
1154
+ <div>
1155
+ <CheckBoxItem
1156
+ header={true}
1157
+ label="Remember conversation history"
1158
+ checked={continueConversation}
1159
+ onClick={() => {
1160
+ setContinueConversation(!continueConversation);
1161
+ }}
1162
+ ></CheckBoxItem>
1163
+ </div>
1164
+ </div>
1165
+ </div>
1166
+ </div>
1167
+ </div>
1168
+
1080
1169
  <div className="model-config-section">
1081
1170
  <div className="model-config-section-header">Claude account</div>
1082
1171
  <div className="model-config-section-body">
package/src/index.ts CHANGED
@@ -356,7 +356,7 @@ class NBIInlineCompletionProvider
356
356
  get schema(): ISettingRegistry.IProperty {
357
357
  return {
358
358
  default: {
359
- debouncerDelay: 200,
359
+ debouncerDelay: NBIAPI.config.inlineCompletionDebouncerDelay,
360
360
  timeout: 15000
361
361
  }
362
362
  };
@@ -491,7 +491,11 @@ class NBIInlineCompletionProvider
491
491
  }
492
492
 
493
493
  get icon(): LabIcon.ILabIcon {
494
- return NBIAPI.config.isInClaudeCodeMode
494
+ const isClaudeModel =
495
+ NBIAPI.config.isInClaudeCodeMode &&
496
+ NBIAPI.config.claudeSettings.inline_completion_model !== 'none' &&
497
+ NBIAPI.config.claudeSettings.inline_completion_model !== 'inherit';
498
+ return isClaudeModel
495
499
  ? claudeIcon
496
500
  : NBIAPI.config.usingGitHubCopilotModel
497
501
  ? githubCopilotIcon
@@ -769,7 +773,7 @@ const plugin: JupyterFrontEndPlugin<INotebookIntelligence> = {
769
773
  }
770
774
  });
771
775
  panel.addWidget(sidebar);
772
- app.shell.add(panel, 'right', { rank: 1000 });
776
+ app.shell.add(panel, 'left', { rank: 1000 });
773
777
  app.shell.activateById(panel.id);
774
778
 
775
779
  const updateSidebarIcon = () => {