
    `gjb2                        d Z ddlmZ ddlZddlZddlmZmZ ddlm	Z	m
Z
 ddZddZe G d d	             Z G d
 d      Zy)u  Projects codex app-server events into Hermes' messages list.

The translator that lets Hermes' memory/skill review keep working under the
Codex runtime: it converts Codex `item/*` notifications into the standard
OpenAI-shaped `{role, content, tool_calls, tool_call_id}` entries that
`agent/curator.py` already knows how to read.

Codex emits items with a discriminator field `type`:
  - userMessage         → {role: "user", content}
  - agentMessage        → {role: "assistant", content}
  - reasoning           → stashed in the assistant's "reasoning" field
  - commandExecution    → assistant tool_call(name="exec") + tool result
  - fileChange          → assistant tool_call(name="apply_patch") + tool result
  - mcpToolCall         → assistant tool_call(name=f"mcp.{server}.{tool}") + tool result
  - dynamicToolCall     → assistant tool_call(name=tool) + tool result
  - plan/hookPrompt/collabAgentToolCall → recorded as opaque assistant notes

Each item maps to AT MOST one assistant entry + one tool entry, preserving
Hermes' message-alternation invariants (system → user → assistant → user/tool
→ assistant → ...). Multiple Codex tool calls within one Codex turn produce
multiple consecutive (assistant, tool) pairs, which is the same shape Hermes
already produces for parallel tool calls.

Counters tracked alongside projection:
  - tool_iterations: ticks once per completed tool-shaped item. Used by
    AIAgent._iters_since_skill (skill nudge gate, default threshold 10).
    )annotationsN)	dataclassfield)AnyOptionalc                    |rd|  d| S t        j                  |  j                               j                         dd }d|  d| S )a*  Stable id for tool_call message correlation.

    Uses the codex item id directly when present (already a uuid); falls back
    to a content hash so replay produces the same id across sessions and
    prefix caches stay valid. See AGENTS.md Pitfall #16 (deterministic IDs in
    tool call history).codex__N   )hashlibsha256encode	hexdigest)	item_typeitem_iddigests      Y/root/.hermes/venv/lib/python3.12/site-packages/agent/transports/codex_event_projector.py_deterministic_call_idr   %   sV     	{!G9--^^yk1134>>@"EFI;ax((    c                2    t        j                  | dd      S )zDFormat a dict as JSON the way Hermes' existing tool_calls path does.FT)ensure_ascii	sort_keys)jsondumps)ds    r   _format_tool_argsr   2   s    ::aet<<r   c                  J    e Zd ZU dZ ee      Zded<   dZded<   dZ	d	ed
<   y)ProjectionResulta!  Output of projecting one Codex item.

    `messages` is a list because some Codex items produce two messages
    (assistant tool_call + tool result). Empty list = item ignored (e.g. a
    streaming `outputDelta` that doesn't materialize into messages until the
    `item/completed` event).)default_factoryz
list[dict]messagesFboolis_tool_iterationNzOptional[str]
final_text)
__name__
__module____qualname____doc__r   listr    __annotations__r"   r#    r   r   r   r   7   s-      !6Hj6#t# $J$r   r   c                  d    e Zd ZdZddZddZddZddZddZddZ	ddZ
	 	 	 	 	 	 dd	Zdd
Zy)CodexEventProjectorzStateful projector consuming Codex notifications in arrival order.

    Owns the in-progress reasoning content (codex emits reasoning as separate
    items but Hermes stashes it on the next assistant message).c                    g | _         y )N)_pending_reasoning)selfs    r   __init__zCodexEventProjector.__init__K   s
    -/r   c                   |j                  dd      }|j                  di       xs i }|dk7  r
t               S |j                  d      xs i }|j                  d      xs d}|j                  d      xs d}|dk(  r| j                  |      S |d	k(  rf| j                  j	                  |j                  d
      xs g        | j                  j	                  |j                  d      xs g        t               S |dk(  r| j                  ||      S |dk(  r| j                  ||      S |dk(  r| j                  ||      S |dk(  r| j                  ||      S |dk(  r| j                  |      S | j                  ||      S )zProject a single notification. Idempotent for non-completion events;
        only `item/completed` and `turn/completed` materialize messages.method paramszitem/completeditemtypeidagentMessage	reasoningsummarycontentcommandExecution
fileChangemcpToolCalldynamicToolCalluserMessage)getr   _project_agent_messager.   extend_project_command_project_file_change_project_mcp_tool_call_project_dynamic_tool_call_project_user_message_project_opaque)r/   notificationr2   r4   r5   r   r   s          r   projectzCodexEventProjector.projectN   s    !!(B/!!(B/52 %%#%%zz&!'RHHV$*	((4.&B&..t44###**488I+>+D"E##**488I+>+D"E#%%**((w77$,,T7;;%..tW==))224AA%--d33
 ##D)44r   c                    |j                  d      xs d}d|d}| j                  r%dj                  | j                        |d<   g | _        t        |g|      S )Ntextr3   	assistantroler;   
r9   )r    r#   )rA   r.   joinr   )r/   r5   rM   msgs       r   rB   z*CodexEventProjector._project_agent_messagew   sX    xx%2'2tD""#yy)@)@AC&(D##4@@r   c                P   g }|j                  d      xs g D ]n  }t        |t              s|j                  d      dk(  r%|j                  |j                  d      xs d       Md|v sR|j                  t	        |d                p t        ddj                  |      dg      S )	Nr;   r6   rM   r3   userrQ   rO   r    )rA   
isinstancedictappendstrr   rR   )r/   r5   
text_partsfragments       r   rH   z)CodexEventProjector._project_user_message   s     !#
+1r 	=H(D)<<'61%%hll6&:&@bAx'%%c(6*:&;<	=  %$))J2GHI
 	
r   c                   t        d|      }|j                  d      xs d|j                  d      xs dd}dd |ddt        |      d	d
gd}| j                  r%dj	                  | j                        |d<   g | _        |j                  d      xs d}|j                  d      }||dk7  rd| d| }d||d}t        ||gd      S )Nexeccommandr3   cwd)r_   r`   rN   functionexec_commandname	argumentsr7   r6   ra   rP   r;   
tool_callsrQ   r9   aggregatedOutputexitCoder   z[exit z]
toolrP   tool_call_idr;   Tr    r"   )r   rA   r   r.   rR   r   )	r/   r5   r   call_idargsassistant_msgoutput	exit_codetool_msgs	            r   rD   z$CodexEventProjector._project_command   s    (9xx	*0b88E?(b

   "& .%6t%<!	
 "")-43J3J)KM+&&(D#,-3HHZ(	 Y!^i[F84F#

  #X.$
 	
r   c                   t        d|      }g }|j                  d      xs g D ]S  }|j                  d      xs i j                  d      xs d}|j                  d      xs d}|j                  ||d       U d|i}d	d |d
dt        |      ddgd}	| j                  r%dj                  | j                        |	d<   g | _        |j                  d      xs d}
t        |      }d|d|
 d| dd}t        |	|gd      S )Napply_patchchangeskindr6   updatepathr3   )rx   rz   rN   ra   rc   rf   rg   rQ   r9   statusunknownrk   zapply_patch status=z, z
 change(s)rl   Trn   )r   rA   rY   r   r.   rR   lenr   )r/   r5   r   ro   changes_summarychangerx   rz   rp   rq   r{   nrt   s                r   rE   z(CodexEventProjector._project_file_change   s9   (@ hhy)/R 	AFJJv&,"11&9EXD::f%+D""D$#?@	A ?+ "& -%6t%<!	
 "")-43J3J)KM+&&(D#(#0y #,VHBqcD

  #X.$
 	
r   c                T   |j                  d      xs d}|j                  d      xs d}t        d| d| |      }|j                  d      xs i }t        |t              sd|i}dd |d	d
| d| t	        |      ddgd}| j
                  r%dj                  | j
                        |d<   g | _        |j                  d      }|j                  d      }	|	rdt        j                  |	d      d d  }
n|t        j                  |d      d d }
nd}
d||
d}t        ||gd      S )Nservermcprk   r|   mcp____re   rN   ra   zmcp..rc   rf   rg   rQ   r9   resulterrorz[error] Fr   i    r3   rl   Trn   )
rA   r   rW   rX   r   r.   rR   r   r   r   )r/   r5   r   r   rk   ro   rp   rq   r   r   r;   rt   s               r   rF   z*CodexEventProjector._project_mcp_tool_call   s[   (#,uxx,9 )54&)A7Kxx$*$%&D "&"&vhav 6%6t%<!	
 "")-43J3J)KM+&&(D#(#! E!Fu!M NOGjje<UdCGG#

  #X.$
 	
r   c                   |j                  d      xs d}t        d| |      }|j                  d      xs i }t        |t              sd|i}dd |d|t	        |      ddgd	}| j
                  r%d
j                  | j
                        |d<   g | _        |j                  d      xs g }t        |t              r|rt        j                  |d      d d }n|j                  d      }	d|	 }d||d}
t        ||
gd      S )Nrk   r|   dyn_re   rN   ra   rc   rf   rg   rQ   r9   contentItemsFr   r   successzsuccess=rl   Trn   )rA   r   rW   rX   r   r.   rR   r(   r   r   r   )r/   r5   r   rk   ro   rp   rq   content_itemsr;   r   rt   s              r   rG   z.CodexEventProjector._project_dynamic_tool_call  s$    xx,9(4v@xx$*$%&D "& $%6t%<!	
 "")-43J3J)KM+&&(D#06BmT*}jjUCETJGhhy)G 	*G#

  #X.$
 	
r   c                    	 t        j                  |d      d d }t        dd| d| dg      S # t        t        f$ r t	        |      d d }Y 5w xY w)	NFr   i  rN   z[codex z] rO   rV   )r   r   	TypeError
ValueErrorreprr   )r/   r5   r   payloads       r   rI   z#CodexEventProjector._project_opaque,  sr    	(jjE:5DAG   (!(2gY?
 	
 :& 	(4j$'G	(s   2 AAN)returnNone)rJ   rX   r   r   )r5   rX   r   r   )r5   rX   r   rZ   r   r   )r5   rX   r   rZ   r   r   )r$   r%   r&   r'   r0   rK   rB   rH   rD   rE   rF   rG   rI   r*   r   r   r,   r,   E   sS    C
0%5RA
"
H%
N)
V&
&
#&&
	&
P
r   r,   )r   rZ   r   rZ   r   rZ   )r   rX   r   rZ   )r'   
__future__r   r   r   dataclassesr   r   typingr   r   r   r   r   r,   r*   r   r   <module>r      sJ   8 #   (  
)=
 
% 
% 
%u
 u
r   