From 8d9765ea86ca9a58152dd7618ca6aa7ec134604f Mon Sep 17 00:00:00 2001 From: AgentOps Fix Bot Date: Thu, 26 Mar 2026 12:01:00 +0800 Subject: [PATCH] fix: restore get_analytics() on Session and refresh env vars on init - Add get_analytics() method to Session class for backward compatibility with older AgentOps versions (Fixes #929) - Add refresh_from_env() to Config class to re-read env vars on init - Call refresh_from_env() in Client.init() so env vars set after import are properly picked up (Fixes #962) --- agentops/client/client.py | 2 ++ agentops/config.py | 26 ++++++++++++++++++++++++ agentops/legacy/__init__.py | 40 +++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/agentops/client/client.py b/agentops/client/client.py index 87d6afd3d..5ff10a789 100644 --- a/agentops/client/client.py +++ b/agentops/client/client.py @@ -148,6 +148,8 @@ def init(self, **kwargs: Any) -> None: # Return type updated to None # Recreate the Config object to parse environment variables at the time of initialization # This allows re-init with new env vars if needed, though true singletons usually init once. self.config = Config() + # Also refresh from env to ensure env vars set after import are picked up + self.config.refresh_from_env() self.configure(**kwargs) # Only treat as re-initialization if a different non-None API key is explicitly provided diff --git a/agentops/config.py b/agentops/config.py index c618fcd84..be245d603 100644 --- a/agentops/config.py +++ b/agentops/config.py @@ -135,6 +135,32 @@ class Config: default_factory=lambda: None, metadata={"description": "Custom span processor for OpenTelemetry trace data"} ) + def refresh_from_env(self) -> None: + """Re-read all configuration values from environment variables. + + This allows configuration to be updated after import by setting + environment variables and calling init() or configure(). + Values explicitly set via parameters take precedence over env vars. + """ + self.api_key = os.getenv("AGENTOPS_API_KEY") + self.endpoint = os.getenv("AGENTOPS_API_ENDPOINT", "https://api.agentops.ai") + self.app_url = os.getenv("AGENTOPS_APP_URL", "https://app.agentops.ai") + self.max_wait_time = get_env_int("AGENTOPS_MAX_WAIT_TIME", 5000) + self.export_flush_interval = get_env_int("AGENTOPS_EXPORT_FLUSH_INTERVAL", 1000) + self.max_queue_size = get_env_int("AGENTOPS_MAX_QUEUE_SIZE", 512) + self.default_tags = get_env_list("AGENTOPS_DEFAULT_TAGS") + self.trace_name = os.getenv("AGENTOPS_TRACE_NAME") + self.instrument_llm_calls = get_env_bool("AGENTOPS_INSTRUMENT_LLM_CALLS", True) + self.auto_start_session = get_env_bool("AGENTOPS_AUTO_START_SESSION", True) + self.auto_init = get_env_bool("AGENTOPS_AUTO_INIT", True) + self.skip_auto_end_session = get_env_bool("AGENTOPS_SKIP_AUTO_END_SESSION", False) + self.env_data_opt_out = get_env_bool("AGENTOPS_ENV_DATA_OPT_OUT", False) + self.log_level = os.getenv("AGENTOPS_LOG_LEVEL", "INFO") + self.fail_safe = get_env_bool("AGENTOPS_FAIL_SAFE", False) + self.prefetch_jwt_token = get_env_bool("AGENTOPS_PREFETCH_JWT_TOKEN", True) + self.log_session_replay_url = get_env_bool("AGENTOPS_LOG_SESSION_REPLAY_URL", True) + self.exporter_endpoint = os.getenv("AGENTOPS_EXPORTER_ENDPOINT", "https://otlp.agentops.ai/v1/traces") + def configure( self, api_key: Optional[str] = None, diff --git a/agentops/legacy/__init__.py b/agentops/legacy/__init__.py index 5f77800d2..0b9dc54f1 100644 --- a/agentops/legacy/__init__.py +++ b/agentops/legacy/__init__.py @@ -60,6 +60,46 @@ def end_session(self, **kwargs: Any): """Ends the session for CrewAI >= 0.105.0 compatibility. Calls the global legacy end_session.""" end_session(session_or_status=self, **kwargs) + def get_analytics(self) -> Dict[str, Any]: + """ + Returns analytics data for this session. + + Provides backward compatibility with older AgentOps versions where + session.get_analytics() was the standard way to retrieve session metrics. + + Returns: + Dict containing token counts, costs, and other session metrics. + """ + analytics: Dict[str, Any] = { + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0, + "total_cost": 0.0, + } + + if not self.trace_context or not self.trace_context.span: + return analytics + + span = self.trace_context.span + try: + if hasattr(span, "_attributes"): + attrs = span._attributes + elif hasattr(span, "attributes"): + attrs = span.attributes + else: + return analytics + + if attrs: + analytics["prompt_tokens"] = int(attrs.get("gen_ai.usage.prompt_tokens", 0) or 0) + analytics["completion_tokens"] = int(attrs.get("gen_ai.usage.completion_tokens", 0) or 0) + analytics["total_tokens"] = analytics["prompt_tokens"] + analytics["completion_tokens"] + cost_val = attrs.get("gen_ai.usage.total_cost", 0) or 0 + analytics["total_cost"] = float(cost_val) if cost_val else 0.0 + except (TypeError, ValueError, AttributeError): + pass + + return analytics + @deprecated("Use agentops.start_trace() instead.") def start_session(