
    )`i                         d Z ddlmZmZ ddlmZmZ ddlmZmZ ddl	m
Z
mZ ddlZddlmZ ddlmZmZmZ e G d	 d
                      Z G d de          Z G d de          ZdS )a)  
TaskMessageQueue - FIFO queue for task-related messages.

This implements the core message queue pattern from the MCP Tasks spec.
When a handler needs to send a request (like elicitation) during a task-augmented
request, the message is enqueued instead of sent directly. Messages are delivered
to the client only through the `tasks/result` endpoint.

This pattern enables:
1. Decoupling request handling from message delivery
2. Proper bidirectional communication via the tasks/result stream
3. Automatic status management (working <-> input_required)
    )ABCabstractmethod)	dataclassfield)datetimetimezone)AnyLiteralN)Resolver)JSONRPCNotificationJSONRPCRequest	RequestIdc                       e Zd ZU dZed         ed<   	 eez  ed<   	  ed           Z	e
ed<   	 dZeeeef                  dz  ed	<   	 dZedz  ed
<   dS )QueuedMessagez
    A message queued for delivery via tasks/result.

    Messages are stored with their type and a resolver for requests
    that expect responses.
    )requestnotificationtypemessagec                  >    t          j        t          j                  S N)r   nowr   utc     /home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/mcp/shared/experimental/tasks/message_queue.py<lambda>zQueuedMessage.<lambda>)   s    X\8R8R r   )default_factory	timestampNresolveroriginal_request_id)__name__
__module____qualname____doc__r
   __annotations__r   r   r   r   r   r   r   dictstrr	   r    r   r   r   r   r   r      s           +
,,,,Q11111'%0R0RSSSIxSSS(04HhtCH~&-444D,0T)000NNr   r   c                      e Zd ZdZedededdfd            Zedededz  fd            Zedededz  fd            Z	edede
fd	            Zededee         fd
            Zededdfd            Zededdfd            ZdS )TaskMessageQueuea"  
    Abstract interface for task message queuing.

    This is a FIFO queue that stores messages to be delivered via `tasks/result`.
    When a task-augmented handler calls elicit() or sends a notification, the
    message is enqueued here instead of being sent directly to the client.

    The `tasks/result` handler then dequeues and sends these messages through
    the transport, with `relatedRequestId` set to the tasks/result request ID
    so responses are routed correctly.

    Implementations can use in-memory storage, Redis, etc.
    task_idr   returnNc                 
   K   dS )z
        Add a message to the queue for a task.

        Args:
            task_id: The task identifier
            message: The message to enqueue
        Nr   )selfr*   r   s      r   enqueuezTaskMessageQueue.enqueueB   
        r   c                 
   K   dS )z
        Remove and return the next message from the queue.

        Args:
            task_id: The task identifier

        Returns:
            The next message, or None if queue is empty
        Nr   r-   r*   s     r   dequeuezTaskMessageQueue.dequeueL   r/   r   c                 
   K   dS )z
        Return the next message without removing it.

        Args:
            task_id: The task identifier

        Returns:
            The next message, or None if queue is empty
        Nr   r1   s     r   peekzTaskMessageQueue.peekX   r/   r   c                 
   K   dS )z
        Check if the queue is empty for a task.

        Args:
            task_id: The task identifier

        Returns:
            True if no messages are queued
        Nr   r1   s     r   is_emptyzTaskMessageQueue.is_emptyd   r/   r   c                 
   K   dS )a  
        Remove and return all messages from the queue.

        This is useful for cleanup when a task is cancelled or completed.

        Args:
            task_id: The task identifier

        Returns:
            All queued messages (may be empty)
        Nr   r1   s     r   clearzTaskMessageQueue.clearp   r/   r   c                 
   K   dS )z
        Wait until a message is available in the queue.

        This blocks until either:
        1. A message is enqueued for this task
        2. The wait is cancelled

        Args:
            task_id: The task identifier
        Nr   r1   s     r   wait_for_messagez!TaskMessageQueue.wait_for_message~   r/   r   c                 
   K   dS )z
        Signal that a message is available for a task.

        This wakes up any coroutines waiting in wait_for_message().

        Args:
            task_id: The task identifier
        Nr   r1   s     r   notify_message_availablez)TaskMessageQueue.notify_message_available   r/   r   )r!   r"   r#   r$   r   r'   r   r.   r2   r4   boolr6   listr8   r:   r<   r   r   r   r)   r)   3   sv         S = T    ^ 	S 	]T-A 	 	 	 ^	 	# 	-$*> 	 	 	 ^	 	c 	d 	 	 	 ^	 3 4+>    ^ 
c 
d 
 
 
 ^
 c d    ^  r   r)   c                       e Zd ZdZddZdedee         fdZdededdfdZ	dededz  fd	Z
dededz  fd
ZdedefdZdedee         fdZdeddfdZdeddfdZddedz  ddfdZdS )InMemoryTaskMessageQueueaA  
    In-memory implementation of TaskMessageQueue.

    This is suitable for single-process servers. For distributed systems,
    implement TaskMessageQueue with Redis, RabbitMQ, etc.

    Features:
    - FIFO ordering per task
    - Async wait for message availability
    - Thread-safe for single-process async use
    r+   Nc                 "    i | _         i | _        d S r   )_queues_events)r-   s    r   __init__z!InMemoryTaskMessageQueue.__init__   s    79/1r   r*   c                 B    || j         vr
g | j         |<   | j         |         S )z#Get or create the queue for a task.)rB   r1   s     r   
_get_queuez#InMemoryTaskMessageQueue._get_queue   s(    $,&&$&DL!|G$$r   r   c                    K   |                      |          }|                    |           |                     |           d{V  dS )zAdd a message to the queue.N)rF   appendr<   )r-   r*   r   queues       r   r.   z InMemoryTaskMessageQueue.enqueue   sU      ((W++G44444444444r   c                 b   K   |                      |          }|sdS |                    d          S )z#Remove and return the next message.Nr   )rF   popr-   r*   rI   s      r   r2   z InMemoryTaskMessageQueue.dequeue   s4      (( 	4yy||r   c                 H   K   |                      |          }|sdS |d         S )z,Return the next message without removing it.Nr   )rF   rL   s      r   r4   zInMemoryTaskMessageQueue.peek   s-      (( 	4Qxr   c                 V   K   |                      |          }t          |          dk    S )zCheck if the queue is empty.r   )rF   lenrL   s      r   r6   z!InMemoryTaskMessageQueue.is_empty   s'      ((5zzQr   c                 z   K   |                      |          }t          |          }|                                 |S )zRemove and return all messages.)rF   r>   r8   )r-   r*   rI   messagess       r   r8   zInMemoryTaskMessageQueue.clear   s4      ((;;r   c                   K   |                      |           d{V sdS t          j                    | j        |<   | j        |         }|                      |           d{V sdS |                                 d{V  dS )z"Wait until a message is available.N)r6   anyioEventrC   wait)r-   r*   events      r   r:   z)InMemoryTaskMessageQueue.wait_for_message   s       ]]7++++++++ 	F !&WW% ]]7++++++++ 	F jjllr   c                 ^   K   || j         v r!| j         |                                          dS dS )z#Signal that a message is available.N)rC   setr1   s     r   r<   z1InMemoryTaskMessageQueue.notify_message_available   s:      dl""L!%%''''' #"r   c                     |8| j                             |d           | j                            |d           dS | j                                          | j                                         dS )z
        Clean up queues and events.

        Args:
            task_id: If provided, clean up only this task. Otherwise clean up all.
        N)rB   rK   rC   r8   r1   s     r   cleanupz InMemoryTaskMessageQueue.cleanup   sn     LWd+++LWd+++++L   L     r   )r+   Nr   )r!   r"   r#   r$   rD   r'   r>   r   rF   r.   r2   r4   r=   r6   r8   r:   r<   rZ   r   r   r   r@   r@      s       
 
2 2 2 2%# %$}*= % % % %5S 5= 5T 5 5 5 5S ]T-A    # -$*>    c d    
3 4+>    c d    "(c (d ( ( ( (
! !sTz !T ! ! ! ! ! !r   r@   )r$   abcr   r   dataclassesr   r   r   r   typingr	   r
   rS   &mcp.shared.experimental.tasks.resolverr   	mcp.typesr   r   r   r   r)   r@   r   r   r   <module>r`      sX    $ # # # # # # # ( ( ( ( ( ( ( ( ' ' ' ' ' ' ' '          ; ; ; ; ; ; D D D D D D D D D D O O O O O O O O0a a a a as a a aHZ! Z! Z! Z! Z!/ Z! Z! Z! Z! Z!r   