Ë
    ãß²j5ä  ã            ?       ó^	  — d 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ZddlmZ  ej$                  e«      ZdZdZej.                  j1                  d e ee«      j6                  j6                  «      «       ddlmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z( dd	l)m*Z* dd
l+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z< ddl=m>Z>m?Z? deee
f   defd„Z@d�d„ZAdeee
f   deBfd„ZCdefd„ZDd�deee
f   dee   dee   fd„ZEdedeee
f   defd„ZFdZGdedefd„ZHd�deee
f   dee   deee
f   fd„ZIej”                  defd„«       ZKd�deee
f   dee   deee
f   fd„ZL	 d�d edee   deee
f   fd!„ZMd‘ded"eNdee   fd#„ZOdeddfd$„ZPd%ee   defd&„ZQd'eee
f   dededed(eRdeee
f   fd)„ZS	 d’deee
f   d%ee   dee   deeee
f      fd*„ZTd+eee
f   deee
f   dee   deee
f   fd,„ZUd-eee
f   defd.„ZVd-eee
f   defd/„ZWdeee
f   d-eee
f   defd0„ZXd1eee
f   defd2„ZYdedeee
f   fd3„ZZdeee
f   d-eee
f   defd4„Z[d5eee
f   deee
f   d6ede
fd7„Z\deee
f   d-eee
f   d5eee
f   dee   fd8„Z]deee
f   d-eee
f   d5eee
f   dee   fd9„Z^deee
f   d-eee
f   d5eee
f   dee   fd:„Z_deee
f   d-eee
f   d5eee
f   dee   fd;„Z`e]e^e_e`fZadeee
f   d-eee
f   defd<„ZbeVeWd=œZceXebe[e[e[d>„ d?„ d@œZddefdA„Ze	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d“dCedee   dDee   dEee   dFee   dGeeN   dee   dHefdIee   dJeee      dKee   dLee   dMee   dNee   dOee   dPeeeee   f      dQeef   dReee      dSee   dTeef   dUeef   dVee   dWee   dXee   dYeeeee   f      dZed%ee   d[efd\ee   d]eef   def>d^„Zgd_edefd`„Zhdeifda„Zjdbdcddi d[dedfdgœ“d\dhdidgœ“dCdhdjdgœ“ddhdkdgœ“d]dedldgœ“dDdhdmdgœ“dEdhdhdndoœ“dFdhdpdgœ“dGdqdrdgœ“ddhdsdgœ“dYdhdtdgœ“dJdudvdhidwdxœ“dOdh ehdy«      dgœ“dzdhd{dgœ“dTdedBd|d}œ“dPdudvdhid~dxœ“dQdeddgœ“dudvdhid€dxœdhd�dgœded‚dgœdƒœ¥dCgd„œd…œZkdeffd†„Zld‡Zmdˆ„ Zn e>jÞ                  dbd‰ekeneldŠej¬‹«       ddlpZpdŒd�iZqdŽ„ Zry)”z¤Cron job management tool: one compressed action-oriented `cronjob_manage` tool
(schema/context bloat avoided); `cronjob()` stays callable for direct Python callers.é    N)ÚPath)ÚAnyÚDictÚListÚOptionalÚUnion)Údisplay_hermes_homeç      $@g     Õ@)ÚAmbiguousJobReferenceÚclaim_job_for_fireÚget_jobÚis_job_runnableÚ	list_jobsÚmark_job_runÚparse_scheduleÚ	pause_jobÚ
remove_jobÚresolve_job_refÚ
resume_jobÚ
update_job)Ú_scan_cron_prompt)Ú_apply_continuityÚ_canonical_skillsÚ_clean_str_listÚ_format_jobÚ_gateway_liveness_noticeÚ_local_delivery_noticeÚ_mode_guidance_notesÚ_normalize_deliver_paramÚ_normalize_optional_job_valueÚ_origin_from_envÚ_repeat_displayÚ_resolve_cron_context_deliverÚ_split_monitor_argÚ_validate_bot_chat_deliverÚ_validate_context_from_refsÚ_validate_cron_base_urlÚ_validate_cron_script_path)ÚregistryÚ
tool_errorÚpayloadÚreturnc                 ó0   — t        j                  | d¬«      S )Né   )Úindent)ÚjsonÚdumps)r+   s    ú8/home/ubuntu/.hermes/hermes-agent/tools/cronjob_tools.pyÚ_dumpsr3   D   s   € Ü�:‰:�g aÔ(Ð(ó    c                  ó>   — 	 ddl m}   | «        y# t        $ r Y yw xY w)zRTell the active scheduler provider the job set changed; best-effort, never raises.r   ©Ú_notify_provider_jobs_changedN)Úcron.schedulerr7   Ú	Exceptionr6   s    r2   Ú"_notify_provider_jobs_changed_safer:   H   s"   € ðÝ@Ù%Õ'øÜò Ùðús   ‚ �	›Újobc                 ó2  — 	 ddl m}  |«       }|s
t        «       S 	 ddlm}  || «      xs g }|D �ch c]%  }|j                  d«      sŒ|j                  d«      ’Œ' c}|z  S # t        $ r t        «       cY S w xY w# t        $ r t        «       cY S w xY wc c}w )zEDelivery-platform names for this job that the relay connector fronts.r   )Úrelay_fronted_platforms)Ú_resolve_delivery_targetsÚplatform)Úgateway.relayr=   r9   Úsetr8   r>   Úget)r;   r=   Úfrontedr>   ÚtargetsÚts         r2   Ú!_relay_fronted_delivery_platformsrF   U   s’   € ðÝ9ñ &Ó'€GÙÜ‹uˆðÝ<Ù+¨CÓ0Ò6°Bˆð (/ÖD !°!·%±%¸
Õ2CˆA�E‰E�*ÕÒDÀwÑNÐNøô ò Ü‹uŠðûô ò Ü‹uŠðüâDs-   ‚A" œA; ²BÁ	BÁ"A8Á7A8Á;BÂBc            
      óº  — ddl } | j                  dd«      j                  «       }	 |rt        |«      nd}	 ddlm}m} t         | |«       ddd	d
d¬«      xs d«      j                  «       }|xs  | j                  dd«      j                  «       }|r|dv rd}d|v r|j                  d«      sd|› d�}d|› d|› �S # t        $ r d}Y Œ“w xY w# t        $ r d}Y Œmw xY w)z¦``http://host:port`` of the local api_server, mirroring its bind resolution
    (extra.host -> API_SERVER_HOST -> 127.0.0.1); a wildcard bind listens on loopback too.r   NÚAPI_SERVER_PORTÚ iÂ!  )Úcfg_getÚload_config_readonlyÚ	platformsÚ
api_serverÚextraÚhost©ÚdefaultÚAPI_SERVER_HOST)z0.0.0.0z::Ú*z	127.0.0.1ú:ú[ú]zhttp://)ÚosÚgetenvÚstripÚintÚ
ValueErrorÚhermes_cli.configrJ   rK   Ústrr9   Ú
startswith)rW   Úport_rawÚportrJ   rK   rO   s         r2   Ú_api_server_base_urlra   f   s÷   € ó Ø�y‰yÐ*¨BÓ/×5Ñ5Ó7€HðÙ (Œs�8Œ}¨dˆðßCÜ‘7Ñ/Ó1°;ÀÈgÐW]ÐgiÔjÒpÐnpÓq×wÑwÓyˆð Ò;�2—9‘9Ð.°Ó3×9Ñ9Ó;€DÙ�4Ð1Ñ1ØˆØ
ˆd�{˜4Ÿ?™?¨3Ô/Ø�4�&˜ˆ{ˆØ�T�F˜!˜D˜6Ð"Ð"øô ò ØŠðûô
 ò ØŠðús"   ¦B; ¶6C Â;C	ÃC	ÃCÃCÚextra_promptc                 ó*  — t        | «      syddlm}  |dd«      xs d}	 ddl}|j	                  t        «       › d| d   › d�d	d
|› �i|rd|ini d¬«      }|�|j                  dk  rt        ddddœ«      S t        dddœ«      S # t        $ r d}Y Œ;w xY w)uq  Forward a manual run to the gateway when it targets a relay-fronted platform: such delivery
    has no standalone sender â€” the gateway's live relay adapter is the only path, reached via
    ``POST /api/jobs/{id}/run`` (marks the job due; ``extra_prompt`` rides in the body). Returns a
    JSON result string when forwarding engages, else None (normal in-process run).Nr   )Ú
get_secretÚAPI_SERVER_KEYrI   z
/api/jobs/Úidz/runÚAuthorizationzBearer Úpromptr
   )Úheadersr0   Útimeouti,  Tz�This job targets a relay-fronted platform; it was dispatched to the running gateway, whose live relay adapter owns that delivery.)ÚsuccessÚforwarded_to_gatewayÚnoteFu¨   This job targets a relay-fronted platform, which has no standalone sender. Start the gateway â€” its ticker will deliver the job on schedule via the live relay adapter.©rk   Úerror)	rF   Úagent.secret_scoperd   ÚhttpxÚpostra   r9   Ústatus_coder3   )r;   rb   rd   Úkeyrq   Úresps         r2   Ú_forward_relay_fronted_runrv   |   sÜ   € ô
 -¨SÔ1ØÝ-Ù
Ð% rÓ
*Ò
0¨b€CðÛØ�z‰zÜ#Ó%Ð& j°°T±°¸4Ð@È?Ð^eÐfiÐejÐ\kÐJlÙ.:�8˜\Ñ*ÀÈTð ó Sˆð
 Ð˜D×,Ñ,¨sÒ2ÜØØ$(ðñ	
ó ð 	ô ØðFñó ð øô ò ØŠðús   ¡5B ÂBÂBÚdeliverÚ	refreshedc                 ó¦   — | r| dk(  ryt        |j                  d«      xs d«      j                  «       }|s|j                  d«      ryyd|d	d
 › d�S )u2  Parenthetical delivery note for a manual run's summary; follows the refreshed record's
    ``last_delivery_error`` so the summary never claims success over a failed delivery.

    Follows the refreshed job record (#83993): ``run_one_job`` writes ``last_delivery_error`` via
    ``mark_job_run`` when the post-run delivery (telegram/discord/â€¦) failed, and the summary must not claim
    success over that record â€” the calling agent relays this line to the user. Local jobs never deliver; an
    empty/missing error keeps the legacy wording byte-for-byte.
    Úlocalz (output saved locally only)Úlast_delivery_errorrI   Úlast_delivery_queuedzC (output queued for Bot Chat; completion unverified, do not resend)z/ (output was delivered there by the job itself)u    (âš  delivery FAILED: NéÈ   ú))r]   rB   rY   )rw   rx   Úerrs      r2   Ú_manual_run_delivery_noter€   ž   s^   € ñ �g Ò(Ø-Ü
ˆi�m‰mÐ1Ó2Ò8°bÓ
9×
?Ñ
?Ó
A€CÙØ�=‰=Ð/Ô0ØXØ@Ø$ S¨¨# Y K¨qÐ1Ð1r4   zcJob is already running (a scheduler tick or another manual run is executing it); not started again.Újob_idÚ	log_labelc           	      ó   — 	 t        | dd¬«      }t        |t        «      r|dfS t        | «      }|€d}nt	        |«      sd}nd}ddd|dœfS # t
        $ rx}t        j                  d	| ||«       t        j                  t
        «      5  t        | dt        |«      «       ddd«       n# 1 sw Y   nxY wdddt        |«      dœfcY d}~S d}~ww xY w)
u$  At-most-once claim shared by the sync and background run paths: ``(claimed_job, None)`` or
    ``(None, error_dict)`` in the ``_execute_job_now`` shape. A lost claim is labelled precisely â€”
    claim_job_for_fire also returns False for paused/disabled/missing jobs, not just in-flight ones.T)ÚmanualÚ
return_jobNz%Job no longer exists; nothing to run.z1Job is paused/disabled; resume it before running.z;Job is already being fired by the scheduler; not run again.F©Úclaimedrk   ro   z&Failed to claim cron job %s for %s: %s)r   Ú
isinstanceÚdictr   r   r9   Úloggerro   Ú
contextlibÚsuppressr   r]   )r�   r‚   Úclaimed_jobrx   ÚreasonÚes         r2   Ú_claim_for_manual_runr�   ¸   sÒ   € ðJÜ(¨¸ÈÔNˆÜ�k¤4Ô(Ø Ð$Ð$Ü˜F“Oˆ	ØÐØ<‰FÜ  Ô+ØH‰FàRˆFØ °5À6ÑJÐJÐJøÜò JÜ�‰Ð=¸vÀyÐRSÔTÜ× Ñ ¤Ó+ñ 	0Ü˜ ¬¨A«Ô/÷	0÷ 	0ñ 	0úà °%Ä#ÀaÃ&ÑIÐIÕIûð	Jús:   ‚!A ¤'A Á	CÁ1CÂB&Â	CÂ&B/	Â+CÃCÃCc                 óH   — t        | d   d«      \  }}|�|S t        ||¬«      S )a  Run a job now, outside the scheduler tick: claim via ``claim_job_for_fire`` (the ticker's
    CAS, so a concurrent tick cannot double-fire and next_run_at advances), then fire through
    the shared ``run_one_job`` body. Returns {"claimed", "success", "error"}.rf   zimmediate run©rb   )r�   Ú_run_claimed_job)r;   rb   r�   r   s       r2   Ú_execute_job_nowr”   Ï   s1   € ô -¨S°©Y¸ÓHÑ€K�Ø�/ˆ3Ð_Ô'7¸ÐR^Ô'_Ð_r4   Újob_namec              #   ó¤  ‡ ‡‡K  — t        j                  «       Šd}	 ddlm}  |«       Šd
ˆˆ ˆfd„}‰�(t        j
                  |dd¬«      }|j                  «        	 d–— ‰j                  «        |�|j                  t        dz   ¬	«       yy# t        $ r dŠY Œqw xY w# ‰j                  «        |�|j                  t        dz   ¬	«       w w xY w­w)uý   Heartbeat into the caller's activity tracker while a manual run executes (minutes,
    synchronously on the caller's thread â€” without tool activity the gateway inactivity
    watchdog would kill the parent turn). Best-effort: no callback -> no thread.Nr   )Úget_activity_callbackc                  óF  •— t        j                  «       } ‰j                  t        «      sht        j                  «       | z
  }|t        kD  rt
        j                  d‰|«       y 	  ‰d‰› dt        |«      › d�«       ‰j                  t        «      sŒgy y # t        $ r Y Œ‰w xY w)Nuu   cronjob run heartbeat ceiling reached for job '%s' (%.0fs) â€” stopping heartbeat; gateway watchdog regains authorityzcronjob: running job 'ú' (z
s elapsed))	ÚtimeÚ	monotonicÚwaitÚ_CRON_RUN_HEARTBEAT_INTERVALÚ_CRON_RUN_HEARTBEAT_CEILINGrŠ   ÚwarningrZ   r9   )ÚstartedÚelapsedÚactivity_cbr•   Ústops     €€€r2   Ú_heartbeat_loopz'_run_heartbeat.<locals>._heartbeat_loopð   s–   ø€ Ü—.‘.Ó"ˆØ—)‘)Ô8Ô9Ü—n‘nÓ&¨Ñ0ˆGØÔ4Ò4ä—‘ð^à˜gô'ð ðÙÐ4°X°J¸cÄ#ÀgÃ,ÀÈzÐZÔ[ð —)‘)Ô8×9øô ò Ùðús   Á$B Â	B ÂB Tzcronjob-run-heartbeat)ÚtargetÚdaemonÚnameé   )rj   ©r,   N)
Ú	threadingÚEventÚtools.environments.baser—   r9   ÚThreadÚstartrA   Újoinr�   )r•   Úthreadr—   r¤   r¢   r£   s   `   @@r2   Ú_run_heartbeatr±   ×   sË   úè ø€ ô
 �?‰?Ó€DØ€Fðõ 	Bñ ,Ó-ˆ÷ð  ÐÜ×!Ñ!¨ÀÐLcÔdˆØ�‰ŒðBÛà�‰Œ
ØÐØ�K‰KÔ <¸qÑ @ˆKÕAð øô5 ò ØŠðûð2 	�‰Œ
ØÐØ�K‰KÔ <¸qÑ @ˆKÕAð üs?   …C�B ª2CÁB Á!-CÂBÂCÂBÂCÂ.CÃCc           	      óp  — | d   }d}d}	 ddl m}m}m}  ||«      s
ddt        dœS d}| j                  d«      }t        |t        «      rt        |j                  d	«      xs d
«      nd}t        t        j                  j                  d«      dd«      }	t        |	«      r |	«       nd}
|
�t        |
dd«      nd}|
�t        |
dd«      nd}	 t        t        | j                  d«      xs |«      «      5   || |||¬«      }ddd«       d} ||«       t        |«      xs i }d}| j                  d«      }|rddlm}  |t        |«      «      }|j                  d«      }|j                  d«      }|dk(  r|s|j                  d«      }|dv }|�B|j                  d«      dk7  r.d}|j                  d«      xs d|j                  d«      xs d› d�}dt#        xr |«      |dœS # 1 sw Y   ŒãxY w# d} ||«       w xY w# t$        $ r°}t&        j)                  d||«       |r7t+        j,                  t$        «      5   |«       ddd«       n# 1 sw Y   nxY wt+        j,                  t$        «      5  t/        |dt        |«      |¬«       ddd«       n# 1 sw Y   nxY wddt        |«      dœcY d}~S d}~ww xY w) zôFire an already-claimed job through the shared ``run_one_job`` body (split from
    ``_execute_job_now`` so the background path can claim synchronously and hand the run
    to a worker). Returns {"claimed": True, "success": bool, "error": ...}.rf   FNr   )Úrelease_running_jobÚrun_one_jobÚtry_register_running_jobTr†   Ú
fire_claimÚbyrI   zgateway.runÚ_gateway_runner_refÚadaptersÚ_gateway_loopr§   )r¹   Úlooprb   Úexecution_id)Úget_executionÚlast_statusÚ
last_errorÚdelivery_failedr{   >   ÚokÚdelivery_queuedÚstatusÚ	completedro   zexecution ended in Úunknownz statez-Failed to execute cron job %s immediately: %s)Úexpected_fire_owner)r8   r³   r´   rµ   Ú_ALREADY_RUNNING_ERRORrB   rˆ   r‰   r]   ÚgetattrÚsysÚmodulesÚcallabler±   r   Úcron.executionsr½   Úboolr9   rŠ   ro   r‹   rŒ   r   )r;   rb   r�   Ú_registeredÚ
fire_ownerr³   r´   rµ   ÚclaimÚ
runner_refÚrunnerr¹   Úgateway_loopÚ	processedrx   Ú	executionr¼   r½   r¾   Ú	run_errorrÁ   r�   s                         r2   r“   r“     s³  € ð �‰Y€FØ€KØ€JðADß]Ñ]ñ (¨Ô/Ø#°Ô@VÑWÐWØˆà—‘˜Ó%ˆÜ3=¸eÄTÔ3J”S˜Ÿ™ 4›Ò.¨BÔ/ÐPTˆ
ô œSŸ[™[Ÿ_™_¨]Ó;Ð=RÐTXÓYˆ
ô
 "*¨*Ô!5‘”¸4ˆØ8>Ð8J”7˜6 :¨tÔ4ÐPTˆØAGÐAS”w˜v ¸Ô=ÐY]ˆð	(ô  ¤ C§G¡G¨F£OÒ$=°vÓ >Ó?ñ nÙ'¨°hÀ\Ð`lÔm�	÷nð  ˆKÙ Ô'Ü˜F“OÒ) rˆ	Øˆ	Ø—w‘w˜~Ó.ˆÙÝ5á%¤c¨,Ó&7Ó8ˆIØ—m‘m MÓ2ˆð —M‘M ,Ó/ˆ	ØÐ+Ò+±IØ!Ÿ™Ð&;Ó<ˆIð Ð5Ð5ˆØÐ  Y§]¡]°8Ó%<ÀÒ%KØˆBØ!Ÿ™ gÓ.ÒtÐ4GÈ	ÏÉÐV^ÓH_ÒHlÐclÐGmÐmsÐ2tˆIØ¬D°Ò1A¸rÓ,BÈYÑWÐW÷3nð nûð  ˆKÙ Õ'ûô, ò 
DÜ�‰ÐDÀfÈaÔPÙô ×$Ñ$¤YÓ/ñ ,Ù# FÔ+÷,÷ ,ñ ,úä× Ñ ¤Ó+ñ 	PÜ˜ ¬¨A«ÀJÕO÷	P÷ 	Pñ 	Púà¨E¼CÀ»FÑCÕCûð
Dús„   ‹G< §B#G< Ã'G- Ã2G!Ã?G- ÄCG< Ç!G*Ç&G- Ç-G9Ç9G< Ç<	J5È2J0È7	I	É 	J0É	I	É J0É.JÊ	J0ÊJ	ÊJ0Ê*J5Ê0J5Újob_refc                 ó–   — 	 t        | «      }|€
ddd| › d�dœS t        ||¬«      S # t        $ r}ddt        |«      dœcY d}~S d}~ww xY w)aß  Fire an existing cron job in response to an external event.

    Public entry point for event-driven triggers (the webhook adapter's
    ``cron_job`` routes). Resolves ``job_ref`` (ID or name) and
    fires it through the exact same claimed-run body a manual
    ``cronjob(action='run')`` uses, so at-most-once claiming, in-flight
    dedupe, delivery, and ``[SILENT]`` handling stay identical across the
    scheduler / manual / event paths.

    ``extra_prompt`` is injected as transient per-run context (the job's
    stored prompt is never mutated), exactly like ``action='run'`` with a
    ``prompt`` argument.

    Returns the ``_execute_job_now`` result shape:
    ``{"claimed": bool, "success": bool, "error": str|None}``.
    Fr†   Nú
Cron job 'z' not found.r’   )r   r   r]   r”   )r×   rb   r;   r�   s       r2   Úexecute_job_for_eventrÚ   V  si   € ð&EÜ˜gÓ&ˆð €{àØØ! ' ¨,Ð7ñ
ð 	
ô
 ˜C¨lÔ;Ð;øô !ò EØ ¨U¼SÀ»VÑDÕDûðEús   ‚& ¦	A¯A½AÁAÚ	max_charsc                 ó  — 	 ddl m} t         |«       | z  j                  d«      «      }|r$|d   j	                  dd¬«      j                  «       nd}|sy	t        |«      |kD  r|d	| d
|d   › d�z   }|S # t        $ r Y y	w xY w)z�Excerpt of the job's most recent saved output file for the background completion
    block (parent sees what the job produced). Never raises.r   )Úget_cron_output_dirz*.mdéÿÿÿÿzutf-8Úreplace)ÚencodingÚerrorsrI   Nu   
â€¦ (truncated; full output: r~   )Ú	cron.jobsrÝ   ÚsortedÚglobÚ	read_textrY   Úlenr9   )r�   rÛ   rÝ   ÚfilesÚtexts        r2   Ú_latest_job_output_excerptré   v  s˜   € ð
Ý1ÜÑ+Ó-°Ñ6×<Ñ<¸VÓDÓEˆÙRWˆu�R‰y×"Ñ"¨G¸IÐ"ÓF×LÑLÔNÐ]_ˆÙØÜˆt‹9�yÒ Ø˜
˜Ð#Ð(GÈÈbÉ	À{ÐRSÐ&TÑTˆDØˆøÜò Ùðús   ‚AA4 ÁA4 Á4	B Á?B c                 ó¬   — 	 ddl m}  |«       }|rt        j                  d|| «       yy# t        $ r }t        j                  d|«       Y d}~yd}~ww xY w)a>  Reap execution rows left 'claimed'/'running' by a provably-dead owner (e.g. a prior
    one-shot `hermes cron run` that died mid-run). The ticker does this at startup; one-shot
    invocations have no such moment, so a stale claim would block every later manual run.
    Best-effort self-heal: must not block dispatch.r   )Úrecover_interrupted_executionszSReclaimed %d stale cron execution(s) from dead owner(s) before dispatching job '%s'z"Stale execution reclaim failed: %sN)rÌ   rë   rŠ   rŸ   r9   Údebug)r•   rë   Ú
_reclaimedÚ	_reap_excs       r2   Ú_reap_stale_executionsrï   †  sX   € ð
Fõ 	CÙ3Ó5ˆ
ÙÜ�N‰NØeØ˜Hõ&ð øô ò FÜ�‰Ð9¸9×EÑEûðFús   ‚&* ª	A³AÁAÚ
session_idc                 ój   — 	 ddl m}  |d¬«      }|xs | rt        | «      S dS # t        $ r d}Y Œ w xY w)zŠRouting key for a detached completion, captured on THIS thread (contextvars don't
    cross the pool). Empty string = no durable consumer.r   )Úget_current_session_keyrI   rP   )Útools.approval_contextrò   r9   r]   )rð   rò   Úsession_keys      r2   Ú_background_session_keyrõ   ›  sB   € ðÝBÙ-°bÔ9ˆð ÒA©jœ3˜z›?ÐA¸bÐAøô ò ØŠðús   ‚$ ¤2±2ÚresÚ
started_atc                 ó   — t        t        j                  «       |z
  d«      }t        |«      xs i }d|› d|› d�d| j                  d«      rdnd› �| j                  d	«      rd
| j                  d	«      › �ndz   d|› �t	        ||«      z   g}|j                  d«      r|j                  d|d   › �«       t        |«      }|r|d|gz  }| j                  d«      rdnd	dj                  |«      | j                  d	«      d|dœS )zGAsync-delegation completion block for a finished background manual run.r.   rÙ   r™   z) finished its manual run.zResult: rk   rÁ   ÚFAILEDro   u    â€” rI   zDelivery target: Únext_run_atzNext scheduled run: z--- JOB OUTPUT ---rÄ   Ú
r   )rÃ   Úsummaryro   Ú	api_callsÚduration_seconds)Úroundrš   r   rB   r€   Úappendré   r¯   )	rö   r�   r•   rw   r÷   Údurationrx   ÚlinesÚexcerpts	            r2   Ú_manual_run_completionr  ©  s  € ô ”T—Y‘Y“[ :Ñ-¨qÓ1€HÜ˜“Ò% 2€Ià
�X�J˜c & Ð)CÐDØ
˜3Ÿ7™7 9Ô-‘4°8Ð<Ð=Ø),¯©°Ô)9ˆU�3—7‘7˜7Ó#Ð$Ñ%¸rñ	Cà
˜G˜9Ð%Ô(AÀ'È9Ó(UÑUð	€Eð ‡}�}�]Ô#Ø�‰Ð+¨I°mÑ,DÐ+EÐFÔGÜ(¨Ó0€GÙØÐ&¨Ð0Ñ0ˆà!$§¡¨Ô!3‘+¸ÈTÏYÉYÐW\ÓM]Ø—‘˜Ó!°Àxñð r4   c                 óV  ‡‡‡‡‡‡— | d   Št        | j                  d«      xs ‰«      Št        ‰«       	 ddlm}  |«       sy	 t        |«      }|sy	 ddlm}  |‰«      r
ddt        dœS 	 t        ‰d	«      \  Š}|�|d
   rd|d<   |S d}	 ddlm}  |dd«      xs d}	 ddlm}	m}
  |	«       }	 ddlm}  |«       }t)        j(                  «       Šddlm}  |‰j                  dd«      «      Šdt,        t         t.        f   fˆˆˆˆˆˆfd„} |
d‰› d‰› d�ddd| j                  d«      ||rt        |«      nd||||¬«      }|j                  d «      dk(  rd!d!|j                  d"«      d#œS t        j1                  d$|j                  d%d&«      ‰«       t#        | ‰¬«      }d|d<   |S # t
        $ r Y �Œow xY w# t
        $ r Y �ŒWw xY w# t
        $ r Y �Œ4w xY w# t
        $ r5}t        j!                  d|‰«       t#        ‰‰¬«      }d|d<   |cY d}~S d}~ww xY w# t
        $ r d}Y �Œiw xY w)'aƒ  Claim ``job`` now (SYNCHRONOUSLY, so unrunnable jobs report immediately), then fire it
    on the async-delegation executor like ``delegate_task``'s background mode: the tool returns
    a handle and a ``type="async_delegation"`` completion re-enters as a fresh turn (role
    alternation legal, prompt cache intact) instead of blocking the parent turn for minutes.
    Returns None when background delivery is unavailable (caller runs sync); ``{"claimed":
    False}`` on a lost claim; ``{"claimed": True, "dispatched": True, "delegation_id"}``; or
    ``{"claimed": True, "dispatched": False, ...}`` when the pool was full and it ran inline.rf   r§   r   )Úasync_delivery_supportedN)Úis_job_runningFr†   zbackground runr‡   Ú
dispatchedrI   ©Úget_session_envÚHERMES_UI_SESSION_ID)Ú_current_origin_session_idÚdispatch_async_delegationzQcronjob run: async delegation registry unavailable (%s); running job '%s' inline.r’   )Ú_get_max_async_childrené   )Ú_normalize_deliver_valuerw   rz   r,   c                  ó<   •— t        ‰‰¬«      } t        | ‰‰‰‰«      S )Nr’   )r“   r  )rö   r�   rw   rb   r�   r•   r÷   s    €€€€€€r2   Ú_runnerz-_try_dispatch_background_run.<locals>._runner  s"   ø€ Ü˜{¸ÔFˆÜ% c¨6°8¸WÀjÓQÐQr4   zManual run of cron job 'r™   r~   ztTriggered via cronjob(action='run'). The job executed in its own fresh cron session; this block reports its outcome.Úcron_runÚmodel)ÚgoalÚcontextÚtoolsetsÚroler  rô   Úparent_session_idrÒ   Úorigin_ui_session_idÚorigin_session_idÚmax_async_childrenrÃ   TÚdelegation_id)r‡   r  r  zGcronjob run: background pool unavailable (%s); running job '%s' inline.ro   Úrejected)r]   rB   rï   Úgateway.session_contextr  r9   rõ   r8   r  rÇ   r�   r
  Útools.async_delegationr  r  rŠ   rŸ   r“   Útools.delegate_toolr  rš   r  r   r   Úinfo)r;   rð   rb   r  rô   r  r   r  r
  r  r  r  r�   Úresultr  Ú	max_asyncr  r  Údispatchr�   rw   r�   r•   r÷   s     `                @@@@@r2   Ú_try_dispatch_background_runr&  ¿  st  ý€ ð �‰Y€FÜ�3—7‘7˜6“?Ò, fÓ-€Hô ˜8Ô$ðÝDÙ'Ô)Øð *ô *¨*Ó5€Kñ Øð
Ý1Ù˜&Ô!Ø$°ÔAWÑXÐXð "ô
 -¨VÐ5EÓFÑ€K�Ø
€ØˆyŠ>Ø %ˆC�ÑØˆ
àÐðÝ;Ù.Ð/EÀrÓJÒPÈbÐðß`Ù6Ó8ÐðÝ?Ù+Ó-ˆ	ô —‘“€Jå7Ù& {§¡°yÀ'Ó'JÓK€GðR”Tœ#œs˜(‘^÷ Rò Rñ )Ø'¨ z°°V°H¸AÐ>ðGà˜J¨c¯g©g°gÓ.>ÈKÙ-7œ#˜jœ/¸TÈ'Ø1ÐEVØ$ô&€Hð ‡|�|�HÓ Ò-Ø¨tÀhÇlÁlÐSbÓFcÑdÐdô ‡K�KØQØ�‰�W˜jÓ)¨8ô5ô ˜c°Ô=€FØ €Fˆ<ÑØ€Møô[ ò Úðûô& ò Úðûô ò Úðûô ò Ü�‰Ø_ÐabÐdlô	nä! +¸LÔIˆØ$ˆˆ|ÑØ�ûðûô ò Ø‹	ðúse   ¶F( ÁF8 ÂG Â!G Â1H Æ(	F5Æ4F5Æ8	GÇGÇ	GÇGÇ	HÇ!*HÈHÈHÈH(È'H(r#  c                 ó,   — t        ||«      }|r|| d<   | S )zFAttach mode/delivery guidance (create and update echo the same notes).Úguidance)r   )r#  r;   rw   Ú_notess       r2   Ú_with_guidancer*  )  s    € ä! # wÓ/€FÙØ#ˆˆzÑØ€Mr4   Úac                 óz  — | d   | d   }}t        | d   «      }| d   st        dd¬«      S t        | d   | d	   «      }t        | d
   «      }|r|st        dd¬«      S |s|st        dd¬«      S |xr t	        |«      xs� |xr t        |«      xs | d   xr t        | d   «      xsh t        | d   | d   «      xsT t        |«      xsG t        t        | d   «      «      xs. | d   xr' t        t        | d   t        «      r| d   gn| d   «      }|rt        |d¬«      S | d   }| d   �t        || d   «      }ddlm}m}	 	  |	d1i d|xs d“d| d   “d| d   “d| d   “dt        |«      “dt!        | d   «      “d	|“dt#        | d   «      “dt#        | d   «      “dt#        | d   d¬«      “dt#        |«      “d|“d| d   xs d “dt#        | d   «      “d
|“d| d   “dt#        | d   «      “dt#        | d   «      “d | d    “d!t        | d!   «      “dt        t        | d   «      «      “| d"   dus| d#   �| d"   | d#   d$œni ¤Ž}
d'j)                  t+        d d(|
d   › d)�|
j-                  d*d«      sd+nd t/        |
|«      f«      «      }d|
d,   |
d   |
j-                  d«      |
j-                  d	g «      |
d-   t1        |
«      |
j-                  dd.«      |
d/   t3        |
«      |d0œt5        «       ¥}t7        t9        ||
|«      «      S # |$ r7}|j%                  «       }t        |j'                  d%«      fd&di|¤ŽcY d }~S d }~ww xY w)2Nrh   Úscriptrw   Úschedulezschedule is required for createF©rk   ÚskillÚskillsÚno_agentu  create with no_agent=True requires a script â€” the script is the job. In no_agent mode the LLM is skipped entirely: prompt and skills are ignored, non-empty stdout is delivered verbatim, empty stdout sends nothing (watchdog pattern), and a non-zero exit or timeout sends an error alert.z3create requires either prompt or at least one skillÚmonitor_scriptÚproviderÚbase_urlÚfailure_deliverÚcontext_fromÚ
continuityr   )ÚCronSchedulerRegistrationErrorÚ&create_job_with_scheduler_registrationrI   r§   ÚrepeatÚoriginr  T©Ústrip_trailing_slashÚenabled_toolsetsÚworkdirÚattach_to_sessionÚmonitor_urlÚreasoning_effortÚpinnedÚpausedÚpaused_reason)rE  rF  ro   rk   Ú rÙ   z
' created.Úenabledu=   Created PAUSED â€” resume to schedule, or explicitly run now.rf   Úschedule_displayrz   rú   )rk   r�   r§   r0  r1  r.  r;  rw   rú   r;   Úmessage© )r   r*   r   rÍ   r   r(   r'   r%   r&   rˆ   r]   r   r8   r9  r:  r#   r!   r    Úto_dictÚpopr¯   ÚfilterrB   r   r"   r   r   r3   r*  )r+  rh   r-  rw   Úcanonical_skillsÚ	_no_agentro   r7  r9  r:  r;   ÚexcÚ_partialÚ_create_messageÚ_results                  r2   Ú_action_createrU  1  s_  € Ø�x‘[ ! H¡+ˆF€FÜ& q¨¡|Ó4€GØˆZŠ=ÜÐ;ÀUÔKÐKÜ(¨¨7©°Q°x±[ÓAÐÜ�Q�z‘]Ó#€IáÙÜðið
 ôð ñ Ñ,ÜÐOÐY^Ô_Ð_à	Ò	-Ô% fÓ-ò 	_ØÒ9Ô1°&Ó9ò	_àÐÑÒSÔ$>¸qÐAQÑ?RÓ$Sò	_ô
 # 1 Z¡=°!°J±-Ó@ò	_ô & gÓ.ò	_ô &Ô&>¸qÐARÑ?SÓ&TÓUò	_ð ˆnÑò ^Ô"=Ü#-¨a°Ñ.?ÄÔ#EˆQˆ~ÑÑÈ1È^ÑK\ó#^ð 
ñ Ü˜%¨Ô/Ð/à�^Ñ$€LØˆ�Ð"Ü(¨°q¸±ÓGˆçeðLÙ4ò WØ’<˜RøðWØ*+¨Jª-ðWØ>?ÀºiðWØPQÐRZÒP[ðWä1°'Ô:ðWô $ A j¡MÔ2ðWñ $ð	Wô
 0°°'±
Ô;ðWô
 GdÐdeÐfpÑdqÔFrðWô 3°1°Z±=ÐW[Õ\ðWô 1°Ô8ðWñ HTðWð Ð1Ñ2Ò:°døðWô EbÐbcÐdmÑbnÔDoðWñ ðWð 34Ð4GÒ2HðWô 9¸Ð;KÑ9LÔMðWô 6°a¸Ñ6FÔGðWð Ð1Ò2ðWô ˜˜(™Ô$ðWô :Ô:RÐSTÐUfÑSgÓ:hÔià�H‘+ UÑ*¨a°Ñ.@Ð.Lð ˜H™+¸¸/Ñ8JÒKØRTñ#Wˆð* —h‘hœv d¨z¸#¸f¹+¸ÀjÐ-QØORÏwÉwÐW`ÐbfÔOgÑGÐmqÜ˜s GÓ,ð-.ó  /ó 0€Oð  3 t¡9°c¸&±kÈCÏGÉGÐT[ÓL\Ø—'‘'˜( BÓ'°SÐ9KÑ5LÔXgÐhkÓXlØ—7‘7˜9 gÓ.¸sÀ=Ñ?QÔZeÐfiÓZjØ"ñ	ô '?Ó&@ð	€Gô ”. ¨#¨wÓ7Ó8Ð8øð *ò LØ—;‘;“=ˆÜ˜(Ÿ,™, wÓ/ÑK¸ÐKÀ(ÑKÕKûðLús   Ä?DK> Ë>L:Ì,L5Ì/L:Ì5L:c                 óÄ   — t        | d   ¬«      D �cg c]  }t        |«      ‘Œ }}dt        |«      |dœ}|r|j                  t	        d¬«      «       t        |«      S c c}w )NÚinclude_disabled)rW  T)rk   ÚcountÚjobs)Úplural)r   r   ræ   Úupdater   r3   )r+  r;   rY  rT  s       r2   Ú_action_listr\  }  s\   € Ü(1À1ÐEWÑCXÔ(YÖZ ŒK˜ÕÐZ€DÐZØ¬¨T«¸DÑA€Gáð 	�‰Ô/°tÔ<Ô=Ü�'‹?Ðùò [s   ’Ac           	      ó°   — | d   }t        |«      st        d|› d�d¬«      S t        «        t        dd| d   › d	�|| d   | j	                  d
«      dœdœ«      S )Nrf   zFailed to remove job 'ú'Fr/  TrÙ   r§   z
' removed.rI  )rf   r§   r.  )rk   rJ  Úremoved_job)r   r*   r:   r3   rB   )r;   r+  r�   s      r2   Ú_action_remover`  ˆ  sm   € Ø�‰Y€FÜ�fÔÜÐ2°6°(¸!Ð<ÀeÔLÐLÜ&Ô(ÜØØ  F¡˜}¨JÐ7Ø$¨c°&©kÀsÇwÁwÐOaÓGbÑcñó ð r4   Úupdatedc                 óD   — t        «        t        dt        | «      dœ«      S )NT©rk   r;   )r:   r3   r   )ra  s    r2   Ú_job_state_resultrd  ”  s   € Ü&Ô(Ü˜d¬;°wÓ+?Ñ@ÓAÐAr4   c                 ó6   — t        t        | «      xs d| i«      S )zFRe-read so the response reflects the post-run last_run_at/last_status.rf   )r   r   )r�   s    r2   Ú_refreshed_job_viewrf  ™  s   € ä”w˜v“Ò8¨4°¨.Ó9Ð9r4   c                 ór  — | d   }|d   xs d }|rt        |«      }|rt        |d¬«      S t        | |d   |¬«      }|�S|j                  d«      rBt	        «        t        |«      }d|d	<   d
|d<   |j                  d«      |d<   t        d|ddœ«      S |�|}nt        | |¬«      }|�|S t        | |¬«      }|j                  dd«      }	|	r
t	        «        t        |«      }|	|d	<   |j                  dd«      |d<   |	s|j                  d«      xs d|d<   n|j                  d«      r|d   |d<   t        d|dœ«      S )Nrf   rh   Fr/  rð   )rð   rb   r  TÚexecutedÚ
backgroundÚexecution_moder  u¹   The job is running in the background. You and the user can keep working; its outcome re-enters the conversation as a new message when it finishes. Do not wait or poll â€” just continue.)rk   r;   rm   r’   r‡   rk   Úexecution_successro   z4Already being fired by the scheduler; not run again.Úexecution_skippedÚexecution_errorrc  )	r   r*   r&  rB   r:   rf  r3   rv   r”   )
r;   r+  r�   rb   Ú
scan_errorÚbgr#  Úexec_resultÚ	forwardedr‡   s
             r2   Ú_action_runrr  ž  sx  € Ø�‰Y€Fð �X‘;Ò& $€LáÜ& |Ó4ˆ
ÙÜ˜j°%Ô8Ð8ô 
& c°a¸±oÐT`Ô	a€BØ	€~˜"Ÿ&™& Ô.Ü*Ô,Ü$ VÓ,ˆØ!ˆˆzÑØ#/ˆÐÑ Ø"$§&¡&¨Ó"9ˆˆÑÜØØð9ñ	
ó ð 	ð 
€~Ø‰ô /¨sÀÔNˆ	ØÐ ØÐÜ& s¸ÔFˆð �o‰o˜i¨Ó/€GÙÜ*Ô,Ü  Ó(€FØ €Fˆ:ÑØ"-§/¡/°)¸UÓ"C€FÐÑÙØ&1§o¡o°gÓ&>ò 'DØBð 	Ð"Ò#à	�‰˜Ô	!Ø$/°Ñ$8ˆÐ Ñ!Ü˜d¨6Ñ2Ó3Ð3r4   Úupdatesrt   c                 ó6   — || v r| |   S |j                  |«      S )zVEffective value of ``key`` after this update: pending update wins over the stored job.)rB   )rs  r;   rt   s      r2   Ú_pickru  Ó  s   € à '™>ˆ7�3‰<Ð;¨s¯w©w°s«|Ð;r4   c                 óº  — |d   |d   |d   |d   f\  }}}}|�t        |«      }|r|S ||d<   |d   �|d   j                  «       r|d   |d<   |�/t        t        |«      «      }|r|S t	        t        |«      «      |d<   |d   �/t        |d   «      }	|	rt        |	«      }|r|S t	        |	«      }	|	|d<   |€|�t        ||«      }
|
|d<   |
r|
d   nd|d<   |d	   �t        |d	   «      |d	<   |d
   �t        |d
   «      |d
<   |d   �t        |d   «      |d<   |d   �t        |d   d¬«      |d<   |d   �|d   |d<   t        t        || d
«      t        || d«      «      S )zOprompt / name / deliver / skills / model pins; returns an error string or None.rh   rw   r0  r1  Nr§   r6  r   r  r4  rD  r5  Tr=  rC  )
r   rY   r%   r   r#   r   r    rÍ   r'   ru  )r;   r+  rs  rh   rw   r0  r1  rn  Úbot_chat_errorÚ_norm_fdrO  s              r2   Ú_update_core_fieldsry  Ø  sÝ  € à%& x¡[°!°I±,ÀÀ'Á
ÈAÈhÉKÐ%WÑ"€FˆG�U˜FØÐÜ& vÓ.ˆ
ÙØÐØ"ˆ�ÑØˆ�yÐ  6¡§¡Ô!2ð ˜F™)ˆ�‰ØÐÜ3Ô4LÈWÓ4UÓVˆÙØ!Ð!Ü:Ô;SÐT[Ó;\Ó]ˆ�	ÑØÐ	ÑÐ'ô ,¨AÐ.?Ñ,@ÓAˆÙÜ7¸ÓAˆNÙØ%Ð%Ü4°XÓ>ˆHØ%-ˆÐ!Ñ"ØÐ˜UÐ.Ü,¨U°FÓ;ÐØ,ˆ�ÑÙ2BÐ+¨AÒ.Èˆ�ÑØˆ�zÐÜ8¸¸7¹ÓDˆ�ÑØˆ�}Ð Ü;¸A¸j¹MÓJˆ�
ÑØˆ�{ÐÜ   8¡Ó-ˆ�ÑØˆ�}Ð Ü;¸A¸j¹MÐ`dÔeˆ�
ÑØÐ	ÑÐ(à&'Ð(:Ñ&;ˆÐ"Ñ#ô #¤5¨°#°zÓ#BÄEÈ'ÐSVÐXbÓDcÓdÐdr4   c                 óô   — |d   |d   }}d|d   fd|ffD ]-  \  }}|€Œ	|rt        |«      }|r|c S |rt        |«      nd||<   Œ/ |�|rt        |«      nd|d<   |€|�t        || d«      rt        || d«      ryy)z]script / monitor_script / monitor_url (empty string clears); returns an error string or None.r3  rB  r-  Nu]   monitor_script and monitor_url are mutually exclusive â€” clear one before setting the other.)r(   r    ru  )r;   r+  rs  r3  rB  ÚfieldÚvalueÚ
path_errors           r2   Ú_update_script_fieldsr~  	  sµ   € à"#Ð$4Ñ"5°q¸Ñ7G�K€NØ" A h¡KÐ0Ð3CÀ^Ð2TÐUò U‰ˆˆuØÑÙÜ7¸Ó>�
ÙØ%Ò%ÙEJÔ:¸5ÔAÐPTˆG�EŠNðUð ÐÙOZÔ!>¸{Ô!KÐ`dˆ�ÑØÐ" kÐ&=Üˆg�sÐ,Ô-´%¸ÀÀmÔ2TØnØr4   c                 óÐ   — |d   |d   }}|€|€y|€t        | j                  d«      xs g «      }t        |«      }|�t        ||«      xs g }|rt	        |«      }|r|S |xs d|d<   y)zŒcontext_from / continuity: empty string / list clears; otherwise every ref must
    exist. Stored as a list (or None) to match create_job().r7  r8  N)ÚlistrB   r   r   r&   )r;   r+  rs  r7  r8  ÚrefsÚ	ref_errors          r2   Ú_update_context_fromrƒ    sŠ   € ð  ! Ñ0°!°L±/�*€LØÐ 
Ð 2ØØÐÜ˜CŸG™G NÓ3Ò9°rÓ:ˆÜ˜<Ó(€DØÐÜ   zÓ2Ò8°bˆÙÜ/°Ó5ˆ	ÙØÐØ"šl d€GˆNÑØr4   c                 óì  — |d   �|d   xs d|d<   |d   �t        |d   «      |d<   |d   �t        |d   «      xs d|d<   |d   �$t        |d   «      }|rt        || d«      s	 y||d<   |d   �7d	d
lm} t        | j                  d«      xs i «      } ||d   «      |d<   ||d<   |d   �It        |d   «      }||d<   |j                  d|d   «      |d<   | j                  d«      dk7  r
d|d<   d|d<   y)zNenabled_toolsets / attach_to_session / workdir / no_agent / repeat / schedule.r?  NrA  r@  r2  r-  ziCannot set no_agent=True on a job without a script. Set `script` in the same update, or on the job first.r;  r   )Únormalize_repeat_valueÚtimesr.  ÚdisplayrI  ÚstaterE  Ú	scheduledTrH  )rÍ   r    ru  râ   r…  r‰   rB   r   )r;   r+  rs  Útarget_no_agentr…  Úrepeat_stateÚparsed_schedules          r2   Ú_update_run_fieldsr�  .  sN  € àÐ	ÑÐ(Ø&'Ð(:Ñ&;Ò&C¸tˆÐ"Ñ#ØÐ	ÑÐ)Ü'+¨AÐ.AÑ,BÓ'CˆÐ#Ñ$Øˆ�|Ðä:¸1¸Y¹<ÓHÒPÈDˆ�	ÑØˆ�}Ð ä˜q ™}Ó-ˆÙ¤5¨°#°xÔ#@ðHðIð .ˆ�
ÑØˆ�{Ðå4Ü˜CŸG™G HÓ-Ò3°Ó4ˆÙ 6°q¸±{Ó Cˆ�WÑØ(ˆ�ÑØˆ�}Ð Ü(¨¨:©Ó7ˆØ-ˆ�
ÑØ&5×&9Ñ&9¸)ÀQÀzÁ]Ó&SˆÐ"Ñ#Ø�7‰7�7Ó˜xÒ'Ø*ˆG�GÑØ!%ˆG�IÑØr4   c           
      óþ   — i }t         D ]  } || ||«      }|sŒt        |d¬«      c S  |st        dd¬«      S t        | d   |«      }t        «        t	        t        dt        |«      dœ|t        |d   «      «      «      S )NFr/  zNo updates provided.rf   Trc  rw   )Ú_UPDATE_STEPSr*   r   r:   r3   r*  r   r   )r;   r+  rs  Ústepro   ra  s         r2   Ú_action_updater‘  S  s’   € Ø €GÜò 4ˆÙ�S˜!˜WÓ%ˆÚÜ˜e¨UÔ3Ò3ð4ñ ÜÐ0¸%Ô@Ð@Ü˜˜T™ GÓ,€GÜ&Ô(ä”.Ø¤¨WÓ!5Ñ6¸ÔAYÐZ[Ð\eÑZfÓAgóió jð jr4   )Úcreater€  c                 ó:   — t        t        | d   |d   ¬«      «      S )Nrf   rŽ   )rŽ   )rd  r   ©r;   r+  s     r2   ú<lambda>r•  f  s   € Ô-¬i¸¸D¹	È!ÈHÉ+Ô.VÓW€ r4   c                 ó0   — t        t        | d   «      «      S )Nrf   )rd  r   r”  s     r2   r•  r•  g  s   € Ô.¬z¸#¸d¹)Ó/DÓE€ r4   )Úremover[  ÚrunÚrun_nowÚtriggerÚpauseÚresumec                 óT  — 	 t        | «      }|sdt        dd	| › d
�dœ«      fS |dfS # t        $ rw}dt        dt        |«      |j                  D �cg c]9  }|d   |j                  d«      |j                  d«      |j                  d«      dœ‘Œ; nc c}w c}dœ«      fcY d}~S d}~ww xY w)zF``(job, None)`` or ``(None, json_error)`` for a job_id/name reference.NFrf   r§   rI  rú   )rf   r§   r.  rú   )rk   ro   ÚmatcheszJob with ID or name 'z8' not found. Use cronjob(action='list') to inspect jobs.rn   )r   r   r3   r]   rž  rB   )r�   r;   rQ  Úms       r2   Ú_resolve_job_or_errorr   k  sÜ   € ð
Ü˜fÓ%ˆñ Ø”VØÐ*?À¸xÐGð  )Añ  Bó
ð 
ð 	
ð �ˆ9Ðøô !ò Ø”VØÜ˜“Xð Ÿ™öàð ˜‘w¨¯©¨f«À1Ç5Á5ÐI[ÓC\Ðmn×mrÑmrð  tAó  nBó  Cñùô ñ
ó ð õ 	ûðús&   ‚' §	B'°B"Á>BÂB"ÂB'Â"B'FÚactionrh   r.  r§   r;  rW  r0  r1  r  r4  r5  rŽ   r-  r7  r8  r?  r@  r2  rA  r3  rB  rC  r6  Útask_idrE  rF  rD  c                 ó¶  — t        t        «       «      }|d= 	 | xs dj                  «       j                  «       }t        j                  |«      } | � | |«      S |st        d|› d�d¬«      S t        |«      \  }!}"|"�|"S t        j                  |«      } | €t        d| › d�d¬«      S  | |!|«      S # t        $ r }#t        t        |#«      d¬«      cY d}#~#S d}#~#ww xY w)	z!Unified cron job management tool.r¢  rI   Nzjob_id is required for action 'r^  Fr/  zUnknown cron action ')r‰   ÚlocalsrY   ÚlowerÚ_JOBLESS_ACTIONSrB   r*   r   Ú_JOB_ACTIONSr9   r]   )$r¡  r�   rh   r.  r§   r;  rw   rW  r0  r1  r  r4  r5  rŽ   r-  r7  r8  r?  r@  r2  rA  r3  rB  rC  r6  r¢  rð   rE  rF  rD  r+  Ú
normalizedÚhandlerr;   ro   r�   s$                                       r2   Úcronjobrª    sæ   € ô@ 	ŒV‹X‹€AØ	ˆ)ˆð1Ø’l ×)Ñ)Ó+×1Ñ1Ó3ˆ
Ü"×&Ñ& zÓ2ˆØÐÙ˜1“:ÐÙÜÐ ?À
¸|È1ÐMÐW\Ô]Ð]ô +¨6Ó2‰
ˆˆUØÐØˆLÜ×"Ñ" :Ó.ˆØˆ?ÜÐ 5°f°X¸QÐ?ÈÔOÐOÙ�s˜A‹ÐøÜò 1Üœ#˜a›&¨%Ô0Õ0ûð1ús6   ˜A B/ ÁB/ Á,B/ Á>'B/ Â&B/ Â/	CÂ8CÃCÃCÚhomec                 ó   — d| › d�S )NzžOptional script run each tick; stdout is injected into the agent's prompt as context (with no_agent=True the script IS the job). Relative paths resolve under zA/scripts/; .sh/.bash via bash, else Python. On update, '' clears.rK  )r«  s    r2   Ú_script_descriptionr­  µ  s   € ðDØDHÀ6ð J$ð$ð %r4   c                  óz   — t        j                  t        d   «      } t        t	        «       «      | d   d   d<   d| iS )a  Rebuild the ``script`` path hint from the ACTIVE profile at every get_definitions(): the
    static schema is built once per process, but the multiplexed gateway serves every profile from
    that process, so a path baked in at import would name the launch profile's home (#95685).Ú
parametersÚ
propertiesr-  Údescription)ÚcopyÚdeepcopyÚCRONJOB_SCHEMAr­  r	   )Úparamss    r2   Ú_cronjob_schema_overridesr¶  »  s?   € ô �]‰]œ>¨,Ñ7Ó8€FÜ4GÔH[ÓH]Ó4^€Fˆ<Ñ˜Ñ" =Ñ1Ø˜&Ð!Ð!r4   Úcronjob_manageu~  Manage scheduled cron jobs: action='create' schedules a job from a prompt and/or skills; 'list' inspects jobs; 'update'/'pause'/'resume'/'remove' manage one by job_id (always list first â€” never guess job IDs); 'run' fires a job immediately in the BACKGROUND (returns a handle at once, outcome re-enters the conversation when done â€” do not wait or poll; optional 'prompt' adds transient context for that fire only).

Jobs run on the main agent model (whatever `hermes model` is set to when they fire) unless pinned.

Jobs run in a fresh session with no current-chat context, so prompts must be self-contained, and the agent's FINAL RESPONSE is what gets delivered â€” cron runs are autonomous and cannot ask questions. Jobs run on the main agent model (whatever `hermes model` is set to when they fire) unless the user pins one. Prefer updating an existing job over creating near-duplicates.ÚobjectÚbooleanzlCreate only: persist disabled atomically. Resume to schedule; explicit run remains available. Default false.)Útyper±  Ústringz4Create only: auditable reason; requires paused=true.z~One of: create, list, update, pause, resume, remove, run. When action=create, the 'schedule' and 'prompt' fields are REQUIRED.z,Required for update/pause/resume/remove/run.a~  For create/update. ONLY set when the user explicitly asks to pin (or unpin) a job's model. pinned=true locks the CURRENT main agent model (and its provider) onto the job so later `hermes model` / `/model` changes never touch it; pinned=false releases the lock so the job follows the main agent model again. Never set it on your own initiative: by default jobs follow the main model.z¨For create: the full self-contained prompt (paired with any skills as the task instruction). For run: optional transient context for that single fire (never persisted).u  REQUIRED for create. Schedule forms: (1) recurring interval â€” '30m', 'every 2h', 'every hour' (EVERY 30 minutes / 2 hours / hour, forever by default); (2) explicit one-shot by duration â€” 'in 30m', 'in 2h' (fires ONCE that far from now; use this for 'remind me in N minutes' â€” do NOT hand-compute an absolute timestamp); (3) natural day/time â€” 'every monday 9am', 'weekdays at 9am', 'every day at 9am' (recurring weekly/daily); (4) cron syntax â€” '0 9 * * *' (daily 9am); (5) absolute one-shot â€” ISO timestamp '2026-06-01T09:00:00'.)rº  rº  r±  zOptional human-friendly nameÚintegerzTOptional repeat count. Omit for defaults (once for one-shot, forever for recurring).aÕ  Where the job's output is POSTED as a one-way message (the job itself always runs in a fresh session with no chat context). Omit to address the chat/topic this job was created from. Otherwise: 'local' (save only, no delivery), 'all' (every connected home channel, resolved at fire time), 'bot-chat' or 'bot-chat:<profile>' (inject into a Bot Chat as a real message), or platform:chat_id:thread_id (e.g. 'telegram:-1001234567890:17585'). Comma-combine like 'origin,all'.a�  Optional override target for FAILURE notices only (same grammar as deliver). When set, engine failure/interruption notices go here instead of the deliver target; 'local' suppresses them entirely (state still recorded in cron list/run history). Use for jobs delivering into shared channels where failure noise is unwanted. Omit = failures follow deliver (default). On update, '' clears.Úarrayrº  zQOptional ordered skill names loaded before the cron prompt. On update, [] clears.)rº  Úitemsr±  zthe profile HERMES_HOMEÚmonitoruÅ  Optional change-detector that gates the agent: an http(s) URL (fetched each tick) or a script path (same rules as `script`, run each tick) â€” cheap, no LLM. Output identical to the previous tick skips the agent run entirely; changed output wakes the agent with a diff injected into the prompt. First tick always runs (baseline). Output must be deterministic (no timestamps) or every tick looks changed. Incompatible with no_agent. On update, '' clears.zêTrue = no LLM: the scheduler runs `script` (required) on schedule and delivers its stdout verbatim; empty stdout sends nothing (watchdog pattern). Use for script-only pings with fixed output; keep False for anything needing reasoning.)rº  rQ   r±  uË   Optional job ID(s) whose most recent completed output is injected as context each run â€” chains jobs (A collects, B processes). For a job's OWN previous output prefer `continuity`. On update, [] clears.zºTrue = each run sees the job's own previous output, so it can dedupe and continue where it left off (scouts, monitors, incremental digests). Default false. On update, false turns it off.u²   Optional toolset names to restrict the job's agent to (e.g. ["web", "terminal"]) â€” cuts token overhead. Infer from the prompt. Omit for all default tools. On update, [] clears.z¢Optional absolute existing path to run the job from: injects that directory's AGENTS.md/context files and anchors terminal/file tools there. On update, '' clears.u¨  True = the job's delivery is CONTINUABLE â€” the user can reply and the agent has the brief in context (threads on thread-capable platforms, mirrored into the DM elsewhere). Use for conversational recurring jobs (briefings); leave unset for fire-and-forget alerts. Scope: the job's own conversation only â€” the origin chat, the home-channel fallback when deliver='origin' captured no origin (script-created jobs), a user-written bare platform target (deliver='slack' â€” that platform's home channel), or the job's single explicit platform:chat target (this flag is the only way to attach an explicit target). Broadcast targets are never attached; no effect when deliver='local'.)r?  r@  rA  )rº  r°  Úrequired)r§   r±  r¯  c                  óx   — ddl m}  ddlm}m}  |d«      xs#  |d«      xs  |d«      xs  | | dd«      «      S )	aZ  Available in interactive CLI mode, gateway/messaging platforms, and cron runs (the
    scheduler is internal; no crontab needed). Flags must be explicitly truthy via
    ``env_var_enabled``. An external cron worker has the presence vars stripped from its env, so
    the cron session marker keeps ``cron.allow_agent_scheduling`` meaningful there.r   r	  )Úenv_var_enabledÚis_truthy_valueÚHERMES_INTERACTIVEÚHERMES_GATEWAY_SESSIONÚHERMES_EXEC_ASKÚHERMES_CRON_SESSIONrI   )r  r
  ÚutilsrÂ  rÃ  )r
  rÂ  rÃ  s      r2   Úcheck_cronjob_requirementsrÉ  #  sN   € õ
 8ß6áÐ,Ó-ò 	GÙÐ3Ó4ò	GáÐ,Ó-ò	Gñ ™?Ð+@À"ÓEÓFð	r4   )r�   rh   r.  r§   r;  rw   r6  r0  r1  rŽ   r-  r7  r8  r?  r@  r2  rA  rF  rD  c                 óŒ  — t        | j                  d«      | j                  d«      | j                  d«      «      \  }}t        d| j                  dd«      | j                  dd«      |||j                  d«      |j                  d	«      | j                  d
d«      dœt        D �ci c]  }|| j                  |«      “Œ c}¤ŽS c c}w )z¥Model-tool dispatch: resolves the one model-facing ``monitor`` field into the stored
    ``monitor_script``/``monitor_url`` pair (legacy field names still accepted).r¿  r3  rB  r¡  rI   rW  Tr¢  rð   rE  F)r¡  rW  r3  rB  r¢  rð   rE  rK  )r$   rB   rª  Ú_HANDLER_FORWARDED_ARGS)ÚargsÚkwÚ_mon_scriptÚ_mon_urlrt   s        r2   Ú_cronjob_handlerrÐ  <  s»   € ô /¨t¯x©x¸	Ó/BÀDÇHÁHÐM]ÓD^Ð`d×`hÑ`hÐivÓ`wÓxÑ€K�Üð 	Ø�x‰x˜ "Ó%ØŸ™Ð"4°dÓ;Ø"ØØ—‘�yÓ!Ø—6‘6˜,Ó'Ø�x‰x˜ %Ó(ñ	ô *AÖ
A #ˆ3�—‘˜“ÑÒ
Añ	ð 	ùò Bs   Â#Crª  u   â�°)r§   ÚtoolsetÚschemar©  Úcheck_fnÚemojiÚdynamic_schema_overridesÚeffective_job_state)z	cron.jobsrÖ  c                 óÌ   — t         j                  | «      }|€t        dt        ›d| ›�«      ‚dd l}ddlm}  |t        | g|¢­Ž  t        |j                  |d   «      |d   «      S )Nzmodule z has no attribute r   )Ú	warn_oncer¨   )	Ú_PLUGIN_COMPAT_LAZYrB   ÚAttributeErrorÚ__name__Ú	importlibÚhermes_cli.plugin_compatrØ  rÈ   Úimport_module)r§   r¥   rÜ  rØ  s       r2   Ú__getattr__rß  c  se   € Ü ×$Ñ$ TÓ*€FØ€~Ü˜w¤x lÐ2DÀTÀHÐMÓNÐNÛÝ2ÙŒh˜Ð&˜vÓ&Ü�9×*Ñ*¨6°!©9Ó5°v¸a±yÓAÐAr4   r©   )N)iÐ  )NN)NNNNNNFNNNNNNNNNNNNNNNNNNNFNN)sÚ__doc__r‹   r0   ÚloggingrÉ   rª   rš   Úpathlibr   Útypingr   r   r   r   r   r²  Úhermes_constantsr	   Ú	getLoggerrÛ  rŠ   r�   rž   ÚpathÚinsertr]   Ú__file__Úparentrâ   r   r   r   r   r   r   r   r   r   r   r   r   Útools.cronjob_prompt_scanr   Útools.cronjob_job_argsr   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   Útools.registryr)   r*   r3   r:   rA   rF   ra   rv   r€   rÇ   r�   r”   Úcontextmanagerr±   r“   rÚ   rZ   ré   rï   rõ   Úfloatr  r&  r*  rU  r\  r`  rd  rf  rr  ru  ry  r~  rƒ  r�  r�  r‘  r¦  r§  r   rÍ   rª  r­  r‰   r¶  r´  rÉ  rË  rÐ  ÚregisterÚrerÙ  rß  rK  r4   r2   ú<module>rñ     s•
  ðñYó Û Û Û 
Û Û Ý ß 3Õ 3ã å 0à	ˆ×	Ñ	˜8Ó	$€ð  $Ð ð )Ð à ‡�‡��‘3‘t˜H“~×,Ñ,×3Ñ3Ó4Ô 5÷÷ ÷ ó õ 8÷ ÷  ÷  ÷  õ  ÷$ 0ð)�D˜˜c˜‘Nð ) só )óðO¨4°°S°©>ð O¸có Oð"#˜có #ñ, D¨¨c¨¡Nð À(È3Á-ð Ð[cÐdgÑ[hó ðD2 sð 2°t¸CÀ¸H±~ð 2È#ó 2ð,6ð ð
J #ð J°#ó Jñ.`˜$˜s C˜x™.ð `¸À¹ð `ÐQUÐVYÐ[^ÐV^ÑQ_ó `ð ×Ñð0B˜Sò 0Bó ð0BñfHD˜$˜s C˜x™.ð HD¸À¹ð HDÐQUÐVYÐ[^ÐV^ÑQ_ó HDðX 15ñ<Øð<Ø (¨¡ð<à	ˆ#ˆsˆ(�^ó<ñ@ sð °sð ÀhÈsÁmó ð F Sð F¨Tó Fð*B¨°©ð B¸#ó BðØ	ˆc�3ˆh‰ðØ!$ðØ03ðØ>AðØOTðØY]Ð^aÐcfÐ^fÑYgóð. Z^ñbØ	ˆc�3ˆh‰ðbØ%-¨c¡]ðbØIQÐRUÉðbàˆd�3˜�8‰nÑóbðT˜4  S ™>ð °°S¸#°X±ð ÈÐRUÉð Ð[_Ð`cÐehÐ`hÑ[ió ðI9�d˜3 ˜8‘nð I9¨ó I9ðX�D˜˜c˜‘Nð  só ð	˜˜S #˜X™ð 	¨4°°S°©>ð 	¸có 	ðB˜t C¨ H™~ð B°#ó Bð
: ð :¨¨S°#¨X©ó :ð
24�T˜#˜s˜(‘^ð 24¨¨S°#¨X©ð 24¸3ó 24ðj<�4˜˜S˜‘>ð <¨¨S°#¨X©ð <¸Sð <ÀSó <ð
.e˜T # s (™^ð .e°°S¸#°X±ð .eÈÈcÐSVÈhÉð .eÐ\dÐehÑ\ió .eðb˜t C¨ H™~ð °$°s¸C°x±.ð È4ÐPSÐUXÐPXÉ>ð Ð^fÐgjÑ^kó ð$˜d 3¨ 8™nð °°c¸3°h±ð È$ÈsÐTWÈxÉ.ð Ð]eÐfiÑ]jó ð&˜D  c ™Nð ¨t°C¸°H©~ð ÈÈSÐRUÈXÉð Ð[cÐdgÑ[hó ðD %Ð&;Ð=QÐSeÐf€ðj˜˜S #˜X™ð j¨4°°S°©>ð j¸có jð -°lÑCÐ à¨Ø ;¸;ÙWÙEñ	€ð #ó ð, !Ø Ø"ØØ Ø!Ø"ØØ"&ØØ"Ø"Ø Ø Ø48Ø!%Ø,0Ø!Ø#Ø(,Ø$(Ø!%Ø&*Ø7;ØØ $ØØ#'Ø!ñ=31Øð31à�S‰Mð31ð �S‰Mð31ð �s‰mð	31ð
 �3‰-ð31ð �S‰Mð31ð �c‰]ð31ð ð31ð �C‰=ð31ð �T˜#‘YÑð31ð �C‰=ð31ð �s‰mð31ð �s‰mð31ð �S‰Mð31ð �S‰Mð31ð  ˜5  d¨3¡i Ñ0Ñ1ð!31ð" ˜‘ð#31ð$ ˜t C™yÑ)ð%31ð& �c‰]ð'31ð( �t‰nð)31ð*   ‘~ð+31ð, ˜S‘Mð-31ð. ˜#‘ð/31ð0 ˜s‘mð131ð2 ˜e C¨¨c© NÑ3Ñ4ð331ð4 ð531ð6 ˜‘ð731ð8 ð931ð: ˜C‘=ð;31ð< �T‰Nð=31ð< '*ó=31ðl%˜cð % có %ð" 4ó "ð ðzð ðP
Ø˜yð  :hñ  iðP
à hÐ?uÑvðP
ð Ø ð  `ñðP
ð Ø ØMñðP
ð Ø!ð  `ñðP
ð Ø ð  JñðP
ð& Ø Ø ð  @	ñð'P
ð0 Ø Ø=ñð1P
ð8 Ø!Øuñð9P
ð@ Ø ð  wñðAP
ðH Ø ð  cñ ðIP
ðP ØØ  (Ð+ØrñðQP
ðZ Ø Ù2Ð3LÓMñð[P
ðb Ø ð  gñðcP
ðj Ø!Ø ð  LñðkP
ðt ØØ  (Ð+ð  mñðuP
ð~ Ø!ð  \ñðP
ðH  Ø  (Ð+ð  Xñ!ð !ð  Dñð
 "ð  Jñ"òYP
ðb �JñgTñ\€ð~ Dó ð&Ð òð  €× Ñ Ø	ØØØØ'Ø
Ø6õó 
ð Ð?ðÐ ó
Br4   