mseep-agentops 0.4.18__py3-none-any.whl → 0.4.22__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.
Files changed (153) hide show
  1. agentops/__init__.py +0 -0
  2. agentops/client/api/base.py +28 -30
  3. agentops/client/api/versions/v3.py +29 -25
  4. agentops/client/api/versions/v4.py +87 -46
  5. agentops/client/client.py +98 -29
  6. agentops/client/http/README.md +87 -0
  7. agentops/client/http/http_client.py +126 -172
  8. agentops/config.py +8 -2
  9. agentops/instrumentation/OpenTelemetry.md +133 -0
  10. agentops/instrumentation/README.md +167 -0
  11. agentops/instrumentation/__init__.py +13 -1
  12. agentops/instrumentation/agentic/ag2/__init__.py +18 -0
  13. agentops/instrumentation/agentic/ag2/instrumentor.py +922 -0
  14. agentops/instrumentation/agentic/agno/__init__.py +19 -0
  15. agentops/instrumentation/agentic/agno/attributes/__init__.py +20 -0
  16. agentops/instrumentation/agentic/agno/attributes/agent.py +250 -0
  17. agentops/instrumentation/agentic/agno/attributes/metrics.py +214 -0
  18. agentops/instrumentation/agentic/agno/attributes/storage.py +158 -0
  19. agentops/instrumentation/agentic/agno/attributes/team.py +195 -0
  20. agentops/instrumentation/agentic/agno/attributes/tool.py +210 -0
  21. agentops/instrumentation/agentic/agno/attributes/workflow.py +254 -0
  22. agentops/instrumentation/agentic/agno/instrumentor.py +1313 -0
  23. agentops/instrumentation/agentic/crewai/LICENSE +201 -0
  24. agentops/instrumentation/agentic/crewai/NOTICE.md +10 -0
  25. agentops/instrumentation/agentic/crewai/__init__.py +6 -0
  26. agentops/instrumentation/agentic/crewai/crewai_span_attributes.py +335 -0
  27. agentops/instrumentation/agentic/crewai/instrumentation.py +535 -0
  28. agentops/instrumentation/agentic/crewai/version.py +1 -0
  29. agentops/instrumentation/agentic/google_adk/__init__.py +19 -0
  30. agentops/instrumentation/agentic/google_adk/instrumentor.py +68 -0
  31. agentops/instrumentation/agentic/google_adk/patch.py +767 -0
  32. agentops/instrumentation/agentic/haystack/__init__.py +1 -0
  33. agentops/instrumentation/agentic/haystack/instrumentor.py +186 -0
  34. agentops/instrumentation/agentic/langgraph/__init__.py +3 -0
  35. agentops/instrumentation/agentic/langgraph/attributes.py +54 -0
  36. agentops/instrumentation/agentic/langgraph/instrumentation.py +598 -0
  37. agentops/instrumentation/agentic/langgraph/version.py +1 -0
  38. agentops/instrumentation/agentic/openai_agents/README.md +156 -0
  39. agentops/instrumentation/agentic/openai_agents/SPANS.md +145 -0
  40. agentops/instrumentation/agentic/openai_agents/TRACING_API.md +144 -0
  41. agentops/instrumentation/agentic/openai_agents/__init__.py +30 -0
  42. agentops/instrumentation/agentic/openai_agents/attributes/common.py +549 -0
  43. agentops/instrumentation/agentic/openai_agents/attributes/completion.py +172 -0
  44. agentops/instrumentation/agentic/openai_agents/attributes/model.py +58 -0
  45. agentops/instrumentation/agentic/openai_agents/attributes/tokens.py +275 -0
  46. agentops/instrumentation/agentic/openai_agents/exporter.py +469 -0
  47. agentops/instrumentation/agentic/openai_agents/instrumentor.py +107 -0
  48. agentops/instrumentation/agentic/openai_agents/processor.py +58 -0
  49. agentops/instrumentation/agentic/smolagents/README.md +88 -0
  50. agentops/instrumentation/agentic/smolagents/__init__.py +12 -0
  51. agentops/instrumentation/agentic/smolagents/attributes/agent.py +354 -0
  52. agentops/instrumentation/agentic/smolagents/attributes/model.py +205 -0
  53. agentops/instrumentation/agentic/smolagents/instrumentor.py +286 -0
  54. agentops/instrumentation/agentic/smolagents/stream_wrapper.py +258 -0
  55. agentops/instrumentation/agentic/xpander/__init__.py +15 -0
  56. agentops/instrumentation/agentic/xpander/context.py +112 -0
  57. agentops/instrumentation/agentic/xpander/instrumentor.py +877 -0
  58. agentops/instrumentation/agentic/xpander/trace_probe.py +86 -0
  59. agentops/instrumentation/agentic/xpander/version.py +3 -0
  60. agentops/instrumentation/common/README.md +65 -0
  61. agentops/instrumentation/common/attributes.py +1 -2
  62. agentops/instrumentation/providers/anthropic/__init__.py +24 -0
  63. agentops/instrumentation/providers/anthropic/attributes/__init__.py +23 -0
  64. agentops/instrumentation/providers/anthropic/attributes/common.py +64 -0
  65. agentops/instrumentation/providers/anthropic/attributes/message.py +541 -0
  66. agentops/instrumentation/providers/anthropic/attributes/tools.py +231 -0
  67. agentops/instrumentation/providers/anthropic/event_handler_wrapper.py +90 -0
  68. agentops/instrumentation/providers/anthropic/instrumentor.py +146 -0
  69. agentops/instrumentation/providers/anthropic/stream_wrapper.py +436 -0
  70. agentops/instrumentation/providers/google_genai/README.md +33 -0
  71. agentops/instrumentation/providers/google_genai/__init__.py +24 -0
  72. agentops/instrumentation/providers/google_genai/attributes/__init__.py +25 -0
  73. agentops/instrumentation/providers/google_genai/attributes/chat.py +125 -0
  74. agentops/instrumentation/providers/google_genai/attributes/common.py +88 -0
  75. agentops/instrumentation/providers/google_genai/attributes/model.py +284 -0
  76. agentops/instrumentation/providers/google_genai/instrumentor.py +170 -0
  77. agentops/instrumentation/providers/google_genai/stream_wrapper.py +238 -0
  78. agentops/instrumentation/providers/ibm_watsonx_ai/__init__.py +28 -0
  79. agentops/instrumentation/providers/ibm_watsonx_ai/attributes/__init__.py +27 -0
  80. agentops/instrumentation/providers/ibm_watsonx_ai/attributes/attributes.py +277 -0
  81. agentops/instrumentation/providers/ibm_watsonx_ai/attributes/common.py +104 -0
  82. agentops/instrumentation/providers/ibm_watsonx_ai/instrumentor.py +162 -0
  83. agentops/instrumentation/providers/ibm_watsonx_ai/stream_wrapper.py +302 -0
  84. agentops/instrumentation/providers/mem0/__init__.py +45 -0
  85. agentops/instrumentation/providers/mem0/common.py +377 -0
  86. agentops/instrumentation/providers/mem0/instrumentor.py +270 -0
  87. agentops/instrumentation/providers/mem0/memory.py +430 -0
  88. agentops/instrumentation/providers/openai/__init__.py +21 -0
  89. agentops/instrumentation/providers/openai/attributes/__init__.py +7 -0
  90. agentops/instrumentation/providers/openai/attributes/common.py +55 -0
  91. agentops/instrumentation/providers/openai/attributes/response.py +607 -0
  92. agentops/instrumentation/providers/openai/config.py +36 -0
  93. agentops/instrumentation/providers/openai/instrumentor.py +312 -0
  94. agentops/instrumentation/providers/openai/stream_wrapper.py +941 -0
  95. agentops/instrumentation/providers/openai/utils.py +44 -0
  96. agentops/instrumentation/providers/openai/v0.py +176 -0
  97. agentops/instrumentation/providers/openai/v0_wrappers.py +483 -0
  98. agentops/instrumentation/providers/openai/wrappers/__init__.py +30 -0
  99. agentops/instrumentation/providers/openai/wrappers/assistant.py +277 -0
  100. agentops/instrumentation/providers/openai/wrappers/chat.py +259 -0
  101. agentops/instrumentation/providers/openai/wrappers/completion.py +109 -0
  102. agentops/instrumentation/providers/openai/wrappers/embeddings.py +94 -0
  103. agentops/instrumentation/providers/openai/wrappers/image_gen.py +75 -0
  104. agentops/instrumentation/providers/openai/wrappers/responses.py +191 -0
  105. agentops/instrumentation/providers/openai/wrappers/shared.py +81 -0
  106. agentops/instrumentation/utilities/concurrent_futures/__init__.py +10 -0
  107. agentops/instrumentation/utilities/concurrent_futures/instrumentation.py +206 -0
  108. agentops/integration/callbacks/dspy/__init__.py +11 -0
  109. agentops/integration/callbacks/dspy/callback.py +471 -0
  110. agentops/integration/callbacks/langchain/README.md +59 -0
  111. agentops/integration/callbacks/langchain/__init__.py +15 -0
  112. agentops/integration/callbacks/langchain/callback.py +791 -0
  113. agentops/integration/callbacks/langchain/utils.py +54 -0
  114. agentops/legacy/crewai.md +121 -0
  115. agentops/logging/instrument_logging.py +4 -0
  116. agentops/sdk/README.md +220 -0
  117. agentops/sdk/core.py +75 -32
  118. agentops/sdk/descriptors/classproperty.py +28 -0
  119. agentops/sdk/exporters.py +152 -33
  120. agentops/semconv/README.md +125 -0
  121. agentops/semconv/span_kinds.py +0 -2
  122. agentops/validation.py +102 -63
  123. {mseep_agentops-0.4.18.dist-info → mseep_agentops-0.4.22.dist-info}/METADATA +30 -40
  124. mseep_agentops-0.4.22.dist-info/RECORD +178 -0
  125. {mseep_agentops-0.4.18.dist-info → mseep_agentops-0.4.22.dist-info}/WHEEL +1 -2
  126. mseep_agentops-0.4.18.dist-info/RECORD +0 -94
  127. mseep_agentops-0.4.18.dist-info/top_level.txt +0 -2
  128. tests/conftest.py +0 -10
  129. tests/unit/client/__init__.py +0 -1
  130. tests/unit/client/test_http_adapter.py +0 -221
  131. tests/unit/client/test_http_client.py +0 -206
  132. tests/unit/conftest.py +0 -54
  133. tests/unit/sdk/__init__.py +0 -1
  134. tests/unit/sdk/instrumentation_tester.py +0 -207
  135. tests/unit/sdk/test_attributes.py +0 -392
  136. tests/unit/sdk/test_concurrent_instrumentation.py +0 -468
  137. tests/unit/sdk/test_decorators.py +0 -763
  138. tests/unit/sdk/test_exporters.py +0 -241
  139. tests/unit/sdk/test_factory.py +0 -1188
  140. tests/unit/sdk/test_internal_span_processor.py +0 -397
  141. tests/unit/sdk/test_resource_attributes.py +0 -35
  142. tests/unit/test_config.py +0 -82
  143. tests/unit/test_context_manager.py +0 -777
  144. tests/unit/test_events.py +0 -27
  145. tests/unit/test_host_env.py +0 -54
  146. tests/unit/test_init_py.py +0 -501
  147. tests/unit/test_serialization.py +0 -433
  148. tests/unit/test_session.py +0 -676
  149. tests/unit/test_user_agent.py +0 -34
  150. tests/unit/test_validation.py +0 -405
  151. {tests → agentops/instrumentation/agentic/openai_agents/attributes}/__init__.py +0 -0
  152. /tests/unit/__init__.py → /agentops/instrumentation/providers/openai/attributes/tools.py +0 -0
  153. {mseep_agentops-0.4.18.dist-info → mseep_agentops-0.4.22.dist-info}/licenses/LICENSE +0 -0
@@ -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)