
    Ki                         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y)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
<   y)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                  H    t        j                  t        j                        S N)r   nowr   utc     w/home/jay/workspace/scripts/.codegraph-venv/lib/python3.12/site-packages/mcp/shared/experimental/tasks/message_queue.py<lambda>zQueuedMessage.<lambda>)   s    X\\8R 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      sl     +
,,Q111'0RSIxS(04HhtCH~&-4D,0T)0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y)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   yw)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           c                    K   yw)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/   r0   c                    K   yw)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   r2   s     r   peekzTaskMessageQueue.peekX   r/   r0   c                    K   yw)z
        Check if the queue is empty for a task.

        Args:
            task_id: The task identifier

        Returns:
            True if no messages are queued
        Nr   r2   s     r   is_emptyzTaskMessageQueue.is_emptyd   r/   r0   c                    K   yw)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   r2   s     r   clearzTaskMessageQueue.clearp   r/   r0   c                    K   yw)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   r2   s     r   wait_for_messagez!TaskMessageQueue.wait_for_message~   r/   r0   c                    K   yw)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   r2   s     r   notify_message_availablez)TaskMessageQueue.notify_message_available   r/   r0   )r!   r"   r#   r$   r   r'   r   r.   r3   r5   boolr7   listr9   r;   r=   r   r   r   r)   r)   3   s    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y)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 | _        y r   )_queues_events)r-   s    r   __init__z!InMemoryTaskMessageQueue.__init__   s    79/1r   r*   c                 Z    || j                   vrg | j                   |<   | j                   |   S )z#Get or create the queue for a task.)rC   r2   s     r   
_get_queuez#InMemoryTaskMessageQueue._get_queue   s+    $,,&$&DLL!||G$$r   r   c                    K   | j                  |      }|j                  |       | j                  |       d{    y7 w)zAdd a message to the queue.N)rG   appendr=   )r-   r*   r   queues       r   r.   z InMemoryTaskMessageQueue.enqueue   s4     (W++G444s   7A?Ac                 T   K   | j                  |      }|sy|j                  d      S w)z#Remove and return the next message.Nr   )rG   popr-   r*   rJ   s      r   r3   z InMemoryTaskMessageQueue.dequeue   s(     (yy|s   &(c                 <   K   | j                  |      }|sy|d   S w)z,Return the next message without removing it.Nr   )rG   rM   s      r   r5   zInMemoryTaskMessageQueue.peek   s#     (Qxs   c                 H   K   | j                  |      }t        |      dk(  S w)zCheck if the queue is empty.r   )rG   lenrM   s      r   r7   z!InMemoryTaskMessageQueue.is_empty   s"     (5zQs    "c                 f   K   | j                  |      }t        |      }|j                          |S w)zRemove and return all messages.)rG   r?   r9   )r-   r*   rJ   messagess       r   r9   zInMemoryTaskMessageQueue.clear   s+     (;s   /1c                   K   | j                  |       d{   syt        j                         | j                  |<   | j                  |   }| j                  |       d{   sy|j	                          d{    y7 h7  7 	w)z"Wait until a message is available.N)r7   anyioEventrD   wait)r-   r*   events      r   r;   z)InMemoryTaskMessageQueue.wait_for_message   sz      ]]7+++ !&WW% ]]7+++ jjl , , 	s4   BB A	B!B"B:B;BBBc                 d   K   || j                   v r| j                   |   j                          yyw)z#Signal that a message is available.N)rD   setr2   s     r   r=   z1InMemoryTaskMessageQueue.notify_message_available   s,     dll"LL!%%' #s   .0c                     |9| j                   j                  |d       | j                  j                  |d       y| j                   j                          | j                  j                          y)z
        Clean up queues and events.

        Args:
            task_id: If provided, clean up only this task. Otherwise clean up all.
        N)rC   rL   rD   r9   r2   s     r   cleanupz InMemoryTaskMessageQueue.cleanup   sR     LLWd+LLWd+LL LL r   )r+   Nr   )r!   r"   r#   r$   rE   r'   r?   r   rG   r.   r3   r5   r>   r7   r9   r;   r=   r[   r   r   r   rA   rA      s    
2%# %$}*= %5S 5= 5T 5S ]T-A # -$*> c d 
3 4+> c d "(c (d (
!sTz !T !r   rA   )r$   abcr   r   dataclassesr   r   r   r   typingr	   r
   rT   &mcp.shared.experimental.tasks.resolverr   	mcp.typesr   r   r   r   r)   rA   r   r   r   <module>ra      s^    $ ( '   ; D D O O O0as aHZ!/ Z!r   