From e2bc52216f9c6da6afea18ed025ef2e9d0edb2c5 Mon Sep 17 00:00:00 2001 From: Shyam Desigan Date: Sat, 20 Jun 2026 13:00:35 +0000 Subject: [PATCH] fix: restore @record_function decorator for backward compatibility Adds the missing @record_function decorator to the legacy module with a proper deprecation warning. The decorator creates a trace span using the new v4 instrumentation system. Fixes #1076 --- agentops/__init__.py | 3 +++ agentops/legacy/__init__.py | 46 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/agentops/__init__.py b/agentops/__init__.py index 816e77443..c3b4d0299 100755 --- a/agentops/__init__.py +++ b/agentops/__init__.py @@ -4,6 +4,7 @@ end_session, track_agent, track_tool, + record_function, end_all_sessions, Session, ToolEvent, @@ -476,6 +477,8 @@ def extract_key_from_attr(attr_value: str) -> str: "tool", "guardrail", "track_endpoint", + # Legacy decorator + "record_function", # Enums "TraceState", "SUCCESS", diff --git a/agentops/legacy/__init__.py b/agentops/legacy/__init__.py index 5f77800d2..3ec7fc9c1 100644 --- a/agentops/legacy/__init__.py +++ b/agentops/legacy/__init__.py @@ -9,6 +9,8 @@ This module maintains backward compatibility with all these API patterns. """ +import asyncio +import functools from typing import Optional, Any, Dict, List, Union from agentops.logging import logger @@ -263,6 +265,49 @@ def noop(f: Any) -> Any: return noop +@deprecated("Use @task or @tool decorator from agentops instead.") +def record_function(event_name: Optional[str] = None, **kwargs: Any) -> Any: + """ + @deprecated Decorator for manually instrumenting functions. + + Previously available in v3.x, this decorator is kept for backward compatibility. + It wraps the function to create a trace span using the new v4 instrumentation system. + + Args: + event_name: Optional name for the span. Defaults to the wrapped function name. + **kwargs: Additional span attributes. + + Returns: + A decorator that instruments the wrapped function. + """ + from agentops.sdk.core import tracer + from opentelemetry.trace import SpanKind + from agentops.semconv.span_kinds import AgentOpsSpanKindValues + + def decorator(func): + @functools.wraps(func) + def sync_wrapper(*args, **kwargs): + span_name = event_name or func.__name__ + with tracer.start_as_current_span(span_name, kind=SpanKind.INTERNAL) as span: + span.set_attribute("agentops.span_kind", AgentOpsSpanKindValues.TASK.value) + span.set_attribute("agentops.entity_name", "record_function") + return func(*args, **kwargs) + + @functools.wraps(func) + async def async_wrapper(*args, **kwargs): + span_name = event_name or func.__name__ + with tracer.start_as_current_span(span_name, kind=SpanKind.INTERNAL) as span: + span.set_attribute("agentops.span_kind", AgentOpsSpanKindValues.TASK.value) + span.set_attribute("agentops.entity_name", "record_function") + return await func(*args, **kwargs) + + if asyncio.iscoroutinefunction(func): + return async_wrapper + return sync_wrapper + + return decorator + + __all__ = [ "start_session", "end_session", @@ -271,6 +316,7 @@ def noop(f: Any) -> Any: "ActionEvent", "track_agent", "track_tool", + "record_function", "end_all_sessions", "Session", "LLMEvent",