
    i                       d dl mZ d dlZd dlZd dlZd dlZd dlmZmZ d dl	m
Z
 d dlZd dlZd dlmZmZmZmZmZmZmZmZ d dlmZmZmZ d dlmZmZ d dlmZmZ d d	l m!Z!m"Z" d d
l#m$Z$m%Z%  G d de&e
      Z'e G d d             Z( G d de)      Z*eee&ef   ee   ee&df   geee&ef   eee&ef      f   f   Z+eee&ef   gdf   Z,e G d d             Z-e G d d             Z. G d d      Z/dddZ0y)    )annotationsN)	dataclassfield)Enum)Any	AwaitableCallableDictIterableListOptionalUnion)	DAGParser	PlanGraphParseResult)PeriodicTriggerTriggerCondition)	TTSClient	TTSConfig)FRClientFRConfig)	VLMClient	VLMConfigc                  $    e Zd ZdZdZdZdZdZdZy)NavStatezhNavigation state for Edge Proxy integration.

    Tracks the state of an active navigation command.
    accepted
navigatingarrivedfailed	cancelledN)	__name__
__module____qualname____doc__ACCEPTED
NAVIGATINGARRIVEDFAILED	CANCELLED     L/home/nelsen/Projects/kognitive/orchestrator/src/executor/action_executor.pyr   r      s"    
 HJGFIr+   r   c                  V    e Zd ZU dZded<   ded<   ded<   ded<   dZd	ed
<   dZded<   y)NavigationContextzuContext for an active navigation operation.

    Stores state for the current navigation command being executed.
    str
request_iddestinationspeedr   status        floatprogressNOptional[str]error)r!   r"   r#   r$   __annotations__r6   r8   r*   r+   r,   r.   r.   &   s3    
 OJHeE=r+   r.   c                      e Zd Zy)ActionExecutionErrorN)r!   r"   r#   r*   r+   r,   r;   r;   5   s    r+   r;   StepOutcomec                  V    e Zd ZU ded<   ded<   ded<    ee      Zded<   dZd	ed
<   y)r<   r/   step_idactionr3   default_factoryDict[str, Any]outputNr7   r8   )r!   r"   r#   r9   r   dictrC   r8   r*   r+   r,   r<   r<   @   s*    LKK"48FN8E=r+   c                  H    e Zd ZU ded<   ded<   ded<    ee      Zded	<   y
)ExecutionReportr/   plan_idboolsuccessDict[str, StepOutcome]resultsr@   z	List[str]errorsN)r!   r"   r#   r9   r   listrL   r*   r+   r,   rF   rF   I   s!    LM##d3FI3r+   rF   c                     e Zd ZdZ	 	 	 	 d#	 	 	 	 	 	 	 	 	 d$dZ	 	 	 	 d%dZd&dZd'd(dZd)dZd*dZ	d+d	Z
d)d
Zd)dZd)dZd,dZd)dZd-dZd.dZd/dZd-dZ	 	 	 	 d0	 	 	 	 	 	 	 	 	 	 	 d1dZd2dZ	 	 	 	 	 	 	 	 d3dZd4dZd5dZ	 	 	 	 	 	 	 	 d6dZ	 	 	 	 	 	 	 	 d7dZ	 	 	 	 	 	 	 	 d8dZ	 d9	 	 	 	 	 d:dZ	 	 	 	 	 	 	 	 d7dZ	 	 	 	 	 	 	 	 d7dZ	 	 	 	 	 	 	 	 d7dZ	 	 	 	 	 	 	 	 d7dZ 	 	 	 	 	 	 	 	 d7d Z!d;d<d!Z"	 	 	 	 	 	 	 	 d7d"Z#y)=ActionExecutor)hazardspillchemicalvaporsmokegasleakfireinjurytrappedunconscious	collapseddeceasedhelpNc                8   |xs
 t               | _        |xs t        j                  t              | _        || _        | j                         | _        |r| j                  j                  |       d| _
        d | _        d | _        d | _        d| _        i | _        g | _        t#        t%        t'        j(                  dd                  | _        t-        t/        t'        j(                  dd                  | _        t3        t5                     | _        d | _        y )NF TTS_ENDPOINTz!http://kluster.klass.dev:8200/tts)endpointFR_ENDPOINTzws://kluster.klass.dev:42067/)r   parserlogging	getLoggerr!   loggerstop_on_error_default_handlers	_handlersupdate
_cancelled_cancel_reason_edge_client_nav_context_robot_location
_waypoints	_triggersr   r   osgetenv_tts_clientr   r   
_fr_clientr   r   _vlm_client_broadcast_callback)selfhandlersrc   rf   rg   s        r,   __init__zActionExecutor.__init__d   s     +	; 1 1( ;*//1NN!!(+-1 ,09=$&*, 13 %"$G
 #!#B
 %Y[1 [_ r+   c                    || _         y)a  Register an async callback for broadcasting messages to dashboard clients.

        Args:
            callback: Async callable that accepts a message dict and broadcasts it
                      to all connected dashboard WebSocket clients, or None to clear.
        N)rw   )rx   callbacks     r,   register_broadcast_callbackz*ActionExecutor.register_broadcast_callback   s     $, r+   c                "    || j                   |<   y N)ri   )rx   r?   handlers      r,   register_handlerzActionExecutor.register_handler   s    !(vr+   c                     d| _         || _        y )NTrk   rl   )rx   reasons     r,   cancelzActionExecutor.cancel   s    $r+   c                     d| _         d | _        y )NFr   rx   s    r,   reset_cancelzActionExecutor.reset_cancel   s    "r+   c                R   || _         |t        |d      r|j                  | j                         t        |d      r|j	                  | j
                         t        |d      r|j                  | j                         t        |d      r|j                  | j                         yyy)zRegister an Edge Proxy WebSocket client for navigation.

        Args:
            client: EdgeProxyClient instance or None to clear.
        Non_nav_statuson_robot_stateon_erroron_waypoint_list)
rm   hasattrr   _handle_nav_statusr   _update_robot_stater   _handle_edge_errorr   _update_waypoint_list)rx   clients     r,   register_edge_proxy_clientz)ActionExecutor.register_edge_proxy_client   s     #v/$$T%<%<=v/0%%d&>&>?vz* 7 78v12''(B(BC 3 r+   c                :    | j                   j                  |       y)ziRegister a periodic trigger.

        Args:
            trigger: PeriodicTrigger instance to add
        N)rq   appendrx   triggers     r,   add_triggerzActionExecutor.add_trigger   s     	g&r+   c                z    | j                   D ]  }|j                           | j                   j                          y)zClear all registered triggers.N)rq   stopclearr   s     r,   clear_triggerszActionExecutor.clear_triggers   s.    ~~ 	GLLN	r+   c                N   K   | j                   D ]  }|j                           yw)zStart all periodic triggers.N)rq   startr   s     r,   _start_triggerszActionExecutor._start_triggers   s"     ~~ 	GMMO	   #%c                N   K   | j                   D ]  }|j                           yw)zStop all periodic triggers.N)rq   r   r   s     r,   _stop_triggerszActionExecutor._stop_triggers   s"     ~~ 	GLLN	r   c                P   K   | j                   D ]  }|j                  |        yw)znUpdate progress for all triggers.

        Args:
            progress: Progress value from 0.0 to 1.0
        N)rq   update_progress)rx   r6   r   s      r,   _update_trigger_progressz'ActionExecutor._update_trigger_progress   s)      ~~ 	.G##H-	.s   $&c                N   K   | j                   D ]  }|j                           yw)z0Notify all triggers that navigation is complete.N)rq   on_navigation_completer   s     r,   $_notify_triggers_navigation_completez3ActionExecutor._notify_triggers_navigation_complete   s%     ~~ 	-G**,	-r   c                4  K   | j                   yt        |dd      }|r|| j                   j                  k7  ryt        |d      r|j                  nd}|dk(  r t
        j                  | j                   _        y|dk(  rkt
        j                  | j                   _        t        |d      r?|j                  | j                   _        | j                  |j                         d{    yy|dk(  rJt
        j                  | j                   _        d	| j                   _        | j                  d	       d{    y|d
k(  rUt
        j                  | j                   _        t        |d      r)|j                  r|j                  | j                   _        yyy|dk(  r|t
        j                  | j                   _        t        |d      r|j                  | j                   _        t        |d      r)|j                  r|j                  | j                   _        yyyy7 27 w)z|Handle navigation status updates from Edge Proxy.

        Args:
            msg: NavStatusMessage from Edge Proxy.
        Nr0   r_   r3   r   r   r6   r         ?r   r   r    )rn   getattrr0   r   r3   r   r%   r&   r6   r   r'   r(   r   r8   r)   )rx   msgmsg_request_id
status_strs       r,   r   z!ActionExecutor._handle_nav_status   s     $ lB7n0A0A0L0LL $+3#9SZZr
#'/'8'8D$<''/':':D$sJ'-0\\!!*33CLLAAA ( 9$'/'7'7D$),D&//4448#'/D$sH%#***-**!!' +5%;&'/'9'9D$sJ'-0\\!!*sH%#***-**!!' +5%	 ' B 5s&   CH!H"AH1H2C"HHc                H   K   t        |d      r|j                  | _        yyw)zrHandle robot state updates from Edge Proxy.

        Args:
            state: RobotState from Edge Proxy.
        locationN)r   r   ro   )rx   states     r,   r   z"ActionExecutor._update_robot_state  s#      5*%#(>>D  &s    "c                   K   | j                   Ht        j                  | j                   _        t	        |d      r|j
                  | j                   _        yyyw)zmHandle error messages from Edge Proxy.

        Args:
            err: ErrorMessage from Edge Proxy.
        Nmessage)rn   r   r(   r3   r   r   r8   )rx   errs     r,   r   z!ActionExecutor._handle_edge_error  sL      ('/D$sI&*-++!!' ' )s   AAc                   K   t        |d      r+|j                  D ci c]  }|j                  | c}| _        yyc c}w w)z{Handle waypoint list updates from Edge Proxy.

        Args:
            msg: WaypointListMessage from Edge Proxy.
        	waypointsN)r   r   namerp   )rx   r   wps      r,   r   z$ActionExecutor._update_waypoint_list"  s8      3$58]]Crrww{CDO %Cs   A ;A c           	     @  K   | j                  |      }|j                  j                  dd      }i }g }	t        |j                  j                               }
t        |j                        }|r|j                  d      }|j                  |   }| j                  r!|	j                  | j                  xs d       nb|r ||       	 | j                  |||       d {   }t        ||j                  dd      d|      }|||<   |
j!                  |       |r ||       |k|j$                  dk(  r\|j&                  dk(  rM| j)                  |j*                        \  }}|r- |d|j,                  |j&                  ||j*                  |d       t        |j.                  j                  |t                           D ]\  }||
vr|j0                  j                  |t                     }|j3                  |j                               sL|j                  |       ^ |r|
r|	s| j                  s|	j                  d       |
D ]3  }|j                  |   }t        ||j                  dd      dd
      ||<   5 |	 xr | j                   }t5        ||||	      S 7 # t        $ rw}t        |      }t        ||j                  dd      d	|
      }|	j                  |       |||<   |
j!                  |       |r ||       | j"                  rY d }~Y d }~d }~ww xY ww)NrG   unknown_planr   execution_cancelledr?   r_   rI   )r>   r?   r3   rC   r   )r>   r?   r3   r8   	SCAN_AREAdynamic_replan_requested)typer>   r?   reasonsscan_outputrG   deadlock_detectedskipped)rG   rI   rK   rL   )_ensure_plan_graphplangetsetstep_lookupkeyssortedentry_stepspoprk   r   rl   _execute_stepr<   	Exceptionr/   discardrg   r3   r?   _should_replan_after_scanrC   r>   childrendependenciesissubsetrF   )rx   r   contexton_step_starton_step_completeon_replan_requested
plan_graphrG   rK   rL   pendingreadyr>   steprC   outcomeexcr   r   r   childdepsrI   s                          r,   execute_planzActionExecutor.execute_plan,  s     ,,T2
//%%i@*,j,,1134!*"8"89iilG))'2Dd11J5JKd##11$II%#88Hb1$!	.  'GGOOG$ ) $/NNi/NNk1#'#A#A'..#Q '$>'.&-nn'.+2>>'.	  
 3 3 7 7 GH ('!..225#%@==0LL'(y F 6$//MM-. 	G))'2D*xx"- 	 GG	 *4T__!4wY_``I J  c(%#88Hb1#!	 g&#* (#$W-%%sQ   CLJ J#J DLLA:LJ 	L$A'LLLLc                `   g }|j                  d      r|j                  d       t        |j                  dd            j                         }t	        | j
                  D ch c]	  }||v s| c}      }|r#|j                  ddj                  |              t        |      dkD  |fS c c}w )zDecide whether SCAN_AREA findings warrant a dynamic replan.

        Trigger when:
        - Structured signal says scene is interesting, OR
        - Free-form analysis text contains hazard/casualty keywords.
        interestingscan_marked_interestinganalysisr_   zanalysis_keywords:,r   )r   r   r/   lowerr   _SCAN_REPLAN_KEYWORDSjoinlen)rx   rC   r   r   kwmatcheds         r,   r   z(ActionExecutor._should_replan_after_scan  s      ::m$NN45vzz*b1288:t'A'ATR8^"TUNN/0A/BCDGq 7**	 Us   !	B++B+c                   K   |j                  d      }| j                  j                  |      }|t        d| d       ||||      }t        j                  |      r
| d {   S |S 7 w)Nr?   z"No handler registered for action 'z'.)r   ri   r;   inspectisawaitable)rx   r   r   rK   r?   r   responses          r,   r   zActionExecutor._execute_step  ss      (#..$$V,?&)KF8SU'VWW4'2x(!>! "s   A"A-$A+%A-c                   t        |t              r|S | j                  j                  |      }|j                  r|j
                  s/|j                  r|j                  j                  nd}t        |      |j
                  S )NzUnknown parse failure.)	
isinstancer   rc   parseokr   r8   r   r;   )rx   r   parse_resultr   s       r,   r   z!ActionExecutor._ensure_plan_graph  sg    dI&K$(KK$5$5d$;l&=&=4@4F4Fl((00LdG&w//&&&r+   c           	         | j                   | j                  | j                  | j                  | j                  | j
                  | j                  | j                  dS )N)CHECK_BATTERYNAVIGATEr   VERIFY_OBJECTSPEAKWAITIDENTIFY_PERSONALERT_OPERATOR)_handle_check_battery_handle_navigate_handle_scan_area_handle_verify_object_handle_speak_handle_wait_handle_identify_person_handle_alert_operatorr   s    r,   rh   z ActionExecutor._default_handlers  sT    !77--//!77''%%#;;"99	
 		
r+   c                  K   |j                  d      xs i }|j                  dd      }d }| j                  r| j                  j                  r\| j                  j                  F| j                  j                  j                  j
                  }| j                  j                  d|       |t        |dd       }|d}||k\  |dS w)	Nparams	min_levelr   z,CHECK_BATTERY: using live battery level %d%%battery_level)defaultd   )
battery_okcurrent_level)	r   rm   is_connectedlast_robot_statebatterylevelrf   debug_context_value)rx   r   r   _resultsr  r  r  s          r,   r   z$ActionExecutor._handle_check_battery  s      (#)rJJ{A.	  $)!!..!!22>%%66>>DDEKKLeT ="7OTJE =E#y05IIs   CCc                @  K   |j                  d      xs i }|j                  dd      }|j                  dd      }|j                  dd      }| j                  <| j                  r|| j                  vrd||dd	S | j                  |||       d {   S d
||dS 7 
w)Nr  r1   unknownr2   normalr>   r   unknown_waypointr3   r1   r2   r8   r   r3   r1   r2   )r   rm   rp   _navigate_with_edge_proxy)rx   r   _contextr  r  r1   r2   r>   s           r,   r   zActionExecutor._handle_navigate  s      (#)rjj	:

7H-((9i0 (;doo#E&#."/	  77UGTTT $K%PP Us   BBBBc                D  K   ddl m} d| }t        |||t        j                        | _        	 | j                  j                  |||       d{    | j                          d{    	 | j                  |d
       d{    	 | j'                          d{    d||dS 7 W# t        $ r6}| j                  j                  d|       d||t        |      d	cY d}~S d}~ww xY w7 7 i# t        j                  $ r | j                  j                  d|       t        j                   | j
                  _        d| j
                  _
        | j%                          d{  7   d||dd	cY | j'                          d{  7   S t        $ rh}| j                  j                  d|       | j%                          d{  7   d||t        |      d	cY d}~| j'                          d{  7   S d}~ww xY w7 `# | j'                          d{  7   w xY ww)a  Execute navigation using Edge Proxy client.

        Args:
            destination: Target waypoint name.
            speed: Navigation speed.
            step_id: Step ID for tracking.

        Returns:
            Result dictionary with navigation outcome.
        r   )	NavStatusnav_)r0   r1   r2   r3   )r   r0   r2   Nz#Failed to send navigate command: %sr   r        ^@timeoutzNavigation timeout for %sr!  zNavigation failed: %sr   r  )edge_proxy.messagesr  r.   r   r%   rn   rm   send_navigate_waypointr   rf   r8   r/   r   _wait_for_navigationasyncioTimeoutErrorr(   r3   r   r   )rx   r1   r2   r>   r  r0   r   s          r,   r  z(ActionExecutor._navigate_with_edge_proxy  s     	2 G9%
-!#$$	
	##:: Zu ;    ""$$$	(++J+FFF. %%'''  &
 	
W  	KKCSI"*S	 	 	% G## 
	KK9;G'/D$&/D#;;==="*"	 " %%'''  	KK5s;;;==="*S	  %%'''	 ($%%'''s  .H !B, B*B, H *C.+H 0C2 C0C2 H G? 
H *B, ,	C+5+C& C+!H &C++H 0C2 2A2G<$E'%G<1H 2H FH G</G7GG7G<H H 0G31H 7G<<H ?H HHHH c                  K   t        j                         j                         }d}	 t        j                         j                         |z
  }||kD  rt        j                  d| d|       | j                  t        d      | j                  j                  }|t        j                  k(  r| j                  d       d{    y|t        j                  k(  r(| j                  j                  xs d}t        d|       |t        j                  k(  rt        d	      | j                  j                  d
kD  r-| j                  | j                  j                         d{    t        j                  |       d{    ]7 7 %7 
w)a&  Wait for navigation to complete or fail.

        Args:
            request_id: Navigation request ID to track.
            timeout: Maximum time to wait in seconds.

        Raises:
            asyncio.TimeoutError: If navigation times out.
            Exception: If navigation fails.
        皙?zNavigation timeout after zs for request Nz#Navigation context lost during waitr   zUnknown navigation failurezNavigation failed: zNavigation was cancelledr   )r%  get_event_looptimer&  rn   RuntimeErrorr3   r   r'   r   r(   r8   r   r)   r6   sleep)rx   r0   r!  
start_timecheck_intervalelapsedr3   r8   s           r,   r$  z#ActionExecutor._wait_for_navigationI  so     ++-224
,,.335
BG **/yzlS 
   ("#HII&&--F)))33C8888??*))//O3O"5eW =>>8--- :;;   ))A-33D4E4E4N4NOOO --///;   9 P 0s7   B?FFBF!F"F>F	?FF	Fc                (  K   |j                  d      xs i }|j                  dd      }d}| j                          d{   }|| j                  j                  d|       d}nEt	        j
                         }		 |	j                  d| j                  j                  ||       d{   }|j                         }t        | j                  D ch c]	  }||v s| c}      }t        |      d	kD  }| j                  	 | j                  d
|d       d{    ||d||dS 7 7 }# t        $ r(}
| j                  j                  d|
       d}Y d}
~
d}
~
ww xY wc c}w 7 I# t        $ r&}
| j                  j                  d|
       Y d}
~
qd}
~
ww xY ww)a  Run VLM scene analysis on the current camera frame.

        Captures a JPEG frame, sends it to the VLM endpoint together with a
        chemical-spill-oriented prompt, broadcasts the result to the dashboard
        as a ``vlm_caption`` message, and returns a structured outcome dict.

        If no frame is available (camera not wired), the VLM call is skipped
        and the analysis field contains an empty string.
        r  targetareau;  You are an emergency-response robot assistant analysing a scene for a chemical spill exercise.  Describe what you see concisely: number and state of any people (conscious / unconscious), visible chemical containers or hazard markings, exit routes, and any immediate dangers.  Be factual and brief (3–5 sentences).NuA   SCAN_AREA: no frame available — skipping VLM call for target %rr_   zSCAN_AREA: VLM call failed: %sr   vlm_caption)r   textz.SCAN_AREA: failed to broadcast vlm_caption: %sg      Y@)r   r1  coverage_percentr   signals)r   _capture_framerf   warningr%  r)  run_in_executorrv   analyze_scener   r8   r   r   r   r   rw   )rx   r   r  r  r  r1  promptframer   loopr   analysis_lcr   r6  r   s                  r,   r   z ActionExecutor._handle_scan_areax  s     (#)rHf-J 	 (,':':'<!<=KKS H))+D!%!5!5$**88%"  nn&t'A'AWR;EV"WX'lQ& ##/[..x/XYYY
 ! %&
 	
; "=  !!"BCH
 X Z [##$TVYZZ[s   =FD! 9F:+D% %D#&D% *#F	EE!F=E  EE  	F#D% %	E.EFEFE   	F)F
F
FFc                `  K   |j                  d      xs i }|j                  dd      }|j                  d|      }d| d}| j                          d{   }|| j                  j                  d|       d	}	nEt	        j
                         }
	 |
j                  d| j                  j                  ||       d{   }	|	j                         }|j                         }||v }|||r|nd|	|rddS ddS 7 7 <# t        $ r(}| j                  j                  d
|       d	}	Y d}~fd}~ww xY ww)zVerify an object in the scene using VLM.

        Captures a JPEG frame, sends it to the VLM endpoint with a prompt
        asking to identify/verify the object, and returns the verification result.
        r  expected_classobjectr1  zrYou are an emergency-response robot assistant inspecting an object. Look at this scene and identify if there is a u   . If visible, describe its appearance, location, and condition. If not visible, state that clearly. Be concise (2–3 sentences).NuE   VERIFY_OBJECT: no frame available — skipping VLM call for target %rr_   z"VERIFY_OBJECT: VLM call failed: %sr  g?r(  )verifiedr@  actual_classr   
confidence)r   r7  rf   r8  r%  r)  r9  rv   r:  r   r8   r   )rx   r   r  r  r  expectedr1  r;  r<  r   r=  r   r>  	target_lcrB  s                  r,   r   z$ActionExecutor._handle_verify_object  sU     (#)r::.9Hh/==CH EPQ 	 (,':':'<!<=KKW H))+D!%!5!5$**88%"  nn&LLN	+ !&&.FI !)#
 	

 03
 	
/ "=  !!"FLsN   AD.C69D.+C: ;C8<C:  7D.8C: :	D+D&!D.&D++D.c                l  K   |j                  d      xs i }|j                  dd      }|s!| j                  j                  d       ddddS | j                  j	                  |       d {   }|s%| j                  j                  d|d d	        d|d
dS | j                  Vdd l}t        j                  |      j                  d      }	 | j                  d||d|j                         d       d {    d|dS 7 7 # t        $ r&}	| j                  j                  d|	       Y d }	~	3d }	~	ww xY ww)Nr  r   r_   u7   SPEAK action called with empty message — skipping TTSFempty_message)spokenr   r8   zTTS failed for message: %rP   
tts_failedr   zutf-8	tts_audiowav)r   	audio_b64r4  format	timestampz(SPEAK: failed to broadcast tts_audio: %sT)rI  r   )r   rf   r8  rt   speakr8   rw   r*  base64	b64encodedecoder   )
rx   r   r  r  r  r   	wav_bytesr*  rN  r   s
             r,   r  zActionExecutor._handle_speak  s:     (#)r**Y+KK YZ#_MM**0099	KK:GCRLI#,OO ##/((3::7CI	U..'!*##!%0    733- :  U##$NPSTTUsO   A)D4+C>,AD4(D 4D 5D 9D4 D 	D1D,'D4,D11D4c                   K   |j                  d      xs i }|j                  dd      }t        j                  t        |d      dz         d {    d|iS 7 w)Nr  duration_msr   g     @@	waited_ms)r   r%  r,  max)rx   r   r  r  r  rW  s         r,   r  zActionExecutor._handle_wait  sY      (#)rjj2mmCQ/&8999[)) 	:s   AAA	Ac                  K   | j                          d {   }|!| j                  j                  d       ddddS | j                  j	                  |       d {   }|s!| j                  j                  d       ddg dS t        |d 	      }| j                  j                  d
|j                  d      |j                  dd             |j                  dd      |j                  dd      |j                  d      |dS 7 7 w)Nu9   IDENTIFY_PERSON: no frame available — returning unknownr  r4   no_frame)identityrD  r8   z*IDENTIFY_PERSON: FR returned no detections)r\  rD  
detectionsc                &    | j                  dd      S )NrD  r4   )r   )ds    r,   <lambda>z8ActionExecutor._handle_identify_person.<locals>.<lambda>0  s    QUU<-E r+   )keyz7IDENTIFY_PERSON: best match identity=%r confidence=%.2fr\  rD  bbox)r\  rD  rb  r]  )r7  rf   r8  ru   identifyinforY  r   )rx   r   r  r  frame_bytesr]  bests          r,   r  z&ActionExecutor._handle_identify_person  s      !//11KK [\ )zRR  ??33K@@
KKIJ )BOO :#EFEHHZ HH\3'	
 Y7((<5HHV$$	
 	
' 2 As#   DDADDB(DDc                  K   | j                   | j                   j                  s| j                  j                  d       yt	        t        j                               }t        j                         }|j                         }|| j                   j                  |<   	 | j                   j                  |       d{    	 ddlm} t        j"                  ||       d{   }|j                  r'| j                  j'                  d
|j                         y|j(                  s| j                  j'                  d       y	 t+        j,                  |j(                        }| j                  j                  dt/        |             |S 7 # t        $ rL}| j                  j                  d|       | j                   j                  j                  |d       Y d}~yd}~ww xY w7 # t        j$                  $ rE | j                  j'                  d|       | j                   j                  j                  |d       Y yt        $ rL}| j                  j                  d	|       | j                   j                  j                  |d       Y d}~yd}~ww xY w# t        $ r&}| j                  j                  d|       Y d}~yd}~ww xY ww)a  Capture a single JPEG frame from the robot camera via the Edge Proxy.

        Sends a ``capture_frame`` command over the existing Edge Proxy WebSocket
        connection and waits for the matching ``frame_response`` message.

        The Edge Proxy handles the actual frame grab (HTTP snapshot from
        MediaMTX, with an ffmpeg-RTSP fallback) so this method only needs the
        WS connection.

        Args:
            timeout: Maximum seconds to wait for the frame response.

        Returns:
            Raw JPEG bytes decoded from the base64 response, or ``None`` if
            no Edge Proxy client is connected, capture fails, or the request
            times out.
        NuA   _capture_frame: no connected edge proxy client — returning None)r0   z0_capture_frame: failed to send capture_frame: %sr   )FrameResponseMessager   z@_capture_frame: timed out after %.1fs waiting for frame_responsez4_capture_frame: error waiting for frame_response: %sz-_capture_frame: edge proxy reported error: %sz/_capture_frame: frame_response missing jpeg_b64z+_capture_frame: failed to decode base64: %sz!_capture_frame: received %d bytes)rm   r  rf   r  r/   uuiduuid4r%  r)  create_future_pending_framessend_capture_framer   r8   r   r"  rh  wait_forr&  r8  jpeg_b64rR  	b64decoder   )	rx   r!  r0   r=  futurer   rh  r   re  s	            r,   r7  zActionExecutor._capture_frame=  sA    $ $D,=,=,J,JKKab&
 %%'!%!3!3!58>))*5	##66*6MMM	@.5.>.>vw.W(WC 99KK OQTQZQZ[||KK QR	 **3<<8K
 	=s;?OPG N 	KKPRUV--11*dC	 )X## 	KKRT[ --11*dC 	KKTVYZ--11*dC	  	KKKSQ	s   BKF
 ;F<F
  G% !G""G% &AKJ !'KF
 
	GAGKGK"G% %AJ:K<JAJKJK	KJ=8K=KKc                  K   |j                  d      xs i }|j                  dd      }|j                  dd      }| j                  Qdd l}d|||j                         d}	 | j                  |       d {    | j                  j	                  d	||       n| j                  j                  d       d||dS 7 C# t
        $ r&}	| j                  j                  d
|	       Y d }	~	2d }	~	ww xY ww)Nr  r   unspecifiedseverityrd  r   alert)r   r   rt  rP  z'Alert broadcasted to dashboard: %s (%s)z*Failed to broadcast alert to dashboard: %szMALERT_OPERATOR: no broadcast callback registered, alert not sent to dashboardT)alertedr   rt  )r   rw   r*  rf   rd  r   r8  )
rx   r   r  r  r  r   rt  r*  alert_messager   s
             r,   r  z%ActionExecutor._handle_alert_operator  s      (#)rHm4::j&1##/   $!YY[	-MW..}===  !JFT\] KK op  
 	
 > W##$PRUVVWsB   AC."B< 6B:7!B< "C.:B< <	C+C&!C.&C++C.)NNNT)
ry   z"Optional[Dict[str, ActionHandler]]rc   zOptional[DAGParser]rf   zOptional[logging.Logger]rg   rH   returnNone)r|   z5Optional[Callable[[Dict[str, Any]], Awaitable[None]]]rx  ry  )r?   r/   r   ActionHandlerrx  ry  r   )r   r7   rx  ry  )rx  ry  )r   Optional[Any]rx  ry  )r   r   rx  ry  )r6   r5   rx  ry  )r   r   rx  ry  )r   r   rx  ry  )r   r   rx  ry  )NNNN)r   %Union[PlanGraph, Dict[str, Any], str]r   r{  r   z*Optional[Callable[[Dict[str, Any]], None]]r   z'Optional[Callable[[StepOutcome], None]]r   zOptional[ReplanCallback]rx  rF   )rC   rB   rx  ztuple[bool, List[str]])r   rB   r   r{  rK   rJ   rx  rB   )r   r|  rx  r   )rx  zDict[str, ActionHandler])r   rB   r   r{  r  rJ   rx  rB   )r   rB   r  r{  r  rJ   rx  rB   )r1   r/   r2   r/   r>   r/   rx  rB   )r  )r0   r/   r!  r5   rx  ry  )g       @)r!  r5   rx  zOptional[bytes])$r!   r"   r#   r   rz   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rh   r   r   r  r$  r   r   r  r  r  r7  r  r*   r+   r,   rO   rO   Q   s   & 8<&*+/"/_4/_ $/_ )	/_
 /_ 
/_b	,M	,		,)%#D&'

.-$5L2	6D "&DHDH8<aa3aa aa B	aa
 Baa 6aa 
aaF+&  (	
 
 '

JJ J )	J
 
J:QQ  Q )	Q
 
Q4I
I
'*I
58I
	I
X 16-0-0(--0	-0^=
=
  =
 )	=

 
=
~3
3
  3
 )	3

 
3
j#4#4  #4 )	#4
 
#4J	*	*  	* )		*
 
	*

  
 )	

 

BAF

  
 )	

 

r+   rO   c                h    | |S t        | t              r| j                  ||      S t        | ||      S r   )r   rD   r   r   )r   ra  r	  s      r,   r  r    s6    '4 {{3((7C))r+   r   )r   r{  ra  r/   r	  r   rx  r   )1
__future__r   r%  rR  rr   ri  dataclassesr   r   enumr   r   rd   typingr   r   r	   r
   r   r   r   r   planner.dag_parserr   r   r   executor.triggersr   r   services.tts_clientr   r   services.fr_clientr   r   services.vlm_clientr   r   r/   r   r.   r+  r;   rz  ReplanCallbackr<   rF   rO   r  r*   r+   r,   <module>r     s!   "   	  (    R R R @ @ ? 4 1 4
sD 
      	< 	 	#s(^Xc]Dm);$<=	$sCx.)DcN3
346 4S>*D01       4 4 4N
 N
b*r+   