
    kKj4                    $   d Z ddlmZ ddlZddlmZmZ ddlmZm	Z	 ddl
mZ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 erddlmZ ddlmZ ddlm Z  ddl!m"Z"  ejF                  e$      Z% ed      Z&ed   Z' G d de      Z(y)ay  AggregateProvider for combining multiple providers into one.

This module provides `AggregateProvider`, a utility class that presents
multiple providers as a single unified provider. Useful when you want to
combine custom providers without creating a full FastMCP server.

Example:
    ```python
    from fastmcp.server.providers import AggregateProvider

    # Combine multiple providers into one
    combined = AggregateProvider()
    combined.add_provider(provider1)
    combined.add_provider(provider2, namespace="api")  # Tools become "api_foo"

    # Use like any other provider
    tools = await combined.list_tools()
    ```
    )annotationsN)AsyncIteratorSequence)AsyncExitStackasynccontextmanager)TYPE_CHECKINGLiteralTypeVar)NotFoundError)Provider)	Namespace)gather)FastMCPComponent)VersionSpecversion_sort_key)Prompt)Resource)ResourceTemplate)ToolT)warnraisec                      e Zd ZdZ	 ddd	 	 	 	 	 d fdZddddZ	 	 	 	 	 	 ddZ	 	 	 	 	 	 dd	Zdd
ZddZ		 d	 	 	 	 	 ddZ
ddZd dZd!dZ	 d	 	 	 	 	 d"dZd#dZ	 d	 	 	 	 	 d$dZd%dZ	 d	 	 	 	 	 d&dZd'dZed(d       Z xZS ))AggregateProvidera  Utility provider that combines multiple providers into one.

    Components are aggregated from all providers. For get_* operations,
    providers are queried in parallel and the highest version is returned.

    When adding providers with a namespace, wrap_transform() is used to apply
    the Namespace transform. This means namespace transformation is handled
    by the wrapped provider, not by AggregateProvider.

    Errors from individual providers are logged and skipped by default. Set
    ``provider_error_strategy="raise"`` to fail the aggregate operation when
    any provider fails.

    Example:
        ```python
        combined = AggregateProvider()
        combined.add_provider(db_provider)
        combined.add_provider(api_provider, namespace="api")
        # db_provider's tools keep original names
        # api_provider's tools become "api_foo", "api_bar", etc.
        ```
    r   )provider_error_strategyc               X    t         |           || _        t        |xs g       | _        y)a  Initialize with an optional sequence of providers.

        Args:
            providers: Optional initial providers (without namespacing).
                For namespaced providers, use add_provider() instead.
            provider_error_strategy: How provider errors should affect aggregate
                operations. ``"warn"`` logs and skips failed providers.
                ``"raise"`` propagates the first provider error.
        N)super__init__r   list	providers)selfr    r   	__class__s      s/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/fastmcp/server/providers/aggregate.pyr   zAggregateProvider.__init__G   s(     	'>$)-io2)>     )	namespacec                   ddl m} t        ||      rddlm}  ||      }|r|j                  t        |            }| j                  j                  |       y)a  Add a provider with optional namespace.

        If the provider is a FastMCP server, it's automatically wrapped in
        FastMCPProvider to ensure middleware is invoked correctly.

        Args:
            provider: The provider to add.
            namespace: Optional namespace prefix. When set:
                - Tools become "namespace_toolname"
                - Resources become "protocol://namespace/path"
                - Prompts become "namespace_promptname"
        r   )FastMCP)FastMCPProviderN)	fastmcp.server.serverr(   
isinstance)fastmcp.server.providers.fastmcp_providerr)   wrap_transformr   r    append)r!   providerr&   r(   r)   s        r#   add_providerzAggregateProvider.add_providerZ   sL     	2 h(Q&x0H ..y/CDHh'r$   c                   g }i }t        |      D ]  \  }}t        |t              r=| j                  dk(  r|t        j                  d| d| j                  |    d|        S|D ]u  }t        |dd      }|S|j                  ||      }	|	|k7  r<t        j                  d| d|d| j                  |    d	| j                  |	    d
	       |j                  |       w  |S )u  Collect successful list results, logging any exceptions.

        Emits a warning when the same MCP identity is returned by more than
        one provider — surfaces composition mistakes to the server author.
        This is always a warning: cross-provider collisions happen at runtime
        (sometimes dynamically), so an errorable/strict mode would give the
        author no way to react and would crash list calls in production.
        r   Error during  from provider : keyNz
Duplicate z component z (first seen from provider ))
	enumerater+   BaseExceptionr   loggerwarningr    getattr
setdefaultr.   )
r!   results	operation	collected	seen_keysiresultitemr5   firsts
             r#   _collect_list_resultsz'AggregateProvider._collect_list_resultsv   s     	 %'	"7+IAv&-0//7: L#I;o~~a()F85 dE40?%00a8Ez(;sg F--1^^A->,? @99=9N8OqR
   &  ,( r$   c           	     6   g }t        |      D ]v  \  }}t        |t              rMt        |t              s<| j                  dk(  r|t
        j                  d| d| j                  |    d|        c|f|j                  |       x |syt        |t              S )zGet the highest version from successful non-None results.

        Used for versioned components where we want the highest version
        across all providers rather than the first match.
        r   r2   r3   r4   N)r5   )r7   r+   r8   r   r   r9   r:   r    r.   maxr   )r!   r=   r>   validrA   rB   s         r#   _get_highest_version_resultz-AggregateProvider._get_highest_version_result   s     )+"7+IAv&-0!&-833w>$NN'	{/>>!,-Rx9 !V$ , 5.//r$   c                "    d| j                   dS )NzAggregateProvider(providers=r6   )r    )r!   s    r#   __repr__zAggregateProvider.__repr__   s    -dnn-?qAAr$   c                   K   t        | j                  D cg c]  }|j                          c}ddi d{   }| j                  |d      S c c}w 7 w)z"List all tools from all providers.return_exceptionsTN
list_tools)r   r    rN   rE   r!   pr=   s      r#   _list_toolszAggregateProvider._list_tools   sX     &*nn5nallnn5
"
 
 ))'<@@ 6
   AA
AAAc           	        K   t        | j                  D cg c]  }|j                  ||       c}ddi d{   }| j                  |d|d      S c c}w 7 w)z Get tool by name from providers.rM   TNz	get_tool(r6   )r   r    get_toolrI   r!   nameversionrP   r=   s        r#   	_get_toolzAggregateProvider._get_tool   si      15@Aajjw'@
"
 
 //9THA9NOO A
   AA
AA Ac           	        K   t        | j                  D cg c]  }|j                  ||       c}ddi d{   }|D ]*  }t        |t              r| j
                  dk(  r|%|(|c S  yc c}w 7 9w)z*Query all child providers for an app tool.rM   TNr   )r   r    get_app_toolr+   r8   r   )r!   app_name	tool_namerP   r=   rs         r#   r[   zAggregateProvider.get_app_tool   s     ;?>>J>aannXy1>J
"
 
 A!]+//7:G}   K
   A5A.
A5A3-A5(A5c           	        K   t        | j                  D cg c]  }|j                  ||       c}ddi d{   }|D ]*  }t        |t              r| j
                  dk(  r|%|(|c S  yc c}w 7 9w)z5Query all child providers for a tool matching a hash.rM   TNr   )r   r    get_tool_by_hashr+   r8   r   )r!   	tool_hashr]   rP   r=   r^   s         r#   ra   z"AggregateProvider.get_tool_by_hash   s     @DO1a  I6O
"
 
 A!]+//7:G}   P
r_   c                   K   t        | j                  D cg c]  }|j                          c}ddi d{   }| j                  |d      S c c}w 7 w)z&List all resources from all providers.rM   TNlist_resources)r   r    rd   rE   rO   s      r#   _list_resourcesz!AggregateProvider._list_resources   s\     *...9.Qa .9
"
 
 ))'3CDD :
rR   c           	        K   t        | j                  D cg c]  }|j                  ||       c}ddi d{   }| j                  |d|d      S c c}w 7 w)z#Get resource by URI from providers.rM   TNzget_resource(r6   )r   r    get_resourcerI   r!   urirW   rP   r=   s        r#   _get_resourcezAggregateProvider._get_resource   si      48NNCNqannS'*NC
"
 
 //=q9QRR D
rY   c                   K   t        | j                  D cg c]  }|j                          c}ddi d{   }| j                  |d      S c c}w 7 w)z/List all resource templates from all providers.rM   TNlist_resource_templates)r   r    rl   rE   rO   s      r#   _list_resource_templatesz*AggregateProvider._list_resource_templates  s]     37>>B>aa'')>B
"
 
 ))'3LMM C
rR   c           	        K   t        | j                  D cg c]  }|j                  ||       c}ddi d{   }| j                  t	        |      d|d      S c c}w 7 (w)z,Get resource template by URI from providers.rM   TNzget_resource_template(r6   )r   r    get_resource_templaterI   r   rh   s        r#   _get_resource_templatez(AggregateProvider._get_resource_template  su      =A^^L^a%%c73^L
"
 
 //M3C7!<
 	
 M
s   A$A
A$A")A$c                   K   t        | j                  D cg c]  }|j                          c}ddi d{   }| j                  |d      S c c}w 7 w)z$List all prompts from all providers.rM   TNlist_prompts)r   r    rr   rE   rO   s      r#   _list_promptszAggregateProvider._list_prompts   sY     (,71ann7
"
 
 ))'>BB 8
rR   c           	        K   t        | j                  D cg c]  }|j                  ||       c}ddi d{   }| j                  |d|d      S c c}w 7 w)z"Get prompt by name from providers.rM   TNzget_prompt(r6   )r   r    
get_promptrI   rU   s        r#   _get_promptzAggregateProvider._get_prompt(  si      37>>B>aall4)>B
"
 
 //;tha9PQQ C
rY   c                   K   t        | j                  D cg c]  }|j                          c}ddi d{   }| j                  |d      S c c}w 7 w)z4Get all task-eligible components from all providers.rM   TN	get_tasks)r   r    rx   rE   rO   s      r#   rx   zAggregateProvider.get_tasks6  sX     %)^^4^akkm^4
"
 
 ))';?? 5
rR   c                 K   t               4 d{   }| j                  D ])  }|j                  |j                                d{    + d ddd      d{    y7 R7 7 	# 1 d{  7  sw Y   yxY ww)z#Combine lifespans of all providers.N)r   r    enter_async_contextlifespan)r!   stackrP   s      r#   r{   zAggregateProvider.lifespanB  s]      "##u^^//

=== $ $##= $###sV   A?A$A?2A*A&A*A?A(A?&A*(A?*A<0A31A<8A?)N)r    zSequence[Provider] | Noner   ProviderErrorStrategyreturnNone)r/   r   r&   strr~   r   )r=   z!list[Sequence[T] | BaseException]r>   r   r~   zlist[T])r=   z-list[FastMCPComponent | None | BaseException]r>   r   r~   zFastMCPComponent | None)r~   r   )r~   zSequence[Tool])rV   r   rW   VersionSpec | Noner~   Tool | None)r\   r   r]   r   r~   r   )rb   r   r]   r   r~   r   )r~   zSequence[Resource])ri   r   rW   r   r~   zResource | None)r~   zSequence[ResourceTemplate])ri   r   rW   r   r~   zResourceTemplate | None)r~   zSequence[Prompt])rV   r   rW   r   r~   zPrompt | None)r~   zSequence[FastMCPComponent])r~   zAsyncIterator[None])__name__
__module____qualname____doc__r   r0   rE   rI   rK   rQ   rX   r[   ra   re   rj   rm   rp   rs   rv   rx   r   r{   __classcell__)r"   s   @r#   r   r   /   sZ   2 04? :@	?,? "7	?
 
?& DF (8$8$EH$	$L0>0 0 
!	06BA 8<PP"4P	P&E 7;SS!3S	SN 7;



!3

	 

 C 8<RR"4R	R@  r$   r   ))r   
__future__r   loggingcollections.abcr   r   
contextlibr   r   typingr   r	   r
   fastmcp.exceptionsr   fastmcp.server.providers.baser   fastmcp.server.transformsr   fastmcp.utilities.async_utilsr   fastmcp.utilities.componentsr   fastmcp.utilities.versionsr   r   fastmcp.prompts.baser   fastmcp.resources.baser   fastmcp.resources.templater   fastmcp.tools.baser   	getLoggerr   r9   r   r}   r    r$   r#   <module>r      ss   ( #  3 : 2 2 , 2 / 0 9 D+/;'			8	$CL0 Y Yr$   