
    bpjq                         d Z ddlZddlZddlZddlZddlZi Zd Z ej        dej	                  Z
d ZddZd Zd	 Zd
 Zd Zd Zd Zd Zd Zd Zd Zd ZdS )u  
Tool handlers for the Qwen Pipeline.

All tool call logic lives here. The server routes tool calls to these handlers.

To add a new tool:
1. Add the tool definition in your profile's tools.json (with parameters, description)
2. If the tool just calls an API endpoint, add "x_endpoint" to the tool definition — done.
   The pipeline will POST the args as JSON and return the response automatically.
3. If the tool needs custom pre/post-processing, add a handler function here
   and register it with @register_handler('tool_name').
    Nc                       fd}|S )a  Decorator to register a custom tool handler (simple API tools).

    Usage:
        @register_handler('book_car_service')
        def handle_book_car_service(args, tool_def=None):
            # ... your logic ...
            return 'Booking confirmed.'
    c                     | t           <   | S N)CUSTOM_HANDLERS)funcnames    K/home/m1-ai/DEPLOYMENTS/AI-PHONE/ZACK-UPDATE/fixing_leaked/tool_handlers.py	decoratorz#register_handler.<locals>.decorator"   s     $     )r   r
   s   ` r	   register_handlerr      s$         r   z>pinn|pins_only|variant_pin|locked|permitted|fixed spec|set forc                    t          | t                    s| S |                     d          }t          |t                    r]|                    d          pi }t          d |                                D                       }|s| d= |                     dd           |                     d          }t          |t                    rt                              |          r| d= | S )u  Post-process a custom-tool JSON response before the model sees it.

    - Drops a top-level 'hint' whose text uses pin/lock vocabulary the agent
      must never speak.
    - Drops 'did_you_mean' (and its fuzzy-suggestion hint) when the fuzzy
      search corrected nothing — a merely relaxed match is a normal success,
      and the marker only prompts the model to say "I couldn't find ...".
    Mutates and returns `data`; non-dict input is returned unchanged.
    did_you_mean	correctedc              3      K   | ]o\  }}t          |                                                                          t          |                                                                          k    V  pd S r   )strstriplower).0kvs      r	   	<genexpr>z'sanitize_tool_result.<locals>.<genexpr>C   ss       + +1 FFLLNN  ""c!ffllnn&:&:&<&<<+ + + + + +r   hintN)	
isinstancedictgetanyitemspopr   _HINT_BANNED_REsearch)datadymr   real_correctionr   s        r	   sanitize_tool_resultr%   3   s     dD!! 
((>
"
"C#t 	#GGK((.B	 + +!))+ + + + +  	#^$ HHVT"""88FD$ !7!7!=!= LKr   +60c                 0   |                      dd                               dd          } |                     d          r|| dd         z   } nH|                     |                    d                    rd| z   } n|                     d          s|| z   } | S )z8Normalize phone numbers (default: Malaysian +60 prefix).  -0   N+)replace
startswithlstrip)phonecountry_codes     r	   normalize_phone_numberr3   S   s    MM#r""**333E %uQRRy(			,--c22	3	3 %ec"" %u$Lr   c                 \   | sdS |                      d          }|sdS d|v rt          |d                   |d<   |                      d          pd                                }|                      dd          }dd	i}|                      d
          }|r*t          |t                    r|                    |           	 |dk    s|rIt          d| dt          j        |          dd                     t          j         |||dd          }nHt          d| dt          j        |          dd                     t          j
        |||dd          }t          d|j         d|j        dd                     |j        rS	 t          j        t          |                                                    S # t          $ r |j        dd         cY S w xY wd|j         d|j        dd          S # t          $ r.}t          d|            dt!          |           cY d}~S d}~ww xY w)a  Execute a tool's x_endpoint API call.

    Args:
        tool_def: The tool definition dict (from tools.json), must contain 'x_endpoint'.
        args: The parsed arguments dict from the model.

    Returns:
        Result string, or None if no endpoint configured.
    N
x_endpointphone_numberx_methodPOSTx_query_paramsFzContent-Typezapplication/json	x_headersGETz  [Tool API] GET z with params       )paramsheaderstimeoutverifyz  [Tool API] POST z with )jsonr?   r@   rA   z  [Tool API] Response: r(   i,  i  zAPI error: z  [Tool API] Error: zAPI call failed: )r   r3   upperr   r   updateprintrB   dumpsrequestspoststatus_codetextokr%   	Exceptionr   )	tool_defargsendpointmethoduse_query_paramsr?   r:   respes	            r	   execute_tool_endpointrT   _   s     t||L))H t 5d>6JKK^ll:&&0&7799F||$4e<<12G[))I "Z	400 "y!!!,U??.?UhUUTZ=M=Mdsd=SUUVVV<w(*5: : :DD OxOOtz$7G7G7MOOPPP=g)+E; ; ;DL(8LL49TcT?LLMMM7 	F'z"6tyy{{"C"CDDD ' ' 'y#&&&' F!1EEDIdsdOEEE , , ,(Q(()))+3q66++++++++,s=   ?CG3 2F: :GG3 GG3 3
H+=#H& H+&H+c                 b    d| dd| dd| dd}|                     | pd|d                   S )	zFixed transfer farewell sentence per language.

    Spoken verbatim via 'Say EXACTLY' so the departing agent cannot
    hallucinate a failed transfer ("no one is available...").zConnecting you to z now, please hold.u   正在为您转接u   ，请稍候。z!Sedang menyambungkan anda kepada z, sila tunggu sebentar.)enzhmsrV   )r   )langto_nametextss      r	   _transfer_farewell_textr\      sX     ?7>>>;7;;;R'RRR E
 99T\T5;///r   c                 0   | j         r| j         dk    r| j         S 	 d | j                            dg           dd         D             }d                    |          }t	          d |D                       }|dk    rd	S n# t
          $ r Y nw xY w| j         pdS )
u   Best-effort language for fixed farewell text.

    session_language is only set by select/switch_language. When the
    caller simply speaks Chinese and Omni follows along, it stays 'en'
    — so fall back to CJK detection over recent conversation turns.rV   c                 T    g | ]%}t          |                    d d                    &S )contentr)   )r   r   )r   ms     r	   
<listcomp>z'_detect_spoken_lang.<locals>.<listcomp>   s>     = = = aeeIr**++ = = =r   historyiNr(   c              3   :   K   | ]}d |cxk    rdk    n ndV  dS )u   一u   鿿r,   Nr   )r   chs     r	   r   z&_detect_spoken_lang.<locals>.<genexpr>   sC      ;;er&:&:&:&:U&:&:&:&:&:!&:&:&:&:;;r      rW   )session_language_agentr   joinsumrL   )precentrJ   cjks       r	   _detect_spoken_langrm      s     	 "a0D88!!= =8<<	266rss;= = =xx;;d;;;;;!884    %%s   A!A? ?
BBc           
        K   |                     dd          }|                     dd          }|                     |          \  }}|sd| dS |d         }	| j        d         }
|                     d|
|	|d           d	{V  |                     d
d|
 d|	 d| d           |r| j        rt          j        ddi          }| j        	                    d	| j        j
        |           d	{V  t          j        d           d	{V  t          j        dd|d|	 ddd          }| j                                         d| _        | j        	                    d	| j        j
        |           d	{V  |                     d           d	{V  d| _        t#          t%          |           |	          }t          j        dddgd| d d!d"          }|                     |d#           d	{V  | j        d$k    r?|                     | j                   d	{V  t          j        | j                   d	{V  || _        |                     d%||	d&           d	{V  |                                  d	{V  | j        rd}| j        rD| j        d'k    r9d(|                     | j                   d)|                     | j                   d*}d+|	 d,|pd- d.| }d| _        t          j        dddg|d!d"          }| j        	                    d	| j        j
        |           d	{V  t7          d/|	            d	S )0z,Transfer caller to another agent/department.
departmentr)   reasonzTransfer target "z" not found.r   transfertypefromtorp   Nsystemz
Transfer:  ->  ()rs   response.cancel皙?conversation.item.createfunction_call_outputz>SUCCESS: transfer initiated. The caller is being connected to  now.rs   call_idoutputrs   itemT   r@   Fresponse.createrJ   audioTSay EXACTLY the following, word for word. Do not add, remove, or change anything:

""
modalitiesinstructionsrs   response
   r   agent_changers   agentr   rV   z The caller has been speaking z . You MUST greet and respond in .zXYou have just been connected to a caller who was transferred to you. Your name/role is: z. Reason for transfer: zgeneral inquiryzs. Introduce yourself briefly (1-2 sentences) and ask how you can help with their request. Be warm and professional.z)  [Omni] Transfer greeting triggered for )r   _resolve_transfer_targetrg   _emit_log_message
_omni_convrB   rF   looprun_in_executorsend_rawasynciosleep_omni_response_done_eventclear_omni_swallow_next_response_omni_wait_response_doner\   rm   _omni_send_response_and_waittransfer_delay_emit_silenceactive_agent_omni_update_agent_sessionrf   
_lang_name_omni_suppress_flushrE   )rj   rN   r   	argumentsbuffered_audioro   rp   
target_keytarget_agentrZ   	from_name
cancel_msgtool_result_msg_fw_textfarewell_msg_gr_langgreeting_instructionresponse_msgs                     r	   handle_transfer_callr      s     ,++JXXh##F 99*EEJ <;:;;;;6"G I
'':y F4 4 5 5 5 5 5 5 5 5 5NN8M)MMMMFMMMNNN -21< -2Z): ;<<
f$$T1<+@*MMMMMMMMMmC          *..":+2: : : &
 &
   	
#))+++(,%f$$T1<+@/RRRRRRRRR (((333333333(-% ++>q+A+A7KKz%%w/$ $ $ $ 	#
 	#
 	 	 ,,\2,FFFFFFFFFa//!"2333333333- 0111111111  AN
''>JPP
Q
QQQQQQQQ

&
&
(
(((((((( 	| E 	@!"4"<"<?<<(:;;? ? <<(:;;? ? ?H
G")G G$*$?.?G G =E	G G 	 "&z%%w/ 4 #
 #
   f$$T1<+@,OOOOOOOOOC'CCDDD4r   c           
      |  K   | j         d         }| j        d         d         }|                    dd          }|                     d|||d           d{V  |                     dd	| d
| d| d           |r| j        rt          j        ddi          }| j        	                    d| j        j
        |           d{V  t          j        d           d{V  t          j        dd|d| ddd          }	| j                                         d| _        | j        	                    d| j        j
        |	           d{V  |                     d           d{V  d| _        t#          t%          |           |          }
t          j        dddgd|
 ddd           }|                     |d!           d{V  | j        d"k    r?|                     | j                   d{V  t          j        | j                   d{V  d| _        |                     d#d|d$           d{V  |rd%| d&| nd%| d'}| j        d         d(                             d|d)           |                                  d{V  | j        r)|                     | j        | j        pd*          }|rTd| _        t          j        dddgd| ddd           }| j        	                    d| j        j
        |           d{V  nd+| d&|pd, d-}t          j        dd.d/d0|d1gd2d          }| j        	                    d| j        j
        |           d{V  d| _        t          j        ddi          }| j        	                    d| j        j
        |           d{V  t;          d3|            dS )4z1Transfer caller back to the main agent (Agent A).r   arp   r)   rq   rr   Nrv   zTransfer back: rw   rx   ry   rs   rz   r{   r|   r}   zCSUCCESS: transfer initiated. The caller is being connected back to r~   r   r   Tr   r   Fr   rJ   r   r   r   r   r   r   r   r   r   zCaller returned from z
. Reason: r   rb   )roler_   rV   z+[The caller was just transferred back from zcompleted their requestu   . Act on this reason immediately — if it requires calling a function (like dialing an extension or transferring), do so now. Briefly acknowledge the transfer.]messageuser
input_text)rs   rJ   )rs   r   r_   z.  [Omni] Transfer-back greeting triggered for )rg   agentsr   r   r   r   rB   rF   r   r   r   r   r   r   r   r   r   r\   rm   r   r   r   r   appendr   
_pick_langagent_a_returned_greeting_maprf   r   rE   )rj   rN   r   r   r   r   rZ   rp   r   r   _bw_textr   context_msgreturned_greetingr   context_textitem_msgs                    r	   handle_transfer_backr   "  sY      IhsmF#GXXh##F
'':y F4 4 5 5 5 5 5 5 5 5 5NN8RyRRgRRRRRSSS )21< )2Z): ;<<
f$$T1<+@*MMMMMMMMMmC         
 *.."?07? ? ? &
 &
   	
#))+++(,%f$$T1<+@/RRRRRRRRR(((333333333(-%
 ++>q+A+A7KKz%%w/$ $ $ $ 	#
 	#
 	 	 ,,\2,FFFFFFFFFa//!"2333333333- 0111111111 AN
''>CII
J
JJJJJJJJ GH9HHHHH"F)"F"F"F HSM)##X+$N$NOOO

&
&
(
((((((((| &JLL+Q-?-G4I I "	T%)A":)#)7"31-1 1 1 	' 	' 	 	L &((q|/DlSSSSSSSSSS
Ai A A!>%>A A A  z2%")5| L LM # #  H &((q|/DhOOOOOOOOO%)A":v/@&ABBL&((q|/DlSSSSSSSSSHwHHIII4r   c                   K   |                     dd          }t          d| j         d|            |                     dd| d           |rt          dt	          |           d	           t          j                    | _        d
| _        |D ]I}|                     d|| j	        d           d{V  | xj        t	          |          dz  dz  z  c_        Jnt          d           t          d          D ]7}| j                                        r nt          j        d           d{V  8d}| j        d
k    r?| j        r8| j        dz  }	t          j                    | j        z
  }
t          |	|
z
  d
          }|dz   }t          d|dd| j         d           t          j        |           d{V  |                     dd|d           d{V  t          d           d| _        dS )uE   End the call — flush buffered farewell audio and wait for playback.rp   r)   z  [Omni end_call] agent=z
, call_id=rv   zCall ended by agent (ry   z  [Omni end_call] Flushing z buffered farewell audio chunksr   r   )rs   r"   _genN   re   z,  [Omni end_call] No buffered farewell audio2   g?g        i  g      ?z  [Omni end_call] Waiting z.1fz%s for farewell playback (audio_bytes=	tool_callend_call)rs   r   r   z/  [Omni end_call] Farewell done, ending sessionF)r   rE   r   r   lentime_omni_response_start_time_omni_response_audio_bytesr   _omni_audio_genrangequeueemptyr   r   maxactive)rj   rN   r   r   r   rp   chunk_iremaining_playbackaudio_durationelapsedwait_bufs               r	   handle_end_callr     s     XXh##F	
HQ^
H
Hw
H
HIIINN8>V>>>???  	?`C,?,?```aaa&*ikk#'($# 	@ 	@E''7E#$#46 6 7 7 7 7 7 7 7 7 7((CJJNa,??(((	@
 	=>>> Bii ! !7==?? 	EmC          #a''A,G'5C)++ ;; '!91==!C'H	 :x
M : :6: : : ; ; ;
-
!
!!!!!!!! ''Z          
 

<===AH4r   c           
      :  K   |                     dd          }|                     dd                              dd          }|                     dd          }|                     d| j                             dd          |||d	           d
{V  |                     dd| d| d|            | j        r| j        r| j        r| j        s	 | j	        
                    d
| j        |||           d
{V }|                     d          rd| _        |                     dd|                     dd          |                     dd          |                     dd          d           d
{V  n)# t          $ r}	t          d|	            Y d
}	~	nd
}	~	ww xY wdS )z:Record a callback request and optionally dispatch to ACRS.customer_namer)   customer_phoner(   rp   	call_backr   AI)rs   r   r   r   rp   Nrv   z
Callback: rx   z) - successTacrs_statusFr   case_no)rs   callbackr   r   r   z'  [Omni ACRS] Callback dispatch error: zCallback request recorded.)r   r.   r   rg   r   acrs_enabledacrs_api_urlacrs_callback_dept_idacrs_dispatchedr   r   _dispatch_callback_to_acrsrL   rE   )
rj   rN   r   r   r   r   r   rp   acrs_resultrS   s
             r	   handle_call_backr     sA     HH_b11MXX.33;;CDDNXXh##F
''fd++&(           NN8W-WW>WWvWWXXX 	
 A1> A'A010AA	A ! 6 6a2~v!7 !7 7 7 7 7 7 7K y)) )$(!''%4&??9e<<&??9b99&??9b99	             	A 	A 	A?A??@@@@@@@@	A ('s   B"E2 2
F<FFc                   K   |                     dd          }|| j        vrd}|| _        |                     |          }t	          d| d| d           |                     dd|            d| _        | j        d         d	         }|                     d
d|d           d{V  | 	                                 d{V  d| d}|r| j
        rt          j        dd||dd          }	| j                            d| j
        j        |	           d{V  | j        s#|                     | j        |          }
d| _        n6|                     | j        |          p|                     | j        |          }
|
rd|
 d}nd| d| d| d}d| _        t          j        dddg|dd          }| j                            d| j
        j        |           d{V  dS )z2Handle language selection from the language agent.languagerV   z!  [Omni LANG] Language selected: rx   ry   rv   zLanguage selected: r   r   r   r   NzLanguage set to z. Transferred to main agent.r|   r}   r   r   TzUSay EXACTLY the following greeting, word for word, in the same language as written: "r   z=You have just been connected to a caller. Your name/role is: z. The caller selected zB as their language. Introduce yourself briefly (1-2 sentences) in z and ask how you can help.r   rJ   r   r   r   )r   supported_languagesrf   r   rE   r   r   r   r   r   r   rB   rF   r   r   r   _main_agent_visitedr   fixed_greeting_mapr   r   )rj   rN   r   r   r   rY   
lang_labelrZ   result_textr   greetingr   r   s                r	   handle_select_languager     s     88J%%D1(((Ad##J	
Cd
C
Cj
C
C
CDDDNN89499:::ANhsmF#G
''>CII
J
JJJJJJJJ

&
&
(
((((((((MZMMMK )P1< )P*.."% &
 &
   f$$T1<+@/RRRRRRRRR $ 	=||A$8$??H$(A!! Q<dCC <<< 4d;;   
	.A5=A A A ! 
-&-- -'1- - BL- - - ! "&z%%w/ 4 #
 #
   f$$T1<+@,OOOOOOOOO4r   c                    K   |                     dd          }t          d| d           |                     dd|            d| _        d| j        v rg | j        d         d	<   d| _        | j                             di                                d
d          }|                     dd|d           d{V  |                                  d{V  d}|r| j        rt          j
        dd||dd          }| j                            d| j        j        |           d{V  | j        rd| j         d}	nd| d}	d| _        t          j
        dddg|	dd          }
| j                            d| j        j        |
           d{V  dS )z%Transfer to language selection agent.rp   r)   z1  [Omni LANG] Change language requested (reason: ry   rv   zChange language requested: NrY   rb   r   zLanguage Agentr   r   z"Transferred to language selection.r|   r}   r   r   z4Say EXACTLY the following greeting, word for word: "r   zYou are z. The caller wants to change their language. Ask them which language they would like to continue in. Keep it brief (1-2 sentences).Tr   rJ   r   r   r   )r   rE   r   rf   r   r   r   r   r   rB   rF   r   r   r   language_agent_greetingr   )rj   rN   r   r   r   rp   rZ   r   r   r   r   s              r	   handle_change_languager     s3     XXh##F	
Gf
G
G
GHHHNN8C6CCDDD A&(#ANhll62&&**63CDDG
''>FGLL
M
MMMMMMMM

&
&
(
((((((((6K P1< P*.."% &
 &
   f$$T1<+@/RRRRRRRRR $ 	@1-1 1 1 ! 
?7 ? ? ? !
 "&z%%w/ 4 #
 #
   f$$T1<+@,OOOOOOOOO4r   c           	        K   |                     dd          }|| j        vrd}|                     |          }|| j        k    rt	          d| d           d| dS || _        t	          d| d| d	           |                     d
|d           d{V  |                     dd|            |                                  d{V  d| d}|r| j        rt          j
        dd||dd          }| j                            d| j        j        |           d{V  d| _        t          j
        dddgd| d| ddd          }	| j                            d| j        j        |	           d{V  dS )zFSwitch language mid-conversation (without transferring to lang agent).r   rV   z  [Omni LANG] Already in z, ignoring no-op switchzAlready using r   z  [Omni LANG] Switched to: rx   ry   language_switched)rs   r   Nrv   zLanguage switched to: zLanguage switched to r|   r}   r   r   Tr   rJ   r   zYou just switched to z!. Say a single short sentence in z: asking how you can help. Do NOT introduce yourself again.r   r   )r   r   r   rf   rE   r   r   r   r   rB   rF   r   r   r   r   )
rj   rN   r   r   r   rY   r   r   r   r   s
             r	   handle_switch_languager   Q  s,     88J%%D1(((d##J q!!!G$GGGHHH-
----A	
=
=
=

=
=
=>>>
''.DAA
B
BBBBBBBBNN8<d<<===

&
&
(
((((((((7*777K P1< P*.."% &
 &
   f$$T1<+@/RRRRRRRRR "&z%%w/8J 8 86@8 8 8 
#
 
#
 
 
 f$$T1<+@,OOOOOOOOO4r   c                   K   |                     dd          p|                     dd          }d}| j        r)| j        dk    rd|                     | j                   d}t          j        ddd	gd
| d| dd          }	t          d| d           |                     |	d           d{V  t          d| d           dS )uK   Handle dial_extension / dial_department — speak 'connecting' then return.r   r)   ro   rV   z
 Speak in r   r   rJ   r   z/Tell the caller you are now connecting them to z. Keep it to 1 short sentence.r   r   z  [Omni z:] Generating "connecting" speech via dedicated response...r   r   Nz] "Connecting" speech done)r   rf   r   rB   rF   rE   r   )
rj   r   rN   r   r   r   r   person_dl_langconnecting_msgs
             r	   handle_dialr     s     XXfb!!?TXXlB%?%?FH Da0D88CQ-? @ @CCCZ!!7+:& : :/7: :
 
! !  N 

UT
U
U
UVVV

(
(
(
D
DDDDDDDD	
5T
5
5
56664r   )r&   )__doc__r   rB   rer   rG   r   r   compileIr    r%   r3   rT   r\   rm   r   r   r   r   r   r   r   r   r   r   r	   <module>r     sS      				     , "*ErtM M  @	 	 	 	/, /, /,D
0 
0 
0& & &(] ] ]@g g gT+ + +\!( !( !(H; ; ;|2 2 2j/ / /d    r   