
    `gj                       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
 ddlmZ ddlmZ  ej                  e      Zd	Z G d
 d      ZdZdZd#dZd$dZd%dZd&dZ	 	 	 	 	 	 d'dZddd	 	 	 	 	 	 	 	 	 d(dZddd	 	 	 	 	 	 	 	 	 d)dZefd*dZd+dZdZd,dZ d-dZ!d.dZ"dddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d/dZ#d0dZ$ G d d       Z% G d! d"      Z&y)1a(  Mixture-of-Agents runtime helpers for /moa turns.

The slash command is deliberately not a model tool. It marks one user turn as
MoA-enabled; the normal Hermes agent loop still owns tool calling and turn
termination, while this module gathers reference-model context before each model
iteration.
    )annotationsN)ThreadPoolExecutor)Any)call_llm)flatten_message_text)get_transport   c                  T    e Zd ZdZdZ	 	 	 ddddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZy)_RefAccountingub  Per-reference token usage + estimated cost + full trace, carried as the
    third slot of a reference-output tuple.

    Kept as a tiny object (not a bare CanonicalUsage) because an advisor may
    run on a different model/provider than the aggregator, so its cost MUST be
    priced at its OWN model's rate — folding advisor tokens into the
    aggregator's usage and pricing the sum at the aggregator's rate would
    misprice every advisor. ``usage`` feeds accurate token counts;
    ``cost_usd`` feeds accurate cost.

    ``messages`` / ``output`` / ``model`` / ``provider`` / ``temperature``
    carry the FULL reference input and output for trace persistence (the
    display ``text`` is a truncated preview and is not enough to audit what an
    advisor actually saw). They are only populated when tracing is on; they add
    negligible cost otherwise.
    	usagecost_usdcost_statuscost_sourcemessagesoutputmodelprovidertemperatureNr   r   r   r   r   c                   || _         || _        || _        || _        || _        || _        || _        || _        |	| _        y Nr   )
selfr   r   r   r   r   r   r   r   r   s
             A/root/.hermes/venv/lib/python3.12/site-packages/agent/moa_loop.py__init__z_RefAccounting.__init__=   sF     
 && 
 &    )NNN)r   r   r   r   r   
str | Noner   r   r   r   r   r   r   r   r   r   r   r   )__name__
__module____qualname____doc__	__slots__r    r   r   r   r      s    "
I "&"&' ! #'' '  	'
  ' ' ' ' ' 'r   r   i  u0  You are a reference advisor in a Mixture of Agents (MoA) process. You are NOT the acting agent and you do NOT execute anything: you cannot call tools, run commands, browse, or access files, repositories, or URLs, and you should not try to or apologize for being unable to. A separate aggregator/orchestrator model holds those capabilities and will take the actual actions.

The conversation below is the current state of a task handled by that acting agent. Your job is to give your most intelligent analysis of that state: understand the goal, reason about the problem, and advise on what to do next. Surface the best approach, concrete next steps and tool-use strategy, likely pitfalls and risks, and anything the acting agent may have missed or gotten wrong. Assume any referenced files, URLs, or systems exist and reason about them from the context given rather than asking for access.

Respond with your advice directly — no preamble, no disclaimers about tools or access. Your response is private guidance handed to the aggregator, not an answer shown to the user.c                   | j                  d      xs dj                          d| j                  d      xs dj                          }t        | j                  d      xs d      j                         }|r| d| dS |S )Nr    :r   reasoning_effortz[reasoning=])getstripstr)slotlabelefforts      r   _slot_labelr/   {   s~    $*1134Atxx7H7NB6U6U6W5XYE,-34::<F-3eWKxq)>>r   c                `    | j                  d      }	 ddlm}  ||      S # t        $ r Y yw xY w)zETranslate optional per-MoA-slot reasoning_effort into runtime config.r'   r   )parse_reasoning_effortN)r)   hermes_constantsr1   	Exception)r,   r.   r1   s      r   _slot_reasoning_configr4      s6    XX()F;%f-- s   ! 	--c                    t        |       }||S 	 ddlm} ddlm}  | |       xs i t        | j                  d      xs d            S # t        $ r Y yw xY w)aO  Resolve the aggregator's reasoning config: slot > per-model > global.

    The aggregator is MoA's ACTING model, so when its slot doesn't pin a
    reasoning_effort it must resolve exactly like any other acting model:
    through the shared chokepoint (``resolve_reasoning_config``), which
    applies ``agent.reasoning_overrides`` for the slot's model first, then
    the global ``agent.reasoning_effort``. Without this the main loop's
    reasoning gates (keyed to the virtual ``moa://local`` identity) never
    fire, so the aggregator silently ran at the backend default (#64187).

    Reference advisors intentionally do NOT get this fallback: they are side
    calls (like auxiliary tasks), and inheriting a global ``xhigh`` into every
    advisor fan-out would silently multiply cost. Their depth is slot-or-
    provider-default only.
    Nr   load_config)resolve_reasoning_configr   r%   )r4   hermes_cli.configr7   r2   r8   r+   r)   r3   )
aggregatorcfgr7   r8   s       r   _aggregator_reasoning_configr<      sc      !
,C

1='MRZ^^G%<%B!C
 	
  s   9A 	AAc                   t        | j                  d      xs d      j                         }t        | j                  d      xs d      j                         }||d}	 ddlm}  |||      }|j                  d      r|d   |d<   |j                  d	      r|d	   |d	<   |j                  d
      r|d
   |d
<   |S # t
        $ r+}t        j                  dt        |       |       Y d}~|S d}~ww xY w)u  Resolve a reference/aggregator slot to real runtime call kwargs.

    A MoA slot is just a model selection — it must be called the same way any
    model is called elsewhere, not through a bare ``call_llm(provider=...,
    model=...)`` that leaves base_url/api_key/api_mode unresolved and lets the
    auxiliary auto-detector guess. We route the slot's provider through
    ``resolve_runtime_provider`` (the canonical provider→api_mode/base_url/
    api_key resolver the CLI, gateway, and delegate_task all use), so the slot
    gets its provider's real API surface — e.g. MiniMax → anthropic_messages,
    GPT-5/o-series → max_completion_tokens, custom endpoints → their base_url.

    Returns the kwargs to pass through to ``call_llm`` (provider/model plus the
    resolved base_url/api_key when available). Falls back to the bare
    provider/model on any resolution error so a misconfigured slot still
    attempts the call rather than aborting the whole MoA turn.
    r   r%   r   )r   r   r   )resolve_runtime_provider)	requestedtarget_modelbase_urlapi_keyapi_modez-MoA slot runtime resolution failed for %s: %sN)	r+   r)   r*   hermes_cli.runtime_providerr>   r3   loggerdebugr/   )r,   r   r   outr>   rtexcs          r   _slot_runtimerJ      s    " 488J'-2.446H!'R(..0E'/%@C^H%uM  66* nC
O66)	]C	N66* nC
O J  ^DkRVFWY\]]J^s   AB< <	C0 C++C0c           	     p   	 ddl m} ddlm} ddlm}  |dddd      } |||j                  d      xs d|j                  d      xs d|j                  d	      xs d|j                  d
      xs d      \  }}|s| S  || |      S # t        $ r"}t        j                  d|       | cY d}~S d}~ww xY w)uu  Decorate an advisor or aggregator request with cache_control when its
    route honors it.

    Reuses the SAME policy function as the main agent loop
    (``anthropic_prompt_cache_policy``) resolved against the slot's own
    provider/base_url/api_mode/model, and the SAME breakpoint layout
    (``apply_anthropic_cache_control``, system_and_3). This keeps advisor and
    aggregator calls decorated exactly like an acting agent on that provider
    would be — no MoA-specific caching logic to drift.

    Returns the messages unchanged on any resolution error or when the
    policy says the route doesn't honor markers.
    r   )SimpleNamespace)anthropic_prompt_cache_policy)apply_anthropic_cache_controlr%   )r   rA   rC   r   r   rA   rC   r   )native_anthropicz(MoA cache_control decoration skipped: %sN)
typesrL   agent.agent_runtime_helpersrM   agent.prompt_cachingrN   r)   r3   rE   rF   )	r   runtimerL   rM   rN   stubshould_cachenative_layoutrI   s	            r   _maybe_apply_moa_cache_controlrW      s    ")MF
 R"BO&C[[,2[[,2[[,2++g&,"'
#m O,}
 	
  ?Es$   A=B
  	B
 
	B5B0*B50B5r   
max_tokensc               &   ddl m}m}m} t	        |       }t        |       }	 dt        dg|}	t        |	|      }	t        dd|	||t        |       d|}
 |       }t        |
dd      }|r*	  |||j                  d	      |j                  d
            }d}d}d}	  || j                  d      xs d||j                  d	      |j                  d      |j                  d            }|j                  }|j                  }|j                  }t!        |
      xs d}t#        |||||	|| j                  d      |j                  d	      xs | j                  d	      |	      }|||fS # t        $ r
  |       }Y w xY w# t        $ r Y zw xY w# t        $ r}}t$        j'                  d||       |d| dt#         |       dt        dg|d| d| j                  d      |j                  d	      xs | j                  d	      |      fcY d}~S d}~ww xY w)u  Call one reference model and return ``(label, text, usage)``.

    The slot is resolved to its provider's real runtime (via ``_slot_runtime``)
    and called through the same ``call_llm`` request-building path any model
    uses, so per-model wire-format handling (anthropic_messages,
    max_completion_tokens, fixed/forbidden temperature) applies identically to
    a reference as it would if that model were the acting model. MoA imposes no
    cap of its own (``max_tokens`` defaults to ``None`` → omitted → the model's
    real maximum); ``temperature`` is only the user's configured preset value,
    which call_llm may still override per model.

    The reference's token usage is normalized with the slot's OWN resolved
    provider/api_mode (advisors may run on a different provider than the
    aggregator, with different usage wire shapes) and returned as a
    ``CanonicalUsage`` so the caller can fold advisor spend into session
    accounting. Without this, the entire reference fan-out — often the bulk of
    a MoA turn's token spend — is invisible to cost tracking, which only ever
    saw the aggregator's usage.

    Never raises: a failed reference becomes a labelled note so the aggregator
    can still act with partial context. Designed to run inside a thread pool —
    ``call_llm`` is synchronous/blocking, so threads (not asyncio) are the right
    concurrency primitive, mirroring ``delegate_task``'s batch fan-out.
    r   )CanonicalUsageestimate_usage_costnormalize_usagesystemrolecontentmoa_referencetaskr   r   rY   reasoning_configr   Nr   rC   )r   rC   r   r%   rA   rB   )r   rA   rB   z(empty response)r   z!MoA reference model %s failed: %sz	[failed: r(   r#   )agent.usage_pricingr[   r\   r]   r/   rJ   _REFERENCE_SYSTEM_PROMPTrW   r   r4   getattrr)   r3   
amount_usdstatussource_extract_textr   rE   warning)r,   ref_messagesr   rY   r[   r\   r]   r-   rS   r   responser   	raw_usager   r   r   cost_output_textacctrI   s                       r   _run_referencert     sP   > YXED!GO

 &2JK[l[ 2(GD 
 #!3D9
 
  Hgt4	)'$[[4$[[4 	&!'R Z0 Z0I.D H++K++K %X.D2D((7#[[,D0D#

 lD((E  )&()(  		  	
:E3G	#a(.'4LM]P\]se1%((7#[[,D0D#+
 
 	
	
si   AF
 +)E% F
 A1E; AF
 %E85F
 7E88F
 ;	FF
 FF
 
	HA2HHHc                  ddl m} | sg S dgt        |       z  }i }t        t        t        |             }ddlm} t        |      5 }	t        |       D ]\  \  }
}|j                  d      dk(  r t        |      dt         |             f||
<   :|
||	j                   |t              ||||	      <   ^ |j                         D ]  \  }}
|j                         ||
<    	 ddd       |D cg c]  }||	 c}S # 1 sw Y   xY wc c}w )
aG  Fan out all reference models in parallel, returning outputs in order.

    Like ``delegate_task``'s batch mode, every reference is dispatched at once
    and we block until all of them finish before handing the joined results to
    the aggregator. Output order matches ``reference_models`` so the
    ``Reference {idx}`` labelling stays stable. MoA presets that reference
    another MoA preset are skipped here (recursion guard) with a labelled note.

    Each element is ``(label, text, usage)`` where usage is a
    ``CanonicalUsage`` (zeroed for skipped/failed references).
    r   r[   N)propagate_context_to_thread)max_workersr   moaz7[skipped: MoA presets cannot recursively reference MoA]rX   )rf   r[   lenmin_MAX_REFERENCE_WORKERStools.thread_contextrw   r   	enumerater)   r/   r   submitrt   itemsresult)reference_modelsrn   r   rY   r[   resultsfuturesworkersrw   executoridxr,   futurers                 r   _run_references_parallelr   }  s'   $ 3	26#>N:O1OGG(#.>*?@G
 A		0 +H"#34 	ICxx
#u,%M">#34 
   /?  +)   	& #==? 	+KFC!==?GCL	+)+. 0!!-A00/+ +. 1s   BC9*D2D9Dc                t    | rt        |       |k  r| S |dz  }t        |       d|z  z
  }| d|  d| d| | d  S )a  Head+tail preview of a tool result for the advisory view.

    Keeps the first and last halves of the budget with a ``[... N chars
    omitted ...]`` marker between them, so a reference sees both how the result
    started and how it ended without replaying the whole payload.
       Nz
[... z chars omitted ...]
)rz   )textbudgethalfomitteds       r   _truncate_tool_resultr     sX     3t9&Q;D$i!d("G5Dk]''*?dUV~NNr   c                   g }| xs g D ]  }t        |t              r|j                  d      xs i ni }|j                  d      xs' t        |t              r|j                  d      ndxs d}|j                  d      }t        |t              r|}n|	 ddl}|j                  |d	      }nd}|j                  |r	d
| d| dnd
| d        dj                  |      S # t        $ r t        |      }Y Iw xY w)a$  Render an assistant turn's tool_calls as readable text lines.

    The advisory view cannot carry real ``tool_calls`` payloads (strict
    providers reject tool_calls the reference never produced), so the agent's
    actions are flattened to text the reference can read and reason about.
    functionnamer%   tool	argumentsNr   F)ensure_asciiz[called tool: (z)]r(   
)	
isinstancedictr)   r+   jsondumpsr3   appendjoin)
tool_callslinestcfnr   args	args_textr   s           r   _render_tool_callsr     s    EB g+5b$+?bffZ &BRvvf~[Jr44H"&&.b[U[vvk"dC I& JJt%J@	 Ii~dV1YKr:~^b]ccdMefg  99U  &I	&s   C!!C87C8z[The conversation above is the current state of the task. Give your most intelligent judgement: what is going on, what should happen next, what risks or mistakes you see, and how the acting agent should proceed.]c                N   g }d}| D ]m  }|j                  d      }|j                  d      }t        |      }|dk(  r7|dk(  rL|j                         st        |t              r|rd}|j                         sq|}|j                  d|d       |dk(  rg }|j                         r|j                  |j                                t        |j                  d	            }|r|j                  |       |s|j                  dd
j                  |      d       |dk(  st        |      }	d|	 d}
|r-|d   j                  d      dk(  r|d   d   d
z   |
z   |d   d<   Z|j                  d|
d       p |r0|d   j                  d      dk(  r|j                  dt        d       n|r|d   j                  d      dk(  r	 |s_|d|dgS t        |       D ]I  }|j                  d      dk(  st        |j                  d            }|j                         sCd|dgc S  |S )u  Build an advisory view of the conversation for reference models.

    A reference gives an INFORMED judgement on the current state, so it must
    see what the agent actually did — its tool calls AND the tool results that
    came back — not just the agent's narration. We therefore preserve the whole
    conversation flow, but flatten it into clean user/assistant *text* turns:

      - system prompt: dropped (8K of Hermes boilerplate, not advisory signal).
      - assistant turns: kept; any ``tool_calls`` are rendered inline as
        ``[called tool: name(args)]`` text lines appended to the turn's text.
      - ``tool``-role results: NOT dropped. Each is folded (head+tail preview,
        see ``_truncate_tool_result``) into the *preceding* assistant turn as a
        ``[tool result: ...]`` block, so the reference sees what came back.

    This emits ZERO ``tool``-role messages and ZERO ``tool_calls`` arrays — only
    plain user/assistant text — so strict providers (Mistral, Fireworks) that
    reject orphan tool messages / unproduced tool_calls don't 400, while the
    reference still has the full picture.

    The view MUST end with a ``user`` turn. Anthropic (and OpenRouter→Anthropic)
    interpret a trailing assistant turn as an assistant *prefill* to continue,
    and no-prefill models (e.g. Claude Opus 4.8) reject it with
    ``400 ... must end with a user message``. Rather than DELETE the agent's
    latest context to satisfy that (which would blind the reference to the
    current state), we APPEND a synthetic user turn asking the reference to
    judge the state above. End-on-user is satisfied and no context is lost.

    The acting aggregator always receives the full, untrimmed transcript; this
    function only shapes the disposable advisory copy.
    Nr`   ra   r^   userz7[user sent non-text content (e.g. an image attachment)]r_   	assistantr   r   r   z[tool result: r(   )r)   r   r*   r   listr   r   r   r   _ADVISORY_INSTRUCTIONreversed)r   renderedlast_user_contentmsgr`   ra   r   parts
calls_textresult_textblockfallback_texts               r   _reference_messagesr     s0   > &(H$( GIwwv'')$  $G,86>::<Jw$=' Q::<  $OOV=>[ !Ezz|TZZ\*+CGGL,ABJZ(5AQ RSV^ 05K$[M3EHRL,,V4C*22,y*AD*H5*PY'  GHOGIZ HRL$$V,;4IJK	hrl&&v.&8 	(#0ABCCH% 	HCwwv&( 4SWWY5G H &&(%+FGG		H
 Or   c                   	 t        d      }|t        d      |j                  |       }|j                  xs dj	                         }|r|S 	 	 | j                  d   j                  }t        |t              r|j                  d      }nt        |d|      }t        |t              s|rt        |      nd}|j	                         S # t
        $ r Y w xY w# t
        $ r Y yw xY w)Nchat_completionsz&chat_completions transport unavailabler%   r   ra   )r   RuntimeErrornormalize_responsera   r*   r3   choicesmessager   r   r)   rh   r+   )ro   	transport
normalizedr   r   ra   s         r   rl   rl   j  s    	!"45	GHH11(;
""(b//1K 
""1%--gt$kk),Ggy':G'3'&-c'l2G}}    s%   A
C A6C 	CC	C! C!c                    | j                  |      }| t        |t              r|j                         sy	 t	        |      S # t
        t        f$ r t        j                  d||       Y yw xY w)u,  Read an optional temperature from a preset.

    Returns None when the key is absent, empty, or explicitly null — meaning
    "don't send temperature; let the provider default apply", exactly like a
    single-model Hermes agent (which never sends temperature unless
    configured). The old coercion ``float(preset.get(key, 0.6) or 0.6)``
    made unset impossible: absent, null, and even 0 all collapsed to the
    hardcoded default, so MoA advisors/aggregator always ran at 0.6/0.4
    while the same model running solo used the provider default.
    Nz(ignoring non-numeric %s=%r in MoA preset)	r)   r   r+   r*   float	TypeError
ValueErrorrE   rm   )presetkeyvalues      r   _preset_temperaturer     sa     JJsOE}E3/U|z" A3Ns   
A &A*)A*)r   aggregator_temperaturerY   c           
        g }t        |      }t        ||||      }dj                  d t        |d      D              }	d|  d|	 }
t	        |      }t        |      }	 t        d|
d	g|      }t        dd
|||t        |      d|}t        |      }|s|	}d| ddj                  d |D               d|j                          S # t        $ r#}t        j                  d||       d}Y d}~Zd}~ww xY w)uE  Run configured reference models and synthesize their advice.

    Failures are returned as model-specific notes instead of aborting the normal
    agent loop; the main model can still act with partial context.

    ``max_tokens`` is ``None`` by default: MoA does not cap reference or
    aggregator output, so each model uses its own maximum. ``call_llm`` omits
    the parameter entirely when it is ``None`` (see its docstring), which also
    sidesteps providers that reject ``max_tokens`` outright. A hardcoded cap
    here previously truncated long aggregator syntheses.

    ``temperature`` / ``aggregator_temperature`` are ``None`` by default:
    like max_tokens, ``call_llm`` omits temperature when None so the
    provider default applies — matching single-model agent behavior. Presets
    may still pin explicit values.
    rX   

c              3  @   K   | ]  \  }\  }}}d | d| d|   ywz
Reference u    — z:
Nr#   .0r   r-   r   _usages        r   	<genexpr>z(aggregate_moa_context.<locals>.<genexpr>  s6      &C&%v SEugS/      startau  You are the aggregator in a Mixture of Agents process. Synthesize the reference responses into concise, actionable guidance for the main Hermes agent. Focus on next steps, tool-use strategy, risks, and any disagreements. Do not answer the user directly unless that is all that is needed; produce context the main agent should use in its normal loop.

Original user prompt:
z

Reference responses:
r   r_   moa_aggregatorrc   z"MoA aggregator model %s failed: %sr%   Nu   [Mixture of Agents context — use this as private guidance for the normal Hermes agent loop. You may call tools, continue reasoning, or finish normally.]
Aggregator: 
References: , c              3  2   K   | ]  }t        |        y wr   r/   )r   r,   s     r   r   z(aggregate_moa_context.<locals>.<genexpr>  s      PtT!2 P   r#   )r   r   r   r~   r/   rJ   rW   r   r<   rl   r3   rE   rm   r*   )user_promptapi_messagesr   r:   r   r   rY   reference_outputsrn   joinedsynth_prompt	agg_labelagg_runtimeagg_messagesro   	synthesisrI   s                    r   aggregate_moa_contextr     sR   4 57&|4L0	 [[ *34EQ*O F
	"
 #. /!!'	*  J'I
+K 667
  
!!.!9*E
 
 "(+	
 		 !k "yy P?O PPQQU??
	  ;YL	s   5C 	C3C..C3c                   | r| d   nd}|a|j                  d      dk(  rM|j                  d      }t        |t              r|dz   |z   |d<   yt        |t              rg |dd|z   d|d<   y| j	                  d|d	       y)
u  Attach the per-turn reference block at the END of the aggregator prompt.

    The reference text differs on every tool-loop iteration. In an agentic loop
    the most recent ``user`` message is the *original task* sitting near the TOP
    of the context (everything after it is assistant/tool turns), so merging the
    turn-varying reference block into it diverges the prompt prefix early — the
    server's KV cache cannot be reused and the entire conversation re-prefills on
    every step (full prefill each tool call, dominating latency on long contexts).

    Appending at the very end keeps the ``[system][task][tool-history]`` prefix
    stable and cache-reusable (only the new block re-prefills), and gives the
    aggregator the references with recency. Merge into the last message only when
    it is already a trailing ``user`` turn (plain chat — still at the end).

    A trailing user turn's content may be a STRING or a LIST of content parts —
    Anthropic prompt-cache decoration (which runs before the MoA facade)
    converts string content to ``[{"type": "text", ..., "cache_control": ...}]``,
    and multimodal turns are lists natively. Both shapes are merged in place:
    appending a new text part AFTER the cache_control-marked part keeps the
    cached prefix byte-stable (the marker still terminates it) while the
    turn-varying guidance rides outside the cached span. Appending a SEPARATE
    user message here instead would produce two consecutive user turns —
    strict providers reject that.
    r   Nr`   r   ra   r   r   )typer   r_   )r)   r   r+   r   r   )r   guidancelastlast_contents       r   _attach_reference_guidancer     s    2  ,<DDHHV,6xx	*lC(*V3h>DOlD)ZZvvPXGX.YZDOH=>r   c                  H    e Zd ZdZdd	dZd
dZ	 d	 	 	 	 	 ddZddZddZy)MoAChatCompletionszGOpenAI-chat-compatible facade where the aggregator is the acting model.Nc                    |xs d| _         || _        d | _        g | _        ddlm}  |       | _        d | _        d | _        d | _	        y )Ndefaultr   rv   )
preset_namereference_callback_ref_cache_key_ref_cache_outputsrf   r[   _pending_reference_usage_pending_reference_costlast_aggregator_slot_pending_trace)r   r   r   r[   s       r   r   zMoAChatCompletions.__init__  sW    &3) #5 -1>@ 	7-;-=%,0$ *.! $(r   c                ~    ddl m} | j                  xs  |       }| j                  } |       | _        d| _        ||fS )a  Pop pending reference-fan-out usage + cost, resetting both to empty.

        Returns ``(CanonicalUsage, cost_usd_or_None)`` for the most recent
        ``create()`` and clears the pending values, so a subsequent read (e.g.
        a streaming retry re-entering accounting) cannot double-count. Usage is
        always a ``CanonicalUsage`` (zeroed if none); cost is a summed-dollars
        float or ``None`` when no advisor could be priced.
        r   rv   N)rf   r[   r   r   )r   r[   r   rq   s       r   consume_reference_usagez*MoAChatCompletions.consume_reference_usageC  sB     	7--A1A++(6(8%'+$d{r   c                "   | j                   }d| _         |rd|vry	 ddlm} |j                  d      xs i }|j                  d      }||r|} |||j                  dd      |j                  d	g       |j                  d
d      |j                  d      |j                  d      |j                  d      |j                  d      |t	        |j                  d            
       y# t
        $ r }t        j                  d|       Y d}~yd}~ww xY w)u  Flush the pending full-turn trace to disk, if one is pending.

        No-op when tracing is off (``save_moa_turn`` checks the config), when
        there is no pending trace (a cache-HIT iteration ran no references), or
        when the aggregator input was never recorded. Clears the pending trace
        so a repeat consume cannot double-write. Best-effort — never raises.

        ``aggregator_output_fallback`` is the aggregator's resolved acting text
        as the caller already holds it in memory (the streamed assistant text).
        On the streaming path the aggregator's output could not be captured
        inline at ``create()`` time (the raw token stream was handed to the live
        consumer), so ``pending["aggregator_output"]`` is None; we fold the
        caller's resolved text in here so the trace is self-contained in BOTH
        streaming and non-streaming modes. Non-streaming already has the inline
        output and ignores the fallback.
        Naggregator_input_messagesr   )save_moa_turnaggregator_slotaggregator_outputr   r%   r   aggregator_labelr   r   r   aggregator_streamed)

session_idr   r   r   aggregator_modelaggregator_providerr   r   r   r   zMoA trace flush failed: %s)r   agent.moa_tracer   r)   boolr3   rE   rF   )r   r   aggregator_output_fallbackpendingr   agg_slot
agg_outputrI   s           r   consume_and_save_tracez)MoAChatCompletions.consume_and_save_traceT  s   & %%"5WD	<5{{#45;H !%89J!&@7
%#KK"5")++.A2"F!(-?!D!)g!6$,LL$<'.{{3K'L*1++6Q*R",$(5J)K$L  	<LL5s;;	<s   CC% %	D.D		Dc                    | j                   }|y 	  ||fi | y # t        $ r!}t        j                  d||       Y d }~y d }~ww xY w)Nz(MoA reference_callback failed for %s: %s)r   r3   rE   rF   )r   eventkwargscbrI   s        r   _emitzMoAChatCompletions._emit  sN    $$:	Qu 	QLLCUCPP	Qs   	 	AA  Ac                   ddl m} ddlm}  | |       j	                  d      xs i | j
                        }t        |j	                  d      xs g       }|j	                  d      xs g }|j	                  d      xs i }|rt        |      nd | _        |j	                  d      }t        |d	      }	t        |d
      }
|
"|j	                  d      |j	                  d      }
|j	                  dd      sg }ddl
m} g }t        |      }t        |j	                  d      xs d      j                         j                         }|}|dk(  r`d }t!        t#        |      dz
  dd      D ]8  }||   }|j	                  d      dk(  s|j	                  d      t$        k7  s6|} n ||d |dz    }t'        j(                  dj+                  d |D              j-                  dd            j/                         }| j
                  |t1        d |D              f}|| j2                  k(  xr t5        | j6                        }|r1t        | j6                        } |       | _        d | _        d | _        nt?        |||	|      }|| _        t        |      | _         |       }d }|D ]\  \  }}}tA        |tB              stA        |jD                  |      r||jD                  z   }|jF                  J|xs d|jF                  z   }^ || _        || _        | j
                  t        |      ||
d| _        t#        |      }tI        |d      D ]  \  }\  }}}| jK                  d||||        ! |r| jK                  d!tM        |      |"       |D  cg c]  } t        |        }!} |rfd#j+                  d$ tI        |d      D              }"d%| j
                   d&tM        |       d'd(j+                  d) |D               d*|" }#tO        |!|#       |j	                  d+      dk(  rtQ        d,      t        |      }$|!|$d<   | j<                  '|!| j<                  d-<   tM        |      | j<                  d.<   t5        |j	                  d/            }%i }&|%r8d|&d/<   |j	                  d0      xs d1di|&d0<   |j	                  d2      |d2   |&d2<   tS        d;d3|!|
|$j	                  d4      |$j	                  d5      |$j	                  d6      tU        |      d7|&tW        |      }'| j<                  L|%r d| j<                  d8<   d | j<                  d9<   |'S d:| j<                  d8<   	 tY        |'      | j<                  d9<   |'S |'S c c} w # tZ        $ r d | j<                  d9<   Y |'S w xY w)<Nr   r6   )resolve_moa_presetry   r   r   r:   reference_max_tokensreference_temperaturer   r   enabledTrv   fanoutper_iteration	user_turnr   r   r`   r   ra    c              3  f   K   | ])  }|j                  d        d|j                  d        + yw)r`   r&   ra   N)r)   )r   ms     r   r   z,MoAChatCompletions.create.<locals>.<genexpr>  s2      :;155=/155#3"45s   /1zutf-8replacec              3  2   K   | ]  }t        |        y wr   r   )r   ss     r   r   z,MoAChatCompletions.create.<locals>.<genexpr>  s     3]qKN3]r   rX   )r   r   r   r   r   zmoa.reference)indexcountr-   r   zmoa.aggregating)r:   	ref_countr   c              3  @   K   | ]  \  }\  }}}d | d| d|   ywr   r#   r   s        r   r   z,MoAChatCompletions.create.<locals>.<genexpr>.  s6      !.C.%v SEugS7!r   z.[Mixture of Agents reference context]
Preset: z
Aggregator/acting model: r   r   c              3  (   K   | ]
  \  }}}|  y wr   r#   )r   r-   _s      r   r   z,MoAChatCompletions.create.<locals>.<genexpr>6  s     (T;5!Q(Ts   z

Use the reference responses below as private context. You are the aggregator and acting model: answer the user directly or call tools as needed.

r   z+MoA aggregator cannot be another MoA presetr   r   streamstream_optionsinclude_usagetimeoutr   rY   tools
extra_body)rd   r   r   rY   r&  r'  re   r   r   Fr#   ).r9   r7   hermes_cli.moa_configr  r)   r   r   r   r   r   rf   r[   r   r+   r*   lowerrangerz   r   hashlibsha256r   encode	hexdigesttupler   r  r   r   r   r   r   r   r   r   r   r~   r  r/   r   r   r   r<   rJ   rl   r3   )(r   
api_kwargsr7   r  r   r   r   r:   r  r   r   r[   r   rn   fanout_modesig_messageslast_user_idx_i_m_sig
_cache_key_refs_from_cache
_ref_usage	_ref_cost_lbl_txt_acct
_ref_count_idx_label_textr   r  r   r   r   
agg_kwargsr"  stream_kwargs_agg_responses(                                           r   createzMoAChatCompletions.create  s   1<#KM$5$5e$<$BDDTDTU
z28b9!::&89?RZZ-3
 9CD$4!  &zz*@A *&2IJ!4V=U!V!)jnn].K.W &0^^M%B"
 zz)T*!68:*84 &**X.A/BHHJPPR#+% !MC-12r: !"%66&>V+y0AEZ0Z$&M	
 (+,?ma.?@ ~~MM ?K fWi(
 )+	 	
 &&e3]L\3].]^
%)<)<<^dF]F]A^ $T%<%< =
 -;,<D)+/D( #'D 8 '/	! #-D&*+<&=D# ()J!I%6 F!dEe^4!%++~>%/%++%=
~~1%.^!u~~$E	F -7D)+4D( **%)*;%<#-*@	#D ./J1:;LTU1V --vuf

#$    

%*:6(   *22AQ22[[ !2;<MUV2W! F
++, -,,7
,C+D E#yy(TBS(TTU VH (  '|X>>>*%.LMM*%
!-
: *?KD ;<6A*6MD 23  jnnX./(*&*M(#/0K_d4K *+
 ~~i(4+5i+@i(  

!!.!~~l3..)!~~l39*E

 

 J'

  *=A##$9:;?##$78  >C##$9:D?L]?[D''(;< }_ 3Z ! D?CD''(;<Ds   U&
U+ +VVr   r   r+   r   r   )returnztuple[Any, Any]NNr   r   r  r   rG  None)r
  r+   r  r   rG  rJ  )r0  r   rG  r   )	r   r   r    r!   r   r   r  r  rE  r#   r   r   r   r     sA    Q'(R$ IM-<-<BE-<	-<^Qor   r   c                  F    e Zd ZdddZddZedd       Z	 d		 	 	 	 	 d
dZy)	MoAClientNc                j     t        ddi              | _        t        ||      | j                  _        y )N_MoAChatr#   )r   )r   chatr   completions)r   r   r   s      r   r   zMoAClient.__init__  s+    ,DR,.	 2;Se f		r   c                J    | j                   j                  j                         S )zPop the pending reference-fan-out usage from the completions facade.

        Lets session accounting fold the MoA advisor tokens into the turn's
        usage without reaching into ``.chat.completions`` internals.
        )rO  rP  r   r   s    r   r   z!MoAClient.consume_reference_usage  s     yy$$<<>>r   c                D    t        | j                  j                  dd      S )zResolved aggregator slot ({provider, model, ...}) from the most
        recent create(), or None. Read by session cost accounting to price the
        aggregator's acting turn at its real model instead of the virtual
        preset name.r   N)rh   rO  rP  rR  s    r   r   zMoAClient.last_aggregator_slot  s     tyy,,.DdKKr   c                P    | j                   j                  j                  ||      S )a3  Flush the pending full-turn MoA trace via the completions facade.

        No-op unless ``moa.save_traces`` is enabled and a turn is pending.
        ``aggregator_output_fallback`` supplies the resolved acting text so the
        streaming path's trace is self-contained (see the facade docstring).
        )r  )rO  rP  r  )r   r   r  s      r   r  z MoAClient.consume_and_save_trace  s,     yy$$;;3M < 
 	
r   r   rF  )rG  r   rH  rI  )r   r   r    r   r   propertyr   r  r#   r   r   rL  rL  ~  sG    g? L L IM

BE
	
r   rL  )r,   dict[str, Any]rG  r+   )r,   rV  rG  dict[str, Any] | None)r:   rV  rG  rW  )r,   rV  rG  rV  )r   list[dict[str, Any]]rS   rV  rG  rX  )
r,   dict[str, str]rn   rX  r   float | NonerY   
int | NonerG  ztuple[str, str, Any])
r   list[dict[str, str]]rn   rX  r   rZ  rY   r[  rG  zlist[tuple[str, str, Any]])r   r+   r   intrG  r+   )r   r   rG  r+   )r   rX  rG  rX  )ro   r   rG  r+   )r   rV  r   r+   rG  rZ  )r   r+   r   rX  r   r\  r:   rY  r   rZ  r   rZ  rY   r[  rG  r+   )r   rX  r   r+   rG  rJ  )'r!   
__future__r   r+  loggingconcurrent.futuresr   typingr   agent.auxiliary_clientr   agent.message_contentr   agent.transportsr   	getLoggerr   rE   r|   r   _REFERENCE_TOOL_RESULT_BUDGETrg   r/   r4   r<   rJ   rW   rt   r   r   r   r   r   rl   r   r   r   r   rL  r#   r   r   <module>rg     s   #   1  + 6 *			8	$  3' 3'z !% 3 ,?</d)")) )` !%!r

r
&r
 	r

 r
 r
r !%!71*71&71 	71
 71  71t 4Q O8 ~D06 !%+/!XX 'X +	X
 X X )X X 	Xv"?Jd dN 
  
r   