
    $j0                        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j"        e#          Z$ ed          Z% G d de          Z&dS )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d5d6 fdZdd	d7dZd8dZd9dZd:dZd;dZ		 d5d<dZ
d=d!Zd>d#Zd?d%Z	 d5d@d(ZdAd*Z	 d5dBd,ZdCd.Z	 d5dDd0ZdEd2ZedFd4            Z xZS )G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.
        ```
    N	providersSequence[Provider] | NonereturnNonec                t    t                                                       t          |pg           | _        dS )zInitialize with an optional sequence of providers.

        Args:
            providers: Optional initial providers (without namespacing).
                For namespaced providers, use add_provider() instead.
        N)super__init__listr   )selfr   	__class__s     j/home/rurouni/.hermes/hermes-agent/venv/lib/python3.11/site-packages/fastmcp/server/providers/aggregate.pyr   zAggregateProvider.__init__D   s2     	)-io2)>)>     )	namespaceproviderr   r%   strc                   ddl m} t          ||          rddlm}  ||          }|r"|                    t          |                    }| j                            |           dS )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    r&   r%   r)   r*   s        r"   add_providerzAggregateProvider.add_providerN   s     	211111 h(( 	1QQQQQQ&x00H  	E..y/C/CDDHh'''''r#   results!list[Sequence[T] | BaseException]	operationlist[T]c                   g }i }t          |          D ]\  }}t          |t                    r/t                              d| d| j        |          d|            I|D ]}t          |dd          }|Y|                    ||          }	|	|k    r=t                              d| d|d| j        |          d| j        |	          d		           |                    |           |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.
        Error during  from provider : keyNz
Duplicate z component z (first seen from provider ))		enumerater,   BaseExceptionloggerwarningr   getattr
setdefaultr/   )
r    r1   r3   	collected	seen_keysiresultitemr9   firsts
             r"   _collect_list_resultsz'AggregateProvider._collect_list_resultsj   s]     	 %'	"7++ 	' 	'IAv&-00 5I 5 5~a(5 5,25 5    
' 
'dE400?%00a88EzzR R Rs R R-1^A->R R9=9NR R R  
   &&&&
' r#   -list[FastMCPComponent | None | BaseException]FastMCPComponent | Nonec           	     D   g }t          |          D ]u\  }}t          |t                    rDt          |t                    s.t                              d| d| j        |          d|            ^||                    |           v|sdS 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.
        r6   r7   r8   N)r9   )
r;   r,   r<   r
   r=   r>   r   r/   maxr   )r    r1   r3   validrC   rD   s         r"   _get_highest_version_resultz-AggregateProvider._get_highest_version_result   s     )+"7++ 		% 		%IAv&-00 !&-88 NN9	 9 9>!,9 9069 9   !V$$$ 	45.////r#   c                    d| j         dS )NzAggregateProvider(providers=r:   )r   )r    s    r"   __repr__zAggregateProvider.__repr__   s    AdnAAAAr#   Sequence[Tool]c                t   K   t          d | j        D             ddi d{V }|                     |d          S )z"List all tools from all providers.c                6    g | ]}|                                 S  )
list_tools.0ps     r"   
<listcomp>z1AggregateProvider._list_tools.<locals>.<listcomp>   s     555allnn555r#   return_exceptionsTNrT   r   r   rG   r    r1   s     r"   _list_toolszAggregateProvider._list_tools   sf      55dn555
"
 
 
 
 
 
 
 
 ))'<@@@r#   nameversionVersionSpec | NoneTool | Nonec                   K   t          fd| j        D             ddi d{V }|                     |dd          S )z Get tool by name from providers.c                <    g | ]}|                               S rS   )get_toolrV   rW   r]   r^   s     r"   rX   z/AggregateProvider._get_tool.<locals>.<listcomp>   s'    @@@Aajjw''@@@r#   rY   TNz	get_tool(r:   r   r   rM   r    r]   r^   r1   s    `` r"   	_get_toolzAggregateProvider._get_tool   s       @@@@@@@@
"
 
 
 
 
 
 
 
 //9NT9N9N9NOOOr#   app_name	tool_namec                   K   t          fd| j        D             ddi d{V }|D ]}t          |t                    r||c S dS )z*Query all child providers for an app tool.c                <    g | ]}|                               S rS   )get_app_tool)rV   rW   rh   ri   s     r"   rX   z2AggregateProvider.get_app_tool.<locals>.<listcomp>   s'    JJJaannXy11JJJr#   rY   TNr   r   r,   r<   )r    rh   ri   r1   rs    ``  r"   rl   zAggregateProvider.get_app_tool   s      JJJJJ4>JJJ
"
 
 
 
 
 
 
 
  	 	A!]++ } tr#   	tool_hashc                   K   t          fd| j        D             ddi d{V }|D ]}t          |t                    r||c S dS )z5Query all child providers for a tool matching a hash.c                <    g | ]}|                               S rS   )get_tool_by_hash)rV   rW   ro   ri   s     r"   rX   z6AggregateProvider.get_tool_by_hash.<locals>.<listcomp>   s)    OOO1a  I66OOOr#   rY   TNrm   )r    ro   ri   r1   rn   s    ``  r"   rr   z"AggregateProvider.get_tool_by_hash   s      OOOOOOOO
"
 
 
 
 
 
 
 
  	 	A!]++ } tr#   Sequence[Resource]c                t   K   t          d | j        D             ddi d{V }|                     |d          S )z&List all resources from all providers.c                6    g | ]}|                                 S rS   )list_resourcesrU   s     r"   rX   z5AggregateProvider._list_resources.<locals>.<listcomp>   s$    999Qa  999r#   rY   TNrv   rZ   r[   s     r"   _list_resourcesz!AggregateProvider._list_resources   sg      99$.999
"
 
 
 
 
 
 
 
 ))'3CDDDr#   uriResource | Nonec                   K   t          fd| j        D             ddi d{V }|                     |dd          S )z#Get resource by URI from providers.c                <    g | ]}|                               S rS   )get_resourcerV   rW   rx   r^   s     r"   rX   z3AggregateProvider._get_resource.<locals>.<listcomp>   s'    CCCqannS'**CCCr#   rY   TNzget_resource(r:   re   r    rx   r^   r1   s    `` r"   _get_resourcezAggregateProvider._get_resource   s       CCCCCDNCCC
"
 
 
 
 
 
 
 
 //9Q9Q9Q9QRRRr#   Sequence[ResourceTemplate]c                t   K   t          d | j        D             ddi d{V }|                     |d          S )z/List all resource templates from all providers.c                6    g | ]}|                                 S rS   )list_resource_templatesrU   s     r"   rX   z>AggregateProvider._list_resource_templates.<locals>.<listcomp>   s$    BBBaa''))BBBr#   rY   TNr   rZ   r[   s     r"   _list_resource_templatesz*AggregateProvider._list_resource_templates   sg      BB4>BBB
"
 
 
 
 
 
 
 
 ))'3LMMMr#   ResourceTemplate | Nonec                   K   t          fd| j        D             ddi d{V }|                     t          |          dd          S )z,Get resource template by URI from providers.c                <    g | ]}|                               S rS   )get_resource_templater}   s     r"   rX   z<AggregateProvider._get_resource_template.<locals>.<listcomp>  s)    LLLa%%c733LLLr#   rY   TNzget_resource_template(r:   )r   r   rM   r   r~   s    `` r"   _get_resource_templatez(AggregateProvider._get_resource_template   s       LLLLLT^LLL
"
 
 
 
 
 
 
 
 //MM<C<<<
 
 	
r#   Sequence[Prompt]c                t   K   t          d | j        D             ddi d{V }|                     |d          S )z$List all prompts from all providers.c                6    g | ]}|                                 S rS   )list_promptsrU   s     r"   rX   z3AggregateProvider._list_prompts.<locals>.<listcomp>  s"    7771ann777r#   rY   TNr   rZ   r[   s     r"   _list_promptszAggregateProvider._list_prompts  sf      77777
"
 
 
 
 
 
 
 
 ))'>BBBr#   Prompt | Nonec                   K   t          fd| j        D             ddi d{V }|                     |dd          S )z"Get prompt by name from providers.c                <    g | ]}|                               S rS   )
get_promptrd   s     r"   rX   z1AggregateProvider._get_prompt.<locals>.<listcomp>  s'    BBBaall4))BBBr#   rY   TNzget_prompt(r:   re   rf   s    `` r"   _get_promptzAggregateProvider._get_prompt  s       BBBBB4>BBB
"
 
 
 
 
 
 
 
 //9Pt9P9P9PQQQr#   Sequence[FastMCPComponent]c                t   K   t          d | j        D             ddi d{V }|                     |d          S )z4Get all task-eligible components from all providers.c                6    g | ]}|                                 S rS   )	get_tasksrU   s     r"   rX   z/AggregateProvider.get_tasks.<locals>.<listcomp>%  s     444akkmm444r#   rY   TNr   rZ   r[   s     r"   r   zAggregateProvider.get_tasks"  sf      44T^444
"
 
 
 
 
 
 
 
 ))';???r#   AsyncIterator[None]c                  K   t                      4 d{V }| j        D ]/}|                    |                                           d{V  0dW V  ddd          d{V  dS # 1 d{V swxY w Y   dS )z#Combine lifespans of all providers.N)r   r   enter_async_contextlifespan)r    stackrW   s      r"   r   zAggregateProvider.lifespan.  s      "## 	 	 	 	 	 	 	u^ > >//

==========EEEE	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   =A''
A14A1)N)r   r   r   r   )r&   r   r%   r'   r   r   )r1   r2   r3   r'   r   r4   )r1   rH   r3   r'   r   rI   )r   r'   )r   rP   )r]   r'   r^   r_   r   r`   )rh   r'   ri   r'   r   r`   )ro   r'   ri   r'   r   r`   )r   rs   )rx   r'   r^   r_   r   ry   )r   r   )rx   r'   r^   r_   r   r   )r   r   )r]   r'   r^   r_   r   r   )r   r   )r   r   )__name__
__module____qualname____doc__r   r0   rG   rM   rO   r\   rg   rl   rr   rw   r   r   r   r   r   r   r   r   __classcell__)r!   s   @r"   r   r   .   s        *? ? ? ? ? ? ? DF ( ( ( ( ( (8" " " "H0 0 0 02B B B BA A A A 8<P P P P P      "E E E E 7;S S S S SN N N N 7;

 

 

 

 

 C C C C 8<R R R R R@ @ @ @        r#   r   )'r   
__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.baser   fastmcp.resources.baser   fastmcp.resources.templater   fastmcp.tools.baser   	getLoggerr   r=   r   r   rS   r#   r"   <module>r      s   ( # " " " " "  3 3 3 3 3 3 3 3 : : : : : : : : ) ) ) ) ) ) ) ) , , , , , , 2 2 2 2 2 2 / / / / / / 0 0 0 0 0 0 9 9 9 9 9 9 D D D D D D D D (++++++//////;;;;;;''''''		8	$	$GCLLF F F F F F F F F Fr#   