Skip to content

Commit 5441e4b

Browse files
committed
feat(ai): Full session replay mode
1 parent fc75987 commit 5441e4b

File tree

8 files changed

+347
-196
lines changed

8 files changed

+347
-196
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from posthog.schema import AgentMode
44

5-
from ee.hogai.tools.replay.summarize_sessions import SummarizeSessionsTool
5+
from ee.hogai.tools.replay.summarize_sessions import FilterSessionRecordingsTool, SummarizeSessionsTool
66

77
from ..factory import AgentModeDefinition
88
from ..toolkit import AgentToolkit
@@ -14,12 +14,12 @@
1414
class SessionReplayAgentToolkit(AgentToolkit):
1515
@property
1616
def tools(self) -> list[type["MaxTool"]]:
17-
tools: list[type[MaxTool]] = [SummarizeSessionsTool]
17+
tools: list[type[MaxTool]] = [FilterSessionRecordingsTool, SummarizeSessionsTool]
1818
return tools
1919

2020

2121
session_replay_agent = AgentModeDefinition(
2222
mode=AgentMode.SESSION_REPLAY,
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.",
23+
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.",
2424
toolkit_class=SessionReplayAgentToolkit,
2525
)

ee/hogai/tools/replay/summarize_sessions.py

Lines changed: 303 additions & 190 deletions
Large diffs are not rendered by default.

frontend/src/queries/schema.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,6 +1881,7 @@
18811881
"execute_sql",
18821882
"switch_mode",
18831883
"summarize_sessions",
1884+
"filter_session_recordings",
18841885
"create_insight"
18851886
],
18861887
"type": "string"

frontend/src/queries/schema/schema-assistant-messages.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,9 +294,11 @@ export type AssistantTool =
294294
| 'filter_web_analytics'
295295
| 'create_feature_flag'
296296
| 'create_experiment'
297+
// Below are modes-only
297298
| 'execute_sql'
298299
| 'switch_mode'
299300
| 'summarize_sessions'
301+
| 'filter_session_recordings'
300302
| 'create_insight'
301303

302304
export enum AgentMode {

frontend/src/scenes/max/Thread.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,7 @@ function AssistantActionComponent({
702702
icon,
703703
animate = true,
704704
showCompletionIcon = true,
705+
widget = null,
705706
}: {
706707
id: string
707708
content: string
@@ -710,6 +711,7 @@ function AssistantActionComponent({
710711
icon?: React.ReactNode
711712
animate?: boolean
712713
showCompletionIcon?: boolean
714+
widget?: JSX.Element | null
713715
}): JSX.Element {
714716
const isPending = state === 'pending'
715717
const isCompleted = state === 'completed'
@@ -801,6 +803,7 @@ function AssistantActionComponent({
801803
})}
802804
</div>
803805
)}
806+
{widget}
804807
</div>
805808
)
806809
}
@@ -867,9 +870,18 @@ function ToolCallsAnswer({ toolCalls, registeredToolMap }: ToolCallsAnswerProps)
867870
const updates = toolCall.updates ?? []
868871
const definition = getToolDefinition(toolCall.name)
869872
let description = `Executing ${toolCall.name}`
873+
let widget: JSX.Element | null = null
870874
if (definition) {
871875
if (definition.displayFormatter) {
872-
description = definition.displayFormatter(toolCall, { registeredToolMap })
876+
const displayFormatterResult = definition.displayFormatter(toolCall, {
877+
registeredToolMap,
878+
})
879+
if (typeof displayFormatterResult === 'string') {
880+
description = displayFormatterResult
881+
} else {
882+
description = displayFormatterResult[0]
883+
widget = displayFormatterResult[1]
884+
}
873885
}
874886
if (commentary) {
875887
description = commentary
@@ -884,6 +896,7 @@ function ToolCallsAnswer({ toolCalls, registeredToolMap }: ToolCallsAnswerProps)
884896
state={toolCall.status}
885897
icon={definition?.icon || <IconWrench />}
886898
showCompletionIcon={true}
899+
widget={widget}
887900
/>
888901
)
889902
})}

frontend/src/scenes/max/max-constants.tsx

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import { Scene } from 'scenes/sceneTypes'
55

66
import { iconForType } from '~/layout/panel-layout/ProjectTree/defaultTree'
77
import { AgentMode, AssistantTool } from '~/queries/schema/schema-assistant-messages'
8+
import { RecordingUniversalFilters } from '~/types'
89

910
import { EnhancedToolCall } from './Thread'
1011
import { isAgentMode } from './maxTypes'
12+
import { RecordingsWidget } from './messages/UIPayloadAnswer'
1113

1214
/** Static tool definition for display purposes. */
1315
export interface ToolDefinition<N extends string = string> {
@@ -29,7 +31,7 @@ export interface ToolDefinition<N extends string = string> {
2931
displayFormatter?: (
3032
toolCall: EnhancedToolCall,
3133
{ registeredToolMap }: { registeredToolMap: Record<string, ToolRegistration> }
32-
) => string
34+
) => string | [text: string, widget: JSX.Element | null]
3335
/**
3436
* If only available in a specific product, specify it here.
3537
* We're using Scene instead of ProductKey, because that's more flexible (specifically for SQL editor there
@@ -212,6 +214,25 @@ export const TOOL_DEFINITIONS: Record<Exclude<AssistantTool, 'todo_write'>, Tool
212214
return 'Searching recordings...'
213215
},
214216
},
217+
filter_session_recordings: {
218+
name: 'Filter recordings',
219+
description: 'Filter recordings to find the most relevant ones',
220+
product: Scene.Replay,
221+
icon: iconForType('session_replay'),
222+
displayFormatter: (toolCall) => {
223+
const widget = toolCall.args?.recordings_filters ? (
224+
<RecordingsWidget
225+
toolCallId={toolCall.id}
226+
filters={toolCall.args.recordings_filters as RecordingUniversalFilters}
227+
/>
228+
) : null
229+
230+
if (toolCall.status === 'completed') {
231+
return ['Filtered recordings', widget]
232+
}
233+
return ['Filtering recordings...', widget]
234+
},
235+
},
215236
generate_hogql_query: {
216237
name: 'Write and tweak SQL',
217238
description: 'Write and tweak SQL right there',

frontend/src/scenes/max/messages/UIPayloadAnswer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export function UIPayloadAnswer({
3535
return null
3636
}
3737

38-
function RecordingsWidget({
38+
export function RecordingsWidget({
3939
toolCallId,
4040
filters,
4141
}: {

posthog/schema.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ class AssistantTool(StrEnum):
295295
EXECUTE_SQL = "execute_sql"
296296
SWITCH_MODE = "switch_mode"
297297
SUMMARIZE_SESSIONS = "summarize_sessions"
298+
FILTER_SESSION_RECORDINGS = "filter_session_recordings"
298299
CREATE_INSIGHT = "create_insight"
299300

300301

0 commit comments

Comments
 (0)