diff --git a/.github/workflows/lint-check.yml b/.github/workflows/lint-check.yml index 76feed9..555b1fd 100644 --- a/.github/workflows/lint-check.yml +++ b/.github/workflows/lint-check.yml @@ -9,12 +9,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: - python-version: 3.11 + python-version: "3.11" - name: Install poetry run: | @@ -25,7 +25,7 @@ jobs: python -m poetry config virtualenvs.in-project true - name: Cache the virtualenv - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ./.venv key: ${{ runner.os }}-venv-${{ hashFiles('**/poetry.lock') }} diff --git a/poetry.lock b/poetry.lock index 8f0036d..250323f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. [[package]] name = "agentcore" @@ -6,6 +6,7 @@ version = "0.1.3" description = "A core API for agentsea" optional = false python-versions = "<4.0,>=3.10" +groups = ["main"] files = [ {file = "agentcore-0.1.3-py3-none-any.whl", hash = "sha256:0b651ec29afb3021a406a3b3ed5946f0832a223c08edde881c96e4c8bec571bc"}, {file = "agentcore-0.1.3.tar.gz", hash = "sha256:ce800077cefee25b4e1efe7b8444d8dc3a916c8a5fd702d70b25c89de00c4f55"}, @@ -20,6 +21,7 @@ version = "0.2.118" description = "A desktop for AI agents" optional = false python-versions = "<4.0,>=3.10" +groups = ["main"] files = [ {file = "agentdesk-0.2.118-py3-none-any.whl", hash = "sha256:b48523744a41485b5d4a6273716459e66c8222ba99f9821fe6b9c2f092f41240"}, {file = "agentdesk-0.2.118.tar.gz", hash = "sha256:ade6aee1c19296a5f424b7c8d779a2e4b737085480bc2eb88c9b8d174b1d5168"}, @@ -57,6 +59,7 @@ version = "3.9.5" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7"}, {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c"}, @@ -153,6 +156,7 @@ version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, @@ -167,6 +171,7 @@ version = "0.6.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, @@ -178,6 +183,7 @@ version = "4.3.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, @@ -200,6 +206,8 @@ version = "0.1.4" description = "Disable App Nap on macOS >= 10.9" optional = false python-versions = ">=3.6" +groups = ["dev"] +markers = "platform_system == \"Darwin\"" files = [ {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, @@ -211,6 +219,7 @@ version = "2.4.1" description = "Annotate AST trees with source code positions" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, @@ -229,6 +238,8 @@ version = "4.0.3" description = "Timeout context manager for asyncio programs" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_full_version < \"3.11.3\"" files = [ {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, @@ -240,6 +251,7 @@ version = "23.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, @@ -259,6 +271,7 @@ version = "4.2.1" description = "Modern password hashing for your software and your servers" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "bcrypt-4.2.1-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:1340411a0894b7d3ef562fb233e4b6ed58add185228650942bdc885362f32c17"}, {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ee315739bc8387aa36ff127afc99120ee452924e0df517a8f3e4c0187a0f5f"}, @@ -297,6 +310,7 @@ version = "24.4.2" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, @@ -343,6 +357,7 @@ version = "1.7" description = "A thin, practical wrapper around terminal coloring, styling, and positioning" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] files = [ {file = "blessings-1.7-py2-none-any.whl", hash = "sha256:caad5211e7ba5afe04367cdd4cfc68fa886e2e08f6f35e76b7387d2109ccea6e"}, {file = "blessings-1.7-py3-none-any.whl", hash = "sha256:b1fdd7e7a675295630f9ae71527a8ebc10bfefa236b3d6aa4932ee4462c17ba3"}, @@ -358,6 +373,7 @@ version = "1.36.7" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "boto3-1.36.7-py3-none-any.whl", hash = "sha256:ab501f75557863e2d2c9fa731e4fe25c45f35e0d92ea0ee11a4eaa63929d3ede"}, {file = "boto3-1.36.7.tar.gz", hash = "sha256:ae98634efa7b47ced1b0d7342e2940b32639eee913f33ab406590b8ed55ee94b"}, @@ -377,6 +393,7 @@ version = "1.36.7" description = "Type annotations for boto3 1.36.7 generated with mypy-boto3-builder 8.8.0" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "boto3_stubs-1.36.7-py3-none-any.whl", hash = "sha256:d5d3f1f537c4d317f1f11b1cb4ce8f427822204936e29419b43c709ec54758ea"}, {file = "boto3_stubs-1.36.7.tar.gz", hash = "sha256:197bdbacd3a9085c6310a06f21616f30f6103ed8be67705962620ac4587ba1fb"}, @@ -803,6 +820,7 @@ version = "1.36.7" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "botocore-1.36.7-py3-none-any.whl", hash = "sha256:a6c6772d777af2957ac9975207fac1ccc4ce101408b85e9b5e3c5ba0bb949102"}, {file = "botocore-1.36.7.tar.gz", hash = "sha256:9abc64bde5e7d8f814ea91d6fc0a8142511fc96427c19fe9209677c20a0c9e6e"}, @@ -822,6 +840,7 @@ version = "1.36.7" description = "Type annotations and code completion for botocore" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "botocore_stubs-1.36.7-py3-none-any.whl", hash = "sha256:77052e3a86a3f77383c638db63379652bafac3a2b310954392e0cfb3dacd3dad"}, {file = "botocore_stubs-1.36.7.tar.gz", hash = "sha256:51c51da5379d3e4c4cb7e3dbe8451f572ecbfe6a5ced3a76a6b958941ef72409"}, @@ -839,6 +858,7 @@ version = "5.3.3" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "cachetools-5.3.3-py3-none-any.whl", hash = "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945"}, {file = "cachetools-5.3.3.tar.gz", hash = "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105"}, @@ -850,6 +870,7 @@ version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main", "dev"] files = [ {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, @@ -861,6 +882,7 @@ version = "1.16.0" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, @@ -915,6 +937,7 @@ files = [ {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, ] +markers = {dev = "implementation_name == \"pypy\""} [package.dependencies] pycparser = "*" @@ -925,6 +948,7 @@ version = "5.2.0" description = "Universal encoding detector for Python 3" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, @@ -936,6 +960,7 @@ version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" +groups = ["main", "dev"] files = [ {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, @@ -1035,6 +1060,7 @@ version = "8.1.7" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, @@ -1049,6 +1075,7 @@ version = "2.1.13" description = "Hosted coverage reports for GitHub, Bitbucket and Gitlab" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] files = [ {file = "codecov-2.1.13-py2.py3-none-any.whl", hash = "sha256:c2ca5e51bba9ebb43644c43d0690148a55086f7f5e6fd36170858fa4206744d5"}, {file = "codecov-2.1.13.tar.gz", hash = "sha256:2362b685633caeaf45b9951a9b76ce359cd3581dd515b430c6c3f5dfb4d92a8c"}, @@ -1064,10 +1091,12 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "dev"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +markers = {dev = "platform_system == \"Windows\" or sys_platform == \"win32\""} [[package]] name = "coloredlogs" @@ -1075,6 +1104,7 @@ version = "15.0.1" description = "Colored terminal output for Python's logging module" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main"] files = [ {file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"}, {file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"}, @@ -1092,6 +1122,7 @@ version = "0.1.1" description = "Colour formatting for unittest tests" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "colour-runner-0.1.1.tar.gz", hash = "sha256:38b1ad31ffc34a517a8b8e39026b63f6cbe165852c30e0912dc18e0c2f9939f9"}, {file = "colour_runner-0.1.1-py2.py3-none-any.whl", hash = "sha256:18227068941e455aec3dfe6c64e683bb0e53f56527529748994dc559b928c50d"}, @@ -1107,6 +1138,7 @@ version = "0.2.2" description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"}, {file = "comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e"}, @@ -1124,6 +1156,7 @@ version = "7.5.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "coverage-7.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0884920835a033b78d1c73b6d3bbcda8161a900f38a488829a83982925f6c2e"}, {file = "coverage-7.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:39afcd3d4339329c5f58de48a52f6e4e50f6578dd6099961cf22228feb25f38f"}, @@ -1188,6 +1221,7 @@ version = "43.0.1" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}, {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"}, @@ -1237,6 +1271,7 @@ version = "1.8.1" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, @@ -1268,6 +1303,7 @@ version = "5.1.1" description = "Decorators for Humans" optional = false python-versions = ">=3.5" +groups = ["dev"] files = [ {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, @@ -1279,6 +1315,7 @@ version = "7.0.1" description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "deepdiff-7.0.1-py3-none-any.whl", hash = "sha256:447760081918216aa4fd4ca78a4b6a848b81307b2ea94c810255334b759e1dc3"}, {file = "deepdiff-7.0.1.tar.gz", hash = "sha256:260c16f052d4badbf60351b4f77e8390bee03a0b516246f6839bc813fb429ddf"}, @@ -1297,6 +1334,7 @@ version = "0.1.28" description = "Devices for AI agents" optional = false python-versions = "<4.0,>=3.10" +groups = ["main"] files = [ {file = "devicebay-0.1.28-py3-none-any.whl", hash = "sha256:67eb15a8d3284e22d896ea8a8096a6d9798214ce258fcfa1aa08df7dd1c4620b"}, {file = "devicebay-0.1.28.tar.gz", hash = "sha256:e9ccce087b203a124b0936445967ec97e5388a5fe358bca5ee82ef70950ba11a"}, @@ -1316,6 +1354,7 @@ version = "0.3.8" description = "Distribution utilities" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, @@ -1327,6 +1366,7 @@ version = "1.9.0" description = "Distro - an OS platform information API" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, @@ -1338,6 +1378,7 @@ version = "2.6.1" description = "DNS toolkit" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, {file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"}, @@ -1358,6 +1399,7 @@ version = "7.0.0" description = "A Python library for the Docker Engine API." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "docker-7.0.0-py3-none-any.whl", hash = "sha256:12ba681f2777a0ad28ffbcc846a69c31b4dfd9752b47eb425a274ee269c5e14b"}, {file = "docker-7.0.0.tar.gz", hash = "sha256:323736fb92cd9418fc5e7133bc953e11a9da04f4483f828b527db553f1e7e5a3"}, @@ -1379,6 +1421,7 @@ version = "0.15" description = "Parse Python docstrings in reST, Google and Numpydoc format" optional = false python-versions = ">=3.6,<4.0" +groups = ["main", "dev"] files = [ {file = "docstring_parser-0.15-py3-none-any.whl", hash = "sha256:d1679b86250d269d06a99670924d6bce45adc00b08069dae8c47d98e89b667a9"}, {file = "docstring_parser-0.15.tar.gz", hash = "sha256:48ddc093e8b1865899956fcc03b03e66bb7240c310fac5af81814580c55bf682"}, @@ -1390,6 +1433,7 @@ version = "0.9" description = "Module for converting between datetime.timedelta and Go's Duration strings." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "durationpy-0.9-py3-none-any.whl", hash = "sha256:e65359a7af5cedad07fb77a2dd3f390f8eb0b74cb845589fa6c057086834dd38"}, {file = "durationpy-0.9.tar.gz", hash = "sha256:fd3feb0a69a0057d582ef643c355c40d2fa1c942191f914d12203b1a01ac722a"}, @@ -1401,6 +1445,7 @@ version = "2.1.1" description = "A robust email address syntax and deliverability validation library." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "email_validator-2.1.1-py3-none-any.whl", hash = "sha256:97d882d174e2a65732fb43bfce81a3a834cbc1bde8bf419e30ef5ea976370a05"}, {file = "email_validator-2.1.1.tar.gz", hash = "sha256:200a70680ba08904be6d1eef729205cc0d687634399a5924d842533efb824b84"}, @@ -1416,6 +1461,8 @@ version = "1.2.1" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] +markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, @@ -1430,6 +1477,7 @@ version = "2.0.1" description = "Get the currently executing AST node of a frame, and other information" optional = false python-versions = ">=3.5" +groups = ["dev"] files = [ {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, @@ -1444,6 +1492,7 @@ version = "0.109.2" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "fastapi-0.109.2-py3-none-any.whl", hash = "sha256:2c9bab24667293b501cad8dd388c05240c850b58ec5876ee3283c47d6e1e3a4d"}, {file = "fastapi-0.109.2.tar.gz", hash = "sha256:f3817eac96fe4f65a2ebb4baa000f394e55f5fccdaf7f75250804bc58f354f73"}, @@ -1474,6 +1523,7 @@ version = "3.14.0" description = "A platform independent file lock." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "filelock-3.14.0-py3-none-any.whl", hash = "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f"}, {file = "filelock-3.14.0.tar.gz", hash = "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"}, @@ -1490,6 +1540,7 @@ version = "1.4.1" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, @@ -1576,6 +1627,7 @@ version = "2024.5.0" description = "File-system specification" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "fsspec-2024.5.0-py3-none-any.whl", hash = "sha256:e0fdbc446d67e182f49a70b82cf7889028a63588fde6b222521f10937b2b670c"}, {file = "fsspec-2024.5.0.tar.gz", hash = "sha256:1d021b0b0f933e3b3029ed808eb400c08ba101ca2de4b3483fbc9ca23fcee94a"}, @@ -1614,6 +1666,7 @@ version = "2.19.0" description = "Google API client core library" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "google-api-core-2.19.0.tar.gz", hash = "sha256:cf1b7c2694047886d2af1128a03ae99e391108a08804f87cfd35970e49c9cd10"}, {file = "google_api_core-2.19.0-py3-none-any.whl", hash = "sha256:8661eec4078c35428fd3f69a2c7ee29e342896b70f01d1a1cbcb334372dd6251"}, @@ -1645,6 +1698,7 @@ version = "2.29.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "google-auth-2.29.0.tar.gz", hash = "sha256:672dff332d073227550ffc7457868ac4218d6c500b155fe6cc17d2b13602c360"}, {file = "google_auth-2.29.0-py2.py3-none-any.whl", hash = "sha256:d452ad095688cd52bae0ad6fafe027f6a6d6f560e810fec20914e17a09526415"}, @@ -1668,6 +1722,7 @@ version = "1.53.0" description = "Vertex AI API client library" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "google-cloud-aiplatform-1.53.0.tar.gz", hash = "sha256:574cfad8ac5fa5d57ef717f5335ce05636a5fa9b8aeea0f5c325b46b9448e6b1"}, {file = "google_cloud_aiplatform-1.53.0-py2.py3-none-any.whl", hash = "sha256:9dfb1f110e6d4795b45afcfab79108fc5c8ed9aa4eaf899e433bc2ca1b76c778"}, @@ -1715,6 +1770,7 @@ version = "3.23.1" description = "Google BigQuery API client library" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "google-cloud-bigquery-3.23.1.tar.gz", hash = "sha256:4b4597f9291b42102c9667d3b4528f801d4c8f24ef2b12dd1ecb881273330955"}, {file = "google_cloud_bigquery-3.23.1-py2.py3-none-any.whl", hash = "sha256:9fb72884fdbec9c4643cea6b7f21e1ecf3eb61d5305f87493d271dc801647a9e"}, @@ -1746,6 +1802,8 @@ version = "1.19.2" description = "Google Cloud Compute API client library" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version >= \"3.13\"" files = [ {file = "google_cloud_compute-1.19.2-py2.py3-none-any.whl", hash = "sha256:e15b03da54fef17be18a20ebd8716e12aa5e17379e63042d15e8b6a3a4f08597"}, {file = "google_cloud_compute-1.19.2.tar.gz", hash = "sha256:3fce82abe14e76faaa81234d9a7be1e634b2ed8a27f55feefcf2b146467f7fab"}, @@ -1763,6 +1821,8 @@ version = "1.24.0" description = "Google Cloud Compute API client library" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version < \"3.13\"" files = [ {file = "google_cloud_compute-1.24.0-py2.py3-none-any.whl", hash = "sha256:e50b4827b6d7027eaf480f472f4a0d4b097d38a6d3cc10704bc9135dca69e190"}, {file = "google_cloud_compute-1.24.0.tar.gz", hash = "sha256:3538830f77cdae6e4ac5d9cee1827180c36a2a4574c4ce4a4ffef7562b23c078"}, @@ -1780,6 +1840,8 @@ version = "2.52.0" description = "Google Cloud Container API client library" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version >= \"3.13\"" files = [ {file = "google_cloud_container-2.52.0-py2.py3-none-any.whl", hash = "sha256:a62ede7256cf113bbb134685c703ea2dc4cbf60e08875e23dc4369c46743adaa"}, {file = "google_cloud_container-2.52.0.tar.gz", hash = "sha256:7a2fac7680a6a5bb2776b494a1fd1e2e64e4935643b2a01fb93bb8d1bb73b0ef"}, @@ -1797,6 +1859,8 @@ version = "2.55.1" description = "Google Cloud Container API client library" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version < \"3.13\"" files = [ {file = "google_cloud_container-2.55.1-py2.py3-none-any.whl", hash = "sha256:77e640f3c3b25c5e8b7ac5293d8865b7ca7c5bfd77750dff9fb0b59d0bfb3460"}, {file = "google_cloud_container-2.55.1.tar.gz", hash = "sha256:0f2c351ef6b0f6e01de9e99193ebba4e7f5debba428e9a0b8074919c97cd7555"}, @@ -1814,6 +1878,7 @@ version = "2.4.1" description = "Google Cloud API client core library" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "google-cloud-core-2.4.1.tar.gz", hash = "sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073"}, {file = "google_cloud_core-2.4.1-py2.py3-none-any.whl", hash = "sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61"}, @@ -1832,6 +1897,7 @@ version = "1.12.3" description = "Google Cloud Resource Manager API client library" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "google-cloud-resource-manager-1.12.3.tar.gz", hash = "sha256:809851824119834e4f2310b2c4f38621c1d16b2bb14d5b9f132e69c79d355e7f"}, {file = "google_cloud_resource_manager-1.12.3-py2.py3-none-any.whl", hash = "sha256:92be7d6959927b76d90eafc4028985c37975a46ded5466a018f02e8649e113d4"}, @@ -1850,6 +1916,7 @@ version = "2.17.0" description = "Google Cloud Storage API client library" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "google-cloud-storage-2.17.0.tar.gz", hash = "sha256:49378abff54ef656b52dca5ef0f2eba9aa83dc2b2c72c78714b03a1a95fe9388"}, {file = "google_cloud_storage-2.17.0-py2.py3-none-any.whl", hash = "sha256:5b393bc766b7a3bc6f5407b9e665b2450d36282614b7945e570b3480a456d1e1"}, @@ -1872,6 +1939,7 @@ version = "1.5.0" description = "A python wrapper of the C library 'Google CRC32C'" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "google-crc32c-1.5.0.tar.gz", hash = "sha256:89284716bc6a5a415d4eaa11b1726d2d60a0cd12aadf5439828353662ede9dd7"}, {file = "google_crc32c-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:596d1f98fc70232fcb6590c439f43b350cb762fb5d61ce7b0e9db4539654cc13"}, @@ -1952,6 +2020,7 @@ version = "2.7.0" description = "Utilities for Google Media Downloads and Resumable Uploads" optional = false python-versions = ">= 3.7" +groups = ["main", "dev"] files = [ {file = "google-resumable-media-2.7.0.tar.gz", hash = "sha256:5f18f5fa9836f4b083162064a1c2c98c17239bfda9ca50ad970ccf905f3e625b"}, {file = "google_resumable_media-2.7.0-py2.py3-none-any.whl", hash = "sha256:79543cfe433b63fd81c0844b7803aba1bb8950b47bedf7d980c38fa123937e08"}, @@ -1970,6 +2039,7 @@ version = "1.63.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "googleapis-common-protos-1.63.0.tar.gz", hash = "sha256:17ad01b11d5f1d0171c06d3ba5c04c54474e883b66b949722b4938ee2694ef4e"}, {file = "googleapis_common_protos-1.63.0-py2.py3-none-any.whl", hash = "sha256:ae45f75702f7c08b541f750854a678bd8f534a1a6bace6afe975f1d0a82d6632"}, @@ -1988,6 +2058,8 @@ version = "3.0.3" description = "Lightweight in-process concurrent programming" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\"" files = [ {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"}, {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"}, @@ -2059,6 +2131,7 @@ version = "0.13.0" description = "IAM API client library" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "grpc-google-iam-v1-0.13.0.tar.gz", hash = "sha256:fad318608b9e093258fbf12529180f400d1c44453698a33509cc6ecf005b294e"}, {file = "grpc_google_iam_v1-0.13.0-py2.py3-none-any.whl", hash = "sha256:53902e2af7de8df8c1bd91373d9be55b0743ec267a7428ea638db3775becae89"}, @@ -2075,6 +2148,7 @@ version = "1.64.0" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "grpcio-1.64.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:3b09c3d9de95461214a11d82cc0e6a46a6f4e1f91834b50782f932895215e5db"}, {file = "grpcio-1.64.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:7e013428ab472892830287dd082b7d129f4d8afef49227a28223a77337555eaa"}, @@ -2133,6 +2207,7 @@ version = "1.62.2" description = "Status proto mapping for gRPC" optional = false python-versions = ">=3.6" +groups = ["main", "dev"] files = [ {file = "grpcio-status-1.62.2.tar.gz", hash = "sha256:62e1bfcb02025a1cd73732a2d33672d3e9d0df4d21c12c51e0bbcaf09bab742a"}, {file = "grpcio_status-1.62.2-py3-none-any.whl", hash = "sha256:206ddf0eb36bc99b033f03b2c8e95d319f0044defae9b41ae21408e7e0cda48f"}, @@ -2149,6 +2224,7 @@ version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, @@ -2160,6 +2236,7 @@ version = "1.0.5" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, @@ -2181,6 +2258,7 @@ version = "0.6.1" description = "A collection of framework independent HTTP protocol utils." optional = false python-versions = ">=3.8.0" +groups = ["main"] files = [ {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f"}, {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563"}, @@ -2229,6 +2307,7 @@ version = "0.27.0" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, @@ -2253,6 +2332,7 @@ version = "0.23.0" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" optional = false python-versions = ">=3.8.0" +groups = ["main"] files = [ {file = "huggingface_hub-0.23.0-py3-none-any.whl", hash = "sha256:075c30d48ee7db2bba779190dc526d2c11d422aed6f9044c5e2fdc2c432fdb91"}, {file = "huggingface_hub-0.23.0.tar.gz", hash = "sha256:7126dedd10a4c6fac796ced4d87a8cf004efc722a5125c2c09299017fa366fa9"}, @@ -2287,6 +2367,7 @@ version = "10.0" description = "Human friendly output for text interfaces using Python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main"] files = [ {file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"}, {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"}, @@ -2301,6 +2382,7 @@ version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" +groups = ["main", "dev"] files = [ {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, @@ -2312,6 +2394,7 @@ version = "7.1.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, @@ -2331,6 +2414,7 @@ version = "6.29.5" description = "IPython Kernel for Jupyter" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5"}, {file = "ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215"}, @@ -2364,6 +2448,7 @@ version = "8.24.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" +groups = ["dev"] files = [ {file = "ipython-8.24.0-py3-none-any.whl", hash = "sha256:d7bf2f6c4314984e3e02393213bab8703cf163ede39672ce5918c51fe253a2a3"}, {file = "ipython-8.24.0.tar.gz", hash = "sha256:010db3f8a728a578bb641fdd06c063b9fb8e96a9464c63aec6310fbcb5e80501"}, @@ -2402,6 +2487,7 @@ version = "5.13.2" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.8.0" +groups = ["dev"] files = [ {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, @@ -2416,6 +2502,7 @@ version = "2.2.0" description = "Safely pass data to untrusted environments and back." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, @@ -2427,6 +2514,7 @@ version = "0.19.1" description = "An autocompletion tool for Python that can be used for text editors." optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, @@ -2446,6 +2534,7 @@ version = "3.1.4" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, @@ -2463,6 +2552,7 @@ version = "0.6.1" description = "Fast iterable JSON parser." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "jiter-0.6.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d08510593cb57296851080018006dfc394070178d238b767b1879dc1013b106c"}, {file = "jiter-0.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:adef59d5e2394ebbad13b7ed5e0306cceb1df92e2de688824232a91588e77aa7"}, @@ -2545,6 +2635,7 @@ version = "1.0.1" description = "JSON Matching Expressions" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, @@ -2556,6 +2647,7 @@ version = "4.22.0" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"}, {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"}, @@ -2577,6 +2669,7 @@ version = "2023.12.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, @@ -2591,6 +2684,7 @@ version = "8.6.1" description = "Jupyter protocol implementation and client libraries" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "jupyter_client-8.6.1-py3-none-any.whl", hash = "sha256:3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f"}, {file = "jupyter_client-8.6.1.tar.gz", hash = "sha256:e842515e2bab8e19186d89fdfea7abd15e39dd581f94e399f00e2af5a1652d3f"}, @@ -2613,6 +2707,7 @@ version = "5.7.2" description = "Jupyter core package. A base package on which Jupyter projects rely." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"}, {file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"}, @@ -2633,6 +2728,7 @@ version = "31.0.0" description = "Kubernetes python client" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "kubernetes-31.0.0-py2.py3-none-any.whl", hash = "sha256:bf141e2d380c8520eada8b351f4e319ffee9636328c137aa432bc486ca1200e1"}, {file = "kubernetes-31.0.0.tar.gz", hash = "sha256:28945de906c8c259c1ebe62703b56a03b714049372196f854105afe4e6d014c0"}, @@ -2660,6 +2756,7 @@ version = "1.55.2" description = "Library to easily interface with LLM API providers" optional = false python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8" +groups = ["main"] files = [ {file = "litellm-1.55.2-py3-none-any.whl", hash = "sha256:499b2a1713a9fa35cc9ff4bf82ac42f5eb0a675ae9e6909f9d8dcee208181d4a"}, {file = "litellm-1.55.2.tar.gz", hash = "sha256:e410499136ae98f932df152942d8bf9b06f917663d2de25529af761a7260fcd8"}, @@ -2689,6 +2786,7 @@ version = "3.0.0" description = "Python port of markdown-it. Markdown parsing, done right!" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, @@ -2713,6 +2811,7 @@ version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, @@ -2782,6 +2881,7 @@ version = "0.1.7" description = "Inline Matplotlib backend for Jupyter" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, @@ -2796,6 +2896,7 @@ version = "0.1.2" description = "Markdown URL utilities" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, @@ -2807,6 +2908,7 @@ version = "0.1.56" description = "Multimodal Large Language Models" optional = false python-versions = "<4.0,>=3.10" +groups = ["main"] files = [ {file = "mllm-0.1.56-py3-none-any.whl", hash = "sha256:c8142ba49f1a468d7ef632886a438898fad0c59617e44c1746a9604e40c2a360"}, {file = "mllm-0.1.56.tar.gz", hash = "sha256:845a7bde5fc053d4d3df50897e5d9adfce1502b2efd01690d38a0c8b16b135bc"}, @@ -2827,6 +2929,7 @@ version = "6.0.5" description = "multidict implementation" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, @@ -2926,6 +3029,7 @@ version = "1.36.5" description = "Type annotations for boto3 EC2 1.36.5 service generated with mypy-boto3-builder 8.8.0" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "mypy_boto3_ec2-1.36.5-py3-none-any.whl", hash = "sha256:ffa53e0e0fd0b932b9ba6d38f995442a8008b388a70b2790a053be478d7bcf71"}, {file = "mypy_boto3_ec2-1.36.5.tar.gz", hash = "sha256:04a7ae6fe63e0ca000313b69b3dee8f673151e970f03e405d74b110081f9544f"}, @@ -2940,6 +3044,7 @@ version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.5" +groups = ["dev"] files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -2951,6 +3056,7 @@ version = "0.3" description = "" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "namesgenerator-0.3.tar.gz", hash = "sha256:50a03cc15e95edbf88a7ff86179f217f43eb2b2d6ee30fac3e9a20a54985b72e"}, ] @@ -2961,6 +3067,7 @@ version = "1.6.0" description = "Patch asyncio to allow nested event loops" optional = false python-versions = ">=3.5" +groups = ["dev"] files = [ {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, @@ -2972,6 +3079,7 @@ version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" +groups = ["main", "dev"] files = [ {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, @@ -3017,6 +3125,7 @@ version = "3.2.2" description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}, {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"}, @@ -3033,6 +3142,7 @@ version = "1.57.4" description = "The official Python library for the openai API" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "openai-1.57.4-py3-none-any.whl", hash = "sha256:7def1ab2d52f196357ce31b9cfcf4181529ce00838286426bb35be81c035dafb"}, {file = "openai-1.57.4.tar.gz", hash = "sha256:a8f071a3e9198e2818f63aade68e759417b9f62c0971bdb83de82504b70b77f7"}, @@ -3057,6 +3167,7 @@ version = "4.1.0" description = "An OrderedSet is a custom MutableSet that remembers its order, so that every" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "ordered-set-4.1.0.tar.gz", hash = "sha256:694a8e44c87657c59292ede72891eb91d34131f6531463aab3009191c77364a8"}, {file = "ordered_set-4.1.0-py3-none-any.whl", hash = "sha256:046e1132c71fcf3330438a539928932caf51ddbc582496833e23de611de14562"}, @@ -3071,6 +3182,7 @@ version = "0.1.26" description = "A Python client for Orign" optional = false python-versions = "<4.0,>=3.10" +groups = ["main"] files = [ {file = "orign-0.1.26-py3-none-any.whl", hash = "sha256:3724b3279f60cada224ac22c729699bca28b9b0d06b84463f89101f507af2c9f"}, {file = "orign-0.1.26.tar.gz", hash = "sha256:324558f033d6e03f225db3d2142a495ae29fbc56556eef2352e6ddddf5851f6d"}, @@ -3089,6 +3201,7 @@ version = "3.10.3" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "orjson-3.10.3-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9fb6c3f9f5490a3eb4ddd46fc1b6eadb0d6fc16fb3f07320149c3286a1409dd8"}, {file = "orjson-3.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:252124b198662eee80428f1af8c63f7ff077c88723fe206a25df8dc57a57b1fa"}, @@ -3144,6 +3257,7 @@ version = "24.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, @@ -3155,6 +3269,7 @@ version = "3.5.0" description = "SSH2 protocol library" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "paramiko-3.5.0-py3-none-any.whl", hash = "sha256:1fedf06b085359051cd7d0d270cebe19e755a8a921cc2ddbfa647fb0cd7d68f9"}, {file = "paramiko-3.5.0.tar.gz", hash = "sha256:ad11e540da4f55cedda52931f1a3f812a8238a7af7f62a60de538cd80bb28124"}, @@ -3176,6 +3291,7 @@ version = "0.8.4" description = "A Python Parser" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, @@ -3191,6 +3307,7 @@ version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, @@ -3202,6 +3319,8 @@ version = "4.9.0" description = "Pexpect allows easy control of interactive console applications." optional = false python-versions = "*" +groups = ["dev"] +markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\"" files = [ {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, @@ -3216,6 +3335,7 @@ version = "10.4.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}, {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"}, @@ -3313,6 +3433,7 @@ version = "4.2.2" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, @@ -3329,6 +3450,7 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -3344,6 +3466,7 @@ version = "3.0.43" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" +groups = ["dev"] files = [ {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, @@ -3358,6 +3481,7 @@ version = "1.23.0" description = "Beautiful, Pythonic protocol buffers." optional = false python-versions = ">=3.6" +groups = ["main", "dev"] files = [ {file = "proto-plus-1.23.0.tar.gz", hash = "sha256:89075171ef11988b3fa157f5dbd8b9cf09d65fffee97e29ce403cd8defba19d2"}, {file = "proto_plus-1.23.0-py3-none-any.whl", hash = "sha256:a829c79e619e1cf632de091013a4173deed13a55f326ef84f05af6f50ff4c82c"}, @@ -3375,6 +3499,7 @@ version = "4.25.3" description = "" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"}, {file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"}, @@ -3395,6 +3520,7 @@ version = "5.9.8" description = "Cross-platform lib for process and system monitoring in Python." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +groups = ["main", "dev"] files = [ {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, @@ -3423,6 +3549,7 @@ version = "2.9.10" description = "psycopg2 - Python-PostgreSQL Database Adapter" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "psycopg2-binary-2.9.10.tar.gz", hash = "sha256:4b3df0e6990aa98acda57d983942eff13d824135fe2250e6522edaa782a06de2"}, {file = "psycopg2_binary-2.9.10-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:0ea8e3d0ae83564f2fc554955d327fa081d065c8ca5cc6d2abb643e2c9c1200f"}, @@ -3500,6 +3627,8 @@ version = "0.7.0" description = "Run a subprocess in a pseudo terminal" optional = false python-versions = "*" +groups = ["dev"] +markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\"" files = [ {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, @@ -3511,6 +3640,7 @@ version = "0.2.2" description = "Safely evaluate AST nodes without side effects" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, @@ -3525,6 +3655,7 @@ version = "0.6.0" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "pyasn1-0.6.0-py2.py3-none-any.whl", hash = "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473"}, {file = "pyasn1-0.6.0.tar.gz", hash = "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c"}, @@ -3536,6 +3667,7 @@ version = "0.4.0" description = "A collection of ASN.1-based protocols modules" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "pyasn1_modules-0.4.0-py3-none-any.whl", hash = "sha256:be04f15b66c206eed667e0bb5ab27e2b1855ea54a842e5037738099e8ca4ae0b"}, {file = "pyasn1_modules-0.4.0.tar.gz", hash = "sha256:831dbcea1b177b28c9baddf4c6d1013c24c3accd14a1873fffaa6a2e905f17b6"}, @@ -3550,6 +3682,7 @@ version = "1.14.0" description = "Pure python ISO manipulation library" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "pycdlib-1.14.0-py2.py3-none-any.whl", hash = "sha256:a905827335f0066af3fd416c5cf9b1f29dffaf4d0914b714555213d1809f38d4"}, {file = "pycdlib-1.14.0.tar.gz", hash = "sha256:8ec306b31d9c850f28c5fda52438d904edd1e8fcf862c5ffd756272efac9f422"}, @@ -3561,10 +3694,12 @@ version = "2.22" description = "C parser in Python" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] +markers = {dev = "implementation_name == \"pypy\""} [[package]] name = "pydantic" @@ -3572,6 +3707,7 @@ version = "2.10.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "pydantic-2.10.3-py3-none-any.whl", hash = "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d"}, {file = "pydantic-2.10.3.tar.gz", hash = "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9"}, @@ -3592,6 +3728,7 @@ version = "2.27.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "pydantic_core-2.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a"}, {file = "pydantic_core-2.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b"}, @@ -3704,6 +3841,7 @@ version = "2.7.0" description = "Extra Pydantic types." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pydantic_extra_types-2.7.0-py3-none-any.whl", hash = "sha256:ac01bbdaa4f85e4c4744a9792c5b0cfe61efa5028a0e670c3d8bfbf8b36c8543"}, {file = "pydantic_extra_types-2.7.0.tar.gz", hash = "sha256:b9d9ddd755fa5960ec5a77cffcbd5d8796a0116e1dfc8f7c3a27fa0041693382"}, @@ -3721,6 +3859,7 @@ version = "2.2.1" description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pydantic_settings-2.2.1-py3-none-any.whl", hash = "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091"}, {file = "pydantic_settings-2.2.1.tar.gz", hash = "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed"}, @@ -3740,6 +3879,7 @@ version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, @@ -3754,6 +3894,7 @@ version = "1.5.0" description = "Python binding to the Networking and Cryptography (NaCl) library" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, @@ -3780,6 +3921,7 @@ version = "1.6.1" description = "API to interact with the python pyproject.toml based projects" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pyproject_api-1.6.1-py3-none-any.whl", hash = "sha256:4c0116d60476b0786c88692cf4e325a9814965e2469c5998b830bba16b183675"}, {file = "pyproject_api-1.6.1.tar.gz", hash = "sha256:1817dc018adc0d1ff9ca1ed8c60e1623d5aaca40814b953af14a9cf9a5cae538"}, @@ -3799,6 +3941,8 @@ version = "3.4.1" description = "A python implementation of GNU readline." optional = false python-versions = "*" +groups = ["main"] +markers = "sys_platform == \"win32\"" files = [ {file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"}, {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"}, @@ -3810,6 +3954,7 @@ version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main", "dev"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -3824,6 +3969,7 @@ version = "1.0.1" description = "Read key-value pairs from a .env file and set them as environment variables" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, @@ -3838,6 +3984,7 @@ version = "0.0.9" description = "A streaming multipart parser for Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "python_multipart-0.0.9-py3-none-any.whl", hash = "sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215"}, {file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"}, @@ -3852,6 +3999,7 @@ version = "306" description = "Python for Window Extensions" optional = false python-versions = "*" +groups = ["main", "dev"] files = [ {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, @@ -3868,6 +4016,7 @@ files = [ {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, ] +markers = {main = "sys_platform == \"win32\"", dev = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} [[package]] name = "pyyaml" @@ -3875,6 +4024,7 @@ version = "6.0.2" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, @@ -3937,6 +4087,7 @@ version = "26.0.3" description = "Python bindings for 0MQ" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:44dd6fc3034f1eaa72ece33588867df9e006a7303725a12d64c3dff92330f625"}, {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:acb704195a71ac5ea5ecf2811c9ee19ecdc62b91878528302dd0be1b9451cc90"}, @@ -4037,6 +4188,7 @@ version = "5.2.1" description = "Python client for Redis database and key-value store" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "redis-5.2.1-py3-none-any.whl", hash = "sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4"}, {file = "redis-5.2.1.tar.gz", hash = "sha256:16f2e22dff21d5125e8481515e386711a34cbec50f0e44413dd7d9c060a54e0f"}, @@ -4055,6 +4207,7 @@ version = "0.35.1" description = "JSON Referencing + Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, @@ -4070,6 +4223,7 @@ version = "2024.5.15" description = "Alternative regular expression module, to replace re." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "regex-2024.5.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a81e3cfbae20378d75185171587cbf756015ccb14840702944f014e0d93ea09f"}, {file = "regex-2024.5.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7b59138b219ffa8979013be7bc85bb60c6f7b7575df3d56dc1e403a438c7a3f6"}, @@ -4158,6 +4312,7 @@ version = "2.31.0" description = "Python HTTP for Humans." optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, @@ -4179,6 +4334,7 @@ version = "2.0.0" description = "OAuthlib authentication support for Requests." optional = false python-versions = ">=3.4" +groups = ["main"] files = [ {file = "requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9"}, {file = "requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36"}, @@ -4197,6 +4353,7 @@ version = "13.7.1" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.7.0" +groups = ["main"] files = [ {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, @@ -4215,6 +4372,7 @@ version = "0.1.1" description = "Python project/package root path detection." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "rootpath-0.1.1-py3-none-any.whl", hash = "sha256:98f417747b3e25d2ad1e94a555d7562b48f642cbdf993dabc61259170720ed45"}, {file = "rootpath-0.1.1.tar.gz", hash = "sha256:ecc3f9de280ff11c6ade0e956229e4dcb74c1ead5efde8579ba721e6459c518f"}, @@ -4237,6 +4395,7 @@ version = "0.18.1" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"}, {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"}, @@ -4345,6 +4504,7 @@ version = "4.9" description = "Pure-Python RSA implementation" optional = false python-versions = ">=3.6,<4" +groups = ["main", "dev"] files = [ {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, @@ -4359,6 +4519,7 @@ version = "0.6.5" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "ruff-0.6.5-py3-none-linux_armv6l.whl", hash = "sha256:7e4e308f16e07c95fc7753fc1aaac690a323b2bb9f4ec5e844a97bb7fbebd748"}, {file = "ruff-0.6.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:932cd69eefe4daf8c7d92bd6689f7e8182571cb934ea720af218929da7bd7d69"}, @@ -4386,6 +4547,7 @@ version = "0.11.2" description = "An Amazon S3 Transfer Manager" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "s3transfer-0.11.2-py3-none-any.whl", hash = "sha256:be6ecb39fadd986ef1701097771f87e4d2f821f27f6071c872143884d2950fbc"}, {file = "s3transfer-0.11.2.tar.gz", hash = "sha256:3b39185cb72f5acc77db1a58b6e25b977f28d20496b6e58d6813d75f464d632f"}, @@ -4403,6 +4565,7 @@ version = "2.0.4" description = "Manipulation and analysis of geometric objects" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "shapely-2.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:011b77153906030b795791f2fdfa2d68f1a8d7e40bce78b029782ade3afe4f2f"}, {file = "shapely-2.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9831816a5d34d5170aa9ed32a64982c3d6f4332e7ecfe62dc97767e163cb0b17"}, @@ -4460,6 +4623,7 @@ version = "1.0.13" description = "A generator library for concise, unambiguous and URL-safe UUIDs." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "shortuuid-1.0.13-py3-none-any.whl", hash = "sha256:a482a497300b49b4953e15108a7913244e1bb0d41f9d332f5e9925dba33a3c5a"}, {file = "shortuuid-1.0.13.tar.gz", hash = "sha256:3bb9cf07f606260584b1df46399c0b87dd84773e7b25912b7e391e30797c5e72"}, @@ -4471,6 +4635,7 @@ version = "1.16.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main", "dev"] files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, @@ -4482,6 +4647,7 @@ version = "0.1.119" description = "Pluggable skills for AI agents" optional = false python-versions = "<4.0,>=3.10" +groups = ["main"] files = [ {file = "skillpacks-0.1.119-py3-none-any.whl", hash = "sha256:84c386a1147990556ed3893b8b5ef9880ed5a9cfa3c96ed5302aa133446a56f9"}, {file = "skillpacks-0.1.119.tar.gz", hash = "sha256:730a6c31b4c92485f7d2dcbdb52246161c0c6145a98e8d00cf94406e5bd7ae89"}, @@ -4501,6 +4667,7 @@ version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, @@ -4512,6 +4679,7 @@ version = "2.0.30" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "SQLAlchemy-2.0.30-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3b48154678e76445c7ded1896715ce05319f74b1e73cf82d4f8b59b46e9c0ddc"}, {file = "SQLAlchemy-2.0.30-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2753743c2afd061bb95a61a51bbb6a1a11ac1c44292fad898f10c9839a7f75b2"}, @@ -4599,6 +4767,7 @@ version = "0.6.3" description = "Extract data from python stack frames and tracebacks for informative displays" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, @@ -4618,6 +4787,7 @@ version = "0.36.3" description = "The little ASGI library that shines." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "starlette-0.36.3-py3-none-any.whl", hash = "sha256:13d429aa93a61dc40bf503e8c801db1f1bca3dc706b10ef2434a36123568f044"}, {file = "starlette-0.36.3.tar.gz", hash = "sha256:90a671733cfb35771d8cc605e0b679d23b992f8dcfad48cc60b38cb29aeb7080"}, @@ -4635,6 +4805,7 @@ version = "0.9.0" description = "Pretty-print tabular data" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, @@ -4649,6 +4820,7 @@ version = "0.1.227" description = "Task management for AI agents" optional = false python-versions = "<4.0,>=3.10" +groups = ["main"] files = [ {file = "taskara-0.1.227-py3-none-any.whl", hash = "sha256:e9b4b7ac712357cf62f078e0d06aa81e2091e6eafcc508cfc94acd28833fa737"}, {file = "taskara-0.1.227.tar.gz", hash = "sha256:52c238dc5df8680b426ebb16b0f83ae75410af03b9a0733cb794728c6b7f5bd5"}, @@ -4677,6 +4849,7 @@ version = "8.3.0" description = "Retry code until it succeeds" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "tenacity-8.3.0-py3-none-any.whl", hash = "sha256:3649f6443dbc0d9b01b9d8020a9c4ec7a1ff5f6f3c6c8a036ef371f573fe9185"}, {file = "tenacity-8.3.0.tar.gz", hash = "sha256:953d4e6ad24357bceffbc9707bc74349aca9d245f68eb65419cf0c249a1949a2"}, @@ -4692,6 +4865,7 @@ version = "2.4.0" description = "ANSI color formatting for output in terminal" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"}, {file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"}, @@ -4706,6 +4880,7 @@ version = "0.2.37" description = "Thread memory for AI agents" optional = false python-versions = "<4.0,>=3.10" +groups = ["main"] files = [ {file = "threadmem-0.2.37-py3-none-any.whl", hash = "sha256:1d5d0c4ab8345c11814ab40f5274bf2c77364c99b0033a6f3c4925fbfbcfeb3a"}, {file = "threadmem-0.2.37.tar.gz", hash = "sha256:5a5abfc3cc7376101a27fd996d8f020012cb1302bcddc90ab1d875050708dc18"}, @@ -4727,6 +4902,7 @@ version = "0.8.0" description = "tiktoken is a fast BPE tokeniser for use with OpenAI's models" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "tiktoken-0.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b07e33283463089c81ef1467180e3e00ab00d46c2c4bbcef0acab5f771d6695e"}, {file = "tiktoken-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9269348cb650726f44dd3bbb3f9110ac19a8dcc8f54949ad3ef652ca22a38e21"}, @@ -4774,6 +4950,7 @@ version = "0.19.1" description = "" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "tokenizers-0.19.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:952078130b3d101e05ecfc7fc3640282d74ed26bcf691400f872563fca15ac97"}, {file = "tokenizers-0.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82c8b8063de6c0468f08e82c4e198763e7b97aabfe573fd4cf7b33930ca4df77"}, @@ -4891,6 +5068,8 @@ version = "2.0.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] +markers = "python_version < \"3.11\"" files = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, @@ -4902,6 +5081,7 @@ version = "0.1.0" description = "Core utilities for AI agent tools" optional = false python-versions = "<4.0,>=3.8" +groups = ["main"] files = [ {file = "toolcore-0.1.0-py3-none-any.whl", hash = "sha256:4460b62ff9c711b076cc4823445ffe83edc91dbea0fdb5846bfdc6d7abafa171"}, {file = "toolcore-0.1.0.tar.gz", hash = "sha256:dcde76acc9ec43f9cce88d9fba5bc71c3b25d654b11ce81f719de621f73ec7a0"}, @@ -4917,6 +5097,7 @@ version = "0.1.25" description = "Tools for AI agents" optional = false python-versions = "<4.0,>=3.10" +groups = ["main"] files = [ {file = "toolfuse-0.1.25-py3-none-any.whl", hash = "sha256:144d6b97441cb93cf9ca33c405732fdeba33cb2441dc1f8978e7c2e450497aee"}, {file = "toolfuse-0.1.25.tar.gz", hash = "sha256:54948d6b4faf2fd2837e33534629db8fc3bcd1fbeb2d643ceb691b6b776dad59"}, @@ -4936,6 +5117,7 @@ version = "6.4" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." optional = false python-versions = ">= 3.8" +groups = ["dev"] files = [ {file = "tornado-6.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0"}, {file = "tornado-6.4-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263"}, @@ -4956,6 +5138,7 @@ version = "4.15.0" description = "tox is a generic virtualenv management and test command line tool" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "tox-4.15.0-py3-none-any.whl", hash = "sha256:300055f335d855b2ab1b12c5802de7f62a36d4fd53f30bd2835f6a201dda46ea"}, {file = "tox-4.15.0.tar.gz", hash = "sha256:7a0beeef166fbe566f54f795b4906c31b428eddafc0102ac00d20998dd1933f6"}, @@ -4983,6 +5166,7 @@ version = "4.66.4" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "tqdm-4.66.4-py3-none-any.whl", hash = "sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644"}, {file = "tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb"}, @@ -5003,6 +5187,7 @@ version = "5.14.3" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, @@ -5018,6 +5203,7 @@ version = "0.9.4" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "typer-0.9.4-py3-none-any.whl", hash = "sha256:aa6c4a4e2329d868b80ecbaf16f807f2b54e192209d7ac9dd42691d63f7a54eb"}, {file = "typer-0.9.4.tar.gz", hash = "sha256:f714c2d90afae3a7929fcd72a3abb08df305e1ff61719381384211c4070af57f"}, @@ -5039,6 +5225,7 @@ version = "0.23.8" description = "Type annotations and code completion for awscrt" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "types_awscrt-0.23.8-py3-none-any.whl", hash = "sha256:d66b3817565769f5311b7e171a3c48d3dbf8a8f9c22f02686c2f003b6559a2a5"}, {file = "types_awscrt-0.23.8.tar.gz", hash = "sha256:2141391a8f4d36cf098406c19d9060b34f13a558c22d4aadac250a0c57d12710"}, @@ -5050,6 +5237,7 @@ version = "0.11.2" description = "Type annotations and code completion for s3transfer" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "types_s3transfer-0.11.2-py3-none-any.whl", hash = "sha256:09c31cff8c79a433fcf703b840b66d1f694a6c70c410ef52015dd4fe07ee0ae2"}, {file = "types_s3transfer-0.11.2.tar.gz", hash = "sha256:3ccb8b90b14434af2fb0d6c08500596d93f3a83fb804a2bb843d9bf4f7c2ca60"}, @@ -5061,6 +5249,7 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -5072,6 +5261,7 @@ version = "5.10.0" description = "Ultra fast JSON encoder and decoder for Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "ujson-5.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2601aa9ecdbee1118a1c2065323bda35e2c5a2cf0797ef4522d485f9d3ef65bd"}, {file = "ujson-5.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:348898dd702fc1c4f1051bc3aacbf894caa0927fe2c53e68679c073375f732cf"}, @@ -5159,6 +5349,7 @@ version = "1.26.18" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +groups = ["main", "dev"] files = [ {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, @@ -5175,6 +5366,7 @@ version = "0.29.0" description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "uvicorn-0.29.0-py3-none-any.whl", hash = "sha256:2c2aac7ff4f4365c206fd773a39bf4ebd1047c238f8b8268ad996829323473de"}, {file = "uvicorn-0.29.0.tar.gz", hash = "sha256:6a69214c0b6a087462412670b3ef21224fa48cae0e452b5883e8e8bdfdd11dd0"}, @@ -5201,6 +5393,8 @@ version = "0.19.0" description = "Fast implementation of asyncio event loop on top of libuv" optional = false python-versions = ">=3.8.0" +groups = ["main"] +markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\"" files = [ {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e"}, {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428"}, @@ -5245,6 +5439,7 @@ version = "20.26.2" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"}, {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"}, @@ -5265,6 +5460,7 @@ version = "0.21.0" description = "Simple, modern and high performance file watching and code reload in python." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "watchfiles-0.21.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:27b4035013f1ea49c6c0b42d983133b136637a527e48c132d368eb19bf1ac6aa"}, {file = "watchfiles-0.21.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c81818595eff6e92535ff32825f31c116f867f64ff8cdf6562cd1d6b2e1e8f3e"}, @@ -5352,6 +5548,7 @@ version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, @@ -5363,6 +5560,7 @@ version = "1.8.0" description = "WebSocket client for Python with low level API options" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526"}, {file = "websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da"}, @@ -5379,6 +5577,7 @@ version = "13.1" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"}, {file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"}, @@ -5474,6 +5673,7 @@ version = "1.9.4" description = "Yet another URL library" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, @@ -5577,6 +5777,7 @@ version = "3.18.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "zipp-3.18.2-py3-none-any.whl", hash = "sha256:dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e"}, {file = "zipp-3.18.2.tar.gz", hash = "sha256:6278d9ddbcfb1f1089a88fde84481528b07b0e10474e09dcfe53dad4069fa059"}, @@ -5587,6 +5788,6 @@ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.link testing = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.10" content-hash = "b1bc9f6453a40105bb146507b51972547e6b05a77d188cbb139a5400404e3014" diff --git a/pyproject.toml b/pyproject.toml index 213bff5..db63bb8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "surfkit" -version = "0.1.393" +version = "0.1.394" description = "A toolkit for building AI agents that use devices" authors = ["Patrick Barker ", "Jeffrey Huckabay "] license = "MIT" diff --git a/surfkit/runtime/agent/kube.py b/surfkit/runtime/agent/kube.py index a6a5696..d8c7921 100644 --- a/surfkit/runtime/agent/kube.py +++ b/surfkit/runtime/agent/kube.py @@ -4,16 +4,14 @@ import logging import os import signal -import socket import subprocess import sys import threading import traceback -import urllib.error -import urllib.parse -import urllib.request from typing import Dict, Iterator, List, Literal, Optional, Tuple, Type, Union +import httpx + def custom_thread_excepthook(args): # Format the traceback @@ -34,14 +32,10 @@ def custom_thread_excepthook(args): from google.cloud import container_v1 from google.oauth2 import service_account from kubernetes import client, config -from kubernetes.client import Configuration -from kubernetes.client.api import core_v1_api from kubernetes.client.rest import ApiException -from kubernetes.stream import portforward from mllm import Router from namesgenerator import get_random_name from pydantic import BaseModel -from taskara.server.models import V1Task from tenacity import retry, stop_after_attempt, wait_fixed from surfkit.server.models import ( @@ -75,14 +69,9 @@ def my_proxy_override(self, *args, **kwargs): ws_client.PortForward._proxy = my_proxy_override - logger = logging.getLogger(__name__) -class APIOpts(BaseModel): - url: str - - class GKEOpts(BaseModel): cluster_name: str region: str @@ -94,27 +83,21 @@ class LocalOpts(BaseModel): class KubeConnectConfig(BaseModel): - provider: Literal["api", "gke", "local"] = "local" + provider: Literal["gke", "local"] = "local" namespace: str = "default" - api_opts: Optional[APIOpts] = None gke_opts: Optional[GKEOpts] = None local_opts: Optional[LocalOpts] = None + branch: Optional[str] = None class KubeAgentRuntime(AgentRuntime["KubeAgentRuntime", KubeConnectConfig]): """A container runtime that uses Kubernetes to manage Pods directly""" def __init__(self, cfg: Optional[KubeConnectConfig] = None) -> None: - # Load the Kubernetes configuration, typically from ~/.kube/config - if not cfg: - cfg = KubeConnectConfig() - self.cfg = cfg - if cfg.provider == "api": - opts = cfg.api_opts - if not opts: - raise ValueError("API opts missing") - self.connect_to_api(opts) - elif cfg.provider == "gke": + self.cfg = cfg or KubeConnectConfig() + + self.kubeconfig = None + if cfg.provider == "gke": opts = cfg.gke_opts if not opts: raise ValueError("GKE opts missing") @@ -125,14 +108,19 @@ def __init__(self, cfg: Optional[KubeConnectConfig] = None) -> None: opts = LocalOpts() if opts.path: config.load_kube_config(opts.path) + self.kubeconfig = opts.path else: raise ValueError("Unsupported provider: " + cfg.provider) - self.core_api = core_v1_api.CoreV1Api() + self.core_api = client.CoreV1Api() + self.namespace = cfg.namespace + self.subprocesses = [] self.setup_signal_handlers() + self.branch = cfg.branch + @classmethod def name(cls) -> str: return "kube" @@ -299,13 +287,6 @@ def connect_config(self) -> KubeConnectConfig: def connect(cls, cfg: KubeConnectConfig) -> "KubeAgentRuntime": return cls(cfg) - def connect_to_api(self, opts: APIOpts) -> Tuple[client.CoreV1Api, str, str]: - configuration = client.Configuration() - configuration.host = opts.url - api_client = client.ApiClient(configuration) - v1_client = client.CoreV1Api(api_client) - return v1_client, "unknown", "anonymous" - @retry(stop=stop_after_attempt(15)) def connect_to_gke(self, opts: GKEOpts) -> Tuple[client.CoreV1Api, str, str]: """ @@ -451,155 +432,51 @@ def call( data: Optional[dict] = None, headers: Optional[dict] = None, ) -> Tuple[int, str]: - c = Configuration.get_default_copy() - c.assert_hostname = False # type: ignore - Configuration.set_default(c) - core_v1 = client.CoreV1Api() - ############################################################################## - # Kubernetes pod port forwarding works by directly providing a socket which - # the python application uses to send and receive data on. This is in contrast - # to the go client, which opens a local port that the go application then has - # to open to get a socket to transmit data. - # - # This simplifies the python application, there is not a local port to worry - # about if that port number is available. Nor does the python application have - # to then deal with opening this local port. The socket used to transmit data - # is immediately provided to the python application. - # - # Below also is an example of monkey patching the socket.create_connection - # function so that DNS names of the following formats will access kubernetes - # ports: - # - # ..kubernetes - # .pod..kubernetes - # .svc..kubernetes - # .service..kubernetes - # - # These DNS name can be used to interact with pod ports using python libraries, - # such as urllib.request and http.client. For example: - # - # response = urllib.request.urlopen( - # 'https://metrics-server.service.kube-system.kubernetes/' - # ) - # - ############################################################################## - - # Monkey patch socket.create_connection which is used by http.client and - # urllib.request. The same can be done with urllib3.util.connection.create_connection - # if the "requests" package is used. - socket_create_connection = socket.create_connection - - def kubernetes_create_connection(address, *args, **kwargs): - dns_name = address[0] - if isinstance(dns_name, bytes): - dns_name = dns_name.decode() - dns_name = dns_name.split(".") - if dns_name[-1] != "kubernetes": - return socket_create_connection(address, *args, **kwargs) - if len(dns_name) not in (3, 4): - raise RuntimeError("Unexpected kubernetes DNS name.") - namespace = dns_name[-2] - name = dns_name[0] - port = address[1] - # print("connecting to: ", namespace, name, port) - if len(dns_name) == 4: - if dns_name[1] in ("svc", "service"): - service = core_v1.read_namespaced_service(name, namespace) - for service_port in service.spec.ports: # type: ignore - if service_port.port == port: - port = service_port.target_port - break - else: - raise RuntimeError(f"Unable to find service port: {port}") - label_selector = [] - for key, value in service.spec.selector.items(): # type: ignore - label_selector.append(f"{key}={value}") - pods = core_v1.list_namespaced_pod( - namespace, label_selector=",".join(label_selector) - ) - if not pods.items: - raise RuntimeError("Unable to find service pods.") - name = pods.items[0].metadata.name - if isinstance(port, str): - for container in pods.items[0].spec.containers: - for container_port in container.ports: - if container_port.name == port: - port = container_port.container_port - break - else: - continue - break - else: - raise RuntimeError( - f"Unable to find service port name: {port}" - ) - elif dns_name[1] != "pod": - raise RuntimeError(f"Unsupported resource type: {dns_name[1]}") - pf = portforward( - core_v1.connect_get_namespaced_pod_portforward, - name, - namespace, - ports=str(port), + data = data or {} + headers = headers or {} + + workload_proxy_url = os.getenv("WORKLOAD_PROXY_URL") + if workload_proxy_url is not None: + print("Using workload proxy at", workload_proxy_url) + client_cert = os.getenv("WORKLOAD_PROXY_CLIENT_CERT") + client_key = os.getenv("WORKLOAD_PROXY_CLIENT_KEY") + ca_cert = os.getenv("WORKLOAD_PROXY_CA_CERT") + + workload_proxy_client = httpx.Client( + verify=ca_cert, cert=(client_cert, client_key) ) - return pf.socket(port) - - socket.create_connection = kubernetes_create_connection - - namespace = self.namespace - if not namespace: - raise ValueError("NAMESPACE environment variable not set") - # Access the nginx http server using the - # ".pod..kubernetes" dns name. - # Construct the URL with the custom path - print( - f"connecting to: {name.lower()}.pod.{namespace}.kubernetes:{port}{path}", - flush=True, - ) - url = f"http://{name.lower()}.pod.{namespace}.kubernetes:{port}{path}" - - # Create a request object based on the HTTP method - if method.upper() == "GET": - if data: - # Convert data to URL-encoded query parameters for GET requests - query_params = urllib.parse.urlencode(data) - url += f"?{query_params}" - request = urllib.request.Request(url) + + merged_headers = { + **headers, + "X-Pod-Name": name, + "X-Namespace": self.cfg.namespace, + "X-Port": str(port), + } else: - # Set the request method and data for POST, PUT, etc. - request = urllib.request.Request(url, method=method.upper()) - if data: - # Convert data to JSON string and set the request body - request.add_header("Content-Type", "application/json") - if headers: - for k, v in headers.items(): - request.add_header(k, v) - request.data = json.dumps(data).encode("utf-8") - logger.debug(f"Request Data: {request.data}") - - # Send the request and handle the response - try: - response = urllib.request.urlopen(request) - status_code = response.code - response_text = response.read().decode("utf-8") - logger.debug(f"Status Code: {status_code}") - - # Parse the JSON response and return a dictionary - return status_code, response_text - except urllib.error.HTTPError as e: - status_code = e.code - error_message = e.read().decode("utf-8") - logger.error(f"Error: {status_code}") - logger.error(error_message) - - raise SystemError( - f"Error making http request kubernetes pod {status_code}: {error_message}" + print("Using direct connection to workload service") + workload_proxy_client = httpx.Client() + merged_headers = headers + workload_proxy_url = ( + f"http://{name}.{self.cfg.namespace}.svc.cluster.local:{port}" ) - finally: - try: - if response: # type: ignore - response.close() - except: - pass + + json_data = None if method == "GET" else data + query_parameters = "" + if method == "GET" and data: + query_parameters = "?" + "&".join([f"{k}={v}" for k, v in data.items()]) + + url = f"{workload_proxy_url.rstrip('/')}/{path.lstrip('/')}" + query_parameters + + print("Method: ", method) + print("URL: ", url) + print("Headers: ", merged_headers) + print("JSON Data: ", json_data) + + r = workload_proxy_client.request( + method=method, url=url, headers=merged_headers, json=json_data + ) + + return r.status_code, r.text def setup_signal_handlers(self): signal.signal(signal.SIGINT, self.graceful_exit) diff --git a/surfkit/runtime/container/kube.py b/surfkit/runtime/container/kube.py index 2577198..530b714 100644 --- a/surfkit/runtime/container/kube.py +++ b/surfkit/runtime/container/kube.py @@ -1,20 +1,14 @@ import base64 import json import os -import socket -import urllib.error -import urllib.parse -import urllib.request from typing import Literal, List, Optional, Tuple, Type +import httpx from google.auth.transport.requests import Request from google.cloud import container_v1 from google.oauth2 import service_account -from kubernetes import client, config, stream -from kubernetes.client import Configuration -from kubernetes.client.api import core_v1_api +from kubernetes import client, config from kubernetes.client.rest import ApiException -from kubernetes.stream import portforward from namesgenerator import get_random_name from pydantic import BaseModel from tenacity import retry, stop_after_attempt @@ -22,10 +16,6 @@ from .base import ContainerRuntime -class APIOpts(BaseModel): - url: str - - class GKEOpts(BaseModel): cluster_name: str region: str @@ -33,28 +23,43 @@ class GKEOpts(BaseModel): class LocalOpts(BaseModel): - path: Optional[str] = os.getenv("KUBECONFIG") + path: Optional[str] = os.getenv("KUBECONFIG", os.path.expanduser("~/.kube/config")) class ConnectConfig(BaseModel): - provider: Literal["api", "gke", "local"] = "local" + provider: Literal["gke", "local"] = "local" namespace: str = "default" - api_opts: Optional[APIOpts] = None gke_opts: Optional[GKEOpts] = None local_opts: Optional[LocalOpts] = None + branch: Optional[str] = None + + +def gke_opts_from_env( + gke_sa_json=os.getenv("GKE_SA_JSON"), + cluster_name=os.getenv("CLUSTER_NAME"), + region=os.getenv("CLUSTER_REGION"), +) -> GKEOpts: + if not gke_sa_json: + raise ValueError("GKE_SA_JSON not set") + if not cluster_name: + raise ValueError("CLUSTER_NAME not set") + if not region: + raise ValueError("CLUSTER_REGION not set") + return GKEOpts( + service_account_json=gke_sa_json, + cluster_name=cluster_name, + region=region, + ) class KubernetesRuntime(ContainerRuntime): """A container runtime that uses Kubernetes to manage Pods directly""" def __init__(self, cfg: ConnectConfig) -> None: - # Load the Kubernetes configuration, typically from ~/.kube/config - if cfg.provider == "api": - opts = cfg.api_opts - if not opts: - raise ValueError("API opts missing") - self.connect_to_api(opts) - elif cfg.provider == "gke": + self.cfg = cfg or ConnectConfig() + + self.kubeconfig = None + if cfg.provider == "gke": opts = cfg.gke_opts if not opts: raise ValueError("GKE opts missing") @@ -62,15 +67,19 @@ def __init__(self, cfg: ConnectConfig) -> None: elif cfg.provider == "local": opts = cfg.local_opts if not opts: - raise ValueError("Local opts missing") + opts = LocalOpts() if opts.path: config.load_kube_config(opts.path) + self.kubeconfig = opts.path else: raise ValueError("Unsupported provider: " + cfg.provider) - self.core_api = core_v1_api.CoreV1Api() + self.core_api = client.CoreV1Api() + self.namespace = cfg.namespace + self.branch = cfg.branch + @classmethod def name(cls) -> str: return "kube" @@ -147,13 +156,6 @@ def connect_config_type(cls) -> Type[ConnectConfig]: def connect(cls, cfg: ConnectConfig) -> "KubernetesRuntime": return cls(cfg) - def connect_to_api(self, opts: APIOpts) -> Tuple[client.CoreV1Api, str, str]: - configuration = client.Configuration() - configuration.host = opts.url - api_client = client.ApiClient(configuration) - v1_client = client.CoreV1Api(api_client) - return v1_client, "unknown", "anonymous" - @retry(stop=stop_after_attempt(15)) def connect_to_gke(self, opts: GKEOpts) -> Tuple[client.CoreV1Api, str, str]: """ @@ -246,152 +248,51 @@ def call( data: Optional[dict] = None, headers: Optional[dict] = None, ) -> Tuple[int, str]: - - c = Configuration.get_default_copy() - c.assert_hostname = False # type: ignore - Configuration.set_default(c) - core_v1 = client.CoreV1Api() - ############################################################################## - # Kubernetes pod port forwarding works by directly providing a socket which - # the python application uses to send and receive data on. This is in contrast - # to the go client, which opens a local port that the go application then has - # to open to get a socket to transmit data. - # - # This simplifies the python application, there is not a local port to worry - # about if that port number is available. Nor does the python application have - # to then deal with opening this local port. The socket used to transmit data - # is immediately provided to the python application. - # - # Below also is an example of monkey patching the socket.create_connection - # function so that DNS names of the following formats will access kubernetes - # ports: - # - # ..kubernetes - # .pod..kubernetes - # .svc..kubernetes - # .service..kubernetes - # - # These DNS name can be used to interact with pod ports using python libraries, - # such as urllib.request and http.client. For example: - # - # response = urllib.request.urlopen( - # 'https://metrics-server.service.kube-system.kubernetes/' - # ) - # - ############################################################################## - - # Monkey patch socket.create_connection which is used by http.client and - # urllib.request. The same can be done with urllib3.util.connection.create_connection - # if the "requests" package is used. - socket_create_connection = socket.create_connection - - def kubernetes_create_connection(address, *args, **kwargs): - dns_name = address[0] - if isinstance(dns_name, bytes): - dns_name = dns_name.decode() - dns_name = dns_name.split(".") - if dns_name[-1] != "kubernetes": - return socket_create_connection(address, *args, **kwargs) - if len(dns_name) not in (3, 4): - raise RuntimeError("Unexpected kubernetes DNS name.") - namespace = dns_name[-2] - name = dns_name[0] - port = address[1] - print("connecting to: ", namespace, name, port) - if len(dns_name) == 4: - if dns_name[1] in ("svc", "service"): - service = core_v1.read_namespaced_service(name, namespace) - for service_port in service.spec.ports: # type: ignore - if service_port.port == port: - port = service_port.target_port - break - else: - raise RuntimeError(f"Unable to find service port: {port}") - label_selector = [] - for key, value in service.spec.selector.items(): # type: ignore - label_selector.append(f"{key}={value}") - pods = core_v1.list_namespaced_pod( - namespace, label_selector=",".join(label_selector) - ) - if not pods.items: - raise RuntimeError("Unable to find service pods.") - name = pods.items[0].metadata.name - if isinstance(port, str): - for container in pods.items[0].spec.containers: - for container_port in container.ports: - if container_port.name == port: - port = container_port.container_port - break - else: - continue - break - else: - raise RuntimeError( - f"Unable to find service port name: {port}" - ) - elif dns_name[1] != "pod": - raise RuntimeError(f"Unsupported resource type: {dns_name[1]}") - pf = portforward( - core_v1.connect_get_namespaced_pod_portforward, - name, - namespace, - ports=str(port), + data = data or {} + headers = headers or {} + + workload_proxy_url = os.getenv("WORKLOAD_PROXY_URL") + if workload_proxy_url is not None: + print("Using workload proxy at", workload_proxy_url) + client_cert = os.getenv("WORKLOAD_PROXY_CLIENT_CERT") + client_key = os.getenv("WORKLOAD_PROXY_CLIENT_KEY") + ca_cert = os.getenv("WORKLOAD_PROXY_CA_CERT") + + workload_proxy_client = httpx.Client( + verify=ca_cert, cert=(client_cert, client_key) ) - return pf.socket(port) - - socket.create_connection = kubernetes_create_connection - - namespace = self.namespace - if not namespace: - raise ValueError("NAMESPACE environment variable not set") - # Access the nginx http server using the - # ".pod..kubernetes" dns name. - # Construct the URL with the custom path - url = f"http://{name.lower()}.pod.{namespace}.kubernetes:{port}{path}" - - # Create a request object based on the HTTP method - if method.upper() == "GET": - if data: - # Convert data to URL-encoded query parameters for GET requests - query_params = urllib.parse.urlencode(data) - url += f"?{query_params}" - request = urllib.request.Request(url) + + merged_headers = { + **headers, + "X-Pod-Name": name, + "X-Namespace": self.cfg.namespace, + "X-Port": str(port), + } else: - # Set the request method and data for POST, PUT, etc. - request = urllib.request.Request(url, method=method.upper()) - if data: - # Convert data to JSON string and set the request body - request.add_header("Content-Type", "application/json") - if headers: - for k, v in headers.items(): - request.add_header(k, v) - request.data = json.dumps(data).encode("utf-8") - print(f"Request Data: {request.data}") - - # Send the request and handle the response - try: - response = urllib.request.urlopen(request) - status_code = response.code - response_text = response.read().decode("utf-8") - print(f"Status Code: {status_code}") - - # Parse the JSON response and return a dictionary - return status_code, response_text - except urllib.error.HTTPError as e: - status_code = e.code - error_message = e.read().decode("utf-8") - print(f"Error: {status_code}") - print(error_message) - - raise SystemError( - f"Error making http request kubernetes pod {status_code}: {error_message}" + print("Using direct connection to workload service") + workload_proxy_client = httpx.Client() + merged_headers = headers + workload_proxy_url = ( + f"http://{name}.{self.cfg.namespace}.svc.cluster.local:{port}" ) - finally: - try: - if response: # type: ignore - response.close() - except: - pass + + json_data = None if method == "GET" else data + query_parameters = "" + if method == "GET" and data: + query_parameters = "?" + "&".join([f"{k}={v}" for k, v in data.items()]) + + url = f"{workload_proxy_url.rstrip('/')}/{path.lstrip('/')}" + query_parameters + + print("Method: ", method) + print("URL: ", url) + print("Headers: ", merged_headers) + print("JSON Data: ", json_data) + + r = workload_proxy_client.request( + method=method, url=url, headers=merged_headers, json=json_data + ) + + return r.status_code, r.text def logs(self, name: str) -> str: """ diff --git a/surfkit/server/models.py b/surfkit/server/models.py index 9f1f8a6..6e0909d 100644 --- a/surfkit/server/models.py +++ b/surfkit/server/models.py @@ -213,11 +213,13 @@ class V1Skill(BaseModel): created: int updated: int + class SkillsWithGenTasks(BaseModel): skill_id: str in_queue_count: int tasks_needed: int + class V1UpdateSkill(BaseModel): name: Optional[str] = None description: Optional[str] = None diff --git a/surfkit/skill.py b/surfkit/skill.py index 1052c4e..18c5a85 100644 --- a/surfkit/skill.py +++ b/surfkit/skill.py @@ -17,7 +17,13 @@ from taskara.db.models import TaskRecord, LabelRecord from surfkit.db.conn import WithDB from surfkit.db.models import SkillRecord -from surfkit.server.models import SkillsWithGenTasks, UserTask, UserTasks, V1Skill, V1UpdateSkill +from surfkit.server.models import ( + SkillsWithGenTasks, + UserTask, + UserTasks, + V1Skill, + V1UpdateSkill, +) class SkillStatus(Enum): @@ -76,9 +82,7 @@ def __init__( self.demos_outstanding = ( demos_outstanding if demos_outstanding is not None else 3 ) - self.demo_queue_size = ( - demo_queue_size if demo_queue_size is not None else 5 - ) + self.demo_queue_size = demo_queue_size if demo_queue_size is not None else 5 self.remote = remote self.threads: List[RoleThread] = [] self.kvs = kvs or {} @@ -116,19 +120,21 @@ def to_v1(self) -> V1Skill: description=self.description, requirements=self.requirements, max_steps=self.max_steps, - review_requirements=[review.to_v1() for review in self.review_requirements] - if self.review_requirements - else [], + review_requirements=( + [review.to_v1() for review in self.review_requirements] + if self.review_requirements + else [] + ), agent_type=self.agent_type, # type: ignore tasks=[task.to_v1() for task in self.tasks], threads=[thread.to_v1() for thread in self.threads], example_tasks=self.example_tasks, status=self.status.value, - generating_tasks=self.generating_tasks - if hasattr(self, "generating_tasks") - else False, + generating_tasks=( + self.generating_tasks if hasattr(self, "generating_tasks") else False + ), min_demos=self.min_demos, - demo_queue_size = self.demo_queue_size, + demo_queue_size=self.demo_queue_size, demos_outstanding=self.demos_outstanding, owner_id=self.owner_id, created=self.created, @@ -588,7 +594,7 @@ def generate_tasks( ) -> List[Task]: self.set_generating_tasks(True) task_assigned_to = assigned_to or self.owner_id - if assigned_to is None and assigned_type != 'user': + if assigned_to is None and assigned_type != "user": task_assigned_to = None router = Router( @@ -783,7 +789,9 @@ def find_skills_for_task_gen(cls) -> list[SkillsWithGenTasks]: skill_records = ( skill_session.query(SkillRecord.id, SkillRecord.demo_queue_size) .filter( - SkillRecord.status.in_([SkillStatus.TRAINING.value, SkillStatus.DEMO.value]), + SkillRecord.status.in_( + [SkillStatus.TRAINING.value, SkillStatus.DEMO.value] + ), SkillRecord.generating_tasks == False, # noqa: E712 ) .all() @@ -811,7 +819,10 @@ def find_skills_for_task_gen(cls) -> list[SkillsWithGenTasks]: TaskRecord.skill.label("skill_id"), func.count().label("count"), ) - .filter(TaskRecord.status == (TaskStatus.IN_QUEUE.value), TaskRecord.skill.in_(skill_ids)) + .filter( + TaskRecord.status == (TaskStatus.IN_QUEUE.value), + TaskRecord.skill.in_(skill_ids), + ) .group_by(TaskRecord.skill) .all() ) @@ -823,7 +834,9 @@ def find_skills_for_task_gen(cls) -> list[SkillsWithGenTasks]: func.count().label("count"), ) .join( - TaskRecord.labels.and_(LabelRecord.key == "skill").and_(TaskRecord.skill.is_(None)).and_(TaskRecord.status == (TaskStatus.IN_QUEUE.value)) + TaskRecord.labels.and_(LabelRecord.key == "skill") + .and_(TaskRecord.skill.is_(None)) + .and_(TaskRecord.status == (TaskStatus.IN_QUEUE.value)) ) .filter( LabelRecord.value.in_(skill_ids), @@ -836,7 +849,7 @@ def find_skills_for_task_gen(cls) -> list[SkillsWithGenTasks]: # Combine all counts into a single dict. If a skill never appears, it remains 0. in_queue_counts = defaultdict(int) - + # direct_rows + labeled_rows => e.g. [("skillA", 2), ("skillC", 1), ...] for sid, count_value in direct_rows + labeled_rows: in_queue_counts[sid] += count_value @@ -847,10 +860,12 @@ def find_skills_for_task_gen(cls) -> list[SkillsWithGenTasks]: min_demos = skill_map[sid]["demo_queue_size"] count_value = in_queue_counts[sid] # defaults to 0 if sid never occurred if count_value < min_demos: - results.append(SkillsWithGenTasks( - skill_id=sid, - in_queue_count=count_value, - tasks_needed=min_demos - count_value - )) + results.append( + SkillsWithGenTasks( + skill_id=sid, + in_queue_count=count_value, + tasks_needed=min_demos - count_value, + ) + ) - return results \ No newline at end of file + return results