§
    ‰eîi¤  ã                  ój   — d Z ddlmZ ddlZddlZddlmZ  ej        e¦  «        Z	dd„Z
dd„Zdd„ZdS )u  Sanitize tool JSON schemas for broad LLM-backend compatibility.

Some local inference backends (notably llama.cpp's ``json-schema-to-grammar``
converter used to build GBNF tool-call parsers) are strict about what JSON
Schema shapes they accept. Schemas that OpenAI / Anthropic / most cloud
providers silently accept can make llama.cpp fail the entire request with:

    HTTP 400: Unable to generate parser for this template.
    Automatic parser generation failed: JSON schema conversion failed:
    Unrecognized schema: "object"

The failure modes we've seen in the wild:

* ``{"type": "object"}`` with no ``properties`` â€” rejected as a node the
  grammar generator can't constrain.
* A schema value that is the bare string ``"object"`` instead of a dict
  (malformed MCP server output, e.g. ``additionalProperties: "object"``).
* ``"type": ["string", "null"]`` array types â€” many converters only accept
  single-string ``type``.
* Unconstrained ``additionalProperties`` on objects with empty properties.

This module walks the final tool schema tree (after MCP-level normalization
and any per-tool dynamic rebuilds) and fixes the known-hostile constructs
in-place on a deep copy. It is intentionally conservative: it only modifies
shapes the LLM backend couldn't use anyway.
é    )ÚannotationsN)ÚAnyÚtoolsú
list[dict]Úreturnc                ó`   — | s| S g }| D ]$}|                      t          |¦  «        ¦  «         Œ%|S )uA  Return a copy of ``tools`` with each tool's parameter schema sanitized.

    Input is an OpenAI-format tool list:
    ``[{"type": "function", "function": {"name": ..., "parameters": {...}}}]``

    The returned list is a deep copy â€” callers can safely mutate it without
    affecting the original registry entries.
    )ÚappendÚ_sanitize_single_tool)r   Ú	sanitizedÚtools      ú8/home/div/.hermes/hermes-agent/tools/schema_sanitizer.pyÚsanitize_tool_schemasr   %   sK   € ð ð Øˆà€IØð 6ð 6ˆØ×ÒÕ.¨tÑ4Ô4Ñ5Ô5Ð5Ð5ØÐó    r   Údictc                óV  — t          j        | ¦  «        }t          |t          ¦  «        r|                     d¦  «        nd}t          |t          ¦  «        s|S |                     d¦  «        }t          |t          ¦  «        s
di dœ|d<   |S t          ||                     dd¦  «        ¬¦  «        |d<   |d         }t          |t          ¦  «        s	di dœ|d<   nO|                     d	¦  «        dk    rd|d	<   d
|vs(t          |                     d
¦  «        t          ¦  «        si |d
<   |S )z9Deep-copy and sanitize a single OpenAI-format tool entry.ÚfunctionNÚ
parametersÚobject©ÚtypeÚ
propertiesÚnamez<tool>)Úpathr   r   )ÚcopyÚdeepcopyÚ
isinstancer   ÚgetÚ_sanitize_node)r   ÚoutÚfnÚparamsÚtops        r   r
   r
   7   s0  € å
Œ-˜Ñ
Ô
€CÝ *¨3µÑ 5Ô 5Ð	?ˆ�Š�Ñ	Ô	Ð	¸4€BÝ�b�$ÑÔð Øˆ
à�VŠV�LÑ!Ô!€Få�f�dÑ#Ô#ð Ø$,¸BÐ?Ð?ˆˆ<ÑØˆ
å% f°2·6²6¸&À(Ñ3KÔ3KÐLÑLÔL€B€|Ñà
ˆ\Ô
€CÝ�c�4Ñ Ô ð #Ø$,¸BÐ?Ð?ˆˆ<ÑÐà�7Š7�6‰?Œ?˜hÒ&Ð&Ø"ˆC�‰KØ˜sÐ"Ð"­*°S·W²W¸\Ñ5JÔ5JÍDÑ*QÔ*QÐ"Ø "ˆC�ÑØ€Jr   Únoder   r   Ústrc                ó  ‡‡‡— t          | t          ¦  «        rQ| dv r,t                               d‰| | ¦  «         | dk    rd| indi dœS t                               d‰| ¦  «         di dœS t          | t          ¦  «        rˆfd„t          | ¦  «        D ¦   «         S t          | t          ¦  «        s| S i }|                      ¦   «         D �]Ì\  Š}‰dk    r�t          |t          ¦  «        rˆd„ |D ¦   «         }t          |¦  «        d	k    rAt          |d
         t          ¦  «        r&|d
         |d<   d|v r| 	                    dd¦  «         Œ�t          d„ |D ¦   «         d¦  «        }|r||d<   Œ£d|d<   Œ©‰dv r:t          |t          ¦  «        r%ˆˆfd„|                     ¦   «         D ¦   «         |‰<   Œç‰dv r6t          |t          ¦  «        r||‰<   �Œt          |‰› d‰› �¦  «        |‰<   �Œ!‰dv r6t          |t          ¦  «        r!ˆˆfd„t          |¦  «        D ¦   «         |‰<   �Œ[‰dv r7t          |t          t          f¦  «        rt          j        |¦  «        n||‰<   �Œ–t          |t          t          f¦  «        rt          |‰› d‰› �¦  «        n||‰<   �ŒÎ|                     d¦  «        dk    r-t          |                     d¦  «        t          ¦  «        si |d<   |                     d¦  «        dk    r—t          |                     d¦  «        t          ¦  «        ro|                     d¦  «        pi Šˆfd„|d         D ¦   «         }|s|                     dd¦  «         n+t          |¦  «        t          |d         ¦  «        k    r||d<   |S )a  Recursively sanitize a JSON-Schema fragment.

    - Replaces bare-string schema values ("object", "string", ...) with
      ``{"type": <value>}`` so downstream consumers see a dict.
    - Injects ``properties: {}`` into object-typed nodes missing it.
    - Normalizes ``type: [X, "null"]`` arrays to single ``type: X`` (keeping
      ``nullable: true`` as a hint).
    - Recurses into ``properties``, ``items``, ``additionalProperties``,
      ``anyOf``, ``oneOf``, ``allOf``, and ``$defs`` / ``definitions``.
    >   ÚnullÚarrayÚnumberr   ÚstringÚbooleanÚintegerzGschema_sanitizer[%s]: replacing bare-string schema %r with {'type': %r}r   r   r   zMschema_sanitizer[%s]: replacing non-schema string %r with empty object schemac           	     óB   •— g | ]\  }}t          |‰› d |› d�¦  «        ‘ŒS )Ú[Ú]©r   )Ú.0ÚiÚitemr   s      €r   ú
<listcomp>z"_sanitize_node.<locals>.<listcomp>r   s3   ø€ ÐTÐTÐT¹¸¸D•˜t¨ ^ ^¨q ^ ^ ^Ñ4Ô4ÐTÐTÐTr   c                ó   — g | ]
}|d k    ¯|‘ŒS )r&   © ©r0   Úts     r   r3   z"_sanitize_node.<locals>.<listcomp>}   s   € Ð8Ð8Ð8˜a¨A°ªK¨K˜¨K¨K¨Kr   é   r   r&   ÚnullableTc              3  óP   K  — | ]!}t          |t          ¦  «        ¯|d k    ¯|V — Œ"dS )r&   N©r   r$   r6   s     r   ú	<genexpr>z!_sanitize_node.<locals>.<genexpr>„   s5   è è € ÐUÐU Aµ*¸QÅÑ2DÔ2DÐUÈÈfÊÈ˜aÈÈÈÈÐUÐUr   N>   ú$defsr   Údefinitionsc                óH   •— i | ]\  }}|t          |‰› d ‰› d |› �¦  «        “ŒS )ú.r/   )r0   Úsub_kÚsub_vÚkeyr   s      €€r   ú
<dictcomp>z"_sanitize_node.<locals>.<dictcomp>�   sO   ø€ ð ð ð á �E˜5ð •~ e°Ð-DÐ-D°sÐ-DÐ-D¸UÐ-DÐ-DÑEÔEðð ð r   >   ÚitemsÚadditionalPropertiesr@   >   ÚallOfÚanyOfÚoneOfc                óH   •— g | ]\  }}t          |‰› d ‰› d|› d�¦  «        ‘ŒS )r@   r-   r.   r/   )r0   r1   r2   rC   r   s      €€r   r3   z"_sanitize_node.<locals>.<listcomp>š   sP   ø€ ð ð ð á�A�tõ ˜t¨Ð%9Ð%9¨sÐ%9Ð%9°QÐ%9Ð%9Ð%9Ñ:Ô:ðð ð r   >   ÚenumÚexamplesÚrequiredr   rM   c                óF   •— g | ]}t          |t          ¦  «        ¯|‰v ¯|‘ŒS r5   r;   )r0   ÚrÚpropss     €r   r3   z"_sanitize_node.<locals>.<listcomp>´   s-   ø€ ÐQÐQÐQ�q­z¸!½SÑ/AÔ/AÐQÀaÈ5ÀjÀj�ÀjÀjÀjr   )r   r$   ÚloggerÚdebugÚlistÚ	enumerater   rE   ÚlenÚ
setdefaultÚnextÚboolr   r   r   r   Úpop)	r#   r   r   ÚvalueÚnon_nullÚ	first_strÚvalidrC   rP   s	    `     @@r   r   r   Q   s(  øøø€ õ �$�ÑÔð 4ØÐXÐXÐXÝ�LŠLð$à�d˜Dñô ð ð
 &*¨XÒ%5Ð%5�F˜D�>�>Ø Ø ð<ð <ð õ 	�Šð'Ø(,¨dñ	
ô 	
ð 	
ð !°Ð3Ð3Ð3å�$�ÑÔð UØTÐTÐTÐTÅIÈdÁOÄOÐTÑTÔTÐTå�d�DÑ!Ô!ð Øˆà€CØ—j’j‘l”lð 0lñ 0l‰
ˆˆUð �&Š=ˆ=�Z¨­tÑ4Ô4ˆ=Ø8Ð8 5Ð8Ñ8Ô8ˆHÝ�8‰}Œ} Ò!Ð!¥j°¸!´½cÑ&BÔ&BÐ!Ø& qœk��F‘Ø˜U�?�?Ø—N’N :¨tÑ4Ô4Ð4ØåÐUÐU¨ÐUÑUÔUÐW[Ñ\Ô\ˆIØð Ø'��F‘Øà"ˆC�‰KØàÐ8Ð8Ð8½ZÈÍtÑ=TÔ=TÐ8ðð ð ð ð à$)§K¢K¡M¤Mðñ ô ˆC�‰HˆHð Ð5Ð5Ð5Ý˜%¥Ñ&Ô&ð Bð !��C‘‘å)¨%°D°°¸3°°ÑAÔA��C‘‘ØÐ/Ð/Ð/µJ¸uÅdÑ4KÔ4KÐ/ðð ð ð ð å(¨Ñ/Ô/ðñ ô ˆC�‰H‰Hð Ð4Ð4Ð4õ 0:¸%Å$ÍÀÑ/NÔ/NÐY•t”} UÑ+Ô+Ð+ÐTYˆC�‰H‰HåAKÈEÕTXÕZ^ÐS_ÑA`ÔA`Ðk•~ e°¨_¨_°s¨_¨_Ñ=Ô=Ð=ÐfkˆC�‰H‰Hð ‡w‚wˆv�„˜(Ò"Ð"­:°c·g²g¸lÑ6KÔ6KÍTÑ+RÔ+RÐ"ØˆˆLÑð
 ‡w‚wˆv�„˜(Ò"Ð"¥z°#·'²'¸*Ñ2EÔ2EÅtÑ'LÔ'LÐ"Ø—’˜Ñ%Ô%Ð+¨ˆØQÐQÐQÐQ˜C 
œOÐQÑQÔQˆØð 	$Ø�GŠG�J Ñ%Ô%Ð%Ð%Ý�‰ZŒZ�3˜s :œÑ/Ô/Ò/Ð/Ø#ˆC�
‰Oà€Jr   )r   r   r   r   )r   r   r   r   )r#   r   r   r$   r   r   )Ú__doc__Ú
__future__r   r   ÚloggingÚtypingr   Ú	getLoggerÚ__name__rQ   r   r
   r   r5   r   r   ú<module>rd      s¥   ððð ð6 #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø Ð Ð Ð Ð Ð à	ˆÔ	˜8Ñ	$Ô	$€ðð ð ð ð$ð ð ð ð4ið ið ið ið ið ir   