Skip to content

Commit 45d82bd

Browse files
committed
fix(agents): correct AGENTS_VIEWED payload + track failed setup attempts
Addresses Codex review on the analytics PR: - has_github_integration: derive from the integrations query data instead of the store-backed value, which is hydrated by a passive effect that lags the query by a render and could lock in a stale false on the settle render. - responder counts: count only RESPONDER_AGENT_GROUPS sources; displayValues also carries the legacy signals_scout toggle, which renders separately and was inflating responder_total_count / responder_enabled_count. - run_setup_agent: emit success:false at the precondition guards (missing github/repo/region/user-integration, unresolved model) so failed setup attempts stay in the funnel instead of biasing the success rate upward.
1 parent 7f11b0d commit 45d82bd

1 file changed

Lines changed: 49 additions & 3 deletions

File tree

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

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
REPORT_MODEL_RESOLVER,
44
type ReportModelResolver,
55
} from "@posthog/core/inbox/identifiers";
6+
import { classifyIntegrations } from "@posthog/core/integrations/selectors";
67
import {
78
TASK_SERVICE,
89
type TaskCreationInput,
@@ -21,6 +22,10 @@ import {
2122
ResponderAgentRoster,
2223
ResponderAgentRosterSkeleton,
2324
} from "@posthog/ui/features/inbox/components/ResponderAgentRoster";
25+
import {
26+
RESPONDER_AGENT_GROUPS,
27+
type ResponderAgentSource,
28+
} from "@posthog/ui/features/inbox/components/responderAgentMeta";
2429
import { resolveDefaultModel } from "@posthog/ui/features/inbox/hooks/resolveDefaultModel";
2530
import { useSignalSourceManager } from "@posthog/ui/features/inbox/hooks/useSignalSourceManager";
2631
import {
@@ -72,6 +77,18 @@ Inspect the connected PostHog project and repository, figure out which Self-driv
7277

7378
const log = logger.scope("agents-setup-task");
7479

80+
/**
81+
* Source products that count as Responders on this page. `displayValues` also
82+
* carries the legacy `signals_scout` toggle, but scouts render separately in
83+
* `ScoutsFleetSection` and are excluded from the responder roster — so they must
84+
* not inflate the responder counts in `AGENTS_VIEWED`.
85+
*/
86+
const RESPONDER_SOURCE_PRODUCTS = new Set<ResponderAgentSource>(
87+
RESPONDER_AGENT_GROUPS.flatMap((group) =>
88+
group.agents.map((agent) => agent.source),
89+
),
90+
);
91+
7592
export function ConfigureAgentsSection() {
7693
const {
7794
displayValues,
@@ -92,18 +109,33 @@ export function ConfigureAgentsSection() {
92109
const {
93110
isLoading: isLoadingSlackIntegrations,
94111
isError: isIntegrationsError,
112+
data: integrationsData,
95113
} = useIntegrations();
96114
const isLoadingSlack = isLoadingIntegrations || isLoadingSlackIntegrations;
97115
const showSetupTask = useFeatureFlag(SELF_DRIVING_SETUP_TASK_FLAG);
98116
const userAutostartPriority =
99117
userAutonomyConfig?.autostart_priority ?? NEVER_AUTOSTART_VALUE;
100118

119+
// Derive from the query data, not the store-backed `hasGithubIntegration`: the
120+
// store is hydrated by a passive effect that lags the query by a render, so the
121+
// store value can still read `false` on the render where the query settles —
122+
// exactly when the view event fires. Classifying the query data avoids the lag.
123+
const trackedHasGithubIntegration = classifyIntegrations(
124+
integrationsData ?? [],
125+
).hasGithubIntegration;
126+
// Count only Responder sources; `displayValues` also includes `signals_scout`,
127+
// which renders separately and would otherwise inflate the responder counts.
128+
const responderEntries = Object.entries(displayValues).filter(([source]) =>
129+
RESPONDER_SOURCE_PRODUCTS.has(source as ResponderAgentSource),
130+
);
131+
101132
useTrackAgentsViewed({
102133
isLoading: isLoading || isLoadingIntegrations || userAutonomyConfigLoading,
103134
isError: isIntegrationsError,
104-
hasGithubIntegration,
105-
responderTotalCount: Object.keys(displayValues).length,
106-
responderEnabledCount: Object.values(displayValues).filter(Boolean).length,
135+
hasGithubIntegration: trackedHasGithubIntegration,
136+
responderTotalCount: responderEntries.length,
137+
responderEnabledCount: responderEntries.filter(([, enabled]) => enabled)
138+
.length,
107139
autostartPriority: userAutonomyConfig?.autostart_priority ?? null,
108140
setupTaskAvailable: showSetupTask,
109141
});
@@ -292,23 +324,36 @@ function SetupTaskSection() {
292324
);
293325

294326
const handleStartSetup = useCallback(async () => {
327+
// A click that fails a precondition is still a failed setup attempt; emit
328+
// `run_setup_agent` with success:false so these don't drop out of the funnel
329+
// and bias the success rate upward. (The re-entrancy and still-loading guards
330+
// below are not attempts, so they don't fire.)
331+
const trackSetupFailure = () =>
332+
track(ANALYTICS_EVENTS.AGENTS_ACTION, {
333+
action_type: "run_setup_agent",
334+
success: false,
335+
});
336+
295337
if (isStartingSetupTask) return;
296338
if (isLoadingRepos) {
297339
toast.error("Still loading GitHub repositories");
298340
return;
299341
}
300342
if (!hasGithubIntegration || !setupRepository) {
343+
trackSetupFailure();
301344
toast.error("Connect GitHub before starting Self-driving setup");
302345
return;
303346
}
304347
if (!cloudRegion) {
348+
trackSetupFailure();
305349
toast.error("Sign in to start Self-driving setup");
306350
return;
307351
}
308352

309353
const githubUserIntegrationId =
310354
getUserIntegrationIdForRepo(setupRepository);
311355
if (!githubUserIntegrationId) {
356+
trackSetupFailure();
312357
toast.error("Connect a GitHub integration with repository access");
313358
return;
314359
}
@@ -334,6 +379,7 @@ function SetupTaskSection() {
334379

335380
if (!model) {
336381
sonnerToast.dismiss(toastId);
382+
trackSetupFailure();
337383
toast.error("Failed to start Self-driving setup", {
338384
description:
339385
"Couldn't resolve a default model. Open the task page once and pick a model, then try again.",

0 commit comments

Comments
 (0)