Ë
    âß²j‘@ ã            	      ó>  — 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mZmZ ddlmZmZ ddlmZ ddlmZmZmZmZmZ ddlmZ  ej6                  e«      Zd	Zd
ZdZ dZ!dZ"dZ#dZ$dZ%dZ&dZ'dZ(dZ)dZ*dZ+dZ,dZ-dZ.dZ/dZ0dZ1dZ2dZ3ddd d!d"dœZ4i d#d#“d$d#“d%d#“d&d#“d'd'“d(d'“d)d'“d*d'“d+d'“d,d,“d-d,“d.d,“d/d,“d0d,“d1d1“d2d1“d3d1“d1d1d4d4d4d4d4d5œ¥Z5e G d6„ d7«      «       Z6dyd8„Z7dzd9„Z8e G d:„ d;«      «       Z9dd<œd{d=„Z:e G d>„ d?«      «       Z;d|d@„Z<i Z=dAe>dB<    e	j~                  «       Z@i ZAdCe>dD<   dEZBdFZCd}dG„ZDd~dH„ZEddI„ZFd€dJ„ZGd�dK„ZHd‚dL„ZIdƒdM„ZJd„dN„ZKd…dO„ZLdPdQœd†dR„ZMd‡dS„ZNdˆdT„ZOd‰dU„ZP ej¢                  dVej¤                  «      ZSdŠdW„ZTd‹dX„ZUdŒdY„ZVd�dZ„ZWdŽd[„ZXd�d\„ZYd�d]„ZZdddddd^œ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d‘d_„Z[d’d`„Z\daZ]dbZ^dcZ_d“dd„Z`d”de„Zad•df„Zbd–ddgœd—dh„Zcddiœd˜dj„Zdd™dk„ZedlZf G dm„ dn«      ZgdoZhdpZidqdrdsdtduœZjedPddvœ	 	 	 	 	 	 	 	 	 dšdw„Zkg dx¢Zly)›u±  Persistent session goals â€” the Ralph loop for Hermes.

A goal is a free-form objective that stays active across turns; after each turn an auxiliary-model
judge decides whether it is satisfied. The continuation prompt is a normal user message appended via
``run_conversation`` (no system-prompt mutation or toolset swap â€” prompt caching stays intact). Judge
failures are fail-OPEN (``continue``); the turn budget is the backstop.
é    )ÚannotationsN)Ú	dataclassÚfieldÚasdict)ÚdatetimeÚtimezone)ÚPath)ÚAnyÚDictÚListÚOptionalÚTuple)Únoninteractive_git_envé   g      >@i   é   é   é   é,  i  i¸  a  [Continuing toward your standing goal]
Goal: {goal}

Continue working toward this goal. Take the next concrete step. If you believe the goal is complete, state so explicitly and stop. If you are blocked and need input from the user, say so clearly and stop.aç  [Continuing toward your standing goal]
Goal: {goal}

Completion contract:
{contract_block}

Continue working toward the outcome above. Take the next concrete step. Stay within the stated boundaries and do not violate the constraints. Before claiming the goal is done, satisfy the Verification criterion and show the concrete evidence (command output, file contents, test result). If you hit the stated stop condition or are otherwise blocked and need user input, say so clearly and stop.a{  [Continuing toward your standing goal]
Goal: {goal}

Additional criteria the user added mid-loop:
{subgoals_block}

Continue working toward the goal AND all additional criteria. Take the next concrete step. If you believe the goal and every additional criterion are complete, state so explicitly and stop. If you are blocked and need input from the user, say so clearly and stop.uá  [Continuing toward your standing goal â€” a quality gate failed]
Goal: {goal}

The quality gate command below must pass before this goal can be declared done, and it just failed (attempt {attempt}/{max_retries}):
  $ {command}
Exit code: {exit_code}
Output (tail):
```
{output}
```

Fix the underlying problem so this gate passes, then re-run it to confirm. Do not declare the goal complete while any gate fails. If the gate itself is wrong or cannot pass, say so clearly and stop.un  You are a strict judge evaluating whether an autonomous agent has achieved a user's stated goal. You receive the goal text, the agent's most recent response, and â€” when present â€” a list of background processes the agent has running. Decide one of four verdicts.

DONE â€” the goal is fully satisfied:
- The response explicitly confirms the goal was completed, OR
- The response clearly shows the final deliverable was produced.
DONE requires the deliverable to actually exist. If the response only explains why the goal cannot be reached, the verdict is BLOCKED, not DONE.

BLOCKED â€” the goal cannot be satisfied as stated:
- The response explains the goal is genuinely unachievable (impossible, out of scope, no valid path to the deliverable), or refuses to fabricate a deliverable that cannot exist, OR
- The response explains progress is blocked and the next step needs user input to proceed.
Return BLOCKED with the reason describing what is blocking. BLOCKED is a refusal, not a completion â€” never return BLOCKED for a goal that was achieved.
When the block is an error the agent hit (an HTTP status, an API, sign-in or token failure), quote the error text verbatim in the reason and attribute it only to a provider, service or credential the response itself names. Never infer one the response does not name â€” an unnamed 401 belongs to the model provider the agent was calling, not to some other service's token.

WAIT â€” the goal is NOT done, but the next step is to wait for async work to finish rather than act again. Choose this ONLY when the agent's progress is genuinely gated on something running on its own:
- A background process listed below is still running AND the response shows the agent is waiting on its result (e.g. a CI poller, build, test run, deploy). If the process has a session id, return it in ``wait_on_session`` â€” that releases when the process exits OR its watch_patterns trigger fires (use this for a long-lived watcher that signals mid-run and may never exit). Otherwise return its pid in ``wait_on_pid`` (releases on exit only).
- The agent says it is rate-limited / backing off / must wait a fixed period â€” return seconds in ``wait_for_seconds``.
- The agent has delegated subagents still running (stated below as active delegations) and the response says it is waiting on them with nothing else dispatchable â€” return ``wait_for_seconds`` between 600 and 1800. Their results wake the agent on their own; re-poking it now only produces a status recap.
Picking WAIT parks the loop without burning a turn; it resumes automatically when the pid exits or the time elapses. Do NOT pick WAIT just because work remains â€” only when re-poking now would be pure busy-work because the agent can't progress until the async thing finishes.

CONTINUE â€” not done, and there is a concrete next step the agent can take right now. This is the default when in doubt.

Reply ONLY with a single JSON object on one line. Shapes:
{"verdict": "done", "reason": "<one sentence>"}
{"verdict": "blocked", "reason": "<one sentence>"}
{"verdict": "continue", "reason": "<one sentence>"}
{"verdict": "wait", "wait_on_session": "<id>", "reason": "<one sentence>"}
{"verdict": "wait", "wait_on_pid": <int>, "reason": "<one sentence>"}
{"verdict": "wait", "wait_for_seconds": <int>, "reason": "<one sentence>"}
The legacy shape {"done": <true|false>, "reason": "..."} is still accepted (true=done, false=continue).z™Active delegations: the agent has {count} delegated subagent batch(es) still running; their results are delivered to it automatically when they finish.

znBackground processes the agent currently has running (it may be waiting on one of these):
{background_lines}

u£   Goal:
{goal}

Agent's most recent response:
{response}

{background_block}Current time: {current_time}

Is the goal satisfied â€” done, blocked, continue, or wait?uÖ  Goal:
{goal}

Additional criteria the user added mid-loop (all must also be satisfied for the goal to be DONE):
{subgoals_block}

Agent's most recent response:
{response}

{background_block}Current time: {current_time}

Decision: For each numbered criterion above, find concrete evidence in the agent's response that the criterion is satisfied. Do not accept generic phrases like 'all requirements met' or 'implying it was done' â€” require specific evidence (a file contents excerpt, an output line, a command result). If ANY criterion lacks specific evidence in the response, the goal is NOT done â€” return CONTINUE (or WAIT if blocked on a listed background process).

Is the goal AND every additional criterion satisfied?uX  Goal:
{goal}

Completion contract (the authoritative definition of done):
{contract_block}

Agent's most recent response:
{response}

{background_block}Current time: {current_time}

Decision rules:
- The goal is DONE only when the Verification criterion is satisfied AND the response shows concrete evidence of it (a command result, file contents excerpt, test/benchmark output) â€” not a claim like 'done' or 'all tests pass' without evidence.
- If any stated Constraint was violated, the goal is NOT done â€” CONTINUE.
- If the response shows the agent is waiting on a listed background process to satisfy the Verification criterion (e.g. CI is the verification and it's still running), return WAIT on that process instead of re-poking â€” re-poking now would be pure busy-work.
- If the response explains the work is genuinely unachievable or hits the stated Stop condition and needs user input, the goal is NOT done â€” return BLOCKED with the reason describing the block.
- Otherwise the goal is NOT done â€” CONTINUE.

Is the goal satisfied per its completion contract â€” done, blocked, continue, or wait?a×  You turn a user's plain-language objective into a structured completion contract for an autonomous coding agent. The contract has five fields:
- outcome: the single end state that must be true when done
- verification: the specific test / command / artifact that PROVES the outcome (must be concrete and checkable)
- constraints: what must NOT change or regress
- boundaries: which files, dirs, tools, or systems are in scope
- stop_when: the condition under which the agent should stop and ask for human input instead of pushing on

Infer sensible, specific values from the objective and any project context implied by it. Prefer concrete verification (a named test command, a build, a benchmark) over vague phrases. Keep each field to one or two sentences. If a field genuinely cannot be inferred, use an empty string for it.

Reply ONLY with a single JSON object on one line:
{"outcome": "...", "verification": "...", "constraints": "...", "boundaries": "...", "stop_when": "..."})ÚoutcomeÚverificationÚconstraintsÚ
boundariesÚ	stop_whenÚOutcomeÚVerificationÚConstraintsÚ
BoundarieszStop when blockedr   ÚgoalÚdonez	done whenr   Úverifyzverified byÚevidenceÚproofr   Ú
constraintÚpreservezmust notzdo not changer   ÚboundaryÚscoper   )ÚallowedÚfilesz	stop whenr   Úblockedzstop if blockedzgive up whenc                  ó‚   — e Zd ZU dZdZded<   dZded<   dZded<   dZded<   dZ	ded<   dd	„Z
dd
„Zedd„«       Zdd„Zy)ÚGoalContractzMOptional structured completion contract; empty fields are omitted everywhere.Ú Ústrr   r   r   r   r   c                ó6   ‡ — t        ˆ fd„t        D «       «       S )Nc              3  óR   •K  — | ]  }t        ‰|«      j                  «       –— Œ  y ­w©N)ÚgetattrÚstrip©Ú.0ÚfÚselfs     €ú5/home/ubuntu/.hermes/hermes-agent/hermes_cli/goals.pyú	<genexpr>z(GoalContract.is_empty.<locals>.<genexpr>'  s!   øè ø€ ÒJ°A”w˜t QÓ'×-Ñ-×/ÑJùs   ƒ$')ÚanyÚ_CONTRACT_FIELDS©r6   s   `r7   Úis_emptyzGoalContract.is_empty&  s   ø€ ÜÓJÔ9IÔJÓJÐJÐJó    c                óJ   — t         D �ci c]  }|t        | |«      “Œ c}S c c}w r0   )r:   r1   )r6   r5   s     r7   Úto_dictzGoalContract.to_dict)  s"   € Ü-=Ö>¨�”7˜4 Ó#Ñ#Ò>Ð>ùÒ>s   ‰ c                óÄ   — t        |t        «      s | «       S  | di t        D �ci c]/  }|t        |j	                  |«      xs d«      j                  «       “Œ1 c}¤ŽS c c}w )Nr,   © )Ú
isinstanceÚdictr:   r-   Úgetr2   )ÚclsÚdatar5   s      r7   Ú	from_dictzGoalContract.from_dict,  sP   € ä˜$¤Ô%Ù“5ˆLÙÑSÔAQÖR¸A�aœ˜TŸX™X a›[Ò.¨BÓ/×5Ñ5Ó7Ñ7ÒRÑSÐSùÒRs   ¤4Ac                ó@   ‡ — dj                  ˆ fd„t        D «       «      S )uF   Non-empty fields as a labelled block; empty contract â†’ empty string.Ú
c              3  ó¢   •K  — | ]F  }t        ‰|«      j                  «       sŒd t        |   › dt        ‰|«      j                  «       › �–— ŒH y­w)ú- ú: N)r1   r2   Ú_CONTRACT_LABELSr3   s     €r7   r8   z,GoalContract.render_block.<locals>.<genexpr>4  s^   øè ø€ ò  GÐTUÔmtÐuyÐ{|Óm}÷  nDñ  nDõ  nF˜2Ô.¨qÑ1Ð2°"´W¸TÀ1Ó5E×5KÑ5KÓ5MÐ4NÔOñ  Gùs
   ƒA£,A)Újoinr:   r;   s   `r7   Úrender_blockzGoalContract.render_block2  s%   ø€ à�y‰yó  GÔYiô  Gó  Gð  	Gr=   N©ÚreturnÚbool)rQ   zDict[str, str])rF   úOptional[Dict[str, Any]]rQ   z'GoalContract'©rQ   r-   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   Ú__annotations__r   r   r   r   r<   r?   ÚclassmethodrG   rO   rA   r=   r7   r+   r+     s^   … áWØ€GˆSÓØ€L�#ÓØ€K�ÓØ€J�ÓØ€IˆsÓóKó?ð òTó ðTô
Gr=   r+   c                ó¦  — | sdt        «       fS g }t        D �ci c]  }|g “Œ }}| j                  «       D ]¥  }|j                  «       }|sŒd|v r{|j	                  d«      \  }}}t
        j                  |j                  «       j                  «       «      }	|	�3|j                  «       r#||	   j                  |j                  «       «       Œ•|j                  |«       Œ§ t        di |j                  «       D ��
ci c]%  \  }}
|dj                  |
«      j                  «       “Œ' c}
}¤Ž}dj                  |«      j                  «       |fS c c}w c c}
}w )u  Split user-typed goal text into a headline + contract from inline ``field: value`` lines.

    A headline without an explicit ``outcome:`` IS the outcome â€” it is not duplicated into the
    contract block (the goal text already carries it), so outcome stays empty in that case.
    r,   ú:Ú rA   )r+   r:   Ú
splitlinesr2   Ú	partitionÚ_CONTRACT_ALIASESrD   ÚlowerÚappendÚitemsrN   )ÚtextÚheadline_partsr5   ÚfieldsÚraw_lineÚlineÚprefixÚ_ÚvalueÚkeyÚvÚcontracts               r7   Úparse_contractro   7  s,  € ñ Ø”<“>Ð!Ð!Ø "€NÜ3CÖ#D¨a A r¡EÐ#D€FÐ#DØ—O‘OÓ%ò 
$ˆØ�~‰~ÓˆÙØØ�$‰;Ø#Ÿ~™~¨cÓ2ÑˆF�A�uÜ#×'Ñ'¨¯©«×(<Ñ(<Ó(>Ó?ˆCØˆ 5§;¡;¤=Ø�s‘×"Ñ" 5§;¡;£=Ô1ØØ×Ñ˜dÕ#ð
$ô ÑRÀ&Ç,Á,Ã.×Q¹$¸!¸Q˜q #§(¡(¨1£+×"3Ñ"3Ó"5Ñ5ÓQÑR€HØ�8‰8�NÓ#×)Ñ)Ó+¨XÐ5Ð5ùò $Eùó Rs   ™
EÃ7*Ec                óH   — dj                  d„ t        | d¬«      D «       «      S )NrI   c              3  ó2   K  — | ]  \  }}d |› d|› �–— Œ y­w)z- Extra criterion rL   NrA   ©r4   Úird   s      r7   r8   z)_render_extra_criteria.<locals>.<genexpr>Q  s"   è ø€ Òb¹'¸!¸TÐ)¨!¨¨B¨t¨fÔ5Ñbùó   ‚é   ©Ústart)rN   Ú	enumerate)Úsubgoalss    r7   Ú_render_extra_criteriarz   P  s   € Ø�9‰9ÑbÄYÈxÐ_`ÔEaÔbÓbÐbr=   c                  ó|   — e Zd ZU dZded<   eZded<   eZded<   dZ	ded<   d	Z
d
ed<   dZded<   dd„Zedd„«       Zy	)ÚGoalGatezäA deterministic shell command that must pass before a goal can be done.

    Gates run at turn boundary BEFORE the LLM judge; a failing gate short-circuits judging and its
    bounded output becomes the continuation prompt.
    r-   ÚcommandÚintÚtimeout_secondsÚmax_retriesr   ÚattemptsNúOptional[int]Úlast_exit_coder,   Úlast_output_tailc                ó   — t        | «      S r0   )r   r;   s    r7   r?   zGoalGate.to_dictd  s   € Ü�d‹|Ðr=   c                ó¶  — t        |t        «      s	 | d¬«      S  | t        |j                  d«      xs d«      t	        |j                  d«      xs t
        «      t	        |j                  d«      xs t        «      t	        |j                  d«      xs d«      |j                  d«      �t	        |d   «      nd t        |j                  d	«      xs d«      ¬
«      S )Nr,   )r}   r}   r   r€   r�   r   rƒ   r„   )r}   r   r€   r�   rƒ   r„   )rB   rC   r-   rD   r~   ÚDEFAULT_GATE_TIMEOUT_SECONDSÚDEFAULT_GATE_MAX_RETRIES)rE   rF   s     r7   rG   zGoalGate.from_dictg  sµ   € ä˜$¤Ô%Ù˜r”?Ð"ÙÜ˜Ÿ™ Ó+Ò1¨rÓ2Ü §¡Ð):Ó ;Ò [Ô?[Ó\Ü˜DŸH™H ]Ó3ÒOÔ7OÓPÜ˜Ÿ™ *Ó-Ò2°Ó3Ø;?¿8¹8ÐDTÓ;UÐ;aœC Ð%5Ñ 6Ô7ÐgkÜ  §¡Ð*<Ó!=Ò!CÀÓDô
ð 	
r=   )rQ   úDict[str, Any])rF   rS   rQ   z
'GoalGate')rU   rV   rW   rX   rY   r‡   r   rˆ   r€   r�   rƒ   r„   r?   rZ   rG   rA   r=   r7   r|   r|   V  sZ   … ñð
 ƒLØ7€O�SÓ7Ø/€K�Ó/Ø€HˆcÓØ$(€N�MÓ(ØÐ�cÓóð ò

ó ñ

r=   r|   )Úcwdc               óp  — 	 t        j                  | j                  dddddt        dt	        | j
                  «      «      |xs d¬«      }|j                  xs d|j                  rd|j                  z   ndz   }|j                  d	k(  |j                  |t         d fS # t         j                  $ rV}dj                  d
„ |j                  |j                  fD «       «      }dd|d| j
                  › d�z   t         d fcY d}~S d}~wt        $ r)}dddt        |«      j                  › d|› d�fcY d}~S d}~ww xY w)z‰Run one gate through the shell. Returns ``(passed, exit_code, output_tail)``; a timeout kills
    the process and counts as exit code -1.Túutf-8Úreplaceru   N)ÚshellÚcapture_outputrd   ÚencodingÚerrorsÚtimeoutrŠ   r,   rI   r   c              3  ój   K  — | ]+  }|sŒt        |t        «      r|n|j                  d d«      –— Œ- y­w)rŒ   r�   N)rB   r-   Údecode)r4   Úcs     r7   r8   zrun_gate.<locals>.<genexpr>ƒ  s-   è ø€ ÒwÐTUÒuvœ: a¬Ô-‘a°1·8±8¸GÀYÓ3OÓOÑwùs   ‚3Š)3Féÿÿÿÿz
[gate timed out after zs]z[gate could not run: rL   ú])Ú
subprocessÚrunr}   Úmaxr~   r   ÚstdoutÚstderrÚ
returncodeÚ_GATE_OUTPUT_TAIL_CHARSÚTimeoutExpiredrN   Ú	ExceptionÚtyperU   )ÚgaterŠ   ÚprocÚcombinedÚexcÚouts         r7   Úrun_gater§   u  s3  € ðOô �~‰~Ø�L‰L °TÀÈwÐ_hÜ˜œ3˜t×3Ñ3Ó4Ó5¸3º;À$ô
ˆð —K‘KÒ% 2À$Ç+Â+¨4°$·+±+Ò+=ÐSUÑVˆØ�‰ !Ñ# T§_¡_°hÔ@WÐ?WÐ?XÐ6YÐYÐYøÜ×$Ñ$ò qØ�g‰gÑwÐZ]×ZdÑZdÐfi×fpÑfpÐYqÔwÓwˆØ�b˜3Ð#;¸D×<PÑ<PÐ;QÐQSÐ!TÑTÔWnÐVnÐVoÐpÐpÕpûÜò OØ�bÐ1´$°s³)×2DÑ2DÐ1EÀRÈÀuÈAÐNÐNÕNûðOús1   ‚BB ÂD5Â/AD Ã:D5Ä D5ÄD0Ä*D5Ä0D5c                  ó‚  — e Zd ZU dZded<   dZded<   dZded<   eZded	<   d
Z	ded<   d
Z
ded<   dZded<   dZded<   dZded<   dZded<   dZded<    ee¬«      Zded<   dZded<   dZded<   d
Zded<   dZded<   dZded<   d
Zded<    ee¬«      Zded <    ee¬«      Zd!ed"<   d(d#„Zed)d$„«       Zd*d%„Zd(d&„Z d+d'„Z!y),Ú	GoalStatez+Serializable goal state stored per session.r-   r   ÚactiveÚstatusr   r~   Ú
turns_usedÚ	max_turnsç        ÚfloatÚ
created_atÚlast_turn_atNúOptional[str]Úlast_verdictÚlast_reasonÚpaused_reasonÚconsecutive_parse_failuresÚconsecutive_transport_failures)Údefault_factoryú	List[str]ry   r‚   Úwaiting_on_pidÚwaiting_on_sessionÚwaiting_untilÚwaiting_on_delegationsÚwaiting_reasonÚwaiting_sincer+   rn   zList[GoalGate]Úgatesc                óB   — t        j                  t        | «      d¬«      S )NF)Úensure_ascii)ÚjsonÚdumpsr   r;   s    r7   Úto_jsonzGoalState.to_json¯  s   € Ü�z‰zœ& ›,°UÔ;Ð;r=   c                ó–  — t        j                  |«      }|j                  d«      xs g }dD �ci c]!  }|t        |j                  |«      xs d«      “Œ# }}dD �ci c]!  }|t	        |j                  |«      xs d«      “Œ# }} | d|j                  dd«      |j                  dd	«      t        |j                  d
«      xs t
        «      |j                  d«      |j                  d«      |j                  d«      t        |t        «      rA|D �cg c]5  }t        |«      j                  «       sŒt        |«      j                  «       ‘Œ7 c}ng |j                  d«      rt        |d   «      nd |j                  d«      rt        |d   «      nd |j                  d«      t        j                  |j                  d«      «      |j                  d«      xs g D �cg c]S  }t        |t        «      rAt        |j                  d«      xs d«      j                  «       rt        j                  |«      ‘ŒU c}dœ|¤|¤ŽS c c}w c c}w c c}w c c}w )Nry   )r¬   r¶   r·   r½   r   )r°   r±   r¼   r¿   r®   r   r,   r«   rª   r­   r³   r´   rµ   rº   r»   r¾   rn   rÀ   r}   )r   r«   r­   r³   r´   rµ   ry   rº   r»   r¾   rn   rÀ   rA   )rÃ   ÚloadsrD   r~   r¯   ÚDEFAULT_MAX_TURNSrB   Úlistr-   r2   r+   rG   rC   r|   )	rE   ÚrawrF   Úraw_subgoalsÚkÚintsÚfloatsÚsÚgs	            r7   Ú	from_jsonzGoalState.from_json²  sú  € ä�z‰z˜#‹ˆØ—x‘x 
Ó+Ò1¨rˆð 3[ö  \¨Q�”3�t—x‘x “{Ò' aÓ(Ñ(ð  \ˆð  \Ø8xÖy°1�!”U˜4Ÿ8™8 A›;Ò-¨#Ó.Ñ.ÐyˆÐyÙð 
Ø—‘˜& "Ó%Ø—8‘8˜H hÓ/Ü˜$Ÿ(™( ;Ó/ÒDÔ3DÓEØŸ™ .Ó1ØŸ™ Ó/ØŸ(™( ?Ó3ÜQ[Ð\hÔjnÔQo¨lÖM¨¼cÀ!»f¿l¹l½n”c˜!“f—l‘l•nÓMÐuwØ;?¿8¹8ÐDTÔ;UœC Ð%5Ñ 6Ô7Ð[_ØCGÇ8Á8ÐL`ÔCa¤ DÐ)=Ñ$>Ô ?ÐgkØŸ8™8Ð$4Ó5Ü!×+Ñ+¨D¯H©H°ZÓ,@ÓAà04·±¸Ó0AÒ0GÀRöØ*+Ü˜a¤Ô&¬3¨q¯u©u°YÓ/?Ò/EÀ2Ó+F×+LÑ+LÔ+Nô ×"Ñ" 1Õ%òñ
ð  ð!
ð  ñ!
ð 	
ùò \ùÚyùò Nùò
s   ¯&H7Á&H<ÄIÄ,IÇAI c                óX   — | j                   d uxr | j                   j                  «        S r0   )rn   r<   r;   s    r7   Úhas_contractzGoalState.has_contractË  s&   € Ø�}‰} DÐ(ÒI°·±×1GÑ1GÓ1IÐ-IÐIr=   c                ó\   — dj                  d„ t        | j                  d¬«      D «       «      S )z?Numbered ``- N. text`` block; empty when there are no subgoals.rI   c              3  ó2   K  — | ]  \  }}d |› d|› �–— Œ y­w©rK   z. NrA   rr   s      r7   r8   z2GoalState.render_subgoals_block.<locals>.<genexpr>Ð  s!   è ø€ Ò[©g¨a°˜2˜a˜S  4 &Ô)Ñ[ùrt   ru   rv   )rN   rx   ry   r;   s    r7   Úrender_subgoals_blockzGoalState.render_subgoals_blockÎ  s#   € à�y‰yÑ[¼À4Ç=Á=ÐXYÔ9ZÔ[Ó[Ð[r=   c                óX   — d | _         d | _        d| _        d| _        d | _        d| _        y )Nr®   r   )rº   r»   r¼   r½   r¾   r¿   r;   s    r7   Ú
clear_waitzGoalState.clear_waitÒ  s2   € Ø"ˆÔØ"&ˆÔØ ˆÔØ&'ˆÔ#Ø"ˆÔØ ˆÕr=   rT   )rÊ   r-   rQ   z'GoalState'rP   ©rQ   ÚNone)"rU   rV   rW   rX   rY   r«   r¬   rÈ   r­   r°   r±   r³   r´   rµ   r¶   r·   r   rÉ   ry   rº   r»   r¼   r½   r¾   r¿   r+   rn   rÀ   rÅ   rZ   rÑ   rÓ   r×   rÙ   rA   r=   r7   r©   r©   ‹  s  … á5Ø
ƒIØ€FˆCÓØ€J�ÓØ&€IˆsÓ&Ø€J�ÓØ€L�%ÓØ"&€L�-Ó&Ø!%€K�Ó%Ø#'€M�=Ó'Ø&'Ð Ó'ð +,Ð" CÓ+á°Ô5€HˆiÓ5ð %)€N�MÓ(Ø(,Ð˜Ó,Ø€M�5Óð #$Ð˜CÓ#Ø$(€N�MÓ(Ø€M�5ÓÙ"°<Ô@€HˆlÓ@á!°$Ô7€Eˆ>Ó7ó<ð ò
ó ð
ó0Jó\ô!r=   r©   c                ó   — d| › �S )Nzgoal:rA   )Ú
session_ids    r7   Ú	_meta_keyrÞ   Ý  s   € Ø�:�,ÐÐr=   r‰   Ú	_DB_CACHEzDict[str, threading.Event]Ú_DB_BOOTSTRAP_INFLIGHTg      Ð?g      ø?c                ó>  — 	 t        | «      }t        5  |�| t
        vr|t
        | <   d}t        j                  | d«       ddd«       |�t        |«       |j                  «        y# t        $ r"}t        j                  d|«       d}Y d}~Œ~d}~ww xY w# 1 sw Y   ŒUxY w)zDConstruct SessionDB off-loop and populate the cache (worker thread).z/GoalManager: background SessionDB() raised (%s)N)
Ú_acquire_session_dbr    ÚloggerÚdebugÚ_DB_BOOTSTRAP_LOCKrß   rà   ÚpopÚ_release_session_dbÚset)Úhomer   Údbr¥   s       r7   Ú_bootstrap_session_dbrë   ò  s“   € ðÜ  Ó&ˆô 
ñ /Øˆ>˜d¬)Ñ3Ø ŒI�d‰OØˆBÜ×"Ñ" 4¨Ô.÷	/ð
 
€~Ü˜BÔØ‡H�H…Jøô ò Ü�‰ÐFÈÔLØ�ûðú÷/ð /ús"   ‚A% “,BÁ%	BÁ.BÂBÂBc                 óZ  — 	 ddl m}  t         | «       «      }t        j                  |«      }|�:t        |«      r/t        5  t        j                  |«      |u rt        |= ddd«       d}|�|S 	 t        j                  «        d}|rÄt        5  t        j                  |«      }|�|cddd«       S t        j                  |«      }t        }|€Pt        j                   «       x}t        |<   t        j"                  t$        ||fdd¬«      j'                  «        t(        }ddd«       j+                  «       t        j                  |«      S 	 t-        |«      }t        5  t        j                  |«      }|�t/        |«       |cddd«       S |t        |<   ddd«       |S # t        $ r }t        j                  d|«       Y d}~yd}~ww xY w# 1 sw Y   �ŒlxY w# t        $ r d}Y �Œ`w xY w# 1 sw Y   ŒÍxY w# t        $ r }t        j                  d	|«       Y d}~yd}~ww xY w# 1 sw Y   |S xY w)
as  Cached SessionDB per HERMES_HOME (profile switches pick the right DB); None on any failure.

    Never constructs SessionDB on an event-loop thread: a cache miss there kicks a one-shot background
    bootstrap and waits a bounded grace window (the kick call waits ``_DB_BOOTSTRAP_INIT_WAIT_S`` so a
    healthy cold init completes and the first write isn't dropped).
    r   )Úget_hermes_homez,GoalManager: SessionDB bootstrap failed (%s)NTFzgoals-sessiondb-bootstrap)ÚtargetÚargsÚnameÚdaemonz$GoalManager: SessionDB() raised (%s))Úhermes_constantsrí   r-   r    rã   rä   rß   rD   Ú_registry_tore_downrå   ÚasyncioÚget_running_loopÚRuntimeErrorrà   Ú_DB_BOOTSTRAP_LOOP_WAIT_SÚ	threadingÚEventÚThreadrë   rw   Ú_DB_BOOTSTRAP_INIT_WAIT_SÚwaitrâ   rç   )	rí   ré   r¥   ÚcachedÚon_loop_threadr   rü   rê   Úexistings	            r7   Ú_get_session_dbr     s  € ðÝ4ä‘?Ó$Ó%ˆô
 �]‰]˜4Ó €FØÐÔ1°&Ô9ô  ñ 	$Ü�}‰}˜TÓ" fÑ,Ü˜d�O÷	$ð ˆØÐØˆðÜ× Ñ Ô"ð ˆáÜñ 
	1ä—]‘] 4Ó(ˆFØÐ!Ø÷	
	1ñ 
	1ô
 *×-Ñ-¨dÓ3ˆDÜ,ˆDØˆ|Ü6?·o±oÓ6GÐG�Ô-¨dÑ3Ü× Ñ Ô(=ÀTÈ4ÀLÐWrÐ{ô  A÷  Gñ  Gô  IÜ0�÷
	1ð 	�	‰	�$ŒÜ�}‰}˜TÓ"Ð"ðÜ  Ó&ˆô 
ñ Ü—=‘= Ó&ˆØÐä Ô#Ø÷ñ ð Œ	�$‰÷ð €Iøôe ò Ü�‰ÐCÀSÔIÜûðú÷	$ñ 	$ûô ò Ø‹ðú÷
	1ð 
	1ûô  ò Ü�‰Ð;¸SÔAÜûðú÷ð €Iúsr   ‚F Á G	Á.G ÂG(Â/A-G(ÅG4 Å$H Æ
	H Æ	GÆ&GÇGÇ	GÇG%Ç$G%Ç(G1Ç4	HÇ=HÈHÈ H*c                ó6   — ddl m}  |t        | «      dz  «      S )u  The registry's shared handle for ``home/state.db``. A bare ``SessionDB()`` here was a SECOND
    writer per profile beside the gateway's registry handle â€” its own token-writer thread and
    close-time checkpoint (the #90837 corruption shape), doubled under multiplexing.r   )Úacquirezstate.db)Úhermes_state_registryr  r	   )ré   r  s     r7   râ   râ   C  s   € õ .Ù”4˜“: 
Ñ*Ó+Ð+r=   c                ó@   — ddl m} 	  || «       y # t        $ r Y y w xY w)Nr   )Úrelease_or_close)r  r  r    )rê   r  s     r7   rç   rç   K  s$   € Ý6ðÙ˜ÕøÜò Ùðús   ˆ ‘	œc                ó    — t        | dd«      du S )a  True once the registry force-closed *db* (``close_all`` / ``close_all_under`` clear the
    shared-owned flag at teardown); every handle cached here was acquired through the registry, so a
    cleared flag means the connection is gone and the cache entry is stale.Ú_shared_registry_ownedTF)r1   )rê   s    r7   ró   ró   S  s   € ô �2Ð/°Ó6¸%Ð?Ð?r=   c                ó4   — t         j                  d| ||«       y)u«   WARN on a dropped state write â€” the reply already told the user the state was set. One shared
    message keeps goal, loop and heartbeat logs greppable as one bug class.up   %s: %s for %s not persisted â€” session DB unavailable (bootstrap window exceeded, in-memory state still active)N)rã   Úwarning)ÚmanagerÚkindrÝ   s      r7   Ú_warn_dropped_writer  Z  s   € ô ‡N�Nð	Dà��zõr=   c                ó<  — | syt        «       }|€y	 |j                  t        | «      «      }|sy	 t        j                  |«      S # t        $ r }t        j                  d|«       Y d}~yd}~ww xY w# t        $ r!}t        j                  d| |«       Y d}~yd}~ww xY w)z4Load the goal for a session, or None if none exists.Nz GoalManager: get_meta failed: %sz3GoalManager: could not parse stored goal for %s: %s)	r   Úget_metarÞ   r    rã   rä   r©   rÑ   r	  )rÝ   rê   rÊ   r¥   s       r7   Ú	load_goalr  d  s˜   € áØÜ	Ó	€BØ	€zØðØ�k‰kœ) JÓ/Ó0ˆñ ØðÜ×"Ñ" 3Ó'Ð'øô ò Ü�‰Ð7¸Ô=Üûðûô ò Ü�‰ÐLÈjÐZ]Ô^Üûðús.   ’A °A1 Á	A.ÁA)Á)A.Á1	BÁ:BÂBc                óê   — | syt        «       }|€t        dd| «       y	 |j                  t        | «      |j	                  «       «       y# t
        $ r }t        j                  d|«       Y d}~yd}~ww xY w)z5Persist a goal to SessionDB. No-op if DB unavailable.NÚGoalManagerr   z GoalManager: set_meta failed: %s)r   r  Úset_metarÞ   rÅ   r    rã   rä   )rÝ   Ústaterê   r¥   s       r7   Ú	save_goalr  y  sd   € áØÜ	Ó	€BØ	€zÜ˜M¨6°:Ô>Øð>Ø
�‰”I˜jÓ)¨5¯=©=«?Õ;øÜò >Ü�‰Ð7¸×=Ñ=ûð>ús   Ÿ)A	 Á		A2ÁA-Á-A2c                óF   — t        | «      }|€yd|_        t        | |«       y)zDMark a goal cleared in the DB (preserved for audit, status=cleared).NÚcleared)r  r«   r  )rÝ   r  s     r7   Ú
clear_goalr  ‡  s%   € ä�jÓ!€EØ€}ØØ€E„LÜˆj˜%Õ r=   r,   ©Úreasonc               ó*  — | r|r| |k(  ry	 t        | «      }|�|j                  dk(  ryt        |«      �yt        ||«       t        | «       t        j                  d| ||xs d«       y# t        $ r }t        j                  d|«       Y d}~yd}~ww xY w)ut  Carry a persistent /goal from a parent session to its continuation. Best-effort, never raises
    (a failure here must not block compression). Returns True when a goal was migrated.

    Context compression rotates ``session_id`` to a fresh child session, but ``load_goal`` does a flat
    ``goal:<session_id>`` lookup with no parent-lineage walk â€” so an active goal silently dies at the
    compaction boundary (#33618). Copy the goal onto the new session and archive the old row as ``cleared``
    so exactly one active goal row exists per logical conversation (avoids the "two active goals" hazard of
    a pure copy).
    FNr  z(GoalManager: migrated goal %s -> %s (%s)ÚrotationTz&GoalManager: goal migration failed: %s)r  r«   r  r  rã   rä   r    )Úold_session_idÚnew_session_idr  r  r¥   s        r7   Úmigrate_goal_to_sessionr  �  s•   € ñ ¡°>À^Ò3SØðÜ˜.Ó)ˆØˆ=˜EŸL™L¨IÒ5Øä�^Ó$Ð0ØÜ�. %Ô(ä�>Ô"Ü�‰Ð?ÀÐQ_ÐagÒauÐkuÔvØøÜò Ü�‰Ð=¸sÔCÜûðús!   ŒA) ©A) µ3A) Á)	BÁ2BÂBc                ó8   — | syt        | «      |k  r| S | d | dz   S )Nr,   u   â€¦ [truncated])Úlen)rd   Úlimits     r7   Ú	_truncater"  ¯  s*   € ÙØÜ�t“9 Ò%ˆ4ÐK¨4°°¨<Ð:KÑ+KÐKr=   c                óà   — | r| dk  ry	 ddl m} t         |t        | «      «      «      S # t        $ r Y nw xY w	 ddl}t        |j                  t        | «      «      «      S # t        $ r Y yw xY w)zÓLiveness via ``gateway.status._pid_exists`` (psutil + ctypes/POSIX fallback). Never uses
    ``os.kill(pid, 0)``: on Windows that routes to CTRL_C_EVENT and hard-kills the target's console
    group (bpo-14484).r   F)Ú_pid_existsN)Úgateway.statusr$  rR   r~   r    ÚpsutilÚ
pid_exists)Úpidr$  r&  s      r7   Ú
_pid_aliver)  µ  sr   € ñ �#˜’(ØðÝ.ä‘K¤ C£Ó)Ó*Ð*øÜò ÙðúðÛä�F×%Ñ%¤c¨#£hÓ/Ó0Ð0øÜò Ùðús   Š* ª	6µ6º&A! Á!	A-Á,A-c                óh   — | sy	 ddl m} t        |j                  | «      «      S # t        $ r Y yw xY w)z³True while the process_registry session is running and its trigger hasn't fired. Fail-safe:
    any import/registry error yields False so a stale barrier can never wedge the loop.Fr   ©Úprocess_registry)Útools.process_registryr,  rR   Úis_session_waitingr    )rÝ   r,  s     r7   Ú_session_waitingr/  É  s;   € ñ ØðÝ;äÐ$×7Ñ7¸
ÓCÓDÐDøÜò Ùðús   …% ¥	1°1z\{.*?\}c                óÄ   — 	 ddl m}  | |«       j                  d«      xs i j                  di «      j                  | |«      «      }|dkD  r|S 	 |S # t        $ r Y |S w xY w)z¸Resolve ``auxiliary.goal_judge.<key>``; non-positive/garbage falls back to ``default``
    rather than crashing the loop. ``load_config()`` is cached on (mtime, size) so this is cheap.r   )Úload_configÚ	auxiliaryÚ
goal_judge)Úhermes_cli.configr1  rD   r    )rl   ÚdefaultÚcastr1  rk   s        r7   Ú_goal_judge_settingr7  Ù  ss   € ðÝ1á‘k“m×'Ñ'¨Ó4Ò:¸×?Ñ?ÀÈbÓQ×UÑUÐVYÐ[bÓcÓdˆØ�1Š9ØˆLð ð €Nøô ò ØØ€Nðús   ‚AA Á	AÁAc                 ó,   — t        dt        t        «      S )NÚ
max_tokens)r7  ÚDEFAULT_JUDGE_MAX_TOKENSr~   rA   r=   r7   Ú_goal_judge_max_tokensr;  ç  s   € Ü˜|Ô-EÄsÓKÐKr=   c                 ó,   — t        dt        t        «      S )Nr’   )r7  ÚDEFAULT_JUDGE_TIMEOUTr¯   rA   r=   r7   Ú_goal_judge_timeoutr>  ë  s   € Ü˜yÔ*?ÄÓGÐGr=   c                ó¸  — | sy| j                  «       }|j                  d«      r/|j                  d«      }|j                  d«      }|dk7  r||dz   d }	 t        j                  |«      }t        |t        «      r|S dS # t
        $ rR t        j                  |«      }|sY y	 t        j                  |j                  d«      «      }n# t
        $ r Y Y yw xY wY Œnw xY w)zRBest-effort: strip code fences, parse the blob, else pull the first ``{...}`` out.Nz```ú`rI   r–   ru   r   )r2   Ú
startswithÚfindrÃ   rÇ   r    Ú_JSON_OBJECT_REÚsearchÚgrouprB   rC   )rÊ   rd   ÚnlrF   Úmatchs        r7   Ú_extract_json_objectrH  ï  sÑ   € áØØ�9‰9‹;€DØ‡��uÔØ�z‰z˜#‹ˆØ�Y‰Y�t‹_ˆØ�Š8Ø˜˜Q™˜�=ˆDð	Ü�z‰z˜$Óˆô ˜d¤DÔ)ˆ4Ð3¨tÐ3øô ò Ü×&Ñ& tÓ,ˆÙÙð	Ü—:‘:˜eŸk™k¨!›nÓ-‰DøÜò 	Úð	úñ ðús6   ÁA> Á> CÂ!$CÃCÃ	CÃCÃCÃCÃCc                ó8  ‡
— | syt        | «      Š
‰
€ddt        | d«      ›�ddfS t        ‰
j                  d«      xs d«      j	                  «       xs d	}‰
j                  d
«      }t        |t        «      r|j	                  «       j                  «       }nR‰
j                  d«      }t        |t        «      r |j	                  «       j                  «       dv n
t        |«      }|rdnd}|dvrd}|dk7  r||ddfS dˆ
fd„}‰
j                  d«      xs$ ‰
j                  d«      xs ‰
j                  d«      }t        |t        «      r&|j	                  «       rd|dd|j	                  «       ifS  |ddd«      }|�d|dd|ifS  |ddd«      }	|	�d|dd|	ifS d|› d�ddfS )a§  Parse the judge's reply, fail-open. Returns ``(verdict, reason, parse_failed, wait_directive)``.

    ``parse_failed`` flags non-JSON output so callers can auto-pause after N in a row.
    ``wait_directive`` is ``{"session_id"}`` / ``{"pid"}`` / ``{"seconds"}`` for a ``wait``
    verdict; a wait with no target is downgraded to ``continue``. Accepts ``{"verdict": ...}`` and
    the legacy ``{"done": <bool>}`` shape.
    )Úcontinuezjudge returned empty responseTNNrJ  zjudge reply was not JSON: éÈ   Tr  r,   zno reason providedÚverdictr   >   Ú1Úyesr   Útrue>   r   rü   r)   rJ  rü   Fc                 ó”   •— | D ]-  }	 ‰j                  |«      �t        ‰|   «      nd}|dkD  sŒ+|c S  y # t        t        f$ r Y ŒBw xY w)Nr   )rD   r~   Ú	TypeErrorÚ
ValueError)ÚkeysrÌ   ÚivrF   s      €r7   Ú
_first_intz)_parse_judge_response.<locals>._first_int!  s_   ø€ Øò 	ˆAðØ%)§X¡X¨a£[Ð%<”S˜˜a™”\À!�ð �A‹vØ’	ð	ð øô	 œzÐ*ò Ùðús   ˆ!5µAÁAÚwait_on_sessionrÝ   Úwait_sessionÚwait_on_pidr(  Úwait_pidÚwait_for_secondsÚsecondsÚwait_secondsu,    (wait verdict had no target â€” continuing))rS  r-   rQ   r‚   )rH  r"  r-   rD   r2   rB   ra   rR   )rÊ   r  Úverdict_rawrL  Údone_valr   rU  Úsessr(  r[  rF   s             @r7   Ú_parse_judge_responser`    sÂ  ø€ ñ ØFÜ Ó$€DØ€|ØÐ7¼	À#ÀsÓ8KÐ7NÐOÐQUÐW[Ð[Ð[ä�—‘˜(Ó#Ò) rÓ*×0Ñ0Ó2ÒJÐ6J€FØ—(‘(˜9Ó%€KÜ�+œsÔ#Ø×#Ñ#Ó%×+Ñ+Ó-‰à—8‘8˜FÓ#ˆÜKUÐV^Ô`cÔKdˆx�~‰~Ó×%Ñ%Ó'Ð+GÑGÔjnÐowÓjxˆÙ ‘& jˆØÐ=Ñ=ØˆØ�&ÒØ˜  tÐ+Ð+õð �8‰8Ð%Ó&Ò\¨$¯(©(°<Ó*@Ò\ÀDÇHÁHÈ^ÓD\€DÜ�$œÔ §¡¤Ø�v˜u |°T·Z±Z³\Ð&BÐBÐBÙ
�] E¨:Ó
6€CØ
€Ø�v˜u u¨c lÐ2Ð2ÙÐ+¨Y¸ÓG€GØÐØ�v˜u y°'Ð&:Ð:Ð:Ø˜&˜Ð!MÐNÐPUÐW[Ð[Ð[r=   c                óN  — g }| xs g D �]r  }t        |t        «      r%|j                  d«      dk(  s|j                  d«      sŒ:t        t	        |j                  d«      xs d«      j                  dd«      j                  «       d«      }t        t	        |j                  d	«      xs d«      j                  dd«      j                  «       d«      }d
|d   › �}|j                  d«      r|d|d   › �z  }|d|› �z  }|j                  d«      �|d|d   › d�z  }|j                  d«      }|r |j                  d«      rdnd}|d|› |› �z  }n|j                  d«      r|dz  }|r|d|› �z  }|j                  |«       �Œu |syt        j                  dj                  |«      ¬«      S )z¹Render RUNNING ``process_registry.list_sessions()`` entries for the judge prompt. Empty string
    when nothing is running, so the prompt stays byte-identical to the no-background case.r«   Úexitedr(  r}   r,   rI   r]   éx   Úoutput_previewz- pid rÝ   z / session rL   Úuptime_secondsz
 (running zs)Úwatch_patternsÚ	watch_hitz [already matched]z | watch_patterns=Únotify_on_completez | notify_on_completez | recent output: )Úbackground_lines)rB   rC   rD   r"  r-   r�   r2   rb   ÚJUDGE_BACKGROUND_BLOCK_TEMPLATEÚformatrN   )Úbackground_processesÚlinesÚpÚcmdÚtailrh   ÚwpsÚhits           r7   Ú_render_background_blockrs  8  sµ  € ð €EØ!Ò' Ró ˆÜ˜!œTÔ" a§e¡e¨H£o¸Ò&AÈÏÉÈuÌØÜœ˜AŸE™E )Ó,Ò2°Ó3×;Ñ;¸DÀ#ÓF×LÑLÓNÐPSÓTˆÜœ˜QŸU™UÐ#3Ó4Ò:¸Ó;×CÑCÀDÈ#ÓN×TÑTÓVÐX[Ó\ˆØ˜˜%™�zÐ"ˆØ�5‰5�ÔØ�k ! L¡/Ð!2Ð3Ñ3ˆDØ�"�S�E�
ÑˆØ�5‰5Ð!Ó"Ð.Ø�j Ð#3Ñ!4Ð 5°RÐ8Ñ8ˆDà�e‰eÐ$Ó%ˆÙØ*+¯%©%°Ô*<Ñ&À"ˆCØÐ(¨¨¨c¨UÐ3Ñ3‰DØ�U‰UÐ'Ô(ØÐ+Ñ+ˆDÙØÐ(¨¨Ð/Ñ/ˆDØ�‰�TÖð)ñ* ØÜ*×1Ñ1À4Ç9Á9ÈUÓCSÐ1ÓTÐTr=   c                óª   —  | dd|dœd|dœgdt        «       |¬«      }	 |j                  d   j                  j                  xs dS # t        $ r Y yw xY w)zšRoute through call_llm so auxiliary.goal_judge.* config (provider/model, extra_body,
    reasoning_effort, retries) all apply. Returns the raw reply text.r3  Úsystem)ÚroleÚcontentÚuserr   )ÚtaskÚmessagesÚtemperaturer9  r’   r,   )r;  ÚchoicesÚmessagerw  r    )Úcall_llmÚsystem_promptÚuser_promptr’   Úresps        r7   Ú_call_goal_judge_llmr‚  V  se   € ñ
 ØØ#°Ñ>ÈÐ\gÑ@hÐiØÔ"8Ó":ÀGô€Dð
Ø�|‰|˜A‰×&Ñ&×.Ñ.Ò4°"Ð4øÜò Ùðús   Ÿ&A Á	AÁA)r’   ry   rl  rn   Úactive_delegationsc               óT  — | j                  «       sy|j                  «       sy|€
t        «       }	 ddlm} ddlm} |xs g D �
cg c]&  }
|
sŒ|
j                  «       sŒ|
j                  «       ‘Œ( }}
t        t        | d	«      t        |t        «      t        |«      |dkD  rt        j                  |¬
«      ndz   t        j                   t"        j$                  ¬«      j'                  «       j)                  d«      ¬«      }|�T|j+                  «       sD|j-                  «       }|r|› dt/        |«      › �}t1        j                  d dt        |d«      i|¤Ž}n\|rEdj3                  d„ t5        |d¬«      D «       «      }t7        j                  d dt        |d	«      i|¤Ž}nt9        j                  d i |¤Ž}	 t;        |t<        ||«      }tE        |«      \  }}}}t        j?                  d|t        |d«      |rd|› �nd«       ||||dfS # t        $ r }	t        j                  d|	«       Y d}	~	yd}	~	ww xY wc c}
w # |$ r*}	t        j?                  d|	«       dd|	› �dddfcY d}	~	S d}	~	wt        $ r=}	t        j?                  d|	«       ddtA        |	«      jB                  › �dddfcY d}	~	S d}	~	ww xY w)!aG  Ask the auxiliary model whether the goal is satisfied.

    Returns ``(verdict, reason, parse_failed, wait_directive, transport_failed)``; verdict is done /
    blocked / continue / wait / skipped. ``parse_failed`` means unusable output; transport errors
    set ``transport_failed`` instead and fail-open to ``continue``.
    )Úskippedz
empty goalFNF)rJ  z$empty response (nothing to evaluate)FNFNr   ©r~  )ÚAuxiliaryClientUnavailablez.goal judge: auxiliary client import failed: %s)rJ  zauxiliary client unavailableFNFiÐ  )Úcountr,   )Útzz%Y-%m-%d %H:%M:%S %Z)r   ÚresponseÚbackground_blockÚcurrent_timerI   Úcontract_blockiÄ	  c              3  ó2   K  — | ]  \  }}d |› d|› �–— Œ y­wrÖ   rA   rr   s      r7   r8   zjudge_goal.<locals>.<genexpr>”  s!   è ø€ Ò"f¹¸¸4 R¨ s¨"¨T¨FÔ#3Ñ"fùrt   ru   rv   Úsubgoals_blockuM   goal judge: auxiliary client unavailable (%s) â€” falling through to continuerJ  z)goal_judge auxiliary client unavailable: FTu@   goal judge: API call failed (%s) â€” falling through to continuezjudge error: z"goal judge: verdict=%s reason=%s%src  z wait=rA   )#r2   r>  Úagent.auxiliary_clientr~  Úagent.auxiliary_unavailabler‡  r    rã   rä   rC   r"  Ú_JUDGE_RESPONSE_SNIPPET_CHARSrs  Ú JUDGE_DELEGATIONS_BLOCK_TEMPLATErk  r   Únowr   ÚutcÚ
astimezoneÚstrftimer<   rO   rz   Ú(JUDGE_USER_PROMPT_WITH_CONTRACT_TEMPLATErN   rx   Ú(JUDGE_USER_PROMPT_WITH_SUBGOALS_TEMPLATEÚJUDGE_USER_PROMPT_TEMPLATEr‚  ÚJUDGE_SYSTEM_PROMPTÚinfor¡   rU   r`  )r   Úlast_responser’   ry   rl  rn   rƒ  r~  r‡  r¥   rÏ   Úclean_subgoalsÚcommonr�  Úpromptr�  rÊ   rL  r  Úparse_failedÚwait_directives                        r7   Ú
judge_goalr£  f  s™  € ð  �:‰:Œ<Ø:Ø×ÑÔ ØUØ€Ü%Ó'ˆðNÝ3ÝJð +3ª.°bÖM AºQÀ1Ç7Á7Å9�a—g‘g•iÐM€NÐMÜÜ�t˜TÓ"Ü˜=Ô*GÓHÜ1Ð2FÓGØPbÐefÒPfÔ+×2Ñ2Ð9KÐ2ÔLÐlnñpä—\‘\¤X§\¡\Ô2×=Ñ=Ó?×HÑHÐI_Ó`ô€Fð Ð H×$5Ñ$5Ô$7Ø!×.Ñ.Ó0ˆÙØ .Ð/¨rÔ2HÈÓ2XÐ1YÐZˆNÜ9×@Ñ@ÑzÔPYÐZhÐjnÓPoÐzÐsyÑz‰Ù	ØŸ™Ñ"fÄ9È^ÐcdÔCeÔ"fÓfˆÜ9×@Ñ@ÑzÔPYÐZhÐjnÓPoÐzÐsyÑz‰ä+×2Ñ2Ñ<°VÑ<ˆð	SÜ" 8Ô-@À&È'ÓRˆô 5JÈ#Ó4NÑ1€GˆV�\ >Ü
‡K�KÐ4°g¼yÈÐQTÓ?UÙ-;�&˜Ð(Ñ)ÀôEà�F˜L¨.¸%Ð?Ð?øôO ò NÜ�‰ÐEÀsÔKÜMûðNüò Nøð* &ò `ô 	�‰ÐcÐehÔiØÐFÀsÀeÐLÈeÐUYÐ[_Ð_Õ_ûÜò SÜ�‰ÐVÐX[Ô\Ø˜]¬4°«9×+=Ñ+=Ð*>Ð?ÀÈÈdÐRÕRûðSúsY   °H ÁH/ÁH/ÁH/Æ1H4 È	H,ÈH'È'H,È4J'È9IÉJ'ÉJ'É*2J"ÊJ'Ê"J'c           
     ór   — | sy	 ddl m}m} t         ||ddt	        | «      «      «      S # t
        $ r Y yw xY w)zDLive async delegation batches spawned by this session (fail-safe 0).r   )Ú_LIVE_STATESÚ_session_recordsr,   )Útools.async_delegationr¥  r¦  r   r-   r    )rÝ   r¥  r¦  s      r7   Úcount_active_delegationsr¨  ª  s=   € áØðßIÜÑ# L°"°b¼#¸j»/ÓJÓKÐKøÜò Ùðús   …$* ª	6µ6zV[Goal set] Continue with the goal you were just given; there is no need to re-read it.é�  gš™™™™™é?c                ó~  — |}t        |t        «      rdj                  d„ |D «       «      }dj                  t        | xs d«      j	                  «       «      dj                  t        |xs d«      j	                  «       «      }}t        |«      t        k\  r(||v r$t        |«      t        t        |«      z  k\  rt        S | S )zaThe goal text, or ``GOAL_ALREADY_SEEN_KICK`` when ``last_user_message`` is essentially that text.r]   c              3  ót   K  — | ]0  }t        |t        «      sŒt        |j                  d d«      «      –— Œ2 y­w)rd   r,   N)rB   rC   r-   rD   )r4   Úbs     r7   r8   z#goal_kick_prompt.<locals>.<genexpr>Ä  s+   è ø€ ÒZ°aÄjÐQRÔTXÕFYœ3˜qŸu™u V¨RÓ0×1ÑZùs   ‚8˜ 8r,   )	rB   rÉ   rN   r-   Úsplitr   Ú_GOAL_REPASTE_MIN_CHARSÚ_GOAL_REPASTE_MIN_SHAREÚGOAL_ALREADY_SEEN_KICK)r   Úlast_user_messagerw  Ú	goal_normÚ	last_norms        r7   Úgoal_kick_promptr´  À  sš   € à€GÜ�'œ4Ô Ø—(‘(ÑZ¸7ÔZÓZˆØŸ8™8¤C¨ª
°£O×$9Ñ$9Ó$;Ó<¸c¿h¹hÄsÈ7Ê=ÐVXÓGY×G_ÑG_ÓGaÓ>bˆy€IäˆI‹Ô1Ò1Ø˜Ñ"Ü�	‹NÔ5¼¸I»ÑFÒFä%Ð%Ø€Kr=   c                óœ   — t        | xs g «      D ]:  }t        |t        «      sŒ|j                  d«      dk(  sŒ)|j                  d«      c S  y)zZContent of the newest ``role == "user"`` message in an OpenAI-shaped history, else ``""``.rv  rx  rw  r,   )ÚreversedrB   rC   rD   )ÚhistoryÚmsgs     r7   Úlast_user_message_contentr¹  Ï  sG   € ä˜š 2Ó&ò &ˆÜ�cœ4Õ  S§W¡W¨V£_¸Ó%>Ø—7‘7˜9Ó%Ò%ð&ð r=   c                ó’   — | sy	 t        «       }|€y|j                  t        | «      dd¬«      }t        |«      S # t        $ r Y yw xY w)z›Newest user message of ``session_id`` from the SessionDB (gateway/TUI surfaces have no live
    history object at slash-command time); ``""`` on any error.r,   r   T)r!  Úlatest)r   Úget_messagesr-   r¹  r    )rÝ   rê   Úrowss      r7   Úlast_user_message_from_dbr¾  ×  sT   € ñ ØðÜÓˆØˆ:ØØ�‰œs :›°bÀˆÓFˆÜ(¨Ó.Ð.øÜò Ùðús   …: ’': º	AÁA)Úowner_task_idc               ó¸  — 	 ddl m} |j                  | ¬«      xs g }|D �cg c]*  }t        |t        «      sŒ|j                  d«      dk7  sŒ)|‘Œ, }}|rM|D �cg c]B  }t        |j                  d«      xs |j                  d	«      xs d
«      t        |«      k(  sŒA|‘ŒD }}|S # t        $ r"}t        j                  d|«       g cY d}~S d}~ww xY wc c}w c c}w )a  Fail-safe snapshot of RUNNING ``process_registry`` sessions for the judge; ``[]`` on any error
    so the loop degrades to its pre-wait-barrier behavior.

    ``owner_task_id`` restricts the snapshot to processes the goal's OWN session spawned. The registry's
    ``task_id`` is the container key, which collapses to one value for every agent in the process, so
    without this filter a fan-out parent's judge saw every subagent's pollers and parked the goal on a
    grandchild's ``proc_*`` session (one run: 7 of 7 root verdicts were WAIT on child-owned processes;
    parked 3 h 22 min at the end while nothing of its own was running).r   r+  )Útask_idz&gather_background_processes failed: %sNr«   rb  r¿  rÁ  r,   )
r-  r,  Úlist_sessionsr    rã   rä   rB   rC   rD   r-   )rÁ  r¿  r,  Úsessionsr¥   rÏ   Úrunnings          r7   Úgather_background_processesrÅ  æ  sÉ   € ðÝ;à#×1Ñ1¸'Ð1ÓBÒHÀbˆð #ÖZ�Q¤j°´DÕ&9¸a¿e¹eÀH»oÐQYÓ>YŠqÐZ€GÐZÙØ%Öu˜¬¨Q¯U©U°?Ó-CÒ-]ÀqÇuÁuÈYÓGWÒ-]Ð[]Ó)^ÔbeÐfsÓbtÓ)t’1ÐuˆÐuØ€Nøô ò Ü�‰Ð=¸sÔCØ�	ûðüò [ùâus:   ‚B$ ¢C¸CÁCÁACÂCÂ$	CÂ-C
ÃCÃ
C)r’   c          	     ó  — | xs dj                  «       } | sy|€
t        «       }	 ddlm} 	 t        |t        dt        | d«      › �|«      }t        |«      }t        |t        «      s!t
        j                  d	t        |d
«      «       yt        j                  |«      }|j!                  «       rdS |S # t        $ r }t
        j                  d|«       Y d}~yd}~ww xY w# t        $ r }t
        j                  d|«       Y d}~yd}~ww xY w)z¸Expand a plain-language objective into a completion contract via the ``goal_judge`` auxiliary
    task (a side LLM call, not a conversation turn). None when unavailable or unparseable.r,   Nr   r†  z.goal draft: auxiliary client import failed: %szObjective:
r   z goal draft: API call failed (%s)z"goal draft: reply was not JSON: %rrK  )r2   r>  r�  r~  r    rã   rä   r‚  ÚDRAFT_CONTRACT_SYSTEM_PROMPTr"  rœ  rH  rB   rC   r+   rG   r<   )Ú	objectiver’   r~  r¥   rÊ   rF   rn   s          r7   Údraft_contractrÉ  ü  sû   € ð ’˜b×'Ñ'Ó)€IÙØØ€ô &Ó'ˆðÝ3ð
Ü" 8Ô-IÈ\ÔZcÐdmÐosÓZtÐYuÐKvÐxó  Aˆô
   Ó$€DÜ�dœDÔ!Ü�‰Ð9¼9ÀSÈ#Ó;NÔOØÜ×%Ñ% dÓ+€HØ×$Ñ$Ô&ˆ4Ð4¨HÐ4øô ò Ü�‰ÐEÀsÔKÜûðûô ò Ü�‰Ð6¸Ô<Üûðús.   ¥B0 ¬C Â0	CÂ9CÃCÃ	DÃ%D Ä Dc                ó   — | |||||dœS )N)r«   Úshould_continueÚcontinuation_promptrL  r  r}  rA   )r«   rË  r   rL  r  r}  s         r7   Ú	_decisionrÍ    s   € Ø°ÐY_Ø¨&¸WñFð Fr=   z‚~/.hermes/config.yaml:
  auxiliary:
    goal_judge:
      provider: {provider}
      model: {model}
Then /goal resume to continue.c                  ó¨  — e Zd ZdZedœd4d„Zed5d„«       Zd6d„Zd6d„Z	d6d„Z
d7d„Zd5d	„Zd8d
„Zd8d„Zd9d„Zd:d„Zdddœd;d„Zd<d„Zd=d>d„Zddœd?d„Zd@d„Zd9d„ZdAd„ZdBd„ZdCd„ZdDd„ZdEd„Zd7d„ZdddœdFd„ZdDd „ZdEd!„Zd7d"„Z dGd#„Z!dHd$„Z"dIdJd%„Z#dIdKd&„Z$dId'd(œdLd)„Z%d6d*„Z&d6d+„Z'dMd,„Z(d'd-œdNd.„Z)dIdOd/„Z*ddd'd0œ	 	 	 	 	 	 	 	 	 dPd1„Z+dQd2„Z,d7d3„Z-y)Rr  a?  Per-session goal state + continuation decisions.

    The CLI and gateway each hold one per live session. ``evaluate_after_turn`` calls the judge and
    returns the decision dict that drives the next turn; ``next_continuation_prompt`` is the
    canonical user-role message to feed back into ``run_conversation``.
    )Údefault_max_turnsc               ób   — || _         t        |xs t        «      | _        t	        |«      | _        y r0   )rÝ   r~   rÈ   rÏ  r  Ú_state)r6   rÝ   rÏ  s      r7   Ú__init__zGoalManager.__init__1  s)   € Ø$ˆŒÜ!$Ð%6Ò%KÔ:KÓ!LˆÔÜ+4°ZÓ+@ˆ�r=   c                ó   — | j                   S r0   )rÑ  r;   s    r7   r  zGoalManager.state8  s   € à�{‰{Ðr=   c                óT   — | j                   d uxr | j                   j                  dk(  S )Nrª   ©rÑ  r«   r;   s    r7   Ú	is_activezGoalManager.is_active<  s%   € Ø�{‰{ $Ð&ÒI¨4¯;©;×+=Ñ+=ÀÑ+IÐIr=   c                óR   — | j                   d uxr | j                   j                  dv S )N>   rª   ÚpausedrÕ  r;   s    r7   Úhas_goalzGoalManager.has_goal?  s&   € Ø�{‰{ $Ð&ÒU¨4¯;©;×+=Ñ+=ÐAUÐ+UÐUr=   c                óV   — | j                   d uxr | j                   j                  «       S r0   )rÑ  rÓ   r;   s    r7   rÓ   zGoalManager.has_contractB  s#   € Ø�{‰{ $Ð&ÒE¨4¯;©;×+CÑ+CÓ+EÐEr=   c                óJ  — | j                   }|�|j                  dk(  ry|j                  › d|j                  › d�}|j                  r5dt        |j                  «      › dt        |j                  «      dk7  rdnd	› �nd	}| j                  «       rd
nd	}|j                  r5dt        |j                  «      › dt        |j                  «      dk7  rdnd	› �nd	}|› |› |› |› �}|j                  dk(  �r6|j                  rEt        |j                  «      r0d|j                  xs d|j                  › �› d|› d|j                  › �S |j                  rEt        |j                  «      r0d|j                  xs d|j                  › �› d|› d|j                  › �S |j                  rvt        j                  «       |j                  k  rUt!        |j                  t        j                  «       z
  «      }|j                  xs |› d�}d|› d|› d|› d|j                  › �S d|› d|j                  › �S |j                  dk(  r1|j"                  rd|j"                  › �nd	}	d|› |	› d|j                  › �S |j                  dk(  rd|› d|j                  › �S d|j                  › d|› d|j                  › �S )Nr  z*No active goal. Set one with /goal <text>.ú/z turnsz, z subgoalru   rÏ   r,   z
, contractz gaterª   u   â�³ Goal (parked on úsession ú): úpid u   â�³ Goal (parked u   s â€” u   âŠ™ Goal (active, rØ  u    â€” u   â�¸ Goal (paused, r   u   âœ“ Goal done (zGoal ()rÑ  r«   r¬   r­   ry   r   rÓ   rÀ   r»   r/  r¾   r   rº   r)  r¼   Útimer~   rµ   )
r6   rÏ   ÚturnsÚsubÚconÚgatÚmetaÚ	remainingÚwrÚextras
             r7   Ústatus_linezGoalManager.status_lineE  s‰  € Ø�K‰KˆØˆ9˜Ÿ™ IÒ-Ø?Ø—<‘<�.  !§+¡+ ¨fÐ5ˆØUV×U_ÒU_�”3�q—z‘z“?Ð# 8´3°q·z±z³?ÀaÒ3G©CÈRÐ+PÑQÐegˆØ"×/Ñ/Ô1‰l°rˆØLMÏGÊG�”3�q—w‘w“<�. ¬S°·±«\¸QÒ->¡cÀBÐ%GÑHÐY[ˆØ�˜˜˜c˜U 3 %Ð(ˆØ�8‰8�xÓØ×#Ò#Ô(8¸×9MÑ9MÔ(NØ-¨a×.>Ñ.>Ò.cÀHÈQ×MaÑMaÐLbÐBcÐ-dÐdfÐgkÐflÐloÐpq×pvÑpvÐowÐxÐxØ×Ò¤J¨q×/?Ñ/?Ô$@Ø-¨a×.>Ñ.>Ò.[ÀDÈ×IYÑIYÐHZÐB[Ð-\Ð\^Ð_cÐ^dÐdgÐhi×hnÑhnÐgoÐpÐpØ�Š¤4§9¡9£;°·±Ò#@Ü §¡´$·)±)³+Ñ =Ó>�	Ø×%Ñ%Ò8¨I¨;°a¨�Ø*¨9¨+°V¸B¸4¸rÀ$ÀÀsÈ1Ï6É6È(ÐSÐSØ'¨ v¨S°·±°Ð9Ð9Ø�8‰8�xÒØ12·²�e˜AŸO™OÐ,Ñ-ÀbˆEØ'¨ v¨e¨W°C¸¿¹°xÐ@Ð@Ø�8‰8�vÒØ$ T F¨#¨a¯f©f¨XÐ6Ð6Ø˜Ÿ™�z  D 6¨¨Q¯V©V¨HÐ5Ð5r=   c                óZ   — t        | j                  | j                  «       | j                  S r0   )r  rÝ   rÑ  r;   s    r7   Ú_savezGoalManager._savea  s   € Ü�$—/‘/ 4§;¡;Ô/Ø�{‰{Ðr=   c                óh   — | j                   �| j                  «       st        d«      ‚| j                   S )Núno active goal)rÑ  rÙ  rö   r;   s    r7   Ú_require_goalzGoalManager._require_goale  s*   € Ø�;‰;Ð d§m¡m¤oÜÐ/Ó0Ð0Ø�{‰{Ðr=   c                óz   — | j                   �| j                   j                  dk7  rt        d«      ‚| j                   S )Nrª   zno active goal to park)rÑ  r«   rö   r;   s    r7   Ú_require_activezGoalManager._require_activej  s3   € Ø�;‰;Ð $§+¡+×"4Ñ"4¸Ò"@ÜÐ7Ó8Ð8Ø�{‰{Ðr=   c                óh   — d| j                   _        || j                   _        | j                  «        y ©NrØ  )rÑ  r«   rµ   rë  ©r6   r  s     r7   Ú_pause_statezGoalManager._pause_stateo  s#   € Ø%ˆ�‰ÔØ$*ˆ�‰Ô!Ø�
‰
�r=   c                óD   — | j                  |«       t        ddd |||«      S )NrØ  F)rô  rÍ  )r6   rµ   rL  r  r}  s        r7   Ú_pause_decisionzGoalManager._pause_decisiont  s%   € Ø×Ñ˜-Ô(Ü˜ 5¨$°¸ÀÓIÐIr=   N)r­   rn   c          
     óü   — |xs dj                  «       }|st        d«      ‚t        |ddt        j                  «       d|rt	        |«      n| j
                  |�|n	t        «       ¬«      | _        | j                  «       S )Nr,   zgoal text is emptyrª   r   r®   )r   r«   r¬   r°   r±   r­   rn   )	r2   rR  r©   rà  r~   rÏ  r+   rÑ  rë  )r6   r   r­   rn   s       r7   rè   zGoalManager.setx  sl   € Ø’
˜×!Ñ!Ó#ˆÙÜÐ1Ó2Ð2ÜØ˜h°1ÄÇÁÃÐ[^Ù(1”c˜)”n°t×7MÑ7MØ!)Ð!5‘X¼<»>ô
ˆŒð
 �z‰z‹|Ðr=   c                óv   — | j                   €y|xs
 t        «       | j                   _        | j                  «       S )z=Attach or replace the completion contract on the active goal.N)rÑ  r+   rn   rë  )r6   rn   s     r7   Úset_contractzGoalManager.set_contractƒ  s.   € à�;‰;ÐØØ'Ò9¬<«>ˆ�‰ÔØ�z‰z‹|Ðr=   c                ó´   — | j                   sy d| j                   _        || j                   _        | j                   j                  «        | j	                  «       S rò  )rÑ  r«   rµ   rÙ   rë  ró  s     r7   ÚpausezGoalManager.pauseŠ  s@   € Ø�{Š{ØØ%ˆ�‰ÔØ$*ˆ�‰Ô!Ø�‰×ÑÔ Ø�z‰z‹|Ðr=   T)Úreset_budgetc               óÚ   — | j                   sy d| j                   _        d | j                   _        | j                   j                  «        |rd| j                   _        | j                  «       S )Nrª   r   )rÑ  r«   rµ   rÙ   r¬   rë  )r6   rü  s     r7   ÚresumezGoalManager.resume’  sO   € Ø�{Š{ØØ%ˆ�‰ÔØ$(ˆ�‰Ô!Ø�‰×ÑÔ ÙØ%&ˆD�K‰KÔ"Ø�z‰z‹|Ðr=   c                ón   — | j                   €y d| j                   _        | j                  «        d | _         y )Nr  )rÑ  r«   rë  r;   s    r7   ÚclearzGoalManager.clearœ  s+   € Ø�;‰;ÐØØ&ˆ�‰ÔØ�
‰
ŒØˆ�r=   c                ó¤   — | j                   sy d| j                   _        d| j                   _        || j                   _        | j	                  «        y )Nr   )rÑ  r«   r³   r´   rë  ró  s     r7   Ú	mark_donezGoalManager.mark_done£  s9   € Ø�{Š{ØØ#ˆ�‰ÔØ#)ˆ�‰Ô Ø"(ˆ�‰ÔØ�
‰
�r=   c                ó¾   — | j                  «       }|xs dj                  «       }|st        d«      ‚|j                  j	                  |«       | j                  «        |S )zNAppend a user-added criterion; raises ``RuntimeError`` without ``has_goal()``.r,   zsubgoal text is empty)rî  r2   rR  ry   rb   rë  )r6   rd   r  s      r7   Úadd_subgoalzGoalManager.add_subgoal­  sQ   € à×"Ñ"Ó$ˆØ’
˜×!Ñ!Ó#ˆÙÜÐ4Ó5Ð5Ø�‰×Ñ˜dÔ#Ø�
‰
ŒØˆr=   c                óî   — t        | j                  «       |«      }t        |«      dz
  }|dk  s|t        |«      k\  rt	        dt        |«      › d�«      ‚|j                  |«      }| j                  «        |S )Nru   r   zindex out of range (1..ú))r1   rî  r~   r   Ú
IndexErrorræ   rë  )r6   ÚattrÚindex_1basedrc   ÚidxÚremoveds         r7   Ú	_pop_itemzGoalManager._pop_item·  sl   € Ü˜×*Ñ*Ó,¨dÓ3ˆÜ�,Ó !Ñ#ˆØ�Š7�cœS ›ZÒ'ÜÐ6´s¸5³z°lÀ!ÐDÓEÐEØ—)‘)˜C“.ˆØ�
‰
ŒØˆr=   c                óŠ   — | j                  «       }t        t        ||«      «      }t        ||g «       | j	                  «        |S r0   )rî  r   r1   Úsetattrrë  )r6   r  r  Úprevs       r7   Ú_clear_itemszGoalManager._clear_itemsÀ  s;   € Ø×"Ñ"Ó$ˆÜ”7˜5 $Ó'Ó(ˆÜ��t˜RÔ Ø�
‰
ŒØˆr=   c                ó&   — | j                  d|«      S )z<Remove a subgoal by 1-based index. Returns the removed text.ry   )r  ©r6   r	  s     r7   Úremove_subgoalzGoalManager.remove_subgoalÇ  s   € à�~‰~˜j¨,Ó7Ð7r=   c                ó$   — | j                  d«      S )z.Wipe all subgoals. Returns the previous count.ry   ©r  r;   s    r7   Úclear_subgoalszGoalManager.clear_subgoalsË  s   € à× Ñ  Ó,Ð,r=   c                óX   — | j                   €y| j                   j                  «       xs dS )z-Public helper for the /subgoal slash command.ú(no active goal)u5   (no subgoals â€” use /subgoal <text> to add criteria))rÑ  r×   r;   s    r7   Úrender_subgoalszGoalManager.render_subgoalsÏ  s(   € à�;‰;ÐØ%Ø�{‰{×0Ñ0Ó2ÒmÐ6mÐmr=   )r   r€   c               ó  — | j                  «       }|xs dj                  «       }|st        d«      ‚t        ||rt	        |«      nt
        |rt	        |«      nt        ¬«      }|j                  j                  |«       | j                  «        |S )zNAppend a quality-gate command; raises ``RuntimeError`` without ``has_goal()``.r,   zgate command is empty)r}   r   r€   )
rî  r2   rR  r|   r~   r‡   rˆ   rÀ   rb   rë  )r6   r}   r   r€   r  r¢   s         r7   Úadd_gatezGoalManager.add_gate×  sz   € à×"Ñ"Ó$ˆØ’=˜b×'Ñ'Ó)ˆÙÜÐ4Ó5Ð5ÜØÙ4CœC Ô0ÔIeÙ,7œ˜KÔ(Ô=Uô
ˆð
 	�‰×Ñ˜4Ô Ø�
‰
ŒØˆr=   c                ó:   — | j                  d|«      j                  S )z<Remove a gate by 1-based index. Returns the removed command.rÀ   )r  r}   r  s     r7   Úremove_gatezGoalManager.remove_gateæ  s   € à�~‰~˜g |Ó4×<Ñ<Ð<r=   c                ó$   — | j                  d«      S )z-Remove all gates. Returns the previous count.rÀ   r  r;   s    r7   Úclear_gateszGoalManager.clear_gatesê  s   € à× Ñ  Ó)Ð)r=   c                óœ  — | j                   €y| j                   j                  syg }t        | j                   j                  d¬«      D ]r  \  }}d}|j                  dk(  rd}n6|j                  �*d|j                  › d	|j                  › d
|j
                  › d�}|j                  d|› d|j                  › |› �«       Œt dj                  |«      S )z/Public helper for the /goal gate slash command.r  uB   (no quality gates â€” use /goal gate add <command> to require one)ru   rv   r,   r   u    âœ“ passingu    âœ— failing (exit z
, attempt rÜ  r  rK   z. $ rI   )	rÑ  rÀ   rx   rƒ   r�   r€   rb   r}   rN   )r6   rm  rs   rÐ   r«   s        r7   Úrender_gateszGoalManager.render_gatesî  sÍ   € à�;‰;ÐØ%Ø�{‰{× Ò ØWØˆÜ˜dŸk™k×/Ñ/°qÔ9ò 	:‰DˆAˆqØˆFØ×Ñ 1Ò$Ø'‘Ø×!Ñ!Ð-Ø.¨q×/?Ñ/?Ð.@À
È1Ï:É:È,ÐVWÐXY×XeÑXeÐWfÐfgÐh�Ø�L‰L˜2˜a˜S  Q§Y¡Y K°¨xÐ8Õ9ð	:ð �y‰y˜ÓÐr=   c                óV  — | j                   }|�|j                  sy|j                  D �]n  }t        |«      \  }}}||_        ||_        |rd|_        Œ+|xj
                  dz  c_        |j
                  |j                  kD  r^| j                  d|j
                  dz
  › d|j                  › �dd|j                  › �d|j                  › d|j                  › d	|› d
�«      c S | j                  «        t        j                  |j                  |j                  ||j
                  |j                  |xs d¬«      }t        dd|dd|› d|j                  › �d|j                  › d|j                  › d|j
                  › d|j                  › d|j                  › �
«      c S  | j                  «        y)a  Run quality gates in order; return a decision dict on failure.

        Every eligible boundary re-executes a failed gate. A git HEAD+porcelain fingerprint used to
        replay the recorded failure when "nothing changed", but porcelain sees neither the contents
        of an untracked or already-modified file nor inputs outside the repo, so a repaired input
        was replayed as still-failing until retry exhaustion paused the goal (#110649). The
        retry cap below still bounds a genuinely stuck red suite.
        Nr   ru   zquality gate exhausted z retries: $ Úgate_failedzgate exhausted retries: $ u5   â�¸ Goal paused â€” quality gate still failing after z (exit z>). Fix it manually or /goal gate remove it, then /goal resume.z(no output))r   r}   Ú	exit_codeÚattemptr€   Úoutputrª   Tzgate failed (exit z): $ u   âœ— Quality gate failed (rÜ  z turns, attempt )rÑ  rÀ   r§   rƒ   r„   r�   r€   rö  r}   rë  Ú(CONTINUATION_PROMPT_GATE_FAILED_TEMPLATErk  r   rÍ  r¬   r­   )r6   r  r¢   Úpassedr$  rp  r   s          r7   Ú_check_gateszGoalManager._check_gatesþ  s´  € ð —‘ˆØˆ= §¢Øà—K‘Kó 	ˆDÜ&.¨t£nÑ#ˆF�I˜tØ"+ˆDÔØ$(ˆDÔ!ÙØ !�”Øà�MŠM˜QÑ�Mà�}‰}˜t×/Ñ/Ò/Ø×+Ñ+Ø-¨d¯m©m¸aÑ.?Ð-@ÀÈTÏ\É\ÈNÐ[Ø!Ð%?ÀÇÁ¸~Ð#NØKØ×'Ñ'Ð(¨°T·\±\°Nð CØ&˜Kð ()ð*óò ð �J‰JŒLÜ=×DÑDØ—Z‘Z¨¯©ÀÐTX×TaÑTaØ ×,Ñ,°TÒ5J¸]ð Eó ˆFô Ø˜$ ¨Ø$ Y K¨u°T·\±\°NÐCØ+¨E×,<Ñ,<Ð+=¸Q¸u¿¹Ð>Oð PØŸ=™=˜/¨¨4×+;Ñ+;Ð*<¸EÀ$Ç,Á,ÀðQóò ð3	ð@ 	�
‰
ŒØr=   c                ó  — | j                  «       }|j                  «        |j                  «       D ]  \  }}t        |||«       Œ |xs dj	                  «       xs d |_        t        j                  «       |_        | j                  «       S )Nr,   )	rð  rÙ   rc   r  r2   r¾   rà  r¿   rë  )r6   r  Úbarrierr  rÌ   rm   s         r7   Ú_parkzGoalManager._park0  su   € Ø×$Ñ$Ó&ˆØ×ÑÔØ—M‘M“Oò 	!‰DˆAˆqÜ�E˜1˜aÕ ð	!à &¢¨"×3Ñ3Ó5Ò=¸ˆÔÜ"Ÿi™i›kˆÔØ�z‰z‹|Ðr=   c                óª   — | j                  «        t        |«      }|dk  rt        d«      ‚t        |«      st        d«      ‚| j	                  ||¬«      S )z·Park the goal loop until a background PID exits (no turn burned, no judge call). For a
        process with a watch/notify trigger prefer ``wait_on_session``. Requires an active goal.r   zpid must be a positive integerzpid is not alive on this host)rº   )rð  r~   rR  r)  r,  )r6   r(  r  s      r7   Úwait_onzGoalManager.wait_on9  sR   € ð 	×ÑÔÜ�#‹hˆØ�!Š8ÜÐ=Ó>Ð>Ü˜#ŒÜÐ<Ó=Ð=Ø�z‰z˜&°ˆzÓ5Ð5r=   c                óœ   — | j                  «        t        |xs d«      j                  «       }|st        d«      ‚| j	                  ||¬«      S )z¶Park on a process_registry session's OWN trigger: exit OR ``watch_patterns`` match. The
        right barrier for a long-lived watcher/poller that signals mid-run and may never exit.r,   z%session_id must be a non-empty string)r»   )rð  r-   r2   rR  r,  )r6   rÝ   r  s      r7   rV  zGoalManager.wait_on_sessionD  sJ   € ð 	×ÑÔÜ˜Ò) rÓ*×0Ñ0Ó2ˆ
ÙÜÐDÓEÐEØ�z‰z˜&°ZˆzÓ@Ð@r=   r   )Úon_delegationsc          
     óÐ   — | j                  «        t        |«      }|dk  rt        d«      ‚| j                  |t	        j                  «       |z   t        dt        |«      «      ¬«      S )a±  Park until ``seconds`` from now (backoff/cooldown waits with no process to track). With
        ``on_delegations`` the wait is FOR those live delegation batches: it also lifts as soon as
        fewer are live (a batch result came back), so the loop re-judges with the result in hand
        instead of sleeping out a 20-minute timer (independent review: results arrived with 1,199 s
        left on the timer and nothing re-judged).r   z"seconds must be a positive integer)r¼   r½   )rð  r~   rR  r,  rà  rš   )r6   r[  r  r0  s       r7   rZ  zGoalManager.wait_for_secondsM  s\   € ð 	×ÑÔÜ�g“,ˆØ�aŠ<ÜÐAÓBÐBØ�z‰z˜&´·	±	³¸gÑ0EÔ^aÐbcÔehÐiwÓexÓ^yˆzÓzÐzr=   c                óª   — | j                   }|�$|j                  €|j                  €|j                  sy|j	                  «        | j                  «        y)zVClear any active wait barrier (pid / session / time). Returns True if one was cleared.FT)rÑ  rº   r»   r¼   rÙ   rë  )r6   rÏ   s     r7   Ústop_waitingzGoalManager.stop_waitingY  sG   € à�K‰KˆØˆ9˜×)Ñ)Ð1°a×6JÑ6JÐ6RÐ[\×[jÒ[jØØ	�‰ŒØ�
‰
ŒØr=   c                ó¦  — | j                   }|€y|j                  �t        |j                  «      }nˆ|j                  �t	        |j                  «      }nf|j
                  rYt        j                  «       |j
                  k  }|r7|j                  dkD  r(t        | j                  «      }||j                  k  rd}ny|rƒ|j                  rw|j
                  dk(  rht        j                  «       |j                  z
  t        kD  r@t        j                  d| j                  |j                  xs |j                  t        «       d}|s| j                  «        |S )a“  True iff a barrier is set AND not yet satisfied. A satisfied barrier is cleared here
        (lazy auto-clear) so the next evaluation resumes normal judging. A pid/session barrier
        also expires after ``_MAX_BARRIER_WAIT_S``: a watcher or poller that never exits would
        otherwise park the goal indefinitely (one run sat 3 h 22 min on a poller that outlived
        the work it was polling).Fr   r®   z:goal %s: wait barrier on %s exceeded %ds; resuming judging)rÑ  r»   r/  rº   r)  r¼   rà  r½   r¨  rÝ   r¿   Ú_MAX_BARRIER_WAIT_Srã   rœ  r3  )r6   rÏ   ÚstillÚlives       r7   Ú
is_waitingzGoalManager.is_waitingb  s  € ð �K‰KˆØˆ9ØØ×ÑÐ+Ü$ Q×%9Ñ%9Ó:‰EØ×ÑÐ)Ü˜q×/Ñ/Ó0‰EØ�_Š_Ü—I‘I“K !§/¡/Ñ1ˆEÙ˜×1Ñ1°AÒ5ä/°·±Ó@�Ø˜!×2Ñ2Ò2Ø!‘EàÙ�Q—_’_¨¯©¸CÒ)?ÄDÇIÁIÃKÐRS×RaÑRaÑDaÔdwÒDwÜ�K‰KÐTØŸ™¨×)=Ñ)=Ò)QÀ×AQÑAQÔSfôhàˆEÙØ×ÑÔØˆr=   c                ó,  — |j                   �d|j                   › �}nS|j                  �d|j                  › �}n7t        dt        |j                  t        j
                  «       z
  «      «      › d�}|j                  xs |}t        ddd d|d|› d	|› �«      S )
NrÝ  rß  r   zs remainingrª   FÚwaitingu   â�³ Goal parked â€” waiting on rL   )r»   rº   rš   r~   r¼   rà  r¾   rÍ  )r6   r  Útgtr  s       r7   Ú_waiting_decisionzGoalManager._waiting_decision‚  s¢   € Ø×#Ñ#Ð/Ø˜U×5Ñ5Ð6Ð7‰CØ×!Ñ!Ð-Ø˜×-Ñ-Ð.Ð/‰Cä˜œC × 3Ñ 3´d·i±i³kÑ AÓBÓCÐDÀKÐPˆCØ×%Ñ%Ò,¨ˆÜ˜ 5¨$°	¸6ÐEdÐehÐdiÐikÐlrÐksÐCtÓuÐur=   ©rƒ  c               óÆ  — |j                  d«      r-d| j                  t        |d   «      |¬«      j                  › �}ni|j                  d«      r0t	        |d   «      }	 d| j                  ||¬«      j                  › �}n(| j                  t	        |d   «      ||¬	«       |d   › d
�}t        dddd|d|› d|› �«      S # t        $ r t        j                  d|«       Y yw xY w)zõJudge said WAIT: set the barrier and park. The counted turn stands (the judge ran) but no
        continuation fires; the loop resumes once the barrier clears. ``None`` = the barrier is
        unobservable here, so the caller continues instead.rÝ   rÝ  r  r(  rß  z@goal judge: wait_on_pid %s is not alive on this host; continuingNr[  )r  r0  rÏ   rª   Frü   u'   â�³ Goal parked (judge) â€” waiting on rL   )rD   rV  r-   r»   r~   r.  rº   rR  rã   rœ  rZ  rÍ  )r6   r¢  r  rƒ  r;  r(  s         r7   Ú_apply_wait_directivez!GoalManager._apply_wait_directiveŒ  s  € ð ×Ñ˜lÔ+Ø˜T×1Ñ1´#°nÀ\Ñ6RÓ2SÐ\bÐ1Óc×vÑvÐwÐx‰CØ×Ñ Ô&Ü�n UÑ+Ó,ˆCðØ˜TŸ\™\¨#°f˜\Ó=×LÑLÐMÐN‘ð ×!Ñ!¤# n°YÑ&?Ó"@ÈÐ`rÐ!ÔsØ# IÑ.Ð/¨qÐ1ˆCÜ˜ 5¨$°¸ÐBiÐjmÐinÐnpÐqwÐpxÐ@yÓzÐzøô ò ô
 —‘Ð^Ð`cÔdÙðús   Á B> Â>C ÃC c                óœ   — | j                  d|j                  › d|j                  › d�||d|j                  › d|j                  › d|› d�«      S )Nzturn budget exhausted (rÜ  r  u   â�¸ Goal paused â€” z turns usedz9. Use /goal resume to keep going, or /goal clear to stop.)rö  r¬   r­   )r6   r  rL  r  Únotes        r7   Ú_budget_pausezGoalManager._budget_pause¢  sf   € Ø×#Ñ#Ø% e×&6Ñ&6Ð%7°q¸¿¹Ð8IÈÐKÈWÐV\Ø" 5×#3Ñ#3Ð"4°A°e·o±oÐ5FÀkÐRVÐQWð XFð Fó
ð 	
r=   )Úuser_initiatedrl  rƒ  c               óÜ  — | j                   }|�|j                  dk7  rt        |r|j                  ndddddd«      S | j                  «       r| j	                  |«      S |xj
                  dz  c_        t        j                  «       |_        | j                  «       }|�Q|j                  d«      r>|j
                  |j                  k\  r%| j                  |d	|j                  d
d«      d¬«      S |S t        |j                  ||j                  xs d||j                  «       r|j                   nd|¬«      \  }}}	}
}||_        ||_        |	r|j&                  dz   nd|_        |r|j(                  dz   nd|_        |dk(  r|
r| j+                  |
||¬«      }|�|S |dk(  r| j-                  d|› �d|d|› d�«      S |dk(  r*d|_        | j/                  «        t        dddd|d|› �«      S |j(                  |j&                  }}|t0        k\  r4| j-                  d|› d�d|d|› d�t2        j5                  dd¬«      z   «      S |t6        k\  r4| j-                  d|› d �d|d!|› d"�t2        j5                  d#d$¬«      z   «      S |j
                  |j                  k\  r| j                  |d|«      S | j/                  «        t        dd%| j9                  «       d|d&|j
                  › d'|j                  › d(|› �«      S ))u  Run gates + judge and update state. Return a decision dict (``status``, ``should_continue``,
        ``continuation_prompt``, ``verdict``, ``reason``, ``message``). Both real user prompts and our
        own continuations increment ``turns_used`` â€” both consume model budget.Nrª   FÚinactiverí  r,   ru   rË  r#  r  z" (a quality gate is still failing))rA  )ry   rl  rn   rƒ  r   rü   r=  r)   zjudged unachievable: u*   ðŸš« Goal judged unachievable â€” paused: z8 Re-scope with /goal set, or override with /goal resume.r   u   âœ“ Goal achieved: zjudge API unreachable zH turns in a row (check auxiliary.goal_judge provider/key in config.yaml)rJ  u/   â�¸ Goal paused â€” judge API returned errors (z. turns). Check the goal_judge provider/key in Údeepseekzdeepseek-flash)ÚproviderÚmodelz(judge model returned unparseable output z turns in a rowu%   â�¸ Goal paused â€” the judge model (zZ turns) isn't returning the required JSON verdict. Route the judge to a stricter model in Ú
openrouterzgoogle/gemini-3-flash-previewTu   â†» Continuing toward goal (rÜ  rÞ  )rÑ  r«   rÍ  r8  r<  r¬   rà  r±   r)  rD   r­   rB  r£  r   ry   rÓ   rn   r³   r´   r¶   r·   r?  rö  rë  Ú*DEFAULT_MAX_CONSECUTIVE_TRANSPORT_FAILURESÚ_JUDGE_CONFIG_HINTrk  Ú&DEFAULT_MAX_CONSECUTIVE_PARSE_FAILURESÚnext_continuation_prompt)r6   r�  rC  rl  rƒ  r  Úgate_decisionrL  r  r¡  r¢  Útransport_failedÚparkedÚn_txÚn_parses                  r7   Úevaluate_after_turnzGoalManager.evaluate_after_turn©  sQ  € ð —‘ˆØˆ=˜EŸL™L¨HÒ4Ü©U˜UŸ\š\¸¸eÀTÈ:ÐWgÐikÓlÐlð �?‰?ÔØ×)Ñ)¨%Ó0Ð0à×Ò˜AÑÕÜ!ŸY™Y›[ˆÔð ×)Ñ)Ó+ˆØÐ$Ø× Ñ Ð!2Ô3¸×8HÑ8HÈEÏOÉOÒ8[Ø×)Ñ)¨%°À×@QÑ@QÐRZÐ\^Ó@_ð  gKÐ)ó  Lð  LØ Ð äJTØ�J‰J˜°·±Ò0FÀ$Ð]qØ',×'9Ñ'9Ô';�U—^’^ÀÐZlôK
ÑGˆ�˜ ~Ð7Gð %ˆÔØ"ˆÔñ T`¨5×+KÑ+KÈaÒ+OÐefˆÔ(Ù[k¨u×/SÑ/SÐVWÒ/WÐqrˆÔ,à�fÒ¡Ø×/Ñ/°ÀÐ[mÐ/ÓnˆFØÐ!Ø�ð �iÒØ×'Ñ'Ø'¨ xÐ0°)¸VØ<¸V¸HÐD|Ð}óð ð
 �fÒØ!ˆEŒLØ�J‰JŒLÜ˜V U¨D°&¸&ÐDWÐX^ÐW_ÐB`ÓaÐað ×<Ñ<¸e×>^Ñ>^ˆgˆØÔ=Ò=Ø×'Ñ'Ø(¨¨Ð.vÐwØ˜FØAÀ$ÀÐGuÐvÜ$×+Ñ+°ZÐGWÐ+ÓXñYóð ð Ô<Ò<Ø×'Ñ'Ø:¸7¸)À?ÐSÐU_ÐagØ7¸°yð A:ð :ä$×+Ñ+°\ÐIhÐ+Óiñjóð ð ×Ñ˜uŸ™Ò.Ø×%Ñ% e¨Z¸Ó@Ð@à�
‰
ŒÜØ�d˜D×9Ñ9Ó;¸ZÈØ*¨5×+;Ñ+;Ð*<¸A¸e¿o¹oÐ=NÈcÐRXÐQYÐZó
ð 	
r=   c                óÖ  — | j                   }|r|j                  dk7  ry |j                  «       ra|j                  j	                  «       }|j
                  r|› dt        |j
                  «      › �}t        j                  |j                  |¬«      S |j
                  r/t        j                  |j                  |j                  «       ¬«      S t        j                  |j                  ¬«      S )Nrª   rI   )r   r�  )r   r�  )r   )rÑ  r«   rÓ   rn   rO   ry   rz   Ú*CONTINUATION_PROMPT_WITH_CONTRACT_TEMPLATErk  r   Ú*CONTINUATION_PROMPT_WITH_SUBGOALS_TEMPLATEr×   ÚCONTINUATION_PROMPT_TEMPLATE)r6   rÏ   r�  s      r7   rM  z$GoalManager.next_continuation_promptÿ  s¹   € Ø�K‰KˆÙ�A—H‘H Ò(Øà�>‰>ÔØŸZ™Z×4Ñ4Ó6ˆNØ�zŠzØ$2Ð#3°2Ô6LÈQÏZÉZÓ6XÐ5YÐ!Z�Ü=×DÑDÈ!Ï&É&ÐaoÐDÓpÐpØ�:Š:Ü=×DÑDÈ!Ï&É&Ðab×axÑaxÓazÐDÓ{Ð{Ü+×2Ñ2¸¿¹Ð2Ó?Ð?r=   c                óœ   — | j                   €y| j                   j                  «       r$| j                   j                  j                  «       S dS )z>Public helper for the /goal show + /goal draft slash commands.r  u^   (no completion contract â€” set one with /goal draft <objective> or inline field: value lines))rÑ  rÓ   rn   rO   r;   s    r7   Úrender_contractzGoalManager.render_contract  sC   € à�;‰;ÐØ%Ø6:·k±k×6NÑ6NÔ6Pˆt�{‰{×#Ñ#×0Ñ0Ó2ð 	nØlð	nr=   )rÝ   r-   rÏ  r~   )rQ   úOptional[GoalState]rP   rT   )rQ   r©   )r  r-   rQ   rÛ   )
rµ   r-   rL  r-   r  r-   r}  r-   rQ   r‰   )r   r-   r­   r‚   rn   úOptional[GoalContract]rQ   r©   )rn   r+   rQ   rZ  )zuser-paused)r  r-   rQ   rZ  )rü  rR   rQ   rZ  rÚ   )rd   r-   rQ   r-   )r  r-   r	  r~   )r  r-   rQ   r~   )r	  r~   rQ   r-   ©rQ   r~   )r}   r-   r   r‚   r€   r‚   rQ   r|   )rQ   rS   )r  r-   rQ   r©   )r,   )r(  r~   r  r-   rQ   r©   )rÝ   r-   r  r-   rQ   r©   )r[  r~   r  r-   r0  r~   rQ   r©   )r  r©   rQ   r‰   )r¢  r‰   r  r-   rƒ  r~   rQ   rS   )
r  r©   rL  r-   r  r-   rA  r-   rQ   r‰   )
r�  r-   rC  rR   rl  úOptional[List[Dict[str, Any]]]rƒ  r~   rQ   r‰   )rQ   r²   ).rU   rV   rW   rX   rÈ   rÒ  Úpropertyr  rÖ  rÙ  rÓ   ré  rë  rî  rð  rô  rö  rè   rù  rû  rþ  r   r  r  r  r  r  r  r  r  r  r  r!  r)  r,  r.  rV  rZ  r3  r8  r<  r?  rB  rS  rM  rY  rA   r=   r7   r  r  )  sZ  „ ñð EVõ Að òó ðóJóVóFó6ó8óó
ó
ó
Jð <@Ðdhõ 	óôð .2õ óóóóóó8ó-ónð JNÐlpõ ó=ó*ó ó .ódô	6ôAð
{ÐXYõ 
{óóó@vð opõ {ô,
ð =AØ?CØ"#ñT
Ø ðT
Ø59ðT
à<ðT
ð  ðT
ð 
ó	T
ól@ônr=   r  uÌ  [Continuing toward this kanban task â€” judge says it is not done yet]
Reason: {reason}

Take the next concrete step toward completing the task. When the work is genuinely finished, call kanban_complete with a summary. If it is a code change that needs same-card review before counting as done, call kanban_request_review with a summary instead. If you are blocked and need human input, call kanban_block with a reason. Do not stop without calling one of them.a^  [The work looks complete, but the task is still open]
Reason: {reason}

If the task is genuinely done, call kanban_complete now with a short summary of what you did. If it is a code change awaiting same-card review, call kanban_request_review with that summary instead. If something still blocks completion, call kanban_block with the reason instead.)Úcompleted_by_workerzworker completed the taskz8task {task_id} completed by worker after {turns} turn(s))Úblocked_by_workerzworker blocked the taskz6task {task_id} blocked by worker after {turns} turn(s))Úreview_requested_by_workerzworker requested reviewzDtask {task_id} handed off for review by worker after {turns} turn(s))Úchanges_requested_by_reviewerzreviewer requested changeszBreviewer returned task {task_id} for changes after {turns} turn(s))r   r)   ÚreviewÚchanges_requested)r­   Úfirst_responseÚlogc                óÒ  ‡‡‡‡— d3ˆfd„Šd4ˆˆfd„}d5ˆfd„}	t        |xs t        «      }|dk  rt        }|xs d}
dŠd}	 	  |«       }t        j	                  |«      }|�+|\  }}} ‰d|j                  | ‰¬«      z   «        |	||«      S |dvr ‰d| › d|›d�«        |	d
d|› �«      S ddlm}m}m	}  |«       rdn
 |d| › �«      }	 t        ||
«      \  }}}}}|�	 ||«       	 |dk(  rd} ‰d‰› d|› d|› dt        |d«      › �«       |dk(  r# ‰d| › d�«        |d |› �«        |	d!d"|› �«      S |d#k(  rF|r! ‰d| › d$�«        |d%|› d&�«        |	d'd(«      S t        j                  t        |d)«      ¬*«      }d}n t        j                  t        |d)«      ¬*«      }‰|k\  r6 ‰d| › d+‰› d|› d,�«        |d-‰› d|› d.t        |d/«      › �«        |	d'd0«      S 	  ||«      xs d}
‰dz  Š�Œ¬# t        $ r} ‰d|› d	�«        |	d
d«      cY d}~S d}~ww xY w# |�	 ||«       w w xY w# t        $ r5} ‰d1|› d	�«        |	d
d2t        |«      j                  › �«      cY d}~S d}~ww xY w)6aŸ  Drive a kanban worker through a Ralph-style goal loop.

    Each iteration: stop if the worker already terminated the task (``kanban_complete`` /
    ``kanban_block`` / review hand-off); otherwise judge the latest response against ``goal_text``
    (the card's title + body) and feed a continuation or finalize nudge. A WAIT verdict is treated
    as CONTINUE (workers finish via kanban tools, not by parking).
    c                ó<   •— ‰�
	  ‰| «       y y # t         $ r Y y w xY wr0   ©r    )r¸  rf  s    €r7   Ú_logz"run_kanban_goal_loop.<locals>._logN  s-   ø€ Øˆ?ðÙ�C•ð øô ò Ùðús   … �	šc                ó\   •— 	  ‰| «       y # t         $ r} ‰d|› d�«       Y d }~y d }~ww xY w)Nz#kanban goal loop: block_fn failed (r  ri  )r}  r¥   rj  Úblock_fns     €€r7   Ú_blockz$run_kanban_goal_loop.<locals>._blockU  s5   ø€ ð	?Ù�WÕøÜò 	?ÙÐ6°s°e¸1Ð=×>Ñ>ûð	?ús   ƒ Œ	+•&¦+c                ó   •— | ‰|dœS )N)r   r¬   r  rA   )r   r  r¬   s     €r7   Ú_resultz%run_kanban_goal_loop.<locals>._result[  s   ø€ Ø"°*ÈÑOÐOr=   ru   r,   FTz'kanban goal loop: status check failed (z); stoppingÚstoppedzstatus check failedNzkanban goal loop: )rÁ  rá  )rÄ  Úreadyzkanban goal loop: task z status=z
; stoppingzstatus=r   )Úget_affinity_scopeÚreset_affinity_scopeÚset_affinity_scopezkanban:rü   rJ  zkanban goal loop: turn rÜ  z	 verdict=z reason=rc  r)   z judged unachievable; blockingz-Goal-mode judge ruled the goal unachievable: Úblocked_unachievablezjudge verdict blocked: r   z0 judged done but worker won't finalize; blockingzfGoal-mode worker's output looked complete but it never called kanban_complete after a finalize nudge (z).Úblocked_budgetzjudged done, never finalizedr©  r  z exhausted z turns; blockingz,Goal-mode worker exhausted its turn budget (z3) without completing the task. Last judge verdict: r   zturn budget exhaustedz#kanban goal loop: run_turn failed (zrun_turn error: )r¸  r-   rQ   rÛ   )r}  r-   rQ   rÛ   )r   r-   r  r-   rQ   r‰   )r~   rÈ   r    Ú_KANBAN_TERMINAL_STATUSESrD   rk  Úagent.portal_tagsrr  rs  rt  r£  r"  ÚKANBAN_GOAL_FINALIZE_TEMPLATEÚ!KANBAN_GOAL_CONTINUATION_TEMPLATEr¡   rU   )rÁ  Ú	goal_textÚrun_turnÚtask_status_fnrl  r­   re  rf  rm  ro  r�  Únudged_to_finalizer«   r¥   Úterminalr   r  Úlog_fmtrr  rs  rt  Úaffinity_tokenrL  Ú_parse_failedÚ_waitÚ_transport_failedr   rj  r¬   s       `  `                   @@r7   Úrun_kanban_goal_loopr…  ;  sK  û€ õ&ö?õPô �IÒ2Ô!2Ó3€IØ�1‚}Ü%ˆ	à"Ò( b€MØ€JØÐà
ð	=Ù#Ó%ˆFô
 -×0Ñ0°Ó8ˆØÐØ'/Ñ$ˆG�V˜WÙÐ%¨¯©¸wÈj¨Ó(YÑYÔZÙ˜7 FÓ+Ð+ØÐ-Ñ-áÐ*¨7¨)°8¸F¸:ÀZÐPÔQÙ˜9¨°¨xÐ&8Ó9Ð9÷ 	cÑbÙ!3Ô!5™Ñ;MÐPWÐX_ÐW`ÐNaÓ;bˆð	5ÜGQÐR[Ð]jÓGkÑDˆG�V˜]¨EÐ3DàÐ)Ù$ ^Õ4Ø�fÒØ ˆGÙÐ& z l°!°I°;¸iÈÀyÐPXÔYbÐciÐknÓYoÐXpÐqÔrà�iÒñ Ð*¨7¨)Ð3QÐRÔSÙÐBÀ6À(ÐKÔLÙÐ1Ð5LÈVÈHÐ3UÓVÐVà�fÒÙ!áÐ.¨w¨iÐ7gÐhÔiÙðFØFLÀXÈRðQôñ Ð/Ð1OÓPÐPÜ2×9Ñ9ÄÈ6ÐSVÓAWÐ9ÓXˆFØ!%Ñä6×=Ñ=ÄYÈvÐWZÓE[Ð=Ó\ˆFð ˜Ò"ÙÐ*¨7¨)°;¸z¸lÈ!ÈIÈ;ÐVfÐgÔhÙðØ�<˜q  ð ,'Ü'0°¸Ó'=Ð&>ð@ôñ
 Ð+Ð-DÓEÐEð	OÙ$ VÓ,Ò2°ˆMð 	�a‰ˆ
ñG øô ò 	=ÙÐ:¸3¸%¸{ÐKÔLÙ˜9Ð&;Ó<Õ<ûð	=ûð* Ð)Ù$ ^Õ4ð *ûôP ò 	OÙÐ6°s°e¸;ÐGÔHÙ˜9Ð(8¼¸c»×9KÑ9KÐ8LÐ&MÓNÕNûð	OúsH   ÁG- Ã	H ÇH( Ç-	HÇ6HÈ
HÈHÈH%È(	I&È1*I!ÉI&É!I&)r©   r+   r|   r  ro   rÉ  r§   rW  rV  rU  rš  r™  r˜  rÇ  rz  ry  rÈ   r  r  r  r  r£  r…  )rd   r-   rQ   zTuple[str, GoalContract])ry   r¹   rQ   r-   )r¢   r|   rŠ   r²   rQ   zTuple[bool, int, str])rÝ   r-   rQ   r-   )ré   r-   r   zthreading.EventrQ   rÛ   )rQ   zOptional[Any])ré   r-   rÚ   rP   )r
  r-   r  r-   rÝ   r-   rQ   rÛ   )rÝ   r-   rQ   rZ  )rÝ   r-   r  r©   rQ   rÛ   )rÝ   r-   rQ   rÛ   )r  r-   r  r-   r  r-   rQ   rR   )rd   r-   r!  r~   rQ   r-   )r(  r~   rQ   rR   )rÝ   r-   rQ   rR   )rl   r-   r\  )rQ   r¯   )rÊ   r-   rQ   rS   )rÊ   r-   rQ   z/Tuple[str, str, bool, Optional[Dict[str, Any]]])rl  r]  rQ   r-   )r  r-   r€  r-   r’   úOptional[float]rQ   r-   )r   r-   r�  r-   r’   r†  ry   zOptional[List[str]]rl  r]  rn   r[  rƒ  r~   rQ   z5Tuple[str, str, bool, Optional[Dict[str, Any]], bool])rÝ   r²   rQ   r~   )r   r-   r±  r
   rQ   r-   )r·  r
   rQ   r
   )rÝ   r²   rQ   r
   r0   )rÁ  r²   r¿  r²   rQ   zList[Dict[str, Any]])rÈ  r-   r’   r†  rQ   r[  )rË  rR   r   r²   rL  r-   r  r-   r}  r-   rQ   r‰   )
rÁ  r-   r{  r-   r­   r~   re  r-   rQ   r‰   )mrX   Ú
__future__r   rô   rÃ   ÚloggingÚosÚrer˜   rø   rà  Údataclassesr   r   r   r   r   Úpathlibr	   Útypingr
   r   r   r   r   Úhermes_cli._subprocess_compatr   Ú	getLoggerrU   rã   rÈ   r=  r:  r’  rL  rJ  r‡   rˆ   r5  rž   rW  rU  rV  r'  r›  r“  rj  rš  r™  r˜  rÇ  r:   rM   r`   r+   ro   rz   r|   r§   r©   rÞ   rß   rY   ÚLockrå   rà   r÷   rû   rë   r   râ   rç   ró   r  r  r  r  r  r"  r)  r/  ÚcompileÚDOTALLrC  r7  r;  r>  rH  r`  rs  r‚  r£  r¨  r°  r®  r¯  r´  r¹  r¾  rÅ  rÉ  rÍ  rK  r  rz  ry  rw  r…  Ú__all__rA   r=   r7   ú<module>r”     s‘  ðòõ #ã Û Û Û 	Û 	Û Û Û ß 0Ñ 0ß 'Ý ß 3Õ 3å @à	ˆ×	Ñ	˜8Ó	$€ð
 Ð ØÐ ð  Ð à $Ð ð *+Ð &ð ./Ð *ð
  #Ð ØÐ ð Ð àÐ ðPð ð	+ð +ðð +ðDð )ð"9,ð ð~Lð !ð0ð  ðBð ð<ð )ð(^ð )ð4/ð ð4 YÐ ð ¨.ÈØÐ-@ñÐ ð
Øˆyð
Ø  )ð
Ø-3°Yð
Ø@KÈYð
à�Nð
à$,¨nð
à>KÈ^ð
ð �ð
ð !(¨ð
ð �=ð	
ð #/°ð	
ð @JÈ=ð	
ð
 �ð
ð
  /°ð
ð �,ð
ð !+¨Lð
ð ;BÀ<ð
ð  lØ¨;À;Ø"°Kò
Ð ð ÷Gð Gó ðGó26ó2cð ÷
ð 
ó ð
ð< 6:õ Oð, ÷L!ð L!ó ðL!ób ð €	ˆ>Ó Ø#�Y—^‘^Ó%Ð Ø57Ð Ð2Ó 7ð !Ð ð  Ð óó"=ó@,óó@óóó*>ó!ð XZõ ó>Lóó(
ð �"—*‘*˜Z¨¯©Ó3€óóLóHó4ó./\ódUó<ð(  $Ø$(Ø;?Ø'+ØñA@Ø
ðA@àðA@ð ð	A@ð
 "ðA@ð 9ðA@ð %ðA@ð ðA@ð ;óA@óHð" rÐ ØÐ ØÐ óóóðÐaeõ ð, BFõ 5óDFð%ð ÷inñ inðbð "ðDð ð }Øyð Pð _ñÐ ð  'ØØñnàðnð ðnð ðnð ðnð ónòb�r=   