Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions posthog/ai/claude_agent_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,14 +242,12 @@ async def disconnect(self) -> None:
**self._extra_props,
}

if resolved_id is None:
properties["$process_person_profile"] = False

self._processor._capture_event(
"$ai_trace",
properties,
resolved_id or self._trace_id,
self._groups,
personless=resolved_id is None,
)

try:
Expand Down
42 changes: 26 additions & 16 deletions posthog/ai/claude_agent_sdk/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ def _capture_event(
properties: Dict[str, Any],
distinct_id: Optional[str] = None,
groups: Optional[Dict[str, Any]] = None,
personless: bool = False,
) -> None:
_capture_processor_event(
self._client,
Expand All @@ -200,6 +201,7 @@ def _capture_event(
default_properties=self._properties,
distinct_id=distinct_id,
groups=groups if groups is not None else self._groups,
personless=personless,
)

async def query(
Expand Down Expand Up @@ -449,11 +451,12 @@ def _emit_generation(
if gen.stop_reason is not None:
properties["$ai_stop_reason"] = gen.stop_reason

if resolved_id is None:
properties["$process_person_profile"] = False

self._capture_event(
"$ai_generation", properties, resolved_id or trace_id, groups
"$ai_generation",
properties,
resolved_id or trace_id,
groups,
personless=resolved_id is None,
)

def _emit_generation_from_result(
Expand Down Expand Up @@ -522,11 +525,12 @@ def _emit_generation_from_result(
if result.total_cost_usd is not None:
properties["$ai_total_cost_usd"] = result.total_cost_usd

if resolved_id is None:
properties["$process_person_profile"] = False

self._capture_event(
"$ai_generation", properties, resolved_id or trace_id, groups
"$ai_generation",
properties,
resolved_id or trace_id,
groups,
personless=resolved_id is None,
)

def _emit_tool_span(
Expand Down Expand Up @@ -557,10 +561,13 @@ def _emit_tool_span(
_ensure_serializable(block.input), self._client
)

if resolved_id is None:
properties["$process_person_profile"] = False

self._capture_event("$ai_span", properties, resolved_id or trace_id, groups)
self._capture_event(
"$ai_span",
properties,
resolved_id or trace_id,
groups,
personless=resolved_id is None,
)

def _emit_trace(
self,
Expand Down Expand Up @@ -592,10 +599,13 @@ def _emit_trace(
if result.total_cost_usd is not None:
properties["$ai_total_cost_usd"] = result.total_cost_usd

if resolved_id is None:
properties["$process_person_profile"] = False

self._capture_event("$ai_trace", properties, resolved_id or trace_id, groups)
self._capture_event(
"$ai_trace",
properties,
resolved_id or trace_id,
groups,
personless=resolved_id is None,
)

# Flush to ensure events are sent before process exits
try:
Expand Down
4 changes: 1 addition & 3 deletions posthog/ai/gemini/_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,13 +266,11 @@ def _capture_embedding_outcome(
event_properties["$ai_is_error"] = True
event_properties["$ai_error"] = str(error)

if distinct_id is None:
event_properties["$process_person_profile"] = False

_capture_ai_event(
self._ph_client,
"$ai_embedding",
distinct_id=distinct_id or trace_id,
properties=event_properties,
groups=groups,
personless=distinct_id is None,
)
8 changes: 2 additions & 6 deletions posthog/ai/langchain/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,15 +577,13 @@ def _capture_trace_or_span(
finalize_ai_content(outputs, self._ph_client),
)

if self._distinct_id is None:
event_properties["$process_person_profile"] = False

_capture_ai_event(
self._ph_client,
event_name,
distinct_id=self._distinct_id or run_id,
properties=event_properties,
groups=self._groups,
personless=self._distinct_id is None,
)

def _pop_run_and_capture_generation(
Expand Down Expand Up @@ -662,9 +660,6 @@ def _capture_generation(
if self._properties:
event_properties.update(self._properties)

if self._distinct_id is None:
event_properties["$process_person_profile"] = False

if isinstance(output, BaseException):
event_properties["$ai_http_status"] = _get_http_status(output)
event_properties["$ai_error"] = _stringify_exception(output)
Expand Down Expand Up @@ -737,6 +732,7 @@ def _capture_generation(
distinct_id=self._distinct_id or trace_id,
properties=event_properties,
groups=self._groups,
personless=self._distinct_id is None,
)

def _log_debug_event(
Expand Down
4 changes: 1 addition & 3 deletions posthog/ai/openai/_embeddings.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,12 @@ def _capture_embedding_event(
**(properties or {}),
}

if distinct_id is None:
event_properties["$process_person_profile"] = False

if hasattr(posthog_client, "capture"):
_capture_ai_event(
posthog_client,
"$ai_embedding",
distinct_id=distinct_id or trace_id,
properties=event_properties,
groups=groups,
personless=distinct_id is None,
)
42 changes: 19 additions & 23 deletions posthog/ai/openai_agents/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,18 @@ def _capture_event(
properties: Dict[str, Any],
distinct_id: Optional[str] = None,
) -> None:
"""Capture an event without allowing telemetry failures to escape."""
"""Capture an event without allowing telemetry failures to escape.

Without a distinct ID, the event is personless and uses its trace ID.
"""
_capture_processor_event(
self._client,
event,
properties,
default_properties=self._properties,
distinct_id=distinct_id,
distinct_id=distinct_id or properties.get("$ai_trace_id"),
groups=self._groups,
personless=distinct_id is None,
)

def on_trace_start(self, trace: Trace) -> None:
Expand Down Expand Up @@ -228,12 +232,9 @@ def on_trace_end(self, trace: Trace) -> None:
if metadata:
properties["$ai_trace_metadata"] = _ensure_serializable(metadata)

if distinct_id is None:
properties["$process_person_profile"] = False

self._capture_event(
event="$ai_trace",
distinct_id=distinct_id or trace_id,
distinct_id=distinct_id,
properties=properties,
)
except Exception as e:
Expand Down Expand Up @@ -267,8 +268,8 @@ def on_span_end(self, span: Span[Any]) -> None:
latency = (ended - started) if (started and ended) else 0

# Get user-provided distinct ID from trace metadata (resolved at trace start).
# None means no user-provided ID — use trace_id as fallback in personless mode,
# matching the langchain/openai pattern: `distinct_id or trace_id`.
# None means no user-provided ID: _capture_event falls back to the
# trace ID and makes the event personless.
trace_info = self._trace_metadata.get(trace_id, {})
distinct_id = trace_info.get("distinct_id") or self._get_distinct_id(None)

Expand Down Expand Up @@ -317,11 +318,6 @@ def on_span_end(self, span: Span[Any]) -> None:
"$ai_error_type": error_type,
}

# Personless mode: no user-provided distinct_id, fallback to trace_id
if distinct_id is None:
error_properties["$process_person_profile"] = False
distinct_id = trace_id

# Dispatch based on span data type
if isinstance(span_data, GenerationSpanData):
self._handle_generation_span(
Expand Down Expand Up @@ -471,7 +467,7 @@ def _handle_generation_span(
span_id: str,
parent_id: Optional[str],
latency: float,
distinct_id: str,
distinct_id: Optional[str],
group_id: Optional[str],
error_properties: Dict[str, Any],
) -> None:
Expand Down Expand Up @@ -554,7 +550,7 @@ def _handle_function_span(
span_id: str,
parent_id: Optional[str],
latency: float,
distinct_id: str,
distinct_id: Optional[str],
group_id: Optional[str],
error_properties: Dict[str, Any],
) -> None:
Expand Down Expand Up @@ -587,7 +583,7 @@ def _handle_agent_span(
span_id: str,
parent_id: Optional[str],
latency: float,
distinct_id: str,
distinct_id: Optional[str],
group_id: Optional[str],
error_properties: Dict[str, Any],
) -> None:
Expand Down Expand Up @@ -616,7 +612,7 @@ def _handle_handoff_span(
span_id: str,
parent_id: Optional[str],
latency: float,
distinct_id: str,
distinct_id: Optional[str],
group_id: Optional[str],
error_properties: Dict[str, Any],
) -> None:
Expand All @@ -640,7 +636,7 @@ def _handle_guardrail_span(
span_id: str,
parent_id: Optional[str],
latency: float,
distinct_id: str,
distinct_id: Optional[str],
group_id: Optional[str],
error_properties: Dict[str, Any],
) -> None:
Expand All @@ -663,7 +659,7 @@ def _handle_response_span(
span_id: str,
parent_id: Optional[str],
latency: float,
distinct_id: str,
distinct_id: Optional[str],
group_id: Optional[str],
error_properties: Dict[str, Any],
) -> None:
Expand Down Expand Up @@ -732,7 +728,7 @@ def _handle_custom_span(
span_id: str,
parent_id: Optional[str],
latency: float,
distinct_id: str,
distinct_id: Optional[str],
group_id: Optional[str],
error_properties: Dict[str, Any],
) -> None:
Expand All @@ -757,7 +753,7 @@ def _handle_audio_span(
span_id: str,
parent_id: Optional[str],
latency: float,
distinct_id: str,
distinct_id: Optional[str],
group_id: Optional[str],
error_properties: Dict[str, Any],
) -> None:
Expand Down Expand Up @@ -832,7 +828,7 @@ def _handle_mcp_span(
span_id: str,
parent_id: Optional[str],
latency: float,
distinct_id: str,
distinct_id: Optional[str],
group_id: Optional[str],
error_properties: Dict[str, Any],
) -> None:
Expand All @@ -856,7 +852,7 @@ def _handle_generic_span(
span_id: str,
parent_id: Optional[str],
latency: float,
distinct_id: str,
distinct_id: Optional[str],
group_id: Optional[str],
error_properties: Dict[str, Any],
) -> None:
Expand Down
Loading
Loading