diff --git a/django_ai_assistant/helpers/assistants.py b/django_ai_assistant/helpers/assistants.py index 3551b6f..dd85204 100644 --- a/django_ai_assistant/helpers/assistants.py +++ b/django_ai_assistant/helpers/assistants.py @@ -1,7 +1,8 @@ import abc import inspect +import json import re -from typing import Annotated, Any, ClassVar, Sequence, TypedDict, cast +from typing import Annotated, Any, ClassVar, Dict, Sequence, Type, TypedDict, cast from langchain.chains.combine_documents.base import ( DEFAULT_DOCUMENT_PROMPT, @@ -37,6 +38,7 @@ from langgraph.graph import END, StateGraph from langgraph.graph.message import add_messages from langgraph.prebuilt import ToolNode +from pydantic import BaseModel from django_ai_assistant.decorators import with_cast_id from django_ai_assistant.exceptions import ( @@ -79,6 +81,12 @@ class AIAssistant(abc.ABC): # noqa: F821 When True, the assistant will use a retriever to get documents to provide as context to the LLM. Additionally, the assistant class should implement the `get_retriever` method to return the retriever to use.""" + structured_output: Dict[str, Any] | Type[BaseModel] | Type | None = None + """Structured output to use for the assistant.\n + Defaults to `None`. + When not `None`, the assistant will return a structured output in the provided format. + See https://python.langchain.com/v0.2/docs/how_to/structured_output/ for the available formats. + """ _user: Any | None """The current user the assistant is helping. A model instance.\n Set by the constructor. @@ -269,6 +277,26 @@ def get_llm(self) -> BaseChatModel: model_kwargs=model_kwargs, ) + def get_structured_output_llm(self) -> Runnable: + """Get the LLM model to use for the structured output. + + Returns: + BaseChatModel: The LLM model to use for the structured output. + """ + if not self.structured_output: + raise ValueError("structured_output is not defined") + + llm = self.get_llm() + + method = "json_mode" + if isinstance(llm, ChatOpenAI): + # When using ChatOpenAI, it's better to use json_schema method + # because it enables strict mode. + # https://platform.openai.com/docs/guides/structured-outputs + method = "json_schema" + + return llm.with_structured_output(self.structured_output, method=method) + def get_tools(self) -> Sequence[BaseTool]: """Get the list of method tools the assistant can use. By default, this is the `_method_tools` attribute, which are all `@method_tool`s.\n @@ -422,7 +450,37 @@ class AgentState(TypedDict): output: str def setup(state: AgentState): - return {"messages": [SystemMessage(content=self.get_instructions())]} + messages: list[AnyMessage] = [SystemMessage(content=self.get_instructions())] + + if self.structured_output: + schema = None + + # If Pydantic + if inspect.isclass(self.structured_output) and issubclass( + self.structured_output, BaseModel + ): + schema = json.dumps(self.structured_output.model_json_schema()) + + schema_information = ( + f"JSON will have the following schema:\n\n{schema}\n\n" if schema else "" + ) + tools_information = "Gather information using tools. " if tools else "" + + # The assistant won't have access to the schema of the structured output before + # the last step of the chat. This message gives visibility about what fields the + # response should have so it can gather the necessary information by using tools. + messages.append( + HumanMessage( + content=( + "In the last step of this chat you will be asked to respond in JSON. " + + schema_information + + tools_information + + "Don't generate JSON until you are explicitly told to. " + ) + ) + ) + + return {"messages": messages} def history(state: AgentState): history = message_history.messages if message_history else [] @@ -433,7 +491,9 @@ def retriever(state: AgentState): return retriever = self.get_history_aware_retriever() - messages_without_input = state["messages"][:-1] + # Remove the initial instructions to prevent having two SystemMessages + # This is necessary for compatibility with Anthropic + messages_without_input = state["messages"][1:-1] docs = retriever.invoke({"input": state["input"], "history": messages_without_input}) document_separator = self.get_document_separator() @@ -443,11 +503,10 @@ def retriever(state: AgentState): format_document(doc, document_prompt) for doc in docs ) - return { - "messages": SystemMessage( - content=f"---START OF CONTEXT---\n{formatted_docs}---END OF CONTEXT---\n" - ) - } + system_message = state["messages"][0] + system_message.content += ( + f"\n\n---START OF CONTEXT---\n{formatted_docs}---END OF CONTEXT---\n\n" + ) def agent(state: AgentState): response = llm_with_tools.invoke(state["messages"]) @@ -463,7 +522,20 @@ def tool_selector(state: AgentState): return "continue" def record_response(state: AgentState): - return {"output": state["messages"][-1].content} + if self.structured_output: + llm_with_structured_output = self.get_structured_output_llm() + response = llm_with_structured_output.invoke( + [ + *state["messages"], + HumanMessage( + content="Use the information gathered in the conversation to answer." + ), + ] + ) + else: + response = state["messages"][-1].content + + return {"output": response} workflow = StateGraph(AgentState) diff --git a/example/demo/views.py b/example/demo/views.py index 74c2a1c..d2b91b6 100644 --- a/example/demo/views.py +++ b/example/demo/views.py @@ -1,5 +1,3 @@ -import json - from django.contrib import messages from django.http import JsonResponse from django.shortcuts import get_object_or_404, redirect, render @@ -122,4 +120,4 @@ def get(self, request, *args, **kwargs): a = TourGuideAIAssistant() data = a.run(f"My coordinates are: ({coordinates})") - return JsonResponse(json.loads(data)) + return JsonResponse(data.model_dump()) diff --git a/example/tour_guide/ai_assistants.py b/example/tour_guide/ai_assistants.py index e44840f..c91dd85 100644 --- a/example/tour_guide/ai_assistants.py +++ b/example/tour_guide/ai_assistants.py @@ -2,49 +2,37 @@ from django.utils import timezone +from pydantic import BaseModel, Field + from django_ai_assistant import AIAssistant, method_tool from tour_guide.integrations import fetch_points_of_interest -def _tour_guide_example_json(): - return json.dumps( - { - "nearby_attractions": [ - { - "attraction_name": f"", - "attraction_description": f"", - "attraction_url": f"", - } - for i in range(1, 6) - ] - }, - indent=2, - ).translate( # Necessary due to ChatPromptTemplate - str.maketrans( - { - "{": "{{", - "}": "}}", - } - ) +class Attraction(BaseModel): + attraction_name: str = Field(description="The name of the attraction in english") + attraction_description: str = Field( + description="The description of the attraction, provide information in an entertaining way" + ) + attraction_url: str = Field( + description="The URL of the attraction, keep empty if you don't have this information" ) +class TourGuide(BaseModel): + nearby_attractions: list[Attraction] = Field(description="The list of nearby attractions") + + class TourGuideAIAssistant(AIAssistant): id = "tour_guide_assistant" # noqa: A003 name = "Tour Guide Assistant" instructions = ( "You are a tour guide assistant that offers information about nearby attractions. " "You will receive the user coordinates and should use available tools to find nearby attractions. " + "Only include in your response the items that are relevant to a tourist visiting the area. " "Only call the find_nearby_attractions tool once. " - "Your response should only contain valid JSON data. DON'T include '```json' in your response. " - "The JSON should be formatted according to the following structure: \n" - f"\n\n{_tour_guide_example_json()}\n\n\n" - "In the 'attraction_name' field provide the name of the attraction in english. " - "In the 'attraction_description' field generate an overview about the attraction with the most important information, " - "curiosities and interesting facts. " - "Only include a value for the 'attraction_url' field if you find a real value in the provided data otherwise keep it empty. " ) model = "gpt-4o-2024-08-06" + structured_output = TourGuide def get_instructions(self): # Warning: this will use the server's timezone diff --git a/poetry.lock b/poetry.lock index b02684b..610a544 100644 --- a/poetry.lock +++ b/poetry.lock @@ -121,6 +121,31 @@ files = [ {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, ] +[[package]] +name = "anthropic" +version = "0.34.2" +description = "The official Python library for the anthropic API" +optional = false +python-versions = ">=3.7" +files = [ + {file = "anthropic-0.34.2-py3-none-any.whl", hash = "sha256:f50a628eb71e2c76858b106c8cbea278c45c6bd2077cb3aff716a112abddc9fc"}, + {file = "anthropic-0.34.2.tar.gz", hash = "sha256:808ea19276f26646bfde9ee535669735519376e4eeb301a2974fc69892be1d6e"}, +] + +[package.dependencies] +anyio = ">=3.5.0,<5" +distro = ">=1.7.0,<2" +httpx = ">=0.23.0,<1" +jiter = ">=0.4.0,<1" +pydantic = ">=1.9.0,<3" +sniffio = "*" +tokenizers = ">=0.13.0" +typing-extensions = ">=4.7,<5" + +[package.extras] +bedrock = ["boto3 (>=1.28.57)", "botocore (>=1.31.57)"] +vertex = ["google-auth (>=2,<3)"] + [[package]] name = "anyio" version = "4.4.0" @@ -681,6 +706,17 @@ files = [ {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, ] +[[package]] +name = "defusedxml" +version = "0.7.1" +description = "XML bomb protection for Python stdlib modules" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] + [[package]] name = "distlib" version = "0.3.8" @@ -921,6 +957,45 @@ files = [ {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, ] +[[package]] +name = "fsspec" +version = "2024.9.0" +description = "File-system specification" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fsspec-2024.9.0-py3-none-any.whl", hash = "sha256:a0947d552d8a6efa72cc2c730b12c41d043509156966cca4fb157b0f2a0c574b"}, + {file = "fsspec-2024.9.0.tar.gz", hash = "sha256:4b0afb90c2f21832df142f292649035d80b421f60a9e1c027802e5a0da2b04e8"}, +] + +[package.extras] +abfs = ["adlfs"] +adl = ["adlfs"] +arrow = ["pyarrow (>=1)"] +dask = ["dask", "distributed"] +dev = ["pre-commit", "ruff"] +doc = ["numpydoc", "sphinx", "sphinx-design", "sphinx-rtd-theme", "yarl"] +dropbox = ["dropbox", "dropboxdrivefs", "requests"] +full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"] +fuse = ["fusepy"] +gcs = ["gcsfs"] +git = ["pygit2"] +github = ["requests"] +gs = ["gcsfs"] +gui = ["panel"] +hdfs = ["pyarrow (>=1)"] +http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)"] +libarchive = ["libarchive-c"] +oci = ["ocifs"] +s3 = ["s3fs"] +sftp = ["paramiko"] +smb = ["smbprotocol"] +ssh = ["paramiko"] +test = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "numpy", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "requests"] +test-downstream = ["aiobotocore (>=2.5.4,<3.0.0)", "dask-expr", "dask[dataframe,test]", "moto[server] (>4,<5)", "pytest-timeout", "xarray"] +test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr", "zstandard"] +tqdm = ["tqdm"] + [[package]] name = "ghp-import" version = "2.1.0" @@ -1111,6 +1186,40 @@ cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] +[[package]] +name = "huggingface-hub" +version = "0.24.7" +description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "huggingface_hub-0.24.7-py3-none-any.whl", hash = "sha256:a212c555324c8a7b1ffdd07266bb7e7d69ca71aa238d27b7842d65e9a26ac3e5"}, + {file = "huggingface_hub-0.24.7.tar.gz", hash = "sha256:0ad8fb756e2831da0ac0491175b960f341fe06ebcf80ed6f8728313f95fc0207"}, +] + +[package.dependencies] +filelock = "*" +fsspec = ">=2023.5.0" +packaging = ">=20.9" +pyyaml = ">=5.1" +requests = "*" +tqdm = ">=4.42.1" +typing-extensions = ">=3.7.4.3" + +[package.extras] +all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.5.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] +cli = ["InquirerPy (==0.3.4)"] +dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.5.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] +fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"] +hf-transfer = ["hf-transfer (>=0.1.4)"] +inference = ["aiohttp", "minijinja (>=1.0)"] +quality = ["mypy (==1.5.1)", "ruff (>=0.5.0)"] +tensorflow = ["graphviz", "pydot", "tensorflow"] +tensorflow-testing = ["keras (<3.0)", "tensorflow"] +testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] +torch = ["safetensors[torch]", "torch"] +typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"] + [[package]] name = "identify" version = "2.5.36" @@ -1324,6 +1433,76 @@ MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] +[[package]] +name = "jiter" +version = "0.5.0" +description = "Fast iterable JSON parser." +optional = false +python-versions = ">=3.8" +files = [ + {file = "jiter-0.5.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b599f4e89b3def9a94091e6ee52e1d7ad7bc33e238ebb9c4c63f211d74822c3f"}, + {file = "jiter-0.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a063f71c4b06225543dddadbe09d203dc0c95ba352d8b85f1221173480a71d5"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acc0d5b8b3dd12e91dd184b87273f864b363dfabc90ef29a1092d269f18c7e28"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c22541f0b672f4d741382a97c65609332a783501551445ab2df137ada01e019e"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:63314832e302cc10d8dfbda0333a384bf4bcfce80d65fe99b0f3c0da8945a91a"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a25fbd8a5a58061e433d6fae6d5298777c0814a8bcefa1e5ecfff20c594bd749"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:503b2c27d87dfff5ab717a8200fbbcf4714516c9d85558048b1fc14d2de7d8dc"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6d1f3d27cce923713933a844872d213d244e09b53ec99b7a7fdf73d543529d6d"}, + {file = "jiter-0.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c95980207b3998f2c3b3098f357994d3fd7661121f30669ca7cb945f09510a87"}, + {file = "jiter-0.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:afa66939d834b0ce063f57d9895e8036ffc41c4bd90e4a99631e5f261d9b518e"}, + {file = "jiter-0.5.0-cp310-none-win32.whl", hash = "sha256:f16ca8f10e62f25fd81d5310e852df6649af17824146ca74647a018424ddeccf"}, + {file = "jiter-0.5.0-cp310-none-win_amd64.whl", hash = "sha256:b2950e4798e82dd9176935ef6a55cf6a448b5c71515a556da3f6b811a7844f1e"}, + {file = "jiter-0.5.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d4c8e1ed0ef31ad29cae5ea16b9e41529eb50a7fba70600008e9f8de6376d553"}, + {file = "jiter-0.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6f16e21276074a12d8421692515b3fd6d2ea9c94fd0734c39a12960a20e85f3"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5280e68e7740c8c128d3ae5ab63335ce6d1fb6603d3b809637b11713487af9e6"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:583c57fc30cc1fec360e66323aadd7fc3edeec01289bfafc35d3b9dcb29495e4"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26351cc14507bdf466b5f99aba3df3143a59da75799bf64a53a3ad3155ecded9"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4829df14d656b3fb87e50ae8b48253a8851c707da9f30d45aacab2aa2ba2d614"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a42a4bdcf7307b86cb863b2fb9bb55029b422d8f86276a50487982d99eed7c6e"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04d461ad0aebf696f8da13c99bc1b3e06f66ecf6cfd56254cc402f6385231c06"}, + {file = "jiter-0.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e6375923c5f19888c9226582a124b77b622f8fd0018b843c45eeb19d9701c403"}, + {file = "jiter-0.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2cec323a853c24fd0472517113768c92ae0be8f8c384ef4441d3632da8baa646"}, + {file = "jiter-0.5.0-cp311-none-win32.whl", hash = "sha256:aa1db0967130b5cab63dfe4d6ff547c88b2a394c3410db64744d491df7f069bb"}, + {file = "jiter-0.5.0-cp311-none-win_amd64.whl", hash = "sha256:aa9d2b85b2ed7dc7697597dcfaac66e63c1b3028652f751c81c65a9f220899ae"}, + {file = "jiter-0.5.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9f664e7351604f91dcdd557603c57fc0d551bc65cc0a732fdacbf73ad335049a"}, + {file = "jiter-0.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:044f2f1148b5248ad2c8c3afb43430dccf676c5a5834d2f5089a4e6c5bbd64df"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:702e3520384c88b6e270c55c772d4bd6d7b150608dcc94dea87ceba1b6391248"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:528d742dcde73fad9d63e8242c036ab4a84389a56e04efd854062b660f559544"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8cf80e5fe6ab582c82f0c3331df27a7e1565e2dcf06265afd5173d809cdbf9ba"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:44dfc9ddfb9b51a5626568ef4e55ada462b7328996294fe4d36de02fce42721f"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c451f7922992751a936b96c5f5b9bb9312243d9b754c34b33d0cb72c84669f4e"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:308fce789a2f093dca1ff91ac391f11a9f99c35369117ad5a5c6c4903e1b3e3a"}, + {file = "jiter-0.5.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7f5ad4a7c6b0d90776fdefa294f662e8a86871e601309643de30bf94bb93a64e"}, + {file = "jiter-0.5.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ea189db75f8eca08807d02ae27929e890c7d47599ce3d0a6a5d41f2419ecf338"}, + {file = "jiter-0.5.0-cp312-none-win32.whl", hash = "sha256:e3bbe3910c724b877846186c25fe3c802e105a2c1fc2b57d6688b9f8772026e4"}, + {file = "jiter-0.5.0-cp312-none-win_amd64.whl", hash = "sha256:a586832f70c3f1481732919215f36d41c59ca080fa27a65cf23d9490e75b2ef5"}, + {file = "jiter-0.5.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:f04bc2fc50dc77be9d10f73fcc4e39346402ffe21726ff41028f36e179b587e6"}, + {file = "jiter-0.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6f433a4169ad22fcb550b11179bb2b4fd405de9b982601914ef448390b2954f3"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad4a6398c85d3a20067e6c69890ca01f68659da94d74c800298581724e426c7e"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6baa88334e7af3f4d7a5c66c3a63808e5efbc3698a1c57626541ddd22f8e4fbf"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ece0a115c05efca597c6d938f88c9357c843f8c245dbbb53361a1c01afd7148"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:335942557162ad372cc367ffaf93217117401bf930483b4b3ebdb1223dbddfa7"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:649b0ee97a6e6da174bffcb3c8c051a5935d7d4f2f52ea1583b5b3e7822fbf14"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f4be354c5de82157886ca7f5925dbda369b77344b4b4adf2723079715f823989"}, + {file = "jiter-0.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5206144578831a6de278a38896864ded4ed96af66e1e63ec5dd7f4a1fce38a3a"}, + {file = "jiter-0.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8120c60f8121ac3d6f072b97ef0e71770cc72b3c23084c72c4189428b1b1d3b6"}, + {file = "jiter-0.5.0-cp38-none-win32.whl", hash = "sha256:6f1223f88b6d76b519cb033a4d3687ca157c272ec5d6015c322fc5b3074d8a5e"}, + {file = "jiter-0.5.0-cp38-none-win_amd64.whl", hash = "sha256:c59614b225d9f434ea8fc0d0bec51ef5fa8c83679afedc0433905994fb36d631"}, + {file = "jiter-0.5.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:0af3838cfb7e6afee3f00dc66fa24695199e20ba87df26e942820345b0afc566"}, + {file = "jiter-0.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:550b11d669600dbc342364fd4adbe987f14d0bbedaf06feb1b983383dcc4b961"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:489875bf1a0ffb3cb38a727b01e6673f0f2e395b2aad3c9387f94187cb214bbf"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b250ca2594f5599ca82ba7e68785a669b352156260c5362ea1b4e04a0f3e2389"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ea18e01f785c6667ca15407cd6dabbe029d77474d53595a189bdc813347218e"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:462a52be85b53cd9bffd94e2d788a09984274fe6cebb893d6287e1c296d50653"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92cc68b48d50fa472c79c93965e19bd48f40f207cb557a8346daa020d6ba973b"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1c834133e59a8521bc87ebcad773608c6fa6ab5c7a022df24a45030826cf10bc"}, + {file = "jiter-0.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab3a71ff31cf2d45cb216dc37af522d335211f3a972d2fe14ea99073de6cb104"}, + {file = "jiter-0.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cccd3af9c48ac500c95e1bcbc498020c87e1781ff0345dd371462d67b76643eb"}, + {file = "jiter-0.5.0-cp39-none-win32.whl", hash = "sha256:368084d8d5c4fc40ff7c3cc513c4f73e02c85f6009217922d0823a48ee7adf61"}, + {file = "jiter-0.5.0-cp39-none-win_amd64.whl", hash = "sha256:ce03f7b4129eb72f1687fa11300fbf677b02990618428934662406d2a76742a1"}, + {file = "jiter-0.5.0.tar.gz", hash = "sha256:1d916ba875bcab5c5f7d927df998c4cb694d27dceddf3392e58beaf10563368a"}, +] + [[package]] name = "joblib" version = "1.4.2" @@ -1412,6 +1591,22 @@ requests = ">=2,<3" SQLAlchemy = ">=1.4,<3" tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<9.0.0" +[[package]] +name = "langchain-anthropic" +version = "0.1.23" +description = "An integration package connecting AnthropicMessages and LangChain" +optional = false +python-versions = "<4.0,>=3.8.1" +files = [ + {file = "langchain_anthropic-0.1.23-py3-none-any.whl", hash = "sha256:89cafdaf4c9e522484b0ca8bafcceb0a5e4ffca89f7c7c9cec1e2ba411208208"}, + {file = "langchain_anthropic-0.1.23.tar.gz", hash = "sha256:f2ce045bd0ae09d5f11fed4b84a38ce306822b7bcac77232345f40115df66d51"}, +] + +[package.dependencies] +anthropic = ">=0.30.0,<1" +defusedxml = ">=0.7.1,<0.8.0" +langchain-core = ">=0.2.26,<0.3.0" + [[package]] name = "langchain-community" version = "0.2.6" @@ -1463,18 +1658,18 @@ typing-extensions = ">=4.7" [[package]] name = "langchain-openai" -version = "0.1.14" +version = "0.1.23" description = "An integration package connecting OpenAI and LangChain" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_openai-0.1.14-py3-none-any.whl", hash = "sha256:fcd34cc5b5713798908a5828d364b4426e3b1afccbd564d344e5477acb86634a"}, - {file = "langchain_openai-0.1.14.tar.gz", hash = "sha256:1f13d6041e8bedddf6eb47ccad7416e05af38fa169324f7f1bdf4f385780f8d8"}, + {file = "langchain_openai-0.1.23-py3-none-any.whl", hash = "sha256:8e3d215803e157f26480c6108eb4333629832b1a0e746723060c24f93b8b78f4"}, + {file = "langchain_openai-0.1.23.tar.gz", hash = "sha256:ed7f16671ea0af177ac5f82d5645a746c5097c56f97b31798e5c07b5c84f0eed"}, ] [package.dependencies] -langchain-core = ">=0.2.2,<0.3" -openai = ">=1.32.0,<2.0.0" +langchain-core = ">=0.2.35,<0.3.0" +openai = ">=1.40.0,<2.0.0" tiktoken = ">=0.7,<1" [[package]] @@ -2251,23 +2446,24 @@ files = [ [[package]] name = "openai" -version = "1.35.10" +version = "1.44.1" description = "The official Python library for the openai API" optional = false python-versions = ">=3.7.1" files = [ - {file = "openai-1.35.10-py3-none-any.whl", hash = "sha256:962cb5c23224b5cbd16078308dabab97a08b0a5ad736a4fdb3dc2ffc44ac974f"}, - {file = "openai-1.35.10.tar.gz", hash = "sha256:85966949f4f960f3e4b239a659f9fd64d3a97ecc43c44dc0a044b5c7f11cccc6"}, + {file = "openai-1.44.1-py3-none-any.whl", hash = "sha256:07e2c2758d1c94151c740b14dab638ba0d04bcb41a2e397045c90e7661cdf741"}, + {file = "openai-1.44.1.tar.gz", hash = "sha256:e0ffdab601118329ea7529e684b606a72c6c9d4f05be9ee1116255fcf5593874"}, ] [package.dependencies] anyio = ">=3.5.0,<5" distro = ">=1.7.0,<2" httpx = ">=0.23.0,<1" +jiter = ">=0.4.0,<1" pydantic = ">=1.9.0,<3" sniffio = "*" tqdm = ">4" -typing-extensions = ">=4.7,<5" +typing-extensions = ">=4.11,<5" [package.extras] datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"] @@ -3460,6 +3656,123 @@ requests = ">=2.26.0" [package.extras] blobfile = ["blobfile (>=2)"] +[[package]] +name = "tokenizers" +version = "0.20.0" +description = "" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tokenizers-0.20.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6cff5c5e37c41bc5faa519d6f3df0679e4b37da54ea1f42121719c5e2b4905c0"}, + {file = "tokenizers-0.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:62a56bf75c27443432456f4ca5ca055befa95e25be8a28141cc495cac8ae4d6d"}, + {file = "tokenizers-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68cc7de6a63f09c4a86909c2597b995aa66e19df852a23aea894929c74369929"}, + {file = "tokenizers-0.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:053c37ecee482cc958fdee53af3c6534286a86f5d35aac476f7c246830e53ae5"}, + {file = "tokenizers-0.20.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d7074aaabc151a6363fa03db5493fc95b423b2a1874456783989e96d541c7b6"}, + {file = "tokenizers-0.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a11435780f2acd89e8fefe5e81cecf01776f6edb9b3ac95bcb76baee76b30b90"}, + {file = "tokenizers-0.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9a81cd2712973b007d84268d45fc3f6f90a79c31dfe7f1925e6732f8d2959987"}, + {file = "tokenizers-0.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7dfd796ab9d909f76fb93080e1c7c8309f196ecb316eb130718cd5e34231c69"}, + {file = "tokenizers-0.20.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8029ad2aa8cb00605c9374566034c1cc1b15130713e0eb5afcef6cface8255c9"}, + {file = "tokenizers-0.20.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ca4d54260ebe97d59dfa9a30baa20d0c4dd9137d99a8801700055c561145c24e"}, + {file = "tokenizers-0.20.0-cp310-none-win32.whl", hash = "sha256:95ee16b57cec11b86a7940174ec5197d506439b0f415ab3859f254b1dffe9df0"}, + {file = "tokenizers-0.20.0-cp310-none-win_amd64.whl", hash = "sha256:0a61a11e93eeadbf02aea082ffc75241c4198e0608bbbac4f65a9026851dcf37"}, + {file = "tokenizers-0.20.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6636b798b3c4d6c9b1af1a918bd07c867808e5a21c64324e95318a237e6366c3"}, + {file = "tokenizers-0.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ec603e42eaf499ffd58b9258162add948717cf21372458132f14e13a6bc7172"}, + {file = "tokenizers-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cce124264903a8ea6f8f48e1cc7669e5ef638c18bd4ab0a88769d5f92debdf7f"}, + {file = "tokenizers-0.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07bbeba0231cf8de07aa6b9e33e9779ff103d47042eeeb859a8c432e3292fb98"}, + {file = "tokenizers-0.20.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:06c0ca8397b35d38b83a44a9c6929790c1692957d88541df061cb34d82ebbf08"}, + {file = "tokenizers-0.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ca6557ac3b83d912dfbb1f70ab56bd4b0594043916688e906ede09f42e192401"}, + {file = "tokenizers-0.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a5ad94c9e80ac6098328bee2e3264dbced4c6faa34429994d473f795ec58ef4"}, + {file = "tokenizers-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b5c7f906ee6bec30a9dc20268a8b80f3b9584de1c9f051671cb057dc6ce28f6"}, + {file = "tokenizers-0.20.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:31e087e9ee1b8f075b002bfee257e858dc695f955b43903e1bb4aa9f170e37fe"}, + {file = "tokenizers-0.20.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c3124fb6f3346cb3d8d775375d3b429bf4dcfc24f739822702009d20a4297990"}, + {file = "tokenizers-0.20.0-cp311-none-win32.whl", hash = "sha256:a4bb8b40ba9eefa621fdcabf04a74aa6038ae3be0c614c6458bd91a4697a452f"}, + {file = "tokenizers-0.20.0-cp311-none-win_amd64.whl", hash = "sha256:2b709d371f1fe60a28ef0c5c67815952d455ca7f34dbe7197eaaed3cc54b658e"}, + {file = "tokenizers-0.20.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:15c81a17d0d66f4987c6ca16f4bea7ec253b8c7ed1bb00fdc5d038b1bb56e714"}, + {file = "tokenizers-0.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6a531cdf1fb6dc41c984c785a3b299cb0586de0b35683842a3afbb1e5207f910"}, + {file = "tokenizers-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06caabeb4587f8404e0cd9d40f458e9cba3e815c8155a38e579a74ff3e2a4301"}, + {file = "tokenizers-0.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8768f964f23f5b9f50546c0369c75ab3262de926983888bbe8b98be05392a79c"}, + {file = "tokenizers-0.20.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:626403860152c816f97b649fd279bd622c3d417678c93b4b1a8909b6380b69a8"}, + {file = "tokenizers-0.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c1b88fa9e5ff062326f4bf82681da5a96fca7104d921a6bd7b1e6fcf224af26"}, + {file = "tokenizers-0.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d7e559436a07dc547f22ce1101f26d8b2fad387e28ec8e7e1e3b11695d681d8"}, + {file = "tokenizers-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e48afb75e50449848964e4a67b0da01261dd3aa8df8daecf10db8fd7f5b076eb"}, + {file = "tokenizers-0.20.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:baf5d0e1ff44710a95eefc196dd87666ffc609fd447c5e5b68272a7c3d342a1d"}, + {file = "tokenizers-0.20.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e5e56df0e8ed23ba60ae3848c3f069a0710c4b197218fe4f89e27eba38510768"}, + {file = "tokenizers-0.20.0-cp312-none-win32.whl", hash = "sha256:ec53e5ecc142a82432f9c6c677dbbe5a2bfee92b8abf409a9ecb0d425ee0ce75"}, + {file = "tokenizers-0.20.0-cp312-none-win_amd64.whl", hash = "sha256:f18661ece72e39c0dfaa174d6223248a15b457dbd4b0fc07809b8e6d3ca1a234"}, + {file = "tokenizers-0.20.0-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:f7065b1084d8d1a03dc89d9aad69bcbc8415d4bc123c367063eb32958cd85054"}, + {file = "tokenizers-0.20.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:e5d4069e4714e3f7ba0a4d3d44f9d84a432cd4e4aa85c3d7dd1f51440f12e4a1"}, + {file = "tokenizers-0.20.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:799b808529e54b7e1a36350bda2aeb470e8390e484d3e98c10395cee61d4e3c6"}, + {file = "tokenizers-0.20.0-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f9baa027cc8a281ad5f7725a93c204d7a46986f88edbe8ef7357f40a23fb9c7"}, + {file = "tokenizers-0.20.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:010ec7f3f7a96adc4c2a34a3ada41fa14b4b936b5628b4ff7b33791258646c6b"}, + {file = "tokenizers-0.20.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98d88f06155335b14fd78e32ee28ca5b2eb30fced4614e06eb14ae5f7fba24ed"}, + {file = "tokenizers-0.20.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e13eb000ef540c2280758d1b9cfa5fe424b0424ae4458f440e6340a4f18b2638"}, + {file = "tokenizers-0.20.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fab3cf066ff426f7e6d70435dc28a9ff01b2747be83810e397cba106f39430b0"}, + {file = "tokenizers-0.20.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:39fa3761b30a89368f322e5daf4130dce8495b79ad831f370449cdacfb0c0d37"}, + {file = "tokenizers-0.20.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c8da0fba4d179ddf2607821575998df3c294aa59aa8df5a6646dc64bc7352bce"}, + {file = "tokenizers-0.20.0-cp37-none-win32.whl", hash = "sha256:fada996d6da8cf213f6e3c91c12297ad4f6cdf7a85c2fadcd05ec32fa6846fcd"}, + {file = "tokenizers-0.20.0-cp37-none-win_amd64.whl", hash = "sha256:7d29aad702279e0760c265fcae832e89349078e3418dd329732d4503259fd6bd"}, + {file = "tokenizers-0.20.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:099c68207f3ef0227ecb6f80ab98ea74de559f7b124adc7b17778af0250ee90a"}, + {file = "tokenizers-0.20.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:68012d8a8cddb2eab3880870d7e2086cb359c7f7a2b03f5795044f5abff4e850"}, + {file = "tokenizers-0.20.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9253bdd209c6aee168deca7d0e780581bf303e0058f268f9bb06859379de19b6"}, + {file = "tokenizers-0.20.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f868600ddbcb0545905ed075eb7218a0756bf6c09dae7528ea2f8436ebd2c93"}, + {file = "tokenizers-0.20.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a9643d9c8c5f99b6aba43fd10034f77cc6c22c31f496d2f0ee183047d948fa0"}, + {file = "tokenizers-0.20.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c375c6a889aeab44734028bc65cc070acf93ccb0f9368be42b67a98e1063d3f6"}, + {file = "tokenizers-0.20.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e359f852328e254f070bbd09a19a568421d23388f04aad9f2fb7da7704c7228d"}, + {file = "tokenizers-0.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d98b01a309d4387f3b1c1dd68a8b8136af50376cf146c1b7e8d8ead217a5be4b"}, + {file = "tokenizers-0.20.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:459f7537119554c2899067dec1ac74a00d02beef6558f4ee2e99513bf6d568af"}, + {file = "tokenizers-0.20.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:392b87ec89452628c045c9f2a88bc2a827f4c79e7d84bc3b72752b74c2581f70"}, + {file = "tokenizers-0.20.0-cp38-none-win32.whl", hash = "sha256:55a393f893d2ed4dd95a1553c2e42d4d4086878266f437b03590d3f81984c4fe"}, + {file = "tokenizers-0.20.0-cp38-none-win_amd64.whl", hash = "sha256:30ffe33c5c2f2aab8e9a3340d0110dd9f7ace7eec7362e20a697802306bd8068"}, + {file = "tokenizers-0.20.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:aa2d4a6fed2a7e3f860c7fc9d48764bb30f2649d83915d66150d6340e06742b8"}, + {file = "tokenizers-0.20.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b5ef0f814084a897e9071fc4a868595f018c5c92889197bdc4bf19018769b148"}, + {file = "tokenizers-0.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc1e1b791e8c3bf4c4f265f180dadaff1c957bf27129e16fdd5e5d43c2d3762c"}, + {file = "tokenizers-0.20.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b69e55e481459c07885263743a0d3c18d52db19bae8226a19bcca4aaa213fff"}, + {file = "tokenizers-0.20.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4806b4d82e27a2512bc23057b2986bc8b85824914286975b84d8105ff40d03d9"}, + {file = "tokenizers-0.20.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9859e9ef13adf5a473ccab39d31bff9c550606ae3c784bf772b40f615742a24f"}, + {file = "tokenizers-0.20.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef703efedf4c20488a8eb17637b55973745b27997ff87bad88ed499b397d1144"}, + {file = "tokenizers-0.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6eec0061bab94b1841ab87d10831fdf1b48ebaed60e6d66d66dbe1d873f92bf5"}, + {file = "tokenizers-0.20.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:980f3d0d7e73f845b69087f29a63c11c7eb924c4ad6b358da60f3db4cf24bdb4"}, + {file = "tokenizers-0.20.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7c157550a2f3851b29d7fdc9dc059fcf81ff0c0fc49a1e5173a89d533ed043fa"}, + {file = "tokenizers-0.20.0-cp39-none-win32.whl", hash = "sha256:8a3d2f4d08608ec4f9895ec25b4b36a97f05812543190a5f2c3cd19e8f041e5a"}, + {file = "tokenizers-0.20.0-cp39-none-win_amd64.whl", hash = "sha256:d90188d12afd0c75e537f9a1d92f9c7375650188ee4f48fdc76f9e38afbd2251"}, + {file = "tokenizers-0.20.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d68e15f1815357b059ec266062340c343ea7f98f7f330602df81ffa3474b6122"}, + {file = "tokenizers-0.20.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:23f9ecec637b9bc80da5f703808d29ed5329e56b5aa8d791d1088014f48afadc"}, + {file = "tokenizers-0.20.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f830b318ee599e3d0665b3e325f85bc75ee2d2ca6285f52e439dc22b64691580"}, + {file = "tokenizers-0.20.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3dc750def789cb1de1b5a37657919545e1d9ffa667658b3fa9cb7862407a1b8"}, + {file = "tokenizers-0.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e26e6c755ae884c2ea6135cd215bdd0fccafe4ee62405014b8c3cd19954e3ab9"}, + {file = "tokenizers-0.20.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:a1158c7174f427182e08baa2a8ded2940f2b4a3e94969a85cc9cfd16004cbcea"}, + {file = "tokenizers-0.20.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:6324826287a3fc198898d3dcf758fe4a8479e42d6039f4c59e2cedd3cf92f64e"}, + {file = "tokenizers-0.20.0-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7d8653149405bb0c16feaf9cfee327fdb6aaef9dc2998349fec686f35e81c4e2"}, + {file = "tokenizers-0.20.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8a2dc1e402a155e97309287ca085c80eb1b7fab8ae91527d3b729181639fa51"}, + {file = "tokenizers-0.20.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07bef67b20aa6e5f7868c42c7c5eae4d24f856274a464ae62e47a0f2cccec3da"}, + {file = "tokenizers-0.20.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da06e397182ff53789c506c7833220c192952c57e1581a53f503d8d953e2d67e"}, + {file = "tokenizers-0.20.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:302f7e11a14814028b7fc88c45a41f1bbe9b5b35fd76d6869558d1d1809baa43"}, + {file = "tokenizers-0.20.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:055ec46e807b875589dfbe3d9259f9a6ee43394fb553b03b3d1e9541662dbf25"}, + {file = "tokenizers-0.20.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e3144b8acebfa6ae062e8f45f7ed52e4b50fb6c62f93afc8871b525ab9fdcab3"}, + {file = "tokenizers-0.20.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b52aa3fd14b2a07588c00a19f66511cff5cca8f7266ca3edcdd17f3512ad159f"}, + {file = "tokenizers-0.20.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b8cf52779ffc5d4d63a0170fbeb512372bad0dd014ce92bbb9149756c831124"}, + {file = "tokenizers-0.20.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:983a45dd11a876124378dae71d6d9761822199b68a4c73f32873d8cdaf326a5b"}, + {file = "tokenizers-0.20.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df6b819c9a19831ebec581e71a7686a54ab45d90faf3842269a10c11d746de0c"}, + {file = "tokenizers-0.20.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e738cfd80795fcafcef89c5731c84b05638a4ab3f412f97d5ed7765466576eb1"}, + {file = "tokenizers-0.20.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:c8842c7be2fadb9c9edcee233b1b7fe7ade406c99b0973f07439985c1c1d0683"}, + {file = "tokenizers-0.20.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e47a82355511c373a4a430c4909dc1e518e00031207b1fec536c49127388886b"}, + {file = "tokenizers-0.20.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:9afbf359004551179a5db19424180c81276682773cff2c5d002f6eaaffe17230"}, + {file = "tokenizers-0.20.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a07eaa8799a92e6af6f472c21a75bf71575de2af3c0284120b7a09297c0de2f3"}, + {file = "tokenizers-0.20.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0994b2e5fc53a301071806bc4303e4bc3bdc3f490e92a21338146a36746b0872"}, + {file = "tokenizers-0.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b6466e0355b603d10e3cc3d282d350b646341b601e50969464a54939f9848d0"}, + {file = "tokenizers-0.20.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:1e86594c2a433cb1ea09cfbe596454448c566e57ee8905bd557e489d93e89986"}, + {file = "tokenizers-0.20.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3e14cdef1efa96ecead6ea64a891828432c3ebba128bdc0596e3059fea104ef3"}, + {file = "tokenizers-0.20.0.tar.gz", hash = "sha256:39d7acc43f564c274085cafcd1dae9d36f332456de1a31970296a6b8da4eac8d"}, +] + +[package.dependencies] +huggingface-hub = ">=0.16.4,<1.0" + +[package.extras] +dev = ["tokenizers[testing]"] +docs = ["setuptools-rust", "sphinx", "sphinx-rtd-theme"] +testing = ["black (==22.3)", "datasets", "numpy", "pytest", "requests", "ruff"] + [[package]] name = "tomli" version = "2.0.1" @@ -3948,4 +4261,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "12be93152db28673d01f8e97da0e1c19c9194ad20fb60ba8035baab5b26fefb5" +content-hash = "273ab2a439b81b973129090c8ae7311e37898401c82af8ce777d6ecaa07da15a" diff --git a/pyproject.toml b/pyproject.toml index 6089f65..9fa36fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ django-ninja = "^1.1.0" langchain = "^0.2.1" langchain-openai = "^0.1.8" langgraph = "^0.2.16" +langchain-anthropic = "^0.1.23" [tool.poetry.group.dev.dependencies] coverage = "^7.2.7" diff --git a/tests/test_helpers/cassettes/test_assistants/test_AIAssistant_pydantic_structured_output.yaml b/tests/test_helpers/cassettes/test_assistants/test_AIAssistant_pydantic_structured_output.yaml new file mode 100644 index 0000000..f2f9c6d --- /dev/null +++ b/tests/test_helpers/cassettes/test_assistants/test_AIAssistant_pydantic_structured_output.yaml @@ -0,0 +1,323 @@ +interactions: +- request: + body: '{"messages": [{"content": "You are a helpful assistant that provides information + about people.", "role": "system"}, {"content": "In the last step of this chat + you will be asked to respond in JSON. Gather information using tools. Don''t + generate JSON until you are explicitly told to. ", "role": "system"}, {"content": + "Tell me about John who is 30 years old and not a student.", "role": "user"}], + "model": "gpt-4o-2024-08-06", "n": 1, "stream": false, "temperature": 1.0}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - DUMMY + connection: + - keep-alive + content-length: + - '470' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: !!binary | + H4sIAAAAAAAAA1RSwW7bMAy9+ysInZ0iTlyny2XoZQOG7rChQA/rECgybWmVRU2km2ZF/32Q4ybb + RRDeI58e9fhaACjXqi0oY7WYIfrFbeO+fzK3rglPvx/oW/Xn7u7rYWUflk19/KzK3EH7X2jkvevK + 0BA9iqNwok1CLZhVq82qqZq6ul5PxEAt+tzWR1nUtFgtV/ViebNYNnOjJWeQ1RZ+FAAAr9OZLYYW + X9QWluU7MiCz7lFtz0UAKpHPiNLMjkUHUeWFNBQEw+T6niAmenYtwpFGODixkNDjsw4CLnSUBp3H + Ab2nUeAL2VCCodG3U330qBmBrU4IAyWEFkU7z0AJpmdeBBL2OrUu9HCwzljgiMZ1zsCjynqPapLK + Cgk7TClXCn2Ee4sJJ3zQ4QgRKXo8WRSrBYIesAQmyKxuW5eNan+2wKOxoBmsYyBjxjhNUoInM98o + gQuCCVkYDtNUFn0E43Vy3XH2GzExhcnkgDpc/fuVCbuRdU4yjN7P+Ns5G099TLTnmT/jnQuO7S6h + Zgo5BxaKamLfCoCf0w6M/8WqYqIhyk7oCUMW3KxPcuqydBfyejOTQqL9Ba/Wy2I2qPjIgsOuc6HH + FJM7bUQXd1W93u9v6g8ro4q34i8AAAD//wMA5g4c6BoDAAA= + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: Sun, 09 Jun 2024 23:39:08 GMT + Server: DUMMY + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + status: + code: 200 + message: OK +- request: + body: '{"messages": [{"content": "You are a helpful assistant that provides information + about people.", "role": "system"}, {"content": "In the last step of this chat + you will be asked to respond in JSON. JSON will have the following schema:\n\n{\"properties\": + {\"name\": {\"title\": \"Name\", \"type\": \"string\"}, \"age\": {\"title\": + \"Age\", \"type\": \"integer\"}, \"is_student\": {\"title\": \"Is Student\", + \"type\": \"boolean\"}}, \"required\": [\"name\", \"age\", \"is_student\"], + \"title\": \"OutputSchema\", \"type\": \"object\"}\n\nGather information using + tools. Don''t generate JSON until you are explicitly told to. ", "role": "system"}, + {"content": "Tell me about John who is 30 years old and not a student.", "role": + "user"}], "model": "gpt-4o-2024-08-06", "n": 1, "stream": false, "temperature": + 1.0}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - DUMMY + connection: + - keep-alive + content-length: + - '811' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: !!binary | + H4sIAAAAAAAAA1RSy27bMBC86ysWvPQiB5LiR+tLUaSXBL0ELdoAQWHQ5FpiTXFZ7iquEfjfC8qK + 3V54mOHMDnf4WgAoZ9UalOm0mD762ael+/rFfj/Yav94d9f2WD+F1cP9D//4lFiVWUHbX2jkTXVj + qI8exVE40yahFsyu9apZ1st509Qj0ZNFn2VtlNmcZk3VzGfV+1m1nIQdOYOs1vBcAAC8jmeOGCz+ + UWuoyjekR2bdolpfLgGoRD4jSjM7Fh1ElVfSUBAMY+pvBDHRi7MIRxrg4KQD6RAS/h6QBS24sKPU + 6/ymEu7feQ+tlg4TWBTtPIPe0iCgIWJiChB0jxYeqAtw6Agcw20FR9SJgbwFHSwEyvdZBotBbuAz + jbM7/YKgwxE4onE7Z2CM4Cgw0HXcGFMHASHYBzpM86VzPE4tgQfTgWbICBkzxCm8C4IJWbjMfp7M + iH/8dzMJdwPrXEwYvJ/w02XVntqYaMsTf8F3LjjuNgk1U8hrZaGoRvZUAPwcKx3+a0nFRH2UjdAe + QzasF6uzn7p+oiu7uJ1IIdH+ijd1VUwJFR9ZsN/sXGgxxeTODe/i5gPWC2PsUs9VcSr+AgAA//8D + AEEAD0DqAgAA + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: Sun, 09 Jun 2024 23:39:08 GMT + Server: DUMMY + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + status: + code: 200 + message: OK +- request: + body: '{"messages": [{"content": "You are a helpful assistant that provides information + about people.", "role": "system"}, {"content": "In the last step of this chat + you will be asked to respond in JSON. JSON will have the following schema:\n\n{\"properties\": + {\"name\": {\"title\": \"Name\", \"type\": \"string\"}, \"age\": {\"title\": + \"Age\", \"type\": \"integer\"}, \"is_student\": {\"title\": \"Is Student\", + \"type\": \"boolean\"}}, \"required\": [\"name\", \"age\", \"is_student\"], + \"title\": \"OutputSchema\", \"type\": \"object\"}\n\nGather information using + tools. Don''t generate JSON until you are explicitly told to. ", "role": "system"}, + {"content": "Tell me about John who is 30 years old and not a student.", "role": + "user"}, {"content": "To provide you with the requested information, I''ll gather + details about a person named John who is 30 years old and not a student. Do + you have any specific questions or details you want to know about this John, + such as his occupation, interests, or location?", "role": "assistant"}, {"content": + "Use the information gathered in the conversation to answer.", "role": "system"}], + "model": "gpt-4o-2024-08-06", "n": 1, "response_format": {"type": "json_schema", + "json_schema": {"schema": {"properties": {"name": {"title": "Name", "type": + "string"}, "age": {"title": "Age", "type": "integer"}, "is_student": {"title": + "Is Student", "type": "boolean"}}, "required": ["name", "age", "is_student"], + "title": "OutputSchema", "type": "object", "additionalProperties": false}, "name": + "OutputSchema", "strict": true}}, "temperature": 1.0}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - DUMMY + connection: + - keep-alive + content-length: + - '1578' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python + x-stainless-helper-method: + - beta.chat.completions.parse + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: !!binary | + H4sIAAAAAAAAA1SQwU+DMBjF7/wVzXcGA4zhxs3ExLgYPajxIIaU8gHdStvQEmcW/ndTxoZeeni/ + vpf3vZNHCPAKMgKspZZ1WgR3KX99KYfmvi3l80O6e/z4Xh9xfyjl+9Mb+M6hyj0ye3HdMNVpgZYr + ecasR2rRpUa3cRqlSRwnE+hUhcLZGm2DRAVxGCdBuAnCdDa2ijM0kJFPjxBCTtPrKsoKj5CR0L8o + HRpDG4Ts+okQ6JVwClBjuLFUWvAXyJS0KKfWpxwk7TCHLIedamUOfg60ccIq9HPgpjB2qFDaHLKa + CoPj36Qe68FQd4gchJj18VpNqEb3qjQzv+o1l9y0RY/UKOlqGKs0THT0CPmaJhj+XQW6V522hVUH + lC4w3kbnPFhGX2iUzNAqS8Wir8K1NzcE82MsdkXNZYO97vl5kVoXUbIqy02yjRl4o/cLAAD//wMA + b8XsohoCAAA= + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: Sun, 09 Jun 2024 23:39:08 GMT + Server: DUMMY + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + status: + code: 200 + message: OK +- request: + body: '{"messages": [{"content": "You are a helpful assistant that provides information + about people.", "role": "system"}, {"content": "In the last step of this chat + you will be asked to respond in JSON. JSON will have the following schema:\n\n{\"properties\": + {\"name\": {\"title\": \"Name\", \"type\": \"string\"}, \"age\": {\"title\": + \"Age\", \"type\": \"integer\"}, \"is_student\": {\"title\": \"Is Student\", + \"type\": \"boolean\"}}, \"required\": [\"name\", \"age\", \"is_student\"], + \"title\": \"OutputSchema\", \"type\": \"object\"}\n\nDon''t generate JSON until + you are explicitly told to. ", "role": "user"}, {"content": "Tell me about John + who is 30 years old and not a student.", "role": "user"}], "model": "gpt-4o-2024-08-06", + "n": 1, "stream": false, "temperature": 1.0}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - DUMMY + connection: + - keep-alive + content-length: + - '777' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: !!binary | + H4sIAAAAAAAAA3RSQW7bMBC8+xVTnu3Ake3E8S3tKT21CIoWKApjTa4kNhRXIFdujCB/Lyg7dnro + RYRmOMNZcl4mgPHObGBsS2q7Pszub+fPd48/vj481hWt+Ps3Xn8J1brZ337ipZkWhex+s9U31ZWV + rg+sXuKRtolJubhe31Y31WK1qBYj0YnjUGRNr7OlzKp5tZzN17P5zUnYireczQY/JwDwMn5LxOj4 + 2Wwwn74hHedMDZvNeRNgkoSCGMrZZ6WoZnohrUTlOKb+LG2EzyAs5rMDU5pJcPDR+b13AwX8aaXw + dkiJo4YDoij6IeXBxwYUD6gldZB6XCmA3WCp3MAV7hXaFvOGpxhP6uiAHaMWO2R2kIjCW0rMaYqe + U5ZIAT4qJ86ap5AE0ZYTODqmvaQMGTR7x+VMiiBLjjtvkVnVx+YKH7lEKzkJWQfHUdH5plV0TBEt + o6WM2kefW3ZjgmxbkVBkkkbWtpI5gtCTttCWFE44j64+7iXsGfWQjsneJgadBlbf8RUeahxkQGR2 + 6CQxcs/W197Cx/GyRo0kEGpvyw8F9ElqH3iKmjmgTsxQAeWnD+9fMHE9ZCoFikMIJ/z1XIkgTZ9k + l0/8GT/OvE1MWWJ5/qzSm5F9nQC/xuoN/7TJ9Em6XrcqTxyL4fWqOvqZS9kv7Hp1IlWUwgWvFrf/ + U20dK/mQ3xXYHBP62Fwc5ueY45wmH7Jyt619bDj1yR/7XPfb6+Vit1sv7yprJq+TvwAAAP//AwD6 + zByE2AMAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: Sun, 09 Jun 2024 23:39:08 GMT + Server: DUMMY + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + status: + code: 200 + message: OK +- request: + body: '{"messages": [{"content": "You are a helpful assistant that provides information + about people.", "role": "system"}, {"content": "In the last step of this chat + you will be asked to respond in JSON. JSON will have the following schema:\n\n{\"properties\": + {\"name\": {\"title\": \"Name\", \"type\": \"string\"}, \"age\": {\"title\": + \"Age\", \"type\": \"integer\"}, \"is_student\": {\"title\": \"Is Student\", + \"type\": \"boolean\"}}, \"required\": [\"name\", \"age\", \"is_student\"], + \"title\": \"OutputSchema\", \"type\": \"object\"}\n\nDon''t generate JSON until + you are explicitly told to. ", "role": "user"}, {"content": "Tell me about John + who is 30 years old and not a student.", "role": "user"}, {"content": "John + is a 30-year-old individual who is currently not pursuing any form of formal + education. At this age, John may be focused on his career, personal interests, + or other endeavors outside of an academic setting. Being not a student might + mean he has finished his schooling or has chosen a path that does not involve + further education at this time. If you need more specific information or a fictional + profile, feel free to ask!", "role": "assistant"}, {"content": "Use the information + gathered in the conversation to answer.", "role": "user"}], "model": "gpt-4o-2024-08-06", + "n": 1, "response_format": {"type": "json_schema", "json_schema": {"schema": + {"properties": {"name": {"title": "Name", "type": "string"}, "age": {"title": + "Age", "type": "integer"}, "is_student": {"title": "Is Student", "type": "boolean"}}, + "required": ["name", "age", "is_student"], "title": "OutputSchema", "type": + "object", "additionalProperties": false}, "name": "OutputSchema", "strict": + true}}, "temperature": 1.0}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - DUMMY + connection: + - keep-alive + content-length: + - '1710' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python + x-stainless-helper-method: + - beta.chat.completions.parse + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: !!binary | + H4sIAAAAAAAAAwAAAP//dJBLT8MwEITv+RXWnhOUF6XNjceJEwIJgQiKXGeTGhzbym6lQtX/jpyW + thy4+DCfZzQ720gI0C1UAtRKshq8Sa6v0s3tk1lsZg+L7OamfPy+e/36fPb3xZ16gTg43PIDFf+6 + LpQbvEHWzu6xGlEyhtTsKp/lxWWRzyYwuBZNsPWek9IleZqXSTpP0tnBuHJaIUEl3iIhhNhOb6ho + W9xAJdL4VxmQSPYI1fGTEDA6ExSQRJpYWob4BJWzjHZqva3BygFrqGq4dytbQ1yD7INQpHENmhri + dYuWa6g6aQh350kjdmuS4RC7Nuag747VjOv96JZ04Ee901bTqhlRkrOhBrHzMNFdJMT7NMH6z1Xg + Rzd4bth9og2BRTbf58Fp9BPNygNkx9KcuYr8P1fTIktt6GxI2DfUtj8lpMea051AX8Q4NJ22PY5+ + 1PtdO99kZbFczstFriDaRT8AAAD//wMA7mJmC2ACAAA= + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: Sun, 09 Jun 2024 23:39:08 GMT + Server: DUMMY + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + status: + code: 200 + message: OK +version: 1 diff --git a/tests/test_helpers/cassettes/test_assistants/test_AIAssistant_typeddict_structured_output.yaml b/tests/test_helpers/cassettes/test_assistants/test_AIAssistant_typeddict_structured_output.yaml new file mode 100644 index 0000000..09c3e40 --- /dev/null +++ b/tests/test_helpers/cassettes/test_assistants/test_AIAssistant_typeddict_structured_output.yaml @@ -0,0 +1,333 @@ +interactions: +- request: + body: '{"messages": [{"content": "You are a helpful assistant that provides information + about movies.", "role": "system"}, {"content": "In the last step of this chat + you will be asked to respond in JSON. Gather information using tools. Don''t + generate JSON until you are explicitly told to. ", "role": "system"}, {"content": + "Provide information about the movie Shrek. It was released in 2001 and is an + animation and comedy movie.", "role": "user"}], "model": "gpt-4o-2024-08-06", + "n": 1, "stream": false, "temperature": 1.0}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - DUMMY + connection: + - keep-alive + content-length: + - '517' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: !!binary | + H4sIAAAAAAAAAwAAAP//bFZRb9xGDn73ryD0dDV2F7brprbf3DhpmsYHw+u74HAuAu6IktidGaqc + kTdKkf9+4EjrdYJ7EXaH5Dfkx4/E/H0EUHFdXUHlOswu9H55/Yoffht+Pb/78s/txe7H3z//ZxPX + N018H+/avlpYhGz+JJf3USsnofeUWeJkdkqYyVBPfz57dfrq/OzipBiC1OQtrO3z8lyWZydn58uT + i+XJqzmwE3aUqiv47xEAwN/laynGmj5XV1BgykmglLCl6urZCaBS8XZSYUqcMsZcLQ5GJzFTLFk/ + VutOaftYASfACBg5WMbgJFA9QsM+QK9SD45q2Ixwo4Tho+g2wXXxZbGoGpQ8YaIaOMLZycnpCh46 + muI5waaYzBVOLy9PoEHWETJ6gp5dHpRgI7IFaSB3BAkDQbTPZoSP7D1jgHUmblfwjpQAlSBJINjS + CDVlZJ8ANzLkEh/kienqMT7GJRwf37CSyyX/4+MruI610g6uawxpTv7f7LYjvKeYZI65O9RcYlQi + fESNpAt4L12Ed6t9YmlRMN5T0yiN8DvmLxQ3pO2EtHZKFHuP44z1QDW88Z4l5wU8kOoI95ISiyET + rDN7HzBOqPfSksJ6ZfetXTeYZcbNqMqxNcjHCLCEW94S3I6kCTBBaSz848mE9MPk8KaumeB20L4b + zeVGovH3jc9rDGTF3jB+MZ875egoJXjLEvFb30LEB85dKzvz/SBaw1vUvwbE+uBq2d4Oid1MwDu0 + mn9VapPE5Z7FiURDvJMdef+yD0VlryX0GAvC/1PhvtcpK2+GQ7tf+N5NUkuT6/0QI8cWMgcqPe57 + lc9F/36EyxMIHIe89/6AsR2wLZ5vYus5dZPhtQwxa7nqX5Ht3nXG57D7aSzgBnMJvcURTi8WZURM + n8fHd14yrIcQsIA8xsNMZvI+TQORRUebDgQl54fET1QIa3UI/QjS6jQw9dz3XSfQcKwTdJwg7TD0 + IE+kOkSbqRfzV3aUsQK5wwwdPhFsiCJsMHLqprG3HOiJ/bctXsGDgFKLHKdrxHMealrMSQTcUgKE + mtDDjnN3EEe2wOQG+l5gVtTGdA0dqbl1HFZw7cU61RHscNzD28pyrqiCpzTRStpiNnbqSdwTKZPS + V3C9nwu7ZrqwpWzXbKPsgNB1ILmzKc8djYXC6VfhJYiSLTgnIUg0wuJk5ciZ0XtjSoa2y6upuffk + qDd1ftfZHRovTjmzQ1+yMUxSx+ghDc4YWcFvuXj2imz7sxEFzgm6IYgu5mXNEhdQRg160kY0oPE5 + rY8kQ6yzotu+2Mfok0BA3VJdmtOjlg3cqITCcVas2YDRv1RKwc7Gc8LMyl+sS3ZLjyr1yFOHQkl7 + Q87Wt0Ta7/SO245SXrZqyy62JZdkVpuFgrMrnFqWmvKSnkjh2mFNYYTrHepEwC+U8jz1VMPbSbzP + VJXaogSOxXwIqLEvs/m8jecOfaAW3feDl3rcRaohDD5z7wkS/TWQTwvg6PxQW/qzN5wtHqvnP5b9 + Q8da26GVtDe8FZ3qaTLp3jiThJC4jdyww5iNzGys9NIPHhXc4J8rLNVxTD1r6V3qOS6laQqXC3is + 7oaUTKC/iOS0vwYh2PY1nRkLRTKrlw8CpWZIaO+ROHg/n399fmF4aXuVTZrtz+cN24L4pIRJor0m + Upa+KtavRwB/lJfM8M3jpOpVQp8/ZdlSNMCL0wmuOjydDsbzy4vZmiWjPxh++vnyaM6wSmPKFD41 + HFvSXnl62DT9p9PzHzebi/PLM1cdfT36HwAAAP//AwBZgHU64QkAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: Sun, 09 Jun 2024 23:39:08 GMT + Server: DUMMY + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + status: + code: 200 + message: OK +- request: + body: '{"messages": [{"content": "You are a helpful assistant that provides information + about movies.", "role": "system"}, {"content": "In the last step of this chat + you will be asked to respond in JSON. Gather information using tools. Don''t + generate JSON until you are explicitly told to. ", "role": "system"}, {"content": + "Provide information about the movie Shrek. It was released in 2001 and is an + animation and comedy movie.", "role": "user"}, {"content": "\"Shrek\" is an + animated comedy film produced by DreamWorks Animation and released in 2001. + The film is based on a 1990 fairy tale picture book of the same name by William + Steig. Here are some key details about the movie:\n\n- **Directed by**: Andrew + Adamson and Vicky Jenson\n- **Produced by**: Aron Warner, John H. Williams, + and Jeffrey Katzenberg\n- **Screenplay by**: Ted Elliott, Terry Rossio, Joe + Stillman, and Roger S. H. Schulman\n- **Starring**: \n - Mike Myers as Shrek + (voice)\n - Eddie Murphy as Donkey (voice)\n - Cameron Diaz as Princess Fiona + (voice)\n - John Lithgow as Lord Farquaad (voice)\n- **Music by**: Harry Gregson-Williams + and John Powell\n- **Production Company**: DreamWorks Animation\n- **Distributed + by**: DreamWorks Pictures\n- **Running time**: Approximately 90 minutes\n- **Language**: + English\n- **Country**: United States\n- **Release Date**: May 18, 2001\n\n**Plot + Summary**:\n\"Shrek\" tells the story of a reclusive and grumpy ogre named Shrek + who finds his swamp overrun by fairy tale creatures that have been banished + by the evil Lord Farquaad. To regain his solitude, Shrek makes a deal with Farquaad + to rescue Princess Fiona and bring her to him. Along the way, Shrek is accompanied + by a talkative donkey named Donkey. As Shrek and Fiona get to know each other, + they find they have more in common than they initially thought.\n\n**Reception**:\n\"Shrek\" + was a critical and commercial success. It was praised for its humor, animation, + voice performances, and soundtrack. The film also marked a departure from the + traditional fairy tale format by satirizing and parodying them. It became one + of the highest-grossing films of 2001 and won the first-ever Academy Award for + Best Animated Feature. It was also nominated for Best Adapted Screenplay.\n\n**Legacy**:\n\"Shrek\" + spawned multiple sequels, including \"Shrek 2,\" \"Shrek the Third,\" and \"Shrek + Forever After,\" and became a significant part of popular culture. It also inspired + a spin-off film, \"Puss in Boots,\" and a musical adaptation.", "role": "assistant"}, + {"content": "Use the information gathered in the conversation to answer.", "role": + "system"}], "model": "gpt-4o-2024-08-06", "n": 1, "response_format": {"type": + "json_schema", "json_schema": {"name": "OutputSchema", "description": "dict() + -> new empty dictionary\ndict(mapping) -> new dictionary initialized from a + mapping object''s\n (key, value) pairs\ndict(iterable) -> new dictionary + initialized as if via:\n d = {}\n for k, v in iterable:\n d[k] + = v\ndict(**kwargs) -> new dictionary initialized with the name=value pairs\n in + the keyword argument list. For example: dict(one=1, two=2)", "strict": true, + "schema": {"type": "object", "properties": {"title": {"type": "string"}, "year": + {"type": "integer"}, "genres": {"type": "array", "items": {"type": "string"}}}, + "required": ["title", "year", "genres"], "additionalProperties": false}}}, "temperature": + 1.0}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - DUMMY + connection: + - keep-alive + content-length: + - '3406' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python + x-stainless-helper-method: + - beta.chat.completions.parse + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: !!binary | + H4sIAAAAAAAAA1SRzW7CMBCE73kKa89JlaRpoLmhHipVqpAKN4yQEzbBxbEte5FKEe9eOYSfXnyY + b2c0uz5FjIHcQsWg2QlqequSWSmX88K6A7bzxRf9LmVRYz2rZx/d+yfEwWHqb2zo6npqTG8VkjT6 + ghuHgjCkZpO8zMoin5YD6M0WVbB1lpLCJHmaF0k6TdJyNO6MbNBDxVYRY4ydhjdU1Fv8gYql8VXp + 0XvRIVS3IcbAGRUUEN5LT0ITxHfYGE2oh9YnDiRJIYeKw2LncM8h5nBE4ThUeZpmMYcOtUPPoVpx + mGnZi7DgMPdmetweOazPj/kO24MXYT19UGrUz7fCynTWmdqP/Ka3Uku/2zgU3uhQzpOxMNBzxNh6 + OMzh365gnektbcjsUYfASZFd8uD+FXeaTUdIhoR6cL28RmND8EdP2G9aqTt01snLnVq7mWKWTSb1 + c1pCdI7+AAAA//8DAEyr8E8wAgAA + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: Sun, 09 Jun 2024 23:39:08 GMT + Server: DUMMY + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + status: + code: 200 + message: OK +- request: + body: '{"messages": [{"content": "You are a helpful assistant that provides information + about movies.", "role": "system"}, {"content": "In the last step of this chat + you will be asked to respond in JSON. Don''t generate JSON until you are explicitly + told to. ", "role": "user"}, {"content": "Provide information about the movie + Shrek. It was released in 2001 and is an animation and comedy movie.", "role": + "user"}], "model": "gpt-4o-2024-08-06", "n": 1, "stream": false, "temperature": + 1.0}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - DUMMY + connection: + - keep-alive + content-length: + - '483' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: !!binary | + H4sIAAAAAAAAA3RWy24cuQ7d+yuIymKAoN1odxI7yc55YTKIB5mJb7K4HhhsiVXFtERW9OhKzSD/ + fiFVP+IB7qbRJVLiIXl4pH/OABq2zUtoTI/J+MGdX1+tvn/8I8nb/u3zD9P22Z8i62ef++HD11// + eNssyg7dfCWTDruWRv3gKLHKbDaBMFE59eJqfbl+8uzJkxfV4NWSK9u6IZ0/1fP1av30fPX8fHW5 + 39grG4rNS/jvGQDAP/W3QBRL35uXsFocVjzFiB01L49OAE1QV1YajJFjQknN4mQ0Komkor5rPvWB + tncNcASEDTndkQUU9gU4GPVkJ2jZeUg9JhgxQiBHGMmCCtzgBBfPF7BerS6WcNvT7FvchqA2G7Kw + meBNIPRfNGwjXNezWQVQLFgOZNLsdC020AjXFn3cmz+z2U7wG0lUWcL7VGBuDrFTT3Dx4sUKWuQw + QUJHMLBJORBsVLegbfWJ6Amk/Gwm+MLOMXr4lIi75Z3cyaNHj+Cj0wSfsvcYpjspacSkYYJWndMx + Qq3SAhACGZcj76jC60L2wwTaBYKxVyD5qlMExzuWDlggquOULZX/PUeII/phCb/qSDsKi7o2EBoq + iVmOKYcNWRh7EkDoguahZFETPK8JVkrlQHEBLMZlWyKZHgOaRKHE3lLN+rYPRPDKsVi4YTMDLoZX + 3MErtPBFXbsADAQ2+4HsA4ylVMWZduzggwYL7zB8y4h2CbcKEXdUnXv1tJjLAx63VFhkCR2MnPrj + HkgKgaLJBB8Di6EY4R2r4KKWjSOkgMMeA0LSkQJ0GYOdmYFgA3aFArd90Nz1mlMN/1VzEJoOCAqJ + TRlCFD7sTOi2mA4dQxGdSsmsypamSgsLb+rHEv4zqIAnSsXj30jnEJaj0V2pdJ2H2NfWiSYYD98l + EywOChtagCOsTUoKWej7MPM9jRxTnDFBTxjSiMHXZqpUjqkc6fm5qAG8xpju5BweP74pTb6ZKMTH + jwH39JxNb61lgpschn6ajXNys/U1egoq8Ibx79n6MMvZ6zftBT5w6jsdZ68HDDig+l0TbhzBtemZ + duRJUiwHnESlyECqmhBi2quIwsjz7F4btOQnuB4xWGg1wCuKaS8QZOHdzPQydgYTdWUgWdJBVliK + 6qyXJeT7WZnQRQVRz1IPOB1pcSgLn0wgksHhVHeVOfe6Y5o3gwmc2KCrXTHqPQXD6CBmU0r0oJWx + DHCx0bdMbm5kHFjOtW3jsXG3PXmKd/JAZ7eio1RwnCL02WtYQMTENdf9lGYxKjuSopQF0TAERdOX + 0D+rwXHwqzrS98FpoFp0T3sxQGNoSCiGFtAGJrGx5+EUiS3hTOYNYU5TgajiJohbFrBEwzGd19ml + XLJ+7wc06V95aZtIYAjIcV/8kl+dBleHQVMPpmdnA83yjja7FBegbUuhFLYWo5q8ljiOYlSZkxsw + qGWqWmF5X5eT9M8t6DHChsq1Vfq5h1ty4U64ZYMy83ABccBRSkyENqCYniPNZZh1lSL47BIPjg5N + XhQm9GUe9nnDenHXHD9m1eVgy2IBczC801DYAtdtolCNEUZyDirr9uxqs4OYsCPwORYW1qofbtRf + ImThb5lg40hsuRT2xKnaMXeTRXR30LrDLZvI9HVnrMUxdU7L+KQIjjo0Zagq9lGDqycfr/8SOS5/ + fjsEanPE8nSR7Nx+/cfxMeK0G4Ju4t5+XG9ZOPb3gTCqlIdHTDo01frjDOCv+ujJD94xzRDUD+k+ + 6ZakHHh1OR/XnF5ZJ+PTy4M1aUJ3Mjx7uv5/2+4tJWQXf3o6NTNClu50wuoIs+bZxCkm8vctS0dh + CDy/pNrh/jldXFxdbZ6sLpuzH2f/AwAA//8DAJBogqdSCgAA + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: Sun, 09 Jun 2024 23:39:08 GMT + Server: DUMMY + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + status: + code: 200 + message: OK +- request: + body: '{"messages": [{"content": "You are a helpful assistant that provides information + about movies.", "role": "system"}, {"content": "In the last step of this chat + you will be asked to respond in JSON. Don''t generate JSON until you are explicitly + told to. ", "role": "user"}, {"content": "Provide information about the movie + Shrek. It was released in 2001 and is an animation and comedy movie.", "role": + "user"}, {"content": "\"Shrek\" is a beloved animated comedy film that was released + on May 18, 2001. The film was produced by DreamWorks Animation and directed + by Andrew Adamson and Vicky Jenson. It is based on the 1990 fairy tale picture + book of the same name by William Steig.\n\n### Plot Summary\nThe story follows + Shrek, a reclusive and grumpy ogre who enjoys living in solitude in his swamp. + However, his peace is disturbed when a group of fairy-tale creatures, including + characters like the Three Blind Mice and the Big Bad Wolf, are dumped in his + swamp by the evil Lord Farquaad. To save his home, Shrek makes a deal with Farquaad + to rescue Princess Fiona, who is trapped in a tower guarded by a dragon. Throughout + his journey, Shrek is accompanied by a talkative and annoying donkey named Donkey. + Upon meeting Princess Fiona, Shrek discovers that she is not what she appears + to be, leading to unexpected twists and a heartwarming conclusion.\n\n### Voice + Cast\n- **Mike Myers** as Shrek\n- **Eddie Murphy** as Donkey\n- **Cameron Diaz** + as Princess Fiona\n- **John Lithgow** as Lord Farquaad\n\n### Notable Achievements\n- + \"Shrek\" was the first film to win the Academy Award for Best Animated Feature, + a category introduced in 2002.\n- It was also nominated for Best Adapted Screenplay.\n- + The movie was a critical and commercial success, leading to several sequels + and spin-offs.\n\n### Themes\n\"Shrek\" is known for its humor, satire, and + the unconventional approach to fairy-tale characters. It explores themes like + acceptance, friendship, and the idea that beauty is only skin deep.\n\n### Cultural + Impact\n\"Shrek\" is often praised for its appeal to both children and adults, + offering humor and moral lessons. It parodies traditional fairy tales and has + become a culturally significant film, spawning a franchise that includes multiple + sequels, such as \"Shrek 2,\" \"Shrek the Third,\" and \"Shrek Forever After,\" + as well as a successful stage musical.\n\nThe film''s unique blend of humor, + heart, and innovative animation techniques has cemented its legacy in the world + of animated films.", "role": "assistant"}, {"content": "Use the information + gathered in the conversation to answer.", "role": "user"}], "model": "gpt-4o-2024-08-06", + "n": 1, "response_format": {"type": "json_schema", "json_schema": {"name": "OutputSchema", + "description": "dict() -> new empty dictionary\ndict(mapping) -> new dictionary + initialized from a mapping object''s\n (key, value) pairs\ndict(iterable) + -> new dictionary initialized as if via:\n d = {}\n for k, v in iterable:\n d[k] + = v\ndict(**kwargs) -> new dictionary initialized with the name=value pairs\n in + the keyword argument list. For example: dict(one=1, two=2)", "strict": true, + "schema": {"type": "object", "properties": {"title": {"type": "string"}, "year": + {"type": "integer"}, "genres": {"type": "array", "items": {"type": "string"}}}, + "required": ["title", "year", "genres"], "additionalProperties": false}}}, "temperature": + 1.0}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - DUMMY + connection: + - keep-alive + content-length: + - '3413' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python + x-stainless-helper-method: + - beta.chat.completions.parse + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: !!binary | + H4sIAAAAAAAAA3RRPW/bMBTc9SuIN0sFTSu2oy1IinYMkiFAwkCgpSeZNkWy5DMQ1/B/Dyh/dujC + 4e7d4e64zxgD3ULFoFkpagZvioc5/8Knn79nbave/iw6sQ6/1i92M7Pvz38hTwq3XGNDZ9WPxg3e + IGlnj3QTUBEm18lczMT0bnpXjsTgWjRJ1nsqSlcILsqCLwo+OwlXTjcYoWIfGWOM7cc3RbQtfkHF + eH5GBoxR9QjV5YgxCM4kBFSMOpKyBPmVbJwltGPqvQTSZFBCJeF1FXAjIZewQxUkVILzSS6hRxsw + Sqg+JDxYPahUcLx7dAO2Owmfh1v/gN02qlTPbo054YdLYON6H9wynvgL3mmr46oOqKKzKVwk52Fk + Dxljn+Mw23+6gg9u8FST26BNhnNeHv3g+hVXdrI4keRImRuVEP9T1S2S0ibezAvHhNr2Vwd+iTn2 + hLiLhEPdadtj8EEf1+58PSmny+WivBcNZIfsGwAA//8DAFj9bIN2AgAA + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: Sun, 09 Jun 2024 23:39:08 GMT + Server: DUMMY + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + status: + code: 200 + message: OK +version: 1 diff --git a/tests/test_helpers/cassettes/test_assistants/test_AIAssistant_with_rag_invoke.yaml b/tests/test_helpers/cassettes/test_assistants/test_AIAssistant_with_rag_invoke.yaml index c75ff1c..310825d 100644 --- a/tests/test_helpers/cassettes/test_assistants/test_AIAssistant_with_rag_invoke.yaml +++ b/tests/test_helpers/cassettes/test_assistants/test_AIAssistant_with_rag_invoke.yaml @@ -251,4 +251,184 @@ interactions: status: code: 200 message: OK +- request: + body: '{"messages": [{"content": "You are a tour guide assistant offers information + about nearby attractions. The user is at a location and wants to know what to + learn about nearby attractions. Use the following pieces of context to suggest + nearby attractions to the user. If there are no interesting attractions nearby, + tell the user there''s nothing to see where they''re at. Use three sentences + maximum and keep your suggestions concise.\n\n---START OF CONTEXT---\nCentral + Park\n\nAmerican Museum of Natural History---END OF CONTEXT---\n\n", "role": + "system"}, {"content": "I''m at Central Park W & 79st, New York, NY 10024, United + States.", "role": "user"}], "model": "gpt-4o", "n": 1, "stream": false, "temperature": + 1.0}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - DUMMY + connection: + - keep-alive + content-length: + - '716' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: !!binary | + H4sIAAAAAAAAA3RRsY7aQBTs+Yp326SBEzb2IeiQDumaS5GrkihCj/WzvYe9b7PvWYd14t8jGwKk + SLPFzM5o3sznBMC4wqzB2BrVtqGZbZbz7nX59vuQfMgqW8mPZLM9ZG/b7DnsyUwHBe/fyepf1aPl + NjSkjv2ZtpFQaXBNlulTusiTfD4SLRfUDLIq6CzjWTpPs9k8nyWLi7BmZ0nMGn5OAAA+x3eI6As6 + mjWMNiPSkghWZNbXTwAmcjMgBkWcKHo10xtp2Sv5MfV37r5EAucBoUSvKOosSGB9gG+uqhU8Ydz3 + 4AS0Jti0FJ1FD6+dUNcCl/AVtYvYwIsT5dhP4aOmSNBzB8NHOoaGI0GJYp1Hdb4COtZu71SAPRTO + s2AXZQoS0NIU0BfQdraGliM9wta/cz/YRSiwf7g/JFLZCQ49+q5pLvjp2kzDVYi8lwt/xUvnndS7 + SCjshxZEOZiRPU0Afo0LdP+UakLkNuhO+UB+MEzS7Oxnbpvf2EV+IZUVmztVvvqfaleQomvkbkdz + Tuh8dXOYX2OOdxrpRandlc5XFEN051nLsEvzpzRDWmBuJqfJHwAAAP//AwC6ujE63wIAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: Sun, 09 Jun 2024 23:39:08 GMT + Server: DUMMY + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + status: + code: 200 + message: OK +- request: + body: '{"messages": [{"content": "Given a chat history and the latest user question + which might reference context in the chat history, formulate a standalone question + which can be understood without the chat history. Do NOT answer the question, + just reformulate it if needed and otherwise return it as is.", "role": "system"}, + {"content": "I''m at Central Park W & 79st, New York, NY 10024, United States.", + "role": "user"}, {"content": "You''re in a fantastic spot! Right nearby is the + American Museum of Natural History, where you can explore fascinating exhibits + on dinosaurs, space, and much more. Enjoy your day!", "role": "assistant"}, + {"content": "11 W 53rd St, New York, NY 10019, United States.", "role": "user"}], + "model": "gpt-4o", "n": 1, "stream": false, "temperature": 1.0}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - DUMMY + connection: + - keep-alive + content-length: + - '778' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: !!binary | + H4sIAAAAAAAAAwAAAP//dJFBj9MwEIXv+RUjnxMUJ8126WW1QgKBoAcQqiqEokkySU0dO/JMtcCq + /x057bblsBcf3uf3/Gb8nAAo06kVqHaH0o6TzR6X+WF9/xg2X/MvxYd3n0bOP//djsumef/EKo0O + 3/yiVl5cb1o/TpbEeHfCbSAUiql6WdwVZaUrPYPRd2SjbZgkW/isyItFlleZLs/GnTctsVrBjwQA + 4Hk+Y0XX0W+1gjx9UUZixoHU6nIJQAVvo6KQ2bCgE5VeYeudkJtbb3Yo4LxgYwlQJGAb2zP4ABZd + N2LYM7To4CP0xnWAAlrDBqoydPBNUljTE2x92Kew3oLOc/02he/OCEWMQvxw+3Sg/sAYJ3cHa8/6 + 8TKL9cMUfMNnftF74wzv6kDI3sXeLH5SMz0mAD/nnR3+W4Oagh8nqcXvycVAvShPeer6S1da3J+h + eEF741rq11x1R4LG8s3m1amhccM1Ib/UnOdU/IeFxro3bqAwBXP6iH6qi+quWCCVWKnkmPwDAAD/ + /wMA9OAVapECAAA= + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: Sun, 09 Jun 2024 23:39:08 GMT + Server: DUMMY + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + status: + code: 200 + message: OK +- request: + body: '{"messages": [{"content": "You are a tour guide assistant offers information + about nearby attractions. The user is at a location and wants to know what to + learn about nearby attractions. Use the following pieces of context to suggest + nearby attractions to the user. If there are no interesting attractions nearby, + tell the user there''s nothing to see where they''re at. Use three sentences + maximum and keep your suggestions concise.\n\n---START OF CONTEXT---\nCentral + Park\n\nAmerican Museum of Natural History---END OF CONTEXT---\n\n", "role": + "system"}, {"content": "I''m at Central Park W & 79st, New York, NY 10024, United + States.", "role": "user"}, {"content": "You''re in a fantastic spot! Right nearby + is the American Museum of Natural History, where you can explore fascinating + exhibits on dinosaurs, space, and much more. Enjoy your day!", "role": "assistant"}, + {"content": "11 W 53rd St, New York, NY 10019, United States.", "role": "user"}], + "model": "gpt-4o", "n": 1, "stream": false, "temperature": 1.0}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - DUMMY + connection: + - keep-alive + content-length: + - '1013' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: !!binary | + H4sIAAAAAAAAAwAAAP//dFGxbtswEN39FVcuaQErsCUrDrx5SwejQLeiKAyaOkmsSR7DO7lxA/97 + Qdmxk6ELh/fuPb579zoBULZRK1Cm12J8dMV6ORu+7Q+Y1st92zzrw/e/a9x1LYXon9Q0K2j3G428 + qe4N+ehQLIUzbRJqwew6X5YPZVXP63IkPDXosqyLUiyoKGflopjVxby6CHuyBlmt4OcEAOB1fHPE + 0OCLWsFs+oZ4ZNYdqtV1CEAlchlRmtmy6CBqeiMNBcEwpv5Bw11COGA6gnHECEIgPcJmYBw8UAsb + ajAFWCeBzxvarL9M4U9vTQ8tahkSMugA+CIY2B4QDDmHJleQxeNXPlLS6Qg6NODPbjrJPXyVOwYN + fmApDpatQEspU4BB+oGtZuFP75MnbAfWubgwOHfBT9cqHHUx0Y4v/BVvbbDcbxNqppDXZqGoRvY0 + Afg1Vj58aFHFRD7KVmiPIRvOH+uzn7od+cZW1YUUEu1ueDl//J9q26Bo6/jd4dQ5oQ3dzWF2jTnu + qfjIgn7b2tBhisme79jGbVk/lAuNla7V5DT5BwAA//8DAE9G6b7QAgAA + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: Sun, 09 Jun 2024 23:39:08 GMT + Server: DUMMY + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + status: + code: 200 + message: OK version: 1 diff --git a/tests/test_helpers/test_assistants.py b/tests/test_helpers/test_assistants.py index aaf5865..827caf6 100644 --- a/tests/test_helpers/test_assistants.py +++ b/tests/test_helpers/test_assistants.py @@ -1,4 +1,4 @@ -from typing import List +from typing import List, TypedDict from unittest.mock import patch import pytest @@ -172,18 +172,13 @@ def test_AIAssistant_with_rag_invoke(): assert response_0["input"] == "I'm at Central Park W & 79st, New York, NY 10024, United States." assert response_0["output"] == ( - "You're right by Central Park, perfect for a scenic walk or a visit to its famous landmarks. " - "Just across the street, you can explore the American Museum of Natural History, " - "home to fascinating exhibits on human cultures, the natural world, and the universe. " - "Both offer a rich experience in nature and history." + "You're in a fantastic spot! Right nearby is the American Museum of Natural History, where you " + "can explore fascinating exhibits on dinosaurs, space, and much more. Enjoy your day!" ) assert response_1["input"] == "11 W 53rd St, New York, NY 10019, United States." assert response_1["output"] == ( - "You're right near the Museum of Modern Art (MoMA), " - "which houses an impressive collection of modern and contemporary art. " - "Additionally, Rockefeller Center is just a short walk away, " - "featuring shops, restaurants, and the Top of the Rock observation deck for stunning city views. " - "Both locations provide enriching cultural and sightseeing opportunities." + "You're very close to the Museum of Modern Art (MoMA), which features an extensive collection of " + "contemporary and modern art. It's a must-visit for art enthusiasts!" ) expected_messages = messages_to_dict( @@ -238,3 +233,56 @@ def tool_a(self, foo: str) -> str: "tool_b", "tool_a", ] + + +@pytest.mark.vcr +def test_AIAssistant_pydantic_structured_output(): + from pydantic import BaseModel + + class OutputSchema(BaseModel): + name: str + age: int + is_student: bool + + class StructuredOutputAssistant(AIAssistant): + id = "structured_output_assistant" # noqa: A003 + name = "Structured Output Assistant" + instructions = "You are a helpful assistant that provides information about people." + model = "gpt-4o-2024-08-06" + structured_output = OutputSchema + + assistant = StructuredOutputAssistant() + + # Test invoking the assistant with structured output + result = assistant.run("Tell me about John who is 30 years old and not a student.") + assert isinstance(result, OutputSchema) + assert result.name == "John" + assert result.age == 30 + assert result.is_student is False + + +@pytest.mark.vcr +def test_AIAssistant_typeddict_structured_output(): + class OutputSchema(TypedDict): + title: str + year: int + genres: List[str] + + class DictStructuredOutputAssistant(AIAssistant): + id = "dict_structured_output_assistant" # noqa: A003 + name = "Dict Structured Output Assistant" + instructions = "You are a helpful assistant that provides information about movies." + model = "gpt-4o-2024-08-06" + structured_output = OutputSchema + + assistant = DictStructuredOutputAssistant() + + # Test invoking the assistant with dict structured output + result = assistant.run( + "Provide information about the movie Shrek. " + "It was released in 2001 and is an animation and comedy movie." + ) + + assert result["title"] == "Shrek" + assert result["year"] == 2001 + assert result["genres"] == ["Animation", "Comedy"]