Skip to content

Commit a71fa67

Browse files
stainless-app[bot]cyntwang99claudechakrrisdeclan-scale
authored
chore: release main (#506)
Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> Co-authored-by: Cynthia Wang <cynthia.wang@scale.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Rishav Chakravarti <rishav.chakravarti@scale.com> Co-authored-by: Declan Brady <declan.brady@scale.com>
1 parent 4b446e6 commit a71fa67

29 files changed

Lines changed: 1110 additions & 17 deletions

‎.release-please-manifest.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
".": "0.25.0",
3-
"adk": "0.25.0"
2+
".": "0.26.0",
3+
"adk": "0.26.0"
44
}

‎.stats.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 75
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/sgp/agentex-sdk-7acaeb315af90255109ae17afc71e32a8e5851bb8a956a2a284cb4d344dfab51.yml
3-
openapi_spec_hash: 3044e94b48d60311b6048e8df88e7552
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/sgp/agentex-sdk-fbc0683871d6abb03588f30d9468eeeeacb2b8538eb0c9002813e6df68c5802b.yml
3+
openapi_spec_hash: 4ecd8d496f056dccf80826264ddf8fe1
44
config_hash: 593e89b291976a5e84e4c3c3f8324354

‎CHANGELOG.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,20 @@
1212

1313
* **tracing:** emit OTel metrics for async span queue depth, batch drain, and SGP export success/failure (HTTP status labels). Disable SDK-side recording with ``AGENTEX_TRACING_METRICS=0``.
1414

15+
## 0.26.0 (2026-09-14)
16+
17+
Full Changelog: [agentex-client-v0.25.0...agentex-client-v0.26.0](https://github.com/scaleapi/scale-agentex-python/compare/agentex-client-v0.25.0...agentex-client-v0.26.0)
18+
19+
### Features
20+
21+
* **agent-card:** add metadata field and expose list filter ([#502](https://github.com/scaleapi/scale-agentex-python/issues/502)) ([55a0178](https://github.com/scaleapi/scale-agentex-python/commit/55a0178c2d210325770b56dbb58eac2f644cc14b))
22+
* **api:** add agent_card_metadata parameter to agents list method ([ebb632a](https://github.com/scaleapi/scale-agentex-python/commit/ebb632a4b22287e157bcf086dd98b27f26188fc5))
23+
* **tracing:** add opt-in commit SHA stamping for SGP spans ([#505](https://github.com/scaleapi/scale-agentex-python/issues/505)) ([76252a9](https://github.com/scaleapi/scale-agentex-python/commit/76252a98f28663e8c95777456d07e42171592c62))
24+
25+
### Bug Fixes
26+
27+
* keep agent output streaming alive on an unreadable line, and honor LOG_LEVEL ([#509](https://github.com/scaleapi/scale-agentex-python/issues/509)) ([0db6037](https://github.com/scaleapi/scale-agentex-python/commit/0db6037e63ca1b24b80ae0d38883f7687ae5b9e5))
28+
1529
## 0.25.0 (2026-08-26)
1630

1731
Full Changelog: [agentex-client-v0.24.0...agentex-client-v0.25.0](https://github.com/scaleapi/scale-agentex-python/compare/agentex-client-v0.24.0...agentex-client-v0.25.0)

‎adk/CHANGELOG.md‎

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

3+
## 0.26.0 (2026-09-14)
4+
5+
Full Changelog: [agentex-sdk-v0.25.0...agentex-sdk-v0.26.0](https://github.com/scaleapi/scale-agentex-python/compare/agentex-sdk-v0.25.0...agentex-sdk-v0.26.0)
6+
7+
### Chores
8+
9+
* **agentex-sdk:** Synchronize agentex versions
10+
311
## 0.25.0 (2026-08-26)
412

513
Full Changelog: [agentex-sdk-v0.24.0...agentex-sdk-v0.25.0](https://github.com/scaleapi/scale-agentex-python/compare/agentex-sdk-v0.24.0...agentex-sdk-v0.25.0)

‎adk/pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# (agentex/{__init__.py, _*.py, types/, resources/}) ships from the slim
55
# sibling package `agentex-client` which is pinned as a runtime dep.
66
name = "agentex-sdk"
7-
version = "0.25.0"
7+
version = "0.26.0"
88
description = "Agent Development Kit (ADK) overlay for the Agentex API — FastACP server, Temporal workflows, LLM provider integrations, observability"
99
license = "Apache-2.0"
1010
authors = [

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# overlay (formerly `src/agentex/lib/*`) now lives in `adk/` and ships
44
# as the sibling `agentex-sdk` package — see `adk/pyproject.toml`.
55
name = "agentex-client"
6-
version = "0.25.0"
6+
version = "0.26.0"
77
description = "The official Python REST client for the Agentex API"
88
dynamic = ["readme"]
99
license = "Apache-2.0"

‎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.25.0" # x-release-please-version
4+
__version__ = "0.26.0" # x-release-please-version

‎src/agentex/lib/adk/__init__.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131

3232
# Data-source refs for lineage (SGP-6513); implementation lives in core.tracing
3333
from agentex.lib.core.tracing import lineage
34+
35+
# Opt-in commit-SHA stamping (AGX1-969); implementation in core.tracing
36+
from agentex.lib.core.tracing import code_revision
3437
from agentex.lib.core.tracing.lineage import DataSourceRef, data_sources
3538

3639
# Unified harness surface (AGX1-375)
@@ -73,6 +76,7 @@
7376
"TurnSpan",
7477
# Lineage data-source refs (SGP-6513)
7578
"lineage",
79+
"code_revision",
7680
"DataSourceRef",
7781
"data_sources",
7882
# Checkpointing / LangGraph

‎src/agentex/lib/cli/debug/debug_handlers.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
pass
1717

1818
from agentex.lib.utils.logging import make_logger
19+
from agentex.lib.cli.utils.cli_utils import SUBPROCESS_STREAM_LIMIT
1920

2021
from .debug_config import DebugConfig, resolve_debug_port
2122

@@ -66,6 +67,7 @@ async def start_temporal_worker_debug(
6667
env=debug_env,
6768
stdout=asyncio.subprocess.PIPE,
6869
stderr=asyncio.subprocess.STDOUT,
70+
limit=SUBPROCESS_STREAM_LIMIT,
6971
)
7072

7173

@@ -119,6 +121,7 @@ async def start_acp_server_debug(
119121
env=debug_env,
120122
stdout=asyncio.subprocess.PIPE,
121123
stderr=asyncio.subprocess.STDOUT,
124+
limit=SUBPROCESS_STREAM_LIMIT,
122125
)
123126

124127

‎src/agentex/lib/cli/handlers/run_handlers.py‎

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from agentex.lib.cli.debug import DebugConfig, start_acp_server_debug, start_temporal_worker_debug
1313
from agentex.lib.utils.logging import make_logger
1414
from agentex.config.agent_manifest import AgentManifest
15+
from agentex.lib.cli.utils.cli_utils import SUBPROCESS_STREAM_LIMIT
1516
from agentex.lib.cli.utils.path_utils import (
1617
get_file_paths,
1718
calculate_uvicorn_target_for_local,
@@ -23,6 +24,11 @@
2324
logger = make_logger(__name__)
2425
console = Console()
2526

27+
# How many consecutive unreadable lines to skip before giving up on the stream.
28+
# Skipping is only known-safe for the limit-overrun case; this bounds the damage
29+
# if some other error repeats without consuming anything.
30+
MAX_CONSECUTIVE_READ_ERRORS = 100
31+
2632

2733
class RunError(Exception):
2834
"""An error occurred during agent run"""
@@ -215,6 +221,7 @@ async def start_acp_server(
215221
env=env,
216222
stdout=asyncio.subprocess.PIPE,
217223
stderr=asyncio.subprocess.STDOUT,
224+
limit=SUBPROCESS_STREAM_LIMIT,
218225
)
219226

220227

@@ -234,23 +241,68 @@ async def start_temporal_worker(
234241
env=env,
235242
stdout=asyncio.subprocess.PIPE,
236243
stderr=asyncio.subprocess.STDOUT,
244+
limit=SUBPROCESS_STREAM_LIMIT,
237245
)
238246

239247

240248
async def stream_process_output(process: asyncio.subprocess.Process, prefix: str):
241-
"""Stream process output with prefix"""
249+
"""Stream process output with prefix.
250+
251+
This loop is the only reader of the child's stdout pipe. If it ever stops
252+
reading, the pipe fills and the child blocks forever inside ``write()``,
253+
which presents as a silent freeze: 0% CPU, no further logs, no traceback.
254+
So a single unreadable line must never end the loop.
255+
"""
242256
try:
243257
if process.stdout is None:
244258
return
259+
consecutive_read_errors = 0
245260
while True:
246-
line = await process.stdout.readline()
261+
try:
262+
line = await process.stdout.readline()
263+
except ValueError as e:
264+
# readline() raises ValueError when a line exceeds the stream limit.
265+
# In *that* case it has already discarded the line and resumed the
266+
# transport, so skipping it makes guaranteed progress. Any other
267+
# ValueError carries no such guarantee, and retrying it forever would
268+
# spin without draining. We cannot tell the two apart (readline
269+
# flattens LimitOverrunError into a bare ValueError), so bound the
270+
# retries and let the outer handler report the hang risk.
271+
consecutive_read_errors += 1
272+
if consecutive_read_errors > MAX_CONSECUTIVE_READ_ERRORS:
273+
raise
274+
logger.warning(
275+
f"Skipping an unreadable line from {prefix}: {e!r} "
276+
f"(consecutive failure {consecutive_read_errors}/{MAX_CONSECUTIVE_READ_ERRORS}). "
277+
f"If this says the chunk exceeded the limit, raise limit= on this "
278+
f"process's create_subprocess_exec."
279+
)
280+
continue
281+
282+
consecutive_read_errors = 0
283+
247284
if not line:
248285
break
249-
decoded_line = line.decode("utf-8").rstrip()
286+
287+
try:
288+
decoded_line = line.decode("utf-8").rstrip()
289+
except UnicodeDecodeError as e:
290+
logger.warning(f"Dropped an undecodable log line from {prefix} ({e}).")
291+
continue
292+
250293
if decoded_line: # Only print non-empty lines
251294
console.print(f"[dim]{prefix}:[/dim] {decoded_line}")
252295
except Exception as e:
253-
logger.debug(f"Output streaming ended for {prefix}: {e}")
296+
# The escalation path, including for the re-raise above. Anything reaching
297+
# here ends the loop, so the child is now at risk of blocking on a full pipe.
298+
# Warning rather than debug: this used to be a debug() that make_logger could
299+
# never emit, which is why three freezes produced no clue.
300+
# CancelledError derives from BaseException, so the auto-reload path that
301+
# cancels these tasks passes straight through and is unaffected.
302+
logger.warning(
303+
f"Output streaming for {prefix} stopped on {e!r}. "
304+
f"Nothing is draining its stdout now, so {prefix} will hang once the pipe fills."
305+
)
254306

255307

256308
async def run_agent(manifest_path: str, debug_config: "DebugConfig | None" = None):

0 commit comments

Comments
 (0)