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
43 changes: 17 additions & 26 deletions libs/python/agent/cua_agent/callbacks/otel.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,14 @@

from .base import AsyncCallbackHandler

# Import OTEL functions - these are available when cua-core[telemetry] is installed
try:
from core.telemetry import (
create_span,
is_otel_enabled,
record_error,
record_operation,
record_tokens,
track_concurrent,
)

OTEL_AVAILABLE = True
except ImportError:
OTEL_AVAILABLE = False

def is_otel_enabled() -> bool:
return False
from cua_core.telemetry import (
create_span,
is_otel_enabled,
record_error,
record_operation,
record_tokens,
track_concurrent,
)


class OtelCallback(AsyncCallbackHandler):
Expand Down Expand Up @@ -75,7 +66,7 @@ def _get_agent_type(self) -> str:

async def on_run_start(self, kwargs: Dict[str, Any], old_items: List[Dict[str, Any]]) -> None:
"""Called at the start of an agent run loop."""
if not OTEL_AVAILABLE or not is_otel_enabled():
if not is_otel_enabled():
return

self.run_start_time = time.perf_counter()
Expand All @@ -89,7 +80,7 @@ async def on_run_end(
new_items: List[Dict[str, Any]],
) -> None:
"""Called at the end of an agent run loop."""
if not OTEL_AVAILABLE or not is_otel_enabled():
if not is_otel_enabled():
return

if self.run_start_time is not None:
Expand All @@ -108,7 +99,7 @@ async def on_run_end(

async def on_responses(self, kwargs: Dict[str, Any], responses: Dict[str, Any]) -> None:
"""Called when responses are received (each step)."""
if not OTEL_AVAILABLE or not is_otel_enabled():
if not is_otel_enabled():
return

self.step_count += 1
Expand All @@ -130,7 +121,7 @@ async def on_responses(self, kwargs: Dict[str, Any], responses: Dict[str, Any])

async def on_usage(self, usage: Dict[str, Any]) -> None:
"""Called when usage information is received."""
if not OTEL_AVAILABLE or not is_otel_enabled():
if not is_otel_enabled():
return

prompt_tokens = usage.get("prompt_tokens", 0)
Expand All @@ -145,14 +136,14 @@ async def on_usage(self, usage: Dict[str, Any]) -> None:

async def on_computer_call_start(self, item: Dict[str, Any]) -> None:
"""Called when a computer call is about to start."""
if not OTEL_AVAILABLE or not is_otel_enabled():
if not is_otel_enabled():
return

async def on_computer_call_end(
self, item: Dict[str, Any], result: List[Dict[str, Any]]
) -> None:
"""Called when a computer call has completed."""
if not OTEL_AVAILABLE or not is_otel_enabled():
if not is_otel_enabled():
return

action = item.get("action", {})
Expand All @@ -170,12 +161,12 @@ async def on_computer_call_end(

async def on_api_start(self, kwargs: Dict[str, Any]) -> None:
"""Called when an LLM API call is about to start."""
if not OTEL_AVAILABLE or not is_otel_enabled():
if not is_otel_enabled():
return

async def on_api_end(self, kwargs: Dict[str, Any], result: Any) -> None:
"""Called when an LLM API call has completed."""
if not OTEL_AVAILABLE or not is_otel_enabled():
if not is_otel_enabled():
return


Expand All @@ -198,7 +189,7 @@ def __init__(self, agent: Any):

async def on_error(self, error: Exception, context: Dict[str, Any]) -> None:
"""Called when an error occurs during agent execution."""
if not OTEL_AVAILABLE or not is_otel_enabled():
if not is_otel_enabled():
return

error_type = type(error).__name__
Expand Down
27 changes: 9 additions & 18 deletions libs/python/computer/computer/computer.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,11 @@
from .tracing_wrapper import TracingInterfaceWrapper

# Import OTEL functions for session-level metrics
try:
from cua_core.telemetry import (
is_otel_enabled,
record_operation,
track_concurrent,
)

OTEL_AVAILABLE = True
except ImportError:
OTEL_AVAILABLE = False

def is_otel_enabled() -> bool:
return False
from cua_core.telemetry import (
is_otel_enabled,
record_operation,
track_concurrent,
)


SYSTEM_INFO = {
Expand Down Expand Up @@ -681,7 +673,7 @@ async def run(self) -> Optional[str]:
self.logger.info("Computer successfully initialized")

# Record session start in OTEL
if OTEL_AVAILABLE and is_otel_enabled() and self._telemetry_enabled:
if is_otel_enabled() and self._telemetry_enabled:
duration_seconds = time.time() - start_time
record_operation(
operation="computer.session.start",
Expand All @@ -692,7 +684,7 @@ async def run(self) -> Optional[str]:
)
except Exception as e:
# Record failed session start
if OTEL_AVAILABLE and is_otel_enabled() and self._telemetry_enabled:
if is_otel_enabled() and self._telemetry_enabled:
duration_seconds = time.time() - start_time
record_operation(
operation="computer.session.start",
Expand Down Expand Up @@ -743,7 +735,7 @@ async def stop(self) -> None:
self.logger.info("Computer stopped")

# Record session stop in OTEL
if OTEL_AVAILABLE and is_otel_enabled() and self._telemetry_enabled:
if is_otel_enabled() and self._telemetry_enabled:
duration_seconds = time.time() - start_time
record_operation(
operation="computer.session.stop",
Expand Down Expand Up @@ -1057,8 +1049,7 @@ def interface(self):

# Apply OTEL wrapper if enabled and telemetry is on
if (
OTEL_AVAILABLE
and is_otel_enabled()
is_otel_enabled()
and self._telemetry_enabled
and hasattr(self, "_original_interface")
and self._original_interface is not None
Expand Down
46 changes: 18 additions & 28 deletions libs/python/computer/computer/otel_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,12 @@

from .interface.base import BaseComputerInterface

# Import OTEL functions - available when cua-core[telemetry] is installed
try:
from cua_core.telemetry import (
create_span,
is_otel_enabled,
record_error,
record_operation,
)

OTEL_AVAILABLE = True
except ImportError:
OTEL_AVAILABLE = False

def is_otel_enabled() -> bool:
return False
from cua_core.telemetry import (
create_span,
is_otel_enabled,
record_error,
record_operation,
)


# Actions that should be instrumented
Expand Down Expand Up @@ -95,7 +86,7 @@ def __init__(
"""
self._original_interface = original_interface
self._os_type = os_type
self._enabled = OTEL_AVAILABLE and is_otel_enabled()
self._enabled = is_otel_enabled()

def __getattr__(self, name: str) -> Any:
"""
Expand Down Expand Up @@ -149,20 +140,19 @@ async def instrumented(*args: Any, **kwargs: Any) -> Any:
duration = time.perf_counter() - start_time

# Record operation metrics
if OTEL_AVAILABLE:
record_operation(
record_operation(
operation=f"computer.action.{name}",
duration_seconds=duration,
status=status,
os_type=self._os_type,
)

if error_type:
record_error(
error_type=error_type,
operation=f"computer.action.{name}",
duration_seconds=duration,
status=status,
os_type=self._os_type,
)

if error_type:
record_error(
error_type=error_type,
operation=f"computer.action.{name}",
)

return instrumented


Expand All @@ -180,7 +170,7 @@ def wrap_interface_with_otel(
Returns:
The wrapped interface (or original if OTEL disabled)
"""
if not OTEL_AVAILABLE or not is_otel_enabled():
if not is_otel_enabled():
return interface

return OtelInterfaceWrapper(interface, os_type) # type: ignore
9 changes: 9 additions & 0 deletions libs/python/core/cua_core/telemetry/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@

# OpenTelemetry instrumentation for Four Golden Signals
from cua_core.telemetry.otel import (
StabilityTracker,
create_span,
get_stability_tracker,
instrument_async,
instrument_sync,
is_otel_enabled,
record_api_error,
record_api_request,
record_error,
record_operation,
record_tokens,
Expand All @@ -35,4 +39,9 @@
"create_span",
"instrument_async",
"instrument_sync",
# Stability metrics
"record_api_request",
"record_api_error",
"StabilityTracker",
"get_stability_tracker",
]
Loading