
    `gjv                    V    d Z ddlmZ ddlZddlmZ ddlmZ ddZdZ	ddZ
dd	d
dZy)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_textc                x    | j                  d      syt        | j                  d            j                          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)msgs    G/root/.hermes/venv/lib/python3.12/site-packages/agent/turn_finalizer.py_is_pure_tool_call_tailr      s3     77< #CGGI$67==???    )_verification_stop_synthetic_pre_verify_syntheticc                    | D cg c],  t        t              rt        fdt        D              s. c}| dd yc c}w )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              3  @   K   | ]  }j                  |        y w)N)r	   ).0fms     r   	<genexpr>z>_drop_verification_continuation_scaffolding.<locals>.<genexpr>A   s     +_AEE!H+_s   N)
isinstancedictany _VERIFICATION_CONTINUATION_FLAGS)messagesr   s    `r   +_drop_verification_continuation_scaffoldingr   8   s>     1d#+_>^+_(_ 	
HQK s   1?F)_pending_verification_response(_pending_verification_response_previewedc                  ddl m} || j                  k\  xs | j                  j                  dk  }|xr | xr | xr t        |      dv }|du xr t        |      xr |}d}d}|r#|}|rd| _        d| d| j                   d	}d}d}n{|y|rwd| d| j                   d	}| j                  d
| d| j                   d       | j                  s"| j                  d| d| j                   d       | j                  ||      }d}|rt        j                  j                  d      }|r}	 ddlm} |j#                         }	 |j%                  ||d| d| j                   dddd|| j                  d       |j'                  d||| j                         	 |j)                          t        |      j/                  d      }|duxr | xr || j                  k  xs |}g }	 | j1                  |t3        |	      |       	 | j9                  |       	 | j;                  |       t=        |       |rddlm }  |||       |r|s	 |r|d   nd}tC        |tD              r|j                  d      nd}|d k7  r|j5                  d |d!       nFtC        |tD              r6|j                  d"      |k7  r"tG        |      r||d"<   |jI                  d#d       tK        | d$d      } tM        |       r | |       | jO                  ||       |r|d   j                  d      nd}"d}#|"d'k(  rvtQ        |      D ]h  }$|$j                  d      d k(  s|$j                  d(      s*|$d(   }%|%r7tC        |%d   tD              r$|%d   j                  d)i       j                  d*      }# n tS        d+ |D              }&|rtU        |      nd}'| j                  r| j                  jV                  nd}(| j                  r| j                  jX                  nd})d,}*|| jZ                  || j                  |(|)|&|"|'| j\                  xs d-f
}+|"d'k(  r|s |j,                  d.|*z   d/z   g|+|#  n |j&                  |*g|+  |rO|sM	 tK        | d0d      xs i },|,r9| j_                         r)| ja                  |,      }-|-r|jc                         d1z   |-z   }|s	 | jg                         r|xs d3ji                         }/|/d3k(  xs |/d4k(  }0|0 xr9 | xr4 t        |      j/                  d5       xr tU        |/      d6k  xr |/dd d7v}1t        |      d8k(  }2|0s|1s|2r | jk                  |      }3|3r|0r|3}n|/d1z   |3z   }d}5|r]|s[	 dd:l6m7}6  |6d;|| j\                  xs d3| jZ                  tK        | d<d      xs d3=      }7|7D ]  }8tC        |8t
              s|8s|8}d}5 n |rF|sD	 dd:l6m7}6  |6d?| j\                  |||
|tq        |      | jZ                  tK        | d<d      xs d3@	       d}:tQ        |      D ]E  };|;j                  d      dBk(  r n/|;j                  d      d k(  s.|;j                  dC      s@|;dC   }: n i dD|dE|:dF|dG|dH|dI|dJ|dKddL|dM|5dNtK        | dOd      dP| jZ                  dQ| jr                  dR| jt                  dS| jv                  dT| jx                  dU| jz                  | j|                  | j~                  | j                  | j                  | j                  tK        | j                  dVd      xs d| j                  | j                  | j                  tK        | dWi       xs i j                  dX      xs i j                  dY      | j\                  dZ}<| j                  | j                  j                         |<d[<   |r||<d\<   | j                         }=|=r|=|<d]<   d| _        |r| j                  r| j                  |<d^<   | j                          d| _L        d}>| j                  dkD  r0| j                  | j                  k\  rd_| j                  v r	d}>d| _N        | j                  |
|||`       |r$|s"|s|>r	 | j                  tq        |      ||>a       	 dd:l6m7}6  |6db| j\                  ||||| jZ                  tK        | d<d      xs d3c       |<S # t*        $ r Y &w xY w# 	 |j)                          w # t*        $ r Y w w xY wxY w# t*        $ r |j-                  d|d       Y ow xY w# t*        $ r3}|j5                  d|        |j7                  d|d       Y d}~Sd}~ww xY w# t*        $ r3}|j5                  d|        |j7                  d|d       Y d}~d}~ww xY w# t*        $ r d}Y Zw xY w# t*        $ r3}!|j5                  d%|!        |j7                  d&|!d       Y d}!~!d}!~!ww xY w# t*        $ r}.|je                  d2|.       Y d}.~.Td}.~.ww xY w# t*        $ r}4|je                  d9|4       Y d}4~4d}4~4ww xY w# t*        $ r}9|j-                  d>|9       Y d}9~9d}9~9ww xY w# t*        $ r}9|j-                  dA|9       Y d}9~9d}9~9ww xY w# t*        $ r Y w xY w# t*        $ r}9|j-                  dd|9       Y d}9~9|<S d}9~9ww xY w)ezRun 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   )logger>   unknownbudget_exhaustedNFTzmax_iterations_reached(/)u#   ⚠️ Iteration budget exhausted (u   ) — asking model to summariseu%   
⚠️  Iteration budget exhausted (u   ) — requesting summary...HERMES_KANBAN_TASK)	kanban_dbzIteration budget exhausted (u;   ) — task could not complete within the allowed iterations	timed_out)budget_used
budget_max)erroroutcomerelease_claimend_runevent_payload_extraz5recorded budget-exhausted failure for task %s (%d/%d)z5Failed to record budget-exhausted failure for task %s)exc_infoztext_response(zsave_trajectory: z*finalize_turn: _save_trajectory failed: %szcleanup_task_resources: z1finalize_turn: _cleanup_task_resources failed: %s)close_interrupted_tool_sequencerole	assistant)r2   r   r   _db_persisted$_apply_persist_user_message_overridezpersist_session: z*finalize_turn: _persist_session failed: %stoolr   functionnamec              3     K   | ];  }t        |t              r)|j                  d       dk(  r|j                  d      rd = yw)r2   r3   r      N)r   r   r	   )r   r   s     r   r   z finalize_turn.<locals>.<genexpr>V  s<      a155=K#?AEE,DW 	
s   AA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   >      。   ！   ？!r$   .?`partial_stream_recoveryz$turn-completion explainer failed: %s)invoke_hooktransform_llm_outputplatform)response_text
session_idmodelrJ   z$transform_llm_output hook failed: %spost_llm_call)rL   task_idturn_iduser_messageassistant_responseconversation_historyrM   rJ   zpost_llm_call hook failed: %suser	reasoningfinal_responselast_reasoningr   	api_calls	completedturn_exit_reasonfailedpartialinterruptedresponse_transformedresponse_previewed_response_was_previewedrM   providerbase_urlinput_tokensoutput_tokenscache_read_tokenslast_prompt_tokensrequest_overrides
extra_bodyservice_tier)cache_write_tokensreasoning_tokensprompt_tokenscompletion_tokenstotal_tokensrf   estimated_cost_usdcost_statuscost_sourceri   rL   	guardrailcleanup_errorspending_steerinterrupt_messageskill_manage)original_user_messagerV   r]   r   )messages_snapshotreview_memoryreview_skillson_session_end)rL   rO   rP   rY   r]   rM   rJ   zon_session_end hook failed: %s)Ragent.conversation_loopr    max_iterationsiteration_budget	remainingstrboolr`   _emit_status
quiet_mode_safe_print_handle_max_iterationsosenvironr	   
hermes_clir&   connect_record_task_failureinfoclose	Exceptionwarning
startswith_save_trajectoryr   appendr*   _cleanup_task_resources)_drop_trailing_empty_response_scaffoldingr   agent.message_sanitizationr0   r   r   r   popgetattrcallable_persist_sessionreversedsumlenused	max_totalrM   rL   _file_mutation_verifier_enabled$_format_file_mutation_failure_footerrstripdebug"_turn_completion_explainer_enabledr
   #_format_turn_completion_explanationhermes_cli.pluginsrH   listra   rb   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context_compressor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_review)?agentrV   api_call_countr]   r[   r   rS   effective_task_idrP   rQ   rw   _should_review_memory_turn_exit_reasonr   r   r    r"   budget_fallback_eligiblecontinuation_budget_exhaustediteration_limit_fallbackpreserved_verification_fallback_kanban_task_kb_connnormal_text_responserY   _cleanup_errors	_save_err_cleanup_errr0   _tail
_tail_role_apply_override_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_invoke_hook_transform_results_hook_resultexcrW   r   result_leftover_steer_should_review_skillss?                                                                  r   finalize_turnr   E   s   . / 	%... 	1!!++q0 
 	 	FO	FJ	F !"&EE	  	$ 	%/0	%$ "  %&+#$ 8 4,0E)5n5EQuG[G[F\\]^#' *.'		$< 6n5EQuG[G[F\\]^1.1A5CWCWBX Y, ,	
 88H%J^J^I_ `, , 55hO#'  zz~~&:;#7,,$  ./q1E1E0F G))
 !,&* $+9*/*>*>- - " KKO$ne6J6J
 01<<=MNd" 	
J	
 U111 $# ( O]x)H)VXabg%%&78Y`77A 	4H=  R+HnE" +(0d /9.E6*4J[(  PQE4(UYYy-A^-SXopuXv $2i  		/40 "%)OQUVO$H%x)=> 2:Xb\%%f-tNO8$ 	Bvvf~,1E,'JtAw5&*2hll:r&B&F&Fv&NO	    (6N#1I272H2H5))..aL6;6L6L%((22RSK	D 
 	5;;8L8Lk.)"F	J L)*	
 	
 )	
 	I+
+" k	Oe%BDIORG5@@BCCGL%3%:%:%<v%E%NN( &	K779+1r88:	%."_%N	Y8N"
 +* ];;] 12==oNN] I",] ""#.\\ % )*.GG , '+2#(#L#L)$L $- .:N !*F 2\ A + " k	HF!-&, ++1rkk 
D9?R" !3 lC0\%1N,0)	 k	AF ++)2#1%)(^kk 
D9?R
. N! 776?f$776?k)cggk.B -N!.!.! 	H! 	^	!
 	Y! 	-! 	&! 	5! 	{! 	 5! 	ge-FN! 	! 	ENN! 	ENN! 	22!  	44!!" 	U<<#!$ $>>!::44"<<22%e&>&>@TVWX]\]#>>0000 U/4:??MSQS
#n
&&A!FD **6#AAMMO{ #2  002O"1$)E! u//&+&>&>"# 
 "E "##a'((E,G,GG%"8"88 $#$  
((3%	 )  k/DH]	**"&x.33 + $>B''%#++UJ5;		
 My % $  K !  F  ]!29+>?A9W[\\]  g!9,HIH,aeffgj  T  `!2<.ABA<Z^__`L  	OLLCXNN	Or  	KLL?JJ	K0  	HNNA3GG	H*  	ANN:C@@	AR  		2  >7==M>sn  )c4  Ac b?  d =e 1f( 	f 
B5f( (Ag' 7B"h  Ah9 0h9 3h9 ?Ai" &j 9j ?	cc4 cc4 c1c"!c1"	c.+c1-c..c11c4 4dd	e!(ee	f (fff%!f( $f%%f( (	g$1(gg$'	h0hh	h6h11h69	iii"	j+jj	jj	k$j<<k)r   r   returnr   )r   None)__doc__
__future__r   r   agent.codex_responses_adapterr   agent.message_contentr   r   r   r   r    r   r   <module>r      s9   , # 	 I 6@&$  
8 $(-2!or   