
    kKj-                    (   d Z ddlmZ ddlZddlZddl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 ddlmZ dd	lmZ  ej*                  e      Ze	rdd
lmZ dZddZ	 	 	 	 	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 	 	 	 	 	 	 ddZy)aY  Background task elicitation support (SEP-1686).

This module provides elicitation capabilities for background tasks running
in Docket workers. Unlike regular MCP requests, background tasks don't have
an active request context, so elicitation requires special handling:

1. Set task status to "input_required" via Redis
2. Send notifications/tasks/status with elicitation metadata
3. Wait for client to send input via tasks/sendInput
4. Resume task execution with the provided input

This uses the public MCP SDK APIs where possible, with minimal use of
internal APIs for background task coordination.
    )annotationsN)datetimetimezone)TYPE_CHECKINGAny)ServerSession)get_task_contextget_task_session_idtask_redis_prefix)push_notification)FastMCPi  c                @    t        |        d| d}| d| d| dfS )zFBuild (request, response, status) Redis keys for a task's elicitation.:z:elicitz:requestz	:responsez:statusr   )
task_scopetask_idprefixs      q/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/fastmcp/server/tasks/elicitation.py_elicit_keysr   )   s<    !*-.ay@FXX6() 46HHH    c                	  K   |j                   }|t        d      t        t        j                               }t               }|&|j                  }t        |dd      xs
 t               }	nt        d      t        ||       \  }
}}|||d}|j                         4 d{   }|j                  |j                  |
      t        j                  |      t               d{    |j                  |j                  |      dt               d{    ddd      d{    t!        j"                  t$        j&                        j)                         }d| d	|||t        d
z  dd| d	|||||ddid}|	7t*        j-                  d|        t.        j0                  j3                  dd      S 	 t5        |	||       d{    t        }	 |j                         4 d{   }|j;                  |j                  |      g|       d{   }|r|\  }}t        j<                  |      }|j9                  |j                  |
      |j                  |             d{    t.        j0                  j3                  |j?                  dd      |j?                  d            cddd      d{    S ddd      d{    	 |j                         4 d{   }|j9                  |j                  |
      |j                  |      |j                  |             d{    ddd      d{    t.        j0                  j3                  dd      S 7 7 z7 N7 A# 1 d{  7  sw Y   RxY w7 # t6        $ r}t*        j-                  d| |       	 |j                         4 d{  7  }|j9                  |j                  |
      |j                  |             d{  7   ddd      d{  7   n# 1 d{  7  sw Y   nxY wn# t6        $ r Y nw xY wt.        j0                  j3                  dd      cY d}~S d}~ww xY w7 v7 N7 7 7 # 1 d{  7  sw Y   xY w# t6        $ r"}t*        j-                  d| |       Y d}~d}~ww xY w7 7 7 }# 1 d{  7  sw Y   xY w# t6        $ r"}t*        jA                  d| |       Y d}~d}~ww xY ww)a  Send an elicitation request from a background task.

    This function handles the complexity of eliciting user input when running
    in a Docket worker context where there's no active MCP request.

    Args:
        task_id: The background task ID
        session: The MCP ServerSession for this task
        message: The message to display to the user
        schema: The JSON schema for the expected response
        fastmcp: The FastMCP server instance

    Returns:
        ElicitResult containing the user's response

    Raises:
        RuntimeError: If Docket is not available
        McpError: If the elicitation request fails
    Nz}Background task elicitation requires Docket. Ensure 'fastmcp[tasks]' is installed and the server has task-enabled components._fastmcp_state_prefixzCannot determine task scope for elicitation. This typically means elicit_for_task() was called outside a Docket worker context.)
request_idmessageschemaexwaitingznotifications/tasks/statusinput_requiredi  )taskIdstatusstatusMessage	createdAtlastUpdatedAtttlz$io.modelcontextprotocol/related-task)	requestIdr   requestedSchema)r    r!   r"   r   elicitation)methodparams_metazLNo session_id available for task %s, cannot deliver elicitation notificationcancelactioncontentzSFailed to queue input_required notification for task %s, cancelling elicitation: %s)timeoutr.   acceptr/   z@BLPOP failed for task %s elicitation, falling back to cancel: %szIFailed to clean up elicitation keys for task %s (will expire via TTL): %s)!_docketRuntimeErrorstruuiduuid4r	   r   getattrr
   r   redissetkeyjsondumpsELICIT_TTL_SECONDSr   nowr   utc	isoformatloggerwarningmcptypesElicitResultr   	Exceptiondeleteblpoploadsgetdebug)r   sessionr   r   fastmcpdocketr   task_contextr   
session_idrequest_keyresponse_key
status_keyelicit_requestr8   	timestampnotification_dictemax_wait_secondsresult_keyresponse_dataresponsecleanup_errors                           r   elicit_for_taskr^   /   s    4 __F~_
 	
 TZZ\"J#%L!,,
 G4d;T?R?T 	 a
 	
 -9W,M)Kz !N ||~~iiJJ{#JJ~&!  
 	
 	
 iiJJz"!  
 	
 	
 ~( X\\*446I.&$"&%,
 3!*!((!+&'- 
5
2 Z	
 yy%%Xt%DDE
,=vFFF. *
<<>>U !;;L)*( '  F
 &,#m::m4 llJJ{+JJz*   yy--#<<(;$LL3 . ) ">>>>B
<<>>U,,

;'

<(

:&   "> 99!!4!@@ 	
	
 ~~~l 	G E 	a	
	||~~llJJ{+JJz*   &~~~~
  		yy%%Xt%DD#E2 " ">>>>0  
N	
 	

 " ">>>  
W	
 	

sP  BS7 M!S7$>M%"M#.M%MM%S7!M""BS71M> M;M> S7Q< !Q"Q< %'Q&QAQ& Q!AQ&$Q< 0Q 1Q< 5S76Q< Q#Q< S	 R*S	 AR3#R-$R3(S	 3R04S	 8"S7M%M%"S7%M8+M.,M83S7;M> >	QQP3N64P84P,O/-P2P=P >PP	
PP	PQ	P&#Q%P&&#Q	Q
S7QS7Q< Q&Q& Q< #Q< &Q9,Q/-Q94Q< <	R'R"S7"R''S7*S	 -R30S	 3S9R<:SS	 		S4S/)S7/S44S7c                  K   	 | j                  |d   |d          d{   }t        |||j                  |j                  |       d{    t        j                  d||j                         y7 R7 (# t        $ rW}t        j                  d||       t        ||dd|       d{  7  }|st        j                  d	|       Y d}~yY d}~yd}~ww xY ww)
ah  Relay elicitation from a background task worker to the client.

    Called by the notification subscriber when it detects an input_required
    notification with elicitation metadata. Sends a standard elicitation/create
    request to the client session, then uses handle_task_input() to push the
    response to Redis so the blocked worker can resume.

    Args:
        session: MCP ServerSession
        task_scope: Authorization scope for Redis key construction
        task_id: Background task ID
        elicitation: Elicitation metadata (message, requestedSchema)
        fastmcp: FastMCP server instance
    r   r'   )r   r'   N)r   r   r.   r/   rM   z4Relayed elicitation response for task %s (action=%s)z+Failed to relay elicitation for task %s: %sr,   zGFailed to push cancel response for task %s (worker may block until TTL))elicithandle_task_inputr.   r/   rA   rK   rF   rB   )rL   r   r   r(   rM   rY   rW   successs           r   relay_elicitationrc      s     * ~~	*'(9: & 
 
  !==NN
 	
 	
 	BMM	

	
  DgqQ)!
 
 
 NN/  s\   CA7 A3+A7 A5%A7 2C3A7 5A7 7	C *C*B-+C
CCCc                  K   |j                   }|yt        ||       \  }}}||d}	|j                         4 d{   }
|
j                  |j	                  |             d{   }||j                  d      dk7  r	 ddd      d{    y|
j                  |j	                  |      t        j                  |	             d{    |
j                  |j	                  |      t               d{    |
j                  |j	                  |      dt               d{    ddd      d{    y7 7 7 7 w7 L7 7 # 1 d{  7  sw Y   yxY ww)	a'  Handle input sent to a background task via tasks/sendInput.

    This is called when a client sends input in response to an elicitation
    request from a background task.

    Args:
        task_id: The background task ID
        task_scope: Authorization scope for Redis key construction
        action: The elicitation action ("accept", "decline", "cancel")
        content: The response content (for "accept" action)
        fastmcp: The FastMCP server instance

    Returns:
        True if the input was successfully stored, False otherwise
    NFr-   zutf-8r   	respondedr   T)r2   r   r8   rJ   r:   decodelpushr;   r<   expirer=   r9   )r   r   r.   r/   rM   rN   _rR   rS   r\   r8   r!   s               r   ra   ra   $  sD    , __F~".z7"CA|Z H
 ||~~yyJ!788>V]]73y@	 ~~ kkJJ|$JJx 
 	
 	

 ll6::l35GHHH iiJJz"!  
 	
 	
! ~, - 8 	

 	I	
! ~~~, s   9ED9E$E#D;$E?E
D=E7ED?,E4E5.E#E$E(E3E4E;E=E?EEEEEEEE)r   
str | Noner   r4   returnztuple[str, str, str])r   r4   rL   zServerSession | Noner   r4   r   dict[str, Any]rM   r   rk   zmcp.types.ElicitResult)rL   r   r   rj   r   r4   r(   rl   rM   r   rk   None)r   r4   r   rj   r.   r4   r/   zdict[str, Any] | NonerM   r   rk   bool)__doc__
__future__r   r;   loggingr5   r   r   typingr   r   	mcp.typesrC   r   fastmcp.server.tasks.contextr	   r
   fastmcp.server.tasks.keysr   "fastmcp.server.tasks.notificationsr   	getLogger__name__rA   fastmcp.server.serverr   r=   r   r^   rc   ra    r   r   <module>r{      s   #    ' %   N 7 @			8	$-  IzAzA!zA zA 	zA
 zA zAz555 5  	5
 5 
5p777 7 #	7
 7 
7r   