From 27c5b75d7cc2798ded18437688816110183ae169 Mon Sep 17 00:00:00 2001 From: Nicolas Brichet Date: Tue, 23 Sep 2025 23:08:38 +0200 Subject: [PATCH 1/6] Use a react context in the chat component and its children --- .../src/components/attachments.tsx | 6 +- packages/jupyter-chat/src/components/chat.tsx | 28 ++++----- .../src/components/input/chat-input.tsx | 35 ++++------- .../src/components/messages/footer.tsx | 22 +++---- .../components/messages/message-renderer.tsx | 18 ++---- .../src/components/messages/message.tsx | 11 ++-- .../src/components/messages/messages.tsx | 59 +++---------------- .../src/components/messages/navigation.tsx | 6 +- .../src/components/messages/welcome.tsx | 15 ++++- packages/jupyter-chat/src/context.ts | 20 +++++-- 10 files changed, 89 insertions(+), 131 deletions(-) diff --git a/packages/jupyter-chat/src/components/attachments.tsx b/packages/jupyter-chat/src/components/attachments.tsx index f9c62e5c..dc677339 100644 --- a/packages/jupyter-chat/src/components/attachments.tsx +++ b/packages/jupyter-chat/src/components/attachments.tsx @@ -5,13 +5,13 @@ import CloseIcon from '@mui/icons-material/Close'; import { Box } from '@mui/material'; -import React, { useContext } from 'react'; +import React from 'react'; import { PathExt } from '@jupyterlab/coreutils'; import { UUID } from '@lumino/coreutils'; import { TooltippedButton } from './mui-extras/tooltipped-button'; +import { useChatContext } from '../context'; import { IAttachment } from '../types'; -import { AttachmentOpenerContext } from '../context'; const ATTACHMENTS_CLASS = 'jp-chat-attachments'; const ATTACHMENT_CLASS = 'jp-chat-attachment'; @@ -81,7 +81,7 @@ export type AttachmentProps = AttachmentsProps & { */ export function AttachmentPreview(props: AttachmentProps): JSX.Element { const remove_tooltip = 'Remove attachment'; - const attachmentOpenerRegistry = useContext(AttachmentOpenerContext); + const { attachmentOpenerRegistry } = useChatContext(); return ( diff --git a/packages/jupyter-chat/src/components/chat.tsx b/packages/jupyter-chat/src/components/chat.tsx index 019c0acd..b67c02b8 100644 --- a/packages/jupyter-chat/src/components/chat.tsx +++ b/packages/jupyter-chat/src/components/chat.tsx @@ -18,7 +18,7 @@ import { } from './input'; import { JlThemeProvider } from './jl-theme-provider'; import { ChatMessages } from './messages'; -import { AttachmentOpenerContext } from '../context'; +import { ChatReactContext } from '../context'; import { IChatModel } from '../model'; import { IAttachmentOpenerRegistry, @@ -26,23 +26,21 @@ import { IMessageFooterRegistry } from '../registers'; -export function ChatBody(props: Chat.IChatBodyProps): JSX.Element { +export function ChatBody(props: Chat.IChatProps): JSX.Element { const { model } = props; let { inputToolbarRegistry } = props; if (!inputToolbarRegistry) { inputToolbarRegistry = InputToolbarRegistry.defaultToolbarRegistry(); } + const contextValue: Chat.IChatProps = { + ...props, + inputToolbarRegistry + }; + return ( - - + + - + ); } @@ -112,7 +108,7 @@ export namespace Chat { /** * The props for the chat body component. */ - export interface IChatBodyProps { + export interface IChatProps { /** * The chat model. */ @@ -146,7 +142,7 @@ export namespace Chat { /** * The options to build the Chat UI. */ - export interface IOptions extends IChatBodyProps { + export interface IOptions extends IChatProps { /** * The theme manager. */ diff --git a/packages/jupyter-chat/src/components/input/chat-input.tsx b/packages/jupyter-chat/src/components/input/chat-input.tsx index 208681da..27379b8f 100644 --- a/packages/jupyter-chat/src/components/input/chat-input.tsx +++ b/packages/jupyter-chat/src/components/input/chat-input.tsx @@ -15,14 +15,11 @@ import { import clsx from 'clsx'; import React, { useEffect, useRef, useState } from 'react'; +import { InputToolbarRegistry } from './toolbar-registry'; +import { useChatCommands } from './use-chat-commands'; import { AttachmentPreviewList } from '../attachments'; -import { - IInputToolbarRegistry, - InputToolbarRegistry, - useChatCommands -} from '.'; +import { useChatContext } from '../../context'; import { IInputModel, InputModel } from '../../input-model'; -import { IChatCommandRegistry } from '../../registers'; import { IAttachment } from '../../types'; const INPUT_BOX_CLASS = 'jp-chat-input-container'; @@ -31,11 +28,13 @@ const INPUT_COMPONENT_CLASS = 'jp-chat-input-component'; const INPUT_TOOLBAR_CLASS = 'jp-chat-input-toolbar'; export function ChatInput(props: ChatInput.IProps): JSX.Element { - const { model, toolbarRegistry } = props; + const { model } = props; + const { chatCommandRegistry, inputToolbarRegistry } = useChatContext(); + const [input, setInput] = useState(model.value); const inputRef = useRef(); - const chatCommands = useChatCommands(model, props.chatCommandRegistry); + const chatCommands = useChatCommands(model, chatCommandRegistry); const [sendWithShiftEnter, setSendWithShiftEnter] = useState( model.config.sendWithShiftEnter ?? false @@ -88,16 +87,16 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element { */ useEffect(() => { const updateToolbar = () => { - setToolbarElements(toolbarRegistry.getItems()); + setToolbarElements(inputToolbarRegistry?.getItems() || []); }; - toolbarRegistry.itemsChanged.connect(updateToolbar); + inputToolbarRegistry?.itemsChanged.connect(updateToolbar); updateToolbar(); return () => { - toolbarRegistry.itemsChanged.disconnect(updateToolbar); + inputToolbarRegistry?.itemsChanged.disconnect(updateToolbar); }; - }, [toolbarRegistry]); + }, [inputToolbarRegistry]); const inputExists = !!input.trim(); @@ -160,7 +159,7 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element { (!sendWithShiftEnter && !event.shiftKey) ) { // Run all command providers - await props.chatCommandRegistry?.onSubmit(model); + await chatCommandRegistry?.onSubmit(model); model.send(model.value); event.stopPropagation(); event.preventDefault(); @@ -245,7 +244,7 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element { {toolbarElements.map(item => ( ))} @@ -265,10 +264,6 @@ export namespace ChatInput { * The input model. */ model: IInputModel; - /** - * The toolbar registry. - */ - toolbarRegistry: IInputToolbarRegistry; /** * The function to be called to cancel editing. */ @@ -277,9 +272,5 @@ export namespace ChatInput { * Custom mui/material styles. */ sx?: SxProps; - /** - * Chat command registry. - */ - chatCommandRegistry?: IChatCommandRegistry; } } diff --git a/packages/jupyter-chat/src/components/messages/footer.tsx b/packages/jupyter-chat/src/components/messages/footer.tsx index 036ccbbc..0f7d6cf9 100644 --- a/packages/jupyter-chat/src/components/messages/footer.tsx +++ b/packages/jupyter-chat/src/components/messages/footer.tsx @@ -6,19 +6,17 @@ import { Box } from '@mui/material'; import React from 'react'; -import { - IMessageFooterRegistry, - MessageFooterSectionProps -} from '../../registers'; +import { useChatContext } from '../../context'; +import { IChatMessage } from '../../types'; /** * The chat footer component properties. */ -export interface IMessageFootersProps extends MessageFooterSectionProps { +export interface IMessageFootersProps { /** - * The chat footer registry. + * The chat model. */ - registry: IMessageFooterRegistry; + message: IChatMessage; } /** @@ -27,9 +25,13 @@ export interface IMessageFootersProps extends MessageFooterSectionProps { */ export function MessageFooterComponent( props: IMessageFootersProps -): JSX.Element { - const { message, model, registry } = props; - const footer = registry.getFooter(); +): JSX.Element | null { + const { message } = props; + const { model, messageFooterRegistry } = useChatContext(); + if (!messageFooterRegistry) { + return null; + } + const footer = messageFooterRegistry.getFooter(); return ( diff --git a/packages/jupyter-chat/src/components/messages/message-renderer.tsx b/packages/jupyter-chat/src/components/messages/message-renderer.tsx index c028001b..3514b636 100644 --- a/packages/jupyter-chat/src/components/messages/message-renderer.tsx +++ b/packages/jupyter-chat/src/components/messages/message-renderer.tsx @@ -3,15 +3,14 @@ * Distributed under the terms of the Modified BSD License. */ -import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { PromiseDelegate } from '@lumino/coreutils'; import React, { useState, useEffect } from 'react'; import { createPortal } from 'react-dom'; -import { CodeToolbar, CodeToolbarProps } from '../code-blocks/code-toolbar'; import { MessageToolbar } from './toolbar'; +import { CodeToolbar, CodeToolbarProps } from '../code-blocks/code-toolbar'; +import { useChatContext } from '../../context'; import { MarkdownRenderer, MD_RENDERED_CLASS } from '../../markdown-renderer'; -import { IChatModel } from '../../model'; /** * The type of the props for the MessageRenderer component. @@ -21,14 +20,6 @@ type MessageRendererProps = { * The string to render. */ markdownStr: string; - /** - * The rendermime registry. - */ - rmRegistry: IRenderMimeRegistry; - /** - * The model of the chat. - */ - model: IChatModel; /** * The promise to resolve when the message is rendered. */ @@ -51,7 +42,8 @@ type MessageRendererProps = { * The message renderer base component. */ function MessageRendererBase(props: MessageRendererProps): JSX.Element { - const { markdownStr, rmRegistry } = props; + const { markdownStr } = props; + const { model, rmRegistry } = useChatContext(); const appendContent = props.appendContent || false; const [renderedContent, setRenderedContent] = useState( null @@ -81,7 +73,7 @@ function MessageRendererBase(props: MessageRendererProps): JSX.Element { ); newCodeToolbarDefns.push([ codeToolbarRoot, - { model: props.model, content: preBlock.textContent || '' } + { model: model, content: preBlock.textContent || '' } ]); }); diff --git a/packages/jupyter-chat/src/components/messages/message.tsx b/packages/jupyter-chat/src/components/messages/message.tsx index 4d5fdd99..2b8dd6eb 100644 --- a/packages/jupyter-chat/src/components/messages/message.tsx +++ b/packages/jupyter-chat/src/components/messages/message.tsx @@ -7,9 +7,9 @@ import { PromiseDelegate } from '@lumino/coreutils'; import React, { forwardRef, useEffect, useState } from 'react'; import { MessageRenderer } from './message-renderer'; -import { BaseMessageProps } from './messages'; import { AttachmentPreviewList } from '../attachments'; import { ChatInput } from '../input'; +import { useChatContext } from '../../context'; import { IInputModel, InputModel } from '../../input-model'; import { IChatMessage } from '../../types'; import { replaceSpanToMention } from '../../utils'; @@ -17,7 +17,7 @@ import { replaceSpanToMention } from '../../utils'; /** * The message component props. */ -type ChatMessageProps = BaseMessageProps & { +type ChatMessageProps = { /** * The message to display. */ @@ -37,7 +37,8 @@ type ChatMessageProps = BaseMessageProps & { */ export const ChatMessage = forwardRef( (props, ref): JSX.Element => { - const { message, model, rmRegistry } = props; + const { message } = props; + const { model } = useChatContext(); const [edit, setEdit] = useState(false); const [deleted, setDeleted] = useState(false); const [canEdit, setCanEdit] = useState(false); @@ -132,14 +133,10 @@ export const ChatMessage = forwardRef( cancelEdition()} model={model.getEditionModel(message.id)!} - chatCommandRegistry={props.chatCommandRegistry} - toolbarRegistry={props.inputToolbarRegistry} /> ) : ( deleteMessage(message.id) : undefined} rendered={props.renderedPromise} diff --git a/packages/jupyter-chat/src/components/messages/messages.tsx b/packages/jupyter-chat/src/components/messages/messages.tsx index 8922fbce..e674a665 100644 --- a/packages/jupyter-chat/src/components/messages/messages.tsx +++ b/packages/jupyter-chat/src/components/messages/messages.tsx @@ -3,7 +3,6 @@ * Distributed under the terms of the Modified BSD License. */ -import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { PromiseDelegate } from '@lumino/coreutils'; import { Box } from '@mui/material'; import clsx from 'clsx'; @@ -15,9 +14,8 @@ import { ChatMessage } from './message'; import { Navigation } from './navigation'; import { WelcomeMessage } from './welcome'; import { WritingUsersList } from './writers'; -import { IInputToolbarRegistry } from '../input'; import { ScrollContainer } from '../scroll-container'; -import { IChatCommandRegistry, IMessageFooterRegistry } from '../../registers'; +import { useChatContext } from '../../context'; import { IChatModel } from '../../model'; import { IChatMessage, IUser } from '../../types'; @@ -25,41 +23,12 @@ const MESSAGES_BOX_CLASS = 'jp-chat-messages-container'; const MESSAGE_CLASS = 'jp-chat-message'; const MESSAGE_STACKED_CLASS = 'jp-chat-message-stacked'; -/** - * The base components props. - */ -export type BaseMessageProps = { - /** - * The mime renderer registry. - */ - rmRegistry: IRenderMimeRegistry; - /** - * The chat model. - */ - model: IChatModel; - /** - * The chat commands registry. - */ - chatCommandRegistry?: IChatCommandRegistry; - /** - * The input toolbar registry. - */ - inputToolbarRegistry: IInputToolbarRegistry; - /** - * The footer registry. - */ - messageFooterRegistry?: IMessageFooterRegistry; - /** - * The welcome message. - */ - welcomeMessage?: string; -}; - /** * The messages list component. */ -export function ChatMessages(props: BaseMessageProps): JSX.Element { - const { model } = props; +export function ChatMessages(): JSX.Element { + const { messageFooterRegistry, model, welcomeMessage } = useChatContext(); + const [messages, setMessages] = useState(model.messages); const refMsgBox = useRef(null); const [currentWriters, setCurrentWriters] = useState([]); @@ -142,7 +111,7 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element { } }); - props.model.messagesInViewport = inViewport; + model.messagesInViewport = inViewport; // Ensure that all messages are rendered before updating unread messages, otherwise // it can lead to wrong assumption , because more message are in the viewport @@ -173,12 +142,7 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element { return ( <> - {props.welcomeMessage && ( - - )} + {welcomeMessage && } {messages.map((message, i) => { renderedPromise.current[i] = new PromiseDelegate(); @@ -193,18 +157,13 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element { > (listRef.current[i] = el)} /> - {props.messageFooterRegistry && ( - + {messageFooterRegistry && ( + )} ); @@ -212,7 +171,7 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element { - + ); } diff --git a/packages/jupyter-chat/src/components/messages/navigation.tsx b/packages/jupyter-chat/src/components/messages/navigation.tsx index b31bae07..cf502432 100644 --- a/packages/jupyter-chat/src/components/messages/navigation.tsx +++ b/packages/jupyter-chat/src/components/messages/navigation.tsx @@ -11,7 +11,7 @@ import { } from '@jupyterlab/ui-components'; import React, { useEffect, useState } from 'react'; -import { BaseMessageProps } from './messages'; +import { useChatContext } from '../../context'; import { IChatModel } from '../../model'; const NAVIGATION_BUTTON_CLASS = 'jp-chat-navigation'; @@ -22,7 +22,7 @@ const NAVIGATION_BOTTOM_CLASS = 'jp-chat-navigation-bottom'; /** * The navigation component props. */ -type NavigationProps = BaseMessageProps & { +type NavigationProps = { /** * The reference to the messages container. */ @@ -37,7 +37,7 @@ type NavigationProps = BaseMessageProps & { * The navigation component, to navigate to unread messages. */ export function Navigation(props: NavigationProps): JSX.Element { - const { model } = props; + const { model } = useChatContext(); const [lastInViewport, setLastInViewport] = useState(true); const [unreadBefore, setUnreadBefore] = useState(null); const [unreadAfter, setUnreadAfter] = useState(null); diff --git a/packages/jupyter-chat/src/components/messages/welcome.tsx b/packages/jupyter-chat/src/components/messages/welcome.tsx index 7ad82bfe..e3f7cdfc 100644 --- a/packages/jupyter-chat/src/components/messages/welcome.tsx +++ b/packages/jupyter-chat/src/components/messages/welcome.tsx @@ -6,17 +6,28 @@ import { classes } from '@jupyterlab/ui-components'; import React, { useEffect, useRef } from 'react'; +import { useChatContext } from '../../context'; import { MarkdownRenderer, MD_RENDERED_CLASS } from '../../markdown-renderer'; const WELCOME_MESSAGE_CLASS = 'jp-chat-welcome-message'; +/** + * The component props. + */ +export interface IWelcomeMessageProps { + /** + * The content of the welcome message (markdown). + */ + content: string; +} + /** * The welcome message component. * This message is displayed on top of the chat messages, and is rendered using a * markdown renderer. */ -export function WelcomeMessage(props: MarkdownRenderer.IOptions): JSX.Element { - const { rmRegistry } = props; +export function WelcomeMessage(props: IWelcomeMessageProps): JSX.Element { + const { rmRegistry } = useChatContext(); const content = props.content + '\n----\n'; // ref that tracks the content container to store the rendermime node in diff --git a/packages/jupyter-chat/src/context.ts b/packages/jupyter-chat/src/context.ts index 75f4166f..94009a46 100644 --- a/packages/jupyter-chat/src/context.ts +++ b/packages/jupyter-chat/src/context.ts @@ -2,9 +2,19 @@ * Copyright (c) Jupyter Development Team. * Distributed under the terms of the Modified BSD License. */ -import { createContext } from 'react'; -import { IAttachmentOpenerRegistry } from './registers'; -export const AttachmentOpenerContext = createContext< - IAttachmentOpenerRegistry | undefined ->(undefined); +import { createContext, useContext } from 'react'; + +import { Chat } from './components'; + +export const ChatReactContext = createContext( + undefined +); + +export function useChatContext(): Chat.IChatProps { + const context = useContext(ChatReactContext); + if (!context) { + throw new Error('The chat context is missing in the chat'); + } + return context; +} From 5e69662ff534bd03ad594a69c838dc9c38bd37cc Mon Sep 17 00:00:00 2001 From: Nicolas Brichet Date: Tue, 23 Sep 2025 23:28:37 +0200 Subject: [PATCH 2/6] Use the chat.IOptions in multichat panel to clarify. --- packages/jupyter-chat/src/components/chat.tsx | 6 +--- .../src/widgets/multichat-panel.tsx | 31 +++---------------- 2 files changed, 6 insertions(+), 31 deletions(-) diff --git a/packages/jupyter-chat/src/components/chat.tsx b/packages/jupyter-chat/src/components/chat.tsx index b67c02b8..f0e452a7 100644 --- a/packages/jupyter-chat/src/components/chat.tsx +++ b/packages/jupyter-chat/src/components/chat.tsx @@ -56,7 +56,7 @@ export function ChatBody(props: Chat.IChatProps): JSX.Element { } export function Chat(props: Chat.IOptions): JSX.Element { - const [view, setView] = useState(props.chatView || Chat.View.chat); + const [view, setView] = useState(Chat.View.chat); return ( (this); - private _rmRegistry: IRenderMimeRegistry; - private _themeManager?: IThemeManager | null; - private _chatCommandRegistry?: IChatCommandRegistry; - private _attachmentOpenerRegistry?: IAttachmentOpenerRegistry; + private _chatOptions: Omit; private _inputToolbarFactory?: IInputToolbarRegistryFactory; - private _messageFooterRegistry?: IMessageFooterRegistry; - private _welcomeMessage?: string; private _updateChatListDebouncer: Debouncer; private _createModel?: ( From 177fdb705161272125483c8e164cce81649b1b75 Mon Sep 17 00:00:00 2001 From: Nicolas Brichet Date: Tue, 23 Sep 2025 23:49:40 +0200 Subject: [PATCH 3/6] Use the Chat.IOptions in widget fatory --- packages/jupyterlab-chat/src/factory.ts | 52 +++++-------------------- 1 file changed, 10 insertions(+), 42 deletions(-) diff --git a/packages/jupyterlab-chat/src/factory.ts b/packages/jupyterlab-chat/src/factory.ts index 2badb370..3a036b61 100644 --- a/packages/jupyterlab-chat/src/factory.ts +++ b/packages/jupyterlab-chat/src/factory.ts @@ -4,19 +4,14 @@ */ import { + Chat, ChatWidget, IActiveCellManager, - IAttachmentOpenerRegistry, - IChatCommandRegistry, - IInputToolbarRegistry, - IMessageFooterRegistry, ISelectionWatcher, IInputToolbarRegistryFactory } from '@jupyter/chat'; -import { IThemeManager } from '@jupyterlab/apputils'; import { IDocumentManager } from '@jupyterlab/docmanager'; import { ABCWidgetFactory, DocumentRegistry } from '@jupyterlab/docregistry'; -import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; import { Contents, User } from '@jupyterlab/services'; import { CommandRegistry } from '@lumino/commands'; import { ISignal, Signal } from '@lumino/signaling'; @@ -77,13 +72,8 @@ export class ChatWidgetFactory extends ABCWidgetFactory< */ constructor(options: ChatWidgetFactory.IOptions) { super(options); - this._themeManager = options.themeManager; - this._rmRegistry = options.rmRegistry; - this._chatCommandRegistry = options.chatCommandRegistry; - this._attachmentOpenerRegistry = options.attachmentOpenerRegistry; + this._chatOptions = options; this._inputToolbarFactory = options.inputToolbarFactory; - this._messageFooterRegistry = options.messageFooterRegistry; - this._welcomeMessage = options.welcomeMessage; } /** @@ -93,12 +83,7 @@ export class ChatWidgetFactory extends ABCWidgetFactory< * @returns The widget */ protected createNewWidget(context: ChatWidgetFactory.IContext): LabChatPanel { - context.rmRegistry = this._rmRegistry; - context.themeManager = this._themeManager; - context.chatCommandRegistry = this._chatCommandRegistry; - context.attachmentOpenerRegistry = this._attachmentOpenerRegistry; - context.messageFooterRegistry = this._messageFooterRegistry; - context.welcomeMessage = this._welcomeMessage; + context = { ...context, ...this._chatOptions }; if (this._inputToolbarFactory) { context.inputToolbarRegistry = this._inputToolbarFactory.create(); } @@ -118,36 +103,19 @@ export class ChatWidgetFactory extends ABCWidgetFactory< } // Must override both getter and setter from ABCFactory for type compatibility. set contentProviderId(_value: string | undefined) {} - private _themeManager: IThemeManager | null; - private _rmRegistry: IRenderMimeRegistry; - private _chatCommandRegistry?: IChatCommandRegistry; - private _attachmentOpenerRegistry?: IAttachmentOpenerRegistry; + private _chatOptions: Omit; private _inputToolbarFactory?: IInputToolbarRegistryFactory; - private _messageFooterRegistry?: IMessageFooterRegistry; - private _welcomeMessage?: string; } export namespace ChatWidgetFactory { - export interface IContext extends DocumentRegistry.IContext { - themeManager: IThemeManager | null; - rmRegistry: IRenderMimeRegistry; - documentManager?: IDocumentManager; - chatCommandRegistry?: IChatCommandRegistry; - attachmentOpenerRegistry?: IAttachmentOpenerRegistry; - inputToolbarRegistry?: IInputToolbarRegistry; - messageFooterRegistry?: IMessageFooterRegistry; - welcomeMessage?: string; - } + export interface IContext + extends DocumentRegistry.IContext, + Omit {} export interface IOptions - extends DocumentRegistry.IWidgetFactoryOptions { - themeManager: IThemeManager | null; - rmRegistry: IRenderMimeRegistry; - chatCommandRegistry?: IChatCommandRegistry; - attachmentOpenerRegistry?: IAttachmentOpenerRegistry; - inputToolbarFactory?: IInputToolbarRegistryFactory; - messageFooterRegistry?: IMessageFooterRegistry; - welcomeMessage?: string; + extends DocumentRegistry.IWidgetFactoryOptions, + Omit { + inputToolbarFactory: IInputToolbarRegistryFactory; } } From de5bee9905ef7e6473b0ad6fe24619d40d262d36 Mon Sep 17 00:00:00 2001 From: Nicolas Brichet Date: Wed, 24 Sep 2025 00:07:56 +0200 Subject: [PATCH 4/6] Use ChatModel.IOptions in model factory --- packages/jupyterlab-chat/src/factory.ts | 33 ++++--------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/packages/jupyterlab-chat/src/factory.ts b/packages/jupyterlab-chat/src/factory.ts index 3a036b61..9794a63d 100644 --- a/packages/jupyterlab-chat/src/factory.ts +++ b/packages/jupyterlab-chat/src/factory.ts @@ -3,17 +3,9 @@ * Distributed under the terms of the Modified BSD License. */ -import { - Chat, - ChatWidget, - IActiveCellManager, - ISelectionWatcher, - IInputToolbarRegistryFactory -} from '@jupyter/chat'; -import { IDocumentManager } from '@jupyterlab/docmanager'; +import { Chat, ChatWidget, IInputToolbarRegistryFactory } from '@jupyter/chat'; import { ABCWidgetFactory, DocumentRegistry } from '@jupyterlab/docregistry'; -import { Contents, User } from '@jupyterlab/services'; -import { CommandRegistry } from '@lumino/commands'; +import { Contents } from '@jupyterlab/services'; import { ISignal, Signal } from '@lumino/signaling'; import { LabChatModel } from './model'; @@ -123,12 +115,7 @@ export class LabChatModelFactory implements DocumentRegistry.IModelFactory { constructor(options: LabChatModel.IOptions) { - this._user = options.user; - this._widgetConfig = options.widgetConfig; - this._commands = options.commands; - this._activeCellManager = options.activeCellManager ?? null; - this._selectionWatcher = options.selectionWatcher ?? null; - this._documentManager = options.documentManager ?? null; + this._modelOptions = options; } collaborative = true; @@ -197,20 +184,10 @@ export class LabChatModelFactory createNew(options: DocumentRegistry.IModelOptions): LabChatModel { return new LabChatModel({ ...options, - user: this._user, - widgetConfig: this._widgetConfig, - commands: this._commands, - activeCellManager: this._activeCellManager, - selectionWatcher: this._selectionWatcher, - documentManager: this._documentManager + ...this._modelOptions }); } private _disposed = false; - private _user: User.IIdentity | null; - private _widgetConfig: IWidgetConfig; - private _commands?: CommandRegistry; - private _activeCellManager: IActiveCellManager | null; - private _selectionWatcher: ISelectionWatcher | null; - private _documentManager: IDocumentManager | null; + private _modelOptions: Omit; } From 559244b21b8ea1cca332ebf7b46427e93ce75edd Mon Sep 17 00:00:00 2001 From: Nicolas Brichet Date: Wed, 24 Sep 2025 00:10:33 +0200 Subject: [PATCH 5/6] update gitignore to ignore vscode project files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 13915bd9..14ecde64 100644 --- a/.gitignore +++ b/.gitignore @@ -103,6 +103,9 @@ celerybeat-schedule .spyderproject .spyproject +# vscode project settings +.vscode + # Rope project settings .ropeproject From beca396935735e4a80786dbf95356dc1c25c3aae Mon Sep 17 00:00:00 2001 From: Nicolas Brichet Date: Wed, 24 Sep 2025 21:55:53 +0200 Subject: [PATCH 6/6] Fix the chat widget factory context --- packages/jupyterlab-chat/src/factory.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/jupyterlab-chat/src/factory.ts b/packages/jupyterlab-chat/src/factory.ts index 9794a63d..de5ad59e 100644 --- a/packages/jupyterlab-chat/src/factory.ts +++ b/packages/jupyterlab-chat/src/factory.ts @@ -75,7 +75,7 @@ export class ChatWidgetFactory extends ABCWidgetFactory< * @returns The widget */ protected createNewWidget(context: ChatWidgetFactory.IContext): LabChatPanel { - context = { ...context, ...this._chatOptions }; + Object.assign(context, this._chatOptions); if (this._inputToolbarFactory) { context.inputToolbarRegistry = this._inputToolbarFactory.create(); } @@ -93,6 +93,7 @@ export class ChatWidgetFactory extends ABCWidgetFactory< get contentProviderId(): string { return 'rtc'; } + // Must override both getter and setter from ABCFactory for type compatibility. set contentProviderId(_value: string | undefined) {} private _chatOptions: Omit; @@ -176,8 +177,6 @@ export class LabChatModelFactory /** * Create a new instance of LabChatModel. * - * @param languagePreference Language - * @param modelDB Model database * @returns The model */