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.
Files changed (94) hide show
  1. agentops/__init__.py +488 -0
  2. agentops/client/__init__.py +5 -0
  3. agentops/client/api/__init__.py +71 -0
  4. agentops/client/api/base.py +162 -0
  5. agentops/client/api/types.py +21 -0
  6. agentops/client/api/versions/__init__.py +10 -0
  7. agentops/client/api/versions/v3.py +65 -0
  8. agentops/client/api/versions/v4.py +104 -0
  9. agentops/client/client.py +211 -0
  10. agentops/client/http/__init__.py +0 -0
  11. agentops/client/http/http_adapter.py +116 -0
  12. agentops/client/http/http_client.py +215 -0
  13. agentops/config.py +268 -0
  14. agentops/enums.py +36 -0
  15. agentops/exceptions.py +38 -0
  16. agentops/helpers/__init__.py +44 -0
  17. agentops/helpers/dashboard.py +54 -0
  18. agentops/helpers/deprecation.py +50 -0
  19. agentops/helpers/env.py +52 -0
  20. agentops/helpers/serialization.py +137 -0
  21. agentops/helpers/system.py +178 -0
  22. agentops/helpers/time.py +11 -0
  23. agentops/helpers/version.py +36 -0
  24. agentops/instrumentation/__init__.py +598 -0
  25. agentops/instrumentation/common/__init__.py +82 -0
  26. agentops/instrumentation/common/attributes.py +278 -0
  27. agentops/instrumentation/common/instrumentor.py +147 -0
  28. agentops/instrumentation/common/metrics.py +100 -0
  29. agentops/instrumentation/common/objects.py +26 -0
  30. agentops/instrumentation/common/span_management.py +176 -0
  31. agentops/instrumentation/common/streaming.py +218 -0
  32. agentops/instrumentation/common/token_counting.py +177 -0
  33. agentops/instrumentation/common/version.py +71 -0
  34. agentops/instrumentation/common/wrappers.py +235 -0
  35. agentops/legacy/__init__.py +277 -0
  36. agentops/legacy/event.py +156 -0
  37. agentops/logging/__init__.py +4 -0
  38. agentops/logging/config.py +86 -0
  39. agentops/logging/formatters.py +34 -0
  40. agentops/logging/instrument_logging.py +91 -0
  41. agentops/sdk/__init__.py +27 -0
  42. agentops/sdk/attributes.py +151 -0
  43. agentops/sdk/core.py +607 -0
  44. agentops/sdk/decorators/__init__.py +51 -0
  45. agentops/sdk/decorators/factory.py +486 -0
  46. agentops/sdk/decorators/utility.py +216 -0
  47. agentops/sdk/exporters.py +87 -0
  48. agentops/sdk/processors.py +71 -0
  49. agentops/sdk/types.py +21 -0
  50. agentops/semconv/__init__.py +36 -0
  51. agentops/semconv/agent.py +29 -0
  52. agentops/semconv/core.py +19 -0
  53. agentops/semconv/enum.py +11 -0
  54. agentops/semconv/instrumentation.py +13 -0
  55. agentops/semconv/langchain.py +63 -0
  56. agentops/semconv/message.py +61 -0
  57. agentops/semconv/meters.py +24 -0
  58. agentops/semconv/resource.py +52 -0
  59. agentops/semconv/span_attributes.py +118 -0
  60. agentops/semconv/span_kinds.py +50 -0
  61. agentops/semconv/status.py +11 -0
  62. agentops/semconv/tool.py +15 -0
  63. agentops/semconv/workflow.py +69 -0
  64. agentops/validation.py +357 -0
  65. mseep_agentops-0.4.18.dist-info/METADATA +49 -0
  66. mseep_agentops-0.4.18.dist-info/RECORD +94 -0
  67. mseep_agentops-0.4.18.dist-info/WHEEL +5 -0
  68. mseep_agentops-0.4.18.dist-info/licenses/LICENSE +21 -0
  69. mseep_agentops-0.4.18.dist-info/top_level.txt +2 -0
  70. tests/__init__.py +0 -0
  71. tests/conftest.py +10 -0
  72. tests/unit/__init__.py +0 -0
  73. tests/unit/client/__init__.py +1 -0
  74. tests/unit/client/test_http_adapter.py +221 -0
  75. tests/unit/client/test_http_client.py +206 -0
  76. tests/unit/conftest.py +54 -0
  77. tests/unit/sdk/__init__.py +1 -0
  78. tests/unit/sdk/instrumentation_tester.py +207 -0
  79. tests/unit/sdk/test_attributes.py +392 -0
  80. tests/unit/sdk/test_concurrent_instrumentation.py +468 -0
  81. tests/unit/sdk/test_decorators.py +763 -0
  82. tests/unit/sdk/test_exporters.py +241 -0
  83. tests/unit/sdk/test_factory.py +1188 -0
  84. tests/unit/sdk/test_internal_span_processor.py +397 -0
  85. tests/unit/sdk/test_resource_attributes.py +35 -0
  86. tests/unit/test_config.py +82 -0
  87. tests/unit/test_context_manager.py +777 -0
  88. tests/unit/test_events.py +27 -0
  89. tests/unit/test_host_env.py +54 -0
  90. tests/unit/test_init_py.py +501 -0
  91. tests/unit/test_serialization.py +433 -0
  92. tests/unit/test_session.py +676 -0
  93. tests/unit/test_user_agent.py +34 -0
  94. tests/unit/test_validation.py +405 -0
agentops/__init__.py ADDED
@@ -0,0 +1,488 @@
1
+ # For backwards compatibility
2
+ from agentops.legacy import (
3
+ start_session,
4
+ end_session,
5
+ track_agent,
6
+ track_tool,
7
+ end_all_sessions,
8
+ Session,
9
+ ToolEvent,
10
+ ErrorEvent,
11
+ ActionEvent,
12
+ LLMEvent,
13
+ ) # type: ignore
14
+
15
+ # Import all required modules at the top
16
+ from opentelemetry.trace import get_current_span
17
+ from agentops.semconv import (
18
+ AgentAttributes,
19
+ ToolAttributes,
20
+ WorkflowAttributes,
21
+ CoreAttributes,
22
+ SpanKind,
23
+ SpanAttributes,
24
+ )
25
+ import json
26
+ from typing import List, Optional, Union, Dict, Any
27
+ from agentops.client import Client
28
+ from agentops.sdk.core import TraceContext, tracer
29
+ from agentops.sdk.decorators import trace, session, agent, task, workflow, operation, tool, guardrail, track_endpoint
30
+ from agentops.enums import TraceState, SUCCESS, ERROR, UNSET
31
+ from opentelemetry.trace.status import StatusCode
32
+
33
+ from agentops.logging.config import logger
34
+ from agentops.helpers.deprecation import deprecated, warn_deprecated_param
35
+ import threading
36
+
37
+ # Import validation functions
38
+ from agentops.validation import validate_trace_spans, print_validation_summary, ValidationError
39
+
40
+ # Thread-safe client management
41
+ _client_lock = threading.Lock()
42
+ _client = None
43
+
44
+
45
+ def get_client() -> Client:
46
+ """Get the singleton client instance in a thread-safe manner"""
47
+ global _client
48
+
49
+ # Double-checked locking pattern for thread safety
50
+ if _client is None:
51
+ with _client_lock:
52
+ if _client is None:
53
+ _client = Client()
54
+
55
+ return _client
56
+
57
+
58
+ @deprecated("Automatically tracked in v4.")
59
+ def record(event):
60
+ """
61
+ Legacy function to record an event. This is kept for backward compatibility.
62
+
63
+ In the current version, this simply sets the end_timestamp on the event.
64
+
65
+ Args:
66
+ event: The event to record
67
+ """
68
+ from agentops.helpers.time import get_ISO_time
69
+
70
+ # TODO: Manual timestamp assignment is a temporary fix; should use proper event lifecycle
71
+ if event and hasattr(event, "end_timestamp"):
72
+ event.end_timestamp = get_ISO_time()
73
+
74
+ return event
75
+
76
+
77
+ def init(
78
+ api_key: Optional[str] = None,
79
+ endpoint: Optional[str] = None,
80
+ app_url: Optional[str] = None,
81
+ max_wait_time: Optional[int] = None,
82
+ max_queue_size: Optional[int] = None,
83
+ tags: Optional[List[str]] = None,
84
+ default_tags: Optional[List[str]] = None,
85
+ trace_name: Optional[str] = None,
86
+ instrument_llm_calls: Optional[bool] = None,
87
+ auto_start_session: Optional[bool] = None,
88
+ auto_init: Optional[bool] = None,
89
+ skip_auto_end_session: Optional[bool] = None,
90
+ env_data_opt_out: Optional[bool] = None,
91
+ log_level: Optional[Union[str, int]] = None,
92
+ fail_safe: Optional[bool] = None,
93
+ log_session_replay_url: Optional[bool] = None,
94
+ exporter_endpoint: Optional[str] = None,
95
+ **kwargs,
96
+ ):
97
+ """
98
+ Initializes the AgentOps SDK.
99
+
100
+ Args:
101
+ api_key (str, optional): API Key for AgentOps services. If none is provided, key will
102
+ be read from the AGENTOPS_API_KEY environment variable.
103
+ endpoint (str, optional): The endpoint for the AgentOps service. If none is provided, key will
104
+ be read from the AGENTOPS_API_ENDPOINT environment variable. Defaults to 'https://api.agentops.ai'.
105
+ app_url (str, optional): The dashboard URL for the AgentOps app. If none is provided, key will
106
+ be read from the AGENTOPS_APP_URL environment variable. Defaults to 'https://app.agentops.ai'.
107
+ max_wait_time (int, optional): The maximum time to wait in milliseconds before flushing the queue.
108
+ Defaults to 5,000 (5 seconds)
109
+ max_queue_size (int, optional): The maximum size of the event queue. Defaults to 512.
110
+ tags (List[str], optional): [Deprecated] Use `default_tags` instead.
111
+ default_tags (List[str], optional): Default tags for the sessions that can be used for grouping or sorting later (e.g. ["GPT-4"]).
112
+ trace_name (str, optional): Name for the default trace/session. If none is provided, defaults to "default".
113
+ instrument_llm_calls (bool): Whether to instrument LLM calls and emit LLMEvents.
114
+ auto_start_session (bool): Whether to start a session automatically when the client is created.
115
+ auto_init (bool): Whether to automatically initialize the client on import. Defaults to True.
116
+ skip_auto_end_session (optional, bool): Don't automatically end session based on your framework's decision-making
117
+ (i.e. Crew determining when tasks are complete and ending the session)
118
+ env_data_opt_out (bool): Whether to opt out of collecting environment data.
119
+ log_level (str, int): The log level to use for the client. Defaults to 'CRITICAL'.
120
+ fail_safe (bool): Whether to suppress errors and continue execution when possible.
121
+ log_session_replay_url (bool): Whether to log session replay URLs to the console. Defaults to True.
122
+ exporter_endpoint (str, optional): Endpoint for the exporter. If none is provided, key will
123
+ be read from the AGENTOPS_EXPORTER_ENDPOINT environment variable.
124
+ **kwargs: Additional configuration parameters to be passed to the client.
125
+ """
126
+ global _client
127
+
128
+ # Check for deprecated parameters and emit warnings
129
+ if tags is not None:
130
+ warn_deprecated_param("tags", "default_tags")
131
+
132
+ # Merge tags and default_tags if both are provided
133
+ merged_tags = None
134
+ if tags and default_tags:
135
+ merged_tags = list(set(tags + default_tags))
136
+ elif tags:
137
+ merged_tags = tags
138
+ elif default_tags:
139
+ merged_tags = default_tags
140
+
141
+ # Check if in a Jupyter Notebook (manual start/end_trace())
142
+ try:
143
+ get_ipython().__class__.__name__ == "ZMQInteractiveShell" # type: ignore
144
+ auto_start_session = False
145
+ except NameError:
146
+ pass
147
+
148
+ # Prepare initialization arguments
149
+ init_kwargs = {
150
+ "api_key": api_key,
151
+ "endpoint": endpoint,
152
+ "app_url": app_url,
153
+ "max_wait_time": max_wait_time,
154
+ "max_queue_size": max_queue_size,
155
+ "default_tags": merged_tags,
156
+ "trace_name": trace_name,
157
+ "instrument_llm_calls": instrument_llm_calls,
158
+ "auto_start_session": auto_start_session,
159
+ "auto_init": auto_init,
160
+ "skip_auto_end_session": skip_auto_end_session,
161
+ "env_data_opt_out": env_data_opt_out,
162
+ "log_level": log_level,
163
+ "fail_safe": fail_safe,
164
+ "log_session_replay_url": log_session_replay_url,
165
+ "exporter_endpoint": exporter_endpoint,
166
+ **kwargs,
167
+ }
168
+
169
+ # Get the current client instance (creates new one if needed)
170
+ client = get_client()
171
+
172
+ # Initialize the client directly
173
+ return client.init(**init_kwargs)
174
+
175
+
176
+ def configure(**kwargs):
177
+ """Update client configuration
178
+
179
+ Args:
180
+ **kwargs: Configuration parameters. Supported parameters include:
181
+ - api_key: API Key for AgentOps services
182
+ - endpoint: The endpoint for the AgentOps service
183
+ - app_url: The dashboard URL for the AgentOps app
184
+ - max_wait_time: Maximum time to wait in milliseconds before flushing the queue
185
+ - max_queue_size: Maximum size of the event queue
186
+ - default_tags: Default tags for the sessions
187
+ - instrument_llm_calls: Whether to instrument LLM calls
188
+ - auto_start_session: Whether to start a session automatically
189
+ - skip_auto_end_session: Don't automatically end session
190
+ - env_data_opt_out: Whether to opt out of collecting environment data
191
+ - log_level: The log level to use for the client
192
+ - fail_safe: Whether to suppress errors and continue execution
193
+ - exporter: Custom span exporter for OpenTelemetry trace data
194
+ - processor: Custom span processor for OpenTelemetry trace data
195
+ - exporter_endpoint: Endpoint for the exporter
196
+ """
197
+ global _client
198
+
199
+ # List of valid parameters that can be passed to configure
200
+ valid_params = {
201
+ "api_key",
202
+ "endpoint",
203
+ "app_url",
204
+ "max_wait_time",
205
+ "max_queue_size",
206
+ "default_tags",
207
+ "instrument_llm_calls",
208
+ "auto_start_session",
209
+ "skip_auto_end_session",
210
+ "env_data_opt_out",
211
+ "log_level",
212
+ "fail_safe",
213
+ "exporter",
214
+ "processor",
215
+ "exporter_endpoint",
216
+ }
217
+
218
+ # Check for invalid parameters
219
+ invalid_params = set(kwargs.keys()) - valid_params
220
+ if invalid_params:
221
+ logger.warning(f"Invalid configuration parameters: {invalid_params}")
222
+
223
+ client = get_client()
224
+ client.configure(**kwargs)
225
+
226
+
227
+ def start_trace(
228
+ trace_name: str = "session", tags: Optional[Union[Dict[str, Any], List[str]]] = None
229
+ ) -> Optional[TraceContext]:
230
+ """
231
+ Starts a new trace (root span) and returns its context.
232
+ This allows for multiple concurrent, user-managed traces.
233
+
234
+ Args:
235
+ trace_name: Name for the trace (e.g., "session", "my_custom_task").
236
+ tags: Optional tags to attach to the trace span (list of strings or dict).
237
+
238
+ Returns:
239
+ A TraceContext object containing the span and context token, or None if SDK not initialized.
240
+ """
241
+ if not tracer.initialized:
242
+ # Optionally, attempt to initialize the client if not already, or log a more severe warning.
243
+ # For now, align with legacy start_session that would try to init.
244
+ # However, explicit init is preferred before starting traces.
245
+ logger.warning("AgentOps SDK not initialized. Attempting to initialize with defaults before starting trace.")
246
+ try:
247
+ init() # Attempt to initialize with environment variables / defaults
248
+ if not tracer.initialized:
249
+ logger.error("SDK initialization failed. Cannot start trace.")
250
+ return None
251
+ except Exception as e:
252
+ logger.error(f"SDK auto-initialization failed during start_trace: {e}. Cannot start trace.")
253
+ return None
254
+
255
+ return tracer.start_trace(trace_name=trace_name, tags=tags)
256
+
257
+
258
+ def end_trace(
259
+ trace_context: Optional[TraceContext] = None, end_state: Union[TraceState, StatusCode, str] = TraceState.SUCCESS
260
+ ) -> None:
261
+ """
262
+ Ends a trace (its root span) and finalizes it.
263
+ If no trace_context is provided, ends all active session spans.
264
+
265
+ Args:
266
+ trace_context: The TraceContext object returned by start_trace. If None, ends all active traces.
267
+ end_state: The final state of the trace (e.g., "Success", "Indeterminate", "Error").
268
+ """
269
+ if not tracer.initialized:
270
+ logger.warning("AgentOps SDK not initialized. Cannot end trace.")
271
+ return
272
+ tracer.end_trace(trace_context=trace_context, end_state=end_state)
273
+
274
+
275
+ def update_trace_metadata(metadata: Dict[str, Any], prefix: str = "trace.metadata") -> bool:
276
+ """
277
+ Update metadata on the current running trace.
278
+
279
+ Args:
280
+ metadata: Dictionary of key-value pairs to set as trace metadata.
281
+ Values must be strings, numbers, booleans, or lists of these types.
282
+ Lists are converted to JSON string representation.
283
+ Keys can be either custom keys or semantic convention aliases.
284
+ prefix: Prefix for metadata attributes (default: "trace.metadata").
285
+ Ignored for semantic convention attributes.
286
+
287
+ Returns:
288
+ bool: True if metadata was successfully updated, False otherwise.
289
+
290
+ """
291
+ if not tracer.initialized:
292
+ logger.warning("AgentOps SDK not initialized. Cannot update trace metadata.")
293
+ return False
294
+
295
+ # Build semantic convention mappings dynamically
296
+ def build_semconv_mappings():
297
+ """Build mappings from user-friendly keys to semantic convention attributes."""
298
+ mappings = {}
299
+
300
+ # Helper function to extract attribute name from semantic convention
301
+ def extract_key_from_attr(attr_value: str) -> str:
302
+ parts = attr_value.split(".")
303
+ if len(parts) >= 2:
304
+ # Handle special cases
305
+ if parts[0] == "error":
306
+ # error.type -> error_type
307
+ return "_".join(parts)
308
+ else:
309
+ # Default: entity.attribute -> entity_attribute
310
+ return "_".join(parts)
311
+ return attr_value
312
+
313
+ # Process each semantic convention class
314
+ for cls in [AgentAttributes, ToolAttributes, WorkflowAttributes, CoreAttributes, SpanAttributes]:
315
+ for attr_name, attr_value in cls.__dict__.items():
316
+ if not attr_name.startswith("_") and isinstance(attr_value, str):
317
+ # Skip gen_ai attributes
318
+ if attr_value.startswith("gen_ai."):
319
+ continue
320
+
321
+ # Generate user-friendly key
322
+ user_key = extract_key_from_attr(attr_value)
323
+ mappings[user_key] = attr_value
324
+
325
+ # Add some additional convenience mappings
326
+ if attr_value == CoreAttributes.TAGS:
327
+ mappings["tags"] = attr_value
328
+
329
+ return mappings
330
+
331
+ # Build mappings if using semantic conventions
332
+ SEMCONV_MAPPINGS = build_semconv_mappings()
333
+
334
+ # Collect all valid semantic convention attributes
335
+ VALID_SEMCONV_ATTRS = set()
336
+ for cls in [AgentAttributes, ToolAttributes, WorkflowAttributes, CoreAttributes, SpanAttributes]:
337
+ for key, value in cls.__dict__.items():
338
+ if not key.startswith("_") and isinstance(value, str):
339
+ # Include all attributes except gen_ai ones
340
+ if not value.startswith("gen_ai."):
341
+ VALID_SEMCONV_ATTRS.add(value)
342
+
343
+ # Find the current trace span
344
+ span = None
345
+
346
+ # Get the current span from OpenTelemetry context
347
+ current_span = get_current_span()
348
+
349
+ # Check if the current span is valid and recording
350
+ if current_span and hasattr(current_span, "is_recording") and current_span.is_recording():
351
+ # Check if this is a trace/session span or a child span
352
+ span_name = getattr(current_span, "name", "")
353
+
354
+ # If it's a session/trace span, use it directly
355
+ if span_name.endswith(f".{SpanKind.SESSION}"):
356
+ span = current_span
357
+ else:
358
+ # It's a child span, try to find the root trace span
359
+ # Get all active traces
360
+ active_traces = tracer.get_active_traces()
361
+ if active_traces:
362
+ # Find the trace that contains the current span
363
+ current_trace_id = current_span.get_span_context().trace_id
364
+
365
+ for trace_id_str, trace_ctx in active_traces.items():
366
+ try:
367
+ # Convert hex string back to int for comparison
368
+ trace_id = int(trace_id_str, 16)
369
+ if trace_id == current_trace_id:
370
+ span = trace_ctx.span
371
+ break
372
+ except (ValueError, AttributeError):
373
+ continue
374
+
375
+ # If we couldn't find the parent trace, use the current span
376
+ if not span:
377
+ span = current_span
378
+ else:
379
+ # No active traces, use the current span
380
+ span = current_span
381
+
382
+ # If no current span or it's not recording, check active traces
383
+ if not span:
384
+ active_traces = tracer.get_active_traces()
385
+ if active_traces:
386
+ # Get the most recently created trace (last in the dict)
387
+ trace_context = list(active_traces.values())[-1]
388
+ span = trace_context.span
389
+ logger.debug("Using most recent active trace for metadata update")
390
+ else:
391
+ logger.warning("No active trace found. Cannot update metadata.")
392
+ return False
393
+
394
+ # Ensure the span is recording before updating
395
+ if not span or (hasattr(span, "is_recording") and not span.is_recording()):
396
+ logger.warning("Span is not recording. Cannot update metadata.")
397
+ return False
398
+
399
+ # Update the span attributes with the metadata
400
+ try:
401
+ updated_count = 0
402
+ for key, value in metadata.items():
403
+ # Validate the value type
404
+ if value is None:
405
+ continue
406
+
407
+ # Convert lists to JSON string representation for OpenTelemetry compatibility
408
+ if isinstance(value, list):
409
+ # Ensure all list items are valid types
410
+ if all(isinstance(item, (str, int, float, bool)) for item in value):
411
+ value = json.dumps(value)
412
+ else:
413
+ logger.warning(f"Skipping metadata key '{key}': list contains invalid types")
414
+ continue
415
+ elif not isinstance(value, (str, int, float, bool)):
416
+ logger.warning(f"Skipping metadata key '{key}': value type {type(value)} not supported")
417
+ continue
418
+
419
+ # Determine the attribute key
420
+ attribute_key = key
421
+
422
+ # Check if key is already a valid semantic convention attribute
423
+ if key in VALID_SEMCONV_ATTRS:
424
+ # Key is already a valid semantic convention, use as-is
425
+ attribute_key = key
426
+ elif key in SEMCONV_MAPPINGS:
427
+ # It's a user-friendly key, map it to semantic convention
428
+ attribute_key = SEMCONV_MAPPINGS[key]
429
+ logger.debug(f"Mapped '{key}' to semantic convention '{attribute_key}'")
430
+ else:
431
+ # Not a semantic convention, use with prefix
432
+ attribute_key = f"{prefix}.{key}"
433
+
434
+ # Set the attribute
435
+ span.set_attribute(attribute_key, value)
436
+ updated_count += 1
437
+
438
+ if updated_count > 0:
439
+ logger.debug(f"Successfully updated {updated_count} metadata attributes on trace")
440
+ return True
441
+ else:
442
+ logger.warning("No valid metadata attributes were updated")
443
+ return False
444
+
445
+ except Exception as e:
446
+ logger.error(f"Error updating trace metadata: {e}")
447
+ return False
448
+
449
+
450
+ __all__ = [
451
+ # Legacy exports
452
+ "start_session",
453
+ "end_session",
454
+ "track_agent",
455
+ "track_tool",
456
+ "end_all_sessions",
457
+ "Session",
458
+ "ToolEvent",
459
+ "ErrorEvent",
460
+ "ActionEvent",
461
+ "LLMEvent",
462
+ # Modern exports
463
+ "init",
464
+ "start_trace",
465
+ "end_trace",
466
+ "update_trace_metadata",
467
+ "Client",
468
+ "get_client",
469
+ # Decorators
470
+ "trace",
471
+ "session",
472
+ "agent",
473
+ "task",
474
+ "workflow",
475
+ "operation",
476
+ "tool",
477
+ "guardrail",
478
+ "track_endpoint",
479
+ # Enums
480
+ "TraceState",
481
+ "SUCCESS",
482
+ "ERROR",
483
+ "UNSET",
484
+ # Validation
485
+ "validate_trace_spans",
486
+ "print_validation_summary",
487
+ "ValidationError",
488
+ ]
@@ -0,0 +1,5 @@
1
+ from agentops.client.client import Client
2
+ from agentops.client.api import ApiClient
3
+
4
+
5
+ __all__ = ["Client", "ApiClient"]
@@ -0,0 +1,71 @@
1
+ """
2
+ API client for the AgentOps API.
3
+
4
+ This module provides the client for the AgentOps API.
5
+ """
6
+
7
+ from typing import Dict, Type, TypeVar, cast
8
+
9
+ from agentops.client.api.base import BaseApiClient
10
+ from agentops.client.api.types import AuthTokenResponse
11
+ from agentops.client.api.versions.v3 import V3Client
12
+ from agentops.client.api.versions.v4 import V4Client
13
+
14
+ # Define a type variable for client classes
15
+ T = TypeVar("T", bound=BaseApiClient)
16
+
17
+ __all__ = ["ApiClient", "BaseApiClient", "AuthTokenResponse"]
18
+
19
+
20
+ class ApiClient:
21
+ """
22
+ Master API client that contains all version-specific clients.
23
+
24
+ This client provides a unified interface for accessing different API versions.
25
+ It lazily initializes version-specific clients when they are first accessed.
26
+ """
27
+
28
+ def __init__(self, endpoint: str = "https://api.agentops.ai"):
29
+ """
30
+ Initialize the master API client.
31
+
32
+ Args:
33
+ endpoint: The base URL for the API
34
+ """
35
+ self.endpoint = endpoint
36
+ self._clients: Dict[str, BaseApiClient] = {}
37
+
38
+ @property
39
+ def v3(self) -> V3Client:
40
+ """
41
+ Get the V3 API client.
42
+
43
+ Returns:
44
+ The V3 API client
45
+ """
46
+ return self._get_client("v3", V3Client)
47
+
48
+ @property
49
+ def v4(self) -> V4Client:
50
+ """
51
+ Get the V4 API client.
52
+
53
+ Returns:
54
+ The V4 API client
55
+ """
56
+ return self._get_client("v4", V4Client)
57
+
58
+ def _get_client(self, version: str, client_class: Type[T]) -> T:
59
+ """
60
+ Get or create a version-specific client.
61
+
62
+ Args:
63
+ version: The API version
64
+ client_class: The client class to instantiate
65
+
66
+ Returns:
67
+ The version-specific client
68
+ """
69
+ if version not in self._clients:
70
+ self._clients[version] = client_class(self.endpoint)
71
+ return cast(T, self._clients[version])