Skip to content

Commit fd3864f

Browse files
committed
feat(agents): instrument /code/agents page with analytics events
Add AGENTS_VIEWED and AGENTS_ACTION events mirroring the inbox-reports instrumentation. AGENTS_VIEWED fires once per visit via a new useTrackAgentsViewed hook; AGENTS_ACTION covers change_autostart_priority, open_mcp_servers, and run_setup_agent from ConfigureAgentsSection.
1 parent 39487b2 commit fd3864f

3 files changed

Lines changed: 118 additions & 5 deletions

File tree

packages/shared/src/analytics-events.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,33 @@ export interface SignalSourceConnectedProperties {
738738
via_setup_wizard: boolean;
739739
}
740740

741+
// Agents page events (the `/code/agents` configuration surface)
742+
export type AgentsActionType =
743+
| "run_setup_agent"
744+
| "change_autostart_priority"
745+
| "open_mcp_servers";
746+
747+
export interface AgentsViewedProperties {
748+
/** Whether code access (GitHub) is connected — gates responder configuration. */
749+
has_github_integration: boolean;
750+
/** Total number of responder source products on the page. */
751+
responder_total_count: number;
752+
/** How many of those responders are currently enabled. */
753+
responder_enabled_count: number;
754+
/** User's PR auto-start threshold priority (P0–P4), or null when set to "Never". */
755+
autostart_priority: string | null;
756+
/** Whether the agent-driven setup entry point is shown (feature-flagged). */
757+
setup_task_available: boolean;
758+
}
759+
760+
export interface AgentsActionProperties {
761+
action_type: AgentsActionType;
762+
/** New threshold for `change_autostart_priority` (P0–P4, or null for "Never"). */
763+
autostart_priority?: string | null;
764+
/** Whether `run_setup_agent` successfully created the setup task. */
765+
success?: boolean;
766+
}
767+
741768
// Subscription / billing events
742769

743770
export type UpgradePromptShownSurface = "usage_limit_modal" | "upgrade_dialog";
@@ -885,6 +912,10 @@ export const ANALYTICS_EVENTS = {
885912
INBOX_REPORT_SCROLLED: "Inbox report scrolled",
886913
SIGNAL_SOURCE_CONNECTED: "Signal source connected",
887914

915+
// Agents page events
916+
AGENTS_VIEWED: "Agents viewed",
917+
AGENTS_ACTION: "Agents action",
918+
888919
// Scout events
889920
SCOUT_FLEET_VIEWED: "Scout fleet viewed",
890921
SCOUT_DETAIL_VIEWED: "Scout detail viewed",
@@ -1015,6 +1046,10 @@ export type EventPropertyMap = {
10151046
[ANALYTICS_EVENTS.INBOX_REPORT_SCROLLED]: InboxReportScrolledProperties;
10161047
[ANALYTICS_EVENTS.SIGNAL_SOURCE_CONNECTED]: SignalSourceConnectedProperties;
10171048

1049+
// Agents page events
1050+
[ANALYTICS_EVENTS.AGENTS_VIEWED]: AgentsViewedProperties;
1051+
[ANALYTICS_EVENTS.AGENTS_ACTION]: AgentsActionProperties;
1052+
10181053
// Scout events
10191054
[ANALYTICS_EVENTS.SCOUT_FLEET_VIEWED]: ScoutFleetViewedProperties;
10201055
[ANALYTICS_EVENTS.SCOUT_DETAIL_VIEWED]: ScoutDetailViewedProperties;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { ANALYTICS_EVENTS } from "@posthog/shared/analytics-events";
2+
import { track } from "@posthog/ui/shell/analytics";
3+
import { useEffect, useRef } from "react";
4+
5+
export interface TrackAgentsViewedInput {
6+
/** Gate the event until responder / integration / autonomy data has settled. */
7+
isLoading: boolean;
8+
hasGithubIntegration: boolean;
9+
responderTotalCount: number;
10+
responderEnabledCount: number;
11+
/** P0–P4, or null when the user's auto-start threshold is "Never". */
12+
autostartPriority: string | null;
13+
setupTaskAvailable: boolean;
14+
}
15+
16+
/**
17+
* Fires `AGENTS_VIEWED` once per visit to the `/code/agents` configuration page,
18+
* after the responder/integration/autonomy data settles, with the state the user
19+
* sees on load. Mirrors `useTrackInboxViewed`; mounted from `ConfigureAgentsSection`
20+
* where the data already lives, so it fires once and survives re-renders.
21+
*/
22+
export function useTrackAgentsViewed(input: TrackAgentsViewedInput): void {
23+
const {
24+
isLoading,
25+
hasGithubIntegration,
26+
responderTotalCount,
27+
responderEnabledCount,
28+
autostartPriority,
29+
setupTaskAvailable,
30+
} = input;
31+
32+
const firedRef = useRef(false);
33+
useEffect(() => {
34+
if (firedRef.current) return;
35+
if (isLoading) return;
36+
firedRef.current = true;
37+
track(ANALYTICS_EVENTS.AGENTS_VIEWED, {
38+
has_github_integration: hasGithubIntegration,
39+
responder_total_count: responderTotalCount,
40+
responder_enabled_count: responderEnabledCount,
41+
autostart_priority: autostartPriority,
42+
setup_task_available: setupTaskAvailable,
43+
});
44+
}, [
45+
isLoading,
46+
hasGithubIntegration,
47+
responderTotalCount,
48+
responderEnabledCount,
49+
autostartPriority,
50+
setupTaskAvailable,
51+
]);
52+
}

packages/ui/src/features/inbox/components/ConfigureAgentsSection.tsx

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { Button } from "@posthog/quill";
1313
import { ANALYTICS_EVENTS, getCloudUrlFromRegion } from "@posthog/shared";
1414
import { SELF_DRIVING_SETUP_TASK_FLAG } from "@posthog/shared/constants";
1515
import type { SignalReportPriority } from "@posthog/shared/types";
16+
import { useTrackAgentsViewed } from "@posthog/ui/features/agents/hooks/useTrackAgentsViewed";
1617
import { useAuthStateValue } from "@posthog/ui/features/auth/store";
1718
import { useFeatureFlag } from "@posthog/ui/features/feature-flags/useFeatureFlag";
1819
import { DataSourceSetup } from "@posthog/ui/features/inbox/components/DataSourceSetup";
@@ -94,6 +95,15 @@ export function ConfigureAgentsSection() {
9495
const userAutostartPriority =
9596
userAutonomyConfig?.autostart_priority ?? NEVER_AUTOSTART_VALUE;
9697

98+
useTrackAgentsViewed({
99+
isLoading: isLoading || isLoadingIntegrations || userAutonomyConfigLoading,
100+
hasGithubIntegration,
101+
responderTotalCount: Object.keys(displayValues).length,
102+
responderEnabledCount: Object.values(displayValues).filter(Boolean).length,
103+
autostartPriority: userAutonomyConfig?.autostart_priority ?? null,
104+
setupTaskAvailable: showSetupTask,
105+
});
106+
97107
return (
98108
<Flex direction="column" gap="8">
99109
{showSetupTask ? <SetupTaskSection /> : null}
@@ -210,11 +220,14 @@ export function ConfigureAgentsSection() {
210220
options={USER_AUTOSTART_OPTIONS}
211221
ariaLabel="PR auto-start threshold"
212222
className="min-w-[260px] max-w-[300px]"
213-
onValueChange={(value) =>
214-
void handleUpdateUserAutonomyPriority(
215-
value === NEVER_AUTOSTART_VALUE ? null : value,
216-
)
217-
}
223+
onValueChange={(value) => {
224+
const priority = value === NEVER_AUTOSTART_VALUE ? null : value;
225+
track(ANALYTICS_EVENTS.AGENTS_ACTION, {
226+
action_type: "change_autostart_priority",
227+
autostart_priority: priority,
228+
});
229+
void handleUpdateUserAutonomyPriority(priority);
230+
}}
218231
/>
219232
)}
220233
</Flex>
@@ -226,6 +239,11 @@ export function ConfigureAgentsSection() {
226239
>
227240
<Link
228241
to="/mcp-servers"
242+
onClick={() =>
243+
track(ANALYTICS_EVENTS.AGENTS_ACTION, {
244+
action_type: "open_mcp_servers",
245+
})
246+
}
229247
className="flex items-center justify-between gap-3 rounded-(--radius-2) border border-border bg-(--color-panel-solid) px-4 py-3.5 no-underline transition-colors duration-150 hover:border-(--gray-6) hover:bg-(--gray-2)"
230248
>
231249
<Flex align="center" gap="3" className="min-w-0">
@@ -337,6 +355,10 @@ function SetupTaskSection() {
337355
});
338356

339357
sonnerToast.dismiss(toastId);
358+
track(ANALYTICS_EVENTS.AGENTS_ACTION, {
359+
action_type: "run_setup_agent",
360+
success: result.success,
361+
});
340362
if (result.success) {
341363
track(ANALYTICS_EVENTS.TASK_CREATED, {
342364
auto_run: true,
@@ -359,6 +381,10 @@ function SetupTaskSection() {
359381
}
360382
} catch (error) {
361383
sonnerToast.dismiss(toastId);
384+
track(ANALYTICS_EVENTS.AGENTS_ACTION, {
385+
action_type: "run_setup_agent",
386+
success: false,
387+
});
362388
const description =
363389
error instanceof Error ? error.message : "Unknown error";
364390
toast.error("Failed to start Self-driving setup", { description });

0 commit comments

Comments
 (0)