
    Jjm                       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Z@dddCdZAe>ddDd ZB G d! d"          ZC G d# d$          ZD G d% d&          ZEdEd'ZFdEd(ZGdEd)ZHdFd+ZId,ZJ eKd-d.h          ZLddlMZN eNjO        d/          ZPdGd3ZQdddd4dHd<ZRdEd=ZS G d> d?e5          ZTdIdAZUdIdBZVdS )Ja  
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  i   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)
isinstancer1   strstriplower)r0   r/   
normalizeds      E/home/rurouni/.hermes/hermes-agent/plugins/platforms/teams/adapter.py_parse_boolrB   o   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)rD   	TypeError
ValueError)r0   r/   s     rA   _coerce_portrI   {   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_tokenr=   c                V    t          |pd                                          | _        d S N )r=   r>   _access_token)selfrL   s     rA   __init__z#_StaticAccessTokenProvider.__init__   s)     !344::<<rC   F)force_refreshrS   r1   r2   c               B   K   ~| j         st          d          | j         S )Nz=TEAMS_GRAPH_ACCESS_TOKEN is required for graph delivery mode.)rP   rH   )rQ   rS   s     rA   get_access_tokenz+_StaticAccessTokenProvider.get_access_token   s-      ! 	^\]]]!!rC   Nonec                    d S rF    rQ   s    rA   clear_cachez&_StaticAccessTokenProvider.clear_cache   s    trC   N)rL   r=   )rS   r1   r2   r=   r2   rV   )__name__
__module____qualname____doc__rR   rU   rZ   rX   rC   rA   rK   rK      sf        ]]= = = = ?D " " " " " "     rC   rK   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 | Nonerb   
Any | Nonerc   httpx.AsyncBaseTransport | Noner2   rV   c               0    || _         || _        || _        d S rF   )_platform_config_graph_client
_transport)rQ   rd   rb   rc   s       rA   rR   zTeamsSummaryWriter.__init__   s     !0)#rC   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moderO   incoming_webhook_urlincoming_webhookchat_idteam_id
channel_idgraphz:Teams delivery_mode must be 'incoming_webhook' or 'graph'.)
_resolve_delivery_configrB   getdictr=   r>   r?   #_write_summary_via_incoming_webhook_write_summary_via_graphrH   )rQ   rl   rm   ro   mergedru   s         rA   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
 
 	
rC   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 )NrL   rz   TEAMS_DELIVERY_MODErO   TEAMS_INCOMING_WEBHOOK_URLTEAMS_GRAPH_ACCESS_TOKENTEAMS_TEAM_IDTEAMS_CHANNEL_IDTEAMS_CHAT_ID)rt   rv   rL   ry   rz   rx   )ri   updater~   extratokenhome_channel
setdefaultrx   osgetenvitemsr}   )rQ   rm   r   platform_cfgenv_defaultskeyr0   s          rA   r|   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rC   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   rv   rO   zATEAMS_INCOMING_WEBHOOK_URL is required for incoming_webhook mode.textg      4@)timeoutrc   )jsonrw   T)rt   webhook_urlstatus_code	delivered)httpxr=   r}   r>   rH   _render_summary_markdownAsyncClientrk   postraise_for_statusr   )rQ   rl   rm   r   r   bodyclientresponses           rA   r   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 )Nrx   rO   z/chats/)safez	/messagesr   html)contentTypecontent)	json_bodyr{   chatidwebUrl)rt   target_typerx   
message_idweb_urlry   rz   zEGraph delivery mode requires chat_id, or both team_id and channel_id.z/teams/z
/channels/channel)rt   r   ry   rz   r   r   )_build_graph_clientr=   r}   r>   r   	post_json_render_summary_htmlrH   )	rQ   rl   rm   rb   rx   pathr   ry   rz   s	            rA   r   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
 
 	
rC   c                ,   | j         | j         S ddlm} ddlm} t          |                    d          pd                                          }|r |t          |          | j	                  S  ||
                                | j	                  S )Nr   )MicrosoftGraphTokenProvider)MicrosoftGraphClientrL   rO   )rc   )rj   tools.microsoft_graph_authr   tools.microsoft_graph_clientr   r=   r}   r>   rK   rk   from_env)rQ   rm   r   r   rL   s        rA   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
 
 
 	
rC   r=   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**rO   z	Summary: summaryNo summary available.zKey decisions:key_decisionszAction items:action_itemszRisks:risks
)_title_textgetattr_bullet_linesjoin)rQ   rl   liness      rA   r   z+TeamsSummaryWriter._render_summary_markdown,  s    )W%%)))`

77It#D#DF]^^``
 $ G GHH
 
 
  F FGG
 
 
 $ ? ?@@
 yyrC   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>rO   c              3     K   | ]J}t          |                                          #d t          j        t          |                     dV  KdS )z<li>z</li>N)r=   r>   r   escape.0items     rA   	<genexpr>z:TeamsSummaryWriter._render_summary_html.<locals>.<genexpr>K  sY      "o"oD]`ae]f]f]l]l]n]n"o#G$+c$ii*@*@#G#G#G"o"o"o"o"o"orC   z<ul>z</ul>z<p>None</p>)
r   r   listr   r   r   appendlenr=   r   )rQ   rl   sectionsblocksheadingr   rendereds          rA   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rC   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   r=   )rl   r   r   r   s       rA   r   zTeamsSummaryWriter._titleQ  sg    $// 	u::g}d;;ALVW[,===RV
3*1	333rC   r0   r/   c                P    t          | pd                                          }|p|S rN   r=   r>   )r0   r/   r   s      rA   r   zTeamsSummaryWriter._textZ  s)    5;B%%''wrC   values	list[str]c                <    d |pg D             }d |D             pdgS )Nc                    g | ]D}t          |                                          #t          |                                          ES rX   r   r   s     rA   
<listcomp>z4TeamsSummaryWriter._bullet_lines.<locals>.<listcomp>a  s=    SSStTARARST""SSSrC   c                    g | ]}d | S )z- rX   r   s     rA   r   z4TeamsSummaryWriter._bullet_lines.<locals>.<listcomp>b  s    ...T...rC   z- NonerX   )clsr   r   s      rA   r   z TeamsSummaryWriter._bullet_lines_  s4    SS"SSS.....<8*<rC   rF   )rd   re   rb   rf   rc   rg   r2   rV   )rl   r   rm   rn   ro   rp   r2   rq   )rm   rn   r2   rq   )rl   r   rm   rq   r2   rq   )rm   rq   r2   r   )rl   r   r2   r=   )r0   r   r/   r=   r2   r=   )r   r   r2   r   )r\   r]   r^   r_   rR   r   r|   r   r   r   r   r   staticmethodr   r   classmethodr   rX   rC   rA   ra   ra      sE         26	$ $(59	$ 	$ 	$ 	$ 	$ 	$ 59	
 
 
 
 
4   0
 
 
 
.*
 *
 *
 *
X
 
 
 
$       "   ( 4 4 4 \4    \ = = = [= = =rC   ra   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 rF   )_aiohttp_app)rQ   r   s     rA   rR   z_AiohttpBridgeAdapter.__init__m  s    'rC   method'HttpMethod'r   r=   handler'HttpRouteHandler'r2   rV   c                V    dfd}| j         j                            |||           dS )z2Register an SDK route handler as an aiohttp route.request'web.Request'r2   '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   r~   r   r   r}   r	   Responsedumps)r   r   r   resultr   	resp_bodyr   s         rA   _aiohttp_handlerz>_AiohttpBridgeAdapter.register_route.<locals>._aiohttp_handlers  s       ''''''D7?++G+27;DRY3Z3Z3Z+[+[%[%[%[%[%[%[FZZ#..F

6**I$|!I..!3   
 <v....rC   N)r   r   r2   r   )r   router	add_route)rQ   r   r   r   r   s      ` rA   register_routez$_AiohttpBridgeAdapter.register_routep  sH    	/ 	/ 	/ 	/ 	/ 	/ 	 **649IJJJJJrC   	directoryc                    d S rF   rX   )rQ   r   r  s      rA   serve_staticz"_AiohttpBridgeAdapter.serve_static  s    rC   portrD   c                $   K   t          d          )Nz(aiohttp server is managed by the adapter)NotImplementedError)rQ   r  s     rA   startz_AiohttpBridgeAdapter.start  s      !"LMMMrC   c                
   K   d S rF   rX   rY   s    rA   stopz_AiohttpBridgeAdapter.stop  s      rC   N)r   r   )r   r   r   r=   r   r   r2   rV   )r   r=   r  r=   r2   rV   )r  rD   r2   rV   r[   )	r\   r]   r^   r_   rR   r  r  r
  r  rX   rC   rA   r   r   e  s         ( ( ( (K K K K&   N N N N     rC   r   c                     t           ot          S )zDReturn True when all Teams dependencies and credentials are present.)TEAMS_SDK_AVAILABLEAIOHTTP_AVAILABLErX   rC   rA   check_requirementsr    s    4#44rC   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_idrO   TEAMS_CLIENT_SECRETclient_secretTEAMS_TENANT_ID	tenant_id)r   r   r   r}   r1   )rm   r   r  r  r  s        rA   validate_configr    s    FGR((.BE	+,,J		+r0J0JII344V		/SU8V8VM	+,,J		+r0J0JI	9m9	:::rC   c                     t          |           S )z7Check whether Teams is configured (env or config.yaml).)r  )rm   s    rA   is_connectedr    s    6"""rC   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  rO   r  r  N)r  r  r  
TEAMS_PORTr  TEAMS_SERVICE_URLservice_urlTEAMS_HOME_CHANNELTEAMS_HOME_CHANNEL_NAMEHome)rx   namer   )r   r   r>   rD   rH   )r  r  r  seedr  r  homes          rA   _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:@\-_.]+$rawr=   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*  parsedr@   s       rA   _validate_teams_service_urlr4    s      t))))))#   tt}t:::tS))8sSyJs    
&&)	thread_idmedia_filesforce_documentrx   messager5  r6  Optional[list]r7  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  rO   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,  rL   z:Teams standalone send: token response missing access_tokenr8  markdown)typer   
textFormatzBearer r   )AuthorizationrB  )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   r}   _DEFAULT_TEAMS_SERVICE_URLr4  sortedr1  _TEAMS_CONV_ID_REmatchr  aiohttpClientTimeoutClientSessionr   r   r   r   asyncioCancelledErrorr.  loggerdebug)pconfigrx   r8  r5  r6  r7  r   r  r  r  raw_service_urlr  	token_urlactivities_url_aiohttpper_request_timeoutsession
token_respr   token_payloadrL   activity	send_respsend_payloades                            rA   _standalone_sendrd    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                 l    t           r	t          rdS d
d} ddlm}  |d| t	                      d	          S )a^  Ensure the Teams SDK is importable, lazy-installing it on first use.

    Lazy-installs ``microsoft-teams-apps`` via
    ``tools.lazy_deps.ensure("platform.teams")`` if not present, then rebinds
    all module-level SDK globals on success. Returns True once the SDK (and
    aiohttp) are importable, False if they couldn't be installed/imported.
    Tr2   r~   c                    ddl m}  ddlm}m} ddlm} ddlm}m	} ddl
m} ddlm} ddlm}m}	 dd	lm}
m} dd
lm}m}m}m} ddlm}m}m} i d| ddd|d|d|d|d|d|d|d|d|	d|
d|d|d|d|d||||ddS )Nr   r   r
   r   r   r   r   r   r   r   r!   r	   r  Tr   r   r   r   r   r   r   r   r   r   r   r   r   r   r    )r"   r#   r$   r  )rP  r	   microsoft_teams.appsr   r   "microsoft_teams.common.http.clientr   microsoft_teams.apir   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$   )_webr   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r"   r#   r$   s                      rA   _importz)check_teams_requirements.<locals>._import  s)   ''''''========DDDDDDNNNNNNNNMMMMMM	
 	
 	
 	
 	
 	
	
 	
 	
 	
 	
 	
 	
 	
	
 	
 	
 	
 	
 	
 	
 	
	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	QPPPPPPPPP
4

 3
 	

 ]
 
 $%:
 "#6
 )*D
 -.L
 01R
 n
 )*D
 *
 ;
  L!
"  0#
$ )*"#'+
 
 
 	
rC   r   )ensure_and_bindzplatform.teamsF)prompt)r2   r~   )r  r  tools.lazy_depsrr  globals)rq  rr  s     rA   check_teams_requirementsrv  t  s`      0 t/
 /
 /
 /
b 0/////?+WgiiNNNNrC   c                       e Zd ZdZdZdZdB fdZdddCdZdDdZdEdFdZ	dGdZ
dHdZdId Z	 	 dJdKd)Z	 	 dLdMd-ZdNdOd.Z	 	 dPdQd4Z	 	 	 dRdSd6Z	 	 dLdTd8Z	 	 	 dRdUd:Z	 	 	 dRdVd<Z	 	 	 	 dWdXd?ZdYdAZ xZS )ZTeamsAdapterz;Microsoft Teams adapter using the microsoft-teams-apps SDK.`m  Trm   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  rO   r  r  r  r  r  r  i  )max_size)superrR   r%   r   r}   r   r   
_client_id_client_secret
_tenant_idrI   r=   _DEFAULT_PORT_port_app_runnerr'   _dedup
_conv_refs)rQ   rm   r   	__class__s      rA   rR   zTeamsAdapter.__init__  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 +-rC   F)is_reconnectr  r1   r2   c          
        K   t                       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        t                    }|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 _                                          t6                              d j        t:                     dS # t<          $ rA}                     dd| d           t6                              d|           Y d }~dS d }~ww xY w)NMISSING_SDKzRmicrosoft-teams-apps could not be 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 required)client_max_sizez/healthc                ,    t          j        d          S )Nok)r   )r	   r   )_s    rA   <lambda>z&TeamsAdapter.connect.<locals>.<lambda>  s    CLd<S<S<S rC   
User-AgentHermesr   )r  r  r  http_server_adapterr   ctx ActivityContext[MessageActivity]c                B   K                        |            d {V  d S rF   )_on_messager  rQ   s    rA   _handle_messagez-TeamsAdapter.connect.<locals>._handle_message  s3      &&s+++++++++++rC   +ActivityContext[AdaptiveCardInvokeActivity]r2   1InvokeResponse[AdaptiveCardActionMessageResponse]c                >   K                        |            d {V S rF   )_on_card_actionr  s    rA   _handle_card_actionz1TeamsAdapter.connect.<locals>._handle_card_action  s/       "11#666666666rC   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)r  r  )r  r  r2   r  ) rv  r  _set_fatal_errorr  r~  r  r  r	   Application_MAX_BODY_BYTESr  add_getr   r   r   r  
on_messageon_card_action
initialize	AppRunnerr  setupTCPSiter  r
  _running_mark_connectedrU  info_WEBHOOK_PATHr.  r<  )rQ   r  r   r  r  siterc  s   `      rA   connectzTeamsAdapter.connect  s      	!"""" 	!!d "   
 5  	!!A "   
 5 	d&9 	 	!!%\ "   
 55	 //JJJK&&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   E=H 
I6I		IrV   c                   K   d| _         | j        r&| j                                         d {V  d | _        d | _        |                                  t
                              d           d S )NFz[teams] Disconnected)r  r  cleanupr  _mark_disconnectedrU  r  rY   s    rA   
disconnectzTeamsAdapter.disconnect  sv      < 	 ,&&(((((((((DL	!!!*+++++rC         >@urlr=   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_hooksr  z)Mozilla/5.0 (compatible; HermesAgent/1.0)r  )
tools.url_safetyr  gateway.platforms.baser  rH   r   r   r}   r   r   )rQ   r  r   r  r  r   r   r   s           rA   _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&r  r  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   rO   r   z<at>r   z<at>[^<]*</at>\s*conversation_typepersonaldm	groupChatgroupr   aad_object_idr#  r  )rx   	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   )*r`  r  r   r   from_r  is_duplicateconversationconversation_refr  hasattrr   resubr>   build_sourcer=   r  r?   
startswithr<   r~   r}   lstripr  r-   r   r   
media_typekindrU  warningr.  r,   r*   DOCUMENTPHOTOVIDEOAUDIOTEXTr)   handle_message)rQ   r  r`  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  rC  cachedrc  msg_typeevents                                  rA   r  zTeamsAdapter._on_messageC  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rx   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)ri  r  r  r}   r  add_cardactivity_sendersend)rQ   rx   r  r  conv_refr`  s         rA   
_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trC   -'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_actionrO   session_keyr   zUnknown action.)r0   )r   r   TEAMS_ALLOWED_USERSTEAMS_ALLOW_ALL_USERS>   r4   r6   r7   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 rX   )r>   )r   uids     rA   	<setcomp>z/TeamsAdapter._on_card_action.<locals>.<setcomp>  s-    XXX3CIIKKX399;;XXXrC   ,*u3   [teams] Unauthorized card action by %s — ignoringu   ⛔ Not authorized.oncer]  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  r]  r  r  cmddesc    ⚠️ Command Approval RequiredBolderr   r  weight```

```Reason: r   r  isSubtle)tools.approvalr  r  r`  r0   actionrC  r}   r   r   r   r   r>   r?   rU  r  r  r   splitr   r"   with_version	with_bodyr$   r   )rQ   r  r  r  r,  rC  r  r  allowed_csv	allow_allr  
clicker_idallowed_ids
choice_mapchoice	label_mapr   r!  r   s                      rA   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  
 
 
 	
rC   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rI  r<  i  Nz...r   )r  r   r!  r  r"  Tr#  r$  r&  r'  r  r(  r)  z
Allow Oncehermes_approver  r  positive)r   verbrC  stylezAllow Sessionr  )r   rA  rC  zAlways Allowr  Denyr  destructiver   rH  z%[teams] send_exec_approval failed: %srJ  rI  r<  r  )r  r+   r   r"   r.  r/  r$   with_actionsr#   r  r   r.  rU  r<  r=   )rQ   rx   r8  r  r9  r:  cmd_previewbtn_data_baser  r   r   rc  s               rA   send_exec_approvalzTeamsAdapter.send_exec_approvalF  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>  r8   z3Teams reply() failed, falling back to flat send: %sr   TrE  rH  )r  r+   format_messagetruncate_messageisdigitreplyr.  rU  rV  r  r   r=   )rQ   rx   r   rJ  r:  	formattedchunkslast_message_idchunkr   	reply_errrc  s               rA   r  zTeamsAdapter.send  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rF   )r  r  r   r.  )rQ   rx   r:  s      rA   send_typingzTeamsAdapter.send_typing  sq      y 	F	)..*=*?*?@@@@@@@@@@@ 	 	 	DD	s   -< 
A
	A
mediar  default_mimecaptionmedia_labelc                  K   | j         st          dd          S 	 ddl}ddl}ddlm}m}	 |                    d          s|                    d          r9|}
|                    |	                    d	          d                   d         p|}n|
                    d
          }|                    |          d         p|}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,          $ rG}t.                              d||d           t          dt3          |          d          cY d}~S d}~ww xY w)a  Send any media file/URL as a Teams attachment.

        Remote ``http(s)://`` URLs are attached by reference; local paths
        (with optional ``file://`` prefix) are base64-encoded into a data
        URI. MIME type is guessed from the path/extension, falling back to
        ``default_mime``. Shared by send_image / send_video / send_voice /
        send_document so every media kind uses the same Attachment path.
        Fr=  r>  r   N)
Attachmentr  zhttp://zhttps://?zfile://rbzdata:z;base64,)r   r  Tr   rH  z[teams] send_%s failed: %srJ  rE  )r  r+   base64	mimetypesri  r\  r  r  
guess_typer-  removeprefixopen	b64encodereaddecodeadd_attachmentsadd_textr  r}   r  r  r   r.  rU  r<  r=   )rQ   rx   r  rX  rY  rZ  r_  r`  r\  r  r  r  r   f
attachmentr`  r  r   rc  s                      rA   _send_media_attachmentz#TeamsAdapter._send_media_attachment  s       y 	Pe3NOOOO	KMMMLLLLLLLL  ++ cv/@/@/L/L c$%00c1B1B11EFFqIY\		 **955%0066q9I\	$%% 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5{APTLUUUe3q66TJJJJJJJJJ	KsD   B5G- A DG- D!!G- $D!%CG- -
H>7<H93H>9H>	image_urlc                F   K   |                      ||d|d           d {V S )Nz	image/pngr  rx   r  rX  rY  rZ  rk  )rQ   rx   rl  rY  rJ  r:  s         rA   
send_imagezTeamsAdapter.send_image  sR       00$ 1 
 
 
 
 
 
 
 
 	
rC   
image_pathc                D   K   |                      ||||           d {V S )N)rx   rl  rY  rJ  )rp  )rQ   rx   rq  rY  rJ  kwargss         rA   send_image_filezTeamsAdapter.send_image_file  sM       __ 	 % 
 
 
 
 
 
 
 
 	
rC   
video_pathc                F   K   |                      ||d|d           d {V S )Nz	video/mp4r  rn  ro  )rQ   rx   ru  rY  rJ  r:  rs  s          rA   
send_videozTeamsAdapter.send_video  sR       00$ 1 
 
 
 
 
 
 
 
 	
rC   
audio_pathc                F   K   |                      ||d|d           d {V S )Nz
audio/mpegvoicern  ro  )rQ   rx   rx  rY  rJ  r:  rs  s          rA   
send_voicezTeamsAdapter.send_voice  sR       00% 1 
 
 
 
 
 
 
 
 	
rC   	file_path	file_namec                F   K   |                      ||d|d           d {V S )Nzapplication/octet-streamr  rn  ro  )rQ   rx   r|  rY  r}  rJ  r:  rs  s           rA   send_documentzTeamsAdapter.send_document#  sR       003" 1 
 
 
 
 
 
 
 
 	
rC   r~   c                   K   |d|dS )Nunknown)r#  rE  rx   rX   )rQ   rx   s     rA   get_chat_infozTeamsAdapter.get_chat_info5  s      wGGGrC   )rm   r&   )r  r1   r2   r1   r[   )r  )r  r=   r   r  r2   r  )r  r  r2   rV   )rx   r=   r  r   r2   r  )r  r	  r2   r
  )r7  N)rx   r=   r8  r=   r  r=   r9  r=   r:  r;  r2   r+   )NN)
rx   r=   r   r=   rJ  r(  r:  r;  r2   r+   rF   )rx   r=   r:  r;  r2   rV   )NrW  )rx   r=   r  r=   rX  r=   rY  r(  rZ  r=   r2   r+   )NNN)rx   r=   rl  r=   rY  r(  rJ  r(  r:  r;  r2   r+   )
rx   r=   rq  r=   rY  r(  rJ  r(  r2   r+   )rx   r=   ru  r=   rY  r(  rJ  r(  r:  r;  r2   r+   )rx   r=   rx  r=   rY  r(  rJ  r(  r:  r;  r2   r+   )NNNN)rx   r=   r|  r=   rY  r(  r}  r(  rJ  r(  r:  r;  r2   r+   )rx   r=   r2   r~   )r\   r]   r^   r_   MAX_MESSAGE_LENGTHsplits_long_messagesrR   r  r  r  r  r  r  rI  r  rV  rk  rp  rt  rw  r{  r  r  __classcell__)r  s   @rA   rx  rx    sJ       EE- - - - - -  5: Q Q Q Q Q Qf, , , ,$ $ $ $ $8V) V) V) V)p
 
 
 
]
 ]
 ]
 ]
H /-1<K <K <K <K <KD #'-1"D "D "D "D "DH     "&"0K 0K 0K 0K 0Kl "&"&-1
 
 
 
 
( "&"&
 
 
 
 
& "&"&-1
 
 
 
 
* "&"&-1
 
 
 
 
* "&#'"&-1
 
 
 
 
$H H H H H H H HrC   rx  rV   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)rs  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 IDrO   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  r7   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.configr  r  hermes_cli.cli_outputrs  r  r  r  r  printr>   replace)r  r  rs  r  r  r  r  existing_idr  r  r  alloweds               rA   interactive_setupr  ;  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CrC   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 rF   )rx  )cfgs    rA   r  zregister.<locals>.<lambda>  s    L$5$5 rC   )r  r  r  z(pip install microsoft-teams-apps aiohttpr   r  r  ry  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  r  r&  rd  )r  s    rA   registerr    sq    55#'!RRR?" * 2 ./- !0A  % % % % %rC   )r0   r   r/   r1   r2   r1   )r0   r   r/   rD   r2   rD   )r2   r1   )r2   r  )r'  r=   r2   r(  )rx   r=   r8  r=   r5  r(  r6  r9  r7  r1   r2   r:  r[   )Wr_   
__future__r   rS  r   r   loggingr   typingr   r   r   r-  r   rP  r	   r  ImportErrorrg  r   r   rh  r   ri  r   r   rj  r   rk  r   rl  r   r   rm  r   r   rn  r   r   r   r    ro  r"   r#   r$   r  r=   gateway.configr%   r&   gateway.platforms.helpersr'   r  r(   r)   r*   r+   r,   r-   	getLoggerr\   rU  r  r  r  rB   rI   rK   ra   r   r  r  r  r&  rL  	frozensetr1  r  	_re_teamscompilerN  r4  rd  rv  rx  r  r  rX   rC   rA   <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?@>O >O >O >OBA
H A
H A
H A
H A
H& A
H A
H A
HLDD DD DD DDR' ' ' ' ' 's"   7 	AAA
B +C ?C 