+
    Q(i/G                        ^ RI Ht ^ RIHt ^ RIHt ^ RIHtHt R R lt	R R lt
RR
 R lltR R ltR R ltRR R lltRR R lltR	# )    )annotations)defaultdict)Any)JsonRefErrorreplace_refsc                    V ^8  d   QhRRRR/# )   defsdict[str, Any]returnbool )formats   "c/Users/agent/.openclaw/workspace/venv/lib/python3.14/site-packages/fastmcp/utilities/json_schema.py__annotate__r   	   s     ,O ,ON ,Ot ,O    c                `  a aaaaaaa	 S '       g   R# \        \        4      oR VV3R lloS P                  4        F  w  rS! W!4       K  	  ^ ^^uooo\        \        4      o	R VVVVV VV	3R llo\        ;QJ d!    VVV	3R lS  4       F  '       g   K   R# 	  R# ! VVV	3R lS  4       4      # )u6  Check whether any definitions in ``$defs`` form a reference cycle.

A cycle means a definition directly or transitively references itself
(e.g. Node → children → Node, or A → B → A).  ``jsonref.replace_refs``
silently produces Python-level object cycles for these, which Pydantic's
serializer rejects.
Fc               $    V ^8  d   QhRRRRRR/# )r	   objr   sourcestrr   Noner   )r   s   "r   r   '_defs_have_cycles.<locals>.__annotate__   s!     	, 	,3 	, 	, 	,r   c                  < \        V \        4      '       d   V P                  R 4      p\        V\        4      '       dF   VP	                  R4      '       d/   SV,          P                  VP                  R4      R,          4       V P                  4        F  pS! W14       K  	  R# \        V \        4      '       d   V  F  pS! WA4       K  	  R# R# )$ref#/$defs//N)	
isinstancedictgetr   
startswithaddsplitvalueslist)r   r   refvitem_collect_refsedgess   &&   r   r*   (_defs_have_cycles.<locals>._collect_refs   s    c4  ''&/C#s##z(B(Bf!!#))C."45ZZ\a( "T""d+  #r   c                    V ^8  d   QhRRRR/# )r	   noder   r   r   r   )r   s   "r   r   r   )   s     
 
 
 
r   c                   < SSV &   SP                  V R4       F>  pVS9  d   K  SV,          S8X  d    R # SV,          S8X  g   K-  S! V4      '       g   K=   R # 	  SSV &   R# )TFr   )r!   )	r.   neighborDONEIN_STACK	UNVISITED
_has_cycler
   r+   states	   & r   r4   %_defs_have_cycles.<locals>._has_cycle)   sb    d		$+Ht#X(*X)+
80D0D , dr   c              3  \   <"   T F!  pSV,          S8H  ;'       d	    S! V4      x  K#  	  R # 5iNr   ).0namer3   r4   r5   s   & r   	<genexpr>$_defs_have_cycles.<locals>.<genexpr>5   s*     NuT{i'<<Jt,<<s   ,,T)r   setitemsintany)
r
   r:   
definitionr1   r2   r3   r*   r4   r+   r5   s
   f  @@@@@@@r   _defs_have_cyclesrB   	   s      "-S!1E	, 	, !JJLj' ) !"1aIx',E
 
 3NN33N3N3NNNNr   c                    V ^8  d   QhRRRR/# r	   schemar   r   r   )r   s   "r   r   r   8   s     ;( ;(^ ;( ;(r   c                   \        V P                  R/ 4      4      '       d   \        V 4      #  \        V RRR7      pV P                  R/ 4      p\	        WV4      p\        V\        4      '       g   Q hTpRV9   d-   VP                  4        UUu/ uF  w  rEVR8w  g   K  WEbK  	  pppV# u uppi   \         d    \        T 4      u # i ; i)aY  Resolve all $ref references in a JSON schema by inlining definitions.

This function resolves $ref references that point to $defs, replacing them
with the actual definition content while preserving sibling keywords (like
description, default, examples) that Pydantic places alongside $ref.

This is necessary because some MCP clients (e.g., VS Code Copilot) don't
properly handle $ref in tool input schemas.

For self-referencing/circular schemas where full dereferencing is not possible,
this function falls back to resolving only the root-level $ref while preserving
$defs for nested references.

Args:
    schema: JSON schema dict that may contain $ref references

Returns:
    A new schema dict with $ref resolved where possible and $defs removed
    when no longer needed

Example:
    >>> schema = {
    ...     "$defs": {"Category": {"enum": ["a", "b"], "type": "string"}},
    ...     "properties": {"cat": {"$ref": "#/$defs/Category", "default": "a"}}
    ... }
    >>> resolved = dereference_refs(schema)
    >>> # Result: {"properties": {"cat": {"enum": ["a", "b"], "type": "string", "default": "a"}}}
$defsF)proxies	lazy_load)	rB   r!   resolve_root_refr   _merge_ref_siblingsr   r    r>   r   )rE   dereferencedr
   mergedkr(   s   &     r   dereference_refsrO   8   s    B GR011''( $FEUK zz'2&$V4@&$'''' l"-9-?-?-AR-ATQQ'\DAD-ALR S  (  ''(s*   A B/ B)B)$B/ )B/ /CCNc          
     ,    V ^8  d   QhRRRRRRRRRR/# )	r	   originalr   rL   r
   r   visitedset[str] | Noner   r   )r   s   "r   r   r   v   sA     @ @@@ @ 	@
 	@r   c           
        Vf   \        4       p\        V \        4      '       Ed%   \        V\        4      '       Ed   RV 9   d   V R,          pV P                  4        UUu/ uF  w  rVVR9  g   K  WVbK  	  ppp\        V\        4      '       dV   VP                  R4      '       d?   VP                  R4      R,          pW9   d!   W9  d   \        W(,          WW80,          4      pV'       d   \        V4      p	V	P                  V4       V	# V# / p
VP                  4        F&  w  rW9   d   \        W,          WV4      W&   K"  WV&   K(  	  V
# \        V \        4      '       dp   \        V\        4      '       dZ   \        \        V 4      \        V4      4      p\        V RV VRV RR7       UUu. uF  w  r\        WW#4      NK  	  uppWR ,           # V# u uppi u uppi )	a  Merge sibling keywords from original $ref nodes into dereferenced schema.

When jsonref resolves $ref, it replaces the entire node with the referenced
definition, losing any sibling keywords like description, default, or examples.
This function walks both trees in parallel and merges those siblings back.

Args:
    original: The original schema with $ref and potential siblings
    dereferenced: The schema after jsonref processing
    defs: The $defs from the original schema, for looking up referenced definitions
    visited: Set of definition names already being processed (prevents cycles)

Returns:
    The dereferenced schema with sibling keywords restored
Nr   r   r   F)strict)r   rG   r   )r=   r   r    r>   r   r"   r$   rK   updater&   minlenzip)rQ   rL   r
   rR   r'   rN   r(   siblingsdef_namerM   resultkeyvaluemin_lenods   &&&&            r   rK   rK   v   s   * %(D!!jt&D&DX6"C)1)9X)9QFW=W)9HX #s##z(B(B99S>"-#(?#6Gj<P$L l+h' &,,.JC1(-gV#s	 /
 	Hd	#	#
<(F(Fc(mS%67 HXg.Xg0FuU
U  d4U
 "# 	#
 I Y>
s    G0G+Gc                    V ^8  d   QhRRRR/# rD   r   )r   s   "r   r   r      s     $ $^ $ $r   c                   RV 9   d   RV 9   d|   RV 9  du   V R,          p\        V\        4      '       dV   VP                  R4      '       d?   VP                  R4      R,          pV R,          pW#9   d   \	        W2,          4      pW4R&   V# V # )a;  Resolve $ref at root level to meet MCP spec requirements.

MCP specification requires outputSchema to have "type": "object" at the root level.
When Pydantic generates schemas for self-referential models, it uses $ref at the
root level pointing to $defs. This function resolves such references by inlining
the referenced definition while preserving $defs for nested references.

Args:
    schema: JSON schema dict that may have $ref at root level

Returns:
    A new schema dict with root-level $ref resolved, or the original schema
    if no resolution is needed

Example:
    >>> schema = {
    ...     "$defs": {"Node": {"type": "object", "properties": {...}}},
    ...     "$ref": "#/$defs/Node"
    ... }
    >>> resolved = resolve_root_ref(schema)
    >>> # Result: {"type": "object", "properties": {...}, "$defs": {...}}
r   rG   typer   r   r   )r   r   r"   r$   r    )rE   r'   r[   r
   resolveds   &    r   rJ   rJ      s}    0 Gv-&2FVnc3CNN:$>$>yy~b)H'?D/$(!Mr   c               $    V ^8  d   QhRRRRRR/# )r	   rE   r   paramr   r   r   )r   s   "r   r   r      s!         r   c                    V P                  R/ 4      pVP                  VR4      pVf   V # W R&   WP                  R. 4      9   d9   V R,          P                  V4       V R,          '       g   V P                  R4       V # )zoReturn a new schema with *param* removed from `properties`, `required`,
and (if no longer referenced) `$defs`.

propertiesNrequired)r!   popremove)rE   rg   propsremoveds   &&  r   _prune_paramro      sx     JJ|R(Eiit$G !<

:r**z!!%(j!!JJz"Mr   c          
     ,    V ^8  d   QhRRRRRRRRRR/# )r	   rE   r   prune_titlesr   prune_additional_properties
prune_defsr   r   )r   s   "r   r   r      sA     j jjj "&j 	j
 jr   c                  aaaaaa	a
 S'       g   S'       g   S'       g   V # \        4       o	\        \        4      oV P                  R4      pR
R VVVVV	V
3R lllo
S
! V RR7       S'       d   V'       d   VP	                  4        F  w  rVS
! WeR7       K  	  RR VVV	3R	 lllo\        VP                  4       4       F$  pS! V4      '       d   K  VP                  V4       K&  	  V'       g   V P                  RR4       V # )a  
Optimize JSON schemas in a single traversal for better performance.

This function combines three schema cleanup operations that would normally require
separate tree traversals:

1. **Remove unused definitions** (prune_defs): Finds and removes `$defs` entries
   that aren't referenced anywhere in the schema, reducing schema size.

2. **Remove titles** (prune_titles): Strips `title` fields throughout the schema
   to reduce verbosity while preserving functional information.

3. **Remove restrictive additionalProperties** (prune_additional_properties):
   Removes `"additionalProperties": false` constraints to make schemas more flexible.

**Performance Benefits:**
- Single tree traversal instead of multiple passes (2-3x faster)
- Immutable design prevents shared reference bugs
- Early termination prevents runaway recursion on deeply nested schemas

**Algorithm Overview:**
1. Traverse main schema, collecting $ref references and applying cleanups
2. Traverse $defs section to map inter-definition dependencies
3. Remove unused definitions based on reference analysis

Args:
    schema: JSON schema dict to optimize (not modified)
    prune_titles: Remove title fields for cleaner output
    prune_additional_properties: Remove "additionalProperties": false constraints
    prune_defs: Remove unused $defs entries to reduce size

Returns:
    A new optimized schema dict

Example:
    >>> schema = {
    ...     "type": "object",
    ...     "title": "MySchema",
    ...     "additionalProperties": False,
    ...     "$defs": {"UnusedDef": {"type": "string"}}
    ... }
    >>> result = _single_pass_optimize(schema, prune_titles=True, prune_defs=True)
    >>> # Result: {"type": "object", "additionalProperties": False}
rG   Nc          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )r	   r.   objectcurrent_def_namez
str | Noneskip_defs_sectionr   depthr?   r   r   r   )r   s   "r   r   +_single_pass_optimize.<locals>.__annotate__2  sH     @L @L@L$@L  @L 	@L
 
@Lr   c                  <a  V^28  d   R# \        S \        4      '       Ed   S'       d   S P                  R4      p\        V\        4      '       db   VP	                  R4      '       dK   VP                  R4      R,          pV'       d   S	V,          P                  V4       MSP                  V4       S'       dY   RS 9   dR   \        ;QJ d    V 3R lR 4       F  '       g   K   RM	  RM! V 3R lR 4       4      '       d   S P                  R4       S
'       d'   S P                  R	4      RJ d   S P                  R	4       S P                  4        F`  w  rgV'       d
   VR
8X  d   K  VR9   d3   \        V\        4      '       d   V F  pS! WV^,           R7       K  	  KO  S! WqV^,           R7       Kb  	  R# \        S \        4      '       d   S  F  pS! WV^,           R7       K  	  R# R# )zATraverse schema tree, collecting $ref info and applying cleanups.Nr   r   r   titlec              3  .   <"   T F
  pVS9   x  K  	  R # 5ir8   r   )r9   rN   r.   s   & r   r;   D_single_pass_optimize.<locals>.traverse_and_clean.<locals>.<genexpr>O  s       	 I	s   TFadditionalPropertiesrG   )ry   r   )rd   ri   r   r>   allOfoneOfanyOfrj   )r   r   r   )r   r    r!   r   r"   r$   appendr#   r@   rk   r>   r&   )r.   rw   rx   ry   r'   referenced_defr]   r^   r)   def_dependenciesrr   rs   rq   	root_refstraverse_and_cleans   f&&&     r   r   1_single_pass_optimize.<locals>.traverse_and_clean2  s{    2:dD!!hhv&c3''CNN:,F,F%(YYs^B%7N'(8??@PQ "n5 43 	333 	   HHW% ,HH34=/0 #jjl
$ 55*UD:Q:Q %*4QRS !& 'ueaiP + d##"4K  $r   T)rx   )rw   c               $    V ^8  d   QhRRRRRR/# )r	   r[   r   visitingrS   r   r   r   )r   s   "r   r   rz   }  s!     	 	# 	 	D 	r   c                   < V S9   d   R# SP                  V . 4      pV'       dB   Vf   \        4       pW9   d   R# W0,          pV F  pW19  g   K  S! W14      '       g   K   R# 	  R# )z<Check if a definition is used, handling circular references.TF)r!   r=   )r[   r   referencing_defsreferencing_defr   is_def_usedr   s   &&  r   r   *_single_pass_optimize.<locals>.is_def_used}  ss    9$  033HbA#"uH ' #j0 (8O&6;'< <  $	 (8 r   )NFr   r8   )r=   r   r&   r!   r>   keysrk   )rE   rq   rr   rs   r
   r[   
def_schemar   r   r   r   s   &fff   @@@@r   _single_pass_optimizer      s    d ,*E %I4?5 ::gD@L @LF v6 d$(JJL HzE %1	 	4 TYY[)Hx((" *
 JJw%Mr   c               0    V ^8  d   QhRRRRRRRRRRR	R/# )
r	   rE   r   prune_paramszlist[str] | Nonerr   r   rq   dereferencer   r   )r   s   "r   r   r     sD     ( (("( "&( 	(
 ( (r   c                    V'       d   \        V 4      p \        V 4      p T;'       g    .  F  p\        WR7      p K  	  \        V VVRR7      p V # )a  
Compress and optimize a JSON schema for MCP compatibility.

Args:
    schema: The schema to compress
    prune_params: List of parameter names to remove from properties
    prune_additional_properties: Whether to remove additionalProperties: false.
        Defaults to False to maintain MCP client compatibility, as some clients
        (e.g., Claude) require additionalProperties: false for strict validation.
    prune_titles: Whether to remove title fields from the schema
    dereference: Whether to dereference $ref by inlining definitions.
        Defaults to False; dereferencing is typically handled by
        middleware at serve-time instead.
)rg   T)rq   rr   rs   )rO   rJ   ro   r   )rE   r   rr   rq   r   rg   s   &&&&& r   compress_schemar     s]    * !&) f%F ###f2 $
 #!$?	F Mr   r8   )FFT)NFFF)
__future__r   collectionsr   typingr   jsonrefr   r   rB   rO   rK   rJ   ro   r   r   r   r   r   <module>r      sA    " #  .,O^;(|@F$N*jZ( (r   