Skip to content

Commit aa535aa

Browse files
joshsnytatoalo
andauthored
feat: cloud environments (#1285)
Co-authored-by: Alessandro Pogliaghi <alessandro@posthog.com>
1 parent dd244a0 commit aa535aa

18 files changed

Lines changed: 1002 additions & 52 deletions

File tree

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

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import type {
2+
SandboxEnvironment,
3+
SandboxEnvironmentInput,
24
SignalReportArtefact,
35
SignalReportArtefactsResponse,
46
SignalReportSignalsResponse,
@@ -504,6 +506,7 @@ export class PostHogAPIClient {
504506
taskId: string,
505507
branch?: string | null,
506508
resumeOptions?: { resumeFromRunId: string; pendingUserMessage: string },
509+
sandboxEnvironmentId?: string,
507510
): Promise<Task> {
508511
const teamId = await this.getTeamId();
509512
const body: Record<string, unknown> = { mode: "interactive" };
@@ -514,6 +517,9 @@ export class PostHogAPIClient {
514517
body.resume_from_run_id = resumeOptions.resumeFromRunId;
515518
body.pending_user_message = resumeOptions.pendingUserMessage;
516519
}
520+
if (sandboxEnvironmentId) {
521+
body.sandbox_environment_id = sandboxEnvironmentId;
522+
}
517523

518524
const data = await this.api.post(
519525
`/api/projects/{project_id}/tasks/{id}/run/`,
@@ -1164,4 +1170,89 @@ export class PostHogAPIClient {
11641170
return false;
11651171
}
11661172
}
1173+
1174+
// Sandbox Environments
1175+
1176+
async listSandboxEnvironments(): Promise<SandboxEnvironment[]> {
1177+
const teamId = await this.getTeamId();
1178+
const url = new URL(
1179+
`${this.api.baseUrl}/api/projects/${teamId}/sandbox_environments/`,
1180+
);
1181+
const response = await this.api.fetcher.fetch({
1182+
method: "get",
1183+
url,
1184+
path: `/api/projects/${teamId}/sandbox_environments/`,
1185+
});
1186+
if (!response.ok) {
1187+
throw new Error(
1188+
`Failed to fetch sandbox environments: ${response.statusText}`,
1189+
);
1190+
}
1191+
const data = await response.json();
1192+
return (data.results ?? data) as SandboxEnvironment[];
1193+
}
1194+
1195+
async createSandboxEnvironment(
1196+
input: SandboxEnvironmentInput,
1197+
): Promise<SandboxEnvironment> {
1198+
const teamId = await this.getTeamId();
1199+
const url = new URL(
1200+
`${this.api.baseUrl}/api/projects/${teamId}/sandbox_environments/`,
1201+
);
1202+
const response = await this.api.fetcher.fetch({
1203+
method: "post",
1204+
url,
1205+
path: `/api/projects/${teamId}/sandbox_environments/`,
1206+
overrides: {
1207+
body: JSON.stringify(input),
1208+
},
1209+
});
1210+
if (!response.ok) {
1211+
throw new Error(
1212+
`Failed to create sandbox environment: ${response.statusText}`,
1213+
);
1214+
}
1215+
return (await response.json()) as SandboxEnvironment;
1216+
}
1217+
1218+
async updateSandboxEnvironment(
1219+
id: string,
1220+
input: Partial<SandboxEnvironmentInput>,
1221+
): Promise<SandboxEnvironment> {
1222+
const teamId = await this.getTeamId();
1223+
const url = new URL(
1224+
`${this.api.baseUrl}/api/projects/${teamId}/sandbox_environments/${id}/`,
1225+
);
1226+
const response = await this.api.fetcher.fetch({
1227+
method: "patch",
1228+
url,
1229+
path: `/api/projects/${teamId}/sandbox_environments/${id}/`,
1230+
overrides: {
1231+
body: JSON.stringify(input),
1232+
},
1233+
});
1234+
if (!response.ok) {
1235+
throw new Error(
1236+
`Failed to update sandbox environment: ${response.statusText}`,
1237+
);
1238+
}
1239+
return (await response.json()) as SandboxEnvironment;
1240+
}
1241+
1242+
async deleteSandboxEnvironment(id: string): Promise<void> {
1243+
const teamId = await this.getTeamId();
1244+
const url = new URL(
1245+
`${this.api.baseUrl}/api/projects/${teamId}/sandbox_environments/${id}/`,
1246+
);
1247+
const response = await this.api.fetcher.fetch({
1248+
method: "delete",
1249+
url,
1250+
path: `/api/projects/${teamId}/sandbox_environments/${id}/`,
1251+
});
1252+
if (!response.ok) {
1253+
throw new Error(
1254+
`Failed to delete sandbox environment: ${response.statusText}`,
1255+
);
1256+
}
1257+
}
11671258
}

apps/code/src/renderer/features/sessions/components/ConversationView.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
useSessionForTask,
88
} from "@features/sessions/stores/sessionStore";
99
import { useSettingsStore } from "@features/settings/stores/settingsStore";
10-
import { useFeatureFlag } from "@hooks/useFeatureFlag";
1110
import { ArrowDown, XCircle } from "@phosphor-icons/react";
1211
import { Box, Button, Flex, Text } from "@radix-ui/themes";
1312
import type { AcpMessage } from "@shared/types/session-events";
@@ -50,9 +49,8 @@ export function ConversationView({
5049
}: ConversationViewProps) {
5150
const listRef = useRef<VirtualizedListHandle>(null);
5251
const [showScrollButton, setShowScrollButton] = useState(false);
53-
const agentLogsEnabled = useFeatureFlag("posthog-code-background-agent-logs");
5452
const debugLogsCloudRuns = useSettingsStore((s) => s.debugLogsCloudRuns);
55-
const showDebugLogs = agentLogsEnabled && debugLogsCloudRuns;
53+
const showDebugLogs = debugLogsCloudRuns;
5654
const contextUsage = useContextUsage(events);
5755

5856
const {

apps/code/src/renderer/features/settings/components/SettingsDialog.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
ArrowLeft,
77
ArrowsClockwise,
88
CaretRight,
9+
Cloud,
910
Code,
1011
Folder,
1112
GearSix,
@@ -24,6 +25,7 @@ import { useHotkeys } from "react-hotkeys-hook";
2425
import { AccountSettings } from "./sections/AccountSettings";
2526
import { AdvancedSettings } from "./sections/AdvancedSettings";
2627
import { ClaudeCodeSettings } from "./sections/ClaudeCodeSettings";
28+
import { CloudEnvironmentsSettings } from "./sections/CloudEnvironmentsSettings";
2729
import { EnvironmentsSettings } from "./sections/environments/EnvironmentsSettings";
2830
import { GeneralSettings } from "./sections/GeneralSettings";
2931
import { McpServersSettings } from "./sections/McpServersSettings";
@@ -51,6 +53,11 @@ const SIDEBAR_ITEMS: SidebarItem[] = [
5153
label: "Environments",
5254
icon: <HardDrives size={16} />,
5355
},
56+
{
57+
id: "cloud-environments",
58+
label: "Cloud environments",
59+
icon: <Cloud size={16} />,
60+
},
5461
{
5562
id: "personalization",
5663
label: "Personalization",
@@ -75,6 +82,7 @@ const CATEGORY_TITLES: Record<SettingsCategory, string> = {
7582
workspaces: "Workspaces",
7683
worktrees: "Worktrees",
7784
environments: "Environments",
85+
"cloud-environments": "Cloud environments",
7886
personalization: "Personalization",
7987
"claude-code": "Claude Code",
8088
"mcp-servers": "MCP Servers",
@@ -91,6 +99,7 @@ const CATEGORY_COMPONENTS: Record<SettingsCategory, React.ComponentType> = {
9199
workspaces: WorkspacesSettings,
92100
worktrees: WorktreesSettings,
93101
environments: EnvironmentsSettings,
102+
"cloud-environments": CloudEnvironmentsSettings,
94103
personalization: PersonalizationSettings,
95104
"claude-code": ClaudeCodeSettings,
96105
"mcp-servers": McpServersSettings,

apps/code/src/renderer/features/settings/components/sections/AdvancedSettings.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ import { Button, Flex, Switch } from "@radix-ui/themes";
66
import { clearApplicationStorage } from "@utils/clearStorage";
77

88
export function AdvancedSettings() {
9-
const showDebugLogsToggle = useFeatureFlag(
10-
"posthog-code-background-agent-logs",
11-
);
9+
const showDebugLogsToggle =
10+
useFeatureFlag("posthog-code-background-agent-logs") || import.meta.env.DEV;
1211
const debugLogsCloudRuns = useSettingsStore((s) => s.debugLogsCloudRuns);
1312
const setDebugLogsCloudRuns = useSettingsStore(
1413
(s) => s.setDebugLogsCloudRuns,

0 commit comments

Comments
 (0)