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

Fix sending empty message with enter #945

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/jupyter-ai/jupyter_ai/chat_handlers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from jupyter_ai_magics import Persona
from jupyter_ai_magics.providers import BaseProvider
from langchain.pydantic_v1 import BaseModel
from langchain_core.chat_history import BaseChatMessageHistory

if TYPE_CHECKING:
from jupyter_ai.handlers import RootChatHandler
Expand Down Expand Up @@ -113,6 +114,7 @@ def __init__(
root_chat_handlers: Dict[str, "RootChatHandler"],
model_parameters: Dict[str, Dict],
chat_history: List[ChatMessage],
llm_chat_history: BaseChatMessageHistory,
root_dir: str,
preferred_dir: Optional[str],
dask_client_future: Awaitable[DaskClient],
Expand All @@ -122,6 +124,7 @@ def __init__(
self._root_chat_handlers = root_chat_handlers
self.model_parameters = model_parameters
self._chat_history = chat_history
self.llm_chat_history = llm_chat_history
self.parser = argparse.ArgumentParser(
add_help=False, description=self.help, formatter_class=MarkdownHelpFormatter
)
Expand Down
1 change: 1 addition & 0 deletions packages/jupyter-ai/jupyter_ai/chat_handlers/clear.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ async def process_message(self, _):
# Clear chat
handler.broadcast_message(ClearMessage())
self._chat_history.clear()
self.llm_chat_history.clear()

# Build /help message and reinstate it in chat
chat_handlers = handler.chat_handlers
Expand Down
4 changes: 1 addition & 3 deletions packages/jupyter-ai/jupyter_ai/chat_handlers/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from langchain_core.messages import AIMessageChunk
from langchain_core.runnables.history import RunnableWithMessageHistory

from ..history import BoundedChatHistory
from .base import BaseChatHandler, SlashCommandRoutingType


Expand Down Expand Up @@ -42,10 +41,9 @@ def create_llm_chain(

runnable = prompt_template | llm
if not llm.manages_history:
history = BoundedChatHistory(k=2)
runnable = RunnableWithMessageHistory(
runnable=runnable,
get_session_history=lambda *args: history,
get_session_history=lambda *args: self.llm_chat_history,
input_messages_key="input",
history_messages_key="history",
)
Expand Down
18 changes: 17 additions & 1 deletion packages/jupyter-ai/jupyter_ai/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from jupyter_ai_magics.utils import get_em_providers, get_lm_providers
from jupyter_server.extension.application import ExtensionApp
from tornado.web import StaticFileHandler
from traitlets import Dict, List, Unicode
from traitlets import Dict, Integer, List, Unicode

from .chat_handlers import (
AskChatHandler,
Expand All @@ -34,6 +34,7 @@
RootChatHandler,
SlashCommandsInfoHandler,
)
from .history import BoundedChatHistory

JUPYTERNAUT_AVATAR_ROUTE = JupyternautPersona.avatar_route
JUPYTERNAUT_AVATAR_PATH = str(
Expand Down Expand Up @@ -158,6 +159,15 @@ class AiExtension(ExtensionApp):
config=True,
)

default_max_chat_history = Integer(
default_value=2,
allow_none=False,
help="""
Number of chat interactions to keep in the conversational memory object.
""",
config=True,
)

def initialize_settings(self):
start = time.time()

Expand Down Expand Up @@ -222,6 +232,11 @@ def initialize_settings(self):
# memory object used by the LM chain.
self.settings["chat_history"] = []

# conversational memory object used by LM chain
self.settings["llm_chat_history"] = BoundedChatHistory(
k=self.default_max_chat_history
)

# list of pending messages
self.settings["pending_messages"] = []

Expand Down Expand Up @@ -252,6 +267,7 @@ def initialize_settings(self):
**common_handler_kargs,
"root_chat_handlers": self.settings["jai_root_chat_handlers"],
"chat_history": self.settings["chat_history"],
"llm_chat_history": self.settings["llm_chat_history"],
"root_dir": self.serverapp.root_dir,
"dask_client_future": self.settings["dask_client_future"],
"model_parameters": self.settings["model_parameters"],
Expand Down
16 changes: 8 additions & 8 deletions packages/jupyter-ai/jupyter_ai/history.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List, Sequence
from typing import List, Optional, Sequence

from langchain_core.chat_history import BaseChatMessageHistory
from langchain_core.messages import BaseMessage
Expand All @@ -14,27 +14,27 @@ class BoundedChatHistory(BaseChatMessageHistory, BaseModel):
messages and 2 AI messages.
"""

messages: List[BaseMessage] = Field(default_factory=list)
all_messages: List[BaseMessage] = Field(default_factory=list, alias="messages")
size: int = 0
k: int

@property
def messages(self) -> List[BaseMessage]:
return self.all_messages[-self.k * 2 :]

async def aget_messages(self) -> List[BaseMessage]:
return self.messages

def add_message(self, message: BaseMessage) -> None:
"""Add a self-created message to the store"""
self.messages.append(message)
self.size += 1

if self.size > self.k * 2:
self.messages.pop(0)
self.all_messages.append(message)

async def aadd_messages(self, messages: Sequence[BaseMessage]) -> None:
"""Add messages to the store"""
self.add_messages(messages)

def clear(self) -> None:
self.messages = []
self.all_messages = []

async def aclear(self) -> None:
self.clear()
2 changes: 2 additions & 0 deletions packages/jupyter-ai/jupyter_ai/tests/test_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from jupyter_ai.chat_handlers import DefaultChatHandler, learn
from jupyter_ai.config_manager import ConfigManager
from jupyter_ai.handlers import RootChatHandler
from jupyter_ai.history import BoundedChatHistory
from jupyter_ai.models import (
AgentStreamChunkMessage,
AgentStreamMessage,
Expand Down Expand Up @@ -70,6 +71,7 @@ def broadcast_message(message: Message) -> None:
root_chat_handlers={"root": root_handler},
model_parameters={},
chat_history=[],
llm_chat_history=BoundedChatHistory(k=2),
root_dir="",
preferred_dir="",
dask_client_future=None,
Expand Down
8 changes: 7 additions & 1 deletion packages/jupyter-ai/src/components/chat-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ export function ChatInput(props: ChatInputProps): JSX.Element {
props.chatHandler.sendMessage({ prompt, selection });
}

const inputExists = !!input.trim();
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
if (event.key !== 'Enter') {
return;
Expand All @@ -218,6 +219,12 @@ export function ChatInput(props: ChatInputProps): JSX.Element {
return;
}

if (!inputExists) {
event.stopPropagation();
event.preventDefault();
return;
}

if (
event.key === 'Enter' &&
((props.sendWithShiftEnter && event.shiftKey) ||
Expand All @@ -240,7 +247,6 @@ export function ChatInput(props: ChatInputProps): JSX.Element {
</span>
);

const inputExists = !!input.trim();
const sendButtonProps: SendButtonProps = {
onSend,
sendWithShiftEnter: props.sendWithShiftEnter,
Expand Down
Loading