Skip to content

Commit 0c38168

Browse files
authored
Merge branch 'next' into stas/tracing-concurrent-egress
2 parents c6b117e + ab5a7d9 commit 0c38168

17 files changed

Lines changed: 340 additions & 53 deletions

File tree

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "0.11.4"
2+
".": "0.11.5"
33
}

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
11
# Changelog
22

3+
## 0.11.5 (2026-05-29)
4+
5+
Full Changelog: [v0.11.4...v0.11.5](https://github.com/scaleapi/scale-agentex-python/compare/v0.11.4...v0.11.5)
6+
7+
### Features
8+
9+
* **api:** add cleaned_at field to task response types ([38ed338](https://github.com/scaleapi/scale-agentex-python/commit/38ed3384094f7f07f6b2482489f457fd1dc4f76d))
10+
* **deps:** bump openai-agents to >=0.14.3 for scale-sandbox oai_agents adapter ([#375](https://github.com/scaleapi/scale-agentex-python/issues/375)) ([e1b31d9](https://github.com/scaleapi/scale-agentex-python/commit/e1b31d91abadec572989b805592b788500d61994))
11+
12+
13+
### Performance Improvements
14+
15+
* **tracing:** span queue linger + per-loop httpx keepalive ([#362](https://github.com/scaleapi/scale-agentex-python/issues/362)) ([feec842](https://github.com/scaleapi/scale-agentex-python/commit/feec8426f79e9f02533451d44997717655fd33f2))
16+
17+
18+
### Chores
19+
20+
* **deps:** drop unused runtime deps and exclude tests from wheel ([#367](https://github.com/scaleapi/scale-agentex-python/issues/367)) ([f4303d1](https://github.com/scaleapi/scale-agentex-python/commit/f4303d1e7211783d19beca6554e44eb73bb29c42))
21+
22+
23+
### Refactors
24+
25+
* **types:** promote protocol types to agentex.protocol.* ([#371](https://github.com/scaleapi/scale-agentex-python/issues/371)) ([6f1c14f](https://github.com/scaleapi/scale-agentex-python/commit/6f1c14fd61077da52038361642a9fbc4a0a56c8b))
26+
327
## 0.11.4 (2026-05-26)
428

529
Full Changelog: [v0.11.3...v0.11.4](https://github.com/scaleapi/scale-agentex-python/compare/v0.11.3...v0.11.4)

examples/tutorials/10_async/10_temporal/060_open_ai_agents_sdk_hello_world/tests/test_agent.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# ci: touch to re-run tutorial integration tests for the openai-agents>=0.14.3 bump
12
"""
23
Sample tests for AgentEx ACP agent.
34

examples/tutorials/run_agent_test.sh

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,16 +259,23 @@ run_test() {
259259
cd "$tutorial_path" || return 1
260260

261261

262-
# Run the tests with retry mechanism
263-
local -a pytest_cmd=("uv" "run" "pytest")
262+
# Run the tests with retry mechanism.
263+
#
264+
# pytest is brought in explicitly via --with: the tutorials only list it
265+
# under an optional `dev` extra (which `uv run` does not install), and it
266+
# used to be pulled in transitively by agentex-sdk's runtime deps. Once
267+
# agentex-sdk 0.11.5 dropped pytest as a runtime dep, `uv run pytest` could
268+
# no longer find it ("Failed to spawn: pytest"). Requesting it directly is
269+
# robust across all tutorials regardless of how each declares test deps.
270+
local -a pytest_cmd=("uv" "run" "--with" "pytest" "--with" "pytest-asyncio" "pytest")
264271
if [ "$BUILD_CLI" = true ]; then
265272
local wheel_file
266273
wheel_file=$(ls /home/runner/work/*/*/dist/agentex_sdk-*.whl 2>/dev/null | head -n1)
267274
if [[ -z "$wheel_file" ]]; then
268275
wheel_file=$(ls "${SCRIPT_DIR}/../../dist/agentex_sdk-*.whl" 2>/dev/null | head -n1)
269276
fi
270277
if [[ -n "$wheel_file" ]]; then
271-
pytest_cmd=("uv" "run" "--with" "$wheel_file" "pytest")
278+
pytest_cmd=("uv" "run" "--with" "$wheel_file" "--with" "pytest" "--with" "pytest-asyncio" "pytest")
272279
fi
273280
fi
274281

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "agentex-sdk"
3-
version = "0.11.4"
3+
version = "0.11.5"
44
description = "The official Python library for the agentex API"
55
dynamic = ["readme"]
66
license = "Apache-2.0"
@@ -34,7 +34,7 @@ dependencies = [
3434
"jinja2>=3.1.3,<4",
3535
"mcp>=1.4.1",
3636
"scale-gp>=0.1.0a59",
37-
"openai-agents==0.14.1",
37+
"openai-agents>=0.14.3,<0.15",
3838
"pydantic-ai-slim>=1.0,<2",
3939
"json_log_formatter>=1.1.1",
4040
"scale-gp-beta>=0.2.0",

requirements-dev.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ openai==2.30.0
237237
# via agentex-sdk
238238
# via litellm
239239
# via openai-agents
240-
openai-agents==0.14.1
240+
openai-agents==0.14.8
241241
# via agentex-sdk
242242
opentelemetry-api==1.40.0
243243
# via agentex-sdk

requirements.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ openai==2.30.0
215215
# via agentex-sdk
216216
# via litellm
217217
# via openai-agents
218-
openai-agents==0.14.1
218+
openai-agents==0.14.8
219219
# via agentex-sdk
220220
opentelemetry-api==1.40.0
221221
# via agentex-sdk

src/agentex/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
22

33
__title__ = "agentex"
4-
__version__ = "0.11.4" # x-release-please-version
4+
__version__ = "0.11.5" # x-release-please-version

src/agentex/lib/core/clients/temporal/temporal_client.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from temporalio.client import Client, WorkflowExecutionStatus
88
from temporalio.common import RetryPolicy as TemporalRetryPolicy, WorkflowIDReusePolicy
99
from temporalio.service import RPCError, RPCStatusCode
10-
from temporalio.converter import PayloadCodec
10+
from temporalio.converter import PayloadCodec, DataConverter
1111

1212
from agentex.lib.utils.logging import make_logger
1313
from agentex.lib.utils.model_utils import BaseModel
@@ -78,11 +78,16 @@
7878

7979
class TemporalClient:
8080
def __init__(
81-
self, temporal_client: Client | None = None, plugins: list[Any] = [], payload_codec: PayloadCodec | None = None
81+
self,
82+
temporal_client: Client | None = None,
83+
plugins: list[Any] = [],
84+
payload_codec: PayloadCodec | None = None,
85+
data_converter: DataConverter | None = None,
8286
):
8387
self._client: Client | None = temporal_client
8488
self._plugins = plugins
8589
self._payload_codec = payload_codec
90+
self._data_converter = data_converter
8691

8792
@property
8893
def client(self) -> Client:
@@ -92,7 +97,13 @@ def client(self) -> Client:
9297
return self._client
9398

9499
@classmethod
95-
async def create(cls, temporal_address: str, plugins: list[Any] = [], payload_codec: PayloadCodec | None = None):
100+
async def create(
101+
cls,
102+
temporal_address: str,
103+
plugins: list[Any] = [],
104+
payload_codec: PayloadCodec | None = None,
105+
data_converter: DataConverter | None = None,
106+
):
96107
if temporal_address in [
97108
"false",
98109
"False",
@@ -105,8 +116,13 @@ async def create(cls, temporal_address: str, plugins: list[Any] = [], payload_co
105116
]:
106117
_client = None
107118
else:
108-
_client = await get_temporal_client(temporal_address, plugins=plugins, payload_codec=payload_codec)
109-
return cls(_client, plugins, payload_codec)
119+
_client = await get_temporal_client(
120+
temporal_address,
121+
plugins=plugins,
122+
payload_codec=payload_codec,
123+
data_converter=data_converter,
124+
)
125+
return cls(_client, plugins, payload_codec, data_converter)
110126

111127
async def setup(self, temporal_address: str):
112128
self._client = await self._get_temporal_client(temporal_address=temporal_address)
@@ -124,7 +140,12 @@ async def _get_temporal_client(self, temporal_address: str) -> Client | None:
124140
]:
125141
return None
126142
else:
127-
return await get_temporal_client(temporal_address, plugins=self._plugins, payload_codec=self._payload_codec)
143+
return await get_temporal_client(
144+
temporal_address,
145+
plugins=self._plugins,
146+
payload_codec=self._payload_codec,
147+
data_converter=self._data_converter,
148+
)
128149

129150
async def start_workflow(
130151
self,

src/agentex/lib/core/clients/temporal/utils.py

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from temporalio.client import Client, Plugin as ClientPlugin
77
from temporalio.worker import Interceptor
88
from temporalio.runtime import Runtime, TelemetryConfig, OpenTelemetryConfig
9-
from temporalio.converter import PayloadCodec
9+
from temporalio.converter import PayloadCodec, DataConverter
1010
from temporalio.contrib.pydantic import pydantic_data_converter
1111

1212
# class DateTimeJSONEncoder(AdvancedJSONEncoder):
@@ -86,6 +86,7 @@ async def get_temporal_client(
8686
metrics_url: str | None = None,
8787
plugins: list[Any] = [],
8888
payload_codec: PayloadCodec | None = None,
89+
data_converter: DataConverter | None = None,
8990
) -> Client:
9091
"""
9192
Create a Temporal client with plugin integration.
@@ -94,7 +95,14 @@ async def get_temporal_client(
9495
temporal_address: Temporal server address
9596
metrics_url: Optional metrics endpoint URL
9697
plugins: List of Temporal plugins to include
97-
payload_codec: Optional payload codec for encoding/decoding payloads (e.g. encryption, compression)
98+
payload_codec: Optional payload codec for encoding/decoding payloads
99+
(e.g. encryption, compression). Cannot be combined with the
100+
OpenAIAgentsPlugin via this kwarg — see ``data_converter``.
101+
data_converter: Optional pre-built ``DataConverter``. Use this when
102+
composing the OpenAIAgentsPlugin with a payload codec: build a
103+
``DataConverter(payload_converter_class=OpenAIPayloadConverter,
104+
payload_codec=...)`` and pass it here. Mutually exclusive with
105+
``payload_codec``.
98106
99107
Returns:
100108
Configured Temporal client
@@ -103,29 +111,40 @@ async def get_temporal_client(
103111
if plugins:
104112
validate_client_plugins(plugins)
105113

106-
# Check if OpenAI plugin is present - it needs to configure its own data converter
114+
if payload_codec is not None and data_converter is not None:
115+
raise ValueError(
116+
"Pass payload_codec inside `data_converter` "
117+
"(DataConverter(..., payload_codec=...)) instead of as a separate "
118+
"kwarg. Specifying both is ambiguous."
119+
)
120+
107121
# Lazy import to avoid pulling in opentelemetry.sdk for non-Temporal agents
108122
from temporalio.contrib.openai_agents import OpenAIAgentsPlugin
109123

110124
has_openai_plugin = any(isinstance(p, OpenAIAgentsPlugin) for p in (plugins or []))
111125

112-
if has_openai_plugin and payload_codec is not None:
126+
if has_openai_plugin and payload_codec is not None and data_converter is None:
113127
raise ValueError(
114-
"payload_codec is not supported alongside OpenAIAgentsPlugin: the plugin "
115-
"installs its own data converter and the codec would be silently ignored, "
116-
"leaving payloads unencoded. Remove one or the other."
128+
"payload_codec passed as a kwarg alongside OpenAIAgentsPlugin would "
129+
"be silently dropped by the plugin's data-converter transformer. "
130+
"Build a DataConverter explicitly with "
131+
"`payload_converter_class=OpenAIPayloadConverter` (or a subclass) "
132+
"and `payload_codec=...`, then pass it via the `data_converter` "
133+
"kwarg instead."
117134
)
118135

119-
connect_kwargs = {
136+
connect_kwargs: dict[str, Any] = {
120137
"target_host": temporal_address,
121138
"plugins": plugins,
122139
}
123140

124-
if not has_openai_plugin:
125-
data_converter = pydantic_data_converter
126-
if payload_codec:
127-
data_converter = dataclasses.replace(data_converter, payload_codec=payload_codec)
141+
if data_converter is not None:
128142
connect_kwargs["data_converter"] = data_converter
143+
elif not has_openai_plugin:
144+
dc = pydantic_data_converter
145+
if payload_codec:
146+
dc = dataclasses.replace(dc, payload_codec=payload_codec)
147+
connect_kwargs["data_converter"] = dc
129148

130149
if not metrics_url:
131150
client = await Client.connect(**connect_kwargs)

0 commit comments

Comments
 (0)