
    i'                       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 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jD                  e#      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TypeVar)NotFoundError)Provider)	Namespace)gather)FastMCPComponent)VersionSpecversion_sort_key)Prompt)Resource)ResourceTemplate)ToolTc                       e Zd ZdZ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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 (graceful degradation).

    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.
        ```
    c                J    t         |           t        |xs g       | _        y)zInitialize with an optional sequence of providers.

        Args:
            providers: Optional initial providers (without namespacing).
                For namespaced providers, use add_provider() instead.
        N)super__init__list	providers)selfr   	__class__s     r/Users/bowang/.openclaw/workspace/ChatDev/.venv/lib/python3.12/site-packages/fastmcp/server/providers/aggregate.pyr   zAggregateProvider.__init__D   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_providerN   sL     	2 h(Q&x0H ..y/CDHh'r    c           	         g }t        |      D ]R  \  }}t        |t              r,t        j	                  d| d| j
                  |    d|        B|j                  |       T |S )z8Collect successful list results, logging any exceptions.Error during  from provider : )	enumerater'   BaseExceptionloggerdebugr   extend)r   results	operation	collectediresults         r   _collect_list_resultsz'AggregateProvider._collect_list_resultsj   sp      	"7+IAv&-0#I;o~~a()F85 V$ , r    c           	        g }t        |      D ]e  \  }}t        |t              r<t        |t              s+t        j                  d| d| j                  |    d|        R|U|j                  |       g |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.   r/   r0   N)key)
r1   r'   r2   r
   r3   r4   r   r*   maxr   )r   r6   r7   validr9   r:   s         r   _get_highest_version_resultz-AggregateProvider._get_highest_version_resulty   s     )+"7+IAv&-0!&-8LL'	{/>>!,-Rx9 !V$ , 5.//r    c                "    d| j                   dS )NzAggregateProvider(providers=))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   rF   r;   r   pr6   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.rE   TNz	get_tool(rB   )r   r   get_toolr@   r   nameversionrH   r6   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{   }| j                  |d      S c c}w 7 w)z&List all resources from all providers.rE   TNlist_resources)r   r   rS   r;   rG   s      r   _list_resourcesz!AggregateProvider._list_resources   s\     *...9.Qa .9
"
 
 ))'3CDD :
rJ   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.rE   TNzget_resource(rB   )r   r   get_resourcer@   r   urirO   rH   r6   s        r   _get_resourcezAggregateProvider._get_resource   si      48NNCNqannS'*NC
"
 
 //=q9QRR D
rQ   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.rE   TNlist_resource_templates)r   r   r[   r;   rG   s      r   _list_resource_templatesz*AggregateProvider._list_resource_templates   s]     37>>B>aa'')>B
"
 
 ))'3LMM C
rJ   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 template by URI from providers.rE   TNzget_resource_template(rB   )r   r   get_resource_templater@   rW   s        r   _get_resource_templatez(AggregateProvider._get_resource_template   sq      =A^^L^a%%c73^L
"
 
 //-cWA6
 	
 M
rQ   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.rE   TNlist_prompts)r   r   ra   r;   rG   s      r   _list_promptszAggregateProvider._list_prompts   sY     (,71ann7
"
 
 ))'>BB 8
rJ   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.rE   TNzget_prompt(rB   )r   r   
get_promptr@   rM   s        r   _get_promptzAggregateProvider._get_prompt   si      37>>B>aall4)>B
"
 
 //;tha9PQQ C
rQ   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.rE   TN	get_tasks)r   r   rg   r;   rG   s      r   rg   zAggregateProvider.get_tasks   sX     %)^^4^akkm^4
"
 
 ))';?? 5
rJ   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   stackrH   s      r   rj   zAggregateProvider.lifespan   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] | NonereturnNone)r+   r   r"   strrl   rm   )r6   z!list[Sequence[T] | BaseException]r7   rn   rl   zlist[T])r6   z-list[FastMCPComponent | None | BaseException]r7   rn   rl   zFastMCPComponent | None)rl   rn   )rl   zSequence[Tool])rN   rn   rO   VersionSpec | Nonerl   zTool | None)rl   zSequence[Resource])rX   rn   rO   ro   rl   zResource | None)rl   zSequence[ResourceTemplate])rX   rn   rO   ro   rl   zResourceTemplate | None)rl   zSequence[Prompt])rN   rn   rO   ro   rl   zPrompt | None)rl   zSequence[FastMCPComponent])rl   zAsyncIterator[None])__name__
__module____qualname____doc__r   r,   r;   r@   rC   rI   rP   rT   rY   r\   r_   rb   re   rg   r   rj   __classcell__)r   s   @r   r   r   .   s#   *? DF (88EH	0>0 0 
!	02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   )'rs   
__future__r   loggingcollections.abcr   r   
contextlibr   r   typingr   r	   fastmcp.exceptionsr
   fastmcp.server.providers.baser   fastmcp.server.transformsr   fastmcp.utilities.async_utilsr   fastmcp.utilities.componentsr   fastmcp.utilities.versionsr   r   fastmcp.prompts.promptr   fastmcp.resources.resourcer   fastmcp.resources.templater   fastmcp.tools.toolr   	getLoggerrp   r3   r   r    r    r   <module>r      se   ( #  3 : ) , 2 / 0 9 D-3;'			8	$CLW Wr    