diff --git a/agentops/__init__.py b/agentops/__init__.py index 29557e7d0..947ddd530 100755 --- a/agentops/__init__.py +++ b/agentops/__init__.py @@ -61,6 +61,7 @@ def init( log_level: Optional[Union[str, int]] = None, fail_safe: Optional[bool] = None, exporter_endpoint: Optional[str] = None, + session_name: Optional[str] = None, **kwargs, ): """ @@ -88,6 +89,7 @@ def init( fail_safe (bool): Whether to suppress errors and continue execution when possible. exporter_endpoint (str, optional): Endpoint for the exporter. If none is provided, key will be read from the AGENTOPS_EXPORTER_ENDPOINT environment variable. + session_name (str, optional): Name of the session to be used in the span attributes. **kwargs: Additional configuration parameters to be passed to the client. """ global _client @@ -116,6 +118,7 @@ def init( log_level=log_level, fail_safe=fail_safe, exporter_endpoint=exporter_endpoint, + session_name=session_name, **kwargs, ) diff --git a/agentops/client/client.py b/agentops/client/client.py index 9f29dcc92..7d4b25b03 100644 --- a/agentops/client/client.py +++ b/agentops/client/client.py @@ -99,10 +99,18 @@ def init(self, **kwargs): if self.config.auto_start_session: from agentops.legacy import start_session - # Pass default_tags if they exist - if self.config.default_tags: + if self.config.default_tags and self.config.session_name: + logger.debug(f"Starting session with tags: {self.config.default_tags}") + logger.debug(f"Starting session with name: {self.config.session_name}") + session = start_session(session_name=self.config.session_name, tags=list(self.config.default_tags)) + elif self.config.default_tags: + logger.debug(f"Starting session with tags: {self.config.default_tags}") session = start_session(tags=list(self.config.default_tags)) + elif self.config.session_name: + logger.debug(f"Starting session with name: {self.config.session_name}") + session = start_session(session_name=self.config.session_name) else: + logger.debug("Starting session without tags or name") session = start_session() # Register this session globally diff --git a/agentops/config.py b/agentops/config.py index 6af2005c4..d931f404e 100644 --- a/agentops/config.py +++ b/agentops/config.py @@ -124,6 +124,11 @@ class Config: default_factory=lambda: None, metadata={"description": "Custom span processor for OpenTelemetry trace data"} ) + session_name: Optional[str] = field( + default_factory=lambda: None, + metadata={"description": "Name of the session to be used in the span attributes"}, + ) + def configure( self, api_key: Optional[str] = None, @@ -144,6 +149,7 @@ def configure( exporter: Optional[SpanExporter] = None, processor: Optional[SpanProcessor] = None, exporter_endpoint: Optional[str] = None, + session_name: Optional[str] = None, ): """Configure settings from kwargs, validating where necessary""" if api_key is not None: @@ -214,6 +220,9 @@ def configure( # else: # self.exporter_endpoint = self.endpoint + if session_name is not None: + self.session_name = session_name + def dict(self): """Return a dictionary representation of the config""" return { @@ -235,6 +244,7 @@ def dict(self): "exporter": self.exporter, "processor": self.processor, "exporter_endpoint": self.exporter_endpoint, + "session_name": self.session_name, } def json(self): diff --git a/agentops/instrumentation/crewai/instrumentation.py b/agentops/instrumentation/crewai/instrumentation.py index 3a2964733..afb5eff02 100644 --- a/agentops/instrumentation/crewai/instrumentation.py +++ b/agentops/instrumentation/crewai/instrumentation.py @@ -14,6 +14,8 @@ from agentops.instrumentation.crewai.version import __version__ from agentops.semconv import SpanAttributes, AgentOpsSpanKindValues, Meters, ToolAttributes, MessageAttributes from .crewai_span_attributes import CrewAISpanAttributes, set_span_attribute +from agentops import get_client + # Initialize logger logger = logging.getLogger(__name__) @@ -156,15 +158,26 @@ def wrap_kickoff( args, kwargs, ): + span_name = "crewai.workflow" logger.debug( f"CrewAI: Starting workflow instrumentation for Crew with {len(getattr(instance, 'agents', []))} agents" ) + config = get_client().config + attributes = { + SpanAttributes.LLM_SYSTEM: "crewai", + } + + if config.session_name: + span_name = f"{config.session_name}.workflow" + + if config.default_tags and len(config.default_tags) > 0: + tag_list = list(config.default_tags) + attributes[SpanAttributes.AGENTOPS_SPAN_TAGS] = tag_list + with tracer.start_as_current_span( - "crewai.workflow", + name=span_name, kind=SpanKind.INTERNAL, - attributes={ - SpanAttributes.LLM_SYSTEM: "crewai", - }, + attributes=attributes, ) as span: try: span.set_attribute(TELEMETRY_SDK_NAME, "agentops") @@ -327,12 +340,19 @@ def wrap_agent_execute_task( tracer, duration_histogram, token_histogram, environment, application_name, wrapped, instance, args, kwargs ): agent_name = instance.role if hasattr(instance, "role") else "agent" + attributes = { + SpanAttributes.AGENTOPS_SPAN_KIND: AgentOpsSpanKindValues.AGENT.value, + } + + config = get_client().config + if config.default_tags and len(config.default_tags) > 0: + tag_list = list(config.default_tags) + attributes[SpanAttributes.AGENTOPS_SPAN_TAGS] = tag_list + with tracer.start_as_current_span( f"{agent_name}.agent", kind=SpanKind.CLIENT, - attributes={ - SpanAttributes.AGENTOPS_SPAN_KIND: AgentOpsSpanKindValues.AGENT.value, - }, + attributes=attributes, ) as span: try: span.set_attribute(TELEMETRY_SDK_NAME, "agentops") @@ -381,12 +401,22 @@ def wrap_task_execute( ): task_name = instance.description if hasattr(instance, "description") else "task" + config = get_client().config + attributes = { + SpanAttributes.AGENTOPS_SPAN_KIND: AgentOpsSpanKindValues.TASK.value, + } + + if config.default_tags and len(config.default_tags) > 0: + tag_list = list(config.default_tags) + attributes[SpanAttributes.AGENTOPS_SPAN_TAGS] = tag_list + + if config.session_name: + task_name = config.session_name + with tracer.start_as_current_span( f"{task_name}.task", kind=SpanKind.CLIENT, - attributes={ - SpanAttributes.AGENTOPS_SPAN_KIND: AgentOpsSpanKindValues.TASK.value, - }, + attributes=attributes, ) as span: try: span.set_attribute(TELEMETRY_SDK_NAME, "agentops") @@ -411,7 +441,16 @@ def wrap_llm_call( tracer, duration_histogram, token_histogram, environment, application_name, wrapped, instance, args, kwargs ): llm = instance.model if hasattr(instance, "model") else "llm" - with tracer.start_as_current_span(f"{llm}.llm", kind=SpanKind.CLIENT, attributes={}) as span: + attributes = { + SpanAttributes.AGENTOPS_SPAN_KIND: AgentOpsSpanKindValues.LLM.value, + } + + config = get_client().config + if config.default_tags and len(config.default_tags) > 0: + tag_list = list(config.default_tags) + attributes[SpanAttributes.AGENTOPS_SPAN_TAGS] = tag_list + + with tracer.start_as_current_span(f"{llm}.llm", kind=SpanKind.CLIENT, attributes=attributes) as span: start_time = time.time() try: span.set_attribute(TELEMETRY_SDK_NAME, "agentops") diff --git a/agentops/legacy/__init__.py b/agentops/legacy/__init__.py index f733f2aeb..780e0318a 100644 --- a/agentops/legacy/__init__.py +++ b/agentops/legacy/__init__.py @@ -73,7 +73,9 @@ def end_session(self, **kwargs): _flush_span_processors() -def _create_session_span(tags: Union[Dict[str, Any], List[str], None] = None) -> tuple: +def _create_session_span( + session_name: Optional[str] = None, tags: Union[Dict[str, Any], List[str], None] = None +) -> tuple: """ Helper function to create a session span with tags. @@ -94,10 +96,13 @@ def _create_session_span(tags: Union[Dict[str, Any], List[str], None] = None) -> attributes = {} if tags: attributes["tags"] = tags - return _make_span("session", span_kind=SpanKind.SESSION, attributes=attributes) + + span_name = "session" if session_name is None else session_name + return _make_span(span_name, span_kind=SpanKind.SESSION, attributes=attributes) def start_session( + session_name: Optional[str] = None, tags: Union[Dict[str, Any], List[str], None] = None, ) -> Session: """ @@ -153,7 +158,7 @@ def start_session( _current_session = dummy_session return dummy_session - span, ctx, token = _create_session_span(tags) + span, ctx, token = _create_session_span(session_name, tags) session = Session(span, token) # Set the global session reference diff --git a/agentops/semconv/span_attributes.py b/agentops/semconv/span_attributes.py index 23d1d3d23..4c08d2f86 100644 --- a/agentops/semconv/span_attributes.py +++ b/agentops/semconv/span_attributes.py @@ -88,6 +88,7 @@ class SpanAttributes: AGENTOPS_ENTITY_INPUT = "agentops.entity.input" AGENTOPS_SPAN_KIND = "agentops.span.kind" AGENTOPS_ENTITY_NAME = "agentops.entity.name" + AGENTOPS_SPAN_TAGS = "tags" # Operation attributes OPERATION_NAME = "operation.name" diff --git a/docs/v1/concepts/sessions.mdx b/docs/v1/concepts/sessions.mdx index 60a503c8f..7c9a51b4e 100644 --- a/docs/v1/concepts/sessions.mdx +++ b/docs/v1/concepts/sessions.mdx @@ -27,6 +27,7 @@ Optionally, sessions may include: - **Tags**: Tags allow for the categorization and later retrieval of sessions. - **Host Environment**: Automatically gathers basic information about the system on which the session ran. - **Video**: If applicable, an optional video recording of the session. +- **Session Name**: A custom name for the session that helps identify and organize different types of sessions in the dashboard. Can be set during initialization or when starting a session. ### Methods diff --git a/docs/v1/usage/sdk-reference.mdx b/docs/v1/usage/sdk-reference.mdx index ae0690c3d..f1f565646 100644 --- a/docs/v1/usage/sdk-reference.mdx +++ b/docs/v1/usage/sdk-reference.mdx @@ -26,6 +26,7 @@ The first element of AgentOps is always calling .init() - `auto_start_session` (bool): Whether to start a session automatically when the client is created. You may wish to delay starting a session in order to do additional setup or starting a session on a child process. - `inherited_session_id` (str, optional): When creating the client, passing in this value will connect the client to an existing session. This is useful when having separate processes contribute to the same session. - `skip_auto_end_session` (bool, optional): If you are using a framework such as Crew, the framework can decide when to halt execution. Setting this parameter to true will not end your agentops session when this happens. +- `session_name` (str, optional): Name of the session to be used in the span attributes. This helps identify and organize different types of sessions in the dashboard. **Returns**: diff --git a/docs/v2/concepts/sessions.mdx b/docs/v2/concepts/sessions.mdx index b2eae78f2..5f9b78df1 100644 --- a/docs/v2/concepts/sessions.mdx +++ b/docs/v2/concepts/sessions.mdx @@ -13,6 +13,19 @@ import agentops agentops.init(api_key="YOUR_API_KEY", tags=["production"]) ``` +You can also provide a custom name for your session during initialization: + +```python +import agentops + +# Initialize with a custom session name +agentops.init( + api_key="YOUR_API_KEY", + session_name="customer-support-bot", + tags=["production"] +) +``` + This approach: - Creates a session automatically when you initialize the SDK - Tracks all events in the context of this session diff --git a/docs/v2/concepts/tags.mdx b/docs/v2/concepts/tags.mdx index 40ea2bbd1..42b478698 100644 --- a/docs/v2/concepts/tags.mdx +++ b/docs/v2/concepts/tags.mdx @@ -13,6 +13,7 @@ import agentops agentops.init( api_key="YOUR_API_KEY", tags=["production", "customer-service", "gpt-4"] + session_name="customer-support-agent" ) ``` diff --git a/docs/v2/usage/sdk-reference.mdx b/docs/v2/usage/sdk-reference.mdx index 6852bc7e9..4f796c392 100644 --- a/docs/v2/usage/sdk-reference.mdx +++ b/docs/v2/usage/sdk-reference.mdx @@ -33,6 +33,7 @@ Initializes the AgentOps SDK and automatically starts tracking your application. - `fail_safe` (bool, optional): Whether to suppress errors and continue execution when possible. Defaults to False. - `exporter_endpoint` (str, optional): Endpoint for the exporter. If not provided, will be read from the `AGENTOPS_EXPORTER_ENDPOINT` environment variable. Defaults to 'https://otlp.agentops.ai/v1/traces'. - `export_flush_interval` (int, optional): Time interval in milliseconds between automatic exports of telemetry data. Defaults to 1000. +- `session_name` (str, optional): Name of the session to be used in the span attributes. This helps identify and organize different types of sessions in the dashboard. **Returns**: