
    id              
         d Z ddlmZ ddlZddlZddlmZmZ ddlm	Z	 ddl
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mZ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$ 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. ddl/m0Z0 ddl1m2Z2 ddl3m4Z4 ddl5m6Z6 ddl7m8Z8  e6e9      Z:erddl;m<Z<  e&d      Z=ed   Z>e	 G d dee=                Z?e	 G d d             Z@	 	 	 	 d)dZAd*dZB	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d+dZC	 	 d,	 	 	 	 	 	 	 	 	 d-dZD	 	 	 	 d.d ZE	 	 	 	 d/d!ZF	 	 	 	 d0d"ZGd1d#ZHddddddd$ddd%		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d2d&ZIddddddddd'	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d3d(ZJy)4z8Sampling types and helper functions for FastMCP servers.    )annotationsN)CallableSequence)	dataclass)TYPE_CHECKINGAnyGenericLiteralcast)ClientCapabilitiesCreateMessageResultCreateMessageResultWithTools	ModelHintModelPreferencesSamplingCapabilitySamplingMessageSamplingMessageContentBlockSamplingToolsCapabilityTextContent
ToolChoiceToolResultContentToolUseContent)CreateMessageRequestParams)Tool)ValidationError)TypeVar)settings)	ToolError)SamplingTool)FunctionTool)TransformedTool)gather)compress_schema)
get_logger)get_cached_typeadapter)ContextResultTautorequirednonec                  0    e Zd ZU dZded<   ded<   ded<   y)	SamplingResulta  Result of a sampling operation.

    Attributes:
        text: The text representation of the result (raw text or JSON for structured).
        result: The typed result (str for text, parsed object for structured output).
        history: All messages exchanged during sampling.
    
str | Nonetextr'   resultlist[SamplingMessage]historyN)__name__
__module____qualname____doc____annotations__     k/Users/bowang/.openclaw/workspace/ChatDev/.venv/lib/python3.12/site-packages/fastmcp/server/sampling/run.pyr-   r-   5   s     O""r9   r-   c                  \    e Zd ZU dZded<   ded<   ed
d       Zedd       Zedd       Zy	)
SampleStepzsResult of a single sampling call.

    Represents what the LLM returned in this step plus the message history.
    2CreateMessageResult | CreateMessageResultWithToolsresponser1   r2   c                j    t        | j                  t              r| j                  j                  dk(  S y)z-True if the LLM is requesting tool execution.toolUseF)
isinstancer>   r   
stopReason)selfs    r:   is_tool_usezSampleStep.is_tool_useN   s+     dmm%AB==++y88r9   c                    | j                   j                  }t        |t              r&|D ]   }t        |t              s|j
                  c S  yt        |t              r|j
                  S y)z-Extract text from the response, if available.N)r>   contentrA   listr   r/   )rC   rF   blocks      r:   r/   zSampleStep.textU   sW     --''gt$ e[1 ::% ! -<<r9   c                    | j                   j                  }t        |t              r!|D cg c]  }t        |t              s| c}S t        |t              r|gS g S c c}w )z-Get the list of tool calls from the response.)r>   rF   rA   rG   r   )rC   rF   cs      r:   
tool_callszSampleStep.tool_callsb   sX     --''gt$&Hw!*Q*GAwHH09	 Is   AAN)returnbool)rL   r.   )rL   list[ToolUseContent])	r3   r4   r5   r6   r7   propertyrD   r/   rK   r8   r9   r:   r<   r<   D   sP    
 A@""  
 
  r9   r<   c                <   | yt        | t              r| S t        | t              rt        t        |       g      S t        | t              rAt        d | D              st        d      t        | D cg c]  }t        |       c}      S t        d      c c}w )z5Convert model preferences to ModelPreferences object.N)name)hintsc              3  <   K   | ]  }t        |t                y wN)rA   str).0hs     r:   	<genexpr>z+_parse_model_preferences.<locals>.<genexpr>x   s     A/@!:a%/@s   z7All elements of model_preferences list must be strings.zLmodel_preferences must be one of: ModelPreferences, str, list[str], or None.)rA   r   rU   r   rG   all
ValueError)model_preferencesrW   s     r:   _parse_model_preferencesr\   m   s      	%'7	8  	%s	+y6G'H&IJJ	%t	,A/@AAVWWBS&TBSQya'8BS&TUUZ
 	
 'Us   3Bc                4   | j                   }| j                  }|j                  t        t	                           }|j                  t        t	        t                                 }|j                  dk(  r|j                  t        d      y|j                  dk(  r7|xr | xs |}|s)|j                  |r|r|st        d      t        d	      yy|j                  t        d
|j                  d      |st        d	      |r|st        d      y)aq  Determine whether to use fallback handler or client for sampling.

    Args:
        context: The MCP context.
        needs_tools: Whether the sampling request requires tool support.

    Returns:
        True if fallback handler should be used, False to use client.

    Raises:
        ValueError: If client lacks required capability and no fallback configured.
    )sampling)
capability)toolsalwaysz?sampling_handler_behavior is 'always' but no handler configuredTfallbackzeClient does not support sampling with tools. The client must advertise the sampling.tools capability.z Client does not support samplingz#Invalid sampling_handler_behavior: z(. Must be 'always', 'fallback', or None.F)	fastmcpsessioncheck_client_capabilityr   r   r   sampling_handler_behaviorsampling_handlerrZ   )contextneeds_toolsrc   rd   has_samplinghas_tools_capabilityclient_sufficients          r:   determine_handler_moderm      sZ    ooGooG 22%/A/CD 3 L #::%'.E.GH
 ;  ((H4##+Q  		*	*j	8(V+o.UAU ''/<8L$S  !!CDD  
	*	*	61'2S2S1V W5 5
 	
 ;<<	1G
 	

 r9   c                 K   | j                   j                  t        d      | j                  t        d      | j                   j                  |t	        ||||t        |      ||      | j                        }t        j                  |      r
| d{   }t        |t              rt        dt        d|      dd	
      S |S 7 0w)zMake LLM call using the fallback handler.

    Note: This function expects the caller (sample_step) to have validated that
    sampling_handler is set via determine_handler_mode(). The checks below are
    safeguards against internal misuse.
    Nzsampling_handler is Nonezrequest_context is None)systemPromptmessagestemperature	maxTokensmodelPreferencesr`   
toolChoice	assistantr/   typer/   unknownendTurn)rolerF   modelrB   )rc   rg   RuntimeErrorrequest_contextSamplingParamsr\   inspectisawaitablerA   rU   r   r   )	rh   rp   system_promptrq   
max_tokensr[   	sdk_toolstool_choicer0   s	            r:   call_sampling_handlerr      s     " ''/566&455__--&# 56GH"	
 	F 6" &#"V&9 	
 	
 M s   BCC1Cc                  
K   ||dk  rt        d|       dfd
t        fd| D              }||r,g }| D ]#  } 
|       d{   }|j                  |       % |S |dk(  r$t        | D cg c]
  } 
|       c}  d{   S t	        j
                  |      d
fd}	t        | D cg c]
  } |	|       c}  d{   S 7 c c}w 7 Kc c}w 7 w)a  Execute tool calls and return results.

    Args:
        tool_calls: List of tool use requests from the LLM.
        tool_map: Mapping from tool name to SamplingTool.
        mask_error_details: If True, mask detailed error messages from tool execution.
            When masked, only generic error messages are returned to the LLM.
            Tools can explicitly raise ToolError to bypass masking when they want
            to provide specific error messages to the LLM.
        tool_concurrency: Controls parallel execution of tools:
            - None (default): Sequential execution (one at a time)
            - 0: Unlimited parallel execution
            - N > 0: Execute at most N tools concurrently
            If any tool has sequential=True, all tools execute sequentially
            regardless of this setting.

    Returns:
        List of tool result content blocks in the same order as tool_calls.
    Nr   zItool_concurrency must be None, 0 (unlimited), or a positive integer, got c                  K   j                  | j                        }|3t        d| j                  t	        dd| j                   d      gd      S 	 |j                  | j                         d{   }t        d| j                  t	        dt        |            g	      S 7 1# t        $ r[}t        j                  d
| j                   d       t        d| j                  t	        dt        |            gd      cY d}~S d}~wt        $ rw}t        j                  d
| j                   d       rd| j                   d}nd| j                   d| }t        d| j                  t	        d|      gd      cY d}~S d}~ww xY ww)z,Execute a single tool and return its result.Ntool_resultr/   zError: Unknown tool ''rv   Trw   	toolUseIdrF   isError)rw   r   rF   zError calling sampling tool 'zError executing tool 'z': )getrQ   r   idr   runinputrU   r   logger	exception	Exception)tool_usetoolresult_valuee
error_textmask_error_detailstool_maps        r:   _execute_single_toolz+execute_tools.<locals>._execute_single_tool  ss    ||HMM*<$""++#4X]]O1E 
 
	!%(..!99L$""++$&s<7HIJ  :  	<X]]O1MN$""++$&s1v>?	   	<X]]O1MN!5hmm_AF
5hmm_CsK
$""++$&zBC	 	sb   AFB' 3B%40B' $F%B' '	F	0AD F	FF	A,F>F	?FF		Fc              3  p   K   | ]-  }j                  |j                        xj                   / y wrT   )r   rQ   
sequential)rV   r   r   r   s     r:   rX   z execute_tools.<locals>.<genexpr>@  s5      "HLL//D< 	"s   36c                   K   4 d {     |        d {   cd d d       d {    S 7 %7 7 	# 1 d {  7  sw Y   y xY wwrT   r8   )r   r   	semaphores    r:   bounded_executez&execute_tools.<locals>.bounded_executeV  s1      y1(;; !yy; !yyysE   A0A626A4A6AA?AA)r   r   rL   r   )rZ   anyappendr"   anyio	Semaphore)rK   r   r   tool_concurrencyrequires_sequentialtool_resultsr   r0   tcr   r   r   r   s    ``       @@@r:   execute_toolsr      s    2 #(81(<#$&
 	

,^  "  #602"H/99F' #  1L2226LMMM OO$45		< JGJbob1JGHHH! : MM HHsN   AC"C'C"7CC"C)C"7CC"C C"C"C"c           	         t        | t              rt        t        | d      d      gS | D cg c],  }t        |t              rt        t        |d      d      n|. c}S c c}w )zEConvert various message formats to a list of SamplingMessage objects.r/   )r/   rw   user)rF   rz   )rA   rU   r   r   )rp   ms     r:   prepare_messagesr   `  sy     (C #?f
 	
 	
  !S! KQV$D6R 	
 	
 
s   1A"c                l   | yg }| D ]  }t        |t              r|j                  |       %t        |t        t        f      r%|j                  t        j
                  |             `t        |      r%|j                  t        j                  |             t        dt        |              |r|S dS )a  Convert tools to SamplingTool objects.

    Accepts SamplingTool instances, FunctionTool instances, TransformedTool instances,
    or plain callable functions. FunctionTool and TransformedTool are converted using
    from_callable_tool(), while plain functions use from_function().

    Args:
        tools: Sequence of tools to prepare. Can be SamplingTool, FunctionTool,
            TransformedTool, or plain callable functions.

    Returns:
        List of SamplingTool instances, or None if tools is None.
    NzGExpected SamplingTool, FunctionTool, TransformedTool, or callable, got )
rA   r   r   r    r!   from_callable_toolcallablefrom_function	TypeErrorrw   )r`   sampling_toolsts      r:   prepare_toolsr   s  s    " })+Na&!!!$L/:;!!,"A"A!"DEa[!!,"<"<Q"?@YZ^_`ZaYbc   ,>55r9   c                    | j                   }t        |t              r!|D cg c]  }t        |t              s| c}S t        |t              r|gS g S c c}w )z#Extract tool calls from a response.)rF   rA   rG   r   )r>   rF   rJ   s      r:   extract_tool_callsr     sT     G'4 "D7ajN&C7DD	G^	,yI Es
   AAc                    t        |       }|j                         }t        |d      }|j                  d      dk7  r	dd|idgd}dd}t	        dd	||
      S )zCreate a synthetic 'final_response' tool for structured output.

    This tool is used to capture structured responses from the LLM.
    The tool's schema is derived from the result_type.
    Tprune_titlesrw   objectvalue)rw   
propertiesr*   c                     | S rT   r8   )kwargss    r:   final_responsez2create_final_response_tool.<locals>.final_response  s    r9   r   z|Call this tool to provide your final response. Use this when you have completed the task and are ready to return the result.)rQ   description
parametersfn)r   r   rL   zdict[str, Any])r%   json_schemar#   r   r   )result_typetype_adapterschemar   s       r:   create_final_response_toolr     sw     *+6L%%'FV$7F zz&X%"F+ 	
 \  r9   T)	r   rq   r   r[   r`   r   auto_execute_toolsr   r   c       	   
       K   t        |      }t        |      }|r|D cg c]  }|j                          c}nd}|r|D ci c]  }|j                  | c}ni }t	        | t        |            }d}|0|dvrt        d|d      t        t        t        d   |            }||nd}|rt        | |||||||       d{   }n>| j                  j                  ||||t        |      ||| j                         d{   }t        |t               xr |j"                  d	k(  }|j%                  t'        d
|j(                               |st+        ||      S |st+        ||      S t-        |      }|r^|	|	nt.        j0                  }t3        ||||
       d{   }|r1|j%                  t'        dt        t4        t6           |                   t+        ||      S c c}w c c}w 7 +7 7 Sw)zImplementation of Context.sample_step().

    Make a single LLM sampling call. This is a stateless function that makes
    exactly one LLM call and optionally executes any requested tools.
    Nr(   zInvalid tool_choice: z(. Must be 'auto', 'required', or 'none'.modei   )r   rq   r   r[   r   r   )rp   r   rq   r   r[   r`   r   related_request_idr@   ru   rz   rF   )r>   r2   )r   r   r   )r   r   _to_sdk_toolrQ   rm   rM   rZ   r   r   r
   r   rd   create_messager\   
request_idrA   r   rB   r   r   rF   r<   r   r   r   r   rG   r   )rh   rp   r   rq   r   r[   r`   r   r   r   r   current_messagesr   r   r   r   use_fallbackeffective_tool_choiceeffective_max_tokensr>   is_tool_use_responsestep_tool_callseffective_maskr   s                           r:   sample_step_implr     sU    * (1 #5)N6D>2>a	>2$  0>N+NqN+2 
 *'43GHL 04::' 79 9  !+g89;G!

 *4)?:S .'#+/-	
 	
 !77%'#+67HI-&11 8 	
 	
 	89: 	-9,  OhFVFVWX  85EFF 85EFF )2O "- ,, 	
 7D--	7
 1
 ## &A!BLQ x1ABBq 	3 	,.	
	
H1
sN   G3G"G3G'A,G3G,>G3 G/BG3G1AG3/G31G3)r   rq   r   r[   r`   r   r   r   c                 K   d}
t        |      }d}|5|t        ur-t        |      }|rt        |      ng }|j	                  |       d}|}t        |
      D ]  }t        | |||||||||	
       d{   }||t        ur|j                  r|j                  D ]  }|j                  dk(  st        |      }|j                  }t        |j                         d      }|j                  d      d	k7  rt        |t               r	d
|v r|d
   }	 |j#                  |      }t%        j&                  |j)                  |d            }t+        |||j,                        c c S  |j                  sm|!|t        urt9        d|j:                   d      t+        |j<                  t?        t@        |j<                  r|j<                  nd      |j,                        c S |j,                  }|
|t        u sd} t9        d|
 d      7 # t.        $ rY}|j,                  j	                  t1        dt3        d|j4                  t7        dd| d      gd      g             Y d}~d}~ww xY ww)zImplementation of Context.sample().

    Send a sampling request to the client and await the response. This method
    runs to completion automatically, executing a tool loop until the LLM
    provides a final text response.
    d   Nr*   )	rp   r   rq   r   r[   r`   r   r   r   r   Tr   rw   r   r   jsonr   )r/   r0   r2   r   r   r/   zValidation error: z#. Please try again with valid data.rv   r   r   z#Expected structured output of type zR, but the LLM returned a text response instead of calling the final_response tool. z&Sampling exceeded maximum iterations ())!r   rU   r   rG   r   ranger   rD   rK   rQ   r%   r   r#   r   r   rA   dictvalidate_pythonr   dumpsdump_pythonr-   r2   r   r   r   r   r   r|   r3   r/   r   r'   )rh   rp   r   rq   r   r[   r`   r   r   r   max_iterationsr   r   final_response_toolr   
_iterationstep	tool_callr   
input_dataoriginal_schemavalidated_resultr/   r   s                           r:   sample_implr   <  s    * N #5)N #K;c#98E1?n-R12 ! ?GN+
%%'#!/ #1-
 
 "{#'=$BRBR!__	>>%55#9+#FL "+J&5$002'O (++F3x?&z48#z1%/%8
 +7+G+G
+S(#zz(445EF4S   .!%#3$(LL  - -h &;c+A"9+:N:N9O P/ / 
 "YYG$))TYYD   << +"4Ko ,r ??OqQ
RRq
T + +++%+$5-:2;,,,75;6H LX 5X-.1* 15%&)" sL   A0I-2H38I-,AI-AHBI-1I-	I*AI%I-%I**I-)r[   )ModelPreferences | str | list[str] | NonerL   zModelPreferences | None)rh   r&   ri   rM   rL   rM   )rh   r&   rp   r1   r   r.   rq   float | Noner   intr[   r   r   zlist[SDKTool] | Noner   zToolChoice | NonerL   r=   )FN)
rK   rN   r   zdict[str, SamplingTool]r   rM   r   
int | NonerL   zlist[ToolResultContent])rp   %str | Sequence[str | SamplingMessage]rL   r1   )r`   SSequence[SamplingTool | FunctionTool | TransformedTool | Callable[..., Any]] | NonerL   zlist[SamplingTool] | None)r>   r=   rL   rN   )r   rw   rL   r   )rh   r&   rp   r   r   r.   rq   r   r   r   r[   r   r`   r   r   zToolChoiceOption | str | Noner   rM   r   bool | Noner   r   rL   r<   )rh   r&   rp   r   r   r.   rq   r   r   r   r[   r   r`   r   r   ztype[ResultT] | Noner   r   r   r   rL   zSamplingResult[ResultT])Kr6   
__future__r   r   r   collections.abcr   r   dataclassesr   typingr   r   r	   r
   r   r   	mcp.typesr   r   r   r   r   r   r   r   r   r   r   r   r   r   r~   r   SDKToolpydanticr   typing_extensionsr   rc   r   fastmcp.exceptionsr   %fastmcp.server.sampling.sampling_toolr   fastmcp.tools.function_toolr    fastmcp.tools.tool_transformr!   fastmcp.utilities.async_utilsr"   fastmcp.utilities.json_schemar#   fastmcp.utilities.loggingr$   fastmcp.utilities.typesr%   r3   r   fastmcp.server.contextr&   r'   ToolChoiceOptionr-   r<   r\   rm   r   r   r   r   r   r   r   r   r8   r9   r:   <module>r     s   > "   . ! = =     C % $ %  ( > 4 8 0 9 0 :	H	.
)
 56  #WW% # # % % %P
@

.8v00#0 	0
 0 0 A0 $0 #0 80l  %#'	hI$hI%hI hI !	hI
 hI\
3

&!6!6 !6H	@		P !% $!CG15#&*#'rCrC3rC 	rC
 rC rC ArCrC /rC rC $rC !rC rCr !% $!CG(,&*#'ASAS3AS 	AS
 AS AS AASAS &AS $AS !AS ASr9   