
    xj                       U d Z ddlmZ ddlmZ ddlmZmZ ddlm	Z	m
Z
mZ  edd          Zd	ed
<    edd          Zd	ed<   dZdZded<   ed(d)d            Zd*dZed+d            Zd*dZd,dZd-dZd*d Zd.d$Z	 d(d/d'ZdS )0a  Context-local state for delegate_task child execution.

The parent Hermes process may itself be a Kanban dispatcher worker with
HERMES_KANBAN_* variables in process env. delegate_task children run inside the
same Python process, but they are not dispatcher-owned Kanban workers. This
module lets code paths that resolve tool schemas or spawn subprocesses fail
closed for delegated children without mutating global os.environ for the parent.

Cron jobs need the same treatment for the same reason: ``cronjob(action="run")``
executes ``run_job()`` in-process, so a cron agent fired from inside a Kanban
worker would otherwise inherit that worker's dispatcher identity.
``non_dispatcher_owned_context()`` covers both cases.
    )annotations)contextmanager)
ContextVarToken)IteratorMappingMutableMappinghermes_delegated_child_contextF)defaultzContextVar[bool]_DELEGATED_CHILD_CONTEXT#hermes_non_dispatcher_owned_context_NON_DISPATCHER_OWNED_CONTEXTHERMES_DELEGATED_CHILD_CONTEXT)HERMES_KANBAN_TASKHERMES_KANBAN_RUN_IDHERMES_KANBAN_WORKSPACEHERMES_KANBAN_WORKSPACES_ROOTHERMES_KANBAN_CLAIM_LOCKHERMES_KANBAN_BOARDHERMES_KANBAN_DBztuple[str, ...]KANBAN_ENV_KEYSN
session_id
str | NonereturnIterator[None]c              #    K   t                               d          }	 ddlm}  ||           5  dV  ddd           n# 1 swxY w Y   t                               |           dS # t                               |           w xY w)a.  Mark child execution and isolate its task-local session identity.

    Child construction calls ``set_current_session_id`` internally, so even a
    context entered without an id must restore the parent's ContextVar.  Child
    execution passes its explicit id and receives it only for this scope.
    Tr   )scoped_current_session_idN)r   setgateway.session_contextr   reset)r   tokenr   s      </home/agent/.hermes/hermes-agent/agent/delegation_context.pydelegated_child_contextr#   0   s       %((..E. 	FEEEEE&&z22 	 	EEE	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	!&&u----- &&u----s-   A' A A'  AA' AA' 'Bboolc                 N    t          t                                                    S )z<Return True while code is running for a delegate_task child.)r$   r   get     r"   is_delegated_child_contextr)   D   s    (,,..///r(   c               #     K   t                               d          } 	 dV  t                               |            dS # t                               |            w xY w)u  Mark in-process execution that does NOT own the dispatcher's Kanban task.

    A Kanban worker is a normal CLI agent whose default toolset includes
    ``cronjob``; ``cronjob(action="run")`` runs ``run_job()`` inside the worker's
    own process, where ``HERMES_KANBAN_TASK`` is legitimately set.  Without this
    marker the cron agent is misread as that worker: the kanban toolset is
    force-added, the worker protocol is injected into its system prompt, and
    ``kanban_complete`` defaults ``task_id`` to ``$HERMES_KANBAN_TASK`` — letting
    an unrelated cron job close the worker's task and overwrite real results.

    Scoped via ContextVar rather than by clearing ``os.environ``: the env is
    process-global and shared with the worker's own claim heartbeat, the
    gateway's Kanban watchers, and concurrent cron jobs on the parallel pool, so
    mutating it would starve the worker's claim and race those readers.
    TN)r   r   r    r!   s    r"   non_dispatcher_owned_contextr,   I   s^      " *--d33E3%++E22222%++E2222s	   > Ac                 l    t                                           rdS t                                           S )a  Return True only when this execution owns the dispatcher's Kanban task.

    The single predicate every ``HERMES_KANBAN_*`` identity gate should use
    before trusting those vars.  False for delegate_task children and for cron
    jobs fired in-process from a worker.
    F)r   r&   r   r'   r(   r"   "is_dispatcher_owned_worker_contextr.   a   s2      ##%% u,002222r(   Token[bool]c                 6    t                               d          S )a  Token-based form of :func:`non_dispatcher_owned_context`.

    For callers whose scope is a long ``try`` with a matching ``finally`` rather
    than a ``with`` block (``cron.scheduler.run_job``).  Pair with
    :func:`exit_non_dispatcher_owned_context`.
    T)r   r   r'   r(   r"   "enter_non_dispatcher_owned_contextr1   m   s     ),,T222r(   r!   Nonec                :    t                               |            dS )zERestore the flag saved by :func:`enter_non_dispatcher_owned_context`.N)r   r    r+   s    r"   !exit_non_dispatcher_owned_contextr4   w   s    !''.....r(   c                     ddl } t          t                                                    p+t          | j                            t
                              S )z?Return True in this process or a subprocess spawned by a child.r   N)osr$   r   r&   environDELEGATED_CHILD_ENV_MARKER)r6   s    r"   "is_delegated_child_process_contextr9   |   sK    III(,,..// 4

1224 4 r(   env,Mapping[str, str] | MutableMapping[str, str]dict[str, str]c                x    t          |           }t          D ]}|                    |d           d|t          <   |S )z;Return *env* with dispatcher-only Kanban variables removed.N1)dictr   popr8   )r:   cleanedkeys      r"   scrub_kanban_envrC      sC    3iiG  C*-G&'Nr(   3Mapping[str, str] | MutableMapping[str, str] | Nonedict[str, str] | Nonec                |    t                      s| dnt          |           S | ddl}|j        } t	          |           S )a  Return an env override only when delegated-child lineage must cross fork.

    Most subprocess call sites historically used ``env=None`` to inherit the
    process environment.  In a ``delegate_task`` child, inheriting as-is leaks
    parent dispatcher ``HERMES_KANBAN_*`` vars while losing the ContextVar in
    the new process.  This helper preserves normal ``env=None`` semantics for
    non-delegated calls, and only materializes a scrubbed env when the lineage
    marker must be propagated across a child-process boundary.
    Nr   )r9   r?   r6   r7   rC   )r:   r6   s     r"   delegated_child_subprocess_envrG      sI     .// 2{ttS		1
{			jC   r(   )N)r   r   r   r   )r   r$   )r   r   )r   r/   )r!   r/   r   r2   )r:   r;   r   r<   )r:   rD   r   rE   )__doc__
__future__r   
contextlibr   contextvarsr   r   typingr   r   r	   r   __annotations__r   r8   r   r#   r)   r,   r.   r1   r4   r9   rC   rG   r'   r(   r"   <module>rN      s     # " " " " " % % % % % % ) ) ) ) ) ) ) ) 4 4 4 4 4 4 4 4 4 4-7Z$. . .      3=*)3 3 3     
 > $     . . . . .&0 0 0 0
 3 3 3 3.	3 	3 	3 	33 3 3 3/ / / /
       @D! ! ! ! ! ! !r(   