
    i]                    $   d Z ddlmZ ddlZddlZddlZddlZddlZddlm	Z	 ddl
mZmZmZmZmZ ddlZddlmZ  ej        e          ZdZdZd	Z eeeeh          ZeZd
ZdZdZdZdZ dZ!de! dZ"dZ#e	 G d d                      Z$e	 G d d                      Z%e	 G d d                      Z&e	 G d d                      Z' e	d           G d d                      Z( G d d           Z) G d! d"          Z* e*            Z+g d#Z,dS )$u  Persistent CDP supervisor for browser dialog + frame detection.

One ``CDPSupervisor`` runs per Hermes ``task_id`` that has a reachable CDP
endpoint. It holds a single persistent WebSocket to the backend, subscribes
to ``Page`` / ``Runtime`` / ``Target`` events on every attached session
(top-level page and every OOPIF / worker target that auto-attaches), and
surfaces observable state — pending dialogs and frame tree — through a
thread-safe snapshot object that tool handlers consume synchronously.

The supervisor is NOT in the agent's tool schema. Its output reaches the
agent via two channels:

1. ``browser_snapshot`` merges supervisor state into its return payload
   (see ``tools/browser_tool.py``).
2. ``browser_dialog`` tool responds to a pending dialog by calling
   ``respond_to_dialog()`` on the active supervisor.

Design spec: ``website/docs/developer-guide/browser-supervisor.md``.
    )annotationsN)	dataclass)AnyDictListOptionalTuple)ClientConnectionmust_respondauto_dismissauto_acceptg     r@      2      zhermes-dialog-bridge.invalidzhttp://z/*u.  
(() => {
  if (window.__hermesDialogBridgeInstalled) return;
  window.__hermesDialogBridgeInstalled = true;
  const ENDPOINT = "http://hermes-dialog-bridge.invalid/";
  function ask(kind, message, defaultPrompt) {
    try {
      const xhr = new XMLHttpRequest();
      // Use GET with query params so we don't need to worry about request
      // body encoding in the Fetch interceptor.
      const params = new URLSearchParams({
        kind: String(kind || ""),
        message: String(message == null ? "" : message),
        default_prompt: String(defaultPrompt == null ? "" : defaultPrompt),
      });
      xhr.open("GET", ENDPOINT + "?" + params.toString(), false);  // sync
      xhr.send(null);
      if (xhr.status !== 200) return null;
      const body = xhr.responseText || "";
      let parsed;
      try { parsed = JSON.parse(body); } catch (e) { return null; }
      if (kind === "alert") return undefined;
      if (kind === "confirm") return Boolean(parsed && parsed.accept);
      if (kind === "prompt") {
        if (!parsed || !parsed.accept) return null;
        return parsed.prompt_text == null ? "" : String(parsed.prompt_text);
      }
      return null;
    } catch (e) {
      // If the bridge is unreachable, fall back to the native call so the
      // page still sees *some* behavior (the backend will auto-dismiss).
      return null;
    }
  }
  const realAlert   = window.alert;
  const realConfirm = window.confirm;
  const realPrompt  = window.prompt;
  window.alert   = function(message) { ask("alert",   message, ""); };
  window.confirm = function(message) {
    const r = ask("confirm", message, "");
    return r === null ? false : Boolean(r);
  };
  window.prompt  = function(message, def) {
    const r = ask("prompt", message, def == null ? "" : def);
    return r === null ? null : String(r);
  };
  // onbeforeunload — we can't really synchronously prompt the user from this
  // event without racing navigation.  Leave native behavior for now; the
  // supervisor's native-dialog fallback path still surfaces them in
  // recent_dialogs.
})();
c                  t    e Zd ZU dZded<   ded<   ded<   ded<   ded<   ded	<   d
Zded<   d
Zded<   ddZd
S )PendingDialogz3A JS dialog currently open on some frame's session.stridtypemessagedefault_promptfloat	opened_atcdp_session_idNOptional[str]frame_idbridge_request_idreturnDict[str, Any]c                P    | j         | j        | j        | j        | j        | j        dS )Nr   r   r   r   r   r   r"   selfs    =/home/ubuntu/.hermes/hermes-agent/tools/browser_supervisor.pyto_dictzPendingDialog.to_dict   s0    'I|"1
 
 	
    r   r    )__name__
__module____qualname____doc____annotations__r   r   r&    r'   r%   r   r      s         ==GGGIIILLL"H"""" (,++++
 
 
 
 
 
r'   r   c                  f    e Zd ZU dZded<   ded<   ded<   ded<   ded<   ded	<   d
Zded<   ddZd
S )DialogRecorda  A historical record of a dialog that was opened and then handled.

    Retained in ``recent_dialogs`` for a short window so agents on backends
    that auto-dismiss dialogs server-side (Browserbase) can still observe
    that a dialog fired, even though they couldn't respond to it.
    r   r   r   r   r   r   	closed_at	closed_byNr   r   r   r    c                \    | j         | j        | j        | j        | j        | j        | j        dS )Nr   r   r   r   r1   r2   r   r4   r#   s    r%   r&   zDialogRecord.to_dict   s4    'I|
 
 	
r'   r(   )r)   r*   r+   r,   r-   r   r&   r.   r'   r%   r0   r0      s           GGGIIILLLNNN"H""""	
 	
 	
 	
 	
 	
r'   r0   c                  j    e Zd ZU dZded<   ded<   ded<   ded<   ded	<   d
Zded<   dZded<   ddZd
S )	FrameInfoa  One frame in the page's frame tree.

    ``is_oopif`` means the frame has its own CDP target (separate process,
    reachable via ``cdp_session_id``). Same-origin / srcdoc iframes share
    the parent process and have ``is_oopif=False`` + ``cdp_session_id=None``.
    r   r   urloriginr   parent_frame_idboolis_oopifNr    namer   r    c                    | j         | j        | j        | j        d}| j        r
| j        |d<   | j        r
| j        |d<   | j        r
| j        |d<   |S )N)r   r7   r8   r;   
session_idr9   r=   )r   r7   r8   r;   r   r9   r=   )r$   ds     r%   r&   zFrameInfo.to_dict   sn    8k	
 
  	2"1AlO 	8#'#7A 9 	"	AfIr'   r(   )r)   r*   r+   r,   r-   r   r=   r&   r.   r'   r%   r6   r6      s           MMMHHHKKK""""NNN$(N((((DNNNN     r'   r6   c                  @    e Zd ZU dZded<   ded<   ded<   dZded	<   dS )
ConsoleEventz2Ring buffer entry for console + exception traffic.r   tsr   leveltextNr   r7   )r)   r*   r+   r,   r-   r7   r.   r'   r%   rB   rB      sD         <<IIIJJJIIICr'   rB   T)frozenc                  b    e Zd ZU dZded<   ded<   ded<   ded	<   d
ed<   ded<   ded<   ddZdS )SupervisorSnapshotzRead-only snapshot of supervisor state.

    Frozen dataclass so tool handlers can freely dereference without
    worrying about mutation under their feet.
    zTuple[PendingDialog, ...]pending_dialogszTuple[DialogRecord, ...]recent_dialogsr    
frame_treezTuple[ConsoleEvent, ...]console_errorsr:   activer   cdp_urltask_idr   c                n    d | j         D             | j        d}| j        rd | j        D             |d<   |S )z7Serialize for inclusion in ``browser_snapshot`` output.c                6    g | ]}|                                 S r.   r&   .0r@   s     r%   
<listcomp>z.SupervisorSnapshot.to_dict.<locals>.<listcomp>   s     JJJ		JJJr'   )rI   rK   c                6    g | ]}|                                 S r.   rR   rS   s     r%   rU   z.SupervisorSnapshot.to_dict.<locals>.<listcomp>   s     $N$N$NQQYY[[$N$N$Nr'   rJ   )rI   rK   rJ   )r$   outs     r%   r&   zSupervisorSnapshot.to_dict   sY      KJT5IJJJ/
 
  	O$N$N$:M$N$N$NC !
r'   Nr(   )r)   r*   r+   r,   r-   r&   r.   r'   r%   rH   rH      s           /...,,,,,,,,LLLLLLLLL     r'   rH   c                     e Zd ZdZeedd?dZd@dAdZdBdAdZdCdZ	dddddDdZ
dEdZdEdZdEdZdFd Z	 dGddd!dHd%ZdEd&ZdId'ZdJd(ZdKd-ZdLd.ZdMd0ZdKd1ZdJd2ZdJd3ZdKd4ZdJd5ZdJd6ZdJd7ZdNd8ZdOd:ZdNd;ZdPd=Z dQd>Z!dS )RCDPSupervisoru  One supervisor per (task_id, cdp_url) pair.

    Lifecycle:
      * ``start()`` — kicked off by ``SupervisorRegistry.get_or_start``; spawns
        a daemon thread running its own asyncio loop, connects the WebSocket,
        attaches to the first page target, enables domains, starts
        auto-attaching to child targets.
      * ``snapshot()`` — sync, thread-safe, called from tool handlers.
      * ``respond_to_dialog(action, ...)`` — sync bridge; schedules a coroutine
        on the supervisor's loop and waits (with timeout) for the CDP ack.
      * ``stop()`` — cancels task, closes WebSocket, joins thread.

    All CDP I/O lives on the supervisor's own loop. External callers never
    touch the loop directly; they go through the sync API above.
    )dialog_policydialog_timeout_srO   r   rN   rZ   r[   r   r   Nonec                  |t           vr't          d|dt          t                                || _        || _        || _        t          |          | _        t          j	                    | _
        i | _        g | _        i | _        g | _        d| _        d | _        d | _        t          j                    | _        d | _        d| _        d| _        i | _        d | _        d | _        i | _        i | _        d| _        d S )NzInvalid dialog_policy z; must be one of F   r   )_VALID_POLICIES
ValueErrorsortedrO   rN   rZ   r   r[   	threadingLock_state_lock_pending_dialogs_recent_dialogs_frames_console_events_active_loop_threadEvent_ready_event_start_error_stop_requested_next_call_id_pending_calls_ws_page_session_id_child_sessions_dialog_watchdogs_dialog_seq)r$   rO   rN   rZ   r[   s        r%   __init__zCDPSupervisor.__init__  s    //< < <"("9"9< <   * %&6 7 7 %>++:<35-/35 ;?
37%O--59$ 9;/3/3:< BDr'         .@timeoutc                   | j         r| j                                         rdS | j                                         d| _        d| _        t          j        | j        d| j	         d          | _         | j         
                                 | j                            |          s7|                                  t          d| d| j        dd	          d
          | j        | j        }|                                  |dS )u[  Launch the background loop and wait until attachment is complete.

        Raises whatever exception attach failed with (connect error, bad
        WebSocket URL, CDP domain enable failure, etc.). On success, the
        supervisor is fully wired up — pending-dialog events will be captured
        as of the moment ``start()`` returns.
        NFzcdp-supervisor-T)targetr=   daemonry   z%CDP supervisor did not attach within zs (cdp_url=P   z...))rk   is_aliverm   clearrn   ro   rb   Thread_thread_mainrO   startwaitstopTimeoutErrorrN   )r$   ry   errs      r%   r   zCDPSupervisor.startC  s(    < 	DL1133 	F!!! $ '$14<11
 
 

 	 %%g%66 	IIKKK4 4 4 L"-4 4 4   (#CIIKKKI )(r'         @c                    d _          j        }|p|                                r\ fd}	 t          j         |            |          }	 |                    d           n# t          $ r Y nw xY wn# t          $ r Y nw xY w j         j        	                    |            j
        5  d _        ddd           dS # 1 swxY w Y   dS )z/Cancel the supervisor task and join the thread.TNc                    K   j         } d _         | .	 |                                  d {V  d S # t          $ r Y d S w xY wd S N)rr   close	Exception)wsr$   s    r%   	_close_wsz%CDPSupervisor.stop.<locals>._close_wsi  sn      X> hhjj((((((((($    ">s   1 
??g       @r}   F)ro   rj   
is_runningasynciorun_coroutine_threadsaferesultr   RuntimeErrorrk   joinrd   ri   )r$   ry   loopr   futs   `    r%   r   zCDPSupervisor.stopa  sO   #z 1 1    6yy{{DIIJJsJ++++    D   <#Lg... 	! 	! DL	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	!sG   A2 
A!  A2 !
A.+A2 -A..A2 2
A?>A?+C  CCrH   c           	        | j         5  t          | j                                                  }t          | j        t
           d                   }|                                 }t          | j        t           d                   }| j	        }ddd           n# 1 swxY w Y   t          |||||| j        | j                  S )z.Return an immutable snapshot of current state.N)rI   rJ   rK   rL   rM   rN   rO   )rd   tuplere   valuesrf   RECENT_DIALOGS_MAX_build_frame_tree_lockedrh   CONSOLE_HISTORY_MAXri   rH   rN   rO   )r$   dialogsrecentframes_treeconsolerM   s         r%   snapshotzCDPSupervisor.snapshot  s    	" 	"D188::;;G4/1C0C0D0DEFFF7799KD02E1E1F1FGHHG\F	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" "#!""LL
 
 
 	
s   BBB!BN      $@)prompt_text	dialog_idry   actionr   r   r   r    c               R    dvrdddS  j         5   j        sdddcddd           S t           j                                                  }|sdddcddd           S |rG j                            |          }|*dd|d	t           j                   d
dcddd           S nHt          |          dk    r-dt          |           dd |D              dcddd           S |d         }|ddd           n# 1 swxY w Y    j        }|dddS  fd}	 t          j
         |            |          }	|	                    |           n3# t          $ r&}
dt          |
          j         d|
 dcY d}
~
S d}
~
ww xY wd                                dS )a  Accept/dismiss a pending dialog. Sync bridge onto the supervisor loop.

        Returns ``{"ok": True, "dialog": {...}}`` on success,
        ``{"ok": False, "error": "..."}`` on a recoverable error (no dialog,
        ambiguous dialog_id, supervisor inactive).
        )acceptdismissFz*action must be 'accept' or 'dismiss', got )okerrorzsupervisor is not activeNzno dialog is currently openz
dialog_id z not found (known: )r^   z1 pending dialogs; specify dialog_id. Candidates: c                    g | ]	}|j         
S r.   )r   rS   s     r%   rU   z3CDPSupervisor.respond_to_dialog.<locals>.<listcomp>  s    '>'>'>'>'>'>r'   r   zsupervisor loop is not runningc                 P   K                         dk    pd           d {V S )Nr   r<   r   r   )_handle_dialog_cdp)r   r   r$   snapshot_copys   r%   _do_respondz4CDPSupervisor.respond_to_dialog.<locals>._do_respond  sT      00v'9HYWY 1         r'   r}   : T)r   dialog)rd   ri   listre   r   getra   lenrj   r   r   r   r   r   r)   r&   )r$   r   r   r   ry   pendingr   r   r   r   er   s   ```        @r%   respond_to_dialogzCDPSupervisor.respond_to_dialog  s,    ...*aW]*a*abbb 	# 	#< J#.HII	# 	# 	# 	# 	# 	# 	# 	# 407799::G M#.KLL	# 	# 	# 	# 	# 	# 	# 	#  $.229==>#"Di "D "D#)$*?#@#@"D "D "D 	# 	# 	# 	# 	# 	# 	# 	# " W!!w<< A A'>'>g'>'>'>A A 	# 	# 	# 	# 	# 	# 	# 	#. !"M1	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	# 	#4 z<*JKKK	 	 	 	 	 	 	 	
	F2;;==$GGCJJwJ'''' 	F 	F 	FT!WW-=*D*D*D*DEEEEEEEE	Fm&;&;&=&=>>>sF   D	,D	*;D	24D	3
D		DD+3E 
F)F
F
Fc           	        t          j                    }|| _        	 t          j        |           |                    |                                            nr# t          $ re}| j                                        s!|| _	        | j        
                                 n!t                              d| j        |           Y d}~nd}~ww xY w	 d t          j        |          D             }|D ]}|                                 |r$|                    t          j        |ddi           n# t"          $ r Y nw xY w	 |                                 n# t"          $ r Y nw xY w| j        5  d| _        ddd           dS # 1 swxY w Y   dS # 	 d t          j        |          D             }|D ]}|                                 |r$|                    t          j        |ddi           n# t"          $ r Y nw xY w	 |                                 n# t"          $ r Y nw xY w| j        5  d| _        ddd           w # 1 swxY w Y   w xY w)z2Entry point for the supervisor's dedicated thread.zCDP supervisor %s crashed: %sNc                :    g | ]}|                                 |S r.   )donerT   ts     r%   rU   z.CDPSupervisor._thread_main.<locals>.<listcomp>  s%    NNNQVVXXN1NNNr'   return_exceptionsTF)r   new_event_looprj   set_event_looprun_until_complete_runBaseExceptionrm   is_setrn   setloggerwarningrO   	all_taskscancelgatherr   r   rd   ri   )r$   r   r   r   r   s        r%   r   zCDPSupervisor._thread_main  s-   %''
	%"4(((##DIIKK0000 	Q 	Q 	Q$++-- Q$%!!%%''''>aPPP	QNNg&7&=&=NNN   AHHJJJJ ^++GNG,\W[,\,\]]]   

   ! % %$% % % % % % % % % % % % % % % % % %NNg&7&=&=NNN   AHHJJJJ ^++GNG,\W[,\,\]]]   

   ! % %$% % % % % % % % % % % % % % % %s   ;A F 
C"AC=F CF AD) )
D65D6:E 
EE&E;;E?E?I
AG('I(
G52I4G55I9HI
HIH
I%H9-I9H==I H=Ic                	  K   d}d}d}| j         s	 t          j        t          j        | j        d          d           d{V | _        n# t          $ r}|d	z  }| j        	                                s&|| _
        | j                                         Y d}~dS t                              d
| j        ||           t          j        t!          |d                     d{V  t!          |dz  d          }Y d}~d}~ww xY wt          j        |                                 d          }	 d| _        | j                                         |                                  d{V  | j        5  d| _        ddd           n# 1 swxY w Y   t3          j                    }d}| j        	                                s| j                                         | d{V  n# t4          $ rz}| j        	                                s!|| _
        | j                                          t                              d| j        t3          j                    |z
  |           Y d}~nd}~ww xY w| j        5  d| _        ddd           n# 1 swxY w Y   |                                s:|                                 	 | d{V  n# t          j        t          f$ r Y nw xY wt=          | j                                                   D ]}|                                 | j                                         | j        }d| _        |.	 |!                                 d{V  n# t          $ r Y nw xY wn# | j        5  d| _        ddd           n# 1 swxY w Y   |                                s:|                                 	 | d{V  n# t          j        t          f$ r Y nw xY wt=          | j                                                   D ]}|                                 | j                                         | j        }d| _        |,	 |!                                 d{V  w # t          $ r Y w w xY ww xY w| j         rdS t          "                    d| j        |           t          j        |           d{V  t!          |dz  d          }| j         dS dS )u  Top-level supervisor coroutine.

        Holds a reconnecting loop so we survive the remote closing the
        WebSocket — Browserbase in particular tears down the CDP socket
        every time a short-lived client (e.g. agent-browser's per-command
        CDP client) disconnects.  We drop our state snapshot keys that
        depend on specific CDP session ids, re-attach, and keep going.
        r   g        g      ?i   )max_sizer   r}   Nr^   z2CDP supervisor %s: connect failed (attempt %s): %sr   z
cdp-reader)r=   Tz2CDP supervisor %s: session dropped after %.1fs: %sFz+CDP supervisor %s: reconnecting in %.1fs...)#ro   r   wait_for
websocketsconnectrN   rr   r   rm   r   rn   r   r   r   rO   sleepmincreate_task
_read_looprs   rt   r   _attach_initial_pagerd   ri   timer   r   r   CancelledErrorr   ru   r   r   debug)r$   attemptlast_success_atbackoffr   reader_taskhandler   s           r%   r   zCDPSupervisor._run  s      & R	-!(!1&t|>NOOO " " "          1(//11 ()D%%))+++FFFFFHL'1   mC$6$6777777777gk400 "-doo.?.?lSSSK2 )-%$**,,, //111111111% ( (#'DL( ( ( ( ( ( ( ( ( ( ( ( ( ( ("&)++(//11 ,%))+++!!!!!!!!!    (//11 ()D%%))+++HLIKK/1	        % ) )#(DL) ) ) ) ) ) ) ) ) ) ) ) ) ) )"'')) &&((()))))))))#2I>   "4#9#@#@#B#BCC $ $FMMOOOO&,,...X> hhjj(((((((($    " % ) )#(DL) ) ) ) ) ) ) ) ) ) ) ) ) ) )"'')) &&((()))))))))#2I>   "4#9#@#@#B#BCC $ $FMMOOOO&,,...X> hhjj(((((((($    " #  LL=t|W   -((((((((('A+t,,Ge & R	- R	- R	- R	- R	-s  :A 
D>C=AC==D.AG /F7G FG 
FAG M/ 
I"(A0IM/ I""M/ ,J  JJ4J= =KK M 
M*)M*/Q77N?Q7NQ7N+Q7?OQ7O!Q7 O!!A)Q7Q&%Q7&
Q30Q72Q33Q7c                  K   |                      d           d{V }|                    di                               dg           }t          d |D             d          }|-|                      dddi           d{V }|d         d	         }n|d	         }|                      d
|dd           d{V }|d         d         | _        |                      d| j                   d{V  |                      d| j                   d{V  |                      ddddd| j                   d{V  |                     | j                   d{V  dS )zTFind a page target, attach flattened session, enable domains, install dialog bridge.zTarget.getTargetsNr   targetInfosc              3  L   K   | ]}|                     d           dk    |V   dS )r   pageNr   r   s     r%   	<genexpr>z5CDPSupervisor._attach_initial_page.<locals>.<genexpr>Q  s6      JJ!!%%--62I2IA2I2I2I2IJJr'   zTarget.createTargetr7   zabout:blanktargetIdzTarget.attachToTargetT)r   flatten	sessionIdPage.enable)r?   Runtime.enableTarget.setAutoAttachF
autoAttachwaitForDebuggerOnStartr   )_cdpr   nextrs   _install_dialog_bridge)r$   resptargetspage_targetcreated	target_idattachs          r%   r   z"CDPSupervisor._attach_initial_pageM  s     YY233333333((8R((,,]B??JJwJJJDQQ II&;e]=STTTTTTTTG)*5II#J/Iyy#"t44
 
 
 
 
 
 
 
 !'x 0 =ii$2GiHHHHHHHHHii(T5JiKKKKKKKKKii"5TRR,  
 
 	
 	
 	
 	
 	
 	
 	
 ))$*?@@@@@@@@@@@r'   r?   c                  K   	 |                      dt          dd|d           d{V  n=# t          $ r0}t                              d|pddd	         |           Y d}~nd}~ww xY w	 |                      d
t
          ddgdd|d           d{V  n=# t          $ r0}t                              d|pddd	         |           Y d}~nd}~ww xY w	 |                      dt          dd|d           d{V  dS # t          $ r Y dS w xY w)u  Install the dialog-bridge init script + Fetch interceptor on a session.

        Two CDP calls:
          1. ``Page.addScriptToEvaluateOnNewDocument`` — the JS override runs
             in every frame before any page script. Replaces alert/confirm/
             prompt with a sync XHR to our bridge URL.
          2. ``Fetch.enable`` scoped to the bridge URL — we catch those XHRs,
             surface them as pending dialogs, then fulfill once the agent
             responds.

        Idempotent at the CDP level: Chromium de-duplicates identical
        add-script calls by source, and Fetch.enable replaces prior patterns.
        z%Page.addScriptToEvaluateOnNewDocumentT)sourcerunImmediatelyr   r?   ry   NzDdialog bridge: addScriptToEvaluateOnNewDocument failed on sid=%s: %sr<      zFetch.enableRequest)
urlPatternrequestStageF)patternshandleAuthRequestsz0dialog bridge: Fetch.enable failed on sid=%s: %szRuntime.evaluate)
expressionreturnByValue      @)r   _DIALOG_BRIDGE_SCRIPTr   r   r   DIALOG_BRIDGE_URL_PATTERN)r$   r?   r   s      r%   r   z$CDPSupervisor._install_dialog_bridgej  s     	))70DII%	             	 	 	LLV!r3B3'       	
	)) +D,5 ! +0  &             	 	 	LLB!r3B3'       		))"4tLL%	              	 	 	DD	s>   ', 
A&&A!!A&*+B 
C &CC'C= =
D
Dr   methodparamsOptional[Dict[str, Any]]c                 K   | j         t          d          | j        }| xj        dz  c_        ||d}|r||d<   |r||d<   t          j                                                    }|| j        |<   | j                             t          j	        |                     d{V  	 t          j
        ||           d{V 	 | j                            |d           S # | j                            |d           w xY w)z*Send a CDP command and await its response.Nz%supervisor WebSocket is not connectedr^   )r   r  r  r   r}   )rr   r   rp   r   get_running_loopcreate_futurerq   sendjsondumpsr   pop)r$   r  r  r?   ry   call_idpayloadr   s           r%   r   zCDPSupervisor._cdp  s+      8FGGG$a)0F"C"C 	' &GH 	.#-GK %688FFHH'*G$hmmDJw//000000000	3 )#w??????????##GT2222D##GT2222s   %C C:c           
       K   | j         J 	 | j         2 3 d{V }| j        r dS 	 t          j        |          }n*# t          $ r t
                              d           Y Mw xY wd|v r| j                            |d         d          }|b|	                                sNd|v r5|
                    t          d|d          d|d                               |                    |           d|v rJ|                     |d         |                    di           |                    d	                     d{V  +6 dS # t          $ r&}t
                              d
|           Y d}~dS d}~ww xY w)z*Continuously dispatch incoming CDP frames.Nz&CDP supervisor: non-JSON frame droppedr   r   zCDP error on id=r   r  r  r   zCDP read loop exited: %s)rr   ro   r  loadsr   r   r   rq   r  r   set_exceptionr   
set_result	_on_eventr   )r$   rawmsgr   r   s        r%   r   zCDPSupervisor._read_loop  s     x###	8!X e e e e e e ec' EE*S//CC    LL!IJJJH 3;;-11#d)TBBCsxxzz"c>>-- ,-[D	-[-[SQX\-[-[ \ \     NN3///__..X"8M8MswwWbOcOcddddddddd% &XX&  	8 	8 	8LL3Q777777777	8sB   E D?	E ;E $A"E !A""CE 
E2E--E2c                  K   |dk    r|                      ||           d {V  d S |dk    r|                     ||           d {V  d S |dk    r|                     ||           d {V  d S |dk    r|                     ||           d S |dk    r|                     ||           d S |dk    r|                     ||           d S |dk    r|                     |           d {V  d S |dk    r|                     |           d S |d	k    r|                     |d
           d S |dk    r|                     |d           d S d S )NzPage.javascriptDialogOpeningzPage.javascriptDialogClosedzFetch.requestPausedzPage.frameAttachedzPage.frameNavigatedzPage.frameDetachedzTarget.attachedToTargetzTarget.detachedFromTargetzRuntime.consoleAPICalledapi)
level_fromzRuntime.exceptionThrown	exception)	_on_dialog_opening_on_dialog_closed_on_fetch_paused_on_frame_attached_on_frame_navigated_on_frame_detached_on_target_attached_on_target_detached_on_console)r$   r  r  r?   s       r%   r  zCDPSupervisor._on_event  s      333))&*===========444((<<<<<<<<<<<,,,''
;;;;;;;;;;;+++##FJ77777,,,$$VZ88888+++##FJ77777000**622222222222222$$V,,,,,111V66666000V<<<<< 10r'   c                <   K    xj         dz  c_         t          d j          t          |                    d          pd          t          |                    d          pd          t          |                    d          pd          t	          j                    |p j        pd|                    d                     j        t          k    ra j        5   	                    d	           d d d            n# 1 swxY w Y   t          j                             d
d                     d S  j        t          k    rf j        5   	                    d	           d d d            n# 1 swxY w Y   t          j                             dj                             d S  j        5   j        j        <   d d d            n# 1 swxY w Y   t          j                    }|                     j         fd          }| j        j        <   d S )Nr^   d-r   r<   r   defaultPromptframeId)r   r   r   r   r   r   r   auto_policyFr   Tc                 \    t          j                             j                            S r   r   r   _dialog_timeout_expiredr   r   r$   s   r%   <lambda>z2CDPSupervisor._on_dialog_opening.<locals>.<lambda>  "    +D,H,H,S,STT r'   )rv   r   r   r   r   rs   rZ   DIALOG_POLICY_AUTO_DISMISSrd   _archive_dialog_lockedr   r   _auto_handle_dialogDIALOG_POLICY_AUTO_ACCEPTr   re   r   r
  
call_laterr[   ru   )r$   r  r?   r   r   r   s   `    @r%   r  z CDPSupervisor._on_dialog_opening  s      	A&D$&&VZZ''-2..

9--344vzz/::@bAAikk%D)>D"ZZ	**
 
 
 !;;; ! C C++FMBBBC C C C C C C C C C C C C C C((2(NN     #<<<! C C++FMBBBC C C C C C C C C C C C C C C((4V5J )       ! : :39%fi0: : : : : : : : : : : : : : :+--D__%TTTTT F 17D"69---s6   D  DDE11E58E54GGGr   r   r   r:   c                  K   d|i}|j         dk    r||d<   	 |                     d||j        pdd           d{V  dS # t          $ r,}t                              d|j        |           Y d}~dS d}~ww xY w)	zSend handleJavaScriptDialog for auto_dismiss/auto_accept.

        Dialog has already been archived by the caller (``_on_dialog_opening``);
        this just fires the CDP call so the page unblocks.
        r   prompt
promptTextPage.handleJavaScriptDialogNr   r   z&auto-handle CDP call failed for %s: %s)r   r   r   r   r   r   r   )r$   r   r   r   r  r   s         r%   r3  z!CDPSupervisor._auto_handle_dialog  s       #+F!3;(""#.F< 	Q))-!08D	              	Q 	Q 	QLLA69aPPPPPPPPP	Qs   &A   
A6
!A11A6c                  K   | j         5  | j                            |          }d d d            n# 1 swxY w Y   |d S t                              d| j        ||j        | j                   	 | j         5  || j        v r1| j                            |d            | 	                    |d           d d d            n# 1 swxY w Y   |j
        r |                     |dd           d {V  d S |                     dddi|j        pd d	           d {V  d S # t          $ r'}t                              d
||           Y d }~d S d }~ww xY w)NzBCDP supervisor %s: dialog %s (%s) auto-dismissed after %ss timeoutwatchdogFr<   r   r9  r   r   r   zauto-dismiss failed for %s: %s)rd   re   r   r   r   rO   r   r[   r  r2  r   _fulfill_bridge_requestr   r   r   r   )r$   r   r   r   s       r%   r-  z%CDPSupervisor._dialog_timeout_expired1  sM      	: 	:*..y99F	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	:>FPLK!	
 	
 	
	I! D D 555)--i>>>//
CCCD D D D D D D D D D D D D D D ' 226%UW2XXXXXXXXXXXii1u%%4<	               	I 	I 	ILL99aHHHHHHHHH	IsN   155.D 5;B<0D <C  D C (D .(D 
E	"EE	r2   c           	     2   t          |j        |j        |j        |j        t          j                    ||j                  }| j                            |           t          | j                  t          dz  k    r| j        t           d         | _        dS dS )zNMove a pending dialog to the recent_dialogs ring buffer. Must hold state_lock.r4   r   N)r0   r   r   r   r   r   r   rf   appendr   r   )r$   r   r2   records       r%   r2  z$CDPSupervisor._archive_dialog_lockedQ  s    yN&ikk_
 
 
 	##F+++t#$$'9A'===#'#79K8K8L8L#MD    >=r'   c                 K   |j         rZ	 |                     |||           d{V  | j        5  |j        | j        v r6| j                            |j        d           |                     |d           ddd           n# 1 swxY w Y   | j                            |j        d          }||                                 n# | j        5  |j        | j        v r6| j                            |j        d           |                     |d           ddd           n# 1 swxY w Y   | j                            |j        d          }||                                 w w xY wdS d|i}|j	        dk    r||d<   	 | 
                    d||j        pdd	           d{V  | j        5  |j        | j        v r6| j                            |j        d           |                     |d           ddd           n# 1 swxY w Y   | j                            |j        d          }||                                 dS dS # | j        5  |j        | j        v r6| j                            |j        d           |                     |d           ddd           n# 1 swxY w Y   | j                            |j        d          }||                                 w w xY w)
zSend the Page.handleJavaScriptDialog CDP command (agent path only).

        Routes to the bridge-fulfill path when the dialog was captured via
        the injected XHR override (see ``_on_fetch_paused``).
        r   Nagentr   r7  r8  r9  r   r   )r   r<  rd   r   re   r  r2  ru   r   r   r   r   )r$   r   r   r   r   r  s         r%   r   z CDPSupervisor._handle_dialog_cdp`  sy      # 	$226{ 3          % E EyD$999-11&)TBBB33FGDDDE E E E E E E E E E E E E E E /33FItDD%MMOOO % E EyD$999-11&)TBBB33FGDDDE E E E E E E E E E E E E E E /33FItDD%MMOOOO &F"*F!3;(""#.F< 	 ))-!08D	           ! A A9 555)--fi>>>//@@@A A A A A A A A A A A A A A A +//	4@@F! "! ! A A9 555)--fi>>>//@@@A A A A A A A A A A A A A A A +//	4@@F! "s   C ABB	BE ADE D!!E $D!%;E :&H= 'AG88G<?G<=KAJ
KJKJ;Kc                r  K   | j         5  fd| j                                        D             }|rl|d         }| j                            |d           }||                     |d           | j                            |d           }||                                 d d d            d S # 1 swxY w Y   d S )Nc                B    g | ]}|j         k    r|j        |j        S r   )r   r   r   )rT   r@   r?   s     r%   rU   z3CDPSupervisor._on_dialog_closed.<locals>.<listcomp>  s@       #z11 '/  0//r'   r   remote)rd   re   r   r  r2  ru   r   )r$   r  r?   candidate_idsdidr   r   s     `    r%   r  zCDPSupervisor._on_dialog_closed  s        	$ 	$   .5577  M  $#A&.223==%//AAA/33C>>%MMOOO#	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$s   BB,,B03B0c                6   K   t          |                    di                               d          pd          }|                    d          }|sdS t          |vr5	                      dd|i|d           d{V  n# t          $ r Y nw xY wdS d	d
lm}m}  | ||          j                  dfd} |d          pd} |d          }	 |d          }
 xj	        dz  c_	        t          d j	         ||	|
t          j                    |p j        pd|                    d          t          |                     j        t          k    ra j        5                       d           ddd           n# 1 swxY w Y   t#          j                             dd                     dS  j        t(          k    ra j        5                       d           ddd           n# 1 swxY w Y   t#          j                             d|
                     dS  j        5   j        j        <   ddd           n# 1 swxY w Y   t#          j                    }|                     j         fd          }| j        j        <   dS )u	  Bridge XHR captured mid-flight — materialize as a pending dialog.

        The injected script (``_DIALOG_BRIDGE_SCRIPT``) fires a synchronous
        XHR to ``DIALOG_BRIDGE_HOST`` whenever page code calls alert/confirm/
        prompt. We catch it via Fetch.enable pattern; the page's JS thread
        is blocked on the XHR's response until we call Fetch.fulfillRequest
        (which happens from ``respond_to_dialog``) or until the watchdog
        fires (at which point we fulfill with a cancel response).
        requestr7   r<   	requestIdNzFetch.continueRequestr  r   r   )urlparseparse_qsr=   r   r   c                J                         | dg          }|r|d         ndS )Nr<   r   r   )r=   vqs     r%   _qz*CDPSupervisor._on_fetch_paused.<locals>._q  s+    dRD!!A$1Q44"$r'   kindalertr   r   r^   r'  r)  )r   r   r   r   r   r   r   r   r*  Fr   Tc                 \    t          j                             j                            S r   r,  r.  s   r%   r/  z0CDPSupervisor._on_fetch_paused.<locals>.<lambda>  r0  r'   )r=   r   r   r   )r   r   DIALOG_BRIDGE_HOSTr   r   urllib.parserJ  rK  queryrv   r   r   rs   rZ   r1  rd   r2  r   r   r<  r4  re   r   r
  r5  r[   ru   )r$   r  r?   r7   
request_idrJ  rK  rO  rP  r   r   r   r   r   rN  s   `            @@r%   r  zCDPSupervisor._on_fetch_paused  s-      &**Y++//66<"==ZZ,,
 	F S((ii+k:-F)3                F 	43333333HXXc]]())	% 	% 	% 	% 	% 	% r&zz$W"Y--,--A&D$&&)ikk%D)>D"ZZ	**!*oo	
 	
 	
 !;;;! C C++FMBBBC C C C C C C C C C C C C C C,,VEr,RR     #<<<! C C++FMBBBC C C C C C C C C C C C C C C,,4^ -       ! : :39%fi0: : : : : : : : : : : : : : :+--D__%TTTTT F 17D"69---sH   !!B 
BBFF	FG33G7:G71IIIc          	       K   |j         sdS t          |          |j        dk    r|nd|j        d}t	          j        |                                          }	 ddl}|                     d|j         ddd	d
ddd
g|	                    |          
                                d|j        pdd           d{V  dS # t          $ r,}t                              d|j        |           Y d}~dS d}~ww xY w)zCResolve a bridge XHR via Fetch.fulfillRequest so the page unblocks.Nr7  r<   )r   r   r   r   zFetch.fulfillRequest   zContent-Typezapplication/json)r=   valuezAccess-Control-Allow-Origin*)rI  responseCoderesponseHeadersbodyr   r   z bridge fulfill failed for %s: %s)r   r:   r   r   r  r  encodebase64r   	b64encodedecoder   r   r   r   )r$   r   r   r   r  r]  _b64r   s           r%   r<  z%CDPSupervisor._fulfill_bridge_request  sf      ' 	F6ll*0+*A*A;;r
 

 z'""))++	K!!!!))&!'!9$'!/:LMM!>MM( !NN4007799  "08D              	K 	K 	KLL;VYJJJJJJJJJ	Ks   A!B; ;
C1!C,,C1c           	         |                     d          }|sd S | j        5  t          |dd|                     d          d|          | j        |<   d d d            d S # 1 swxY w Y   d S )Nr)  r<   parentFrameIdF)r   r7   r8   r9   r;   r   )r   rd   r6   rg   )r$   r  r?   r   s       r%   r   z CDPSupervisor._on_frame_attached  s     ::i(( 	F 	 	%.! &

? ; ;)& & &DL"	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   1AA#&A#c                   |                     d          pi }|                     d          }|sd S | j        5  | j                             |          }t          |t	          |                     d          pd          t	          |                     d          p|                     d          pd          |                     d          p
|r|j        nd t          |r|j        nd          |r|j        n|t	          |                     d	          p
|r|j	        nd          
          }|| j        |<   d d d            d S # 1 swxY w Y   d S )Nframer   r7   r<   securityOriginr8   parentIdFr=   r   r7   r8   r9   r;   r   r=   )
r   rd   rg   r6   r   r9   r:   r;   r   r=   )r$   r  r?   rf  r   existinginfos          r%   r!  z!CDPSupervisor._on_frame_navigated)  s    

7##)r99T?? 	F 	* 	*|''11H!		%((.B//599%566S%))H:M:MSQSTT %		* 5 5 iV^:h(:R:Rdh8Fh//GG:BRx66
6**Q/Px}}bRR  D &*DL"	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	*s   C<EEEc                   |                     d          }|sdS t          |                     d          pd                                          }|dk    rdS | j        5  | j                             |          }|r|j        r|j        r	 ddd           dS | j                            |d           ddd           dS # 1 swxY w Y   dS )u  Remove a frame from our state only when it's truly gone.

        CDP emits ``Page.frameDetached`` with a ``reason`` of either
        ``"remove"`` (the frame is actually gone from the DOM) or ``"swap"``
        (the frame is migrating to a new process — typical when a
        same-process iframe becomes an OOPIF, or when history navigates).
        Dropping on ``swap`` would hide OOPIFs from the agent the moment
        Chromium promotes them to their own process, so treat swap as a
        no-op.

        Even with ``reason=remove``, the parent page's perspective is
        "the child frame left MY process tree" — which is what happens
        when a same-origin iframe gets promoted to an OOPIF. If we
        already have a live child CDP session attached for that frame_id,
        the frame is still very much alive; only drop it when we have
        no session record.
        r)  Nreasonremoveswap)r   r   lowerrd   rg   r;   r   r  )r$   r  r?   r   rm  rj  s         r%   r"  z CDPSupervisor._on_frame_detached=  sA   ( ::i(( 	FVZZ))5X66<<>>VF 		- 		-|''11H  H- (2I 		- 		- 		- 		- 		- 		- 		- 		- LXt,,,		- 		- 		- 		- 		- 		- 		- 		- 		- 		- 		- 		- 		- 		- 		- 		- 		- 		-s   ,C C  CCc                  K   |                     d          pi }|                     d          }|                     d          }|r|dvrd S ||d| j        |<   |dk    r|                     d          }| j        5  | j                             |          }t	          |t          |                     d          pd	          d	|r|j        nd d
|t          |                     d          p
|r|j        nd	                    | j        |<   d d d            n# 1 swxY w Y   t          j	        | 
                    |                     d S )N
targetInfor   r   )iframeworker)rk  r   rs  r   r7   r<   Ttitleri  )r   rt   rd   rg   r6   r   r9   r=   r   r   _enable_child_domains)r$   r  rk  sidtarget_typer   rj  s          r%   r#  z!CDPSupervisor._on_target_attachedb  s     zz,''-2jj%%hhv&& 	k)===F-1;$G$GS! ("",,I! 
 
<++I66*3&DHHUOO1r22AI%SX%=%=t!#&TXXg..UH3T8==RTVV+ + +Y'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 	D66s;;<<<<<s   ;BDDDrw  c                x  K   	 |                      d|d           d{V  |                      d|d           d{V  |                      ddddd	|d           d{V  n;# t          $ r.}t                              d
|dd         |           Y d}~nd}~ww xY w|                     |           d{V  dS )zEnable Page+Runtime (+nested setAutoAttach) on a child CDP session.

        Also installs the dialog bridge so iframe-scoped alert/confirm/prompt
        calls round-trip through Fetch too.
        r   r  r   Nr   r   TFr   z!child session %s setup failed: %sr   )r   r   r   r   r   )r$   rw  r   s      r%   rv  z#CDPSupervisor._enable_child_domains~  s7     
	K))Mc3)GGGGGGGGG)),c)JJJJJJJJJ))&#uQUVV	             	K 	K 	KLL<c#2#hJJJJJJJJ	K ))#...........s   AA$ $
B.$BBc                   |                     d          }|sdS | j                            |d           | j        5  t	          | j                                                  D ]L\  }}|j        |k    r<t          |j	        |j
        |j        |j        |j        d|j                  | j        |<   M	 ddd           dS # 1 swxY w Y   dS )u7  Handle a child CDP session detaching.

        We deliberately DO NOT drop frames from ``_frames`` here — Browserbase
        fires transient detach events during page transitions even while the
        iframe is still visible to the user, and dropping the record hides
        OOPIFs from the agent between the detach and the next
        ``Target.attachedToTarget``. Instead, we just clear the session
        binding so stale ``cdp_session_id`` values aren't used for routing.
        If the iframe truly goes away, ``Page.frameDetached`` will clean up.
        r   Nri  )r   rt   r  rd   r   rg   itemsr   r6   r   r7   r8   r9   r;   r=   )r$   r  rw  fidrf  s        r%   r$  z!CDPSupervisor._on_target_detached  s$    jj%% 	F  d+++ 	 	"4<#5#5#7#788  
U'3.. )2!&!I$|(-(=!&'+"Z) ) )DL%		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   A4B>>CCr  c                  |dk    ru|                     d          pi }t          |                     d          pd          }|                     d          }t          t          j                    d||          }nt          |                     d          pd          }|d	v rd
n	|dk    rdnd}|                     d          pg }	g }
|	d d         D ]c}t	          |t
                    rL|
                    t          |                     d          p|                     d          pd                     dt          t          j                    |d                    |
                    }| j        5  | j	                            |           t          | j	                  t          dz  k    r| j	        t           d          | _	        d d d            d S # 1 swxY w Y   d S )Nr  exceptionDetailsrE   r<   r7   )rC   rD   rE   r7   r   log)r   assertr   r   args   rY  description )rC   rD   rE   r   )r   r   rB   r   
isinstancedictr>  r   rd   rh   r   r   )r$   r  r  detailsrE   r7   event	raw_levelrD   r  partsas               r%   r%  zCDPSupervisor._on_console  s,   $$jj!344:Gw{{6**0b11D++e$$C DIKK{SVWWWEEFJJv..7%88I(,???GG&)33		  ::f%%+D!E"1"X T Ta&& TLLQUU7^^%Qquu]7K7K%Qr!R!RSSS DIKKu388E??SSSE 	S 	S ''...4'((+>+BBB'+';=P<P<Q<Q'R$		S 	S 	S 	S 	S 	S 	S 	S 	S 	S 	S 	S 	S 	S 	S 	S 	S 	Ss   4AGGGc                2  
 | j         }|sdg ddS d |                                D             }t          d |D             |r|d         nd          
g }d}
dg ddS 
fd|                                D             }
j        h}|rt	          |          t
          k     r|                    d          \  }}|j        |v r<|                    |j                   |j        r|t          k    rd}k|
                    |                                           |                                D ]5}	|	j        |j        k    r#|	j        |vr|
                    |	|d	z   f           6|rt	          |          t
          k     |rd}
                                ||dS )
zEBuild the capped frame_tree payload. Must be called under state lock.NF)topchildren	truncatedc                     g | ]}|j         	|S r.   )r9   rT   fs     r%   rU   z:CDPSupervisor._build_frame_tree_locked.<locals>.<listcomp>  s     DDDa!2CDDDDr'   c              3  (   K   | ]}|j         	|V  d S r   )r;   r  s     r%   r   z9CDPSupervisor._build_frame_tree_locked.<locals>.<genexpr>  s)      66!1:6A666666r'   r   c                8    g | ]}|j         j        k    |d fS )r^   )r9   r   )rT   r  r  s     r%   rU   z:CDPSupervisor._build_frame_tree_locked.<locals>.<listcomp>  s3     .
 .
 .
q/@CL/P/PQF/P/P/Pr'   Tr^   )rg   r   r   r   r   FRAME_TREE_MAX_ENTRIESr  addr;   FRAME_TREE_MAX_OOPIF_DEPTHr>  r&   r9   )r$   framestopsr  r  queuevisitedrf  depthr  r  s             @r%   r   z&CDPSupervisor._build_frame_tree_locked  s    	EReDDD ED6==??DDD66t66648QQTRR *,	;ReDDD.
 .
 .
 .
"MMOO.
 .
 .
 !\N 	1H(>>> 99Q<<LE5~((KK'''~ %*D"D"D 	OOEMMOO,,,]]__ 1 1$661:W;T;TLL!UQY000  	1H(>>>  	I ;;== "
 
 	
r'   )
rO   r   rN   r   rZ   r   r[   r   r   r\   )rx   )ry   r   r   r\   )r   )r   rH   )
r   r   r   r   r   r   ry   r   r   r    r   r\   )r?   r   r   r\   r   )
r  r   r  r  r?   r   ry   r   r   r    )r  r   r  r    r?   r   r   r\   )r  r    r?   r   r   r\   )r   r   r   r:   r   r   r   r\   )r   r   r   r\   )r   r   r2   r   r   r\   )r  r    r   r\   )rw  r   r   r\   )r  r    r  r   r   r\   r(   )"r)   r*   r+   r,   DEFAULT_DIALOG_POLICYDEFAULT_DIALOG_TIMEOUT_Srw   r   r   r   r   r   r   r   r   r   r   r  r  r3  r-  r2  r   r  r  r<  r   r!  r"  r#  rv  r$  r%  r   r.   r'   r%   rY   rY     s        * 3":+ + + + + +^    <! ! ! ! !<
 
 
 
, &*#'9? 9? 9? 9? 9? 9?z% % % %>^- ^- ^- ^-@A A A A:8 8 8 8z ,03
 %)3 3 3 3 3 348 8 8 88= = = =0(7 (7 (7 (7TQ Q Q Q*I I I I@N N N N*  *  *  * X$ $ $ $:M7 M7 M7 M7^K K K KB    * * * *(#- #- #- #-J= = = =8/ / / /(   @S S S S2(
 (
 (
 (
 (
 (
r'   rY   c                  D    e Zd ZdZddZddZeed	d
ddZddZ	ddZ
dS )_SupervisorRegistryu   Process-global (task_id → supervisor) map with idempotent start/stop.

    One instance, exposed as ``SUPERVISOR_REGISTRY``. Safe to call from any
    thread — mutations go through ``_lock``.
    r   r\   c                D    t          j                    | _        i | _        d S r   )rb   rc   _lock_by_taskr#   s    r%   rw   z_SupervisorRegistry.__init__   s    ^%%
24r'   rO   r   Optional[CDPSupervisor]c                x    | j         5  | j                            |          cddd           S # 1 swxY w Y   dS )z@Return the supervisor for ``task_id`` if running, else ``None``.N)r  r  r   )r$   rO   s     r%   r   z_SupervisorRegistry.get  s    Z 	. 	.=$$W--	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	.s   /33rx   )rZ   r[   start_timeoutrN   rZ   r[   r   r  rY   c                  | j         5  | j                            |          }|||j        |k    rV|j        duo|j                                        }|j        duo|j                                        }|r|r|cddd           S | j                            |d           ddd           n# 1 swxY w Y   ||	                                 t          ||||          }	|	                    |           | j         5  | j                            |          }
|
-|
j        |k    r"|		                                 |
cddd           S |	| j        |<   ddd           n# 1 swxY w Y   |	S )zIdempotently ensure a supervisor is running for ``(task_id, cdp_url)``.

        If a supervisor exists for this task but was bound to a different
        ``cdp_url``, the old one is stopped and a fresh one is started.
        N)rO   rN   rZ   r[   r}   )r  r  r   rN   rk   r   rj   r   r  r   rY   r   )r$   rO   rN   rZ   r[   r  rj  	thread_okloop_ok
supervisoralreadys              r%   get_or_startz _SupervisorRegistry.get_or_start	  sA    Z 
	1 
	1}((11H##w.. ( 0 < \AQAZAZA\A\I&nD8XX^=V=V=X=XG  (W ('
	1 
	1 
	1 
	1 
	1 
	1 
	1 
	1 !!'4000
	1 
	1 
	1 
	1 
	1 
	1 
	1 
	1 
	1 
	1 
	1 
	1 
	1 
	1 
	1 MMOOO"'-	
 
 

 	///Z 	0 	0m''00G"w''A'A!!!	0 	0 	0 	0 	0 	0 	0 	0 &0DM'"	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 s0   A1B-B--B14B1>=E
EE"%E"c                    | j         5  | j                            |d          }ddd           n# 1 swxY w Y   ||                                 dS dS )z=Stop and discard the supervisor for ``task_id`` if it exists.N)r  r  r  r   )r$   rO   r  s      r%   r   z_SupervisorRegistry.stop5  s    Z 	: 	:**7D99J	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	: 	:!OO "!s   044c                    | j         5  t          | j                                                  }| j                                         ddd           n# 1 swxY w Y   |D ]\  }}|                                 dS )z<Stop every running supervisor. For shutdown / test teardown.N)r  r   r  r{  r   r   )r$   r{  _r  s       r%   stop_allz_SupervisorRegistry.stop_all<  s    Z 	" 	",,..//EM!!!	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" 	" # 	 	MAzOO	 	s   A AAANr  )rO   r   r   r  )rO   r   rN   r   rZ   r   r[   r   r  r   r   rY   )rO   r   r   r\   )r)   r*   r+   r,   rw   r   r  r  r  r   r  r.   r'   r%   r  r    s         5 5 5 5. . . . 3":#* * * * * *X        r'   r  )rY   rB   r  r  r4  r1  DIALOG_POLICY_MUST_RESPONDr0   r6   r   SUPERVISOR_REGISTRYrH   r  )-r,   
__future__r   r   r  loggingrb   r   dataclassesr   typingr   r   r   r   r	   r   websockets.asyncio.clientr
   	getLoggerr)   r   r  r1  r4  	frozensetr_   r  r  r  r  r   r   rS  r  r  r   r0   r6   rB   rH   rY   r  r  __all__r.   r'   r%   <module>r     s   ( # " " " " "         ! ! ! ! ! ! 3 3 3 3 3 3 3 3 3 3 3 3 3 3     6 6 6 6 6 6		8	$	$
 , + ) )!;=VW  3        
  
 4 <&8<<< 3 r 
 
 
 
 
 
 
 
4 
 
 
 
 
 
 
 
8        @         $       :p
 p
 p
 p
 p
 p
 p
 p
lI I I I I I I IX *)++   r'   