Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new InputModel class for managing input state #171

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

brichet
Copy link
Collaborator

@brichet brichet commented Feb 17, 2025

This PR adds an InputModel class to handle input state.
This is proposed for:

  • simplifying the use of the chats commands, that needs to get the input content, the current word and to be able to replace it.
  • enhancing the messages editiing, by allowing adding and deleting attachments.

By default, the chat model includes an input model, for the "main" input of the chat panel. When editing a message, a new input model is created for this edition, and deleted when edition is over (cancelled or validated).

Fixes #163

Copy link
Contributor

Binder 👈 Launch a Binder on branch brichet/jupyter-chat/input-model

@brichet brichet added the enhancement New feature or request label Feb 17, 2025
@brichet brichet marked this pull request as ready for review February 17, 2025 16:25
@dlqqq
Copy link
Member

dlqqq commented Feb 17, 2025

@brichet I think this PR will cause some conflicts with the chat commands PR in #161. I think it would be best to rebase this branch & fix conflicts after merging #161. I'll give this a review after.

@dlqqq dlqqq changed the title Add an input model Add new InputModel class for managing input state Feb 17, 2025
@dlqqq
Copy link
Member

dlqqq commented Feb 17, 2025

#148 should probably also be merged first to address any merge conflicts. I've approved that PR.

@brichet brichet marked this pull request as draft February 17, 2025 22:26
@brichet brichet marked this pull request as ready for review February 18, 2025 13:59
Comment on lines +112 to +114
// When a command is selected, the input value is not updated to avoid conflict
// changes. It must be updated here, even if there is no replacement string.
inputModel.replaceCurrentWord(command.replaceWith ?? command.name);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is to avoid concurrency on the input update.
When a command is selected from the list, the onInputChange() callback of the ChatInput is called first with the value (name) of the command. Then the onChange() callback of the Autocomplete is called. This resulted to a replacement of the whole input.
To avoid this behavior, the onInputChange() does not update the input value when change come from a selected command (using the reason props, set to reset in that case), and the value is updated in the onchange(), whether it need to be replaced or not.

This seems to work smoothly, but maybe it deserves some more testing to ensure it did not break anything else.

cc. @dlqqq

Copy link
Member

@dlqqq dlqqq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brichet Wow, thanks for working on this so quickly! All of the high-level changes look good. I left some feedback for you below, but still need more time to complete a full review.

My day tomorrow will be full of meetings, so I will likely need until the end of Thursday to finish reviewing this. Feel free to work on another issue using the Kanban board: https://github.com/orgs/jupyterlab/projects/9

Comment on lines 69 to 72
handleChatCommand(
command: ChatCommand,
currentWord: string,
replaceCurrentWord: (newWord: string) => void
inputModel: IInputModel
): Promise<void>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also pass the input model to getChatCommands() method above on line 60? The currentWord: string argument should be replaced with inputModel: IInputModel.

import { useChatCommands } from './input/use-chat-commands';
import { IChatCommandRegistry } from '../chat-commands';

const INPUT_BOX_CLASS = 'jp-chat-input-container';

export function ChatInput(props: ChatInput.IProps): JSX.Element {
const { documentManager, model } = props;
const [input, setInput] = useState<string>(props.value || '');
const [input, setInput] = useState<string>(model.value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm hesitant to leave this line here because it creates 2 sources of truth about what the current state of the input is (model.value v.s. input). It seems like we should remove the input and setInput variables entirely. Can you explore making these changes?

* The initial value of the input (default to '')
*/
value?: string;
model: IInputModel;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a nitpick, but can we prefer naming input models just input instead of model or inputModel? The word model doesn't convey anything useful. Preferring input produces code that is easier to follow:

input.value // value of the input
input.attachments // the input attachments
input.cursorIndex // index of the cursor in the input

Same goes for the arguments to the IChatCommandProvider methods.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Subissue: Lift chat input state to ChatModel
2 participants