Skip to content

Commit 8be24ed

Browse files
Merge remote-tracking branch 'origin/next' into stephen/agentex-sdk-genai-metrics
# Conflicts: # .stats.yml # src/agentex/lib/utils/logging.py
2 parents 0b2520d + a71fa67 commit 8be24ed

17 files changed

Lines changed: 462 additions & 10 deletions

File tree

‎.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-ee0c521f0612c31b874bd595b90cd9209545bab603983552a1a7a87f38ed931e.yml
3-
openapi_spec_hash: 917a1ffe9e353bed2740524dec786ed2
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/core/temporal/workers/worker.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ def __init__(
180180
metrics_headers: dict[str, str] | None = None,
181181
metrics_use_http: bool = False,
182182
metrics_temporality_delta: bool = False,
183+
agent_card: Any | None = None,
183184
):
184185
self.task_queue = task_queue
185186
self.activity_handles = []
@@ -198,6 +199,7 @@ def __init__(
198199
self.metrics_temporality_delta = metrics_temporality_delta
199200
self.payload_codec = payload_codec
200201
self.data_converter = data_converter
202+
self.agent_card = agent_card
201203

202204
@overload
203205
async def run(
@@ -333,6 +335,6 @@ async def _register_agent(self):
333335
# the worker process never goes through the ACP server lifespan, so it needs its
334336
# own guard (mirrors base_acp_server.lifespan_context).
335337
await assert_backend_compatible(env_vars.AGENTEX_BASE_URL)
336-
await register_agent(env_vars)
338+
await register_agent(env_vars, agent_card=self.agent_card)
337339
else:
338340
logger.warning("AGENTEX_BASE_URL not set, skipping worker registration")

‎src/agentex/lib/types/agent_card.py‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from enum import Enum
66
from typing import TYPE_CHECKING, Any, get_args, get_origin
77

8-
from pydantic import BaseModel
8+
from pydantic import Field, BaseModel
99

1010
if TYPE_CHECKING:
1111
from agentex.lib.sdk.state_machine.state import State
@@ -31,6 +31,11 @@ class AgentCard(BaseModel):
3131
data_events: list[str] = []
3232
input_types: list[str] = []
3333
output_schema: dict | None = None
34+
# Free-form JSON object for opt-in self-description (e.g. protocol-specific
35+
# capability flags). Not interpreted by the platform, but callers can filter
36+
# agents on it with ``agents.list(agent_card_metadata=...)`` -- see
37+
# ``agentex.lib.utils.metadata_filters.encode_metadata_filter``.
38+
metadata: dict[str, Any] = Field(default_factory=dict)
3439

3540
@classmethod
3641
def from_states(
@@ -40,6 +45,7 @@ def from_states(
4045
output_event_model: type[BaseModel] | None = None,
4146
extra_input_types: list[str] | None = None,
4247
queries: list[str] | None = None,
48+
metadata: dict[str, Any] | None = None,
4349
) -> AgentCard:
4450
"""Build an AgentCard directly from a list[State] + initial_state.
4551
@@ -81,6 +87,7 @@ def from_states(
8187
data_events=data_events,
8288
input_types=sorted(derived_input_types | set(extra_input_types or [])),
8389
output_schema=output_schema,
90+
metadata=metadata or {},
8491
)
8592

8693
@classmethod
@@ -90,6 +97,7 @@ def from_state_machine(
9097
output_event_model: type[BaseModel] | None = None,
9198
extra_input_types: list[str] | None = None,
9299
queries: list[str] | None = None,
100+
metadata: dict[str, Any] | None = None,
93101
) -> AgentCard:
94102
"""Build an AgentCard from a StateMachine instance. Delegates to from_states()."""
95103
lifecycle = state_machine.get_lifecycle()
@@ -125,6 +133,7 @@ def from_state_machine(
125133
data_events=data_events,
126134
input_types=sorted(derived_input_types | set(extra_input_types or [])),
127135
output_schema=output_schema,
136+
metadata=metadata or {},
128137
)
129138

130139

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""Helpers for the platform's JSON-encoded metadata filter query parameters.
2+
3+
The containment filters on ``agents.list(agent_card_metadata=...)`` and
4+
``tasks.list(task_metadata=...)`` carry their filter as a JSON-encoded object
5+
inside a single query string value, so the generated clients type them as
6+
``str``. Encoding by hand is easy to get subtly wrong -- Python's ``json``
7+
happily emits ``NaN``/``Infinity``, which the server rejects with a 400 -- so
8+
these helpers do it once, here, in the hand-written layer where they survive
9+
SDK regeneration.
10+
11+
from agentex.lib.utils.metadata_filters import encode_metadata_filter
12+
13+
client.agents.list(
14+
agent_card_metadata=encode_metadata_filter({"permits_capable": True}),
15+
)
16+
17+
The ``agent_card_metadata`` filter requires an Agentex server that includes
18+
scaleapi/scale-agentex#411. Older servers ignore the unknown query parameter
19+
and return the full unfiltered agent list rather than erroring, and the SDK's
20+
startup backend-contract check does not guard against this.
21+
"""
22+
23+
from __future__ import annotations
24+
25+
import json
26+
from typing import Any, Mapping
27+
28+
__all__ = ["encode_metadata_filter"]
29+
30+
31+
def encode_metadata_filter(metadata: Mapping[str, Any]) -> str:
32+
"""Encode a metadata filter mapping into the wire form the platform expects.
33+
34+
Args:
35+
metadata: The key/value pairs the target's metadata object must contain.
36+
Values may be any JSON type; matching is exact containment, so
37+
``{"permits_capable": True}`` matches a stored JSON ``true`` but not
38+
the string ``"true"``. An empty mapping matches any target that has
39+
a metadata object at all.
40+
41+
Returns:
42+
A compact JSON object string, with keys sorted so the same filter always
43+
produces the same query value.
44+
45+
Raises:
46+
TypeError: If ``metadata`` is not a mapping, or contains a value that
47+
isn't JSON-serializable.
48+
ValueError: If a value is a non-finite float. ``NaN`` and ``Infinity``
49+
aren't valid JSON and the server rejects them with a 400, so fail
50+
here with a clearer message instead.
51+
"""
52+
if not isinstance(metadata, Mapping):
53+
raise TypeError(f"metadata must be a mapping, got {type(metadata).__name__}")
54+
55+
try:
56+
return json.dumps(metadata, allow_nan=False, separators=(",", ":"), sort_keys=True)
57+
except ValueError as exc:
58+
raise ValueError(f"metadata filter is not encodable as JSON: {exc}") from exc

0 commit comments

Comments
 (0)