
    0ja                        d Z ddlZddlZddlZddlZddlmZmZm	Z	m
Z
mZmZmZmZmZmZmZ ddlmZ ddlmZmZ ddlmZmZmZmZmZmZmZmZm Z m!Z!m"Z"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-m.Z.m/Z/m0Z0 erddl1m2Z2 ddl3m4Z4 ddl5m6Z6 ddl7m8Z8 ddl9m:Z: ddl;m<Z< ddl=m>Z> ddl?m@Z@ ddlAmBZB ddlCmDZD ddlEmFZFmGZGmHZHmIZImJZJmKZK ddlLmMZMmNZN ddlOmPZPmQZQ ddlRmSZSmTZT ddlUmVZVmWZW ddlXmYZYmZZZ ddl[m\Z\ ddl]m^Z^ ddl_m`Z` ddlambZb ejc        d                    d           Zd ed!e
d"ef         #          Ze ed$e
eDe         gef         #          Zf e ed%&                     d'ed Zg ejh        ei          Zj G d( d)eY          ZkdS )*z[
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License.
    N)TYPE_CHECKINGAny	AwaitableCallableListOptionalTypeVarUnionUnpackcastoverload)	providers)find_dotenvload_dotenv)AccountActivityBaseActivityParams	ApiClientClientCredentialsConversationAccountConversationReferenceCredentialsFederatedIdentityCredentialsManagedIdentityCredentialsMessageActivityInputSentActivityTokenCredentialsTokenProtocol)PUBLIC)	from_name)AdaptiveCard)ClientClientOptionsEventEmitterLocalStorage)GraphServiceClient   )ActivitySender)EventManager)OauthHandlers)PluginProcessor)ActivityProcessor)TokenValidator) validate_remote_function_request)	Container)FunctionContext)
ErrorEvent	EventType
StartEvent	StopEventget_event_type_from_signatureis_registered_event)FastAPIAdapter
HttpServer)HttpRequestHttpResponse)
AppOptionsInternalAppOptions)
PluginBasePluginStartEvent)ActivityHandlerMixinActivityRouter)ActivityContext)TokenManager)create_graph_client)to_threaded_conversation_idzmicrosoft-teams-appsF.)boundFCtxT)usecwdzteams.py[apps]/c            	          e Zd ZdZdee         fdZedee	         fd            Z
edee         fd            Zedefd            Zedee         fd            Zd/d
ZdedefdZd0dee	         dd	fdZd/dZdedeez  ez  fdZedededeez  ez  defd            Zededeez  ez  defd            Z	 	 d1dedeez  ez  deez  ez  d	z  defdZdeee         ge d	         f         dd	fdZ!de"fdZ#dee$         fdZ%ede&de&fd            Z'ede(eef         dee&ge&f         fd            Z'ed0dd	dee&ge&f         fd            Z'	 d0de(e&eed	f         de(e&ee&ge&f         f         fd Z'd0d!ed"ed#ee         dd	fd$Z)d!ed%edd	fd&Z*d0d'e(ee+d	f         de(e+ee+ge+f         f         fd(Z,d/d)Z-d* Z.d0d+ee         dee/         fd,Z0d0d+ee         dd-fd.Z1d	S )2Appz
    The main Teams application orchestrator.

    Manages plugins, tokens, and application lifecycle for Microsoft Teams apps.
    optionsc                 
    t          j        |           _        t          j        d          } j        j        p|rt          |          nt           _         j        j        pt                       _         
                                 _        t          t                                _        t                       _                                          _        t'           j         j                   _        t+                       _         j                            dt1          j         j                              j                            dt1          j         j                              j                            dt1          j         fd                      j                            dt1          j         j                              j                             j        j        j        t1          j         fd                      j        j        pt          j        d	          pd
                    d          }tA          | j        !                    tE           j#                             j        j$         j                   _%        tM           j        j'                  } j        j(        ptS                      }tU          | j        j+                   _,         j                            dt1          j         j,                             d  _-        d _.        t_           j        !                    tE           j#                                       _0        tc           j         j         j         j        j2         j         j         j        j$         j0         j        	  	         _3        ti           j                   _5         j5         j3        _5        tm           j         j5         j         j3                   _7         j7        8                    |           _'        ts           j        j2         j                  } :                    |j;                    <                    |j=                    >                    |j?                   d  _@         j        rWt           j        d          rDt          jC         j        jD         j        jE         j        jF         j                   _@        d S d S d S )NCLOUD)credentialscloudidrN   	bot_tokenc                       j         S N)_get_bot_tokenselfs   `/home/rurouni/.hermes/hermes-agent/venv/lib/python3.11/site-packages/microsoft_teams/apps/app.py<lambda>zApp.__init__.<locals>.<lambda>k   s
    4K^     storagec                       j         S rS   )http_clientrU   s   rW   rX   zApp.__init__.<locals>.<lambda>m   s    cgcs rY   SERVICE_URLz%https://smba.trafficmanager.net/teams/)tokenrO   )messaging_endpointr8   F)default_connection_nameevent_emitter	client_id)application_id_urirO   )Gr<   from_typeddictrK   osgetenvrO   cloud_from_namer   rZ   r%   _init_http_clientr\   r$   r2   _eventsr@   _router_init_credentialsrN   rB   _token_managerr/   	containerset_providerr   ObjectrP   Factory	__class____name__service_urlrstripr   cloner#   rT   api_client_settingsapilistpluginshttp_server_adapterr7   r8   ra   server_port_initializedr(   activity_senderr,   rb   activity_processorr)   event_managerr+   _plugin_processorinitialize_pluginsr*   on_signin_token_exchangesign_in_token_exchangeon_signin_verify_statesign_in_verify_stateon_signin_failuresign_in_failureentra_token_validatorhasattrr-   	for_entrard   	tenant_idre   )rV   rK   cloud_env_nameru   r{   adapteroauth_handlerss   `      rW   __init__zApp.__init__S   sZ   )8AA 7++\'j~,iON,K,K,Kci
|+=|~~1133#I.00%''1133*(*
 
 

 ###D)*:47*C*CDDD##M93CDDT3U3UVVV##K1BC^C^C^C^1_1_```##Iy/?/M/MNNN##D$4$>$GIZ[s[s[s[sItItuuu L$k	-(@(@kDk
&++ 	 ""=t7J#K#K#KLLL,*	
 
 
 %))=$>$> ,2Fn6F6F T\=\]]]##L)2B4;2O2OPPP$(
!  .d.>.D.D]Y]YlEmEmEm.n.noo #4LGLL0L, J
#
 
#
 *$,77040B-!0ND.d>U"
 "
 -@@II '$(L$H,
 
 
 	%%n&KLLL##N$GHHH~=>>>?C" 	(8+ F F 	)7)A * *#'<#Bj	* * *D&&&	 	 	 	rY   returnc                     | j         S )zPort the app is running on.)r~   rU   s    rW   portzApp.port   s     zrY   c                     | j         S )z+The event emitter instance used by the app.)rk   rU   s    rW   eventsz
App.events        |rY   c                     | j         S )zThe activity router instance.)rl   rU   s    rW   routerz
App.router   r   rY   c                 ,    | j         sdS | j         j        S )zThe app's ID from credentials.N)rN   rd   rU   s    rW   rP   zApp.id   s       	4))rY   Nc           	        K   | j         rt                              d           dS 	 | j        D ]Z}| j                            |           t          |d          r.t          |j                  r|                                 d{V  [| j	        | j
        _        | j
                            | j        | j        j        | j                   d| _         t                              d           dS # t$          $ rO}t                              d|            | j                            dt-          |d	d
i                      d}~ww xY w)a  
        Initialize the Teams application without starting the HTTP server.

        This method sets up credentials, token manager, activity sender, and plugins,
        allowing you to use app.send() for proactive messaging without running a server.
        zApp is already initializedNon_init)rN   	skip_authrO   Tz"Teams app initialized successfullyzFailed to initialize app: errormethod
initializecontext)r   loggerwarningr{   r   injectr   callabler   _process_activity_eventr}   
on_requestr   rN   rK   r   rO   info	Exceptionr   rk   emitr1   )rV   pluginr   s      rW   r   zApp.initialize   si       	NN7888F	, + +&--f55569-- +(6>2J2J + ..********* &*%ADK"K"" ,,0j #    !%DKK<===== 	 	 	LL=e==>>>Lgz%(LAY'Z'Z'Z[[[	s   CC. .
E8A
EEeventc                    K   | j                             |           d{V  | j                            | j        |           d{V S )z[Process an activity event through the app pipeline. Used as HttpServer.on_request callback.N)r   on_activityr   process_activityr{   )rV   r   s     rW   r   zApp._process_activity_event   s\       ,,U333333333,==dlERRRRRRRRRrY   r   c           
        K   |p!t          t          j        dd                    | _        	 | j        s|                                  d{V  g }t          | j                  }| j        D ]P}t          |d          ot          |j
                  }|r(|                    |
                    |                     Qt                              d           | j                            dt!          | j                             |                    | j        j                            | j                             t)          j        |  d{V  dS # t(          j        t.          f$ r t                              d           	 |                                  d{V  d	| _        | j                            d
t5                                 Y dS # d	| _        | j                            d
t5                                 w xY wt6          $ rU}t                              d|            | j                            dt;          |d| j        d                      d}~ww xY w)a5  
        Start the Teams application and begin serving HTTP requests.

        This method will block and keep the application running until stopped.
        This is the main entry point for running your Teams app.

        Args:
            port: Port to listen on (defaults to PORT env var or 3978)
        PORT3978N)r   on_startzTeams app started successfullystartzTeams app shutting downFstopzFailed to start app: r   )r   r   r   )intrg   rh   r~   r   r   r>   r{   r   r   r   appendr   r   rk   r   r3   r}   r   r   asynciogatherCancelledErrorKeyboardInterrupt_stop_plugins_runningr4   r   r   r1   )rV   r   tasksr   r   is_callabler   s          rW   r   z	App.start   sj      ;S66!:!:;;
	$ (oo''''''''' +-E$$*555E, 9 9%fj99Whv>W>W 9LL!7!7888KK8999Lgztz'B'B'BCCCLL,224:>>???.%((((((((((&(9: 	7 	7 	7KK12227((********* %!!&)++666666 !&!!&)++6666 	 	 	LL888999Lgz%G]a]gAhAh'i'i'ijjj	s1   D#E 0IG.I0G>>I
AIIc           	      <  K   	 | j         j                                         d{V  t          | j                  D ]B}t          |d          ot          |j                  }|r|                                 d{V  Ct          	                    d           | j
                            dt                                 dS # t          $ rO}t                              d|            | j
                            dt          |ddi                      d}~ww xY w)	zStop the Teams application.Non_stopzTeams app stoppedr   zFailed to stop app: r   r   r   )r}   r   r   reversedr{   r   r   r   r   r   rk   r   r4   r   r   r1   )rV   r   r   r   s       rW   r   zApp.stop  s4     	+%**,,,,,,,,, #4<00 + +%fi88UXfn=U=U + ..*********KK+,,,Lfikk22222 	 	 	LL777888Lgz%(FAS'T'T'TUUU	s   B<C 
DA
DDconversation_idactivityc                   K   | j         st          d          | j        t          d          t          d| j        j        t          | j                  t          |                    }t          |t                    rt          |          }n9t          |t                    r"t                                          |          }n|}| j                            ||           d{V S )a6  Send an activity proactively to a conversation.

        Sends to the exact conversation ID provided. For channel threads,
        the conversation ID must include ``;messageid=`` - use :func:`to_threaded_conversation_id`
        to construct it, or use :meth:`reply` which handles this automatically.
        z@app not initialized - call app.initialize() or app.start() firstNzapp credentials not configuredmsteams)rP   )
channel_idru   botconversation)text)r   
ValueErrorrP   r   ry   ru   r   r   
isinstancestrr   r!   add_cardr   send)rV   r   r   conversation_refs       rW   r   zApp.send)  s         	a_```7?=>>>0 ,47###,@@@	
 
 
 h$$ 	 +:::HH,// 	 +--66x@@HHH)..x9IJJJJJJJJJrY   
message_idc                 
   K   d S rS    rV   r   r   r   s       rW   replyz	App.replyG  s       srY   c                 
   K   d S rS   r   )rV   r   r   s      rW   r   z	App.replyO  s      
 srY    c                    K   |Nt          |t                    st          d          |                     t	          ||          |           d{V S |                     ||           d{V S )a  Send an activity proactively to a conversation, optionally as a threaded reply.

        **3-arg form** ``reply(conversation_id, message_id, activity)``:
        Constructs a threaded conversation ID via :func:`to_threaded_conversation_id`
        and sends to that thread. The service determines whether threading is
        supported for the given conversation type.

        **2-arg form** ``reply(conversation_id, activity)``:
        Sends to the exact conversation ID provided - threaded if it contains
        ``;messageid=``, flat otherwise.

        Args:
            conversation_id: The conversation ID
            message_id: The thread root message ID (3-arg form) or the activity (2-arg form)
            activity: The activity to send (only in 3-arg form)
        Nz5message_id must be a string when activity is provided)r   r   	TypeErrorr   rD   r   s       rW   r   z	App.replyV  s      , j#.. Y WXXX#>PZ#[#[]efffffffffYY
;;;;;;;;;rY   
middlewarec                 >    | j                             d |           dS )z(Add middleware to run on all activities.c                     dS )NTr   )_s    rW   rX   zApp.use.<locals>.<lambda>u  s    $ rY   N)r   add_handler)rV   r   s     rW   usezApp.uses  s"    
;;;;;rY   c                 (   t          dt          i          }| j        j        }t	          |t
                    r|                    |          S t	          |t                     r"t          |                              |          S t          |          S )zInitialize the HTTP client from options or create a default one.

        Always injects the app's User-Agent header via clone, which merges
        User-Agent values rather than overwriting them.
        z
User-Agent)headers)r#   
USER_AGENTrK   clientr   r"   rw   )rV   
ua_options
client_opts      rW   rj   zApp._init_http_clientw  s     #L*+EFFF
\(
j&)) 	0##J///j-00 	8*%%++J777j!!!rY   c                    | j         j        pt          j        d          }| j         j        pt          j        d          }| j         j        pt          j        d          }| j         j        }| j         j        pt          j        d          }t          	                    d|            |st          
                    d           nt          	                    d| d           |r.|r,t          	                    d	           t          |||
          S |r|rt          |||          S |r|dk    r-t          	                    d           t          |dd|          S |r3||k    r-t          	                    d           t          |d||          S t          	                    d           |p|}t          ||          S dS )zCInitialize authentication credentials from options and environment.	CLIENT_IDCLIENT_SECRET	TENANT_IDMANAGED_IDENTITY_CLIENT_IDzUsing CLIENT_ID: z/TENANT_ID is not set, assuming multi-tenant appzUsing TENANT_ID: z (assuming single-tenant app)zUsing client secret for auth)rd   client_secretr   )rd   r   r_   systemzJUsing Federated Identity Credentials with system-assigned managed identityN)rd   managed_identity_typemanaged_identity_client_idr   zHUsing Federated Identity Credentials with user-assigned managed identityuserz-Using user-assigned managed identity (direct))rd   r   )rK   rd   rg   rh   r   r   r_   r   r   debugr   r   r   r   r   )rV   rd   r   r   r_   r   mi_client_ids          rW   rm   zApp._init_credentials  s   L*Dbi.D.D	2Pbi6P6PL*Dbi.D.D	"%)\%L%wPRPYZvPwPw"444555 	WNNLMMMMLLUYUUUVVV 	l 	lLL7888$yajkkkk 	[ 	[#i9TYZZZZ 	)X55ijjj3'*2/3'	    * .HI.U.Ughhh3'*0/I'	    LLHIII5BL-&#   
 trY   func_or_event_typec                     dS )zGRegister event handler with auto-detected type from function signature.Nr   rV   r   s     rW   r   z	App.event  	     	rY   c                     dS )z0Register event handler with explicit event type.Nr   r   s     rW   r   z	App.event  r   rY   c                     dS )z&Register event handler (no arguments).Nr   r   s     rW   r   z	App.event  r   rY   c                      dt           dt           f fd}t                    r"t          t                    s} ||          S |S )a  
        Decorator to register event handlers with automatic type inference.

        Can be used in multiple ways:
        - @app.event (auto-detect from type hints)
        - @app.event("activity")

        Args:
            func_or_event_type: Either the function to decorate or an event type string
            event_type: Explicit event type (keyword-only)

        Returns:
            Decorated function or decorator

        Example:
            ```python
            @app.event
            async def handle_activity(event: ActivityEvent):
                print(f"Activity: {event.activity}")


            @app.event("error")
            async def handle_error(event: ErrorEvent):
                print(f"Error: {event.error}")
            ```
        funcr   c                 H   d }t          t                    r}nt          |           }|st          d| j         d          t          |          st                              d| d           t          t          |          }j
                            ||            | S )Nz#Could not determine event type for zA. Either provide an explicit event_type or use a typed parameter.zEvent type 'z' is not a registered type.)r   r   r5   r   rt   r6   r   r   r   r2   rk   on)r   detected_typer   rV   s     rW   	decoratorzApp.event.<locals>.decorator  s     M ,c22 D 2 !>d C C   V$- V V V   '}55 WU=UUUVVV M::M LOOM4000KrY   )rE   r   r   r   )rV   r   r   r   s   ``  rW   r   z	App.event  su    >	A 	! 	 	 	 	 	 	 	4 &'' 	#
;Ms0S0S 	#(D9T??" rY   namedir_path	page_pathc                 P    | j         j                            |pd| |           dS )a  
        Register a static page to serve at a specific path.

         Args:
            name: Unique name for the page
            dir_path: Directory containing the static files
            page_path: Optional path to serve the page at (defaults to /pages/{name})

        Example:
            ```python
            app.page("customform", os.path.join(os.path.dirname(__file__), "views", "customform"), "/tabs/dialog-form")
            ```
        r^   N)r}   r   serve_static)rV   r   r  r  s       rW   pagezApp.page  s0     	(()@j$jj(KKKKKrY   pathc                 >    |                      ||d| d           dS )a{  
        Add/update a static tab.
        The tab will be hosted at
        http://localhost:<PORT>/tabs/<name> or https://<BOT_DOMAIN>/tabs/<name>
        Scopes default to 'personal'.

        Args:
            name A unique identifier for the entity which the tab displays.
            path The path to the directory containing the tab's content (HTML, JS, CSS, etc.)
        z/tabs/r^   )r  r  N)r  )rV   r   r  s      rW   tabzApp.tab  s.     			$1A$1A1A1A	BBBBBrY   name_or_funcc                      dt           dt           f fd}t                    r t          t                    s |          S |S )a  
        Decorator that registers a function as a remotely callable endpoint.

        Args:
            name_or_func:
            - str: explicit name for the endpoint
            - Callable: directly decorating the function, endpoint name defaults to the function's name

        Example:
            ```python
            @app.func
            async def post_to_chat(ctx: FunctionContext[Any]):
                await ctx.send(ctx.data["message"])
            ```
        r   r   c                 "    t          t                    rn j                            dd          }t                              d j        |           dt          dt          f fd}j        j	        
                    dd| |            S )	Nr   -z-Generated endpoint name for function '%s': %srequestr   c                   K   t          | d         j                   d {V \  }}|s|st          dd|pdi          S t          d	j        j        j        | d         d|j        } |           d {V }t          d|          S )
Nr   i  detailunauthorized)statusbodyr  )rP   ry   r   data   r   )r.   r   r:   r0   rP   ry   r   __dict__)r  client_contextr   ctxresultr   rV   s        rW   handlerz,App.func.<locals>.decorator.<locals>.handler8  s      .NI&(B/ / ) ) ) ) ) )%  ^ ^'s(ED[^9\]]]]% w$($8 	 
 %-   $tCyy#3V<<<<rY   POSTz/api/functions/)r   r   rt   replacer   r   r9   r:   r}   r   register_route)r   endpoint_namer  r	  rV   s   `  rW   r   zApp.func.<locals>.decorator4  s    ,6|S,I,InLLt}OdOdehjmOnOnMLLH$-Yfggg={ =| = = = = = = =" K..v7X7X7XZabbbKrY   )rG   r   r   r   )rV   r	  r   s   `` rW   r   zApp.func#  sp    "	D 	T 	 	 	 	 	 	 	2 L!! 	+*\3*G*G 	+9\*** rY   c                    K   t          | j                  D ]@}t          |d          r.t          |j                  r|                                 d {V  Ad S )Nr   )r   r{   r   r   r   )rV   r   s     rW   r   zApp._stop_pluginsS  so      t|,, 	' 	'Fvy)) 'hv~.F.F 'nn&&&&&&&&&	' 	'rY   c                 D   K   | j                                          d {V S rS   )rn   get_bot_tokenrU   s    rW   rT   zApp._get_bot_tokenX  s-      (66888888888rY   r   c                 F   K   | j                             |           d {V S rS   )rn   get_graph_tokenrV   r   s     rW   _get_graph_tokenzApp._get_graph_token[  s/      (88CCCCCCCCCrY   r&   c                 :     t           fd j                  S )a  
        Get a Microsoft Graph client configured with the app's token.

        This client can be used for app-only operations that don't require user context.
        For multi-tenant apps, pass a tenant_id to get a tenant-specific token.

        Args:
            tenant_id: Optional tenant ID. If not provided, uses the app's default tenant.

        Raises:
            ImportError: If the graph dependencies are not installed.

        c                  .                                    S rS   )r$  r#  s   rW   rX   z#App.get_app_graph.<locals>.<lambda>l  s    4+@+@+K+K rY   r`   )rC   rO   r#  s   ``rW   get_app_graphzApp.get_app_graph^  s*     ##K#K#K#K#KSWS]^^^^rY   )r   NrS   )r   N)2rt   
__module____qualname____doc__r   r;   r   propertyr   r   r   r$   r2   r   r@   r   r   rP   r   r   r   r   r   r   r!   r   r   r   r   r   rA   r   r   r   r"   rj   r   rm   rE   r   r
   r  r  rG   r   r   rT   r   r$  r'  r   rY   rW   rJ   rJ   L   s\        W&"4 W W W Wr hsm    X Y/    X     X *HSM * * * X*       DS3 S3 S S S S
* * * * * * *X   (K# K~9MP\9\ K K K K<   &5	
 
   X  .(<7 
	   X ;=?C	< << .(<7< &5<	<
 
< < < <:<h(E'F	RV'WX <]a < < < <"6 " " " "/8K#8 / / / /b  a    X in(= (A3PQ6BR    X   !a8H    X >B? ?!!YT"9:? 
q(A36""	#? ? ? ?BL L L L LQU L L L L C C3 C4 C C C C. .sD$!7 .5xY]X^`dXdOeIeCf . . . .`' ' ' '
9 9 9D D DR_I` D D D D_ _x} _@T _ _ _ _ _ _rY   rJ   )lr*  r   importlib.metadata	importlibloggingrg   typingr   r   r   r   r   r   r	   r
   r   r   r   dependency_injectorr   dotenvr   r   microsoft_teams.apir   r   r   r   r   r   r   r   r   r   r   r   r   r   *microsoft_teams.api.auth.cloud_environmentr   r    ri   microsoft_teams.cardsr!   microsoft_teams.commonr"   r#   r$   r%   msgraph.graph_service_clientr&   r   r(   
app_eventsr)   	app_oauthr*   app_pluginsr+   app_processr,   authr-   #auth.remote_function_jwt_middlewarer.   ro   r/   contexts.function_contextr0   r   r1   r2   r3   r4   r5   r6   httpr7   r8   http.adapterr9   r:   rK   r;   r<   r{   r=   r>   routingr?   r@   routing.activity_contextrA   token_managerrB   utilsrC   utils.threadrD   metadataversionrE   rG   r   	getLoggerrt   r   rJ   r   rY   rW   <module>rH     sZ   
       				 r r r r r r r r r r r r r r r r r r r r r r r r r r ) ) ) ) ) ) + + + + + + + +                                 > = = = = = S S S S S S . . . . . . T T T T T T T T T T T T @?????? + + + + + + $ $ $ $ $ $ $ $ $ $ $ $ ( ( ( ( ( ( * * * * * *             Q Q Q Q Q Q             6 6 6 6 6 6                - , , , , , , , 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 9 9 9 9 9 9 9 9 5 5 5 5 5 5 ' ' ' ' ' ' & & & & & & 5 5 5 5 5 5


$
$%;
<
<GCxS)***wvXs';&<c&ABCCC KKt$$$ % % %(w((
		8	$	$`_ `_ `_ `_ `_
 `_ `_ `_ `_ `_rY   