From 5064059a4512cb438e62016003d78dd401e75145 Mon Sep 17 00:00:00 2001 From: David Just Date: Tue, 16 Dec 2025 15:53:06 -0600 Subject: [PATCH 1/2] Fix issue where span creation was not allowing List[Any] This change is primarily to fix an issue where if you try to create a trace span using a List instead of a dictionary or BaseModel it errored out even though the upper function signature specified that List[Any] is allowed. To be able to verify this with built in tests I had to update the requirements * .lock files and then the uv.lock file also got updated. This all resulted in no longer needing or being required to limit the nox session to pydantic 1.x and it was failing because the code wants pydantic 2 so i removed the pydantic 1.x requirement from the nox file. --- noxfile.py | 3 +- pyproject.toml | 14 ++++--- requirements-dev.lock | 37 +++++++++++++---- requirements.lock | 60 +++++++++++++++++++++++---- src/agentex/lib/core/tracing/trace.py | 16 +++---- uv.lock | 2 +- 6 files changed, 101 insertions(+), 31 deletions(-) diff --git a/noxfile.py b/noxfile.py index 53bca7ff2..b4c1c9031 100644 --- a/noxfile.py +++ b/noxfile.py @@ -4,6 +4,5 @@ @nox.session(reuse_venv=True, name="test-pydantic-v1") def test_pydantic_v1(session: nox.Session) -> None: session.install("-r", "requirements-dev.lock") - session.install("pydantic<2") - + session.run("pytest", "--showlocals", "--ignore=tests/functional", *session.posargs) diff --git a/pyproject.toml b/pyproject.toml index 738a20a74..b035d70d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,10 +11,10 @@ authors = [ dependencies = [ "httpx>=0.27.2,<0.28", "pydantic>=2.0.0, <3", - "typing-extensions>=4.10, <5", - "anyio>=3.5.0, <5", - "distro>=1.7.0, <2", - "sniffio", + "typing-extensions>=4.10, <5", + "anyio>=3.5.0, <5", + "distro>=1.7.0, <2", + "sniffio", "typer>=0.16,<0.17", "questionary>=2.0.1,<3", "rich>=13.9.2,<14", @@ -48,6 +48,7 @@ dependencies = [ "yaspin>=3.1.0", "claude-agent-sdk>=0.1.0", "anthropic>=0.40.0", + ] requires-python = ">= 3.12,<4" @@ -90,13 +91,14 @@ dev-dependencies = [ "pytest-asyncio", "ruff", "time-machine", - "nox", + "nox>=2025.11.12", "dirty-equals>=0.6.0", "importlib-metadata>=6.7.0", "rich>=13.7.1", "nest_asyncio==1.6.0", "pytest-xdist>=3.6.1", "debugpy>=1.8.15", + ] [tool.rye.scripts] @@ -174,7 +176,7 @@ replacement = '[\1](https://github.com/scaleapi/scale-agentex-python/tree/main/\ [tool.pytest.ini_options] testpaths = ["tests"] -addopts = "--tb=short -n auto" +addopts = "--tb=short" xfail_strict = true asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "session" diff --git a/requirements-dev.lock b/requirements-dev.lock index 1078b30de..3f8d088ce 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -16,12 +16,16 @@ aiohttp==3.13.2 # via agentex-sdk # via httpx-aiohttp # via litellm -aiosignal==1.3.2 +aiosignal==1.4.0 # via aiohttp annotated-types==0.7.0 # via pydantic +anthropic==0.75.0 + # via agentex-sdk anyio==4.10.0 # via agentex-sdk + # via anthropic + # via claude-agent-sdk # via httpx # via mcp # via openai @@ -30,8 +34,6 @@ anyio==4.10.0 # via sse-starlette # via starlette # via watchfiles -appnope==0.1.4 - # via ipykernel argcomplete==3.1.2 # via nox asttokens==3.0.0 @@ -39,6 +41,7 @@ asttokens==3.0.0 attrs==25.3.0 # via aiohttp # via jsonschema + # via nox # via referencing bytecode==0.17.0 # via ddtrace @@ -51,6 +54,8 @@ certifi==2023.7.22 # via requests charset-normalizer==3.4.3 # via requests +claude-agent-sdk==0.1.17 + # via agentex-sdk click==8.2.1 # via litellm # via typer @@ -71,14 +76,19 @@ debugpy==1.8.16 # via ipykernel decorator==5.2.1 # via ipython +dependency-groups==1.3.1 + # via nox dirty-equals==0.6.0 distlib==0.3.7 # via virtualenv distro==1.9.0 # via agentex-sdk + # via anthropic # via openai # via scale-gp # via scale-gp-beta +docstring-parser==0.17.0 + # via anthropic envier==0.6.1 # via ddtrace execnet==2.1.1 @@ -108,6 +118,7 @@ httpcore==1.0.9 # via httpx httpx==0.27.2 # via agentex-sdk + # via anthropic # via httpx-aiohttp # via litellm # via mcp @@ -121,6 +132,8 @@ httpx-sse==0.4.1 # via mcp huggingface-hub==0.34.4 # via tokenizers +humanize==4.14.0 + # via nox idna==3.4 # via anyio # via httpx @@ -143,6 +156,7 @@ jinja2==3.1.6 # via agentex-sdk # via litellm jiter==0.10.0 + # via anthropic # via openai json-log-formatter==1.1.1 # via agentex-sdk @@ -172,6 +186,7 @@ matplotlib-inline==0.1.7 # via ipython mcp==1.12.4 # via agentex-sdk + # via claude-agent-sdk # via openai-agents mdurl==0.1.2 # via markdown-it-py @@ -187,7 +202,8 @@ nexus-rpc==1.1.0 # via temporalio nodeenv==1.8.0 # via pyright -nox==2023.4.22 +nox==2025.11.12 + # via agentex-sdk oauthlib==3.3.1 # via kubernetes # via requests-oauthlib @@ -200,14 +216,15 @@ openai-agents==0.4.2 opentelemetry-api==1.37.0 # via ddtrace packaging==23.2 + # via dependency-groups # via huggingface-hub # via ipykernel # via nox # via pytest -pathspec==0.12.1 - # via mypy parso==0.8.4 # via jedi +pathspec==0.12.1 + # via mypy pexpect==4.9.0 # via ipython platformdirs==3.11.0 @@ -237,6 +254,7 @@ pyasn1-modules==0.4.2 # via google-auth pydantic==2.11.9 # via agentex-sdk + # via anthropic # via fastapi # via litellm # via mcp @@ -329,6 +347,7 @@ six==1.16.0 # via python-dateutil sniffio==1.3.1 # via agentex-sdk + # via anthropic # via anyio # via httpx # via openai @@ -343,6 +362,8 @@ starlette==0.46.2 # via mcp temporalio==1.18.2 # via agentex-sdk +termcolor==3.2.0 + # via yaspin tiktoken==0.11.0 # via litellm time-machine==2.9.0 @@ -374,6 +395,7 @@ types-urllib3==1.26.25.14 typing-extensions==4.12.2 # via agentex-sdk # via aiosignal + # via anthropic # via anyio # via fastapi # via huggingface-hub @@ -392,7 +414,6 @@ typing-extensions==4.12.2 # via temporalio # via typer # via typing-inspection - # via virtualenv typing-inspection==0.4.2 # via pydantic # via pydantic-settings @@ -418,5 +439,7 @@ wrapt==1.17.3 # via ddtrace yarl==1.20.0 # via aiohttp +yaspin==3.4.0 + # via agentex-sdk zipp==3.23.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index 79519671e..c1bafd7bb 100644 --- a/requirements.lock +++ b/requirements.lock @@ -16,12 +16,16 @@ aiohttp==3.13.2 # via agentex-sdk # via httpx-aiohttp # via litellm -aiosignal==1.3.2 +aiosignal==1.4.0 # via aiohttp annotated-types==0.7.0 # via pydantic +anthropic==0.75.0 + # via agentex-sdk anyio==4.10.0 # via agentex-sdk + # via anthropic + # via claude-agent-sdk # via httpx # via mcp # via openai @@ -30,13 +34,14 @@ anyio==4.10.0 # via sse-starlette # via starlette # via watchfiles -appnope==0.1.4 - # via ipykernel +argcomplete==3.6.3 + # via nox asttokens==3.0.0 # via stack-data attrs==25.3.0 # via aiohttp # via jsonschema + # via nox # via referencing bytecode==0.17.0 # via ddtrace @@ -49,6 +54,8 @@ certifi==2023.7.22 # via requests charset-normalizer==3.4.3 # via requests +claude-agent-sdk==0.1.17 + # via agentex-sdk click==8.2.1 # via litellm # via typer @@ -57,6 +64,8 @@ cloudpickle==3.1.1 # via agentex-sdk colorama==0.4.6 # via griffe +colorlog==6.10.1 + # via nox comm==0.2.3 # via ipykernel datadog==0.52.1 @@ -67,11 +76,18 @@ debugpy==1.8.16 # via ipykernel decorator==5.2.1 # via ipython +dependency-groups==1.3.1 + # via nox +distlib==0.4.0 + # via virtualenv distro==1.8.0 # via agentex-sdk + # via anthropic # via openai # via scale-gp # via scale-gp-beta +docstring-parser==0.17.0 + # via anthropic envier==0.6.1 # via ddtrace executing==2.2.0 @@ -80,6 +96,7 @@ fastapi==0.115.14 # via agentex-sdk filelock==3.19.1 # via huggingface-hub + # via virtualenv frozenlist==1.6.2 # via aiohttp # via aiosignal @@ -98,6 +115,7 @@ httpcore==1.0.9 # via httpx httpx==0.27.2 # via agentex-sdk + # via anthropic # via httpx-aiohttp # via litellm # via mcp @@ -110,6 +128,8 @@ httpx-sse==0.4.1 # via mcp huggingface-hub==0.34.4 # via tokenizers +humanize==4.14.0 + # via nox idna==3.4 # via anyio # via httpx @@ -132,6 +152,7 @@ jinja2==3.1.6 # via agentex-sdk # via litellm jiter==0.10.0 + # via anthropic # via openai json-log-formatter==1.1.1 # via agentex-sdk @@ -161,6 +182,7 @@ matplotlib-inline==0.1.7 # via ipython mcp==1.12.4 # via agentex-sdk + # via claude-agent-sdk # via openai-agents mdurl==0.1.2 # via markdown-it-py @@ -171,6 +193,8 @@ nest-asyncio==1.6.0 # via ipykernel nexus-rpc==1.1.0 # via temporalio +nox==2025.11.12 + # via agentex-sdk oauthlib==3.3.1 # via kubernetes # via requests-oauthlib @@ -183,8 +207,10 @@ openai-agents==0.4.2 opentelemetry-api==1.37.0 # via ddtrace packaging==25.0 + # via dependency-groups # via huggingface-hub # via ipykernel + # via nox # via pytest parso==0.8.4 # via jedi @@ -192,6 +218,7 @@ pexpect==4.9.0 # via ipython platformdirs==4.3.8 # via jupyter-core + # via virtualenv pluggy==1.6.0 # via pytest prompt-toolkit==3.0.51 @@ -200,9 +227,6 @@ prompt-toolkit==3.0.51 propcache==0.3.1 # via aiohttp # via yarl -pydantic==2.12.5 - # via agentex-sdk -pydantic-core==2.41.5 protobuf==5.29.5 # via ddtrace # via temporalio @@ -217,6 +241,19 @@ pyasn1==0.6.1 # via rsa pyasn1-modules==0.4.2 # via google-auth +pydantic==2.12.5 + # via agentex-sdk + # via anthropic + # via fastapi + # via litellm + # via mcp + # via openai + # via openai-agents + # via pydantic-settings + # via python-on-whales + # via scale-gp + # via scale-gp-beta +pydantic-core==2.41.5 # via pydantic pydantic-settings==2.10.1 # via mcp @@ -290,7 +327,8 @@ six==1.17.0 # via python-dateutil sniffio==1.3.0 # via agentex-sdk -typing-extensions==4.15.0 + # via anthropic + # via anyio # via httpx # via openai # via scale-gp @@ -304,6 +342,8 @@ starlette==0.46.2 # via mcp temporalio==1.18.2 # via agentex-sdk +termcolor==3.2.0 + # via yaspin tiktoken==0.11.0 # via litellm tokenizers==0.21.4 @@ -331,8 +371,10 @@ types-requests==2.31.0.6 # via openai-agents types-urllib3==1.26.25.14 # via types-requests +typing-extensions==4.15.0 # via agentex-sdk # via aiosignal + # via anthropic # via anyio # via fastapi # via huggingface-hub @@ -362,6 +404,8 @@ urllib3==1.26.20 uvicorn==0.35.0 # via agentex-sdk # via mcp +virtualenv==20.35.4 + # via nox watchfiles==0.24.0 # via agentex-sdk wcwidth==0.2.13 @@ -372,5 +416,7 @@ wrapt==1.17.3 # via ddtrace yarl==1.20.0 # via aiohttp +yaspin==3.4.0 + # via agentex-sdk zipp==3.23.0 # via importlib-metadata diff --git a/src/agentex/lib/core/tracing/trace.py b/src/agentex/lib/core/tracing/trace.py index 2ba1d489e..8e24f22c2 100644 --- a/src/agentex/lib/core/tracing/trace.py +++ b/src/agentex/lib/core/tracing/trace.py @@ -48,8 +48,8 @@ def start_span( self, name: str, parent_id: str | None = None, - input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, - data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, + input: dict[str, Any] | list[Any] | BaseModel | None = None, + data: dict[str, Any] | list[Any] | BaseModel | None = None, ) -> Span: """ Start a new span and register it with the API. @@ -144,8 +144,8 @@ def span( self, name: str, parent_id: str | None = None, - input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, - data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, + input: dict[str, Any] | list[Any] | BaseModel | None = None, + data: dict[str, Any] | list[Any] | BaseModel | None = None, ): """ Context manager for spans. @@ -189,8 +189,8 @@ async def start_span( self, name: str, parent_id: str | None = None, - input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, - data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, + input: dict[str, Any] | list[Any] | BaseModel | None = None, + data: dict[str, Any] | list[Any] | BaseModel | None = None, ) -> Span: """ Start a new span and register it with the API. @@ -288,8 +288,8 @@ async def span( self, name: str, parent_id: str | None = None, - input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, - data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, + input: dict[str, Any] | list[Any] | BaseModel | None = None, + data: dict[str, Any] | list[Any] | BaseModel | None = None, ) -> AsyncGenerator[Span | None, None]: """ Context manager for spans. diff --git a/uv.lock b/uv.lock index 0a0242aed..d4a1a62dc 100644 --- a/uv.lock +++ b/uv.lock @@ -8,7 +8,7 @@ resolution-markers = [ [[package]] name = "agentex-sdk" -version = "0.6.7" +version = "0.7.3" source = { editable = "." } dependencies = [ { name = "aiohttp" }, From 3056b77d405e3985166825814862b59ace287f2d Mon Sep 17 00:00:00 2001 From: David Just Date: Thu, 18 Dec 2025 13:27:03 -0600 Subject: [PATCH 2/2] Fix issue where span creation was not allowing List[Any] by actually not allowing List[Any] This flips the fix on it's head and instead of allowing List[Any] goes the other way and requires that a list be a List[Dict[str, Any]] which is what the deeper SPAN object actually wants. I noticed that the `data` parameter suffers the same lack of type consistency that the `input` parameter had where the SPAN object actually specifies only dicts and lists of dicts are accepted, but upper level functions allow list[Any] so I normalized those as well. --- src/agentex/lib/adk/_modules/tracing.py | 16 ++++++++-------- src/agentex/lib/core/services/adk/tracing.py | 4 ++-- .../activities/adk/tracing_activities.py | 4 ++-- src/agentex/lib/core/tracing/trace.py | 16 ++++++++-------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/agentex/lib/adk/_modules/tracing.py b/src/agentex/lib/adk/_modules/tracing.py index 93fd2365e..65f782802 100644 --- a/src/agentex/lib/adk/_modules/tracing.py +++ b/src/agentex/lib/adk/_modules/tracing.py @@ -53,8 +53,8 @@ async def span( self, trace_id: str, name: str, - input: list[Any] | dict[str, Any] | BaseModel | None = None, - data: list[Any] | dict[str, Any] | BaseModel | None = None, + input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, + data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, parent_id: str | None = None, start_to_close_timeout: timedelta = timedelta(seconds=5), heartbeat_timeout: timedelta = timedelta(seconds=5), @@ -69,9 +69,9 @@ async def span( Args: trace_id (str): The trace ID for the span. name (str): The name of the span. - input (Union[List, Dict, BaseModel]): The input for the span. + input (Union[Dict, List[Dict], BaseModel]): The input for the span. parent_id (Optional[str]): The parent span ID for the span. - data (Optional[Union[List, Dict, BaseModel]]): The data for the span. + data (Optional[Union[Dict, List[Dict], BaseModel]]): The data for the span. start_to_close_timeout (timedelta): The start to close timeout for the span. heartbeat_timeout (timedelta): The heartbeat timeout for the span. retry_policy (RetryPolicy): The retry policy for the span. @@ -109,9 +109,9 @@ async def start_span( self, trace_id: str, name: str, - input: list[Any] | dict[str, Any] | BaseModel | None = None, + input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, parent_id: str | None = None, - data: list[Any] | dict[str, Any] | BaseModel | None = None, + data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, start_to_close_timeout: timedelta = timedelta(seconds=5), heartbeat_timeout: timedelta = timedelta(seconds=1), retry_policy: RetryPolicy = DEFAULT_RETRY_POLICY, @@ -122,9 +122,9 @@ async def start_span( Args: trace_id (str): The trace ID for the span. name (str): The name of the span. - input (Union[List, Dict, BaseModel]): The input for the span. + input (Union[Dict, List[Dict], BaseModel]): The input for the span. parent_id (Optional[str]): The parent span ID for the span. - data (Optional[Union[List, Dict, BaseModel]]): The data for the span. + data (Optional[Union[Dict, List[Dict], BaseModel]]): The data for the span. start_to_close_timeout (timedelta): The start to close timeout for the span. heartbeat_timeout (timedelta): The heartbeat timeout for the span. retry_policy (RetryPolicy): The retry policy for the span. diff --git a/src/agentex/lib/core/services/adk/tracing.py b/src/agentex/lib/core/services/adk/tracing.py index 7e55c7501..7b381267b 100644 --- a/src/agentex/lib/core/services/adk/tracing.py +++ b/src/agentex/lib/core/services/adk/tracing.py @@ -20,8 +20,8 @@ async def start_span( trace_id: str, name: str, parent_id: str | None = None, - input: list[Any] | dict[str, Any] | BaseModel | None = None, - data: list[Any] | dict[str, Any] | BaseModel | None = None, + input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, + data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, ) -> Span | None: trace = self._tracer.trace(trace_id) async with trace.span( diff --git a/src/agentex/lib/core/temporal/activities/adk/tracing_activities.py b/src/agentex/lib/core/temporal/activities/adk/tracing_activities.py index 65afcded0..2db335880 100644 --- a/src/agentex/lib/core/temporal/activities/adk/tracing_activities.py +++ b/src/agentex/lib/core/temporal/activities/adk/tracing_activities.py @@ -22,8 +22,8 @@ class StartSpanParams(BaseModel): trace_id: str parent_id: str | None = None name: str - input: list[Any] | dict[str, Any] | BaseModel | None = None - data: list[Any] | dict[str, Any] | BaseModel | None = None + input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None + data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None class EndSpanParams(BaseModel): diff --git a/src/agentex/lib/core/tracing/trace.py b/src/agentex/lib/core/tracing/trace.py index 8e24f22c2..2ba1d489e 100644 --- a/src/agentex/lib/core/tracing/trace.py +++ b/src/agentex/lib/core/tracing/trace.py @@ -48,8 +48,8 @@ def start_span( self, name: str, parent_id: str | None = None, - input: dict[str, Any] | list[Any] | BaseModel | None = None, - data: dict[str, Any] | list[Any] | BaseModel | None = None, + input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, + data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, ) -> Span: """ Start a new span and register it with the API. @@ -144,8 +144,8 @@ def span( self, name: str, parent_id: str | None = None, - input: dict[str, Any] | list[Any] | BaseModel | None = None, - data: dict[str, Any] | list[Any] | BaseModel | None = None, + input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, + data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, ): """ Context manager for spans. @@ -189,8 +189,8 @@ async def start_span( self, name: str, parent_id: str | None = None, - input: dict[str, Any] | list[Any] | BaseModel | None = None, - data: dict[str, Any] | list[Any] | BaseModel | None = None, + input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, + data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, ) -> Span: """ Start a new span and register it with the API. @@ -288,8 +288,8 @@ async def span( self, name: str, parent_id: str | None = None, - input: dict[str, Any] | list[Any] | BaseModel | None = None, - data: dict[str, Any] | list[Any] | BaseModel | None = None, + input: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, + data: dict[str, Any] | list[dict[str, Any]] | BaseModel | None = None, ) -> AsyncGenerator[Span | None, None]: """ Context manager for spans.