diff --git a/docs/source/contributors/index.md b/docs/source/contributors/index.md index b15e81d89..0cc174098 100644 --- a/docs/source/contributors/index.md +++ b/docs/source/contributors/index.md @@ -2,6 +2,8 @@ This page is intended for people interested in building new or modified functionality for Jupyter AI. +If you would like to build applications that enhance Jupyter AI, please see the {doc}`developer's guide `. + ## Design principles Maintainers of Jupyter AI have adopted principles that contributors should also follow. These principles, which build on top of [the Zen of Python](https://peps.python.org/pep-0020/), are intended to earn users' trust by keeping their data under their control. The following list is non-exhaustive; maintainers have discretion to interpret and revise these principles. diff --git a/docs/source/developers/index.md b/docs/source/developers/index.md new file mode 100644 index 000000000..123315f7a --- /dev/null +++ b/docs/source/developers/index.md @@ -0,0 +1,18 @@ +# Developers + +The developer documentation is for authors who want to enhance +the functionality of Jupyter AI. + +If you are interested in contributing to Jupyter AI, +please see our {doc}`contributor's guide `. + +## Pydantic compatibility + +Jupyter AI is fully compatible with Python environments using Pydantic v1 +or Pydantic v2. Jupyter AI imports Pydantic classes from the +`langchain.pydantic_v1` module. Developers should do the same when they extend +Jupyter AI classes. + +For more details about using `langchain.pydantic_v1` in an environment with +Pydantic v2 installed, see the +[LangChain documentation on Pydantic compatibility](https://python.langchain.com/docs/guides/pydantic_compatibility). diff --git a/docs/source/index.md b/docs/source/index.md index b0c141068..28d094e93 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -34,4 +34,5 @@ maxdepth: 2 users/index contributors/index +developers/index ``` diff --git a/docs/source/users/index.md b/docs/source/users/index.md index 7cdc9162d..1deff65bf 100644 --- a/docs/source/users/index.md +++ b/docs/source/users/index.md @@ -5,6 +5,9 @@ Welcome to the user documentation for Jupyter AI. If you are interested in contributing to Jupyter AI, please see our {doc}`contributor's guide `. +If you would like to build applications that enhance Jupyter AI, +please see the {doc}`developer's guide `. + ## Prerequisites You can run Jupyter AI on any system that can run a supported Python version @@ -45,6 +48,13 @@ does not depend on JupyterLab or `jupyter_ai`. You can install If you have both `jupyter_ai_magics` and `jupyter_ai` installed, you should have the same version of each, to avoid errors. +Jupyter AI internally uses Pydantic v1 and should work with either Pydantic +version 1 or version 2. For compatibility, developers using Pydantic V2 +should import classes using the `pydantic.v1` package. See the +[LangChain Pydantic migration plan](https://python.langchain.com/docs/guides/pydantic_compatibility) +for advice about how developers should use `v1` to avoid mixing v1 and v2 +classes in their code. + ## Installation ### Installation via `pip` diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/embedding_providers.py b/packages/jupyter-ai-magics/jupyter_ai_magics/embedding_providers.py index 7ee7334fb..7dcda78b8 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/embedding_providers.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/embedding_providers.py @@ -14,7 +14,7 @@ HuggingFaceHubEmbeddings, OpenAIEmbeddings, ) -from pydantic import BaseModel, Extra +from langchain.pydantic_v1 import BaseModel, Extra class BaseEmbeddingsProvider(BaseModel): diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/parsers.py b/packages/jupyter-ai-magics/jupyter_ai_magics/parsers.py index cadd41f4a..168eece6b 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/parsers.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/parsers.py @@ -2,7 +2,7 @@ from typing import Literal, Optional, get_args import click -from pydantic import BaseModel +from langchain.pydantic_v1 import BaseModel FORMAT_CHOICES_TYPE = Literal[ "code", "html", "image", "json", "markdown", "math", "md", "text" diff --git a/packages/jupyter-ai-magics/jupyter_ai_magics/providers.py b/packages/jupyter-ai-magics/jupyter_ai_magics/providers.py index 865deb0e1..8155c2f2b 100644 --- a/packages/jupyter-ai-magics/jupyter_ai_magics/providers.py +++ b/packages/jupyter-ai-magics/jupyter_ai_magics/providers.py @@ -39,9 +39,9 @@ from langchain.llms.sagemaker_endpoint import LLMContentHandler from langchain.llms.utils import enforce_stop_tokens from langchain.prompts import PromptTemplate +from langchain.pydantic_v1 import BaseModel, Extra, root_validator from langchain.schema import LLMResult from langchain.utils import get_from_dict_or_env -from pydantic import BaseModel, Extra, root_validator class EnvAuthStrategy(BaseModel): diff --git a/packages/jupyter-ai-magics/pyproject.toml b/packages/jupyter-ai-magics/pyproject.toml index 60e231047..bb7a6dc57 100644 --- a/packages/jupyter-ai-magics/pyproject.toml +++ b/packages/jupyter-ai-magics/pyproject.toml @@ -22,7 +22,6 @@ dynamic = ["version", "description", "authors", "urls", "keywords"] dependencies = [ "ipython", - "pydantic~=1.0", "importlib_metadata>=5.2.0", "langchain==0.0.318", "typing_extensions>=4.5.0", diff --git a/packages/jupyter-ai/jupyter_ai/chat_handlers/generate.py b/packages/jupyter-ai/jupyter_ai/chat_handlers/generate.py index cdddee92d..42cb0e497 100644 --- a/packages/jupyter-ai/jupyter_ai/chat_handlers/generate.py +++ b/packages/jupyter-ai/jupyter_ai/chat_handlers/generate.py @@ -13,8 +13,8 @@ from langchain.llms import BaseLLM from langchain.output_parsers import PydanticOutputParser from langchain.prompts import PromptTemplate +from langchain.pydantic_v1 import BaseModel from langchain.schema.output_parser import BaseOutputParser -from pydantic import BaseModel class OutlineSection(BaseModel): diff --git a/packages/jupyter-ai/jupyter_ai/chat_handlers/learn.py b/packages/jupyter-ai/jupyter_ai/chat_handlers/learn.py index 40cae643b..d07e76b35 100644 --- a/packages/jupyter-ai/jupyter_ai/chat_handlers/learn.py +++ b/packages/jupyter-ai/jupyter_ai/chat_handlers/learn.py @@ -82,8 +82,7 @@ async def process_message(self, message: HumanChatMessage): em_provider_cls, em_provider_args = self.get_embedding_provider() if not em_provider_cls: self.reply( - "Please select an embedding provider in the chat settings, " - "then run your **/learn** command again." + "Sorry, please select an embedding provider before using the `/learn` command." ) return @@ -122,18 +121,17 @@ async def process_message(self, message: HumanChatMessage): ) self.save() - response = f"""🎉 I have learned from documents at **{load_path}** and - I am ready to answer questions about them. You can ask questions about these - documents by starting your message with **/ask**.""" + response = f"""🎉 I have learned documents at **{load_path}** and I am ready to answer questions about them. + You can ask questions about these docs by prefixing your message with **/ask**.""" self.reply(response, message) def _build_list_response(self): if not self.metadata.dirs: - return "I haven't learned from any documents yet." + return "There are no docs that have been learned yet." dirs = [dir.path for dir in self.metadata.dirs] dir_list = "\n- " + "\n- ".join(dirs) + "\n\n" - message = f"""I can answer questions about documents in these directories: + message = f"""I can answer questions from docs in these directories: {dir_list}""" return message @@ -200,10 +198,10 @@ async def delete_and_relearn(self): self.log.info( f"Switching embedding provider from {prev_em_id} to {curr_em_id}." ) - message = f"""🔔 Hi there! It seems like you have changed the embedding + message = f"""🔔 Hi there, it seems like you have updated the embeddings model from `{prev_em_id}` to `{curr_em_id}`. I have to re-learn the - documents you had previously submitted for learning. Please wait - until I am done with this task before you use the **/ask** command.""" + documents you had previously submitted for learning. Please wait to use + the **/ask** command until I am done with this task.""" self.reply(message) @@ -238,7 +236,7 @@ async def relearn(self, metadata: IndexMetadata): dir_list = ( "\n- " + "\n- ".join([dir.path for dir in self.metadata.dirs]) + "\n\n" ) - message = f"""🎉 I am done learning about documents in these directories: + message = f"""🎉 I am done learning docs in these directories: {dir_list} I am ready to answer questions about them. You can ask me about these documents by starting your message with **/ask**.""" self.reply(message) diff --git a/packages/jupyter-ai/jupyter_ai/handlers.py b/packages/jupyter-ai/jupyter_ai/handlers.py index 289df81dc..126a6c94c 100644 --- a/packages/jupyter-ai/jupyter_ai/handlers.py +++ b/packages/jupyter-ai/jupyter_ai/handlers.py @@ -11,7 +11,7 @@ from jupyter_ai.config_manager import ConfigManager, KeyEmptyError, WriteConflictError from jupyter_server.base.handlers import APIHandler as BaseAPIHandler from jupyter_server.base.handlers import JupyterHandler -from pydantic import ValidationError +from langchain.pydantic_v1 import ValidationError from tornado import web, websocket from tornado.web import HTTPError diff --git a/packages/jupyter-ai/jupyter_ai/models.py b/packages/jupyter-ai/jupyter_ai/models.py index efe501923..41509a74d 100644 --- a/packages/jupyter-ai/jupyter_ai/models.py +++ b/packages/jupyter-ai/jupyter_ai/models.py @@ -1,7 +1,7 @@ from typing import Any, Dict, List, Literal, Optional, Union from jupyter_ai_magics.providers import AuthStrategy, Field -from pydantic import BaseModel, validator +from langchain.pydantic_v1 import BaseModel, validator DEFAULT_CHUNK_SIZE = 2000 DEFAULT_CHUNK_OVERLAP = 100 diff --git a/packages/jupyter-ai/jupyter_ai/tests/test_config_manager.py b/packages/jupyter-ai/jupyter_ai/tests/test_config_manager.py index 8fa59ab6a..dca79393a 100644 --- a/packages/jupyter-ai/jupyter_ai/tests/test_config_manager.py +++ b/packages/jupyter-ai/jupyter_ai/tests/test_config_manager.py @@ -12,7 +12,7 @@ ) from jupyter_ai.models import DescribeConfigResponse, GlobalConfig, UpdateConfigRequest from jupyter_ai_magics.utils import get_em_providers, get_lm_providers -from pydantic import ValidationError +from langchain.pydantic_v1 import ValidationError @pytest.fixture diff --git a/packages/jupyter-ai/pyproject.toml b/packages/jupyter-ai/pyproject.toml index 99dd13ddd..0f8d4a58a 100644 --- a/packages/jupyter-ai/pyproject.toml +++ b/packages/jupyter-ai/pyproject.toml @@ -24,7 +24,6 @@ classifiers = [ dependencies = [ "jupyter_server>=1.6,<3", "jupyterlab~=4.0", - "pydantic~=1.0", "openai~=0.26", "aiosqlite>=0.18", "importlib_metadata>=5.2.0",