Ë
    ãß²jðl  ã                  óª  — 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mZm	Z
 ddlmZmZ ddlmZmZmZmZ ddlmZmZ ddlmZmZmZ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$  ejJ                  d«      Z&e G d„ d«      «       Z'd)d„Z(d*d„Z)d+d„Z*d,d„Z+d-d„Z,ddœd.d„Z-dddœZ.d/d„Z/d0d1d„Z0d2d„Z1d3d„Z2ddd d!d"œZ3d4d#„Z4d5d$„Z5d6d%„Z6d7d&„Z7d8d'„Z8d9d(„Z9y):uL  Batch execution + background dispatch for delegate_task: ``delegate_task`` builds a ``_Batch``
(children + origin identity) and hands it to ``_run_batch``, which runs it synchronously or as
detached async units â€” one per task ``group`` (ungrouped tasks are a unit each), so a finished
review does not wait for the slowest sibling.é    )ÚannotationsN)ÚFIRST_COMPLETEDÚwait)Ú	dataclassÚreplace)ÚAnyÚDictÚListÚOptional)Ú_new_delegation_idÚrecord_unit_child)Ú_attach_childÚ_detach_childÚ_fabricated_entryÚ_signal_child_stop)ÚSUBAGENT_FAILURE_STATUSESÚ_print_completion_lineÚ_quietÚdescribe_subagent_failureÚformat_batch_tag)Ú _capture_gateway_steer_authority)Ú_finalize_child_resultsztools.delegate_toolc                  óÞ   — e Zd ZU dZded<   ded<   ded<   ded	<   d
ed<   ded<   ded<   d
ed<   ded<   ded<   ded<   ded<   ded<   ded<   ded<   ded<   dZd
ed<   dZd
ed<   d!d„Zd"d „Zy)#Ú_Batchz¤One delegate_task call's built children plus everything needed to run them
    and assemble the combined result (shared by the sync path and the background runner).zList[Dict[str, Any]]Ú	task_listzList[tuple]Úchildrenr   Úparent_agentúDict[str, Any]ÚcredsúOptional[str]ÚcontextÚstrÚtop_roleÚintÚmax_childrenÚlive_deleg_idÚlistÚlive_writersÚ
live_pathsÚorigin_wake_sidÚorigin_ui_session_idÚorigin_owner_transportÚorigin_owner_session_recordÚboolÚorigin_session_history_deliveryÚfloatÚoverall_startNÚgroupÚunit_idc                óR   — | j                   xs d| j                  | j                  dœS )zKSteer/stop authority of the originating session, passed to every child run.N)Úowner_session_idÚowner_transportÚowner_session_record)r+   r,   r-   )Úselfs    úA/home/ubuntu/.hermes/hermes-agent/tools/delegate_tool_dispatch.pyÚowner_kwargsz_Batch.owner_kwargs4   s.   € ð !%× 9Ñ 9Ò A¸TÐVZ×VqÑVqØ$(×$DÑ$Dñ
ð 	
ó    c                ó^   — ddl m}  |d||d   || j                  dœ| j                  «       ¤ŽS )Nr   )Ú_run_single_childÚgoal)Ú
task_indexr>   Úchildr   © )Útools.delegate_toolr=   r   r:   )r8   ÚiÚtaskr@   r=   s        r9   Ú	run_childz_Batch.run_child;   sK   € Ý9Ù ð  F¨A°D¸±LÈÐ\`×\mÑ\mñ  FÐqu÷  rCñ  rCó  rEñ  Fð  	Fr;   )Úreturnr   )rC   r$   rD   r   r@   r   rF   r   )	Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú__annotations__r2   r3   r:   rE   rA   r;   r9   r   r      sˆ   … ñ]ð $Ó#ØÓØÓØÓØÓØƒMØÓØ Ó ØÓØÓØÓØÓØÓØ!$Ó$Ø%)Ó)ØÓà€Eˆ=ÓØ!€Gˆ]Ó!ó
ôFr;   r   c                óp   — |dkD  r1|r.dt        || «      › d|› d�}t        | t        | dd«      ||¬«       yyy)zPAnnounce the batch tag once so interleaved ``[tag n/N]`` lines are attributable.é   u     ðŸ”€ [z] delegating z tasksÚ_delegate_spinnerN)Úconsole_line)r   r   Úgetattr)r   Ún_tasksr&   Ú_hdrs       r9   Ú_announce_batchrS   @   sM   € à�‚{‘}ØÔ*¨=¸,ÓGÐHÈÐV]ÐU^Ð^dÐeˆÜ˜|¬W°\ÐCVÐX\Ó-]Ð_cÐrvÖwð %€{r;   c                 ó¸   — ddl m}   | «       }d}d}t        d«      5  ddlm}m}  |dd«      } |«       }ddd«       ||gt        |«      ¢|‘­S # 1 sw Y   ŒxY w)u   ``(wake_sid, ui_session_id, owner_transport, owner_session_record, session_history_delivery)`` of the
    ORIGINATING session, captured BEFORE building any child: AIAgent construction
    clobbers the HERMES_SESSION_ID ContextVar/os.environ with the subagent's id.  The wake-
    capability flag rides the same request-scoped binding and is captured here for the same
    reason â€” and fails closed: a binding that never declared it (or a read error) leaves the
    session treated as non-wake-capable (#98619).r   )Ú_current_origin_session_idÚ FN)Úget_session_envÚ"session_history_delivery_supportedÚHERMES_UI_SESSION_ID)Útools.async_delegationrU   r   Úgateway.session_contextrW   rX   r   )rU   Ú_origin_wake_sidÚ_origin_ui_session_idÚ _origin_session_history_deliveryrW   rX   s         r9   Ú_capture_originr_   F   s‡   € õ BÙ1Ó3ÐØÐØ',Ð$Ü	�‹ñ Pß_Ù /Ð0FÈÓ KÐÙ+MÓ+OÐ(÷Pð Ð3ð  QÔ6VÐWlÓ6mð  Qð  pPñ  Qð  Q÷	Pð Pús   �AÁAc           
     óh  — |d   }|t        |«      k  r||   nd|› �}|j                  dd«      }	|r|› d|dz   › d|› �n	|dz   › d|› �}
|j                  d«      d	u xr |	d
k(  }|rdn|	d
k(  rdnd}|› d|
› d|› d|j                  dd«      › d�}|	t        v r,t        |j                  d«      |j                  d«      d¬«      nd}|rd}|r|d|› �z  }t	        | ||«       |rF|dkD  r@t        d«      5  |j                  d|rd|z   dz   nd› |› d|dk7  rdnd› d �«       d!d!d!«       y!y!y!# 1 sw Y   y!xY w)"u·   Print one completion line for a finished child and refresh the spinner text. Failed/errored/timed-out children
    say WHY on the same line â€” a bare âœ— reads as "silently dropped".r?   zTask Ústatusú?u    Â· rM   ú/Úschema_validFÚ	completedu   âš u   âœ“u   âœ—z [z] z  (Úduration_secondsr   zs)Úfailure_reasonÚerroréx   )Ú	max_charsrV   uF   output_schema not satisfied â€” raw text returned (schema_valid=false)u    â€” zSpinner update_text failed: %su   ðŸ”€ ú[z taskÚsz
 remainingN)ÚlenÚgetr   r   r   r   Úupdate_text)r   Úspinner_refÚentryÚtagÚtask_labelsrQ   Ú	remainingÚidxÚlabelra   Ú_slotÚschema_invalidÚiconÚcompletion_lineÚ	_err_lines                  r9   Ú_report_child_doner|   W   s¥  € ð �Ñ
€CØ #¤c¨+Ó&6Ò 6ˆK˜Ò¸eÀCÀ5¸M€EØ�Y‰Y�x Ó%€FÙ-0ˆsˆe�4˜˜A™�w˜a ˜yÑ)¸¸Q¹¸¸qÀÀ	Ð6J€EØ—Y‘Y˜~Ó.°%Ð7ÒQ¸FÀkÑ<Q€NÙ"‰5°&¸KÒ2G©ÈU€DØ˜˜b   r¨%¨°°E·I±IÐ>PÐRSÓ4TÐ3UÐUWÐX€Oð Ô.Ñ.ô 	" %§)¡)Ð,<Ó"=¸u¿y¹yÈÓ?QÐ]`ÕaØ46ð ñ Ø\ˆ	ÙØ˜U 9 +Ð.Ñ.ˆÜ˜<¨°oÔFÙ�y 1’}ÜÐ4Ó5ñ 	HØ×#Ñ# eÁ¨C°#©I¸Ò,<ÈÐ+LÈYÈKÐW\ÐdmÐqrÒdrÑ]`ÐxzÐ\{ð  |Fð  %Gô  H÷	Hð 	Hð %€{÷	Hð 	Hús   Ã1,D(Ä(D1c                ór   — |s5| j                   r(t        |t        «      rt        | j                   |«       yyyy)u�  Detached (background) unit: durably record a child on the unit's own row the moment it finishes, so an owner
    death before the unit's join â€” or anywhere before its durable completion write, the whole remaining window for a
    one-child unit â€” loses only children still running, never finished work (#116000). Best-effort by construction:
    ``record_unit_child`` never raises into the join.N)r3   Ú
isinstanceÚdictr   )Úbatchrq   Úhonor_parent_interrupts      r9   Ú_record_finished_childr‚   m   s/   € ñ
 " e§m¢m¼
À5Ì$Ô8OÜ˜%Ÿ-™-¨Õ/ð 9P mÐ!r;   c               óÔ  ‡‡‡— ddl m} | j                  t        | j                  «      }}| j                  D �cg c]
  }|d   dd ‘Œ }}t        |dd«      }t        | j                  |«      }	| j                  D �
��ci c]	  \  }
}}|
|“Œ c}}}
Št        | j                  «      }ˆfd„Š || j                  ¬«      }d	}	 | j                  D �
��ci c]B  \  }
}}|j                  t        j                  «       j                  | j                  |
||«      |
“ŒD c}}}
Št        ‰«      }|�r_|r.t        |d
d	«      du r|j!                  ˆˆfd„|D «       «       d}�n/t#        |dt$        ¬«      \  }}|D �]  } ‰|‰|   «      }|j'                  |«       t)        | ||«       t+        ||||	|||t        |«      z
  «       |rŒN| j,                  sŒ[|j/                  d«      t0        v sŒst        |«      |k  sŒ‚t3        dd¬«      5  ddlm} |j/                  dd«      }t9        |t:        «      r0d|cxk  rt        | j<                  «      k  rn n| j<                  |   nd} || j,                  i |¥|rd|ini ¥|¬«       ddd«       �Œ |r�Œ_|j?                  | |¬«       |jA                  d„ ¬«       yc c}w c c}}}
w c c}}}
w # 1 sw Y   �Œ]xY w# |j?                  | |¬«       w xY w)a°  Run the batch's children in parallel, appending entries to ``results`` (sorted by task_index on return, one
    completion line printed per child). Polls futures with a short ``wait()`` timeout instead of ``as_completed()``
    so a wedged child cannot block the parent forever after an interrupt; on parent interrupt the still-pending
    children are reported ``interrupted`` and abandoned (they already got the interrupt signal).r   )ÚDaemonThreadPoolExecutorr>   Né(   rN   c           	     óø   •— | j                  «       st        |dd‰j                  |«      «      S 	 | j                  «       S # t        $ r0}t        |dt        |«      ‰j                  |«      «      cY d }~S d }~ww xY w)NÚinterruptedu9   Parent agent interrupted â€” child did not finish in timerh   )Údoner   rn   ÚresultÚ	Exceptionr"   )Úfutureru   ÚexcÚ_child_by_indexs      €r9   Ú	_entry_ofz)_run_children_parallel.<locals>._entry_of…   su   ø€ Ø�{‰{Œ}Ü$Ø�]Ð$_Ðap×atÑatÐuxÓayóð ð	WØ—=‘=“?Ð"øÜò 	WÜ$ S¨'´3°s³8¸_×=PÑ=PÐQTÓ=UÓVÕVûð	Wús   °A  Á 	A9Á	%A4Á.A9Á4A9)Úmax_workersFÚ_interrupt_requestedTc              3  ó6   •K  — | ]  } ‰|‰|   «      –— Œ y ­w©NrA   )Ú.0ÚfrŽ   Úfuturess     €€r9   ú	<genexpr>z)_run_children_parallel.<locals>.<genexpr>š   s   øè ø€ ÒI¸A™y¨¨G°A©J×7ÑIùs   ƒg      à?)ÚtimeoutÚreturn_whenra   ztask failure notice failed©Úexc_info)Úpush_task_failure_noticer?   éÿÿÿÿÚlive_transcript)rQ   )r   Úcancel_futuresc                ó   — | d   S )Nr?   rA   )Úrs    r9   ú<lambda>z(_run_children_parallel.<locals>.<lambda>²   s
   € ˜q ™€ r;   )Úkey)!Útools.daemon_poolr„   r   rm   r   rP   r   r&   r   r%   ÚsubmitÚcontextvarsÚcopy_contextÚrunrE   ÚsetÚextendÚ_cf_waitr   Úappendr‚   r|   r3   rn   r   r   rZ   r›   r~   r$   r)   ÚshutdownÚsort)r€   Úresultsr�   r„   r   rQ   Útrs   rp   Ú_tagrC   Ú_r@   Ún_hereÚexecutorr‡   Úpendingrˆ   r‹   rq   r›   Ú_iÚ_liver�   rŽ   r•   s                          @@@r9   Ú_run_children_parallelr·   u   sÞ  ú€ õ ;Ø!×.Ñ.´°E·O±OÓ0D�'€LØ+0¯?©?Ö; a�1�V‘9˜S˜b’>Ð;€KÐ;Ü˜,Ð(;¸TÓB€KÜ˜E×/Ñ/°Ó>€Dà5:·^±^×DÐD¡M Q¨¨5�q˜%‘xÔD€OÜ�—‘Ó €FôWñ (°E×4FÑ4FÔG€Hð
 €KðLØw|÷  xFñ  xF÷  Gð  GÑhsÐhiÐklÐns�8—?‘?¤;×#;Ñ#;Ó#=×#AÑ#AÀ5Ç?Á?ÐTUÐWXÐZ_Ó`ÐbcÑcô  GˆÜ�g“,ˆÚÙ%¬'°,Ð@VÐX]Ó*^ÐbfÑ*fØ—‘ÔIÀÔIÔIØ"�ÙÜ$ W°cÄÔW‰MˆD�'Øó x�Ù! &¨'°&©/Ó:�Ø—‘˜uÔ%ä& u¨eÐ5KÔLÜ" <°¸eÀTÈ;ÐX_ÐagÔjmÐnuÓjvÑavÔwÚ.°5·=³=ÀUÇYÁYÈxÓEXÔ\uÒEuÜ ›L¨6Ó1ô  Ð <ÀtÔLñ xÝSØ"ŸY™Y |°RÓ8˜Ü8BÀ2ÄsÔ8KÐPQÐUWÔPoÔZ]Ð^c×^nÑ^nÓZoÕPo × 0Ñ 0°Ò 4Ðuy˜Ù0Ø!ŸM™MÐ+e¨eÐ+eÑV[Ð9JÈEÑ8RÐacÐ+eÐovõx÷	xñ xðxó ð2 	×Ñ ;˜¸{ÐÔKØ‡L�LÑ.€LÕ/ùòi <ùô Eùô( G÷$xñ xûð 	×Ñ ;˜¸{ÐÕKús\   ¹J1Á=J6Ã K ÃAJ=ÄB'K Æ?K ÇK Ç$K Ç3K È A:KÉ:K Ê=K ËK	Ë	K ËK'T©r�   c               ó‚  — ddl m} g }t        | j                  «      dk(  r<|j	                   | j
                  | j                  d   Ž «       t        | |d   |«       nt        | ||¬«       t        || j                  | j                  | j                  «       t        t        j                  «       | j                  z
  d«      }|D ]¶  }|j                  dd«      }t!        |t"        «      sŒ&d|cxk  rt        | j$                  «      k  sŒEn ŒH| j$                  |   €ŒXt'        d	d
¬«      5  | j$                  |   j)                  |«       ddd«       |t        | j*                  «      k  sŒ¥| j*                  |   |d<   Œ¸  || j,                  |«       ||dœ}ddlm} |D ��	cg c]  } ||«      D ]  }	|	‘Œ Œ }
}}	|
r|
|d<   | j                  D ��cg c].  \  }}}|t        | j*                  «      k  sŒ | j*                  |   ‘Œ0 }}}|r||d<   | j2                  �| j2                  |d<   |S # 1 sw Y   ŒâxY wc c}	}w c c}}w )aŒ  Run the batch's built children, join, finalize (hooks + cost rollup), return the combined dict. Shared by the
    sync path and the background runner; a background runner receives a per-group unit (a subset of the call's
    children) so each group JOINS only on itself. Live transcripts are finalized but retained as the full-fidelity
    record (retention pruning happens on future dispatches).r   )Úupdate_manifest_statusesrM   rœ   r¸   é   r?   NzLive transcript finalize failedTr™   r�   )r®   Útotal_duration_seconds)Ú_process_accounting_linesÚprocess_notesÚlive_transcriptsr2   )Útools.delegation_live_logrº   rm   r   r«   rE   r‚   r·   r   r   r   ÚroundÚtimeÚ	monotonicr1   rn   r~   r$   r(   r   Úfinalizer)   r&   Ú$tools.process_registry_notificationsr½   r2   )r€   r�   rº   r®   Útotal_durationrq   Ú_idxÚcombinedr½   Úliner¾   rC   r±   Ú
unit_pathss                 r9   Ú_execute_and_aggregaterË   ´   s  € õ
 CØ€GÜ
ˆ5�>‰>Ó˜aÒØ�‰��u—‘¨¯©°qÑ(9Ð:Ô;ô 	˜u g¨b¡kÐ3IÕJä˜u gÐF\Õ]ä˜G U§_¡_°e·n±nÀe×FXÑFXÔYÜœ4Ÿ>™>Ó+¨e×.AÑ.AÑAÀ1ÓE€NØò BˆØ�y‰y˜ rÓ*ˆÜ�dœCÕ  Q¨$Ô%H´°U×5GÑ5GÓ1HÖ%HÈU×M_ÑM_Ð`dÑMeÑMqÜÐ9ÀDÔIñ 9Ø×"Ñ" 4Ñ(×1Ñ1°%Ô8÷9à”c˜%×*Ñ*Ó+Ó+Ø+0×+;Ñ+;¸DÑ+A�Ð'Ò(ðBñ ˜U×0Ñ0°'Ô:à+2ÈnÑ]€HåNØ'.×\˜eÑ;TÐUZÓ;[Ò\°4’TÐ\�TÐ\€MÑ\ÙØ$1ˆ�Ñ!Ø7<·~±~×c©)¨1¨a°ÈÌSÐQV×QaÑQaÓMbÓIb�%×"Ñ" 1Ó%Ðc€JÑcÙØ'1ˆÐ#Ñ$Ø‡{�{ÐØ!ŸK™Kˆ�ÑØ€O÷#9ð 9üó ]ùó ds   Ä)H)Æ H5Ç!H;Ç1H;È)H2	u8  background=true is not available in this session â€” it cannot receive a detached subagent result after the turn ends (a finite chat using -Q, --oneshot, or non-TTY stdio, `hermes -z`, a cron job, a Kanban worker, or a stateless HTTP endpoint). The subagent(s) ran SYNCHRONOUSLY and the result is included above.a  The background delegation pool was at capacity (delegation.max_concurrent_children), so the subagent(s) ran SYNCHRONOUSLY and the result is included above. Raise delegation.max_concurrent_children in config.yaml to allow more concurrent background delegations.)Úno_asyncÚat_capacityc                ó~   — t        | «      }t        |t        «      rt        |   |d<   t	        j
                  |d¬«      S )zGInline fallback: run the batch now and explain why it was not detached.ÚnoteF©Úensure_ascii)rË   r~   r   Ú_SYNC_FALLBACK_NOTESÚjsonÚdumps)r€   Úreasonr‰   s      r9   Ú_run_sync_with_noterÖ   é   s5   € ä# EÓ*€FÜ�&œ$ÔÜ-¨fÑ5ˆˆv‰Ü�:‰:�f¨5Ô1Ð1r;   c                óÎ   — ddl m}  |d«      dk(  ry	 ddl m}  |«       ry	 | r|rt        j                  d| «       | S | rt        j                  d	| «       y# t        $ r Y yw xY w)
zóDetached result target: empty for push, a resumable API id, or None for inline.

    API completion only persists a row; this does not authorize a model wake. The
    continuation must read that row, not an authoritative caller-owned snapshot.r   ©rW   ÚHERMES_SINGLE_QUERY_SESSIONÚ1N)Úasync_delivery_supportedrV   u€   delegate_task: session %s resumes server history â€” detached result will be persisted for the next client turn (no model wake).u‰   delegate_task: session %s has no declared server-history consumer â€” running the batch synchronously so the result returns in this turn.)r[   rW   rÛ   rŠ   ÚloggerÚinfo)r*   r/   rW   rÛ   s       r9   Ú_resolve_async_wake_sidrÞ   ð   sˆ   € õ
 8ñ
 Ð4Ó5¸Ò<Øð	õ
 	EÙ#Ô%Øð &ñ Ñ:Ü�‰ð8Ø9Hô	
ð ÐÙÜ�‰ð@ØAPô	
ð øô ò Ùðús   ”A Á	A$Á#A$c                óî   — ddl m}  |d¬«      }t        t        | dd«      xs d«      }t	        d«      5  ddlm}  |dd«      } |d	d«      xs |}|d
k(  r|r|}ddd«       |xs ||fS # 1 sw Y   ŒxY w)u[  ``(session_key, origin_ui_session_id)`` the async registry routes completions by.

    Desktop/TUI: the routable key is the durable AIAgent.session_id â€” compression can rotate it mid-turn before the
    TUI-side dict is re-anchored, and a stale approval-context key would orphan the completion. Gateway chats keep the
    platform conversation key (agent:main:...). The CLI has no bound approval contextvar and no HERMES_SESSION_KEY, so
    the key resolves empty; its drain is a positive-ownership filter on the durable session_id (empty would fail
    closed), so stamp the parent's durable id.
    r   )Úget_current_session_keyrV   )ÚdefaultÚ
session_idNrØ   ÚHERMES_SESSION_SOURCErY   Útui)Útools.approval_contextrà   r"   rP   r   r[   rW   )r   r+   rà   Úsession_keyÚagent_session_idrW   Úsources          r9   Ú_resolve_async_session_keyré     s�   € õ ?Ù)°"Ô5€KÜœ7 <°¸rÓBÒHÀbÓIÐÜ	�‹ñ +Ý;Ù Ð!8¸"Ó=ˆñ  /Ð/EÀrÓJÒbÐNbÐØ�UŠ?Ñ/Ø*ˆK÷+ð Ò*Ð*Ð,@Ð@Ð@÷+ð +ús   µ&A+Á+A4c                ó:  — g }d}| D ]f  }	 |j                  «       }|j                  d«      }|j                  |j                  dd«      ||j                  d«      f«       |xs t        |«      }Œh t        |«      |fS # t        $ r |j                  d«       Y Œ’w xY w)aÒ  Progress token for the async registry's stale monitor: every child's (api_call_count, current_tool,
    last_activity_ts). last_activity_ts ticks on streamed chunks, tool transitions and API-call start/completion,
    so a child streaming a long response counts as alive; a fully frozen token past the threshold means the batch
    is wedged. ``in_tool`` is True while ANY child is inside a tool so slow tools get the higher ceiling (mirrors
    the sync heartbeat).FÚcurrent_toolÚapi_call_countr   Úlast_activity_tsN)Úget_activity_summaryrn   r«   r.   rŠ   Útuple)Úchild_agentsÚpartsÚin_toolÚcÚsummaryÚtools         r9   Ú_batch_progress_tokenrö   *  s£   € ð €EØ€GØò ˆð	Ø×,Ñ,Ó.ˆGØ—;‘;˜~Ó.ˆDØ�L‰L˜'Ÿ+™+Ð&6¸Ó:¸DÀ'Ç+Á+ÐN`ÓBaÐbÔcØÒ+¤ d£‰Gðô �‹<˜Ð Ð øô ò 	Ø�L‰L˜Öð	ús   ‹A#A=Á=BÂBa*  Subagent is running in the background; its full result re-enters the conversation as a new message when it finishes. Results are delivered only after you END YOUR TURN: do anything that does not depend on it, then stop with a one-line status. Do not poll its transcript or artifacts to wait for it.ai  {n} subagents are running in parallel in the background as {k} completion unit(s); each unit's results re-enter the conversation as their own new message when THAT unit finishes. Results are delivered only after you END YOUR TURN: do anything that does not depend on them, then stop with a one-line status. Do not poll transcripts or artifacts to wait for them.zâWhile a child runs you can orchestrate it live with this same tool: delegate_task(action='list') to see live children, action='steer' with subagent_id + message to redirect one, action='stop' with subagent_id to end one early.zÈEach subagent streams a human-readable transcript of its operations to the file listed above (append-only, one per task). Read or `tail -f` these paths at any time to watch a child work while it runs.)ÚoneÚmanyÚcontrol_hintÚlive_transcripts_hintc                óÄ  — | j                   D �cg c]  }|d   ‘Œ	 }}t        |«      }dd|| j                  xs |d   d   ||dk(  r	t        d   n"t        d   j	                  |t        |«      ¬«      d	œ}t        |«      dkD  rH|D ����	cg c]3  \  }}||j
                  |j                  D ��	cg c]  \  }}	}	|‘Œ
 c}	}d
œ‘Œ5 c}	}}}|d<   | j                  D �	�
cg c]  \  }	}	}
t        |
dd«      ‘Œ }}	}
t        d„ |D «       «      r||d<   t        d   |d<   | j                  r$t        | j                  «      |d<   t        d   |d<   |S c c}w c c}	}w c c}	}}}w c c}
}	w )zNModel-facing handle for an accepted background call: one entry per async unit.r>   Ú
dispatchedÚ
backgroundr   rM   r÷   rø   )ÚnÚk)ra   ÚmodeÚcountÚdelegation_idÚgoalsrÏ   )r  r2   Útask_indexesÚunitsÚ_subagent_idNc              3  óD   K  — | ]  }t        |t        «      xr |–— Œ y ­wr’   )r~   r"   )r“   rl   s     r9   r–   z&_dispatched_payload.<locals>.<genexpr>g  s   è ø€ Ò
2¨Œ:�aœÓÒ# !Ó#Ñ
2ùs   ‚ Úsubagent_idsrù   r¿   rú   )r   rm   r&   Ú_BACKGROUND_NOTESÚformatr2   r   rP   Úanyr)   r'   )r€   r  r¯   r  rþ   ÚpayloadÚunitÚuidrC   r±   ró   Úsidss               r9   Ú_dispatched_payloadr  X  sr  € à %§¡Ö0˜1ˆQˆv‹YÐ0€EÐ0ÜˆE‹
€Aà¨¸qØ×,Ñ,Ò;°°a±¸±ÀeØ,-°ªFÔ! %Ò(Ô8IÈ&Ñ8Q×8XÑ8XÐ[\Ô`cÐdiÓ`jÐ8XÓ8kñ€Gô
 ˆ5ƒz�A‚~ð #÷
ñ 
á��cð "¨D¯J©JÐ\`×\iÑ\i×HjÉyÐPQÐSTÐVWÊÓHjÓkõ
ˆ�Ñð ?D¿n¹n×M±°!°Q¸ŒG�A�~ tÕ,ÐM€DÑMÜ
Ñ
2¨TÔ
2Ô2Ø"&ˆ�ÑÜ"3°NÑ"Cˆ�ÑØ×ÒÜ&*¨5×+;Ñ+;Ó&<ˆÐ"Ñ#Ü+<Ð=TÑ+UˆÐ'Ñ(Ø€Nùò' 1ùó Ikùõ
ùó Ns#   �E	Â	#E
Â,EÂ9E
ÃEÅE
c           
     óh  — ddl m}  |«       s| gS i }| j                  D ]P  \  }}}|j                  d«      }|dvrdt	        |«      fnd|f}|j                  |g «      j                  |||f«       ŒR |j                  «       D ��cg c]   \  }}t        | ||d   dk(  r|d   nd¬	«      ‘Œ" c}}S c c}}w )
a-  Partition the call's children into async units: one per distinct task ``group`` (first-appearance order) and
    one per ungrouped task. Each unit is a ``_Batch`` sharing the call's task_list/transcripts but owning a subset of
    ``children``, so a unit joins only on itself and its completion re-enters the conversation on its own.

    Off by default (``delegation.independent_completions``): the whole call is ONE unit and returns as one message.
    A per-task flurry of completions (one new turn each) fragmented orchestrators that had no plan for it.r   )Ú_get_independent_completionsr2   )NrV   ÚgrC   rM   N)r   r2   )	Útools.delegate_tool_configr  r   rn   r"   Ú
setdefaultr«   Úitemsr   )	r€   r  ÚmembersrC   r¯   ró   r  r¢   Úchs	            r9   Ú	_units_ofr  o  s¼   € õ HÙ'Ô)ØˆwˆØ&(€GØ—>‘>ò 6‰ˆˆ1ˆaØ�E‰E�'‹NˆØ ¨
Ñ2ˆs”C˜“F‰m¸¸a¸ˆØ×Ñ˜3 Ó#×*Ñ*¨A¨q°!¨9Õ5ð6ð cj×boÑboÓbq×rÑW^ÐWZÐ\^ŒG�E B¸¸Q¹À3º¨s°1ªvÈDÖRÓrÐrùÓrs   Â%B.c                óÞ  ‡ ‡
— ddl m} ‰ j                  D ��cg c]  \  }}}|‘Œ
 c}}Š
ˆ
fd„} |d
‰ j                  D �cg c]  }|d   ‘Œ	 c}‰ j                  d‰ j
                  ‰ j                  d   ˆ fd„|||t        ‰ j                  «      t        ‰ j                  «      k  r ‰ j                  D �	�cg c]  \  }	}}|	‘Œ
 c}}	nd‰ j                  D �	�ci c]r  \  }	}}|	t        ‰ j                  «      k  rT‰ j                  |	   �E‰ j                  |	   j                  �,t        |	«      t        ‰ j                  |	   j                  «      “Œt c}}	ˆ
fd„d	œ|¤ŽS c c}}w c c}w c c}}	w c c}}	w )zSHand ONE unit to the async registry; the runner joins on that unit's children only.r   )Údispatch_async_delegation_batchc                 ó,   •— ‰D ]  } t        | d«       Œ y )NzAsync delegation cancelled)r   )ró   rð   s    €r9   Ú
_interruptz"_dispatch_unit.<locals>._interrupt…  s   ø€ Øò 	@ˆAÜ˜qÐ">Õ?ñ	@r;   r>   NÚmodelc                 ó   •— t        ‰ d¬«      S )NFr¸   )rË   )r  s   €r9   r¡   z _dispatch_unit.<locals>.<lambda>Ž  s   ø€ Ô-¨dÈ5ÔQ€ r;   c                 ó   •— t        ‰ «      S r’   )rö   )rð   s   €r9   r¡   z _dispatch_unit.<locals>.<lambda>•  s   ø€ Ô1°,Ó?€ r;   )r  r!   ÚtoolsetsÚroler  ÚrunnerÚinterrupt_fnr  Úslot_keyr  Útask_transcriptsÚprogress_fnrA   )rZ   r  r   r   r!   r#   r   rm   r(   Úpathr"   )r  r3   r%  Úroutingr  r±   ró   r  r¯   rC   rð   s   `         @r9   Ú_dispatch_unitr*  €  sP  ù€ åFØ'+§}¡}×5™)˜1˜a ’AÓ5€Lô@ñ +ð à"&§.¡.Ö1˜Qˆq�‹yÒ1¸4¿<¹<ØØ�]‰] $§*¡*¨WÑ"5ÛQØ¨wÀÜ;>¸t¿}¹}Ó;MÔPSÐTX×TbÑTbÓPcÒ;c¨¯©×7™I˜Q  1’aÔ7ÐimàPT×P]ÑP]÷ EÁWÀQÈÈ1Ø¤ T×%6Ñ%6Ó!7Ò7¸D×<MÑ<MÈaÑ<PÐ<\Ø"×/Ñ/°Ñ2×7Ñ7ÐCô ˜a›&¤# d×&7Ñ&7¸Ñ&:×&?Ñ&?Ó"@Ñ@ó Eó @ñð DKñð ùó 6ùò 2ùó
 8ùóEs   ˜E¿E
Â3E#ÃA7E) c                óZ   — | j                   D ]  \  }}}t        | j                  |«       Œ y)z—Rejected children stay owned by the parent: re-attach them (``_attach_child`` replays a stop that
    arrived while async admission had them detached).N)r   r   r   )r  r±   r@   s      r9   Ú_restore_parent_cancellationr,  ˜  s-   € ð —}‘}ò 0‰ˆˆ1ˆeÜ�d×'Ñ'¨Õ/ñ0r;   c           
     óH  — ddl m} t        | j                  | j                  «      }|€!t
        j                  d«       t        | d«      S | j                  }t        || j                  «      \  }}t        |||t        |dd«       |«       ¬«      }t        | «      }g }g }	d}
t        |«      D �]K  \  }}t        |«      dk(  r| j                   n!| j                   r| j                   › d	|dz   › �nd}|xs
 t#        «       x|_        }|j&                  D ]  \  }}}t)        ||«       Œ t+        |||
|«      }|j-                  d
«      dk(  r |
xs |d   }
|j/                  ||d   f«       Œ»t1        |«       |s4t
        j                  d|j-                  dd«      «       t        | d«      c S t
        j3                  d|dz   t        |«      |j-                  d«      «       |	j5                  t7        |«      d   «       �ŒN t9        | |«      }|	r|	|d<   t;        j<                  |d¬«      S )ar  Dispatch the call as independent async units (see ``_units_of``) and return the tool result JSON. Every unit
    of one call shares ONE pool slot (``slot_key``), so grouping never changes capacity accounting. Falls back to
    running synchronously (with an explanatory ``note``) when the session cannot receive detached completions or the
    async pool is at capacity.r   )Ú_get_max_async_childrenNzkdelegate_task: async delivery unsupported on this session runtime; running the batch synchronously instead.rÌ   râ   )ræ   r+   Úorigin_session_idÚparent_session_idÚmax_async_childrenrM   Ú-ra   rü   r  zZdelegate_task: async pool at capacity (%s); running the whole batch synchronously instead.rh   ÚrejectedrÍ   z?delegate_task: unit %d/%d not accepted (%s); running it inline.r®   Úinline_resultsFrÐ   )rB   r.  rÞ   r*   r/   rÜ   rÝ   rÖ   r   ré   r+   r   rP   r  Ú	enumeraterm   r&   r   r3   r   r   r*  rn   r«   r,  Úwarningr©   rË   r  rÓ   rÔ   )r€   r.  Úwake_sidr   ræ   r+   r)  r  rü   r4  r%  rÿ   r  r3   r±   r@   Údispatchr  s                     r9   Ú_dispatch_backgroundr9  ž  sD  € õ
 <Ü& u×'<Ñ'<¸e×>cÑ>cÓd€HØÐÜ�‰ð  Bô  	CÜ" 5¨*Ó5Ð5à×%Ñ%€LÜ(BÀ<ÐQV×QkÑQkÓ(lÑ%€KÐ%ÜØÐ6JÐ^fÜ! ,°¸dÓCÑXoÓXqô€Gô
 �eÓ€EØ+-€JØ!#€NØ"€HÜ˜UÓ#ó G‰ˆˆ4ô *-¨U«°qª�%×%Ò%Ðch×cvÒcvÀ%×BUÑBUÐAVÐVWÐXYÐ\]ÑX]ÐW^Ñ?_ð  }AˆØ!(Ò!@Ô,>Ó,@Ð@ˆŒ�wð  Ÿ=™=ò 	/‰KˆAˆq�%Ü˜,¨Õ.ð	/ä! $¨°¸7ÓCˆØ�<‰<˜Ó! \Ò1ØÒ< 8¨OÑ#<ˆHØ×Ñ˜t X¨oÑ%>Ð?Ô@ØÜ$ TÔ*ÙÜ�K‰KØlØ—‘˜W jÓ1ôô ' u¨mÓ<Ò<ô 	�‰ÐXÐZ[Ð^_ÑZ_ÔadÐejÓakÐmu×myÑmyð  {Bó  nCô  	DØ×ÑÔ4°TÓ:¸9ÑEÖFð1Gô2 " %¨Ó4€GÙØ$2ˆÐ Ñ!Ü�:‰:�g¨EÔ2Ð2r;   c                ó\   — |rt        | «      S t        j                  t        | «      d¬«      S )zPTool result JSON: a dispatch handle (background) or the joined combined results.FrÐ   )r9  rÓ   rÔ   rË   )r€   rý   s     r9   Ú
_run_batchr;  Ò  s'   € áÜ# EÓ*Ð*Ü�:‰:Ô,¨UÓ3À%ÔHÐHr;   )rQ   r$   r&   r    rF   ÚNone)rF   ztuple[str, str, Any, Any, bool])rF   r<  )r€   r   rq   r   r�   r.   rF   r<  )r€   r   r®   r'   r�   r.   rF   r<  )r€   r   r�   r.   rF   r   )r€   r   rÕ   r"   rF   r"   )F)r*   r"   r/   r.   rF   r    )r   r   r+   r"   rF   ztuple[str, str])rð   z	List[Any]rF   rï   )r€   r   r  zList[tuple[_Batch, str]]rF   r   )r€   r   rF   zList[_Batch])
r  r   r3   r    r%  r    r)  r   rF   r   )r  r   rF   r<  )r€   r   rF   r"   )r€   r   rý   r.   rF   r"   ):rJ   Ú
__future__r   r¥   rÓ   ÚloggingrÂ   Úconcurrent.futuresr   r   rª   Údataclassesr   r   Útypingr   r	   r
   r   rZ   r   r   Útools.delegate_tool_child_runr   r   r   r   Útools.delegate_tool_progressr   r   r   r   r   Útools.delegate_tool_registryr   Útools.delegate_tool_resultsr   Ú	getLoggerrÜ   r   rS   r_   r|   r‚   r·   rË   rÒ   rÖ   rÞ   ré   rö   r	  r  r  r*  r,  r9  r;  rA   r;   r9   ú<module>rG     s  ðñ1õ
 #ã Û Û Û ß @ß *ß ,Ó ,ç Hß mÓ m÷õ õ JÝ ?à	ˆ×	Ñ	Ð0Ó	1€ð ÷!Fð !Fó ð!FóHxóQó"Hó,0ó=0ð~ MQõ %ðR	uð	mñÐ ó2ô"óHAó,!ð2	_ð
	:ð	ð
	hñ%Ð ó.ó.só"ó00ó23ôhIr;   