
    sjԟ                        d Z ddlmZ ddlZddlZddlmZ ddlmZ ddl	m
Z
mZ ddlmZ ddZdZddZddZddddZdS )u  Post-loop turn finalization for ``run_conversation``.

Extracted from ``agent/conversation_loop.py`` as part of the god-file
decomposition campaign (``~/.hermes/plans/god-file-decomposition.md``, Phase 1
step 4 — the post-loop ``TurnFinalizer`` seam). ``run_conversation``'s tail
(everything after the main tool-calling ``while`` loop) is lifted here verbatim:
budget-exhaustion summary, trajectory save, session persist, turn diagnostics,
response transforms, result-dict assembly, steer drain, and the memory/skill
review trigger.

Behavior-neutral: the body is moved unchanged. All ``agent.*`` side effects fire
exactly as before; only the post-loop *locals* are passed in as keyword args, and
the assembled ``result`` dict is returned to ``run_conversation`` which returns it
to the caller. The function is synchronous with a single return — mirroring the
region it replaces (no awaits, no early returns).

Module ``logger`` is imported lazily inside the body (``from
agent.conversation_loop import logger``) so this module never imports
``agent.conversation_loop`` at import time -> no import cycle, and the log records
keep the exact logger name (``"agent.conversation_loop"``).
    )annotationsN)_summarize_user_message_for_log)flatten_message_text)append_messagestamp_message_timestamp)_sanitize_surrogatesmsgdictreturnboolc                    |                      d          sdS t          |                      d                                                     S )u  An assistant row with ``tool_calls`` but no visible text content of its own.

    Such a row satisfies the role check (``tail role == "assistant"``) while
    carrying none of the delivered answer — see the #43849/#44100 invariant
    block in :func:`finalize_turn`. Uses :func:`flatten_message_text` so that
    multimodal (list-type) content is evaluated by its text parts, not just
    its type.
    
tool_callsFcontent)getr   strip)r	   s    8/home/agent/.hermes/hermes-agent/agent/turn_finalizer.py_is_pure_tool_call_tailr   "   sF     77<   u#CGGI$6$677==????    )_verification_stop_synthetic_pre_verify_synthetickanban_taskstrapi_call_countintmax_iterationsloggerlogging.LoggerNonec                |   	 ddl m} |                                }	 |                    || d| d| dddd||d	           	 |                                 dS # t
          $ r Y dS w xY w# 	 |                                 w # t
          $ r Y w w xY wxY w# t
          $ r |                    d
| d           Y dS w xY w)ud  Record a terminal ``timed_out`` outcome for a kanban worker that
    exhausted its iteration budget.

    This is a bounded fallback (#87096): the CAS invariant in ``_end_run``
    (``WHERE ended_at IS NULL``) guarantees idempotence — if another path
    already closed the run this is a no-op — so it is safe to call from
    multiple exit paths.
    r   )	kanban_dbzIteration budget exhausted (/u;   ) — task could not complete within the allowed iterations	timed_outT)budget_used
budget_max)erroroutcomerelease_claimend_runevent_payload_extraz5Failed to record budget-exhausted failure for task %sexc_infoN)
hermes_clir    connect_record_task_failureclose	Exceptionwarning)r   r   r   r   _kb_conns         r   _record_kanban_budget_exhaustedr4   ;   sK   
//////	$$!&! !)7! ! !
 $"#1"0% % %   $       
 
 
C 	 	
 	
 	
 	
 	
 	

sd   B &A+ A 
A($B 'A((B +B-BB
BBBBB "B;:B;c                (    d | D             | dd<   dS )zRemove verification-continuation nudge messages from *messages* in place.

    Only the synthetic nudges carry these flags, so this strips just the
    nudges while preserving the real attempted-final-answer that was
    persisted to state.db.
    c                ~    g | ]9t          t                    r t          fd t          D                       7:S )c              3  B   K   | ]}                     |          V  d S )N)r   ).0fms     r   	<genexpr>zI_drop_verification_continuation_scaffolding.<locals>.<listcomp>.<genexpr>t   s-      +_+_AEE!HH+_+_+_+_+_+_r   )
isinstancer
   any _VERIFICATION_CONTINUATION_FLAGSr8   r:   s    @r   
<listcomp>z?_drop_verification_continuation_scaffolding.<locals>.<listcomp>r   s_       1d##(++_+_+_+_>^+_+_+_(_(_	  r   N )messagess    r   +_drop_verification_continuation_scaffoldingrC   k   s,       HQQQKKKr   F)_pending_verification_response(_pending_verification_response_previewedc               |   ddl m} || j        k    p| j        j        dk    }|o| o| ot          |          dv }|du ot          |          o|}d}d}|r|}|rd| _        d| d| j         d	}d}d}ns|q|rod| d| j         d	}|                     d
| d| j         d           | j	        s!| 
                    d| d| j         d           |                     ||          }d}|r9t          j                            d          }|rt          ||| j        |           n:|r8t          j                            d          }|rt          ||| j        |           t          |                              d          }|duo| o|| j        k     p|}t#          | dd          }|du r~t%          |t&                    rit%          |t                    sTt#          | dd          durAt#          | dd          0t#          | j        dd          }t+          |          r ||           g }	 |                     |t/          |	          |           nG# t0          $ r:}|                    d|            |                    d|d           Y d}~nd}~ww xY w	 |                     |           nG# t0          $ r:}|                    d|            |                    d|d           Y d}~nd}~ww xY w	 |                     |           t;          |           |rddlm}  |||           |r|s	 |r|d         nd}n# t0          $ r d}Y nw xY wt%          |t@                    r|                    d          nd}|dk    rtC          |d|d           nnt%          |t@                    rY|                    d          |k    r@tE          |          r1||d<   tG          |           |$                    dd           d| _%        t#          | d d          } t+          |           r | |           |s|s	 t#          | dd          }!|!rt#          |!d!d          du rt+          t#          |!d"d                    r|rt#          | d#d          stM          |          }"|!'                    |          }#t#          |!d$d          rd|!_(        d| _%        t%          |#tR                    r	|#r|#|dd<   tM          |          }$|"|$k    r|*                    d%|"|$           n-# t0          $ r }%|*                    d&|%           Y d}%~%nd}%~%ww xY w| +                    ||           nG# t0          $ r:}&|                    d'|&            |                    d(|&d           Y d}&~&nd}&~&ww xY w	 || _,        n# t0          $ r Y nw xY w|r|d                             d          nd}'d}(|'d)k    rt[          |          D ]})|)                    d          dk    rk|)                    d*          rV|)d*         }*|*rJt%          |*d         t@                    r/|*d                             d+i                               d,          }( nt]          d- |D                       }+|rtM          |          nd},| j        r| j        j/        nd}-| j        r| j        j0        nd}.d.}/|| j1        || j        |-|.|+|'|,| j2        pd/f
}0|'d)k    r|s |j3        d0|/z   d1z   g|0|(R   n |j*        |/g|0R   |r|s	 t#          | d2d          pi }1|1rE| 4                                r1| 5                    |1          }2|2r|6                                d3z   |2z   }n-# t0          $ r }3|7                    d4|3           Y d}3~3nd}3~3ww xY w|s	 | 8                                r|pd59                                }4|4d5k    p|4d6k    }5|5 oD| oAt          |                              d7           otM          |4          d8k    o|4dd         d9v}6t          |          d:k    }7|5s|6s|7r4| :                    |t#          | d;d                    }8|8r|5r|8}n|4d3z   |8z   }n-# t0          $ r }9|7                    d<|9           Y d}9~9nd}9~9ww xY wd}:d};|r|s	 dd=l;m<}<  |<d>|| j2        pd5| j1        t#          | d?d          pd5@          }=|=D ]!}>t%          |>t
                    r
|>r|};|>}d}: n"n-# t0          $ r }?|3                    dA|?           Y d}?~?nd}?~?ww xY w|rs|sq	 dd=l;m<}<  |<dB| j2        |||
|tS          |          | j1        t#          | d?d          pd5C	  	         n-# t0          $ r }?|3                    dD|?           Y d}?~?nd}?~?ww xY w	 ddEl m=}@ t#          | dFd          }A |@| ||A|||||||G
  
         n-# t0          $ r }?|3                    dH|?           Y d}?~?nd}?~?ww xY wd}Bt[          |          D ]U}C|C                    d          dIk    r n9|C                    d          dk    r|C                    dJ          r
|CdJ         }B nVt%          |t
                    rt}          |          }i dK|dL|BdM|dN|dO|dP|dQ|dRddS|dT|:dU|;dVt#          | dWd          dX| j1        dY| j?        dZ| j@        d[| jA        d\| jB        | jC        | jD        | jE        | jF        | jG        | jH        t#          | j        d]d          pd| jI        | jJ        | jK        t#          | d^i           pi                     d_          pi                     d`          | j2        da}D| jL        | jL        M                                |Ddb<   |r9t          |          dck    r&|pdd|Dde<   df|Dvrt#          | d;d          }Edg|Epdhz   |Ddf<   |r||Ddi<   | N                                }F|Fr|F|Ddj<   d| _        |r| jO        r
| jO        |Ddk<   | P                                 d| _Q        d}G| jR        dk    r"| jS        | jR        k    rdl| jT        v r	d}Gd| _S        | U                    |
|||m           |rN|sLt#          | dnd          s;|s|Gr7	 | V                    tS          |          ||Go           n# t0          $ r Y nw xY w	 dd=l;m<}<  |<dp| j2        ||||||| j1        t#          | d?d          pd5q
  
         n-# t0          $ r }?|3                    dr|?           Y d}?~?nd}?~?ww xY wd| _W        d| _X        |DS )szRun the post-loop finalization and return the turn ``result`` dict.

    Lifted verbatim from ``run_conversation`` (the region after the main agent
    loop). See module docstring.
    r   )r   >   unknownbudget_exhaustedNFTzmax_iterations_reached(r!   )u#   ⚠️ Iteration budget exhausted (u   ) — asking model to summariseu%   
⚠️  Iteration budget exhausted (u   ) — requesting summary...HERMES_KANBAN_TASKztext_response( _turn_preflight_display_snapshot _turn_received_provider_responsecontext_compressor-rollback_interrupted_preflight_display_tokenszsave_trajectory: z*finalize_turn: _save_trajectory failed: %sr*   zcleanup_task_resources: z1finalize_turn: _cleanup_task_resources failed: %s)close_interrupted_tool_sequencerole	assistant)rQ   r   r   _db_persisted$_apply_persist_user_message_override_micro_compact_enabled_micro_compact_persist_disabled_flush_scan_cursor_invalidatedz#Micro-compaction: %d -> %d messageszMicro-compaction failed: %szpersist_session: z*finalize_turn: _persist_session failed: %stoolr   functionnamec              3     K   | ]I}t          |t                    r2|                    d           dk    0|                    d          EdV  JdS )rQ   rR   r      N)r<   r
   r   r?   s     r   r;   z finalize_turn.<locals>.<genexpr>  sf        a#$55==K#?#?AEE,DWDW#? 	
#?#?#?#? r   zuTurn ended: reason=%s model=%s api_calls=%d/%d budget=%d/%d tool_turns=%d last_msg_role=%s response_len=%d session=%snonez>Turn ended with pending tool result (agent may appear stuck). z last_tool=%s_turn_failed_file_mutationsz

z(file-mutation verifier footer failed: %s z(empty)text_response   >      。   ！   ？!rI   .?`partial_stream_recovery_last_persistence_error_causez$turn-completion explainer failed: %s)invoke_hooktransform_llm_outputplatform)response_text
session_idmodelrn   z$transform_llm_output hook failed: %spost_llm_call)rp   task_idturn_iduser_messageassistant_responseconversation_historyrq   rn   zpost_llm_call hook failed: %s)$_notify_context_engine_turn_complete_last_turn_usage)usager   rt   rs   r   interruptedfailedturn_exit_reasonz(on_turn_complete notification failed: %suser	reasoningfinal_responselast_reasoningrB   	api_calls	completedr}   r|   partialr{   response_transformedpre_transform_responseresponse_previewed_response_was_previewedrq   providerbase_urlinput_tokensoutput_tokenslast_prompt_tokensrequest_overrides
extra_bodyservice_tier)cache_read_tokenscache_write_tokensreasoning_tokensprompt_tokenscompletion_tokenstotal_tokensr   estimated_cost_usdcost_statuscost_sourcer   rp   	guardrailsession_persistence_failedux   session storage could not be written — check the state database health (`hermes doctor`), then send your message againr%   failure_reasonzsession_persistence_failed:rG   cleanup_errorspending_steerinterrupt_messageskill_manage)original_user_messager   r{   rB   skip_background_review)messages_snapshotreview_memoryreview_skillson_session_end)	rp   rs   rt   r   r|   r{   r}   rq   rn   zon_session_end hook failed: %s)Yagent.conversation_loopr   r   iteration_budget	remainingr   r   r   _emit_status
quiet_mode_safe_print_handle_max_iterationsosenvironr   r4   
startswithgetattrr<   r   rM   callable_save_trajectoryr   r0   appendr%   _cleanup_task_resources)_drop_trailing_empty_response_scaffoldingrC   agent.message_sanitizationrO   r
   r   r   r   pop_db_flush_scan_prefixlenrV   rX   listinfo_persist_session_session_messagesreversedsumused	max_totalrq   rp   r1   _file_mutation_verifier_enabled$_format_file_mutation_failure_footerrstripdebug"_turn_completion_explainer_enabledr   #_format_turn_completion_explanationhermes_cli.lifecyclerl   rx   r   r   r   session_input_tokenssession_output_tokenssession_cache_read_tokenssession_cache_write_tokenssession_reasoning_tokenssession_prompt_tokenssession_completion_tokenssession_total_tokenssession_estimated_cost_usdsession_cost_statussession_cost_source_tool_guardrail_halt_decisionto_metadata_drain_pending_steer_interrupt_messageclear_interrupt_stream_callback_skill_nudge_interval_iters_since_skillvalid_tool_names_sync_external_memory_for_turn_spawn_background_reviewrK   rL   )Hagentr   r   r{   r|   rB   rw   effective_task_idrt   ru   r   _should_review_memory_turn_exit_reasonrD   rE   r   rH   budget_fallback_eligiblecontinuation_budget_exhaustediteration_limit_fallbackpreserved_verification_fallback_kanban_tasknormal_text_responser   _preflight_snapshot_rollback_fn_cleanup_errors	_save_err_cleanup_errrO   _tail
_tail_role_apply_override_compressor_before
_compacted_after_mc_err_persist_err_last_msg_role_last_tool_name_m_tcs_turn_tool_count	_resp_len_budget_used_budget_max	_diag_msg
_diag_args_failedfooter_ver_err	_stripped_is_empty_terminal_is_partial_fragment_is_partial_stream_recovery_explanation_exp_err_response_transformed_pre_transform_response_invoke_hook_transform_results_hook_resultexcrx   _turn_usager   r	   result_cause_leftover_steer_should_review_skillssH                                                                           r   finalize_turnr  x   s   . /..... 	%.. 	1!+q0 
 	 	FO	FJ	F !""&EE	  	$ 	%/00	%$ "  %&+#$ ( 8 4 	1,0E)^n^^uG[^^^#' *.''		$<	 _n^^uG[^^^,. , ,5CW , , ,	
 	
 	
  	, , ,%J^ , , ,   55hOO#'   z~~&:;; 	+ne.BF   
  z~~&:;; 	+ne.BF  
 011<<=MNNd" 	
J	
 U11 $# * "14  	t*C00 	.55 	 E=uEETQQE/66B$;
 

 L!! 	.L,--- O]x)H)V)VXabbbb ] ] ]>9>>???A9W[\\\\\\\\]
g%%&78888 g g gH,HHIIIH,aeffffffffgZ`77AAA 	4H===   	FRRRRRR++HnEEE"  .	3+ .	3(0:d   .8.E.EO6***4J[(( (^DD    E4(( !3UYYy-A-A^-S-SXopuXvXv-S $2i  (... 		/4000 /3+ "%)OQUVVO$$ 	&OH%%%  ,	D6 ,	D+D%e-A4HH  "-EuMMQUUU 6F!M!MNN V& V $E+>FF V "(mmG!,!;!;H!E!EJ #%Eu  ; FKB6:3!*d33 1
 1&0 ]]F&((A#V    D D D97CCCCCCCCD 	x)=>>>> ` ` `A<AABBBA<Z^________`"*    2:CXb\%%f---tNO8$$ 	 	Bvvf~~,,1E1E,,' OJtAw55 O&*2hll:r&B&B&F&Fv&N&NO       (6<N###1I272HO5)..aL6;6LS%(22RSK	D 
 	5;8Lk.)"F	J L)*	
 	
 )	
 	
 	
 	
 	
 	I+
++++"  Ok O	Oe%BDIIORG O5@@BB OCCGLL O%3%:%:%<%<v%E%NN 	O 	O 	OLLCXNNNNNNNN	O&  (K'	K7799 $+1r88::	%."_%N	Y8N"
 +* ];;] 122==oNNN] I",] ""##.\\ % )**.GG , '+ 3
 $)#L#L)'FMM$ $L $ - 
 .:NN !*F 2\ A +  	K 	K 	KLL?JJJJJJJJ	K ""  Hk H	HHHHHHH!-&, +1rk 
D99?R" " " !3  lC00 \ .<+%1N,0)E 	H 	H 	HNNA3GGGGGGGG	H  Ak A	AHHHHHHL +)2#1%)(^^k 
D99?R
 
 
 
 
  	A 	A 	ANN:C@@@@@@@@	AHPPPPPP e%7>>,,%)#.	
 	
 	
 	
 	
  H H HA3GGGGGGGGH N!!  776??f$$E776??k))cggk.B.B) -NE .#&& >-n=="."." 	H" 	^	"
 	Y" 	-" 	&" 	5" 	{" 	 5" 	!"9" 	ge-FNN" 	" 	EN" 	EN"  	2!"" 	4#"$ #<#>!:4"<2%e&>@TVWXX]\]#>00 U/44:??MMSQS
#n

&C" " "FF *6#AMMOO{  #'((,HHH( 
E 	w 6))U$CTJJF-1D9E #$  3#2  0022O 2"1$)E!  ?u/ ?&+&>"# 
 "E "#a''(E,GGG%"888 $#$  
((3%	 )    	 7?? #	 '<		**"&x..33 +    
  	 	 	D	>DDDDDD'%#.+UJ55;	
 	
 	
 	
 	
  > > >7========> .2E*-2E*MsP  ($I 
J0JJJ+ +
K/50K**K/3<U 0L= <U =M	U MC(U 5C$T U 
U$T?:U ?UU 
V"(0VV"&V. .
V;:V;"A]= =
^'^""^'-Ca9 9
b#bb#/Ad 
d1d,,d19Ae< <
f&f!!f&*,g 
h!g<<h%r9 9
ss
6t 
t+t&&t+)r	   r
   r   r   )
r   r   r   r   r   r   r   r   r   r   )r   r   )__doc__
__future__r   loggingr   agent.codex_responses_adapterr   agent.message_contentr   agent.message_metadatar   r   r   r   r   r>   r4   rC   r  rA   r   r   <module>r     s    , # " " " " "  				 I I I I I I 6 6 6 6 6 6 J J J J J J J J ; ; ; ; ; ;@ @ @ @&$  -
 -
 -
 -
`
 
 
 
8 $(-2!L L L L L L Lr   