+
    ~jE                      a  0 t $ ^ RIHt ^ RIt^ RIt^ RIHt ^ RIHtH	t	H
t
 ^ RIHt ^ RIHt ^RIHtHtHt ^RIHt ^R	IHt ^R
IHt ^RIHt ^RIHtHt ^RIH t H!t! ^RI"H#t#H$t$H%t% ^RI&H't' ^RI(H)t) ^RI*H+t+H,t,H-t-H.t.H/t/H0t0H1t1H2t2H3t3 ]'       d   ^R	IHt ^RIHt ^RI4H5t5 0 R&mt6R]7R&   0 R'mt8R]7R&    ! R R]
RR7      t9R]-R],R].R]/R]0R]+/t:R]7R &    ! R! R"]#]	R#,          ,          4      t;R$ R% lt<R# )(    )annotationsN)TracebackType)TYPE_CHECKINGLiteral	TypedDict)trace)rtc)LLMSTT	LLMModels)get_job_context)r
   )logger)r   )trace_typestracer)	NOT_GIVEN
NotGivenOr)EventEmitteraiois_given)is_cloud)wait_for_track_publication)	
AMD_PROMPTHUMAN_SILENCE_THRESHOLDHUMAN_SPEECH_THRESHOLDMACHINE_SILENCE_THRESHOLDNO_SPEECH_THRESHOLDTIMEOUTAMDCategoryAMDPredictionEvent_AMDClassifier)AgentSessionset[str]EVALUATED_LLM_MODELSEVALUATED_STT_MODELSc                  T    ] tR t^=t$ R]R&   R]R&   R]R&   R]R&   R]R&   R]R&   R	tR
# )DetectionOptionsfloathuman_speech_thresholdhuman_silence_thresholdmachine_silence_thresholdno_speech_thresholdtimeoutstrprompt N)__name__
__module____qualname____firstlineno____annotations____static_attributes__r/       v/Users/mitch_tango/dev/rabbit-r1-livekit/agent/.venv/lib/python3.14/site-packages/livekit/agents/voice/amd/detector.pyr&   r&   =   s$    !!""$$NKr6   r&   F)totalr(   r)   r*   r+   r,   r.   _DEFAULT_DETECTION_OPTIONSc                  f  a  ] tR t^Pt$ RtRtR]R&   RtR]R&   R]R]R	R
RR
R]RRR]/R V 3R lllt	]
R R l4       t]
R R l4       t]
R R l4       tR R ltR R ltR R ltR R ltR  R! ltR" R# ltR$ R% ltR& R' ltR( R) ltR* R+ ltR, R- ltR. R/ ltR0 R1 ltR2 R3 ltR4 R5 ltR6tV ;t# )7AMDao
  Answering Machine Detection (AMD).

Detects whether an outbound call is answered by a human or a machine.

Listens to the call greeting and uses an LLM to classify it into one of
the following categories:

- ``human``: a real person answered.
- ``machine-ivr``: an IVR / DTMF menu prompt was detected.
- ``machine-vm``: a voicemail greeting where leaving a message is possible.
- ``machine-unavailable``: the mailbox is full or not set up; leaving a message is not possible.
- ``uncertain``: the transcript is ambiguous and could not be classified.

AMD should be started before the SIP participant is created so no audio is
missed. Timers begin when the participant's audio track is subscribed.

The recommended pattern is the async context manager::

    async with AMD(session, llm="openai/gpt-4.1-mini") as detector:
        await ctx.api.sip.create_sip_participant(...)
        await ctx.wait_for_participant(identity=participant_identity)
        result = await detector.execute()

Args:
    session: The :class:`AgentSession` to wire AMD to.
    llm: LLM used for greeting classification. Accepts an :class:`LLM`
        instance or an inference model string (e.g.
        ``"openai/gpt-4.1-mini"``). When omitted, AMD auto-selects:
        if LiveKit inference credentials are available in the environment
        it uses ``"google/gemini-3.1-flash-lite"`` via the
        inference gateway; otherwise it falls back to the session's own
        LLM.
    interrupt_on_machine: If ``True`` (default), interrupt any pending
        agent speech immediately when a machine is detected.
    ivr_detection: If ``True`` (default), automatically start IVR
        navigation when a ``machine-ivr`` result is returned.
    participant_identity: If set, only this participant's audio track
        subscription triggers the detection timers. If omitted, the first
        remote audio track wins.
    stt: STT used for transcript generation. Accepts an :class:`STT`
        instance or an inference model string (e.g.
        ``"cartesia/ink-whisper"``). When omitted, AMD auto-selects:
        if LiveKit inference credentials are available it uses
        ``"cartesia/ink-whisper"`` via the inference gateway; otherwise
        it reuses the session's existing STT transcripts.
    suppress_compatibility_warning: If ``True``, do not log a warning when
        the resolved STT or LLM is not among the bundled AMD-tested model
        strings. Has no effect on classification behavior.
    detection_options: Optional overrides for timing thresholds and the AMD
        classification prompt (see :class:`DetectionOptions`). When
        omitted, library defaults apply.
google/gemini-3.1-flash-liter-   _DEFAULT_LLM_MODELcartesia/ink-whisper_DEFAULT_STT_MODELllmsttinterrupt_on_machineTivr_detectionparticipant_identitysuppress_compatibility_warningFdetection_optionsc               <    V ^8  d   QhRRRRRRRRR	RR
RRRRRRR/	# )   sessionr!   r@   z!NotGivenOr[LLM | LLMModels | str]rA   zNotGivenOr[STT | str]rB   boolrC   rD   zNotGivenOr[str]rE   rF   zNotGivenOr[DetectionOptions]returnNoner/   )formats   "r7   __annotate__AMD.__annotate__   sd     7? 7?7? /	7?
 #7? #7? 7? .7? )-7? 87? 
7?r6   c               	P  < \         SV `  4        \        V4      '       d   \        V4      '       Eg   \        P                  ! R 4      ;'       g    \        P                  ! R4      p	\        P                  ! R4      ;'       g    \        P                  ! R4      p
\        \        P                  ! RR4      4      ;'       d    \        V	4      ;'       d    \        V
4      p\        V4      '       g   V'       d   V P                  M\        p\        V4      '       g   V'       d   V P                  M\        pW n
        Wn        W@n        WPn        Wpn        W`n        \!        V\"        4      '       d   \%        V4      MTV n        RV n        RV n        RV n        RV n        \        V4      '       d   / \0        CVCM\0        V n        V P                  '       gB   \        V P&                  4      '       d'   \5        V P&                  P6                  \8        RR	7       RV n        RV n        R# )
LIVEKIT_INFERENCE_API_KEYLIVEKIT_API_KEYLIVEKIT_INFERENCE_API_SECRETLIVEKIT_API_SECRETLIVEKIT_URL NFrA   
model_kind)super__init__r   osgetenvr   rJ   r=   r   r?   _llm_config_session_interrupt_on_machine_ivr_detection_suppress_compatibility_warning_participant_identity
isinstancer-   _InferenceSTT_stt_classifier_result_closed_spanr9   _opts_warn_if_not_evaluatedmodelr$   	_stt_task	_audio_ch)selfrI   r@   rA   rB   rC   rD   rE   rF   api_key
api_secretauto_select	__class__s   &&$$$$$$$   r7   rZ   AMD.__init__   s    	}}HSMMii ;<\\		J[@\G#AB  bii$GJ ="56]]4=]]TR\M]  C==1<d--)C==1<d--)>A&-%9"+/M,6J"<FsC<P<PmC&8VY	2626(,
 )** @)?->?+ 	
 333		""&IIOO($ 59:>r6   c                   V ^8  d   QhRR/# rH   rK   rJ   r/   )rM   s   "r7   rN   rO      s     , , ,r6   c                	    V P                   R J# N)rf   ro   s   &r7   enabledAMD.enabled   s    t++r6   c                   V ^8  d   QhRR/# rv   r/   )rM   s   "r7   rN   rO      s     E E Er6   c                	J    V P                   R J;'       d    V P                  R J # rx   )rf   rg   ry   s   &r7   pendingAMD.pending   s$    t+DD0DDr6   c                   V ^8  d   QhRR/# rv   r/   )rM   s   "r7   rN   rO      s     I I Ir6   c                	Z    V P                   R J;'       d    V P                   P                  # rx   )rf   startedry   s   &r7   r   AMD.started   s'    t+HH0@0@0H0HHr6   c                   V ^8  d   QhRR/# )rH   rK   r   r/   )rM   s   "r7   rN   rO      s      1 r6   c                  "   V P                   '       d-   V P                   P                  P                  4       G Rj  xL
  V P                  '       g   \	        R4      hV P                  pVP
                  '       d7   V P                  '       d%   V P                  P                  RR7      G Rj  xL
  VP                  \        P                  8X  dA   V P                  '       d/   V P                  P                  VP                  R7      G Rj  xL
  V P                  P                  '       d%   V P                  P                  P!                  4        V#  EL L LK5i)zRun AMD and return the result.

While executing, speech playout authorization is locked. Once the
result is available, authorization is resumed and automatic actions
(interrupt on machine, ivr detection) are applied based on the
configured options.
Nz(amd closed before a result was availableT)force)
transcript)rf   _verdict_readywaitrg   RuntimeError
is_machiner_   r^   	interruptcategoryr   MACHINE_IVRr`   _start_ivr_detectionr   	_activity_resume_authorization)ro   results   & r7   executeAMD.execute   s     ""1166888|||IJJ!;!;!;--)))555??k555$:M:M:M--44!,, 5   
 =="""MM##99;' 9 6sQ   :EEE(E<EE-E.4E#)EEE-'EEEc                   V ^8  d   QhRR/# )rH   rK   r;   r/   )rM   s   "r7   rN   rO      s      # r6   c                	X   "   V P                  V P                  4      G R j  xL
  V #  L5irx   )_runr^   ry   s   &r7   
__aenter__AMD.__aenter__   s%     ii&&& 	's   *(*c               (    V ^8  d   QhRRRRRRRR/# )	rH   exc_typeztype[BaseException] | Noneexc_valzBaseException | Noneexc_tbzTracebackType | NonerK   rL   r/   )rM   s   "r7   rN   rO      s2      , & %	
 
r6   c                	B   "   V P                  4       G R j  xL
  R #  L5irx   )aclose)ro   r   r   r   s   &&&&r7   	__aexit__AMD.__aexit__   s      kkms   c                    V ^8  d   QhRRRR/# )rH   framezrtc.AudioFramerK   rL   r/   )rM   s   "r7   rN   rO      s     . . .4 .r6   c                	    V P                   '       dP   V P                   P                  '       g2   V P                  '       d   V P                   P                  V4       R # R # R # R # rx   )rn   closedrf   send_nowait)ro   r   s   &&r7   
push_audioAMD.push_audio   sB    >>>$.."7"7"7D<L<L<LNN&&u- =M"7>r6   c                   V ^8  d   QhRR/# rH   rK   rL   r/   )rM   s   "r7   rN   rO      s     6 6 6r6   c                	b    V P                   '       d   V P                   P                  4        R # R # rx   )rf   on_user_speech_startedry   s   &r7   _on_user_speech_startedAMD._on_user_speech_started   s%    335 r6   c                    V ^8  d   QhRRRR/# )rH   silence_durationr'   rK   rL   r/   )rM   s   "r7   rN   rO     s     D De D Dr6   c                	d    V P                   '       d   V P                   P                  V4       R # R # rx   )rf   on_user_speech_ended)ro   r   s   &&r7   _on_user_speech_endedAMD._on_user_speech_ended  s(    112BC r6   c                    V ^8  d   QhRRRR/# )rH   textr-   rK   rL   r/   )rM   s   "r7   rN   rO     s     - -3 -4 -r6   c                	d    V P                   '       d   V P                   P                  V4       R # R # rx   )rf   	push_text)ro   r   s   &&r7   _on_transcriptAMD._on_transcript  s'    &&t, r6   c                   V ^8  d   QhRR/# r   r/   )rM   s   "r7   rN   rO   
  s     " "d "r6   c                	  "   V P                   '       d   R # RV n         V P                  '       d7   V P                  P                  4         V P                  G R j  xL
  R V n        V P
                  '       dP   V P
                  P                  RV P                  4       V P
                  P                  4       G R j  xL
  R V n        V P                  4        V P                  P                  '       d%   V P                  P                  P                  4        R V P                  n        R #  L  \        P                   d     Li ; i L5i)NTamd_prediction)rh   rm   cancelasyncioCancelledErrorrf   off_on_amd_predictionclose	_end_spanr^   r   r   _amdry   s   &r7   r   
AMD.aclose
  s     <<<>>>NN!!#nn$$ "DN  !143J3JK""((***#D=="""MM##99;! %))  +sY   -E	E	D, D*D, E	8AE	;E<6E	37E	*D, ,EE	EE	c                    V ^8  d   QhRRRR/# rH   rI   r!   rK   rL   r/   )rM   s   "r7   rN   rO   '  s     #U #U, #U4 #Ur6   c                	x  "   V P                   '       d   \        P                  ! R 4       R# Wn        V P	                  V4      V n         V P                   '       g   \        R4      hV P                   P                  RV P                  4       RV n        RV n	        VP                  P                  '       d(   \        P                  ! R4       RVP                  n        VP                  '       d@   \        P                  ! R4       VP                  P                  4       G Rj  xL
  RVn        Wn        V P                   P                  4        V P!                  4        VP"                  '       d   VP"                  P%                  4        \&        P(                  ! V P+                  V4      RR7      V n        R#  L5i)	zAMD already running, skippingNzGAMD classifier could not be resolved, please provide a compatible modelr   Fz=session level ivr_detection will be disabled when AMD is usedz_session-level IVR detection was already started, closing it so AMD can manage the IVR lifecycle	amd_setupname)rf   r   warningr^   _resolve_classifier
ValueErroronr   rh   rg   optionsrC   _ivr_activityr   r   start_start_spanr   _pause_authorizationr   create_task_setuprm   ro   rI   s   &&r7   r   AMD._run'  sP    NN:;33G<Y  	,d.E.EF??(((NNZ[,1GOO)   NNA ''..000$(G! 	 224 ,,T[[-AT 1s   B3F:68F:/3F:"F8#BF:c                    V ^8  d   QhRRRR/# r   r/   )rM   s   "r7   rN   rO   L  s     " "L "T "r6   c                	  "   V P                   '       d   R # VP                  '       gD   \        P                  ! R4       V P                  '       d   V P                  P                  4        M\        VP                  P                  V P                  ;'       g    R \        P                  P                  RR7      G R j  xL
  V P                   '       g-   V P                  '       d   V P                  P                  4        \        V P                  4      '       dE   V P                   '       g1   \        P                  ! R4       V P                  4       G R j  xL
  R # R # R #  L L5i)NzHsession room_io unavailable, starting amd timers immediately as fallbackT)roomidentitykindwait_for_subscriptionzstarting amd stt pipeline)rh   _room_ior   r   rf   start_timersr   r   rb   r	   	TrackKind
KIND_AUDIOr   re   debug_run_sttr   s   &&r7   r   
AMD._setupL  s     <<<NNZ   --/,%%**33;;t]]--&*	   <<<D$4$4$4  --/DIIt|||LL45--/!! (4 "sH   &E&'E&AE&%E&>E"?E&E&'AE&.)E&E$E&$E&c                   V ^8  d   QhRR/# r   r/   )rM   s   "r7   rN   rO   c  s     !2 !2 !2r6   c                	  a a"   \        S P                  4      '       g   Q hS P                  '       g   Q h\        P                  \
        P                  ,          ! 4       S n        S P                  P                  4       ;_uu_4       GR j  xL
 oR V3R llpR V V3R llp\        P                  ! V! S P                  4      RR7      \        P                  ! V! 4       RR7      .p \        P                  ! V!  G R j  xL
  \        P                  ! V!  G R j  xL
  R R R 4      GR j  xL
  R #  L L4 L  \        P                  ! T!  G R j  xL 
  i ; i L.  + GR j  xL 
 '       g   i     R # ; i5i)Nc                    V ^8  d   QhRRRR/# )rH   chanzaio.Chan[rtc.AudioFrame]rK   rL   r/   )rM   s   "r7   rN   "AMD._run_stt.<locals>.__annotate__k  s     ' '": 't 'r6   c                t   <"   V   R j  xL
  pSP                  V4       K   LDSP                  4        R # 5irx   )
push_frame	end_input)r   r   
stt_streams   & r7   _sendAMD._run_stt.<locals>._sendk  s8     #' 1 1%))%014 $$&s   8%#%8%8c                   V ^8  d   QhRR/# r   r/   )rM   s   "r7   rN   r   q  s     
K 
KD 
Kr6   c                 P  <"   ^RI Hp  S  Rj  xL
  pVP                  V P                  8X  g   K'  VP                  '       g   K;  SP
                  '       g   KO  VP                  ^ ,          P                  ;p'       g   Kv  SP
                  P                  VRR7       K   LDR# 5i)   )SpeechEventTypeNamd_stt)source)rA   r   typeFINAL_TRANSCRIPTalternativesrf   r   r   )r   eventr   ro   r   s      r7   _receiveAMD._run_stt.<locals>._receiveq  s     2#- K K%

o&F&FF!... ,,,%*%7%7%:%?%??T??((224	2JK:s<   	B&B#B!B#B&B&B&"B&B&!B##B&amd_stt_sendr   amd_stt_receive)r   re   rf   r   Chanr	   
AudioFramern   streamr   r   gathercancel_and_wait)ro   r   r   tasksr   s   f   @r7   r   AMD._run_sttc  s    		""""#..1399##%%%' '
K 
K ##E$..$9O##HJ5FGE2nne,,,))51117 &%%2 -1c))51117 &%%%s   /E:AE:D3E:AE)D9 D5D9ED7E!E:,E-E:5D97E9EEEEE:E7	#E&$
E7	/E7	1	E:c                    V ^8  d   QhRRRR/# )rH   r   r   rK   rL   r/   )rM   s   "r7   rN   rO     s     0, 0,); 0, 0,r6   c                	   Wn         \        P                  ! R RVP                  P                  RVP
                  RVP                  RVP                  RVP                  /R7       V P                  '       d   V P                  P                  4        V P                  '       d   V P                  P                  4        V P                  '       d   V P                  P                  \        P                   VP                  P                  \        P"                  VP
                  \        P$                  VP                  \        P&                  VP                  \        P(                  VP                  /4       V P+                  4         \-        4       pVP.                  P1                  RVP                  P                   2RVP                  P                  RVP                  RVP
                  RVP                  RVP                  /R7       V P4                  P6                  ;pe   VP9                  V4       V P;                  R
V4       R	#   \2         d     LLi ; i)zamd predictionr   reasonspeech_durationdelayr   )extrazlk.amd:)metadataNr   )rg   r   infor   valuer	  r
  r  r   rf   r   rn   r   ri   set_attributesr   ATTR_AMD_CATEGORYATTR_AMD_REASONATTR_AMD_SPEECH_DURATIONATTR_AMD_DELAYATTR_AMD_TRANSCRIPTr   r   taggeraddr   r^   _session_hostr   emit)ro   r   ctxhosts   &&  r7   r   AMD._on_amd_prediction  s   FOO11&--!6#9#9f//		
 &&(>>>NN  ":::JJ%%116??3H3H//88&:P:P..33V5F5F 		!#CJJNN&////01 5 5%v'='=fmm &"3"3V\\  	 MM///D<##F+		"F+  		s   BI
 
IIc                   V ^8  d   QhRR/# r   r/   )rM   s   "r7   rN   rO     s     X XT Xr6   c                	    V P                   '       d   R # \        P                  ! RV P                  P                  R7      V n         R # )Namd)context)ri   r   
start_spanr^   _root_span_contextry   s   &r7   r   AMD._start_span  s,    :::&&udmm6V6VW
r6   c                   V ^8  d   QhRR/# r   r/   )rM   s   "r7   rN   rO     s      4 r6   c                	p    V P                   '       g   R # V P                   P                  4        R V n         R # rx   )ri   endry   s   &r7   r   AMD._end_span  s#    zzz


r6   c                    V ^8  d   QhRRRR/# )rH   rI   r!   rK   z_AMDClassifier | Noner/   )rM   s   "r7   rN   rO     s       
r6   c                	   R p\        V P                  \        4      '       d   \        V P                  4      pMY\        V P                  \        4      '       d   V P                  pM,VP
                  ;p'       d   \        V\        4      '       d   TpV P                  '       g'   \        V'       d   VP                  MR \        RR7       V'       d   \        TV P                  R,          V P                  R,          V P                  R,          V P                  R,          V P                  R,          V P                  R,          \        V P                  4      '       d   R	R7      # R
R7      # R # )Nr@   rW   r(   r)   r*   r+   r,   r.   r   rA   )r(   r)   r*   r+   r,   r.   r   )rc   r]   r-   _InferenceLLM_LLMr@   ra   rk   rl   r#   r    rj   r   re   )ro   rI   _llm	candidates   &&  r7   r   AMD._resolve_classifier  s    -1d&&,, !1!12D(($//##D";;&i&Jy$,G,GD333""

$  !'+zz2J'K(,

3L(M*.**5P*Q$(JJ/D$E

9-zz(+$,TYY$7$7y	 	 >C	 	 r6   )rn   rf   rh   r_   r`   r]   rj   rb   rg   r^   ri   re   rm   ra   )r0   r1   r2   r3   __doc__r=   r4   r?   r   rZ   propertyrz   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r5   __classcell__)rs   s   @r7   r;   r;   P   s	   3j =<447? 2;	7?
 &/7? &*7? #7? 1:7? 057? ;D7? 7?r , , E E I I<.6D-":#UJ".!2F0,dX
 r6   r;   r   c               (    V ^8  d   QhRRRRRRRR/# )	rH   rl   z
str | Noneevaluated_modelsr"   rX   r-   rK   rL   r/   )rM   s   "r7   rN   rN     s0     
 


 	

 

r6   c                  a  S '       g   R # S P                  4       o \        ;QJ d    V 3R lV 4       F  '       d   K   RM	  RM! V 3R lV 4       4      '       d   \        P                  ! RVS 4       R # R # )Nc              3     <"   T F3  pSVP                  4       8g  ;'       d    SVP                  4       9  x  K5  	  R # 5irx   )lower).0r-  rl   s   & r7   	<genexpr>)_warn_if_not_evaluated.<locals>.<genexpr>  s;      )I 	""EEuIOO4E'EE)s   >>FTz%s model %s hasn't been evaluated with our benchmark, it might not be compatible with amd. Set `suppress_compatibility_warning=True` to silence this warning.)r6  allr   r   )rl   r3  rX   s   f&$r7   rk   rk     sd     KKME
s )sss )   	[		
	r6   >   openai/gpt-4oopenai/gpt-4.1openai/gpt-5.1openai/gpt-5.2openai/gpt-5.4openai/gpt-4.1-miniopenai/gpt-4.1-nanoopenai/gpt-5.1-chat-latestopenai/gpt-5.2-chat-latestgoogle/gemini-2.5-flash-liter<   google/gemini-3-flash-preview>   deepgram/nova-3r>   +assemblyai/universal-streaming-multilingual)=__conditional_annotations__
__future__r   r   r[   typesr   typingr   r   r   opentelemetryr   livekitr	   	inferencer
   r*  r   rd   r   jobr   r@   r+  logr   rA   _STT	telemetryr   r   r   r   utilsr   r   r   
utils.miscr   utils.participantr   
classifierr   r   r   r   r   r   r   r   r    agent_sessionr!   r#   r4   r$   r&   r9   r;   rk   )rH  s   @r7   <module>rX     s    " "  	  4 4   N N "    , * 0 0 " ;
 
 
 ," h " h y  46!:.wj0 , R,w/0
1 Rn
r6   