
    ,j                       d Z ddlmZ ddl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 ddlmZ 	 ddlmZ dZn# e$ r dZdZY nw xY w	 dd	lmZmZ dd
lmZ ddlmZmZ ddlmZ ddlmZ ddlmZm Z  ddl!m"Z"m#Z# ddl$m%Z%m&Z&m'Z'm(Z( ddl)m*Z*m+Z+m,Z, dZ-n1# e$ r) dZ-dZdZdZdZdZdZdZdZdZ dZ#dZ"e.Z%dZ&dZ'dZ(dZ*dZ+dZ,Y nw xY wddl/m0Z0m1Z1 ddl2m3Z3 ddl4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:  ej;        e<          Z=dZ>dZ?dddAdZ@e>ddBdZA G d  d!          ZB G d" d#          ZC G d$ d%          ZDdCd&ZEdCd'ZFdCd(ZGdDd*ZHd+ZI eJd,d-h          ZKddlLZM eMjN        d.          ZOdEd2ZPdddd3dFd;ZQeEZR G d< d=e5          ZSdGd?ZTdGd@ZUdS )Ha  
Microsoft Teams platform adapter for Hermes Agent.

Uses the microsoft-teams-apps SDK for authentication and activity processing.
Runs an aiohttp webhook server to receive messages from Teams.
Proactive messaging (send, typing) uses the SDK's App.send() method.

Requires:
    pip install microsoft-teams-apps aiohttp
    TEAMS_CLIENT_ID, TEAMS_CLIENT_SECRET, and TEAMS_TENANT_ID env vars

Configuration in config.yaml:
    platforms:
      teams:
        enabled: true
        extra:
          client_id: "your-client-id"      # or TEAMS_CLIENT_ID env var
          client_secret: "your-secret"      # or TEAMS_CLIENT_SECRET env var
          tenant_id: "your-tenant-id"       # or TEAMS_TENANT_ID env var
          port: 3978                        # or TEAMS_PORT env var
    )annotationsN)AnyDictOptional)quote)webTF)AppActivityContext)ClientOptions)MessageActivityConversationReference)TypingActivityInput)AdaptiveCardInvokeActivity)AdaptiveCardActionCardResponse!AdaptiveCardActionMessageResponse)InvokeResponseAdaptiveCardInvokeResponse)
HttpMethodHttpRequestHttpResponseHttpRouteHandler)AdaptiveCardExecuteAction	TextBlock)PlatformPlatformConfig)MessageDeduplicator)BasePlatformAdapterMessageEventMessageType
SendResultcache_image_from_urlcache_media_bytesi  z/api/messagesdefaultvaluer   r%   boolreturnc                   t          | t                    r| S t          | t                    r2|                                                                 }|dv rdS |dv rdS |S )N>   1onyestrueT>   0noofffalseF)
isinstancer'   strstriplower)r&   r%   
normalizeds      D/home/ubuntu/.hermes/hermes-agent/plugins/platforms/teams/adapter.py_parse_boolr8   l   sk    % % [[]]((**
33344445N    intc               T    	 t          |           S # t          t          f$ r |cY S w xY wN)r:   	TypeError
ValueError)r&   r%   s     r7   _coerce_portr?   x   s<    5zzz"   s    ''c                  0    e Zd ZdZddZdddd
ZddZdS )_StaticAccessTokenProviderzSMinimal token-provider shim so outbound Graph delivery can reuse the shared client.access_tokenr3   c                V    t          |pd                                          | _        d S N )r3   r4   _access_token)selfrB   s     r7   __init__z#_StaticAccessTokenProvider.__init__   s)     !344::<<r9   F)force_refreshrI   r'   r(   c               B   K   ~| j         st          d          | j         S )Nz=TEAMS_GRAPH_ACCESS_TOKEN is required for graph delivery mode.)rF   r>   )rG   rI   s     r7   get_access_tokenz+_StaticAccessTokenProvider.get_access_token   s-      ! 	^\]]]!!r9   Nonec                    d S r<    rG   s    r7   clear_cachez&_StaticAccessTokenProvider.clear_cache   s    tr9   N)rB   r3   )rI   r'   r(   r3   r(   rL   )__name__
__module____qualname____doc__rH   rK   rP   rN   r9   r7   rA   rA      sf        ]]= = = = ?D " " " " " "     r9   rA   c                      e Zd ZdZ	 d#dddd$dZ	 d#d%dZd&dZd'dZd'dZd(dZ	d)dZ
d)dZed)d            Zed*d            Zed+d"            ZdS ),TeamsSummaryWritera  Pipeline-facing Teams outbound delivery surface.

    This stays inside the existing Teams platform plugin so the meeting-pipeline
    PR can reuse one Teams integration surface instead of introducing a second
    adapter elsewhere in the gateway core.
    N)graph_client	transportplatform_configPlatformConfig | NonerX   
Any | NonerY   httpx.AsyncBaseTransport | Noner(   rL   c               0    || _         || _        || _        d S r<   )_platform_config_graph_client
_transport)rG   rZ   rX   rY   s       r7   rH   zTeamsSummaryWriter.__init__   s     !0)#r9   payloadr   configdict[str, Any] | Noneexisting_recordOptional[dict[str, Any]]dict[str, Any]c                  K   |                      |          }|r3t          |                    d          d          st          |          S t	          |                    d          p|                    d          pd                                                                          }|sY|                    d          rd}nA|                    d	          s*|                    d
          r|                    d          rd}|dk    r|                     ||           d {V S |dk    r|                     ||           d {V S t          d          )Nforce_resendFr$   delivery_modemoderE   incoming_webhook_urlincoming_webhookchat_idteam_id
channel_idgraphz:Teams delivery_mode must be 'incoming_webhook' or 'graph'.)
_resolve_delivery_configr8   getdictr3   r4   r5   #_write_summary_via_incoming_webhook_write_summary_via_graphr>   )rG   rb   rc   re   mergedrk   s         r7   write_summaryz TeamsSummaryWriter.write_summary   sz      ..v66 	);vzz./I/ISX#Y#Y#Y 	)(((6::o..J&**V2D2DJKKQQSSYY[[ 	zz011 )I&& 

9%%*0**\*B*B %%%AA'6RRRRRRRRR7??66wGGGGGGGGGH
 
 	
r9   c           	        i }| j         }|e|                    t          |j        pi                      |j        rd|vr
|j        |d<   |j        r |                    d|j        j                   |                    t          |pi                      t          j	        dd          t          j	        dd          t          j	        dd          t          j	        dd          t          j	        dd          t          j	        d	d          d
}|
                                D ]!\  }}|r|                    |          s|||<   "|S )NrB   rp   TEAMS_DELIVERY_MODErE   TEAMS_INCOMING_WEBHOOK_URLTEAMS_GRAPH_ACCESS_TOKENTEAMS_TEAM_IDTEAMS_CHANNEL_IDTEAMS_CHAT_ID)rj   rl   rB   ro   rp   rn   )r_   updatert   extratokenhome_channel
setdefaultrn   osgetenvitemsrs   )rG   rc   rw   platform_cfgenv_defaultskeyr&   s          r7   rr   z+TeamsSummaryWriter._resolve_delivery_config   sT   !#,#MM$|17R88999! <nF&B&B)5);~&( S!!,0I0QRRRd6<R(()))  Y'<bAA$&I.JB$O$OI&@"EEy"55)$6;;y"55
 
 ',,.. 	$ 	$JC $VZZ__ $#sr9   c                  K   dd l }t          |                    d          pd                                          }|st	          d          d|                     |          i}|                    d| j                  4 d {V }|                    ||           d {V }|	                                 d d d           d {V  n# 1 d {V swxY w Y   d	||j
        d
dS )Nr   rl   rE   zATEAMS_INCOMING_WEBHOOK_URL is required for incoming_webhook mode.textg      4@)timeoutrY   )jsonrm   T)rj   webhook_urlstatus_code	delivered)httpxr3   rs   r4   r>   _render_summary_markdownAsyncClientra   postraise_for_statusr   )rG   rb   rc   r   r   bodyclientresponses           r7   ru   z6TeamsSummaryWriter._write_summary_via_incoming_webhook   s      	&**%;<<BCCIIKK 	b`aaa55g>>?$$TT_$MM 	( 	( 	( 	( 	( 	( 	(QW#[[4[@@@@@@@@H%%'''	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 	( 0&#/	
 
 	
s   2C
CCc                  K   |                      |          }t          |                    d          pd                                          }|r|dt	          |d           d}|                    |dd|                     |          di	           d {V }d
d||pi                     d          |pi                     d          dS t          |                    d          pd                                          }t          |                    d          pd                                          }|r|st          d          dt	          |d           dt	          |d           d}|                    |dd|                     |          di	           d {V }d
d|||pi                     d          |pi                     d          dS )Nrn   rE   z/chats/)safez	/messagesr   html)contentTypecontent)	json_bodyrq   chatidwebUrl)rj   target_typern   
message_idweb_urlro   rp   zEGraph delivery mode requires chat_id, or both team_id and channel_id.z/teams/z
/channels/channel)rj   r   ro   rp   r   r   )_build_graph_clientr3   rs   r4   r   	post_json_render_summary_htmlr>   )	rG   rb   rc   rX   rn   pathr   ro   rp   s	            r7   rv   z+TeamsSummaryWriter._write_summary_via_graph   sg     
 //77fjj++1r2288:: 	?U7444???D)33!6dF_F_`gFhFh#i#ij 4        H
 ")%"'~222488$N//99   fjj++1r2288::L117R88>>@@
 	j 	W  5eG"--- 5 5Zb)))5 5 5 	 &//v$B[B[\cBdBdeef 0 
 
 
 
 
 
 
 

 %$$#>r..t44 B++H55
 
 	
r9   c                ,   | j         | j         S ddlm} ddlm} t          |                    d          pd                                          }|r |t          |          | j	                  S  ||
                                | j	                  S )Nr   )MicrosoftGraphTokenProvider)MicrosoftGraphClientrB   rE   )rY   )r`   tools.microsoft_graph_authr   tools.microsoft_graph_clientr   r3   rs   r4   rA   ra   from_env)rG   rc   r   r   rB   s        r7   r   z&TeamsSummaryWriter._build_graph_client  s    )%%JJJJJJEEEEEE6::n55;<<BBDD 	''*<88/    $#'0022o
 
 
 	
r9   r3   c           
        d|                      |           ddd|                     t          |dd           d           ddg|                     t          |dd                     dd|                     t          |d	d                     dd
|                     t          |dd                     }d                    |          S )Nz**rE   z	Summary: summaryNo summary available.zKey decisions:key_decisionszAction items:action_itemszRisks:risks
)_title_textgetattr_bullet_linesjoin)rG   rb   liness      r7   r   z+TeamsSummaryWriter._render_summary_markdown)  s    )W%%)))`

77It#D#DF]^^``
 $ G GHH
 
 
  F FGG
 
 
 $ ? ?@@
 yyr9   c                Z   d|                      t          |dd           d          gfdt          t          |dd           pg           fdt          t          |dd           pg           fdt          t          |d	d           pg           fg}d
t          j        |                     |                     dg}|D ]\  }}|                    dt          j        |           d           t          |          dk    rE|dk    r?|                    dt          j        t          |d                              d           |r=d	                    d |D                       }|                    |rd| dpd           |                    d           d	                    |          S )NSummaryr   r   zKey decisionsr   zAction itemsr   Risksr   z<h2>z</h2>z<h3>z</h3>   z<p>r   z</p>rE   c              3     K   | ]J}t          |                                          #d t          j        t          |                     dV  KdS )z<li>z</li>N)r3   r4   r   escape.0items     r7   	<genexpr>z:TeamsSummaryWriter._render_summary_html.<locals>.<genexpr>H  sY      "o"oD]`ae]f]f]l]l]n]n"o#G$+c$ii*@*@#G#G#G"o"o"o"o"o"or9   z<ul>z</ul>z<p>None</p>)
r   r   listr   r   r   appendlenr3   r   )rG   rb   sectionsblocksheadingr   rendereds          r7   r   z'TeamsSummaryWriter._render_summary_html:  s   GGY$E$EG^__`ad77OT#J#J#PbQQRT''>4"H"H"NBOOPd77GT::@bAAB	
 BT[[%9%9::AAAB& 		- 		-NGUMM<W!5!5<<<===5zzQ7i#7#7DDKE!H$>$>DDDEEE -77"o"oTY"o"o"ooohA+A(+A+A+AR]SSSSm,,,,wwvr9   c                    t          | dd           }|rt          |          S t          | dd           }|rt          |dd           nd }d|pd S )Ntitlemeeting_ref
meeting_idzMeeting r   )r   r3   )rb   r   r   r   s       r7   r   zTeamsSummaryWriter._titleN  sg    $// 	u::g}d;;ALVW[,===RV
3*1	333r9   r&   r%   c                P    t          | pd                                          }|p|S rD   r3   r4   )r&   r%   r   s      r7   r   zTeamsSummaryWriter._textW  s)    5;B%%''wr9   values	list[str]c                <    d |pg D             }d |D             pdgS )Nc                    g | ]D}t          |                                          #t          |                                          ES rN   r   r   s     r7   
<listcomp>z4TeamsSummaryWriter._bullet_lines.<locals>.<listcomp>^  s=    SSStTARARST""SSSr9   c                    g | ]}d | S )z- rN   r   s     r7   r   z4TeamsSummaryWriter._bullet_lines.<locals>.<listcomp>_  s    ...T...r9   z- NonerN   )clsr   r   s      r7   r   z TeamsSummaryWriter._bullet_lines\  s4    SS"SSS.....<8*<r9   r<   )rZ   r[   rX   r\   rY   r]   r(   rL   )rb   r   rc   rd   re   rf   r(   rg   )rc   rd   r(   rg   )rb   r   rc   rg   r(   rg   )rc   rg   r(   r   )rb   r   r(   r3   )r&   r   r%   r3   r(   r3   )r   r   r(   r   )rR   rS   rT   rU   rH   rx   rr   ru   rv   r   r   r   staticmethodr   r   classmethodr   rN   r9   r7   rW   rW      sE         26	$ $(59	$ 	$ 	$ 	$ 	$ 	$ 59	
 
 
 
 
4   0
 
 
 
.*
 *
 *
 *
X
 
 
 
$       "   ( 4 4 4 \4    \ = = = [= = =r9   rW   c                  :    e Zd ZdZddZddZddZddZddZdS )_AiohttpBridgeAdaptera3  HttpServerAdapter that bridges the Teams SDK into an aiohttp server.

    Without a custom adapter, ``App()`` unconditionally imports fastapi/uvicorn
    and allocates a ``FastAPI()`` instance.  This bridge captures the SDK's
    route registrations and wires them into our own aiohttp ``Application``.
    aiohttp_app'web.Application'c                    || _         d S r<   )_aiohttp_app)rG   r   s     r7   rH   z_AiohttpBridgeAdapter.__init__j  s    'r9   method'HttpMethod'r   r3   handler'HttpRouteHandler'r(   rL   c                V    dfd}| j         j                            |||           dS )z2Register an SDK route handler as an aiohttp route.request'web.Request'r(   'web.Response'c                z  K   |                                   d {V }t          | j                  } t          ||                     d {V }|                    dd          }|                    d          }|)t          j        |t          j        |          d          S t          j        |          S )N)r   headersstatus   r   application/json)r   r   content_type)r   )r   rt   r   r   rs   r   Responsedumps)r   r   r   resultr   	resp_bodyr   s         r7   _aiohttp_handlerz>_AiohttpBridgeAdapter.register_route.<locals>._aiohttp_handlerp  s       ''''''D7?++G+27;DRY3Z3Z3Z+[+[%[%[%[%[%[%[FZZ#..F

6**I$|!I..!3   
 <v....r9   N)r   r   r(   r   )r   router	add_route)rG   r   r   r   r   s      ` r7   register_routez$_AiohttpBridgeAdapter.register_routem  sH    	/ 	/ 	/ 	/ 	/ 	/ 	 **649IJJJJJr9   	directoryc                    d S r<   rN   )rG   r   r   s      r7   serve_staticz"_AiohttpBridgeAdapter.serve_static  s    r9   portr:   c                $   K   t          d          )Nz(aiohttp server is managed by the adapter)NotImplementedError)rG   r   s     r7   startz_AiohttpBridgeAdapter.start  s      !"LMMMr9   c                
   K   d S r<   rN   rO   s    r7   stopz_AiohttpBridgeAdapter.stop  s      r9   N)r   r   )r   r   r   r3   r   r   r(   rL   )r   r3   r   r3   r(   rL   )r   r:   r(   rL   rQ   )	rR   rS   rT   rU   rH   r   r   r   r  rN   r9   r7   r   r   b  s         ( ( ( (K K K K&   N N N N     r9   r   c                     t           ot          S )zDReturn True when all Teams dependencies and credentials are present.)TEAMS_SDK_AVAILABLEAIOHTTP_AVAILABLErN   r9   r7   check_requirementsr    s    4#44r9   c                J   t          | di           pi }t          j        d          p|                    dd          }t          j        d          p|                    dd          }t          j        d          p|                    dd          }t	          |o|o|          S )	zAReturn True when the config has the minimum required credentials.r   TEAMS_CLIENT_ID	client_idrE   TEAMS_CLIENT_SECRETclient_secretTEAMS_TENANT_ID	tenant_id)r   r   r   rs   r'   )rc   r   r	  r  r  s        r7   validate_configr    s    FGR((.BE	+,,J		+r0J0JII344V		/SU8V8VM	+,,J		+r0J0JI	9m9	:::r9   c                     t          |           S )z7Check whether Teams is configured (env or config.yaml).)r  )rc   s    r7   is_connectedr    s    6"""r9   dict | Nonec                    t          j        dd                                          } t          j        dd                                          }t          j        dd                                          }| r|r|sdS | ||d}t          j        dd                                          }|r$	 t          |          |d<   n# t          $ r Y nw xY wt          j        d	d                                          }|r||d
<   t          j        dd                                          }|r|t          j        dd          d|d<   |S )a  Seed ``PlatformConfig.extra`` from env vars during gateway config load.

    Called by the platform registry's env-enablement hook BEFORE adapter
    construction, so ``gateway status`` and ``get_connected_platforms()``
    reflect env-only configuration without instantiating the Teams SDK.
    Returns ``None`` when Teams isn't minimally configured.

    The special ``home_channel`` key in the returned dict becomes a proper
    ``HomeChannel`` dataclass on the ``PlatformConfig`` via the core hook.
    r  rE   r
  r  N)r	  r  r  
TEAMS_PORTr   TEAMS_SERVICE_URLservice_urlTEAMS_HOME_CHANNELTEAMS_HOME_CHANNEL_NAMEHome)rn   namer   )r   r   r4   r:   r>   )r	  r  r  seedr   r  homes          r7   _env_enablementr    sl    	+R006688II3R88>>@@M	+R006688I - I t& D
 9\2&&,,..D 	t99DLL 	 	 	D	)/44::<<K *)]9)2..4466D 
I7@@ 
  
^ Ks   .C 
CCz&https://smba.trafficmanager.net/teams/zsmba.trafficmanager.netz!smba.infra.gov.teams.microsoft.usz^[A-Za-z0-9:@\-_.]+$rawr3   Optional[str]c                    | sdS 	 ddl m}  ||           }n# t          $ r Y dS w xY w|j        dk    rdS |j        t
          vrdS |                     d          r| n| dz   }|S )a  Return a normalized service URL or ``None`` if it is not allowed.

    Requires ``https://`` and a host in ``_ALLOWED_TEAMS_SERVICE_HOSTS``.
    The trailing slash is added if absent so callers can append
    ``v3/conversations/...`` without double slashes.
    Nr   )urlparsehttps/)urllib.parser   	Exceptionschemehostname_ALLOWED_TEAMS_SERVICE_HOSTSendswith)r  r   parsedr6   s       r7   _validate_teams_service_urlr*    s      t))))))#   tt}t:::tS))8sSyJs    
&&)	thread_idmedia_filesforce_documentrn   messager+  r,  Optional[list]r-  Dict[str, Any]c          	       K   t          | di           pi }t          j        d          p|                    dd          }t          j        d          p|                    dd          }t          j        d          p|                    dd          }	|r|r|	sd	d
iS t          j        d          p|                    dd          pt          }
t          |
          }|d	dt          t                     iS |sd	diS t          	                    |          sd	diS t          	                    |	          sd	diS d|	 d}| d| d}t          sd	diS 	 ddl}|                    d          }|                    d          4 d{V }|                    |d||dddd i|!          4 d{V 	 }|j        d"k    rU|                                 d{V }d	d#|j         d$|dd%          icddd          d{V  cddd          d{V  S |                                 d{V }ddd          d{V  n# 1 d{V swxY w Y   |                    d&          }|sd	d'icddd          d{V  S d(|d)d*}|                    ||d+| d,d-|.          4 d{V 	 }|j        d"k    rU|                                 d{V }d	d/|j         d$|dd%          icddd          d{V  cddd          d{V  S |                                 d{V }ddd          d{V  n# 1 d{V swxY w Y   ddd          d{V  n# 1 d{V swxY w Y   d|                    d0          d1S # t$          j        $ r  t(          $ r-}t*                              d2d3           d	d4| icY d}~S d}~ww xY w)5a  Acquire a Bot Framework bearer token and POST a single message activity.

    Used by ``tools/send_message_tool._send_via_adapter`` when the gateway
    runner is not in this process (e.g. ``hermes cron`` running as a
    separate process from ``hermes gateway``).  Without this hook,
    ``deliver=teams`` cron jobs fail with ``No live adapter for platform``.

    Configuration: requires ``TEAMS_CLIENT_ID``, ``TEAMS_CLIENT_SECRET``,
    ``TEAMS_TENANT_ID``, ``TEAMS_HOME_CHANNEL`` (the conversation ID), and
    optionally ``TEAMS_SERVICE_URL`` (Bot Framework service host; must be
    a known Bot Framework endpoint, see ``_ALLOWED_TEAMS_SERVICE_HOSTS``).

    Security: ``service_url`` is validated against an allowlist of known
    Bot Framework hosts to block SSRF / token-exfiltration via a tampered
    env var.  ``chat_id`` is validated to match the documented Bot
    Framework ID character set so it cannot escape the URL path.

    ``media_files`` and ``force_document`` are accepted for signature
    parity but not implemented for the standalone path; messages with
    attachments will send as text-only.  The live adapter handles
    attachments via the SDK.
    r   r  r	  rE   r
  r  r  r  errorzaTeams standalone send: TEAMS_CLIENT_ID, TEAMS_CLIENT_SECRET, and TEAMS_TENANT_ID are all requiredr  r  NzeTeams standalone send: TEAMS_SERVICE_URL host is not on the Bot Framework allowlist; expected one of z<Teams standalone send: chat_id (conversation ID) is requiredz`Teams standalone send: chat_id contains characters outside the Bot Framework conversation ID setzSTeams standalone send: TEAMS_TENANT_ID contains characters outside the expected setz"https://login.microsoftonline.com/z/oauth2/v2.0/tokenzv3/conversations/z/activitiesz,Teams standalone send: aiohttp not installedr   g      .@)totalT)	trust_envclient_credentialsz%https://api.botframework.com/.default)
grant_typer	  r  scopeContent-Typez!application/x-www-form-urlencoded)datar   r   i  z-Teams standalone send: token request failed (z): i,  rB   z:Teams standalone send: token response missing access_tokenr.  markdown)typer   
textFormatzBearer r   )Authorizationr8  )r   r   r   z-Teams standalone send: activity post failed (r   successr   zTeams standalone send raisedexc_infozTeams standalone send failed: )r   r   r   rs   _DEFAULT_TEAMS_SERVICE_URLr*  sortedr'  _TEAMS_CONV_ID_REmatchr  aiohttpClientTimeoutClientSessionr   r   r   r   asyncioCancelledErrorr$  loggerdebug)pconfigrn   r.  r+  r,  r-  r   r	  r  r  raw_service_urlr  	token_urlactivities_url_aiohttpper_request_timeoutsession
token_respr   token_payloadrB   activity	send_respsend_payloades                            r7   _standalone_sendrZ    s     > GWb))/RE	+,,J		+r0J0JII344V		/SU8V8VM	+,,J		+r0J0JI ~- ~I ~|}} 		%&& 	&99]B''	&% 
 .o>>K62336 6 	  YWXX""7++ }{||""9-- pnooRYRRRI#JJgJJJN IGHH4?"""" '4444@@))D)99 %	6 %	6 %	6 %	6 %	6 %	6 %	6W||"6!*%2D	  ()LM+ $ 
 
 8 8 8 8 8 8 8 8 $++!+!2!2222222D#%wU_Uf%w%wkoptqtptku%w%wx8 8 8 8 8 8 8 8 8 8 8 8 8%	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 '1oo&7&7 7 7 7 7 7 78 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 ),,^<<L _!]^%%	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6* "( H
 ||%=|%=%=$6  , $   6 6 6 6 6 6 6 6 #s**!*!1!1111111D#%vU^Ue%v%vjnospsosjt%v%vw6 6 6 6 6 6 6 6 6 6 6 6 63%	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6J &/^^%5%55555556 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 63%	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6 %	6N &**400
 
 	
 !    ? ? ?3dCCC=!==>>>>>>>?s   6N 'M3<I /MN I .M 
I
	
MI
	M+N >+M*<L7&M8N L7%M7
M	MM	MN 
M$$N 'M$(N O	"O>O	O	c                       e Zd ZdZdZd2 fdZd3dZd4d
Zd5d6dZd7dZ	d8dZ
d9dZ	 	 d:d;d%Z	 	 d<d=d)Zd>d?d*Z	 	 	 d@dAd-Z	 	 d<dBd/ZdCd1Z xZS )DTeamsAdapterz;Microsoft Teams adapter using the microsoft-teams-apps SDK.`m  rc   r   c                   t                                          |t          d                     |j        pi }|                    d          pt          j        dd          | _        |                    d          pt          j        dd          | _        |                    d          pt          j        dd          | _	        t          |                    d	          p&t          j        d
t          t                                        | _        d | _        d | _        t!          d          | _        i | _        d S )Nteamsr	  r  rE   r  r
  r  r  r   r  i  )max_size)superrH   r   r   rs   r   r   
_client_id_client_secret
_tenant_idr?   r3   _DEFAULT_PORT_port_app_runnerr   _dedup
_conv_refs)rG   rc   r   	__class__s      r7   rH   zTeamsAdapter.__init__t  s   '!2!2333"))K00TBI>OQS4T4T#ii88`BIF[]_<`<`))K00TBI>OQS4T4T!IIfL<]9K9K!L!L
 

 &*	26)4888 +-r9   r(   r'   c           
     x   K   t           s                     ddd           dS t          s                     ddd           dS  j        r j        r j        s                     ddd           dS 	 t          j                    }|j        	                    dd	            t           j         j         j        t          |          t          d
di                     _         j        j        d fd            } j        j        d fd            } j                                         d {V  t          j        |           _         j                                         d {V  t          j         j        d j                  }|                                 d {V  d _                                          t2                              d j        t6                     dS # t8          $ rA}                     dd| d           t2                              d|           Y d }~dS d }~ww xY w)NMISSING_SDKzImicrosoft-teams-apps not installed. Run: pip install microsoft-teams-appsF)	retryablez/aiohttp not installed. Run: pip install aiohttpMISSING_CREDENTIALSzJTEAMS_CLIENT_ID, TEAMS_CLIENT_SECRET, and TEAMS_TENANT_ID are all requiredz/healthc                ,    t          j        d          S )Nok)r   )r   r   )_s    r7   <lambda>z&TeamsAdapter.connect.<locals>.<lambda>  s    CLd<S<S<S r9   
User-AgentHermesr   )r	  r  r  http_server_adapterr   ctx ActivityContext[MessageActivity]c                B   K                        |            d {V  d S r<   )_on_messagerx  rG   s    r7   _handle_messagez-TeamsAdapter.connect.<locals>._handle_message  s3      &&s+++++++++++r9   +ActivityContext[AdaptiveCardInvokeActivity]r(   1InvokeResponse[AdaptiveCardActionMessageResponse]c                >   K                        |            d {V S r<   )_on_card_actionr|  s    r7   _handle_card_actionz1TeamsAdapter.connect.<locals>._handle_card_action  s/       "11#666666666r9   z0.0.0.0Tz0[teams] Webhook server listening on 0.0.0.0:%d%sCONNECT_FAILEDzTeams connection failed: z[teams] Failed to connect: %s)rx  ry  )rx  r~  r(   r  )r  _set_fatal_errorr  rb  rc  rd  r   Applicationr   add_getr	   r   r   rg  
on_messageon_card_action
initialize	AppRunnerrh  setupTCPSiterf  r   _running_mark_connectedrK  info_WEBHOOK_PATHr$  r2  )rG   r   r}  r  siterY  s   `     r7   connectzTeamsAdapter.connect  s     " 	!![ "   
 5  	!!A "   
 5 	d&9 	 	!!%\ "   
 51	/++K&&y2S2STTT/"1/$9+$F$F$lH-EFFF  DI Y!, , , , , "!, Y%7 7 7 7 7 &%7 )&&(((((((((=55DL,$$&&&&&&&&&;t|Y
CCD**,, DM  """KKB
  
 4 	 	 	!! /A// "   
 LL8!<<<55555	s   6E6G. .
H986H44H9rL   c                   K   d| _         | j        r&| j                                         d {V  d | _        d | _        |                                  t
                              d           d S )NFz[teams] Disconnected)r  rh  cleanuprg  _mark_disconnectedrK  r  rO   s    r7   
disconnectzTeamsAdapter.disconnect  sv      < 	 ,&&(((((((((DL	!!!*+++++r9         >@urlr3   r   floatbytesc                ^  K   ddl m} ddlm}  ||          st	          d          ddl}|                    |dd|gi          4 d{V 	 }|                    |d	d
i           d{V }|                                 |j	        cddd          d{V  S # 1 d{V swxY w Y   dS )ac  Download attachment bytes with SSRF protection.

        Teams file attachments carry pre-authenticated SharePoint download
        URLs (no extra auth header needed). Validates the URL against the
        SSRF guard and follows redirects through the shared redirect guard,
        matching the cache_*_from_url helpers in gateway.platforms.base.
        r   )is_safe_url)_ssrf_redirect_guardz/Blocked unsafe attachment URL (SSRF protection)NTr   )r   follow_redirectsevent_hooksrt  z)Mozilla/5.0 (compatible; HermesAgent/1.0)rv  )
tools.url_safetyr  gateway.platforms.baser  r>   r   r   rs   r   r   )rG   r  r   r  r  r   r   r   s           r7   _fetch_attachment_bytesz$TeamsAdapter._fetch_attachment_bytes  s      	100000??????{3 	PNOOO$$!#&:%;< % 
 
 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ #ZZ%'RS (        H %%'''#
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$ 
	$s   :B
B&)B&rx  ry  c                *  K   |j         }| j        r| j        j        nd}|rt          |j        dd          |k    rdS t          |dd          }|r| j                            |          rdS t          |j        dd          }|r|j        | j	        |<   d}t          |d          r|j        r|j        }d|v r-ddl}|                    dd|                                          }|j        }t          |dd          pd}	|	d	k    rd
}
n|	dk    rd}
n|	dk    rd}
nd
}
|j        }t          |dd          pt          |dd          }t          |dd          pd}|                     |j        t          |dd          pd|
t!          |          |t          |dd          p| j                  }g }g }g }t          |dd          pg D ]M}t          |dd          }t          |dd          pd                                }t          |dd          pd}|dv r|sS|                    d          ri|dk    rt          |dd          }t)          |t*                    st          |dd          pi }|                    d          p|                    d          }|                    d          p|                    d          pd                    d          }|s|p|rd| nd }	 |                     |           d{V }t3          ||d!          }|rO|                    |j                   |                    |j                   |                    |j                   nt<                              d"|           n3# t@          $ r&}t<                              d#||           Y d}~nd}~ww xY w|r|                    d$          r	 tC          |           d{V }|r?|                    |           |                    |           |                    d%           n2# t@          $ r%}t<                              d&|           Y d}~nd}~ww xY w|r	 |                     |           d{V }t3          |||!          }|rN|                    |j                   |                    |j                   |                    |j                   # t@          $ r*}t<                              d'|p|||           Y d}~Ed}~ww xY wOd |v rtD          j#        }n?d%|v rtD          j$        }n.d(|v rtD          j%        }nd)|v rtD          j&        }ntD          j'        }tQ          ||||||*          }| )                    |           d{V  dS )+z>Process an incoming Teams message and dispatch to the gateway.Nr   rE   r   z<at>r   z<at>[^<]*</at>\s*conversation_typepersonaldm	groupChatgroupr   aad_object_idr  r  )rn   	chat_name	chat_typeuser_id	user_nameguild_idattachmentscontent_urlr   )z	text/htmlz
text/plainzapplication/vnd.microsoft.cardz2application/vnd.microsoft.teams.file.download.infor   __dict__downloadUrldownload_urlfileType	file_type.z	document.document)filename	mime_typez?[teams] Unsupported document type for attachment '%s', skippingz0[teams] Failed to cache file attachment '%s': %szimage/imagez,[teams] Failed to cache image attachment: %sz0[teams] Failed to cache attachment '%s' (%s): %svideoaudio)r   sourcemessage_type
media_urlsmedia_typesr   )*rV  rg  r   r   from_ri  is_duplicateconversationconversation_refrj  hasattrr   resubr4   build_sourcer3   rd  r5   
startswithr2   rt   rs   lstripr  r#   r   r   
media_typekindrK  warningr$  r"   r    DOCUMENTPHOTOVIDEOAUDIOTEXTr   handle_message)rG   rx  rV  bot_idmsg_idconv_idr   r  conv	conv_typer  from_accountr  r  r  r  r  media_kindsattr  r   att_namer   r  r  r  r9  cachedrY  msg_typeevents                                  r7   r{  zTeamsAdapter._on_message  s     < "&4 	ghndD99VCCF 4.. 	dk..v66 	F (/t<< 	<'*';DOG$ 8V$$ 	! 	!=DT>>III66.D99??AAD $D"5t<<B	
""II+%%II)##!III  ~,>>a',X\^`BaBaL&$77=2	""GdFD117RLLT;55H # 
 
 
8]D99?R B	 B	C!#}d;;K#C>>D"KKMMLsFD117RH
 :::;:&&'GHH SSS "#y$77!'400 G%gz4@@FBG&{{=99XW[[=X=X$[[44VK8P8PVTV^^_bcc	# #]9(\(?I(?(?(?R\d!%!=!=l!K!KKKKKKKD.thRTUUUF "))&+666#**6+<===#**6;7777]$   ! d d dNN#UW_abccccccccd 	|66x@@ 	V#7#D#DDDDDDDF 4"))&111#**<888#**7333  V V VNN#QSTUUUUUUUUV !%!=!=k!J!JJJJJJJD.x<  F  8"))&+666#**6+<===#**6;777    NNJ /Kq       , $$"+HH##"(HH##"(HH##"(HH"'H!!#
 
 
 !!%(((((((((((sK   &BN  
N0
N++N0AP$$
Q.QQA=S
T$T		Trn   card'AdaptiveCard''Any'c                2  K   ddl m} | j                            |          }|rJ| j        rC |                                |          }| j        j                            ||           d{V S | j        r!| j                            ||           d{V S dS )zJSend an AdaptiveCard, using a stored ConversationReference when available.r   )MessageActivityInputN)microsoft_teams.apir  rj  rs   rg  add_cardactivity_sendersend)rG   rn   r  r  conv_refrV  s         r7   
_send_cardzTeamsAdapter._send_card  s      <<<<<<?&&w// 	7	 	7++--66t<<H277(KKKKKKKKKY 	7666666666tr9   -'ActivityContext[AdaptiveCardInvokeActivity]'3'InvokeResponse[AdaptiveCardActionMessageResponse]'c                  K   ddl m}m} |j        j        j        }|j        pi }|                    dd          }|                    dd          }|r|st          dt          d          	          S t          j        d
d                                          }t          j        dd                                                                          dv }	|	s|s9t                              d           t          dt          d          	          S |j        j        }
t#          |
dd          pt#          |
dd          }d |                    d          D             }d|vr>||vr:t                              d|           t          dt          d          	          S ddddd}|                    |          }|st          dt          d          	          S  ||          sat          dt'          t)                                          d                              t/          dd          g                    	          S  |||           d d!d"d#d$}|                    d%d          }|                    d&d          }g }|rM|                    t/          d'dd()                     |                    t/          d*| d+d                     |r(|                    t/          d,| dd-                     |                    t/          ||         dd()                     t          dt'          t)                                          d                              |                    	          S ).z4Handle an Adaptive Card Action.Execute button click.r   )resolve_gateway_approvalhas_blocking_approvalhermes_actionrE   session_keyr   zUnknown action.)r&   )r   r   TEAMS_ALLOWED_USERSTEAMS_ALLOW_ALL_USERS>   r*   r,   r-   us   [teams] card action rejected: TEAMS_ALLOWED_USERS not configured and TEAMS_ALLOW_ALL_USERS not set — default denyuB   ⛔ Approval buttons require TEAMS_ALLOWED_USERS to be configured.r  Nr   c                ^    h | ]*}|                                 |                                 +S rN   )r4   )r   uids     r7   	<setcomp>z/TeamsAdapter._on_card_action.<locals>.<setcomp>  s-    XXX3CIIKKX399;;XXXr9   ,*u3   [teams] Unauthorized card action by %s — ignoringu   ⛔ Not authorized.oncerS  alwaysdeny)approve_onceapprove_sessionapprove_alwaysr  1.4u,   ⚠️ Approval already resolved or expired.Tr   wrapu   ✅ Allowed (once)u   ✅ Allowed (session)u   ✅ Always allowedu
   ❌ Denied)r  rS  r  r  cmddesc    ⚠️ Command Approval RequiredBolderr   r  weight```

```Reason: r   r  isSubtle)tools.approvalr  r  rV  r&   actionr9  rs   r   r   r   r   r4   r5   rK  r  r  r   splitr   r   with_version	with_bodyr   r   )rG   rx  r  r  r  r9  r  r  allowed_csv	allow_allr  
clicker_idallowed_ids
choice_mapchoice	label_mapr  r  r   s                      r7   r  zTeamsAdapter._on_card_action  s      	SRRRRRRR#*{ b"55hh}b11 	K 	!6=NOOO    i 5r::@@BBI5r::@@BBHHJJNbb	 	 
I   &:b      <-L EEhQ]_cegIhIhJXX+2C2CC2H2HXXXK+%%*K*G*GTV`aaa%:AVWWW    #(&	
 

 .. 	!6=NOOO   
 %$[11 	!3&..!\%((Y	/]dh i i ijkk      	! f555 ).* 	
 
	 hhub!!xx## 	GKK	'IPT]efffgggKK	'9s'9'9'9EEEFFF 	UKK	'8$'8'8tdSSSTTTI9V#44QQQRRR/"nn11%88BB4HH  
 
 
 	
r9   dangerous commandNcommandr  descriptionmetadataOptional[Dict[str, Any]]r!   c                  K   | j         st          dd          S t          |          dk    r|dd         dz   n|}|t          |          dk    r|dd         dz   n||d}t                                          d	                              t          d
dd          t          d| dd          t          d| dd          g                              t          ddi |ddid          t          ddi |ddi          t          ddi |ddi          t          ddi |ddid           g          }	 | 	                    ||           d{V }	|	rt          |	d!d          nd}
t          d|
"          S # t          $ rF}t                              d#|d$           t          dt          |          d%          cY d}~S d}~ww xY w)&z>Send an Adaptive Card approval prompt with Allow/Deny buttons.FTeams app not initializedr?  r2  i  Nz...r   )r  r  r  r  r  Tr  r  r  r	  r   r
  r  z
Allow Oncehermes_approver  r  positive)r   verbr9  stylezAllow Sessionr  )r   r#  r9  zAlways Allowr  Denyr  destructiver   r>  z%[teams] send_exec_approval failed: %sr@  r?  r2  rn  )rg  r!   r   r   r  r  r   with_actionsr   r  r   r$  rK  r2  r3   )rG   rn   r  r  r  r  cmd_previewbtn_data_baser  r   r   rY  s               r7   send_exec_approvalzTeamsAdapter.send_exec_approval  s      y 	Pe3NOOOO03Gt0C0Cgetenu,, ',/LL3,>,>74C4=5((G
 
 NN\%  YAU]^^^9{999EEE7+77dTRRR  
 \&)KMK?NKK$	   ))NMN?<MNN  
 ()MMM?<LMM  
  )CMC?FCC'	  #   	D	K??7D99999999F8>Ht444DJdzBBBB 	K 	K 	KLL@!dLSSSe3q66TJJJJJJJJJ	Ks   AF 
G;G	GGr   reply_tor  c                  K   | j         st          dd          S |                     |          }|                     |          }d }|D ] }	 |r|                                r}|dk    rw	 | j                             |||           d {V }	nt# t          $ rF}
t                              d|
           | j         	                    ||           d {V }	Y d }
~
n)d }
~
ww xY w| j         	                    ||           d {V }	t          |	dd           }# t          $ r+}t          dt          |          d          cY d }~c S d }~ww xY wt          d|	          S )
NFr  r   r.   z3Teams reply() failed, falling back to flat send: %sr   Tr'  r>  )rg  r!   format_messagetruncate_messageisdigitreplyr$  rK  rL  r  r   r3   )rG   rn   r   r,  r  	formattedchunkslast_message_idchunkr   	reply_errrY  s               r7   r  zTeamsAdapter.send6  s      y 	Pe3NOOOO''00	&&y11 	O 	OEO B 0 0 2 2 Bx3
F'+yw%'P'P!P!P!P!P!P!P$ F F F Q%   (,y~~gu'E'E!E!E!E!E!E!EF $(9>>'5#A#AAAAAAAF")&$"="= O O O!%s1vvNNNNNNNNNNNO $?CCCCsH   D*"BD
C<CDC5D
EE;EEc                   K   | j         sd S 	 | j                             |t                                 d {V  d S # t          $ r Y d S w xY wr<   )rg  r  r   r$  )rG   rn   r  s      r7   send_typingzTeamsAdapter.send_typingZ  sq      y 	F	)..*=*?*?@@@@@@@@@@@ 	 	 	DD	s   -< 
A
	A
	image_urlcaptionc                  K   | j         st          dd          S 	 dd l}dd l}ddlm}m}	 |                    d          s|                    d          r|}
d}n|                    d	          }|	                    |          d         pd}t          |d
          5 }d| d|                    |                                                                           }
d d d            n# 1 swxY w Y    |||
          } |	                                |          }|r|                    |          }| j                            |          }|r'| j         j                            ||           d {V }n!| j                             ||           d {V }t          dt)          |dd                     S # t*          $ rF}t,                              d|d           t          dt1          |          d          cY d }~S d }~ww xY w)NFr  r   r   )
Attachmentr  zhttp://zhttps://z	image/pngzfile://rbzdata:z;base64,)r   r  Tr   r>  z[teams] send_image failed: %sr@  r'  )rg  r!   base64	mimetypesr  r<  r  r  removeprefix
guess_typeopen	b64encodereaddecodeadd_attachmentsadd_textrj  rs   r  r  r   r$  rK  r2  r3   )rG   rn   r9  r:  r,  r  r>  r?  r<  r  r  r  r   f
attachmentrV  r  r   rY  s                      r7   
send_imagezTeamsAdapter.send_imageb  s      y 	Pe3NOOOO	KMMMLLLLLLLL##I.. c)2F2Fz2R2R c''		 !--i88%0066q9H[	$%% c"b)"b"bV=M=Maffhh=W=W=^=^=`=`"b"bKc c c c c c c c c c c c c c c $TTTJ++--==jIIH 6#,,W55**733H A#y8==hQQQQQQQQ#y~~gx@@@@@@@@dwvtT7R7RSSSS 	K 	K 	KLL8!dLKKKe3q66TJJJJJJJJJ	KsD   BF9 A C)F9 )C--F9 0C-1CF9 9
H	;H>H	H	
image_pathc                D   K   |                      ||||           d {V S )N)rn   r9  r:  r,  )rJ  )rG   rn   rK  r:  r,  kwargss         r7   send_image_filezTeamsAdapter.send_image_file  sM       __ 	 % 
 
 
 
 
 
 
 
 	
r9   rt   c                   K   |d|dS )Nunknown)r  r;  rn   rN   )rG   rn   s     r7   get_chat_infozTeamsAdapter.get_chat_info  s      wGGGr9   )rc   r   r(   r'   rQ   )r  )r  r3   r   r  r(   r  )rx  ry  r(   rL   )rn   r3   r  r  r(   r  )rx  r  r(   r  )r  N)rn   r3   r  r3   r  r3   r  r3   r  r  r(   r!   )NN)
rn   r3   r   r3   r,  r  r  r  r(   r!   r<   )rn   r3   r  r  r(   rL   )NNN)rn   r3   r9  r3   r:  r  r,  r  r  r  r(   r!   )
rn   r3   rK  r3   r:  r  r,  r  r(   r!   )rn   r3   r(   rt   )rR   rS   rT   rU   MAX_MESSAGE_LENGTHrH   r  r  r  r{  r  r  r+  r  r8  rJ  rN  rQ  __classcell__)rk  s   @r7   r\  r\  o  s       EE- - - - - - J J J JX, , , ,$ $ $ $ $8V) V) V) V)p
 
 
 
]
 ]
 ]
 ]
H /-1<K <K <K <K <KD #'-1"D "D "D "D "DH     "&"&-1(K (K (K (K (K\ "&"&
 
 
 
 
H H H H H H H Hr9   r\  rL   c                 ~   ddl m} m} ddlm}m}m}m}m}  | d          }|r |d| d            |dd          sd	S  |d
            |d            |d           t                        |d            |d            |d           t                        |d           t                        |d|pd          }|s |d           d	S  |d|
                                            |d | d          pdd          }	|	s |d           d	S  |d|	
                                            |d | d          pd          }
|
s |d           d	S  |d|

                                           t                        |d            |dd          rS |d | d           pd          }|r, |d |                    d!d                      |d"           n$ |d d           n |d#d$            |d%           t                        |d&            |d'            |d(           d	S ))z7Guide the user through Teams setup using the Teams CLI.r   )get_env_valuesave_env_value)promptprompt_yes_no
print_infoprint_successprint_warningr  z#Teams: already configured (app ID: )zReconfigure Teams?FNz2You'll need the Teams CLI. If you haven't already:z-  npm install -g @microsoft/teams.cli@previewz  teams loginzAThen expose port 3978 publicly (devtunnel / ngrok / cloudflared),zand create your bot:zM  teams app create --name "Hermes" --endpoint "https://<tunnel>/api/messages"zMThe CLI will print CLIENT_ID, CLIENT_SECRET, and TENANT_ID. Paste them below.z	Client IDrE   r$   u.   Client ID is required — skipping Teams setupzClient secretr
  T)r%   passwordu2   Client secret is required — skipping Teams setupz	Tenant IDr  u.   Tenant ID is required — skipping Teams setupzDTo find your AAD object ID for the allowlist: teams status --verbosez0Restrict access to specific users? (recommended)z(Allowed AAD object IDs (comma-separated)r   zAllowlist configuredr  r-   uF   ⚠️  Open access — anyone who can message the bot can command it.z+Teams configuration saved to ~/.hermes/.envz>Install the app in Teams:  teams app install --id <teamsAppId>z1Restart the gateway:       hermes gateway restart)hermes_cli.configrV  rW  hermes_cli.cli_outputrX  rY  rZ  r[  r\  printr4   replace)rV  rW  rX  rY  rZ  r[  r\  existing_idr	  r  r  alloweds               r7   interactive_setuprf    s                         - 122K 
GGGGHHH}1599 	FJCDDDJ>???J	GGGJRSSSJ%&&&Jbccc	GGGJ^___	GGG{K,=2>>>I FGGGN$ioo&7&7888F?MMBW4X4X4^\^imnnnM JKKKN(-*=*=*?*?@@@{MM:K,L,L,RPRSSSI FGGGN$ioo&7&7888	GGGJUVVV}GNN `&6!M"788>B
 
 
  	6N0'//#r2J2JKKKM01111N0"5555.777^___	GGGM?@@@JOPPPJBCCCCCr9   c                    |                      ddd t          t          t          g ddt          t
          dt          ddd	d
dd           dS )u:   Plugin entry point — called by the Hermes plugin system.r_  zMicrosoft Teamsc                     t          |           S r<   )r\  )cfgs    r7   rs  zregister.<locals>.<lambda>  s    L$5$5 r9   )r  r
  r  z(pip install microsoft-teams-apps aiohttpr  r  r  r]  u   💼Tu   You are chatting via Microsoft Teams. Teams renders a subset of markdown — bold (**text**), italic (*text*), and inline code (`code`) work, but complex tables or raw HTML do not. Keep responses clear and professional.)r  labeladapter_factorycheck_fnr  r  required_envinstall_hintsetup_fnenv_enablement_fncron_deliver_env_varstandalone_sender_fnallowed_users_envallow_all_envmax_message_lengthemojiallow_update_commandplatform_hintN)register_platformr  r  r  rf  r  rZ  )rx  s    r7   registerrz    sq    55#'!RRR?" * 2 ./- !0A  % % % % %r9   )r&   r   r%   r'   r(   r'   )r&   r   r%   r:   r(   r:   rR  )r(   r  )r  r3   r(   r  )rn   r3   r.  r3   r+  r  r,  r/  r-  r'   r(   r0  rQ   )VrU   
__future__r   rI  r   r   loggingr   typingr   r   r   r#  r   rF  r   r  ImportErrormicrosoft_teams.appsr	   r
   "microsoft_teams.common.http.clientr   r  r   r   %microsoft_teams.api.activities.typingr   3microsoft_teams.api.activities.invoke.adaptive_cardr   (microsoft_teams.api.models.adaptive_cardr   r   *microsoft_teams.api.models.invoke_responser   r   !microsoft_teams.apps.http.adapterr   r   r   r   microsoft_teams.cardsr   r   r   r  r3   gateway.configr   r   gateway.platforms.helpersr   r  r   r   r    r!   r"   r#   	getLoggerrR   rK  re  r  r8   r?   rA   rW   r   r  r  r  r  rB  	frozensetr'  r  	_re_teamscompilerD  r*  rZ  check_teams_requirementsr\  rf  rz  rN   r9   r7   <module>r     s$   , # " " " " "     				 & & & & & & & & & &         
CCC'99999999@@@@@@JJJJJJJJIIIIII^^^^^^        feeeeeee            MLLLLLLLLL   M
COO !%%)"(,%!%NJKLLMIII'* 4 3 3 3 3 3 3 3 9 9 9 9 9 9                
	8	$	$ 05 	 	 	 	 	 	 0=              P= P= P= P= P= P= P= P=f% % % % % % % %P5 5 5 5
; ; ; ;# # # #
$ $ $ $V F 
  )y'*         %I%&=>>    8  $"& w? w? w? w? w? w?v . mH mH mH mH mH& mH mH mHdDD DD DD DDR' ' ' ' ' 's"   7 	AAA
B +C ?C 