Skip to content

Commit d7f9f76

Browse files
authored
feat: signal source config WIP (#1160)
### TL;DR Replaced repository-based autonomy setup with signal source configuration for the inbox feature, removing complex repository readiness evaluation in favor of a simpler signal source toggle system. ### What changed? - **Removed repository autonomy system**: Deleted `getRepositoryReadiness()` and `getProjectAutonomySettings()` API methods, along with related hooks and components for evaluating repository setup status - **Added signal source configuration**: Introduced `SignalSourceConfig` interface and API methods (`listSignalSourceConfigs()`, `createSignalSourceConfig()`) to manage signal sources like session replay and LLM analytics - **Simplified inbox UI**: Replaced tabbed interface (Signals/Setup) with a single signals view that shows a configuration screen when no sources are enabled - **Updated onboarding flow**: Added new "signals" step to onboarding that allows users to enable signal sources during initial setup - **Removed autonomy feature flag**: Eliminated the `useAutonomy()` hook and related conditional rendering throughout the application
1 parent 75ec830 commit d7f9f76

23 files changed

Lines changed: 669 additions & 1344 deletions

apps/code/src/renderer/api/posthogClient.ts

Lines changed: 83 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type {
2-
RepoAutonomyStatus,
32
SignalReportArtefact,
43
SignalReportArtefactsResponse,
54
SignalReportSignalsResponse,
@@ -19,6 +18,16 @@ export type McpRecommendedServer = Schemas.RecommendedServer;
1918

2019
export type McpServerInstallation = Schemas.MCPServerInstallation;
2120

21+
export interface SignalSourceConfig {
22+
id: string;
23+
source_product: "session_replay" | "llm_analytics";
24+
source_type: "session_analysis_cluster" | "evaluation";
25+
enabled: boolean;
26+
config: Record<string, unknown>;
27+
created_at: string;
28+
updated_at: string;
29+
}
30+
2231
function isObjectRecord(value: unknown): value is Record<string, unknown> {
2332
return typeof value === "object" && value !== null;
2433
}
@@ -166,34 +175,83 @@ export class PostHogAPIClient {
166175
return data as Schemas.Team;
167176
}
168177

169-
async getProjectAutonomySettings(projectId: number): Promise<{
170-
proactive_tasks_enabled?: boolean;
171-
}> {
172-
try {
173-
const urlPath = `/api/environments/${projectId}/`;
174-
const url = new URL(`${this.api.baseUrl}${urlPath}`);
175-
const response = await this.api.fetcher.fetch({
176-
method: "get",
177-
url,
178-
path: urlPath,
179-
});
180-
const data = (await response.json()) as {
181-
proactive_tasks_enabled?: boolean;
178+
async listSignalSourceConfigs(
179+
projectId: number,
180+
): Promise<SignalSourceConfig[]> {
181+
const urlPath = `/api/projects/${projectId}/signal_source_configs/`;
182+
const url = new URL(`${this.api.baseUrl}${urlPath}`);
183+
const response = await this.api.fetcher.fetch({
184+
method: "get",
185+
url,
186+
path: urlPath,
187+
});
188+
if (!response.ok) {
189+
throw new Error(
190+
`Failed to fetch signal source configs: ${response.statusText}`,
191+
);
192+
}
193+
const data = (await response.json()) as
194+
| { results: SignalSourceConfig[] }
195+
| SignalSourceConfig[];
196+
return Array.isArray(data) ? data : (data.results ?? []);
197+
}
198+
199+
async createSignalSourceConfig(
200+
projectId: number,
201+
options: {
202+
source_product: "session_replay" | "llm_analytics";
203+
source_type: "session_analysis_cluster" | "evaluation";
204+
enabled: boolean;
205+
config?: Record<string, unknown>;
206+
},
207+
): Promise<SignalSourceConfig> {
208+
const urlPath = `/api/projects/${projectId}/signal_source_configs/`;
209+
const url = new URL(`${this.api.baseUrl}${urlPath}`);
210+
const response = await this.api.fetcher.fetch({
211+
method: "post",
212+
url,
213+
path: urlPath,
214+
overrides: {
215+
body: JSON.stringify(options),
216+
},
217+
});
218+
if (!response.ok) {
219+
const errorData = (await response.json().catch(() => ({}))) as {
220+
detail?: string;
182221
};
222+
throw new Error(
223+
errorData.detail ??
224+
`Failed to create signal source config: ${response.statusText}`,
225+
);
226+
}
227+
return (await response.json()) as SignalSourceConfig;
228+
}
183229

184-
return {
185-
proactive_tasks_enabled:
186-
typeof data.proactive_tasks_enabled === "boolean"
187-
? data.proactive_tasks_enabled
188-
: false,
230+
async updateSignalSourceConfig(
231+
projectId: number,
232+
configId: string,
233+
updates: { enabled: boolean },
234+
): Promise<SignalSourceConfig> {
235+
const urlPath = `/api/projects/${projectId}/signal_source_configs/${configId}/`;
236+
const url = new URL(`${this.api.baseUrl}${urlPath}`);
237+
const response = await this.api.fetcher.fetch({
238+
method: "patch",
239+
url,
240+
path: urlPath,
241+
overrides: {
242+
body: JSON.stringify(updates),
243+
},
244+
});
245+
if (!response.ok) {
246+
const errorData = (await response.json().catch(() => ({}))) as {
247+
detail?: string;
189248
};
190-
} catch (error) {
191-
log.warn("Failed to resolve autonomy settings; defaulting to disabled", {
192-
projectId,
193-
error,
194-
});
195-
return { proactive_tasks_enabled: false };
249+
throw new Error(
250+
errorData.detail ??
251+
`Failed to update signal source config: ${response.statusText}`,
252+
);
196253
}
254+
return (await response.json()) as SignalSourceConfig;
197255
}
198256

199257
async getTasks(options?: {
@@ -840,51 +898,6 @@ export class PostHogAPIClient {
840898
}
841899
}
842900

843-
async getRepositoryReadiness(
844-
repository: string,
845-
options?: { refresh?: boolean; windowDays?: number },
846-
): Promise<RepoAutonomyStatus> {
847-
const teamId = await this.getTeamId();
848-
const url = new URL(
849-
`${this.api.baseUrl}/api/projects/${teamId}/tasks/repository_readiness/`,
850-
);
851-
url.searchParams.set("repository", repository.toLowerCase());
852-
if (options?.refresh) {
853-
url.searchParams.set("refresh", "true");
854-
}
855-
if (typeof options?.windowDays === "number") {
856-
url.searchParams.set("window_days", String(options.windowDays));
857-
}
858-
859-
const response = await this.api.fetcher.fetch({
860-
method: "get",
861-
url,
862-
path: `/api/projects/${teamId}/tasks/repository_readiness/`,
863-
});
864-
865-
if (!response.ok) {
866-
throw new Error(
867-
`Failed to fetch repository readiness: ${response.statusText}`,
868-
);
869-
}
870-
871-
const data = await response.json();
872-
return {
873-
repository: data.repository,
874-
classification: data.classification,
875-
excluded: data.excluded,
876-
coreSuggestions: data.coreSuggestions,
877-
replayInsights: data.replayInsights,
878-
errorInsights: data.errorInsights,
879-
overall: data.overall,
880-
evidenceTaskCount: data.evidenceTaskCount ?? 0,
881-
windowDays: data.windowDays,
882-
generatedAt: data.generatedAt,
883-
cacheAgeSeconds: data.cacheAgeSeconds,
884-
scan: data.scan,
885-
} as RepoAutonomyStatus;
886-
}
887-
888901
async getMcpServers(): Promise<McpRecommendedServer[]> {
889902
const teamId = await this.getTeamId();
890903
const url = new URL(

apps/code/src/renderer/components/MainLayout.tsx

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { HedgehogMode } from "@components/HedgehogMode";
44
import { KeyboardShortcutsSheet } from "@components/KeyboardShortcutsSheet";
55

66
import { ArchivedTasksView } from "@features/archive/components/ArchivedTasksView";
7-
import { useAutonomy } from "@features/autonomy/hooks/useAutonomy";
87
import { CommandMenu } from "@features/command/components/CommandMenu";
98
import { InboxView } from "@features/inbox/components/InboxView";
109
import { RightSidebar, RightSidebarContent } from "@features/right-sidebar";
@@ -25,7 +24,7 @@ import { useTaskDeepLink } from "../hooks/useTaskDeepLink";
2524
import { GlobalEventHandlers } from "./GlobalEventHandlers";
2625

2726
export function MainLayout() {
28-
const { view, hydrateTask, navigateToTaskInput } = useNavigationStore();
27+
const { view, hydrateTask } = useNavigationStore();
2928
const {
3029
isOpen: commandMenuOpen,
3130
setOpen: setCommandMenuOpen,
@@ -38,7 +37,6 @@ export function MainLayout() {
3837
} = useShortcutsSheetStore();
3938
const { data: tasks } = useTasks();
4039
const { showPrompt, isChecking, check, dismiss } = useConnectivity();
41-
const inboxEnabled = useAutonomy();
4240

4341
useIntegrations();
4442
useTaskDeepLink();
@@ -49,12 +47,6 @@ export function MainLayout() {
4947
}
5048
}, [tasks, hydrateTask]);
5149

52-
useEffect(() => {
53-
if (view.type === "inbox" && !inboxEnabled) {
54-
navigateToTaskInput();
55-
}
56-
}, [view.type, inboxEnabled, navigateToTaskInput]);
57-
5850
const handleToggleCommandMenu = useCallback(() => {
5951
toggleCommandMenu();
6052
}, [toggleCommandMenu]);
@@ -74,9 +66,7 @@ export function MainLayout() {
7466

7567
{view.type === "folder-settings" && <FolderSettingsView />}
7668

77-
{view.type === "inbox" && inboxEnabled && <InboxView />}
78-
79-
{view.type === "inbox" && !inboxEnabled && <TaskInput />}
69+
{view.type === "inbox" && <InboxView />}
8070

8171
{view.type === "archived" && <ArchivedTasksView />}
8272
</Box>

apps/code/src/renderer/features/autonomy/hooks/useAutonomy.ts

Lines changed: 0 additions & 23 deletions
This file was deleted.

apps/code/src/renderer/features/inbox/components/InboxEmptyStates.tsx

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,9 @@ export function SignalsLoadingState() {
5151

5252
export function SignalsErrorState({
5353
onRetry,
54-
onGoToSetup,
5554
isRetrying,
5655
}: {
5756
onRetry: () => void;
58-
onGoToSetup: () => void;
5957
isRetrying: boolean;
6058
}) {
6159
return (
@@ -74,34 +72,23 @@ export function SignalsErrorState({
7472
Could not load signals
7573
</Text>
7674
<Text size="1" color="gray" className="font-mono text-[11px]">
77-
Check your connection or permissions, then retry. You can still use
78-
Setup while this is unavailable.
75+
Check your connection or permissions, then retry.
7976
</Text>
8077
</Flex>
81-
<Flex align="center" gap="2" wrap="wrap" justify="center">
82-
<Button
83-
size="1"
84-
variant="soft"
85-
onClick={onRetry}
86-
className="font-mono text-[11px]"
87-
disabled={isRetrying}
88-
>
89-
{isRetrying ? (
90-
<CircleNotchIcon size={12} className="animate-spin" />
91-
) : (
92-
<ArrowsClockwiseIcon size={12} />
93-
)}
94-
Retry
95-
</Button>
96-
<Button
97-
size="1"
98-
variant="ghost"
99-
onClick={onGoToSetup}
100-
className="font-mono text-[11px]"
101-
>
102-
Go to Setup
103-
</Button>
104-
</Flex>
78+
<Button
79+
size="1"
80+
variant="soft"
81+
onClick={onRetry}
82+
className="font-mono text-[11px]"
83+
disabled={isRetrying}
84+
>
85+
{isRetrying ? (
86+
<CircleNotchIcon size={12} className="animate-spin" />
87+
) : (
88+
<ArrowsClockwiseIcon size={12} />
89+
)}
90+
Retry
91+
</Button>
10592
</Flex>
10693
</Flex>
10794
);

0 commit comments

Comments
 (0)