
    {h$R                        d dl Z d dlZd dlmZmZmZ d dlmZ d dlm	Z	 d dl
mZmZmZmZmZmZmZ d dlZd dlmZmZmZmZmZmZ d dlmZ d dlmZ d d	lmZm 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)m*Z*  e%e+      Z, G d de      Z- G d de      Z. G d de      Z/	 	 d,dedef   dee0   de1dz  de/fdZ2dede0dede3e4e   dz  e5e0ef   dz  e1f   fdZ6de4e   de4e   fd Z7d!e4e   de4e   fd"Z8de0dedede4e   fd#Z9de0d$ede4e   fd%Z:ded&e5e0ef   defd'Z;d(edef   de jx                  fd)Z=d*edee)   fd+Z>y)-    N)	AwaitableCallableSequence)chain)GenericAlias)	AnnotatedAny
ForwardRefcastget_args
get_originget_type_hints)	BaseModel
ConfigDictField	RootModelWithJsonSchemacreate_model)eval_type_backport)	FieldInfo)GenerateJsonSchemaJsonSchemaWarningKind)PydanticUndefined)InvalidSignature)
get_logger)Image)ContentBlockTextContentc                   $    e Zd ZdZdededdfdZy)StrictJsonSchemazA JSON schema generator that raises exceptions instead of emitting warnings.

    This is used to detect non-serializable types during schema generation.
    kinddetailreturnNc                 $    t        d| d|       )NzJSON schema warning: z - )
ValueError)selfr!   r"   s      k/var/www/html/hubwallet-dev/venv/lib/python3.12/site-packages/mcp/server/fastmcp/utilities/func_metadata.pyemit_warningzStrictJsonSchema.emit_warning$   s    0c&BCC    )__name__
__module____qualname____doc__r   strr(    r)   r'   r    r       s&    
D!6 D D Dr)   r    c                   8    e Zd ZdZdeeef   fdZ ed      Z	y)ArgModelBasez1A model representing the arguments to a function.r#   c                     i }| j                   j                  j                         D ]0  \  }}t        | |      }|j                  r|j                  n|}|||<   2 |S )zReturn a dict of the model's fields, one level deep.

        That is, sub-models etc are not dumped - they are kept as pydantic models.
        )	__class__model_fieldsitemsgetattralias)r&   kwargs
field_name
field_infovalueoutput_names         r'   model_dump_one_levelz!ArgModelBase.model_dump_one_level,   sb    
 "$&*nn&A&A&G&G&I 	("J
D*-E.8.>.>***JK"'F;		(
 r)   Tarbitrary_types_allowedN)
r*   r+   r,   r-   dictr.   r	   r=   r   model_configr/   r)   r'   r1   r1   )   s(    ;d38n   $Lr)   r1   c            
       "   e Zd ZU eee    ed      f   ed<   dZe	e
ef   dz  ed<   dZeee    ed      f   dz  ed<   dZeed<   dedeee   z  f   d	ed
e	e
ef   de	e
ef   dz  def
dZdedefdZde	e
ef   de	e
ef   fdZ ed      Zy)FuncMetadataN	arg_modeloutput_schemaoutput_modelFwrap_outputfn.fn_is_asyncarguments_to_validatearguments_to_pass_directlyr#   c                    K   | j                  |      }| j                  j                  |      }|j                         }||xs i z  }|r |di | d{   S  |di |S 7 w)zCall the given function with arguments validated and injected.

        Arguments are first attempted to be parsed from JSON, then validated against
        the argument model, before being passed to the function.
        Nr/   )pre_parse_jsonrD   model_validater=   )r&   rH   rI   rJ   rK   arguments_pre_parsedarguments_parsed_modelarguments_parsed_dicts           r'   call_fn_with_arg_validationz(FuncMetadata.call_fn_with_arg_validationD   sy       $223HI!%!>!>?S!T 6 K K M!;!ArA43444.-.. 5s   AA$A"A$resultc                     t        |      }| j                  |S | j                  rd|i}| j                  J d       | j                  j	                  |      }|j                  dd      }||fS )aB  
        Convert the result of a function call to the appropriate format for
         the lowlevel server tool call handler:

        - If output_model is None, return the unstructured content directly.
        - If output_model is not None, convert the result to structured output format
            (dict[str, Any]) and return both unstructured and structured content.

        Note: we return unstructured content here **even though the lowlevel server
        tool call handler provides generic backwards compatibility serialization of
        structured content**. This is for FastMCP backwards compatibility: we need to
        retain FastMCP's ad hoc conversion logic for constructing unstructured output
        from function return values, whereas the lowlevel server simply serializes
        the structured output.
        rS   z4Output model must be set if output schema is definedjsonT)modeby_alias)_convert_to_contentrE   rG   rF   rN   
model_dump)r&   rS   unstructured_content	validatedstructured_contents        r'   convert_resultzFuncMetadata.convert_result[   s       36:%''"F+$$0h2hh0))88@I!*!5!56D!5!Q(*<==r)   datac                 B   |j                         }i }| j                  j                  j                         D ]&  \  }}|||<   |j                  s|||j                  <   ( |j                         D ]p  }||vr||   }t        ||   t              s!|j                  t        us4	 t        j                  ||         }t        |t        t        z  t        z        rl|||<   r |j                         |j                         k(  sJ |S # t        j                  $ r Y w xY w)a  Pre-parse data from JSON.

        Return a dict with same keys as input but with values parsed from JSON
        if appropriate.

        This is to handle cases like `["a", "b", "c"]` being passed in as JSON inside
        a string rather than an actual list. Claude desktop is prone to this - in fact
        it seems incapable of NOT doing this. For sub-models, it tends to pass
        dicts (JSON objects) as JSON strings, which can be pre-parsed here.
        )copyrD   r4   r5   r7   keys
isinstancer.   
annotationrU   loadsJSONDecodeErrorintfloat)r&   r^   new_datakey_to_field_infor9   r:   data_key
pre_parseds           r'   rM   zFuncMetadata.pre_parse_jsony   s$    99; 35&*nn&A&A&G&G&I 	A"J
,6j)6@!*"2"23		A 		 	0H00*84J$x.#.:3H3HPS3S!%DN!;J j#)e*;< %/"	0  }}$))+--- ++ s   %DDDTr>   )r*   r+   r,   r   typer1   r   __annotations__rE   r@   r.   r	   rF   r   rG   boolr   r   rR   r]   rM   r   rA   r/   r)   r'   rC   rC   >   s   l+^D-AABB+/M4S>D(/LPL)DO^D-AABTIPK/S#	#..// /  $CH~	/
 %)cNT$9/ 
/.>S >S ><&4S> &d38n &P  $Lr)   rC   func.
skip_namesstructured_outputr#   c           	      P   t        |       }|j                  }i }t        | di       }|j                         D ]  }|j                  j                  d      r&t        d|j                   d| j                   d      |j                  |v rT|j                  }|Kt        dt        |j                  t        j                  j                  ur|j                  nt              f   }|t        j                  j                  u r.t        t         t               t#        |j                  dd	      f   }t%        j&                  t)        ||      |j                  t        j                  j                  ur|j                  nt              }	t+        t,        |j                        rwt/        t        t,        |j                              rT|j                  |	_        |j                  |	_        |j                  |	_        d
|j                   }
|	j                  |	f||
<   n|	j                  |	f||j                  <    t7        | j                   dfi |dt8        i}|du rt;        |      S |j<                  t        j                  j                  u r|du rt        d| j                   d      t%        j>                  t)        |j<                  |            }|j                  }tA        || j                  |      \  }}}| |du rt        d| j                   d| d      t;        ||||      S )a  Given a function, return metadata including a pydantic model representing its
    signature.

    The use case for this is
    ```
    meta = func_metadata(func)
    validated_args = meta.arg_model.model_validate(some_raw_data_dict)
    return func(**validated_args.model_dump_one_level())
    ```

    **critically** it also provides pre-parse helper to attempt to parse things from
    JSON.

    Args:
        func: The function to convert to a pydantic model
        skip_names: A list of parameter names to skip. These will not be included in
            the model.
        structured_output: Controls whether the tool's output is structured or unstructured
            - If None, auto-detects based on the function's return type annotation
            - If True, unconditionally creates a structured tool (return type annotation permitting)
            - If False, unconditionally creates an unstructured tool

        If structured, creates a Pydantic model for the function's result based on its annotation.
        Supports various return types:
            - BaseModel subclasses (used directly)
            - Primitive types (str, int, float, bool, bytes, None) - wrapped in a
                model with a 'result' field
            - TypedDict - converted to a Pydantic model with same fields
            - Dataclasses and other annotated classes - converted to Pydantic models
            - Generic types (list, dict, Union, etc.) - wrapped in a model with a 'result' field

    Returns:
        A FuncMetadata object containing:
        - arg_model: A pydantic model representing the function's arguments
        - output_model: A pydantic model for the return type if output is structured
        - output_conversion: Records how function output should be converted before returning.
    __globals___z
Parameter z of z cannot start with '_'N)defaultstring)titlerl   field_	Arguments__base__F)rD   Tz	Function z2: return annotation required for structured outputz: return type z* is not serializable for structured output)rD   rE   rF   rG   )!_get_typed_signature
parametersr6   valuesname
startswithr   r*   rc   r   r   ru   inspect	Parameteremptyr   r	   r   r   from_annotated_attribute_get_typed_annotationhasattrr   callabler7   validation_aliasserialization_aliasr   r1   rC   return_annotationfrom_annotation_try_create_model_and_schema)ro   rp   rq   sigparamsdynamic_pydantic_model_paramsglobalnsparamrc   r:   internal_namearguments_modeloutput_inforF   rE   rG   s                   r'   func_metadatar      s   T t
$C^^F46!t]B/H (::  %"Z

|4Nd#eff::#%%
 "u}}GDUDUD[D[/[emmarsuJ **000"XFGIJ 77!*h7"]]'2C2C2I2IIEMMO`

 9ejj)hwy%**7U.V$zzJ*/**J'-2ZZJ*$UZZL1M<F<Q<QS];^)-89C9N9NPZ8[)%**5Q(T #==/#
' O E!o66  1 1 7 77<MQU<U4==/9klmm++,A#BWBWYa,bcK''J/KJX\XeXegr/s,L- 1T 9nZL@jk
 	
 !#!	 r)   rc   	func_namer:   c                    d}d}| t        || |      }d}n5t        | t              rdt        |       }|t        u rAt        |       }t        |      dk(  r|d   t        u rt        ||       }nt        || |      }d}nt        || |      }d}nt        | t              rt        t        t           |       }t        | t              r| }nt        |d      rt        | t              rt        |      }n_| t        t         t"        t$        t&        t        d      fv rt        || |      }d}n(t)        |      }|rt+        |      }nt        || |      }d}|r	 |j-                  t.              }	||	|fS y# t0        t2        t4        j6                  t4        j8                  f$ r>}
t:        j=                  d|  d	| d
t        |
      j>                   d
|
        Y d}
~
yd}
~
ww xY w)a4  Try to create a model and schema for the given annotation without warnings.

    Returns:
        tuple of (model or None, schema or None, wrap_output)
        Model and schema are None if warnings occur or creation fails.
        wrap_output is True if the result needs to be wrapped in {"result": ...}
    NFT   r   rm   )schema_generatorzCannot create schema for type z in z: )NNF) _create_wrapped_modelrb   r   r   r@   r   lenr.   _create_dict_modelrl   r   r	   
issubclassr   r   _create_model_from_typeddictrf   rg   rn   bytesr   _create_model_from_classmodel_json_schemar    	TypeErrorr%   pydantic_coreSchemaErrorValidationErrorloggerinfor*   )rc   r   r:   modelrG   originargstype_annotation
type_hintsschemaes              r'   r   r     s    EK %iZH 
J	-J' T>J'D4yA~$q'S.*9jA .iZP" *)ZLEK 
J	%%)$s)Z%@ j),E _&78Z
TX=Y0AE CeT5$t*EE))ZLEK (8J0A &iZH		%,,>N,OF fk)) :}'@'@-B_B_` 	% KK8DSUVZ[\V]VfVfUggijkilmn$	%s   E, ,-G4GGclsc                 2   t        |       }i }|j                         D ]O  \  }}|j                  d      rt        | |t              }t        j                  ||      }|j                  |f||<   Q  G d dt              }t        | j                  fi |d|iS )aj  Create a Pydantic model from an ordinary class.

    The created model will:
    - Have the same name as the class
    - Have fields with the same names and types as the class's fields
    - Include all fields whose type does not include None in the set of required fields

    Precondition: cls must have type hints (i.e., get_type_hints(cls) is non-empty)
    rt   c                       e Zd Z ed      Zy)0_create_model_from_class.<locals>.BaseWithConfigT)from_attributesN)r*   r+   r,   r   rA   r/   r)   r'   BaseWithConfigr     s    !$7r)   r   rz   )r   r5   r   r6   r   r   r   rc   r   r   r*   )r   r   r4   r9   
field_typeru   r:   r   s           r'   r   r   v  s      $J#%L","2"2"4 G
J  %#z+<=77
GL
$.$9$9:#FZ G8 8 NN~NNr)   td_typec                 2   t        |       }t        | dt        |j                                     }i }|j	                         D ]6  \  }}t        j                  |      }||vrd|_        |j                  |f||<   8 t        | j                  fi |dt        iS )zzCreate a Pydantic model from a TypedDict.

    The created model will have the same name and fields as the TypedDict.
    __required_keys__Nrz   )r   r6   setra   r5   r   r   ru   rc   r   r*   r   )r   r   required_keysr4   r9   r   r:   s          r'   r   r     s    
  (JG%8#joo>O:PQM#%L","2"2"4 	G
J..z:
]* "&J$.$9$9:#FZ 	G ((MLM9MMr)   c                 N    |  d}|t        d      }t        |||ft              S )zCreate a model that wraps a type in a 'result' field.

    This is used for primitive types, generic types like list/dict, etc.
    OutputN)rS   rz   )rl   r   r   )r   rc   r:   
model_names       r'   r   r     s5    
 ;f%J $Z

J
+CiXXr)   dict_annotationc                 R     G d dt         |         }|  d|_        |  d|_        |S )z*Create a RootModel for dict[str, T] types.c                       e Zd Zy)%_create_dict_model.<locals>.DictModelN)r*   r+   r,   r/   r)   r'   	DictModelr     s    r)   r   
DictOutput)r   r*   r,   )r   r   r   s      r'   r   r     s9    Io.  &;j1I ){*5Ir)   r   c           
          dt         dt        t        t         f   dt        t        t         f   dt        t         t        f   fd}t        | t              r*t        |       }  || ||      \  } }|du rt        d|        | S )Nr;   r   localnsr#   c                 H    	 t        | ||      dfS # t        $ r | dfcY S w xY w)NTF)r   	NameError)r;   r   r   s      r'   try_eval_typez,_get_typed_annotation.<locals>.try_eval_type  s4    	 %eXw?EE 	 %<	 s    !!Fz#Unable to evaluate type annotation )r	   r@   r.   tuplern   rb   r
   r   )rc   r   r   statuss       r'   r   r     s     S  DcN  T#s(^  X]^acg^gXh   *c"
+
*:xJ
F U?"%H#UVVr)   callc                    t        j                  |       }t        | di       }|j                  j	                         D cg c]M  }t        j
                  |j                  |j                  |j                  t        |j                  |            O }}t        |j                  |      }t        j                  ||      }|S c c}w )z:Get function signature while evaluating forward referencesrs   )r~   r!   ru   rc   )r   )r   	signaturer6   r|   r}   r   r~   r!   ru   r   rc   r   	Signature)r   r   r   r   typed_paramstyped_returntyped_signatures          r'   r{   r{     s    !!$'It]B/H ))002  	MM,U-=-=xH		
L  ))D)DhOL''UOs   ACrS   c                 z   | g S t        | t              r| gS t        | t              r| j                         gS t        | t        t
        z        r%t	        t        j                  d | D                    S t        | t              s*t        j                  | t        d      j                         } t        d|       gS )aY  
    Convert a result to a sequence of content objects.

    Note: This conversion logic comes from previous versions of FastMCP and is being
    retained for purposes of backwards compatibility. It produces different unstructured
    output than the lowlevel server tool call handler, which just serializes structured
    content verbatim.
    c              3   2   K   | ]  }t        |        y w)N)rX   ).0items     r'   	<genexpr>z&_convert_to_content.<locals>.<genexpr>  s        $D) s   r   )fallbackindenttext)rl   r   )rb   r   r   to_image_contentlistr   r   from_iterabler.   r   to_jsondecoder   )rS   s    r'   rX   rX     s     ~	&,'x&% '')**&$,'  "  
 	
 fc"&&vAFMMOV&122r)   )r/   N)?r   rU   collections.abcr   r   r   	itertoolsr   typesr   typingr   r	   r
   r   r   r   r   r   pydanticr   r   r   r   r   r    pydantic._internal._typing_extrar   pydantic.fieldsr   pydantic.json_schemar   r   r   mcp.server.fastmcp.exceptionsr   $mcp.server.fastmcp.utilities.loggingr   "mcp.server.fastmcp.utilities.typesr   	mcp.typesr   r   r*   r   r    r1   rC   r.   rn   r   r   rl   r@   r   r   r   r   r   r   r   r{   rX   r/   r)   r'   <module>r      s     9 9   Y Y Y   @ % J + : ; 4 /	H	D) D9 *e9 eT !#%)v
38
vv d{v 	vrTT #T1:T
4	?T!4S>D#8$>?TnO$s) OY O8N$s) NY N.YS Yc Yy YUYZcUd Y
# 
 
Y 
c T#s(^  &xS1 g6G6G $33l3r)   