Ë
    ãß²jwç  ã                  óº  — U 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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mZ ddlmZ ddlmZ  ej2                  e«      Zdad	ed
<    ej<                  «       Zda ded<    ej<                  «       Z!i Z"ded<   dZ#dZ$dZ%dZ&dZ'dZ( ej<                  «       Z)dZ*dZ+dZ,dZ- ej<                  «       Z.da/ded<    ej`                  «       Z1h d£Z2dZ3dZ4dZ5dZ6d „ Z7d\d!„Z8d]d"„Z9d#„ Z:d^d$„Z;d_d%„Z<d`d&„Z=dad'„Z>dbd(„Z?dcd)„Z@ddd*„ZAddd+„ZBded,„ZCdfd-„ZDdgd.„ZEdhd/„ZFdid0„ZGdgd1„ZHdgd2„ZIdgd3„ZJdgd4„ZKdjd5„ZLdjd6„ZMdjd7„ZNdkd8„ZOdld9„ZPddd:„ZQddd;„ZRdmd<„ZSdndod>„ZTdpd?„ZUd`d@„ZVdpdA„ZWdqdB„ZXdqdC„ZYdrdD„ZZd^dE„Z[ddddFœ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dsdG„Z\dd=d=de#ddHœ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dtdI„Z]dd=d=de#ddddddJœ
	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dudK„Z^dvdL„Z_dwdM„Z`dxdN„Zad`dO„ZbdydP„ZcdzdQ„Zdd`dR„Zed{dS„Zfd|dT„Zgd}dU„Zhd~dV„ZiddW„Zjd€d�dX„Zk	 d‚	 	 	 	 	 	 	 	 	 dƒdY„Zld`dZ„Zmd„d[„Zny)…a   Async (background) delegation registry behind ``delegate_task(background=true)``.

The parent dispatches a subagent on a module-level daemon executor and returns a handle
immediately. On completion a ``type="async_delegation"`` event (self-contained task-source
block) is pushed onto the SHARED ``process_registry.completion_queue`` the CLI/gateway drain
while idle, so results surface as a NEW turn (never mid-turn) and inherit its de-dup and
crash-recovery wiring. Only the async lifecycle lives here; the child run is an injected ``runner``.é    )ÚannotationsN)ÚThreadPoolExecutor)ÚAnyÚCallableÚDictÚListÚOptional©Úget_hermes_home)ÚDaemonThreadPoolExecutor)Úpropagate_context_to_threadzOptional[ThreadPoolExecutor]Ú	_executorÚintÚ_executor_max_workerszDict[str, Dict[str, Any]]Ú_recordsé   é2   i€:	 iè  é   g     Ag      >@g      |@g     À’@g      ^@zOptional[threading.Thread]Ú_monitor_thread>   ÚrunningÚstallingÚ
finalizing)r   r   )Úscope_idÚuser_idÚ	user_name©Ústalled_after_quiet_secondsÚstall_threshold_secondsÚstall_phaseÚstall_grace_seconds))Ú_stall_quiet_secondsr   )Ú_stall_threshold_secondsr   )Ú_stall_in_toolÚstall_in_toolc                 ó   — t        «       dz  S )Nzstate.dbr
   © ó    ú;/home/ubuntu/.hermes/hermes-agent/tools/async_delegation.pyÚ_db_pathr)   Q   s   € ÜÓ˜zÑ)Ð)r'   c                 ó´   — ddl m}  ddlm} t	        «       }|j
                  j                  dd¬«        ||d¬«        | |ddd	d t        ¬
«      } ||«       |S )Nr   )Úopen_db)Ú_secure_state_db_filesT)ÚparentsÚexist_ok)Úcreate_mainzstate.db (async_delegation)i'  F)Údb_labelÚbusy_timeout_msÚwalÚrow_factoryÚ
initialize)Úhermes_cli.sqlite_utilr+   Úhermes_stater,   r)   ÚparentÚmkdirÚ_initialize_schema)r+   r,   ÚpathÚconns       r(   Ú_connectr<   U   sZ   € Ý.õ 4ä‹:€DØ‡K�K×Ñ˜d¨TÐÔ2Ù˜4¨TÕ2á�4Ð"?ÐQWØ¨$Ô;MôO€Dá˜4Ô Ø€Kr'   c                ó<   — ddl m} ddlm}  || «        || «       y )Nr   )Úapply_durability_barriers)Úreconcile_state_schema)Úhermes_state_repairr>   Úhermes_state_schemar?   )r;   r>   r?   s      r(   r9   r9   f   s   € Ý=Ý:ñ ˜dÔ#ñ ˜4Õ r'   c                 ó.   — ddl m}   | t        «       «      S )Nr   ©Útransaction)r5   rD   r<   rC   s    r(   Ú_transactionrE   v   s   € Ý2á”x“zÓ"Ð"r'   c                 ó    — 	 ddl m}  t        D �ci c]"  } | d|j                  «       › �d«      x}sŒ ||“Œ$ c}S c c}w # t        $ r i cY S w xY w)zÌSnapshot scope_id/user_id/user_name on the PARENT thread (the daemon worker
    has no contextvars) so a restart-replayed completion can rebuild a SessionSource.
    Best-effort: empty values are omitted.r   ©Úget_session_envÚHERMES_SESSION_Ú )Úgateway.session_contextrH   Ú_ROUTING_KEYSÚupperÚ	Exception)rH   ÚkÚvs      r(   Ú_capture_routing_originrQ   |   sZ   € ðÝ;Ü+Öi˜±_ÀÐWX×W^ÑW^ÓW`ÐVaÐEbÐdfÓ5gÐ0g°Ñ0g��1‘ÒiÐiùÒiøÜò ØŠ	ðús   ‚? �!:²:·? º? ¿AÁAc                óø  — t        j                   «       }	 ddlm}  |t        j                  «       «      }ddddddd	d
dg	t        ¢­D �ci c]  }|| v r|| j                  |«      “Œ }}	 t        j                  «       |d<   t        5  t        «       5 }|j                  d| d   | j                  dd«      | j                  dd«      | j                  d«      | d   |t        j                  «       |t        j                  |«      | j                  dd«      f
«       d d d «       d d d «       t        «        y # t
        $ r d }Y �Œw xY wc c}w # t        $ r Y ŒÕw xY w# 1 sw Y   ŒBxY w# 1 sw Y   t        «        y xY w)Nr   )Úget_process_start_timeÚgoalÚgoalsÚcontextÚtoolsetsÚroleÚmodelÚis_batchÚtask_indexesÚtask_transcriptsÚ	owner_cwda~  INSERT OR REPLACE INTO async_delegations
               (delegation_id, origin_session, origin_ui_session_id,
                parent_session_id, state, dispatched_at, updated_at,
                delivery_state, delivery_attempts, owner_pid,
                owner_started_at, task_json, origin_session_id)
               VALUES (?, ?, ?, ?, 'running', ?, ?, 'pending', 0, ?, ?, ?, ?)Údelegation_idÚsession_keyrJ   Úorigin_ui_session_idÚparent_session_idÚdispatched_atÚorigin_session_id)ÚtimeÚgateway.statusrS   ÚosÚgetpidrN   rL   ÚgetÚgetcwdÚOSErrorÚ_DB_LOCKrE   ÚexecuteÚjsonÚdumpsÚ_prune_durable_records)ÚrecordÚnowrS   Úowner_started_atÚkeyÚtask_payloadr;   s          r(   Ú_persist_dispatchru   ‡   sƒ  € Ü
�)‰)‹+€Cð Ý9Ù1´"·)±)³+Ó>Ðð
 ˜G Y°
¸FÀGÈZÐYgÐi{ð  Mô  Lñ  MöàØ�&‰=ð 	ˆV�Z‰Z˜‹_Ñð€Lð ðÜ$&§I¡I£Kˆ�[Ñ!ô 
ñ 	M”<“>ð 	M TØ�‰ð Qð �OÑ$ f§j¡j°ÀÓ&CÀVÇZÁZÐPfÐhjÓEkØ�Z‰ZÐ+Ó,¨f°_Ñ.EÀsÌBÏIÉIËKÐYiÜ�Z‰Z˜Ó% v§z¡zÐ2EÀrÓ'JðLô	M÷	M÷ 	Mô Õøô) ò  ØÓð üòøô ò Ùðú÷	Mð 	Mú÷ 	Mô ÕúsN   – D4 Á
EÁ*E ÂE&ÂBEÄE&Ä4EÅEÅ	EÅEÅE#	ÅE&Å&E9c                 óè  — t        j                   «       t        z
  } t        5  t        «       5 }|j	                  d| f«       |j	                  d«      j                  «       d   }|t        kD  r|j	                  d|t        z
  f«       |j	                  d«      j                  «       d   }|t        kD  r|j	                  d|t        z
  f«       ddd«       ddd«       y# 1 sw Y   ŒxY w# 1 sw Y   yxY w)zBBound terminal history, preferring delivered records for deletion.zQDELETE FROM async_delegations WHERE delivery_state='delivered' AND updated_at < ?zRSELECT COUNT(*) FROM async_delegations WHERE state NOT IN ('running','finalizing')r   aX  DELETE FROM async_delegations WHERE delegation_id IN (
                     SELECT delegation_id FROM async_delegations
                     WHERE state NOT IN ('running','finalizing')
                     ORDER BY CASE delivery_state WHEN 'delivered' THEN 0 ELSE 1 END,
                              updated_at ASC LIMIT ?
                   )z~SELECT COUNT(*) FROM async_delegations
               WHERE state NOT IN ('running','finalizing') AND delivery_state='pending'a  DELETE FROM async_delegations WHERE delegation_id IN (
                     SELECT delegation_id FROM async_delegations
                     WHERE state NOT IN ('running','finalizing') AND delivery_state='pending'
                     ORDER BY updated_at ASC LIMIT ?
                   )N)rd   Ú_DURABLE_RETENTION_SECONDSrk   rE   rl   ÚfetchoneÚ_MAX_RETAINED_COMPLETEDÚ_MAX_DURABLE_PENDING)Úcutoffr;   Úterminal_countÚpending_counts       r(   ro   ro   £   s  € ä�Y‰Y‹[Ô5Ñ5€FÜ	ñ B”<“>ð B TØ�‰Ø_ÐbhÐajô	làŸ™Ø`óbßbjÑbjÓblÐmnñpˆàÔ3Ò3Ø�L‰Lð ð
 )Ô+BÑBÐDôFð Ÿ™ð &[ó \ß\dÑ\dÓ\fÐghñjˆàÔ/Ò/Ø�L‰Lð ð (Ô*>Ñ>Ð@ô	B÷B÷ B÷ Bñ Bú÷ Bð Bús#   ¢C(­BCÃC(ÃC%	Ã!C(Ã(C1c                ób  — t        j                   «       }t        5  t        «       5 }|j                  d| j	                  dd«      | j	                  d|«      |t        j                  | «      t        j                  |«      | d   f«       d d d «       d d d «       y # 1 sw Y   ŒxY w# 1 sw Y   y xY w)Nz­UPDATE async_delegations SET state=?, completed_at=?, updated_at=?,
               event_json=?, result_json=?, delivery_state='pending'
               WHERE delegation_id=?ÚstatusÚ	completedÚcompleted_atr^   )rd   rk   rE   rl   rh   rm   rn   )ÚeventÚresultrq   r;   s       r(   Ú_persist_completionr„   ¼   s�   € Ü
�)‰)‹+€CÜ	ñ M”<“>ð M TØ�‰ð (ð �Y‰Y�x Ó-¨u¯y©y¸ÈÓ/MÈsÜ�Z‰Z˜Ó¤§
¡
¨6Ó 2°E¸/Ñ4JðLô	M÷M÷ M÷ Mñ Mú÷ Mð Mús#   ›B%¦A"BÂB%ÂB"	ÂB%Â%B.c           
     óÄ  — 	 t         5  t        «       5 }|j                  d| f«      j                  «       }|€	 ddd«       ddd«       yt	        j
                  |d   xs d«      xs i }|j                  d«      xs g D �cg c](  }|j                  d«      |j                  d«      k7  sŒ'|‘Œ* }}|j                  |«       |j                  dt	        j                  |dd	œ«      t        j                  «       | f«       ddd«       ddd«       yc c}w # 1 sw Y   ŒxY w# 1 sw Y   yxY w# t        $ r+ t        j                  d
| |j                  d«      d¬«       Y yw xY w)az  Durably record ONE finished child of a still-running multi-child unit on the unit's own row, so a crash before
    the unit joins loses only the children that had not finished. Stored in ``result_json`` (overwritten by the real
    result at finalize); ``recover_abandoned_delegations`` replays it. Best-effort: a failed write costs recovery
    fidelity, never the live result.zSSELECT result_json FROM async_delegations WHERE delegation_id=? AND state='running'Nr   ú{}ÚresultsÚ
task_indexzbUPDATE async_delegations SET result_json=?, updated_at=? WHERE delegation_id=? AND state='running'T)r‡   Úpartialz7Async delegation %s: could not record finished child %s)Úexc_info)rk   rE   rl   rx   rm   Úloadsrh   Úappendrn   rd   rN   ÚloggerÚwarning)r^   Úentryr;   Úrowr‰   Úrr‡   s          r(   Úrecord_unit_childr’   Æ   s]  € ð
IÜñ 		j”|“~ð 		j¨Ø—,‘,ÐtØ -Ð/ó1ß19±³ð àˆ{Ø÷			j÷ 		jð 		jô
 —j‘j  Q¡¢¨4Ó0Ò6°BˆGØ")§+¡+¨iÓ"8Ò">¸BÖq˜QÀ!Ç%Á%ÈÓBUÐY^×YbÑYbÐcoÓYpÓBp’qÐqˆGÐqØ�N‰N˜5Ô!Ø�L‰LÐ}ÜŸ*™*°ÀTÑ%JÓKÌTÏYÉYË[ÐZgÐhôj÷		j÷ 		jð 		jùò r÷		jð 		jú÷ 		jð 		jûô ò IÜ�‰ÐPÐR_Ðaf×ajÑajÐkwÓaxð  DHˆö  	IðIúso   ‚D+ ˆD“%D¸DÁ D+ Á	7DÂ (DÂ)DÂ-ADÃ=DÄD+ ÄDÄD	ÄDÄD(Ä$D+ Ä(D+ Ä+1EÅEc           	     óú  — t        j                  |xs d«      xs i }| j                  d«      r"|j                  d«      r|j                  d«      sy|d   D �ci c](  }t        |j                  d«      t        «      sŒ#|d   |“Œ* }}| j                  d«      xs0 t        t        t        | j                  d«      xs g «      «      «      }|D �cg c]  }|j                  |«      xs |d	d|d
œ‘Œ c}S c c}w c c}w )zaPer-task results for an abandoned unit: recorded children as they finished, the rest ``unknown``.r†   rZ   r‰   r‡   Nrˆ   r[   rU   Úunknown)rˆ   r   ÚsummaryÚerror)rm   r‹   rh   Ú
isinstancer   ÚlistÚrangeÚlen)ÚtaskÚresult_jsonr–   r‰   r‘   ÚrecordedÚindexesÚis           r(   Ú_recovered_resultsr    Ú   sÚ   € ä�j‰j˜Ò,¨Ó-Ò3°€GØ�H‰H�ZÔ  W§[¡[°Ô%;ÀÇÁÈIÔ@VØØ,3°IÑ,>Ög qÄ*ÈQÏUÉUÐS_ÓM`ÔbeÕBf��,‘ Ñ"Ðg€HÐgØ�h‰h�~Ó&ÒS¬$¬u´S¸¿¹À'Ó9JÒ9PÈbÓ5QÓ/RÓ*S€GØpwÖxÐklˆH�L‰L˜‹OÒf¨a¸9ÐQUÐ`eÑfÑfÒxÐxùò hùâxs   Á$C3Á>C3Ã!C8c                 ób  — 	 ddl m} m}m} t        j
                  «       d}}t        5  t        «       5 }|j                  d«      j                  «       }|D �]  }|\  }}	}
}}}}}}}}|r0 | t        |«      «      r|� || |t        |«      «      xs d«      rŒDt        j                  |xs d«      }d}t        |||«      }|r$t        d„ |D «       «      }d|› d	t        |«      › d
�}||j!                  d«      xs i dœ}ddlm}m}  ||d   «      x}r||d<    ||j!                  d«      «      x}r||d<   i dd“d|“d|	“d|
“d|xs d“d|“d|j!                  dd«      “d|j!                  d«      “d|j!                  d«      “d|j!                  d«      “d|j!                  d«      “d|j!                  d«      “dt)        |j!                  d«      «      “d d!“d"d“d#|“|¥|rd$|ini ¥||d%œ¥t*        D �ci c]  }|j!                  |«      sŒ|||   “Œ c}¥}d!d|d#   d&œ|¥|rd$|ini ¥}|j                  d'||t        j,                  |«      t        j,                  |«      |f«       |d(z  }�Œ 	 ddd«       ddd«       |S # t        $ r Y yw xY wc c}w # 1 sw Y   Œ'xY w# 1 sw Y   |S xY w))z¸Classify records whose owning process disappeared as outcome unknown; children a multi-child unit had already
    recorded (``record_unit_child``) are replayed with their real results.r   )Ú_pid_existsrS   Ústart_time_fingerprints_matcha%  SELECT delegation_id, origin_session, origin_ui_session_id,
                      parent_session_id, dispatched_at, owner_pid,
                      owner_started_at, task_json, origin_session_id, result_json, state
               FROM async_delegations WHERE state IN ('running','finalizing')Nr†   zLDelegation owner exited before recording a terminal result; outcome unknown.c              3  óJ   K  — | ]  }|j                  d «      dk7  sŒd–— Œ y­w)r   r”   é   N©rh   ©Ú.0r‘   s     r(   ú	<genexpr>z0recover_abandoned_delegations.<locals>.<genexpr>û   s   è ø€ ÒX ¸1¿5¹5À»?ÈiÓ;Wœ1ÑXùs   ‚#œ#z2Delegation owner exited before the unit finished; ú/zJ child results were recorded and are included below, the rest are unknown.r\   )Úlast_known_statusr\   )Úgit_state_hintÚtranscript_tailsr­   r]   r¬   ÚtypeÚasync_delegationr^   r_   r`   rc   rJ   ra   rT   rU   rV   rW   rX   rY   rZ   r   r”   r•   r–   r‡   ©rb   r�   )r   r•   r–   z½UPDATE async_delegations SET state='unknown', completed_at=?,
                   updated_at=?, event_json=?, result_json=?, delivery_state='pending'
                   WHERE delegation_id=?r¥   )re   r¢   rS   r£   rN   rd   rk   rE   rl   Úfetchallr   rm   r‹   r    Úsumrš   rh   Ú%tools.async_delegation_recovery_hintsr¬   r­   ÚboolrL   rn   )r¢   rS   r£   rq   Ú	recoveredr;   Úrowsr�   r^   r_   Ú	origin_uiÚ	parent_idrb   ÚpidÚstartedÚ	task_jsonÚ
origin_sidrœ   Ú
last_stater›   r–   Úrecovered_resultsÚdoneÚdiagnosticsr¬   r­   ÚtailsÚhintrO   r‚   rƒ   s                                  r(   Úrecover_abandoned_delegationsrÃ   ä   sÉ  € ðßeÑeô —Y‘Y“[ !ˆ€CÜ	ñ )”<“>ð ) TØ�|‰|ð Qó R÷ S[ÑRZÓR\ð 	ð ó $	ˆCð MPñ  JˆM˜;¨	°9¸mÈSÐRYÐ[dÐfpÐr}ð  @JÙ‘{¤3 s£8Ô,Ø�Ñ#@ÀÑJ`ÔadÐehÓaiÓJjÒJoÐnoÔ#pàÜ—:‘:˜iÒ/¨4Ó0ˆDØbˆEÜ 2°4¸ÀeÓ LÐÙ ÜÑXÐ&7ÔXÓX�ØMÈdÈVÐSTÔUXÐYjÓUkÐTlð m_ð _�à0:ÐPT×PXÑPXÐYkÓPlÒPrÐprÑsˆK÷ _Ù(¨Ð5GÑ)HÓIÐIˆuÐIØ27�Ð.Ñ/Ù% d§h¡h¨{Ó&;Ó<Ð<ˆtÐ<Ø04�Ð,Ñ-ð	FØÐ*ð	FØ,;¸]ð	FØLYÐ[fð	Fà&¨	ð	Fà3FÈ
ÒHXÐVXð	Fð $ Yð	Fð 17¸¿¹ÀÈÓ8Lð	Fð OVÐW[×W_ÑW_Ð`gÓWhð	Fð ˜4Ÿ8™8 IÓ.ð		Fð 1;¸D¿H¹HÀZÓ<Pð		Fð SYÐZ^×ZbÑZbÐciÓZjð		Fð
 ˜Ÿ™ 'Ó*ð	Fð
 -7¼¸T¿X¹XÀjÓ=QÓ8Rð	Fð ˜)ð	Fð &/°ð	Fð 7>¸uð	Fð ITð	Fñ 6G�IÐ0Ñ1ÈBð	Fð "/Àò	Fô (5ÖD !¸¿¹À½�1�d˜1‘g‘:ÒDð	FˆEð !*°dÀUÈ7Á^ñ WÐWbð WÙ;L˜)Ð%6Ñ7ÐRTðWˆFà�L‰Lð ,à.1°3¼¿
¹
À5Ó8IÌ4Ï:É:ÐV\ÓK]Ð_lÐ-môoð ˜‰NŠIñI$	÷)÷ )ðT Ðøô[ ò ÙðüòL E÷G)ð )ú÷ )ðT ÐúsM   ‚
J ¨J$³GJÇ6JÈJÈAJÉ2J$Ê	JÊJÊJÊJ!	ÊJ$Ê$J.c           
     ó0  — t        «        t        j                  «       d}}t        5  t        «       5 }|j	                  d«      j                  «       }|D ]•  \  }}}}|xs |}	|	rF||	z
  t        kD  r:|j	                  d||f«       t        j                  d|||	z
  dz  t        dz  «       ŒVt        j                  |«      }
t        |
t        «      rd|
d<   | j                  |
«       |dz  }Œ— 	 d	d	d	«       d	d	d	«       |S # 1 sw Y   ŒxY w# 1 sw Y   |S xY w)
u¼  Enqueue durable pending completions as fresh turns after process start.
    Restored events are stamped ``restored=True`` in memory only: they came from a PREVIOUS
    process, so drains without an ownership filter must leave them for a consumer that can
    prove ownership. Rows older than ``_MAX_COMPLETION_REPLAY_AGE_S`` are terminally dropped
    instead of replaying a turn nobody is waiting on.

    Every restored event is stamped ``restored=True`` (in-memory only â€” the stamp is added after the durable
    payload is deserialized and is never persisted). Restored events originate from a *previous* process, so
    no consumer in THIS process implicitly owns them: drain paths that run without an ownership filter (the
    legacy single-session behavior) must leave them queued for a consumer that can positively prove
    ownership, otherwise a brand-new session adopts a dead session's delegation results seconds after boot
    (#64484).
    r   z÷SELECT delegation_id, event_json, completed_at, dispatched_at
               FROM async_delegations
               WHERE state != 'running' AND delivery_state='pending' AND event_json IS NOT NULL
               ORDER BY completed_at, delegation_idzøUPDATE async_delegations SET delivery_state='dropped',
                              delivery_claim=NULL, delivery_claimed_at=NULL,
                              updated_at=?
                       WHERE delegation_id=? AND delivery_state='pending'z|Async delegation %s: pending completion is %.1fh old (cap %.1fh); terminally dropping the replay (result remains queryable).g      ¬@TÚrestoredr¥   N)rÃ   rd   rk   rE   rl   r±   Ú_MAX_COMPLETION_REPLAY_AGE_Sr�   rŽ   rm   r‹   r—   ÚdictÚput)Útarget_queuerq   rÅ   r;   r¶   r^   Úpayloadr�   rb   Ú	age_basisÚevts              r(   Úrestore_undelivered_completionsrÍ     s3  € ô "Ô#Ü—I‘I“K ˆ€CÜ	ñ ”<“>ð  TØ�|‰|ð 7ó 8÷ 9A¹»
ð 	ð DHò 	Ñ?ˆM˜7 L°-Ø$Ò5¨ˆIÙ˜c I™oÔ1MÒMØ—‘ð Mð PSÐTaÐNbôdô —‘ð  ià,¨s°Y©À&Ñ.HÔJfÐioÑJoôqð Ü—*‘*˜WÓ%ˆCÜ˜#œtÔ$Ø"&��J‘Ø×Ñ˜SÔ!Ø˜‰M‰Hñ	÷÷ ð* €O÷+ð ú÷ ð* €Oús#   §D²B:C?Ã-DÃ?D	ÄDÄDc                óÊ   — t         5  t        «       5 }|j                  | |«      j                  dk(  cddd«       cddd«       S # 1 sw Y   nxY wddd«       y# 1 sw Y   yxY w)z?Run one UPDATE on the ledger; True iff exactly one row changed.r¥   N)rk   rE   rl   Úrowcount)ÚsqlÚparamsr;   s      r(   Ú_update_deliveryrÒ   A  sS   € ä	ñ 7”<“>ð 7 TØ�|‰|˜C Ó(×1Ñ1°QÑ6÷7÷ 7÷ 7ó 7ú÷ 7÷ 7ñ 7ús!   ‡A’A±	AÁA	Á	AÁA"c                óH   — t        j                   «       }t        d||| f«      S )zDAtomically acknowledge successful injection of a durable completion.z–UPDATE async_delegations SET delivery_state='delivered', delivered_at=?, updated_at=?
           WHERE delegation_id=? AND delivery_state!='delivered'©rd   rÒ   )r^   rq   s     r(   Úmark_completion_deliveredrÕ   G  s-   € ä
�)‰)‹+€CÜð	DØFIÈ3ÐP]ÐE^ó`ð `r'   c                óp  — t        j                   «       }t        5  t        «       5 }|j                  d| f«      j	                  «       }|€	 ddd«       ddd«       y|j                  d|||| |dz
  f«      }|j
                  dk(  cddd«       cddd«       S # 1 sw Y   nxY wddd«       y# 1 sw Y   yxY w)zBClaim one pending completion across competing consumers/processes.zBSELECT delivery_state FROM async_delegations WHERE delegation_id=?NTa  UPDATE async_delegations SET delivery_claim=?, delivery_claimed_at=?,
                      delivery_attempts=delivery_attempts+1, updated_at=?
               WHERE delegation_id=? AND delivery_state='pending'
                 AND (delivery_claim IS NULL OR delivery_claimed_at < ?)i,  r¥   )rd   rk   rE   rl   rx   rÏ   )r^   Úclaim_idrq   r;   r�   Úcurs         r(   Úclaim_completion_deliveryrÙ   O  s¸   € ä
�)‰)‹+€CÜ	ñ 
!”<“>ð 
! TØ�l‰lØPÐS`ÐRbódßdlÑdlÓdnð 	àˆ;Ø÷	
!÷ 
!ð 
!ð
 �l‰lð Lð �s˜C °°c±	Ð:ó	<ˆð
 �|‰|˜qÑ ÷
!÷ 
!÷ 
!ó 
!ú÷ 
!÷ 
!ñ 
!ús.   ›B,¦%BÁB,Á(BÂ	B,ÂB 	ÂB,Â,B5c                ób   — | j                  d«      dk(  xr t        | j                  d«      «      S )a
  An early per-task notice for a batch that is still running. It shares the batch's
    ``delegation_id`` but is NOT the durable completion: it must never claim, acknowledge or
    dedup against the final result's row (independent review reproduced exactly that loss).r®   r¯   Útask_failure_notice)rh   r´   )rÌ   s    r(   Úis_interim_delegation_eventrÜ   _  s,   € ð �7‰7�6‹?Ð0Ñ0ÒY´T¸#¿'¹'ÐBWÓ:XÓ5YÐYr'   c                ó  — t        | «      ry| j                  d«      dk(  rt        | j                  d«      xs d«      nd}|sy|› dt        j                  «       › dt        j                  «       j                  › �}t        ||«      r|S dS )zYClaim a durable delegation event; non-durable events (and interim notices) need no token.rJ   r®   r¯   r^   ú:N)	rÜ   rh   Ústrrf   rg   ÚuuidÚuuid4ÚhexrÙ   )rÌ   Úconsumerr^   r×   s       r(   Úclaim_event_deliveryrä   f  s{   € ä" 3Ô'ØØ;>¿7¹7À6»?ÐN`Ò;`”C˜Ÿ™ Ó0Ò6°BÔ7Ðfh€MÙØØ�˜1œRŸY™Y›[˜M¨¬4¯:©:«<×+;Ñ+;Ð*<Ð=€HÜ0°ÀÔIˆ8ÐSÈtÐSr'   c           	     ó¨  — t        j                   «       }t        5  t        «       5 }|j                  d|| |t        f«      }|j
                  dk(  r-t        j                  d| t        «       	 ddd«       ddd«       y|j                  d|| |f«      }|j
                  dk(  cddd«       cddd«       S # 1 sw Y   nxY wddd«       y# 1 sw Y   yxY w)zØRelease a failed delivery claim so another consumer may retry. Attempts are
    counted at claim time; once the budget is exhausted the row converges to
    terminal ``dropped`` (only pending rows replay on restart).a	  UPDATE async_delegations SET delivery_state='dropped',
                      delivery_claim=NULL, delivery_claimed_at=NULL, updated_at=?
               WHERE delegation_id=? AND delivery_state='pending'
                 AND delivery_claim=? AND delivery_attempts>=?r¥   znAsync delegation %s exhausted its %d delivery attempts; marking terminally dropped (result remains queryable).NTzÖUPDATE async_delegations SET delivery_claim=NULL,
                      delivery_claimed_at=NULL, updated_at=?
               WHERE delegation_id=? AND delivery_state='pending'
                 AND delivery_claim=?)rd   rk   rE   rl   Ú_MAX_DELIVERY_ATTEMPTSrÏ   r�   rŽ   )r^   r×   rq   r;   ÚcappedrØ   s         r(   Úrelease_completion_deliveryrè   q  sÖ   € ô �)‰)‹+€CÜ	ñ !”<“>ð ! TØ—‘ð Bð �- Ô+AÐBó	Dˆð
 �?‰?˜aÒÜ�N‰Nð Tà(Ô*@ôBð ÷!÷ !ð !ð �l‰lð )ð ,/°¸xÐ*HóJˆð �|‰|˜qÑ ÷!÷ !÷ !ó !ú÷ !÷ !ñ !ús/   ›C¦AB3Á,CÁ=#B3Â 	CÂ3B<	Â8CÃCc                óD   — t        dt        j                  «       | |f«      S )zOReturn an unadmitted completion to pending without spending a delivery attempt.zþUPDATE async_delegations SET delivery_claim=NULL,
                  delivery_claimed_at=NULL, delivery_attempts=MAX(0, delivery_attempts-1),
                  updated_at=?
           WHERE delegation_id=? AND delivery_state='pending' AND delivery_claim=?©rÒ   rd   ©r^   r×   s     r(   Údefer_completion_deliveryrì   ˆ  s'   € äð Vô 
�‰‹�m XÐ.ó	0ð 0r'   c                óD   — t        dt        j                  «       | |f«      S )u8  Terminally drop a claimed completion whose target is permanently gone (the
    spawning session ended at an explicit user boundary such as /new or reset).
    ``dropped`` â€” not ``delivered`` â€” keeps the ack honest; not ``pending`` keeps
    restart recovery from replaying it into a fail-closed drop forever.zöUPDATE async_delegations SET delivery_state='dropped',
                  updated_at=?, delivery_claim=NULL,
                  delivery_claimed_at=NULL
           WHERE delegation_id=? AND delivery_state='pending'
             AND delivery_claim=?rê   rë   s     r(   Údrop_completion_deliveryrî   ‘  s*   € ô
 ð %ô (,§y¡y£{°MÀ8Ð&Ló	Nð Nr'   c                óJ   — t        j                   «       }t        d||| |f«      S )z;Acknowledge acceptance for the consumer holding this claim.a  UPDATE async_delegations SET delivery_state='delivered',
                  delivered_at=?, updated_at=?, delivery_claim=NULL,
                  delivery_claimed_at=NULL
           WHERE delegation_id=? AND delivery_state='pending'
             AND delivery_claim=?rÔ   )r^   r×   rq   s      r(   Úcomplete_completion_deliveryrð   �  s/   € ä
�)‰)‹+€CÜð %ð (+¨C°ÀÐ&Ió	Kð Kr'   c                ó&   — t        t        | |«       y ©N)Ú_event_deliveryrð   ©rÌ   r×   s     r(   Úcomplete_event_deliveryrõ   §  s   € ÜÔ0°#°xÕ@r'   c                ó&   — t        t        | |«       y rò   )ró   rè   rô   s     r(   Úrelease_event_deliveryr÷   «  s   € ÜÔ/°°hÕ?r'   c                ó~   — |r;|j                  d«      dk(  r& | t        |j                  d«      xs d«      |«       y y y )Nr®   r¯   r^   rJ   ©rh   rß   )ÚfnrÌ   r×   s      r(   ró   ró   ¯  s9   € Ù�C—G‘G˜F“OÐ'9Ò9Ù
Œ3ˆs�w‰w�Ó'Ò-¨2Ó.°Õ9ð :€xr'   c           
     óD  — t         5  t        «       5 }|j                  d| f«      j                  «       }d d d «       d d d «       €d S | |d   |d   |d   |d   |d   rt	        j
                  |d   «      nd |d   |d   |d	   xs d
dœ	S # 1 sw Y   ŒWxY w# 1 sw Y   Œ[xY w)NzäSELECT origin_session, state, dispatched_at, completed_at,
                      result_json, delivery_state, delivery_attempts,
                      origin_session_id
               FROM async_delegations WHERE delegation_id=?r   r¥   é   r   é   é   é   é   rJ   )	r^   Úorigin_sessionÚstaterb   r�   rƒ   Údelivery_stateÚdelivery_attemptsrc   )rk   rE   rl   rx   rm   r‹   )r^   r;   r�   s      r(   Úget_durable_delegationr  ´  sÖ   € Ü	ñ ]”<“>ð ] TØ�l‰lð ?ð BOÐ@PóR÷ S[ÑRZÓR\ð 	÷]÷ ]ð
 �;ˆ4ð HØ&¸#¸a¹&È3ÈqÉ6ÐdgÐhiÑdjØ˜A™ÀÀAÂ¬$¯*©*°S¸±VÔ*<ÈDÐdgÐhiÑdjØ  ™V¸#¸a¹&º,ÀBñ%Hð H÷]ð ]ú÷ ]ð ]ús!   ‡B’"B
´BÂ
B	ÂBÂBc                óž   — t         5  t        €t        | d¬«      a| an| t        kD  r| t        _        | at        cddd«       S # 1 sw Y   yxY w)z¨Lazily create (or grow in place, never shrink) the shared daemon executor. Raising
    ``_max_workers`` is enough: the next ``submit`` spawns threads up to the new cap.Nzasync-delegate)Úmax_workersÚthread_name_prefix)Ú_executor_lockr   r   r   Ú_max_workers)r  s    r(   Ú_get_executorr  Á  sO   € ô 
ñ ÜÐÜ0¸[Ð]mÔnˆIØ$/Ñ!ØÔ0Ò0Ø%0ŒIÔ"Ø$/Ð!Ü÷÷ ò ús   ‡2AÁAc                 ó‚   — t         5  t        d„ t        j                  «       D «       «      cddd«       S # 1 sw Y   yxY w)zfNumber of live async delegation UNITS (one per completion message: a task group or an ungrouped task).c              3  óP   K  — | ]  }|j                  d «      t        v sŒd–— Œ  y­w©r   r¥   N©rh   Ú_LIVE_STATESr§   s     r(   r©   zactive_count.<locals>.<genexpr>Ò  s   è ø€ ÒS˜°1·5±5¸³?ÄlÒ3R”1ÑSùó   ‚&Ÿ&N©Ú_records_lockr²   r   Úvaluesr&   r'   r(   Úactive_countr  Ï  s3   € ä	ñ TÜÑSœhŸo™oÓ/ÔSÓS÷T÷ Tò Túó   ‡$5µ>c                 ó‚   — t         5  t        d„ t        j                  «       D «       «      cddd«       S # 1 sw Y   yxY w)u›   Number of running child subagents (a batch of N contributes N; a batch with
    no goal list counts 1) â€” the truthful observability figure, unlike slots.c              3  óþ   K  — | ]u  }|j                  d «      dv r`|j                  d«      rKt        |j                  d«      t        t        f«      r&|d   r!t	        |j                  d«      xs |d   «      nd–— Œw y­w)r   >   r   r   rZ   rU   r[   r¥   N)rh   r—   r˜   Útuplerš   r§   s     r(   r©   z$active_task_count.<locals>.<genexpr>Ù  sx   è ø€ ò Xð ¨!¯%©%°«/Ð=VÑ*Vð �u‰u�ZÔ ¤Z°·±°g³ÄÄuÀÔ%NÐSTÐU\ÒS]ô �—‘�nÓ%Ò3¨¨7©Ô4ØcdóeñXùs   ‚A;A=Nr  r&   r'   r(   Úactive_task_countr  Õ  sA   € ô 
ñ XÜñ Xô —_‘_Ó&ôXó X÷X÷ Xò Xúr  c                ó2  ‡— d|fd|fd|ffD ��cg c]  \  }}|r||f‘Œ }}}|sg S t         5  t        j                  «       D �‡cg c],  Š‰j                  d«      | v sŒt	        ˆfd„|D «       «      r‰‘Œ. c}cddd«       S c c}}w c c}w # 1 sw Y   yxY w)uJ  Records in ``statuses`` owned by a session: any non-empty selector claims the
    record â€” ``origin_ui_session_id`` (TUI tab), ``session_key`` (routing key at
    dispatch), or ``parent_session_id`` (spawner's durable id â€” the right one for
    gateway chats, whose session_key survives ``/new`` while the session id rotates).r`   r_   ra   r   c              3  óf   •K  — | ](  \  }}t        ‰j                  |«      xs d «      |k(  –— Œ* y­w)rJ   N)rß   rh   )r¨   ÚfieldÚwantedr‘   s      €r(   r©   z#_session_records.<locals>.<genexpr>ë  s,   øè ø€ ÒY¹m¸eÀVœ˜AŸE™E %›LÒ.¨BÓ/°6Õ9ÑYùs   ƒ.1N)r  r   r  rh   Úany)Ústatusesr_   r`   ra   r  r  Ú	selectorsr‘   s          `r(   Ú_session_recordsr"  ß  s¹   ø€ ð 
 Ð!5Ð6¸ÈÐ8TØ	Ð/Ð0ð72÷ =¡] U¨Fá5;ð ˜’ð =€Iñ =ñ Øˆ	Ü	ñ [Ü#Ÿ?™?Ó,÷ [�a°·±°h³À8Ò0KÜÓYÈyÔYÔYò ò [÷[ñ [ùó=ùò[÷[ð [ús(   �B­BÁBÁBÁ6BÂBÂBrJ   c                ó8   — t        t        t        | ||«      «      S )zOWhether a session still owns any live (running/stalling/finalizing) delegation.)r´   r"  r  )r_   r`   ra   s      r(   Úhas_live_for_sessionr$  î  s   € äÔ ¤¨{Ð<PÐRcÓdÓeÐer'   c                 óJ   — dt        j                  «       j                  d d › �S )NÚdeleg_r   )rà   rá   râ   r&   r'   r(   Ú_new_delegation_idr'  ó  s#   € Ø”D—J‘J“L×$Ñ$ R aÐ(Ð)Ð*Ð*r'   c                 ó0  — t         j                  «       D � �cg c]!  \  } }|j                  d«      t        vsŒ| |f‘Œ# }} }|j	                  d„ ¬«       |dt        dt        |«      t        z
  «       D ]  \  } }t         j                  | d«       Œ yc c}} w )zøDrop the oldest completed records beyond the cap. Caller holds ``_records_lock``.
    ``stalling``/``finalizing`` are still live: evicting one makes the late runner return hit
    ``_finalize``'s missing-record path and silently drop a real result.r   c                ó^   — | d   j                  d«      xs | d   j                  d«      xs dS )Nr¥   r�   rb   r   r¦   )Úkvs    r(   ú<lambda>z)_prune_completed_locked.<locals>.<lambda>ü  s+   €  " Q¡%§)¡)¨NÓ";Ò"^¸rÀ!¹u¿y¹yÈÓ?YÒ"^Ð]^€ r'   )rs   Nr   )	r   Úitemsrh   r  ÚsortÚmaxrš   ry   Úpop)Úridr‘   r€   Ú_s       r(   Ú_prune_completed_lockedr2  ÷  s…   € ô )1¯©Ó(8×`™f˜c 1¸A¿E¹EÀ(»OÔS_Ò<_�#�q’Ð`€IÑ`Ø‡N�NÑ^€NÔ_ØÐNœc !¤S¨£^Ô6MÑ%MÓNÐOò  ‰ˆˆQÜ�‰�S˜$Õñ ùó as
   ˜B¸Bc                 óh   — 	 ddl m}   | dd«      dk(  }|r | dd«      xs dS dS # t        $ r Y yw xY w)aÆ  Raw session id of the ORIGINATING api_server request, or ``""``. ``HERMES_SESSION_ID``
    is unsafe here: building the child agent calls ``set_current_session_id(child.session_id)``
    just before dispatch, so the wake would self-post into the subagent's own session. The
    request-scoped ``HERMES_SESSION_CHAT_ID`` (raw X-Hermes-Session-Id on api_server) survives
    child construction; on push platforms chat_id is a chat, not a session => ``""``.r   rG   ÚHERMES_SESSION_PLATFORMrJ   Ú
api_serverÚHERMES_SESSION_CHAT_ID)rK   rH   rN   )rH   Úis_apis     r(   Ú_current_origin_session_idr8    sI   € ðÝ;Ù Ð!:¸BÓ?À<ÑOˆÙHN‘Ð 8¸"Ó=ÒCÀÐVÐTVÐVøÜò Ùðús   ‚ % £% ¥	1°1c                ó   — dd | d|dœS )Nr–   r   )r   r•   r–   Ú	api_callsÚduration_secondsr&   ©r–   Údurations     r(   Ú_single_crashr>    s   € Ø¨$¸ÈQÐdlÑmÐmr'   c                ó   — g | |dœS )N)r‡   r–   Útotal_duration_secondsr&   r<  s     r(   Ú_batch_crashrA    s   € Ø EÀXÑNÐNr'   c                óf   ‡— | j                  d«      xs g }dŠ|rt        ˆfd„|D «       «      rdS dS )zCBatch status: completed unless every child errored/was interrupted.r‡   )r€   Úsuccessc              3  óD   •K  — | ]  }|j                  d «      ‰v–— Œ y­w)r   Nr¦   )r¨   r‘   Úoks     €r(   r©   z _batch_status.<locals>.<genexpr>  s   øè ø€ Ò+]È!¨A¯E©E°(«OÀ2Ô,EÑ+]ùs   ƒ r–   r€   )rh   Úall)ÚcombinedÚchild_resultsrE  s     @r(   Ú_batch_statusrI    s6   ø€ à—L‘L Ó+Ò1¨r€MØ	!€BÙ#¬Ó+]È}Ô+]Ô(]ˆ7ÐnÐcnÐnr'   c                 ó�   — ddl m} |j                  «       5 }|sdddœcd d d «       S t        di | ¤Žcd d d «       S # 1 sw Y   y xY w)Nr   ©Ú
retirementÚrejectedz*backend is retiring; reconnect to continue©r   r–   r&   )Úhermes_cli.backend_retirementrL  ÚworkÚ_dispatch_admitted)ÚkwargsrL  Úadmitteds      r(   Ú	_dispatchrT    sI   € Ý8à	�‰Ó	ð ,˜hÙØ(Ð3_Ñ`÷,ñ ,ô "Ñ+ FÑ+÷,÷ ,ò ,ús   —<¨
<¼A)Úslot_keyr[   r\   c           
     óx  ‡ ‡	‡‡‡‡ ‡!— |du}|rdndŠ |rt         nd„ Š|rt        nt        Št        j                  «       Š‰ |dœ|rdt	        |«      ini ¥||rt	        |«      nd||||
||dœ¥t        «       ¥d‰d|d	œ¥|rd
dini ¥||xs ‰ dœ¥|rdt        |«      ini ¥|�dt	        |«      ini ¥t        j                  «       d‰ddœ¥}t        5  t        j                  «       D �ch c]2  }|j                  d«      t        v sŒ|j                  d«      xs |d   ’Œ4 }}|d   |vrt        |«      |k\  rd|dœcddd«       S |t        ‰ <   t        d„ t        j                  «       D «       «      }ddd«       t!        |«       t#        t%        |«      «      }dˆˆˆ ˆˆ ˆ	fd„}ddlmŠ! ‰!j+                  «        	 |j-                  t/        |«      «      }|j1                  ˆ!fd„«       |�
t?        «        d‰ dœS c c}w # 1 sw Y   Œ�xY w# t2        $ r¦}‰!j5                  «        t        5  t        j7                  ‰ d«       ddd«       n# 1 sw Y   nxY wt8        5  t;        «       5 }|j=                  d‰ f«       ddd«       n# 1 sw Y   nxY wddd«       n# 1 sw Y   nxY wdd‰ › d|› �dœcY d}~S d}~ww xY w) a0  Shared dispatch core for single (``goals is None``) and batch units. Capacity check +
    record insert happen under ONE lock hold so concurrent dispatches can't both pass the check
    and exceed the cap. At capacity the dispatch is REJECTED (never queued) so a runaway model
    can't pile up unbounded background work. ``slot_key`` names the pool slot the unit occupies
    (default: its own id); the units of one delegate_task call share the first unit's id so
    splitting a call into per-group completions never consumes more capacity than the call did.Nú batchrJ   c                ó,   — | j                  d«      xs dS )Nr   r€   r¦   )r‘   s    r(   r+  z$_dispatch_admitted.<locals>.<lambda>9  s   € ¸¿¹¸x»Ò9WÈK€ r'   )r^   rT   rU   )rV   rW   rX   rY   r_   r`   rc   ra   r   )r   rb   r�   Úinterrupt_fnrZ   T)Úprogress_fnrU  r\   r[   )Ú_contextÚ_progress_tokenÚ_progress_tsÚ_interrupted_atr   rU  r^   rM  rN  c              3  óP   K  — | ]  }|j                  d «      t        v sŒd–— Œ  y­wr  r  r§   s     r(   r©   z%_dispatch_admitted.<locals>.<genexpr>R  s   è ø€ ÒY˜q¸¿¹¸x»ÌLÒ9XœÑYùr  c                 ó  •— i } d}t         5  t        j                  ‰«      }|�%|j                  dt	        j                  «       ¬«       d d d «       	  ‰	«       xs i }  ‰| «      }t        ‰| |«       y # 1 sw Y   Œ+xY w# t
        $ rd}t        j                  d‰› d�‰«        ‰t        |«      j                  › d|› �t        t	        j                  «       ‰z
  d«      «      } Y d }~Œ‚d }~ww xY w# t        ‰| |«       w xY w)Nr–   T)Ú_startedr]  úAsync delegationz %s crashedú: rü   )r  r   rh   Úupdaterd   rN   r�   Ú	exceptionr®   Ú__name__ÚroundÚ	_finalize)
rƒ   r   ÚrecÚexcÚclassifyÚcrash_resultr^   rb   ÚlabelÚrunners
       €€€€€€r(   Ú_workerz#_dispatch_admitted.<locals>._workerX  sì   ø€ Ø!#ˆØˆÜñ 	DÜ—,‘,˜}Ó-ˆCØˆà—
‘
 D´t·y±y³{�
ÔC÷		Dð
	5Ù“X’^ ˆFÙ˜fÓ%ˆFô
 �m V¨VÕ4÷	Dð 	Dûô ò 	iÜ×ÑÐ/°¨w°kÐBÀMÔRÙ!¤T¨#£Y×%7Ñ%7Ð$8¸¸3¸%Ð"@Ä%ÌÏ	É	ËÐVcÑHcÐefÓBgÓh�Fûð	iûô �m V¨VÕ4ús6   Œ=A3ÁA? Á3A<Á?	C,ÂAC'Ã"C/ Ã'C,Ã,C/ Ã/C>r   rK  c                ó$   •— ‰j                  «       S rò   )Úrelease)r1  rL  s    €r(   r+  z$_dispatch_admitted.<locals>.<lambda>p  s   ø€ ¨:×+=Ñ+=Ó+?€ r'   z3DELETE FROM async_delegations WHERE delegation_id=?z#Failed to schedule async delegationrc  Ú
dispatched)r   r^   ©ÚreturnÚNone) rI  rA  r>  rd   r˜   rQ   rÇ   ÚcontextvarsÚcopy_contextr  r   r  rh   Ú_ACTIVE_STATESrš   r²   ru   r  r.  rO  rL  ÚacquireÚsubmitr   Úadd_done_callbackrN   rq  r/  rk   rE   rl   Ú_ensure_stale_monitor)"r^   rT   rU   rV   rW   rX   rY   r_   ra   rn  r`   rc   rY  Úmax_async_childrenrZ  Úcapacity_errorrU  r[   r\   rZ   rp   r‘   Úactive_slotsÚ
live_unitsÚexecutorro  Úfuturerj  r;   rk  rl  rb   rm  rL  s"   `        `                   @@@@@r(   rQ  rQ  (  s  þ€ ð ˜DÐ €HÙ ‰H b€EÙ (�}Ñ/W€HÙ#+•<´€LÜ—I‘I“K€Mà&°ñYÙS[¸'Ä4ÈÃ;Ñ9OÐacðYà¹(¬¨X¬ÈÐVZÐejØ"Ð<PØ.ÐEVò	Yô
 "Ó
#ðYð ¨mÈTØ$òYñ @H¨*°dÑ);ÈRðYð bmØÒ- òYñ <LÐ¤Ð%5Ó 6Ñ7ÐQSðYð 4@Ð3KˆNœD Ó.Ñ/ÐQSðYô  ×,Ñ,Ó.à°ÐSWò!Y€Fô" 
ñ ZÜIQÏÉÓIZö  AÀAÐ^_×^cÑ^cÐdlÓ^mÔqÒ^˜Ÿ™˜jÓ)Ò?¨Q¨Ñ-?Ñ?ð  Aˆð  AØ�*Ñ \Ñ1´c¸,Ó6GÐK]Ò6]Ø(°>ÑB÷Zñ Zð #)Œ�ÑÜÑY¤H§O¡OÓ$5ÔYÓYˆ
÷Zô �fÔô œSÐ!3°ZÓ@ÓA€H÷5ò 5õ" 9ð ×ÑÔð	eØ—‘Ô!<¸WÓ!EÓFˆØ× Ñ Ó!?Ô@ð ÐÜÔØ"°]ÑCÐCùòY A÷Zð ZûôH ò eØ×ÑÔÜñ 	.Ü�L‰L˜¨Ô-÷	.÷ 	.ñ 	.úäñ 	b”|“~ð 	b¨Ø�L‰LÐNÐQ^ÐP`Ôa÷	b÷ 	bñ 	bú÷ 	b÷ 	bñ 	búà$Ð1TÐUZÐT[Ð[]Ð^aÐ]bÐ/cÑdÕdûðeús�   ÃG>Ã'G9ÄG9ÄG>Å-G>Æ:.H
 Ç9G>Ç>HÈ
	J9ÈJ4È)I	É 	J4É	I	ÉJ4ÉJÉ&JÉ:	JÊJÊJÊ	J4ÊJ!	ÊJ4Ê.J9Ê4J9)ra   r`   rc   rY  r}  rZ  c                óê   — t        «       }t        di d|“d| “dd“d|“d|“d|“d|“d	|“d
|“d|“d|“d|	“d|
“d|“d|“dd|› d�“Ž}|d   dk(  r#t        j                  d||xs d| xs ddd «       |S )a°  Spawn ``runner`` on the daemon executor and return a handle immediately.
    ``session_key``/``parent_session_id`` are captured on the parent thread (the worker carries
    no contextvars) and route the completion back to the spawning session.
    ``progress_fn() -> (token, in_tool)`` enables stale monitoring; omitted = unmonitored.
    Returns ``{"status": "dispatched", "delegation_id"}`` or ``{"status": "rejected", "error"}``.r^   rT   rU   NrV   rW   rX   rY   r_   ra   rn  r`   rc   rY  r}  rZ  r~  ú#Async delegation capacity reached (zà running). Wait for one to finish (its result will re-enter the chat), or run this task synchronously (background=false). Raise delegation.max_concurrent_children in config.yaml to allow more concurrent background subagents.r   rr  z3Dispatched async delegation %s (session_key=%s): %sú<cli>rJ   éP   r&   )r'  rT  r�   Úinfo)rT   rV   rW   rX   rY   r_   ra   rn  r`   rc   rY  r}  rZ  r^   Úhandles                  r(   Údispatch_async_delegationr‰  }  s
  € ô 'Ó(€MÜò 	wÙ#ð	wÙ*.ð	wÙ6:ð	wÙDKð	wáð	wá $ð	wá,1ð	wá?Jð	wñ ,ð	wñ 5;ð	wñ 2ð		wñ FWð		wñ
 "ð	wñ
 7Ið	wñ
 Wbð	wð 2Ð2DÐ1Eð Fuñ uð	w€Fð ˆhÑ˜<Ò'Ü�‰ÐIØ! ;Ò#9°'¸DºJÀBÈÈÐ;Lô	Nà€Mr'   )
ra   r`   rc   rY  r}  r^   rZ  rU  r[   r\   c                ó¦  — |xs
 t        «       }|�|D �cg c]  }| |   ‘Œ	 c}n
t        | «      }t        |«      }|dk(  r|d   n|› d�dj                  d„ |D «       «      z   }t	        di d|“d|“d| “d	|“d
|“d|“d|“d|“d|“d|“d|“d|	“d|
“d|“d|“d|“d|“d|“dd|› d�“Ž}|d   dk(  rt
        j                  d|||xs d«       |S c c}w ) u©  Dispatch a fan-out unit (a whole batch, or one ``group`` of a delegate_task call) as ONE
    background unit: ``runner`` runs its tasks and returns the combined ``{"results": [...],
    "total_duration_seconds": N}`` dict. The unit occupies ONE async slot â€” or joins the slot named
    by ``slot_key`` (in-unit parallelism is bounded separately) â€” and produces a SINGLE completion
    event carrying per-task ``results``.r¥   r   z parallel subagents: z; c              3  ó&   K  — | ]	  }|d d –— Œ y ­w)Né(   r&   )r¨   Úgs     r(   r©   z2dispatch_async_delegation_batch.<locals>.<genexpr>«  s   è ø€ ÒXtÐdeÐYZÐ[^Ð\^ÔY_ÑXtùs   ‚r^   rT   rU   rV   rW   rX   rY   r_   ra   rn  r`   rc   rY  r}  rZ  rU  r[   r\   r~  r„  z¬ running). Wait for one to finish (its result will re-enter the chat), or raise delegation.max_concurrent_children in config.yaml to allow more concurrent background units.r   rr  zADispatched async delegation batch %s (%d task(s), session_key=%s)r…  r&   )r'  r˜   rš   ÚjoinrT  r�   r‡  )rU   rV   rW   rX   rY   r_   ra   rn  r`   rc   rY  r}  r^   rZ  rU  r[   r\   rŸ   Ú
unit_goalsÚnÚcombined_goalrˆ  s                         r(   Údispatch_async_delegation_batchr’  ™  s†  € ð "Ò9Ô%7Ó%9€Mà5AÐ5M LÖ1˜q�%˜“(Ó1ÔSWÐX]ÓS^€JÜˆJ‹€AØ%&¨!¢V�J˜q’M°A°3Ð6KÐ1LÈtÏyÉyÑXtÐisÔXtÓOtÑ1t€MÜò 
GÙ#ð
GÙ*7ð
GÙ?Dð
GÙNUð
Gáð
Gá $ð
Gá,1ð
Gá?Jð
Gñ ,ð
Gñ 5;ð
Gñ 2ð	
Gñ FWð	
Gñ
 "ð
Gñ
 7Ið
Gñ
 Wbð
Gñ
 muð
Gñ "ð
Gñ 5Eð
Gð 2Ð2DÐ1Eð FEñ Eð
G€Fð ˆhÑ˜<Ò'Ü�‰ÐWØ! 1 kÒ&<°Wô	>à€Mùò# 2s   •Cc                ó¾  — t         5  t        j                  | «      }|�|j                  d«      t        vr
	 ddd«       yd|d<   t	        j                  «       |d<   d|d<   d|d<   t        |«      }ddd«       t        t        |«      r ||«      n||«       t         5  | t        v r|t        |    d<   t        «        ddd«       y# 1 sw Y   ŒWxY w# 1 sw Y   yxY w)aË  Atomically claim terminal delivery, push the completion event, then mark ``status``.
    ``result`` is a dict or a callable receiving the record snapshot (stall path). The record
    stays active ("finalizing") until durable persistence and queue publication finish; otherwise
    process shutdown can kill this daemon worker after status flips but before SQLite commits.
    A second call for the same id (late runner return after a forced stall) is a no-op.Nr   r   r�   rY  rZ  )	r  r   rh   rx  rd   rÇ   Ú_push_completion_eventÚcallabler2  )r^   rƒ   r   rp   Úsnapshots        r(   rh  rh  ¾  sÜ   € ô 
ñ  Ü—‘˜mÓ,ˆØˆ>˜VŸZ™Z¨Ó1¼ÑGØ÷ ð  ð (ˆˆxÑÜ!%§¡£ˆˆ~ÑØ!%ˆˆ~ÑØ $ˆˆ}ÑÜ˜“<ˆ÷ ô ˜8¼À&Ô9I¡V¨HÔ%5ÈvÐW]Ô^Ü	ñ "ØœHÑ$Ø06ŒH�]Ñ# HÑ-ÜÔ!÷"ð "÷ ð  ú÷"ð "ús   ‡0CÁ 1CÂCÃCÃCc           
     óÞ  — t        | j                  d«      «      }|rdnd}	 ddlm} | j                  d
«      xs t        j                  «       }| j                  d«      xs t        j                  «       }|rcd|j                  d«      xs g |j                  d«      |j                  d«      |j                  d«      dœ|j                  d«      �d|d   ini ¥}	nR|j                  d«      |j                  d«      |j                  dd«      |j                  dt        ||z
  d«      «      dœ}	d| j                  d«      | j                  dd«      | j                  dd«      | j                  dd«      | j                  d«      | j                  dd«      dœ|rd| j                  d«      ini ¥| j                  d «      | j                  d!«      | j                  d"«      |r| j                  d#«      n#|j                  d#«      xs | j                  d#«      |d$œ¥|	¥||d%œ¥|ri nd&|j                  d&«      i¥t        D �
ci c]  }
| j                  |
«      sŒ|
| |
   “Œ c}
¥t        D �
ci c]  }
|
|v sŒ|
||
   “Œ c}
¥}	 t        ||«       	 |j                  j                  |«       y	# t        $ r4}t
        j                  d|› d�| j                  d«      |«       Y d	}~y	d	}~ww xY wc c}
w c c}
w # t        $ r4}t
        j                  d|› d'�| j                  d«      |«       Y d	}~ŒŸd	}~ww xY w# t        $ r4}t
        j                  d|› d(�| j                  d«      |«       Y d	}~y	d	}~ww xY w))ag  Push a type='async_delegation' event onto the shared completion queue. Batch records
    (``is_batch``) carry the per-task ``results`` list (plus live transcript paths, the
    full-fidelity record of each child's run) instead of a single summary. Best-effort: failure
    must not crash the worker, but it WOULD mean a silently-lost result, so we log loudly.rZ   rW  rJ   r   ©Úprocess_registryrb  z@ %s finished but process_registry import failed; result lost: %sr^   Nrb   r�   Tr‡   Úlive_transcriptsr–   r@  )rZ   r‡   rš  r–   r@  Úgroupr•   r:  r;  rü   )r•   r–   r:  r;  r¯   r_   r`   rc   ra   rT   )r®   r^   r_   r`   rc   ra   rT   rU   rV   rW   rX   rY   )rV   rW   rX   rY   r   r°   Úexit_reasonzo %s: durable completion write failed; delivering in-memory only (a restart may report this unit as unknown): %sz8 %s: failed to enqueue completion event; result lost: %s)r´   rh   Útools.process_registryr™  rN   r�   r–   rd   rg  rL   Ú_STALL_META_KEYSr„   Úcompletion_queuerÈ   )rp   rƒ   r   rZ   rm  r™  rj  rb   r�   rÊ   rO   rÌ   s               r(   r”  r”  Ô  ss  € ô
 �F—J‘J˜zÓ*Ó+€HÙ ‰H b€EðÝ;ð
 —J‘J˜Ó/Ò>´4·9±9³;€MØ—:‘:˜nÓ-Ò<´·±³€LÙà¨¯©°IÓ)>Ò)DÀ"Ø &§
¡
Ð+=Ó >ÈÏÉÐT[ÓI\Ø&,§j¡jÐ1IÓ&JñWð .4¯Z©Z¸Ó-@Ð-L�˜ ™Ñ)ÐRTð	W‰ð —z‘z )Ó,°v·z±zÀ'Ó7JÐY_×YcÑYcÐdoÐqrÓYsØ &§
¡
Ð+=¼uÀ\ÐTaÑEaÐcdÓ?eÓ fñhˆð #°V·Z±ZÀÓ5Pà—z‘z -°Ó4Ø &§
¡
Ð+AÀ2Ó FØ#ŸZ™ZÐ(;¸RÓ@Ø#ŸZ™ZÐ(;Ó<Ø—
‘
˜6 2Ó&ñCñ NV¨G°V·Z±ZÀÓ5HÑ+IÐ[]ðCð —:‘:˜iÓ(°f·j±jÀÓ6LÐV\×V`ÑV`ÐagÓVhÙ(0�—‘˜GÔ$°v·z±zÀ'Ó7JÒ7aÈfÏjÉjÐY`ÓNaØòCð $ðCð 7DÐUaòCñ ‰2 ¨v¯z©z¸-Ó/HÐIðCô "/Ö
@˜A°&·*±*¸Qµ-ˆ1ˆf�Q‰i‰<Ò
@ðCô "2Ö
A˜A°Q¸&²[ˆ1ˆf�Q‰i‰<Ò
AðC€CðoÜ˜C Ô(ðJØ×)Ñ)×-Ñ-¨cÕ2øôI ò Ü�‰Ð'¨ wð /'ð 'Ø(.¯
©
°?Ó(CÀSô	Jäûðüò8 AùÚ
Aøô ò oÜ�‰Ð'¨ wð /Lð LØMSÏZÉZÐXgÓMhÐjm÷	oñ 	oûðoûô
 ò JÜ�‰Ð'¨ wð /'ð 'Ø(.¯
©
°?Ó(CÀS÷	Jñ 	JûðJús_   ¢J% È;K%ÉK%É%	K*É/K*É<K/ Ê	L/ Ê%	K"Ê.*KËK"Ë/	L,Ë8*L'Ì'L,Ì/	M,Ì8*M'Í'M,c               ó2  — t         5  t        j                  | «      }|�|j                  d«      t        vr
	 ddd«       yt	        |«      }ddd«       	 ddlm} i dd“dd	“d
d	“d|“d| “d|g“dj                  dd«      “d|j                  dd«      “d|j                  dd«      “d|j                  d«      “d|j                  dd«      “d|j                  d«      “d|j                  d«      “d|j                  d«      “d|j                  d«      “d|j                  d«      “dd“|j                  d«      xs t        j                  «       t        j                  «       dœ¥t        D �ci c]  }|j                  |«      sŒ|||   “Œ c}¥}	 |j                  j                  |«       y# 1 sw Y   �ŒdxY w# t        $ r!}t        j                  d| |«       Y d}~yd}~ww xY wc c}w # t        $ r!}t        j                  d| |«       Y d}~yd}~ww xY w)a–  Surface ONE failed child of a still-running detached batch to the parent now, instead of
    when the slowest sibling finishes. In a 1,393-agent run every wave-1 child died in a 401 storm
    at 08:29 and the parent learned of it at 09:36, when the batch's "unknown outcome" block finally
    arrived: 66 minutes of a dead wave with nothing running. The notice rides the same
    ``type="async_delegation"`` event shape as the batch result (so every drain/route/format path
    treats it identically) with ``task_failure_notice=True`` and a single-entry ``results`` list; the
    batch record is NOT finalized and its consolidated result still arrives as before.Nr   r   r˜  zTAsync delegation batch %s: task failure notice dropped (process_registry import): %sr®   r¯   rÛ   TrZ   Ún_tasksr^   r‡   r_   rJ   r`   rc   ra   rT   rU   rV   rW   rX   rY   r   rb   r°   zDAsync delegation batch %s: failed to enqueue task failure notice: %s)r  r   rh   rx  rÇ   r�  r™  rN   r�   r–   rd   rL   rŸ  rÈ   )	r^   r�   r¡  rp   r–  r™  rj  rO   rÌ   s	            r(   Úpush_task_failure_noticer¢    ss  € ô 
ñ  Ü—‘˜mÓ,ˆØˆ>˜VŸZ™Z¨Ó1¼ÑGØ÷ ð  ô ˜“<ˆ÷	 ð
Ý;ð
FØÐ"ð
FØ$9¸4ð
FØAKÈTð
FØS\Ð^eð
Fà˜ð
Fà(1°E°7ð
Fð 	�x—|‘| M°2Ó6ð
Fð 	 §¡Ð-CÀRÓ Hð	
Fð
 	˜XŸ\™\Ð*=¸rÓBð
Fð 	˜XŸ\™\Ð*=Ó>ð
Fð 	�—‘˜V RÓ(ð
Fð +2°8·<±<ÀÓ3Hð
Fð KTÐU]×UaÑUaÐbkÓUlð
Fð 	�H—L‘L Ó,ð
Fð /5°h·l±lÀ6Ó6Jð
Fð MTÐU]×UaÑUaÐbiÓUjð
Fð 	�)ð
Fð /7¯l©l¸?Ó.KÒ.ZÌtÏyÉyË{Ôlp×luÑluÓlwò
Fô $1Ö
D˜a°H·L±LÀµOˆ1ˆh�q‰k‰>Ò
Dð
F€CðqØ×)Ñ)×-Ñ-¨cÕ2÷- ñ  ûô ò Ü�‰ÐkÐmzÐ|ô  	AÜûðüò Eøô ò qÜ�‰Ð[Ð]jÐlo×pÑpûðqúsM   ‡0F-Á F-ÁF: Å-G'ÆG'ÆG, Æ-F7Æ:	G$ÇGÇG$Ç,	HÇ5HÈHc                 ó
  — t         5  t        �t        j                  «       r
	 ddd«       yt        j	                  «        t        j                  t        dd¬«      at        j                  «        ddd«       y# 1 sw Y   yxY w)zÌStart (once) the stale-delegation monitor thread. One daemon thread serves
    every dispatch; it exits when no monitorable records remain and is restarted
    by the next dispatch with a ``progress_fn``.Nzasync-delegate-stale-monitorT)ÚtargetÚnameÚdaemon)	Ú_monitor_lockr   Úis_aliveÚ_monitor_stopÚclearÚ	threadingÚThreadÚ_stale_monitor_loopÚstartr&   r'   r(   r|  r|  +  sn   € ô
 
ñ  ÜÐ&¬?×+CÑ+CÔ+EØ÷ ð  ô 	×ÑÔÜ#×*Ñ*Ü&Ð-KÐTXôZˆä×ÑÔ÷ ÷  ñ  ús   ‡A9¬AA9Á9Bc           
     óÂ  — g g d}}}t         j                  «       D �]  }|j                  d«      }|dk(  r6d}| |j                  d«      xs | z
  t        k\  r|j	                  |d   «       ŒP|j                  d«      }|dk7  s|€Œid}|j                  d	«      sŒ}	  |«       \  }}||j                  d
«      k7  r|j                  || ¬«       Œ°| |j                  d«      xs | z
  }	|rt        nt        }
|	|
k\  sŒÜ|j                  d| t        |	d«      |
t        |«      ¬«       |j	                  |d   |	|f«       �Œ |||fS # t
        $ r |j                  d
«      d}}Y Œºw xY w)a  One monitor pass over ``_records``; caller holds ``_records_lock``. Returns
    ``(stalled, expired, any_monitorable)``: newly-stalling ``(delegation_id, quiet_for, in_tool)``
    tuples, stalling ids past the grace window, and whether anything is left to monitor.Fr   r   Tr^  r^   rZ  r   ra  r\  )r\  r]  r]  rü   )r   r^  r!   r"   r#   )r   r  rh   Ú_STALL_GRACE_SECONDSrŒ   rN   rd  Ú_STALE_IN_TOOL_SECONDSÚ_STALE_IDLE_SECONDSrg  r´   )rq   ÚstalledÚexpiredÚany_monitorablerp   r   rZ  ÚtokenÚin_toolÚ	quiet_forÚlimits              r(   Ú_sweep_stale_lockedrº  9  s†  € ð )+¨B°�oˆW€GÜ—/‘/Ó#ó JˆØ—‘˜HÓ%ˆØ�ZÒØ"ˆOØ�f—j‘jÐ!2Ó3Ò:°sÑ;Ô?SÒSØ—‘˜v oÑ6Ô7ØØ—j‘j Ó/ˆØ�YÒ +Ð"5ØØˆØ�z‰z˜*Ô%Øð	BÙ(›]‰NˆE�7ð
 �F—J‘JÐ0Ó1Ò1Ø�M‰M¨%¸cˆMÔBØØ˜6Ÿ:™: nÓ5Ò<¸Ñ=ˆ	Ù*1Õ&Ô7JˆØ˜Óà�M‰MØ!°3ÌUÐS\Ð^_ÓM`Ø).¼tÀG»}ð ô Nð �N‰N˜F ?Ñ3°YÀÐHÖIð;Jð< �G˜_Ð,Ð,øô ò 	Bð $ŸZ™ZÐ(9Ó:¸E�7ŠEð	Bús   Â
D?Ä?EÅEc                óˆ   — t        | «      sy	  | «        y# t        $ r"}t        j                  |g|¢|‘­Ž  Y d}~yd}~ww xY w)zLInvoke an ``interrupt_fn``; True on success, else debug-log ``msg`` (+ exc).FTN)r•  rN   r�   Údebug)rú   ÚmsgÚargsrj  s       r(   Ú_call_interruptr¿  _  sB   € ä�BŒ<ØðÙ
ŒØøÜò Ü�‰�SÐ%˜4Ð% Ó%Üûðús   Ž –	AŸ<¼Ac                 óÚ  — t         j                  t        «      �s,t        j                  «       } t        5  t        | «      \  }}}ddd«       D ]g  \  }}}t        j                  d|||t        «       t        5  t        j                  |«      xs i j                  d«      }ddd«       t        d|«       Œi D ]j  }t        5  t        j                  |«      xs i j                  d«      xs t        j                  «       }ddd«       j                  t        ||fd„d«       Œl syt         j                  t        «      s�Œ+yy# 1 sw Y   �ŒxY w# 1 sw Y   Œ´xY w# 1 sw Y   Œ_xY w)aS  Sweep running delegations for stalled progress. A changed progress token refreshes the
    record's timestamp; a frozen token past the idle/in-tool threshold marks the record
    ``stalling`` and calls ``interrupt_fn``; a ``stalling`` record still unreturned after the
    grace window is force-finalized with a terminal ``stalled`` event.Nu`   Async delegation %s made no progress for %.0fs (in_tool=%s) â€” interrupting; grace window %.0fsrY  z.Async delegation %s stall interrupt failed: %sr[  c                ó   — t        || «      S rò   )Ú_stalled_result)ri  Úds     r(   r+  z%_stale_monitor_loop.<locals>.<lambda>~  s   € Ì?Ð[\Ð^aÓKb€ r'   r³  )r©  ÚwaitÚ_STALE_CHECK_INTERVALrd   r  rº  r�   rŽ   r°  r   rh   r¿  rv  rw  Úrunrh  )	rq   r³  r´  rµ  r^   r¸  r·  rú   Úctxs	            r(   r­  r­  k  sW  € ô
 × Ñ Ô!6Õ7Ü�i‰i‹kˆÜñ 	IÜ0CÀCÓ0HÑ-ˆG�W˜o÷	Ià18ò 	aÑ-ˆM˜9 gÜ�N‰Nð Oà(¨)°WÔ>RôTô ñ MÜ—l‘l =Ó1Ò7°R×<Ñ<¸^ÓL�÷Mä˜BÐ PÐR_Õ`ð	að %ò 	oˆMÜñ hÜ—|‘| MÓ2Ò8°b×=Ñ=¸jÓIÒgÌ[×MeÑMeÓMg�÷hà�G‰G”I˜}¸MÒ.bÐdmÕnð	oñ Øô! × Ñ Ô!6×7Ð7÷	Iñ 	Iú÷Mð Mú÷hð hús#   µEÁ9)EÃ?E!ÅEÅE	Å!E*	c                ó  — dj                  t        | j                  d«      xs d«      j                  «       «      }|r	d|dd › d�nd}t	        | j                  d	«      xs d
«      }|dk\  rdt        |dz  «      › d�nd}|› d|› d�S )u  Human wording for a force-finalized stall. This string reaches the user (CLI timeline, Desktop
    async-result card), so it names the task, how long it was silent, and what to do â€” no issue
    numbers or worker internals (those stay in the log line and the stall_* metadata).Ú rT   rJ   zBackground task "Néx   ú"zThe background taskr!   r   é<   z after z min of no progressz stopped respondingz[ and was cancelled. Nothing else was affected; ask me to run it again if you still need it.)rŽ  rß   rh   ÚsplitÚfloatrg  )Úevent_recordrT   rm  ÚquietÚsilences        r(   Ú_stalled_error_textrÒ  ƒ  s¢   € ð �8‰8”C˜×(Ñ(¨Ó0Ò6°BÓ7×=Ñ=Ó?Ó@€DÙ15Ð  T c 
˜|¨1Ñ-Ð;P€EÜ�,×"Ñ"Ð#9Ó:Ò?¸aÓ@€EØBGÈ2Â+�œ˜e b™jÓ)Ð*Ð*=Ñ>ÐSU€GØˆgÐ(¨¨	ð 2;ð ;ð <r'   c                óÈ  — |j                  d«      xs t        j                  «       }t        ||j                  d«      xs |z
  d«      }t        |«      }t        j                  d| |«       |j                  d«      }|j                  d«      |j                  d«      |rdn|�d
nd	t        dœ}|j                  d«      ri t        ||«      ¥|¥S i t        ||«      ¥dddœ¥|¥S )zPSynthetic terminal result for a stalling delegation whose runner never returned.r�   rb   rü   z:Async delegation %s force-finalized as stalled after %.0fsr#   r!   r"   r·  NÚidler   rZ   r³  )r   rœ  )	rh   rd   rg  rÒ  r�   r–   r°  rA  r>  )r^   rÏ  r�   r=  r–   r$   Ú
stall_metas          r(   rÂ  rÂ  �  sì   € à×#Ñ# NÓ3ÒB´t·y±y³{€LÜ�\ \×%5Ñ%5°oÓ%FÒ%VÈ,ÑWÐYZÓ[€HÜ Ó-€EÜ
‡L�LÐMÈ}Ð^fÔgð !×$Ñ$Ð%5Ó6€Mà'3×'7Ñ'7Ð8NÓ'OØ#/×#3Ñ#3Ð4NÓ#OÙ$1‘yÀÐAZ±vÐ`dÜ3ñ	5€Jð
 ×Ñ˜
Ô#Ø>”,˜u hÓ/Ð>°:Ð>Ð>ØjŒm˜E 8Ó,Ðj¸	ÐR[ÒjÐ_iÐjÐjr'   c                ó�  — 	 t        | «      }g }|D ]£  }t        |t         t        f«      rt	        |«      dk\  s|j                  d«       Œ9|d   |d   dœ}t	        |«      dk\  rAt        |d   t        t        f«      r(t        t        d|t        |d   «      z
  «      d«      |d<   |j                  |«       Œ¥ |S # t        $ r Y yw xY w)	zÛParse a progress token into per-child activity dicts (best-effort): delegate_tool
    emits one ``(api_call_count, current_tool, last_activity_ts)`` tuple per child;
    foreign token shapes degrade to ``None`` entries.Nrü   r   r¥   )r:  Úcurrent_toolr   g        Úseconds_since_activity)
r˜   Ú	TypeErrorr—   r  rš   rŒ   r   rÎ  rg  r.  )r¶  rq   ÚpartsÚoutÚpartr�   s         r(   Ú_children_activity_from_tokenrÝ  £  sÉ   € ðÜ�U“ˆð +-€CØò ˆÜ˜4¤$¬ Ô/´C¸³IÀ²NØ�J‰J�tÔØØ.2°1©gÀtÈAÁwÑ OˆÜˆt‹9˜Š>œj¨¨a©´3¼°,Ô?Ü.3´C¸¸SÄ5ÈÈaÉÃ>Ñ=QÓ4RÐTUÓ.VˆEÐ*Ñ+Ø�
‰
�5Õðð €Jøô ò Ùðús   ‚B9 Â9	CÃCc            	     óD  — t        j                   «       } i }t        5  g }t        j                  «       D ]é  }|j	                  «       D ��ci c]  \  }}|dvsŒ|j                  d«      rŒ||“Œ! }}}|j                  d«      }|t        v rK|j                  d«      rt        | |d   z
  d«      |d<   t        |j                  d«      «      r|d   ||d   <   |d	v r4t        D ]+  \  }}	|j                  |«      €Œ|j                  |«      ||	<   Œ- |j                  |«       Œë 	 d
d
d
«       D ]Q  }|j                  |j                  d«      «      }
|
€Œ&	  |
«       \  }}t        || «      }|�||d<   t        |«      |d<   ŒS |S c c}}w # 1 sw Y   ŒgxY w# t        $ r Y Œsw xY w)aI  Snapshot of async delegations (running + recently completed) without callables or private
    monitor bookkeeping; adds computed live fields for UIs (``seconds_since_progress``,
    ``children_activity``/``in_tool`` sampled from ``progress_fn``) and stall context once tripped.

    Safe to call from any thread. See #51690.
    >   rZ  rY  r1  r   r]  r¥   Úseconds_since_progressrZ  r^   )r   r³  NÚchildren_activityr·  )rd   r  r   r  r,  Ú
startswithrh   rx  rg  r•  Ú_STALL_FIELD_MAPrŒ   rN   rÝ  r´   )rq   Úsamplersr,  r‘   rO   rP   Úitemr   ÚsrcÚdstrú   r¶  r·  Úactivitys                 r(   Úlist_async_delegationsrè  ·  s·  € ô �)‰)‹+€CØ$&€HÜ	ñ ØˆÜ—‘Ó"ò 	ˆAØ%&§W¡W£Y×u™T˜Q °!Ð;ZÒ2ZÐcd×coÑcoÐpsÕct�A�q‘DÐuˆDÑuØ—U‘U˜8“_ˆFØœÑ'Ø—5‘5˜Ô(Ü5:¸3ÀÀ>ÑARÑ;RÐTUÓ5V�DÐ1Ñ2Ü˜AŸE™E -Ó0Ô1Ø34°]Ñ3C�H˜Q˜Ñ/Ñ0ØÐ0Ñ0Ü 0ò /‘H�C˜Ø—u‘u˜S“zÑ-Ø$%§E¡E¨#£J˜˜Sš	ð/ð �L‰L˜Õñ	÷ð" ò (ˆØ�\‰\˜$Ÿ(™( ?Ó3Ó4ˆØˆ:Øð	Ù›T‰NˆE�7ô 1°¸Ó<ˆØÐØ(0ˆDÐ$Ñ%Ü˜w›-ˆˆYŠð(ð €Lùó5 v÷ð ûô. ò 	Ùð	úsB   �-FÁ
F
ÁF
Á)F
Á.BFÃ7)FÅ
FÆFÆFÆ	FÆFc                ób   ‡— t        ˆfd„| D «       «      }|rt        j                  |||«       |S )zSCall ``interrupt_fn`` on each record; log ``msg`` once; returns how many succeeded.c           	   3  óv   •K  — | ]0  }t        |j                  d «      d‰|j                  d«      «      –— Œ2 y­w)rY  z%s: %s interrupt failed: %sr^   N)r¿  rh   )r¨   r‘   Úcallers     €r(   r©   z%_interrupt_records.<locals>.<genexpr>â  s;   øè ø€ ò àô 	˜Ÿ™˜nÓ-Ð/LÈfÐVW×V[ÑV[Ð\kÓVl×mñùs   ƒ69)r²   r�   r‡  )Útargetsrë  Úreasonr½  Úcounts    `   r(   Ú_interrupt_recordsrï  à  s4   ø€ äó àôó €Eñ Ü�‰�C˜ Ô'Ø€Lr'   c                óÐ   — t         5  t        j                  «       D �cg c]  }|j                  d«      t        v sŒ|‘Œ }}ddd«       t        d| d«      S c c}w # 1 sw Y   ŒxY w)z¼Signal every running async delegation to stop (``/stop``, shutdown). Returns how
    many. The child still emits a completion event (status='interrupted') via the
    normal finalize path.r   NÚinterrupt_allz'Interrupted %d async delegation(s) (%s))r  r   r  rh   rx  rï  )rí  r‘   rì  s      r(   rñ  rñ  ê  sa   € ô 
ñ VÜ&Ÿo™oÓ/ÖU˜°1·5±5¸³?ÄnÒ3T’1ÐUˆÐU÷Vä˜g ¸Ð@iÓjÐjùò V÷Vð Vús    ‡AžA»A¿AÁAÁA%c                óB   — t        t        | ||«      }t        |d|d«      S )zŒSignal running async delegations owned by ONE ending session to stop (any
    selector matches, see ``_session_records``). Returns how many.Úinterrupt_for_sessionz:Interrupted %d async delegation(s) for ending session (%s))r"  rx  rï  )r_   r`   ra   rí  rì  s        r(   ró  ró  ó  s0   € ô
 œ~¨{Ð<PÐRcÓd€GÜØÐ(¨&Ð2nópð pr'   c                 ó�  — t         5  t        �t        j                  d¬«       dadaddd«       t        j                  «        t        5  t        dc} addd«        �"| j                  «       r| j                  d¬«       t        5  t        j                  «        ddd«       y# 1 sw Y   Œ}xY w# 1 sw Y   Œ]xY w# 1 sw Y   yxY w)z@Test-only: clear all state and tear down the executor + monitor.NF)rÄ  r   rü   )Útimeout)r	  r   Úshutdownr   r©  Úsetr§  r   r¨  rŽ  r  r   rª  )Úthreads    r(   Ú_reset_for_testsrù  ý  s´   € ô 
ñ "ÜÐ Ü×Ñ EÐÔ*Øˆ	Ø !Ð÷	"ô
 ×ÑÔÜ	ñ 8Ü"1°4Ðˆ�÷8àÐ˜fŸo™oÔ/Ø�‰˜AˆÔÜ	ñ Ü�‰Ô÷ð ÷"ð "ú÷8ð 8ú÷ð ús#   ‡!B$Á

B0ÂB<Â$B-Â0B9Â<Cc                óŽ   ‡ — ‰ syt         5  t        ˆ fd„t        j                  «       D «       «      cddd«       S # 1 sw Y   yxY w)z9Number of live async delegations owned by one UI session.r   c              3  óŠ   •K  — | ]:  }|j                  d «      dv r%t        |j                  d«      xs d«      ‰k(  rd–— Œ< y­w)r   >   r   r   r   r`   rJ   r¥   Nrù   )r¨   r‘   r`   s     €r(   r©   z%active_for_session.<locals>.<genexpr>  sI   øè ø€ ò 
àØ�u‰u�X‹Ð"GÑGÜ�A—E‘EÐ0Ó1Ò7°RÓ8Ø#ò$ô ñ
ùs   ƒA ANr  )r`   s   `r(   Úactive_for_sessionrü    s=   ø€ áØÜ	ñ 
Üó 
ä—_‘_Ó&ô
ó 
÷
÷ 
ò 
ús	   ‹&;»A)rt  úsqlite3.Connection)r;   rý  rt  ru  )rt  úDict[str, Any])rp   rþ  rt  ru  rs  )r‚   rþ  rƒ   rþ  rt  ru  )r^   rß   r�   rþ  rt  ru  )r›   rþ  rœ   úOptional[str]r–   rß   rt  zOptional[List[Dict[str, Any]]])rt  r   )rÐ   rß   rÑ   r  rt  r´   )r^   rß   rt  r´   )r^   rß   r×   rß   rt  r´   )rÌ   rþ  rt  r´   )rÌ   rþ  rã   rß   rt  rÿ  )rÌ   rþ  r×   rß   rt  ru  )r^   rß   rt  zOptional[Dict[str, Any]])r  r   rt  r   )r_   rß   r`   rß   ra   rß   rt  r˜   )rJ   rJ   rJ   )r_   rß   r`   rß   ra   rß   rt  r´   )rt  rß   )r–   rß   r=  rÎ  rt  rþ  )rG  rþ  rt  rß   )(r^   rß   rT   rß   rU   úOptional[List[str]]rV   rÿ  rW   r   rX   rß   rY   rÿ  r_   rß   ra   rÿ  rn  úCallable[[], Dict[str, Any]]r`   rß   rc   rß   rY  úOptional[Callable[[], None]]r}  r   rZ  úOptional[Callable[[], tuple]]r~  rß   rU  rÿ  r[   úOptional[List[int]]r\   úOptional[Dict[str, str]]rt  rþ  )rT   rß   rV   rÿ  rW   r   rX   rß   rY   rÿ  r_   rß   ra   rÿ  rn  r  r`   rß   rc   rß   rY  r  r}  r   rZ  r  rt  rþ  )$rU   z	List[str]rV   rÿ  rW   r   rX   rß   rY   rÿ  r_   rß   ra   rÿ  rn  r  r`   rß   rc   rß   rY  r  r}  r   r^   rÿ  rZ  r  rU  rÿ  r[   r  r\   r  rt  rþ  )r^   rß   rƒ   r   r   rß   rt  ru  )rp   rþ  rƒ   rþ  r   rß   rt  ru  )r^   rß   r�   rþ  r¡  r   rt  ru  )rq   rÎ  )r½  rß   rt  r´   )rÏ  rþ  rt  rß   )r^   rß   rÏ  rþ  rt  rþ  )r¶  r   rq   rÎ  rt  zOptional[List])rt  úList[Dict[str, Any]])
rì  r  rë  rß   rí  rß   r½  rß   rt  r   )rö  )rí  rß   rt  r   )rJ   rJ   rJ   Úsession_end)
r_   rß   r`   rß   ra   rß   rí  rß   rt  r   )r`   rß   rt  r   )oÚ__doc__Ú
__future__r   rv  rm   Úloggingrf   Úsqlite3r«  rd   rà   Úconcurrent.futuresr   Útypingr   r   r   r   r	   Úhermes_constantsr   Útools.daemon_poolr   Útools.thread_contextr   Ú	getLoggerrf  r�   r   Ú__annotations__ÚLockr	  r   r  r   Ú_DEFAULT_MAX_ASYNC_CHILDRENry   rw   rz   ræ   rÆ   rk   rÅ  r²  r±  r°  r§  r   ÚEventr©  r  rx  rL   rž  râ  r)   r<   r9   rE   rQ   ru   ro   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  r8  r>  rA  rI  rT  rQ  r‰  r’  rh  r”  r¢  r|  rº  r¿  r­  rÒ  rÂ  rÝ  rè  rï  rñ  ró  rù  rü  r&   r'   r(   ú<module>r     sá  ðòhõ #ã Û Û Û 	Û Û Û Û Ý 1ß 6Õ 6å ,Ý 6Ý <à	ˆ×	Ñ	˜8Ó	$€ð
 +/€	Ð'Ó .Ø�—‘Ó!€ØÐ �sÓ à�	—‘Ó €à&(€Ð
#Ó (àÐ àÐ Ø-Ð ØÐ àÐ ð  +Ð Øˆ9�>‰>Ó€ð Ð ØÐ ØÐ ØÐ à�	—‘Ó €Ø.2€Ð+Ó 2Ø�	—‘Ó!€â4€Ø(€ð 5€àsÐ ðrÐ ò
*óó"!ò #óóó8Bó2MóIó(yó2ój%óP7ó`ó!ó ZóTó!ó.0ó	NóKóAó@ó:ó
	HóóTóXó[ôfó
+ó óónóOóoó,ð `dØ(,Ø15ñRDØðRDØ!$ðRDØ-@ðRDØKXðRDà!ðRDà),ðRDà5BðRDàQTðRDð %ðRDð /KðRDð cfðRDð ð	RDð +Gð	RDð ]`ð	RDð
 /ðRDð
 ADðRDð
 P]ðRDð &ðRDð /ðRDð óRDðn :>Ø "¸RÐnrØ9Ðhlñ	ØðØ(ðØ4GðØORðØ[hðàðà)6ðàGcðð ðð 8;ðð Plðð ð	ð Ifð	ð
 óð< :>Ø "¸RÐnrØ9ÐZ^Ø15ÐQUØ(,Ø15ñ!Øð!Ø"/ð!Ø;Nð!ØVYð!Øboð!àð!à)6ð!àGcð!ð ð!ð 8;ð!ð Plð!ð ð	!ð KXð	!ð
 /ð!ð
 BOð!ð &ð!ð /ð!ð ó!óJ"ó,0Jóf qóH ó#-óL	óó0	<ókó(ó(&óRôkð gtðpØðpØ14ðpØNQðpØ`cðpàópóô,
r'   