mseep-agentops 0.4.18__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agentops/__init__.py +488 -0
- agentops/client/__init__.py +5 -0
- agentops/client/api/__init__.py +71 -0
- agentops/client/api/base.py +162 -0
- agentops/client/api/types.py +21 -0
- agentops/client/api/versions/__init__.py +10 -0
- agentops/client/api/versions/v3.py +65 -0
- agentops/client/api/versions/v4.py +104 -0
- agentops/client/client.py +211 -0
- agentops/client/http/__init__.py +0 -0
- agentops/client/http/http_adapter.py +116 -0
- agentops/client/http/http_client.py +215 -0
- agentops/config.py +268 -0
- agentops/enums.py +36 -0
- agentops/exceptions.py +38 -0
- agentops/helpers/__init__.py +44 -0
- agentops/helpers/dashboard.py +54 -0
- agentops/helpers/deprecation.py +50 -0
- agentops/helpers/env.py +52 -0
- agentops/helpers/serialization.py +137 -0
- agentops/helpers/system.py +178 -0
- agentops/helpers/time.py +11 -0
- agentops/helpers/version.py +36 -0
- agentops/instrumentation/__init__.py +598 -0
- agentops/instrumentation/common/__init__.py +82 -0
- agentops/instrumentation/common/attributes.py +278 -0
- agentops/instrumentation/common/instrumentor.py +147 -0
- agentops/instrumentation/common/metrics.py +100 -0
- agentops/instrumentation/common/objects.py +26 -0
- agentops/instrumentation/common/span_management.py +176 -0
- agentops/instrumentation/common/streaming.py +218 -0
- agentops/instrumentation/common/token_counting.py +177 -0
- agentops/instrumentation/common/version.py +71 -0
- agentops/instrumentation/common/wrappers.py +235 -0
- agentops/legacy/__init__.py +277 -0
- agentops/legacy/event.py +156 -0
- agentops/logging/__init__.py +4 -0
- agentops/logging/config.py +86 -0
- agentops/logging/formatters.py +34 -0
- agentops/logging/instrument_logging.py +91 -0
- agentops/sdk/__init__.py +27 -0
- agentops/sdk/attributes.py +151 -0
- agentops/sdk/core.py +607 -0
- agentops/sdk/decorators/__init__.py +51 -0
- agentops/sdk/decorators/factory.py +486 -0
- agentops/sdk/decorators/utility.py +216 -0
- agentops/sdk/exporters.py +87 -0
- agentops/sdk/processors.py +71 -0
- agentops/sdk/types.py +21 -0
- agentops/semconv/__init__.py +36 -0
- agentops/semconv/agent.py +29 -0
- agentops/semconv/core.py +19 -0
- agentops/semconv/enum.py +11 -0
- agentops/semconv/instrumentation.py +13 -0
- agentops/semconv/langchain.py +63 -0
- agentops/semconv/message.py +61 -0
- agentops/semconv/meters.py +24 -0
- agentops/semconv/resource.py +52 -0
- agentops/semconv/span_attributes.py +118 -0
- agentops/semconv/span_kinds.py +50 -0
- agentops/semconv/status.py +11 -0
- agentops/semconv/tool.py +15 -0
- agentops/semconv/workflow.py +69 -0
- agentops/validation.py +357 -0
- mseep_agentops-0.4.18.dist-info/METADATA +49 -0
- mseep_agentops-0.4.18.dist-info/RECORD +94 -0
- mseep_agentops-0.4.18.dist-info/WHEEL +5 -0
- mseep_agentops-0.4.18.dist-info/licenses/LICENSE +21 -0
- mseep_agentops-0.4.18.dist-info/top_level.txt +2 -0
- tests/__init__.py +0 -0
- tests/conftest.py +10 -0
- tests/unit/__init__.py +0 -0
- tests/unit/client/__init__.py +1 -0
- tests/unit/client/test_http_adapter.py +221 -0
- tests/unit/client/test_http_client.py +206 -0
- tests/unit/conftest.py +54 -0
- tests/unit/sdk/__init__.py +1 -0
- tests/unit/sdk/instrumentation_tester.py +207 -0
- tests/unit/sdk/test_attributes.py +392 -0
- tests/unit/sdk/test_concurrent_instrumentation.py +468 -0
- tests/unit/sdk/test_decorators.py +763 -0
- tests/unit/sdk/test_exporters.py +241 -0
- tests/unit/sdk/test_factory.py +1188 -0
- tests/unit/sdk/test_internal_span_processor.py +397 -0
- tests/unit/sdk/test_resource_attributes.py +35 -0
- tests/unit/test_config.py +82 -0
- tests/unit/test_context_manager.py +777 -0
- tests/unit/test_events.py +27 -0
- tests/unit/test_host_env.py +54 -0
- tests/unit/test_init_py.py +501 -0
- tests/unit/test_serialization.py +433 -0
- tests/unit/test_session.py +676 -0
- tests/unit/test_user_agent.py +34 -0
- tests/unit/test_validation.py +405 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
from agentops.helpers.time import get_ISO_time
|
2
|
+
from agentops.helpers.serialization import (
|
3
|
+
AgentOpsJSONEncoder,
|
4
|
+
serialize_uuid,
|
5
|
+
safe_serialize,
|
6
|
+
is_jsonable,
|
7
|
+
filter_unjsonable,
|
8
|
+
)
|
9
|
+
from agentops.helpers.system import (
|
10
|
+
get_host_env,
|
11
|
+
get_sdk_details,
|
12
|
+
get_os_details,
|
13
|
+
get_cpu_details,
|
14
|
+
get_ram_details,
|
15
|
+
get_disk_details,
|
16
|
+
get_installed_packages,
|
17
|
+
get_current_directory,
|
18
|
+
get_virtual_env,
|
19
|
+
)
|
20
|
+
from agentops.helpers.version import get_agentops_version, check_agentops_update
|
21
|
+
from agentops.helpers.env import get_env_bool, get_env_int, get_env_list
|
22
|
+
|
23
|
+
__all__ = [
|
24
|
+
"get_ISO_time",
|
25
|
+
"AgentOpsJSONEncoder",
|
26
|
+
"serialize_uuid",
|
27
|
+
"safe_serialize",
|
28
|
+
"is_jsonable",
|
29
|
+
"filter_unjsonable",
|
30
|
+
"get_host_env",
|
31
|
+
"get_sdk_details",
|
32
|
+
"get_os_details",
|
33
|
+
"get_cpu_details",
|
34
|
+
"get_ram_details",
|
35
|
+
"get_disk_details",
|
36
|
+
"get_installed_packages",
|
37
|
+
"get_current_directory",
|
38
|
+
"get_virtual_env",
|
39
|
+
"get_agentops_version",
|
40
|
+
"check_agentops_update",
|
41
|
+
"get_env_bool",
|
42
|
+
"get_env_int",
|
43
|
+
"get_env_list",
|
44
|
+
]
|
@@ -0,0 +1,54 @@
|
|
1
|
+
"""
|
2
|
+
Helpers for interacting with the AgentOps dashboard.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import Union, Optional
|
6
|
+
from termcolor import colored
|
7
|
+
from opentelemetry.sdk.trace import Span, ReadableSpan
|
8
|
+
from agentops.logging import logger
|
9
|
+
|
10
|
+
|
11
|
+
def get_trace_url(span: Union[Span, ReadableSpan]) -> str:
|
12
|
+
"""
|
13
|
+
Generate a trace URL for a direct link to the session on the AgentOps dashboard.
|
14
|
+
|
15
|
+
Args:
|
16
|
+
span: The span to generate the URL for.
|
17
|
+
|
18
|
+
Returns:
|
19
|
+
The session URL.
|
20
|
+
"""
|
21
|
+
trace_id: Union[int, str] = span.context.trace_id
|
22
|
+
|
23
|
+
# Convert trace_id to hex string if it's not already
|
24
|
+
# We don't add dashes to this to format it as a UUID since the dashboard doesn't either
|
25
|
+
if isinstance(trace_id, int):
|
26
|
+
trace_id = format(trace_id, "032x")
|
27
|
+
|
28
|
+
# Get the app_url from the config - import here to avoid circular imports
|
29
|
+
from agentops import get_client
|
30
|
+
|
31
|
+
app_url = get_client().config.app_url
|
32
|
+
|
33
|
+
return f"{app_url}/sessions?trace_id={trace_id}"
|
34
|
+
|
35
|
+
|
36
|
+
def log_trace_url(span: Union[Span, ReadableSpan], title: Optional[str] = None) -> None:
|
37
|
+
"""
|
38
|
+
Log the trace URL for the AgentOps dashboard.
|
39
|
+
|
40
|
+
Args:
|
41
|
+
span: The span to log the URL for.
|
42
|
+
title: Optional title for the trace.
|
43
|
+
"""
|
44
|
+
from agentops import get_client
|
45
|
+
|
46
|
+
try:
|
47
|
+
client = get_client()
|
48
|
+
if not client.config.log_session_replay_url:
|
49
|
+
return
|
50
|
+
except Exception:
|
51
|
+
return
|
52
|
+
|
53
|
+
session_url = get_trace_url(span)
|
54
|
+
logger.info(colored(f"\x1b[34mSession Replay for {title} trace: {session_url}\x1b[0m", "blue"))
|
@@ -0,0 +1,50 @@
|
|
1
|
+
"""
|
2
|
+
Deprecation utilities for AgentOps SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import functools
|
6
|
+
from typing import Set, Callable, Any
|
7
|
+
from agentops.logging import logger
|
8
|
+
|
9
|
+
# Track which deprecation warnings have been shown to avoid spam
|
10
|
+
_shown_warnings: Set[str] = set()
|
11
|
+
|
12
|
+
|
13
|
+
def deprecated(message: str):
|
14
|
+
"""
|
15
|
+
Decorator to mark functions as deprecated.
|
16
|
+
|
17
|
+
Args:
|
18
|
+
message: Deprecation message to show
|
19
|
+
"""
|
20
|
+
|
21
|
+
def decorator(func: Callable) -> Callable:
|
22
|
+
@functools.wraps(func)
|
23
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
24
|
+
warning_key = f"{func.__module__}.{func.__name__}"
|
25
|
+
if warning_key not in _shown_warnings:
|
26
|
+
logger.warning(f"{func.__name__}() is deprecated and will be removed in v4 in the future. {message}")
|
27
|
+
_shown_warnings.add(warning_key)
|
28
|
+
return func(*args, **kwargs)
|
29
|
+
|
30
|
+
return wrapper
|
31
|
+
|
32
|
+
return decorator
|
33
|
+
|
34
|
+
|
35
|
+
def warn_deprecated_param(param_name: str, replacement: str = None):
|
36
|
+
"""
|
37
|
+
Warn about deprecated parameter usage.
|
38
|
+
|
39
|
+
Args:
|
40
|
+
param_name: Name of the deprecated parameter
|
41
|
+
replacement: Suggested replacement parameter
|
42
|
+
"""
|
43
|
+
warning_key = f"param.{param_name}"
|
44
|
+
if warning_key not in _shown_warnings:
|
45
|
+
if replacement:
|
46
|
+
message = f"Parameter '{param_name}' is deprecated and will be removed in v4 in the future. Use '{replacement}' instead."
|
47
|
+
else:
|
48
|
+
message = f"Parameter '{param_name}' is deprecated and will be removed in v4 in the future."
|
49
|
+
logger.warning(message)
|
50
|
+
_shown_warnings.add(warning_key)
|
agentops/helpers/env.py
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
"""Environment variable helper functions"""
|
2
|
+
|
3
|
+
import os
|
4
|
+
from typing import List, Optional, Set
|
5
|
+
|
6
|
+
|
7
|
+
def get_env_bool(key: str, default: bool) -> bool:
|
8
|
+
"""Get boolean from environment variable
|
9
|
+
|
10
|
+
Args:
|
11
|
+
key: Environment variable name
|
12
|
+
default: Default value if not set
|
13
|
+
|
14
|
+
Returns:
|
15
|
+
bool: Parsed boolean value
|
16
|
+
"""
|
17
|
+
val = os.getenv(key)
|
18
|
+
if val is None:
|
19
|
+
return default
|
20
|
+
return val.lower() in ("true", "1", "t", "yes")
|
21
|
+
|
22
|
+
|
23
|
+
def get_env_int(key: str, default: int) -> int:
|
24
|
+
"""Get integer from environment variable
|
25
|
+
|
26
|
+
Args:
|
27
|
+
key: Environment variable name
|
28
|
+
default: Default value if not set
|
29
|
+
|
30
|
+
Returns:
|
31
|
+
int: Parsed integer value
|
32
|
+
"""
|
33
|
+
try:
|
34
|
+
return int(os.getenv(key, default))
|
35
|
+
except (TypeError, ValueError):
|
36
|
+
return default
|
37
|
+
|
38
|
+
|
39
|
+
def get_env_list(key: str, default: Optional[List[str]] = None) -> Set[str]:
|
40
|
+
"""Get comma-separated list from environment variable
|
41
|
+
|
42
|
+
Args:
|
43
|
+
key: Environment variable name
|
44
|
+
default: Default list if not set
|
45
|
+
|
46
|
+
Returns:
|
47
|
+
Set[str]: Set of parsed values
|
48
|
+
"""
|
49
|
+
val = os.getenv(key)
|
50
|
+
if val is None:
|
51
|
+
return set(default or [])
|
52
|
+
return set(val.split(","))
|
@@ -0,0 +1,137 @@
|
|
1
|
+
"""Serialization helpers for AgentOps"""
|
2
|
+
|
3
|
+
import json
|
4
|
+
from datetime import datetime
|
5
|
+
from decimal import Decimal
|
6
|
+
from enum import Enum
|
7
|
+
from typing import Any
|
8
|
+
from uuid import UUID
|
9
|
+
|
10
|
+
from agentops.logging import logger
|
11
|
+
|
12
|
+
|
13
|
+
def is_jsonable(x):
|
14
|
+
try:
|
15
|
+
json.dumps(x)
|
16
|
+
return True
|
17
|
+
except (TypeError, OverflowError):
|
18
|
+
return False
|
19
|
+
|
20
|
+
|
21
|
+
def filter_unjsonable(d: dict) -> dict:
|
22
|
+
def filter_dict(obj):
|
23
|
+
if isinstance(obj, dict):
|
24
|
+
return {
|
25
|
+
k: (
|
26
|
+
filter_dict(v)
|
27
|
+
if isinstance(v, (dict, list)) or is_jsonable(v)
|
28
|
+
else str(v)
|
29
|
+
if isinstance(v, UUID)
|
30
|
+
else ""
|
31
|
+
)
|
32
|
+
for k, v in obj.items()
|
33
|
+
}
|
34
|
+
elif isinstance(obj, list):
|
35
|
+
return [
|
36
|
+
(
|
37
|
+
filter_dict(x)
|
38
|
+
if isinstance(x, (dict, list)) or is_jsonable(x)
|
39
|
+
else str(x)
|
40
|
+
if isinstance(x, UUID)
|
41
|
+
else ""
|
42
|
+
)
|
43
|
+
for x in obj
|
44
|
+
]
|
45
|
+
else:
|
46
|
+
return obj if is_jsonable(obj) or isinstance(obj, UUID) else ""
|
47
|
+
|
48
|
+
return filter_dict(d)
|
49
|
+
|
50
|
+
|
51
|
+
class AgentOpsJSONEncoder(json.JSONEncoder):
|
52
|
+
"""Custom JSON encoder for AgentOps types"""
|
53
|
+
|
54
|
+
def default(self, obj: Any) -> Any:
|
55
|
+
if isinstance(obj, UUID):
|
56
|
+
return str(obj)
|
57
|
+
if isinstance(obj, datetime):
|
58
|
+
return obj.isoformat()
|
59
|
+
if isinstance(obj, Decimal):
|
60
|
+
return str(obj)
|
61
|
+
if isinstance(obj, set):
|
62
|
+
return list(obj)
|
63
|
+
if hasattr(obj, "to_json"):
|
64
|
+
return obj.to_json()
|
65
|
+
if isinstance(obj, Enum):
|
66
|
+
return obj.value
|
67
|
+
return str(obj)
|
68
|
+
|
69
|
+
|
70
|
+
def serialize_uuid(obj: UUID) -> str:
|
71
|
+
"""Serialize UUID to string"""
|
72
|
+
return str(obj)
|
73
|
+
|
74
|
+
|
75
|
+
def model_to_dict(obj: Any) -> dict:
|
76
|
+
"""Convert a model object to a dictionary safely.
|
77
|
+
|
78
|
+
Handles various model types including:
|
79
|
+
- Pydantic models (model_dump/dict methods)
|
80
|
+
- Dictionary-like objects
|
81
|
+
- API response objects with parse method
|
82
|
+
- Objects with __dict__ attribute
|
83
|
+
|
84
|
+
Args:
|
85
|
+
obj: The model object to convert to dictionary
|
86
|
+
|
87
|
+
Returns:
|
88
|
+
Dictionary representation of the object, or empty dict if conversion fails
|
89
|
+
"""
|
90
|
+
if obj is None:
|
91
|
+
return {}
|
92
|
+
if isinstance(obj, dict):
|
93
|
+
return obj
|
94
|
+
if hasattr(obj, "model_dump"): # Pydantic v2
|
95
|
+
return obj.model_dump()
|
96
|
+
elif hasattr(obj, "dict"): # Pydantic v1
|
97
|
+
return obj.dict()
|
98
|
+
# TODO this is causing recursion on nested objects.
|
99
|
+
# elif hasattr(obj, "parse"): # Raw API response
|
100
|
+
# return model_to_dict(obj.parse())
|
101
|
+
else:
|
102
|
+
# Try to use __dict__ as fallback
|
103
|
+
try:
|
104
|
+
return obj.__dict__
|
105
|
+
except:
|
106
|
+
return {}
|
107
|
+
|
108
|
+
|
109
|
+
def safe_serialize(obj: Any) -> Any:
|
110
|
+
"""Safely serialize an object to JSON-compatible format
|
111
|
+
|
112
|
+
This function handles complex objects by:
|
113
|
+
1. Returning strings untouched (even if they contain JSON)
|
114
|
+
2. Converting models to dictionaries
|
115
|
+
3. Using custom JSON encoder to handle special types
|
116
|
+
4. Falling back to string representation only when necessary
|
117
|
+
|
118
|
+
Args:
|
119
|
+
obj: The object to serialize
|
120
|
+
|
121
|
+
Returns:
|
122
|
+
If obj is a string, returns the original string untouched.
|
123
|
+
Otherwise, returns a JSON string representation of the object.
|
124
|
+
"""
|
125
|
+
# Return strings untouched
|
126
|
+
if isinstance(obj, str):
|
127
|
+
return obj
|
128
|
+
|
129
|
+
# Convert any model objects to dictionaries
|
130
|
+
if hasattr(obj, "model_dump") or hasattr(obj, "dict") or hasattr(obj, "parse"):
|
131
|
+
obj = model_to_dict(obj)
|
132
|
+
|
133
|
+
try:
|
134
|
+
return json.dumps(obj, cls=AgentOpsJSONEncoder)
|
135
|
+
except (TypeError, ValueError) as e:
|
136
|
+
logger.warning(f"Failed to serialize object: {e}")
|
137
|
+
return str(obj)
|
@@ -0,0 +1,178 @@
|
|
1
|
+
import importlib.metadata
|
2
|
+
import os
|
3
|
+
import platform
|
4
|
+
import socket
|
5
|
+
import sys
|
6
|
+
|
7
|
+
import psutil # type: ignore
|
8
|
+
|
9
|
+
from agentops.logging import logger
|
10
|
+
from agentops.helpers.version import get_agentops_version
|
11
|
+
|
12
|
+
|
13
|
+
def get_imported_libraries():
|
14
|
+
"""
|
15
|
+
Get the top-level imported libraries in the current script.
|
16
|
+
|
17
|
+
Returns:
|
18
|
+
list: List of imported libraries
|
19
|
+
"""
|
20
|
+
user_libs = []
|
21
|
+
|
22
|
+
builtin_modules = {
|
23
|
+
"builtins",
|
24
|
+
"sys",
|
25
|
+
"os",
|
26
|
+
"_thread",
|
27
|
+
"abc",
|
28
|
+
"io",
|
29
|
+
"re",
|
30
|
+
"types",
|
31
|
+
"collections",
|
32
|
+
"enum",
|
33
|
+
"math",
|
34
|
+
"datetime",
|
35
|
+
"time",
|
36
|
+
"warnings",
|
37
|
+
}
|
38
|
+
|
39
|
+
try:
|
40
|
+
main_module = sys.modules.get("__main__")
|
41
|
+
if main_module and hasattr(main_module, "__dict__"):
|
42
|
+
for name, obj in main_module.__dict__.items():
|
43
|
+
if isinstance(obj, type(sys)) and hasattr(obj, "__name__"):
|
44
|
+
mod_name = obj.__name__.split(".")[0]
|
45
|
+
if mod_name and not mod_name.startswith("_") and mod_name not in builtin_modules:
|
46
|
+
user_libs.append(mod_name)
|
47
|
+
except Exception as e:
|
48
|
+
logger.debug(f"Error getting imports: {e}")
|
49
|
+
|
50
|
+
return user_libs
|
51
|
+
|
52
|
+
|
53
|
+
def get_sdk_details():
|
54
|
+
try:
|
55
|
+
return {
|
56
|
+
"AgentOps SDK Version": get_agentops_version(),
|
57
|
+
"Python Version": platform.python_version(),
|
58
|
+
"System Packages": get_sys_packages(),
|
59
|
+
}
|
60
|
+
except:
|
61
|
+
return {}
|
62
|
+
|
63
|
+
|
64
|
+
def get_sys_packages():
|
65
|
+
sys_packages = {}
|
66
|
+
for module in sys.modules:
|
67
|
+
try:
|
68
|
+
version = importlib.metadata.version(module)
|
69
|
+
sys_packages[module] = version
|
70
|
+
except importlib.metadata.PackageNotFoundError:
|
71
|
+
# Skip built-in modules and those without package metadata
|
72
|
+
continue
|
73
|
+
|
74
|
+
return sys_packages
|
75
|
+
|
76
|
+
|
77
|
+
def get_installed_packages():
|
78
|
+
try:
|
79
|
+
return {
|
80
|
+
# TODO: add to opt out
|
81
|
+
"Installed Packages": {
|
82
|
+
dist.metadata.get("Name"): dist.metadata.get("Version") for dist in importlib.metadata.distributions()
|
83
|
+
}
|
84
|
+
}
|
85
|
+
except:
|
86
|
+
return {}
|
87
|
+
|
88
|
+
|
89
|
+
def get_current_directory():
|
90
|
+
try:
|
91
|
+
return {"Project Working Directory": os.getcwd()}
|
92
|
+
except:
|
93
|
+
return {}
|
94
|
+
|
95
|
+
|
96
|
+
def get_virtual_env():
|
97
|
+
try:
|
98
|
+
return {"Virtual Environment": os.environ.get("VIRTUAL_ENV", None)}
|
99
|
+
except:
|
100
|
+
return {}
|
101
|
+
|
102
|
+
|
103
|
+
def get_os_details():
|
104
|
+
try:
|
105
|
+
return {
|
106
|
+
"Hostname": socket.gethostname(),
|
107
|
+
"OS": platform.system(),
|
108
|
+
"OS Version": platform.version(),
|
109
|
+
"OS Release": platform.release(),
|
110
|
+
}
|
111
|
+
except:
|
112
|
+
return {}
|
113
|
+
|
114
|
+
|
115
|
+
def get_cpu_details():
|
116
|
+
try:
|
117
|
+
return {
|
118
|
+
"Physical cores": psutil.cpu_count(logical=False),
|
119
|
+
"Total cores": psutil.cpu_count(logical=True),
|
120
|
+
# "Max Frequency": f"{psutil.cpu_freq().max:.2f}Mhz", # Fails right now
|
121
|
+
"CPU Usage": f"{psutil.cpu_percent()}%",
|
122
|
+
}
|
123
|
+
except:
|
124
|
+
return {}
|
125
|
+
|
126
|
+
|
127
|
+
def get_ram_details():
|
128
|
+
try:
|
129
|
+
ram_info = psutil.virtual_memory()
|
130
|
+
return {
|
131
|
+
"Total": f"{ram_info.total / (1024**3):.2f} GB",
|
132
|
+
"Available": f"{ram_info.available / (1024**3):.2f} GB",
|
133
|
+
"Used": f"{ram_info.used / (1024**3):.2f} GB",
|
134
|
+
"Percentage": f"{ram_info.percent}%",
|
135
|
+
}
|
136
|
+
except:
|
137
|
+
return {}
|
138
|
+
|
139
|
+
|
140
|
+
def get_disk_details():
|
141
|
+
partitions = psutil.disk_partitions()
|
142
|
+
disk_info = {}
|
143
|
+
for partition in partitions:
|
144
|
+
try:
|
145
|
+
usage = psutil.disk_usage(partition.mountpoint)
|
146
|
+
disk_info[partition.device] = {
|
147
|
+
"Mountpoint": partition.mountpoint,
|
148
|
+
"Total": f"{usage.total / (1024**3):.2f} GB",
|
149
|
+
"Used": f"{usage.used / (1024**3):.2f} GB",
|
150
|
+
"Free": f"{usage.free / (1024**3):.2f} GB",
|
151
|
+
"Percentage": f"{usage.percent}%",
|
152
|
+
}
|
153
|
+
except OSError as inaccessible:
|
154
|
+
# Skip inaccessible partitions, such as removable drives with no media
|
155
|
+
logger.debug("Mountpoint %s inaccessible: %s", partition.mountpoint, inaccessible)
|
156
|
+
|
157
|
+
return disk_info
|
158
|
+
|
159
|
+
|
160
|
+
def get_host_env(opt_out: bool = False):
|
161
|
+
if opt_out:
|
162
|
+
return {
|
163
|
+
"SDK": get_sdk_details(),
|
164
|
+
"OS": get_os_details(),
|
165
|
+
"Project Working Directory": get_current_directory(),
|
166
|
+
"Virtual Environment": get_virtual_env(),
|
167
|
+
}
|
168
|
+
else:
|
169
|
+
return {
|
170
|
+
"SDK": get_sdk_details(),
|
171
|
+
"OS": get_os_details(),
|
172
|
+
"CPU": get_cpu_details(),
|
173
|
+
"RAM": get_ram_details(),
|
174
|
+
"Disk": get_disk_details(),
|
175
|
+
"Installed Packages": get_installed_packages(),
|
176
|
+
"Project Working Directory": get_current_directory(),
|
177
|
+
"Virtual Environment": get_virtual_env(),
|
178
|
+
}
|
agentops/helpers/time.py
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
from datetime import datetime, timezone
|
2
|
+
|
3
|
+
|
4
|
+
def get_ISO_time():
|
5
|
+
"""
|
6
|
+
Get the current UTC time in ISO 8601 format with milliseconds precision in UTC timezone.
|
7
|
+
|
8
|
+
Returns:
|
9
|
+
str: The current UTC time as a string in ISO 8601 format.
|
10
|
+
"""
|
11
|
+
return datetime.now(timezone.utc).isoformat()
|
@@ -0,0 +1,36 @@
|
|
1
|
+
from importlib.metadata import PackageNotFoundError, version
|
2
|
+
|
3
|
+
import requests
|
4
|
+
|
5
|
+
from agentops.logging import logger
|
6
|
+
|
7
|
+
|
8
|
+
def get_agentops_version():
|
9
|
+
try:
|
10
|
+
pkg_version = version("agentops")
|
11
|
+
return pkg_version
|
12
|
+
except Exception as e:
|
13
|
+
logger.warning("Error reading package version: %s", e)
|
14
|
+
return None
|
15
|
+
|
16
|
+
|
17
|
+
def check_agentops_update():
|
18
|
+
try:
|
19
|
+
response = requests.get("https://pypi.org/pypi/agentops/json")
|
20
|
+
|
21
|
+
if response.status_code == 200:
|
22
|
+
json_data = response.json()
|
23
|
+
latest_version = json_data["info"]["version"]
|
24
|
+
|
25
|
+
try:
|
26
|
+
current_version = version("agentops")
|
27
|
+
except PackageNotFoundError:
|
28
|
+
return None
|
29
|
+
|
30
|
+
if not latest_version == current_version:
|
31
|
+
logger.warning(
|
32
|
+
" WARNING: agentops is out of date. Please update with the command: 'pip install --upgrade agentops'"
|
33
|
+
)
|
34
|
+
except Exception as e:
|
35
|
+
logger.debug(f"Failed to check for updates: {e}")
|
36
|
+
return None
|