Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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.11.4"
".": "0.11.5"
}
4 changes: 2 additions & 2 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 63
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/sgp/agentex-sdk-77ce1b851a8b44f0e67ce2c3ebc20cd92d5af16ab9d3a9224344cd4c83ffb564.yml
openapi_spec_hash: d31d828c46635cbc20165177c7187a70
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/sgp/agentex-sdk-4d4bf80af19e6a2ef6b890d5d978316b86e9939d8d5116e94b90117525c61325.yml
openapi_spec_hash: 133afeacb42000ed4f9e076abf4b50fd
config_hash: ba5183ca635940fd202d05a2a9fcb630
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
# Changelog

## 0.11.5 (2026-05-29)

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

### Features

* **api:** add cleaned_at field to task response types ([38ed338](https://github.com/scaleapi/scale-agentex-python/commit/38ed3384094f7f07f6b2482489f457fd1dc4f76d))
* **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))


### Performance Improvements

* **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))


### Chores

* **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))


### Refactors

* **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))

## 0.11.4 (2026-05-26)

Full Changelog: [v0.11.3...v0.11.4](https://github.com/scaleapi/scale-agentex-python/compare/v0.11.3...v0.11.4)
Expand Down
16 changes: 16 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,27 @@ The package provides the `agentex` CLI with these main commands:

### Code Structure
- `/src/agentex/` - Core SDK and generated API client code
- `/src/agentex/protocol/` - **Canonical** location for wire-protocol shapes
(JSON-RPC envelopes, ACP method-param types). Depends only on `pydantic`
and the Stainless-generated `agentex.types.*` surface, so it is safe to
import from a future slim REST-only install.
- `acp.py` - `RPCMethod`, `CreateTaskParams`, `SendMessageParams`,
`SendEventParams`, `CancelTaskParams`, `RPC_SYNC_METHODS`,
`PARAMS_MODEL_BY_METHOD`
- `json_rpc.py` - `JSONRPCRequest`, `JSONRPCResponse`, `JSONRPCError`
- `/src/agentex/lib/` - Custom library code (not modified by code generator)
- `/cli/` - Command-line interface implementation
- `/core/` - Core services, adapters, and temporal workflows
- `/sdk/` - SDK utilities and FastACP implementation
- `/types/` - Custom type definitions
- `acp.py`, `json_rpc.py` - **back-compat shims** re-exporting from
`agentex.protocol.*`. Existing `from agentex.lib.types.{acp,json_rpc}
import ...` keeps working; new code should import from the canonical
`agentex.protocol.*` paths.
- Other modules (`tracing`, `agent_card`, `credentials`, `fastacp`,
`llm_messages`, `converters`, etc.) stay here — they have heavier
transitive deps (temporal, openai-agents, model_utils/yaml) and
aren't slim-safe.
- `/utils/` - Utility functions
- `/examples/` - Example implementations and tutorials
- `/tests/` - Test suites
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "0",
"metadata": {},
"outputs": [],
"source": [
"from agentex import Agentex\n",
"\n",
"client = Agentex(base_url=\"http://localhost:5003\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1",
"metadata": {},
"outputs": [],
"source": [
"AGENT_NAME = \"s010-multiturn\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2",
"metadata": {},
"outputs": [],
"source": [
"# # (Optional) Create a new task. If you don't create a new task, each message will be sent to a new task. The server will create the task for you.\n",
"\n",
"# import uuid\n",
"\n",
"# TASK_ID = str(uuid.uuid4())[:8]\n",
"\n",
"# rpc_response = client.agents.rpc_by_name(\n",
"# agent_name=AGENT_NAME,\n",
"# method=\"task/create\",\n",
"# params={\n",
"# \"name\": f\"{TASK_ID}-task\",\n",
"# \"params\": {}\n",
"# }\n",
"# )\n",
"\n",
"# task = rpc_response.result\n",
"# print(task)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3",
"metadata": {},
"outputs": [],
"source": [
"# Test non streaming response\n",
"from agentex.types import TextContent\n",
"\n",
"# The response is expected to be a list of TaskMessage objects, which is a union of the following types:\n",
"# - TextContent: A message with just text content \n",
"# - DataContent: A message with JSON-serializable data content\n",
"# - ToolRequestContent: A message with a tool request, which contains a JSON-serializable request to call a tool\n",
"# - ToolResponseContent: A message with a tool response, which contains response object from a tool call in its content\n",
"\n",
"# When processing the message/send response, if you are expecting more than TextContent, such as DataContent, ToolRequestContent, or ToolResponseContent, you can process them as well\n",
"\n",
"rpc_response = client.agents.send_message(\n",
" agent_name=AGENT_NAME,\n",
" params={\n",
" \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"Hello what can you do?\"},\n",
" \"stream\": False\n",
" }\n",
")\n",
"\n",
"if not rpc_response or not rpc_response.result:\n",
" raise ValueError(\"No result in response\")\n",
"\n",
"# Extract and print just the text content from the response\n",
"for task_message in rpc_response.result:\n",
" content = task_message.content\n",
" if isinstance(content, TextContent):\n",
" text = content.content\n",
" print(text)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4",
"metadata": {},
"outputs": [],
"source": [
"# Test streaming response\n",
"from agentex.types.text_delta import TextDelta\n",
"from agentex.types.task_message_update import StreamTaskMessageFull, StreamTaskMessageDelta\n",
"\n",
"# The result object of message/send will be a TaskMessageUpdate which is a union of the following types:\n",
"# - StreamTaskMessageStart: \n",
"# - An indicator that a streaming message was started, doesn't contain any useful content\n",
"# - StreamTaskMessageDelta: \n",
"# - A delta of a streaming message, contains the text delta to aggregate\n",
"# - StreamTaskMessageDone: \n",
"# - An indicator that a streaming message was done, doesn't contain any useful content\n",
"# - StreamTaskMessageFull: \n",
"# - A non-streaming message, there is nothing to aggregate, since this contains the full message, not deltas\n",
"\n",
"# Whenn processing StreamTaskMessageDelta, if you are expecting more than TextDeltas, such as DataDelta, ToolRequestDelta, or ToolResponseDelta, you can process them as well\n",
"# Whenn processing StreamTaskMessageFull, if you are expecting more than TextContent, such as DataContent, ToolRequestContent, or ToolResponseContent, you can process them as well\n",
"\n",
"for agent_rpc_response_chunk in client.agents.send_message_stream(\n",
" agent_name=AGENT_NAME,\n",
" params={\n",
" \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"Hello what can you do?\"},\n",
" \"stream\": True\n",
" }\n",
"):\n",
" # We know that the result of the message/send when stream is set to True will be a TaskMessageUpdate\n",
" task_message_update = agent_rpc_response_chunk.result\n",
" # Print oly the text deltas as they arrive or any full messages\n",
" if isinstance(task_message_update, StreamTaskMessageDelta):\n",
" delta = task_message_update.delta\n",
" if isinstance(delta, TextDelta):\n",
" print(delta.text_delta, end=\"\", flush=True)\n",
" else:\n",
" print(f\"Found non-text {type(task_message)} object in streaming message.\")\n",
" elif isinstance(task_message_update, StreamTaskMessageFull):\n",
" content = task_message_update.content\n",
" if isinstance(content, TextContent):\n",
" print(content.content)\n",
" else:\n",
" print(f\"Found non-text {type(task_message)} object in full message.\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"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.12.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
4 changes: 2 additions & 2 deletions examples/tutorials/00_sync/010_multiturn/dev.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
Expand All @@ -158,7 +158,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.9"
"version": "3.14.2"
}
},
"nbformat": 4,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# ci: touch to re-run tutorial integration tests for the openai-agents>=0.14.3 bump
"""
Sample tests for AgentEx ACP agent.
Expand Down
22 changes: 11 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "agentex-sdk"
version = "0.11.4"
version = "0.11.5"
description = "The official Python library for the agentex API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand All @@ -20,7 +20,6 @@ dependencies = [
"rich>=13.9.2,<14",
"fastapi>=0.115.0",
"starlette>=0.49.1",
"tornado>=6.5.5",
"uvicorn>=0.31.1",
"watchfiles>=0.24.0,<1.0",
"python-on-whales>=0.73.0,<0.74",
Expand All @@ -33,24 +32,17 @@ dependencies = [
"litellm>=1.83.7,<2",
"kubernetes>=25.0.0,<36.0.0",
"jinja2>=3.1.3,<4",
"mcp[cli]>=1.4.1",
"mcp>=1.4.1",
"scale-gp>=0.1.0a59",
"openai-agents==0.14.1",
"openai-agents>=0.14.3,<0.15",
"pydantic-ai-slim>=1.0,<2",
"tzlocal>=5.3.1",
"tzdata>=2025.2",
"pytest>=8.4.0",
"json_log_formatter>=1.1.1",
"pytest-asyncio>=1.0.0",
"scale-gp-beta>=0.2.0",
"ipykernel>=6.29.5",
"openai>=2.2,<3", # Required by openai-agents; litellm now supports openai 2.x (issue #13711 resolved: https://github.com/BerriAI/litellm/issues/13711)
"cloudpickle>=3.1.1",
"datadog>=0.52.1",
"ddtrace>=3.13.0",
"yaspin>=3.1.0",
"claude-agent-sdk>=0.1.0",
"anthropic>=0.40.0",
"langgraph-checkpoint>=2.0.0",
"opentelemetry-sdk>=1.20.0",
"opentelemetry-api>=1.20.0",
Expand Down Expand Up @@ -152,6 +144,14 @@ include = [

[tool.hatch.build.targets.wheel]
packages = ["src/agentex"]
# Don't ship internal test files in the wheel. `lib/cli/templates/**/test_agent.py.j2`
# is intentionally kept — those render into user projects.
exclude = [
"src/agentex/lib/**/tests/**",
"src/agentex/lib/**/test_*.py",
"src/agentex/lib/**/conftest.py",
"src/agentex/lib/**/pytest.ini",
]

[tool.hatch.build.targets.sdist]
# Basically everything except hidden files/directories (such as .github, .devcontainers, .python-version, etc)
Expand Down
2 changes: 1 addition & 1 deletion requirements-dev.lock
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ openai==2.30.0
# via agentex-sdk
# via litellm
# via openai-agents
openai-agents==0.14.1
openai-agents==0.14.8
# via agentex-sdk
opentelemetry-api==1.40.0
# via agentex-sdk
Expand Down
2 changes: 1 addition & 1 deletion requirements.lock
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ openai==2.30.0
# via agentex-sdk
# via litellm
# via openai-agents
openai-agents==0.14.1
openai-agents==0.14.8
# via agentex-sdk
opentelemetry-api==1.40.0
# via agentex-sdk
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.11.4" # x-release-please-version
__version__ = "0.11.5" # x-release-please-version
11 changes: 5 additions & 6 deletions src/agentex/lib/adk/_modules/tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,13 @@ def _tracing_service(self) -> TracingService:
if self._tracing_service_lazy is None or (loop_id is not None and loop_id != self._bound_loop_id):
import httpx

# Disable keepalive so each span HTTP call gets a fresh TCP
# connection. Reused connections carry asyncio primitives bound
# to the event loop that created them; in sync-ACP / streaming
# contexts the loop context can shift between calls, causing
# "bound to a different event loop" RuntimeErrors.
# Keepalive ON: connections are reused within a single event
# loop, eliminating the TLS-handshake-per-span penalty under
# load. Cross-loop safety is preserved by rebuilding the
# client whenever loop_id changes (the conditional above).
agentex_client = create_async_agentex_client(
http_client=httpx.AsyncClient(
limits=httpx.Limits(max_keepalive_connections=0),
limits=httpx.Limits(max_keepalive_connections=20),
),
)
tracer = AsyncTracer(agentex_client)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import agentex.lib.adk as adk
from agentex.lib.adk import create_langgraph_tracing_handler, stream_langgraph_events
from agentex.lib.core.tracing.tracing_processor_manager import add_tracing_processor_config
from agentex.lib.sdk.fastacp.fastacp import FastACP
from agentex.lib.types.acp import SendEventParams, CancelTaskParams, CreateTaskParams
from agentex.protocol.acp import SendEventParams, CancelTaskParams, CreateTaskParams
from agentex.lib.types.fastacp import AsyncACPConfig
from agentex.lib.types.tracing import SGPTracingProcessorConfig
from agentex.lib.utils.logging import make_logger
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ from agentex.lib.adk import (
stream_pydantic_ai_events,
create_pydantic_ai_tracing_handler,
)
from agentex.lib.types.acp import SendEventParams, CancelTaskParams, CreateTaskParams
from agentex.protocol.acp import SendEventParams, CancelTaskParams, CreateTaskParams
from agentex.lib.types.fastacp import AsyncACPConfig
from agentex.lib.types.tracing import SGPTracingProcessorConfig
from agentex.lib.utils.logging import make_logger
Expand Down
2 changes: 1 addition & 1 deletion src/agentex/lib/cli/templates/default/project/acp.py.j2
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from agentex.lib.sdk.fastacp.fastacp import FastACP
from agentex.lib.types.fastacp import AsyncACPConfig
from agentex.lib.types.acp import SendEventParams, CancelTaskParams, CreateTaskParams
from agentex.protocol.acp import SendEventParams, CancelTaskParams, CreateTaskParams
from agentex.lib.utils.logging import make_logger
from agentex.types.text_content import TextContent
from agentex.lib import adk
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import agentex.lib.adk as adk
from agentex.lib.adk import create_langgraph_tracing_handler, convert_langgraph_to_agentex_events
from agentex.lib.core.tracing.tracing_processor_manager import add_tracing_processor_config
from agentex.lib.sdk.fastacp.fastacp import FastACP
from agentex.lib.types.acp import SendMessageParams
from agentex.protocol.acp import SendMessageParams
from agentex.lib.types.tracing import SGPTracingProcessorConfig
from agentex.lib.utils.logging import make_logger
from agentex.types.task_message_content import TaskMessageContent
Expand Down
Loading
Loading