
    )`i                          d Z ddlZddlmZ ddl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mZ ddlmZmZmZmZmZmZmZ  ej        e          Z G d d          Z dS )a  
TaskResultHandler - Integrated handler for tasks/result endpoint.

This implements the dequeue-send-wait pattern from the MCP Tasks spec:
1. Dequeue all pending messages for the task
2. Send them to the client via transport with relatedRequestId routing
3. Wait if task is not in terminal state
4. Return final result when task completes

This is the core of the task message queue pattern.
    N)Any)ServerSession)McpError)RELATED_TASK_METADATA_KEYis_terminal)TaskMessageQueue)Resolver)	TaskStore)ServerMessageMetadataSessionMessage)INVALID_PARAMS	ErrorDataGetTaskPayloadRequestGetTaskPayloadResultJSONRPCMessageRelatedTaskMetadata	RequestIdc                       e Zd ZdZdedefdZdededdfd	Z	d
e
dededefdZdedededdfdZdeddfdZdedeeef         defdZdededefdZdS )TaskResultHandleraW  
    Handler for tasks/result that implements the message queue pattern.

    This handler:
    1. Dequeues pending messages (elicitations, notifications) for the task
    2. Sends them to the client via the response stream
    3. Waits for responses and resolves them back to callers
    4. Blocks until task reaches terminal state
    5. Returns the final result

    Usage:
        # Create handler with store and queue
        handler = TaskResultHandler(task_store, message_queue)

        # Register it with the server
        @server.experimental.get_task_result()
        async def handle_task_result(req: GetTaskPayloadRequest) -> GetTaskPayloadResult:
            ctx = server.request_context
            return await handler.handle(req, ctx.session, ctx.request_id)

        # Or use the convenience method
        handler.register(server)
    storequeuec                 0    || _         || _        i | _        d S N)_store_queue_pending_requests)selfr   r   s      /home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/mcp/server/experimental/task_result_handler.py__init__zTaskResultHandler.__init__?   s     
 LN    sessionmessagereturnNc                 @   K   |                     |           d{V  dS )zp
        Send a message via the session.

        This is a helper for delivering queued task messages.
        N)send_message)r   r!   r"   s      r   r%   zTaskResultHandler.send_messageI   s4       ""7+++++++++++r    request
request_idc                   K   |j         j        }	 | j                            |           d{V }|&t	          t          t          d|                     |                     |||           d{V  t          |j	                  r| j        
                    |           d{V }t          |          }t          |                    d          i}|J|                    d          }	|	                    d          pi }
i |
||	d<   t          j        |	          S t          j        d|i          S |                     |           d{V  E)ah  
        Handle a tasks/result request.

        This implements the dequeue-send-wait loop:
        1. Dequeue all pending messages
        2. Send each via transport with relatedRequestId = this request's ID
        3. If task not terminal, wait for status change
        4. Loop until task is terminal
        5. Return final result

        Args:
            request: The GetTaskPayloadRequest
            session: The server session for sending messages
            request_id: The request ID for relatedRequestId routing

        Returns:
            GetTaskPayloadResult with the task's final payload
        TNzTask not found: )coder"   )taskId)by_alias_meta)paramsr*   r   get_taskr   r   r   _deliver_queued_messagesr   status
get_resultr   r   
model_dumpgetr   model_validate_wait_for_task_update)r   r&   r!   r'   task_idtaskresultrelated_taskrelated_task_metaresult_dataexisting_metas              r   handlezTaskResultHandler.handleU   s     0 .'	6--g66666666D|+ <7 < <     //*MMMMMMMMM 4;'' Y#{55g>>>>>>>>  3'BBB5NP\PgPgquPgPvPv4w!%"("3"3T"3"B"BK4?OOG4L4L4RPRM+Qm+Q?P+QK(/>{KKK+:GEV;WXXX ,,W5555555559	6r    r6   c                   K   	 | j                             |           d{V }|dS |j        dk    r|j        |j        }||j        | j        |<   t                              d||j                   t          t          |j
                  t          |                    }|                     ||           d{V  )z
        Dequeue and send all pending messages for a task.

        Each message is sent via the session's write stream with
        relatedRequestId set so responses route back to this stream.
        TNr&   z)Delivering queued message for task %s: %s)related_request_id)r"   metadata)r   dequeuetyperesolveroriginal_request_idr   loggerdebugr   r   r"   r   r%   )r   r6   r!   r'   r"   original_idsession_messages          r   r/   z*TaskResultHandler._deliver_queued_messages   s      	> K//88888888G |y((W-=-I%9*:A:JD*;7LLDgw|\\\ -&w77.*MMM  O ##G_========='	>r    c                     K   t          j                    4 d{V d fd}d fd}                    |                               |           ddd          d{V  dS # 1 d{V swxY w Y   dS )z
        Wait for task to be updated (status change or new message).

        Races between store update and queue message - first one wins.
        Nr#   c                     K   	  j                                        d {V  n# t          $ r Y nw xY wj                                         d S # j                                         w xY wr   )r   wait_for_update	Exceptioncancel_scopecancelr   r6   tgs   r   wait_for_storez?TaskResultHandler._wait_for_task_update.<locals>.wait_for_store   s      -+55g>>>>>>>>>>    D O**,,,,,BO**,,,,!    & A 
3A 3A A,c                     K   	  j                                        d {V  n# t          $ r Y nw xY wj                                         d S # j                                         w xY wr   )r   wait_for_messagerL   rM   rN   rO   s   r   wait_for_queuez?TaskResultHandler._wait_for_task_update.<locals>.wait_for_queue   s      -+66w??????????    D O**,,,,,BO**,,,,rR   )r#   N)anyiocreate_task_group
start_soon)r   r6   rQ   rU   rP   s   ``  @r   r5   z'TaskResultHandler._wait_for_task_update   sK      *,, 	* 	* 	* 	* 	* 	* 	*- - - - - - - -- - - - - - - - MM.)))MM.)))'	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	*s   ;A--
A7:A7responsec                     | j                             |d          }|+|                                s|                    |           dS dS )aM  
        Route a response back to the waiting resolver.

        This is called when a response arrives for a queued request.

        Args:
            request_id: The request ID from the response
            response: The response data

        Returns:
            True if response was routed, False if no pending request
        NTF)r   popdone
set_result)r   r'   rY   rC   s       r   route_responsez TaskResultHandler.route_response   sM     )--j$??)))4ur    errorc                     | j                             |d          }|8|                                s$|                    t	          |                     dS dS )a  
        Route an error back to the waiting resolver.

        Args:
            request_id: The request ID from the error response
            error: The error data

        Returns:
            True if error was routed, False if no pending request
        NTF)r   r[   r\   set_exceptionr   )r   r'   r_   rC   s       r   route_errorzTaskResultHandler.route_error   sS     )--j$??""8E??3334ur    )__name__
__module____qualname____doc__r
   r   r   r   r   r%   r   r   r   r=   strr/   r5   dictr   boolr^   r   rb    r    r   r   r   &   sm        0OO  O O O O
,
,  
, 
	
, 
, 
, 
,66&66 66 	66
 
66 66 66 66p>> > 	>
 
> > > >B*3 *4 * * * *6 d38n QU    &i 	 d      r    r   )!rf   loggingtypingr   rV   mcp.server.sessionr   mcp.shared.exceptionsr   %mcp.shared.experimental.tasks.helpersr   r   +mcp.shared.experimental.tasks.message_queuer   &mcp.shared.experimental.tasks.resolverr	   #mcp.shared.experimental.tasks.storer
   mcp.shared.messager   r   	mcp.typesr   r   r   r   r   r   r   	getLoggerrc   rE   r   rj   r    r   <module>rv      si  
 
         , , , , , , * * * * * * X X X X X X X X H H H H H H ; ; ; ; ; ; 9 9 9 9 9 9 D D D D D D D D                  
	8	$	$E E E E E E E E E Er    