diff --git a/=2.11.0 b/=2.11.0 new file mode 100644 index 000000000..e69de29bb diff --git a/aiobotocore_install.log b/aiobotocore_install.log new file mode 100644 index 000000000..3ccd72295 --- /dev/null +++ b/aiobotocore_install.log @@ -0,0 +1,34 @@ +Collecting aiobotocore + Downloading aiobotocore-3.1.0-py3-none-any.whl.metadata (26 kB) +Requirement already satisfied: aiohttp<4.0.0,>=3.12.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from aiobotocore) (3.13.3) +Collecting aioitertools<1.0.0,>=0.5.1 (from aiobotocore) + Downloading aioitertools-0.13.0-py3-none-any.whl.metadata (3.3 kB) +Collecting botocore<1.42.20,>=1.41.0 (from aiobotocore) + Downloading botocore-1.42.19-py3-none-any.whl.metadata (5.9 kB) +Requirement already satisfied: python-dateutil<3.0.0,>=2.1 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from aiobotocore) (2.9.0.post0) +Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from aiobotocore) (1.0.1) +Requirement already satisfied: multidict<7.0.0,>=6.0.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from aiobotocore) (6.7.0) +Requirement already satisfied: wrapt<3.0.0,>=1.10.10 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from aiobotocore) (1.17.3) +Requirement already satisfied: aiohappyeyeballs>=2.5.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from aiohttp<4.0.0,>=3.12.0->aiobotocore) (2.6.1) +Requirement already satisfied: aiosignal>=1.4.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from aiohttp<4.0.0,>=3.12.0->aiobotocore) (1.4.0) +Requirement already satisfied: attrs>=17.3.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from aiohttp<4.0.0,>=3.12.0->aiobotocore) (25.4.0) +Requirement already satisfied: frozenlist>=1.1.1 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from aiohttp<4.0.0,>=3.12.0->aiobotocore) (1.8.0) +Requirement already satisfied: propcache>=0.2.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from aiohttp<4.0.0,>=3.12.0->aiobotocore) (0.4.1) +Requirement already satisfied: yarl<2.0,>=1.17.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from aiohttp<4.0.0,>=3.12.0->aiobotocore) (1.22.0) +Requirement already satisfied: urllib3!=2.2.0,<3,>=1.25.4 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from botocore<1.42.20,>=1.41.0->aiobotocore) (2.6.2) +Requirement already satisfied: six>=1.5 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from python-dateutil<3.0.0,>=2.1->aiobotocore) (1.17.0) +Requirement already satisfied: idna>=2.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from yarl<2.0,>=1.17.0->aiohttp<4.0.0,>=3.12.0->aiobotocore) (3.11) +Downloading aiobotocore-3.1.0-py3-none-any.whl (87 kB) +Downloading aioitertools-0.13.0-py3-none-any.whl (24 kB) +Downloading botocore-1.42.19-py3-none-any.whl (14.6 MB) + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 14.6/14.6 MB 126.9 MB/s 0:00:00 +Installing collected packages: aioitertools, botocore, aiobotocore + Attempting uninstall: botocore + Found existing installation: botocore 1.42.21 + Uninstalling botocore-1.42.21: + Successfully uninstalled botocore-1.42.21 + +ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts. +strands-agents-tools 0.2.19 requires strands-agents>=1.0.0, but you have strands-agents 0.1.dev1+g695ca6654 which is incompatible. +boto3 1.42.21 requires botocore<1.43.0,>=1.42.21, but you have botocore 1.42.19 which is incompatible. +Successfully installed aiobotocore-3.1.0 aioitertools-0.13.0 botocore-1.42.19 diff --git a/dev_install_output.log b/dev_install_output.log new file mode 100644 index 000000000..e74452f77 --- /dev/null +++ b/dev_install_output.log @@ -0,0 +1,54 @@ +Collecting pytest + Downloading pytest-9.0.2-py3-none-any.whl.metadata (7.6 kB) +Collecting pytest-asyncio + Downloading pytest_asyncio-1.3.0-py3-none-any.whl.metadata (4.1 kB) +Collecting moto + Downloading moto-5.1.19-py3-none-any.whl.metadata (12 kB) +Requirement already satisfied: boto3 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (1.42.21) +Collecting iniconfig>=1.0.1 (from pytest) + Downloading iniconfig-2.3.0-py3-none-any.whl.metadata (2.5 kB) +Requirement already satisfied: packaging>=22 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from pytest) (25.0) +Collecting pluggy<2,>=1.5 (from pytest) + Using cached pluggy-1.6.0-py3-none-any.whl.metadata (4.8 kB) +Requirement already satisfied: pygments>=2.7.2 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from pytest) (2.19.2) +Requirement already satisfied: botocore!=1.35.45,!=1.35.46,>=1.20.88 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from moto) (1.42.21) +Requirement already satisfied: cryptography>=35.0.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from moto) (46.0.3) +Requirement already satisfied: requests>=2.5 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from moto) (2.32.5) +Collecting xmltodict (from moto) + Downloading xmltodict-1.0.2-py3-none-any.whl.metadata (15 kB) +Collecting werkzeug!=2.2.0,!=2.2.1,>=0.5 (from moto) + Downloading werkzeug-3.1.4-py3-none-any.whl.metadata (4.0 kB) +Requirement already satisfied: python-dateutil<3.0.0,>=2.1 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from moto) (2.9.0.post0) +Collecting responses!=0.25.5,>=0.15.0 (from moto) + Downloading responses-0.25.8-py3-none-any.whl.metadata (47 kB) +Collecting Jinja2>=2.10.1 (from moto) + Downloading jinja2-3.1.6-py3-none-any.whl.metadata (2.9 kB) +Requirement already satisfied: six>=1.5 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from python-dateutil<3.0.0,>=2.1->moto) (1.17.0) +Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from boto3) (1.0.1) +Requirement already satisfied: s3transfer<0.17.0,>=0.16.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from boto3) (0.16.0) +Requirement already satisfied: urllib3!=2.2.0,<3,>=1.25.4 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from botocore!=1.35.45,!=1.35.46,>=1.20.88->moto) (2.6.2) +Requirement already satisfied: cffi>=2.0.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from cryptography>=35.0.0->moto) (2.0.0) +Requirement already satisfied: pycparser in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from cffi>=2.0.0->cryptography>=35.0.0->moto) (2.23) +Collecting MarkupSafe>=2.0 (from Jinja2>=2.10.1->moto) + Downloading markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.metadata (2.7 kB) +Requirement already satisfied: charset_normalizer<4,>=2 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from requests>=2.5->moto) (3.4.4) +Requirement already satisfied: idna<4,>=2.5 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from requests>=2.5->moto) (3.11) +Requirement already satisfied: certifi>=2017.4.17 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from requests>=2.5->moto) (2026.1.4) +Collecting pyyaml (from responses!=0.25.5,>=0.15.0->moto) + Downloading pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.metadata (2.4 kB) +Downloading pytest-9.0.2-py3-none-any.whl (374 kB) +Using cached pluggy-1.6.0-py3-none-any.whl (20 kB) +Downloading pytest_asyncio-1.3.0-py3-none-any.whl (15 kB) +Downloading moto-5.1.19-py3-none-any.whl (6.5 MB) + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.5/6.5 MB 97.8 MB/s 0:00:00 +Downloading iniconfig-2.3.0-py3-none-any.whl (7.5 kB) +Downloading jinja2-3.1.6-py3-none-any.whl (134 kB) +Downloading markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (22 kB) +Downloading responses-0.25.8-py3-none-any.whl (34 kB) +Downloading werkzeug-3.1.4-py3-none-any.whl (224 kB) +Downloading pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (801 kB) + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 801.6/801.6 kB 97.5 MB/s 0:00:00 +Downloading xmltodict-1.0.2-py3-none-any.whl (13 kB) +Installing collected packages: xmltodict, pyyaml, pluggy, MarkupSafe, iniconfig, werkzeug, responses, pytest, Jinja2, pytest-asyncio, moto + +Successfully installed Jinja2-3.1.6 MarkupSafe-3.0.3 iniconfig-2.3.0 moto-5.1.19 pluggy-1.6.0 pytest-9.0.2 pytest-asyncio-1.3.0 pyyaml-6.0.3 responses-0.25.8 werkzeug-3.1.4 xmltodict-1.0.2 diff --git a/full_test_output.log b/full_test_output.log new file mode 100644 index 000000000..4de5f4d0e --- /dev/null +++ b/full_test_output.log @@ -0,0 +1,47 @@ +============================= test session starts ============================== +platform linux -- Python 3.13.11, pytest-9.0.2, pluggy-1.6.0 -- /opt/hostedtoolcache/Python/3.13.11/x64/bin/python +cachedir: .pytest_cache +rootdir: /home/runner/work/sdk-python/sdk-python +configfile: pyproject.toml +plugins: anyio-4.12.0, asyncio-1.3.0 +asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function +collecting ... collected 36 items + +tests/strands/session/test_s3_session_manager.py::test_init_s3_session_manager PASSED [ 2%] +tests/strands/session/test_s3_session_manager.py::test_init_s3_session_manager_with_config PASSED [ 5%] +tests/strands/session/test_s3_session_manager.py::test_init_s3_session_manager_with_existing_user_agent PASSED [ 8%] +tests/strands/session/test_s3_session_manager.py::test_create_session PASSED [ 11%] +tests/strands/session/test_s3_session_manager.py::test_create_session_already_exists PASSED [ 13%] +tests/strands/session/test_s3_session_manager.py::test_read_session PASSED [ 16%] +tests/strands/session/test_s3_session_manager.py::test_read_nonexistent_session PASSED [ 19%] +tests/strands/session/test_s3_session_manager.py::test_delete_session PASSED [ 22%] +tests/strands/session/test_s3_session_manager.py::test_create_agent PASSED [ 25%] +tests/strands/session/test_s3_session_manager.py::test_read_agent PASSED [ 27%] +tests/strands/session/test_s3_session_manager.py::test_read_nonexistent_agent PASSED [ 30%] +tests/strands/session/test_s3_session_manager.py::test_update_agent PASSED [ 33%] +tests/strands/session/test_s3_session_manager.py::test_update_nonexistent_agent PASSED [ 36%] +tests/strands/session/test_s3_session_manager.py::test_create_message PASSED [ 38%] +tests/strands/session/test_s3_session_manager.py::test_read_message PASSED [ 41%] +tests/strands/session/test_s3_session_manager.py::test_read_nonexistent_message PASSED [ 44%] +tests/strands/session/test_s3_session_manager.py::test_list_messages_all PASSED [ 47%] +tests/strands/session/test_s3_session_manager.py::test_list_messages_with_pagination PASSED [ 50%] +tests/strands/session/test_s3_session_manager.py::test_update_message PASSED [ 52%] +tests/strands/session/test_s3_session_manager.py::test_update_nonexistent_message PASSED [ 55%] +tests/strands/session/test_s3_session_manager.py::test__get_session_path_invalid_session_id[a/../b] PASSED [ 58%] +tests/strands/session/test_s3_session_manager.py::test__get_session_path_invalid_session_id[a/b] PASSED [ 61%] +tests/strands/session/test_s3_session_manager.py::test__get_agent_path_invalid_agent_id[a/../b] PASSED [ 63%] +tests/strands/session/test_s3_session_manager.py::test__get_agent_path_invalid_agent_id[a/b] PASSED [ 66%] +tests/strands/session/test_s3_session_manager.py::test__get_message_path_invalid_message_id[../../../secret] PASSED [ 69%] +tests/strands/session/test_s3_session_manager.py::test__get_message_path_invalid_message_id[../../attack] PASSED [ 72%] +tests/strands/session/test_s3_session_manager.py::test__get_message_path_invalid_message_id[../escape] PASSED [ 75%] +tests/strands/session/test_s3_session_manager.py::test__get_message_path_invalid_message_id[path/traversal] PASSED [ 77%] +tests/strands/session/test_s3_session_manager.py::test__get_message_path_invalid_message_id[not_an_int] PASSED [ 80%] +tests/strands/session/test_s3_session_manager.py::test__get_message_path_invalid_message_id[None] PASSED [ 83%] +tests/strands/session/test_s3_session_manager.py::test__get_message_path_invalid_message_id[message_id6] PASSED [ 86%] +tests/strands/session/test_s3_session_manager.py::test_create_multi_agent PASSED [ 88%] +tests/strands/session/test_s3_session_manager.py::test_read_multi_agent PASSED [ 91%] +tests/strands/session/test_s3_session_manager.py::test_read_nonexistent_multi_agent PASSED [ 94%] +tests/strands/session/test_s3_session_manager.py::test_update_multi_agent PASSED [ 97%] +tests/strands/session/test_s3_session_manager.py::test_update_nonexistent_multi_agent PASSED [100%] + +============================== 36 passed in 8.10s ============================== diff --git a/install_output.log b/install_output.log new file mode 100644 index 000000000..8aea287c2 --- /dev/null +++ b/install_output.log @@ -0,0 +1,72 @@ +Obtaining file:///home/runner/work/sdk-python/sdk-python + Installing build dependencies: started + Installing build dependencies: finished with status 'done' + Checking if build backend supports build_editable: started + Checking if build backend supports build_editable: finished with status 'done' + Getting requirements to build editable: started + Getting requirements to build editable: finished with status 'done' + Installing backend dependencies: started + Installing backend dependencies: finished with status 'done' + Preparing editable metadata (pyproject.toml): started + Preparing editable metadata (pyproject.toml): finished with status 'done' +Requirement already satisfied: boto3<2.0.0,>=1.26.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from strands-agents==0.1.dev1+g695ca6654) (1.42.21) +Requirement already satisfied: botocore<2.0.0,>=1.29.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from strands-agents==0.1.dev1+g695ca6654) (1.42.21) +Requirement already satisfied: docstring-parser<1.0,>=0.15 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from strands-agents==0.1.dev1+g695ca6654) (0.17.0) +Requirement already satisfied: jsonschema<5.0.0,>=4.0.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from strands-agents==0.1.dev1+g695ca6654) (4.25.1) +Requirement already satisfied: mcp<2.0.0,>=1.11.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from strands-agents==0.1.dev1+g695ca6654) (1.25.0) +Requirement already satisfied: opentelemetry-api<2.0.0,>=1.30.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from strands-agents==0.1.dev1+g695ca6654) (1.39.1) +Requirement already satisfied: opentelemetry-instrumentation-threading<1.00b0,>=0.51b0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from strands-agents==0.1.dev1+g695ca6654) (0.60b1) +Requirement already satisfied: opentelemetry-sdk<2.0.0,>=1.30.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from strands-agents==0.1.dev1+g695ca6654) (1.39.1) +Requirement already satisfied: pydantic<3.0.0,>=2.4.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from strands-agents==0.1.dev1+g695ca6654) (2.12.5) +Requirement already satisfied: typing-extensions<5.0.0,>=4.13.2 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from strands-agents==0.1.dev1+g695ca6654) (4.15.0) +Requirement already satisfied: watchdog<7.0.0,>=6.0.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from strands-agents==0.1.dev1+g695ca6654) (6.0.0) +Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from boto3<2.0.0,>=1.26.0->strands-agents==0.1.dev1+g695ca6654) (1.0.1) +Requirement already satisfied: s3transfer<0.17.0,>=0.16.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from boto3<2.0.0,>=1.26.0->strands-agents==0.1.dev1+g695ca6654) (0.16.0) +Requirement already satisfied: python-dateutil<3.0.0,>=2.1 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from botocore<2.0.0,>=1.29.0->strands-agents==0.1.dev1+g695ca6654) (2.9.0.post0) +Requirement already satisfied: urllib3!=2.2.0,<3,>=1.25.4 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from botocore<2.0.0,>=1.29.0->strands-agents==0.1.dev1+g695ca6654) (2.6.2) +Requirement already satisfied: attrs>=22.2.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from jsonschema<5.0.0,>=4.0.0->strands-agents==0.1.dev1+g695ca6654) (25.4.0) +Requirement already satisfied: jsonschema-specifications>=2023.03.6 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from jsonschema<5.0.0,>=4.0.0->strands-agents==0.1.dev1+g695ca6654) (2025.9.1) +Requirement already satisfied: referencing>=0.28.4 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from jsonschema<5.0.0,>=4.0.0->strands-agents==0.1.dev1+g695ca6654) (0.37.0) +Requirement already satisfied: rpds-py>=0.7.1 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from jsonschema<5.0.0,>=4.0.0->strands-agents==0.1.dev1+g695ca6654) (0.30.0) +Requirement already satisfied: anyio>=4.5 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (4.12.0) +Requirement already satisfied: httpx-sse>=0.4 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (0.4.3) +Requirement already satisfied: httpx>=0.27.1 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (0.28.1) +Requirement already satisfied: pydantic-settings>=2.5.2 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (2.12.0) +Requirement already satisfied: pyjwt>=2.10.1 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from pyjwt[crypto]>=2.10.1->mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (2.10.1) +Requirement already satisfied: python-multipart>=0.0.9 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (0.0.21) +Requirement already satisfied: sse-starlette>=1.6.1 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (3.1.2) +Requirement already satisfied: starlette>=0.27 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (0.50.0) +Requirement already satisfied: typing-inspection>=0.4.1 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (0.4.2) +Requirement already satisfied: uvicorn>=0.31.1 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (0.40.0) +Requirement already satisfied: importlib-metadata<8.8.0,>=6.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from opentelemetry-api<2.0.0,>=1.30.0->strands-agents==0.1.dev1+g695ca6654) (8.7.1) +Requirement already satisfied: zipp>=3.20 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from importlib-metadata<8.8.0,>=6.0->opentelemetry-api<2.0.0,>=1.30.0->strands-agents==0.1.dev1+g695ca6654) (3.23.0) +Requirement already satisfied: opentelemetry-instrumentation==0.60b1 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from opentelemetry-instrumentation-threading<1.00b0,>=0.51b0->strands-agents==0.1.dev1+g695ca6654) (0.60b1) +Requirement already satisfied: wrapt<2.0.0,>=1.0.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from opentelemetry-instrumentation-threading<1.00b0,>=0.51b0->strands-agents==0.1.dev1+g695ca6654) (1.17.3) +Requirement already satisfied: opentelemetry-semantic-conventions==0.60b1 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from opentelemetry-instrumentation==0.60b1->opentelemetry-instrumentation-threading<1.00b0,>=0.51b0->strands-agents==0.1.dev1+g695ca6654) (0.60b1) +Requirement already satisfied: packaging>=18.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from opentelemetry-instrumentation==0.60b1->opentelemetry-instrumentation-threading<1.00b0,>=0.51b0->strands-agents==0.1.dev1+g695ca6654) (25.0) +Requirement already satisfied: annotated-types>=0.6.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from pydantic<3.0.0,>=2.4.0->strands-agents==0.1.dev1+g695ca6654) (0.7.0) +Requirement already satisfied: pydantic-core==2.41.5 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from pydantic<3.0.0,>=2.4.0->strands-agents==0.1.dev1+g695ca6654) (2.41.5) +Requirement already satisfied: six>=1.5 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from python-dateutil<3.0.0,>=2.1->botocore<2.0.0,>=1.29.0->strands-agents==0.1.dev1+g695ca6654) (1.17.0) +Requirement already satisfied: idna>=2.8 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from anyio>=4.5->mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (3.11) +Requirement already satisfied: certifi in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from httpx>=0.27.1->mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (2026.1.4) +Requirement already satisfied: httpcore==1.* in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from httpx>=0.27.1->mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (1.0.9) +Requirement already satisfied: h11>=0.16 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from httpcore==1.*->httpx>=0.27.1->mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (0.16.0) +Requirement already satisfied: python-dotenv>=0.21.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from pydantic-settings>=2.5.2->mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (1.2.1) +Requirement already satisfied: cryptography>=3.4.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from pyjwt[crypto]>=2.10.1->mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (46.0.3) +Requirement already satisfied: cffi>=2.0.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from cryptography>=3.4.0->pyjwt[crypto]>=2.10.1->mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (2.0.0) +Requirement already satisfied: pycparser in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from cffi>=2.0.0->cryptography>=3.4.0->pyjwt[crypto]>=2.10.1->mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (2.23) +Requirement already satisfied: click>=7.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from uvicorn>=0.31.1->mcp<2.0.0,>=1.11.0->strands-agents==0.1.dev1+g695ca6654) (8.3.1) +Building wheels for collected packages: strands-agents + Building editable for strands-agents (pyproject.toml): started + Building editable for strands-agents (pyproject.toml): finished with status 'done' + Created wheel for strands-agents: filename=strands_agents-0.1.dev1+g695ca6654-py3-none-any.whl size=10022 sha256=99f2c3ed0190d2d6d4558208e27db0ee7a370d327368839c5b2b1dab4d3ff7be + Stored in directory: /tmp/pip-ephem-wheel-cache-tcbl7msa/wheels/94/60/63/fc2d04fbd73b5e7d5ee8ee2c7af924f44becb4b085a98d9503 +Successfully built strands-agents +Installing collected packages: strands-agents + Attempting uninstall: strands-agents + Found existing installation: strands-agents 1.21.0 + Uninstalling strands-agents-1.21.0: + Successfully uninstalled strands-agents-1.21.0 +ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts. +strands-agents-tools 0.2.19 requires strands-agents>=1.0.0, but you have strands-agents 0.1.dev1+g695ca6654 which is incompatible. +Successfully installed strands-agents-0.1.dev1+g695ca6654 diff --git a/lint_install.log b/lint_install.log new file mode 100644 index 000000000..f349ff8d4 --- /dev/null +++ b/lint_install.log @@ -0,0 +1,21 @@ +Collecting ruff + Downloading ruff-0.14.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (26 kB) +Collecting mypy + Downloading mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.metadata (2.2 kB) +Requirement already satisfied: typing_extensions>=4.6.0 in /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages (from mypy) (4.15.0) +Collecting mypy_extensions>=1.0.0 (from mypy) + Downloading mypy_extensions-1.1.0-py3-none-any.whl.metadata (1.1 kB) +Collecting pathspec>=0.9.0 (from mypy) + Using cached pathspec-0.12.1-py3-none-any.whl.metadata (21 kB) +Collecting librt>=0.6.2 (from mypy) + Downloading librt-0.7.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.metadata (1.3 kB) +Downloading ruff-0.14.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (14.2 MB) + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 14.2/14.2 MB 154.0 MB/s 0:00:00 +Downloading mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (13.6 MB) + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 13.6/13.6 MB 225.8 MB/s 0:00:00 +Downloading librt-0.7.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (189 kB) +Downloading mypy_extensions-1.1.0-py3-none-any.whl (5.0 kB) +Using cached pathspec-0.12.1-py3-none-any.whl (31 kB) +Installing collected packages: ruff, pathspec, mypy_extensions, librt, mypy + +Successfully installed librt-0.7.7 mypy-1.19.1 mypy_extensions-1.1.0 pathspec-0.12.1 ruff-0.14.10 diff --git a/src/strands/session/s3_session_manager.py b/src/strands/session/s3_session_manager.py index 7d081cf09..cac01a749 100644 --- a/src/strands/session/s3_session_manager.py +++ b/src/strands/session/s3_session_manager.py @@ -1,5 +1,6 @@ """S3-based session manager for cloud storage.""" +import asyncio import json import logging from typing import TYPE_CHECKING, Any, Dict, List, Optional, cast @@ -9,6 +10,7 @@ from botocore.exceptions import ClientError from .. import _identifier +from .._async import run_async from ..types.exceptions import SessionException from ..types.session import Session, SessionAgent, SessionMessage from .repository_session_manager import RepositorySessionManager @@ -259,45 +261,56 @@ def update_message(self, session_id: str, agent_id: str, session_message: Sessio def list_messages( self, session_id: str, agent_id: str, limit: Optional[int] = None, offset: int = 0, **kwargs: Any ) -> List[SessionMessage]: - """List messages for an agent with pagination from S3.""" - messages_prefix = f"{self._get_agent_path(session_id, agent_id)}messages/" - try: - paginator = self.client.get_paginator("list_objects_v2") - pages = paginator.paginate(Bucket=self.bucket, Prefix=messages_prefix) + """List messages for an agent with pagination from S3. - # Collect all message keys and extract their indices - message_index_keys: list[tuple[int, str]] = [] - for page in pages: - if "Contents" in page: - for obj in page["Contents"]: - key = obj["Key"] - if key.endswith(".json") and MESSAGE_PREFIX in key: - # Extract the filename part from the full S3 key - filename = key.split("/")[-1] - # Extract index from message_.json format - index = int(filename[len(MESSAGE_PREFIX) : -5]) # Remove prefix and .json suffix - message_index_keys.append((index, key)) - - # Sort by index and extract just the keys - message_keys = [k for _, k in sorted(message_index_keys)] - - # Apply pagination to keys before loading content - if limit is not None: - message_keys = message_keys[offset : offset + limit] - else: - message_keys = message_keys[offset:] - - # Load only the required message objects - messages: List[SessionMessage] = [] - for key in message_keys: - message_data = self._read_s3_object(key) - if message_data: - messages.append(SessionMessage.from_dict(message_data)) - - return messages + Uses concurrent async reading for improved performance when reading multiple messages. + """ - except ClientError as e: - raise SessionException(f"S3 error reading messages: {e}") from e + async def async_list_messages() -> List[SessionMessage]: + messages_prefix = f"{self._get_agent_path(session_id, agent_id)}messages/" + try: + # List message keys using sync client (listing is fast) + paginator = self.client.get_paginator("list_objects_v2") + pages = paginator.paginate(Bucket=self.bucket, Prefix=messages_prefix) + + # Collect all message keys and extract their indices + message_index_keys: list[tuple[int, str]] = [] + for page in pages: + if "Contents" in page: + for obj in page["Contents"]: + key = obj["Key"] + if key.endswith(".json") and MESSAGE_PREFIX in key: + # Extract the filename part from the full S3 key + filename = key.split("/")[-1] + # Extract index from message_.json format + index = int(filename[len(MESSAGE_PREFIX) : -5]) # Remove prefix and .json suffix + message_index_keys.append((index, key)) + + # Sort by index and extract just the keys + message_keys = [k for _, k in sorted(message_index_keys)] + + # Apply pagination to keys before loading content + if limit is not None: + message_keys = message_keys[offset : offset + limit] + else: + message_keys = message_keys[offset:] + + # Read all message objects concurrently using asyncio.to_thread + tasks = [asyncio.to_thread(self._read_s3_object, key) for key in message_keys] + message_data_list = await asyncio.gather(*tasks) + + # Parse messages and filter out None values + messages: List[SessionMessage] = [] + for message_data in message_data_list: + if message_data: + messages.append(SessionMessage.from_dict(message_data)) + + return messages + + except ClientError as e: + raise SessionException(f"S3 error reading messages: {e}") from e + + return run_async(async_list_messages) def _get_multi_agent_path(self, session_id: str, multi_agent_id: str) -> str: """Get multi-agent S3 prefix.""" diff --git a/test_output.log b/test_output.log new file mode 100644 index 000000000..8160e1d15 --- /dev/null +++ b/test_output.log @@ -0,0 +1,47 @@ +============================= test session starts ============================== +platform linux -- Python 3.13.11, pytest-9.0.2, pluggy-1.6.0 -- /opt/hostedtoolcache/Python/3.13.11/x64/bin/python +cachedir: .pytest_cache +rootdir: /home/runner/work/sdk-python/sdk-python +configfile: pyproject.toml +plugins: anyio-4.12.0, asyncio-1.3.0 +asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function +collecting ... collected 36 items + +tests/strands/session/test_s3_session_manager.py::test_init_s3_session_manager PASSED [ 2%] +tests/strands/session/test_s3_session_manager.py::test_init_s3_session_manager_with_config PASSED [ 5%] +tests/strands/session/test_s3_session_manager.py::test_init_s3_session_manager_with_existing_user_agent PASSED [ 8%] +tests/strands/session/test_s3_session_manager.py::test_create_session PASSED [ 11%] +tests/strands/session/test_s3_session_manager.py::test_create_session_already_exists PASSED [ 13%] +tests/strands/session/test_s3_session_manager.py::test_read_session PASSED [ 16%] +tests/strands/session/test_s3_session_manager.py::test_read_nonexistent_session PASSED [ 19%] +tests/strands/session/test_s3_session_manager.py::test_delete_session PASSED [ 22%] +tests/strands/session/test_s3_session_manager.py::test_create_agent PASSED [ 25%] +tests/strands/session/test_s3_session_manager.py::test_read_agent PASSED [ 27%] +tests/strands/session/test_s3_session_manager.py::test_read_nonexistent_agent PASSED [ 30%] +tests/strands/session/test_s3_session_manager.py::test_update_agent PASSED [ 33%] +tests/strands/session/test_s3_session_manager.py::test_update_nonexistent_agent PASSED [ 36%] +tests/strands/session/test_s3_session_manager.py::test_create_message PASSED [ 38%] +tests/strands/session/test_s3_session_manager.py::test_read_message PASSED [ 41%] +tests/strands/session/test_s3_session_manager.py::test_read_nonexistent_message PASSED [ 44%] +tests/strands/session/test_s3_session_manager.py::test_list_messages_all PASSED [ 47%] +tests/strands/session/test_s3_session_manager.py::test_list_messages_with_pagination PASSED [ 50%] +tests/strands/session/test_s3_session_manager.py::test_update_message PASSED [ 52%] +tests/strands/session/test_s3_session_manager.py::test_update_nonexistent_message PASSED [ 55%] +tests/strands/session/test_s3_session_manager.py::test__get_session_path_invalid_session_id[a/../b] PASSED [ 58%] +tests/strands/session/test_s3_session_manager.py::test__get_session_path_invalid_session_id[a/b] PASSED [ 61%] +tests/strands/session/test_s3_session_manager.py::test__get_agent_path_invalid_agent_id[a/../b] PASSED [ 63%] +tests/strands/session/test_s3_session_manager.py::test__get_agent_path_invalid_agent_id[a/b] PASSED [ 66%] +tests/strands/session/test_s3_session_manager.py::test__get_message_path_invalid_message_id[../../../secret] PASSED [ 69%] +tests/strands/session/test_s3_session_manager.py::test__get_message_path_invalid_message_id[../../attack] PASSED [ 72%] +tests/strands/session/test_s3_session_manager.py::test__get_message_path_invalid_message_id[../escape] PASSED [ 75%] +tests/strands/session/test_s3_session_manager.py::test__get_message_path_invalid_message_id[path/traversal] PASSED [ 77%] +tests/strands/session/test_s3_session_manager.py::test__get_message_path_invalid_message_id[not_an_int] PASSED [ 80%] +tests/strands/session/test_s3_session_manager.py::test__get_message_path_invalid_message_id[None] PASSED [ 83%] +tests/strands/session/test_s3_session_manager.py::test__get_message_path_invalid_message_id[message_id6] PASSED [ 86%] +tests/strands/session/test_s3_session_manager.py::test_create_multi_agent PASSED [ 88%] +tests/strands/session/test_s3_session_manager.py::test_read_multi_agent PASSED [ 91%] +tests/strands/session/test_s3_session_manager.py::test_read_nonexistent_multi_agent PASSED [ 94%] +tests/strands/session/test_s3_session_manager.py::test_update_multi_agent PASSED [ 97%] +tests/strands/session/test_s3_session_manager.py::test_update_nonexistent_multi_agent PASSED [100%] + +============================== 36 passed in 7.83s ==============================