Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion apps/mobile/src/app/settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ export default function SettingsScreen() {
const setDefaultReasoningEffort = usePreferencesStore(
(s) => s.setDefaultReasoningEffort,
);
const autoPublishCloudRuns = usePreferencesStore(
(s) => s.autoPublishCloudRuns,
);
const setAutoPublishCloudRuns = usePreferencesStore(
(s) => s.setAutoPublishCloudRuns,
);
const defaultMessagingMode = useMessagingModeStore((s) => s.defaultMode);
const setDefaultMessagingMode = useMessagingModeStore(
(s) => s.setDefaultMode,
Expand Down Expand Up @@ -409,7 +415,6 @@ export default function SettingsScreen() {
label="Messaging mode"
description="What happens when you send while a turn is running"
onPress={() => setMessagingModeSheetOpen(true)}
showDivider={false}
rightSlot={
<>
<Text className="text-[14px] text-gray-11">
Expand All @@ -419,6 +424,17 @@ export default function SettingsScreen() {
</>
}
/>
<SettingsRow
label="Always create pull requests for cloud runs"
description="Cloud runs push their changes and open a draft pull request when they finish, without waiting for you to ask"
showDivider={false}
rightSlot={
<Switch
value={autoPublishCloudRuns}
onValueChange={setAutoPublishCloudRuns}
/>
}
/>
</SettingsSection>

{/* Integrations */}
Expand Down
1 change: 1 addition & 0 deletions apps/mobile/src/app/task/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ export default function NewTaskScreen() {
model,
reasoningEffort: supportsReasoning ? reasoning : undefined,
initialPermissionMode: mode,
autoPublish: usePreferencesStore.getState().autoPublishCloudRuns,
...(signalReport
? {
runSource: "signal_report" as const,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ interface PreferencesState {
* `defaultReasoningEffort === "last_used"` can pre-fill it next time. */
lastUsedReasoningEffort: string;
setLastUsedReasoningEffort: (effort: string) => void;

autoPublishCloudRuns: boolean;
setAutoPublishCloudRuns: (enabled: boolean) => void;
}

export const usePreferencesStore = create<PreferencesState>()(
Expand Down Expand Up @@ -120,6 +123,10 @@ export const usePreferencesStore = create<PreferencesState>()(
lastUsedReasoningEffort: "high",
setLastUsedReasoningEffort: (effort) =>
set({ lastUsedReasoningEffort: effort }),

autoPublishCloudRuns: true,
setAutoPublishCloudRuns: (enabled) =>
set({ autoPublishCloudRuns: enabled }),
}),
{
name: "posthog-preferences",
Expand All @@ -136,6 +143,7 @@ export const usePreferencesStore = create<PreferencesState>()(
lastNewTaskMode: state.lastNewTaskMode,
defaultReasoningEffort: state.defaultReasoningEffort,
lastUsedReasoningEffort: state.lastUsedReasoningEffort,
autoPublishCloudRuns: state.autoPublishCloudRuns,
}),
},
),
Expand Down
65 changes: 65 additions & 0 deletions apps/mobile/src/features/tasks/api.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { beforeEach, describe, expect, it, vi } from "vitest";

const { mockFetch } = vi.hoisted(() => ({
mockFetch: vi.fn(),
}));

vi.mock("expo/fetch", () => ({
fetch: mockFetch,
}));

vi.mock("@/lib/api", () => ({
getBaseUrl: () => "https://app.posthog.test",
getProjectId: () => 42,
getAccessToken: () => "token",
createTimeoutSignal: () => undefined,
authedFetch: (url: string, init?: RequestInit) =>
mockFetch(url, {
...init,
headers: {
Authorization: "Bearer token",
"Content-Type": "application/json",
...((init?.headers as Record<string, string> | undefined) ?? {}),
},
}),
}));

import { runTaskInCloud } from "./api";

function bodyOf(call: unknown): Record<string, unknown> {
const [, init] = call as [string, RequestInit];
return JSON.parse(init.body as string);
}

describe("runTaskInCloud", () => {
beforeEach(() => {
mockFetch.mockReset();
mockFetch.mockResolvedValue(
new Response(JSON.stringify({ id: "task-1" }), { status: 200 }),
);
});

it.each([true, false])(
"forwards auto_publish=%s to the payload",
async (flag) => {
await runTaskInCloud("task-1", { autoPublish: flag });

expect(bodyOf(mockFetch.mock.calls[0])).toMatchObject({
auto_publish: flag,
});
},
);

it("omits auto_publish when not provided", async () => {
await runTaskInCloud("task-1", { model: "claude-opus-4-8" });

expect(bodyOf(mockFetch.mock.calls[0])).not.toHaveProperty("auto_publish");
});

it("sends no body for the plain initial run", async () => {
await runTaskInCloud("task-1");

const [, init] = mockFetch.mock.calls[0] as [string, RequestInit];
expect(init.body).toBeUndefined();
});
});
9 changes: 8 additions & 1 deletion apps/mobile/src/features/tasks/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,9 @@ export interface RunTaskInCloudOptions {
runSource?: "manual" | "signal_report";
/** Signal report ID when run_source is "signal_report". */
signalReportId?: string;
/** When true, the cloud run pushes its changes and opens a draft PR on
* completion without waiting for an explicit ask. */
autoPublish?: boolean;
}

export async function runTaskInCloud(
Expand All @@ -456,7 +459,8 @@ export async function runTaskInCloud(
options.reasoningEffort !== undefined ||
options.initialPermissionMode !== undefined ||
options.runSource !== undefined ||
options.signalReportId !== undefined);
options.signalReportId !== undefined ||
options.autoPublish !== undefined);

let body: string | undefined;
if (hasOptions) {
Expand All @@ -483,6 +487,9 @@ export async function runTaskInCloud(
if (options?.runSource) payload.run_source = options.runSource;
if (options?.signalReportId)
payload.signal_report_id = options.signalReportId;
if (options?.autoPublish !== undefined) {
payload.auto_publish = options.autoPublish;
}
body = JSON.stringify(payload);
}

Expand Down
Loading