Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
1cf98cb
codegen metadata
stainless-app[bot] Nov 7, 2025
ac6a8b5
codegen metadata
stainless-app[bot] Nov 7, 2025
0bfb07e
codegen metadata
stainless-app[bot] Nov 7, 2025
632b25e
codegen metadata
stainless-app[bot] Nov 7, 2025
dccce5d
codegen metadata
stainless-app[bot] Nov 7, 2025
5ec0383
chore(internal): restore stats
Nov 7, 2025
d230615
codegen metadata
stainless-app[bot] Nov 7, 2025
7f149ed
codegen metadata
stainless-app[bot] Nov 7, 2025
6c6c3b8
codegen metadata
stainless-app[bot] Nov 7, 2025
bb65599
codegen metadata
stainless-app[bot] Nov 7, 2025
c8eaeb0
codegen metadata
stainless-app[bot] Nov 8, 2025
035be74
codegen metadata
stainless-app[bot] Nov 8, 2025
d48c596
codegen metadata
stainless-app[bot] Nov 8, 2025
33509e0
codegen metadata
stainless-app[bot] Nov 8, 2025
2ea95a1
codegen metadata
stainless-app[bot] Nov 8, 2025
594822f
codegen metadata
stainless-app[bot] Nov 8, 2025
f44f5fb
codegen metadata
stainless-app[bot] Nov 8, 2025
e34d046
codegen metadata
stainless-app[bot] Nov 8, 2025
533798a
codegen metadata
stainless-app[bot] Nov 8, 2025
65082ea
codegen metadata
stainless-app[bot] Nov 9, 2025
d320888
codegen metadata
stainless-app[bot] Nov 9, 2025
40a7c9d
codegen metadata
stainless-app[bot] Nov 9, 2025
4981668
codegen metadata
stainless-app[bot] Nov 9, 2025
876ec14
codegen metadata
stainless-app[bot] Nov 9, 2025
055269b
codegen metadata
stainless-app[bot] Nov 9, 2025
4db4583
codegen metadata
stainless-app[bot] Nov 9, 2025
8e551af
codegen metadata
stainless-app[bot] Nov 9, 2025
cb4e8a9
codegen metadata
stainless-app[bot] Nov 10, 2025
e61c5fb
codegen metadata
stainless-app[bot] Nov 10, 2025
941854c
codegen metadata
stainless-app[bot] Nov 10, 2025
f3435c3
codegen metadata
stainless-app[bot] Nov 10, 2025
3d4dc37
chore(package): drop Python 3.8 support
stainless-app[bot] Nov 10, 2025
b848924
codegen metadata
stainless-app[bot] Nov 10, 2025
9a62f23
fix: compat with Python 3.14
stainless-app[bot] Nov 10, 2025
e8ab5b8
codegen metadata
stainless-app[bot] Nov 10, 2025
9faf035
codegen metadata
stainless-app[bot] Nov 10, 2025
0d1b6d5
codegen metadata
stainless-app[bot] Nov 10, 2025
d96f5ca
codegen metadata
stainless-app[bot] Nov 10, 2025
62a251b
codegen metadata
stainless-app[bot] Nov 10, 2025
191f2d5
codegen metadata
stainless-app[bot] Nov 10, 2025
243d5d3
codegen metadata
stainless-app[bot] Nov 10, 2025
b00d694
codegen metadata
stainless-app[bot] Nov 11, 2025
6cbe51f
codegen metadata
stainless-app[bot] Nov 11, 2025
7b2a71a
codegen metadata
stainless-app[bot] Nov 11, 2025
a3d0de9
codegen metadata
stainless-app[bot] Nov 11, 2025
ff2bb71
codegen metadata
stainless-app[bot] Nov 11, 2025
1c14abd
codegen metadata
stainless-app[bot] Nov 11, 2025
cf857f9
fix(compat): update signatures of `model_dump` and `model_dump_json` …
stainless-app[bot] Nov 11, 2025
f5c1876
codegen metadata
stainless-app[bot] Nov 11, 2025
36a9921
codegen metadata
stainless-app[bot] Nov 11, 2025
cb220c4
codegen metadata
stainless-app[bot] Nov 11, 2025
df5042e
codegen metadata
stainless-app[bot] Nov 11, 2025
4f7e910
codegen metadata
stainless-app[bot] Nov 11, 2025
6eedac4
codegen metadata
stainless-app[bot] Nov 11, 2025
8d58d2e
codegen metadata
stainless-app[bot] Nov 11, 2025
06f435a
codegen metadata
stainless-app[bot] Nov 11, 2025
ac80c16
codegen metadata
stainless-app[bot] Nov 12, 2025
6be29bb
codegen metadata
stainless-app[bot] Nov 12, 2025
6213c7a
codegen metadata
stainless-app[bot] Nov 12, 2025
6e2a09a
codegen metadata
stainless-app[bot] Nov 12, 2025
ed8eb3c
release: 0.6.6
stainless-app[bot] Nov 12, 2025
6ec37ae
Fix typo in pyproject.toml classifiers
jasonyang101 Nov 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.6.5"
".": "0.6.6"
}
4 changes: 2 additions & 2 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 36
configured_endpoints: 34
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/sgp%2Fagentex-sdk-17022011bf153e3ac9e20d23c5dca8a3072b0e735b47bb391b6e35b00348d5a5.yml
openapi_spec_hash: 0927cdce49a6e6915d6060c2ab43b0d0
config_hash: 758ca2ffe20517da913adf250c924c8a
config_hash: 0197f86ba1a4b1b5ce813d0e62138588
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Changelog

## 0.6.6 (2025-11-12)

Full Changelog: [v0.6.5...v0.6.6](https://github.com/scaleapi/scale-agentex-python/compare/v0.6.5...v0.6.6)

### Bug Fixes

* compat with Python 3.14 ([9a62f23](https://github.com/scaleapi/scale-agentex-python/commit/9a62f23376ef797bafe67f61552eb7635286caa3))
* **compat:** update signatures of `model_dump` and `model_dump_json` for Pydantic v1 ([cf857f9](https://github.com/scaleapi/scale-agentex-python/commit/cf857f9191f10a971e9cba2a8c764229ed4a7dfe))


### Chores

* **internal:** restore stats ([5ec0383](https://github.com/scaleapi/scale-agentex-python/commit/5ec0383d9d6a85b342263ba49b8e3893924c59fc))
* **package:** drop Python 3.8 support ([3d4dc37](https://github.com/scaleapi/scale-agentex-python/commit/3d4dc37f87b8d8f1debbe6505746342e461772ba))

## 0.6.5 (2025-11-06)

Full Changelog: [v0.6.4...v0.6.5](https://github.com/scaleapi/scale-agentex-python/compare/v0.6.4...v0.6.5)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<!-- prettier-ignore -->
[![PyPI version](https://img.shields.io/pypi/v/agentex-sdk.svg?label=pypi%20(stable))](https://pypi.org/project/agentex-sdk/)

The Agentex Python library provides convenient access to the Agentex REST API from any Python 3.8+
The Agentex Python library provides convenient access to the Agentex REST API from any Python 3.9+
application. The library includes type definitions for all request params and response fields,
and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).

Expand Down Expand Up @@ -389,7 +389,7 @@ print(agentex.__version__)

## Requirements

Python 3.8 or higher.
Python 3.9 or higher.

## Contributing

Expand Down
52 changes: 37 additions & 15 deletions src/agentex/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import os
import inspect
import weakref
from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast
from datetime import date, datetime
from typing_extensions import (
Expand Down Expand Up @@ -256,32 +257,41 @@ def model_dump(
mode: Literal["json", "python"] | str = "python",
include: IncEx | None = None,
exclude: IncEx | None = None,
context: Any | None = None,
by_alias: bool | None = None,
exclude_unset: bool = False,
exclude_defaults: bool = False,
exclude_none: bool = False,
exclude_computed_fields: bool = False,
round_trip: bool = False,
warnings: bool | Literal["none", "warn", "error"] = True,
context: dict[str, Any] | None = None,
serialize_as_any: bool = False,
fallback: Callable[[Any], Any] | None = None,
serialize_as_any: bool = False,
) -> dict[str, Any]:
"""Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump

Generate a dictionary representation of the model, optionally specifying which fields to include or exclude.

Args:
mode: The mode in which `to_python` should run.
If mode is 'json', the dictionary will only contain JSON serializable types.
If mode is 'python', the dictionary may contain any Python objects.
include: A list of fields to include in the output.
exclude: A list of fields to exclude from the output.
If mode is 'json', the output will only contain JSON serializable types.
If mode is 'python', the output may contain non-JSON-serializable Python objects.
include: A set of fields to include in the output.
exclude: A set of fields to exclude from the output.
context: Additional context to pass to the serializer.
by_alias: Whether to use the field's alias in the dictionary key if defined.
exclude_unset: Whether to exclude fields that are unset or None from the output.
exclude_defaults: Whether to exclude fields that are set to their default value from the output.
exclude_none: Whether to exclude fields that have a value of `None` from the output.
round_trip: Whether to enable serialization and deserialization round-trip support.
warnings: Whether to log warnings when invalid fields are encountered.
exclude_unset: Whether to exclude fields that have not been explicitly set.
exclude_defaults: Whether to exclude fields that are set to their default value.
exclude_none: Whether to exclude fields that have a value of `None`.
exclude_computed_fields: Whether to exclude computed fields.
While this can be useful for round-tripping, it is usually recommended to use the dedicated
`round_trip` parameter instead.
round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T].
warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors,
"error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError].
fallback: A function to call when an unknown value is encountered. If not provided,
a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised.
serialize_as_any: Whether to serialize fields with duck-typing serialization behavior.

Returns:
A dictionary representation of the model.
Expand All @@ -298,6 +308,8 @@ def model_dump(
raise ValueError("serialize_as_any is only supported in Pydantic v2")
if fallback is not None:
raise ValueError("fallback is only supported in Pydantic v2")
if exclude_computed_fields != False:
raise ValueError("exclude_computed_fields is only supported in Pydantic v2")
dumped = super().dict( # pyright: ignore[reportDeprecated]
include=include,
exclude=exclude,
Expand All @@ -314,15 +326,17 @@ def model_dump_json(
self,
*,
indent: int | None = None,
ensure_ascii: bool = False,
include: IncEx | None = None,
exclude: IncEx | None = None,
context: Any | None = None,
by_alias: bool | None = None,
exclude_unset: bool = False,
exclude_defaults: bool = False,
exclude_none: bool = False,
exclude_computed_fields: bool = False,
round_trip: bool = False,
warnings: bool | Literal["none", "warn", "error"] = True,
context: dict[str, Any] | None = None,
fallback: Callable[[Any], Any] | None = None,
serialize_as_any: bool = False,
) -> str:
Expand Down Expand Up @@ -354,6 +368,10 @@ def model_dump_json(
raise ValueError("serialize_as_any is only supported in Pydantic v2")
if fallback is not None:
raise ValueError("fallback is only supported in Pydantic v2")
if ensure_ascii != False:
raise ValueError("ensure_ascii is only supported in Pydantic v2")
if exclude_computed_fields != False:
raise ValueError("exclude_computed_fields is only supported in Pydantic v2")
return super().json( # type: ignore[reportDeprecated]
indent=indent,
include=include,
Expand Down Expand Up @@ -573,6 +591,9 @@ class CachedDiscriminatorType(Protocol):
__discriminator__: DiscriminatorDetails


DISCRIMINATOR_CACHE: weakref.WeakKeyDictionary[type, DiscriminatorDetails] = weakref.WeakKeyDictionary()


class DiscriminatorDetails:
field_name: str
"""The name of the discriminator field in the variant class, e.g.
Expand Down Expand Up @@ -615,8 +636,9 @@ def __init__(


def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None:
if isinstance(union, CachedDiscriminatorType):
return union.__discriminator__
cached = DISCRIMINATOR_CACHE.get(union)
if cached is not None:
return cached

discriminator_field_name: str | None = None

Expand Down Expand Up @@ -669,7 +691,7 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any,
discriminator_field=discriminator_field_name,
discriminator_alias=discriminator_alias,
)
cast(CachedDiscriminatorType, union).__discriminator__ = details
DISCRIMINATOR_CACHE.setdefault(union, details)
return details


Expand Down
34 changes: 3 additions & 31 deletions src/agentex/_utils/_sync.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
from __future__ import annotations

import sys
import asyncio
import functools
import contextvars
from typing import Any, TypeVar, Callable, Awaitable
from typing import TypeVar, Callable, Awaitable
from typing_extensions import ParamSpec

import anyio
Expand All @@ -15,34 +13,11 @@
T_ParamSpec = ParamSpec("T_ParamSpec")


if sys.version_info >= (3, 9):
_asyncio_to_thread = asyncio.to_thread
else:
# backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread
# for Python 3.8 support
async def _asyncio_to_thread(
func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
) -> Any:
"""Asynchronously run function *func* in a separate thread.

Any *args and **kwargs supplied for this function are directly passed
to *func*. Also, the current :class:`contextvars.Context` is propagated,
allowing context variables from the main thread to be accessed in the
separate thread.

Returns a coroutine that can be awaited to get the eventual result of *func*.
"""
loop = asyncio.events.get_running_loop()
ctx = contextvars.copy_context()
func_call = functools.partial(ctx.run, func, *args, **kwargs)
return await loop.run_in_executor(None, func_call)


async def to_thread(
func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
) -> T_Retval:
if sniffio.current_async_library() == "asyncio":
return await _asyncio_to_thread(func, *args, **kwargs)
return await asyncio.to_thread(func, *args, **kwargs)

return await anyio.to_thread.run_sync(
functools.partial(func, *args, **kwargs),
Expand All @@ -53,10 +28,7 @@ async def to_thread(
def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]:
"""
Take a blocking function and create an async one that receives the same
positional and keyword arguments. For python version 3.9 and above, it uses
asyncio.to_thread to run the function in a separate thread. For python version
3.8, it uses locally defined copy of the asyncio.to_thread function which was
introduced in python 3.9.
positional and keyword arguments.

Usage:

Expand Down
2 changes: 1 addition & 1 deletion src/agentex/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "agentex"
__version__ = "0.6.5" # x-release-please-version
__version__ = "0.6.6" # x-release-please-version
8 changes: 4 additions & 4 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from agentex._utils import PropertyInfo
from agentex._compat import PYDANTIC_V1, parse_obj, model_dump, model_json
from agentex._models import BaseModel, construct_type
from agentex._models import DISCRIMINATOR_CACHE, BaseModel, construct_type


class BasicModel(BaseModel):
Expand Down Expand Up @@ -809,7 +809,7 @@ class B(BaseModel):

UnionType = cast(Any, Union[A, B])

assert not hasattr(UnionType, "__discriminator__")
assert not DISCRIMINATOR_CACHE.get(UnionType)

m = construct_type(
value={"type": "b", "data": "foo"}, type_=cast(Any, Annotated[UnionType, PropertyInfo(discriminator="type")])
Expand All @@ -818,7 +818,7 @@ class B(BaseModel):
assert m.type == "b"
assert m.data == "foo" # type: ignore[comparison-overlap]

discriminator = UnionType.__discriminator__
discriminator = DISCRIMINATOR_CACHE.get(UnionType)
assert discriminator is not None

m = construct_type(
Expand All @@ -830,7 +830,7 @@ class B(BaseModel):

# if the discriminator details object stays the same between invocations then
# we hit the cache
assert UnionType.__discriminator__ is discriminator
assert DISCRIMINATOR_CACHE.get(UnionType) is discriminator


@pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1")
Expand Down