o
    c۷i !                     @   s   d Z ddlmZ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 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mZmZ eG dd dZdS )a	  
Experimental request context features.

This module provides the Experimental class which gives access to experimental
features within a request context, such as task-augmented request handling.

WARNING: These APIs are experimental and may change without notice.
    )	AwaitableCallable)	dataclassfield)Any)ServerTaskContext)TaskSupport)ServerSession)McpError)MODEL_IMMEDIATE_RESPONSE_KEYis_terminal)
METHOD_NOT_FOUNDTASK_FORBIDDENTASK_REQUIREDClientCapabilitiesCreateTaskResult	ErrorDataResultTaskExecutionModeTaskMetadataToolc                	   @   s   e Zd ZU dZdZedB ed< edddZe	dB ed< edddZ
edB ed< edddZedB ed< ed	efd
dZed	efddZdddedB ded	edB fddZdddeded	edB fddZdedB d	efddZddddeegee f dedB dedB d	efddZdS )Experimentala  
    Experimental features context for task-augmented requests.

    Provides helpers for validating task execution compatibility and
    running tasks with automatic lifecycle management.

    WARNING: This API is experimental and may change without notice.
    Ntask_metadataF)defaultrepr_client_capabilities_session_task_supportreturnc                 C   s
   | j duS )z(Check if this request is task-augmented.N)r   self r!   ]/home/ubuntu/vllm_env/lib/python3.10/site-packages/mcp/server/experimental/request_context.pyis_task1   s   
zExperimental.is_taskc                 C   s   | j du rdS | j jduS )z*Check if the client declared task support.NF)r   tasksr   r!   r!   r"   client_supports_tasks6   s   
z"Experimental.client_supports_tasksTraise_errortool_task_moder'   c                C   sZ   |pt }d}|tkr| jsttdd}n|t kr!| jr!ttdd}|dur+|r+t||S )a  
        Validate that the request is compatible with the tool's task execution mode.

        Per MCP spec:
        - "required": Clients MUST invoke as task. Server returns -32601 if not.
        - "forbidden" (or None): Clients MUST NOT invoke as task. Server returns -32601 if they do.
        - "optional": Either is acceptable.

        Args:
            tool_task_mode: The tool's execution.taskSupport value
                ("forbidden", "optional", "required", or None)
            raise_error: If True, raises McpError on validation failure. If False, returns ErrorData.

        Returns:
            None if valid, ErrorData if invalid and raise_error=False

        Raises:
            McpError: If invalid and raise_error=True
        Nz,This tool requires task-augmented invocation)codemessagez4This tool does not support task-augmented invocation)r   r   r#   r   r   r
   )r    r(   r'   modeerrorr!   r!   r"   validate_task_mode=   s   zExperimental.validate_task_modetoolc                C   s    |j r|j jnd}| j||dS )a  
        Validate that the request is compatible with the given tool.

        Convenience wrapper around validate_task_mode that extracts the mode from a Tool.

        Args:
            tool: The Tool definition
            raise_error: If True, raises McpError on validation failure.

        Returns:
            None if valid, ErrorData if invalid and raise_error=False
        Nr&   )	executiontaskSupportr-   )r    r.   r'   r+   r!   r!   r"   validate_for_toolk   s   zExperimental.validate_for_toolc                 C   s   |pt }|tkr| jsdS dS )a  
        Check if this client can use a tool with the given task mode.

        Useful for filtering tool lists or providing warnings.
        Returns False if tool requires "required" but client doesn't support tasks.

        Args:
            tool_task_mode: The tool's execution.taskSupport value

        Returns:
            True if the client can use this tool, False otherwise
        FT)r   r   r%   )r    r(   r+   r!   r!   r"   can_use_tool   s   zExperimental.can_use_tool)task_idmodel_immediate_responseworkr3   r4   c          	         s   | j du r
td| jdu rtd| jdu rtd| j }|j}|j| j|I dH }t||j| j|j|j	d d fdd}|
| d}|durQt|i}tdd	|i|r^d
|iS i S )as  
        Create a task, spawn background work, and return CreateTaskResult immediately.

        This is the recommended way to handle task-augmented tool calls. It:
        1. Creates a task in the store
        2. Spawns the work function in a background task
        3. Returns CreateTaskResult immediately

        The work function receives a ServerTaskContext with:
        - elicit() for sending elicitation requests
        - create_message() for sampling requests
        - update_status() for progress updates
        - complete()/fail() for finishing the task

        When work() returns a Result, the task is auto-completed with that result.
        If work() raises an exception, the task is auto-failed.

        Args:
            work: Async function that does the actual work
            task_id: Optional task ID (generated if not provided)
            model_immediate_response: Optional string to include in _meta as
                io.modelcontextprotocol/model-immediate-response

        Returns:
            CreateTaskResult to return to the client

        Raises:
            RuntimeError: If task support is not enabled or task_metadata is missing

        Example:
            @server.call_tool()
            async def handle_tool(name: str, args: dict):
                ctx = server.request_context

                async def work(task: ServerTaskContext) -> CallToolResult:
                    result = await task.elicit(
                        message="Are you sure?",
                        requestedSchema={"type": "object", ...}
                    )
                    confirmed = result.content.get("confirm", False)
                    return CallToolResult(content=[TextContent(text="Done" if confirmed else "Cancelled")])

                return await ctx.experimental.run_task(work)

        WARNING: This API is experimental and may change without notice.
        NzHTask support not enabled. Call server.experimental.enable_tasks() first.zSession not available.zgRequest is not task-augmented (no task field in params). The client must send a task-augmented request.)taskstoresessionqueuehandlerr   c               
      s   z I d H } t  jjs | I d H  W d S W d S  tyF } zt  jjs; t|I d H  W Y d }~d S W Y d }~d S d }~ww )N)r   r6   statuscomplete	Exceptionfailstr)resultetask_ctxr5   r!   r"   execute   s   "z&Experimental.run_task.<locals>.executer6   _meta)r   Nr!   )r   RuntimeErrorr   r   
task_groupr7   create_taskr   r9   r:   
start_soonr   r   )	r    r5   r3   r4   supportrG   r6   rD   metar!   rB   r"   run_task   s2   
5


	"zExperimental.run_task)__name__
__module____qualname____doc__r   r   __annotations__r   r   r   r   r	   r   r   propertyboolr#   r%   r   r   r-   r   r1   r2   r   r   r   r   r?   r   rL   r!   r!   r!   r"   r   !   sL   
 	

2
r   N) rP   collections.abcr   r   dataclassesr   r   typingr   $mcp.server.experimental.task_contextr   $mcp.server.experimental.task_supportr   mcp.server.sessionr	   mcp.shared.exceptionsr
   %mcp.shared.experimental.tasks.helpersr   r   	mcp.typesr   r   r   r   r   r   r   r   r   r   r   r!   r!   r!   r"   <module>   s    	0