@jupyterlite/ai 0.16.0 → 0.18.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/agent.d.ts +19 -10
- package/lib/agent.js +82 -46
- package/lib/chat-commands/clear.js +1 -1
- package/lib/chat-model-handler.d.ts +2 -3
- package/lib/chat-model-handler.js +6 -2
- package/lib/chat-model.d.ts +129 -26
- package/lib/chat-model.js +543 -160
- package/lib/components/clear-button.d.ts +1 -1
- package/lib/components/clear-button.js +1 -1
- package/lib/components/save-button.d.ts +2 -2
- package/lib/index.js +224 -59
- package/lib/models/settings-model.js +1 -0
- package/lib/providers/built-in-providers.js +1 -1
- package/lib/providers/{generated-context-windows.d.ts → generated-model-info.d.ts} +2 -2
- package/lib/providers/generated-model-info.js +502 -0
- package/lib/providers/model-info.d.ts +3 -0
- package/lib/providers/model-info.js +33 -0
- package/lib/tokens.d.ts +98 -15
- package/lib/tokens.js +1 -0
- package/lib/widgets/ai-settings.js +5 -0
- package/lib/widgets/main-area-chat.d.ts +3 -3
- package/lib/widgets/main-area-chat.js +9 -5
- package/package.json +3 -3
- package/schema/settings-model.json +6 -0
- package/src/agent.ts +100 -52
- package/src/chat-commands/clear.ts +1 -1
- package/src/chat-model-handler.ts +10 -3
- package/src/chat-model.ts +727 -210
- package/src/components/clear-button.tsx +3 -3
- package/src/components/save-button.tsx +3 -3
- package/src/index.ts +289 -83
- package/src/models/settings-model.ts +1 -0
- package/src/providers/built-in-providers.ts +1 -1
- package/src/providers/generated-model-info.ts +508 -0
- package/src/providers/model-info.ts +57 -0
- package/src/tokens.ts +100 -15
- package/src/widgets/ai-settings.tsx +26 -0
- package/src/widgets/main-area-chat.ts +14 -9
- package/lib/providers/generated-context-windows.js +0 -96
- package/src/providers/generated-context-windows.ts +0 -102
|
@@ -21,7 +21,7 @@ export function clearItem(translator) {
|
|
|
21
21
|
return {
|
|
22
22
|
element: (props) => {
|
|
23
23
|
const { model } = props;
|
|
24
|
-
const clearMessages = () => model.chatContext.clearMessages();
|
|
24
|
+
const clearMessages = async () => await model.chatContext.clearMessages();
|
|
25
25
|
const clearProps = {
|
|
26
26
|
...props,
|
|
27
27
|
clearMessages,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ReactWidget } from '@jupyterlab/ui-components';
|
|
2
2
|
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
3
3
|
import React from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { IAIChatModel } from '../tokens';
|
|
5
5
|
/**
|
|
6
6
|
* Properties for the SaveButton component.
|
|
7
7
|
*/
|
|
@@ -9,7 +9,7 @@ export interface ISaveButtonProps {
|
|
|
9
9
|
/**
|
|
10
10
|
* The chat model, used to listen for message changes for auto-save.
|
|
11
11
|
*/
|
|
12
|
-
model:
|
|
12
|
+
model: IAIChatModel;
|
|
13
13
|
/**
|
|
14
14
|
* The application language translator.
|
|
15
15
|
*/
|
package/lib/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { IStatusBar } from '@jupyterlab/statusbar';
|
|
|
11
11
|
import { PathExt } from '@jupyterlab/coreutils';
|
|
12
12
|
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
|
13
13
|
import { fileUploadIcon, saveIcon, settingsIcon, Toolbar, ToolbarButton } from '@jupyterlab/ui-components';
|
|
14
|
-
import {
|
|
14
|
+
import { UUID } from '@lumino/coreutils';
|
|
15
15
|
import { DisposableSet } from '@lumino/disposable';
|
|
16
16
|
import { IComponentsRendererFactory } from 'jupyter-chat-components';
|
|
17
17
|
import { ISecretsManager, SecretsManager } from 'jupyter-secrets-manager';
|
|
@@ -213,6 +213,22 @@ const chatModelHandler = {
|
|
|
213
213
|
});
|
|
214
214
|
}
|
|
215
215
|
};
|
|
216
|
+
/**
|
|
217
|
+
* The active cell manager plugin, to allow copying code from chat to notebook.
|
|
218
|
+
*/
|
|
219
|
+
const activeCellManager = {
|
|
220
|
+
id: '@jupyterlite/ai:activeCellManager',
|
|
221
|
+
description: 'Add the active cell manager to the model handler',
|
|
222
|
+
autoStart: true,
|
|
223
|
+
requires: [IChatModelHandler, INotebookTracker],
|
|
224
|
+
activate: (app, modelHandler, notebookTracker) => {
|
|
225
|
+
const activeCellManager = new ActiveCellManager({
|
|
226
|
+
tracker: notebookTracker,
|
|
227
|
+
shell: app.shell
|
|
228
|
+
});
|
|
229
|
+
modelHandler.activeCellManager = activeCellManager;
|
|
230
|
+
}
|
|
231
|
+
};
|
|
216
232
|
/**
|
|
217
233
|
* Initialization data for the extension.
|
|
218
234
|
*/
|
|
@@ -232,13 +248,12 @@ const plugin = {
|
|
|
232
248
|
IThemeManager,
|
|
233
249
|
ILayoutRestorer,
|
|
234
250
|
ILabShell,
|
|
235
|
-
INotebookTracker,
|
|
236
251
|
ITranslator,
|
|
237
252
|
IComponentsRendererFactory,
|
|
238
253
|
ICommandPalette,
|
|
239
254
|
IDocumentManager
|
|
240
255
|
],
|
|
241
|
-
activate: (app, rmRegistry, inputToolbarFactory, modelHandler, settingsModel, chatCommandRegistry, themeManager, restorer, labShell,
|
|
256
|
+
activate: (app, rmRegistry, inputToolbarFactory, modelHandler, settingsModel, chatCommandRegistry, themeManager, restorer, labShell, translator, chatComponentsFactory, palette, documentManager) => {
|
|
242
257
|
const trans = (translator ?? nullTranslator).load('jupyterlite_ai');
|
|
243
258
|
// Create attachment opener registry to handle file attachments
|
|
244
259
|
const attachmentOpenerRegistry = new AttachmentOpenerRegistry();
|
|
@@ -253,16 +268,6 @@ const plugin = {
|
|
|
253
268
|
void app.commands.execute(CommandIds.openSettings);
|
|
254
269
|
}
|
|
255
270
|
};
|
|
256
|
-
// Create ActiveCellManager if notebook tracker is available, and add it to the
|
|
257
|
-
// model registry.
|
|
258
|
-
let activeCellManager;
|
|
259
|
-
if (notebookTracker) {
|
|
260
|
-
activeCellManager = new ActiveCellManager({
|
|
261
|
-
tracker: notebookTracker,
|
|
262
|
-
shell: app.shell
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
modelHandler.activeCellManager = activeCellManager;
|
|
266
271
|
// Creating the tracker for the chat widgets
|
|
267
272
|
const namespace = 'ai-chat';
|
|
268
273
|
const tracker = new WidgetTracker({ namespace });
|
|
@@ -346,6 +351,16 @@ const plugin = {
|
|
|
346
351
|
function saveTracker() {
|
|
347
352
|
tracker.save(widget);
|
|
348
353
|
}
|
|
354
|
+
function updateToolbarTitleOverlay() {
|
|
355
|
+
const titleNode = chatPanel.current?.toolbar.node
|
|
356
|
+
.getElementsByClassName('jp-chat-sidepanel-widget-title')
|
|
357
|
+
.item(0);
|
|
358
|
+
if (titleNode) {
|
|
359
|
+
titleNode.setAttribute('title', model.title ?? model.name);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
model.titleChanged.connect(updateToolbarTitleOverlay);
|
|
363
|
+
updateToolbarTitleOverlay();
|
|
349
364
|
// Update the tracker if the model name changed.
|
|
350
365
|
model.nameChanged.connect(saveTracker);
|
|
351
366
|
// Update the tracker if the active provider changed.
|
|
@@ -371,12 +386,10 @@ const plugin = {
|
|
|
371
386
|
// Check if AI is currently writing (streaming)
|
|
372
387
|
const aiWriting = writers.some(writer => writer.user.username === 'ai-assistant');
|
|
373
388
|
if (aiWriting) {
|
|
374
|
-
widget.inputToolbarRegistry?.hide('send');
|
|
375
389
|
widget.inputToolbarRegistry?.show('stop');
|
|
376
390
|
}
|
|
377
391
|
else {
|
|
378
392
|
widget.inputToolbarRegistry?.hide('stop');
|
|
379
|
-
widget.inputToolbarRegistry?.show('send');
|
|
380
393
|
}
|
|
381
394
|
}
|
|
382
395
|
model.writersChanged?.connect(writersChanged);
|
|
@@ -386,6 +399,7 @@ const plugin = {
|
|
|
386
399
|
chatPanel: widget
|
|
387
400
|
});
|
|
388
401
|
widget.disposed.connect(() => {
|
|
402
|
+
model.titleChanged.disconnect(updateToolbarTitleOverlay);
|
|
389
403
|
model.nameChanged.disconnect(saveTracker);
|
|
390
404
|
model.agentManager.activeProviderChanged.disconnect(saveTracker);
|
|
391
405
|
model.writersChanged?.disconnect(writersChanged);
|
|
@@ -423,19 +437,29 @@ const plugin = {
|
|
|
423
437
|
});
|
|
424
438
|
registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry, inputToolbarFactory, settingsModel, chatCommandRegistry, tracker, modelHandler, trans, themeManager, labShell, palette, documentManager);
|
|
425
439
|
/**
|
|
426
|
-
* The callback
|
|
440
|
+
* The callback for grouped tool calls permission decisions.
|
|
427
441
|
*/
|
|
428
|
-
function
|
|
429
|
-
const model = tracker.find(chat => chat.model.name ===
|
|
442
|
+
function toolCallPermissionDecision(sessionId, toolCallId, optionId) {
|
|
443
|
+
const model = tracker.find(chat => chat.model.name === sessionId)
|
|
444
|
+
?.model;
|
|
430
445
|
if (!model) {
|
|
431
446
|
return;
|
|
432
447
|
}
|
|
448
|
+
const isApproved = optionId === 'approve';
|
|
433
449
|
isApproved
|
|
434
|
-
? model.agentManager.approveToolCall(
|
|
435
|
-
: model.agentManager.rejectToolCall(
|
|
450
|
+
? model.agentManager.approveToolCall(toolCallId)
|
|
451
|
+
: model.agentManager.rejectToolCall(toolCallId);
|
|
436
452
|
}
|
|
437
453
|
if (chatComponentsFactory) {
|
|
438
|
-
chatComponentsFactory.
|
|
454
|
+
chatComponentsFactory.toolCallPermissionDecision =
|
|
455
|
+
toolCallPermissionDecision;
|
|
456
|
+
chatComponentsFactory.removeQueuedMessage = (targetId, messageId) => {
|
|
457
|
+
const model = tracker.find(chat => chat.model.name === targetId)?.model;
|
|
458
|
+
if (!model) {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
model.removeQueuedMessage(messageId);
|
|
462
|
+
};
|
|
439
463
|
}
|
|
440
464
|
return tracker;
|
|
441
465
|
}
|
|
@@ -486,11 +510,12 @@ function registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry,
|
|
|
486
510
|
}
|
|
487
511
|
});
|
|
488
512
|
const openInMain = (model) => {
|
|
513
|
+
const inputToolbarRegistry = inputToolbarFactory.create();
|
|
489
514
|
const content = new ChatWidget({
|
|
490
515
|
model,
|
|
491
516
|
rmRegistry,
|
|
492
517
|
themeManager: themeManager ?? null,
|
|
493
|
-
inputToolbarRegistry
|
|
518
|
+
inputToolbarRegistry,
|
|
494
519
|
attachmentOpenerRegistry,
|
|
495
520
|
chatCommandRegistry
|
|
496
521
|
});
|
|
@@ -514,6 +539,49 @@ function registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry,
|
|
|
514
539
|
model.nameChanged.disconnect(saveTracker);
|
|
515
540
|
model.agentManager.activeProviderChanged.disconnect(saveTracker);
|
|
516
541
|
});
|
|
542
|
+
return widget;
|
|
543
|
+
};
|
|
544
|
+
const focusOnChat = (area, widget) => {
|
|
545
|
+
if (area === 'main' && widget) {
|
|
546
|
+
app.shell.activateById(widget.id);
|
|
547
|
+
}
|
|
548
|
+
else {
|
|
549
|
+
app.shell.activateById(chatPanel.id);
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
const applyInputArgs = (model, args) => {
|
|
553
|
+
const input = typeof args.input === 'string' ? args.input : undefined;
|
|
554
|
+
const autoSend = args.autoSend === true;
|
|
555
|
+
const shouldFocus = args.focus !== false;
|
|
556
|
+
if (input !== undefined) {
|
|
557
|
+
model.input.value = input;
|
|
558
|
+
}
|
|
559
|
+
if (autoSend && input !== undefined) {
|
|
560
|
+
model.input.send(model.input.value);
|
|
561
|
+
}
|
|
562
|
+
if (shouldFocus) {
|
|
563
|
+
model.input.focus();
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
const findChatWidget = (name, provider) => {
|
|
567
|
+
if (!name && !provider) {
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
return tracker.find(widget => {
|
|
571
|
+
const model = widget.model;
|
|
572
|
+
return ((!name || widget.model.name === name) &&
|
|
573
|
+
(!provider || model.agentManager.activeProvider === provider));
|
|
574
|
+
});
|
|
575
|
+
};
|
|
576
|
+
const disposeSideChatModel = (model) => {
|
|
577
|
+
const loadedName = chatPanel
|
|
578
|
+
.getLoadedModelNames()
|
|
579
|
+
.find(name => chatPanel.getLoadedModel(name) === model);
|
|
580
|
+
if (!loadedName) {
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
583
|
+
chatPanel.disposeLoadedModel(loadedName);
|
|
584
|
+
return true;
|
|
517
585
|
};
|
|
518
586
|
commands.addCommand(CommandIds.openChat, {
|
|
519
587
|
label: trans.__('Open a chat'),
|
|
@@ -543,12 +611,18 @@ function registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry,
|
|
|
543
611
|
if (!model) {
|
|
544
612
|
return false;
|
|
545
613
|
}
|
|
614
|
+
const shouldFocus = args.focus === true;
|
|
615
|
+
let widget;
|
|
546
616
|
if (area === 'main') {
|
|
547
|
-
openInMain(model);
|
|
617
|
+
widget = openInMain(model);
|
|
548
618
|
}
|
|
549
619
|
else {
|
|
550
|
-
chatPanel.open({ model });
|
|
620
|
+
widget = chatPanel.open({ model });
|
|
621
|
+
}
|
|
622
|
+
if (shouldFocus) {
|
|
623
|
+
focusOnChat(area, widget);
|
|
551
624
|
}
|
|
625
|
+
applyInputArgs(model, { ...args, focus: shouldFocus });
|
|
552
626
|
return true;
|
|
553
627
|
},
|
|
554
628
|
describedBy: {
|
|
@@ -567,6 +641,116 @@ function registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry,
|
|
|
567
641
|
provider: {
|
|
568
642
|
type: 'string',
|
|
569
643
|
description: trans.__('The provider/model to use with this chat')
|
|
644
|
+
},
|
|
645
|
+
input: {
|
|
646
|
+
type: 'string',
|
|
647
|
+
description: trans.__('The input text to prefill in the chat')
|
|
648
|
+
},
|
|
649
|
+
focus: {
|
|
650
|
+
type: 'boolean',
|
|
651
|
+
description: trans.__('Whether to focus the chat input after opening it')
|
|
652
|
+
},
|
|
653
|
+
autoSend: {
|
|
654
|
+
type: 'boolean',
|
|
655
|
+
description: trans.__('Whether to auto-send the provided input after opening the chat')
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
});
|
|
661
|
+
commands.addCommand(CommandIds.openOrRevealChat, {
|
|
662
|
+
label: trans.__('Open or reveal the chat panel'),
|
|
663
|
+
execute: async (args) => {
|
|
664
|
+
const area = args.area === 'main' ? 'main' : 'side';
|
|
665
|
+
const provider = args.provider ?? undefined;
|
|
666
|
+
const name = args.name ?? undefined;
|
|
667
|
+
const shouldFocus = args.focus === true;
|
|
668
|
+
let existingWidget = findChatWidget(name, provider);
|
|
669
|
+
if (!existingWidget && !name) {
|
|
670
|
+
const providerConfig = provider
|
|
671
|
+
? settingsModel.getProvider(provider)
|
|
672
|
+
: settingsModel.getDefaultProvider();
|
|
673
|
+
existingWidget = findChatWidget(undefined, providerConfig?.id);
|
|
674
|
+
}
|
|
675
|
+
// If the side chat model is loaded but not currently displayed, reveal it first.
|
|
676
|
+
if (!existingWidget && name) {
|
|
677
|
+
const loadedModel = chatPanel.getLoadedModel(name);
|
|
678
|
+
if (loadedModel) {
|
|
679
|
+
existingWidget = chatPanel.open({ model: loadedModel });
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
if (!existingWidget) {
|
|
683
|
+
return commands.execute(CommandIds.openChat, {
|
|
684
|
+
...args,
|
|
685
|
+
focus: shouldFocus
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
const currentArea = existingWidget instanceof MainAreaChat ? 'main' : 'side';
|
|
689
|
+
if (currentArea !== area) {
|
|
690
|
+
const targetName = existingWidget.model.name;
|
|
691
|
+
const moved = (await commands.execute(CommandIds.moveChat, {
|
|
692
|
+
name: targetName,
|
|
693
|
+
area
|
|
694
|
+
}));
|
|
695
|
+
if (!moved) {
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
const movedWidget = findChatWidget(targetName);
|
|
699
|
+
if (!movedWidget) {
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
if (area === 'side') {
|
|
703
|
+
chatPanel.open({ model: movedWidget.model });
|
|
704
|
+
}
|
|
705
|
+
if (shouldFocus) {
|
|
706
|
+
focusOnChat(area, movedWidget);
|
|
707
|
+
}
|
|
708
|
+
applyInputArgs(movedWidget.model, {
|
|
709
|
+
...args,
|
|
710
|
+
focus: shouldFocus
|
|
711
|
+
});
|
|
712
|
+
return true;
|
|
713
|
+
}
|
|
714
|
+
if (area === 'side') {
|
|
715
|
+
chatPanel.open({ model: existingWidget.model });
|
|
716
|
+
}
|
|
717
|
+
if (shouldFocus) {
|
|
718
|
+
focusOnChat(area, existingWidget);
|
|
719
|
+
}
|
|
720
|
+
applyInputArgs(existingWidget.model, {
|
|
721
|
+
...args,
|
|
722
|
+
focus: shouldFocus
|
|
723
|
+
});
|
|
724
|
+
return true;
|
|
725
|
+
},
|
|
726
|
+
describedBy: {
|
|
727
|
+
args: {
|
|
728
|
+
type: 'object',
|
|
729
|
+
properties: {
|
|
730
|
+
area: {
|
|
731
|
+
type: 'string',
|
|
732
|
+
enum: ['main', 'side'],
|
|
733
|
+
description: trans.__('The name of the area to open or reveal the chat in')
|
|
734
|
+
},
|
|
735
|
+
name: {
|
|
736
|
+
type: 'string',
|
|
737
|
+
description: trans.__('The name of the chat')
|
|
738
|
+
},
|
|
739
|
+
provider: {
|
|
740
|
+
type: 'string',
|
|
741
|
+
description: trans.__('The provider/model to use with this chat')
|
|
742
|
+
},
|
|
743
|
+
input: {
|
|
744
|
+
type: 'string',
|
|
745
|
+
description: trans.__('The input text to prefill in the chat')
|
|
746
|
+
},
|
|
747
|
+
focus: {
|
|
748
|
+
type: 'boolean',
|
|
749
|
+
description: trans.__('Whether to focus the chat input after opening it')
|
|
750
|
+
},
|
|
751
|
+
autoSend: {
|
|
752
|
+
type: 'boolean',
|
|
753
|
+
description: trans.__('Whether to auto-send the provided input after opening the chat')
|
|
570
754
|
}
|
|
571
755
|
}
|
|
572
756
|
}
|
|
@@ -596,45 +780,25 @@ function registerCommands(app, rmRegistry, chatPanel, attachmentOpenerRegistry,
|
|
|
596
780
|
console.error('Error while moving the chat to main area: there is no reference model');
|
|
597
781
|
return false;
|
|
598
782
|
}
|
|
599
|
-
// Listen for the widget updated in tracker, to ensure the previous model name
|
|
600
|
-
// has been updated. This is required to remove the widget from the restorer
|
|
601
|
-
// when the previous widget is disposed.
|
|
602
|
-
const trackerUpdated = new PromiseDelegate();
|
|
603
|
-
const widgetUpdated = (_, widget) => {
|
|
604
|
-
if (widget.model === previousModel) {
|
|
605
|
-
trackerUpdated.resolve(true);
|
|
606
|
-
}
|
|
607
|
-
};
|
|
608
|
-
tracker.widgetUpdated.connect(widgetUpdated);
|
|
609
|
-
// Rename temporary the previous model to be able to reuse this name for the new
|
|
610
|
-
// model. The previous is intended to be disposed anyway.
|
|
611
|
-
previousModel.name = UUID.uuid4();
|
|
612
|
-
// Create a new model by duplicating the previous model attributes.
|
|
613
|
-
const model = modelRegistry.createModel({
|
|
614
|
-
name: args.name,
|
|
615
|
-
activeProvider: previousModel.agentManager.activeProvider,
|
|
616
|
-
tokenUsage: previousModel.agentManager.tokenUsage,
|
|
617
|
-
messages: previousModel.messages,
|
|
618
|
-
autosave: previousModel.autosave
|
|
619
|
-
});
|
|
620
|
-
// Wait (with timeout) for the tracker to have updated the previous widget.
|
|
621
|
-
const status = await Promise.any([
|
|
622
|
-
trackerUpdated.promise,
|
|
623
|
-
new Promise(r => setTimeout(() => {
|
|
624
|
-
r(false);
|
|
625
|
-
}, 2000))
|
|
626
|
-
]);
|
|
627
|
-
tracker.widgetUpdated.disconnect(widgetUpdated);
|
|
628
|
-
if (!status) {
|
|
629
|
-
return false;
|
|
630
|
-
}
|
|
631
783
|
if (area === 'main') {
|
|
632
|
-
|
|
784
|
+
// Temporarily bypass model disposal to transport model to main view
|
|
785
|
+
// to keep the conversation when switching views
|
|
786
|
+
// TODO: Remove this code when jupyter-chat PR #423 is merged and released
|
|
787
|
+
const originalDispose = previousModel.dispose.bind(previousModel);
|
|
788
|
+
previousModel.dispose = () => { };
|
|
789
|
+
if (previousWidget instanceof ChatWidget) {
|
|
790
|
+
if (!disposeSideChatModel(previousModel)) {
|
|
791
|
+
previousWidget.dispose();
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
// Restore model disposal and transport to main view
|
|
795
|
+
previousModel.dispose = originalDispose;
|
|
796
|
+
openInMain(previousModel);
|
|
633
797
|
}
|
|
634
798
|
else {
|
|
799
|
+
// MainAreaChat disposal does not dispose the model internally, so this is safe.
|
|
635
800
|
previousWidget?.dispose();
|
|
636
|
-
|
|
637
|
-
chatPanel.open({ model });
|
|
801
|
+
chatPanel.open({ model: previousModel });
|
|
638
802
|
}
|
|
639
803
|
return true;
|
|
640
804
|
},
|
|
@@ -1118,6 +1282,7 @@ export default [
|
|
|
1118
1282
|
skillRegistryPlugin,
|
|
1119
1283
|
skillsCommandPlugin,
|
|
1120
1284
|
chatModelHandler,
|
|
1285
|
+
activeCellManager,
|
|
1121
1286
|
plugin,
|
|
1122
1287
|
toolRegistry,
|
|
1123
1288
|
agentManagerFactory,
|
|
@@ -19,6 +19,7 @@ export class AISettingsModel extends VDomModel {
|
|
|
19
19
|
diffDisplayMode: 'split',
|
|
20
20
|
skillsPaths: ['.agents/skills', '_agents/skills'],
|
|
21
21
|
chatBackupDirectory: '',
|
|
22
|
+
autoTitle: false,
|
|
22
23
|
commandsRequiringApproval: [
|
|
23
24
|
'notebook:restart-run-all',
|
|
24
25
|
'notebook:run-cell',
|
|
@@ -3,7 +3,7 @@ import { createGoogleGenerativeAI } from '@ai-sdk/google';
|
|
|
3
3
|
import { createMistral } from '@ai-sdk/mistral';
|
|
4
4
|
import { createOpenAI } from '@ai-sdk/openai';
|
|
5
5
|
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
|
|
6
|
-
import { BUILT_IN_PROVIDER_MODEL_INFO } from './generated-
|
|
6
|
+
import { BUILT_IN_PROVIDER_MODEL_INFO } from './generated-model-info';
|
|
7
7
|
/**
|
|
8
8
|
* Anthropic provider
|
|
9
9
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* This file is generated by `jlpm sync:model-
|
|
2
|
+
* This file is generated by `jlpm sync:model-info`.
|
|
3
3
|
* Source: https://models.dev/api.json
|
|
4
4
|
* Backed by: https://github.com/anomalyco/models.dev
|
|
5
|
-
* Generated: 2026-04-
|
|
5
|
+
* Generated: 2026-04-28T11:55:05.327Z
|
|
6
6
|
*/
|
|
7
7
|
import type { IProviderModelInfo } from '../tokens';
|
|
8
8
|
export declare const BUILT_IN_PROVIDER_MODEL_INFO: Record<string, Record<string, IProviderModelInfo>>;
|