mseep-agentops 0.4.18__py3-none-any.whl → 0.4.23__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 +0 -0
- agentops/client/api/base.py +28 -30
- agentops/client/api/versions/v3.py +29 -25
- agentops/client/api/versions/v4.py +87 -46
- agentops/client/client.py +98 -29
- agentops/client/http/README.md +87 -0
- agentops/client/http/http_client.py +126 -172
- agentops/config.py +8 -2
- agentops/instrumentation/OpenTelemetry.md +133 -0
- agentops/instrumentation/README.md +167 -0
- agentops/instrumentation/__init__.py +13 -1
- agentops/instrumentation/agentic/ag2/__init__.py +18 -0
- agentops/instrumentation/agentic/ag2/instrumentor.py +922 -0
- agentops/instrumentation/agentic/agno/__init__.py +19 -0
- agentops/instrumentation/agentic/agno/attributes/__init__.py +20 -0
- agentops/instrumentation/agentic/agno/attributes/agent.py +250 -0
- agentops/instrumentation/agentic/agno/attributes/metrics.py +214 -0
- agentops/instrumentation/agentic/agno/attributes/storage.py +158 -0
- agentops/instrumentation/agentic/agno/attributes/team.py +195 -0
- agentops/instrumentation/agentic/agno/attributes/tool.py +210 -0
- agentops/instrumentation/agentic/agno/attributes/workflow.py +254 -0
- agentops/instrumentation/agentic/agno/instrumentor.py +1313 -0
- agentops/instrumentation/agentic/crewai/LICENSE +201 -0
- agentops/instrumentation/agentic/crewai/NOTICE.md +10 -0
- agentops/instrumentation/agentic/crewai/__init__.py +6 -0
- agentops/instrumentation/agentic/crewai/crewai_span_attributes.py +335 -0
- agentops/instrumentation/agentic/crewai/instrumentation.py +535 -0
- agentops/instrumentation/agentic/crewai/version.py +1 -0
- agentops/instrumentation/agentic/google_adk/__init__.py +19 -0
- agentops/instrumentation/agentic/google_adk/instrumentor.py +68 -0
- agentops/instrumentation/agentic/google_adk/patch.py +767 -0
- agentops/instrumentation/agentic/haystack/__init__.py +1 -0
- agentops/instrumentation/agentic/haystack/instrumentor.py +186 -0
- agentops/instrumentation/agentic/langgraph/__init__.py +3 -0
- agentops/instrumentation/agentic/langgraph/attributes.py +54 -0
- agentops/instrumentation/agentic/langgraph/instrumentation.py +598 -0
- agentops/instrumentation/agentic/langgraph/version.py +1 -0
- agentops/instrumentation/agentic/openai_agents/README.md +156 -0
- agentops/instrumentation/agentic/openai_agents/SPANS.md +145 -0
- agentops/instrumentation/agentic/openai_agents/TRACING_API.md +144 -0
- agentops/instrumentation/agentic/openai_agents/__init__.py +30 -0
- agentops/instrumentation/agentic/openai_agents/attributes/common.py +549 -0
- agentops/instrumentation/agentic/openai_agents/attributes/completion.py +172 -0
- agentops/instrumentation/agentic/openai_agents/attributes/model.py +58 -0
- agentops/instrumentation/agentic/openai_agents/attributes/tokens.py +275 -0
- agentops/instrumentation/agentic/openai_agents/exporter.py +469 -0
- agentops/instrumentation/agentic/openai_agents/instrumentor.py +107 -0
- agentops/instrumentation/agentic/openai_agents/processor.py +58 -0
- agentops/instrumentation/agentic/smolagents/README.md +88 -0
- agentops/instrumentation/agentic/smolagents/__init__.py +12 -0
- agentops/instrumentation/agentic/smolagents/attributes/agent.py +354 -0
- agentops/instrumentation/agentic/smolagents/attributes/model.py +205 -0
- agentops/instrumentation/agentic/smolagents/instrumentor.py +286 -0
- agentops/instrumentation/agentic/smolagents/stream_wrapper.py +258 -0
- agentops/instrumentation/agentic/xpander/__init__.py +15 -0
- agentops/instrumentation/agentic/xpander/context.py +112 -0
- agentops/instrumentation/agentic/xpander/instrumentor.py +877 -0
- agentops/instrumentation/agentic/xpander/trace_probe.py +86 -0
- agentops/instrumentation/agentic/xpander/version.py +3 -0
- agentops/instrumentation/common/README.md +65 -0
- agentops/instrumentation/common/attributes.py +1 -2
- agentops/instrumentation/providers/anthropic/__init__.py +24 -0
- agentops/instrumentation/providers/anthropic/attributes/__init__.py +23 -0
- agentops/instrumentation/providers/anthropic/attributes/common.py +64 -0
- agentops/instrumentation/providers/anthropic/attributes/message.py +541 -0
- agentops/instrumentation/providers/anthropic/attributes/tools.py +231 -0
- agentops/instrumentation/providers/anthropic/event_handler_wrapper.py +90 -0
- agentops/instrumentation/providers/anthropic/instrumentor.py +146 -0
- agentops/instrumentation/providers/anthropic/stream_wrapper.py +436 -0
- agentops/instrumentation/providers/google_genai/README.md +33 -0
- agentops/instrumentation/providers/google_genai/__init__.py +24 -0
- agentops/instrumentation/providers/google_genai/attributes/__init__.py +25 -0
- agentops/instrumentation/providers/google_genai/attributes/chat.py +125 -0
- agentops/instrumentation/providers/google_genai/attributes/common.py +88 -0
- agentops/instrumentation/providers/google_genai/attributes/model.py +284 -0
- agentops/instrumentation/providers/google_genai/instrumentor.py +170 -0
- agentops/instrumentation/providers/google_genai/stream_wrapper.py +238 -0
- agentops/instrumentation/providers/ibm_watsonx_ai/__init__.py +28 -0
- agentops/instrumentation/providers/ibm_watsonx_ai/attributes/__init__.py +27 -0
- agentops/instrumentation/providers/ibm_watsonx_ai/attributes/attributes.py +277 -0
- agentops/instrumentation/providers/ibm_watsonx_ai/attributes/common.py +104 -0
- agentops/instrumentation/providers/ibm_watsonx_ai/instrumentor.py +162 -0
- agentops/instrumentation/providers/ibm_watsonx_ai/stream_wrapper.py +302 -0
- agentops/instrumentation/providers/mem0/__init__.py +45 -0
- agentops/instrumentation/providers/mem0/common.py +377 -0
- agentops/instrumentation/providers/mem0/instrumentor.py +270 -0
- agentops/instrumentation/providers/mem0/memory.py +430 -0
- agentops/instrumentation/providers/openai/__init__.py +21 -0
- agentops/instrumentation/providers/openai/attributes/__init__.py +7 -0
- agentops/instrumentation/providers/openai/attributes/common.py +55 -0
- agentops/instrumentation/providers/openai/attributes/response.py +607 -0
- agentops/instrumentation/providers/openai/config.py +36 -0
- agentops/instrumentation/providers/openai/instrumentor.py +312 -0
- agentops/instrumentation/providers/openai/stream_wrapper.py +941 -0
- agentops/instrumentation/providers/openai/utils.py +44 -0
- agentops/instrumentation/providers/openai/v0.py +176 -0
- agentops/instrumentation/providers/openai/v0_wrappers.py +483 -0
- agentops/instrumentation/providers/openai/wrappers/__init__.py +30 -0
- agentops/instrumentation/providers/openai/wrappers/assistant.py +277 -0
- agentops/instrumentation/providers/openai/wrappers/chat.py +259 -0
- agentops/instrumentation/providers/openai/wrappers/completion.py +109 -0
- agentops/instrumentation/providers/openai/wrappers/embeddings.py +94 -0
- agentops/instrumentation/providers/openai/wrappers/image_gen.py +75 -0
- agentops/instrumentation/providers/openai/wrappers/responses.py +191 -0
- agentops/instrumentation/providers/openai/wrappers/shared.py +81 -0
- agentops/instrumentation/utilities/concurrent_futures/__init__.py +10 -0
- agentops/instrumentation/utilities/concurrent_futures/instrumentation.py +206 -0
- agentops/integration/callbacks/dspy/__init__.py +11 -0
- agentops/integration/callbacks/dspy/callback.py +471 -0
- agentops/integration/callbacks/langchain/README.md +59 -0
- agentops/integration/callbacks/langchain/__init__.py +15 -0
- agentops/integration/callbacks/langchain/callback.py +791 -0
- agentops/integration/callbacks/langchain/utils.py +54 -0
- agentops/legacy/crewai.md +121 -0
- agentops/logging/instrument_logging.py +4 -0
- agentops/sdk/README.md +220 -0
- agentops/sdk/core.py +75 -32
- agentops/sdk/descriptors/classproperty.py +28 -0
- agentops/sdk/exporters.py +152 -33
- agentops/semconv/README.md +125 -0
- agentops/semconv/span_kinds.py +0 -2
- agentops/validation.py +102 -63
- {mseep_agentops-0.4.18.dist-info → mseep_agentops-0.4.23.dist-info}/METADATA +30 -40
- mseep_agentops-0.4.23.dist-info/RECORD +178 -0
- {mseep_agentops-0.4.18.dist-info → mseep_agentops-0.4.23.dist-info}/WHEEL +1 -2
- mseep_agentops-0.4.18.dist-info/RECORD +0 -94
- mseep_agentops-0.4.18.dist-info/top_level.txt +0 -2
- tests/conftest.py +0 -10
- tests/unit/client/__init__.py +0 -1
- tests/unit/client/test_http_adapter.py +0 -221
- tests/unit/client/test_http_client.py +0 -206
- tests/unit/conftest.py +0 -54
- tests/unit/sdk/__init__.py +0 -1
- tests/unit/sdk/instrumentation_tester.py +0 -207
- tests/unit/sdk/test_attributes.py +0 -392
- tests/unit/sdk/test_concurrent_instrumentation.py +0 -468
- tests/unit/sdk/test_decorators.py +0 -763
- tests/unit/sdk/test_exporters.py +0 -241
- tests/unit/sdk/test_factory.py +0 -1188
- tests/unit/sdk/test_internal_span_processor.py +0 -397
- tests/unit/sdk/test_resource_attributes.py +0 -35
- tests/unit/test_config.py +0 -82
- tests/unit/test_context_manager.py +0 -777
- tests/unit/test_events.py +0 -27
- tests/unit/test_host_env.py +0 -54
- tests/unit/test_init_py.py +0 -501
- tests/unit/test_serialization.py +0 -433
- tests/unit/test_session.py +0 -676
- tests/unit/test_user_agent.py +0 -34
- tests/unit/test_validation.py +0 -405
- {tests → agentops/instrumentation/agentic/openai_agents/attributes}/__init__.py +0 -0
- /tests/unit/__init__.py → /agentops/instrumentation/providers/openai/attributes/tools.py +0 -0
- {mseep_agentops-0.4.18.dist-info → mseep_agentops-0.4.23.dist-info}/licenses/LICENSE +0 -0
tests/unit/test_session.py
DELETED
@@ -1,676 +0,0 @@
|
|
1
|
-
import pytest
|
2
|
-
from unittest.mock import patch, MagicMock
|
3
|
-
|
4
|
-
# Tests for the new session management functionality
|
5
|
-
# These tests call the actual public API but mock the underlying implementation
|
6
|
-
# to avoid making real API calls or initializing the full telemetry pipeline
|
7
|
-
|
8
|
-
|
9
|
-
@pytest.fixture(scope="function")
|
10
|
-
def mock_tracing_core():
|
11
|
-
"""Mock the global tracer to avoid actual initialization"""
|
12
|
-
# Patch both the main location and where it's imported in client
|
13
|
-
with (
|
14
|
-
patch("agentops.tracer") as mock_tracer,
|
15
|
-
patch("agentops.client.client.tracer", mock_tracer),
|
16
|
-
patch("agentops.sdk.decorators.factory.tracer", mock_tracer),
|
17
|
-
patch("agentops.legacy.tracer", mock_tracer),
|
18
|
-
):
|
19
|
-
# Create a mock instance
|
20
|
-
mock_tracer.initialized = True
|
21
|
-
|
22
|
-
yield mock_tracer
|
23
|
-
|
24
|
-
|
25
|
-
@pytest.fixture(scope="function")
|
26
|
-
def mock_api_client():
|
27
|
-
"""Mock the API client to avoid actual API calls"""
|
28
|
-
with patch("agentops.client.api.ApiClient") as mock_api:
|
29
|
-
# Configure the v3.fetch_auth_token method to return a valid response
|
30
|
-
mock_v3 = MagicMock()
|
31
|
-
mock_v3.fetch_auth_token.return_value = {"token": "mock-jwt-token", "project_id": "mock-project-id"}
|
32
|
-
mock_api.return_value.v3 = mock_v3
|
33
|
-
|
34
|
-
yield mock_api
|
35
|
-
|
36
|
-
|
37
|
-
@pytest.fixture(scope="function")
|
38
|
-
def mock_trace_context():
|
39
|
-
"""Mock the TraceContext creation"""
|
40
|
-
mock_span = MagicMock()
|
41
|
-
mock_token = MagicMock()
|
42
|
-
mock_trace_context_instance = MagicMock()
|
43
|
-
mock_trace_context_instance.span = mock_span
|
44
|
-
mock_trace_context_instance.token = mock_token
|
45
|
-
mock_trace_context_instance.is_init_trace = False
|
46
|
-
|
47
|
-
return mock_trace_context_instance
|
48
|
-
|
49
|
-
|
50
|
-
@pytest.fixture(scope="function")
|
51
|
-
def reset_client():
|
52
|
-
"""Reset the AgentOps client before each test"""
|
53
|
-
import agentops
|
54
|
-
|
55
|
-
# Create a fresh client instance for each test
|
56
|
-
agentops._client = agentops.Client()
|
57
|
-
# Reset all client state
|
58
|
-
agentops._client._initialized = False
|
59
|
-
agentops._client._init_trace_context = None
|
60
|
-
agentops._client._legacy_session_for_init_trace = None
|
61
|
-
yield
|
62
|
-
# Clean up after test
|
63
|
-
try:
|
64
|
-
if hasattr(agentops._client, "_initialized"):
|
65
|
-
agentops._client._initialized = False
|
66
|
-
if hasattr(agentops._client, "_init_trace_context"):
|
67
|
-
agentops._client._init_trace_context = None
|
68
|
-
if hasattr(agentops._client, "_legacy_session_for_init_trace"):
|
69
|
-
agentops._client._legacy_session_for_init_trace = None
|
70
|
-
except:
|
71
|
-
pass
|
72
|
-
|
73
|
-
|
74
|
-
def test_explicit_init_then_explicit_start_trace(mock_tracing_core, mock_api_client, mock_trace_context, reset_client):
|
75
|
-
"""Test explicitly initializing followed by explicitly starting a trace"""
|
76
|
-
import agentops
|
77
|
-
|
78
|
-
# Explicitly initialize with auto_start_session=False
|
79
|
-
agentops.init(api_key="test-api-key", auto_start_session=False)
|
80
|
-
|
81
|
-
# Verify that no auto-trace was started
|
82
|
-
mock_tracing_core.start_trace.assert_not_called()
|
83
|
-
|
84
|
-
# Mock the start_trace method to return our mock trace context
|
85
|
-
mock_tracing_core.start_trace.return_value = mock_trace_context
|
86
|
-
|
87
|
-
# Explicitly start a trace
|
88
|
-
trace_context = agentops.start_trace(trace_name="test_trace", tags=["test"])
|
89
|
-
|
90
|
-
# Verify the trace was created
|
91
|
-
mock_tracing_core.start_trace.assert_called_once_with(trace_name="test_trace", tags=["test"])
|
92
|
-
assert trace_context == mock_trace_context
|
93
|
-
|
94
|
-
|
95
|
-
def test_auto_start_session_true(mock_tracing_core, mock_api_client, mock_trace_context, reset_client):
|
96
|
-
"""Test initializing with auto_start_session=True"""
|
97
|
-
import agentops
|
98
|
-
from agentops.legacy import Session
|
99
|
-
|
100
|
-
# Mock the start_trace method to return our mock trace context
|
101
|
-
mock_tracing_core.start_trace.return_value = mock_trace_context
|
102
|
-
|
103
|
-
# Initialize with auto_start_session=True
|
104
|
-
result = agentops.init(api_key="test-api-key", auto_start_session=True)
|
105
|
-
|
106
|
-
# Verify a trace was auto-started
|
107
|
-
mock_tracing_core.start_trace.assert_called_once()
|
108
|
-
# init() should return a Session object when auto-starting a session
|
109
|
-
assert isinstance(result, Session)
|
110
|
-
# Check that the session's trace_context has the expected properties
|
111
|
-
assert result.trace_context is not None
|
112
|
-
|
113
|
-
|
114
|
-
def test_auto_start_session_default(mock_tracing_core, mock_api_client, mock_trace_context, reset_client):
|
115
|
-
"""Test initializing with default auto_start_session behavior"""
|
116
|
-
import agentops
|
117
|
-
from agentops.legacy import Session
|
118
|
-
|
119
|
-
# Mock the start_trace method to return our mock trace context
|
120
|
-
mock_tracing_core.start_trace.return_value = mock_trace_context
|
121
|
-
|
122
|
-
# Initialize without explicitly setting auto_start_session (defaults to True)
|
123
|
-
result = agentops.init(api_key="test-api-key")
|
124
|
-
|
125
|
-
# Verify that the client was initialized
|
126
|
-
assert agentops._client.initialized
|
127
|
-
# Since auto_start_session defaults to True, init() should return a Session object
|
128
|
-
assert isinstance(result, Session)
|
129
|
-
# Check that the session's trace_context has the expected properties
|
130
|
-
assert result.trace_context is not None
|
131
|
-
|
132
|
-
|
133
|
-
def test_start_trace_without_init():
|
134
|
-
"""Test starting a trace without initialization triggers auto-init"""
|
135
|
-
import agentops
|
136
|
-
|
137
|
-
# Reset client for test
|
138
|
-
agentops._client = agentops.Client()
|
139
|
-
|
140
|
-
# Mock global tracer to be uninitialized initially, then initialized after init
|
141
|
-
with (
|
142
|
-
patch("agentops.tracer") as mock_tracer,
|
143
|
-
patch("agentops.client.client.tracer", mock_tracer),
|
144
|
-
patch("agentops.sdk.decorators.factory.tracer", mock_tracer),
|
145
|
-
patch("agentops.legacy.tracer", mock_tracer),
|
146
|
-
):
|
147
|
-
mock_tracer.initialized = False
|
148
|
-
|
149
|
-
# Mock the init function to simulate successful initialization
|
150
|
-
with patch("agentops.init") as mock_init:
|
151
|
-
|
152
|
-
def side_effect():
|
153
|
-
# After init is called, mark global tracer as initialized
|
154
|
-
mock_tracer.initialized = True
|
155
|
-
|
156
|
-
mock_init.side_effect = side_effect
|
157
|
-
mock_tracer.start_trace.return_value = None
|
158
|
-
|
159
|
-
# Try to start a trace without initialization
|
160
|
-
result = agentops.start_trace(trace_name="test_trace")
|
161
|
-
|
162
|
-
# Verify that init was called automatically
|
163
|
-
mock_init.assert_called_once()
|
164
|
-
# Should return None since start_trace returned None
|
165
|
-
assert result is None
|
166
|
-
|
167
|
-
|
168
|
-
def test_end_trace(mock_tracing_core, mock_trace_context):
|
169
|
-
"""Test ending a trace"""
|
170
|
-
import agentops
|
171
|
-
|
172
|
-
# End the trace
|
173
|
-
agentops.end_trace(mock_trace_context, end_state="Success")
|
174
|
-
|
175
|
-
# Verify end_trace was called on global tracer
|
176
|
-
mock_tracing_core.end_trace.assert_called_once_with(trace_context=mock_trace_context, end_state="Success")
|
177
|
-
|
178
|
-
|
179
|
-
def test_session_decorator_creates_trace(mock_tracing_core, mock_api_client, mock_trace_context, reset_client):
|
180
|
-
"""Test that the @session decorator creates a trace-level span"""
|
181
|
-
import agentops
|
182
|
-
from agentops.sdk.decorators import session
|
183
|
-
|
184
|
-
# Initialize AgentOps
|
185
|
-
agentops.init(api_key="test-api-key", auto_start_session=False)
|
186
|
-
|
187
|
-
# Reset the call count to start fresh
|
188
|
-
mock_tracing_core.reset_mock()
|
189
|
-
# Mock the start_trace and end_trace methods
|
190
|
-
mock_tracing_core.start_trace.return_value = mock_trace_context
|
191
|
-
|
192
|
-
@session(name="test_session", tags=["decorator_test"])
|
193
|
-
def test_function():
|
194
|
-
return "test_result"
|
195
|
-
|
196
|
-
# Execute the decorated function
|
197
|
-
result = test_function()
|
198
|
-
|
199
|
-
# Verify the function executed successfully
|
200
|
-
assert result == "test_result"
|
201
|
-
|
202
|
-
# Verify that start_trace and end_trace were called
|
203
|
-
# Note: The decorator might call start_trace multiple times due to initialization
|
204
|
-
assert mock_tracing_core.start_trace.call_count >= 1
|
205
|
-
assert mock_tracing_core.end_trace.call_count >= 1
|
206
|
-
|
207
|
-
|
208
|
-
def test_session_decorator_with_exception(mock_tracing_core, mock_api_client, mock_trace_context, reset_client):
|
209
|
-
"""Test that the @session decorator handles exceptions properly"""
|
210
|
-
import agentops
|
211
|
-
from agentops.sdk.decorators import session
|
212
|
-
|
213
|
-
# Initialize AgentOps
|
214
|
-
agentops.init(api_key="test-api-key", auto_start_session=False)
|
215
|
-
|
216
|
-
# Reset the call count to start fresh
|
217
|
-
mock_tracing_core.reset_mock()
|
218
|
-
# Mock the start_trace method
|
219
|
-
mock_tracing_core.start_trace.return_value = mock_trace_context
|
220
|
-
|
221
|
-
@session(name="failing_session")
|
222
|
-
def failing_function():
|
223
|
-
raise ValueError("Test exception")
|
224
|
-
|
225
|
-
# Execute the decorated function and expect an exception
|
226
|
-
with pytest.raises(ValueError, match="Test exception"):
|
227
|
-
failing_function()
|
228
|
-
|
229
|
-
# Verify that start_trace was called
|
230
|
-
assert mock_tracing_core.start_trace.call_count >= 1
|
231
|
-
# Verify that end_trace was called
|
232
|
-
assert mock_tracing_core.end_trace.call_count >= 1
|
233
|
-
|
234
|
-
|
235
|
-
def test_legacy_start_session_compatibility(mock_tracing_core, mock_api_client, mock_trace_context, reset_client):
|
236
|
-
"""Test that legacy start_session still works and calls tracer.start_trace"""
|
237
|
-
import agentops
|
238
|
-
from agentops.legacy import Session
|
239
|
-
|
240
|
-
# Initialize AgentOps
|
241
|
-
agentops.init(api_key="test-api-key", auto_start_session=False)
|
242
|
-
|
243
|
-
# Reset the call count to start fresh
|
244
|
-
mock_tracing_core.reset_mock()
|
245
|
-
# Mock the start_trace method
|
246
|
-
mock_tracing_core.start_trace.return_value = mock_trace_context
|
247
|
-
|
248
|
-
# Start a legacy session
|
249
|
-
session = agentops.start_session(tags=["legacy_test"])
|
250
|
-
|
251
|
-
# Verify the session was created
|
252
|
-
assert isinstance(session, Session)
|
253
|
-
# Check that the session's trace_context has the expected properties
|
254
|
-
assert session.trace_context is not None
|
255
|
-
|
256
|
-
# Verify that tracer.start_trace was called
|
257
|
-
# Note: May be called multiple times due to initialization
|
258
|
-
assert mock_tracing_core.start_trace.call_count >= 1
|
259
|
-
|
260
|
-
|
261
|
-
def test_legacy_end_session_compatibility(mock_tracing_core, mock_api_client, mock_trace_context, reset_client):
|
262
|
-
"""Test that legacy end_session still works and calls tracer.end_trace"""
|
263
|
-
import agentops
|
264
|
-
from agentops.legacy import Session
|
265
|
-
|
266
|
-
# Initialize AgentOps
|
267
|
-
agentops.init(api_key="test-api-key", auto_start_session=False)
|
268
|
-
|
269
|
-
# Reset the call count to start fresh
|
270
|
-
mock_tracing_core.reset_mock()
|
271
|
-
|
272
|
-
# Create a legacy session object
|
273
|
-
session = Session(mock_trace_context)
|
274
|
-
|
275
|
-
# End the session
|
276
|
-
agentops.end_session(session)
|
277
|
-
|
278
|
-
# Verify that tracer.end_trace was called
|
279
|
-
mock_tracing_core.end_trace.assert_called_once_with(mock_trace_context, end_state="Success")
|
280
|
-
|
281
|
-
|
282
|
-
def test_no_double_init(mock_tracing_core, mock_api_client, reset_client):
|
283
|
-
"""Test that calling init multiple times doesn't reinitialize"""
|
284
|
-
import agentops
|
285
|
-
|
286
|
-
# Initialize once
|
287
|
-
agentops.init(api_key="test-api-key", auto_start_session=False)
|
288
|
-
|
289
|
-
# Track the call count
|
290
|
-
call_count = mock_api_client.call_count
|
291
|
-
|
292
|
-
# Call init again with the same API key
|
293
|
-
agentops.init(api_key="test-api-key", auto_start_session=False)
|
294
|
-
|
295
|
-
# Verify that API client wasn't constructed again
|
296
|
-
assert mock_api_client.call_count == call_count
|
297
|
-
|
298
|
-
|
299
|
-
def test_client_initialization_behavior(mock_tracing_core, mock_api_client, mock_trace_context, reset_client):
|
300
|
-
"""Test basic client initialization behavior"""
|
301
|
-
import agentops
|
302
|
-
|
303
|
-
# Mock the start_trace method
|
304
|
-
mock_tracing_core.start_trace.return_value = mock_trace_context
|
305
|
-
|
306
|
-
# Test that initialization works
|
307
|
-
agentops.init(api_key="test-api-key", auto_start_session=False)
|
308
|
-
|
309
|
-
# Verify that the client was initialized
|
310
|
-
assert agentops._client.initialized
|
311
|
-
|
312
|
-
# The API client might not be called if already mocked at a higher level
|
313
|
-
# Just verify that the initialization completed successfully
|
314
|
-
|
315
|
-
# Test that calling init again doesn't cause issues
|
316
|
-
agentops.init(api_key="test-api-key", auto_start_session=False)
|
317
|
-
|
318
|
-
# Should still be initialized
|
319
|
-
assert agentops._client.initialized
|
320
|
-
|
321
|
-
|
322
|
-
def test_multiple_concurrent_traces(mock_tracing_core, mock_api_client, reset_client):
|
323
|
-
"""Test that multiple traces can be started concurrently"""
|
324
|
-
import agentops
|
325
|
-
|
326
|
-
# Initialize AgentOps
|
327
|
-
agentops.init(api_key="test-api-key", auto_start_session=False)
|
328
|
-
|
329
|
-
# Create mock trace contexts for different traces
|
330
|
-
mock_trace_context_1 = MagicMock()
|
331
|
-
mock_trace_context_2 = MagicMock()
|
332
|
-
|
333
|
-
# Mock start_trace to return different contexts
|
334
|
-
mock_tracing_core.start_trace.side_effect = [
|
335
|
-
mock_trace_context_1,
|
336
|
-
mock_trace_context_2,
|
337
|
-
]
|
338
|
-
|
339
|
-
# Start multiple traces
|
340
|
-
trace1 = agentops.start_trace(trace_name="trace1", tags=["test1"])
|
341
|
-
trace2 = agentops.start_trace(trace_name="trace2", tags=["test2"])
|
342
|
-
|
343
|
-
# Verify both traces were created
|
344
|
-
assert trace1 == mock_trace_context_1
|
345
|
-
assert trace2 == mock_trace_context_2
|
346
|
-
|
347
|
-
# Verify start_trace was called twice
|
348
|
-
assert mock_tracing_core.start_trace.call_count == 2
|
349
|
-
|
350
|
-
|
351
|
-
def test_trace_context_properties(mock_trace_context):
|
352
|
-
"""Test that TraceContext properties work correctly"""
|
353
|
-
from agentops.legacy import Session
|
354
|
-
|
355
|
-
# Create a legacy session with the mock trace context
|
356
|
-
session = Session(mock_trace_context)
|
357
|
-
|
358
|
-
# Test that properties are accessible
|
359
|
-
assert session.span == mock_trace_context.span
|
360
|
-
assert session.token == mock_trace_context.token
|
361
|
-
assert session.trace_context == mock_trace_context
|
362
|
-
|
363
|
-
|
364
|
-
def test_session_decorator_async_function(mock_tracing_core, mock_api_client, mock_trace_context, reset_client):
|
365
|
-
"""Test that the @session decorator works with async functions"""
|
366
|
-
import agentops
|
367
|
-
import asyncio
|
368
|
-
from agentops.sdk.decorators import session
|
369
|
-
|
370
|
-
# Initialize AgentOps
|
371
|
-
agentops.init(api_key="test-api-key", auto_start_session=False)
|
372
|
-
|
373
|
-
# Reset the call count to start fresh
|
374
|
-
mock_tracing_core.reset_mock()
|
375
|
-
# Mock the start_trace method
|
376
|
-
mock_tracing_core.start_trace.return_value = mock_trace_context
|
377
|
-
|
378
|
-
@session(name="async_test_session")
|
379
|
-
async def async_test_function():
|
380
|
-
await asyncio.sleep(0.01) # Simulate async work
|
381
|
-
return "async_result"
|
382
|
-
|
383
|
-
# Execute the decorated async function
|
384
|
-
result = asyncio.run(async_test_function())
|
385
|
-
|
386
|
-
# Verify the function executed successfully
|
387
|
-
assert result == "async_result"
|
388
|
-
|
389
|
-
# Verify that start_trace and end_trace were called
|
390
|
-
assert mock_tracing_core.start_trace.call_count >= 1
|
391
|
-
assert mock_tracing_core.end_trace.call_count >= 1
|
392
|
-
|
393
|
-
|
394
|
-
def test_trace_context_creation():
|
395
|
-
"""Test that TraceContext can be created with proper attributes"""
|
396
|
-
from agentops.sdk.core import TraceContext
|
397
|
-
|
398
|
-
mock_span = MagicMock()
|
399
|
-
mock_token = MagicMock()
|
400
|
-
|
401
|
-
# Test creating a TraceContext
|
402
|
-
trace_context = TraceContext(span=mock_span, token=mock_token, is_init_trace=False)
|
403
|
-
|
404
|
-
assert trace_context.span == mock_span
|
405
|
-
assert trace_context.token == mock_token
|
406
|
-
assert trace_context.is_init_trace == False
|
407
|
-
|
408
|
-
|
409
|
-
def test_session_management_integration():
|
410
|
-
"""Test the integration between new and legacy session management"""
|
411
|
-
import agentops
|
412
|
-
|
413
|
-
# Reset client for test
|
414
|
-
agentops._client = agentops.Client()
|
415
|
-
|
416
|
-
# Test that we can use both new and legacy APIs together
|
417
|
-
with (
|
418
|
-
patch("agentops.tracer") as mock_tracer,
|
419
|
-
patch("agentops.client.client.tracer", mock_tracer),
|
420
|
-
patch("agentops.sdk.decorators.factory.tracer", mock_tracer),
|
421
|
-
patch("agentops.legacy.tracer", mock_tracer),
|
422
|
-
):
|
423
|
-
mock_tracer.initialized = True
|
424
|
-
|
425
|
-
# Mock API client
|
426
|
-
with patch("agentops.client.api.ApiClient") as mock_api:
|
427
|
-
mock_v3 = MagicMock()
|
428
|
-
mock_v3.fetch_auth_token.return_value = {"token": "mock-jwt-token", "project_id": "mock-project-id"}
|
429
|
-
mock_api.return_value.v3 = mock_v3
|
430
|
-
|
431
|
-
# Initialize AgentOps
|
432
|
-
agentops.init(api_key="test-api-key", auto_start_session=False)
|
433
|
-
|
434
|
-
# Reset call counts after initialization
|
435
|
-
mock_tracer.reset_mock()
|
436
|
-
|
437
|
-
# Create mock trace context
|
438
|
-
mock_trace_context = MagicMock()
|
439
|
-
mock_tracer.start_trace.return_value = mock_trace_context
|
440
|
-
|
441
|
-
# Test new API
|
442
|
-
trace_context = agentops.start_trace(trace_name="new_api_trace")
|
443
|
-
assert trace_context == mock_trace_context
|
444
|
-
|
445
|
-
# Test legacy API
|
446
|
-
session = agentops.start_session(tags=["legacy"])
|
447
|
-
# Check that the session's trace_context has the expected properties
|
448
|
-
assert session.trace_context is not None
|
449
|
-
|
450
|
-
# Test ending both
|
451
|
-
agentops.end_trace(trace_context)
|
452
|
-
agentops.end_session(session)
|
453
|
-
|
454
|
-
# Verify calls were made
|
455
|
-
assert mock_tracer.start_trace.call_count >= 2
|
456
|
-
assert mock_tracer.end_trace.call_count >= 2
|
457
|
-
|
458
|
-
|
459
|
-
# CrewAI Backwards Compatibility Tests
|
460
|
-
# These tests ensure CrewAI integration patterns continue to work
|
461
|
-
|
462
|
-
|
463
|
-
def test_session_auto_start(mock_tracing_core, mock_api_client, mock_trace_context, reset_client):
|
464
|
-
"""Test auto-start session functionality for CrewAI compatibility"""
|
465
|
-
import agentops
|
466
|
-
from agentops.legacy import Session
|
467
|
-
|
468
|
-
# Configure mocks for session initialization
|
469
|
-
mock_tracing_core.start_trace.return_value = mock_trace_context
|
470
|
-
|
471
|
-
# Pass a dummy API key for the test
|
472
|
-
session = agentops.init(api_key="test-api-key", auto_start_session=True)
|
473
|
-
|
474
|
-
assert isinstance(session, Session)
|
475
|
-
|
476
|
-
|
477
|
-
def test_crewai_backwards_compatibility(mock_tracing_core, mock_api_client, mock_trace_context, reset_client):
|
478
|
-
"""
|
479
|
-
CrewAI needs to access:
|
480
|
-
|
481
|
-
agentops.track_agent
|
482
|
-
agentops.track_tool
|
483
|
-
agentops.start_session
|
484
|
-
agentops.end_session
|
485
|
-
agentops.ActionEvent
|
486
|
-
agentops.ToolEvent
|
487
|
-
"""
|
488
|
-
import agentops
|
489
|
-
from agentops.legacy import Session
|
490
|
-
|
491
|
-
# Configure mocks
|
492
|
-
mock_tracing_core.start_trace.return_value = mock_trace_context
|
493
|
-
|
494
|
-
# Test initialization with API key
|
495
|
-
agentops.init(api_key="test-api-key")
|
496
|
-
|
497
|
-
# Test session management functions
|
498
|
-
session = agentops.start_session(tags=["test", "crewai"])
|
499
|
-
assert isinstance(session, Session)
|
500
|
-
|
501
|
-
# Test that passing a string to end_session doesn't raise an error
|
502
|
-
agentops.end_session("Success") # This pattern is used in CrewAI
|
503
|
-
|
504
|
-
# Test track_agent function exists and doesn't raise errors
|
505
|
-
try:
|
506
|
-
# Mock an agent object similar to what CrewAI would provide
|
507
|
-
class MockAgent:
|
508
|
-
def __init__(self):
|
509
|
-
self.role = "Test Agent"
|
510
|
-
self.goal = "Testing"
|
511
|
-
self.id = "test-agent-id"
|
512
|
-
|
513
|
-
agent = MockAgent()
|
514
|
-
agentops.track_agent(agent)
|
515
|
-
except Exception as e:
|
516
|
-
assert False, f"track_agent raised an exception: {e}"
|
517
|
-
|
518
|
-
# Test track_tool function exists and doesn't raise errors
|
519
|
-
try:
|
520
|
-
# Mock a tool object similar to what CrewAI would provide
|
521
|
-
class MockTool:
|
522
|
-
def __init__(self):
|
523
|
-
self.name = "Test Tool"
|
524
|
-
self.description = "A test tool"
|
525
|
-
|
526
|
-
tool = MockTool()
|
527
|
-
agentops.track_tool(tool, "Test Agent")
|
528
|
-
except Exception as e:
|
529
|
-
assert False, f"track_tool raised an exception: {e}"
|
530
|
-
|
531
|
-
# Test events that CrewAI might use
|
532
|
-
tool_event = agentops.ToolEvent(name="test_tool")
|
533
|
-
action_event = agentops.ActionEvent(action_type="test_action")
|
534
|
-
|
535
|
-
# Verify that record function works with these events
|
536
|
-
agentops.record(tool_event)
|
537
|
-
agentops.record(action_event)
|
538
|
-
|
539
|
-
|
540
|
-
def test_crewai_kwargs_pattern(mock_tracing_core, mock_api_client, mock_trace_context, reset_client):
|
541
|
-
"""
|
542
|
-
Test the CrewAI < 0.105.0 pattern where end_session is called with only kwargs.
|
543
|
-
|
544
|
-
In versions < 0.105.0, CrewAI directly calls:
|
545
|
-
agentops.end_session(
|
546
|
-
end_state="Success",
|
547
|
-
end_state_reason="Finished Execution",
|
548
|
-
is_auto_end=True
|
549
|
-
)
|
550
|
-
"""
|
551
|
-
import agentops
|
552
|
-
from agentops.legacy import Session
|
553
|
-
|
554
|
-
# Configure mocks
|
555
|
-
mock_tracing_core.start_trace.return_value = mock_trace_context
|
556
|
-
|
557
|
-
# Initialize with test API key
|
558
|
-
agentops.init(api_key="test-api-key")
|
559
|
-
|
560
|
-
# Create a session
|
561
|
-
session = agentops.start_session(tags=["test", "crewai-kwargs"])
|
562
|
-
assert isinstance(session, Session)
|
563
|
-
|
564
|
-
# Test the CrewAI < 0.105.0 pattern - calling end_session with only kwargs
|
565
|
-
agentops.end_session(end_state="Success", end_state_reason="Finished Execution", is_auto_end=True)
|
566
|
-
|
567
|
-
# After calling end_session, creating a new session should work correctly
|
568
|
-
# (this implicitly tests that the internal state is reset properly)
|
569
|
-
new_session = agentops.start_session(tags=["test", "post-end"])
|
570
|
-
assert isinstance(new_session, Session)
|
571
|
-
|
572
|
-
|
573
|
-
def test_crewai_kwargs_pattern_no_session(mock_tracing_core, mock_api_client, reset_client):
|
574
|
-
"""
|
575
|
-
Test the CrewAI < 0.105.0 pattern where end_session is called with only kwargs,
|
576
|
-
but no session has been created.
|
577
|
-
|
578
|
-
This should log a warning but not fail.
|
579
|
-
"""
|
580
|
-
import agentops
|
581
|
-
|
582
|
-
# Initialize with test API key
|
583
|
-
agentops.init(api_key="test-api-key")
|
584
|
-
|
585
|
-
# We don't need to explicitly clear the session state
|
586
|
-
# Just make sure we start with a clean state by calling init
|
587
|
-
|
588
|
-
# Test the CrewAI < 0.105.0 pattern - calling end_session with only kwargs
|
589
|
-
# when no session exists. This should not raise an error.
|
590
|
-
agentops.end_session(end_state="Success", end_state_reason="Finished Execution", is_auto_end=True)
|
591
|
-
|
592
|
-
|
593
|
-
def test_crewai_kwargs_force_flush(mock_tracing_core, mock_api_client, mock_trace_context, reset_client):
|
594
|
-
"""
|
595
|
-
Test that when using the CrewAI < 0.105.0 pattern (end_session with kwargs),
|
596
|
-
the spans are properly exported to the backend with force_flush.
|
597
|
-
|
598
|
-
This is a more comprehensive test that ensures spans are actually sent
|
599
|
-
to the backend when using the CrewAI integration pattern.
|
600
|
-
"""
|
601
|
-
import agentops
|
602
|
-
import time
|
603
|
-
|
604
|
-
# Configure mocks
|
605
|
-
mock_tracing_core.start_trace.return_value = mock_trace_context
|
606
|
-
|
607
|
-
# Initialize AgentOps with API key
|
608
|
-
agentops.init(api_key="test-api-key")
|
609
|
-
|
610
|
-
# Create a session
|
611
|
-
agentops.start_session(tags=["test", "crewai-integration"])
|
612
|
-
|
613
|
-
# Simulate some work
|
614
|
-
time.sleep(0.1)
|
615
|
-
|
616
|
-
# End session with kwargs (CrewAI < 0.105.0 pattern)
|
617
|
-
agentops.end_session(end_state="Success", end_state_reason="Test Finished", is_auto_end=True)
|
618
|
-
|
619
|
-
# Explicitly ensure the core isn't already shut down for the test
|
620
|
-
# Note: We're using mocks, so we check the mock's initialized state
|
621
|
-
assert mock_tracing_core.initialized, "Mocked tracer should still be initialized"
|
622
|
-
|
623
|
-
|
624
|
-
def test_crewai_task_instrumentation(mock_tracing_core, mock_api_client, mock_trace_context, reset_client):
|
625
|
-
"""
|
626
|
-
Test the CrewAI task instrumentation focusing on span attributes and tags.
|
627
|
-
This test verifies that task spans are properly created with correct attributes
|
628
|
-
and tags without requiring a session.
|
629
|
-
"""
|
630
|
-
import agentops
|
631
|
-
from opentelemetry.trace import SpanKind
|
632
|
-
from agentops.semconv import SpanAttributes, AgentOpsSpanKindValues
|
633
|
-
from opentelemetry import trace
|
634
|
-
from agentops.semconv.core import CoreAttributes
|
635
|
-
|
636
|
-
# Configure mocks
|
637
|
-
mock_tracing_core.start_trace.return_value = mock_trace_context
|
638
|
-
|
639
|
-
# Initialize AgentOps with API key and default tags
|
640
|
-
agentops.init(
|
641
|
-
api_key="test-api-key",
|
642
|
-
)
|
643
|
-
agentops.start_session(tags=["test", "crewai-integration"])
|
644
|
-
# Get the tracer
|
645
|
-
tracer = trace.get_tracer(__name__)
|
646
|
-
|
647
|
-
# Create a mock task instance
|
648
|
-
class MockTask:
|
649
|
-
def __init__(self):
|
650
|
-
self.description = "Test Task Description"
|
651
|
-
self.agent = "Test Agent"
|
652
|
-
self.tools = ["tool1", "tool2"]
|
653
|
-
|
654
|
-
task = MockTask()
|
655
|
-
|
656
|
-
# Start a span for the task
|
657
|
-
with tracer.start_as_current_span(
|
658
|
-
f"{task.description}.task",
|
659
|
-
kind=SpanKind.CLIENT,
|
660
|
-
attributes={
|
661
|
-
SpanAttributes.AGENTOPS_SPAN_KIND: AgentOpsSpanKindValues.TASK.value,
|
662
|
-
CoreAttributes.TAGS: ["crewai", "task-test"],
|
663
|
-
},
|
664
|
-
) as span:
|
665
|
-
# Verify span attributes
|
666
|
-
assert span.attributes[SpanAttributes.AGENTOPS_SPAN_KIND] == AgentOpsSpanKindValues.TASK.value
|
667
|
-
assert "crewai" in span.attributes[CoreAttributes.TAGS]
|
668
|
-
assert "task-test" in span.attributes[CoreAttributes.TAGS]
|
669
|
-
|
670
|
-
# Verify span name
|
671
|
-
assert span.name == f"{task.description}.task"
|
672
|
-
|
673
|
-
# Verify span kind
|
674
|
-
assert span.kind == SpanKind.CLIENT
|
675
|
-
|
676
|
-
agentops.end_session(end_state="Success", end_state_reason="Test Finished", is_auto_end=True)
|