mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-18 18:44:42 -05:00
Adds analytics tracking to the chat copilot system for better observability of user interactions and agent operations. ### Changes 🏗️ **PostHog Analytics Integration:** - Added `posthog` dependency (v7.6.0) to track chat events - Created new tracking module (`backend/api/features/chat/tracking.py`) with events: - `chat_message_sent` - When a user sends a message - `chat_tool_called` - When a tool is called (includes tool name) - `chat_agent_run_success` - When an agent runs successfully - `chat_agent_scheduled` - When an agent is scheduled - `chat_trigger_setup` - When a trigger is set up - Added PostHog configuration to settings: - `POSTHOG_API_KEY` - API key for PostHog - `POSTHOG_HOST` - PostHog host URL (defaults to `https://us.i.posthog.com`) **OpenRouter Tracing:** - Added `user` and `session_id` fields to chat completion API calls for OpenRouter tracing - Added `posthogDistinctId` and `posthogProperties` (with environment) to API calls **Files Changed:** - `backend/api/features/chat/tracking.py` - New PostHog tracking module - `backend/api/features/chat/service.py` - Added user message tracking and OpenRouter tracing - `backend/api/features/chat/tools/__init__.py` - Added tool call tracking - `backend/api/features/chat/tools/run_agent.py` - Added agent run/schedule tracking - `backend/util/settings.py` - Added PostHog configuration fields - `pyproject.toml` - Added posthog dependency ### Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] Verified code passes linting and formatting - [x] Verified PostHog client initializes correctly when API key is provided - [x] Verified tracking is gracefully skipped when PostHog is not configured #### For configuration changes: - [ ] `.env.default` is updated or already compatible with my changes - [x] `docker-compose.yml` is updated or already compatible with my changes - [x] I have included a list of my configuration changes in the PR description (under **Changes**) **New environment variables (optional):** - `POSTHOG_API_KEY` - PostHog project API key - `POSTHOG_HOST` - PostHog host URL (optional, defaults to US cloud)
251 lines
6.6 KiB
Python
251 lines
6.6 KiB
Python
"""PostHog analytics tracking for the chat system."""
|
|
|
|
import atexit
|
|
import logging
|
|
from typing import Any
|
|
|
|
from posthog import Posthog
|
|
|
|
from backend.util.settings import Settings
|
|
|
|
logger = logging.getLogger(__name__)
|
|
settings = Settings()
|
|
|
|
# PostHog client instance (lazily initialized)
|
|
_posthog_client: Posthog | None = None
|
|
|
|
|
|
def _shutdown_posthog() -> None:
|
|
"""Flush and shutdown PostHog client on process exit."""
|
|
if _posthog_client is not None:
|
|
_posthog_client.flush()
|
|
_posthog_client.shutdown()
|
|
|
|
|
|
atexit.register(_shutdown_posthog)
|
|
|
|
|
|
def _get_posthog_client() -> Posthog | None:
|
|
"""Get or create the PostHog client instance."""
|
|
global _posthog_client
|
|
if _posthog_client is not None:
|
|
return _posthog_client
|
|
|
|
if not settings.secrets.posthog_api_key:
|
|
logger.debug("PostHog API key not configured, analytics disabled")
|
|
return None
|
|
|
|
_posthog_client = Posthog(
|
|
settings.secrets.posthog_api_key,
|
|
host=settings.secrets.posthog_host,
|
|
)
|
|
logger.info(
|
|
f"PostHog client initialized with host: {settings.secrets.posthog_host}"
|
|
)
|
|
return _posthog_client
|
|
|
|
|
|
def _get_base_properties() -> dict[str, Any]:
|
|
"""Get base properties included in all events."""
|
|
return {
|
|
"environment": settings.config.app_env.value,
|
|
"source": "chat_copilot",
|
|
}
|
|
|
|
|
|
def track_user_message(
|
|
user_id: str | None,
|
|
session_id: str,
|
|
message_length: int,
|
|
) -> None:
|
|
"""Track when a user sends a message in chat.
|
|
|
|
Args:
|
|
user_id: The user's ID (or None for anonymous)
|
|
session_id: The chat session ID
|
|
message_length: Length of the user's message
|
|
"""
|
|
client = _get_posthog_client()
|
|
if not client:
|
|
return
|
|
|
|
try:
|
|
properties = {
|
|
**_get_base_properties(),
|
|
"session_id": session_id,
|
|
"message_length": message_length,
|
|
}
|
|
client.capture(
|
|
distinct_id=user_id or f"anonymous_{session_id}",
|
|
event="copilot_message_sent",
|
|
properties=properties,
|
|
)
|
|
except Exception as e:
|
|
logger.warning(f"Failed to track user message: {e}")
|
|
|
|
|
|
def track_tool_called(
|
|
user_id: str | None,
|
|
session_id: str,
|
|
tool_name: str,
|
|
tool_call_id: str,
|
|
) -> None:
|
|
"""Track when a tool is called in chat.
|
|
|
|
Args:
|
|
user_id: The user's ID (or None for anonymous)
|
|
session_id: The chat session ID
|
|
tool_name: Name of the tool being called
|
|
tool_call_id: Unique ID of the tool call
|
|
"""
|
|
client = _get_posthog_client()
|
|
if not client:
|
|
logger.info("PostHog client not available for tool tracking")
|
|
return
|
|
|
|
try:
|
|
properties = {
|
|
**_get_base_properties(),
|
|
"session_id": session_id,
|
|
"tool_name": tool_name,
|
|
"tool_call_id": tool_call_id,
|
|
}
|
|
distinct_id = user_id or f"anonymous_{session_id}"
|
|
logger.info(
|
|
f"Sending copilot_tool_called event to PostHog: distinct_id={distinct_id}, "
|
|
f"tool_name={tool_name}"
|
|
)
|
|
client.capture(
|
|
distinct_id=distinct_id,
|
|
event="copilot_tool_called",
|
|
properties=properties,
|
|
)
|
|
except Exception as e:
|
|
logger.warning(f"Failed to track tool call: {e}")
|
|
|
|
|
|
def track_agent_run_success(
|
|
user_id: str,
|
|
session_id: str,
|
|
graph_id: str,
|
|
graph_name: str,
|
|
execution_id: str,
|
|
library_agent_id: str,
|
|
) -> None:
|
|
"""Track when an agent is successfully run.
|
|
|
|
Args:
|
|
user_id: The user's ID
|
|
session_id: The chat session ID
|
|
graph_id: ID of the agent graph
|
|
graph_name: Name of the agent
|
|
execution_id: ID of the execution
|
|
library_agent_id: ID of the library agent
|
|
"""
|
|
client = _get_posthog_client()
|
|
if not client:
|
|
return
|
|
|
|
try:
|
|
properties = {
|
|
**_get_base_properties(),
|
|
"session_id": session_id,
|
|
"graph_id": graph_id,
|
|
"graph_name": graph_name,
|
|
"execution_id": execution_id,
|
|
"library_agent_id": library_agent_id,
|
|
}
|
|
client.capture(
|
|
distinct_id=user_id,
|
|
event="copilot_agent_run_success",
|
|
properties=properties,
|
|
)
|
|
except Exception as e:
|
|
logger.warning(f"Failed to track agent run: {e}")
|
|
|
|
|
|
def track_agent_scheduled(
|
|
user_id: str,
|
|
session_id: str,
|
|
graph_id: str,
|
|
graph_name: str,
|
|
schedule_id: str,
|
|
schedule_name: str,
|
|
cron: str,
|
|
library_agent_id: str,
|
|
) -> None:
|
|
"""Track when an agent is successfully scheduled.
|
|
|
|
Args:
|
|
user_id: The user's ID
|
|
session_id: The chat session ID
|
|
graph_id: ID of the agent graph
|
|
graph_name: Name of the agent
|
|
schedule_id: ID of the schedule
|
|
schedule_name: Name of the schedule
|
|
cron: Cron expression for the schedule
|
|
library_agent_id: ID of the library agent
|
|
"""
|
|
client = _get_posthog_client()
|
|
if not client:
|
|
return
|
|
|
|
try:
|
|
properties = {
|
|
**_get_base_properties(),
|
|
"session_id": session_id,
|
|
"graph_id": graph_id,
|
|
"graph_name": graph_name,
|
|
"schedule_id": schedule_id,
|
|
"schedule_name": schedule_name,
|
|
"cron": cron,
|
|
"library_agent_id": library_agent_id,
|
|
}
|
|
client.capture(
|
|
distinct_id=user_id,
|
|
event="copilot_agent_scheduled",
|
|
properties=properties,
|
|
)
|
|
except Exception as e:
|
|
logger.warning(f"Failed to track agent schedule: {e}")
|
|
|
|
|
|
def track_trigger_setup(
|
|
user_id: str,
|
|
session_id: str,
|
|
graph_id: str,
|
|
graph_name: str,
|
|
trigger_type: str,
|
|
library_agent_id: str,
|
|
) -> None:
|
|
"""Track when a trigger is set up for an agent.
|
|
|
|
Args:
|
|
user_id: The user's ID
|
|
session_id: The chat session ID
|
|
graph_id: ID of the agent graph
|
|
graph_name: Name of the agent
|
|
trigger_type: Type of trigger (e.g., 'webhook')
|
|
library_agent_id: ID of the library agent
|
|
"""
|
|
client = _get_posthog_client()
|
|
if not client:
|
|
return
|
|
|
|
try:
|
|
properties = {
|
|
**_get_base_properties(),
|
|
"session_id": session_id,
|
|
"graph_id": graph_id,
|
|
"graph_name": graph_name,
|
|
"trigger_type": trigger_type,
|
|
"library_agent_id": library_agent_id,
|
|
}
|
|
client.capture(
|
|
distinct_id=user_id,
|
|
event="copilot_trigger_setup",
|
|
properties=properties,
|
|
)
|
|
except Exception as e:
|
|
logger.warning(f"Failed to track trigger setup: {e}")
|