From 3fd9569138ec6e225976b57e0a0d4eaa39a3a941 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:13:40 -0400 Subject: [PATCH 01/32] update deps --- libs/vertexai/poetry.lock | 129 ++++++++--------------------------- libs/vertexai/pyproject.toml | 21 +++--- 2 files changed, 38 insertions(+), 112 deletions(-) diff --git a/libs/vertexai/poetry.lock b/libs/vertexai/poetry.lock index 5a63e1ec..2642645a 100644 --- a/libs/vertexai/poetry.lock +++ b/libs/vertexai/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -133,9 +133,6 @@ files = [ {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, ] -[package.dependencies] -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} - [[package]] name = "anthropic" version = "0.34.0" @@ -1313,7 +1310,7 @@ files = [ [[package]] name = "langchain" -version = "0.2.14" +version = "0.2.16" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" @@ -1323,7 +1320,7 @@ develop = false [package.dependencies] aiohttp = "^3.8.3" async-timeout = {version = "^4.0.0", markers = "python_version < \"3.11\""} -langchain-core = "^0.2.32" +langchain-core = "^0.2.38" langchain-text-splitters = "^0.2.0" langsmith = "^0.1.17" numpy = [ @@ -1339,16 +1336,16 @@ tenacity = "^8.1.0,!=8.4.0" [package.source] type = "git" url = "https://github.com/langchain-ai/langchain.git" -reference = "HEAD" -resolved_reference = "bda3becbe77a22ce49d77c59035727f3b2ed64f1" +reference = "v0.3rc" +resolved_reference = "e358846b39ad78512bd513f0f11df8b7e6fe249e" subdirectory = "libs/langchain" [[package]] name = "langchain-core" -version = "0.2.33" +version = "0.2.38" description = "Building applications with LLMs through composability" optional = false -python-versions = ">=3.8.1,<4.0" +python-versions = ">=3.9,<4.0" files = [] develop = false @@ -1367,27 +1364,33 @@ typing-extensions = ">=4.7" [package.source] type = "git" url = "https://github.com/langchain-ai/langchain.git" -reference = "HEAD" -resolved_reference = "bda3becbe77a22ce49d77c59035727f3b2ed64f1" +reference = "v0.3rc" +resolved_reference = "e358846b39ad78512bd513f0f11df8b7e6fe249e" subdirectory = "libs/core" [[package]] name = "langchain-mistralai" -version = "0.1.12" +version = "0.1.13" description = "An integration package connecting Mistral and LangChain" optional = false -python-versions = "<4.0,>=3.8.1" -files = [ - {file = "langchain_mistralai-0.1.12-py3-none-any.whl", hash = "sha256:5dc5f3a63a646f848eb5007e410745a11667dcd2bc42939049a84f59f85a9737"}, - {file = "langchain_mistralai-0.1.12.tar.gz", hash = "sha256:d13a55aa84d7defd7a547919643188fd8c18d5a15ac139a1deebbe7a0889047b"}, -] +python-versions = ">=3.9,<4.0" +files = [] +develop = false [package.dependencies] httpx = ">=0.25.2,<1" httpx-sse = ">=0.3.1,<1" -langchain-core = ">=0.2.26,<0.3.0" +langchain-core = "^0.2.38" +pydantic = ">2,<3" tokenizers = ">=0.15.1,<1" +[package.source] +type = "git" +url = "https://github.com/langchain-ai/langchain.git" +reference = "v0.3rc" +resolved_reference = "e358846b39ad78512bd513f0f11df8b7e6fe249e" +subdirectory = "libs/partners/mistralai" + [[package]] name = "langchain-standard-tests" version = "0.1.1" @@ -1401,12 +1404,13 @@ develop = false httpx = "^0.27.0" langchain-core = ">=0.1.40,<0.3" pytest = ">=7,<9" +syrupy = "^4" [package.source] type = "git" url = "https://github.com/langchain-ai/langchain.git" -reference = "HEAD" -resolved_reference = "bda3becbe77a22ce49d77c59035727f3b2ed64f1" +reference = "v0.3rc" +resolved_reference = "e358846b39ad78512bd513f0f11df8b7e6fe249e" subdirectory = "libs/standard-tests" [[package]] @@ -1599,48 +1603,6 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] -[[package]] -name = "numexpr" -version = "2.8.6" -description = "Fast numerical expression evaluator for NumPy" -optional = false -python-versions = ">=3.7" -files = [ - {file = "numexpr-2.8.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80acbfefb68bd92e708e09f0a02b29e04d388b9ae72f9fcd57988aca172a7833"}, - {file = "numexpr-2.8.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6e884687da8af5955dc9beb6a12d469675c90b8fb38b6c93668c989cfc2cd982"}, - {file = "numexpr-2.8.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ef7e8aaa84fce3aba2e65f243d14a9f8cc92aafd5d90d67283815febfe43eeb"}, - {file = "numexpr-2.8.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dee04d72307c09599f786b9231acffb10df7d7a74b2ce3681d74a574880d13ce"}, - {file = "numexpr-2.8.6-cp310-cp310-win32.whl", hash = "sha256:211804ec25a9f6d188eadf4198dd1a92b2f61d7d20993c6c7706139bc4199c5b"}, - {file = "numexpr-2.8.6-cp310-cp310-win_amd64.whl", hash = "sha256:18b1804923cfa3be7bbb45187d01c0540c8f6df4928c22a0f786e15568e9ebc5"}, - {file = "numexpr-2.8.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:95b9da613761e4fc79748535b2a1f58cada22500e22713ae7d9571fa88d1c2e2"}, - {file = "numexpr-2.8.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:47b45da5aa25600081a649f5e8b2aa640e35db3703f4631f34bb1f2f86d1b5b4"}, - {file = "numexpr-2.8.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84979bf14143351c2db8d9dd7fef8aca027c66ad9df9cb5e75c93bf5f7b5a338"}, - {file = "numexpr-2.8.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d36528a33aa9c23743b3ea686e57526a4f71e7128a1be66210e1511b09c4e4e9"}, - {file = "numexpr-2.8.6-cp311-cp311-win32.whl", hash = "sha256:681812e2e71ff1ba9145fac42d03f51ddf6ba911259aa83041323f68e7458002"}, - {file = "numexpr-2.8.6-cp311-cp311-win_amd64.whl", hash = "sha256:27782177a0081bd0aab229be5d37674e7f0ab4264ef576697323dd047432a4cd"}, - {file = "numexpr-2.8.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ef6e8896457a60a539cb6ba27da78315a9bb31edb246829b25b5b0304bfcee91"}, - {file = "numexpr-2.8.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e640bc0eaf1b59f3dde52bc02bbfda98e62f9950202b0584deba28baf9f36bbb"}, - {file = "numexpr-2.8.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d126938c2c3784673c9c58d94e00b1570aa65517d9c33662234d442fc9fb5795"}, - {file = "numexpr-2.8.6-cp37-cp37m-win32.whl", hash = "sha256:e93d64cd20940b726477c3cb64926e683d31b778a1e18f9079a5088fd0d8e7c8"}, - {file = "numexpr-2.8.6-cp37-cp37m-win_amd64.whl", hash = "sha256:31cf610c952eec57081171f0b4427f9bed2395ec70ec432bbf45d260c5c0cdeb"}, - {file = "numexpr-2.8.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b5f96c89aa0b1f13685ec32fa3d71028db0b5981bfd99a0bbc271035949136b3"}, - {file = "numexpr-2.8.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c8f37f7a6af3bdd61f2efd1cafcc083a9525ab0aaf5dc641e7ec8fc0ae2d3aa1"}, - {file = "numexpr-2.8.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38b8b90967026bbc36c7aa6e8ca3b8906e1990914fd21f446e2a043f4ee3bc06"}, - {file = "numexpr-2.8.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1967c16f61c27df1cdc43ba3c0ba30346157048dd420b4259832276144d0f64e"}, - {file = "numexpr-2.8.6-cp38-cp38-win32.whl", hash = "sha256:15469dc722b5ceb92324ec8635411355ebc702303db901ae8cc87f47c5e3a124"}, - {file = "numexpr-2.8.6-cp38-cp38-win_amd64.whl", hash = "sha256:95c09e814b0d6549de98b5ded7cdf7d954d934bb6b505432ff82e83a6d330bda"}, - {file = "numexpr-2.8.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:aa0f661f5f4872fd7350cc9895f5d2594794b2a7e7f1961649a351724c64acc9"}, - {file = "numexpr-2.8.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8e3e6f1588d6c03877cb3b3dcc3096482da9d330013b886b29cb9586af5af3eb"}, - {file = "numexpr-2.8.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8564186aad5a2c88d597ebc79b8171b52fd33e9b085013e1ff2208f7e4b387e3"}, - {file = "numexpr-2.8.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6a88d71c166e86b98d34701285d23e3e89d548d9f5ae3f4b60919ac7151949f"}, - {file = "numexpr-2.8.6-cp39-cp39-win32.whl", hash = "sha256:c48221b6a85494a7be5a022899764e58259af585dff031cecab337277278cc93"}, - {file = "numexpr-2.8.6-cp39-cp39-win_amd64.whl", hash = "sha256:6d7003497d82ef19458dce380b36a99343b96a3bd5773465c2d898bf8f5a38f9"}, - {file = "numexpr-2.8.6.tar.gz", hash = "sha256:6336f8dba3f456e41a4ffc3c97eb63d89c73589ff6e1707141224b930263260d"}, -] - -[package.dependencies] -numpy = ">=1.13.3" - [[package]] name = "numexpr" version = "2.10.1" @@ -1682,43 +1644,6 @@ files = [ [package.dependencies] numpy = ">=1.23.0" -[[package]] -name = "numpy" -version = "1.24.4" -description = "Fundamental package for array computing in Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"}, - {file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"}, - {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"}, - {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"}, - {file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"}, - {file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"}, - {file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"}, - {file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"}, - {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"}, - {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"}, - {file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"}, - {file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"}, - {file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"}, - {file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"}, - {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"}, - {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"}, - {file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"}, - {file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"}, - {file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"}, - {file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"}, - {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"}, - {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"}, - {file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"}, - {file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"}, - {file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"}, - {file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"}, - {file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"}, - {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"}, -] - [[package]] name = "numpy" version = "1.26.4" @@ -2833,5 +2758,5 @@ mistral = ["langchain-mistralai"] [metadata] lock-version = "2.0" -python-versions = ">=3.8.1,<4.0" -content-hash = "8240d23b8fc671345e140d2720298d549a40e05da220a901ee8b72a1b51bcb25" +python-versions = ">=3.9,<4.0" +content-hash = "07178bac539421edbfd91761ca53612aad9ef8f688349b4b63ff278d2a40f181" diff --git a/libs/vertexai/pyproject.toml b/libs/vertexai/pyproject.toml index 00f6b259..54830ae3 100644 --- a/libs/vertexai/pyproject.toml +++ b/libs/vertexai/pyproject.toml @@ -11,15 +11,16 @@ license = "MIT" "Source Code" = "https://github.com/langchain-ai/langchain-google/tree/main/libs/vertexai" [tool.poetry.dependencies] -python = ">=3.8.1,<4.0" -langchain-core = ">=0.2.33,<0.3" +python = ">=3.9,<4.0" +langchain-core = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/core", branch = "v0.3rc" } google-cloud-aiplatform = "^1.56.0" google-cloud-storage = "^2.17.0" # optional dependencies anthropic = { extras = ["vertexai"], version = ">=0.30.0,<1", optional = true } -langchain-mistralai = { version = ">=0.1.12,<1", optional = true } +langchain-mistralai = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/partners/mistralai", branch = "v0.3rc"} httpx = "^0.27.0" httpx-sse = "^0.4.0" +pydantic = ">=2,<3" [tool.poetry.group.test] optional = true @@ -39,9 +40,9 @@ numpy = [ { version = "^1.26.0", python = ">=3.12" }, ] google-api-python-client = "^2.117.0" -langchain = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/langchain" } -langchain-core = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/core" } -langchain-standard-tests = {git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/standard-tests"} +langchain = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/langchain", branch = "v0.3rc" } +langchain-core = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/core", branch = "v0.3rc" } +langchain-standard-tests = {git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/standard-tests", branch = "v0.3rc"} [tool.codespell] @@ -68,8 +69,8 @@ optional = true numexpr = { version = "^2.8.8", python = ">=3.9,<4.0" } google-api-python-client = "^2.114.0" google-cloud-datastore = "^2.19.0" -langchain = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/langchain" } -langchain-mistralai = "^0.1.12" +langchain = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/langchain", branch = "v0.3rc" } +langchain-mistralai = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/partners/mistralai", branch = "v0.3rc"} [tool.poetry.group.lint] optional = true @@ -83,12 +84,12 @@ mypy = "^1" types-google-cloud-ndb = "^2.2.0.20240106" types-protobuf = "^4.24.0.4" types-requests = "^2.31.0" -langchain-core = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/core" } +langchain-core = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/core", branch = "v0.3rc" } [tool.poetry.group.dev.dependencies] -langchain-core = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/core" } +langchain-core = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/core", branch = "v0.3rc" } [tool.ruff.lint] select = [ From 36e7f9f09f828f0488d3488abd538621707da25b Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:14:10 -0400 Subject: [PATCH 02/32] delete check_pydantic script --- libs/vertexai/scripts/check_pydantic.sh | 27 ------------------------- 1 file changed, 27 deletions(-) delete mode 100755 libs/vertexai/scripts/check_pydantic.sh diff --git a/libs/vertexai/scripts/check_pydantic.sh b/libs/vertexai/scripts/check_pydantic.sh deleted file mode 100755 index 06b5bb81..00000000 --- a/libs/vertexai/scripts/check_pydantic.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# -# This script searches for lines starting with "import pydantic" or "from pydantic" -# in tracked files within a Git repository. -# -# Usage: ./scripts/check_pydantic.sh /path/to/repository - -# Check if a path argument is provided -if [ $# -ne 1 ]; then - echo "Usage: $0 /path/to/repository" - exit 1 -fi - -repository_path="$1" - -# Search for lines matching the pattern within the specified repository -result=$(git -C "$repository_path" grep -E '^import pydantic|^from pydantic') - -# Check if any matching lines were found -if [ -n "$result" ]; then - echo "ERROR: The following lines need to be updated:" - echo "$result" - echo "Please replace the code with an import from langchain_core.pydantic_v1." - echo "For example, replace 'from pydantic import BaseModel'" - echo "with 'from langchain_core.pydantic_v1 import BaseModel'" - exit 1 -fi From b6615ccf5380119443d6fb41e54a266cba2de344 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:14:47 -0400 Subject: [PATCH 03/32] to_pydantic_2 --- .../_anthropic_parsers.py | 7 ++++--- .../_anthropic_utils.py | 2 +- .../langchain_google_vertexai/_base.py | 10 ++++------ .../langchain_google_vertexai/chains.py | 2 +- .../langchain_google_vertexai/chat_models.py | 10 ++++------ .../langchain_google_vertexai/embeddings.py | 2 +- .../functions_utils.py | 2 +- .../langchain_google_vertexai/gemma.py | 19 ++++++------------- .../langchain_google_vertexai/llms.py | 9 ++++----- .../langchain_google_vertexai/model_garden.py | 14 +++++--------- .../model_garden_maas/_base.py | 10 ++++------ .../vision_models.py | 2 +- .../tests/integration_tests/test_chains.py | 2 +- .../integration_tests/test_chat_models.py | 2 +- .../integration_tests/test_model_garden.py | 2 +- .../tests/unit_tests/test_chat_models.py | 2 +- .../tests/unit_tests/test_embeddings.py | 2 +- .../tests/unit_tests/test_function_utils.py | 2 +- libs/vertexai/tests/unit_tests/test_llm.py | 2 +- 19 files changed, 43 insertions(+), 60 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/_anthropic_parsers.py b/libs/vertexai/langchain_google_vertexai/_anthropic_parsers.py index d401f78f..b4d5f295 100644 --- a/libs/vertexai/langchain_google_vertexai/_anthropic_parsers.py +++ b/libs/vertexai/langchain_google_vertexai/_anthropic_parsers.py @@ -4,7 +4,9 @@ from langchain_core.messages.tool import tool_call from langchain_core.output_parsers import BaseGenerationOutputParser from langchain_core.outputs import ChatGeneration, Generation -from langchain_core.pydantic_v1 import BaseModel +from pydantic import BaseModel +from pydantic import ConfigDict + class ToolsOutputParser(BaseGenerationOutputParser): @@ -12,8 +14,7 @@ class ToolsOutputParser(BaseGenerationOutputParser): args_only: bool = False pydantic_schemas: Optional[List[Type[BaseModel]]] = None - class Config: - extra = "forbid" + model_config = ConfigDict(extra="forbid",) def parse_result(self, result: List[Generation], *, partial: bool = False) -> Any: """Parse a list of candidate model Generations into a specific format. diff --git a/libs/vertexai/langchain_google_vertexai/_anthropic_utils.py b/libs/vertexai/langchain_google_vertexai/_anthropic_utils.py index e6205d79..98e5904f 100644 --- a/libs/vertexai/langchain_google_vertexai/_anthropic_utils.py +++ b/libs/vertexai/langchain_google_vertexai/_anthropic_utils.py @@ -26,7 +26,7 @@ ToolMessage, ) from langchain_core.messages.ai import UsageMetadata -from langchain_core.pydantic_v1 import BaseModel +from pydantic import BaseModel from langchain_core.tools import BaseTool from langchain_core.utils.function_calling import convert_to_openai_tool diff --git a/libs/vertexai/langchain_google_vertexai/_base.py b/libs/vertexai/langchain_google_vertexai/_base.py index 9bcd09a1..e449c8df 100644 --- a/libs/vertexai/langchain_google_vertexai/_base.py +++ b/libs/vertexai/langchain_google_vertexai/_base.py @@ -22,7 +22,7 @@ from google.protobuf import json_format from google.protobuf.struct_pb2 import Value from langchain_core.outputs import Generation, LLMResult -from langchain_core.pydantic_v1 import BaseModel, Field, root_validator +from pydantic import BaseModel, Field, root_validator from vertexai.generative_models._generative_models import ( # type: ignore SafetySettingsType, ) @@ -42,6 +42,8 @@ get_user_agent, is_gemini_model, ) +from pydantic import ConfigDict + _PALM_DEFAULT_MAX_OUTPUT_TOKENS = TextGenerationModel._DEFAULT_MAX_OUTPUT_TOKENS _PALM_DEFAULT_TEMPERATURE = 0.0 @@ -91,11 +93,7 @@ class _VertexAIBase(BaseModel): "when making API calls. If not provided, credentials will be ascertained from " "the environment." - class Config: - """Configuration for this pydantic object.""" - - allow_population_by_field_name = True - arbitrary_types_allowed = True + model_config = ConfigDict(populate_by_name=True,arbitrary_types_allowed=True,) @root_validator(pre=True) def validate_params_base(cls, values: dict) -> dict: diff --git a/libs/vertexai/langchain_google_vertexai/chains.py b/libs/vertexai/langchain_google_vertexai/chains.py index a6f63455..7efb0524 100644 --- a/libs/vertexai/langchain_google_vertexai/chains.py +++ b/libs/vertexai/langchain_google_vertexai/chains.py @@ -13,7 +13,7 @@ StrOutputParser, ) from langchain_core.prompts import BasePromptTemplate, ChatPromptTemplate -from langchain_core.pydantic_v1 import BaseModel +from pydantic import BaseModel from langchain_core.runnables import Runnable from langchain_google_vertexai.functions_utils import PydanticFunctionsOutputParser diff --git a/libs/vertexai/langchain_google_vertexai/chat_models.py b/libs/vertexai/langchain_google_vertexai/chat_models.py index ad60efe2..5d18284e 100644 --- a/libs/vertexai/langchain_google_vertexai/chat_models.py +++ b/libs/vertexai/langchain_google_vertexai/chat_models.py @@ -62,7 +62,7 @@ ) from langchain_core.output_parsers.openai_tools import parse_tool_calls from langchain_core.outputs import ChatGeneration, ChatGenerationChunk, ChatResult -from langchain_core.pydantic_v1 import BaseModel, root_validator, Field +from pydantic import BaseModel, root_validator, Field from langchain_core.runnables import Runnable, RunnablePassthrough, RunnableGenerator from langchain_core.utils.function_calling import convert_to_openai_tool from langchain_core.utils.pydantic import is_basemodel_subclass @@ -124,6 +124,8 @@ _format_to_gapic_tool, _ToolType, ) +from pydantic import ConfigDict + logger = logging.getLogger(__name__) @@ -1024,11 +1026,7 @@ def __init__(self, *, model_name: Optional[str] = None, **kwargs: Any) -> None: kwargs["model_name"] = model_name super().__init__(**kwargs) - class Config: - """Configuration for this pydantic object.""" - - allow_population_by_field_name = True - arbitrary_types_allowed = True + model_config = ConfigDict(populate_by_name=True,arbitrary_types_allowed=True,) @classmethod def is_lc_serializable(self) -> bool: diff --git a/libs/vertexai/langchain_google_vertexai/embeddings.py b/libs/vertexai/langchain_google_vertexai/embeddings.py index a6a2fae8..7bfaab94 100644 --- a/libs/vertexai/langchain_google_vertexai/embeddings.py +++ b/libs/vertexai/langchain_google_vertexai/embeddings.py @@ -17,7 +17,7 @@ from google.cloud.aiplatform import telemetry from langchain_core.embeddings import Embeddings from langchain_core.language_models.llms import create_base_retry_decorator -from langchain_core.pydantic_v1 import root_validator +from pydantic import root_validator from vertexai.language_models import ( # type: ignore TextEmbeddingInput, TextEmbeddingModel, diff --git a/libs/vertexai/langchain_google_vertexai/functions_utils.py b/libs/vertexai/langchain_google_vertexai/functions_utils.py index 455d298c..813886f6 100644 --- a/libs/vertexai/langchain_google_vertexai/functions_utils.py +++ b/libs/vertexai/langchain_google_vertexai/functions_utils.py @@ -21,7 +21,7 @@ from langchain_core.exceptions import OutputParserException from langchain_core.output_parsers import BaseOutputParser from langchain_core.outputs import ChatGeneration, Generation -from langchain_core.pydantic_v1 import BaseModel +from pydantic import BaseModel from langchain_core.tools import BaseTool from langchain_core.tools import tool as callable_as_lc_tool from langchain_core.utils.function_calling import ( diff --git a/libs/vertexai/langchain_google_vertexai/gemma.py b/libs/vertexai/langchain_google_vertexai/gemma.py index 55e945e8..b3cb5f87 100644 --- a/libs/vertexai/langchain_google_vertexai/gemma.py +++ b/libs/vertexai/langchain_google_vertexai/gemma.py @@ -21,11 +21,13 @@ Generation, LLMResult, ) -from langchain_core.pydantic_v1 import BaseModel, Field, root_validator +from pydantic import BaseModel, Field, root_validator from langchain_google_vertexai._base import _BaseVertexAIModelGarden from langchain_google_vertexai._utils import enforce_stop_tokens from langchain_google_vertexai.model_garden import VertexAIModelGarden +from pydantic import ConfigDict + USER_CHAT_TEMPLATE = "user\n{prompt}\n" MODEL_CHAT_TEMPLATE = "model\n{prompt}\n" @@ -127,10 +129,7 @@ def __init__(self, *, model_name: Optional[str] = None, **kwargs: Any) -> None: kwargs["model_name"] = model_name super().__init__(**kwargs) - class Config: - """Configuration for this pydantic object.""" - - allow_population_by_field_name = True + model_config = ConfigDict(populate_by_name=True,) @property def _llm_type(self) -> str: @@ -200,10 +199,7 @@ class _GemmaLocalKaggleBase(_GemmaBase): model_name: str = Field(default="gemma_2b_en", alias="model") """Gemma model name.""" - class Config: - """Configuration for this pydantic object.""" - - allow_population_by_field_name = True + model_config = ConfigDict(populate_by_name=True,) def __init__(self, *, model_name: Optional[str] = None, **kwargs: Any) -> None: """Needed for mypy typing to recognize model_name as a valid arg.""" @@ -313,10 +309,7 @@ class _GemmaLocalHFBase(_GemmaBase): model_name: str = Field(default="google/gemma-2b", alias="model") """Gemma model name.""" - class Config: - """Configuration for this pydantic object.""" - - allow_population_by_field_name = True + model_config = ConfigDict(populate_by_name=True,) @root_validator() def validate_environment(cls, values: Dict) -> Dict: diff --git a/libs/vertexai/langchain_google_vertexai/llms.py b/libs/vertexai/langchain_google_vertexai/llms.py index b9dc76db..81d1c02e 100644 --- a/libs/vertexai/langchain_google_vertexai/llms.py +++ b/libs/vertexai/langchain_google_vertexai/llms.py @@ -9,7 +9,7 @@ ) from langchain_core.language_models.llms import BaseLLM, LangSmithParams from langchain_core.outputs import Generation, GenerationChunk, LLMResult -from langchain_core.pydantic_v1 import Field, root_validator +from pydantic import Field, root_validator from vertexai.generative_models import ( # type: ignore[import-untyped] Candidate, GenerativeModel, @@ -35,6 +35,8 @@ get_generation_info, is_gemini_model, ) +from pydantic import ConfigDict + def _completion_with_retry( @@ -120,10 +122,7 @@ def __init__(self, *, model_name: Optional[str] = None, **kwargs: Any) -> None: kwargs["model_name"] = model_name super().__init__(**kwargs) - class Config: - """Configuration for this pydantic object.""" - - allow_population_by_field_name = True + model_config = ConfigDict(populate_by_name=True,) @classmethod def is_lc_serializable(self) -> bool: diff --git a/libs/vertexai/langchain_google_vertexai/model_garden.py b/libs/vertexai/langchain_google_vertexai/model_garden.py index 86d6f00e..7921feda 100644 --- a/libs/vertexai/langchain_google_vertexai/model_garden.py +++ b/libs/vertexai/langchain_google_vertexai/model_garden.py @@ -39,7 +39,7 @@ Generation, LLMResult, ) -from langchain_core.pydantic_v1 import BaseModel, Field, root_validator +from pydantic import BaseModel, Field, root_validator from langchain_core.runnables import ( Runnable, RunnableMap, @@ -58,15 +58,14 @@ convert_to_anthropic_tool, ) from langchain_google_vertexai._base import _BaseVertexAIModelGarden, _VertexAICommon +from pydantic import ConfigDict + class VertexAIModelGarden(_BaseVertexAIModelGarden, BaseLLM): """Large language models served from Vertex AI Model Garden.""" - class Config: - """Configuration for this pydantic object.""" - - allow_population_by_field_name = True + model_config = ConfigDict(populate_by_name=True,) # Needed so that mypy doesn't flag missing aliased init args. def __init__(self, **kwargs: Any) -> None: @@ -137,10 +136,7 @@ class ChatAnthropicVertex(_VertexAICommon, BaseChatModel): stream_usage: bool = True # Whether to include usage metadata in streaming output credentials: Optional[Credentials] = None - class Config: - """Configuration for this pydantic object.""" - - allow_population_by_field_name = True + model_config = ConfigDict(populate_by_name=True,) # Needed so that mypy doesn't flag missing aliased init args. def __init__(self, **kwargs: Any) -> None: diff --git a/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py b/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py index 030b1c69..fc6d7248 100644 --- a/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py +++ b/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py @@ -24,9 +24,11 @@ CallbackManagerForLLMRun, ) from langchain_core.language_models.llms import create_base_retry_decorator -from langchain_core.pydantic_v1 import root_validator +from pydantic import root_validator from langchain_google_vertexai._base import _VertexAIBase +from pydantic import ConfigDict + def _get_token(credentials: Optional[Credentials] = None) -> str: @@ -101,11 +103,7 @@ class _BaseVertexMaasModelGarden(_VertexAIBase): model_family: Optional[VertexMaaSModelFamily] = None timeout: int = 120 - class Config: - """Configuration for this pydantic object.""" - - allow_population_by_field_name = True - arbitrary_types_allowed = True + model_config = ConfigDict(populate_by_name=True,arbitrary_types_allowed=True,) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/libs/vertexai/langchain_google_vertexai/vision_models.py b/libs/vertexai/langchain_google_vertexai/vision_models.py index 499f5e58..1ffc254e 100644 --- a/libs/vertexai/langchain_google_vertexai/vision_models.py +++ b/libs/vertexai/langchain_google_vertexai/vision_models.py @@ -9,7 +9,7 @@ from langchain_core.outputs import ChatResult, LLMResult from langchain_core.outputs.chat_generation import ChatGeneration from langchain_core.outputs.generation import Generation -from langchain_core.pydantic_v1 import BaseModel, Field +from pydantic import BaseModel, Field from vertexai.preview.vision_models import ( # type: ignore[import-untyped] GeneratedImage, ImageGenerationModel, diff --git a/libs/vertexai/tests/integration_tests/test_chains.py b/libs/vertexai/tests/integration_tests/test_chains.py index e2e3560f..295219f2 100644 --- a/libs/vertexai/tests/integration_tests/test_chains.py +++ b/libs/vertexai/tests/integration_tests/test_chains.py @@ -5,7 +5,7 @@ AIMessage, ) from langchain_core.prompts import ChatPromptTemplate -from langchain_core.pydantic_v1 import BaseModel, Field +from pydantic import BaseModel, Field from langchain_google_vertexai import ChatVertexAI, create_structured_runnable from tests.integration_tests.conftest import _DEFAULT_MODEL_NAME diff --git a/libs/vertexai/tests/integration_tests/test_chat_models.py b/libs/vertexai/tests/integration_tests/test_chat_models.py index e58a3223..b7148e6c 100644 --- a/libs/vertexai/tests/integration_tests/test_chat_models.py +++ b/libs/vertexai/tests/integration_tests/test_chat_models.py @@ -22,7 +22,7 @@ ) from langchain_core.outputs import ChatGeneration, LLMResult from langchain_core.prompts import ChatPromptTemplate -from langchain_core.pydantic_v1 import BaseModel +from pydantic import BaseModel from langchain_core.rate_limiters import InMemoryRateLimiter from langchain_core.tools import tool diff --git a/libs/vertexai/tests/integration_tests/test_model_garden.py b/libs/vertexai/tests/integration_tests/test_model_garden.py index d0a2a781..e4800431 100644 --- a/libs/vertexai/tests/integration_tests/test_model_garden.py +++ b/libs/vertexai/tests/integration_tests/test_model_garden.py @@ -11,7 +11,7 @@ SystemMessage, ) from langchain_core.outputs import LLMResult -from langchain_core.pydantic_v1 import BaseModel +from pydantic import BaseModel from langchain_core.tools import tool from langchain_google_vertexai.model_garden import ( diff --git a/libs/vertexai/tests/unit_tests/test_chat_models.py b/libs/vertexai/tests/unit_tests/test_chat_models.py index 27727acb..5df10ad5 100644 --- a/libs/vertexai/tests/unit_tests/test_chat_models.py +++ b/libs/vertexai/tests/unit_tests/test_chat_models.py @@ -28,7 +28,7 @@ from langchain_core.output_parsers.openai_tools import ( PydanticToolsParser, ) -from langchain_core.pydantic_v1 import BaseModel +from pydantic import BaseModel from vertexai.language_models import ( # type: ignore ChatMessage, InputOutputTextPair, diff --git a/libs/vertexai/tests/unit_tests/test_embeddings.py b/libs/vertexai/tests/unit_tests/test_embeddings.py index b47d8b5b..65a7a6fc 100644 --- a/libs/vertexai/tests/unit_tests/test_embeddings.py +++ b/libs/vertexai/tests/unit_tests/test_embeddings.py @@ -2,7 +2,7 @@ from unittest.mock import MagicMock import pytest -from langchain_core.pydantic_v1 import root_validator +from pydantic import root_validator from langchain_google_vertexai import VertexAIEmbeddings from langchain_google_vertexai.embeddings import GoogleEmbeddingModelType diff --git a/libs/vertexai/tests/unit_tests/test_function_utils.py b/libs/vertexai/tests/unit_tests/test_function_utils.py index d9cab148..12140b93 100644 --- a/libs/vertexai/tests/unit_tests/test_function_utils.py +++ b/libs/vertexai/tests/unit_tests/test_function_utils.py @@ -6,7 +6,7 @@ import google.cloud.aiplatform_v1beta1.types as gapic import pytest import vertexai.generative_models as vertexai # type: ignore -from langchain_core.pydantic_v1 import BaseModel, Field +from pydantic import BaseModel, Field from langchain_core.tools import BaseTool, tool from langchain_core.utils.json_schema import dereference_refs diff --git a/libs/vertexai/tests/unit_tests/test_llm.py b/libs/vertexai/tests/unit_tests/test_llm.py index e9271b41..8c6c8c55 100644 --- a/libs/vertexai/tests/unit_tests/test_llm.py +++ b/libs/vertexai/tests/unit_tests/test_llm.py @@ -2,7 +2,7 @@ from unittest import TestCase from unittest.mock import MagicMock, patch -from langchain_core.pydantic_v1 import root_validator +from pydantic import root_validator from langchain_google_vertexai._base import _BaseVertexAIModelGarden from langchain_google_vertexai.llms import VertexAI From c9fc32db37b058b0d80ff62846a87e71be508bf8 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:15:05 -0400 Subject: [PATCH 04/32] model_before_rewrite --- libs/vertexai/langchain_google_vertexai/_base.py | 7 ++++--- .../langchain_google_vertexai/model_garden_maas/_base.py | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/_base.py b/libs/vertexai/langchain_google_vertexai/_base.py index e449c8df..7e01effb 100644 --- a/libs/vertexai/langchain_google_vertexai/_base.py +++ b/libs/vertexai/langchain_google_vertexai/_base.py @@ -22,7 +22,7 @@ from google.protobuf import json_format from google.protobuf.struct_pb2 import Value from langchain_core.outputs import Generation, LLMResult -from pydantic import BaseModel, Field, root_validator +from pydantic import BaseModel, Field, root_validator, model_validator from vertexai.generative_models._generative_models import ( # type: ignore SafetySettingsType, ) @@ -95,8 +95,9 @@ class _VertexAIBase(BaseModel): model_config = ConfigDict(populate_by_name=True,arbitrary_types_allowed=True,) - @root_validator(pre=True) - def validate_params_base(cls, values: dict) -> dict: + @model_validator(mode="before") + @classmethod + def validate_params_base(cls, values: dict) -> Any: if "model" in values and "model_name" not in values: values["model_name"] = values.pop("model") if values.get("project") is None: diff --git a/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py b/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py index fc6d7248..6f7bf55e 100644 --- a/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py +++ b/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py @@ -24,7 +24,7 @@ CallbackManagerForLLMRun, ) from langchain_core.language_models.llms import create_base_retry_decorator -from pydantic import root_validator +from pydantic import root_validator, model_validator from langchain_google_vertexai._base import _VertexAIBase from pydantic import ConfigDict @@ -127,8 +127,9 @@ def __init__(self, **kwargs): timeout=self.timeout, ) - @root_validator(pre=True) - def validate_environment_model_garden(cls, values: Dict) -> Dict: + @model_validator(mode="before") + @classmethod + def validate_environment_model_garden(cls, values: Dict) -> Any: """Validate that the python package exists in environment.""" family = VertexMaaSModelFamily(values["model_name"]) values["model_family"] = family From 669a9cda9f80a07162f4a5636785eb02ed0f5e5e Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:15:17 -0400 Subject: [PATCH 05/32] model_after_rewrite --- .../langchain_google_vertexai/_base.py | 14 ++--- .../langchain_google_vertexai/chat_models.py | 52 +++++++++---------- .../langchain_google_vertexai/embeddings.py | 20 +++---- .../langchain_google_vertexai/gemma.py | 12 ++--- .../langchain_google_vertexai/llms.py | 36 ++++++------- .../langchain_google_vertexai/model_garden.py | 32 ++++++------ .../tests/unit_tests/test_embeddings.py | 10 ++-- libs/vertexai/tests/unit_tests/test_llm.py | 8 +-- 8 files changed, 92 insertions(+), 92 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/_base.py b/libs/vertexai/langchain_google_vertexai/_base.py index 7e01effb..ec143946 100644 --- a/libs/vertexai/langchain_google_vertexai/_base.py +++ b/libs/vertexai/langchain_google_vertexai/_base.py @@ -310,26 +310,26 @@ class _BaseVertexAIModelGarden(_VertexAIBase): single_example_per_request: bool = True "LLM endpoint currently serves only the first example in the request" - @root_validator(pre=False, skip_on_failure=True) - def validate_environment(cls, values: Dict) -> Dict: + @model_validator(mode="after") + def validate_environment(self) -> Self: """Validate that the python package exists in environment.""" - if not values["project"]: + if not self.project: raise ValueError( "A GCP project should be provided to run inference on Model Garden!" ) client_options = ClientOptions( - api_endpoint=f"{values['location']}-aiplatform.googleapis.com" + api_endpoint=f"{self.location}-aiplatform.googleapis.com" ) client_info = get_client_info(module="vertex-ai-model-garden") - values["client"] = PredictionServiceClient( + self.client = PredictionServiceClient( client_options=client_options, client_info=client_info ) - values["async_client"] = PredictionServiceAsyncClient( + self.async_client = PredictionServiceAsyncClient( client_options=client_options, client_info=client_info ) - return values + return self @property def endpoint_path(self) -> str: diff --git a/libs/vertexai/langchain_google_vertexai/chat_models.py b/libs/vertexai/langchain_google_vertexai/chat_models.py index 5d18284e..de300458 100644 --- a/libs/vertexai/langchain_google_vertexai/chat_models.py +++ b/libs/vertexai/langchain_google_vertexai/chat_models.py @@ -62,7 +62,7 @@ ) from langchain_core.output_parsers.openai_tools import parse_tool_calls from langchain_core.outputs import ChatGeneration, ChatGenerationChunk, ChatResult -from pydantic import BaseModel, root_validator, Field +from pydantic import BaseModel, root_validator, Field, model_validator from langchain_core.runnables import Runnable, RunnablePassthrough, RunnableGenerator from langchain_core.utils.function_calling import convert_to_openai_tool from langchain_core.utils.pydantic import is_basemodel_subclass @@ -1037,57 +1037,57 @@ def get_lc_namespace(cls) -> List[str]: """Get the namespace of the langchain object.""" return ["langchain", "chat_models", "vertexai"] - @root_validator(pre=False, skip_on_failure=True) - def validate_environment(cls, values: Dict) -> Dict: + @model_validator(mode="after") + def validate_environment(self) -> Self: """Validate that the python package exists in environment.""" - safety_settings = values.get("safety_settings") - tuned_model_name = values.get("tuned_model_name") - values["model_family"] = GoogleModelFamily(values["model_name"]) + safety_settings = (self.safety_settings or None) + tuned_model_name = (self.tuned_model_name or None) + self.model_family = GoogleModelFamily(self.model_name) - if values["model_name"] == "chat-bison-default": + if self.model_name == "chat-bison-default": logger.warning( "Model_name will become a required arg for VertexAIEmbeddings " "starting from Sep-01-2024. Currently the default is set to " "chat-bison" ) - values["model_name"] = "chat-bison" + self.model_name = "chat-bison" - if values.get("full_model_name") is not None: + if (self.full_model_name or None) is not None: pass - elif values.get("tuned_model_name") is not None: - values["full_model_name"] = _format_model_name( - values["tuned_model_name"], - location=values["location"], - project=values["project"], + elif (self.tuned_model_name or None) is not None: + self.full_model_name = _format_model_name( + self.tuned_model_name, + location=self.location, + project=self.project, ) else: - values["full_model_name"] = _format_model_name( - values["model_name"], - location=values["location"], - project=values["project"], + self.full_model_name = _format_model_name( + self.model_name, + location=self.location, + project=self.project, ) - if safety_settings and not is_gemini_model(values["model_family"]): + if safety_settings and not is_gemini_model(self.model_family): raise ValueError("Safety settings are only supported for Gemini models") if tuned_model_name: - generative_model_name = values["tuned_model_name"] + generative_model_name = self.tuned_model_name else: - generative_model_name = values["model_name"] + generative_model_name = self.model_name - if not is_gemini_model(values["model_family"]): + if not is_gemini_model(self.model_family): cls._init_vertexai(values) - if values["model_family"] == GoogleModelFamily.CODEY: + if self.model_family == GoogleModelFamily.CODEY: model_cls = CodeChatModel model_cls_preview = PreviewCodeChatModel else: model_cls = ChatModel model_cls_preview = PreviewChatModel - values["client"] = model_cls.from_pretrained(generative_model_name) - values["client_preview"] = model_cls_preview.from_pretrained( + self.client = model_cls.from_pretrained(generative_model_name) + self.client_preview = model_cls_preview.from_pretrained( generative_model_name ) - return values + return self @property def _is_gemini_advanced(self) -> bool: diff --git a/libs/vertexai/langchain_google_vertexai/embeddings.py b/libs/vertexai/langchain_google_vertexai/embeddings.py index 7bfaab94..e287b3cd 100644 --- a/libs/vertexai/langchain_google_vertexai/embeddings.py +++ b/libs/vertexai/langchain_google_vertexai/embeddings.py @@ -17,7 +17,7 @@ from google.cloud.aiplatform import telemetry from langchain_core.embeddings import Embeddings from langchain_core.language_models.llms import create_base_retry_decorator -from pydantic import root_validator +from pydantic import root_validator, model_validator from vertexai.language_models import ( # type: ignore TextEmbeddingInput, TextEmbeddingModel, @@ -100,24 +100,24 @@ class VertexAIEmbeddings(_VertexAICommon, Embeddings): # Instance context instance: Dict[str, Any] = {} #: :meta private: - @root_validator(pre=False, skip_on_failure=True) - def validate_environment(cls, values: Dict) -> Dict: + @model_validator(mode="after") + def validate_environment(self) -> Self: """Validates that the python package exists in environment.""" cls._init_vertexai(values) - _, user_agent = get_user_agent(f"{cls.__name__}_{values['model_name']}") # type: ignore + _, user_agent = get_user_agent(f"{cls.__name__}_{self.model_name}") # type: ignore with telemetry.tool_context_manager(user_agent): if ( - GoogleEmbeddingModelType(values["model_name"]) + GoogleEmbeddingModelType(self.model_name) == GoogleEmbeddingModelType.MULTIMODAL ): - values["client"] = MultiModalEmbeddingModel.from_pretrained( - values["model_name"] + self.client = MultiModalEmbeddingModel.from_pretrained( + self.model_name ) else: - values["client"] = TextEmbeddingModel.from_pretrained( - values["model_name"] + self.client = TextEmbeddingModel.from_pretrained( + self.model_name ) - return values + return self def __init__( self, diff --git a/libs/vertexai/langchain_google_vertexai/gemma.py b/libs/vertexai/langchain_google_vertexai/gemma.py index b3cb5f87..0b8e9077 100644 --- a/libs/vertexai/langchain_google_vertexai/gemma.py +++ b/libs/vertexai/langchain_google_vertexai/gemma.py @@ -21,7 +21,7 @@ Generation, LLMResult, ) -from pydantic import BaseModel, Field, root_validator +from pydantic import BaseModel, Field, root_validator, model_validator from langchain_google_vertexai._base import _BaseVertexAIModelGarden from langchain_google_vertexai._utils import enforce_stop_tokens @@ -207,11 +207,11 @@ def __init__(self, *, model_name: Optional[str] = None, **kwargs: Any) -> None: kwargs["model_name"] = model_name super().__init__(**kwargs) - @root_validator(pre=False, skip_on_failure=True) - def validate_environment(cls, values: Dict) -> Dict: + @model_validator(mode="after") + def validate_environment(self) -> Self: """Validate that llama-cpp-python library is installed.""" try: - os.environ["KERAS_BACKEND"] = values["keras_backend"] + os.environ["KERAS_BACKEND"] = self.keras_backend from keras_nlp.models import GemmaCausalLM # type: ignore except ImportError: raise ImportError( @@ -220,8 +220,8 @@ def validate_environment(cls, values: Dict) -> Dict: "use this model: pip install keras-nlp keras>=3 kaggle" ) - values["client"] = GemmaCausalLM.from_preset(values["model_name"]) - return values + self.client = GemmaCausalLM.from_preset(self.model_name) + return self @property def _default_params(self) -> Dict[str, Any]: diff --git a/libs/vertexai/langchain_google_vertexai/llms.py b/libs/vertexai/langchain_google_vertexai/llms.py index 81d1c02e..e26a1393 100644 --- a/libs/vertexai/langchain_google_vertexai/llms.py +++ b/libs/vertexai/langchain_google_vertexai/llms.py @@ -9,7 +9,7 @@ ) from langchain_core.language_models.llms import BaseLLM, LangSmithParams from langchain_core.outputs import Generation, GenerationChunk, LLMResult -from pydantic import Field, root_validator +from pydantic import Field, root_validator, model_validator from vertexai.generative_models import ( # type: ignore[import-untyped] Candidate, GenerativeModel, @@ -133,19 +133,19 @@ def get_lc_namespace(cls) -> List[str]: """Get the namespace of the langchain object.""" return ["langchain", "llms", "vertexai"] - @root_validator(pre=False, skip_on_failure=True) - def validate_environment(cls, values: Dict) -> Dict: + @model_validator(mode="after") + def validate_environment(self) -> Self: """Validate that the python package exists in environment.""" - tuned_model_name = values.get("tuned_model_name") - safety_settings = values["safety_settings"] - values["model_family"] = GoogleModelFamily(values["model_name"]) - is_gemini = is_gemini_model(values["model_family"]) + tuned_model_name = (self.tuned_model_name or None) + safety_settings = self.safety_settings + self.model_family = GoogleModelFamily(self.model_name) + is_gemini = is_gemini_model(self.model_family) cls._init_vertexai(values) if safety_settings and (not is_gemini or tuned_model_name): raise ValueError("Safety settings are only supported for Gemini models") - if values["model_family"] == GoogleModelFamily.CODEY: + if self.model_family == GoogleModelFamily.CODEY: model_cls = CodeGenerationModel preview_model_cls = PreviewCodeGenerationModel elif is_gemini: @@ -156,31 +156,31 @@ def validate_environment(cls, values: Dict) -> Dict: preview_model_cls = PreviewTextGenerationModel if tuned_model_name: - generative_model_name = values["tuned_model_name"] + generative_model_name = self.tuned_model_name else: - generative_model_name = values["model_name"] + generative_model_name = self.model_name if is_gemini: - values["client"] = model_cls( + self.client = model_cls( model_name=generative_model_name, safety_settings=safety_settings ) - values["client_preview"] = preview_model_cls( + self.client_preview = preview_model_cls( model_name=generative_model_name, safety_settings=safety_settings ) else: if tuned_model_name: - values["client"] = model_cls.get_tuned_model(generative_model_name) - values["client_preview"] = preview_model_cls.get_tuned_model( + self.client = model_cls.get_tuned_model(generative_model_name) + self.client_preview = preview_model_cls.get_tuned_model( generative_model_name ) else: - values["client"] = model_cls.from_pretrained(generative_model_name) - values["client_preview"] = preview_model_cls.from_pretrained( + self.client = model_cls.from_pretrained(generative_model_name) + self.client_preview = preview_model_cls.from_pretrained( generative_model_name ) - if values["streaming"] and values["n"] > 1: + if self.streaming and self.n > 1: raise ValueError("Only one candidate can be generated with streaming!") - return values + return self def _get_ls_params( self, stop: Optional[List[str]] = None, **kwargs: Any diff --git a/libs/vertexai/langchain_google_vertexai/model_garden.py b/libs/vertexai/langchain_google_vertexai/model_garden.py index 7921feda..24139a20 100644 --- a/libs/vertexai/langchain_google_vertexai/model_garden.py +++ b/libs/vertexai/langchain_google_vertexai/model_garden.py @@ -39,7 +39,7 @@ Generation, LLMResult, ) -from pydantic import BaseModel, Field, root_validator +from pydantic import BaseModel, Field, root_validator, model_validator from langchain_core.runnables import ( Runnable, RunnableMap, @@ -142,28 +142,28 @@ class ChatAnthropicVertex(_VertexAICommon, BaseChatModel): def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) - @root_validator(pre=False, skip_on_failure=True) - def validate_environment(cls, values: Dict) -> Dict: + @model_validator(mode="after") + def validate_environment(self) -> Self: from anthropic import ( # type: ignore AnthropicVertex, AsyncAnthropicVertex, ) - values["client"] = AnthropicVertex( - project_id=values["project"], - region=values["location"], - max_retries=values["max_retries"], - access_token=values["access_token"], - credentials=values["credentials"], + self.client = AnthropicVertex( + project_id=self.project, + region=self.location, + max_retries=self.max_retries, + access_token=self.access_token, + credentials=self.credentials, ) - values["async_client"] = AsyncAnthropicVertex( - project_id=values["project"], - region=values["location"], - max_retries=values["max_retries"], - access_token=values["access_token"], - credentials=values["credentials"], + self.async_client = AsyncAnthropicVertex( + project_id=self.project, + region=self.location, + max_retries=self.max_retries, + access_token=self.access_token, + credentials=self.credentials, ) - return values + return self @property def _default_params(self): diff --git a/libs/vertexai/tests/unit_tests/test_embeddings.py b/libs/vertexai/tests/unit_tests/test_embeddings.py index 65a7a6fc..5decabbc 100644 --- a/libs/vertexai/tests/unit_tests/test_embeddings.py +++ b/libs/vertexai/tests/unit_tests/test_embeddings.py @@ -2,7 +2,7 @@ from unittest.mock import MagicMock import pytest -from pydantic import root_validator +from pydantic import root_validator, model_validator from langchain_google_vertexai import VertexAIEmbeddings from langchain_google_vertexai.embeddings import GoogleEmbeddingModelType @@ -41,7 +41,7 @@ def __init__(self, model_name, **kwargs: Any) -> None: def _init_vertexai(cls, values: Dict) -> None: pass - @root_validator(pre=False, skip_on_failure=True) - def validate_environment(cls, values: Dict) -> Dict: - values["client"] = MagicMock() - return values + @model_validator(mode="after") + def validate_environment(self) -> Self: + self.client = MagicMock() + return self diff --git a/libs/vertexai/tests/unit_tests/test_llm.py b/libs/vertexai/tests/unit_tests/test_llm.py index 8c6c8c55..1f5f993f 100644 --- a/libs/vertexai/tests/unit_tests/test_llm.py +++ b/libs/vertexai/tests/unit_tests/test_llm.py @@ -2,7 +2,7 @@ from unittest import TestCase from unittest.mock import MagicMock, patch -from pydantic import root_validator +from pydantic import root_validator, model_validator from langchain_google_vertexai._base import _BaseVertexAIModelGarden from langchain_google_vertexai.llms import VertexAI @@ -80,9 +80,9 @@ def test_vertexai_args_passed() -> None: def test_extract_response() -> None: class FakeModelGarden(_BaseVertexAIModelGarden): - @root_validator(pre=False, skip_on_failure=True) - def validate_environment(cls, values: Dict) -> Dict: - return values + @model_validator(mode="after") + def validate_environment(self) -> Self: + return self prompts_results = [ ("a prediction", "a prediction"), From ca5a4de921ad87c270d9422694afe5b17a52e22b Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:15:27 -0400 Subject: [PATCH 06/32] Self --- libs/vertexai/langchain_google_vertexai/_base.py | 2 ++ libs/vertexai/langchain_google_vertexai/chat_models.py | 2 ++ libs/vertexai/langchain_google_vertexai/embeddings.py | 2 ++ libs/vertexai/langchain_google_vertexai/gemma.py | 2 ++ libs/vertexai/langchain_google_vertexai/llms.py | 2 ++ libs/vertexai/langchain_google_vertexai/model_garden.py | 2 ++ libs/vertexai/tests/unit_tests/test_embeddings.py | 2 ++ libs/vertexai/tests/unit_tests/test_llm.py | 2 ++ 8 files changed, 16 insertions(+) diff --git a/libs/vertexai/langchain_google_vertexai/_base.py b/libs/vertexai/langchain_google_vertexai/_base.py index ec143946..c2f2cc30 100644 --- a/libs/vertexai/langchain_google_vertexai/_base.py +++ b/libs/vertexai/langchain_google_vertexai/_base.py @@ -43,6 +43,8 @@ is_gemini_model, ) from pydantic import ConfigDict +from typing_extensions import Self + _PALM_DEFAULT_MAX_OUTPUT_TOKENS = TextGenerationModel._DEFAULT_MAX_OUTPUT_TOKENS diff --git a/libs/vertexai/langchain_google_vertexai/chat_models.py b/libs/vertexai/langchain_google_vertexai/chat_models.py index de300458..6064054e 100644 --- a/libs/vertexai/langchain_google_vertexai/chat_models.py +++ b/libs/vertexai/langchain_google_vertexai/chat_models.py @@ -125,6 +125,8 @@ _ToolType, ) from pydantic import ConfigDict +from typing_extensions import Self + logger = logging.getLogger(__name__) diff --git a/libs/vertexai/langchain_google_vertexai/embeddings.py b/libs/vertexai/langchain_google_vertexai/embeddings.py index e287b3cd..897fde71 100644 --- a/libs/vertexai/langchain_google_vertexai/embeddings.py +++ b/libs/vertexai/langchain_google_vertexai/embeddings.py @@ -31,6 +31,8 @@ from langchain_google_vertexai._base import _VertexAICommon from langchain_google_vertexai._image_utils import ImageBytesLoader from langchain_google_vertexai._utils import get_user_agent +from typing_extensions import Self + logger = logging.getLogger(__name__) diff --git a/libs/vertexai/langchain_google_vertexai/gemma.py b/libs/vertexai/langchain_google_vertexai/gemma.py index 0b8e9077..54a45fd5 100644 --- a/libs/vertexai/langchain_google_vertexai/gemma.py +++ b/libs/vertexai/langchain_google_vertexai/gemma.py @@ -27,6 +27,8 @@ from langchain_google_vertexai._utils import enforce_stop_tokens from langchain_google_vertexai.model_garden import VertexAIModelGarden from pydantic import ConfigDict +from typing_extensions import Self + USER_CHAT_TEMPLATE = "user\n{prompt}\n" diff --git a/libs/vertexai/langchain_google_vertexai/llms.py b/libs/vertexai/langchain_google_vertexai/llms.py index e26a1393..3d69e456 100644 --- a/libs/vertexai/langchain_google_vertexai/llms.py +++ b/libs/vertexai/langchain_google_vertexai/llms.py @@ -36,6 +36,8 @@ is_gemini_model, ) from pydantic import ConfigDict +from typing_extensions import Self + diff --git a/libs/vertexai/langchain_google_vertexai/model_garden.py b/libs/vertexai/langchain_google_vertexai/model_garden.py index 24139a20..ab68e963 100644 --- a/libs/vertexai/langchain_google_vertexai/model_garden.py +++ b/libs/vertexai/langchain_google_vertexai/model_garden.py @@ -59,6 +59,8 @@ ) from langchain_google_vertexai._base import _BaseVertexAIModelGarden, _VertexAICommon from pydantic import ConfigDict +from typing_extensions import Self + diff --git a/libs/vertexai/tests/unit_tests/test_embeddings.py b/libs/vertexai/tests/unit_tests/test_embeddings.py index 5decabbc..23f624c3 100644 --- a/libs/vertexai/tests/unit_tests/test_embeddings.py +++ b/libs/vertexai/tests/unit_tests/test_embeddings.py @@ -6,6 +6,8 @@ from langchain_google_vertexai import VertexAIEmbeddings from langchain_google_vertexai.embeddings import GoogleEmbeddingModelType +from typing_extensions import Self + def test_langchain_google_vertexai_embed_image_multimodal_only() -> None: diff --git a/libs/vertexai/tests/unit_tests/test_llm.py b/libs/vertexai/tests/unit_tests/test_llm.py index 1f5f993f..186954e4 100644 --- a/libs/vertexai/tests/unit_tests/test_llm.py +++ b/libs/vertexai/tests/unit_tests/test_llm.py @@ -6,6 +6,8 @@ from langchain_google_vertexai._base import _BaseVertexAIModelGarden from langchain_google_vertexai.llms import VertexAI +from typing_extensions import Self + def test_model_name() -> None: From 0d49776ce55b3cd9a09d76307ad900f2837c73b9 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:15:35 -0400 Subject: [PATCH 07/32] format --- .../_anthropic_parsers.py | 8 ++++---- .../_anthropic_utils.py | 2 +- .../langchain_google_vertexai/_base.py | 12 ++++++------ .../langchain_google_vertexai/chains.py | 2 +- .../langchain_google_vertexai/chat_models.py | 10 ++++++---- .../langchain_google_vertexai/embeddings.py | 13 ++++--------- .../functions_utils.py | 2 +- .../langchain_google_vertexai/gemma.py | 19 +++++++++++-------- .../langchain_google_vertexai/llms.py | 13 ++++++------- .../langchain_google_vertexai/model_garden.py | 15 ++++++++------- .../model_garden_maas/_base.py | 9 +++++---- .../integration_tests/test_chat_models.py | 2 +- .../integration_tests/test_model_garden.py | 2 +- .../tests/unit_tests/test_embeddings.py | 5 ++--- .../tests/unit_tests/test_function_utils.py | 2 +- libs/vertexai/tests/unit_tests/test_llm.py | 5 ++--- 16 files changed, 60 insertions(+), 61 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/_anthropic_parsers.py b/libs/vertexai/langchain_google_vertexai/_anthropic_parsers.py index b4d5f295..a31759bf 100644 --- a/libs/vertexai/langchain_google_vertexai/_anthropic_parsers.py +++ b/libs/vertexai/langchain_google_vertexai/_anthropic_parsers.py @@ -4,9 +4,7 @@ from langchain_core.messages.tool import tool_call from langchain_core.output_parsers import BaseGenerationOutputParser from langchain_core.outputs import ChatGeneration, Generation -from pydantic import BaseModel -from pydantic import ConfigDict - +from pydantic import BaseModel, ConfigDict class ToolsOutputParser(BaseGenerationOutputParser): @@ -14,7 +12,9 @@ class ToolsOutputParser(BaseGenerationOutputParser): args_only: bool = False pydantic_schemas: Optional[List[Type[BaseModel]]] = None - model_config = ConfigDict(extra="forbid",) + model_config = ConfigDict( + extra="forbid", + ) def parse_result(self, result: List[Generation], *, partial: bool = False) -> Any: """Parse a list of candidate model Generations into a specific format. diff --git a/libs/vertexai/langchain_google_vertexai/_anthropic_utils.py b/libs/vertexai/langchain_google_vertexai/_anthropic_utils.py index 98e5904f..976398fa 100644 --- a/libs/vertexai/langchain_google_vertexai/_anthropic_utils.py +++ b/libs/vertexai/langchain_google_vertexai/_anthropic_utils.py @@ -26,9 +26,9 @@ ToolMessage, ) from langchain_core.messages.ai import UsageMetadata -from pydantic import BaseModel from langchain_core.tools import BaseTool from langchain_core.utils.function_calling import convert_to_openai_tool +from pydantic import BaseModel if TYPE_CHECKING: from anthropic.types import RawMessageStreamEvent # type: ignore diff --git a/libs/vertexai/langchain_google_vertexai/_base.py b/libs/vertexai/langchain_google_vertexai/_base.py index c2f2cc30..ba857fc4 100644 --- a/libs/vertexai/langchain_google_vertexai/_base.py +++ b/libs/vertexai/langchain_google_vertexai/_base.py @@ -22,7 +22,8 @@ from google.protobuf import json_format from google.protobuf.struct_pb2 import Value from langchain_core.outputs import Generation, LLMResult -from pydantic import BaseModel, Field, root_validator, model_validator +from pydantic import BaseModel, ConfigDict, Field, model_validator, root_validator +from typing_extensions import Self from vertexai.generative_models._generative_models import ( # type: ignore SafetySettingsType, ) @@ -42,10 +43,6 @@ get_user_agent, is_gemini_model, ) -from pydantic import ConfigDict -from typing_extensions import Self - - _PALM_DEFAULT_MAX_OUTPUT_TOKENS = TextGenerationModel._DEFAULT_MAX_OUTPUT_TOKENS _PALM_DEFAULT_TEMPERATURE = 0.0 @@ -95,7 +92,10 @@ class _VertexAIBase(BaseModel): "when making API calls. If not provided, credentials will be ascertained from " "the environment." - model_config = ConfigDict(populate_by_name=True,arbitrary_types_allowed=True,) + model_config = ConfigDict( + populate_by_name=True, + arbitrary_types_allowed=True, + ) @model_validator(mode="before") @classmethod diff --git a/libs/vertexai/langchain_google_vertexai/chains.py b/libs/vertexai/langchain_google_vertexai/chains.py index 7efb0524..02465763 100644 --- a/libs/vertexai/langchain_google_vertexai/chains.py +++ b/libs/vertexai/langchain_google_vertexai/chains.py @@ -13,8 +13,8 @@ StrOutputParser, ) from langchain_core.prompts import BasePromptTemplate, ChatPromptTemplate -from pydantic import BaseModel from langchain_core.runnables import Runnable +from pydantic import BaseModel from langchain_google_vertexai.functions_utils import PydanticFunctionsOutputParser diff --git a/libs/vertexai/langchain_google_vertexai/chat_models.py b/libs/vertexai/langchain_google_vertexai/chat_models.py index 6064054e..d2c181bb 100644 --- a/libs/vertexai/langchain_google_vertexai/chat_models.py +++ b/libs/vertexai/langchain_google_vertexai/chat_models.py @@ -128,7 +128,6 @@ from typing_extensions import Self - logger = logging.getLogger(__name__) @@ -1028,7 +1027,10 @@ def __init__(self, *, model_name: Optional[str] = None, **kwargs: Any) -> None: kwargs["model_name"] = model_name super().__init__(**kwargs) - model_config = ConfigDict(populate_by_name=True,arbitrary_types_allowed=True,) + model_config = ConfigDict( + populate_by_name=True, + arbitrary_types_allowed=True, + ) @classmethod def is_lc_serializable(self) -> bool: @@ -1042,8 +1044,8 @@ def get_lc_namespace(cls) -> List[str]: @model_validator(mode="after") def validate_environment(self) -> Self: """Validate that the python package exists in environment.""" - safety_settings = (self.safety_settings or None) - tuned_model_name = (self.tuned_model_name or None) + safety_settings = self.safety_settings or None + tuned_model_name = self.tuned_model_name or None self.model_family = GoogleModelFamily(self.model_name) if self.model_name == "chat-bison-default": diff --git a/libs/vertexai/langchain_google_vertexai/embeddings.py b/libs/vertexai/langchain_google_vertexai/embeddings.py index 897fde71..a3f273fe 100644 --- a/libs/vertexai/langchain_google_vertexai/embeddings.py +++ b/libs/vertexai/langchain_google_vertexai/embeddings.py @@ -17,7 +17,8 @@ from google.cloud.aiplatform import telemetry from langchain_core.embeddings import Embeddings from langchain_core.language_models.llms import create_base_retry_decorator -from pydantic import root_validator, model_validator +from pydantic import model_validator, root_validator +from typing_extensions import Self from vertexai.language_models import ( # type: ignore TextEmbeddingInput, TextEmbeddingModel, @@ -31,8 +32,6 @@ from langchain_google_vertexai._base import _VertexAICommon from langchain_google_vertexai._image_utils import ImageBytesLoader from langchain_google_vertexai._utils import get_user_agent -from typing_extensions import Self - logger = logging.getLogger(__name__) @@ -112,13 +111,9 @@ def validate_environment(self) -> Self: GoogleEmbeddingModelType(self.model_name) == GoogleEmbeddingModelType.MULTIMODAL ): - self.client = MultiModalEmbeddingModel.from_pretrained( - self.model_name - ) + self.client = MultiModalEmbeddingModel.from_pretrained(self.model_name) else: - self.client = TextEmbeddingModel.from_pretrained( - self.model_name - ) + self.client = TextEmbeddingModel.from_pretrained(self.model_name) return self def __init__( diff --git a/libs/vertexai/langchain_google_vertexai/functions_utils.py b/libs/vertexai/langchain_google_vertexai/functions_utils.py index 813886f6..69e09e55 100644 --- a/libs/vertexai/langchain_google_vertexai/functions_utils.py +++ b/libs/vertexai/langchain_google_vertexai/functions_utils.py @@ -21,7 +21,6 @@ from langchain_core.exceptions import OutputParserException from langchain_core.output_parsers import BaseOutputParser from langchain_core.outputs import ChatGeneration, Generation -from pydantic import BaseModel from langchain_core.tools import BaseTool from langchain_core.tools import tool as callable_as_lc_tool from langchain_core.utils.function_calling import ( @@ -29,6 +28,7 @@ convert_to_openai_tool, ) from langchain_core.utils.json_schema import dereference_refs +from pydantic import BaseModel logger = logging.getLogger(__name__) diff --git a/libs/vertexai/langchain_google_vertexai/gemma.py b/libs/vertexai/langchain_google_vertexai/gemma.py index 54a45fd5..0e06a399 100644 --- a/libs/vertexai/langchain_google_vertexai/gemma.py +++ b/libs/vertexai/langchain_google_vertexai/gemma.py @@ -21,15 +21,12 @@ Generation, LLMResult, ) -from pydantic import BaseModel, Field, root_validator, model_validator +from pydantic import BaseModel, ConfigDict, Field, model_validator, root_validator +from typing_extensions import Self from langchain_google_vertexai._base import _BaseVertexAIModelGarden from langchain_google_vertexai._utils import enforce_stop_tokens from langchain_google_vertexai.model_garden import VertexAIModelGarden -from pydantic import ConfigDict -from typing_extensions import Self - - USER_CHAT_TEMPLATE = "user\n{prompt}\n" MODEL_CHAT_TEMPLATE = "model\n{prompt}\n" @@ -131,7 +128,9 @@ def __init__(self, *, model_name: Optional[str] = None, **kwargs: Any) -> None: kwargs["model_name"] = model_name super().__init__(**kwargs) - model_config = ConfigDict(populate_by_name=True,) + model_config = ConfigDict( + populate_by_name=True, + ) @property def _llm_type(self) -> str: @@ -201,7 +200,9 @@ class _GemmaLocalKaggleBase(_GemmaBase): model_name: str = Field(default="gemma_2b_en", alias="model") """Gemma model name.""" - model_config = ConfigDict(populate_by_name=True,) + model_config = ConfigDict( + populate_by_name=True, + ) def __init__(self, *, model_name: Optional[str] = None, **kwargs: Any) -> None: """Needed for mypy typing to recognize model_name as a valid arg.""" @@ -311,7 +312,9 @@ class _GemmaLocalHFBase(_GemmaBase): model_name: str = Field(default="google/gemma-2b", alias="model") """Gemma model name.""" - model_config = ConfigDict(populate_by_name=True,) + model_config = ConfigDict( + populate_by_name=True, + ) @root_validator() def validate_environment(cls, values: Dict) -> Dict: diff --git a/libs/vertexai/langchain_google_vertexai/llms.py b/libs/vertexai/langchain_google_vertexai/llms.py index 3d69e456..9022d602 100644 --- a/libs/vertexai/langchain_google_vertexai/llms.py +++ b/libs/vertexai/langchain_google_vertexai/llms.py @@ -9,7 +9,8 @@ ) from langchain_core.language_models.llms import BaseLLM, LangSmithParams from langchain_core.outputs import Generation, GenerationChunk, LLMResult -from pydantic import Field, root_validator, model_validator +from pydantic import ConfigDict, Field, model_validator, root_validator +from typing_extensions import Self from vertexai.generative_models import ( # type: ignore[import-untyped] Candidate, GenerativeModel, @@ -35,10 +36,6 @@ get_generation_info, is_gemini_model, ) -from pydantic import ConfigDict -from typing_extensions import Self - - def _completion_with_retry( @@ -124,7 +121,9 @@ def __init__(self, *, model_name: Optional[str] = None, **kwargs: Any) -> None: kwargs["model_name"] = model_name super().__init__(**kwargs) - model_config = ConfigDict(populate_by_name=True,) + model_config = ConfigDict( + populate_by_name=True, + ) @classmethod def is_lc_serializable(self) -> bool: @@ -138,7 +137,7 @@ def get_lc_namespace(cls) -> List[str]: @model_validator(mode="after") def validate_environment(self) -> Self: """Validate that the python package exists in environment.""" - tuned_model_name = (self.tuned_model_name or None) + tuned_model_name = self.tuned_model_name or None safety_settings = self.safety_settings self.model_family = GoogleModelFamily(self.model_name) is_gemini = is_gemini_model(self.model_family) diff --git a/libs/vertexai/langchain_google_vertexai/model_garden.py b/libs/vertexai/langchain_google_vertexai/model_garden.py index ab68e963..deeab3e1 100644 --- a/libs/vertexai/langchain_google_vertexai/model_garden.py +++ b/libs/vertexai/langchain_google_vertexai/model_garden.py @@ -39,13 +39,14 @@ Generation, LLMResult, ) -from pydantic import BaseModel, Field, root_validator, model_validator from langchain_core.runnables import ( Runnable, RunnableMap, RunnablePassthrough, ) from langchain_core.tools import BaseTool +from pydantic import BaseModel, ConfigDict, Field, model_validator, root_validator +from typing_extensions import Self from langchain_google_vertexai._anthropic_parsers import ( ToolsOutputParser, @@ -58,16 +59,14 @@ convert_to_anthropic_tool, ) from langchain_google_vertexai._base import _BaseVertexAIModelGarden, _VertexAICommon -from pydantic import ConfigDict -from typing_extensions import Self - - class VertexAIModelGarden(_BaseVertexAIModelGarden, BaseLLM): """Large language models served from Vertex AI Model Garden.""" - model_config = ConfigDict(populate_by_name=True,) + model_config = ConfigDict( + populate_by_name=True, + ) # Needed so that mypy doesn't flag missing aliased init args. def __init__(self, **kwargs: Any) -> None: @@ -138,7 +137,9 @@ class ChatAnthropicVertex(_VertexAICommon, BaseChatModel): stream_usage: bool = True # Whether to include usage metadata in streaming output credentials: Optional[Credentials] = None - model_config = ConfigDict(populate_by_name=True,) + model_config = ConfigDict( + populate_by_name=True, + ) # Needed so that mypy doesn't flag missing aliased init args. def __init__(self, **kwargs: Any) -> None: diff --git a/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py b/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py index 6f7bf55e..1e66e847 100644 --- a/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py +++ b/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py @@ -24,11 +24,9 @@ CallbackManagerForLLMRun, ) from langchain_core.language_models.llms import create_base_retry_decorator -from pydantic import root_validator, model_validator +from pydantic import ConfigDict, model_validator, root_validator from langchain_google_vertexai._base import _VertexAIBase -from pydantic import ConfigDict - def _get_token(credentials: Optional[Credentials] = None) -> str: @@ -103,7 +101,10 @@ class _BaseVertexMaasModelGarden(_VertexAIBase): model_family: Optional[VertexMaaSModelFamily] = None timeout: int = 120 - model_config = ConfigDict(populate_by_name=True,arbitrary_types_allowed=True,) + model_config = ConfigDict( + populate_by_name=True, + arbitrary_types_allowed=True, + ) def __init__(self, **kwargs): super().__init__(**kwargs) diff --git a/libs/vertexai/tests/integration_tests/test_chat_models.py b/libs/vertexai/tests/integration_tests/test_chat_models.py index b7148e6c..96a8766b 100644 --- a/libs/vertexai/tests/integration_tests/test_chat_models.py +++ b/libs/vertexai/tests/integration_tests/test_chat_models.py @@ -22,9 +22,9 @@ ) from langchain_core.outputs import ChatGeneration, LLMResult from langchain_core.prompts import ChatPromptTemplate -from pydantic import BaseModel from langchain_core.rate_limiters import InMemoryRateLimiter from langchain_core.tools import tool +from pydantic import BaseModel from langchain_google_vertexai import ( ChatVertexAI, diff --git a/libs/vertexai/tests/integration_tests/test_model_garden.py b/libs/vertexai/tests/integration_tests/test_model_garden.py index e4800431..a0946a6c 100644 --- a/libs/vertexai/tests/integration_tests/test_model_garden.py +++ b/libs/vertexai/tests/integration_tests/test_model_garden.py @@ -11,8 +11,8 @@ SystemMessage, ) from langchain_core.outputs import LLMResult -from pydantic import BaseModel from langchain_core.tools import tool +from pydantic import BaseModel from langchain_google_vertexai.model_garden import ( ChatAnthropicVertex, diff --git a/libs/vertexai/tests/unit_tests/test_embeddings.py b/libs/vertexai/tests/unit_tests/test_embeddings.py index 23f624c3..8088c757 100644 --- a/libs/vertexai/tests/unit_tests/test_embeddings.py +++ b/libs/vertexai/tests/unit_tests/test_embeddings.py @@ -2,12 +2,11 @@ from unittest.mock import MagicMock import pytest -from pydantic import root_validator, model_validator +from pydantic import model_validator, root_validator +from typing_extensions import Self from langchain_google_vertexai import VertexAIEmbeddings from langchain_google_vertexai.embeddings import GoogleEmbeddingModelType -from typing_extensions import Self - def test_langchain_google_vertexai_embed_image_multimodal_only() -> None: diff --git a/libs/vertexai/tests/unit_tests/test_function_utils.py b/libs/vertexai/tests/unit_tests/test_function_utils.py index 12140b93..4f912650 100644 --- a/libs/vertexai/tests/unit_tests/test_function_utils.py +++ b/libs/vertexai/tests/unit_tests/test_function_utils.py @@ -6,9 +6,9 @@ import google.cloud.aiplatform_v1beta1.types as gapic import pytest import vertexai.generative_models as vertexai # type: ignore -from pydantic import BaseModel, Field from langchain_core.tools import BaseTool, tool from langchain_core.utils.json_schema import dereference_refs +from pydantic import BaseModel, Field from langchain_google_vertexai.functions_utils import ( _format_base_tool_to_function_declaration, diff --git a/libs/vertexai/tests/unit_tests/test_llm.py b/libs/vertexai/tests/unit_tests/test_llm.py index 186954e4..2131a243 100644 --- a/libs/vertexai/tests/unit_tests/test_llm.py +++ b/libs/vertexai/tests/unit_tests/test_llm.py @@ -2,12 +2,11 @@ from unittest import TestCase from unittest.mock import MagicMock, patch -from pydantic import root_validator, model_validator +from pydantic import model_validator, root_validator +from typing_extensions import Self from langchain_google_vertexai._base import _BaseVertexAIModelGarden from langchain_google_vertexai.llms import VertexAI -from typing_extensions import Self - def test_model_name() -> None: From 9f7d7b82e484bded42389b7b01677381d1ac392c Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:17:14 -0400 Subject: [PATCH 08/32] clean up --- libs/vertexai/langchain_google_vertexai/chat_models.py | 8 ++++---- libs/vertexai/langchain_google_vertexai/llms.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/chat_models.py b/libs/vertexai/langchain_google_vertexai/chat_models.py index d2c181bb..abfa26ff 100644 --- a/libs/vertexai/langchain_google_vertexai/chat_models.py +++ b/libs/vertexai/langchain_google_vertexai/chat_models.py @@ -1044,8 +1044,8 @@ def get_lc_namespace(cls) -> List[str]: @model_validator(mode="after") def validate_environment(self) -> Self: """Validate that the python package exists in environment.""" - safety_settings = self.safety_settings or None - tuned_model_name = self.tuned_model_name or None + safety_settings = self.safety_settings + tuned_model_name = self.tuned_model_name self.model_family = GoogleModelFamily(self.model_name) if self.model_name == "chat-bison-default": @@ -1056,9 +1056,9 @@ def validate_environment(self) -> Self: ) self.model_name = "chat-bison" - if (self.full_model_name or None) is not None: + if self.full_model_name is not None: pass - elif (self.tuned_model_name or None) is not None: + elif self.tuned_model_name is not None: self.full_model_name = _format_model_name( self.tuned_model_name, location=self.location, diff --git a/libs/vertexai/langchain_google_vertexai/llms.py b/libs/vertexai/langchain_google_vertexai/llms.py index 9022d602..0cc7ac6a 100644 --- a/libs/vertexai/langchain_google_vertexai/llms.py +++ b/libs/vertexai/langchain_google_vertexai/llms.py @@ -137,7 +137,7 @@ def get_lc_namespace(cls) -> List[str]: @model_validator(mode="after") def validate_environment(self) -> Self: """Validate that the python package exists in environment.""" - tuned_model_name = self.tuned_model_name or None + tuned_model_name = self.tuned_model_name safety_settings = self.safety_settings self.model_family = GoogleModelFamily(self.model_name) is_gemini = is_gemini_model(self.model_family) From 52c1f61c6bd4fa23080db4b8da0b64dca8b5feb4 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:19:25 -0400 Subject: [PATCH 09/32] model_before_rewrite --- .../langchain_google_vertexai/llms.py | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/llms.py b/libs/vertexai/langchain_google_vertexai/llms.py index 0cc7ac6a..88b5648b 100644 --- a/libs/vertexai/langchain_google_vertexai/llms.py +++ b/libs/vertexai/langchain_google_vertexai/llms.py @@ -134,19 +134,19 @@ def get_lc_namespace(cls) -> List[str]: """Get the namespace of the langchain object.""" return ["langchain", "llms", "vertexai"] - @model_validator(mode="after") - def validate_environment(self) -> Self: + @root_validator(pre=False, skip_on_failure=True) + def validate_environment(cls, values: Dict) -> Dict: """Validate that the python package exists in environment.""" - tuned_model_name = self.tuned_model_name - safety_settings = self.safety_settings - self.model_family = GoogleModelFamily(self.model_name) - is_gemini = is_gemini_model(self.model_family) + tuned_model_name = values.get("tuned_model_name") + safety_settings = values["safety_settings"] + values["model_family"] = GoogleModelFamily(values["model_name"]) + is_gemini = is_gemini_model(values["model_family"]) cls._init_vertexai(values) if safety_settings and (not is_gemini or tuned_model_name): raise ValueError("Safety settings are only supported for Gemini models") - if self.model_family == GoogleModelFamily.CODEY: + if values["model_family"] == GoogleModelFamily.CODEY: model_cls = CodeGenerationModel preview_model_cls = PreviewCodeGenerationModel elif is_gemini: @@ -157,31 +157,31 @@ def validate_environment(self) -> Self: preview_model_cls = PreviewTextGenerationModel if tuned_model_name: - generative_model_name = self.tuned_model_name + generative_model_name = values["tuned_model_name"] else: - generative_model_name = self.model_name + generative_model_name = values["model_name"] if is_gemini: - self.client = model_cls( + values["client"] = model_cls( model_name=generative_model_name, safety_settings=safety_settings ) - self.client_preview = preview_model_cls( + values["client_preview"] = preview_model_cls( model_name=generative_model_name, safety_settings=safety_settings ) else: if tuned_model_name: - self.client = model_cls.get_tuned_model(generative_model_name) - self.client_preview = preview_model_cls.get_tuned_model( + values["client"] = model_cls.get_tuned_model(generative_model_name) + values["client_preview"] = preview_model_cls.get_tuned_model( generative_model_name ) else: - self.client = model_cls.from_pretrained(generative_model_name) - self.client_preview = preview_model_cls.from_pretrained( + values["client"] = model_cls.from_pretrained(generative_model_name) + values["client_preview"] = preview_model_cls.from_pretrained( generative_model_name ) - if self.streaming and self.n > 1: + if values["streaming"] and values["n"] > 1: raise ValueError("Only one candidate can be generated with streaming!") - return self + return values def _get_ls_params( self, stop: Optional[List[str]] = None, **kwargs: Any From 8a1cd84ed04050a3d9862fd38e72ebbc9a6deb5b Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:20:19 -0400 Subject: [PATCH 10/32] change VertexAI.validate_environment to pre --- libs/vertexai/langchain_google_vertexai/llms.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/llms.py b/libs/vertexai/langchain_google_vertexai/llms.py index 88b5648b..f8017a37 100644 --- a/libs/vertexai/langchain_google_vertexai/llms.py +++ b/libs/vertexai/langchain_google_vertexai/llms.py @@ -134,8 +134,9 @@ def get_lc_namespace(cls) -> List[str]: """Get the namespace of the langchain object.""" return ["langchain", "llms", "vertexai"] - @root_validator(pre=False, skip_on_failure=True) - def validate_environment(cls, values: Dict) -> Dict: + @model_validator(mode="before") + @classmethod + def validate_environment(cls, values: Dict) -> Any: """Validate that the python package exists in environment.""" tuned_model_name = values.get("tuned_model_name") safety_settings = values["safety_settings"] From 69c279e7879f31327c9bb032a4eadf96142370dd Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:23:00 -0400 Subject: [PATCH 11/32] lint --- libs/vertexai/Makefile | 1 - libs/vertexai/langchain_google_vertexai/_base.py | 2 +- libs/vertexai/langchain_google_vertexai/chat_models.py | 2 +- libs/vertexai/langchain_google_vertexai/embeddings.py | 2 +- libs/vertexai/langchain_google_vertexai/llms.py | 2 +- libs/vertexai/langchain_google_vertexai/model_garden.py | 2 +- .../langchain_google_vertexai/model_garden_maas/_base.py | 2 +- libs/vertexai/tests/unit_tests/test_embeddings.py | 2 +- libs/vertexai/tests/unit_tests/test_llm.py | 2 +- 9 files changed, 8 insertions(+), 9 deletions(-) diff --git a/libs/vertexai/Makefile b/libs/vertexai/Makefile index d86dffd2..72668097 100644 --- a/libs/vertexai/Makefile +++ b/libs/vertexai/Makefile @@ -33,7 +33,6 @@ lint_tests: PYTHON_FILES=tests lint_tests: MYPY_CACHE=.mypy_cache_test lint lint_diff lint_package lint_tests: - ./scripts/check_pydantic.sh . ./scripts/lint_imports.sh poetry run ruff check . poetry run ruff format $(PYTHON_FILES) --diff diff --git a/libs/vertexai/langchain_google_vertexai/_base.py b/libs/vertexai/langchain_google_vertexai/_base.py index ba857fc4..90a636ab 100644 --- a/libs/vertexai/langchain_google_vertexai/_base.py +++ b/libs/vertexai/langchain_google_vertexai/_base.py @@ -22,7 +22,7 @@ from google.protobuf import json_format from google.protobuf.struct_pb2 import Value from langchain_core.outputs import Generation, LLMResult -from pydantic import BaseModel, ConfigDict, Field, model_validator, root_validator +from pydantic import BaseModel, ConfigDict, Field, model_validator from typing_extensions import Self from vertexai.generative_models._generative_models import ( # type: ignore SafetySettingsType, diff --git a/libs/vertexai/langchain_google_vertexai/chat_models.py b/libs/vertexai/langchain_google_vertexai/chat_models.py index abfa26ff..bfeafc7a 100644 --- a/libs/vertexai/langchain_google_vertexai/chat_models.py +++ b/libs/vertexai/langchain_google_vertexai/chat_models.py @@ -62,7 +62,7 @@ ) from langchain_core.output_parsers.openai_tools import parse_tool_calls from langchain_core.outputs import ChatGeneration, ChatGenerationChunk, ChatResult -from pydantic import BaseModel, root_validator, Field, model_validator +from pydantic import BaseModel, Field, model_validator from langchain_core.runnables import Runnable, RunnablePassthrough, RunnableGenerator from langchain_core.utils.function_calling import convert_to_openai_tool from langchain_core.utils.pydantic import is_basemodel_subclass diff --git a/libs/vertexai/langchain_google_vertexai/embeddings.py b/libs/vertexai/langchain_google_vertexai/embeddings.py index a3f273fe..00b1d3cf 100644 --- a/libs/vertexai/langchain_google_vertexai/embeddings.py +++ b/libs/vertexai/langchain_google_vertexai/embeddings.py @@ -17,7 +17,7 @@ from google.cloud.aiplatform import telemetry from langchain_core.embeddings import Embeddings from langchain_core.language_models.llms import create_base_retry_decorator -from pydantic import model_validator, root_validator +from pydantic import model_validator from typing_extensions import Self from vertexai.language_models import ( # type: ignore TextEmbeddingInput, diff --git a/libs/vertexai/langchain_google_vertexai/llms.py b/libs/vertexai/langchain_google_vertexai/llms.py index f8017a37..a52a3079 100644 --- a/libs/vertexai/langchain_google_vertexai/llms.py +++ b/libs/vertexai/langchain_google_vertexai/llms.py @@ -9,7 +9,7 @@ ) from langchain_core.language_models.llms import BaseLLM, LangSmithParams from langchain_core.outputs import Generation, GenerationChunk, LLMResult -from pydantic import ConfigDict, Field, model_validator, root_validator +from pydantic import ConfigDict, Field, model_validator from typing_extensions import Self from vertexai.generative_models import ( # type: ignore[import-untyped] Candidate, diff --git a/libs/vertexai/langchain_google_vertexai/model_garden.py b/libs/vertexai/langchain_google_vertexai/model_garden.py index deeab3e1..ad982c81 100644 --- a/libs/vertexai/langchain_google_vertexai/model_garden.py +++ b/libs/vertexai/langchain_google_vertexai/model_garden.py @@ -45,7 +45,7 @@ RunnablePassthrough, ) from langchain_core.tools import BaseTool -from pydantic import BaseModel, ConfigDict, Field, model_validator, root_validator +from pydantic import BaseModel, ConfigDict, Field, model_validator from typing_extensions import Self from langchain_google_vertexai._anthropic_parsers import ( diff --git a/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py b/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py index 1e66e847..94fbf6cf 100644 --- a/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py +++ b/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py @@ -24,7 +24,7 @@ CallbackManagerForLLMRun, ) from langchain_core.language_models.llms import create_base_retry_decorator -from pydantic import ConfigDict, model_validator, root_validator +from pydantic import ConfigDict, model_validator from langchain_google_vertexai._base import _VertexAIBase diff --git a/libs/vertexai/tests/unit_tests/test_embeddings.py b/libs/vertexai/tests/unit_tests/test_embeddings.py index 8088c757..e1b3ceb8 100644 --- a/libs/vertexai/tests/unit_tests/test_embeddings.py +++ b/libs/vertexai/tests/unit_tests/test_embeddings.py @@ -2,7 +2,7 @@ from unittest.mock import MagicMock import pytest -from pydantic import model_validator, root_validator +from pydantic import model_validator from typing_extensions import Self from langchain_google_vertexai import VertexAIEmbeddings diff --git a/libs/vertexai/tests/unit_tests/test_llm.py b/libs/vertexai/tests/unit_tests/test_llm.py index 2131a243..ac6afdba 100644 --- a/libs/vertexai/tests/unit_tests/test_llm.py +++ b/libs/vertexai/tests/unit_tests/test_llm.py @@ -2,7 +2,7 @@ from unittest import TestCase from unittest.mock import MagicMock, patch -from pydantic import model_validator, root_validator +from pydantic import model_validator from typing_extensions import Self from langchain_google_vertexai._base import _BaseVertexAIModelGarden From a1105a3d4ff3b771b81c21c09dc572a389986379 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:26:10 -0400 Subject: [PATCH 12/32] update chat and embeddings validation to pre --- .../langchain_google_vertexai/chat_models.py | 52 +++++++++---------- .../langchain_google_vertexai/embeddings.py | 20 ++++--- .../langchain_google_vertexai/gemma.py | 7 +-- .../langchain_google_vertexai/llms.py | 1 - 4 files changed, 42 insertions(+), 38 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/chat_models.py b/libs/vertexai/langchain_google_vertexai/chat_models.py index bfeafc7a..9539e68e 100644 --- a/libs/vertexai/langchain_google_vertexai/chat_models.py +++ b/libs/vertexai/langchain_google_vertexai/chat_models.py @@ -125,7 +125,6 @@ _ToolType, ) from pydantic import ConfigDict -from typing_extensions import Self logger = logging.getLogger(__name__) @@ -1041,57 +1040,58 @@ def get_lc_namespace(cls) -> List[str]: """Get the namespace of the langchain object.""" return ["langchain", "chat_models", "vertexai"] - @model_validator(mode="after") - def validate_environment(self) -> Self: + @model_validator(mode="before") + @classmethod + def validate_environment(cls, values: Dict) -> Any: """Validate that the python package exists in environment.""" - safety_settings = self.safety_settings - tuned_model_name = self.tuned_model_name - self.model_family = GoogleModelFamily(self.model_name) + safety_settings = values.get("safety_settings") + tuned_model_name = values.get("tuned_model_name") + values["model_family"] = GoogleModelFamily(values["model_name"]) - if self.model_name == "chat-bison-default": + if values["model_name"] == "chat-bison-default": logger.warning( "Model_name will become a required arg for VertexAIEmbeddings " "starting from Sep-01-2024. Currently the default is set to " "chat-bison" ) - self.model_name = "chat-bison" + values["model_name"] = "chat-bison" - if self.full_model_name is not None: + if values.get("full_model_name") is not None: pass - elif self.tuned_model_name is not None: - self.full_model_name = _format_model_name( - self.tuned_model_name, - location=self.location, - project=self.project, + elif values.get("tuned_model_name") is not None: + values["full_model_name"] = _format_model_name( + values["tuned_model_name"], + location=values["location"], + project=values["project"], ) else: - self.full_model_name = _format_model_name( - self.model_name, - location=self.location, - project=self.project, + values["full_model_name"] = _format_model_name( + values["model_name"], + location=values["location"], + project=values["project"], ) - if safety_settings and not is_gemini_model(self.model_family): + if safety_settings and not is_gemini_model(values["model_family"]): raise ValueError("Safety settings are only supported for Gemini models") if tuned_model_name: - generative_model_name = self.tuned_model_name + generative_model_name = values["tuned_model_name"] else: - generative_model_name = self.model_name + generative_model_name = values["model_name"] - if not is_gemini_model(self.model_family): + if not is_gemini_model(values["model_family"]): cls._init_vertexai(values) - if self.model_family == GoogleModelFamily.CODEY: + if values["model_family"] == GoogleModelFamily.CODEY: model_cls = CodeChatModel model_cls_preview = PreviewCodeChatModel else: model_cls = ChatModel model_cls_preview = PreviewChatModel - self.client = model_cls.from_pretrained(generative_model_name) - self.client_preview = model_cls_preview.from_pretrained( + values["client"] = model_cls.from_pretrained(generative_model_name) + values["client_preview"] = model_cls_preview.from_pretrained( generative_model_name ) - return self + return values @property def _is_gemini_advanced(self) -> bool: diff --git a/libs/vertexai/langchain_google_vertexai/embeddings.py b/libs/vertexai/langchain_google_vertexai/embeddings.py index 00b1d3cf..b381d99e 100644 --- a/libs/vertexai/langchain_google_vertexai/embeddings.py +++ b/libs/vertexai/langchain_google_vertexai/embeddings.py @@ -18,7 +18,6 @@ from langchain_core.embeddings import Embeddings from langchain_core.language_models.llms import create_base_retry_decorator from pydantic import model_validator -from typing_extensions import Self from vertexai.language_models import ( # type: ignore TextEmbeddingInput, TextEmbeddingModel, @@ -101,20 +100,25 @@ class VertexAIEmbeddings(_VertexAICommon, Embeddings): # Instance context instance: Dict[str, Any] = {} #: :meta private: - @model_validator(mode="after") - def validate_environment(self) -> Self: + @model_validator(mode="before") + @classmethod + def validate_environment(cls, values: Dict) -> Any: """Validates that the python package exists in environment.""" cls._init_vertexai(values) - _, user_agent = get_user_agent(f"{cls.__name__}_{self.model_name}") # type: ignore + _, user_agent = get_user_agent(f"{cls.__name__}_{values['model_name']}") # type: ignore with telemetry.tool_context_manager(user_agent): if ( - GoogleEmbeddingModelType(self.model_name) + GoogleEmbeddingModelType(values["model_name"]) == GoogleEmbeddingModelType.MULTIMODAL ): - self.client = MultiModalEmbeddingModel.from_pretrained(self.model_name) + values["client"] = MultiModalEmbeddingModel.from_pretrained( + values["model_name"] + ) else: - self.client = TextEmbeddingModel.from_pretrained(self.model_name) - return self + values["client"] = TextEmbeddingModel.from_pretrained( + values["model_name"] + ) + return values def __init__( self, diff --git a/libs/vertexai/langchain_google_vertexai/gemma.py b/libs/vertexai/langchain_google_vertexai/gemma.py index 0e06a399..6f3dea03 100644 --- a/libs/vertexai/langchain_google_vertexai/gemma.py +++ b/libs/vertexai/langchain_google_vertexai/gemma.py @@ -21,7 +21,7 @@ Generation, LLMResult, ) -from pydantic import BaseModel, ConfigDict, Field, model_validator, root_validator +from pydantic import BaseModel, ConfigDict, Field, model_validator from typing_extensions import Self from langchain_google_vertexai._base import _BaseVertexAIModelGarden @@ -316,8 +316,9 @@ class _GemmaLocalHFBase(_GemmaBase): populate_by_name=True, ) - @root_validator() - def validate_environment(cls, values: Dict) -> Dict: + @model_validator(mode="before") + @classmethod + def validate_environment(cls, values: Dict) -> Any: """Validate that llama-cpp-python library is installed.""" try: from transformers import AutoTokenizer, GemmaForCausalLM # type: ignore diff --git a/libs/vertexai/langchain_google_vertexai/llms.py b/libs/vertexai/langchain_google_vertexai/llms.py index a52a3079..e88a3847 100644 --- a/libs/vertexai/langchain_google_vertexai/llms.py +++ b/libs/vertexai/langchain_google_vertexai/llms.py @@ -10,7 +10,6 @@ from langchain_core.language_models.llms import BaseLLM, LangSmithParams from langchain_core.outputs import Generation, GenerationChunk, LLMResult from pydantic import ConfigDict, Field, model_validator -from typing_extensions import Self from vertexai.generative_models import ( # type: ignore[import-untyped] Candidate, GenerativeModel, From 574a51be110a97a61f10e4db97c6fe52aeb0fe99 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:37:24 -0400 Subject: [PATCH 13/32] update some features to pydantic 2 --- libs/vertexai/langchain_google_vertexai/_base.py | 2 +- libs/vertexai/tests/unit_tests/test_function_utils.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/_base.py b/libs/vertexai/langchain_google_vertexai/_base.py index 90a636ab..7b260ec5 100644 --- a/libs/vertexai/langchain_google_vertexai/_base.py +++ b/libs/vertexai/langchain_google_vertexai/_base.py @@ -109,7 +109,7 @@ def validate_params_base(cls, values: dict) -> Any: if values.get("api_endpoint"): api_endpoint = values["api_endpoint"] else: - location = values.get("location", cls.__fields__["location"].default) + location = values.get("location", cls.model_fields["location"].default) api_endpoint = f"{location}-{constants.PREDICTION_API_BASE_PATH}" client_options = ClientOptions(api_endpoint=api_endpoint) if values.get("client_cert_source"): diff --git a/libs/vertexai/tests/unit_tests/test_function_utils.py b/libs/vertexai/tests/unit_tests/test_function_utils.py index 4f912650..2e6f1f7c 100644 --- a/libs/vertexai/tests/unit_tests/test_function_utils.py +++ b/libs/vertexai/tests/unit_tests/test_function_utils.py @@ -39,13 +39,13 @@ class A(BaseModel): class B(BaseModel): object_field: Optional[A] = Field(description="Class A") array_field: Sequence[A] - int_field: int = Field(description="int field", minimum=1, maximum=10) + int_field: int = Field(description="int field", ge=1, le=10) str_field: str = Field( - min_length=1, max_length=10, pattern="^[A-Z]{1,10}$", example="ABCD" + min_length=1, max_length=10, pattern="^[A-Z]{1,10}$", examples=["ABCD"] ) str_enum_field: StringEnum - schema = B.schema() + schema = B.model_json_schema() result = _format_json_schema_to_gapic(dereference_refs(schema)) expected = { From 6b8171dc890c66e851d39887309e37c79864c0ba Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:42:08 -0400 Subject: [PATCH 14/32] remove unused type ignores --- libs/vertexai/langchain_google_vertexai/embeddings.py | 2 +- libs/vertexai/langchain_google_vertexai/gemma.py | 8 ++++---- .../langchain_google_vertexai/model_garden_maas/llama.py | 2 +- libs/vertexai/tests/integration_tests/test_chat_models.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/embeddings.py b/libs/vertexai/langchain_google_vertexai/embeddings.py index b381d99e..ddcd6375 100644 --- a/libs/vertexai/langchain_google_vertexai/embeddings.py +++ b/libs/vertexai/langchain_google_vertexai/embeddings.py @@ -105,7 +105,7 @@ class VertexAIEmbeddings(_VertexAICommon, Embeddings): def validate_environment(cls, values: Dict) -> Any: """Validates that the python package exists in environment.""" cls._init_vertexai(values) - _, user_agent = get_user_agent(f"{cls.__name__}_{values['model_name']}") # type: ignore + _, user_agent = get_user_agent(f"{cls.__name__}_{values['model_name']}") with telemetry.tool_context_manager(user_agent): if ( GoogleEmbeddingModelType(values["model_name"]) diff --git a/libs/vertexai/langchain_google_vertexai/gemma.py b/libs/vertexai/langchain_google_vertexai/gemma.py index 6f3dea03..3961e1af 100644 --- a/libs/vertexai/langchain_google_vertexai/gemma.py +++ b/libs/vertexai/langchain_google_vertexai/gemma.py @@ -238,7 +238,7 @@ def _get_params(self, **kwargs) -> Dict[str, Any]: return {**self._default_params, **params} -class GemmaLocalKaggle(_GemmaLocalKaggleBase, BaseLLM): # type: ignore +class GemmaLocalKaggle(_GemmaLocalKaggleBase, BaseLLM): """Local gemma chat model loaded from Kaggle.""" def __init__(self, *, model_name: Optional[str] = None, **kwargs: Any) -> None: @@ -268,7 +268,7 @@ def _llm_type(self) -> str: return "gemma_local_kaggle" -class GemmaChatLocalKaggle(_GemmaLocalKaggleBase, BaseChatModel): # type: ignore +class GemmaChatLocalKaggle(_GemmaLocalKaggleBase, BaseChatModel): parse_response: bool = False """Whether to post-process the chat response and clean repeations """ """or multi-turn statements.""" @@ -359,7 +359,7 @@ def _run(self, prompt: str, **kwargs: Any) -> str: )[0] -class GemmaLocalHF(_GemmaLocalHFBase, BaseLLM): # type: ignore +class GemmaLocalHF(_GemmaLocalHFBase, BaseLLM): """Local gemma model loaded from HuggingFace.""" def _generate( @@ -381,7 +381,7 @@ def _llm_type(self) -> str: return "gemma_local_hf" -class GemmaChatLocalHF(_GemmaLocalHFBase, BaseChatModel): # type: ignore +class GemmaChatLocalHF(_GemmaLocalHFBase, BaseChatModel): parse_response: bool = False """Whether to post-process the chat response and clean repeations """ """or multi-turn statements.""" diff --git a/libs/vertexai/langchain_google_vertexai/model_garden_maas/llama.py b/libs/vertexai/langchain_google_vertexai/model_garden_maas/llama.py index d80c4dd7..ebfdeaaa 100644 --- a/libs/vertexai/langchain_google_vertexai/model_garden_maas/llama.py +++ b/libs/vertexai/langchain_google_vertexai/model_garden_maas/llama.py @@ -114,7 +114,7 @@ def _parse_response_candidate_llama( ) -class VertexModelGardenLlama(_BaseVertexMaasModelGarden, BaseChatModel): # type: ignore[misc] +class VertexModelGardenLlama(_BaseVertexMaasModelGarden, BaseChatModel): """Integration for Llama 3.1 on Google Cloud Vertex AI Model-as-a-Service. For more information, see: diff --git a/libs/vertexai/tests/integration_tests/test_chat_models.py b/libs/vertexai/tests/integration_tests/test_chat_models.py index 96a8766b..b511cddb 100644 --- a/libs/vertexai/tests/integration_tests/test_chat_models.py +++ b/libs/vertexai/tests/integration_tests/test_chat_models.py @@ -302,7 +302,7 @@ def get_climate_info(query: str): prompt=prompt_template, ) agent_executor = agents.AgentExecutor( # type: ignore[call-arg] - agent=agent, # type: ignore[arg-type] + agent=agent, tools=tools, # type: ignore[arg-type] verbose=False, stream_runnable=False, From bfed90d1d13b5e0e8b662df436475178ccbc45e2 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:53:47 -0400 Subject: [PATCH 15/32] fix validate_environment in llm and chat models --- .../langchain_google_vertexai/chat_models.py | 64 +++++++++++-------- .../langchain_google_vertexai/llms.py | 46 +++++++------ 2 files changed, 63 insertions(+), 47 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/chat_models.py b/libs/vertexai/langchain_google_vertexai/chat_models.py index 9539e68e..ef325fca 100644 --- a/libs/vertexai/langchain_google_vertexai/chat_models.py +++ b/libs/vertexai/langchain_google_vertexai/chat_models.py @@ -125,6 +125,7 @@ _ToolType, ) from pydantic import ConfigDict +from typing_extensions import Self logger = logging.getLogger(__name__) @@ -1040,58 +1041,65 @@ def get_lc_namespace(cls) -> List[str]: """Get the namespace of the langchain object.""" return ["langchain", "chat_models", "vertexai"] - @model_validator(mode="before") - @classmethod - def validate_environment(cls, values: Dict) -> Any: + @model_validator(mode="after") + def validate_environment(self) -> Self: """Validate that the python package exists in environment.""" - safety_settings = values.get("safety_settings") - tuned_model_name = values.get("tuned_model_name") - values["model_family"] = GoogleModelFamily(values["model_name"]) + safety_settings = self.safety_settings + tuned_model_name = self.tuned_model_name + self.model_family = GoogleModelFamily(self.model_name) - if values["model_name"] == "chat-bison-default": + if self.model_name == "chat-bison-default": logger.warning( "Model_name will become a required arg for VertexAIEmbeddings " "starting from Sep-01-2024. Currently the default is set to " "chat-bison" ) - values["model_name"] = "chat-bison" + self.model_name = "chat-bison" - if values.get("full_model_name") is not None: + if self.full_model_name is not None: pass - elif values.get("tuned_model_name") is not None: - values["full_model_name"] = _format_model_name( - values["tuned_model_name"], - location=values["location"], - project=values["project"], + elif self.tuned_model_name is not None: + self.full_model_name = _format_model_name( + self.tuned_model_name, + location=self.location, + project=cast(str, self.project), ) else: - values["full_model_name"] = _format_model_name( - values["model_name"], - location=values["location"], - project=values["project"], + self.full_model_name = _format_model_name( + self.model_name, + location=self.location, + project=cast(str, self.project), ) - if safety_settings and not is_gemini_model(values["model_family"]): + if safety_settings and not is_gemini_model(self.model_family): raise ValueError("Safety settings are only supported for Gemini models") if tuned_model_name: - generative_model_name = values["tuned_model_name"] + generative_model_name = self.tuned_model_name else: - generative_model_name = values["model_name"] - - if not is_gemini_model(values["model_family"]): - cls._init_vertexai(values) - if values["model_family"] == GoogleModelFamily.CODEY: + generative_model_name = self.model_name + + if not is_gemini_model(self.model_family): + values = { + "project": self.project, + "location": self.location, + "credentials": self.credentials, + "api_transport": self.api_transport, + "api_endpoint": self.api_endpoint, + "default_metadata": self.default_metadata, + } + self._init_vertexai(values) + if self.model_family == GoogleModelFamily.CODEY: model_cls = CodeChatModel model_cls_preview = PreviewCodeChatModel else: model_cls = ChatModel model_cls_preview = PreviewChatModel - values["client"] = model_cls.from_pretrained(generative_model_name) - values["client_preview"] = model_cls_preview.from_pretrained( + self.client = model_cls.from_pretrained(generative_model_name) + self.client_preview = model_cls_preview.from_pretrained( generative_model_name ) - return values + return self @property def _is_gemini_advanced(self) -> bool: diff --git a/libs/vertexai/langchain_google_vertexai/llms.py b/libs/vertexai/langchain_google_vertexai/llms.py index e88a3847..303169fb 100644 --- a/libs/vertexai/langchain_google_vertexai/llms.py +++ b/libs/vertexai/langchain_google_vertexai/llms.py @@ -10,6 +10,7 @@ from langchain_core.language_models.llms import BaseLLM, LangSmithParams from langchain_core.outputs import Generation, GenerationChunk, LLMResult from pydantic import ConfigDict, Field, model_validator +from typing_extensions import Self from vertexai.generative_models import ( # type: ignore[import-untyped] Candidate, GenerativeModel, @@ -133,20 +134,27 @@ def get_lc_namespace(cls) -> List[str]: """Get the namespace of the langchain object.""" return ["langchain", "llms", "vertexai"] - @model_validator(mode="before") - @classmethod - def validate_environment(cls, values: Dict) -> Any: + @model_validator(mode="after") + def validate_environment(self) -> Self: """Validate that the python package exists in environment.""" - tuned_model_name = values.get("tuned_model_name") - safety_settings = values["safety_settings"] - values["model_family"] = GoogleModelFamily(values["model_name"]) - is_gemini = is_gemini_model(values["model_family"]) - cls._init_vertexai(values) + tuned_model_name = self.tuned_model_name or None + safety_settings = self.safety_settings + self.model_family = GoogleModelFamily(self.model_name) + is_gemini = is_gemini_model(self.model_family) + values = { + "project": self.project, + "location": self.location, + "credentials": self.credentials, + "api_transport": self.api_transport, + "api_endpoint": self.api_endpoint, + "default_metadata": self.default_metadata, + } + self._init_vertexai(values) if safety_settings and (not is_gemini or tuned_model_name): raise ValueError("Safety settings are only supported for Gemini models") - if values["model_family"] == GoogleModelFamily.CODEY: + if self.model_family == GoogleModelFamily.CODEY: model_cls = CodeGenerationModel preview_model_cls = PreviewCodeGenerationModel elif is_gemini: @@ -157,31 +165,31 @@ def validate_environment(cls, values: Dict) -> Any: preview_model_cls = PreviewTextGenerationModel if tuned_model_name: - generative_model_name = values["tuned_model_name"] + generative_model_name = self.tuned_model_name else: - generative_model_name = values["model_name"] + generative_model_name = self.model_name if is_gemini: - values["client"] = model_cls( + self.client = model_cls( model_name=generative_model_name, safety_settings=safety_settings ) - values["client_preview"] = preview_model_cls( + self.client_preview = preview_model_cls( model_name=generative_model_name, safety_settings=safety_settings ) else: if tuned_model_name: - values["client"] = model_cls.get_tuned_model(generative_model_name) - values["client_preview"] = preview_model_cls.get_tuned_model( + self.client = model_cls.get_tuned_model(generative_model_name) + self.client_preview = preview_model_cls.get_tuned_model( generative_model_name ) else: - values["client"] = model_cls.from_pretrained(generative_model_name) - values["client_preview"] = preview_model_cls.from_pretrained( + self.client = model_cls.from_pretrained(generative_model_name) + self.client_preview = preview_model_cls.from_pretrained( generative_model_name ) - if values["streaming"] and values["n"] > 1: + if self.streaming and self.n > 1: raise ValueError("Only one candidate can be generated with streaming!") - return values + return self def _get_ls_params( self, stop: Optional[List[str]] = None, **kwargs: Any From f282bfe7c4b37956e9f8261ad40bbc8f1ed48229 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 11:58:41 -0400 Subject: [PATCH 16/32] more validation updates --- .../langchain_google_vertexai/embeddings.py | 30 +++++++++++-------- .../langchain_google_vertexai/gemma.py | 19 ++++++------ 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/embeddings.py b/libs/vertexai/langchain_google_vertexai/embeddings.py index ddcd6375..44b9156f 100644 --- a/libs/vertexai/langchain_google_vertexai/embeddings.py +++ b/libs/vertexai/langchain_google_vertexai/embeddings.py @@ -18,6 +18,7 @@ from langchain_core.embeddings import Embeddings from langchain_core.language_models.llms import create_base_retry_decorator from pydantic import model_validator +from typing_extensions import Self from vertexai.language_models import ( # type: ignore TextEmbeddingInput, TextEmbeddingModel, @@ -100,25 +101,28 @@ class VertexAIEmbeddings(_VertexAICommon, Embeddings): # Instance context instance: Dict[str, Any] = {} #: :meta private: - @model_validator(mode="before") - @classmethod - def validate_environment(cls, values: Dict) -> Any: + @model_validator(mode="after") + def validate_environment(self) -> Self: """Validates that the python package exists in environment.""" - cls._init_vertexai(values) - _, user_agent = get_user_agent(f"{cls.__name__}_{values['model_name']}") + values = { + "project": self.project, + "location": self.location, + "credentials": self.credentials, + "api_transport": self.api_transport, + "api_endpoint": self.api_endpoint, + "default_metadata": self.default_metadata, + } + self._init_vertexai(values) + _, user_agent = get_user_agent(f"{self.__name__}_{self.model_name}") # type: ignore with telemetry.tool_context_manager(user_agent): if ( - GoogleEmbeddingModelType(values["model_name"]) + GoogleEmbeddingModelType(self.model_name) == GoogleEmbeddingModelType.MULTIMODAL ): - values["client"] = MultiModalEmbeddingModel.from_pretrained( - values["model_name"] - ) + self.client = MultiModalEmbeddingModel.from_pretrained(self.model_name) else: - values["client"] = TextEmbeddingModel.from_pretrained( - values["model_name"] - ) - return values + self.client = TextEmbeddingModel.from_pretrained(self.model_name) + return self def __init__( self, diff --git a/libs/vertexai/langchain_google_vertexai/gemma.py b/libs/vertexai/langchain_google_vertexai/gemma.py index 3961e1af..57196644 100644 --- a/libs/vertexai/langchain_google_vertexai/gemma.py +++ b/libs/vertexai/langchain_google_vertexai/gemma.py @@ -316,9 +316,8 @@ class _GemmaLocalHFBase(_GemmaBase): populate_by_name=True, ) - @model_validator(mode="before") - @classmethod - def validate_environment(cls, values: Dict) -> Any: + @model_validator(mode="after") + def validate_environment(self) -> Self: """Validate that llama-cpp-python library is installed.""" try: from transformers import AutoTokenizer, GemmaForCausalLM # type: ignore @@ -329,15 +328,15 @@ def validate_environment(cls, values: Dict) -> Any: "use this model: pip install transformers>=4.38.1" ) - values["tokenizer"] = AutoTokenizer.from_pretrained( - values["model_name"], token=values["hf_access_token"] + self.tokenizer = AutoTokenizer.from_pretrained( + self.model_name, token=self.hf_access_token ) - values["client"] = GemmaForCausalLM.from_pretrained( - values["model_name"], - token=values["hf_access_token"], - cache_dir=values["cache_dir"], + self.client = GemmaForCausalLM.from_pretrained( + self.model_name, + token=self.hf_access_token, + cache_dir=self.cache_dir, ) - return values + return self @property def _default_params(self) -> Dict[str, Any]: From 0188eefac31255f0ce947b2309fe2f263e119fe3 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 12:23:08 -0400 Subject: [PATCH 17/32] change maas model garden validation to post --- .../model_garden_maas/_base.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py b/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py index 94fbf6cf..9129f2af 100644 --- a/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py +++ b/libs/vertexai/langchain_google_vertexai/model_garden_maas/_base.py @@ -25,6 +25,7 @@ ) from langchain_core.language_models.llms import create_base_retry_decorator from pydantic import ConfigDict, model_validator +from typing_extensions import Self from langchain_google_vertexai._base import _VertexAIBase @@ -128,17 +129,16 @@ def __init__(self, **kwargs): timeout=self.timeout, ) - @model_validator(mode="before") - @classmethod - def validate_environment_model_garden(cls, values: Dict) -> Any: + @model_validator(mode="after") + def validate_environment_model_garden(self) -> Self: """Validate that the python package exists in environment.""" - family = VertexMaaSModelFamily(values["model_name"]) - values["model_family"] = family + family = VertexMaaSModelFamily(self.model_name) + self.model_family = family if family == VertexMaaSModelFamily.MISTRAL: - model = values["model_name"].split("@")[0] - values["full_model_name"] = values["model_name"] - values["model_name"] = model - return values + model = self.model_name.split("@")[0] if self.model_name else None + self.full_model_name = self.model_name + self.model_name = model + return self def _enrich_params(self, params: Dict[str, Any]) -> Dict[str, Any]: """Fix params to be compliant with Vertex AI.""" From a0d9d0b1687e6b601f95acbddcaf159ef59e04d7 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 13:01:59 -0400 Subject: [PATCH 18/32] add protected namespaces to embeddings --- libs/vertexai/langchain_google_vertexai/embeddings.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libs/vertexai/langchain_google_vertexai/embeddings.py b/libs/vertexai/langchain_google_vertexai/embeddings.py index 44b9156f..6b78ef33 100644 --- a/libs/vertexai/langchain_google_vertexai/embeddings.py +++ b/libs/vertexai/langchain_google_vertexai/embeddings.py @@ -17,7 +17,7 @@ from google.cloud.aiplatform import telemetry from langchain_core.embeddings import Embeddings from langchain_core.language_models.llms import create_base_retry_decorator -from pydantic import model_validator +from pydantic import ConfigDict, model_validator from typing_extensions import Self from vertexai.language_models import ( # type: ignore TextEmbeddingInput, @@ -101,6 +101,11 @@ class VertexAIEmbeddings(_VertexAICommon, Embeddings): # Instance context instance: Dict[str, Any] = {} #: :meta private: + model_config = ConfigDict( + extra="forbid", + protected_namespaces=(), + ) + @model_validator(mode="after") def validate_environment(self) -> Self: """Validates that the python package exists in environment.""" From ddf04c3f69d03c1802339a456ac2709c86def050 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 13:06:55 -0400 Subject: [PATCH 19/32] fix embeddings init --- libs/vertexai/langchain_google_vertexai/embeddings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/vertexai/langchain_google_vertexai/embeddings.py b/libs/vertexai/langchain_google_vertexai/embeddings.py index 6b78ef33..8700c204 100644 --- a/libs/vertexai/langchain_google_vertexai/embeddings.py +++ b/libs/vertexai/langchain_google_vertexai/embeddings.py @@ -118,7 +118,7 @@ def validate_environment(self) -> Self: "default_metadata": self.default_metadata, } self._init_vertexai(values) - _, user_agent = get_user_agent(f"{self.__name__}_{self.model_name}") # type: ignore + _, user_agent = get_user_agent(f"{self.__class__.__name__}_{self.model_name}") with telemetry.tool_context_manager(user_agent): if ( GoogleEmbeddingModelType(self.model_name) From 973a3048b616f131f1b7614054e645b7ce29a566 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 5 Sep 2024 13:16:15 -0400 Subject: [PATCH 20/32] update docstrings --- libs/vertexai/langchain_google_vertexai/chains.py | 2 +- libs/vertexai/langchain_google_vertexai/chat_models.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/chains.py b/libs/vertexai/langchain_google_vertexai/chains.py index 02465763..7394a2a4 100644 --- a/libs/vertexai/langchain_google_vertexai/chains.py +++ b/libs/vertexai/langchain_google_vertexai/chains.py @@ -111,7 +111,7 @@ def create_structured_runnable( from langchain_google_vertexai import ChatVertexAI, create_structured_runnable from langchain_core.prompts import ChatPromptTemplate - from langchain_core.pydantic_v1 import BaseModel, Field + from pydantic import BaseModel, Field class RecordPerson(BaseModel): diff --git a/libs/vertexai/langchain_google_vertexai/chat_models.py b/libs/vertexai/langchain_google_vertexai/chat_models.py index ef325fca..fba782ce 100644 --- a/libs/vertexai/langchain_google_vertexai/chat_models.py +++ b/libs/vertexai/langchain_google_vertexai/chat_models.py @@ -765,7 +765,7 @@ class ChatVertexAI(_VertexAICommon, BaseChatModel): Tool calling: .. code-block:: python - from langchain_core.pydantic_v1 import BaseModel, Field + from pydantic import BaseModel, Field class GetWeather(BaseModel): '''Get the current weather in a given location''' @@ -803,7 +803,7 @@ class GetPopulation(BaseModel): from typing import Optional - from langchain_core.pydantic_v1 import BaseModel, Field + from pydantic import BaseModel, Field class Joke(BaseModel): '''Joke to tell user.''' @@ -1657,7 +1657,7 @@ def with_structured_output( Example: Pydantic schema, exclude raw: .. code-block:: python - from langchain_core.pydantic_v1 import BaseModel + from pydantic import BaseModel from langchain_google_vertexai import ChatVertexAI class AnswerWithJustification(BaseModel): @@ -1676,7 +1676,7 @@ class AnswerWithJustification(BaseModel): Example: Pydantic schema, include raw: .. code-block:: python - from langchain_core.pydantic_v1 import BaseModel + from pydantic import BaseModel from langchain_google_vertexai import ChatVertexAI class AnswerWithJustification(BaseModel): @@ -1697,7 +1697,7 @@ class AnswerWithJustification(BaseModel): Example: Dict schema, exclude raw: .. code-block:: python - from langchain_core.pydantic_v1 import BaseModel + from pydantic import BaseModel from langchain_core.utils.function_calling import convert_to_openai_function from langchain_google_vertexai import ChatVertexAI From 9a0a6b7a330e0e9a55e13cee92c576bdda8d97a2 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Sun, 8 Sep 2024 10:03:48 -0400 Subject: [PATCH 21/32] update _format_json_schema_to_gapic --- .../functions_utils.py | 26 +++++++++++--- .../tests/unit_tests/test_function_utils.py | 34 ++++++++++++++++--- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/functions_utils.py b/libs/vertexai/langchain_google_vertexai/functions_utils.py index 69e09e55..8d968b43 100644 --- a/libs/vertexai/langchain_google_vertexai/functions_utils.py +++ b/libs/vertexai/langchain_google_vertexai/functions_utils.py @@ -69,19 +69,25 @@ class _ToolDictLike(TypedDict): _ALLOWED_SCHEMA_FIELDS_SET = set(_ALLOWED_SCHEMA_FIELDS) -def _format_json_schema_to_gapic(schema: Dict[str, Any]) -> Dict[str, Any]: +def _format_json_schema_to_gapic( + schema: Dict[str, Any], + parent_key: Optional[str] = None, + required_fields: Optional[list] = None, +) -> Dict[str, Any]: converted_schema: Dict[str, Any] = {} for key, value in schema.items(): if key == "definitions": continue elif key == "items": - converted_schema["items"] = _format_json_schema_to_gapic(value) + converted_schema["items"] = _format_json_schema_to_gapic( + value, parent_key, required_fields + ) elif key == "properties": if "properties" not in converted_schema: converted_schema["properties"] = {} for pkey, pvalue in value.items(): converted_schema["properties"][pkey] = _format_json_schema_to_gapic( - pvalue + pvalue, pkey, schema.get("required", []) ) continue elif key in ["type", "_type"]: @@ -92,7 +98,19 @@ def _format_json_schema_to_gapic(schema: Dict[str, Any]) -> Dict[str, Any]: "Only first value for 'allOf' key is supported. " f"Got {len(value)}, ignoring other than first value!" ) - return _format_json_schema_to_gapic(value[0]) + return _format_json_schema_to_gapic(value[0], parent_key, required_fields) + elif key == "anyOf": + if len(value) == 2 and any(v.get("type") == "null" for v in value): + non_null_type = next(v for v in value if v.get("type") != "null") + converted_schema.update( + _format_json_schema_to_gapic( + non_null_type, parent_key, required_fields + ) + ) + # Remove the field from required if it exists + if required_fields and parent_key in required_fields: + required_fields.remove(parent_key) + continue elif key not in _ALLOWED_SCHEMA_FIELDS_SET: logger.warning(f"Key '{key}' is not supported in schema, ignoring") else: diff --git a/libs/vertexai/tests/unit_tests/test_function_utils.py b/libs/vertexai/tests/unit_tests/test_function_utils.py index 2e6f1f7c..461823df 100644 --- a/libs/vertexai/tests/unit_tests/test_function_utils.py +++ b/libs/vertexai/tests/unit_tests/test_function_utils.py @@ -27,6 +27,28 @@ def test_format_json_schema_to_gapic(): + # Simple case + class RecordPerson(BaseModel): + """Record some identifying information about a person.""" + + name: str + age: Optional[int] + + schema = RecordPerson.model_json_schema() + result = _format_json_schema_to_gapic(schema) + expected = { + "title": "RecordPerson", + "type": "OBJECT", + "description": "Record some identifying information about a person.", + "properties": { + "name": {"title": "Name", "type": "STRING"}, + "age": {"type": "INTEGER", "title": "Age"}, + }, + "required": ["name"], + } + assert result == expected + + # Nested case class StringEnum(str, Enum): pear = "pear" banana = "banana" @@ -41,7 +63,10 @@ class B(BaseModel): array_field: Sequence[A] int_field: int = Field(description="int field", ge=1, le=10) str_field: str = Field( - min_length=1, max_length=10, pattern="^[A-Z]{1,10}$", examples=["ABCD"] + min_length=1, + max_length=10, + pattern="^[A-Z]{1,10}$", + example="ABCD", # type: ignore[call-arg] ) str_enum_field: StringEnum @@ -53,6 +78,7 @@ class B(BaseModel): "object_field": { "description": "Class A", "properties": {"int_field": {"type": "INTEGER", "title": "Int Field"}}, + "required": [], "title": "A", "type": "OBJECT", }, @@ -62,6 +88,7 @@ class B(BaseModel): "properties": { "int_field": {"type": "INTEGER", "title": "Int Field"} }, + "required": [], "title": "A", "type": "OBJECT", }, @@ -70,8 +97,8 @@ class B(BaseModel): }, "int_field": { "description": "int field", - "maximum": 10.0, - "minimum": 1.0, + "maximum": 10, + "minimum": 1, "title": "Int Field", "type": "INTEGER", }, @@ -84,7 +111,6 @@ class B(BaseModel): "type": "STRING", }, "str_enum_field": { - "description": "An enumeration.", "enum": ["pear", "banana"], "title": "StringEnum", "type": "STRING", From 03a72e7ef6d16844b92671a5b3c18df89c8ab673 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Sun, 8 Sep 2024 10:12:26 -0400 Subject: [PATCH 22/32] support v1 function --- .../functions_utils.py | 61 +++++++++- .../tests/unit_tests/test_function_utils.py | 109 ++++++++++++++++++ 2 files changed, 164 insertions(+), 6 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/functions_utils.py b/libs/vertexai/langchain_google_vertexai/functions_utils.py index 8d968b43..f4499e8b 100644 --- a/libs/vertexai/langchain_google_vertexai/functions_utils.py +++ b/libs/vertexai/langchain_google_vertexai/functions_utils.py @@ -69,11 +69,44 @@ class _ToolDictLike(TypedDict): _ALLOWED_SCHEMA_FIELDS_SET = set(_ALLOWED_SCHEMA_FIELDS) +def _format_json_schema_to_gapic_v1(schema: Dict[str, Any]) -> Dict[str, Any]: + """Format a JSON schema from a Pydantic V1 BaseModel to gapic.""" + converted_schema: Dict[str, Any] = {} + for key, value in schema.items(): + if key == "definitions": + continue + elif key == "items": + converted_schema["items"] = _format_json_schema_to_gapic_v1(value) + elif key == "properties": + if "properties" not in converted_schema: + converted_schema["properties"] = {} + for pkey, pvalue in value.items(): + converted_schema["properties"][pkey] = _format_json_schema_to_gapic_v1( + pvalue + ) + continue + elif key in ["type", "_type"]: + converted_schema["type"] = str(value).upper() + elif key == "allOf": + if len(value) > 1: + logger.warning( + "Only first value for 'allOf' key is supported. " + f"Got {len(value)}, ignoring other than first value!" + ) + return _format_json_schema_to_gapic_v1(value[0]) + elif key not in _ALLOWED_SCHEMA_FIELDS_SET: + logger.warning(f"Key '{key}' is not supported in schema, ignoring") + else: + converted_schema[key] = value + return converted_schema + + def _format_json_schema_to_gapic( schema: Dict[str, Any], parent_key: Optional[str] = None, required_fields: Optional[list] = None, ) -> Dict[str, Any]: + """Format a JSON schema from a Pydantic V2 BaseModel to gapic.""" converted_schema: Dict[str, Any] = {} for key, value in schema.items(): if key == "definitions": @@ -118,9 +151,14 @@ def _format_json_schema_to_gapic( return converted_schema -def _dict_to_gapic_schema(schema: Dict[str, Any]) -> gapic.Schema: +def _dict_to_gapic_schema( + schema: Dict[str, Any], pydantic_version: str = "v1" +) -> gapic.Schema: dereferenced_schema = dereference_refs(schema) - formatted_schema = _format_json_schema_to_gapic(dereferenced_schema) + if pydantic_version == "v1": + formatted_schema = _format_json_schema_to_gapic_v1(dereferenced_schema) + else: + formatted_schema = _format_json_schema_to_gapic(dereferenced_schema) json_schema = json.dumps(formatted_schema) return gapic.Schema.from_json(json_schema) @@ -142,8 +180,14 @@ def _format_base_tool_to_function_declaration( ), ) - schema = tool.args_schema.schema() - parameters = _dict_to_gapic_schema(schema) + if hasattr(tool.args_schema, "model_json_schema"): + schema = tool.args_schema.model_json_schema() + pydantic_version = "v2" + else: + schema = tool.args_schema.schema() + pydantic_version = "v1" + + parameters = _dict_to_gapic_schema(schema, pydantic_version=pydantic_version) return gapic.FunctionDeclaration( name=tool.name or schema.get("title"), @@ -155,12 +199,17 @@ def _format_base_tool_to_function_declaration( def _format_pydantic_to_function_declaration( pydantic_model: Type[BaseModel], ) -> gapic.FunctionDeclaration: - schema = pydantic_model.schema() + if hasattr(pydantic_model, "model_json_schema"): + schema = pydantic_model.model_json_schema() + pydantic_version = "v2" + else: + schema = pydantic_model.schema() + pydantic_version = "v1" return gapic.FunctionDeclaration( name=schema["title"], description=schema.get("description", ""), - parameters=_dict_to_gapic_schema(schema), + parameters=_dict_to_gapic_schema(schema, pydantic_version=pydantic_version), ) diff --git a/libs/vertexai/tests/unit_tests/test_function_utils.py b/libs/vertexai/tests/unit_tests/test_function_utils.py index 461823df..7664d6bb 100644 --- a/libs/vertexai/tests/unit_tests/test_function_utils.py +++ b/libs/vertexai/tests/unit_tests/test_function_utils.py @@ -9,11 +9,18 @@ from langchain_core.tools import BaseTool, tool from langchain_core.utils.json_schema import dereference_refs from pydantic import BaseModel, Field +from pydantic.v1 import ( + BaseModel as BaseModelV1, +) +from pydantic.v1 import ( + Field as FieldV1, +) from langchain_google_vertexai.functions_utils import ( _format_base_tool_to_function_declaration, _format_dict_to_function_declaration, _format_json_schema_to_gapic, + _format_json_schema_to_gapic_v1, _format_pydantic_to_function_declaration, _format_to_gapic_function_declaration, _format_to_gapic_tool, @@ -132,6 +139,108 @@ class B(BaseModel): ) +def test_format_json_schema_to_gapic_v1(): + # Simple case + class RecordPerson(BaseModelV1): + """Record some identifying information about a person.""" + + name: str + age: Optional[int] + + schema = RecordPerson.schema() + result = _format_json_schema_to_gapic_v1(schema) + expected = { + "title": "RecordPerson", + "type": "OBJECT", + "description": "Record some identifying information about a person.", + "properties": { + "name": {"title": "Name", "type": "STRING"}, + "age": {"type": "INTEGER", "title": "Age"}, + }, + "required": ["name"], + } + assert result == expected + + # Nested case + class StringEnum(str, Enum): + pear = "pear" + banana = "banana" + + class A(BaseModelV1): + """Class A""" + + int_field: Optional[int] + + class B(BaseModelV1): + object_field: Optional[A] = FieldV1(description="Class A") + array_field: Sequence[A] + int_field: int = FieldV1(description="int field", minimum=1, maximum=10) + str_field: str = FieldV1( + min_length=1, max_length=10, pattern="^[A-Z]{1,10}$", example="ABCD" + ) + str_enum_field: StringEnum + + schema = B.schema() + result = _format_json_schema_to_gapic_v1(dereference_refs(schema)) + + expected = { + "properties": { + "object_field": { + "description": "Class A", + "properties": {"int_field": {"type": "INTEGER", "title": "Int Field"}}, + "title": "A", + "type": "OBJECT", + }, + "array_field": { + "items": { + "description": "Class A", + "properties": { + "int_field": {"type": "INTEGER", "title": "Int Field"} + }, + "title": "A", + "type": "OBJECT", + }, + "type": "ARRAY", + "title": "Array Field", + }, + "int_field": { + "description": "int field", + "maximum": 10.0, + "minimum": 1.0, + "title": "Int Field", + "type": "INTEGER", + }, + "str_field": { + "example": "ABCD", + "maxLength": 10, + "minLength": 1, + "pattern": "^[A-Z]{1,10}$", + "title": "Str Field", + "type": "STRING", + }, + "str_enum_field": { + "description": "An enumeration.", + "enum": ["pear", "banana"], + "title": "StringEnum", + "type": "STRING", + }, + }, + "type": "OBJECT", + "title": "B", + "required": ["array_field", "int_field", "str_field", "str_enum_field"], + } + assert result == expected + + gapic_schema = cast(gapic.Schema, gapic.Schema.from_json(json.dumps(result))) + assert gapic_schema.type_ == gapic.Type.OBJECT + assert gapic_schema.title == expected["title"] + assert gapic_schema.required == expected["required"] + assert ( + gapic_schema.properties["str_field"].example + == expected["properties"]["str_field"]["example"] # type: ignore + ) + + # reusable test inputs def search(question: str) -> str: """Search tool""" From 20b395f77b670df2d5444ae2cd7e5bbc002226cc Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Sun, 8 Sep 2024 10:26:56 -0400 Subject: [PATCH 23/32] add test for union types --- .../tests/unit_tests/test_function_utils.py | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/libs/vertexai/tests/unit_tests/test_function_utils.py b/libs/vertexai/tests/unit_tests/test_function_utils.py index 7664d6bb..d2b94b1d 100644 --- a/libs/vertexai/tests/unit_tests/test_function_utils.py +++ b/libs/vertexai/tests/unit_tests/test_function_utils.py @@ -1,6 +1,6 @@ import json from enum import Enum -from typing import Any, Dict, List, Optional, Sequence, Tuple, cast +from typing import Any, Dict, List, Optional, Sequence, Tuple, Union, cast from unittest.mock import Mock, patch import google.cloud.aiplatform_v1beta1.types as gapic @@ -241,6 +241,27 @@ class B(BaseModelV1): ) +def test_format_json_schema_to_gapic_union_types() -> None: + """Test that union types are consistent between v1 and v2.""" + + class RecordPerson_v1(BaseModelV1): + name: str + age: Union[int, str] + + class RecordPerson(BaseModel): + name: str + age: Union[int, str] + + schema_v1 = RecordPerson_v1.schema() + schema_v2 = RecordPerson.model_json_schema() + + result_v1 = _format_json_schema_to_gapic_v1(schema_v1) + result_v2 = _format_json_schema_to_gapic(schema_v2) + result_v1["title"] = "RecordPerson" + + assert result_v1 == result_v2 + + # reusable test inputs def search(question: str) -> str: """Search tool""" From d3f6b28b5d595beef2b04a4248a83661149638cb Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Mon, 9 Sep 2024 14:38:46 -0400 Subject: [PATCH 24/32] increment version to 2.0.0.dev1 --- libs/vertexai/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/vertexai/pyproject.toml b/libs/vertexai/pyproject.toml index 54830ae3..a041177e 100644 --- a/libs/vertexai/pyproject.toml +++ b/libs/vertexai/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langchain-google-vertexai" -version = "1.0.10" +version = "2.0.0.dev1" description = "An integration package connecting Google VertexAI and LangChain" authors = [] readme = "README.md" From 29b7a2a3b94acd0cf2055314b47713e8efc702b7 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Mon, 9 Sep 2024 14:41:00 -0400 Subject: [PATCH 25/32] add snapshots for serialization standard test --- libs/vertexai/Makefile | 3 + .../__snapshots__/test_standard.ambr | 133 ++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 libs/vertexai/tests/unit_tests/__snapshots__/test_standard.ambr diff --git a/libs/vertexai/Makefile b/libs/vertexai/Makefile index 72668097..e68f0a70 100644 --- a/libs/vertexai/Makefile +++ b/libs/vertexai/Makefile @@ -11,6 +11,9 @@ integration_test integration_tests: TEST_FILE = tests/integration_tests/ test tests integration_test integration_tests: poetry run pytest --release $(TEST_FILE) +test_watch: + poetry run ptw --snapshot-update --now . -- -vv $(TEST_FILE) + # Run unit tests and generate a coverage report. coverage: poetry run pytest --cov \ diff --git a/libs/vertexai/tests/unit_tests/__snapshots__/test_standard.ambr b/libs/vertexai/tests/unit_tests/__snapshots__/test_standard.ambr new file mode 100644 index 00000000..65c7176a --- /dev/null +++ b/libs/vertexai/tests/unit_tests/__snapshots__/test_standard.ambr @@ -0,0 +1,133 @@ +# serializer version: 1 +# name: TestGeminiAIStandard.test_serdes[serialized] + dict({ + 'graph': dict({ + 'edges': list([ + dict({ + 'source': 0, + 'target': 1, + }), + dict({ + 'source': 1, + 'target': 2, + }), + ]), + 'nodes': list([ + dict({ + 'data': 'ChatVertexAIInput', + 'id': 0, + 'type': 'schema', + }), + dict({ + 'data': dict({ + 'id': list([ + 'langchain', + 'chat_models', + 'vertexai', + 'ChatVertexAI', + ]), + 'name': 'ChatVertexAI', + }), + 'id': 1, + 'type': 'runnable', + }), + dict({ + 'data': 'ChatVertexAIOutput', + 'id': 2, + 'type': 'schema', + }), + ]), + }), + 'id': list([ + 'langchain', + 'chat_models', + 'vertexai', + 'ChatVertexAI', + ]), + 'kwargs': dict({ + 'default_metadata': list([ + ]), + 'full_model_name': 'projects/test-project/locations/us-central1/publishers/google/models/gemini-1.0-pro-001', + 'location': 'us-central1', + 'max_output_tokens': 100, + 'max_retries': 2, + 'model_family': '1', + 'model_name': 'gemini-1.0-pro-001', + 'n': 1, + 'project': 'test-project', + 'request_parallelism': 5, + 'stop': list([ + ]), + 'temperature': 0.0, + }), + 'lc': 1, + 'name': 'ChatVertexAI', + 'type': 'constructor', + }) +# --- +# name: TestGemini_15_AIStandard.test_serdes[serialized] + dict({ + 'graph': dict({ + 'edges': list([ + dict({ + 'source': 0, + 'target': 1, + }), + dict({ + 'source': 1, + 'target': 2, + }), + ]), + 'nodes': list([ + dict({ + 'data': 'ChatVertexAIInput', + 'id': 0, + 'type': 'schema', + }), + dict({ + 'data': dict({ + 'id': list([ + 'langchain', + 'chat_models', + 'vertexai', + 'ChatVertexAI', + ]), + 'name': 'ChatVertexAI', + }), + 'id': 1, + 'type': 'runnable', + }), + dict({ + 'data': 'ChatVertexAIOutput', + 'id': 2, + 'type': 'schema', + }), + ]), + }), + 'id': list([ + 'langchain', + 'chat_models', + 'vertexai', + 'ChatVertexAI', + ]), + 'kwargs': dict({ + 'default_metadata': list([ + ]), + 'full_model_name': 'projects/test-project/locations/us-central1/publishers/google/models/gemini-1.5-pro-001', + 'location': 'us-central1', + 'max_output_tokens': 100, + 'max_retries': 2, + 'model_family': '2', + 'model_name': 'gemini-1.5-pro-001', + 'n': 1, + 'project': 'test-project', + 'request_parallelism': 5, + 'stop': list([ + ]), + 'temperature': 0.0, + }), + 'lc': 1, + 'name': 'ChatVertexAI', + 'type': 'constructor', + }) +# --- From dd5d8fe71e2768917d810007a9de01be5c3ca786 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Mon, 9 Sep 2024 14:52:55 -0400 Subject: [PATCH 26/32] bump core dep --- libs/vertexai/poetry.lock | 52 +++++++++++++++++------------------- libs/vertexai/pyproject.toml | 2 +- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/libs/vertexai/poetry.lock b/libs/vertexai/poetry.lock index 2642645a..8b003cba 100644 --- a/libs/vertexai/poetry.lock +++ b/libs/vertexai/poetry.lock @@ -1310,24 +1310,24 @@ files = [ [[package]] name = "langchain" -version = "0.2.16" +version = "0.3.0.dev1" description = "Building applications with LLMs through composability" optional = false -python-versions = ">=3.8.1,<4.0" +python-versions = ">=3.9,<4.0" files = [] develop = false [package.dependencies] aiohttp = "^3.8.3" async-timeout = {version = "^4.0.0", markers = "python_version < \"3.11\""} -langchain-core = "^0.2.38" -langchain-text-splitters = "^0.2.0" +langchain-core = "^0.3.0.dev2" +langchain-text-splitters = "^0.3.0.dev1" langsmith = "^0.1.17" numpy = [ {version = ">=1,<2", markers = "python_version < \"3.12\""}, {version = ">=1.26.0,<2.0.0", markers = "python_version >= \"3.12\""}, ] -pydantic = ">=1,<3" +pydantic = "^2.7.4" PyYAML = ">=5.3" requests = "^2" SQLAlchemy = ">=1.4,<3" @@ -1337,12 +1337,12 @@ tenacity = "^8.1.0,!=8.4.0" type = "git" url = "https://github.com/langchain-ai/langchain.git" reference = "v0.3rc" -resolved_reference = "e358846b39ad78512bd513f0f11df8b7e6fe249e" +resolved_reference = "6c8d626d701b9a9e365270d06a80e3a82de19963" subdirectory = "libs/langchain" [[package]] name = "langchain-core" -version = "0.2.38" +version = "0.3.0.dev4" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.9,<4.0" @@ -1351,12 +1351,9 @@ develop = false [package.dependencies] jsonpatch = "^1.33" -langsmith = "^0.1.75" +langsmith = "^0.1.112" packaging = ">=23.2,<25" -pydantic = [ - {version = ">=1,<3", markers = "python_full_version < \"3.12.4\""}, - {version = ">=2.7.4,<3.0.0", markers = "python_full_version >= \"3.12.4\""}, -] +pydantic = "^2.7.4" PyYAML = ">=5.3" tenacity = "^8.1.0,!=8.4.0" typing-extensions = ">=4.7" @@ -1365,7 +1362,7 @@ typing-extensions = ">=4.7" type = "git" url = "https://github.com/langchain-ai/langchain.git" reference = "v0.3rc" -resolved_reference = "e358846b39ad78512bd513f0f11df8b7e6fe249e" +resolved_reference = "6c8d626d701b9a9e365270d06a80e3a82de19963" subdirectory = "libs/core" [[package]] @@ -1380,7 +1377,7 @@ develop = false [package.dependencies] httpx = ">=0.25.2,<1" httpx-sse = ">=0.3.1,<1" -langchain-core = "^0.2.38" +langchain-core = "^0.3.0.dev" pydantic = ">2,<3" tokenizers = ">=0.15.1,<1" @@ -1388,7 +1385,7 @@ tokenizers = ">=0.15.1,<1" type = "git" url = "https://github.com/langchain-ai/langchain.git" reference = "v0.3rc" -resolved_reference = "e358846b39ad78512bd513f0f11df8b7e6fe249e" +resolved_reference = "6c8d626d701b9a9e365270d06a80e3a82de19963" subdirectory = "libs/partners/mistralai" [[package]] @@ -1396,13 +1393,13 @@ name = "langchain-standard-tests" version = "0.1.1" description = "Standard tests for LangChain implementations" optional = false -python-versions = ">=3.8.1,<4.0" +python-versions = ">=3.9,<4.0" files = [] develop = false [package.dependencies] httpx = "^0.27.0" -langchain-core = ">=0.1.40,<0.3" +langchain-core = ">=0.3.0.dev1" pytest = ">=7,<9" syrupy = "^4" @@ -1410,35 +1407,36 @@ syrupy = "^4" type = "git" url = "https://github.com/langchain-ai/langchain.git" reference = "v0.3rc" -resolved_reference = "e358846b39ad78512bd513f0f11df8b7e6fe249e" +resolved_reference = "6c8d626d701b9a9e365270d06a80e3a82de19963" subdirectory = "libs/standard-tests" [[package]] name = "langchain-text-splitters" -version = "0.2.2" +version = "0.3.0.dev1" description = "LangChain text splitting utilities" optional = false -python-versions = "<4.0,>=3.8.1" +python-versions = "<4.0,>=3.9" files = [ - {file = "langchain_text_splitters-0.2.2-py3-none-any.whl", hash = "sha256:1c80d4b11b55e2995f02d2a326c0323ee1eeff24507329bb22924e420c782dff"}, - {file = "langchain_text_splitters-0.2.2.tar.gz", hash = "sha256:a1e45de10919fa6fb080ef0525deab56557e9552083600455cb9fa4238076140"}, + {file = "langchain_text_splitters-0.3.0.dev1-py3-none-any.whl", hash = "sha256:85abe6ab1aa95e8cc3bf985cd9e53848de616c21d3590a25ac13a694d409f133"}, + {file = "langchain_text_splitters-0.3.0.dev1.tar.gz", hash = "sha256:5e13ca0f27719406c6c5575f48cdfb89755f02dd0f1c8af5d1f8a1a9f391f3a2"}, ] [package.dependencies] -langchain-core = ">=0.2.10,<0.3.0" +langchain-core = ">=0.3.0.dev1,<0.4.0" [[package]] name = "langsmith" -version = "0.1.99" +version = "0.1.117" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langsmith-0.1.99-py3-none-any.whl", hash = "sha256:ef8d1d74a2674c514aa429b0171a9fbb661207dc3835142cca0e8f1bf97b26b0"}, - {file = "langsmith-0.1.99.tar.gz", hash = "sha256:b5c6a1f158abda61600a4a445081ee848b4a28b758d91f2793dc02aeffafcaf1"}, + {file = "langsmith-0.1.117-py3-none-any.whl", hash = "sha256:e936ee9bcf8293b0496df7ba462a3702179fbe51f9dc28744b0fbec0dbf206ae"}, + {file = "langsmith-0.1.117.tar.gz", hash = "sha256:a1b532f49968b9339bcaff9118d141846d52ed3d803f342902e7448edf1d662b"}, ] [package.dependencies] +httpx = ">=0.23.0,<1" orjson = ">=3.9.14,<4.0.0" pydantic = [ {version = ">=1,<3", markers = "python_full_version < \"3.12.4\""}, @@ -2759,4 +2757,4 @@ mistral = ["langchain-mistralai"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0" -content-hash = "07178bac539421edbfd91761ca53612aad9ef8f688349b4b63ff278d2a40f181" +content-hash = "f81f09ee71fcd48ec574381f15b0f6a11b76f8aa7e63e2946b25a69fc201f8a9" diff --git a/libs/vertexai/pyproject.toml b/libs/vertexai/pyproject.toml index a041177e..3d0fecbf 100644 --- a/libs/vertexai/pyproject.toml +++ b/libs/vertexai/pyproject.toml @@ -12,7 +12,7 @@ license = "MIT" [tool.poetry.dependencies] python = ">=3.9,<4.0" -langchain-core = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/core", branch = "v0.3rc" } +langchain-core = { version = "^0.3.0.dev4", allow-prereleases = true } google-cloud-aiplatform = "^1.56.0" google-cloud-storage = "^2.17.0" # optional dependencies From 36e9ec447b0073ba2ed7b209cf860c76cfdb1521 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Mon, 9 Sep 2024 14:53:13 -0400 Subject: [PATCH 27/32] json_schema_extra in test --- libs/vertexai/tests/unit_tests/test_function_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/vertexai/tests/unit_tests/test_function_utils.py b/libs/vertexai/tests/unit_tests/test_function_utils.py index d2b94b1d..e2aa0c73 100644 --- a/libs/vertexai/tests/unit_tests/test_function_utils.py +++ b/libs/vertexai/tests/unit_tests/test_function_utils.py @@ -73,7 +73,7 @@ class B(BaseModel): min_length=1, max_length=10, pattern="^[A-Z]{1,10}$", - example="ABCD", # type: ignore[call-arg] + json_schema_extra={"example": "ABCD"}, ) str_enum_field: StringEnum From ec4bc72c8ca2c3e1ce0483f704a6feea5fa6d7d1 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Mon, 9 Sep 2024 14:53:31 -0400 Subject: [PATCH 28/32] protected namespaces --- libs/vertexai/langchain_google_vertexai/_base.py | 1 + libs/vertexai/langchain_google_vertexai/gemma.py | 1 + libs/vertexai/langchain_google_vertexai/model_garden.py | 1 + 3 files changed, 3 insertions(+) diff --git a/libs/vertexai/langchain_google_vertexai/_base.py b/libs/vertexai/langchain_google_vertexai/_base.py index 7b260ec5..d5ac6bfe 100644 --- a/libs/vertexai/langchain_google_vertexai/_base.py +++ b/libs/vertexai/langchain_google_vertexai/_base.py @@ -95,6 +95,7 @@ class _VertexAIBase(BaseModel): model_config = ConfigDict( populate_by_name=True, arbitrary_types_allowed=True, + protected_namespaces=(), ) @model_validator(mode="before") diff --git a/libs/vertexai/langchain_google_vertexai/gemma.py b/libs/vertexai/langchain_google_vertexai/gemma.py index 57196644..051c3809 100644 --- a/libs/vertexai/langchain_google_vertexai/gemma.py +++ b/libs/vertexai/langchain_google_vertexai/gemma.py @@ -130,6 +130,7 @@ def __init__(self, *, model_name: Optional[str] = None, **kwargs: Any) -> None: model_config = ConfigDict( populate_by_name=True, + protected_namespaces=(), ) @property diff --git a/libs/vertexai/langchain_google_vertexai/model_garden.py b/libs/vertexai/langchain_google_vertexai/model_garden.py index ad982c81..4fee0562 100644 --- a/libs/vertexai/langchain_google_vertexai/model_garden.py +++ b/libs/vertexai/langchain_google_vertexai/model_garden.py @@ -66,6 +66,7 @@ class VertexAIModelGarden(_BaseVertexAIModelGarden, BaseLLM): model_config = ConfigDict( populate_by_name=True, + protected_namespaces=(), ) # Needed so that mypy doesn't flag missing aliased init args. From 1dc420c7a692a32b2761c66e23162e8e8b40f043 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Mon, 9 Sep 2024 15:10:38 -0400 Subject: [PATCH 29/32] fix warnings --- libs/vertexai/langchain_google_vertexai/gemma.py | 2 ++ libs/vertexai/langchain_google_vertexai/vision_models.py | 6 +++++- libs/vertexai/tests/unit_tests/test_function_utils.py | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/gemma.py b/libs/vertexai/langchain_google_vertexai/gemma.py index 051c3809..a854af05 100644 --- a/libs/vertexai/langchain_google_vertexai/gemma.py +++ b/libs/vertexai/langchain_google_vertexai/gemma.py @@ -77,6 +77,8 @@ class _GemmaBase(BaseModel): top_k: Optional[int] = None """The top-k value to use for sampling.""" + model_config = ConfigDict(protected_namespaces=()) + @property def _default_params(self) -> Dict[str, Any]: """Get the default parameters for calling gemma.""" diff --git a/libs/vertexai/langchain_google_vertexai/vision_models.py b/libs/vertexai/langchain_google_vertexai/vision_models.py index 1ffc254e..8d5d0e8f 100644 --- a/libs/vertexai/langchain_google_vertexai/vision_models.py +++ b/libs/vertexai/langchain_google_vertexai/vision_models.py @@ -9,7 +9,7 @@ from langchain_core.outputs import ChatResult, LLMResult from langchain_core.outputs.chat_generation import ChatGeneration from langchain_core.outputs.generation import Generation -from pydantic import BaseModel, Field +from pydantic import BaseModel, ConfigDict, Field from vertexai.preview.vision_models import ( # type: ignore[import-untyped] GeneratedImage, ImageGenerationModel, @@ -39,6 +39,8 @@ class _BaseImageTextModel(BaseModel): project: Union[str, None] = Field(default=None) """Google cloud project""" + model_config = ConfigDict(protected_namespaces=()) + @property def client(self) -> ImageTextModel: if self.cached_client is None: @@ -334,6 +336,8 @@ class _BaseVertexAIImageGenerator(BaseModel): project: Union[str, None] = Field(default=None) """Google cloud project id""" + model_config = ConfigDict(protected_namespaces=()) + @property def client(self) -> ImageGenerationModel: if not self.cached_client: diff --git a/libs/vertexai/tests/unit_tests/test_function_utils.py b/libs/vertexai/tests/unit_tests/test_function_utils.py index e2aa0c73..96a04860 100644 --- a/libs/vertexai/tests/unit_tests/test_function_utils.py +++ b/libs/vertexai/tests/unit_tests/test_function_utils.py @@ -320,7 +320,7 @@ class SearchModel(BaseModel): question: str -search_model_schema = SearchModel.schema() +search_model_schema = SearchModel.model_json_schema() search_model_dict = { "name": search_model_schema["title"], "description": search_model_schema["description"], From e598e279c212e3d2d4e62c2a922cb38b973a0743 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Mon, 9 Sep 2024 15:30:45 -0400 Subject: [PATCH 30/32] fix warnings --- libs/vertexai/langchain_google_vertexai/chains.py | 7 ++++++- libs/vertexai/tests/integration_tests/test_chat_models.py | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/libs/vertexai/langchain_google_vertexai/chains.py b/libs/vertexai/langchain_google_vertexai/chains.py index 7394a2a4..6f3c2680 100644 --- a/libs/vertexai/langchain_google_vertexai/chains.py +++ b/libs/vertexai/langchain_google_vertexai/chains.py @@ -51,7 +51,12 @@ def _create_structured_runnable_extra_step( *, prompt: Optional[BasePromptTemplate] = None, ) -> Runnable: - names = [schema.schema()["title"] for schema in functions] + names = [ + schema.model_json_schema()["title"] + if hasattr(schema, "model_json_schema") + else schema.schema()["title"] + for schema in functions + ] if hasattr(llm, "is_gemini_advanced") and llm._is_gemini_advanced: # type: ignore llm_with_functions = llm.bind( functions=functions, diff --git a/libs/vertexai/tests/integration_tests/test_chat_models.py b/libs/vertexai/tests/integration_tests/test_chat_models.py index b511cddb..7965a5b7 100644 --- a/libs/vertexai/tests/integration_tests/test_chat_models.py +++ b/libs/vertexai/tests/integration_tests/test_chat_models.py @@ -616,7 +616,11 @@ class MyModel(BaseModel): assert response == MyModel(name="Erick", age=27) model = llm.with_structured_output( - {"name": "MyModel", "description": "MyModel", "parameters": MyModel.schema()} + { + "name": "MyModel", + "description": "MyModel", + "parameters": MyModel.model_json_schema(), + } ) response = model.invoke([message]) assert response == { From 0c4c5b20c60205e1108eb3fe381d2e253dfe6e5d Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Mon, 9 Sep 2024 15:34:25 -0400 Subject: [PATCH 31/32] fix mistral dependency --- libs/vertexai/poetry.lock | 2 +- libs/vertexai/pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/vertexai/poetry.lock b/libs/vertexai/poetry.lock index 8b003cba..e6a840eb 100644 --- a/libs/vertexai/poetry.lock +++ b/libs/vertexai/poetry.lock @@ -2757,4 +2757,4 @@ mistral = ["langchain-mistralai"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0" -content-hash = "f81f09ee71fcd48ec574381f15b0f6a11b76f8aa7e63e2946b25a69fc201f8a9" +content-hash = "fd6089e49c9de43f254f7643f0a5e6bb631f21f2e1e8558d4d7e82dbdb2de2f9" diff --git a/libs/vertexai/pyproject.toml b/libs/vertexai/pyproject.toml index 3d0fecbf..d0dd0c2b 100644 --- a/libs/vertexai/pyproject.toml +++ b/libs/vertexai/pyproject.toml @@ -17,7 +17,7 @@ google-cloud-aiplatform = "^1.56.0" google-cloud-storage = "^2.17.0" # optional dependencies anthropic = { extras = ["vertexai"], version = ">=0.30.0,<1", optional = true } -langchain-mistralai = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/partners/mistralai", branch = "v0.3rc"} +langchain-mistralai = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/partners/mistralai", optional = true, branch = "v0.3rc"} httpx = "^0.27.0" httpx-sse = "^0.4.0" pydantic = ">=2,<3" From 97b32d815781c39368e8fa2b4d903c9f66aa2c26 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Mon, 9 Sep 2024 16:19:04 -0400 Subject: [PATCH 32/32] fix mistral dep and lock --- libs/vertexai/poetry.lock | 9 ++++----- libs/vertexai/pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/libs/vertexai/poetry.lock b/libs/vertexai/poetry.lock index e6a840eb..677b9e55 100644 --- a/libs/vertexai/poetry.lock +++ b/libs/vertexai/poetry.lock @@ -1367,7 +1367,7 @@ subdirectory = "libs/core" [[package]] name = "langchain-mistralai" -version = "0.1.13" +version = "0.2.0.dev1" description = "An integration package connecting Mistral and LangChain" optional = false python-versions = ">=3.9,<4.0" @@ -1377,15 +1377,14 @@ develop = false [package.dependencies] httpx = ">=0.25.2,<1" httpx-sse = ">=0.3.1,<1" -langchain-core = "^0.3.0.dev" -pydantic = ">2,<3" +langchain-core = "^0.3.0.dev4" tokenizers = ">=0.15.1,<1" [package.source] type = "git" url = "https://github.com/langchain-ai/langchain.git" reference = "v0.3rc" -resolved_reference = "6c8d626d701b9a9e365270d06a80e3a82de19963" +resolved_reference = "2070d659a06d1919093df56b6a63180f56ef8afa" subdirectory = "libs/partners/mistralai" [[package]] @@ -2757,4 +2756,4 @@ mistral = ["langchain-mistralai"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0" -content-hash = "fd6089e49c9de43f254f7643f0a5e6bb631f21f2e1e8558d4d7e82dbdb2de2f9" +content-hash = "00bdba3e2d330934ca0bd2384a01fdaaa42f3f4eefe33eafede493f946f5f604" diff --git a/libs/vertexai/pyproject.toml b/libs/vertexai/pyproject.toml index d0dd0c2b..380a97d1 100644 --- a/libs/vertexai/pyproject.toml +++ b/libs/vertexai/pyproject.toml @@ -17,7 +17,7 @@ google-cloud-aiplatform = "^1.56.0" google-cloud-storage = "^2.17.0" # optional dependencies anthropic = { extras = ["vertexai"], version = ">=0.30.0,<1", optional = true } -langchain-mistralai = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/partners/mistralai", optional = true, branch = "v0.3rc"} +langchain-mistralai = { version = "^0.2.0.dev1", allow-prereleases = true } httpx = "^0.27.0" httpx-sse = "^0.4.0" pydantic = ">=2,<3"