@@ -2,12 +2,10 @@ import { Text } from "@components/text";
22import {
33 DEFAULT_CLAUDE_EXECUTION_MODE ,
44 getAvailableModesForAdapter ,
5- getDefaultExecutionModeForAdapter ,
65} from "@posthog/core/sessions/executionModes" ;
76import { resolveCloudComposerModelChange } from "@posthog/core/task-detail/composerModelPolicy" ;
87import {
98 type Adapter ,
10- DEFAULT_CODEX_MODEL ,
119 DEFAULT_GATEWAY_MODEL ,
1210 DEFAULT_REASONING_EFFORT ,
1311 type ExecutionMode ,
@@ -20,17 +18,10 @@ import { LinearGradient } from "expo-linear-gradient";
2018import { Stack , useLocalSearchParams , useRouter } from "expo-router" ;
2119import {
2220 ArrowUp ,
23- BrainIcon ,
2421 CaretDown ,
25- Cpu ,
2622 GithubLogo ,
2723 MicrophoneIcon ,
2824 PaperclipIcon ,
29- PauseIcon ,
30- PencilIcon ,
31- Robot ,
32- ShieldCheck ,
33- Sparkle ,
3425 StopIcon ,
3526} from "phosphor-react-native" ;
3627import { useCallback , useEffect , useState } from "react" ;
@@ -50,6 +41,7 @@ import { useVoiceRecording } from "@/features/chat";
5041import { usePreferencesStore } from "@/features/preferences/stores/preferencesStore" ;
5142import { GitHubConnectionPrompt } from "@/features/tasks/components/GitHubConnectionPrompt" ;
5243import { GitHubLoadNotice } from "@/features/tasks/components/GitHubLoadNotice" ;
44+ import { AgentConfigControls } from "@/features/tasks/composer/AgentConfigControls" ;
5345import { AttachmentSheet } from "@/features/tasks/composer/attachments/AttachmentSheet" ;
5446import { AttachmentsBar } from "@/features/tasks/composer/attachments/AttachmentsBar" ;
5547import { buildCloudPromptBlocks } from "@/features/tasks/composer/attachments/buildCloudPrompt" ;
@@ -61,14 +53,10 @@ import {
6153import type { PendingAttachment } from "@/features/tasks/composer/attachments/types" ;
6254import { DotBackground } from "@/features/tasks/composer/DotBackground" ;
6355import {
64- getComposerModelOptions ,
65- getConfigOptionLabel ,
6656 getMobileExecutionModes ,
6757 getModelConfigOption ,
6858} from "@/features/tasks/composer/options" ;
69- import { Pill } from "@/features/tasks/composer/Pill" ;
7059import { RepositoryPickerInline } from "@/features/tasks/composer/RepositoryPickerInline" ;
71- import { SelectSheet } from "@/features/tasks/composer/SelectSheet" ;
7260import { useCloudTaskConfigOptions } from "@/features/tasks/hooks/useCloudTaskConfigOptions" ;
7361import { useUserIntegrations } from "@/features/tasks/hooks/useUserIntegrations" ;
7462import { useWarmTask } from "@/features/tasks/hooks/useWarmTask" ;
@@ -82,6 +70,7 @@ import type {
8270 CreateTaskOptions ,
8371 RepositorySelection ,
8472} from "@/features/tasks/types" ;
73+ import { buildCloudTaskRunConfig } from "@/features/tasks/utils/cloudTaskRunConfig" ;
8574import {
8675 findRepositoryOption ,
8776 isRepositorySelectionComplete ,
@@ -93,31 +82,12 @@ import { getPostHogApiClient } from "@/lib/posthogApiClient";
9382import { toRgba , useThemeColors } from "@/lib/theme" ;
9483
9584const log = logger . scope ( "task-create" ) ;
96- const SWITCH_ADAPTER_VALUE = "__switch_adapter__" ;
9785const SUGGESTIONS = [
9886 "Create or update my CLAUDE.md file" ,
9987 "Search for a TODO comment and fix it" ,
10088 "Recommend areas to improve our tests" ,
10189] as const ;
10290
103- function modeIcon ( mode : ExecutionMode , color : string , size = 14 ) {
104- switch ( mode ) {
105- case "plan" :
106- return < PauseIcon size = { size } color = { color } weight = "bold" /> ;
107- case "default" :
108- return < PencilIcon size = { size } color = { color } /> ;
109- case "acceptEdits" :
110- return < ShieldCheck size = { size } color = { color } /> ;
111- case "bypassPermissions" :
112- case "full-access" :
113- return < ShieldCheck size = { size } color = { color } weight = "fill" /> ;
114- case "read-only" :
115- return < PauseIcon size = { size } color = { color } /> ;
116- case "auto" :
117- return < Sparkle size = { size } color = { color } weight = "fill" /> ;
118- }
119- }
120-
12191export default function NewTaskScreen ( ) {
12292 const {
12393 prompt : initialPrompt ,
@@ -136,11 +106,7 @@ export default function NewTaskScreen() {
136106 const [ adapter , setAdapter ] = useState < Adapter > ( "claude" ) ;
137107 const { configOptions, hasLiveConfig, isConfigReady } =
138108 useCloudTaskConfigOptions ( adapter ) ;
139- const executionModes = getMobileExecutionModes (
140- getAvailableModesForAdapter ( adapter ) ,
141- ) ;
142109 const modelConfigOption = getModelConfigOption ( configOptions ) ;
143- const mobileModelOptions = getComposerModelOptions ( modelConfigOption ) ;
144110 const {
145111 error,
146112 hasGithubIntegration,
@@ -236,9 +202,6 @@ export default function NewTaskScreen() {
236202 } , [ adapter , hasLiveConfig , model , modelConfigOption , reasoning ] ) ;
237203 const [ creating , setCreating ] = useState ( false ) ;
238204 const [ repoSheetOpen , setRepoSheetOpen ] = useState ( false ) ;
239- const [ modeSheetOpen , setModeSheetOpen ] = useState ( false ) ;
240- const [ modelSheetOpen , setModelSheetOpen ] = useState ( false ) ;
241- const [ reasoningSheetOpen , setReasoningSheetOpen ] = useState ( false ) ;
242205 const [ attachments , setAttachments ] = useState < PendingAttachment [ ] > ( [ ] ) ;
243206 const [ attachmentSheetOpen , setAttachmentSheetOpen ] = useState ( false ) ;
244207
@@ -381,15 +344,9 @@ export default function NewTaskScreen() {
381344 )
382345 : trimmedPrompt ;
383346
384- const supportsReasoning =
385- getReasoningEffortOptions ( adapter , model ) !== null ;
386-
387347 await client . runTaskInCloud ( task . id , undefined , {
388348 pendingUserMessage,
389- adapter,
390- model,
391- reasoningLevel : supportsReasoning ? reasoning : undefined ,
392- initialPermissionMode : mode ,
349+ ...buildCloudTaskRunConfig ( { adapter, mode, model, reasoning } ) ,
393350 autoPublish : usePreferencesStore . getState ( ) . autoPublishCloudRuns ,
394351 rtkEnabled : usePreferencesStore . getState ( ) . rtkEnabledCloud ,
395352 ...( signalReport
@@ -618,51 +575,27 @@ export default function NewTaskScreen() {
618575 paddingRight : 16 ,
619576 } }
620577 >
621- < Pill
622- icon = { modeIcon (
623- mode ,
624- mode === "plan"
625- ? themeColors . accent [ 11 ]
626- : themeColors . gray [ 11 ] ,
627- ) }
628- label = {
629- executionModes . find ( ( option ) => option . id === mode )
630- ?. name ?? mode
631- }
632- accent = { mode === "plan" }
633- onPress = { ( ) => setModeSheetOpen ( true ) }
578+ < AgentConfigControls
579+ adapter = { adapter }
580+ mode = { mode }
581+ model = { model }
582+ reasoning = { reasoning }
583+ configOptions = { configOptions }
584+ onAdapterChange = { setAdapter }
585+ onModeChange = { ( next ) => {
586+ setMode ( next ) ;
587+ usePreferencesStore
588+ . getState ( )
589+ . setLastNewTaskMode ( next ) ;
590+ } }
591+ onModelChange = { setModel }
592+ onReasoningChange = { ( next ) => {
593+ setReasoning ( next ) ;
594+ usePreferencesStore
595+ . getState ( )
596+ . setLastUsedReasoningEffort ( next ) ;
597+ } }
634598 />
635-
636- < Pill
637- icon = {
638- adapter === "codex" ? (
639- < Cpu size = { 14 } color = { themeColors . gray [ 11 ] } />
640- ) : (
641- < Robot size = { 14 } color = { themeColors . gray [ 11 ] } />
642- )
643- }
644- label = {
645- getConfigOptionLabel (
646- modelConfigOption . options ,
647- model ,
648- ) ?? model
649- }
650- onPress = { ( ) => setModelSheetOpen ( true ) }
651- />
652-
653- { showReasoningPill ? (
654- < Pill
655- icon = {
656- < BrainIcon size = { 14 } color = { themeColors . gray [ 11 ] } />
657- }
658- label = {
659- reasoningOptions . find (
660- ( option ) => option . value === reasoning ,
661- ) ?. name ?? reasoning
662- }
663- onPress = { ( ) => setReasoningSheetOpen ( true ) }
664- />
665- ) : null }
666599 </ ScrollView >
667600 { /* Right-edge fade hints that more pills exist when the row
668601 overflows. Non-interactive so taps fall through. */ }
@@ -771,98 +704,6 @@ export default function NewTaskScreen() {
771704 </ Animated . View >
772705 </ View >
773706
774- < SelectSheet
775- open = { modeSheetOpen }
776- title = "Execution mode"
777- value = { mode }
778- onChange = { ( value ) => {
779- const next = value as ExecutionMode ;
780- setMode ( next ) ;
781- usePreferencesStore . getState ( ) . setLastNewTaskMode ( next ) ;
782- } }
783- onClose = { ( ) => setModeSheetOpen ( false ) }
784- options = { executionModes . map ( ( executionMode ) => ( {
785- value : executionMode . id ,
786- label : executionMode . name ,
787- description : executionMode . description ,
788- icon : modeIcon (
789- executionMode . id as ExecutionMode ,
790- executionMode . id === "plan"
791- ? themeColors . accent [ 11 ]
792- : themeColors . gray [ 11 ] ,
793- 16 ,
794- ) ,
795- } ) ) }
796- />
797-
798- < SelectSheet
799- open = { modelSheetOpen }
800- title = "Model"
801- value = { model }
802- onChange = { ( value ) => {
803- if ( value === SWITCH_ADAPTER_VALUE ) {
804- const nextAdapter : Adapter =
805- adapter === "claude" ? "codex" : "claude" ;
806- setAdapter ( nextAdapter ) ;
807- setMode ( getDefaultExecutionModeForAdapter ( nextAdapter ) ) ;
808- setModel (
809- nextAdapter === "codex"
810- ? DEFAULT_CODEX_MODEL
811- : DEFAULT_GATEWAY_MODEL ,
812- ) ;
813- setReasoning ( DEFAULT_REASONING_EFFORT ) ;
814- return ;
815- }
816- const next = resolveCloudComposerModelChange ( {
817- adapter,
818- modelOption : modelConfigOption ,
819- requestedModel : value ,
820- reasoning,
821- } ) ;
822- setModel ( next . model ) ;
823- setReasoning ( next . reasoning ) ;
824- } }
825- onClose = { ( ) => setModelSheetOpen ( false ) }
826- options = { [
827- ...mobileModelOptions . map ( ( modelOption ) => ( {
828- value : modelOption . value ,
829- label : modelOption . label ,
830- description : modelOption . description ,
831- disabled : modelOption . disabled ,
832- icon :
833- adapter === "codex" ? (
834- < Cpu size = { 16 } color = { themeColors . gray [ 11 ] } />
835- ) : (
836- < Robot size = { 16 } color = { themeColors . gray [ 11 ] } />
837- ) ,
838- } ) ) ,
839- {
840- value : SWITCH_ADAPTER_VALUE ,
841- label : `Switch to ${ adapter === "claude" ? "Codex" : "Claude Code" } ` ,
842- description : "Change coding agent" ,
843- disabled : false ,
844- icon : < Cpu size = { 16 } color = { themeColors . accent [ 11 ] } /> ,
845- } ,
846- ] }
847- />
848-
849- < SelectSheet
850- open = { reasoningSheetOpen }
851- title = "Reasoning"
852- value = { reasoning }
853- onChange = { ( value ) => {
854- const next = value as SupportedReasoningEffort ;
855- setReasoning ( next ) ;
856- usePreferencesStore . getState ( ) . setLastUsedReasoningEffort ( next ) ;
857- } }
858- onClose = { ( ) => setReasoningSheetOpen ( false ) }
859- options = { reasoningOptions . map ( ( reasoningLevel ) => ( {
860- value : reasoningLevel . value ,
861- label : reasoningLevel . name ,
862- icon : < BrainIcon size = { 16 } color = { themeColors . gray [ 11 ] } /> ,
863- } ) ) }
864- />
865-
866707 < AttachmentSheet
867708 open = { attachmentSheetOpen }
868709 onClose = { ( ) => setAttachmentSheetOpen ( false ) }
0 commit comments