
    `gj                       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mZm	Z	 ddl
mZmZmZmZmZmZmZmZ  ej&                  e      Ze G d d             Ze G d d	             Zeeeeeef   f   Z	 e G d
 d             Ze G d d             Ze G d d             Z ed       G d d             Zd'dZd(dZd)dZ  G d de!      Z"	 	 	 	 	 	 	 	 	 	 	 	 d*dZ#d+dZ$	 	 	 	 	 	 	 	 	 	 	 	 	 	 d,dZ% ejL                  dejN                  ejP                  z        Z)d-dZ*	 	 	 	 	 	 	 	 d.dZ+d/dZ,d0d Z-	 	 	 	 	 	 	 	 d1d!Z. G d" d#      Z/ddd$	 	 	 	 	 	 	 	 	 d2d%Z0g d&Z1y)3u	  
Plugin LLM facade — host-owned LLM access for trusted plugins.
==============================================================

Plugins built on Hermes Agent often need to make their own LLM calls
out-of-band — a hook that rewrites a tool error before the user sees
it, a gateway adapter that translates inbound text, a slash command
that summarises a paste, a scheduled job that scores yesterday's
activity into a single line on a status board.

Today the only stable plugin surfaces extend an existing Hermes
subsystem: ``register_tool``, ``register_platform``,
``register_memory_provider``, etc. None of those help when the
plugin's job is to make its own model call. This module is the
supported lane for that case.

The plugin gets ``ctx.llm`` exposed on its
:class:`~hermes_cli.plugins.PluginContext`:

* ``complete(messages, ...)`` — chat completion against the user's
  active model + auth.
* ``complete_structured(instructions=..., input=[...], json_schema=...)``
  — bounded structured inference with optional image inputs, JSON
  schema validation, and parsed JSON output.
* async siblings ``acomplete()`` / ``acomplete_structured()`` for
  plugins running on asyncio loops (gateway adapters, hooks).

Provider/model/agent_id/profile are explicit keyword arguments — no
embedded slugs, no shorthands. This mirrors Hermes' main config
shape (``model.provider`` + ``model.model``) so plugin authors who
already understand the host config don't have to learn anything new.

The host owns provider routing, auth resolution, timeouts, and
fallback. The plugin never sees raw OAuth tokens or API keys. All
override knobs (``provider=``, ``model=``, ``agent_id=``,
``profile=``) are gated behind explicit per-plugin trust flags in
``config.yaml``::

    plugins:
      entries:
        my-plugin:
          llm:
            allow_provider_override: true
            allow_model_override: true
            allowed_providers: [openrouter, anthropic]   # optional
            allowed_models:    [openai/gpt-4o-mini]       # optional
            allow_agent_id_override: false
            allow_profile_override: false

Untrusted plugins still get the default surface — they just can't
steer provider, model, agent, or auth-profile selection. The trust
gate is fail-closed: a missing config block means "no overrides,"
not "anything goes."

Backed by :func:`agent.auxiliary_client.call_llm`, which already
handles every provider, fallback chain, and per-task override Hermes
supports.
    )annotationsN)	dataclassfield)Any	AwaitableCallableDictListOptionalSequenceUnionc                  *    e Zd ZU dZded<   dZded<   y)PluginLlmTextInputz&Text block in a structured input list.strtexttypeN)__name__
__module____qualname____doc____annotations__r        C/root/.hermes/venv/lib/python3.12/site-packages/agent/plugin_llm.pyr   r   M   s    0
ID#r   r   c                  X    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<   y)PluginLlmImageInputa  Image block in a structured input list.

    Either ``data`` (raw bytes) or ``url`` (http(s) or data: URL) must be
    provided. ``mime_type`` defaults to ``image/png`` when ``data`` is
    used and is required for non-PNG bytes to render correctly across
    providers.
    NzOptional[bytes]dataOptional[str]url	image/pngr   	mime_type 	file_nameimager   )
r   r   r   r   r   r   r   r!   r#   r   r   r   r   r   r   U   s;     !D/ C Is IsD#r   r   c                  f    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	Z
d
ed<   y	)PluginLlmUsageu   Token + cost usage for a completion. All fields optional — providers
    differ on what they return. ``cost_usd`` is the host's best estimate.r   intinput_tokensoutput_tokenstotal_tokenscache_read_tokenscache_write_tokensNOptional[float]cost_usd)r   r   r   r   r(   r   r)   r*   r+   r,   r.   r   r   r   r&   r&   r   sH    M L#M3L#s $Ho$r   r&   c                  r    e Zd ZU dZded<   ded<   ded<   ded<    ee      Zded	<    ee      Z	d
ed<   y)PluginLlmCompleteResultz%Result of :meth:`PluginLlm.complete`.r   r   providermodelagent_iddefault_factoryr&   usageDict[str, Any]auditN)
r   r   r   r   r   r   r&   r6   dictr8   r   r   r   r0   r0      s7    /
IMJM!.AE>A!$7E>7r   r0   c                      e Zd ZU dZded<   ded<   ded<   ded<    ee      Zded	<   d
Zded<   dZ	ded<    ee
      Zded<   y
)PluginLlmStructuredResulta5  Result of :meth:`PluginLlm.complete_structured`.

    ``parsed`` is set only when ``json_mode=True`` or ``json_schema`` is
    provided AND the response was valid JSON. ``content_type`` is
    ``"json"`` in that case, ``"text"`` otherwise (e.g. the model
    refused or the response wasn't requested as JSON).r   r   r1   r2   r3   r4   r&   r6   NOptional[Any]parsedcontent_typer7   r8   )r   r   r   r   r   r   r&   r6   r=   r>   r9   r8   r   r   r   r;   r;      sO    : IMJM!.AE>A FM L#!$7E>7r   r;   T)frozenc                      e Zd ZU 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<   dZded<   dZded<   y)_TrustPolicyz0Resolved trust gate for one plugin's LLM access.r   	plugin_idFboolallow_provider_overrideNzOptional[frozenset]allowed_providersallow_any_providerallow_model_overrideallowed_modelsallow_any_modelallow_agent_id_overrideallow_profile_override)r   r   r   r   r   rD   rE   rF   rG   rH   rI   rJ   rK   r   r   r   rA   rA      sb    :N$)T)-1*1$$!&$&*.N'.!OT!$)T)#(D(r   rA   c                F    | xs dj                         j                         S )z;Lower-case + strip whitespace. Used for allowlist matching.r"   )striplower)raws    r   _normalize_refrP      s    I2$$&&r   c                   t        | t              sy| D cg c]  }t        |t              st        |        }}d|v }|D ch c]  }|s|dk7  s| }}|r|st	               dfS |rt	        |      |fS t	               |fS c c}w c c}w )u  Coerce a YAML list into ``(frozenset_or_None, allow_any)``.

    ``["*"]`` (or any list containing ``"*"``) → ``(frozenset(), True)``.
    Any other list → ``(frozenset({...}), False)``.
    Missing / non-list → ``(None, False)`` meaning "no allowlist."
    )NF*T)
isinstancelistr   rP   	frozenset)rO   item
normalized	allow_anycleaneds        r   _coerce_allowlistrZ      s     c4 36P4*T3:O.&PJPz!I *Cdts{tCGC{D  !9,,;	!! QCs   BBBBBc                D   | st        d      S 	 ddlm}  |       xs i }|j	                  d      }t        |t              st        |       S |j	                  d      }t        |t              st        |       S |j	                  |       }t        |t              st        |       S |j	                  d      }t        |t              st        |       S t        |j	                  d            \  }}t        |j	                  d	            \  }	}
t        | t        |j	                  d
d            |	|
t        |j	                  dd            ||t        |j	                  dd            t        |j	                  dd            	      S # t        $ r t        |       cY S w xY w)u  Read ``plugins.entries.<plugin_id>.llm`` from config.yaml.

    Missing config → fully restrictive policy (default deny on every
    override). The policy is resolved per-call rather than cached so
    config edits take effect without restarting the agent.
    r"   )rB   r   )load_configpluginsentriesllmrH   rE   rD   FrG   rJ   rK   )	rB   rD   rE   rF   rG   rH   rI   rJ   rK   )	rA   hermes_cli.configr\   	ExceptiongetrS   r9   rZ   rC   )rB   r\   configplugins_cfgr^   entryllm_cfgrH   rI   rE   rF   s              r   _resolve_trust_policyrg      su    b))11$" **Y'Kk4(i00ooi(Ggt$i00KK	"EeT"i00iiGgt$i00&7DT8U&V#NO,='(-))  $W[[1JE%R S+-!'++.De"LM%' $W[[1JE%R S#GKK0H%$PQ
 
+  1i001s   F FFc                      e Zd ZdZy)PluginLlmTrustErrorz<Raised when a plugin attempts an LLM override without trust.N)r   r   r   r   r   r   r   ri   ri      s    Fr   ri   c          	        d}d}d}|r| j                   s&t        d| j                  d| j                   d      t        |      }| j                  sC| j
                  7|| j
                  vr)t        d| j                  d|d| j                   d      |j                         }|r| j                  s&t        d| j                  d| j                   d	      t        |      }| j                  sC| j                  7|| j                  vr)t        d| j                  d
|d| j                   d      |j                         }|r2| j                  s&t        d| j                  d| j                   d      |rB| j                  s&t        d| j                  d| j                   d      |j                         }||||fS )ai  Apply the trust gate. Returns the validated overrides as
    ``(provider, model, agent_id, profile)`` or raises
    :class:`PluginLlmTrustError`.

    Each override (``provider``, ``model``, ``agent_id``, ``profile``)
    is independently gated. ``provider`` and ``model`` each have an
    optional allowlist via ``allowed_providers`` / ``allowed_models``.
    NzPlugin z3 cannot override the provider (set plugins.entries.z/.llm.allow_provider_override to true to allow).z provider override z is not in plugins.entries.z.llm.allowed_providers.z0 cannot override the model (set plugins.entries.z,.llm.allow_model_override to true to allow).z model override z.llm.allowed_models.zL cannot run completions against a non-default agent id (set plugins.entries.z/.llm.allow_agent_id_override to true to allow).z7 cannot override the auth profile (set plugins.entries.z..llm.allow_profile_override to true to allow).)rD   ri   rB   rP   rF   rE   rM   rG   rI   rH   rJ   rK   )	policyrequested_providerrequested_modelrequested_agent_idrequested_profilefinal_providerfinal_modelfinal_profilerW   s	            r   _check_overridesrs      s2     %)N!%K#'M--%&**- .((.(8(8'9 :%& 
 $$67
))((4&":"::%&**--@%((C##$$;= 
 ,113**%&**- .((.(8(8'9 :%& 
 $O4
&&%%1&"7"77%&**--="%%@##$$8: 
 &++-&"@"@!f&&) *99?9I9I8J K=>
 	
 ,,%&**- .((.(8(8'9 :%& 
 *//1;(:MIIr   c                   t        | t              rd| j                  dS t        | t              rRd| j                  | j
                  d}| j                  | j                  |d<   | j                  r| j                  |d<   |S t        | t              r| j                  d      }|dk(  r1| j                  d      }t        |t              st        d      d|dS |dk(  rld| vr| j                  d      st        d	      d| j                  d      | j                  d      | j                  d
      xs d| j                  d      xs ddS t        d|      t        dt        |       j                         )zyCoerce a structured input block to a plain dict the message
    builder understands. Unknown shapes raise ``ValueError``.r   r   r   r$   )r   r!   r#   r   r   r   z'text input block requires 'text' stringz0image input block requires 'data' bytes or 'url'r!   r    r#   r"   )r   r   r   r!   r#   zUnknown input block type: zUnsupported input block: )rS   r   r   r   r!   r#   r   r   r9   rb   r   
ValueErrorr   r   )blockdkindr   s       r   _normalize_input_blockrz   Q  sa    %+,

33%,-

 ::!

AfI99yyAeH%yy 6>99V$DdC( !JKK"D117?U"599U+; !STT		&)yy'"YY{3B{"YY{39r  5dX>??
0e1E1E0FG
HHr   c           	        g }g }|r|j                  |j                                |s||j                  d       |r#|j                  ddj                  |      d       g }| j                         }	|r|	 d| }	| 	 t        j                  |dd      }
|	 d	|
 }	|j                  d
|	d       |D ]  }t        |      }|d   d
k(  r|j                  d
|d
   d       .|d   dk(  s7|j                  d      r|j                  dd|d   id       b|j                  d      xs d}t        |t        t        f      st        d      t        j                  |      j                  d      }|j                  d      xs d}|j                  ddd| d| id        |j                  d|d       |S # t
        t        f$ r t        |      }
Y ?w xY w)a;  Build the OpenAI-style messages list for a structured call.

    The instructions become the first text part of the user message,
    followed by an optional ``Schema name: <name>`` hint and an optional
    JSON-only directive when JSON output is requested. Image inputs are
    encoded as ``image_url`` parts.
    zlRespond with a single JSON object that matches the requested shape. Do not include prose or markdown fences.systemz

)rolecontentz

Schema name: FT)ensure_ascii	sort_keysz

JSON schema:
r   ru   r   r$   r   	image_url)r   r   r   r   z image input 'data' must be bytesasciir!   r    zdata:z;base64,user)appendrM   joinjsondumps	TypeErrorrv   r   rz   rb   rS   bytes	bytearraybase64	b64encodedecode)instructionsinputs	json_modejson_schemaschema_namesystem_promptmessages	sys_parts
user_partsheaderschema_textrw   normr   b64mimes                   r   _build_structured_messagesr   v  s     &(HI,,./K+7	
 fkk)6LMN')J!F8,[M:	+**[uPTUK 8-k];vv67 %e,<6!vtF|DE&\W$xx!!'"'e!5# 
 xx'.3!$	(:;$%GHH&&t,33G<xx,;!!'"'5hse)D!E# !* OOV
;<O7 :& 	+k*K	+s   >F8 8GGz```(?:json)?\s*(.+?)```c                    t         j                  |       }|r|j                  d      j                         S | j                         S )zqPull the first fenced code block out of ``text`` if any. Returns
    ``text`` unchanged when no fence is present.   )	_FENCE_REsearchgrouprM   )r   matchs     r   _strip_code_fencesr     s:     T"E{{1~##%%::<r   c                t   |s|y| sy	 t        j                  t        |             }|	 ddl}|j                  ||       |dfS |dfS # t         j                  t        f$ r Y yw xY w# t        $ r t        j                  d       Y |dfS j                  $ r}t	        d|j                         |d}~ww xY w)zReturn ``(parsed, content_type)``. ``content_type`` is ``"json"``
    when parsing succeeded and (when a schema was given) validation
    passed; ``"text"`` otherwise.N)Nr   r   z2jsonschema unavailable; skipping schema validationz3Plugin LLM structured output did not match schema: r   )r   loadsr   JSONDecodeErrorrv   
jsonschemavalidateImportErrorloggerdebugValidationErrormessage)r   r   r   r=   r   excs         r   _parse_structured_textr     s     0.t45 		4 6>66>   *-   	OLLMN 6> )) 	Eckk]S	s.   A	 A( 	A%$A%(B7B7B22B7c                R   t               }t        | dd      |S dfd} |d      xs  |d      |_         |d      xs  |d      |_         |d      xs |j                  |j                  z   |_         |d	      xs  |d
      |_         |d      xs  |d      |_        |S )u  Pull token usage out of an OpenAI-shaped response object.

    Tolerant of provider differences — Anthropic via the auxiliary
    adapter exposes ``usage.prompt_tokens`` / ``usage.completion_tokens``;
    direct OpenAI also exposes ``cache_read_input_tokens``.r6   Nc                    t        | d       }|!t        t              rj                  |       }	 |t	        |      S dS # t
        t        f$ r Y yw xY w)Nr   )getattrrS   r9   rb   r'   r   rv   )namevrO   s     r   _gz_extract_usage.<locals>._g  s[    Ct$9C.A	]3q611:& 		s   A  A AAprompt_tokensr(   completion_tokensr)   r*   cache_read_input_tokensr+   cache_creation_input_tokensr,   )r   r   returnr'   )r&   r   r(   r)   r*   r+   r,   )responser6   r   rO   s      @r   _extract_usager     s     E
(GT
*C
{ O,B>0BE01HR5HEN+Y0B0BUEXEX0XE !:;VrBU?VE!"?@\BG[D\ELr   c                   	 | j                   d   j                  }t        |dd      }t        |t              r|S t        |t
              rg }|D ]  }t        |t              rJ|j                  d      dk(  s(t        |j                  d      t              sH|j                  |d          ]t        |dd      }t        |t              s{|j                  |        dj                  |      S 	 y# t        t        t        f$ r Y yw xY w)z@Pull the assistant text out of an OpenAI-shaped response object.r   r~   Nr   r   r"   )choicesr   r   rS   r   rT   r9   rb   r   r   AttributeError
IndexErrorr   )r   msgr~   partsparttxts         r   _extract_textr     s    q!))#y$/gs#Ngt$!E *dD)xx'61j&AQSV6WT&\2!$5C!#s+S)* 775>! %  J	2 s(   7C/ ;C/ 6C/ 2C/ 	#C/ /DDc                   | r| }n$	 ddl m}  |       xs dj                         xs d}t	        |dd      }t        |t              r$|j                         r|j                         }||fS |r|}||fS 	 ddl m}  |       xs dj                         xs d}||fS # t        $ r d}Y ~w xY w# t        $ r d}Y ||fS w xY w)	u  Decide what to record as ``result.provider`` / ``result.model``.

    Precedence:

    1. Explicit overrides win — if the plugin asked for ``provider="x"``
       or ``model="y"``, that's what we record (it's what the call
       actually targeted).
    2. Otherwise we ask the host for the current main provider/model
       via :func:`_read_main_provider` / :func:`_read_main_model`, since
       those are what ``call_llm`` resolves to when ``provider=None``
       and ``model=None`` are passed through. They reflect runtime
       overrides set by ``set_runtime_main()``.
    3. ``response.model`` (if present) overrides the recorded model
       string. Providers post-resolution often return a slightly
       different model id than the request (e.g. ``gpt-4o`` →
       ``gpt-4o-2024-08-06``); the plugin's audit log should reflect
       what actually ran.
    4. If everything above is empty, fall back to ``"auto"`` /
       ``"default"`` so the result object has non-empty strings.
    r   )_read_main_providerr"   autor2   N)_read_main_modeldefault)agent.auxiliary_clientr   rM   ra   r   rS   r   r   )provider_overridemodel_overrider   r1   r   response_modelr2   r   s           r   _resolve_attributionr     s    4 $	B+-3::<FH Xw5N.#&>+?+?+A$$& U? 
 U?	?%'-2446C)E U?  	H	  	EU?	s#   #B 4#B, B)(B),B=<B=c                     e Zd ZdZdddd	 	 	 	 	 	 	 	 	 ddZddddddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZddddddddddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd	Zddddddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd
Zddddddddddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZe		 	 	 	 	 	 dd       Z
dd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZdd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZy)	PluginLlmu  Host-owned LLM access for one trusted plugin.

    Instances are constructed by :class:`hermes_cli.plugins.PluginContext`
    and exposed as ``ctx.llm``. Plugins should not instantiate this
    directly — the constructor binds plugin identity for trust-gate
    enforcement.
    N)policy_loadersync_callerasync_callerc               L    || _         |xs t        | _        || _        || _        y N)
_plugin_idrg   _policy_loader_sync_caller_async_caller)selfrB   r   r   r   s        r   __init__zPluginLlm.__init___  s)     $+D/D')r   )r1   r2   temperature
max_tokenstimeoutr3   profilepurposec                  | j                  | j                        }
t        |
||||      \  }}}}| j                  |||||||      \  }}}t	        |      }t        |      }t        ||||xs d|| j                  |	xs d|xs dd      }t        j                  d| j                  |||	xs d|j                         |S )a  Run a host-owned chat completion against the user's active model.

        ``messages`` is the standard OpenAI shape. ``provider``,
        ``model``, ``agent_id``, and ``profile`` follow the same
        explicit shape as the host's main config (``model.provider``
        + ``model.model``). Each is independently gated by
        ``plugins.entries.<id>.llm.allow_*_override`` (see module
        docstring).
        rl   rm   rn   ro   r   r   r   profile_overrider   r   r   r   r"   rB   r   r   r   r1   r2   r3   r6   r8   zGplugin_llm.complete plugin=%s provider=%s model=%s purpose=%s tokens=%d)
r   r   rs   _invoke_syncr   r   r0   r   infor*   )r   r   r1   r2   r   r   r   r3   r   r   rk   eff_provider	eff_model	eff_agenteff_profilereal_provider
real_modelr   r   r6   results                        r   completezPluginLlm.completen  s    , $$T__5:J'!'%;
7iK /3.?.?*$(#! /@ /
+z8 X&x(("+)!__"=b&,"
 	OO]J2		
 r   F)r   r   r   r   r1   r2   r   r   r   r3   r   r   c               f   |r|j                         st        d      |st        d      | j                  | j                        }t	        |||||      \  }}}}t        |t        |      ||||      }| j                  ||      }| j                  |||||	|
||      \  }}}t        |      }t        |      }t        |||      \  }}t        ||||xs d|||| j                  |xs d	|xs d	|xs d	d
      }t        j                  d| j                  |||xs d	||j                         |S )a?  Run a bounded host-owned structured completion.

        ``input`` accepts text and image blocks (see
        :class:`PluginLlmTextInput` / :class:`PluginLlmImageInput`). When
        ``json_mode=True`` or ``json_schema`` is provided, the response
        is parsed and (if a schema is given) validated; the parsed value
        is returned in :attr:`PluginLlmStructuredResult.parsed`.

        Validation requires the optional ``jsonschema`` package. When it
        isn't installed, JSON mode still works but schema enforcement is
        skipped with a debug log.
        z3complete_structured requires non-empty instructionsz5complete_structured requires at least one input blockr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   
extra_bodyr   r   r   r   r"   rB   r   r   r   r   r1   r2   r3   r6   r=   r>   r8   zbplugin_llm.complete_structured plugin=%s provider=%s model=%s purpose=%s content_type=%s tokens=%d)rM   rv   r   r   rs   r   rT   _json_response_formatr   r   r   r   r;   r   r   r*   )r   r   inputr   r   r   r   r1   r2   r   r   r   r3   r   r   rk   r   r   r   r   r   r   r   r   r   r   r6   r=   r>   r   s                                 r   complete_structuredzPluginLlm.complete_structured  s}   < <#5#5#7RSSTUU$$T__5:J'!'%;
7iK .%;##'
 //)Q\/]
.2.?.?*$(#!! /@ 	/
+z8 X&x(5 
 +"+)%!__"=b&,"*0b	
 	3OO]J2%,,		
 r   c               8  K   | j                  | j                        }
t        |
||||      \  }}}}| j                  |||||||       d{   \  }}}t	        |      }t        |      }t        ||||xs d|| j                  |	xs d|xs dd      S 7 Iw)z"Async sibling of :meth:`complete`.r   r   Nr   r"   r   r   )r   r   rs   _invoke_asyncr   r   r0   )r   r   r1   r2   r   r   r   r3   r   r   rk   r   r   r   r   r   r   r   r   r6   s                       r   	acompletezPluginLlm.acomplete	  s      $$T__5:J'!'%;
7iK 594F4F*$(#! 5G 5
 /
+z8 X&x(&"+)!__"=b&,"
 	
/
s   ABBA
Bc                 K   |r|j                         st        d      |st        d      | j                  | j                        }t	        |||||      \  }}}}t        |t        |      ||||      }| j                  ||      }| j                  |||||	|
||       d{   \  }}}t        |      }t        |      }t        |||      \  }}t        ||||xs d	|||| j                  |xs d
|xs d
|xs d
d      S 7 aw)z-Async sibling of :meth:`complete_structured`.z4acomplete_structured requires non-empty instructionsz6acomplete_structured requires at least one input blockr   r   r   r   Nr   r   r"   r   r   )rM   rv   r   r   rs   r   rT   r   r   r   r   r   r;   )r   r   r   r   r   r   r   r1   r2   r   r   r   r3   r   r   rk   r   r   r   r   r   r   r   r   r   r   r6   r=   r>   s                                r   acomplete_structuredzPluginLlm.acomplete_structured7  sX    & <#5#5#7STTUVV$$T__5:J'!'%;
7iK .%;##'
 //)Q\/]
484F4F*$(#!! 5G 	5
 	/
+z8 X&x(5 
 )"+)%!__"=b&,"*0b	
 	
	/
s   B$D
&D'A"D
c                .    |ddd|dddiS | rddd	iiS y)
zBuild the ``extra_body.response_format`` payload for the
        provider request. Falls back to ``json_object`` when no schema
        is given so providers that ignore json_schema still get a hint.Nresponse_formatr   plugin_structured_outputF)r   schemastrict)r   r   r   json_objectr   r   s     r   r   zPluginLlm._json_response_format  sE     "!) :"-"'$$	 	 %'>??r   )r   c                   | j                   | j                  ||||||||      S ddlm}	 t        |xs i       }
|r||
j	                  di       d<    |	d|||||||
xs d      }t        |||      \  }}|||fS )	zInvoke the host's ``call_llm``. Lazy-imports
        ``agent.auxiliary_client`` to avoid circular deps at plugin
        discovery time.Nr   r   )call_llmmetadataauth_profiletaskr1   r2   r   r   r   r   r   r   r   r   )r   r   r	  r9   
setdefaultr   )r   r   r   r   r   r   r   r   r   r	  merged_extrar   r1   r2   s                 r   r   zPluginLlm._invoke_sync  s     ($$!"3-!1'%% % 	 	 	4J,"-FVL##J3NC& #!#+t	
 //)
%
 ((r   c               (  K   | j                   !| j                  ||||||||       d {   S ddlm}	 t        |xs i       }
|r||
j	                  di       d<    |	d |||||||
xs d        d {   }t        |||      \  }}|||fS 7 b7 w)Nr   r   )async_call_llmr
  r  r  r  )r   r   r  r9   r  r   )r   r   r   r   r   r   r   r   r   r  r  r   r1   r2   s                 r   r   zPluginLlm._invoke_async  s      )++!"3-!1'%% , 	 	 	 	:J,"-FVL##J3NC'& #!#+t	
 	
 //)
%
 ((;		
s"   )BBAB3B4BB)
rB   r   r   z'Optional[Callable[[str], _TrustPolicy]]r   Optional[Callable[..., Any]]r   'Optional[Callable[..., Awaitable[Any]]]r   None)r   List[Dict[str, Any]]r1   r   r2   r   r   r-   r   Optional[int]r   r-   r3   r   r   r   r   r   r   r0   )r   r   r   Sequence[PluginLlmInput]r   r<   r   rC   r   r   r   r   r1   r   r2   r   r   r-   r   r  r   r-   r3   r   r   r   r   r   r   r;   )r   rC   r   r<   r   Optional[Dict[str, Any]])r   r  r   r   r   r   r   r   r   r-   r   r  r   r-   r   r  r   ztuple[str, str, Any])r   r   r   r   r   r   r   r   r  staticmethodr   r   r   r   r   r   r   r   V  s    BF48@D* * ?	*
 2* >* 
*& #'#'+$(#'"&!%!%;&;  	;
 ; %; "; !;  ; ; ; 
!;D &*%)'+"&#'+$(#'"&!%!%!Z Z (	Z
 #Z Z #Z %Z  Z Z %Z "Z !Z  Z Z  !Z" 
##ZD #'#'+$(#'"&!%!%,
&,
  	,

 ,
 %,
 ",
 !,
  ,
 ,
 ,
 
!,
f &*%)'+"&#'+$(#'"&!%!%!F
 F
 (	F

 #F
 F
 #F
 %F
  F
 F
 %F
 "F
 !F
  F
 F
  !F
" 
##F
T )6	! > 04-) '-) )	-)
 &-) (-) %-) "-) !-) --) 
-)r 04*) '*) )	*)
 &*) (*) %*) "*) !*) -*) 
*)r   r   )r   r   c                (    t        | fd||      S )zConstruct a :class:`PluginLlm` with an injected policy and caller.

    Used by unit tests that don't want to round-trip through config.yaml
    or hit a real provider. Not part of the public plugin API.
    c                    S r   r   )_pidrk   s    r   <lambda>z*make_plugin_llm_for_test.<locals>.<lambda>  s    6 r   )rB   r   r   r   )r   )rB   rk   r   r   s    `  r   make_plugin_llm_for_testr    s     )!	 r   )	r   r   r   PluginLlmInputr&   r0   r;   ri   r  )rO   r   r   r   )rO   r   r   z tuple[Optional[frozenset], bool])rB   r   r   rA   )rk   rA   rl   r   rm   r   rn   r   ro   r   r   zAtuple[Optional[str], Optional[str], Optional[str], Optional[str]])rw   r   r   r7   )r   r   r   r  r   rC   r   r<   r   r   r   r   r   r  )r   r   r   r   )r   r   r   rC   r   r<   r   ztuple[Optional[Any], str])r   r   r   r&   )r   r   r   r   )r   r   r   r   r   r   r   ztuple[str, str])
rB   r   rk   rA   r   r  r   r  r   r   )2r   
__future__r   r   r   loggingredataclassesr   r   typingr   r   r   r	   r
   r   r   r   	getLoggerr   r   r   r   r   r   r&   r0   r;   rA   rP   rZ   rg   PermissionErrorri   rs   rz   r   compileDOTALL
IGNORECASEr   r   r   r   r   r   r   r  __all__r   r   r   <module>r,     s  9v #    	 ( R R R			8	$        )+>S#XNO 	% 	% 	% 8 8 8 8 8 8. $) ) )'
"&,^G/ GLJLJ &LJ #	LJ
 &LJ %LJ GLJh"IJ>> %> 	>
 > > !> >L BJJ1299r}}3LM	!0=H8./$/ "/ 	/
 /nZ) Z)L 15<@  .	
 : (
r   