diff --git a/apps/mobile/src/app/settings/index.tsx b/apps/mobile/src/app/settings/index.tsx index d5784feddb..79ac5c10f1 100644 --- a/apps/mobile/src/app/settings/index.tsx +++ b/apps/mobile/src/app/settings/index.tsx @@ -199,6 +199,8 @@ export default function SettingsScreen() { const setAutoPublishCloudRuns = usePreferencesStore( (s) => s.setAutoPublishCloudRuns, ); + const rtkEnabledCloud = usePreferencesStore((s) => s.rtkEnabledCloud); + const setRtkEnabledCloud = usePreferencesStore((s) => s.setRtkEnabledCloud); const defaultMessagingMode = useMessagingModeStore((s) => s.defaultMode); const setDefaultMessagingMode = useMessagingModeStore( (s) => s.setDefaultMode, @@ -427,7 +429,6 @@ export default function SettingsScreen() { } /> + + } + /> {/* Integrations */} diff --git a/apps/mobile/src/app/task/[id].tsx b/apps/mobile/src/app/task/[id].tsx index 485cc79ba9..b2c4c4af75 100644 --- a/apps/mobile/src/app/task/[id].tsx +++ b/apps/mobile/src/app/task/[id].tsx @@ -304,6 +304,7 @@ export default function TaskDetailScreen() { model: composerModel, reasoningEffort: supportsReasoning ? composerReasoning : undefined, initialPermissionMode: composerMode, + rtkEnabled: usePreferencesStore.getState().rtkEnabledCloud, }); setTask(updatedTask); await connectToTask(updatedTask); @@ -478,6 +479,7 @@ export default function TaskDetailScreen() { const updatedTask = await runTaskInCloud(taskId, { resumeFromRunId: task.latest_run?.id, + rtkEnabled: usePreferencesStore.getState().rtkEnabledCloud, }); setTask(updatedTask); await connectToTask(updatedTask); diff --git a/apps/mobile/src/app/task/index.tsx b/apps/mobile/src/app/task/index.tsx index 882d1b92c0..75fe35e96a 100644 --- a/apps/mobile/src/app/task/index.tsx +++ b/apps/mobile/src/app/task/index.tsx @@ -352,6 +352,7 @@ export default function NewTaskScreen() { reasoningEffort: supportsReasoning ? reasoning : undefined, initialPermissionMode: mode, autoPublish: usePreferencesStore.getState().autoPublishCloudRuns, + rtkEnabled: usePreferencesStore.getState().rtkEnabledCloud, ...(signalReport ? { runSource: "signal_report" as const, diff --git a/apps/mobile/src/features/inbox/components/TinderView.tsx b/apps/mobile/src/features/inbox/components/TinderView.tsx index caeae12e87..cc034d6ceb 100644 --- a/apps/mobile/src/features/inbox/components/TinderView.tsx +++ b/apps/mobile/src/features/inbox/components/TinderView.tsx @@ -16,6 +16,7 @@ import { useSafeAreaInsets, } from "react-native-safe-area-context"; import { MarkdownText } from "@/features/chat/components/MarkdownText"; +import { usePreferencesStore } from "@/features/preferences/stores/preferencesStore"; import { createTask, runTaskInCloud } from "@/features/tasks/api"; import { DEFAULT_MODEL } from "@/features/tasks/composer/options"; import type { @@ -256,6 +257,7 @@ export function TinderView({ initialPermissionMode: "plan", runSource: "signal_report", signalReportId: report.id, + rtkEnabled: usePreferencesStore.getState().rtkEnabledCloud, }); acceptReport(report.id); diff --git a/apps/mobile/src/features/preferences/stores/preferencesStore.ts b/apps/mobile/src/features/preferences/stores/preferencesStore.ts index bdf8a3b64f..627d9080c9 100644 --- a/apps/mobile/src/features/preferences/stores/preferencesStore.ts +++ b/apps/mobile/src/features/preferences/stores/preferencesStore.ts @@ -83,6 +83,9 @@ interface PreferencesState { autoPublishCloudRuns: boolean; setAutoPublishCloudRuns: (enabled: boolean) => void; + + rtkEnabledCloud: boolean; + setRtkEnabledCloud: (enabled: boolean) => void; } export const usePreferencesStore = create()( @@ -127,6 +130,9 @@ export const usePreferencesStore = create()( autoPublishCloudRuns: true, setAutoPublishCloudRuns: (enabled) => set({ autoPublishCloudRuns: enabled }), + + rtkEnabledCloud: true, + setRtkEnabledCloud: (enabled) => set({ rtkEnabledCloud: enabled }), }), { name: "posthog-preferences", @@ -144,6 +150,7 @@ export const usePreferencesStore = create()( defaultReasoningEffort: state.defaultReasoningEffort, lastUsedReasoningEffort: state.lastUsedReasoningEffort, autoPublishCloudRuns: state.autoPublishCloudRuns, + rtkEnabledCloud: state.rtkEnabledCloud, }), }, ), diff --git a/apps/mobile/src/features/tasks/api.test.ts b/apps/mobile/src/features/tasks/api.test.ts index e56acbb760..92dfece844 100644 --- a/apps/mobile/src/features/tasks/api.test.ts +++ b/apps/mobile/src/features/tasks/api.test.ts @@ -62,4 +62,19 @@ describe("runTaskInCloud", () => { const [, init] = mockFetch.mock.calls[0] as [string, RequestInit]; expect(init.body).toBeUndefined(); }); + + it("sends rtk_enabled=false when the run opts out", async () => { + await runTaskInCloud("task-1", { rtkEnabled: false }); + + expect(bodyOf(mockFetch.mock.calls[0])).toMatchObject({ + rtk_enabled: false, + }); + }); + + it("omits rtk_enabled when the run keeps compression on", async () => { + await runTaskInCloud("task-1", { rtkEnabled: true }); + + const [, init] = mockFetch.mock.calls[0] as [string, RequestInit]; + expect(init.body).toBeUndefined(); + }); }); diff --git a/apps/mobile/src/features/tasks/api.ts b/apps/mobile/src/features/tasks/api.ts index 68fae4895f..909d059b9e 100644 --- a/apps/mobile/src/features/tasks/api.ts +++ b/apps/mobile/src/features/tasks/api.ts @@ -436,6 +436,8 @@ export interface RunTaskInCloudOptions { /** When true, the cloud run pushes its changes and opens a draft PR on * completion without waiting for an explicit ask. */ autoPublish?: boolean; + /** Only false is sent: opts the run out of rtk command-output compression. */ + rtkEnabled?: boolean; } export async function runTaskInCloud( @@ -460,7 +462,8 @@ export async function runTaskInCloud( options.initialPermissionMode !== undefined || options.runSource !== undefined || options.signalReportId !== undefined || - options.autoPublish !== undefined); + options.autoPublish !== undefined || + options.rtkEnabled === false); let body: string | undefined; if (hasOptions) { @@ -490,6 +493,9 @@ export async function runTaskInCloud( if (options?.autoPublish !== undefined) { payload.auto_publish = options.autoPublish; } + if (options?.rtkEnabled === false) { + payload.rtk_enabled = false; + } body = JSON.stringify(payload); } diff --git a/apps/mobile/src/features/tasks/stores/taskSessionStore.test.ts b/apps/mobile/src/features/tasks/stores/taskSessionStore.test.ts index 77e5b515c4..db60b6b667 100644 --- a/apps/mobile/src/features/tasks/stores/taskSessionStore.test.ts +++ b/apps/mobile/src/features/tasks/stores/taskSessionStore.test.ts @@ -23,6 +23,7 @@ vi.mock("../api", () => ({ sendCloudCommand: vi.fn(), })); +import { usePreferencesStore } from "@/features/preferences/stores/preferencesStore"; import { getTask, runTaskInCloud } from "../api"; import type { CloudTaskUpdatePayload, @@ -155,6 +156,7 @@ describe("_resumeCloudRun", () => { vi.clearAllMocks(); useTaskStore.setState({ composerConfigByTaskId: {} }); useTaskSessionStore.setState({ sessions: {} }); + usePreferencesStore.setState({ rtkEnabledCloud: true }); mockRunTaskInCloud.mockResolvedValue({ id: "t1", latest_run: { id: "new-run" }, @@ -180,9 +182,24 @@ describe("_resumeCloudRun", () => { pendingUserMessage: "hi", reasoningEffort: "low", initialPermissionMode: "acceptEdits", + rtkEnabled: true, }); }); + it("forwards the rtk compression opt-out so resume preserves it", async () => { + usePreferencesStore.setState({ rtkEnabledCloud: false }); + mockGetTask.mockResolvedValue(previousTask({ branch: "feature" })); + + await useTaskSessionStore + .getState() + ._resumeCloudRun("t1", "prev-run", "hi"); + + expect(mockRunTaskInCloud).toHaveBeenCalledWith( + "t1", + expect.objectContaining({ rtkEnabled: false }), + ); + }); + it("prefers the composer's current selection over the previous run", async () => { useTaskStore.setState({ composerConfigByTaskId: { t1: { mode: "plan", reasoning: "max" } }, diff --git a/apps/mobile/src/features/tasks/stores/taskSessionStore.ts b/apps/mobile/src/features/tasks/stores/taskSessionStore.ts index 67792e41ff..967d1dd7b8 100644 --- a/apps/mobile/src/features/tasks/stores/taskSessionStore.ts +++ b/apps/mobile/src/features/tasks/stores/taskSessionStore.ts @@ -1165,6 +1165,7 @@ export const useTaskSessionStore = create((set, get) => ({ pendingUserMessage: prompt, reasoningEffort, initialPermissionMode, + rtkEnabled: usePreferencesStore.getState().rtkEnabledCloud, }); const newRun = updatedTask.latest_run;