
    ig                        U d dl Z d dl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m	Z	 d dl
m
Z
 d dlmZmZ d dlmZ d dlmZ d dlmZmZmZ d dlmZ d dlZd d	lmZ  e         ej6                  d
ej8                        Z ej<                  e      Z  e!ddi       Z"e!e#d<   da$e!dz  e#d<   da%e!dz  e#d<   de!dz  fdZ&de!dz  fdZ'da( ed      Z) ed      Z* ed      Z+ G d d      Z,d:de-deee+e)f   gee+e)f   f   fdZ.	 d:de-deee+e	eee)f   f   gee+e	eee)f   f   f   fdZ/d Z0e1fde2e-   de3fdZ4de-de3fd Z5d!e-de3fd"Z6d;d!e-d#e-d$e3de3fd%Z7d<d&e8d'e8d(e9e-d)f   fd*Z:ede-fd+       Z;de-dz  fd,Z<ede8e-e-f   dz  fd-       Z=d(e-ez  dz  de-fd.Z>d=d/e-d0e?dz  de-fd1Z@dddd2d3e	eee*f   d4e-dz  d5ej                  dz  d6e3de j                  e*   f
d7ZCd8e-de-fd9ZDy)>    N)Callable	Coroutine)fnmatch)cachewraps)Path)stderr)Any	ParamSpecTypeVar)urlparse)load_dotenvzMhttps?://[^\s<>"\']+|www\.[^\s<>"\']+|[^\s<>"\']+\.[a-z]{2,}(?:/[^\s<>"\']*)?_ImportNotFound _IMPORT_NOT_FOUND_openai_bad_request_error_groq_bad_request_errorreturnc                  r    t         		 ddlm}  | a t         t        urt         S dS # t        $ r	 t        a Y %w xY w)z'Lazy loader for OpenAI BadRequestError.Nr   BadRequestError)r   openair   ImportErrorr   r   s    [/mnt/e/genesis-system/.venvs/browser-army/lib/python3.12/site-packages/browser_use/utils.py_get_openai_bad_request_errorr   "   sF     %1%. &?FW%W!a]aa 
 101   $ 66c                  r    t         		 ddlm}  | a t         t        urt         S dS # t        $ r	 t        a Y %w xY w)z%Lazy loader for Groq BadRequestError.Nr   r   )r   groqr   r   r   r   s    r   _get_groq_bad_request_errorr   /   sF     #/#, $;BS#S]Y]] 
 /./r   FRTPc                       e Zd ZdZ	 	 	 	 	 	 ddej
                  dz  deg df   dz  deg df   dz  deg df   dz  dedee	   dz  f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y)SignalHandlera  
	A modular and reusable signal handling system for managing SIGINT (Ctrl+C), SIGTERM,
	and other signals in asyncio applications.

	This class provides:
	- Configurable signal handling for SIGINT and SIGTERM
	- Support for custom pause/resume callbacks
	- Management of event loop state across signals
	- Standardized handling of first and second Ctrl+C presses
	- Cross-platform compatibility (with simplified behavior on Windows)
	Nlooppause_callbackresume_callbackcustom_exit_callbackexit_on_second_intinterruptible_task_patternsc                    |xs t        j                         | _        || _        || _        || _        || _        |xs g d| _        t        j                         dk(  | _
        | j                          d| _        d| _        y)a4  
		Initialize the signal handler.

		Args:
			loop: The asyncio event loop to use. Defaults to current event loop.
			pause_callback: Function to call when system is paused (first Ctrl+C)
			resume_callback: Function to call when system is resumed
			custom_exit_callback: Function to call on exit (second Ctrl+C or SIGTERM)
			exit_on_second_int: Whether to exit on second SIGINT (Ctrl+C)
			interruptible_task_patterns: List of patterns to match task names that should be
										 canceled on first Ctrl+C (default: ['step', 'multi_act', 'get_next_action'])
		)step	multi_actget_next_actionWindowsN)asyncioget_event_loopr%   r&   r'   r(   r)   r*   platformsystem
is_windows_initialize_loop_stateoriginal_sigint_handleroriginal_sigterm_handler)selfr%   r&   r'   r(   r)   r*   s          r   __init__zSignalHandler.__init__R   sz    * .g,,.$)&$($2$.$%@%lDl$"OO%2$/  "&$"&$    c                 `    t        | j                  dd       t        | j                  dd       y)z:Initialize loop state attributes used for signal handling.ctrl_c_pressedFwaiting_for_inputN)setattrr%   r8   s    r   r5   z$SignalHandler._initialize_loop_statev   s$    	$))%u-	$))(%0r:   c                 d    	  j                   r/ fd}t        j                  t        j                  |       _        y j                  j                  t        j                   fd       _         j                  j                  t        j                   fd       _        y# t        $ r Y yw xY w)z0Register signal handlers for SIGINT and SIGTERM.c                     t        dt               j                  rj                          t        j                  d       y )Nu5   

🛑 Got Ctrl+C. Exiting immediately on Windows...
filer   )printr	   r(   os_exit)sigframer8   s     r   windows_handlerz/SignalHandler.register.<locals>.windows_handler   s.    
EFS!!
!XXa[r:   c                  $     j                         S N)sigint_handlerr?   s   r   <lambda>z(SignalHandler.register.<locals>.<lambda>   s    W[WjWjWl r:   c                  $     j                         S rK   )sigterm_handlerr?   s   r   rM   z(SignalHandler.register.<locals>.<lambda>   s    Y]YmYmYo r:   N)	r4   signalSIGINTr6   r%   add_signal_handlerSIGTERMr7   	Exception)r8   rI   s   ` r   registerzSignalHandler.register{   s    
oo $*==#PD  $(99#?#?Ol#mD $(II$@$@Qo$pD!	 
 s   :B# A$B# #	B/.B/c                    	 | j                   r;| j                  rt        j                  t        j                  | j                         y| j                  j                  t        j                         | j                  j                  t        j                         | j                  r.t        j                  t        j                  | j                         | j                  r/t        j                  t        j                  | j                         yyy# t        $ r"}t        j                  d|        Y d}~yd}~ww xY w)zEUnregister signal handlers and restore original handlers if possible.z+Error while unregistering signal handlers: N)r4   r6   rP   rQ   r%   remove_signal_handlerrS   r7   rT   loggerwarningr8   es     r   
unregisterzSignalHandler.unregister   s    E
oo##]]6==$">">? 	II##FMM2II##FNN3 ##]]6==$">">?$$]]6>>4#@#@A % $ 
 E	>>?sCDDEs   AD 	CD 	D=D88D=c                 d   t         sda | j                  r	 | j                          t        dt               t        dddt               t        ddd	       t        d
ddt               t        d
dd	       t        dddt               t        ddd	       t        dddt               t        ddd	       t        dddt               t        ddd	       t        dt               t        j                  d       y# t        $ r#}t        j	                  d|        Y d}~d}~ww xY w)z
		Handle a second Ctrl+C press by performing cleanup and exiting.
		This is shared logic used by both sigint_handler and wait_for_resume.
		TzError in exit callback: Nu2   

🛑  Got second Ctrl+C. Exiting immediately...
rB   z[?25h endflushrC   )r`   ra   [0mz[?1lz[?2004lzI(tip: press [Enter] once to fix escape codes appearing after chrome exit)r   )	_exitingr(   rT   rX   errorrD   r	   rE   rF   rZ   s     r   _handle_second_ctrl_cz#SignalHandler._handle_second_ctrl_c   s    
8 2	 
 ?fM 4f54( 	rF3	r& 
$V4
$' 2T72T* "Dv."D! SZ`a((1+C  2\\,QC0112s   D 	D/D**D/c                    t         rt        j                  d       t        | j                  dd      r4t        | j                  dd      ry| j
                  r| j                          t        | j                  dd       | j                          | j                  r	 | j                          t        dt        	       y# t        $ r"}t        j                  d|        Y d}~8d}~ww xY w)
z
		SIGINT (Ctrl+C) handler.

		First Ctrl+C: Cancel current step and pause.
		Second Ctrl+C: Exit immediately if exit_on_second_int is True.
		r   r<   Fr=   NTzError in pause callback: zF----------------------------------------------------------------------rB   )rd   rE   rF   getattrr%   r)   rf   r>   _cancel_interruptible_tasksr&   rT   rX   re   rD   r	   rZ   s     r   rL   zSignalHandler.sigint_handler   s     88A;TYY(%0dii,e4
   
$))%t, ""$ 
2
 PW]^	  2
LL,QC0112s   B= =	C(C##C(c                     t         s/da t        dt               | j                  r| j                          t	        j
                  d       y)z>
		SIGTERM handler.

		Always exits the program completely.
		Tu1   

🛑 SIGTERM received. Exiting immediately...

rB   r   N)rd   rD   r	   r(   rE   rF   r?   s    r   rO   zSignalHandler.sigterm_handler   s9     
8	@vN ((1+r:   c                    t        j                  | j                        }t        j                  | j                        D ]  }||k7  s	|j	                         rt        |d      r|j                         n
t        |      t        fd| j                  D              s`t        j                  d        |j                          |j                  d         |r|j	                         sot        |d      r|j                         n
t        |      t        fd| j                  D              r)t        j                  d        |j                          yyyy)z2Cancel current tasks that should be interruptible.get_namec              3   &   K   | ]  }|v  
 y wrK   r   .0pattern	task_names     r   	<genexpr>z<SignalHandler._cancel_interruptible_tasks.<locals>.<genexpr>  s     
PG7i
P   zCancelling task: c                 F    | j                         r| j                         S d S rK   )	cancelled	exception)ts    r   rM   z;SignalHandler._cancel_interruptible_tasks.<locals>.<lambda>  s    q{{}akkm $ r:   c              3   &   K   | ]  }|v  
 y wrK   r   rn   s     r   rr   z<SignalHandler._cancel_interruptible_tasks.<locals>.<genexpr>   s     	O7'Y
	Ors   zCancelling current task: N)r0   current_taskr%   	all_tasksdonehasattrrl   stranyr*   rX   debugcanceladd_done_callback)r8   ry   taskrq   s      @r   ri   z)SignalHandler._cancel_interruptible_tasks  s   %%dii0,		* Pd
l499;#*4#<#d)I

Pt/O/O
PP\\%i[12	[[]	NOP ,++-*1,
*K|$$&QTUaQb9		Od.N.N	OO
LL,YK89 P .\r:   c                    t        | j                  dd       t        j                  t        j                        }	 t        j                  t        j                  t        j
                         d}d}d}d}d}	 t        d| d| d	| d
| d| d| dddt               t                | j                  r| j                          	 t        j                  t        j                  |       t        | j                  dd       y# t        $ r Y w xY w# t        $ r | j                          Y gw xY w# t        $ r Y yw xY w# 	 t        j                  t        j                  |       t        | j                  dd       w # t        $ r Y w w xY wxY w)z
		Wait for user input to resume or exit.

		This method should be called after handling the first Ctrl+C.
		It temporarily restores default signal handling to allow catching
		a second Ctrl+C directly.
		r=   Tz[32;1mz[31mz[33;5mrb   u   ➡️  Press z[Enter]z to resume or z[Ctrl+C]z again to exitz... r^   r_   FN)r>   r%   rP   	getsignalrQ   default_int_handler
ValueErrorrD   r	   inputr'   KeyboardInterruptrf   rT   )r8   original_handlergreenredblinkunblinkresets          r   wait_for_resumezSignalHandler.wait_for_resume$  sq    
$))($/ %%fmm4	== : :; %#
%'
%	UG75'uHUG>Z_Y``cdkcllmn

		 	7 
	
MM&--!12DII*E2= 
  . 
     				
MM&--!12DII*E2
 		sl   2D 9AD ;D0 	DDD-*D? ,D--D? 0	D<;D<?F;E=<F=	F	FF		Fc                     t        | j                  d      rt        | j                  dd       t        | j                  d      rt        | j                  dd       yy)zReset state after resuming.r<   Fr=   N)r|   r%   r>   r?   s    r   r   zSignalHandler.resetV  sI     TYY()
499&.TYY+,
499)51 -r:   )NNNNTN)r   N)__name__
__module____qualname____doc__r0   AbstractEventLoopr   boollistr}   r9   r5   rU   r\   rf   rL   rO   ri   r   r   r   r:   r   r$   r$   E   s    
 ,0.2/348!26"'!!D("' 2t8$t+"' BH%,	"'
 !T*T1"' "'  $Cy4/"'H1
2E(/b$_L"(0	d2r:   r$   additional_textc                 `     dt         t        t        f   dt         t        t        f   f fd}|S )Nfuncr   c                      t               dt        j                  dt        j                  dt        f fd       }|S )Nargskwargsr   c                     t        j                          } | i |}t        j                          |z
  }|dkD  r| xr t        | d   dd       }|rt        | d   d      }nAd|v rt        |d   d      }n-d|v rt        |d   d      }nt        j                  t              }|j                  dj                  d       d|d	d
       |S Ng      ?r   rX   agentbrowser_sessionu   ⏳ -z() took z.2fstimerh   logging	getLoggerr   r   strip	r   r   
start_timeresultexecution_timeself_has_loggerrX   r   r   s	          r   wrapperz7time_execution_sync.<locals>.decorator.<locals>.wrappera  s    		:$!&!6IIK*,>t?wtAw$?Od1gx(V	F	fWox0V	f	$f./:V)V
LL4--c238N3;OqQR
=r:   r   r"   r   r   r    r   r   r   s   ` r   	decoratorz&time_execution_sync.<locals>.decorator`  s=    ;QVV qxx A  $ 
.r:   )r   r"   r    r   r   s   ` r   time_execution_syncr   _  s.    Xad^ A , 	r:   c           	           dt         t        t        t        t        t        f   f   dt         t        t        t        t        t        f   f   f fd}|S )Nr   r   c                      t               dt        j                  dt        j                  dt        f fd       }|S )Nr   r   r   c                    K   t        j                          } | i | d {   }t        j                          |z
  }|dkD  r| xr t        | d   dd       }|rt        | d   d      }nAd|v rt        |d   d      }n-d|v rt        |d   d      }nt        j                  t              }|j                  dj                  d       d|d	d
       |S 7 wr   r   r   s	          r   r   z8time_execution_async.<locals>.decorator.<locals>.wrapper}  s     		:'''6IIK*,> t?wtAw$?Od1gx(V	F	fWox0V	f	$f./:V)V
LL4--c238N3;OqQR
= (s    CCB2Cr   r   s   ` r   r   z'time_execution_async.<locals>.decorator|  s=    ;166 QXX !  & 
.r:   )r   r"   r   r
   r    r   s   ` r   time_execution_asyncr   y  sL    Xa3Q;!778 XaSVX[]^S^I_F_=` . 	r:   c                      d g fd}|S )Nc                  .    d    | i |d<   d   S )Nr   r   )r   r   clsinstances     r   r   zsingleton.<locals>.wrapper  s*    a[d%f%8A;	!r:   r   )r   r   r   s   ` @r   	singletonr     s    F
 	r:   keysc                       |d | D              S )z3Check if all required environment variables are setc              3   d   K   | ](  }t        j                  |d       j                          * yw)r^   N)rE   getenvr   )ro   keys     r   rr   z&check_env_variables.<locals>.<genexpr>  s$     >#299S"%++->s   .0r   )r   
any_or_alls     r   check_env_variablesr     s    >>>>r:   rp   c                     d| v r| j                  dd      \  }} | j                  dd      j                  dd      }d|v S )z
	Check if a domain pattern has complex wildcards that could match too many domains.

	Args:
		pattern: The domain pattern to check

	Returns:
		bool: True if the pattern has unsafe wildcards, False otherwise
	://   .*r^   *.*)splitreplace)rp   _bare_domains      r   is_unsafe_patternr     sL     
W}}UA&*!W tR(00r: 	{r:   urlc                 
    | dv S )z
	Check if a URL is a new tab page (about:blank, chrome://new-tab-page, or chrome://newtab).

	Args:
		url: The URL to check

	Returns:
		bool: True if the URL is a new tab page, False otherwise
	)zabout:blankzchrome://new-tab-page/zchrome://new-tab-pagezchrome://newtab/zchrome://newtabr   )r   s    r   is_new_tab_pager     s     	xxxr:   domain_patternlog_warningsc                    	 t        |       ryt        |       }|j                  r|j                  j                         nd}|j                  r|j                  j                         nd}|r|sy|j                         }d|v r|j                  dd      \  }}nd}|}d|v r&|j                  d      s|j                  dd      d   }t        ||      sy|dk(  s||k(  ry	d|v r|j                  d
      dkD  s|j                  d      dkD  r1|r.t        j                  t              }|j                  d| d       y|j                  d      r1|r.t        j                  t              }|j                  d| d       y|j                  d
d      }	d|	v r1|r.t        j                  t              }|j                  d| d       y|j                  d
      r|dd }
||
k(  st        ||
      ry	t        ||      ry	y# t        $ rS}t        j                  t              }|j                  d|  d| dt!        |      j                   d|        Y d}~yd}~ww xY w)a  
	Check if a URL matches a domain pattern. SECURITY CRITICAL.

	Supports optional glob patterns and schemes:
	- *.example.com will match sub.example.com and example.com
	- *google.com will match google.com, agoogle.com, and www.google.com
	- http*://example.com will match http://example.com, https://example.com
	- chrome-extension://* will match chrome-extension://aaaaaaaaaaaa and chrome-extension://bbbbbbbbbbbbb

	When no scheme is specified, https is used by default for security.
	For example, 'example.com' will match 'https://example.com' but not 'http://example.com'.

	Note: New tab pages (about:blank, chrome://new-tab-page) must be handled at the callsite, not inside this function.

	Args:
		url: The URL to check
		domain_pattern: Domain pattern to match against
		log_warnings: Whether to log warnings about unsafe patterns

	Returns:
		bool: True if the URL matches the pattern, False otherwise
	Fr^   r   r   https:r   r   Tr   r   u&   ⛔️ Multiple wildcards in pattern=[z] are not supportedu&   ⛔️ Wildcard TLDs like in pattern=[z ] are not supported for securityuE   ⛔️ Only *.domain style patterns are supported, ignoring pattern=[]   Nu   ⛔️ Error matching URL z with pattern : )r   r   schemelowerhostnamer   
startswithr   countr   r   r   re   endswithr   rT   type)r   r   r   
parsed_urlr   domainpattern_schemepattern_domainrX   r   parent_domainr[   s               r   match_url_with_domain_patternr     ss   .LS
}* )3(9(9:""$r&*4*=*=:$$&2&	v
 "''). n$2$8$8$B!>>>"> 	N>#<#<S#A"((a03> 
	(
 sf6
 	N 4 1$(<(<T(BQ(F)V\\:>:JJ]^_ d#)V\\:>:JJjkl  ''b1;	[)V\\YZhYiijkl %"12&M'&-"@ fn%	 X&&,,+C5~>NbQUVWQXQaQaPbbdefdghi	sL   G; AG; .A$G; 
G; AG; <AG; >AG; 'G; -G; ;	IA	IIabpath.c           
         |D ]  }|| v rt        | |   t              r4t        ||   t              r!t        | |   ||   |t        |      fz          Nt        | |   t              r"t        ||   t              r| |   ||   z   | |<   | |   ||   k7  st        ddj                  |t        |      fz         z         ||   | |<    | S )NzConflict at .)
isinstancedictmerge_dictsr}   r   rT   join)r   r   r   r   s       r   r   r   .  s     	SAX3:afd#;##C{ 231S64 Z#%=sVaf_AcF	#!C&
NSXXdc#h[.@%AA
BBcF1S6	 	
r:   c                  L   	 t        t              j                  j                  } | dz  }|j                         rpddl}t        |d      5 }|j                         } |j                  d|      }|r0|j                  d       }|t        j                  d<   |cddd       S 	 ddd       dd	lm} t         |d
            }|t        j                  d<   |S # 1 sw Y   5xY w# t        $ r8}t        j!                  dt#        |      j$                   d|        Y d}~yd}~ww xY w)zeGet the browser-use package version using the same logic as Agent._set_browser_use_version_and_sourcezpyproject.tomlr   Nutf-8)encodingz!version\s*=\s*["\']([^"\']+)["\']r   LIBRARY_VERSION)versionzbrowser-usez%Error detecting browser-use version: r   unknown)r   __file__parentexistsreopenreadsearchgrouprE   environimportlib.metadatar   r}   rT   rX   r   r   r   )	package_rootpyproject_pathr   fcontentmatchr   get_versionr[   s	            r   get_browser_use_versionr  <  s   h&&--,"22. ^g. !ffhGBII:GDE++a.!W%,RZZ!"   8M*+'")"**	.  	 ,,6tAw7G7G6H1#NO	s7   A	C" AC	C" "3C" CC" "	D#+.DD#c                  f  K   	 t        j                  d      4 d{   } | j                  d       d{   }|j                  dk(  r)|j	                         }|d   d   cddd      d{    S ddd      d{    y7 f7 O7 7 # 1 d{  7  sw Y   yxY w# t
        $ r Y yw xY ww)zCheck the latest version of browser-use from PyPI asynchronously.

	Returns:
		The latest version string if successful, None if failed
	g      @)timeoutNz&https://pypi.org/pypi/browser-use/json   infor   )httpxAsyncClientgetstatus_codejsonrT   )clientresponsedatas      r    check_latest_browser_use_versionr  [  s     s+ # #vJJGHH8c!==?D<	"	# # # # # 	#H# # # # # 	 	 s   B1B" BB" BB*B"B" .B	/B" 3B14B" ?B B" B1B" B	B" B" BBBB" B1B" "	B.+B1-B..B1c                     	 ddl } t        t              j                  j                  }|dz  }|j	                         sy| j                  g d|| j                        j                         j                         }| j                  g d|| j                        j                         j                         }| j                  g d|| j                        j                         j                         }| j                  g d|| j                        j                         j                         }||||d	S # t        $ r8}t        j                  d
t        |      j                   d|        Y d}~yd}~ww xY w)z4Get git information if installed from git repositoryr   Nz.git)git	rev-parseHEAD)cwdr	   )r  r  z--abbrev-refr  )r  configz--getzremote.origin.url)r  showz-sz--format=%cir  )commit_hashbranch
remote_urlcommit_timestampzError getting git info: r   )
subprocessr   r   r   r   check_outputDEVNULLdecoder   rT   rX   r   r   r   )r   r  git_dirr  r  r  r  r[   s           r   get_git_infor%  m  sM   %h&&--,6!'		
 7\R\RdRdellnttv  G\blbtbtu
FH	EG 	 JP\eoewewx
FH	EG  Hlcmcucuv
FH	EG  %jfv	ww ,,)$q'*:*:);2aSAB	s   <D6 C6D6 6	E7?.E22E7c                    | rt        |       j                         syt        | t         t        f      sdt	        |       j
                   dS t        |       j                  t        t        j                               d      j                  t        t        j                         j                               d      }|j                         r
d|v rd| d}|S )z7Pretty-print a path, shorten home dir to ~ and cwd to .r^   <>~r   r   ")
r}   r   r   r   r   r   r   homer  resolve)r   pretty_paths     r   _log_pretty_pathr.    s     	CIOO%	 	4#t% T$Z  !	## 4y  TYY[!137??DHHJDVDVDX@Y[^_ C;.K="+r:   r   max_lenc                     | j                  dd      j                  dd      j                  dd      } |t        |       |kD  r| d| dz   S | S )zXTruncate/pretty-print a URL with a maximum length, removing the protocol and www. prefixzhttps://r^   zhttp://zwww.Nu   …)r   len)r   r/  s     r   _log_pretty_urlr2    sS    YYz2&&y"5==fbICFW,	
8Gu		r:   )namelogger_instancesuppress_exceptionscoror3  r4  r5  c                    t        j                  | |      }|xs t        dt         j                  t           ddffd}|j                  |       |S )a  
	Create an asyncio task with proper exception handling to prevent "Task exception was never retrieved" warnings.

	Args:
		coro: The coroutine to wrap in a task
		name: Optional name for the task (useful for debugging)
		logger_instance: Optional logger instance to use. If None, uses module logger.
		suppress_exceptions: If True, logs exceptions at ERROR level. If False, logs at WARNING level
			and exceptions remain retrievable via task.exception() if the caller awaits the task.
			Default False.

	Returns:
		asyncio.Task: The created task with exception handling callback

	Example:
		# Fire-and-forget with suppressed exceptions
		create_task_with_error_handling(some_async_function(), name="my_task", suppress_exceptions=True)

		# Task with retrievable exceptions (if you plan to await it)
		task = create_task_with_error_handling(critical_function(), name="critical")
		result = await task  # Will raise the exception if one occurred
	)r3  rw   r   Nc           	      $   d}	 | j                         }|t        | d      r| j                         nd}r0j                  d| dt	        |      j
                   d| |       n1j                  d| dt	        |      j
                   d| |       |}||y# t        j                  $ r Y t        $ rU}t        | d      r| j                         nd}j                  d| dt	        |      j
                   d|        Y d}~rd}~ww xY w)	z"Callback to handle task exceptionsNrl   unnamedzException in background task [z]: r   )exc_infoz"Error handling exception in task [)
rv   r|   rl   re   r   r   rY   r0   CancelledErrorrT   )rw   exc_to_raiseexcrq   r[   logr5  s        r   _handle_task_exceptionz?create_task_with_error_handling.<locals>._handle_task_exception  s'   ,Y	
3	o ': 6

IIYY/	{#d3i>P>P=QQSTWSXYdgYh 	[[&ykT#Y5G5G4H3%P   \ 	  
		 	 Y&q*5qzz|99991)CQ@P@P?QQSTUSVWXXYs   BB D2D:AD

D)r0   create_taskrX   Taskr!   r   )r6  r3  r4  r5  r   r?  r>  s      `  @r   create_task_with_error_handlingrB    sR    : 	Dt, &w||A 4 : ./r:   textc                 F    | j                  dd      j                  d      S )a'  Remove surrogate characters that can't be encoded in UTF-8.

	Surrogate pairs (U+D800 to U+DFFF) are invalid in UTF-8 when unpaired.
	These often appear in DOM content from mathematical symbols or emojis.

	Args:
		text: The text to sanitize

	Returns:
		Text with surrogate characters removed
	r   ignore)errors)encoder#  )rC  s    r   sanitize_surrogatesrH    s"     	GH-44W==r:   )r^   )F)r   )   )Er0   r   rE   r2   r   rP   r   collections.abcr   r   r   	functoolsr   r   pathlibr   sysr	   typingr
   r   r   urllib.parser   r  dotenvr   compile
IGNORECASEURL_PATTERNr   r   rX   r   r   __annotations__r   r   r   r   rd   r    r!   r"   r$   r}   r   r   r   allr   r   r   r   r   r   r   tupler   r  r  r%  r.  intr2  LoggerrA  rB  rH  r   r:   r   <module>rY     s     	  	   /  "   * * !    bjjikmkxkxy 
		8	$ 0"b9 4 9)- 4$; -'+  +
btd{ 
b
^TD[ 
^  CLCLcNW2 W2t hA?OQYZ[]^Z^Q_?_6` 6 x9S#q[1123Xa3PSUV;AW>W5XXY: 58 ?d3i ?D ?
s t *
y 
y 
ycs cC ct c`d cL
4 
D 
c3h 
   <d
 $ 'd38nt+ ' 'T3:,  ,
s 
S4Z 
 
 *.">c1> Tz> ..4'	>
 > \\!_>B>c >c >r:   