From 383351efcada96972ad354f9f5e71575e5754a8b Mon Sep 17 00:00:00 2001 From: John Mario Montoya Zapata Date: Thu, 13 Aug 2026 10:41:10 -0500 Subject: [PATCH 1/5] docs(github): add roadmap task issue template --- .github/ISSUE_TEMPLATE/task.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/task.md diff --git a/.github/ISSUE_TEMPLATE/task.md b/.github/ISSUE_TEMPLATE/task.md new file mode 100644 index 0000000..6299a94 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/task.md @@ -0,0 +1,26 @@ +--- +name: Tarea de roadmap +about: Tarea de una versión del roadmap de ResearchOS +title: "[T##] " +labels: '' +--- + +## Objetivo + +## Contexto + +## Criterios de aceptación +- [ ] + +## Capas afectadas + +## Decisiones a documentar + +## Objetivo de aprendizaje + +## Fuera de alcance + +## Estimación +**h** + +## Depende de From a2f16d56978eb82baa3efd571b435a69a34e7f75 Mon Sep 17 00:00:00 2001 From: John Mario Montoya Zapata Date: Fri, 14 Aug 2026 09:09:30 -0500 Subject: [PATCH 2/5] feat(deps): add langgraph and langchain-anthropic for V2 study --- pyproject.toml | 3 + uv.lock | 405 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 377 insertions(+), 31 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index bfa65c5..7af8a57 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,9 @@ dependencies = [ "pyprojroot>=0.3.0", "pysqlite3-binary>=0.5.4; sys_platform == 'linux'", "pysqlite3-binary>=0.5.4.post2", + "langgraph>=1.2.11", + "langchain-anthropic>=1.5.6", + "langchain>=1.3.15", ] [build-system] diff --git a/uv.lock b/uv.lock index 12f1945..759fc1a 100644 --- a/uv.lock +++ b/uv.lock @@ -28,7 +28,7 @@ wheels = [ [[package]] name = "anthropic" -version = "0.96.0" +version = "0.122.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -40,9 +40,9 @@ dependencies = [ { name = "sniffio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/7e/672f533dee813028d2c699bfd2a7f52c9118d7353680d9aa44b9e23f717f/anthropic-0.96.0.tar.gz", hash = "sha256:9de947b737f39452f68aa520f1c2239d44119c9b73b0fb6d4e6ca80f00279ee6", size = 658210, upload-time = "2026-04-16T14:28:02.846Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/23/9987d70b74e3481d5bc5d2021d3e10fd5f60c1f7b54088ea86506d9b7f2b/anthropic-0.122.0.tar.gz", hash = "sha256:ffec56ae96657c8d19fa575ec96f140f380c353a07ab7d61b92eb18ee6536601", size = 1021535, upload-time = "2026-08-13T18:36:00.307Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/48/5a/72f33204064b6e87601a71a6baf8d855769f8a0c1eaae8d06a1094872371/anthropic-0.96.0-py3-none-any.whl", hash = "sha256:9a6e335a354602a521cd9e777e92bfd46ba6e115bf9bbfe6135311e8fb2015b2", size = 635930, upload-time = "2026-04-16T14:28:01.436Z" }, + { url = "https://files.pythonhosted.org/packages/26/5b/f5c87e71097a9f89f1b414d1ef7ae8439051fae57d5e4ee90946082982b8/anthropic-0.122.0-py3-none-any.whl", hash = "sha256:45ec906452ffae6b5f7f0c53d01f50bfb7e4ce878d7ae8e4309d13171e557e67", size = 1041853, upload-time = "2026-08-13T18:36:01.831Z" }, ] [[package]] @@ -1040,6 +1040,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b8/42/cf027b4ac873b076189d935b135397675dac80cb29acb13e1ab86ad6c631/json5-0.14.0-py3-none-any.whl", hash = "sha256:56cf861bab076b1178eb8c92e1311d273a9b9acea2ccc82c276abf839ebaef3a", size = 36271, upload-time = "2026-03-27T22:50:47.073Z" }, ] +[[package]] +name = "jsonpatch" +version = "1.33" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonpointer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/78/18813351fe5d63acad16aec57f94ec2b70a09e53ca98145589e185423873/jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c", size = 21699, upload-time = "2023-06-26T12:07:29.144Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade", size = 12898, upload-time = "2023-06-16T21:01:28.466Z" }, +] + [[package]] name = "jsonpointer" version = "3.1.1" @@ -1309,6 +1321,150 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0c/70/05b685ea2dffcb2adbf3cdcea5d8865b7bc66f67249084cf845012a0ff13/kubernetes-35.0.0-py2.py3-none-any.whl", hash = "sha256:39e2b33b46e5834ef6c3985ebfe2047ab39135d41de51ce7641a7ca5b372a13d", size = 2017602, upload-time = "2026-01-16T01:05:25.991Z" }, ] +[[package]] +name = "langchain" +version = "1.3.15" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph" }, + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6a/1c/b84579174a8e82ed79f4c3e0cd5a7f2323facc5ccd4d1b8390e7d175b663/langchain-1.3.15.tar.gz", hash = "sha256:ab4b775b9703f7e37babe0b325dbbaef25573bda60ecf79f7850bc875f252795", size = 665047, upload-time = "2026-08-11T19:10:52.455Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/09/8d/ae721f4d68ff79a17110cabc9cb39b4568b0e3f1fe0a379b926c3f81d175/langchain-1.3.15-py3-none-any.whl", hash = "sha256:c0d2d0d51ed7da249e8ab7487173872059a9dd46fb071d905957485b7334f987", size = 147001, upload-time = "2026-08-11T19:10:50.846Z" }, +] + +[[package]] +name = "langchain-anthropic" +version = "1.5.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anthropic" }, + { name = "langchain-core" }, + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6f/c6/97c439282c13225beb56ba96ed2a5b1cb2c32eacb84c518fe475ce43711d/langchain_anthropic-1.5.6.tar.gz", hash = "sha256:648fdab25573fc9d29543c4b4af1d682b7b6e548d452bb46e67ebc586e195629", size = 720743, upload-time = "2026-08-13T02:30:48.262Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/5e/61b288074742179041cb5390430e52429a0fc41f4a94efec20042bda009f/langchain_anthropic-1.5.6-py3-none-any.whl", hash = "sha256:c358ed2ca90ef75254bb73a96b0a8a8ef0efc1deabe529ea06db6ff403001a27", size = 56547, upload-time = "2026-08-13T02:30:47.118Z" }, +] + +[[package]] +name = "langchain-core" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonpatch" }, + { name = "langchain-protocol" }, + { name = "langsmith" }, + { name = "packaging" }, + { name = "pydantic" }, + { name = "pyyaml" }, + { name = "tenacity" }, + { name = "typing-extensions" }, + { name = "uuid-utils" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/18/20c3eec05ccf2fff8e553866bec3bb2f92880aea3cb878603e5a854bd5c0/langchain_core-1.5.4.tar.gz", hash = "sha256:aa76104f30b6c7305f292cb2c364e67cb52c321940ae812d7969471dce32a89a", size = 980540, upload-time = "2026-08-11T18:02:52.239Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/9b/2219c2873c182765a2e966015672d725fdf5c9f625ef599e780168661d24/langchain_core-1.5.4-py3-none-any.whl", hash = "sha256:f1d45e84c4e4d6158218b7a8072ebe9b6d4b51e10cb728c0469650a648e18f1b", size = 565086, upload-time = "2026-08-11T18:02:50.16Z" }, +] + +[[package]] +name = "langchain-protocol" +version = "0.0.18" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d2/59/b5959aea96faa9146e2e49a7a22882b3528c62efafe9a6a95beab30c2305/langchain_protocol-0.0.18.tar.gz", hash = "sha256:ec3e11782f1ed0c9db38e5a9ed01b0e7a0d3fba406faa8aef6594b73c56a63e6", size = 6150, upload-time = "2026-06-18T17:08:26.959Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/2e/d82db9eec13ad0f72e7aaad5c4bc730ab111934fdc83c85523206eb9b0a0/langchain_protocol-0.0.18-py3-none-any.whl", hash = "sha256:70b53a86fbf9cedc863555effe44da192ab02d556ddbf2cf95b8873adcf41b5a", size = 7221, upload-time = "2026-06-18T17:08:25.996Z" }, +] + +[[package]] +name = "langgraph" +version = "1.2.11" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph-checkpoint" }, + { name = "langgraph-prebuilt" }, + { name = "langgraph-sdk" }, + { name = "pydantic" }, + { name = "xxhash" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/56/0d/c8e7ee98896659e1b6555db0ab115a9ca899844744645d5d894032bab1d7/langgraph-1.2.11.tar.gz", hash = "sha256:9ecfe11e50d338b34b15cf4d8a442642de103e8ae6971320efba84e4542eb363", size = 725753, upload-time = "2026-08-11T14:00:36.945Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/7f/c5c30e4be99ff821029c7ac872a480676bb179c9f3df85ea3f38d13f86d4/langgraph-1.2.11-py3-none-any.whl", hash = "sha256:8bab70de7b2d00b5300fb289bcf38d8b241400f3184c1e95e8ce706fb0e8686b", size = 248854, upload-time = "2026-08-11T14:00:35.494Z" }, +] + +[[package]] +name = "langgraph-checkpoint" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "ormsgpack" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/e1/089c4c9e0a2fec7f883f82ae8e6a727138d50074cfeb6644bc2d13b1019b/langgraph_checkpoint-4.2.0.tar.gz", hash = "sha256:51a593b6bee684b0818e5d6e58e28ab340c6db7794575056ce7bd1b746a84ed7", size = 180239, upload-time = "2026-08-07T20:05:03.756Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl", hash = "sha256:0547fd228935a0b758865de3a3d6d7a2537c308895d0f9ab092ce9151b5da942", size = 56833, upload-time = "2026-08-07T20:05:02.655Z" }, +] + +[[package]] +name = "langgraph-prebuilt" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph-checkpoint" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/29/66/ed9b93f56bc17ef22d551892f0ac2b225a97fe0fcf23a511b857f70d590b/langgraph_prebuilt-1.1.0.tar.gz", hash = "sha256:3c579cf6eed2d17f9c157c2d0fcaddcd8688524e7022d3b22b37a3bf4589d528", size = 178833, upload-time = "2026-05-12T03:37:49.332Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/43/3fe1a700b8490ed02679cdbbc8c915eb23a092faf496c9c1118abcd10be3/langgraph_prebuilt-1.1.0-py3-none-any.whl", hash = "sha256:51e311747d755b751d5c6b39b0c1446124d3a7643d2515017e6714b323508fc9", size = 41043, upload-time = "2026-05-12T03:37:48.007Z" }, +] + +[[package]] +name = "langgraph-sdk" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "langchain-core" }, + { name = "langchain-protocol" }, + { name = "orjson" }, + { name = "websockets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b4/2b/bd8ac26d4e97f6df88ef05ce5b6a38945a3903e1025d926f4752aa88aa97/langgraph_sdk-0.4.2.tar.gz", hash = "sha256:b88f0f5f6328ac0680d6790614a905b2bcfa257f2276dba4e38f0e86db0aa738", size = 348327, upload-time = "2026-06-01T17:51:19.856Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/05/aac507337cceae773c2cc9ab91eb6301963af7aeeb55b4217a00e15aff17/langgraph_sdk-0.4.2-py3-none-any.whl", hash = "sha256:75fa5096c1177ce39c847096a8fe3745ffd480ddb412995f836e9f5f884c43dd", size = 160521, upload-time = "2026-06-01T17:51:18.849Z" }, +] + +[[package]] +name = "langsmith" +version = "0.10.18" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, + { name = "packaging" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "requests-toolbelt" }, + { name = "sniffio" }, + { name = "typing-extensions" }, + { name = "uuid-utils" }, + { name = "websockets" }, + { name = "xxhash" }, + { name = "zstandard" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8e/08/f6575fbaf22179c52c10286df5c454fc8a7c8ce64b194a18ae0f19232503/langsmith-0.10.18.tar.gz", hash = "sha256:f78402bdbe333727459831fead2c75d0c1d1119c28e4095e5a1d65a7485e2f3a", size = 4801890, upload-time = "2026-08-11T20:27:48.731Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/07/f83cdfef58b3627175f15345105c6ee2ac152f25a0fefb930a53d4bb216c/langsmith-0.10.18-py3-none-any.whl", hash = "sha256:388236a4f031c1fe60e1517891c276ed01b102ad4405e0e9236255f2abd24cfa", size = 735339, upload-time = "2026-08-11T20:27:46.796Z" }, +] + [[package]] name = "lark" version = "1.3.1" @@ -1960,6 +2116,32 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cc/47/5aaf54524a7a4a0dd09dd778f3fa65dd2108290615b652e23d944152bc8e/orjson-3.11.8-cp312-cp312-win_arm64.whl", hash = "sha256:48854463b0572cc87dac7d981aa72ed8bf6deedc0511853dc76b8bbd5482d36d", size = 127364, upload-time = "2026-03-31T16:15:34.748Z" }, ] +[[package]] +name = "ormsgpack" +version = "1.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/12/0c/f1761e21486942ab9bb6feaebc610fa074f7c5e496e6962dea5873348077/ormsgpack-1.12.2.tar.gz", hash = "sha256:944a2233640273bee67521795a73cf1e959538e0dfb7ac635505010455e53b33", size = 39031, upload-time = "2026-01-18T20:55:28.023Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/08/8b68f24b18e69d92238aa8f258218e6dfeacf4381d9d07ab8df303f524a9/ormsgpack-1.12.2-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:bd5f4bf04c37888e864f08e740c5a573c4017f6fd6e99fa944c5c935fabf2dd9", size = 378266, upload-time = "2026-01-18T20:55:59.876Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/29fc13044ecb7c153523ae0a1972269fcd613650d1fa1a9cec1044c6b666/ormsgpack-1.12.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34d5b28b3570e9fed9a5a76528fc7230c3c76333bc214798958e58e9b79cc18a", size = 203035, upload-time = "2026-01-18T20:55:30.59Z" }, + { url = "https://files.pythonhosted.org/packages/ad/c2/00169fb25dd8f9213f5e8a549dfb73e4d592009ebc85fbbcd3e1dcac575b/ormsgpack-1.12.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3708693412c28f3538fb5a65da93787b6bbab3484f6bc6e935bfb77a62400ae5", size = 210539, upload-time = "2026-01-18T20:55:48.569Z" }, + { url = "https://files.pythonhosted.org/packages/1b/33/543627f323ff3c73091f51d6a20db28a1a33531af30873ea90c5ac95a9b5/ormsgpack-1.12.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43013a3f3e2e902e1d05e72c0f1aeb5bedbb8e09240b51e26792a3c89267e181", size = 212401, upload-time = "2026-01-18T20:56:10.101Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5d/f70e2c3da414f46186659d24745483757bcc9adccb481a6eb93e2b729301/ormsgpack-1.12.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7c8b1667a72cbba74f0ae7ecf3105a5e01304620ed14528b2cb4320679d2869b", size = 387082, upload-time = "2026-01-18T20:56:12.047Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d6/06e8dc920c7903e051f30934d874d4afccc9bb1c09dcaf0bc03a7de4b343/ormsgpack-1.12.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:df6961442140193e517303d0b5d7bc2e20e69a879c2d774316125350c4a76b92", size = 482346, upload-time = "2026-01-18T20:56:05.152Z" }, + { url = "https://files.pythonhosted.org/packages/66/c4/f337ac0905eed9c393ef990c54565cd33644918e0a8031fe48c098c71dbf/ormsgpack-1.12.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c6a4c34ddef109647c769d69be65fa1de7a6022b02ad45546a69b3216573eb4a", size = 425181, upload-time = "2026-01-18T20:55:37.83Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/6d5758fabef3babdf4bbbc453738cc7de9cd3334e4c38dd5737e27b85653/ormsgpack-1.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:73670ed0375ecc303858e3613f407628dd1fca18fe6ac57b7b7ce66cc7bb006c", size = 117182, upload-time = "2026-01-18T20:55:31.472Z" }, + { url = "https://files.pythonhosted.org/packages/c4/57/17a15549233c37e7fd054c48fe9207492e06b026dbd872b826a0b5f833b6/ormsgpack-1.12.2-cp311-cp311-win_arm64.whl", hash = "sha256:c2be829954434e33601ae5da328cccce3266b098927ca7a30246a0baec2ce7bd", size = 111464, upload-time = "2026-01-18T20:55:38.811Z" }, + { url = "https://files.pythonhosted.org/packages/4c/36/16c4b1921c308a92cef3bf6663226ae283395aa0ff6e154f925c32e91ff5/ormsgpack-1.12.2-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7a29d09b64b9694b588ff2f80e9826bdceb3a2b91523c5beae1fab27d5c940e7", size = 378618, upload-time = "2026-01-18T20:55:50.835Z" }, + { url = "https://files.pythonhosted.org/packages/c0/68/468de634079615abf66ed13bb5c34ff71da237213f29294363beeeca5306/ormsgpack-1.12.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b39e629fd2e1c5b2f46f99778450b59454d1f901bc507963168985e79f09c5d", size = 203186, upload-time = "2026-01-18T20:56:11.163Z" }, + { url = "https://files.pythonhosted.org/packages/73/a9/d756e01961442688b7939bacd87ce13bfad7d26ce24f910f6028178b2cc8/ormsgpack-1.12.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:958dcb270d30a7cb633a45ee62b9444433fa571a752d2ca484efdac07480876e", size = 210738, upload-time = "2026-01-18T20:56:09.181Z" }, + { url = "https://files.pythonhosted.org/packages/7b/ba/795b1036888542c9113269a3f5690ab53dd2258c6fb17676ac4bd44fcf94/ormsgpack-1.12.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d379d72b6c5e964851c77cfedfb386e474adee4fd39791c2c5d9efb53505cc", size = 212569, upload-time = "2026-01-18T20:56:06.135Z" }, + { url = "https://files.pythonhosted.org/packages/6c/aa/bff73c57497b9e0cba8837c7e4bcab584b1a6dbc91a5dd5526784a5030c8/ormsgpack-1.12.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8463a3fc5f09832e67bdb0e2fda6d518dc4281b133166146a67f54c08496442e", size = 387166, upload-time = "2026-01-18T20:55:36.738Z" }, + { url = "https://files.pythonhosted.org/packages/d3/cf/f8283cba44bcb7b14f97b6274d449db276b3a86589bdb363169b51bc12de/ormsgpack-1.12.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:eddffb77eff0bad4e67547d67a130604e7e2dfbb7b0cde0796045be4090f35c6", size = 482498, upload-time = "2026-01-18T20:55:29.626Z" }, + { url = "https://files.pythonhosted.org/packages/05/be/71e37b852d723dfcbe952ad04178c030df60d6b78eba26bfd14c9a40575e/ormsgpack-1.12.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fcd55e5f6ba0dbce624942adf9f152062135f991a0126064889f68eb850de0dd", size = 425518, upload-time = "2026-01-18T20:55:49.556Z" }, + { url = "https://files.pythonhosted.org/packages/7a/0c/9803aa883d18c7ef197213cd2cbf73ba76472a11fe100fb7dab2884edf48/ormsgpack-1.12.2-cp312-cp312-win_amd64.whl", hash = "sha256:d024b40828f1dde5654faebd0d824f9cc29ad46891f626272dd5bfd7af2333a4", size = 117462, upload-time = "2026-01-18T20:55:47.726Z" }, + { url = "https://files.pythonhosted.org/packages/c8/9e/029e898298b2cc662f10d7a15652a53e3b525b1e7f07e21fef8536a09bb8/ormsgpack-1.12.2-cp312-cp312-win_arm64.whl", hash = "sha256:da538c542bac7d1c8f3f2a937863dba36f013108ce63e55745941dda4b75dbb6", size = 111559, upload-time = "2026-01-18T20:55:54.273Z" }, +] + [[package]] name = "overrides" version = "7.7.0" @@ -2608,6 +2790,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179, upload-time = "2024-03-22T20:32:28.055Z" }, ] +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" }, +] + [[package]] name = "researchos" version = "0.1.0" @@ -2617,6 +2811,9 @@ dependencies = [ { name = "chromadb" }, { name = "fastapi" }, { name = "httpx" }, + { name = "langchain" }, + { name = "langchain-anthropic" }, + { name = "langgraph" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "pymupdf" }, @@ -2647,6 +2844,9 @@ requires-dist = [ { name = "chromadb", specifier = ">=0.5.0" }, { name = "fastapi", specifier = ">=0.115.0" }, { name = "httpx", specifier = ">=0.27.0" }, + { name = "langchain", specifier = ">=1.3.15" }, + { name = "langchain-anthropic", specifier = ">=1.5.6" }, + { name = "langgraph", specifier = ">=1.2.11" }, { name = "pydantic", specifier = ">=2.0.0" }, { name = "pydantic-settings", specifier = ">=2.0.0" }, { name = "pymupdf", specifier = ">=1.24.0" }, @@ -3244,6 +3444,50 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, ] +[[package]] +name = "uuid-utils" +version = "0.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/91/63938e0e7e7876658e5e40178e7c0735b53527886fe11797a11699c55edd/uuid_utils-0.17.0.tar.gz", hash = "sha256:abb5667a36119019b3fa320c4d10c21ebccfcc87c8a739e6a0056cee7f48dde2", size = 43220, upload-time = "2026-07-09T13:49:58.433Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/b2/8f03b61f0aa4afc687855c4f00db35f4d3e58c480cd885abc46f6e41308f/uuid_utils-0.17.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:f9b093cb3b6c9d6233ef45a05cab064d2aa0a8cb3c5777084c9e20fcb77c2371", size = 563901, upload-time = "2026-07-09T13:48:08.961Z" }, + { url = "https://files.pythonhosted.org/packages/e3/cb/88b909ffb9ac11f88d2e6ceabc592ccc660b5830b06dbcbd290ab8981f1f/uuid_utils-0.17.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0bc4c431ccd59c764080ceb43b126043325fe17861b87759d026a0cdd8423bb2", size = 286383, upload-time = "2026-07-09T13:48:10.2Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b8/bc5b64e9898867227c535cd0366c571c580a736748e81329437c1773e442/uuid_utils-0.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c00d182e31034250690f417b9068b78eab423c10d76766664e82d9860c340479", size = 323244, upload-time = "2026-07-09T13:48:11.477Z" }, + { url = "https://files.pythonhosted.org/packages/13/d9/8a17462ce066fbf89670fb737a3f0c93a77816736d2a4d134787e759d8ea/uuid_utils-0.17.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:570db214f6d8507587a8faa968a3fe65e957daeb7bc48b27dc7f69bc3ecdd6f1", size = 330466, upload-time = "2026-07-09T13:48:13.092Z" }, + { url = "https://files.pythonhosted.org/packages/43/37/0c65d0db3bae45183419756d938f1791a82c835fd92bf234eb4f008d2e02/uuid_utils-0.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:351462debd866f1f25e4d4f5c7fac89525b52151f0102a1bdfe94a999b046f5f", size = 443806, upload-time = "2026-07-09T13:48:14.372Z" }, + { url = "https://files.pythonhosted.org/packages/32/d5/7e698466d1f5254620b5ee0d711fdd20a0e9c2acd7040740c37193a8f673/uuid_utils-0.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:622cdde768300591ac79bfcd7bb3468e4b191b1105d5dbfe8d87c39d8f63dd46", size = 324261, upload-time = "2026-07-09T13:48:15.642Z" }, + { url = "https://files.pythonhosted.org/packages/5d/48/3a5b242d7f0b8e3ca77dcd7177f3cf73e0280cee32e2349d9796ca27f183/uuid_utils-0.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:75d7411e8eb9259764dd60310738540649057cda4509b4af14b36b7f663bfeb0", size = 350657, upload-time = "2026-07-09T13:48:17.273Z" }, + { url = "https://files.pythonhosted.org/packages/95/f4/f32ea82a89efed2eafee2f1d925d64687a81e550a9951933fb1b75c95ca6/uuid_utils-0.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1019476b6bdc047216ef7414be5babe0fa5ccfde977c0cac4fd6c75ddec66ff7", size = 500613, upload-time = "2026-07-09T13:48:18.459Z" }, + { url = "https://files.pythonhosted.org/packages/f4/5c/c7b73ec4bbe28db162a4841d352c6eda582801e0dd9fe72f6ad5cc584ee4/uuid_utils-0.17.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:04452640d8b6920c480c16e5afe91ff896d236e0c972830f9247e0898d38c803", size = 606306, upload-time = "2026-07-09T13:48:19.726Z" }, + { url = "https://files.pythonhosted.org/packages/63/95/8a2777204e8691b4961e6aa619001c3e5175aa430ab43da3079142e8d310/uuid_utils-0.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:793229621e1ad6cac55f015cfa9f4eff102accbc3da25d607b91c6b0bec167fb", size = 567231, upload-time = "2026-07-09T13:48:21.024Z" }, + { url = "https://files.pythonhosted.org/packages/1a/6f/1d778ca3ed6d2cf35f22088e2de714675416747ab41be510f22c141043a7/uuid_utils-0.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03815cea572c8a693cab5475b9d750cc161470961c7defa27e9286cad62f38f5", size = 529373, upload-time = "2026-07-09T13:48:22.312Z" }, + { url = "https://files.pythonhosted.org/packages/6e/d3/9ad1ab64b3bed0a0237d1db89dc6f5001d6116a82766753da4ac4496f979/uuid_utils-0.17.0-cp311-cp311-win32.whl", hash = "sha256:c4f845166b09acc65c5213a35551a7f81c17fa010ab467229b5813f79d17fe13", size = 169930, upload-time = "2026-07-09T13:48:23.504Z" }, + { url = "https://files.pythonhosted.org/packages/c2/1a/e01417f52eae6e2cb412260bb332b4ee4b37af2982d9c38cff4b68b2e899/uuid_utils-0.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:14dc2f46abb1091260c0d203fcbdf4e045042cc07e49183fd3b255904b95eb70", size = 177242, upload-time = "2026-07-09T13:48:24.723Z" }, + { url = "https://files.pythonhosted.org/packages/35/20/396c27f996add19f8ac31e49cc4570824e51a97719087dabf94694d25bc4/uuid_utils-0.17.0-cp311-cp311-win_arm64.whl", hash = "sha256:29179ffb7b317239b6d6afb100d14c439c728770460718280b9c0a42d2561ec2", size = 177023, upload-time = "2026-07-09T13:48:25.834Z" }, + { url = "https://files.pythonhosted.org/packages/20/80/a7e685968e3cec99d6fe2fb25d0f5726310e1bba356da68c13dfd8b7d140/uuid_utils-0.17.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:9205068badf453d2f0821fd5d340389b4679992d7ff79d4f3e5608996dd1b287", size = 556403, upload-time = "2026-07-09T13:48:27.022Z" }, + { url = "https://files.pythonhosted.org/packages/56/47/3102d93bcb7b0bfe6bede63ff8f221a7f91348e10a37f682773be27c56d9/uuid_utils-0.17.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0fcca4e838af9ac9243b3358d7c14afa4dca286a87781124c272d6c4cad9c968", size = 285608, upload-time = "2026-07-09T13:48:28.769Z" }, + { url = "https://files.pythonhosted.org/packages/55/fb/d59695f0f8db065b93c63316eaafa05a22d75a0486978a33736c52c646d5/uuid_utils-0.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f3729e839209f3457d0d8b6a35a376fdf65577a5aecaf4cc3587d3305759ba6", size = 319926, upload-time = "2026-07-09T13:48:29.965Z" }, + { url = "https://files.pythonhosted.org/packages/5a/03/62fabcd1e990e07a0e220e8d552af45bc16f107fa8e55c2014a706bb1a1e/uuid_utils-0.17.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3dac0ad0cd9a2818d1775215365a4e8c2f8ada215529dd26f3f8cceeb67a6988", size = 327172, upload-time = "2026-07-09T13:48:31.187Z" }, + { url = "https://files.pythonhosted.org/packages/d9/37/a5081391338b459e2f8d8b12581f00f8caa6317fab510e0e85c18c59e938/uuid_utils-0.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e671b2322ef09106ecb1ca0f4c398b134d5e2c1f80d7a4f3336847a3072c0e94", size = 439075, upload-time = "2026-07-09T13:48:32.295Z" }, + { url = "https://files.pythonhosted.org/packages/59/30/91795bd01e17a13661280d4899fbf38fb05e3f38e873f9aaec106ec30aa0/uuid_utils-0.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8eb3e5caca8d3a6f72ea4cce024583f989f6f2e9186f98800213fff0176e8bcc", size = 320247, upload-time = "2026-07-09T13:48:33.64Z" }, + { url = "https://files.pythonhosted.org/packages/e5/11/09102b78303e4eb62069d6d88ef9fd661dc523e8f429e1fd67eaa78a6f44/uuid_utils-0.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8b72c2002202038666bf647f9a790906214c7c11cd0d6efef77b7d07bef3034a", size = 344738, upload-time = "2026-07-09T13:48:34.786Z" }, + { url = "https://files.pythonhosted.org/packages/74/f9/be95bad6954b60328878c3800258f01a6accd24fd75112d13f023462d53f/uuid_utils-0.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4e2ac1c0b56f2c91b6f158e29ed96b1503223fe8aa6e79b1be1dc55bd8a5131c", size = 496845, upload-time = "2026-07-09T13:48:36.057Z" }, + { url = "https://files.pythonhosted.org/packages/2d/02/8a19a34e0530d987488a068a71576a236f5c8c746630b870b57f71eb24ef/uuid_utils-0.17.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6c142bd0cb4dba31c10babe00d59f7ef6460f0ef55eaa9c1a9da270684af996a", size = 603233, upload-time = "2026-07-09T13:48:37.512Z" }, + { url = "https://files.pythonhosted.org/packages/f4/a8/b1abab36ff73b0248d82179816467f6d39a2e80fd64329a895ca94f3508e/uuid_utils-0.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e252db239eb41c32248e096e0d170bce5896a4fd3405556362bc3dd83d912206", size = 561401, upload-time = "2026-07-09T13:48:38.977Z" }, + { url = "https://files.pythonhosted.org/packages/61/91/70e7b528b351cc03a9ca43e6116371cdde31bb12bcead7ca2ca1367366cc/uuid_utils-0.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:237722b6581bb5b4eb4cefbcbe5c6e2980a440aabe781fbe50ebf1cb71eee4cc", size = 525314, upload-time = "2026-07-09T13:48:40.599Z" }, + { url = "https://files.pythonhosted.org/packages/d6/f6/9167e90cf9937d6558f92d022ff3024a69d938a514d9c8faa4080f73b001/uuid_utils-0.17.0-cp312-cp312-win32.whl", hash = "sha256:46a73cacdf512f473a81f65dbf84186e08cfe6e9118fa582b6c6b33a8288a30d", size = 166831, upload-time = "2026-07-09T13:48:41.862Z" }, + { url = "https://files.pythonhosted.org/packages/5c/7d/0b889654d9ee3413f810cf4685e241285f650d98a4103ac9f3c6bcc95f29/uuid_utils-0.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:e59b60a0a4cb7541480e02090d37dc2df3b72df4c2e776fff64ce3a4e3dd4637", size = 172944, upload-time = "2026-07-09T13:48:42.992Z" }, + { url = "https://files.pythonhosted.org/packages/be/35/8c6e1bf65e4d400352885dadc656ad6d0af96e89231e3f04686bc2197128/uuid_utils-0.17.0-cp312-cp312-win_arm64.whl", hash = "sha256:d561a4c5747a1e6c7fa7c49a0292e78b4e8c456332caa084fc7abad8de828652", size = 172459, upload-time = "2026-07-09T13:48:44.271Z" }, + { url = "https://files.pythonhosted.org/packages/ee/14/4ae708968b15cac7b68d5b854bfce724b21faa1c7a5147fb96d87f468a45/uuid_utils-0.17.0-pp311-pypy311_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7b9044ce4acbf392d4b3a503fe377641f4deff82e6c341c36ef27af0dea76cdf", size = 567823, upload-time = "2026-07-09T13:49:46.902Z" }, + { url = "https://files.pythonhosted.org/packages/4c/e2/d3af9c3d1dc6efb9ee1cffab30f3f2aacacc3892b21b495d78d34c6696bc/uuid_utils-0.17.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9a91c4814c7150a4d798da691b7804eacd78c4b84fb392a60fa0de21341861eb", size = 288763, upload-time = "2026-07-09T13:49:48.491Z" }, + { url = "https://files.pythonhosted.org/packages/bc/c2/f1b183e412387529893015a94a8447633c665f6d0392de20e245680e636a/uuid_utils-0.17.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dd4a21baaac9a88486f0dd166c5793feb101a0bb9f006f2c401657fff5a1343", size = 324919, upload-time = "2026-07-09T13:49:49.972Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3c/d32c799bdd51f3b08b6ee95f9de921b59c69075a96767f937fab55014813/uuid_utils-0.17.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32abaafc8e91928b3d9f4d82e42d2094041e38ad6bb964066faadff28e4162f1", size = 332689, upload-time = "2026-07-09T13:49:51.402Z" }, + { url = "https://files.pythonhosted.org/packages/6f/90/b4cd455619ff276dc3c3262a7420ead63aa1e531362f00df4cdb07d90e0a/uuid_utils-0.17.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd741c73440b328f937dc53b344ecadc46bc4f0cec0333a8f42b55f3468ce7ec", size = 445726, upload-time = "2026-07-09T13:49:52.757Z" }, + { url = "https://files.pythonhosted.org/packages/e2/f1/5cc042a37932aa9a66eb8ab4a9a5b31d80261ae4565ff0193d8cc1fb9392/uuid_utils-0.17.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89a0980d49683c00539c59cd9f46b1908c538e6b5b0a48ad12187bb856d0f391", size = 325610, upload-time = "2026-07-09T13:49:54.191Z" }, + { url = "https://files.pythonhosted.org/packages/5e/72/9e800c41d766484484e97845a7a7f677ba94462df86c97183e0290229d16/uuid_utils-0.17.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:de1064663aa7c839286488a319d2b3b478ca5ab5b2091ade888ed0eeca11a98a", size = 352672, upload-time = "2026-07-09T13:49:55.748Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8e/86ce2c03a1d9674530f6649e49067f7c69929600127077731de590d12132/uuid_utils-0.17.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2db386941cfdecdd0b5a8ceeed5cf7479c83d1730dcf64a48d43cfa018cc3310", size = 178681, upload-time = "2026-07-09T13:49:57.096Z" }, +] + [[package]] name = "uvicorn" version = "0.44.0" @@ -3382,34 +3626,33 @@ wheels = [ [[package]] name = "websockets" -version = "16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/db/de907251b4ff46ae804ad0409809504153b3f30984daf82a1d84a9875830/websockets-16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:31a52addea25187bde0797a97d6fc3d2f92b6f72a9370792d65a6e84615ac8a8", size = 177340, upload-time = "2026-01-10T09:22:34.539Z" }, - { url = "https://files.pythonhosted.org/packages/f3/fa/abe89019d8d8815c8781e90d697dec52523fb8ebe308bf11664e8de1877e/websockets-16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:417b28978cdccab24f46400586d128366313e8a96312e4b9362a4af504f3bbad", size = 175022, upload-time = "2026-01-10T09:22:36.332Z" }, - { url = "https://files.pythonhosted.org/packages/58/5d/88ea17ed1ded2079358b40d31d48abe90a73c9e5819dbcde1606e991e2ad/websockets-16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:af80d74d4edfa3cb9ed973a0a5ba2b2a549371f8a741e0800cb07becdd20f23d", size = 175319, upload-time = "2026-01-10T09:22:37.602Z" }, - { url = "https://files.pythonhosted.org/packages/d2/ae/0ee92b33087a33632f37a635e11e1d99d429d3d323329675a6022312aac2/websockets-16.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:08d7af67b64d29823fed316505a89b86705f2b7981c07848fb5e3ea3020c1abe", size = 184631, upload-time = "2026-01-10T09:22:38.789Z" }, - { url = "https://files.pythonhosted.org/packages/c8/c5/27178df583b6c5b31b29f526ba2da5e2f864ecc79c99dae630a85d68c304/websockets-16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be95cfb0a4dae143eaed2bcba8ac23f4892d8971311f1b06f3c6b78952ee70b", size = 185870, upload-time = "2026-01-10T09:22:39.893Z" }, - { url = "https://files.pythonhosted.org/packages/87/05/536652aa84ddc1c018dbb7e2c4cbcd0db884580bf8e95aece7593fde526f/websockets-16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6297ce39ce5c2e6feb13c1a996a2ded3b6832155fcfc920265c76f24c7cceb5", size = 185361, upload-time = "2026-01-10T09:22:41.016Z" }, - { url = "https://files.pythonhosted.org/packages/6d/e2/d5332c90da12b1e01f06fb1b85c50cfc489783076547415bf9f0a659ec19/websockets-16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c1b30e4f497b0b354057f3467f56244c603a79c0d1dafce1d16c283c25f6e64", size = 184615, upload-time = "2026-01-10T09:22:42.442Z" }, - { url = "https://files.pythonhosted.org/packages/77/fb/d3f9576691cae9253b51555f841bc6600bf0a983a461c79500ace5a5b364/websockets-16.0-cp311-cp311-win32.whl", hash = "sha256:5f451484aeb5cafee1ccf789b1b66f535409d038c56966d6101740c1614b86c6", size = 178246, upload-time = "2026-01-10T09:22:43.654Z" }, - { url = "https://files.pythonhosted.org/packages/54/67/eaff76b3dbaf18dcddabc3b8c1dba50b483761cccff67793897945b37408/websockets-16.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7f0659570eefb578dacde98e24fb60af35350193e4f56e11190787bee77dac", size = 178684, upload-time = "2026-01-10T09:22:44.941Z" }, - { url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" }, - { url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" }, - { url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" }, - { url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" }, - { url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" }, - { url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" }, - { url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" }, - { url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" }, - { url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" }, - { url = "https://files.pythonhosted.org/packages/72/07/c98a68571dcf256e74f1f816b8cc5eae6eb2d3d5cfa44d37f801619d9166/websockets-16.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:349f83cd6c9a415428ee1005cadb5c2c56f4389bc06a9af16103c3bc3dcc8b7d", size = 174947, upload-time = "2026-01-10T09:23:36.166Z" }, - { url = "https://files.pythonhosted.org/packages/7e/52/93e166a81e0305b33fe416338be92ae863563fe7bce446b0f687b9df5aea/websockets-16.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4a1aba3340a8dca8db6eb5a7986157f52eb9e436b74813764241981ca4888f03", size = 175260, upload-time = "2026-01-10T09:23:37.409Z" }, - { url = "https://files.pythonhosted.org/packages/56/0c/2dbf513bafd24889d33de2ff0368190a0e69f37bcfa19009ef819fe4d507/websockets-16.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f4a32d1bd841d4bcbffdcb3d2ce50c09c3909fbead375ab28d0181af89fd04da", size = 176071, upload-time = "2026-01-10T09:23:39.158Z" }, - { url = "https://files.pythonhosted.org/packages/a5/8f/aea9c71cc92bf9b6cc0f7f70df8f0b420636b6c96ef4feee1e16f80f75dd/websockets-16.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0298d07ee155e2e9fda5be8a9042200dd2e3bb0b8a38482156576f863a9d457c", size = 176968, upload-time = "2026-01-10T09:23:41.031Z" }, - { url = "https://files.pythonhosted.org/packages/9a/3f/f70e03f40ffc9a30d817eef7da1be72ee4956ba8d7255c399a01b135902a/websockets-16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a653aea902e0324b52f1613332ddf50b00c06fdaf7e92624fbf8c77c78fa5767", size = 178735, upload-time = "2026-01-10T09:23:42.259Z" }, - { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, +version = "15.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, + { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, + { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, + { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, + { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, + { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, + { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, + { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, + { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, + { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, + { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, + { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, + { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, + { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, + { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, + { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, + { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, + { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, + { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, + { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] [[package]] @@ -3421,6 +3664,64 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503, upload-time = "2025-11-01T21:15:53.565Z" }, ] +[[package]] +name = "xxhash" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/6f/4d42b20b0dc688552f568e356e7d55b8ea18092eb79c78e40a96f59e7e12/xxhash-4.0.0.tar.gz", hash = "sha256:6b4040b26c73c75e6c12273b0ae237f9235f39cce5fabb683a64e9f20d09df8b", size = 100993, upload-time = "2026-08-12T16:59:59.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/9f/3736468bf0680ede8d93a488eba7dac58ca2ff25d6bff168810f7528c300/xxhash-4.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7ce6de9166b8a8c1c29d5eab91b508f4c31ae3ff8626a3ed65bd2cbbe64a40", size = 38087, upload-time = "2026-08-12T16:53:10.683Z" }, + { url = "https://files.pythonhosted.org/packages/23/27/a1370dc53ae4c10efe0eef02dfc57a613b4e104073a335fa88c3983e8b12/xxhash-4.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3b783b3b8a7c6cb79be6be6c32cc0f9c2dc3bbf4beb013bece39b4f8fcb2b4de", size = 35925, upload-time = "2026-08-12T16:52:51.017Z" }, + { url = "https://files.pythonhosted.org/packages/d8/87/f0703078a7cae7caf210d77ad6a2d91509434c1c1496233bb304e1202933/xxhash-4.0.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:601b3c3b09b44ed2ada35674bcb19c435ba9203862a4832731384269391bfed9", size = 252935, upload-time = "2026-08-12T16:52:50.195Z" }, + { url = "https://files.pythonhosted.org/packages/a2/ec/f472a6bc86208de130b2317af1aefe08d5139bd06696e7e920cf47d8b6bb/xxhash-4.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7e38e909ed1d5a86511bf2fc57891d0fea5ef64063cf7995bf954cef2365b2b", size = 276246, upload-time = "2026-08-12T16:53:14.475Z" }, + { url = "https://files.pythonhosted.org/packages/74/7c/4ff4ad2f16169070461460bdb99568eebd167932d8145f793d1cdba8077c/xxhash-4.0.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:492f267d1dedeef7c44310e60a08f38f34db75ed373062fafe68aa09801e4281", size = 295909, upload-time = "2026-08-12T16:53:08.962Z" }, + { url = "https://files.pythonhosted.org/packages/17/1d/417266187a86a340f4b8ec55d16844cbc53c20fd0503e7fb5b7a07aabd55/xxhash-4.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f2bc28050a61684f1c825ca72be56eefe1421112d1ccceb4eb99d86b52aa4c56", size = 279566, upload-time = "2026-08-12T16:53:22.923Z" }, + { url = "https://files.pythonhosted.org/packages/78/2a/c5e4987c4fa758bcaaa6fe320ecde667380e93ae206f36daa37c4545cc8f/xxhash-4.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:97730a254c3d11e43dffa815a9837a622d7f2a30a9d897bd29184d5589b7dc25", size = 509522, upload-time = "2026-08-12T16:54:01.123Z" }, + { url = "https://files.pythonhosted.org/packages/61/d7/1a3e8044c94053e8230ae746218741dcad2e67ceb4ce3d55bc85f923f406/xxhash-4.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:baa9828055ebaa00b95523aabef7504c3d1685bfab48b7c2ed15d0ba56269708", size = 260625, upload-time = "2026-08-12T16:53:19.979Z" }, + { url = "https://files.pythonhosted.org/packages/24/07/05186cfaa8410f5f6d14a691db021d930a84bc2205e45d6bed61078b8af5/xxhash-4.0.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:23ec6388d554e523bc06bf40dbf2dd09b74af246a6f2a6a17223a16fc575f676", size = 339347, upload-time = "2026-08-12T16:52:57.801Z" }, + { url = "https://files.pythonhosted.org/packages/3e/17/7628c83969d68287fb174aa3b993c5147c578ae60856f72ffad488cd1684/xxhash-4.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c1d56a5c9fb9c6c6a6eaf0adbe398c57ab6e89348a83cb99d230a52668cea557", size = 272193, upload-time = "2026-08-12T16:52:58.823Z" }, + { url = "https://files.pythonhosted.org/packages/a7/18/ded75ea5a74b8538d75e825558dbc0304726509890980edf0dd9884f3a02/xxhash-4.0.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:681892a96f5727e4a082af13fb75c1cbf1ef66f2d56cadeddf31db6bbaa09945", size = 300004, upload-time = "2026-08-12T16:53:18.853Z" }, + { url = "https://files.pythonhosted.org/packages/7a/c5/5215550ec7690a9dbc406a6e29cb77a130bdb1942fb639d6fbf2005f11e6/xxhash-4.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4395c0a03a1336915c677fc71e1693afb1317751ea80c130b23d6292d14f75fe", size = 258893, upload-time = "2026-08-12T16:53:41.076Z" }, + { url = "https://files.pythonhosted.org/packages/d7/a0/8d7a0addb64e32762af3f5e7838e1808a6997a516a2493648d651ba795c1/xxhash-4.0.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:2987f0908d5e3908bc1949a0ca4f465583ba55befad5899581edfb6b59441f56", size = 277785, upload-time = "2026-08-12T16:59:00.01Z" }, + { url = "https://files.pythonhosted.org/packages/13/1c/62dd9957ed770b2ef5f8fc0527442975afd4055921ba009fef54d54f0b79/xxhash-4.0.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3de54ba80c88096fbcca29e3b255989b3bca02e47a976bf9303de2f36261c57f", size = 329548, upload-time = "2026-08-12T16:54:05.821Z" }, + { url = "https://files.pythonhosted.org/packages/30/c7/329ba182d0fdc65fce8057fa9bc0d8979e7bd31cd4cfbc4fd991d1db2db0/xxhash-4.0.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0a9d3fc725df9b0029094dbbe700a5d4633881f2afb87392ce5860388c22bebd", size = 477008, upload-time = "2026-08-12T16:53:37.32Z" }, + { url = "https://files.pythonhosted.org/packages/81/c9/f9041891290b403d07de8cdc66da95289e6b407bc83d16be62a6acaad5f1/xxhash-4.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:84e0b626285289e40be24eefd51ab9fef9bc6373f4025c3271b3b0e3a2ac78f3", size = 257166, upload-time = "2026-08-12T16:53:07.244Z" }, + { url = "https://files.pythonhosted.org/packages/ee/ae/6f0f310ea658e83df21f171fed313f6be01fe918a2eec76c4ea549b79233/xxhash-4.0.0-cp311-cp311-win32.whl", hash = "sha256:6ec7a1b252ba32719605ecc2f9bd4230fdb3b5f0bb424c671961d21dd0acf7db", size = 34287, upload-time = "2026-08-12T16:53:09.692Z" }, + { url = "https://files.pythonhosted.org/packages/02/cc/3702bf613a42923627bbad08b434237cef9b525b00341207496548cb10af/xxhash-4.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:50cf753d4d93797c2d32a72c305ab7017af4bae9bb6c999222fb29d9ea9961f7", size = 36653, upload-time = "2026-08-12T16:53:29.162Z" }, + { url = "https://files.pythonhosted.org/packages/6c/5e/d0ccb316354dbf7d5868896e5d87bceb6f50710d6b386159294a4da4679e/xxhash-4.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:460146a030d3dfcd6cd08a0bb45c2fe10f04026f80ac16ae42a846e8d850f0ce", size = 32958, upload-time = "2026-08-12T16:53:46.82Z" }, + { url = "https://files.pythonhosted.org/packages/19/d9/493e761ee66047de5d15b7b5137972bf26d889eb58e49b1f18e2f35cea6e/xxhash-4.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d58ab471ab4442ac29ce225edf496f40d136dba552b0a718c796d14b71550b0", size = 38115, upload-time = "2026-08-12T16:59:02.316Z" }, + { url = "https://files.pythonhosted.org/packages/87/7b/a03aca88de3fae90f619ef6acd72b90e4b06e840a66ed4574558c29a080b/xxhash-4.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d3a42fa24a47961e38ace7e4675680eb3cbd024588eb0dbc9dfbd009f4dce6bd", size = 35932, upload-time = "2026-08-12T16:54:12.151Z" }, + { url = "https://files.pythonhosted.org/packages/e9/b4/8e935dc765a3018ada3da2455eed2e878c6cb686a9c01b3db1619a7c79b5/xxhash-4.0.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e4c6eca223bcd94a9a5d291512114364facc5c4738c0d468ced386e88fa9071b", size = 252775, upload-time = "2026-08-12T16:53:43.21Z" }, + { url = "https://files.pythonhosted.org/packages/f4/aa/7c1cbcf64d8c5e9ea23808356af91a158e891e08d8f206884ceaf0425d61/xxhash-4.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7264a1a8bc4cda273347b6fead2a15c1fc070736160fe927867279a9d991604a", size = 276218, upload-time = "2026-08-12T16:53:12.936Z" }, + { url = "https://files.pythonhosted.org/packages/07/a3/5ffcecc8fb1480f147a5396ae52b27a9b519092d0ba31a4c614a5a0ecc57/xxhash-4.0.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7f9a849a801557a3a2dc9226dfd11b6911c766cb3f16d36822488204788de65b", size = 297412, upload-time = "2026-08-12T16:53:38.689Z" }, + { url = "https://files.pythonhosted.org/packages/5b/90/c4067783a921aa055372bf2f66fccec0bb4fd06edd6ab3b752b973492d05/xxhash-4.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f9a33820c448e9fa3a720396d90ae3eff7dfa942d86af855965a095f954d0ac7", size = 279882, upload-time = "2026-08-12T16:53:38.703Z" }, + { url = "https://files.pythonhosted.org/packages/d1/0c/a777dbcd2f10517a0f49cd276b9c6a2d1f30cc0bde0f67da65b56849a646/xxhash-4.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:76989952a47452f66ac213779b62961b8e489c98f45c4ea7d7dea9115a00d06f", size = 510640, upload-time = "2026-08-12T16:54:01.844Z" }, + { url = "https://files.pythonhosted.org/packages/22/bb/4148016c68211d8cc348eabe06e40686c71c4f7b336261f4b4e72d2d46ab/xxhash-4.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c72ee49f74745e554226018e56dd93d4ff924dfa870d119a59828d29080853", size = 261458, upload-time = "2026-08-12T16:59:04.292Z" }, + { url = "https://files.pythonhosted.org/packages/72/dc/170ee0593a11c472e32b745b6a300f2eaf531347d1053bbc411f24d3071e/xxhash-4.0.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9335b632cdec5498068372b75ab18a6c1905eb51ba76c727db46080b66ef7d4f", size = 339621, upload-time = "2026-08-12T16:54:31.079Z" }, + { url = "https://files.pythonhosted.org/packages/c8/8b/b31e1be5d3f892eb8fa306d1bfbe7c1c5c4d6011e045351434278c2526d3/xxhash-4.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b939f78096460a1e3905cd92815d01fde6fb2c54a544daf8ea03a1fded41d74b", size = 272552, upload-time = "2026-08-12T16:53:48.526Z" }, + { url = "https://files.pythonhosted.org/packages/f0/1f/82830fa11afb369ae8ab0692d316e68be6128d12756e22d23d0f7a5b34aa/xxhash-4.0.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7d6fe512a9c84e5031d1b97c7b931c7694ba7f10f44bf4466c219f468f0ed749", size = 301046, upload-time = "2026-08-12T16:53:30.172Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c0/b081f9ae955d452be3b8f3c17ef8d5d4484606ea871c45f73046d9eaf438/xxhash-4.0.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5a9656d42c8e87013655a8a668a870222235ae26cbaae69c922b12c66b672f38", size = 259794, upload-time = "2026-08-12T16:53:52.134Z" }, + { url = "https://files.pythonhosted.org/packages/1e/01/b35974b9890d5d1d83c325220f9e98482c54109a4e98e3596b9464de4813/xxhash-4.0.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:14b91efc9fc7072ee22b4ce0c778d41e53dd2d45ca5b16fdfe8cf33ebad3c386", size = 277906, upload-time = "2026-08-12T16:53:50.359Z" }, + { url = "https://files.pythonhosted.org/packages/84/95/78d8a7228a9caa65e7adcfe0a72c160b2e739930f90ae0b4267386d8510e/xxhash-4.0.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7e07cba198b78fef4ea81b219058ee3e9ed8d612b055e0388b205a3f20e1b70e", size = 329997, upload-time = "2026-08-12T16:54:06.363Z" }, + { url = "https://files.pythonhosted.org/packages/3c/84/29f5bbbcc14a56ccfa4fe0e025ce2fa55ee4b40485a268c828c47ce52405/xxhash-4.0.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:963e5b1f0152193703997eabcdb7320c0d2e3f934a00be03a25dac4fb4af66dd", size = 478204, upload-time = "2026-08-12T16:59:07.4Z" }, + { url = "https://files.pythonhosted.org/packages/b0/13/56da2f5d5f2eb28b64aca54240e555221a8e2292644b60a73f46dfaaacb5/xxhash-4.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bc49915f326b888773979381140eb1a5e804fbc872670f6a2d36d8d421225a2a", size = 257845, upload-time = "2026-08-12T16:54:42.948Z" }, + { url = "https://files.pythonhosted.org/packages/f7/80/65141cc3d3e6b0cd52b4c7d9af32a6fbc3ea223995cfabf406b2f589e0c1/xxhash-4.0.0-cp312-cp312-pyemscripten_2024_0_wasm32.whl", hash = "sha256:89bc01208487b7f4b0b636b4e8b809ec3c41644fc38487394d9faf9570d4795b", size = 20416, upload-time = "2026-08-12T16:54:03.689Z" }, + { url = "https://files.pythonhosted.org/packages/dd/cb/8e261dc126968573b999908fdc091705e850337af24a3492f44b3d48de58/xxhash-4.0.0-cp312-cp312-win32.whl", hash = "sha256:453c9bff5e2c6a2b938704e41965c65d1339a2e07817e1cacaf239c330af4d5e", size = 34309, upload-time = "2026-08-12T16:54:04.695Z" }, + { url = "https://files.pythonhosted.org/packages/ff/bb/edec8f095a24a331293fbdacbed9addc4f5a6f2e2f88c3ed539d7cbdb438/xxhash-4.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:4f8515f2e70a98382adf2c1b1e413f3bfa46a3cb1b35752928265577f958f1da", size = 36739, upload-time = "2026-08-12T16:54:02.85Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c8/42de8febea42413de52b2d1ac5bf0081aba71c37705a3565c0c021f46bc0/xxhash-4.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:63f3cac239fcdcdcbc56cbaf5b5164f056e8a2b1e06d61436c134628743eabfa", size = 32970, upload-time = "2026-08-12T16:54:28.673Z" }, + { url = "https://files.pythonhosted.org/packages/dc/50/525619de9e4ec98f5738ee4a0aa6177bc297bea5e53288080e5c15f377d2/xxhash-4.0.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:cc563b697d5eefc6a0a699203076687ec87db4ef8fd03330786343e309a6c009", size = 31502, upload-time = "2026-08-12T16:59:45.85Z" }, + { url = "https://files.pythonhosted.org/packages/dc/1b/1718da1d831ce7b00b6ea69fa7f19b52a1a700ac32f8b913a799ee0bdde7/xxhash-4.0.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:9a9d55a4dd7e6693cc1e15119b0719d446495513b06ed020bec8ff77a84288f0", size = 34116, upload-time = "2026-08-12T16:56:51.108Z" }, + { url = "https://files.pythonhosted.org/packages/b5/6d/7ffeb80640ecafdc51a0de3096f450891d1c3baaf77543f49a1451a844a7/xxhash-4.0.0-graalpy312-graalpy250_312_native-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:07b899cf57f2573019a064b66c25b20d3e6934273fb8b921f96d74f417032d87", size = 38163, upload-time = "2026-08-12T16:59:55.311Z" }, + { url = "https://files.pythonhosted.org/packages/9d/88/51ff39be48d02e223942127189359397f87301c6c5f12efb9fda2d7ac8d6/xxhash-4.0.0-graalpy312-graalpy250_312_native-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:affef90b19eb63d054a1c16df70daee553dd735e9109e3ded5f390dda7e1eab4", size = 37885, upload-time = "2026-08-12T16:57:06.59Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f0/cd7d58dc604a395d33f5b73773caba6fdfca7e20ab54087094655c1a474b/xxhash-4.0.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:56ab134b8a5ef7a4d95c8cc0436ccab03ab20cab799e0886f4f1e728e205893e", size = 36816, upload-time = "2026-08-12T16:56:32.76Z" }, + { url = "https://files.pythonhosted.org/packages/83/b1/49cb67d760607af93db044208df1ae51d667e74e9352bdf0a79559445ce0/xxhash-4.0.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a1c8a2ea77ad2b22ab4ad34cc673aedd291143169ce10fac5728f5d3c017b378", size = 35993, upload-time = "2026-08-12T16:56:37.708Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1a/d2855a8bb2f5a7ae10ffd55621a17bef3021646e8b1095494c678f6ace80/xxhash-4.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4a1969258533437c96c8a46028820e9c99741ad7d03476abcb76566e2e324d89", size = 33186, upload-time = "2026-08-12T16:59:10.926Z" }, + { url = "https://files.pythonhosted.org/packages/75/fd/9b6cafb5bcaf99442b5ac0ed2898c830cea9d2f9d962f7f732a17677771e/xxhash-4.0.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8f3808b745a46aebdc844c603c6b9ab550451cbb499f706decd76f7d1a65ca4b", size = 47649, upload-time = "2026-08-12T16:57:00.637Z" }, + { url = "https://files.pythonhosted.org/packages/94/d0/0f527d9b2b5b62ae3fed9c28c870d06e3f68926fed465f0b53f2322e6985/xxhash-4.0.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:627149915a90215c694e4ac0c75bad8ae00eee1937f39f45b4ff46c01130fdee", size = 42388, upload-time = "2026-08-12T16:59:50.026Z" }, + { url = "https://files.pythonhosted.org/packages/3f/9c/ec4801ca684181b0f8bcea447721bc007b740a9ae5c15128e3aed481e51b/xxhash-4.0.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:65a6af70b5f5ed88f88791c5de70905c655cff0fee062604f67acfc843c2841e", size = 39184, upload-time = "2026-08-12T16:56:56.505Z" }, + { url = "https://files.pythonhosted.org/packages/8f/43/efbc17c2a467da34f207dcef369cc9364aa2a8172b4e056a0e875e934688/xxhash-4.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:36f59fa0d52d984a19c3026a951a183ebabfb2a847f9c5addc43e0191d44c3ab", size = 36911, upload-time = "2026-08-12T16:59:58.257Z" }, +] + [[package]] name = "zipp" version = "3.23.1" @@ -3429,3 +3730,45 @@ sdist = { url = "https://files.pythonhosted.org/packages/30/21/093488dfc7cc8964d wheels = [ { url = "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl", hash = "sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc", size = 10378, upload-time = "2026-04-13T23:21:45.386Z" }, ] + +[[package]] +name = "zstandard" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/83/c3ca27c363d104980f1c9cee1101cc8ba724ac8c28a033ede6aab89585b1/zstandard-0.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:933b65d7680ea337180733cf9e87293cc5500cc0eb3fc8769f4d3c88d724ec5c", size = 795254, upload-time = "2025-09-14T22:16:26.137Z" }, + { url = "https://files.pythonhosted.org/packages/ac/4d/e66465c5411a7cf4866aeadc7d108081d8ceba9bc7abe6b14aa21c671ec3/zstandard-0.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3f79487c687b1fc69f19e487cd949bf3aae653d181dfb5fde3bf6d18894706f", size = 640559, upload-time = "2025-09-14T22:16:27.973Z" }, + { url = "https://files.pythonhosted.org/packages/12/56/354fe655905f290d3b147b33fe946b0f27e791e4b50a5f004c802cb3eb7b/zstandard-0.25.0-cp311-cp311-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:0bbc9a0c65ce0eea3c34a691e3c4b6889f5f3909ba4822ab385fab9057099431", size = 5348020, upload-time = "2025-09-14T22:16:29.523Z" }, + { url = "https://files.pythonhosted.org/packages/3b/13/2b7ed68bd85e69a2069bcc72141d378f22cae5a0f3b353a2c8f50ef30c1b/zstandard-0.25.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01582723b3ccd6939ab7b3a78622c573799d5d8737b534b86d0e06ac18dbde4a", size = 5058126, upload-time = "2025-09-14T22:16:31.811Z" }, + { url = "https://files.pythonhosted.org/packages/c9/dd/fdaf0674f4b10d92cb120ccff58bbb6626bf8368f00ebfd2a41ba4a0dc99/zstandard-0.25.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5f1ad7bf88535edcf30038f6919abe087f606f62c00a87d7e33e7fc57cb69fcc", size = 5405390, upload-time = "2025-09-14T22:16:33.486Z" }, + { url = "https://files.pythonhosted.org/packages/0f/67/354d1555575bc2490435f90d67ca4dd65238ff2f119f30f72d5cde09c2ad/zstandard-0.25.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:06acb75eebeedb77b69048031282737717a63e71e4ae3f77cc0c3b9508320df6", size = 5452914, upload-time = "2025-09-14T22:16:35.277Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1f/e9cfd801a3f9190bf3e759c422bbfd2247db9d7f3d54a56ecde70137791a/zstandard-0.25.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9300d02ea7c6506f00e627e287e0492a5eb0371ec1670ae852fefffa6164b072", size = 5559635, upload-time = "2025-09-14T22:16:37.141Z" }, + { url = "https://files.pythonhosted.org/packages/21/88/5ba550f797ca953a52d708c8e4f380959e7e3280af029e38fbf47b55916e/zstandard-0.25.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfd06b1c5584b657a2892a6014c2f4c20e0db0208c159148fa78c65f7e0b0277", size = 5048277, upload-time = "2025-09-14T22:16:38.807Z" }, + { url = "https://files.pythonhosted.org/packages/46/c0/ca3e533b4fa03112facbe7fbe7779cb1ebec215688e5df576fe5429172e0/zstandard-0.25.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f373da2c1757bb7f1acaf09369cdc1d51d84131e50d5fa9863982fd626466313", size = 5574377, upload-time = "2025-09-14T22:16:40.523Z" }, + { url = "https://files.pythonhosted.org/packages/12/9b/3fb626390113f272abd0799fd677ea33d5fc3ec185e62e6be534493c4b60/zstandard-0.25.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c0e5a65158a7946e7a7affa6418878ef97ab66636f13353b8502d7ea03c8097", size = 4961493, upload-time = "2025-09-14T22:16:43.3Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d3/23094a6b6a4b1343b27ae68249daa17ae0651fcfec9ed4de09d14b940285/zstandard-0.25.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c8e167d5adf59476fa3e37bee730890e389410c354771a62e3c076c86f9f7778", size = 5269018, upload-time = "2025-09-14T22:16:45.292Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a7/bb5a0c1c0f3f4b5e9d5b55198e39de91e04ba7c205cc46fcb0f95f0383c1/zstandard-0.25.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:98750a309eb2f020da61e727de7d7ba3c57c97cf6213f6f6277bb7fb42a8e065", size = 5443672, upload-time = "2025-09-14T22:16:47.076Z" }, + { url = "https://files.pythonhosted.org/packages/27/22/503347aa08d073993f25109c36c8d9f029c7d5949198050962cb568dfa5e/zstandard-0.25.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22a086cff1b6ceca18a8dd6096ec631e430e93a8e70a9ca5efa7561a00f826fa", size = 5822753, upload-time = "2025-09-14T22:16:49.316Z" }, + { url = "https://files.pythonhosted.org/packages/e2/be/94267dc6ee64f0f8ba2b2ae7c7a2df934a816baaa7291db9e1aa77394c3c/zstandard-0.25.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:72d35d7aa0bba323965da807a462b0966c91608ef3a48ba761678cb20ce5d8b7", size = 5366047, upload-time = "2025-09-14T22:16:51.328Z" }, + { url = "https://files.pythonhosted.org/packages/7b/a3/732893eab0a3a7aecff8b99052fecf9f605cf0fb5fb6d0290e36beee47a4/zstandard-0.25.0-cp311-cp311-win32.whl", hash = "sha256:f5aeea11ded7320a84dcdd62a3d95b5186834224a9e55b92ccae35d21a8b63d4", size = 436484, upload-time = "2025-09-14T22:16:55.005Z" }, + { url = "https://files.pythonhosted.org/packages/43/a3/c6155f5c1cce691cb80dfd38627046e50af3ee9ddc5d0b45b9b063bfb8c9/zstandard-0.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:daab68faadb847063d0c56f361a289c4f268706b598afbf9ad113cbe5c38b6b2", size = 506183, upload-time = "2025-09-14T22:16:52.753Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3e/8945ab86a0820cc0e0cdbf38086a92868a9172020fdab8a03ac19662b0e5/zstandard-0.25.0-cp311-cp311-win_arm64.whl", hash = "sha256:22a06c5df3751bb7dc67406f5374734ccee8ed37fc5981bf1ad7041831fa1137", size = 462533, upload-time = "2025-09-14T22:16:53.878Z" }, + { url = "https://files.pythonhosted.org/packages/82/fc/f26eb6ef91ae723a03e16eddb198abcfce2bc5a42e224d44cc8b6765e57e/zstandard-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b3c3a3ab9daa3eed242d6ecceead93aebbb8f5f84318d82cee643e019c4b73b", size = 795738, upload-time = "2025-09-14T22:16:56.237Z" }, + { url = "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:913cbd31a400febff93b564a23e17c3ed2d56c064006f54efec210d586171c00", size = 640436, upload-time = "2025-09-14T22:16:57.774Z" }, + { url = "https://files.pythonhosted.org/packages/53/6c/288c3f0bd9fcfe9ca41e2c2fbfd17b2097f6af57b62a81161941f09afa76/zstandard-0.25.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64", size = 5343019, upload-time = "2025-09-14T22:16:59.302Z" }, + { url = "https://files.pythonhosted.org/packages/1e/15/efef5a2f204a64bdb5571e6161d49f7ef0fffdbca953a615efbec045f60f/zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dffecc361d079bb48d7caef5d673c88c8988d3d33fb74ab95b7ee6da42652ea", size = 5063012, upload-time = "2025-09-14T22:17:01.156Z" }, + { url = "https://files.pythonhosted.org/packages/b7/37/a6ce629ffdb43959e92e87ebdaeebb5ac81c944b6a75c9c47e300f85abdf/zstandard-0.25.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7149623bba7fdf7e7f24312953bcf73cae103db8cae49f8154dd1eadc8a29ecb", size = 5394148, upload-time = "2025-09-14T22:17:03.091Z" }, + { url = "https://files.pythonhosted.org/packages/e3/79/2bf870b3abeb5c070fe2d670a5a8d1057a8270f125ef7676d29ea900f496/zstandard-0.25.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6a573a35693e03cf1d67799fd01b50ff578515a8aeadd4595d2a7fa9f3ec002a", size = 5451652, upload-time = "2025-09-14T22:17:04.979Z" }, + { url = "https://files.pythonhosted.org/packages/53/60/7be26e610767316c028a2cbedb9a3beabdbe33e2182c373f71a1c0b88f36/zstandard-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5a56ba0db2d244117ed744dfa8f6f5b366e14148e00de44723413b2f3938a902", size = 5546993, upload-time = "2025-09-14T22:17:06.781Z" }, + { url = "https://files.pythonhosted.org/packages/85/c7/3483ad9ff0662623f3648479b0380d2de5510abf00990468c286c6b04017/zstandard-0.25.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10ef2a79ab8e2974e2075fb984e5b9806c64134810fac21576f0668e7ea19f8f", size = 5046806, upload-time = "2025-09-14T22:17:08.415Z" }, + { url = "https://files.pythonhosted.org/packages/08/b3/206883dd25b8d1591a1caa44b54c2aad84badccf2f1de9e2d60a446f9a25/zstandard-0.25.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aaf21ba8fb76d102b696781bddaa0954b782536446083ae3fdaa6f16b25a1c4b", size = 5576659, upload-time = "2025-09-14T22:17:10.164Z" }, + { url = "https://files.pythonhosted.org/packages/9d/31/76c0779101453e6c117b0ff22565865c54f48f8bd807df2b00c2c404b8e0/zstandard-0.25.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1869da9571d5e94a85a5e8d57e4e8807b175c9e4a6294e3b66fa4efb074d90f6", size = 4953933, upload-time = "2025-09-14T22:17:11.857Z" }, + { url = "https://files.pythonhosted.org/packages/18/e1/97680c664a1bf9a247a280a053d98e251424af51f1b196c6d52f117c9720/zstandard-0.25.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:809c5bcb2c67cd0ed81e9229d227d4ca28f82d0f778fc5fea624a9def3963f91", size = 5268008, upload-time = "2025-09-14T22:17:13.627Z" }, + { url = "https://files.pythonhosted.org/packages/1e/73/316e4010de585ac798e154e88fd81bb16afc5c5cb1a72eeb16dd37e8024a/zstandard-0.25.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f27662e4f7dbf9f9c12391cb37b4c4c3cb90ffbd3b1fb9284dadbbb8935fa708", size = 5433517, upload-time = "2025-09-14T22:17:16.103Z" }, + { url = "https://files.pythonhosted.org/packages/5b/60/dd0f8cfa8129c5a0ce3ea6b7f70be5b33d2618013a161e1ff26c2b39787c/zstandard-0.25.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99c0c846e6e61718715a3c9437ccc625de26593fea60189567f0118dc9db7512", size = 5814292, upload-time = "2025-09-14T22:17:17.827Z" }, + { url = "https://files.pythonhosted.org/packages/fc/5f/75aafd4b9d11b5407b641b8e41a57864097663699f23e9ad4dbb91dc6bfe/zstandard-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:474d2596a2dbc241a556e965fb76002c1ce655445e4e3bf38e5477d413165ffa", size = 5360237, upload-time = "2025-09-14T22:17:19.954Z" }, + { url = "https://files.pythonhosted.org/packages/ff/8d/0309daffea4fcac7981021dbf21cdb2e3427a9e76bafbcdbdf5392ff99a4/zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd", size = 436922, upload-time = "2025-09-14T22:17:24.398Z" }, + { url = "https://files.pythonhosted.org/packages/79/3b/fa54d9015f945330510cb5d0b0501e8253c127cca7ebe8ba46a965df18c5/zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01", size = 506276, upload-time = "2025-09-14T22:17:21.429Z" }, + { url = "https://files.pythonhosted.org/packages/ea/6b/8b51697e5319b1f9ac71087b0af9a40d8a6288ff8025c36486e0c12abcc4/zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9", size = 462679, upload-time = "2025-09-14T22:17:23.147Z" }, +] From 149f168a577def83b89eba0f2a5db1d94aecd2e1 Mon Sep 17 00:00:00 2001 From: John Mario Montoya Zapata Date: Fri, 14 Aug 2026 09:09:48 -0500 Subject: [PATCH 3/5] docs(notebooks): add LangGraph study notebook --- notebooks/201-jmmz-langraph-study.ipynb | 729 ++++++++++++++++++++++++ 1 file changed, 729 insertions(+) create mode 100644 notebooks/201-jmmz-langraph-study.ipynb diff --git a/notebooks/201-jmmz-langraph-study.ipynb b/notebooks/201-jmmz-langraph-study.ipynb new file mode 100644 index 0000000..8a50702 --- /dev/null +++ b/notebooks/201-jmmz-langraph-study.ipynb @@ -0,0 +1,729 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "fce14dd7", + "metadata": { + "vscode": { + "languageId": "plaintext" + } + }, + "source": [ + "Códigos sueltos para ejecución de tutoriales o snippets de código relacionado con langchain, langraph y langsmith para interiorizar sus conceptos, diferencias y mecánicas de escritura así como su sintaxis" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "c53d0c37", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'messages': [HumanMessage(content='hi!', additional_kwargs={}, response_metadata={}, id='9e5835e0-157b-4e93-9bff-0548b69c7d4d'),\n", + " AIMessage(content='hello world', additional_kwargs={}, response_metadata={}, id='c307df22-252e-463c-b522-b3299c3098a4', tool_calls=[], invalid_tool_calls=[])]}" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from langgraph.graph import StateGraph, MessagesState, START, END\n", + "\n", + "def mock_llm(state: MessagesState):\n", + " return {\"messages\": [{\"role\": \"ai\", \"content\": \"hello world\"}]}\n", + "\n", + "graph = StateGraph(MessagesState)\n", + "graph.add_node(mock_llm) # Nodo del LLM\n", + "graph.add_edge(START, \"mock_llm\") # Borde del grafo que establece la conexión START y el nodo previamente definido\n", + "graph.add_edge(\"mock_llm\", END) # Borde del grafo que establece la conexión entre el nodo LLM y el final del grafo\n", + "graph = graph.compile() # Compilador START -> mock_LLM -> END\n", + "\n", + "graph.invoke({\"messages\": [{\"role\": \"user\", \"content\": \"hi!\"}]}) # Invocar el grafo pasándole mensajes \n", + "# muy al estilo de las APIs de OpenAI o Claude: Lista de diccionarios con claves role y mensaje: [{'role': '', 'content': ''}]" + ] + }, + { + "cell_type": "markdown", + "id": "7d4eea90", + "metadata": {}, + "source": [ + "## API de grafos" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46a87433", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.tools import tool\n", + "from langchain.chat_models import init_chat_model\n", + "\n", + "\n", + "model = init_chat_model(\n", + " \"claude-sonnet-4-6\",\n", + " temperature=0\n", + ")\n", + "\n", + "\n", + "# Define tools\n", + "@tool\n", + "def multiply(a: int, b: int) -> int:\n", + " \"\"\"Multiply `a` and `b`.\n", + "\n", + " Args:\n", + " a: First int\n", + " b: Second int\n", + " \"\"\"\n", + " return a * b\n", + "\n", + "\n", + "@tool\n", + "def add(a: int, b: int) -> int:\n", + " \"\"\"Adds `a` and `b`.\n", + "\n", + " Args:\n", + " a: First int\n", + " b: Second int\n", + " \"\"\"\n", + " return a + b\n", + "\n", + "\n", + "@tool\n", + "def divide(a: int, b: int) -> float:\n", + " \"\"\"Divide `a` and `b`.\n", + "\n", + " Args:\n", + " a: First int\n", + " b: Second int\n", + " \"\"\"\n", + " return a / b\n", + "\n", + "\n", + "def rest(a: int, b: int) -> float:\n", + " \"\"\"Rest `a` and `b`.\n", + "\n", + " Args:\n", + " a: First int\n", + " b: Second int\n", + " \"\"\"\n", + " return a - b\n", + "\n", + "\n", + "# Augment the LLM with tools\n", + "tools = [add, multiply, divide]\n", + "tools_by_name = {tool.name: tool for tool in tools}\n", + "model_with_tools = model.bind_tools(tools) #Vincula las tools al modelo" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "0858b23e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'add'" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "add.name" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "e6221e98", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "No es tool\n" + ] + } + ], + "source": [ + "print(rest) # -> NO ES UNA TOOL, es una función. Si le coloco el \n", + "#decorador de tool habilito métodos y propiedades de la tool\n", + "try:\n", + " rest.name\n", + "except:\n", + " print(\"No es tool\")" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "65c07cc6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'add': StructuredTool(name='add', description='Adds `a` and `b`.\\n\\n Args:\\n a: First int\\n b: Second int', args_schema=, func=),\n", + " 'multiply': StructuredTool(name='multiply', description='Multiply `a` and `b`.\\n\\n Args:\\n a: First int\\n b: Second int', args_schema=, func=),\n", + " 'divide': StructuredTool(name='divide', description='Divide `a` and `b`.\\n\\n Args:\\n a: First int\\n b: Second int', args_schema=, func=)}" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tools_by_name" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "1bc9d3b2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "StructuredTool(name='add', description='Adds `a` and `b`.\\n\\n Args:\\n a: First int\\n b: Second int', args_schema=, func=)" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tools_by_name['add']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d5b46c8", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fd8ecc58", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.messages import AnyMessage\n", + "from typing_extensions import TypedDict, Annotated\n", + "import operator\n", + "\n", + "# Definimos el estado del grafo para almacenar los mensaje y el número de llamadas a LLM\n", + "# es similar a como definimos modelos en la capa domain en los que usamos una clase y \n", + "# declaramos que atributos y los tipos que deberían tener las implementaciones que\n", + "# usen ese modelo\n", + "\n", + "class MessagesState(TypedDict):\n", + " messages: Annotated[list[AnyMessage], operator.add]\n", + " llm_calls: int" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "bc87221e", + "metadata": {}, + "outputs": [], + "source": [ + "# Aquí definimos un nodo modelo que se utiliza para llamar al LLM y decidir si llamar a una herramienta o no\n", + "from langchain.messages import SystemMessage\n", + "\n", + "\n", + "def llm_call(state: dict):\n", + " \"\"\"LLM decides whether to call a tool or not\"\"\"\n", + "\n", + " return {\n", + " \"messages\": [\n", + " model_with_tools.invoke(\n", + " [\n", + " SystemMessage(\n", + " content=\"You are a helpful assistant tasked with performing arithmetic on a set of inputs.\"\n", + " )\n", + " ]\n", + " + state[\"messages\"]\n", + " )\n", + " ],\n", + " \"llm_calls\": state.get('llm_calls', 0) + 1\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "651a33ce", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.messages import ToolMessage\n", + "#El nodo herramienta se utiliza para llamar a las herramientas y devolver los resultados.\n", + "\n", + "\n", + "def tool_node(state: dict):\n", + " \"\"\"Performs the tool call\"\"\"\n", + "\n", + " result = []\n", + " for tool_call in state[\"messages\"][-1].tool_calls:\n", + " tool = tools_by_name[tool_call[\"name\"]]\n", + " observation = tool.invoke(tool_call[\"args\"])\n", + " result.append(ToolMessage(content=observation, tool_call_id=tool_call[\"id\"]))\n", + " return {\"messages\": result}" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "128c7023", + "metadata": {}, + "outputs": [], + "source": [ + "# 5. Definir la lógica final\n", + "# La función de arista condicional se utiliza para enrutar al nodo o extremo de la \n", + "# herramienta según si el LLM realizó una llamada a la herramienta.\n", + "\n", + "from typing import Literal\n", + "from langgraph.graph import StateGraph, START, END\n", + "\n", + "\n", + "def should_continue(state: MessagesState) -> Literal[\"tool_node\", END]:\n", + " \"\"\"Decide if we should continue the loop or stop based upon whether the LLM made a tool call\"\"\"\n", + "\n", + " messages = state[\"messages\"]\n", + " last_message = messages[-1]\n", + "\n", + " # If the LLM makes a tool call, then perform an action\n", + " if last_message.tool_calls:\n", + " return \"tool_node\"\n", + "\n", + " # Otherwise, we stop (reply to the user)\n", + " return END" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "6c208396", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hola\n" + ] + } + ], + "source": [ + "if not None:\n", + " print('hola')\n", + "else:\n", + " print('está en None')" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "b43d5c70", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# 6. Compilar y construir el agente\n", + "# El agente se construye usando el StateGraph y compilado usando la compile método.\n", + "\n", + "# Build workflow\n", + "agent_builder = StateGraph(MessagesState)\n", + "\n", + "# Add nodes\n", + "agent_builder.add_node(\"llm_call\", llm_call)\n", + "agent_builder.add_node(\"tool_node\", tool_node)\n", + "\n", + "# Add edges to connect nodes\n", + "agent_builder.add_edge(START, \"llm_call\")\n", + "agent_builder.add_conditional_edges(\n", + " \"llm_call\",\n", + " should_continue,\n", + " [\"tool_node\", END]\n", + ")\n", + "agent_builder.add_edge(\"tool_node\", \"llm_call\")\n", + "\n", + "# Compile the agent\n", + "agent = agent_builder.compile()\n", + "\n", + "# Show the agent\n", + "from IPython.display import Image, display\n", + "display(Image(agent.get_graph(xray=True).draw_mermaid_png()))" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "ad3ab008", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "Deriva la expresión '3x**2 + 2' y luego dame la multiplicación de 4*3 y una vez que conozcas el resultado, tómalo y divídelo entre 2\n", + "\n", + "\n", + "1\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "[{'text': 'Voy a empezar con lo que puedo hacer en paralelo: calcular la derivada de forma analítica y la multiplicación de 4×3 al mismo tiempo.\\n\\n**Derivada de `3x² + 2`:**\\nAplicando las reglas de derivación:\\n- La derivada de `3x²` es `6x`\\n- La derivada de `2` (constante) es `0`\\n\\n**∴ La derivada de `3x² + 2` es `6x`** ✅\\n\\nAhora, mientras tanto, calculo `4 × 3`:', 'type': 'text'}, {'id': 'toolu_01J2T5ZdM7b759aZE6BHxoni', 'caller': {'type': 'direct'}, 'input': {'a': 4, 'b': 3}, 'name': 'multiply', 'type': 'tool_use'}]\n", + "Tool Calls:\n", + " multiply (toolu_01J2T5ZdM7b759aZE6BHxoni)\n", + " Call ID: toolu_01J2T5ZdM7b759aZE6BHxoni\n", + " Args:\n", + " a: 4\n", + " b: 3\n", + "\n", + "\n", + "2\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "\n", + "12\n", + "\n", + "\n", + "3\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "[{'text': '`4 × 3 = 12` ✅. Ahora divido ese resultado entre 2:', 'type': 'text'}, {'id': 'toolu_017neW69ZFTQHGfKSQqo3oGK', 'caller': {'type': 'direct'}, 'input': {'a': 12, 'b': 2}, 'name': 'divide', 'type': 'tool_use'}]\n", + "Tool Calls:\n", + " divide (toolu_017neW69ZFTQHGfKSQqo3oGK)\n", + " Call ID: toolu_017neW69ZFTQHGfKSQqo3oGK\n", + " Args:\n", + " a: 12\n", + " b: 2\n", + "\n", + "\n", + "4\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "\n", + "6.0\n", + "\n", + "\n", + "5\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Aquí tienes el resumen completo:\n", + "\n", + "1. 📐 **Derivada de `3x² + 2`** → **`6x`**\n", + "2. ✖️ **`4 × 3`** → **`12`**\n", + "3. ➗ **`12 ÷ 2`** → **`6`**\n", + "\n", + "\n" + ] + } + ], + "source": [ + "# Invoke\n", + "from langchain.messages import HumanMessage\n", + "\n", + "messages = [HumanMessage(content=\"Deriva la expresión '3x**2 + 2' y luego dame la multiplicación de 4*3 y una vez que conozcas el resultado, tómalo y divídelo entre 2\")]\n", + "messages = agent.invoke({\"messages\": messages})\n", + "\n", + "count=0\n", + "for m in messages[\"messages\"]:\n", + " print(count)\n", + " m.pretty_print()\n", + " count += 1\n", + " print(\"\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "ac2e4dd3", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Modifico el grafo para no tener el borde de tool hacia llm_call\n", + "\n", + "# Build workflow\n", + "agent_builder = StateGraph(MessagesState)\n", + "\n", + "# Add nodes\n", + "agent_builder.add_node(\"llm_call\", llm_call)\n", + "agent_builder.add_node(\"tool_node\", tool_node)\n", + "\n", + "# Add edges to connect nodes\n", + "agent_builder.add_edge(START, \"llm_call\")\n", + "agent_builder.add_conditional_edges(\n", + " \"llm_call\",\n", + " should_continue,\n", + " [\"tool_node\", END]\n", + ")\n", + "# agent_builder.add_edge(\"tool_node\", \"llm_call\") # -> COMENTADA PARA VER QUÉ PASA CON LA MISMA PREGUNTA\n", + "\n", + "# Compile the agent\n", + "agent = agent_builder.compile()\n", + "\n", + "# Show the agent\n", + "from IPython.display import Image, display\n", + "display(Image(agent.get_graph(xray=True).draw_mermaid_png()))" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "75be9079", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "Deriva la expresión '3x**2 + 2' y luego dame la multiplicación de 4*3 y una vez que conozcas el resultado, tómalo y divídelo entre 2\n", + "\n", + "\n", + "1\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "[{'text': 'Voy a empezar con lo que puedo hacer en paralelo: calcular la derivada de forma analítica y la multiplicación de 4×3 al mismo tiempo.\\n\\n**Derivada de `3x² + 2`:**\\nAplicando las reglas de derivación:\\n- La derivada de `3x²` es `6x`\\n- La derivada de `2` (constante) es `0`\\n\\n**∴ d/dx(3x² + 2) = 6x**\\n\\nAhora, simultáneamente calculo `4 × 3`:', 'type': 'text'}, {'id': 'toolu_01U7PCYuZFSdJbg3X3p2ngTw', 'caller': {'type': 'direct'}, 'input': {'a': 4, 'b': 3}, 'name': 'multiply', 'type': 'tool_use'}]\n", + "Tool Calls:\n", + " multiply (toolu_01U7PCYuZFSdJbg3X3p2ngTw)\n", + " Call ID: toolu_01U7PCYuZFSdJbg3X3p2ngTw\n", + " Args:\n", + " a: 4\n", + " b: 3\n", + "\n", + "\n", + "2\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "\n", + "12\n", + "\n", + "\n" + ] + } + ], + "source": [ + "# Invoke\n", + "from langchain.messages import HumanMessage\n", + "\n", + "messages = [HumanMessage(content=\"Deriva la expresión '3x**2 + 2' y luego dame la multiplicación de 4*3 y una vez que conozcas el resultado, tómalo y divídelo entre 2\")]\n", + "messages = agent.invoke({\"messages\": messages})\n", + "\n", + "count=0\n", + "for m in messages[\"messages\"]:\n", + " print(count)\n", + " m.pretty_print()\n", + " count += 1\n", + " print(\"\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "56b7ad03", + "metadata": {}, + "source": [ + "Conclusión: Al modificar el nodo doble vía entre el llm_call y el nodo tool no se pudo hacer la siguiente operación porque el agente solo tuvo acceso a la tool 1 vez y luego pasó al END\n" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "d5844b2a", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Modifico el grafo para no tener el borde de tool hacia llm_call\n", + "\n", + "# Build workflow\n", + "agent_builder = StateGraph(MessagesState)\n", + "\n", + "# Add nodes\n", + "agent_builder.add_node(\"llm_call\", llm_call)\n", + "agent_builder.add_node(\"tool_node\", tool_node)\n", + "\n", + "# Add edges to connect nodes\n", + "agent_builder.add_edge(START, \"llm_call\")\n", + "agent_builder.add_edge(\"tool_node\", \"llm_call\") # -> Modifico la definición, primero el borde y luego el borde condicional\n", + "\n", + "agent_builder.add_conditional_edges(\n", + " \"llm_call\",\n", + " should_continue,\n", + " [\"tool_node\", END]\n", + ")\n", + "\n", + "# Compile the agent\n", + "agent = agent_builder.compile()\n", + "\n", + "# Show the agent\n", + "from IPython.display import Image, display\n", + "display(Image(agent.get_graph(xray=True).draw_mermaid_png()))" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "e18245ba", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "Deriva la expresión '3x**2 + 2' y luego dame la multiplicación de 4*3 y una vez que conozcas el resultado, tómalo y divídelo entre 2\n", + "\n", + "\n", + "1\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "[{'text': \"Voy a empezar con lo que puedo hacer en paralelo: derivar la expresión y calcular la multiplicación de 4×3 al mismo tiempo.\\n\\n> 📐 **Derivada de `3x² + 2`:**\\n> Aplicando las reglas de derivación:\\n> - La derivada de `3x²` es `6x`\\n> - La derivada de la constante `2` es `0`\\n>\\n> ∴ **f'(x) = 6x**\\n\\nAhora, simultáneamente calculo la multiplicación:\", 'type': 'text'}, {'id': 'toolu_01D6uoGaHGqu6bz99GhRo5CN', 'caller': {'type': 'direct'}, 'input': {'a': 4, 'b': 3}, 'name': 'multiply', 'type': 'tool_use'}]\n", + "Tool Calls:\n", + " multiply (toolu_01D6uoGaHGqu6bz99GhRo5CN)\n", + " Call ID: toolu_01D6uoGaHGqu6bz99GhRo5CN\n", + " Args:\n", + " a: 4\n", + " b: 3\n", + "\n", + "\n", + "2\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "\n", + "12\n", + "\n", + "\n", + "3\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "[{'text': '¡El resultado de 4×3 es **12**! Ahora lo divido entre 2:', 'type': 'text'}, {'id': 'toolu_01955iLjUYweYE54AxBH27YZ', 'caller': {'type': 'direct'}, 'input': {'a': 12, 'b': 2}, 'name': 'divide', 'type': 'tool_use'}]\n", + "Tool Calls:\n", + " divide (toolu_01955iLjUYweYE54AxBH27YZ)\n", + " Call ID: toolu_01955iLjUYweYE54AxBH27YZ\n", + " Args:\n", + " a: 12\n", + " b: 2\n", + "\n", + "\n", + "4\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "\n", + "6.0\n", + "\n", + "\n", + "5\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Aquí tienes el resumen completo de todo lo realizado:\n", + "\n", + "| Operación | Resultado |\n", + "|---|---|\n", + "| 📐 Derivada de `3x² + 2` | **f'(x) = 6x** |\n", + "| ✖️ Multiplicación `4 × 3` | **12** |\n", + "| ➗ División `12 ÷ 2` | **6** |\n", + "\n", + "\n" + ] + } + ], + "source": [ + "# Invoke\n", + "from langchain.messages import HumanMessage\n", + "\n", + "messages = [HumanMessage(content=\"Deriva la expresión '3x**2 + 2' y luego dame la multiplicación de 4*3 y una vez que conozcas el resultado, tómalo y divídelo entre 2\")]\n", + "messages = agent.invoke({\"messages\": messages})\n", + "\n", + "count=0\n", + "for m in messages[\"messages\"]:\n", + " print(count)\n", + " m.pretty_print()\n", + " count += 1\n", + " print(\"\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "204c6af5", + "metadata": {}, + "source": [ + "Conclusión: en la lógica definida no hubo cambio si definía primero el edge y luego el conditional_edge o visceversa" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "researchos (3.11.8)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From fddf4b041c3dcbd48fd672f07385a76ccb934c0f Mon Sep 17 00:00:00 2001 From: John Mario Montoya Zapata Date: Fri, 14 Aug 2026 09:10:10 -0500 Subject: [PATCH 4/5] docs(claude): document GitHub Project weekly work cycle --- CLAUDE.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 281d06c..a294f7a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -152,3 +152,19 @@ Two rules that always apply, regardless of the skill being loaded: ``. Shall I proceed?" 2. Commit messages are written in English, even though code comments and project docs may be in Spanish. + + +--- + +## Weekly Work Cycle (GitHub Project) + +Given that the repo already has a Project and associated Issues on GitHub, the weekly workflow is as follows: + +- Monday. Choose the issue for the week, move it to “In Progress” in the Project, and enter an estimate (h). Create a branch with a name matching the issue. + +- Monday through Thursday. Make commits referencing the issue with (#N). Acceptance criteria are checked off as they’re met—this gives you visible progress without having to write reports. +Upon closing. Create a pull request with “Closes #N” in the description; merge it, and the issue closes automatically, advancing the milestone bar. Enter the Actual (h). + +- Friday. The closed issues from the week serve as input for generating the question bank. The “interview-bank” skill reads the git log; if the commits reference issues, the context it receives is richer. + +And the metric that really matters in the long run isn’t the milestone bar: it’s the ratio of Estimate to cumulative Actual. In three months, you’ll know whether you systematically underestimate infrastructure work, refactoring, or integration with external APIs. That data stays with you for the rest of your career, and almost no one has it because almost no one measures it. From 387b3e8fa9144e58204b24993e4e737b65c88271 Mon Sep 17 00:00:00 2001 From: John Mario Montoya Zapata Date: Fri, 14 Aug 2026 09:13:52 -0500 Subject: [PATCH 5/5] docs: close out 2026-08-13 session (work_log + learnings) --- docs/learnings.md | 60 +++++++++++++++++++++++++++++++++++++++++++++++ docs/work_log.md | 28 ++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/docs/learnings.md b/docs/learnings.md index be4b375..4c01c09 100644 --- a/docs/learnings.md +++ b/docs/learnings.md @@ -348,3 +348,63 @@ Regla simple para ResearchOS: - Tercer error mecánico de escritura de Python en una semana (los anteriores: `:` en vez de `=` en una asignación, `self` omitido en firmas de Protocol). No son conceptuales — es un hueco de automatismo que se cierra con repetición. --- + +**Fecha:** 13/08/2026 + +### ¿Qué aprendí? + +- **La razón de ser de un grafo no es el estado — es poder volver atrás.** Le + pregunté a mi tutor qué gana un grafo sobre mi pipeline lineal + (`retrieve → generate`) y mi primera respuesta se quedó en el estado + explícito. La corrección: el estado es el *mecanismo* que hace que un ciclo + signifique algo (sin estado compartido, una iteración no puede acumular lo + que aprendió la anterior), pero el *fin* es poder bifurcar (conditional + edge — ir a arXiv si la recuperación local trajo poco, ir directo a + generar si trajo suficiente, mi T19) y poder ciclar (volver a un nodo + anterior — recuperar, evaluar que es malo, reescribir la query, recuperar + de nuevo, mi T22). Una cadena de funciones no puede hacer ninguna de las + dos: va en una sola dirección. +- **"No puedo conocer el estado intermedio" es falso — es incompleto.** Dije + que con mi pipeline lineal no podía saber qué pasó en cada paso. Sí puedo: + un `logger.debug` después del retrieval, o devolver los documentos junto + con la respuesta. La diferencia real no es posible-vs-imposible, es + construcción-vs-instrumentación: en un grafo la inspeccionabilidad viene + gratis porque cada nodo ya es una unidad nombrada con entrada y salida + declaradas — cuando conecte Langfuse en V3 no voy a instrumentar nada, las + trazas van a salir solas de la estructura. Con funciones encadenadas, cada + punto de observación lo tengo que agregar yo, y se me puede olvidar. +- **Tampoco es cierto que el grafo me dé el resultado final antes.** También + hay que ejecutarlo completo para tener la respuesta. Lo que cambia no es + *cuándo* conozco el final, es que conozco los pasos intermedios sin + esfuerzo extra. +- **Para mi pipeline de hoy (dos pasos, sin ramas ni ciclos), LangGraph es + sobrecosto puro.** Un DAG lineal de dos nodos no necesita un grafo — para + eso alcanza encadenar dos funciones. La justificación de T18 no está en + T18 mismo: está en que T19 (rama condicional) y T22 (ciclo de reescritura + de query) no se pueden construir sin el grafo ya montado. Es + infraestructura que se paga adelante, no un beneficio inmediato. +- **LangGraph es orquestación de bajo nivel; LangChain es construcción de + agentes de alto nivel** (modelos + tools ya integrados, con + `create_agent`). El cambio de LangGraph 0.x a 1.x deprecó + `create_react_agent` en favor de ese `create_agent` de LangChain, que por + debajo se apoya en LangGraph para control de flujo, human-in-the-loop y + persistencia de estado. +- **El human-in-the-loop depende de que el estado sea explícito y + persistente.** Si el flujo fuera una cadena de llamadas continua, un + humano solo se entera del resultado al final (ej. un correo ya borrado + por error, marcado incorrectamente como spam). Con estado explícito y una + interrupción que lo persiste, el flujo se puede pausar, un humano corrige + el estado ("este correo no es spam"), y el agente continúa desde ahí sin + perder lo ya hecho ni reiniciar el proceso completo. +- Versiones fijadas hoy para arrancar V2: `langgraph==1.2.11`, + `langchain==1.3.15`, `langchain-anthropic==1.5.6`, + `langgraph-checkpoint==4.2.0`. + +### ¿Qué no entendí bien? + +- El mecanismo concreto de una interrupción de LangGraph que persista el + estado para que un humano intervenga y el flujo continúe después — sé que + existe (`AgentState`/`AgentStatePydantic` y objetos de human-in-the-loop + cambiaron en la migración 0.x → 1.x) pero no verifiqué la API real todavía. + +--- diff --git a/docs/work_log.md b/docs/work_log.md index 8615553..f96ae1e 100644 --- a/docs/work_log.md +++ b/docs/work_log.md @@ -259,3 +259,31 @@ - V1 real cerrada tras el merge — arrancar V2 (T18: LangGraph fundamentals) --- + +## 2026-08-13 + +### Trabajo desarrollado +- Fix real de T14: `_download_pdf` crea el directorio padre antes de escribir + (`ingestion_service.py`), y `test_extract_text_pdf` parcha `PAPERS_DIR` a + `tmp_path` para no ensuciar el repo — verificado en un clon fresco real, + no solo en el working copy (`9491967`, merge PR#5) +- `ROADMAP.md` corregido: T14 tenía fecha de cierre falsa (12/08), quedó con + la fecha real (13/08) y la nota de qué faltaba; T17 (merge a `main`) marcado +- Tag `v1.0.0` re-apuntado al commit de merge de PR#5 — V1 real cerrada +- Tracking de V2 configurado en GitHub: 11 labels, milestone "V2 — Agente + LangGraph + Briefing matutino" (vence 02/10), `.github/ISSUE_TEMPLATE/task.md`, + y los 7 issues T18–T24 con estimaciones, dependencias y labels +- Estudio de LangGraph: notebook de práctica, dependencias agregadas + (`langgraph`, `langchain`, `langchain-anthropic`), y entrada en + `learnings.md` sobre por qué un grafo aporta (bifurcaciones y ciclos, no + el estado) — corregida una confusión conceptual real en la conversación + con el tutor +- `CLAUDE.md` actualizado con el ciclo semanal de trabajo vía GitHub Project + +### Próximos pasos +- Abrir PR y mergear `docs/v2-github-tracking` a `main` +- Arrancar T18 (LangGraph fundamentals) el lunes 17/08 +- Mañana (14/08, viernes): agregar la pregunta de grafo-vs-pipeline al banco + de preguntas en el ritual normal + +---