Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### ⚠ BREAKING CHANGES

* **tracing:** removed the Agentex-native span processor and its `AgentexTracingProcessorConfig` (the Agentex server is retiring its Postgres spans API), along with `Trace.get_span` / `Trace.list_spans` and their async twins. `SGPTracingProcessorConfig` is the only processor config and registering any other type raises `ValueError`. The in-memory `Span` is now `agentex.lib.types.tracing.Span` (also exported as `agentex.lib.core.tracing.Span`); the generated `agentex.types.span.Span` disappears with the next client generation. Its `to_dict()` / `to_json()` return the full JSON-mode dump rather than only the fields that were set.
* **harness:** removed the deprecated bespoke LangGraph tracing handler `create_langgraph_tracing_handler` (and its `AgentexLangGraphTracingHandler` class) from the public `agentex.lib.adk` surface. Span tracing is now derived from the canonical `StreamTaskMessage*` stream by `UnifiedEmitter` — wrap your run in the harness `*Turn` and drive `UnifiedEmitter.yield_turn` / `auto_send_turn`. The `agentex init` templates were migrated accordingly.
* **harness:** removed the deprecated bespoke Pydantic-AI tracing handler `create_pydantic_ai_tracing_handler` (and its `AgentexPydanticAITracingHandler` class) from the public `agentex.lib.adk` surface. Span tracing is now derived from the canonical `StreamTaskMessage*` stream by `UnifiedEmitter` — wrap your run in `PydanticAITurn` and drive `UnifiedEmitter.yield_turn` / `auto_send_turn`. The `agentex init` templates were migrated accordingly.
* **harness:** each harness now exposes exactly `_<harness>_sync.py` + `_<harness>_turn.py` under `agentex.lib.adk._modules`. The OpenAI harness `OpenAITurn` and `convert_openai_to_agentex_events` moved to `agentex.lib.adk._modules._openai_turn` / `_openai_sync`; back-compat shims remain at `agentex.lib.adk.providers._modules.{openai_turn,sync_provider}` for one release. Public facade names (`stream_pydantic_ai_events`, `stream_langgraph_events`, `emit_langgraph_messages`, etc.) are unchanged.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from pydantic import BaseModel

from agentex.types.span import Span
from agentex.lib.types.tracing import Span
from agentex.lib.sdk.state_machine import StateMachine


Expand Down
38 changes: 4 additions & 34 deletions src/agentex/lib/adk/_modules/tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from temporalio.exceptions import ActivityError, TimeoutError as TemporalTimeoutError, is_cancelled_exception

from agentex import AsyncAgentex # noqa: F401
from agentex.lib.adk.utils._modules.client import create_async_agentex_client
from agentex.lib.core.services.adk.tracing import TracingService
from agentex.lib.core.temporal.activities.activity_helpers import ActivityHelpers
from agentex.lib.core.temporal.activities.adk.tracing_activities import (
Expand All @@ -22,7 +21,7 @@
from agentex.lib.core.tracing.span_error import set_span_error
from agentex.lib.core.tracing.tracer import AsyncTracer
from agentex.lib.core.harness.types import TurnUsage
from agentex.types.span import Span
from agentex.lib.types.tracing import Span
from agentex.lib.utils.logging import make_logger
from agentex.lib.utils.model_utils import BaseModel
from agentex.lib.utils.temporal import in_temporal_workflow
Expand Down Expand Up @@ -145,46 +144,17 @@ def __init__(self, tracing_service: TracingService | None = None):

Args:
tracing_service (Optional[TracingService]): Optional pre-configured tracing service.
If None, will be lazily created on first use so the httpx client is
bound to the correct running event loop.
If None, one is created on first use.
"""
self._tracing_service_explicit = tracing_service
self._tracing_service_lazy: TracingService | None = None
self._bound_loop_id: int | None = None

@property
def _tracing_service(self) -> TracingService:
if self._tracing_service_explicit is not None:
return self._tracing_service_explicit

import asyncio

# Determine the current event loop (if any).
try:
loop = asyncio.get_running_loop()
loop_id = id(loop)
except RuntimeError:
loop_id = None

# Re-create the underlying httpx client when the event loop changes
# (e.g. between HTTP requests in a sync ASGI server) to avoid
# "Event loop is closed" / "bound to a different event loop" errors.
if self._tracing_service_lazy is None or (loop_id is not None and loop_id != self._bound_loop_id):
import httpx

# 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=20),
),
)
tracer = AsyncTracer(agentex_client)
self._tracing_service_lazy = TracingService(tracer=tracer)
self._bound_loop_id = loop_id

if self._tracing_service_lazy is None:
self._tracing_service_lazy = TracingService(tracer=AsyncTracer())
return self._tracing_service_lazy

@asynccontextmanager
Expand Down
2 changes: 1 addition & 1 deletion src/agentex/lib/core/services/adk/tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from typing import Any

from agentex.types.span import Span
from agentex.lib.types.tracing import Span
from agentex.lib.utils.logging import make_logger
from agentex.lib.utils.temporal import heartbeat_if_in_workflow
from agentex.lib.utils.model_utils import BaseModel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from temporalio import activity

from agentex.types.span import Span
from agentex.lib.types.tracing import Span
from agentex.lib.utils.logging import make_logger
from agentex.lib.utils.model_utils import BaseModel
from agentex.lib.core.services.adk.tracing import TracingService
Expand Down
2 changes: 1 addition & 1 deletion src/agentex/lib/core/tracing/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from agentex.types.span import Span
from agentex.lib.types.tracing import Span
from agentex.lib.core.tracing.trace import Trace, AsyncTrace
from agentex.lib.core.tracing.tracer import Tracer, AsyncTracer
from agentex.lib.core.tracing.span_error import (
Expand Down
232 changes: 0 additions & 232 deletions src/agentex/lib/core/tracing/processors/agentex_tracing_processor.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
from scale_gp_beta.lib.tracing import create_span, flush_queue
from scale_gp_beta.lib.tracing.span import Span as SGPSpan

from agentex.types.span import Span
from agentex.lib.core.tracing import code_revision
from agentex.lib.types.tracing import SGPTracingProcessorConfig
from agentex.lib.types.tracing import Span, SGPTracingProcessorConfig
from agentex.lib.utils.logging import make_logger
from agentex.lib.core.observability import tracing_metrics_recording as _metrics
from agentex.lib.environment_variables import EnvironmentVariables
Expand Down Expand Up @@ -75,8 +74,8 @@ def _sgp_metadata(span: Span) -> Any:

Returns a COPY rather than mutating ``span``. ``trace.py`` hands the same
Span instance to every registered processor, so anything written onto
``span.data`` here would also be serialized by the Agentex processor and
show up in caller-visible span data. ``__commit_sha__`` is opt-in and
``span.data`` here would also reach every other processor and show up in
caller-visible span data. ``__commit_sha__`` is opt-in and
SGP-scoped, so it must not leak that way.

(The ``__source__`` / ``__agent_*`` keys set by ``_add_source_to_span`` do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
import asyncio
from abc import ABC, abstractmethod

from agentex.types.span import Span
from agentex.lib.types.tracing import TracingProcessorConfig
from agentex.lib.types.tracing import Span, TracingProcessorConfig
from agentex.lib.utils.logging import make_logger

logger = make_logger(__name__)
Expand Down
11 changes: 4 additions & 7 deletions src/agentex/lib/core/tracing/span_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,12 @@
)
from scale_gp_beta.lib.tracing.types import ErrorCategory

from agentex.types.span import Span
from agentex.lib.types.tracing import Span

# Reserved key under ``Span.data`` carrying failure info for a span whose
# context-manager body raised. Mirrors the existing ``__span_type__`` /
# ``__source__`` reserved-key convention already read/written by the SGP
# processor. Stored in ``data`` because the Span model is generated from the
# OpenAPI spec and has no first-class status/error field; ``data`` is a real
# field, so it survives ``model_copy(deep=True)`` and round-trips to both the
# SGP and agentex-native span stores.
# context-manager body raised, alongside the ``__span_type__`` / ``__source__``
# keys the SGP processor already reads. Kept in ``data`` so it survives
# ``model_copy(deep=True)`` and reaches the processors with the span.
SPAN_ERROR_KEY = "__error__"

ERROR_CATEGORY_UNKNOWN: ErrorCategory = "unknown"
Expand Down
Loading
Loading