diff --git a/hooks/langfuse_hook.py b/hooks/langfuse_hook.py index cdd8f64..856a03d 100644 --- a/hooks/langfuse_hook.py +++ b/hooks/langfuse_hook.py @@ -639,6 +639,9 @@ def get_user_or_assistant_role_from_row(row: Dict[str, Any]) -> Optional[str]: # Claude Code transcript row format is internal. Prefer top-level row.type # when it marks a chat row, then fall back to nested message.role. row_type = row.get("type") + # Request snapshots are internal records, not conversation messages. + if row_type == "api-request-blob": + return None if row_type in ("user", "assistant"): return row_type diff --git a/tests/integration/test_state_lock_contention.py b/tests/integration/test_state_lock_contention.py index 899105b..4b7734a 100644 --- a/tests/integration/test_state_lock_contention.py +++ b/tests/integration/test_state_lock_contention.py @@ -111,7 +111,7 @@ def test_entry_of_another_session_survives_the_emit( def other_session_saves() -> None: with hook_module.FileLock(hook_module.LOCK_FILE): state = hook_module.load_hook_state() - state["other-session-key"] = {"offset": 42, "updated": "2026-09-10T00:00:00+00:00"} + state["other-session-key"] = {"offset": 42, "updated": _now_iso()} hook_module.save_hook_state(state) _during_emit(hook_module, monkeypatch, other_session_saves) diff --git a/tests/unit/test_turn_assembly.py b/tests/unit/test_turn_assembly.py index 22eeb85..ffaafdd 100644 --- a/tests/unit/test_turn_assembly.py +++ b/tests/unit/test_turn_assembly.py @@ -1,5 +1,13 @@ from __future__ import annotations +import pytest + + +@pytest.mark.parametrize("role", ["user", "assistant"]) +def test_api_request_snapshots_are_not_conversation_rows(hook_module, role): + row = {"type": "api-request-blob", "message": {"role": role}} + assert hook_module.get_user_or_assistant_role_from_row(row) is None + def test_build_turns_merges_split_assistant_rows( hook_module,