@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
|
@@ -16,7 +16,7 @@ export interface IClearButtonProps
|
|
|
16
16
|
/**
|
|
17
17
|
* The function to clear messages.
|
|
18
18
|
*/
|
|
19
|
-
clearMessages: () => void
|
|
19
|
+
clearMessages: () => Promise<void>;
|
|
20
20
|
/**
|
|
21
21
|
* The application language translator.
|
|
22
22
|
*/
|
|
@@ -53,8 +53,8 @@ export function clearItem(
|
|
|
53
53
|
return {
|
|
54
54
|
element: (props: InputToolbarRegistry.IToolbarItemProps) => {
|
|
55
55
|
const { model } = props;
|
|
56
|
-
const clearMessages = () =>
|
|
57
|
-
(model.chatContext as AIChatModel.IAIChatContext).clearMessages();
|
|
56
|
+
const clearMessages = async () =>
|
|
57
|
+
await (model.chatContext as AIChatModel.IAIChatContext).clearMessages();
|
|
58
58
|
const clearProps: IClearButtonProps = {
|
|
59
59
|
...props,
|
|
60
60
|
clearMessages,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
8
8
|
import React, { useEffect, useState } from 'react';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { IAIChatModel } from '../tokens';
|
|
11
11
|
|
|
12
12
|
const COMPONENT_CLASS = 'jp-ai-SaveButton';
|
|
13
13
|
const AUTOSAVE_BUTTON_CLASS = 'jp-ai-AutoSaveButton';
|
|
@@ -19,7 +19,7 @@ export interface ISaveButtonProps {
|
|
|
19
19
|
/**
|
|
20
20
|
* The chat model, used to listen for message changes for auto-save.
|
|
21
21
|
*/
|
|
22
|
-
model:
|
|
22
|
+
model: IAIChatModel;
|
|
23
23
|
/**
|
|
24
24
|
* The application language translator.
|
|
25
25
|
*/
|
|
@@ -40,7 +40,7 @@ export function SaveComponent(props: ISaveButtonProps): JSX.Element {
|
|
|
40
40
|
* Effect that update the autosave state when it is updated on the model.
|
|
41
41
|
*/
|
|
42
42
|
useEffect(() => {
|
|
43
|
-
const updateAutosave = (_:
|
|
43
|
+
const updateAutosave = (_: IAIChatModel, value: boolean) => {
|
|
44
44
|
setAutosave(value);
|
|
45
45
|
};
|
|
46
46
|
|
package/src/index.ts
CHANGED
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
ToolbarButton
|
|
59
59
|
} from '@jupyterlab/ui-components';
|
|
60
60
|
|
|
61
|
-
import {
|
|
61
|
+
import { UUID } from '@lumino/coreutils';
|
|
62
62
|
|
|
63
63
|
import { DisposableSet } from '@lumino/disposable';
|
|
64
64
|
|
|
@@ -70,8 +70,6 @@ import { ISecretsManager, SecretsManager } from 'jupyter-secrets-manager';
|
|
|
70
70
|
|
|
71
71
|
import { AgentManagerFactory } from './agent';
|
|
72
72
|
|
|
73
|
-
import { AIChatModel } from './chat-model';
|
|
74
|
-
|
|
75
73
|
import { RenderedMessageOutputAreaCompat } from './rendered-message-outputarea';
|
|
76
74
|
|
|
77
75
|
import { ClearCommandProvider } from './chat-commands/clear';
|
|
@@ -95,7 +93,8 @@ import {
|
|
|
95
93
|
IProviderRegistry,
|
|
96
94
|
IToolRegistry,
|
|
97
95
|
ISkillRegistry,
|
|
98
|
-
SECRETS_NAMESPACE
|
|
96
|
+
SECRETS_NAMESPACE,
|
|
97
|
+
IAIChatModel
|
|
99
98
|
} from './tokens';
|
|
100
99
|
|
|
101
100
|
import {
|
|
@@ -357,6 +356,27 @@ const chatModelHandler: JupyterFrontEndPlugin<IChatModelHandler> = {
|
|
|
357
356
|
}
|
|
358
357
|
};
|
|
359
358
|
|
|
359
|
+
/**
|
|
360
|
+
* The active cell manager plugin, to allow copying code from chat to notebook.
|
|
361
|
+
*/
|
|
362
|
+
const activeCellManager: JupyterFrontEndPlugin<void> = {
|
|
363
|
+
id: '@jupyterlite/ai:activeCellManager',
|
|
364
|
+
description: 'Add the active cell manager to the model handler',
|
|
365
|
+
autoStart: true,
|
|
366
|
+
requires: [IChatModelHandler, INotebookTracker],
|
|
367
|
+
activate: (
|
|
368
|
+
app: JupyterFrontEnd,
|
|
369
|
+
modelHandler: IChatModelHandler,
|
|
370
|
+
notebookTracker: INotebookTracker
|
|
371
|
+
) => {
|
|
372
|
+
const activeCellManager = new ActiveCellManager({
|
|
373
|
+
tracker: notebookTracker,
|
|
374
|
+
shell: app.shell
|
|
375
|
+
});
|
|
376
|
+
modelHandler.activeCellManager = activeCellManager;
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
|
|
360
380
|
/**
|
|
361
381
|
* Initialization data for the extension.
|
|
362
382
|
*/
|
|
@@ -376,7 +396,6 @@ const plugin: JupyterFrontEndPlugin<IChatTracker> = {
|
|
|
376
396
|
IThemeManager,
|
|
377
397
|
ILayoutRestorer,
|
|
378
398
|
ILabShell,
|
|
379
|
-
INotebookTracker,
|
|
380
399
|
ITranslator,
|
|
381
400
|
IComponentsRendererFactory,
|
|
382
401
|
ICommandPalette,
|
|
@@ -392,7 +411,6 @@ const plugin: JupyterFrontEndPlugin<IChatTracker> = {
|
|
|
392
411
|
themeManager?: IThemeManager,
|
|
393
412
|
restorer?: ILayoutRestorer,
|
|
394
413
|
labShell?: ILabShell,
|
|
395
|
-
notebookTracker?: INotebookTracker,
|
|
396
414
|
translator?: ITranslator,
|
|
397
415
|
chatComponentsFactory?: IComponentsRendererFactory,
|
|
398
416
|
palette?: ICommandPalette,
|
|
@@ -416,17 +434,6 @@ const plugin: JupyterFrontEndPlugin<IChatTracker> = {
|
|
|
416
434
|
}
|
|
417
435
|
};
|
|
418
436
|
|
|
419
|
-
// Create ActiveCellManager if notebook tracker is available, and add it to the
|
|
420
|
-
// model registry.
|
|
421
|
-
let activeCellManager: ActiveCellManager | undefined;
|
|
422
|
-
if (notebookTracker) {
|
|
423
|
-
activeCellManager = new ActiveCellManager({
|
|
424
|
-
tracker: notebookTracker,
|
|
425
|
-
shell: app.shell
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
modelHandler.activeCellManager = activeCellManager;
|
|
429
|
-
|
|
430
437
|
// Creating the tracker for the chat widgets
|
|
431
438
|
const namespace = 'ai-chat';
|
|
432
439
|
const tracker = new WidgetTracker<MainAreaChat | ChatWidget>({ namespace });
|
|
@@ -518,7 +525,7 @@ const plugin: JupyterFrontEndPlugin<IChatTracker> = {
|
|
|
518
525
|
|
|
519
526
|
let usageWidget: UsageWidget | null = null;
|
|
520
527
|
chatPanel.chatOpened.connect((_, widget) => {
|
|
521
|
-
const model = widget.model as
|
|
528
|
+
const model = widget.model as IAIChatModel;
|
|
522
529
|
|
|
523
530
|
// Add the widget to the tracker.
|
|
524
531
|
tracker.add(widget);
|
|
@@ -527,6 +534,18 @@ const plugin: JupyterFrontEndPlugin<IChatTracker> = {
|
|
|
527
534
|
tracker.save(widget);
|
|
528
535
|
}
|
|
529
536
|
|
|
537
|
+
function updateToolbarTitleOverlay() {
|
|
538
|
+
const titleNode = chatPanel.current?.toolbar.node
|
|
539
|
+
.getElementsByClassName('jp-chat-sidepanel-widget-title')
|
|
540
|
+
.item(0);
|
|
541
|
+
if (titleNode) {
|
|
542
|
+
titleNode.setAttribute('title', model.title ?? model.name);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
model.titleChanged.connect(updateToolbarTitleOverlay);
|
|
547
|
+
updateToolbarTitleOverlay();
|
|
548
|
+
|
|
530
549
|
// Update the tracker if the model name changed.
|
|
531
550
|
model.nameChanged.connect(saveTracker);
|
|
532
551
|
|
|
@@ -565,11 +584,9 @@ const plugin: JupyterFrontEndPlugin<IChatTracker> = {
|
|
|
565
584
|
);
|
|
566
585
|
|
|
567
586
|
if (aiWriting) {
|
|
568
|
-
widget.inputToolbarRegistry?.hide('send');
|
|
569
587
|
widget.inputToolbarRegistry?.show('stop');
|
|
570
588
|
} else {
|
|
571
589
|
widget.inputToolbarRegistry?.hide('stop');
|
|
572
|
-
widget.inputToolbarRegistry?.show('send');
|
|
573
590
|
}
|
|
574
591
|
}
|
|
575
592
|
|
|
@@ -582,6 +599,7 @@ const plugin: JupyterFrontEndPlugin<IChatTracker> = {
|
|
|
582
599
|
});
|
|
583
600
|
|
|
584
601
|
widget.disposed.connect(() => {
|
|
602
|
+
model.titleChanged.disconnect(updateToolbarTitleOverlay);
|
|
585
603
|
model.nameChanged.disconnect(saveTracker);
|
|
586
604
|
model.agentManager.activeProviderChanged.disconnect(saveTracker);
|
|
587
605
|
model.writersChanged?.disconnect(writersChanged);
|
|
@@ -607,7 +625,7 @@ const plugin: JupyterFrontEndPlugin<IChatTracker> = {
|
|
|
607
625
|
args: widget => ({
|
|
608
626
|
name: widget.model.name,
|
|
609
627
|
area: widget instanceof MainAreaChat ? 'main' : 'side',
|
|
610
|
-
provider: (widget.model as
|
|
628
|
+
provider: (widget.model as IAIChatModel).agentManager.activeProvider
|
|
611
629
|
}),
|
|
612
630
|
name: widget => {
|
|
613
631
|
const area = widget instanceof MainAreaChat ? 'main' : 'side';
|
|
@@ -641,24 +659,39 @@ const plugin: JupyterFrontEndPlugin<IChatTracker> = {
|
|
|
641
659
|
);
|
|
642
660
|
|
|
643
661
|
/**
|
|
644
|
-
* The callback
|
|
662
|
+
* The callback for grouped tool calls permission decisions.
|
|
645
663
|
*/
|
|
646
|
-
function
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
664
|
+
function toolCallPermissionDecision(
|
|
665
|
+
sessionId: string,
|
|
666
|
+
toolCallId: string,
|
|
667
|
+
optionId: string
|
|
650
668
|
) {
|
|
651
|
-
const model = tracker.find(chat => chat.model.name ===
|
|
669
|
+
const model = tracker.find(chat => chat.model.name === sessionId)
|
|
670
|
+
?.model as IAIChatModel;
|
|
652
671
|
if (!model) {
|
|
653
672
|
return;
|
|
654
673
|
}
|
|
674
|
+
|
|
675
|
+
const isApproved = optionId === 'approve';
|
|
655
676
|
isApproved
|
|
656
|
-
?
|
|
657
|
-
:
|
|
677
|
+
? model.agentManager.approveToolCall(toolCallId)
|
|
678
|
+
: model.agentManager.rejectToolCall(toolCallId);
|
|
658
679
|
}
|
|
659
680
|
|
|
660
681
|
if (chatComponentsFactory) {
|
|
661
|
-
chatComponentsFactory.
|
|
682
|
+
chatComponentsFactory.toolCallPermissionDecision =
|
|
683
|
+
toolCallPermissionDecision;
|
|
684
|
+
|
|
685
|
+
chatComponentsFactory.removeQueuedMessage = (
|
|
686
|
+
targetId: string,
|
|
687
|
+
messageId: string
|
|
688
|
+
) => {
|
|
689
|
+
const model = tracker.find(chat => chat.model.name === targetId)?.model;
|
|
690
|
+
if (!model) {
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
(model as IAIChatModel).removeQueuedMessage(messageId);
|
|
694
|
+
};
|
|
662
695
|
}
|
|
663
696
|
|
|
664
697
|
return tracker;
|
|
@@ -734,12 +767,13 @@ function registerCommands(
|
|
|
734
767
|
}
|
|
735
768
|
});
|
|
736
769
|
|
|
737
|
-
const openInMain = (model:
|
|
770
|
+
const openInMain = (model: IAIChatModel): MainAreaChat => {
|
|
771
|
+
const inputToolbarRegistry = inputToolbarFactory.create();
|
|
738
772
|
const content = new ChatWidget({
|
|
739
773
|
model,
|
|
740
774
|
rmRegistry,
|
|
741
775
|
themeManager: themeManager ?? null,
|
|
742
|
-
inputToolbarRegistry
|
|
776
|
+
inputToolbarRegistry,
|
|
743
777
|
attachmentOpenerRegistry,
|
|
744
778
|
chatCommandRegistry
|
|
745
779
|
});
|
|
@@ -767,6 +801,64 @@ function registerCommands(
|
|
|
767
801
|
model.nameChanged.disconnect(saveTracker);
|
|
768
802
|
model.agentManager.activeProviderChanged.disconnect(saveTracker);
|
|
769
803
|
});
|
|
804
|
+
|
|
805
|
+
return widget;
|
|
806
|
+
};
|
|
807
|
+
|
|
808
|
+
const focusOnChat = (
|
|
809
|
+
area: 'main' | 'side',
|
|
810
|
+
widget?: ChatWidget | MainAreaChat
|
|
811
|
+
) => {
|
|
812
|
+
if (area === 'main' && widget) {
|
|
813
|
+
app.shell.activateById(widget.id);
|
|
814
|
+
} else {
|
|
815
|
+
app.shell.activateById(chatPanel.id);
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
const applyInputArgs = (model: IChatModel, args: any) => {
|
|
820
|
+
const input = typeof args.input === 'string' ? args.input : undefined;
|
|
821
|
+
const autoSend = args.autoSend === true;
|
|
822
|
+
const shouldFocus = args.focus !== false;
|
|
823
|
+
|
|
824
|
+
if (input !== undefined) {
|
|
825
|
+
model.input.value = input;
|
|
826
|
+
}
|
|
827
|
+
if (autoSend && input !== undefined) {
|
|
828
|
+
model.input.send(model.input.value);
|
|
829
|
+
}
|
|
830
|
+
if (shouldFocus) {
|
|
831
|
+
model.input.focus();
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
|
|
835
|
+
const findChatWidget = (
|
|
836
|
+
name?: string,
|
|
837
|
+
provider?: string
|
|
838
|
+
): ChatWidget | MainAreaChat | undefined => {
|
|
839
|
+
if (!name && !provider) {
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
return tracker.find(widget => {
|
|
843
|
+
const model = widget.model as IAIChatModel;
|
|
844
|
+
return (
|
|
845
|
+
(!name || widget.model.name === name) &&
|
|
846
|
+
(!provider || model.agentManager.activeProvider === provider)
|
|
847
|
+
);
|
|
848
|
+
});
|
|
849
|
+
};
|
|
850
|
+
|
|
851
|
+
const disposeSideChatModel = (model: IChatModel): boolean => {
|
|
852
|
+
const loadedName = chatPanel
|
|
853
|
+
.getLoadedModelNames()
|
|
854
|
+
.find(name => chatPanel.getLoadedModel(name) === model);
|
|
855
|
+
|
|
856
|
+
if (!loadedName) {
|
|
857
|
+
return false;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
chatPanel.disposeLoadedModel(loadedName);
|
|
861
|
+
return true;
|
|
770
862
|
};
|
|
771
863
|
|
|
772
864
|
commands.addCommand(CommandIds.openChat, {
|
|
@@ -801,11 +893,18 @@ function registerCommands(
|
|
|
801
893
|
return false;
|
|
802
894
|
}
|
|
803
895
|
|
|
896
|
+
const shouldFocus = args.focus === true;
|
|
897
|
+
let widget: ChatWidget | MainAreaChat | undefined;
|
|
804
898
|
if (area === 'main') {
|
|
805
|
-
openInMain(model);
|
|
899
|
+
widget = openInMain(model);
|
|
806
900
|
} else {
|
|
807
|
-
chatPanel.open({ model });
|
|
901
|
+
widget = chatPanel.open({ model });
|
|
902
|
+
}
|
|
903
|
+
if (shouldFocus) {
|
|
904
|
+
focusOnChat(area, widget);
|
|
808
905
|
}
|
|
906
|
+
applyInputArgs(model, { ...args, focus: shouldFocus });
|
|
907
|
+
|
|
809
908
|
return true;
|
|
810
909
|
},
|
|
811
910
|
describedBy: {
|
|
@@ -824,6 +923,137 @@ function registerCommands(
|
|
|
824
923
|
provider: {
|
|
825
924
|
type: 'string',
|
|
826
925
|
description: trans.__('The provider/model to use with this chat')
|
|
926
|
+
},
|
|
927
|
+
input: {
|
|
928
|
+
type: 'string',
|
|
929
|
+
description: trans.__('The input text to prefill in the chat')
|
|
930
|
+
},
|
|
931
|
+
focus: {
|
|
932
|
+
type: 'boolean',
|
|
933
|
+
description: trans.__(
|
|
934
|
+
'Whether to focus the chat input after opening it'
|
|
935
|
+
)
|
|
936
|
+
},
|
|
937
|
+
autoSend: {
|
|
938
|
+
type: 'boolean',
|
|
939
|
+
description: trans.__(
|
|
940
|
+
'Whether to auto-send the provided input after opening the chat'
|
|
941
|
+
)
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
commands.addCommand(CommandIds.openOrRevealChat, {
|
|
949
|
+
label: trans.__('Open or reveal the chat panel'),
|
|
950
|
+
execute: async (args): Promise<boolean> => {
|
|
951
|
+
const area = (args.area as string) === 'main' ? 'main' : 'side';
|
|
952
|
+
const provider = (args.provider as string) ?? undefined;
|
|
953
|
+
const name = (args.name as string) ?? undefined;
|
|
954
|
+
const shouldFocus = args.focus === true;
|
|
955
|
+
|
|
956
|
+
let existingWidget = findChatWidget(name, provider);
|
|
957
|
+
if (!existingWidget && !name) {
|
|
958
|
+
const providerConfig = provider
|
|
959
|
+
? settingsModel.getProvider(provider)
|
|
960
|
+
: settingsModel.getDefaultProvider();
|
|
961
|
+
existingWidget = findChatWidget(undefined, providerConfig?.id);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// If the side chat model is loaded but not currently displayed, reveal it first.
|
|
965
|
+
if (!existingWidget && name) {
|
|
966
|
+
const loadedModel = chatPanel.getLoadedModel(name);
|
|
967
|
+
if (loadedModel) {
|
|
968
|
+
existingWidget = chatPanel.open({ model: loadedModel });
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
if (!existingWidget) {
|
|
973
|
+
return commands.execute(CommandIds.openChat, {
|
|
974
|
+
...args,
|
|
975
|
+
focus: shouldFocus
|
|
976
|
+
}) as Promise<boolean>;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
const currentArea =
|
|
980
|
+
existingWidget instanceof MainAreaChat ? 'main' : 'side';
|
|
981
|
+
if (currentArea !== area) {
|
|
982
|
+
const targetName = existingWidget.model.name;
|
|
983
|
+
const moved = (await commands.execute(CommandIds.moveChat, {
|
|
984
|
+
name: targetName,
|
|
985
|
+
area
|
|
986
|
+
})) as boolean;
|
|
987
|
+
if (!moved) {
|
|
988
|
+
return false;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
const movedWidget = findChatWidget(targetName);
|
|
992
|
+
if (!movedWidget) {
|
|
993
|
+
return false;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
if (area === 'side') {
|
|
997
|
+
chatPanel.open({ model: movedWidget.model });
|
|
998
|
+
}
|
|
999
|
+
if (shouldFocus) {
|
|
1000
|
+
focusOnChat(area, movedWidget);
|
|
1001
|
+
}
|
|
1002
|
+
applyInputArgs(movedWidget.model, {
|
|
1003
|
+
...args,
|
|
1004
|
+
focus: shouldFocus
|
|
1005
|
+
});
|
|
1006
|
+
|
|
1007
|
+
return true;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
if (area === 'side') {
|
|
1011
|
+
chatPanel.open({ model: existingWidget.model });
|
|
1012
|
+
}
|
|
1013
|
+
if (shouldFocus) {
|
|
1014
|
+
focusOnChat(area, existingWidget);
|
|
1015
|
+
}
|
|
1016
|
+
applyInputArgs(existingWidget.model, {
|
|
1017
|
+
...args,
|
|
1018
|
+
focus: shouldFocus
|
|
1019
|
+
});
|
|
1020
|
+
|
|
1021
|
+
return true;
|
|
1022
|
+
},
|
|
1023
|
+
describedBy: {
|
|
1024
|
+
args: {
|
|
1025
|
+
type: 'object',
|
|
1026
|
+
properties: {
|
|
1027
|
+
area: {
|
|
1028
|
+
type: 'string',
|
|
1029
|
+
enum: ['main', 'side'],
|
|
1030
|
+
description: trans.__(
|
|
1031
|
+
'The name of the area to open or reveal the chat in'
|
|
1032
|
+
)
|
|
1033
|
+
},
|
|
1034
|
+
name: {
|
|
1035
|
+
type: 'string',
|
|
1036
|
+
description: trans.__('The name of the chat')
|
|
1037
|
+
},
|
|
1038
|
+
provider: {
|
|
1039
|
+
type: 'string',
|
|
1040
|
+
description: trans.__('The provider/model to use with this chat')
|
|
1041
|
+
},
|
|
1042
|
+
input: {
|
|
1043
|
+
type: 'string',
|
|
1044
|
+
description: trans.__('The input text to prefill in the chat')
|
|
1045
|
+
},
|
|
1046
|
+
focus: {
|
|
1047
|
+
type: 'boolean',
|
|
1048
|
+
description: trans.__(
|
|
1049
|
+
'Whether to focus the chat input after opening it'
|
|
1050
|
+
)
|
|
1051
|
+
},
|
|
1052
|
+
autoSend: {
|
|
1053
|
+
type: 'boolean',
|
|
1054
|
+
description: trans.__(
|
|
1055
|
+
'Whether to auto-send the provided input after opening the chat'
|
|
1056
|
+
)
|
|
827
1057
|
}
|
|
828
1058
|
}
|
|
829
1059
|
}
|
|
@@ -847,11 +1077,11 @@ function registerCommands(
|
|
|
847
1077
|
return false;
|
|
848
1078
|
}
|
|
849
1079
|
let previousWidget: ChatWidget | MainAreaChat | undefined;
|
|
850
|
-
let previousModel:
|
|
1080
|
+
let previousModel: IAIChatModel | undefined;
|
|
851
1081
|
tracker.forEach(widget => {
|
|
852
1082
|
if (widget.model.name === args.name) {
|
|
853
1083
|
previousWidget = widget;
|
|
854
|
-
previousModel = widget.model as
|
|
1084
|
+
previousModel = widget.model as IAIChatModel;
|
|
855
1085
|
}
|
|
856
1086
|
});
|
|
857
1087
|
|
|
@@ -862,51 +1092,26 @@ function registerCommands(
|
|
|
862
1092
|
return false;
|
|
863
1093
|
}
|
|
864
1094
|
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
1095
|
+
if (area === 'main') {
|
|
1096
|
+
// Temporarily bypass model disposal to transport model to main view
|
|
1097
|
+
// to keep the conversation when switching views
|
|
1098
|
+
// TODO: Remove this code when jupyter-chat PR #423 is merged and released
|
|
1099
|
+
const originalDispose = previousModel.dispose.bind(previousModel);
|
|
1100
|
+
previousModel.dispose = () => {};
|
|
1101
|
+
|
|
1102
|
+
if (previousWidget instanceof ChatWidget) {
|
|
1103
|
+
if (!disposeSideChatModel(previousModel)) {
|
|
1104
|
+
previousWidget.dispose();
|
|
1105
|
+
}
|
|
872
1106
|
}
|
|
873
|
-
};
|
|
874
|
-
tracker.widgetUpdated.connect(widgetUpdated);
|
|
875
1107
|
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
// Create a new model by duplicating the previous model attributes.
|
|
881
|
-
const model = modelRegistry.createModel({
|
|
882
|
-
name: args.name as string,
|
|
883
|
-
activeProvider: previousModel.agentManager.activeProvider,
|
|
884
|
-
tokenUsage: previousModel.agentManager.tokenUsage,
|
|
885
|
-
messages: previousModel.messages,
|
|
886
|
-
autosave: previousModel.autosave
|
|
887
|
-
});
|
|
888
|
-
|
|
889
|
-
// Wait (with timeout) for the tracker to have updated the previous widget.
|
|
890
|
-
const status = await Promise.any([
|
|
891
|
-
trackerUpdated.promise,
|
|
892
|
-
new Promise<boolean>(r =>
|
|
893
|
-
setTimeout(() => {
|
|
894
|
-
r(false);
|
|
895
|
-
}, 2000)
|
|
896
|
-
)
|
|
897
|
-
]);
|
|
898
|
-
tracker.widgetUpdated.disconnect(widgetUpdated);
|
|
899
|
-
|
|
900
|
-
if (!status) {
|
|
901
|
-
return false;
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
if (area === 'main') {
|
|
905
|
-
openInMain(model);
|
|
1108
|
+
// Restore model disposal and transport to main view
|
|
1109
|
+
previousModel.dispose = originalDispose;
|
|
1110
|
+
openInMain(previousModel);
|
|
906
1111
|
} else {
|
|
1112
|
+
// MainAreaChat disposal does not dispose the model internally, so this is safe.
|
|
907
1113
|
previousWidget?.dispose();
|
|
908
|
-
|
|
909
|
-
chatPanel.open({ model });
|
|
1114
|
+
chatPanel.open({ model: previousModel });
|
|
910
1115
|
}
|
|
911
1116
|
|
|
912
1117
|
return true;
|
|
@@ -935,15 +1140,15 @@ function registerCommands(
|
|
|
935
1140
|
caption: trans.__('Save the chat as local file'),
|
|
936
1141
|
icon: saveIcon,
|
|
937
1142
|
execute: async (args): Promise<boolean> => {
|
|
938
|
-
let model:
|
|
1143
|
+
let model: IAIChatModel | null = null;
|
|
939
1144
|
if (args.name) {
|
|
940
1145
|
tracker.forEach(widget => {
|
|
941
1146
|
if (widget.model.name === args.name) {
|
|
942
|
-
model = widget.model as
|
|
1147
|
+
model = widget.model as IAIChatModel;
|
|
943
1148
|
}
|
|
944
1149
|
});
|
|
945
1150
|
} else {
|
|
946
|
-
model = (tracker.currentWidget?.model as
|
|
1151
|
+
model = (tracker.currentWidget?.model as IAIChatModel) ?? null;
|
|
947
1152
|
}
|
|
948
1153
|
if (model === null) {
|
|
949
1154
|
console.log('No chat to save');
|
|
@@ -980,15 +1185,15 @@ function registerCommands(
|
|
|
980
1185
|
console.warn('The restoration is not possible');
|
|
981
1186
|
return false;
|
|
982
1187
|
}
|
|
983
|
-
let model:
|
|
1188
|
+
let model: IAIChatModel | null = null;
|
|
984
1189
|
if (args.name) {
|
|
985
1190
|
tracker.forEach(widget => {
|
|
986
1191
|
if (widget.model.name === args.name) {
|
|
987
|
-
model = widget.model as
|
|
1192
|
+
model = widget.model as IAIChatModel;
|
|
988
1193
|
}
|
|
989
1194
|
});
|
|
990
1195
|
} else {
|
|
991
|
-
model = (tracker.currentWidget?.model as
|
|
1196
|
+
model = (tracker.currentWidget?.model as IAIChatModel) ?? null;
|
|
992
1197
|
}
|
|
993
1198
|
if (model === null) {
|
|
994
1199
|
console.warn('There is no chat to restore');
|
|
@@ -1512,6 +1717,7 @@ export default [
|
|
|
1512
1717
|
skillRegistryPlugin,
|
|
1513
1718
|
skillsCommandPlugin,
|
|
1514
1719
|
chatModelHandler,
|
|
1720
|
+
activeCellManager,
|
|
1515
1721
|
plugin,
|
|
1516
1722
|
toolRegistry,
|
|
1517
1723
|
agentManagerFactory,
|
|
@@ -29,6 +29,7 @@ export class AISettingsModel extends VDomModel implements IAISettingsModel {
|
|
|
29
29
|
diffDisplayMode: 'split',
|
|
30
30
|
skillsPaths: ['.agents/skills', '_agents/skills'],
|
|
31
31
|
chatBackupDirectory: '',
|
|
32
|
+
autoTitle: false,
|
|
32
33
|
commandsRequiringApproval: [
|
|
33
34
|
'notebook:restart-run-all',
|
|
34
35
|
'notebook:run-cell',
|
|
@@ -4,7 +4,7 @@ import { createMistral } from '@ai-sdk/mistral';
|
|
|
4
4
|
import { createOpenAI } from '@ai-sdk/openai';
|
|
5
5
|
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
|
|
6
6
|
|
|
7
|
-
import { BUILT_IN_PROVIDER_MODEL_INFO } from './generated-
|
|
7
|
+
import { BUILT_IN_PROVIDER_MODEL_INFO } from './generated-model-info';
|
|
8
8
|
import type { IProviderInfo } from '../tokens';
|
|
9
9
|
import type { IModelOptions } from './models';
|
|
10
10
|
|