
    i+Z              	          d Z ddlZddlZddlZddlZddlmZ ddlmZ d,dZ	 e	         ee
      j                  j                  dz  Zej                         r6 ee      ej                  vr"ej                  j!                  d ee             	 ddlmZ dddddddddZdZdZ G d d      Zd-dee   defdZdededefdZd.dededee   fdZd,d Z d!eddfd"Z!d!eddfd#Z"d!eddfd$Z#d!eddfd%Z$d!eddfd&Z%d!eddfd'Z&d!eddfd(Z'd!eddfd)Z(d,d*Z)e*d+k(  r e)        yy# e$ r%  ed	        ed
        ej*                  d       Y w xY w)/u  
tools/telnyx_client.py — Genesis Telnyx SDK Client
====================================================
SDK-first wrapper for all Telnyx AI assistant and phone number operations.
Replaces every raw curl/requests call in the codebase.

Venv:   source /mnt/e/genesis-system/.venv_telnyx/bin/activate
Usage:  python3 tools/telnyx_client.py <command> [options]

Commands:
  list                     List all assistants
  get <id>                 Get one assistant (full config)
  create                   Interactive create (prompts for fields)
  update <id> [--field v]  Update specific fields
  versions <id>            List versions of an assistant
  promote <id> <ver_id>    Promote a version to main
  numbers                  List your Telnyx phone numbers
  search                   Search available numbers (AU/US)
  audit                    Full system audit
  assign <num_id> <conn>   Assign number to a connection

Examples:
  python3 tools/telnyx_client.py list
  python3 tools/telnyx_client.py get assistant-9c42d3ce-e05a-4e34-8083-c91081917637
  python3 tools/telnyx_client.py search --country AU --area 07 --limit 5
  python3 tools/telnyx_client.py audit
    N)Path)Optionalreturnc                     t        t              j                  j                  dz  dz  } | j                         r| j	                         j                         D ]  }|j                         }|s|j                  d      r(d|v s-|j                  d      \  }}}|j                         }|j                         j                  d      j                  d      }|s|s|t        j                  vs|t        j                  |<    y y )Nconfigzsecrets.env#="')r   __file__parentexists	read_text
splitlinesstrip
startswith	partitionosenviron)secrets_pathlinekey_vals        ,/mnt/e/genesis-system/tools/telnyx_client.py_load_secretsr   &   s    >((//(:]JL **,779 	*D::<DDOOC0SD["nnS1Qiikiik'',223733bjj#8&)BJJsO	*     z).venv_telnyx/lib/python3.12/site-packages)Telnyxz:ERROR: Telnyx SDK not found. Activate .venv_telnyx or run:z8  source /mnt/e/genesis-system/.venv_telnyx/bin/activate   z.assistant-696799a5-e994-4ac1-8f26-7b0923aee682z.assistant-991f3950-12fd-4e90-a728-4149c16524e0z.assistant-cffc79bc-fd3b-4f96-a8e1-31a360100eb5z.assistant-233d7403-044b-4b95-8eef-3554186306ccz.assistant-6f6f4ca2-3155-4930-95cb-27f59514af3ez.assistant-c0265496-86a2-46fd-a932-4c4398009013z.assistant-9c42d3ce-e05a-4e34-8083-c91081917637)aivazaiva-v2zvoice-terminalzvoice-terminal2georgezgrowth-director
agileadaptzwidget-stage1zgoogle/gemini-2.5-flashzTelnyx.NaturalHD.eucalyptusc                      e Zd ZdZd4dee   ddfdZdedefdZdee	   fdZ
d	ede	fd
Zeedddddddf	dedededededededededee   dede	fdZd	ede	fdZ	 d5d	ededede	fdZd5d	ededede	fdZ	 	 d6d	edededed ed!ee	   de	fd"Zd	edee	   fd#Zd	ed$ede	fd%Z	 	 	 	 	 	 d7d&ed'ee   d(ee   d)eee      d*ed+edee	   fd,Zdee	   fd-Zd.ed/ede	fd0Zd.ed1ee   de	fd2Zde	fd3Zy)8TelnyxClientzy
    SDK-first wrapper for Genesis Telnyx operations.
    All public methods return plain dicts (JSON-serialisable).
    Napi_keyr   c                     |xs t         j                  j                  d      }|st        d      t	        |      | _        y )NTELNYX_API_KEYzBTELNYX_API_KEY not found. Set env var or add to config/secrets.envr%   )r   r   getRuntimeErrorr   _client)selfr%   r   s      r   __init__zTelnyxClient.__init__Y   s;    9(89T  c*r   id_or_aliasc                 .    t         j                  ||      S N)KNOWN_ASSISTANTSr)   )r,   r.   s     r   _resolvezTelnyxClient._resolveb   s    ##K==r   c           
      t   | j                   j                  j                  j                         }t	        |d|      }g }|D ]u  }t        |t              r|n
t        |      }|j                  |j                  dd      |j                  dd      |j                  dd      |j                  dd      d       w |S )z)Return all assistants as a list of dicts.dataid namemodeldescription)r5   r7   r8   r9   )
r+   ai
assistantslistgetattr
isinstancedictvarsappendr)   )r,   resultr;   outads         r   list_assistantszTelnyxClient.list_assistantsg   s    ++002VVV4
 	A4(d1gAJJ uuT2 uuVR0 uuWb1 uu]B7	 	 
r   assistant_idc                     | j                  |      }| j                  j                  j                  j	                  |      }t        |t              r|S t        |      S )z&Get full config of a single assistant.)r2   r+   r:   r;   retriever>   r?   r@   )r,   rG   rB   s      r   get_assistantzTelnyxClient.get_assistantv   sF    }}\2++44\B#FD1vCtF|Cr   r6   TkrispiX  r7   instructionsr8   voicegreetingr9   unauthenticated_web_callsnoise_suppressiontime_limit_secstoolsdvw_urlc                     t        |||||d|i|||	d      }|
r|
|d<   |r||d<    | j                  j                  j                  j                  di |}t        |t               r|S t        |      S )a  
        Create a new Telnyx AI assistant.

        Args:
            name:                      Display name
            instructions:             System prompt
            model:                    Model ID (default: google/gemini-2.5-flash)
            voice:                    TTS voice (default: Telnyx.NaturalHD.eucalyptus)
            greeting:                 Opening message (empty = user speaks first)
            description:              Internal description
            unauthenticated_web_calls: Allow unauthenticated browser widget calls
            noise_suppression:        "krisp" | "deepfilternet" | "disabled"
            time_limit_secs:          Max call duration
            tools:                    List of tool dicts (webhook tools etc.)
            dvw_url:                  Dynamic variables webhook URL

        Returns:
            dict with at least {"id": "assistant-xxxx", "name": ...}
        rM   )"supports_unauthenticated_web_callsrP   rQ   )r7   rL   r8   r9   rN   voice_settingstelephony_settingsrR   dynamic_variables_webhook_url )r?   r+   r:   r;   creater>   r@   )r,   r7   rL   r8   rM   rN   r9   rO   rP   rQ   rR   rS   kwargsrB   s                 r   create_assistantzTelnyxClient.create_assistant|   s    B %##U+6O%6#2 
 #F7O6=F232++22<V<#FD1vCtF|Cr   c                     | j                  |      }d|v r|j                  d      |d<    | j                  j                  j                  j
                  |fi |}t        |t              r|S t        |      S )a  
        Update one or more fields on an existing assistant.

        Common fields:
            instructions, model, name, description, greeting,
            voice_settings, telephony_settings, tools, dvw_url,
            promote_to_main (bool)

        Example:
            client.update_assistant("aiva", instructions="New prompt",
                                    promote_to_main=True)
        rS   rX   )	r2   popr+   r:   r;   updater>   r?   r@   )r,   rG   fieldsrB   s       r   update_assistantzTelnyxClient.update_assistant   sk     }}\26<jj6KF232++22<J6J#FD1vCtF|Cr   promotec                 *    | j                  |||      S )z<Update just the system prompt, optionally promoting to main.)rL   promote_to_mainra   )r,   rG   rL   rb   s       r   update_instructionsz TelnyxClient.update_instructions   s%     $$%# % 
 	
r   c                 *    | j                  |||      S )z"Replace all tools on an assistant.)rR   rd   re   )r,   rG   rR   rb   s       r   	set_toolszTelnyxClient.set_tools   s!    $$w % 
 	
r   urlmethod
parametersc                     | j                  |      }t        |j                  dg       xs g       }d||||dd}	|r||	d<   |j                  |	       | j	                  ||      S )a  
        Add a single webhook tool to an assistant, preserving existing tools.

        Args:
            assistant_id: Assistant ID or alias
            name:         Tool function name (snake_case)
            description:  What the AI should use this tool for
            url:          Webhook endpoint URL
            method:       HTTP method (GET/POST)
            parameters:   JSON Schema for parameters (optional)

        Returns:
            Updated assistant dict
        rR   webhook)ri   rj   )typer7   r9   rm   rk   )rJ   r<   r)   rA   rh   )
r,   rG   r7   r9   ri   rj   rk   currentexisting_toolsnew_tools
             r   add_webhook_toolzTelnyxClient.add_webhook_tool   sv    . $$\2gkk'26<"= &"f5	
 %/H\"h'~~lN;;r   c           
         | j                  |      }| j                  j                  j                  j                  j                  |      }t        |d|      }g }|D ]u  }t        |t              r|n
t        |      }|j                  |j                  dd      |j                  dd      |j                  dd      |j                  dd      d       w |S )	z"List all versions of an assistant.r4   r5   r6   versionmainF
created_at)r5   rt   ru   rv   )r2   r+   r:   r;   versionsr<   r=   r>   r?   r@   rA   r)   )r,   rG   rB   rw   rC   vrE   s          r   list_versionszTelnyxClient.list_versions   s    }}\2++4499,G6662 	A4(d1gAJJeeD"oeeIr2eeFE2eeL"5	 	 
r   
version_idc                     | j                  |      }| j                  j                  j                  j                  j                  ||      }t        |t              r|S t        |      S )zAPromote a specific version to main (sends 100% of traffic to it).)rG   )	r2   r+   r:   r;   rw   rb   r>   r?   r@   )r,   rG   rz   rB   s       r   promote_versionzTelnyxClient.promote_version  sX    }}\2++44<<\ = 
 $FD1vCtF|Cr   country	area_codelocalityfeaturesnumber_typelimitc                 (   |||xs dg|d}|r||d<   |r||d<   | j                   j                  j                  |      }t        |d|      }	g }
|	D ]  }t	        |t
              r|n
t        |      }|
j                  |j                  dd      |j                  d	      r&|j                  d	i g      d
   j                  dd      nd|j                  di       j                  dd      |j                  dd      |j                  dg       d        |
S )a  
        Search available phone numbers.

        Args:
            country:    ISO country code ("AU", "US", "GB")
            area_code:  National destination code / area code (e.g. "07" for QLD)
            locality:   City name (e.g. "Brisbane")
            features:   ["voice", "sms"] etc. Default: ["voice"]
            number_type: "local" | "toll_free" | "mobile"
            limit:       Max results

        Returns:
            List of {"phone_number", "region", "monthly_cost"}
        rM   )country_codephone_number_typer   r   national_destination_coder   )filterr4   phone_numberr6   region_informationr   region_namecost_informationmonthly_costr   r   )r   regionr   rn   r   )	r+   available_phone_numbersr<   r=   r>   r?   r@   rA   r)   )r,   r}   r~   r   r   r   r   filter_paramsrB   numbersrC   nrE   s                r   search_numberszTelnyxClient.search_numbers  s'   0 $!, -WI	
 9BM56(0M*%55::-:P&&&1 	A4(d1gAJJ!"~r!:`a`e`efz`{';bT!B1!E!I!I-Y[!\  BD!"'92!>!B!B>SU!V!"':B!?!"z2!6 	 
r   c                    | j                   j                  j                         }t        |d|      }g }|D ]  }t	        |t
              r|n
t        |      }|j                  |j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  dg       d        |S )	z.List all phone numbers in your Telnyx account.r4   r5   r6   r   statusconnection_idtags)r5   r   r   r   r   )	r+   phone_numbersr<   r=   r>   r?   r@   rA   r)   )r,   rB   r   rC   r   rE   s         r   list_my_numberszTelnyxClient.list_my_numbersI  s    ++002&&&1 	A4(d1gAJJ!"tR!"~r!:!"x!4!"!;!"vr!2 	 
r   phone_number_idr   c                     | j                   j                  j                  ||      }t        |t              r|S t        |      S )z
        Assign a phone number to a call-control connection.
        This routes inbound calls through the given connection.
        )r   r+   r   r_   r>   r?   r@   )r,   r   r   rB   s       r   assign_number_to_connectionz(TelnyxClient.assign_number_to_connectionY  sB     ++22= 3 
 $FD1vCtF|Cr   r   c                     | j                   j                  j                  ||      }t        |t              r|S t        |      S )z,Add tags to a phone number for organisation.)r   r   )r,   r   r   rB   s       r   
tag_numberzTelnyxClient.tag_numbere  s9    ++22?2N#FD1vCtF|Cr   c                     t        ddd       | j                         }t        t        |       d       t        ddd       | j                         }t        t        |       d       ||t        t
        t        dS )z
        Full system audit: all assistants + their tool counts,
        all owned phone numbers, known alias registry.

        Returns a structured dict suitable for logging or printing.
        zAuditing assistants... T)endflushz foundzAuditing phone numbers...)r;   r   known_aliasesdefault_modeldefault_voice)printrF   lenr   r1   DEFAULT_MODELDEFAULT_VOICE)r,   r;   r   s      r   auditzTelnyxClient.auditl  s|     	&Ct<))+
Z!())s$?&&(Wf%& !+ ' 0 - -
 	
r   r0   )T)POSTN)AUNNNlocal
   )__name__
__module____qualname____doc__r   strr-   r2   r<   r?   rF   rJ   r   r   boolintr\   ra   rf   rh   rr   ry   r|   r   r   r   r   r   rY   r   r   r$   r$   S   s   
+ + +>C >C >
d D# D$ D #"*.!(" $4D4D 4D 	4D
 4D 4D 4D $(4D 4D 4D ~4D 4D 
4DlDS Dt D, EI

/2
=A
	

c 
$ 
 
QU 
 %)$<$< $< 	$<
 $< $< TN$< 
$<P# $t*  DC DS DT D #'"&(,".. C=. 3-	.
 49%. . . 
d.`d  
D"
D36
D	
DD# DT#Y D4 D
t 
r   r$   r%   c                     t        |       S )z'Get a configured TelnyxClient instance.r(   )r$   r(   s    r   
get_clientr     s    ((r   assistant_aliasrL   c                 6    t               j                  | |      S )z4One-liner: update instructions on a known assistant.)r   rf   )r   rL   s     r   quick_update_instructionsr     s    <++O\JJr   r~   r   c                 :    t               j                  d| |      S )z1One-liner: find available QLD (07) phone numbers.r   )r}   r~   r   )r   r   )r~   r   s     r   quick_search_au_numbersr     s    <&&tyPU&VVr   c                 N    t        t        j                  | dt                     y )N   )indentdefault)r   jsondumpsr   )r4   s    r   _print_jsonr     s    	$**T!S
12r   clientc           	      H   | j                         }t        dddddddd        t        d       |D ]T  t        fd	t        j	                         D        d
      }|rd| dnd
}t        d   ddd   |z   ddd           V t        dt        |              y )N
ID<50r   NAMEz<30MODELzd----------------------------------------------------------------------------------------------------c              3   :   K   | ]  \  }}|d    k(  s|  ywr5   NrY   .0krx   rD   s      r   	<genexpr>z_cli_list.<locals>.<genexpr>       MDAqQtWaM   r6   z []r5   r7   r8   
Total: )rF   r   nextr1   itemsr   )r   _argsr;   alias	alias_strrD   s        @r   	_cli_listr     s    '')J	BtCj&Qwi
01	) KM$4$:$:$<MrR%*bqM	4Q&	I 5s;1QwZLIJK 
Ic*o&
'(r   c           
         | j                  |j                        }dD ](  }|j                  |d      }|st        |dd|        * |j                  dd      }|r't        dddd|d d  t	        |      dkD  rd	nd        |j                  d
g       }|rt        dd
ddt	        |       d       |D ]  }t        |t              rY|j                  d|j                  dd            }|j                  di       }	t        |	t              r|	j                  dd      nd}
n6t        |dt        |dd            }t        |dd       }	|	rt        |	dd      nd}
t        ddd| d|
         y y )N)r5   r7   r8   r9   rN   r6   z>15z: rL   r   z:
i  z...rR   z tool(s)r7   rn   ?rm   ri   z>17z - )rJ   r5   r)   r   r   r>   r?   r=   )r   argsrB   fieldr   rL   rR   tt_namerm   t_urls              r   _cli_getr     s   !!$''*FC )jj#U3Kr#'() ::nb1L>#&c,t*<)=s<GX[^G^edf=ghiJJw#E73-r#e*X67 
	3A!T"vquuVS'9:%%	2.2<Wd2KE2.QS !FGAvs,CD!!Y57>3BRHCxr%12
	3 r   c           
         | j                  |j                        }t        d|j                   d       |D ]K  }|j                  d      rdnd}t        d|j                  dd      dd	|j                  d
d       |        M y )Nz
Versions for :ru   u	    ← MAINr6     r5   r   r   rv   )ry   r5   r   r)   )r   r   rw   rx   	main_flags        r   _cli_versionsr     s    ##DGG,H	ODGG9A
&' O#$55=Kb	155r?3'q|R)@(A)MNOr   c                    t        d|j                   d|j                  xs d d|j                   d       | j	                  |j                  |j                  xs d |j
                  xs d |j                        }|st        d       y t        dd	d
dddddddd        t        d       |D ]'  }t        |d   d
d|d   dd|d   dd|d           ) y )Nz
Searching z numbers (area: anyz	, limit: z)...)r}   r~   r   r   zNo numbers found.r   PHONE NUMBER<20r   TYPEz<10REGIONz<25MONTHLYzF----------------------------------------------------------------------r   rn   r   r   )r   r}   arear   r   r   )r   r   resultsr   s       r   _cli_searchr     s    	Jt||n$4TYY5G%4H	RVR\R\Q]]a
bc##))#t&$jj	 $ G !"	B~c"!F3<q#a	{
KL	(O `>"3'q63q8S8I1^K\J]^_`r   c                    | j                         }t        ddddddddddd	        t        d
       |D ]4  }t        |d   dd|d   dd|d   dd|j                  dd              6 t        dt        |              y )Nr   r   r   r   r   z<45STATUSz<15
CONNECTIONzn--------------------------------------------------------------------------------------------------------------r   r5   r   r   r6   r   )r   r   r)   r   )r   r   r   r   s       r   _cli_numbersr     s    $$&G	B~c"!D:QxnAl^
LM	) f>"3'q4Qq{36Gq_aIbHcdef	Ic'l^
$%r   c                    | j                         }t        d       t        dt        |d          d       |d   D ]D  t        fdt        j                         D        d      }t        d|dd	d
    dd           F t        dt        |d          d       |d   D ],  }t        d|d    d|d    d|j                  dd              . t        d|d           t        d|d           y )Nu*   
═══ GENESIS TELNYX AUDIT ═══
zAssistants (r;   z):c              3   :   K   | ]  \  }}|d    k(  s|  ywr   rY   r   s      r   r   z_cli_audit.<locals>.<genexpr>  r   r   r6   z  [z>14z] r5   r   r7   z
Phone numbers (r   r   z	  status=r   z  conn=r   u   —z
Default model: r   zDefault voice: r   )r   r   r   r   r1   r   r)   )r   r   rB   r   r   rD   s        @r   
_cli_auditr     s   \\^F	
89	LVL1232
67L! 9M$4$:$:$<MrRE#;b4	AfI;789 
c&"9:;2
>?O$ c1^$%Yq{m7155Y^C_B`abc	f_56
78	OF?34
56r   c                     | j                  |j                  |j                        }t        d|j                   d|j                          t	        |       y )NzPromoted version z to main for )r|   r5   rz   r   r   r   r   rB   s      r   _cli_promoter     sC    ##DGGT__=F	doo.mDGG9
EFr   c                     | j                  |j                  |j                        }t        d|j                   d|j                          t	        |       y )Nz	Assigned u    → connection )r   	number_idr   r   r   r   s      r   _cli_assignr     sH    //@R@RSF	Idnn%%5d6H6H5I
JKr   c            	      4   t        j                  dt         j                  t              } | j	                  dd      }|j                  dd       |j                  d	d
      }|j                  dd       |j                  dd      }|j                  dd       |j                  dd      }|j                  dd       |j                  dd       |j                  dd       |j                  dd      }|j                  ddd       |j                  ddd       |j                  ddd        |j                  d!t        d"d#$       |j                  d%d&       |j                  d'd(      }|j                  d)d*       |j                  d+d,       | j                         }t               }t        t        t        t        t        t        t         t"        d-}	|	j%                  |j&                        }
|
r
 |
||       y | j)                          y ).Nu;   Genesis Telnyx Client — SDK-first voice assistant manager)r9   formatter_classepilogcommandT)destrequiredr<   zList all assistants)helpr)   zGet one assistant (full config)r5   z7Assistant ID or alias (aiva, george, voice-terminal...)rw   zList versions of an assistantzAssistant ID or aliasrb   zPromote a version to mainrz   zVersion ID to promoter   zList your Telnyx phone numberssearchzSearch available phone numbersz	--countryr   zCountry code (default: AU))r   r  z--arear6   z!Area code / NDC (e.g. 07 for QLD)z
--localityz	City namez--limitr   zMax results (default: 10))rn   r   r  r   zFull system auditassignz%Assign a phone number to a connectionr   zPhone number IDr   zConnection ID)r<   r)   rw   rb   r   r  r   r  )argparseArgumentParserRawDescriptionHelpFormatterr   add_subparsers
add_parseradd_argumentr   
parse_argsr$   r   r   r   r   r   r   r   r   r)   r  
print_help)parsersubp_getp_verp_promop_searchp_assignr   r   dispatchhandlers              r   ru   ru     s   $$Q <<F
 

Y

>C NN6 5N6 NN5'HNIE	t"[\ NN:,KNLE	t"9: nnY-HnIG$;<,CD NN9#CND ~~h-M~NH+t:VW(B5XY,E)#r@[\ NN7!4N5 ~~h-T~UH+,=>/@D^F !  	H ll4<<(Gr   __main__)r   Nr0   )07   )+r   r   sysr   r  pathlibr   typingr   r   r   r   	VENV_SITEr   r   pathinserttelnyxr   ImportErrorr   exitr1   r   r   r$   r   r?   r   r   r<   r   r   r   r   r   r   r   r   r   r   ru   r   rY   r   r   <module>r%     s  8 
 
    
*  N!!((+VV	#i.8HHOOAs9~& GFFFFFFF	  *-n
 n
f	) ) )
Ks K# K$ K
Ws W# Wd4j W3)l )d )3\ 3D 34O, O O` `t `"& & &7| 7t 7   t =@ zF C  	
FG	
DECHHQKs   D) )'EE