Skip to content

Commit fc871a1

Browse files
authored
revert: "feat(ai): Full session replay mode" (#42633)
1 parent 2239b61 commit fc871a1

File tree

56 files changed

+382
-1102
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+382
-1102
lines changed

ee/hogai/chat_agent/session_summaries/nodes.py

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
from posthog.schema import AssistantMessage, AssistantToolCallMessage, MaxRecordingUniversalFilters, RecordingsQuery
1414

15-
from posthog.session_recordings.playlist_counters import convert_filters_to_recordings_query
15+
from posthog.session_recordings.models.session_recording_playlist import SessionRecordingPlaylist
1616
from posthog.sync import database_sync_to_async
1717
from posthog.temporal.ai.session_summary.summarize_session import execute_summarize_session
1818
from posthog.temporal.ai.session_summary.summarize_session_group import (
@@ -299,6 +299,41 @@ async def _generate_replay_filters(
299299
)
300300
return None
301301

302+
def _convert_max_filters_to_recordings_query(self, replay_filters: MaxRecordingUniversalFilters) -> RecordingsQuery:
303+
"""Convert Max-generated filters into recordings query format"""
304+
properties = []
305+
if replay_filters.filter_group and replay_filters.filter_group.values:
306+
for inner_group in replay_filters.filter_group.values:
307+
if hasattr(inner_group, "values"):
308+
properties.extend(inner_group.values)
309+
recordings_query = RecordingsQuery(
310+
date_from=replay_filters.date_from,
311+
date_to=replay_filters.date_to,
312+
properties=properties,
313+
filter_test_accounts=replay_filters.filter_test_accounts,
314+
limit=replay_filters.limit,
315+
order=replay_filters.order,
316+
# Handle duration filters - preserve the original key (e.g., "active_seconds" or "duration")
317+
having_predicates=(
318+
[
319+
{"key": dur.key, "type": "recording", "operator": dur.operator, "value": dur.value}
320+
for dur in (replay_filters.duration or [])
321+
]
322+
if replay_filters.duration
323+
else None
324+
),
325+
)
326+
return recordings_query
327+
328+
def _convert_current_filters_to_recordings_query(self, current_filters: dict[str, Any]) -> RecordingsQuery:
329+
"""Convert current filters into recordings query format"""
330+
from posthog.session_recordings.playlist_counters import convert_filters_to_recordings_query
331+
332+
# Create a temporary playlist object to use the conversion function
333+
temp_playlist = SessionRecordingPlaylist(filters=current_filters)
334+
recordings_query = convert_filters_to_recordings_query(temp_playlist)
335+
return recordings_query
336+
302337
def _get_session_ids_with_filters(self, replay_filters: RecordingsQuery) -> list[str] | None:
303338
"""Get session ids from DB with filters"""
304339
from posthog.session_recordings.queries.session_recording_list_from_query import SessionRecordingListFromQuery
@@ -404,7 +439,7 @@ async def search_sessions(
404439
)
405440
return self._node._create_error_response(self._node._base_error_instructions, state)
406441
current_filters = cast(dict[str, Any], current_filters)
407-
replay_filters = convert_filters_to_recordings_query(current_filters)
442+
replay_filters = self._convert_current_filters_to_recordings_query(current_filters)
408443
# If not - generate filters to get session ids from DB
409444
else:
410445
filter_query = await self._generate_filter_query(state.session_summarization_query, config)
@@ -436,9 +471,7 @@ async def search_sessions(
436471
root_tool_call_id=None,
437472
)
438473
# Use filters when generated successfully
439-
replay_filters = convert_filters_to_recordings_query(
440-
filter_generation_result.model_dump(exclude_none=True)
441-
)
474+
replay_filters = self._convert_max_filters_to_recordings_query(filter_generation_result)
442475
self._node._stream_filters(filter_generation_result)
443476
# Query the filters to get session ids
444477
if (

ee/hogai/chat_agent/session_summaries/test/test_nodes.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
from posthog.clickhouse.client import sync_execute
3333
from posthog.clickhouse.log_entries import TRUNCATE_LOG_ENTRIES_TABLE_SQL
3434
from posthog.models import SessionRecording
35-
from posthog.session_recordings.playlist_counters import convert_filters_to_recordings_query
3635
from posthog.session_recordings.queries.test.session_replay_sql import produce_replay_summary
3736
from posthog.session_recordings.sql.session_replay_event_sql import TRUNCATE_SESSION_REPLAY_EVENTS_TABLE_SQL
3837
from posthog.temporal.ai.session_summary.summarize_session_group import SessionSummaryStreamUpdate
@@ -141,7 +140,7 @@ def test_get_session_ids_with_filters_empty(self, mock_query_runner_class: Magic
141140
mock_query_runner_class.return_value = mock_query_runner
142141

143142
# Convert MaxRecordingUniversalFilters to RecordingsQuery
144-
recordings_query = convert_filters_to_recordings_query(mock_filters.model_dump(exclude_none=True))
143+
recordings_query = self.node._session_search._convert_max_filters_to_recordings_query(mock_filters)
145144
result = self.node._session_search._get_session_ids_with_filters(
146145
replay_filters=recordings_query,
147146
)
@@ -156,10 +155,20 @@ def test_get_session_ids_with_filters_with_duration(self, mock_query_runner_clas
156155
mock_query_runner_class.return_value = mock_query_runner
157156

158157
# First convert MaxRecordingUniversalFilters to RecordingsQuery
159-
recordings_query = convert_filters_to_recordings_query(mock_filters.model_dump(exclude_none=True))
160-
result = self.node._session_search._get_session_ids_with_filters(recordings_query)
158+
recordings_query = self.node._session_search._convert_max_filters_to_recordings_query(mock_filters)
159+
result = self.node._session_search._get_session_ids_with_filters(
160+
replay_filters=recordings_query,
161+
)
162+
161163
self.assertEqual(result, ["session-1"])
162164

165+
# Verify duration filters were converted to having_predicates
166+
call_args = mock_query_runner_class.call_args
167+
# The query parameter should have having_predicates
168+
query_param = call_args[1]["query"]
169+
self.assertIsNotNone(query_param.having_predicates)
170+
self.assertEqual(len(query_param.having_predicates), 2)
171+
163172
@patch("posthog.session_recordings.queries.session_recording_list_from_query.SessionRecordingListFromQuery")
164173
@patch("ee.hogai.chat_agent.session_summaries.nodes.database_sync_to_async")
165174
@patch("products.replay.backend.max_tools.SearchSessionRecordingsTool")
@@ -813,7 +822,7 @@ def test_use_current_filters_with_os_and_events(self) -> None:
813822
}
814823

815824
# Convert custom filters to recordings query
816-
recordings_query = convert_filters_to_recordings_query(custom_filters)
825+
recordings_query = self.node._session_search._convert_current_filters_to_recordings_query(custom_filters)
817826

818827
# Use the node's method to get session IDs
819828
session_ids = self.node._session_search._get_session_ids_with_filters(
@@ -850,7 +859,7 @@ def test_use_current_filters_with_date_range(self) -> None:
850859
}
851860

852861
# Convert custom filters to recordings query
853-
recordings_query = convert_filters_to_recordings_query(custom_filters)
862+
recordings_query = self.node._session_search._convert_current_filters_to_recordings_query(custom_filters)
854863

855864
# Use the node's method to get session IDs
856865
session_ids = self.node._session_search._get_session_ids_with_filters(
@@ -888,7 +897,7 @@ def test_generate_filters_last_10_days(self) -> None:
888897
)
889898

890899
# Convert the generated filters to recordings query using the node's method
891-
recordings_query = convert_filters_to_recordings_query(generated_filters.model_dump(exclude_none=True))
900+
recordings_query = self.node._session_search._convert_max_filters_to_recordings_query(generated_filters)
892901

893902
# Use the node's method to get session IDs
894903
session_ids = self.node._session_search._get_session_ids_with_filters(
@@ -923,7 +932,7 @@ def test_get_session_ids_respects_limit(self) -> None:
923932
}
924933

925934
# Convert custom filters to recordings query
926-
recordings_query = convert_filters_to_recordings_query(custom_filters)
935+
recordings_query = self.node._session_search._convert_current_filters_to_recordings_query(custom_filters)
927936

928937
# Get session IDs with explicit limit of 1
929938
session_ids = self.node._session_search._get_session_ids_with_filters(replay_filters=recordings_query)

ee/hogai/core/agent_modes/presets/session_replay.py

Lines changed: 2 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -2,102 +2,24 @@
22

33
from posthog.schema import AgentMode
44

5-
from ee.hogai.tools.replay.filter_session_recordings import FilterSessionRecordingsTool
65
from ee.hogai.tools.replay.summarize_sessions import SummarizeSessionsTool
7-
from ee.hogai.tools.todo_write import TodoWriteExample
86

97
from ..factory import AgentModeDefinition
108
from ..toolkit import AgentToolkit
119

1210
if TYPE_CHECKING:
1311
from ee.hogai.tool import MaxTool
1412

15-
POSITIVE_EXAMPLE_FILTER_WITH_PROPERTIES = """
16-
User: Show me recordings of mobile users from the US who encountered errors
17-
Assistant: I'll help you find those recordings. Let me create a todo list to ensure I discover the right properties and filters.
18-
*Creates todo list with the following items:*
19-
1. Use read_taxonomy to discover person properties for country filtering
20-
2. Use read_taxonomy to discover session properties for device type
21-
3. Use read_taxonomy to discover recording properties for errors
22-
4. Filter session recordings with the discovered properties
23-
*Begins working on the first task*
24-
""".strip()
25-
26-
POSITIVE_EXAMPLE_FILTER_WITH_PROPERTIES_REASONING = """
27-
The assistant used the todo list because:
28-
1. Filtering session recordings requires discovering multiple property types (person, session, recording)
29-
2. Property names and values must be validated through read_taxonomy before creating filters
30-
3. The query involves multiple filter criteria that need to be combined
31-
4. The filter_session_recordings tool documentation explicitly requires using read_taxonomy for property discovery
32-
5. Breaking this into steps ensures all properties are discovered before attempting to filter
33-
""".strip()
34-
35-
POSITIVE_EXAMPLE_SUMMARIZE_WITH_CONTEXT = """
36-
User: Summarize sessions where users clicked the checkout button but didn't complete purchase
37-
Assistant: I'll help you analyze those sessions. This requires multiple steps to ensure we get the right recordings.
38-
*Creates todo list with the following items:*
39-
1. Use read_taxonomy to discover events related to checkout
40-
2. Use read_taxonomy to discover events related to purchase completion
41-
3. Filter session recordings for sessions with checkout events but without purchase events
42-
4. Summarize the filtered sessions to identify patterns and issues
43-
*Begins working on the first task*
44-
""".strip()
45-
46-
POSITIVE_EXAMPLE_SUMMARIZE_WITH_CONTEXT_REASONING = """
47-
The assistant used the todo list because:
48-
1. Session summarization requires filtering first (can't summarize without identifying relevant sessions)
49-
2. The filtering requires discovering event properties through read_taxonomy
50-
3. Complex event-based filters need validation before being used
51-
4. The summarize_sessions tool requires filter_session_recordings to be called first
52-
5. This is a multi-step analysis requiring systematic progression through discovery, filtering, and summarization
53-
""".strip()
54-
55-
POSITIVE_EXAMPLE_MULTIPLE_RECORDING_ANALYSES = """
56-
User: Compare mobile vs desktop user behavior and also check if users with errors have different session patterns
57-
Assistant: I'll help you analyze these different user segments. Let me break this down into separate analyses.
58-
*Creates todo list with the following items:*
59-
1. Filter and summarize mobile user sessions
60-
2. Filter and summarize desktop user sessions
61-
3. Filter and summarize sessions with console errors
62-
4. Filter and summarize sessions without errors
63-
5. Compare findings across segments
64-
*Begins working on the first task*
65-
""".strip()
66-
67-
POSITIVE_EXAMPLE_MULTIPLE_RECORDING_ANALYSES_REASONING = """
68-
The assistant used the todo list because:
69-
1. The user requested multiple separate recording analyses that need distinct filters
70-
2. Each segment (mobile, desktop, errors, no errors) requires its own filter_session_recordings call
71-
3. Each segment needs individual summarization
72-
4. The todo list helps organize these parallel analyses into manageable tasks
73-
5. This approach allows for tracking progress across multiple recording queries and summaries
74-
""".strip()
75-
7613

7714
class SessionReplayAgentToolkit(AgentToolkit):
78-
POSITIVE_TODO_EXAMPLES = [
79-
TodoWriteExample(
80-
example=POSITIVE_EXAMPLE_FILTER_WITH_PROPERTIES,
81-
reasoning=POSITIVE_EXAMPLE_FILTER_WITH_PROPERTIES_REASONING,
82-
),
83-
TodoWriteExample(
84-
example=POSITIVE_EXAMPLE_SUMMARIZE_WITH_CONTEXT,
85-
reasoning=POSITIVE_EXAMPLE_SUMMARIZE_WITH_CONTEXT_REASONING,
86-
),
87-
TodoWriteExample(
88-
example=POSITIVE_EXAMPLE_MULTIPLE_RECORDING_ANALYSES,
89-
reasoning=POSITIVE_EXAMPLE_MULTIPLE_RECORDING_ANALYSES_REASONING,
90-
),
91-
]
92-
9315
@property
9416
def tools(self) -> list[type["MaxTool"]]:
95-
tools: list[type[MaxTool]] = [FilterSessionRecordingsTool, SummarizeSessionsTool]
17+
tools: list[type[MaxTool]] = [SummarizeSessionsTool]
9618
return tools
9719

9820

9921
session_replay_agent = AgentModeDefinition(
10022
mode=AgentMode.SESSION_REPLAY,
101-
mode_description="Specialized mode for analyzing session recordings and user behavior. This mode allows you to filter session recordings, and summarize entire sessions or a set of them.",
23+
mode_description="Specialized mode for analyzing session recordings and user behavior. This mode allows you to get summaries of session recordings and insights about them in natural language.",
10224
toolkit_class=SessionReplayAgentToolkit,
10325
)

0 commit comments

Comments
 (0)