Skip to content

Commit c4ff25d

Browse files
committed
fix: exception serialization
1 parent 4fe220d commit c4ff25d

File tree

2 files changed

+49
-5
lines changed

2 files changed

+49
-5
lines changed

posthog/ai/langchain/callbacks.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ def on_chain_error(
163163
**kwargs: Any,
164164
):
165165
self._log_debug_event("on_chain_error", run_id, parent_run_id, error=error)
166-
self._pop_run_and_capture_trace_or_span(run_id, parent_run_id, str(error))
166+
self._pop_run_and_capture_trace_or_span(run_id, parent_run_id, error)
167167

168168
def on_chat_model_start(
169169
self,
@@ -262,7 +262,7 @@ def on_tool_error(
262262
**kwargs: Any,
263263
) -> Any:
264264
self._log_debug_event("on_tool_error", run_id, parent_run_id, error=error)
265-
self._pop_run_and_capture_trace_or_span(run_id, parent_run_id, str(error))
265+
self._pop_run_and_capture_trace_or_span(run_id, parent_run_id, error)
266266

267267
def on_retriever_start(
268268
self,
@@ -299,7 +299,7 @@ def on_retriever_error(
299299
) -> Any:
300300
"""Run when Retriever errors."""
301301
self._log_debug_event("on_retriever_error", run_id, parent_run_id, error=error)
302-
self._pop_run_and_capture_trace_or_span(run_id, parent_run_id, str(error))
302+
self._pop_run_and_capture_trace_or_span(run_id, parent_run_id, error)
303303

304304
def on_agent_action(
305305
self,
@@ -448,8 +448,13 @@ def _capture_trace_or_span(
448448
event_properties["$ai_trace_name"] = run.name
449449
if self._properties:
450450
event_properties.update(self._properties)
451-
if outputs is not None:
451+
452+
if isinstance(outputs, BaseException):
453+
event_properties["$ai_error"] = _stringify_exception(outputs)
454+
event_properties["$ai_is_error"] = True
455+
elif outputs is not None:
452456
event_properties["$ai_output_state"] = with_privacy_mode(self._client, self._privacy_mode, outputs)
457+
453458
if self._distinct_id is None:
454459
event_properties["$process_person_profile"] = False
455460

@@ -498,7 +503,7 @@ def _capture_generation(
498503

499504
if isinstance(output, BaseException):
500505
event_properties["$ai_http_status"] = _get_http_status(output)
501-
event_properties["$ai_error"] = str(output)
506+
event_properties["$ai_error"] = _stringify_exception(output)
502507
event_properties["$ai_is_error"] = True
503508
else:
504509
# Add usage
@@ -687,3 +692,10 @@ def _get_langchain_run_name(serialized: Optional[Dict[str, Any]], **kwargs: Any)
687692
except (KeyError, TypeError):
688693
pass
689694
return None
695+
696+
697+
def _stringify_exception(exception: BaseException) -> str:
698+
description = str(exception)
699+
if description:
700+
return f"{exception.__class__.__name__}: {description}"
701+
return exception.__class__.__name__

posthog/test/ai/langchain/test_callbacks.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,3 +1311,35 @@ def span_3(_):
13111311
span2, span1, trace = [call[1]["properties"] for call in mock_client.capture.call_args_list]
13121312
assert span2["$ai_parent_id"] == span1["$ai_span_id"]
13131313
assert span1["$ai_parent_id"] == trace["$ai_trace_id"]
1314+
1315+
1316+
def test_captures_error_with_details_in_span(mock_client):
1317+
def span(_):
1318+
raise ValueError("test")
1319+
1320+
callbacks = [CallbackHandler(mock_client)]
1321+
chain = RunnableLambda(span) | RunnableLambda(lambda _: "foo")
1322+
try:
1323+
chain.invoke({}, config={"callbacks": callbacks})
1324+
except ValueError:
1325+
pass
1326+
1327+
assert mock_client.capture.call_count == 2
1328+
assert mock_client.capture.call_args_list[1][1]["properties"]["$ai_error"] == "ValueError: test"
1329+
assert mock_client.capture.call_args_list[1][1]["properties"]["$ai_is_error"]
1330+
1331+
1332+
def test_captures_error_without_details_in_span(mock_client):
1333+
def span(_):
1334+
raise ValueError
1335+
1336+
callbacks = [CallbackHandler(mock_client)]
1337+
chain = RunnableLambda(span) | RunnableLambda(lambda _: "foo")
1338+
try:
1339+
chain.invoke({}, config={"callbacks": callbacks})
1340+
except ValueError:
1341+
pass
1342+
1343+
assert mock_client.capture.call_count == 2
1344+
assert mock_client.capture.call_args_list[1][1]["properties"]["$ai_error"] == "ValueError"
1345+
assert mock_client.capture.call_args_list[1][1]["properties"]["$ai_is_error"]

0 commit comments

Comments
 (0)