Skip to content

Commit 156d541

Browse files
committed
fix: added posthog traces
1 parent 5d187fc commit 156d541

4 files changed

Lines changed: 101 additions & 5 deletions

File tree

strix/llm/dedupe.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,16 @@ def check_duplicate(
186186
if api_base:
187187
completion_kwargs["api_base"] = api_base
188188

189+
try:
190+
from strix.telemetry.tracer import get_global_tracer
191+
192+
tracer = get_global_tracer()
193+
if tracer:
194+
run_id = tracer.run_id
195+
completion_kwargs["metadata"] = {"user_id": run_id, "$ai_trace_id": run_id}
196+
except Exception as e:
197+
logger.error(f"Could not set trace metadata: {e}")
198+
189199
response = litellm.completion(**completion_kwargs)
190200

191201
content = response.choices[0].message.content

strix/llm/llm.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import logging
23
from collections.abc import AsyncIterator
34
from dataclasses import dataclass
45
from typing import Any
@@ -17,10 +18,14 @@
1718
parse_tool_invocations,
1819
)
1920
from strix.skills import load_skills
21+
from strix.telemetry import posthog
2022
from strix.tools import get_tools_prompt
2123
from strix.utils.resource_paths import get_strix_resource_path
2224

2325

26+
logger = logging.getLogger(__name__)
27+
28+
2429
litellm.drop_params = True
2530
litellm.modify_params = True
2631

@@ -74,6 +79,11 @@ def __init__(self, config: LLMConfig, agent_name: str | None = None):
7479
else:
7580
self._reasoning_effort = "high"
7681

82+
try:
83+
posthog.configure_litellm_posthog()
84+
except Exception as e:
85+
logger.error(f"Could not config posthog traces: {e}")
86+
7787
def _load_system_prompt(self, agent_name: str | None) -> str:
7888
if not agent_name:
7989
return ""
@@ -200,6 +210,27 @@ def _build_completion_args(self, messages: list[dict[str, Any]]) -> dict[str, An
200210
"stream_options": {"include_usage": True},
201211
}
202212

213+
metadata: dict[str, Any] = {}
214+
215+
try:
216+
from strix.telemetry.tracer import get_global_tracer
217+
218+
tracer = get_global_tracer()
219+
if tracer:
220+
run_id = tracer.run_id
221+
222+
metadata["$ai_trace_id"] = run_id
223+
metadata["user_id"] = run_id
224+
225+
if self.agent_id:
226+
metadata["agent_id"] = self.agent_id
227+
if self.agent_name:
228+
metadata["agent_name"] = self.agent_name
229+
except Exception as e:
230+
logger.error(f"Could not set trace metadata: {e}")
231+
if metadata:
232+
args["metadata"] = metadata
233+
203234
if api_key := Config.get("llm_api_key"):
204235
args["api_key"] = api_key
205236
if api_base := (

strix/llm/memory_compressor.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,19 @@ def _summarize_messages(
111111
"timeout": timeout,
112112
}
113113

114+
try:
115+
from strix.telemetry.tracer import get_global_tracer
116+
117+
tracer = get_global_tracer()
118+
if tracer:
119+
run_id = tracer.run_id
120+
completion_args["metadata"] = {
121+
"user_id": run_id,
122+
"$ai_trace_id": run_id,
123+
}
124+
except Exception as e:
125+
logger.error(f"Could not set trace metadata: {e}")
126+
114127
response = litellm.completion(**completion_args)
115128
summary = response.choices[0].message.content or ""
116129
if not summary.strip():

strix/telemetry/posthog.py

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,65 @@
1+
from litellm import CALLBACK_TYPES
2+
3+
14
import json
5+
import logging
6+
import os
27
import platform
38
import sys
49
import urllib.request
510
from pathlib import Path
611
from typing import TYPE_CHECKING, Any
712
from uuid import uuid4
813

14+
import litellm
15+
916
from strix.config import Config
1017

1118

19+
logger = logging.getLogger(__name__)
20+
1221
if TYPE_CHECKING:
1322
from strix.telemetry.tracer import Tracer
1423

15-
_POSTHOG_PUBLIC_API_KEY = "phc_7rO3XRuNT5sgSKAl6HDIrWdSGh1COzxw0vxVIAR6vVZ"
16-
_POSTHOG_HOST = "https://us.i.posthog.com"
24+
_POSTHOG_PRIMARY_API_KEY = "phc_7rO3XRuNT5sgSKAl6HDIrWdSGh1COzxw0vxVIAR6vVZ"
25+
_POSTHOG_PRIMARY_HOST = "https://us.i.posthog.com"
26+
27+
_POSTHOG_LLM_API_KEY = os.environ.get("POSTHOG_LLM_API_KEY")
28+
_POSTHOG_LLM_HOST = os.environ.get("POSTHOG_LLM_HOST")
1729

1830
_SESSION_ID = uuid4().hex[:16]
1931

2032

2133
def _is_enabled() -> bool:
22-
return (Config.get("strix_telemetry") or "1").lower() not in ("0", "false", "no", "off")
34+
telemetry_value = Config.get("strix_telemetry") or "1"
35+
return telemetry_value.lower() not in ("0", "false", "no", "off")
36+
37+
38+
def configure_litellm_posthog() -> None:
39+
"""Configure LiteLLM to send LLM traces to env postHog account."""
40+
41+
should_send_trace_to_posthog = _POSTHOG_LLM_API_KEY is not None and _POSTHOG_LLM_HOST is not None
42+
43+
if not _is_enabled():
44+
logger.info("PostHog telemetry (traces) is disabled")
45+
return
46+
47+
if not should_send_trace_to_posthog:
48+
logger.info("PostHog telemetry (traces) is disabled")
49+
return
50+
51+
os.environ["POSTHOG_API_KEY"] = _POSTHOG_LLM_API_KEY
52+
os.environ["POSTHOG_API_URL"] = _POSTHOG_LLM_HOST
53+
54+
if "posthog" not in (litellm.success_callback or []):
55+
callbacks = list[CALLBACK_TYPES](litellm.success_callback or [])
56+
callbacks.append("posthog")
57+
litellm.success_callback = callbacks
58+
59+
if "posthog" not in (litellm.failure_callback or []):
60+
callbacks = list[CALLBACK_TYPES](litellm.failure_callback or [])
61+
callbacks.append("posthog")
62+
litellm.failure_callback = callbacks
2363

2464

2565
def _is_first_run() -> bool:
@@ -44,22 +84,24 @@ def _get_version() -> str:
4484

4585

4686
def _send(event: str, properties: dict[str, Any]) -> None:
87+
"""Send custom events to Instance A (Primary) for manual tracking."""
4788
if not _is_enabled():
4889
return
4990
try:
5091
payload = {
51-
"api_key": _POSTHOG_PUBLIC_API_KEY,
92+
"api_key": _POSTHOG_PRIMARY_API_KEY,
5293
"event": event,
5394
"distinct_id": _SESSION_ID,
5495
"properties": properties,
5596
}
5697
req = urllib.request.Request( # noqa: S310
57-
f"{_POSTHOG_HOST}/capture/",
98+
f"{_POSTHOG_PRIMARY_HOST}/capture/",
5899
data=json.dumps(payload).encode(),
59100
headers={"Content-Type": "application/json"},
60101
)
61102
with urllib.request.urlopen(req, timeout=10): # noqa: S310 # nosec B310
62103
pass
104+
logger.error(f"Sent custom event '{event}' to hardcoded posthog account")
63105
except Exception: # noqa: BLE001, S110
64106
pass # nosec B110
65107

0 commit comments

Comments
 (0)