From 0dd55c8b94711a8509f85b8ab02f889553dab941 Mon Sep 17 00:00:00 2001 From: Eugene Yurtsev Date: Tue, 7 Nov 2023 21:02:27 -0500 Subject: [PATCH] Add pydantic v2 support (#181) This PR adds pydantic v2 support to LangServe. With pydantic v2 all endpoints will work, but openapi docs will not be generated for these endpoints. (At least at the moment.) --------- Co-authored-by: jakerachleff --- .github/workflows/langserve_ci.yml | 8 +- langserve/pydantic.py | 10 + langserve/schema.py | 15 +- langserve/server.py | 362 +++++++++++++++++------------ langserve/validation.py | 10 + poetry.lock | 25 +- pyproject.toml | 2 +- 7 files changed, 272 insertions(+), 160 deletions(-) create mode 100644 langserve/pydantic.py diff --git a/.github/workflows/langserve_ci.yml b/.github/workflows/langserve_ci.yml index 335a37ac..57b50c7d 100644 --- a/.github/workflows/langserve_ci.yml +++ b/.github/workflows/langserve_ci.yml @@ -39,6 +39,12 @@ jobs: working-directory: . secrets: inherit + pydantic-compatibility: + uses: + ./.github/workflows/_pydantic_compatibility.yml + with: + working-directory: . + secrets: inherit test: runs-on: ubuntu-latest defaults: @@ -51,7 +57,7 @@ jobs: - "3.9" - "3.10" - "3.11" - name: Python ${{ matrix.python-version }} extended tests + name: Python ${{ matrix.python-version }} tests steps: - uses: actions/checkout@v3 diff --git a/langserve/pydantic.py b/langserve/pydantic.py new file mode 100644 index 00000000..f0458eb0 --- /dev/null +++ b/langserve/pydantic.py @@ -0,0 +1,10 @@ +import pydantic + + +def _get_pydantic_version() -> int: + """Get the pydantic major version.""" + return int(pydantic.__version__.split(".")[0]) + + +# Code is written to support both version 1 and 2 +PYDANTIC_MAJOR_VERSION = _get_pydantic_version() diff --git a/langserve/schema.py b/langserve/schema.py index e0a63be3..ca3ec92c 100644 --- a/langserve/schema.py +++ b/langserve/schema.py @@ -2,13 +2,16 @@ from typing import Dict, List, Optional, Union from uuid import UUID -try: - from pydantic.v1 import BaseModel -except ImportError: - from pydantic import BaseModel +from langserve.pydantic import PYDANTIC_MAJOR_VERSION +if PYDANTIC_MAJOR_VERSION == 2: + from pydantic.v1 import BaseModel as BaseModelV1 +else: + from pydantic import BaseModel as BaseModelV1 +from pydantic import BaseModel -class CustomUserType(BaseModel): + +class CustomUserType(BaseModelV1): """Inherit from this class to create a custom user type. Use a custom user type if you want the data to de-serialize @@ -27,7 +30,7 @@ class CustomUserType(BaseModel): """ -class SharedResponseMetadata(BaseModel): +class SharedResponseMetadata(BaseModelV1): """ Any response metadata should inherit from this class. Response metadata represents non-output data that may be useful to some clients, but diff --git a/langserve/server.py b/langserve/server.py index 62ca135b..60895ed6 100644 --- a/langserve/server.py +++ b/langserve/server.py @@ -25,8 +25,10 @@ Union, ) -from fastapi import HTTPException, Request +from fastapi import HTTPException, Request, Response +from fastapi.encoders import jsonable_encoder from fastapi.exceptions import RequestValidationError +from fastapi.responses import JSONResponse from langchain.callbacks.tracers.log_stream import RunLogPatch from langchain.load.serializable import Serializable from langchain.schema.runnable import Runnable, RunnableConfig @@ -35,8 +37,15 @@ from langsmith.utils import tracing_is_enabled from typing_extensions import Annotated +try: + from pydantic.v1 import BaseModel, Field, ValidationError, create_model +except ImportError: + from pydantic import BaseModel, Field, ValidationError, create_model + from langserve.callbacks import AsyncEventAggregatorCallback, CallbackEventDict from langserve.lzstring import LZString +from langserve.playground import serve_playground +from langserve.pydantic import PYDANTIC_MAJOR_VERSION from langserve.schema import ( BatchResponseMetadata, CustomUserType, @@ -44,16 +53,11 @@ FeedbackCreateRequest, SingletonResponseMetadata, ) - -try: - from pydantic.v1 import BaseModel, create_model -except ImportError: - from pydantic import BaseModel, Field, ValidationError, create_model - -from langserve.playground import serve_playground from langserve.serialization import WellKnownLCSerializer from langserve.validation import ( + BatchBaseResponse, BatchRequestShallowValidator, + InvokeBaseResponse, InvokeRequestShallowValidator, StreamLogParameters, create_batch_request_model, @@ -333,6 +337,64 @@ def _get_base_run_id_as_str( raise AssertionError("No run_id found for the given run") +def _json_encode_response(model: BaseModel) -> JSONResponse: + """Return a JSONResponse with the given content. + + We're doing the encoding manually here as a workaround to fastapi + not supporting models from pydantic v1 when pydantic + v2 is imported. + + Args: + obj: The object to encode; either an invoke response or a batch response. + + Returns: + A JSONResponse with the given content. + """ + obj = jsonable_encoder(model) + + if isinstance(model, InvokeBaseResponse): + # Invoke Response + # Collapse '__root__' from output field if it exists. This is done + # automatically by fastapi when annotating request and response with + # We need to do this manually since we're using vanilla JSONResponse + if isinstance(obj["output"], dict) and "__root__" in obj["output"]: + obj["output"] = obj["output"]["__root__"] + + if "callback_events" in obj: + for idx, callback_event in enumerate(obj["callback_events"]): + if isinstance(callback_event, dict) and "__root__" in callback_event: + obj["callback_events"][idx] = callback_event["__root__"] + elif isinstance(model, BatchBaseResponse): + if not isinstance(obj["output"], list): + raise AssertionError("Expected output to be a list") + + # Collapse '__root__' from output field if it exists. This is done + # automatically by fastapi when annotating request and response with + # We need to do this manually since we're using vanilla JSONResponse + outputs = obj["output"] + for idx, output in enumerate(outputs): + if isinstance(output, dict) and "__root__" in output: + outputs[idx] = output["__root__"] + + if "callback_events" in obj: + if not isinstance(obj["callback_events"], list): + raise AssertionError("Expected callback_events to be a list") + + for callback_events in obj["callback_events"]: + for idx, callback_event in enumerate(callback_events): + if ( + isinstance(callback_event, dict) + and "__root__" in callback_event + ): + callback_events[idx] = callback_event["__root__"] + else: + raise AssertionError( + f"Expected a InvokeBaseResponse or BatchBaseResponse got: {type(model)}" + ) + + return JSONResponse(content=obj) + + # PUBLIC API @@ -523,16 +585,13 @@ async def _get_config_and_input( @app.post( namespace + "/c/{config_hash}/invoke", - response_model=InvokeResponse, include_in_schema=False, ) - @app.post( - f"{namespace}/invoke", response_model=InvokeResponse, include_in_schema=False - ) + @app.post(f"{namespace}/invoke", include_in_schema=False) async def invoke( request: Request, config_hash: str = "", - ) -> InvokeResponse: + ) -> Response: """Invoke the runnable with the given input and config.""" # We do not use the InvokeRequest model here since configurable runnables # have dynamic schema -- so the validation below is a bit more involved. @@ -551,28 +610,27 @@ async def invoke( else: callback_events = [] - return InvokeResponse( - output=well_known_lc_serializer.dumpd(output), - # Callbacks are scrubbed and exceptions are converted to serializable format - # before returned in the response. - callback_events=callback_events, - metadata=SingletonResponseMetadata( - run_id=_get_base_run_id_as_str(event_aggregator) + return _json_encode_response( + InvokeResponse( + output=well_known_lc_serializer.dumpd(output), + # Callbacks are scrubbed and exceptions are converted to serializable format + # before returned in the response. + callback_events=callback_events, + metadata=SingletonResponseMetadata( + run_id=_get_base_run_id_as_str(event_aggregator) + ), ), ) @app.post( namespace + "/c/{config_hash}/batch", - response_model=BatchResponse, include_in_schema=False, ) - @app.post( - f"{namespace}/batch", response_model=BatchResponse, include_in_schema=False - ) + @app.post(f"{namespace}/batch", include_in_schema=False) async def batch( request: Request, config_hash: str = "", - ) -> BatchResponse: + ) -> Response: """Invoke the runnable with the given inputs and config.""" try: body = await request.json() @@ -654,13 +712,14 @@ async def batch( else: callback_events = [] - return BatchResponse( + obj = BatchResponse( output=well_known_lc_serializer.dumpd(output), callback_events=callback_events, metadata=BatchResponseMetadata( run_ids=[_get_base_run_id_as_str(agg) for agg in aggregators] ), ) + return _json_encode_response(obj) @app.post(namespace + "/c/{config_hash}/stream", include_in_schema=False) @app.post(f"{namespace}/stream", include_in_schema=False) @@ -986,159 +1045,162 @@ async def feedback(feedback_create_req: FeedbackCreateRequest) -> Feedback: ####################################### # Documentation variants of end points. ####################################### - @app.post( - namespace + "/c/{config_hash}/invoke", - response_model=InvokeResponse, - tags=route_tags_with_config, - name=_route_name_with_config("invoke"), - ) - @app.post( - f"{namespace}/invoke", - response_model=InvokeResponse, - tags=route_tags, - name=_route_name("invoke"), - ) - async def _invoke_docs( - invoke_request: Annotated[InvokeRequest, InvokeRequest], - config_hash: str = "", - ) -> InvokeResponse: - """Invoke the runnable with the given input and config.""" - raise AssertionError("This endpoint should not be reachable.") + # At the moment, we only support pydantic 1.x + if PYDANTIC_MAJOR_VERSION == 1: + + @app.post( + namespace + "/c/{config_hash}/invoke", + response_model=InvokeResponse, + tags=route_tags_with_config, + name=_route_name_with_config("invoke"), + ) + @app.post( + f"{namespace}/invoke", + response_model=InvokeResponse, + tags=route_tags, + name=_route_name("invoke"), + ) + async def _invoke_docs( + invoke_request: Annotated[InvokeRequest, InvokeRequest], + config_hash: str = "", + ) -> InvokeResponse: + """Invoke the runnable with the given input and config.""" + raise AssertionError("This endpoint should not be reachable.") + + @app.post( + namespace + "/c/{config_hash}/batch", + response_model=BatchResponse, + tags=route_tags_with_config, + name=_route_name_with_config("batch"), + ) + @app.post( + f"{namespace}/batch", + response_model=BatchResponse, + tags=route_tags, + name=_route_name("batch"), + ) + async def _batch_docs( + batch_request: Annotated[BatchRequest, BatchRequest], + config_hash: str = "", + ) -> BatchResponse: + """Batch invoke the runnable with the given inputs and config.""" + raise AssertionError("This endpoint should not be reachable.") + + @app.post( + namespace + "/c/{config_hash}/stream", + include_in_schema=True, + tags=route_tags_with_config, + name=_route_name_with_config("stream"), + ) + @app.post( + f"{namespace}/stream", + include_in_schema=True, + tags=route_tags, + name=_route_name("stream"), + ) + async def _stream_docs( + stream_request: Annotated[StreamRequest, StreamRequest], + config_hash: str = "", + ) -> EventSourceResponse: + """Invoke the runnable stream the output. - @app.post( - namespace + "/c/{config_hash}/batch", - response_model=BatchResponse, - tags=route_tags_with_config, - name=_route_name_with_config("batch"), - ) - @app.post( - f"{namespace}/batch", - response_model=BatchResponse, - tags=route_tags, - name=_route_name("batch"), - ) - async def _batch_docs( - batch_request: Annotated[BatchRequest, BatchRequest], - config_hash: str = "", - ) -> BatchResponse: - """Batch invoke the runnable with the given inputs and config.""" - raise AssertionError("This endpoint should not be reachable.") + This endpoint allows to stream the output of the runnable. - @app.post( - namespace + "/c/{config_hash}/stream", - include_in_schema=True, - tags=route_tags_with_config, - name=_route_name_with_config("stream"), - ) - @app.post( - f"{namespace}/stream", - include_in_schema=True, - tags=route_tags, - name=_route_name("stream"), - ) - async def _stream_docs( - stream_request: Annotated[StreamRequest, StreamRequest], - config_hash: str = "", - ) -> EventSourceResponse: - """Invoke the runnable stream the output. + The endpoint uses a server sent event stream to stream the output. - This endpoint allows to stream the output of the runnable. + https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events - The endpoint uses a server sent event stream to stream the output. + Important: Set the "text/event-stream" media type for request headers if + not using an existing SDK. - https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events + This endpoint uses two different types of events: - Important: Set the "text/event-stream" media type for request headers if - not using an existing SDK. + * data - for streaming the output of the runnable - This endpoint uses two different types of events: + { + "event": "data", + "data": { + ... + } + } - * data - for streaming the output of the runnable + * error - for signaling an error in the stream, also ends the stream. { - "event": "data", + "event": "error", "data": { - ... + "status_code": 500, + "message": "Internal Server Error" } } - * error - for signaling an error in the stream, also ends the stream. + * end - for signaling the end of the stream. - { - "event": "error", - "data": { - "status_code": 500, - "message": "Internal Server Error" - } - } + This helps the client to know when to stop listening for events and + know that the streaming has ended successfully. - * end - for signaling the end of the stream. + { + "event": "end", + } + """ + raise AssertionError("This endpoint should not be reachable.") + + @app.post( + namespace + "/c/{config_hash}/stream_log", + include_in_schema=True, + tags=route_tags_with_config, + name=_route_name_with_config("stream_log"), + ) + @app.post( + f"{namespace}/stream_log", + include_in_schema=True, + tags=route_tags, + name=_route_name("stream_log"), + ) + async def _stream_log_docs( + stream_log_request: Annotated[StreamLogRequest, StreamLogRequest], + config_hash: str = "", + ) -> EventSourceResponse: + """Invoke the runnable stream_log the output. - This helps the client to know when to stop listening for events and - know that the streaming has ended successfully. + This endpoint allows to stream the output of the runnable, including + the output of all intermediate steps. - { - "event": "end", - } - """ - raise AssertionError("This endpoint should not be reachable.") + The endpoint uses a server sent event stream to stream the output. - @app.post( - namespace + "/c/{config_hash}/stream_log", - include_in_schema=True, - tags=route_tags_with_config, - name=_route_name_with_config("stream_log"), - ) - @app.post( - f"{namespace}/stream_log", - include_in_schema=True, - tags=route_tags, - name=_route_name("stream_log"), - ) - async def _stream_log_docs( - stream_log_request: Annotated[StreamLogRequest, StreamLogRequest], - config_hash: str = "", - ) -> EventSourceResponse: - """Invoke the runnable stream_log the output. - - This endpoint allows to stream the output of the runnable, including - the output of all intermediate steps. + https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events - The endpoint uses a server sent event stream to stream the output. + Important: Set the "text/event-stream" media type for request headers if + not using an existing SDK. - https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events + This endpoint uses two different types of events: - Important: Set the "text/event-stream" media type for request headers if - not using an existing SDK. + * data - for streaming the output of the runnable - This endpoint uses two different types of events: + { + "event": "data", + "data": { + ... + } + } - * data - for streaming the output of the runnable + * error - for signaling an error in the stream, also ends the stream. { - "event": "data", + "event": "error", "data": { - ... + "status_code": 500, + "message": "Internal Server Error" } } - * error - for signaling an error in the stream, also ends the stream. - - { - "event": "error", - "data": { - "status_code": 500, - "message": "Internal Server Error" - } - } + * end - for signaling the end of the stream. - * end - for signaling the end of the stream. + This helps the client to know when to stop listening for events and + know that the streaming has ended successfully. - This helps the client to know when to stop listening for events and - know that the streaming has ended successfully. - - { - "event": "end", - } - """ - raise AssertionError("This endpoint should not be reachable.") + { + "event": "end", + } + """ + raise AssertionError("This endpoint should not be reachable.") diff --git a/langserve/validation.py b/langserve/validation.py index 99cc512a..fdee9873 100644 --- a/langserve/validation.py +++ b/langserve/validation.py @@ -195,6 +195,14 @@ def create_stream_log_request_model( return stream_log_request +class InvokeBaseResponse(BaseModel): + """Base class for invoke request.""" + + +class BatchBaseResponse(BaseModel): + """Base class for batch response.""" + + def create_invoke_response_model( namespace: str, output_type: Validator, @@ -219,6 +227,7 @@ def create_invoke_response_model( ), ), ), + __base__=InvokeBaseResponse, ) invoke_response_type.update_forward_refs() return invoke_response_type @@ -262,6 +271,7 @@ def create_batch_response_model( ), ), ), + __base__=BatchBaseResponse, ) batch_response_type.update_forward_refs() return batch_response_type diff --git a/poetry.lock b/poetry.lock index fbca0062..743195a3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -922,7 +922,7 @@ files = [ {file = "greenlet-3.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0b72b802496cccbd9b31acea72b6f87e7771ccfd7f7927437d592e5c92ed703c"}, {file = "greenlet-3.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:527cd90ba3d8d7ae7dceb06fda619895768a46a1b4e423bdb24c1969823b8362"}, {file = "greenlet-3.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:37f60b3a42d8b5499be910d1267b24355c495064f271cfe74bf28b17b099133c"}, - {file = "greenlet-3.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1482fba7fbed96ea7842b5a7fc11d61727e8be75a077e603e8ab49d24e234383"}, + {file = "greenlet-3.0.0-cp311-universal2-macosx_10_9_universal2.whl", hash = "sha256:c3692ecf3fe754c8c0f2c95ff19626584459eab110eaab66413b1e7425cd84e9"}, {file = "greenlet-3.0.0-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:be557119bf467d37a8099d91fbf11b2de5eb1fd5fc5b91598407574848dc910f"}, {file = "greenlet-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73b2f1922a39d5d59cc0e597987300df3396b148a9bd10b76a058a2f2772fc04"}, {file = "greenlet-3.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1e22c22f7826096ad503e9bb681b05b8c1f5a8138469b255eb91f26a76634f2"}, @@ -932,6 +932,7 @@ files = [ {file = "greenlet-3.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:952256c2bc5b4ee8df8dfc54fc4de330970bf5d79253c863fb5e6761f00dda35"}, {file = "greenlet-3.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:269d06fa0f9624455ce08ae0179430eea61085e3cf6457f05982b37fd2cefe17"}, {file = "greenlet-3.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:9adbd8ecf097e34ada8efde9b6fec4dd2a903b1e98037adf72d12993a1c80b51"}, + {file = "greenlet-3.0.0-cp312-universal2-macosx_10_9_universal2.whl", hash = "sha256:553d6fb2324e7f4f0899e5ad2c427a4579ed4873f42124beba763f16032959af"}, {file = "greenlet-3.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6b5ce7f40f0e2f8b88c28e6691ca6806814157ff05e794cdd161be928550f4c"}, {file = "greenlet-3.0.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecf94aa539e97a8411b5ea52fc6ccd8371be9550c4041011a091eb8b3ca1d810"}, {file = "greenlet-3.0.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80dcd3c938cbcac986c5c92779db8e8ce51a89a849c135172c88ecbdc8c056b7"}, @@ -1690,6 +1691,16 @@ files = [ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, @@ -2586,6 +2597,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -2593,8 +2605,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -2611,6 +2630,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -2618,6 +2638,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -3822,4 +3843,4 @@ server = ["fastapi", "sse-starlette"] [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "5175284ed862c0a87cb8cbe166795841069ad416c8e1549fcd9974c1a4d4fe5f" +content-hash = "beb12fd214e3477e22f429e6782705d48b8a541978c60ff8572d31b7c2768f4c" diff --git a/pyproject.toml b/pyproject.toml index 34aacccf..9a26b179 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ httpx = ">=0.23.0" # May be able to decrease this version fastapi = {version = ">=0.90.1", optional = true} sse-starlette = {version = "^1.3.0", optional = true} httpx-sse = {version = ">=0.3.1", optional = true} -pydantic = "^1" +pydantic = ">=1" langchain = ">=0.0.322" [tool.poetry.group.dev.dependencies]