+
    ihB                       a  R& t+0 t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RIHt	 ^ RI
HtHt ^ RIHt ^RIHt ^RIHt ^RIHt ]P*                  ! R4      t]! 4        ]P.                  ! R	R
4      t]P.                  ! RR4      t]P.                  ! RR4      t]P.                  ! RR4      t]P.                  ! RR4      t]P.                  ! RR4      t]P.                  ! RR4      P=                  R4      t]! RR7      t Rs!] ^ k ] PE                  R4      R R l4       t#] PI                  R4      R R l4       t%] PM                  ]4      R R  l4       t'R! R" lt(] PM                  ]4      R# R$ l4       t)]*R%8X  d
   ](! 4        R# R# )'    NAny)FastAPIRequest)JSONResponse)load_agent_runtime_dotenv)'get_runtime_overrides_from_agents_table)get_default_mcube_call_configzmcube.webhook	REDIS_URLzredis://localhost:6379/0MCUBE_WEBHOOK_PATHz/webhooks/mcubeMCUBE_OUTBOUND_PATHz/api/mcube/outbound-callMCUBE_PUBLIC_BASE_URL MCUBE_PUBLIC_WS_URL_BASEMCUBE_WS_PATH_PREFIXz/bid/websocketAGENT_BACKEND_BASE_URLzhttp://localhost:8000/zMCube Webhook Receiver)titlestartupc                    V ^8  d   QhRR/#    returnN )formats   "`E:\live-kit-agent\livekit_voicebot\backend\agent_runtime\src\mcube_integration\webhook_server.py__annotate__r   (   s     @ @ @    c                     "   \         P                  ! \        R R7      s\        P	                  4       G Rj  xL
  \
        P                  R\        4       R#  L 5i)F)decode_responsesNz$mcube webhook: connected to redis %s)redis_asyncfrom_urlr   _redispingloginfor   r   r   _startupr'   '   s<      !!)eDF
++-HH3Y? s   4AA!Az/healthc                F    V ^8  d   QhR\         \        \        3,          /# )r   r   )dictstrr   )r   s   "r   r   r   1   s      d38n r   c                     "   R R/# 5i)statusokr   r   r   r   healthr.   0   s     ds   c                0    V ^8  d   QhR\         R\        /# r   requestr   r   r   )r   s   "r   r   r   6   s     1
 1
 1
\ 1
r   c                   "    V P                  4       G R j  xL
 pVP                  R4      ;'       g+    VP                  R4      ;'       g    VP                  R4      p\        VP                  RR4      4      P                  4       pVP                  R^ 4      pVP                  RR4      pV'       g   \	        R	R
RR/RR7      # \
        pVf   Q hRV RV 2pVP                  V^R^R7      G R j  xL
 pV'       g   \	        R	RRR/4      # TP                  RV 2\        V\        4      '       d   VP                  R4      MTRR7      G R j  xL
  TP                  RV 2\        V\        \        34      '       d   \        V4      P                  R4      M\        V4      P                  R4      RR7      G R j  xL
  VP                  RV 2\        V4      P                  R4      RR7      G R j  xL
  VR9   p	V	'       d    VP                  RV 2^R R7      G R j  xL
  \	        R	R/4      #  EL ELB L L| LG L  \         d<   p
\        P                  R4       \	        R	R
RRR\        T
4      /RR7      u R p
?
# R p
?
ii ; i5i)!Ncall_idcallIdcallIDr,   r   durationanswered_byhumanr-   Ferrorzmissing call_id  status_codezmcube_webhook_processed::T)nxexskippedzmcube_call_status:utf-8r@   zmcube_call_duration:zmcube_call_answered_by:zmcube_call_ended:zmcube webhook failedmcube_webhook_faileddetaili  iQ >   busyfailedblocked	completed	voicemailnot_answered	no-answer`T  )jsongetr*   lowerr   r#   set
isinstanceencodeintfloat	Exceptionr%   	exception)r1   payloadcall_sidr,   r7   r8   redisidem_keyalreadyterminales   &          r   mcube_webhookr_   5   sy    0
(/"6;;y)[[W[[-B[[gkkRZF[W[[2./557;;z1-kk-9ug7H IWZ[[   -hZqA		(A$2	>>tY =>> ii 
+&0&=&=FMM'"6  
 	
 	

 ii"8*--73,-O-OCM  )UXYaUbUiUijqUr  
 	
 	

 ii%hZ0##G,  
 	
 	
 qq))/z:A()KKKT4L))S #7 ?
	

	

	
 L  
,-5'#98SVL
 	

s   JH> H0H> H> A7H> J,H> 1H32H> >H> JAH> H6A,H> ;H8<6H> 2H:3+H> H<H> /J0H> 3H> 6H> 8H> :H> <H> >J	0I?9J:J?JJc                    V ^8  d   QhRR/# r   r   )r   s   "r   r   r   j   s     + +d +r   c                      \         P                  ! \         P                  R 7       ^ RIp \        P
                  ! RR4      p\        \        P
                  ! RR4      4      pV P                  \        WR7       R# ))levelNMCUBE_WEBHOOK_HOSTz0.0.0.0MCUBE_WEBHOOK_PORT8002)hostport)	loggingbasicConfigINFOuvicornosgetenvrT   runAPP)rk   rf   rg   s      r   mainrp   j   sN    gll+99)95Dryy-v67DKK$K*r   c                0    V ^8  d   QhR\         R\        /# r0   r2   )r   s   "r   r   r   t   s     F F F\ Fr   c                P  "   ^ RI Hp V P                  4       G Rj  xL
 p\        VP	                  R4      ;'       g5    VP	                  R4      ;'       g    VP	                  R4      ;'       g    R4      P                  4       pVP	                  R4      ;'       g+    VP	                  R4      ;'       g    VP	                  R	4      pVP	                  R
4      ;'       g    VP	                  R4      pR R lpR R lp\        VP	                  R4      ;'       g    \        P                  ! RR4      4      P                  4       pV'       g   VP                  R4      '       g   VP                  R4      '       dg   VP                  R^4      ^ ,          P                  R4      P                  R4      p	 V	P                  R4      p
W^,           ,          P                  4       p/ pV'       d   V! V4      G Rj  xL
 pV! WE4      G Rj  xL
 pVP	                  R4      ;'       g    VP	                  R4      ;'       g    RP                  4       pV'       g   \        RRRR/RR7      # \        VP	                  R4      ;'       g!    VP	                  R4      ;'       g    V! 4       4      pTpVP	                  R 4      pVP	                  R!4      pVP	                  R"4      ;'       g    VP	                  R"4      pVP	                  R#4      ;'       g    VP	                  R#4      pVRR9  d   \        V4      M7\        T;'       g    \        P                  ! R$R4      4      P                  4       pVRR9  d   \        V4      M7\        T;'       g    \        P                  ! R%R&4      4      P                  4       p\        VP	                  R'4      ;'       g    VP	                  R(4      ;'       g    VP	                  R)4      ;'       g    VP	                  R*4      ;'       g    VP	                  R+4      ;'       g}    V P                  P	                  R'4      ;'       gZ    V P                  P	                  R+4      ;'       g7    \        P                  ! R'R4      ;'       g    \        P                  ! R,R4      4      P                  4       p\        f   Q h\        4       pR- R. lp\!        V4      pVP#                  4        F=  pV! VP	                  V4      VP	                  V4      VP	                  V4      4      VV&   K?  	  VRR9  Ed    \%        V4      pVEe   \&        P(                  ! \*        TVP	                  R/4      ;'       g    VP	                  R04      VP	                  R14      ;'       g    VP	                  R24      VP	                  R34      ;'       g    VP	                  R44      VP	                  R4      ;'       g    VP	                  R54      R67      G Rj  xL
 pVP-                  4        F  w  ppV'       g   K  VVV&   K  	  RS F  pT! VP	                  V4      VP	                  V4      VP	                  V4      \/        V\         4      '       d   VP	                  V4      MR4      p V f   Kh  \/        V \        4      '       d   V P                  4       R8w  g   K  V VV&   K  	  VP	                  R74      p!\/        V!\        4      '       d   V!P1                  R8R94      p!V! V!VP	                  R74      4      ;'       g
    VR7,          VR7&   V! VP	                  R:4      VP	                  R;4      VP	                  R:4      4      ;'       g    RP                  4       VR:&   RT F>  pV! VP	                  V4      VP	                  V4      4      ;'       g
    VV,          VV&   K@  	  RU FL  pVP	                  V4      p"V"f   K  \/        V"\        4      '       d   V"P                  4       R8w  g   KG  V"VV&   KN  	  VP	                  R34      ec   \        VP	                  R34      ;'       g    R4      P                  4       R8w  d,   \        VP	                  R34      4      P                  4       VR4&   VP	                  R44      ec   \        VP	                  R44      ;'       g    R4      P                  4       R8w  d,   \        VP	                  R44      4      P                  4       VR4&   V'       d	   V'       g^   \        P3                  R<V 2\        P4                  ! V4      P7                  R=4      RVR>7      G Rj  xL
  \        RR?RVR@RRARBRCRDRER?/4      # ^RFIHp# V#! VRG7      p$VP	                  RH4      ;'       g    VP	                  RI4      ;'       g    RP                  4       ;'       g    \<        '       d   \<         \>         2MRp%VP	                  RJ4      ;'       g    VP	                  RK4      ;'       g    RP                  4       ;'       g     \@        '       d   \@         \B         RV 2MRp&V&'       d9   V'       d/   VP                  R4      '       g   VP                  R4      '       d   T&p T$PE                  TTTTTT%;'       g    RT&;'       g    RRL7      G Rj  xL
 p'\        P3                  R<T 2\        P4                  ! T4      P7                  R=4      RVR>7      G Rj  xL
  \        P3                  R<T'PJ                   2\        P4                  ! T4      P7                  R=4      RVR>7      G Rj  xL
  \        RR?RTR@T'PJ                  RAT'PL                  RHT%RJT&RQT/4      #  EL  \         d     E	Li ; i E	L E	L  \         d    Rp EL{i ; i EL ELd L  \         d?   p(\F        PI                  RMT4       \        RRRRNRTRO\        T(4      /RPR7      u Rp(?(# Rp(?(ii ; i EL L5i)Wa  
Minimal endpoint to kick off an outbound MCube click-to-call.

This integrates with MCube's Restmcube-api/outbound-calls endpoint which expects:
- HTTP header: Authorization
- JSON body keys: custnumber, exenumber, gid, refurl, refid (as per your doc)

Body examples supported:
- { "to": "+1555..." , "exenumber": "8700...", "gid": "1", "call_id": "optional" }
- or use env defaults for exenumber/gid/auth.
)uuid4N
agent_name	agentNameagentr   business_id
businessIdbidbot_idbotIdc                R    V ^8  d   QhR\         R\        \         \        3,          /# )r   namer   )r*   r)   r   )r   s   "r   r   #outbound_call.<locals>.__annotate__   s"      c d38n r   c           
      8  "   V '       g   / # \          R V  R2p\        \        P                  ! RR4      4      p \        P
                  ! 4       ;_uu_4       GRj  xL
 pVP                  WR7      ;_uu_4       GRj  xL
 pVP                  ^8w  dH   \        P                  RV VP                  4       / uuRRR4      GRj  xL
  uuRRR4      GRj  xL
  # VP                  4       G Rj  xL
 uuRRR4      GRj  xL
  uuRRR4      GRj  xL
  #  L L LW LG L0 L! L  + GRj  xL 
 '       g   i     M; iRRR4      GRj  xL 
  R#   + GRj  xL 
 '       g   i     R# ; i  \         d    \        P                  RT 4       / u # i ; i5i)z/api/agents/z/config/AGENT_BACKEND_FETCH_TIMEOUT_S5.0Ntimeoutz<mcube outbound: agent config fetch failed agent=%s status=%sz3mcube outbound: agent config fetch errored agent=%s)r   rU   rl   rm   aiohttpClientSessionrO   r,   r%   warningrN   rV   rW   )r}   url	timeout_ssessionresps   &    r   _fetch_agent_mcube_config0outbound_call.<locals>._fetch_agent_mcube_config   s&    I'(TF(C"))$CUKL		,,...'";;s;>>>${{c)Z  KK
  " ?>> /.. "&, ?>> /..> / - ? />>>> /.....  	MMOQUVI	s6  7F!E1 DE1 E>D?E4D%	6ED
EE1 DE1 FD%	.D/D%	2E?D!
 EE1 D#E1 FE1 EEE1 D%	!E#E1 %D>+D.,
D>7D>9EE1 EE1 FE.	E
E.	&E.	(E1 ,F.E1 1#FFFFc                ^    V ^8  d   QhR\         R\         R\        \        \         3,          /# )r   business_id_val
bot_id_valr   )r   r)   r*   )r   s   "r   r   r~      s/      s PS X\]`be]eXf r   c           
        "   V R	9   g   VR	9   d   / #  \        V 4      p\        V4      p\         RT RT R2p\        \        P
                  ! RR4      4      p \        P                  ! 4       ;_uu_4       GR j  xL
 pTP                  YER7      ;_uu_4       GR j  xL
 pTP                  ^8w  dI   \        P                  RTTTP                  4       / uuR R R 4      GR j  xL
  uuR R R 4      GR j  xL
  # TP                  4       G R j  xL
 uuR R R 4      GR j  xL
  uuR R R 4      GR j  xL
  #   \         d    / u # i ; i L L Lj LZ LC L4 L$  + GR j  xL 
 '       g   i     M; iR R R 4      GR j  xL 
  R #   + GR j  xL 
 '       g   i     R # ; i  \         d    \        P                  RY#4       / u # i ; i5i)
Nz/api/agents/cluster/bots/r   z/mcube-config/r   r   r   zJmcube outbound: cluster bot config fetch failed bid=%s bot_id=%s status=%szAmcube outbound: cluster bot config fetch errored bid=%s bot_id=%sNr   )rT   rV   r   rU   rl   rm   r   r   rO   r,   r%   r   rN   rW   )r   r   bid_intbot_intr   r   r   r   s   &&      r   _fetch_cluster_bot_mcube_config6outbound_call.<locals>._fetch_cluster_bot_mcube_config   sr    j(J*,DI	/*G*oG (((A'!G9Tbc"))$CUKL		,,...'";;s;>>>${{c)h## KK	  " ?>> /.. "&, ?>> /..  	I	
 /> / - ? />>>> /.....  	MM]_fpI	sY  GD8 /G!F% ;E<F% ?FEF"5E	F$E
%F)F% 6E7F% ;G<E	EE	F E
!F%F% 2E3F% 7G8EGEGF% FFF% E	FF% E2E" 
E2+E2-F5F%  FF% GF"	F
F"	F"	F%  G"F% %#GG
GGrefurlMCUBE_REFURLzhttp://zhttps://?r   
custnumbertor-   Fr:   z$missing 'to' (or 'custnumber') valuer;   r<   refidr4   	exenumbergidmcube_exenumber	mcube_gidMCUBE_EXENUMBER	MCUBE_GID1HTTP_AUTHORIZATIONhttp_authorizationhttpAuthorizationauthorizationAuthorizationMCUBE_HTTP_AUTHORIZATIONc                0    V ^8  d   QhR\         R\         /# )r   valsr   r   )r   s   "r   r   r~     s      S S r   c                      V  F8  pVf   K	  \        V\        4      '       d   VP                  4       R8X  d   K6  Vu # 	  R # r   )rR   r*   strip)r   vs   * r   _pickoutbound_call.<locals>._pick  s:    Ay!S!!aggi2oH  r   agent_idagentIduser_iduserIdemailagent_emailr}   )r   r   r   r}   system_promptz\n
first_messageagent_first_messagezmcube_call_config:rB   rC   Tmcube_call_sidr,   not_initiatedr   z)MCube auth token and/or exenumber not setstored_config)MCubeProvider)r   callback_urlcallbackUrlwebsocket_urlwebsocketUrl)r   r   r   r   r   r   r   z/mcube outbound: initiate_call failed call_id=%smcube_initiate_call_failedrE   i  mcube_refurlr   )message_inboundmessage_outboundplatform_settingsconversation_behavior)	llm_modelllm_providerstt_providerstt_language_codestt_model_idtts_provider	tts_modeltts_voice_idtts_encodingtts_chunk_mstts_gainplayback_pace_factorcheckpoint_every)rw   rz   r   r   rt   rM   )'uuidrs   rN   r*   rO   r   rl   rm   
startswithsplitindexrV   r   headersr#   r
   r)   keysrT   asyncio	to_threadr	   itemsrR   replacerQ   dumpsrS   providers.mcube_providerr   r   r   r   r   initiate_callr%   rW   rY   r,   ))r1   rs   bodyrt   rw   rz   r   r   r   partsidx	agent_cfgcluster_bot_cfgcustnumber_inr   r   exenumber_bodygid_bodyexenumber_dbgid_dbr   r   r   defaultsr   call_configkr   biabkbv	extra_keyevbody_system_promptr   r   providerr   r   resultr^   s)   &                                        r   outbound_callr   s   s
     D  	 	88K 	 	88G	 	 	
 eg  ((=)VVTXXl-CVVtxxPUKXXh44488G#4F(8 (#DDryy'DEKKMFV..y99V=N=Nz=Z=ZS!$Q'--c288=	++g&CQw--/J !#I3J??	,KK,`&`OXXl+CCtxx~CCJJLM5'#IJ
 	
 !CCTXXi%8CCEGDE J
 XXk*NxxH"&&'89]]Y]]K\=]L  -KK{1KF + 	NAA+<b!ABHHJ  :% 	H66299[#67==?  %& 	5 	588()	5 	588'(	5 	5 88O$	5 	5 88O$		5 	5
 ??34	5 	5 ??/	5 	5 99)2.	5 	5 99/4
 eg  ,.H x.K2215y}}Q7GYZI[\A   *$	+&G ))7*-DD)1D+AAtxx/Ahhw'BB488M+BXXl+??txx/? C ))+B2&(KO &	 HHY'#''	2MM),*4S$*?*?CGGI&T	 >:b#+>+>"((*PRBR-/K	* /2$c**/77tD#();[___=]#^#~#~bmn}b~K  	HH_%HH*+OOO,	
 	 	
 eg   txx{KOOA,>?QQ;q>A$ LHHQK=*Q"4"4	RKN L xx$TXXg->-D-D")E)K)K)MQS)S%('):%;%A%A%CM"xx*s488M3J3P3Pb/Q/W/W/Y]_/_%(-)@%A%G%G%IM" Yjj (JJ{#**73  
 	
 	

 d5 $/F	
 		
 80BCH 
.	!	B	BTXXm%<	B	BIIK 	] 	]>S>S$%&8%9:Y[ 
 
/	"	D	Ddhh~&>	D	D"KKM 	
 	
 (' (()=(>awG  f(9(9)(D(DHYHYZdHeHe
--!%--'//4 . 
 
$ **
UG$

;&&w/     **
V__-.

;&&w/     $ufoofmmL]F	

 
]	  H  		
 @&`\  	G	R	
V
  
GO5'#?ES[]`ab]cd
 	

s\  p&n p&p&p&0,p&p&6)p& :p&1p&p&$p&;7p&3.n! !	p&+p&6n37p&n6p&#p&<p&-p&p&Ap&$)p&1p& A	p&
Ap&p&*p&p&p&5"p&"p&;p&B(p&n9 2p&(p&*(p&(p&<p&op&;A.p&.(p&A p&<A
p&Ap&(p&;(p&(8p&!A4p&Ap&#p&+Ap&,o-Ap&/p&p& p&-'p&p&.p&p&p&.p&6p&p&$p&'o  
o o oo Ap&p!Ap&,p$-2p&!n0,p&/n00p&6p&9o
p&	o

p&p&o p 3ppp&pp&$p&__main__c                b    V ^8  d   Qh/ ^ \         9   d   \        P                  R,          ;R&   # )r   Nr#   )__conditional_annotations__r!   Redis)r   s   "r   r   r      s%    F ( 'D  'G r   ),r   r   rh   rN   rl   r   typingr   redis.asyncior!   fastapir   r   fastapi.responsesr   env_loadr   business_id_agentsr	   mcube_defaultsr
   	getLoggerr%   rm   r   r   r   r   r   r   rstripr   ro   r#   on_eventr'   rO   r.   postr_   rp   r   __name__r   )r   s   @r   <module>r     s{      	   # $ * / G 9(  IIk#=>	YY35FG ii 57QR 
 		"92> 99%?D yy!79IJ  #;=TU\\]`a ,-#' ' i@ @   
1
 1
h+ 
F FR
 zF r   