@@ -31,7 +31,13 @@ import {
3131 type ReasoningEffort ,
3232} from "@/features/tasks/composer/options" ;
3333import { TaskChatComposer } from "@/features/tasks/composer/TaskChatComposer" ;
34+ import {
35+ useMessagingMode ,
36+ useQueuedCount ,
37+ useToggleMessagingMode ,
38+ } from "@/features/tasks/hooks/useMessagingMode" ;
3439import { taskKeys } from "@/features/tasks/hooks/useTasks" ;
40+ import { useMessageQueueStore } from "@/features/tasks/stores/messageQueueStore" ;
3541import {
3642 pendingTaskPromptStoreApi ,
3743 usePendingTaskPrompt ,
@@ -41,7 +47,11 @@ import { useTaskStore } from "@/features/tasks/stores/taskStore";
4147import type { Task } from "@/features/tasks/types" ;
4248import { getSessionActivityPhase } from "@/features/tasks/utils/sessionActivity" ;
4349import { useScreenInsets } from "@/hooks/useScreenInsets" ;
44- import { useActiveTaskAnalyticsContext } from "@/lib/analytics" ;
50+ import {
51+ ANALYTICS_EVENTS ,
52+ useActiveTaskAnalyticsContext ,
53+ useAnalytics ,
54+ } from "@/lib/analytics" ;
4555import { logger } from "@/lib/logger" ;
4656import { useThemeColors } from "@/lib/theme" ;
4757
@@ -81,6 +91,7 @@ export default function TaskDetailScreen() {
8191 disconnectFromTask,
8292 sendPrompt,
8393 cancelPrompt,
94+ sendInterrupting,
8495 sendPermissionResponse,
8596 setConfigOption,
8697 getSessionForTask,
@@ -147,6 +158,11 @@ export default function TaskDetailScreen() {
147158 const composerReasoning : ReasoningEffort =
148159 composerConfig ?. reasoning ?? DEFAULT_REASONING ;
149160
161+ const messagingMode = useMessagingMode ( taskId ) ;
162+ const queuedCount = useQueuedCount ( taskId ) ;
163+ const toggleMessagingMode = useToggleMessagingMode ( taskId ) ;
164+ const analytics = useAnalytics ( ) ;
165+
150166 const { height } = useReanimatedKeyboardAnimation ( ) ;
151167
152168 // useReanimatedKeyboardAnimation returns negative height values
@@ -309,6 +325,20 @@ export default function TaskDetailScreen() {
309325 ] ,
310326 ) ;
311327
328+ const trackPromptSent = useCallback (
329+ ( text : string , isSteer : boolean ) => {
330+ if ( ! taskId ) return ;
331+ analytics . track ( ANALYTICS_EVENTS . PROMPT_SENT , {
332+ task_id : taskId ,
333+ is_initial : false ,
334+ execution_type : "cloud" ,
335+ prompt_length_chars : text . length ,
336+ is_steer : isSteer ,
337+ } ) ;
338+ } ,
339+ [ taskId , analytics ] ,
340+ ) ;
341+
312342 const handleSendPrompt = useCallback (
313343 ( text : string , attachments : PendingAttachment [ ] ) => {
314344 if ( ! taskId ) return ;
@@ -319,15 +349,41 @@ export default function TaskDetailScreen() {
319349 return ;
320350 }
321351
322- sendPrompt ( taskId , text , attachments ) . catch ( ( err ) => {
352+ const onSendFailed = ( err : unknown ) => {
323353 log . error ( "Failed to send prompt" , err ) ;
324354 Alert . alert (
325355 "Failed to send" ,
326356 "Your message could not be delivered. Please try again." ,
327357 ) ;
328- } ) ;
358+ } ;
359+
360+ // A turn is running. Queue holds the message locally until it ends;
361+ // Steer interrupts the turn and resends right away.
362+ if ( session ?. isPromptPending ) {
363+ if ( messagingMode === "queue" ) {
364+ useMessageQueueStore . getState ( ) . enqueue ( taskId , text , attachments ) ;
365+ return ;
366+ }
367+ sendInterrupting ( taskId , text , attachments )
368+ . then ( ( ) => trackPromptSent ( text , true ) )
369+ . catch ( onSendFailed ) ;
370+ return ;
371+ }
372+
373+ sendPrompt ( taskId , text , attachments )
374+ . then ( ( ) => trackPromptSent ( text , false ) )
375+ . catch ( onSendFailed ) ;
329376 } ,
330- [ taskId , sendPrompt , session ?. terminalStatus , handleSendAfterTerminal ] ,
377+ [
378+ taskId ,
379+ sendPrompt ,
380+ sendInterrupting ,
381+ session ?. terminalStatus ,
382+ session ?. isPromptPending ,
383+ messagingMode ,
384+ handleSendAfterTerminal ,
385+ trackPromptSent ,
386+ ] ,
331387 ) ;
332388
333389 const handleModeChange = useCallback (
@@ -577,6 +633,9 @@ export default function TaskDetailScreen() {
577633 onModeChange = { handleModeChange }
578634 onModelChange = { handleModelChange }
579635 onReasoningChange = { handleReasoningChange }
636+ messagingMode = { messagingMode }
637+ queuedCount = { queuedCount }
638+ onToggleMessagingMode = { toggleMessagingMode }
580639 />
581640 </ Animated . View >
582641 </ Animated . View >
0 commit comments