
    Y5j                    z   % S r SSKJr  SSKrSSKJrJr  SSKJr  SSKJ	r	  SSK
Jr  SSKJr  SS	KJrJr  SS
KJrJr  SSKJrJrJrJrJrJrJrJrJr  SSKJr  SSK J!r!  \RD                  " \#5      r$\" SS9r% " S S\&5      r'SES jr(SFS jr)S r*SGS jr+SGS jr,SHSIS jjr-SJS jr.SKS jr/SLS jr0SMS jr1          SNS jr2SS.       SOS jjr3SHSPS jjr4SQS  jr5SRS! jr6        SSS" jr7 SHSSSS#.         STS$ jjjr8    SU           SVS% jjr9SWS& jr:SXS' jr;SSSS(.               SYS) jjr<S*S+S,S-S.S/S0S1S2S3S4S5S6S7.r=S8\>S9'   \?" 1 S:k5      r@S;rASZS< jrBS=S>.     S[S? jjrCSXS@ jrDSZSA jrES\SB jrF    SU               S]SC jjrG    SU                 S^SD jjrHg)_u@   Integración OpenAI: archivos, Responses API y code interpreter.    )annotationsN)datetime	timedelta)Path)Any)Session)settings)AgentFileModel
AgentModel)role_instructions_to_text
strip_html)	build_familia_form_rules(build_familia_narrative_enrichment_rules#build_form_template_supremacy_block$build_redaction_min_paragraphs_rules"filter_familia_template_file_namesis_familia_form_fileis_familia_tabla_filepick_familia_base_template"resolve_familia_template_from_rows)format_student_context_block)	agent_dir   )minutesc                      \ rS rSrSrSrg)OpenAIUploadError"   z#Fallo al subir un archivo a OpenAI. N)__name__
__module____qualname____firstlineno____doc____static_attributes__r       [C:\Users\jesus\Desktop\proyecto_pie360\backend\app\backend\services\openai_agent_service.pyr   r   "   s    -r%   r   c                 ,    [         R                  " 5       $ N)r   utcnowr   r%   r&   _utcnowr*   &   s    ??r%   c                :    U (       d  g[        5       U -
  [        :  $ )NT)r*   CONTAINER_TTL)
updated_ats    r&   is_container_expiredr.   *   s    9z!M11r%   c                 v    [         R                  (       d  [        S5      eSSKJn   U " [         R                  S9$ )NOPENAI_API_KEY no configuradar   OpenAI)api_key)r	   openai_api_keyRuntimeErroropenair2   r1   s    r&   get_openai_clientr7   0   s+    "":;;(1122r%   c                    SSK Jn  [        5       nU" U 5      nUR                  R	                  X4SS9nUR
                  $ )Nr   )BytesIO
assistantsfilepurpose)ior9   r7   filescreateid)contentdisplay_namer9   clienthandleuploadeds         r&   upload_bytes_to_openairG   8   s=     FWF||""(>"UH;;r%   c                   [         R                  (       d  [        S5      e UR                  SS5      R	                  S5      S   =(       d    Un[        X5      $ ! [         a    e [         a  n[        [        U5      5      UeS nAff = f)Nr0   \/)r	   r4   r   replacesplitrG   	Exceptionstr)rB   rC   	leaf_nameexcs       r&   require_openai_file_uploadrR   A   sz    "" ?@@3 ((s399#>rBRl	%g99  3C)s23s   7A B.BBc                    [        5       nU=(       d    U R                  nU R                  S5       nUR                  R	                  X44SS9nS S S 5        UR
                  $ ! , (       d  f       WR
                  $ = f)Nrbr:   r;   )r7   nameopenr?   r@   rA   )	file_pathrC   rD   upload_namerE   rF   s         r&   upload_local_file_to_openairY   M   sd     F0)..K		<<&&[,A<&X 
;; 
	;;s   A!!
A:c                    U (       a  [         R                  (       d  g  [        5       nUR                  R	                  U 5        g ! [
         a   n[        R                  SX5         S nAg S nAff = f)Nz)No se pudo eliminar archivo OpenAI %s: %s)r	   r4   r7   r?   deleterN   loggerwarning)file_idrD   rQ   s      r&   delete_openai_filer_   U   sT    (11R"$G$ RBGQQRs   %A 
A/A**A/c                ^    [        5       nUR                  R                  R                  XS9  g )N)r^   )r7   
containersr?   r@   )container_idr^   rD   s      r&   attach_file_to_containerrc   _   s'     F
""<"Ar%   c                    U(       a  U R                   (       d  g[        U R                  5      (       a  gU H  n [        U R                   U5        M     g! [         a-  n[
        R                  SUU R                   U5         SnAMQ  SnAff = f)uQ   Adjunta archivos al contenedor reutilizado (p. ej. base PIE360 recién generada).Nz+No se pudo adjuntar %s al contenedor %s: %s)openai_container_idr.   openai_container_updated_atrc   rN   r\   r]   )agentfile_idsr^   rQ   s       r&    ensure_openai_files_in_containerri   d   sx    544E==>>	$U%>%>H   	NN=))	 	s   A
B "BBc                     S U l         S U l        g r(   )re   rf   )rg   s    r&   clear_agent_containerrk   v   s     $E(,E%r%   c                   UR                   (       ad  UR                  (       aG  [        UR                  5      (       d-   [	        UR                  UR                   5        UR                   $ UR                   $ [        R                  (       d  [        S5      e [        X2R                  5      nXRl         S Ul        U R                  5         UR                  (       a3  [        UR                  5      (       d   [	        UR                  U5        U$ U$ ! [
         a6  n[        R                  SU5        [        U5         S nAUR                   $ S nAff = f! [
         a,  n[        R                  SU5        [        U5         S nAU$ S nAff = f! [
         a=  n[!        U5      S S Ul        [        R#                  SUR$                  5         S nAg S nAff = f)Nu9   Contenedor expirado o inválido, se creará uno nuevo: %sr0   z7No se pudo adjuntar archivo al contenedor existente: %si  z#Error subiendo archivo a OpenAI: %s)openai_file_idre   r.   rf   rc   rN   r\   r]   rk   r	   r4   r   rY   rC   openai_upload_errorflushrO   	exceptionrA   )dbrg   row	disk_pathrQ   r^   s         r&   ensure_openai_file_for_rowrt   {   s{    $$-A%BcBc-d-d-()B)BCDVDVW !!!s!!!"" ?@@-i9I9IJ$"&

$$-A%BcBc-d-d-()B)BGL w)  -Z\_`%e,,!!!-"  -XZ]^%e,,-  "%c(4C.>Gs`    D AF 5E F F 
E!E

E
F!F=F FF 
G3GG)	only_rowsc               F   U R                  [        5      R                  [        R                  U:H  5      R	                  5       nU(       d  / $ Ub  UnOnU R                  [
        5      R                  [
        R                  U:H  5      R                  [
        R                  R                  5       5      R                  5       n/ nU HX  n[        U5      UR                  -  nUR                  5       (       d  M2  [        XXg5      nU(       d  MG  UR                  U5        MZ     U$ r(   )queryr   filterrA   firstr
   agent_idorder_byuploaded_atascallr   is_filert   append)	rq   rz   ru   rg   rowsrh   rr   rs   	openai_ids	            r&   sync_agent_openai_filesr      s     HHZ ''
(ABHHJE	 HH^$VN++x78Xn004467SU	 	 Hh'#&&0	  "".r#I	9OOI&  Or%   c                    SSK Jn  U" U 5      nU(       a  U$ U(       a7  UR                  (       a&  [        UR                  5      (       d  UR                  $ g )Nr   )#_extract_container_id_from_response)1app.backend.services.agent_response_files_servicer   re   r.   rf   )responserg   r   rb   s       r&   _extract_container_idr      sC    e6x@L**3GHiHi3j3j(((r%   c                >   U R                  [        R                  5      R                  [        R                  U:H  5      R                  [        R                  R                  5       5      R                  5       nU Vs/ s H  o3S   (       d  M  US   PM     sn$ s  snf )Nr   )	rw   r
   rC   rx   rz   r{   r|   r}   r~   )rq   rz   r   rr   s       r&   _agent_uploaded_file_namesr      sr    
,,-	''83	4	.,,002	3		 	 #-ds!fFCFd---s   =B	Bc                      g)Nu8  - Para informe a la familia (solo si NO hay plantilla tipo formulario en archivos): abre FORMATO INFORME DE FAMILIA.docx como plantilla base y solo completa celdas.
- TIPOGRAFÍA DE PLANTILLA (OBLIGATORIO): copia fuente, tamaño y alineación del run existente en cada párrafo (típicamente 10 pt). NUNCA uses cell.text = ... ni add_paragraph() con estilo por defecto (11 pt). PROHIBIDO forzar justificado.
- TEXTO ARRIBA EN LA CELDA: el contenido debe empezar en la primera línea útil de la celda, sin espacio en blanco arriba. Antes de escribir, elimina párrafos vacíos sobrantes; space_before y space_after = 0; no centres verticalmente el texto.
- Contenido narrativo → doc.tables[3] (2 párrafos LARGOS por campo, 6-10 oraciones c/u):
    fila 3 p0: motivo e instrumentos; fila 5 p0: diagnóstico (borra p1 vacío);
    fila 8 p1: fortalezas (cols 0-2) y necesidades (cols 3-9) ámbito pedagógico;
    fila 10 p1: fortalezas y necesidades ámbito social/afectivo;
    fila 12 p0: trabajo colaborativo; fila 14 p0: apoyos en hogar;
    fila 16 p0: acuerdos y compromisos.
  En filas 8 y 10 NO sobrescribas el párrafo 0 (título 'Fortalezas…' / 'Necesidades…'); escribe el cuerpo en el párrafo 1.
  Patrón Python (conservar formato de plantilla):
    from docx.shared import Pt
    def poner_contenido(celda, texto, idx=0):
        while len(celda.paragraphs) > idx + 1 and not celda.paragraphs[-1].text.strip():
            celda.paragraphs[-1]._element.getparent().remove(celda.paragraphs[-1]._element)
        p = celda.paragraphs[idx]
        p.paragraph_format.space_before = Pt(0)
        p.paragraph_format.space_after = Pt(0)
        p.paragraph_format.keep_with_next = False
        p.paragraph_format.keep_together = False
        p.paragraph_format.page_break_before = False
        ref = p.runs[0] if p.runs else None
        for run in p.runs: run.text = ''
        r = p.runs[0] if p.runs else p.add_run()
        r.text = texto; r.bold = False
        if ref and ref.font.size: r.font.size = ref.font.size
        if ref and ref.font.name: r.font.name = ref.font.name
- Contenido narrativo → doc.tables[3] (sin cambiar alineación ni fuente de plantilla):
    fila 3 p0: motivo; fila 5 p0: diagnóstico; fila 8/10 p1: fortalezas y necesidades;
    fila 12 p0: trabajo colaborativo; fila 14 p0: apoyos hogar; fila 16 p1+: acuerdos.
  Estudiante → doc.tables[1]: fila 3 nombre+RUT; fila 5 nombre social+fecha; fila 6 edad/curso/establecimiento.
  Profesional → doc.tables[2]: fila 3 nombre+RUT; fila 5 nombre social+rol; fila 6 tel/email/fecha.
  Receptor → doc.tables[2]: fila 10 nombre+RUT; fila 12 nombre social+teléfono.
  Si el .docx base ya trae identificación rellena (modo híbrido PIE360), NO toques tablas 1 ni 2.
  El RUT del profesional NUNCA va en Rol/cargo. Si falta RUT estudiante: 'No informado' en fila 3 celda 3.
r   r   r%   r&   _build_familia_tabla_rulesr      s    (	w*r%   c                x   0 n/ nU(       am  U HY  n[        USS5      =(       d    SnU(       d  M"  UR                  U5        [        USS5      nU(       d  MI  [        U 5      U-  X6'   M[     [        X5      u  pO6[	        U=(       d    / 5      n[        U5      u  pU H  n
[        5       X:'   M     [        XCS9nXX4$ )zP(base_file, kind, filtered_names, disk_paths) inspeccionando disco si hay filas.rC   N rA   )
file_paths)getattrr   r   r   listr   r   r   )rz   available_filesselected_rowspathsnamesrr   rU   fid	base_filetemplate_kindrow_idfiltereds               r&   _familia_template_stater     s      EE C35;DLL#tT*Cs'1C7 ! $Fh#^ 	=_*+#=e#D 	F FEM  2%JHX44r%   r   r   familia_base_doc_namec                   Ub  Uc  [        U 5      u  pU(       a  SOSnSU-   S-   nU(       d  U[        5       -  nU(       a  SU S3nO,US:X  a  U(       a  [        U5      nOUS:X  a  [        5       nOS	nS
nXV-   U-   $ )Nu  - Formato Word narrativo (informe familia): texto JUSTIFICADO (w:jc both / WD_ALIGN_PARAGRAPH.JUSTIFY) en doc.tables[3]. Un w:p por bloque; PROHIBIDO w:br dentro del mismo párrafo (estira líneas cortas con espacios enormes). Solo encabezados de sección (fondo naranja) en negrita.
u  - Formato Word: conserva la plantilla tal cual (misma fuente, tamaño y alineación). PROHIBIDO forzar texto justificado. Solo los encabezados de sección (fondo naranja, mayúsculas) van en negrita. Las etiquetas de campo y los valores completados NO deben ir en negrita.
u  === REGLAS DE LA PLATAFORMA (no reemplazan ni acortan el rol) ===
- Responde en español.
- Usa el code interpreter con los archivos listados abajo.
- Genera UN solo archivo .docx por solicitud, solo para el estudiante o caso pedido.
- En tu razonamiento interno, narra el trabajo como un proceso paso a paso (archivos que abres, contrastes, plan del documento, maquetación Word, revisión visual de tablas/saltos de página y exportación final).
- En el mensaje al usuario (chat): confirma brevemente qué generaste y el nombre del archivo.
- En el archivo Word: aplica el ROL DEL AGENTE completo; revisa maquetación antes de dar por finalizado.
uV  - No uses markdown (**texto**) dentro del Word ni conviertas etiquetas a negrita.
- Espaciado uniforme en Word: dentro de una misma celda usa w:p distintos por bloque (no w:br). No dejes párrafos vacíos entre bloques.
- Si usas python-docx: reutiliza párrafos existentes de la plantilla; no insertes párrafos nuevos con spacing distinto.
u   - Modo híbrido activo: «u/  » ya trae identificación desde PIE360.
  PROHIBIDO abrir otra plantilla, copiar family_report.docx de cero o rellenar tablas 1 y 2.
  PROHIBIDO modificar doc.tables[0], doc.tables[1], doc.tables[2] y doc.tables[4].
  Redacta SOLO doc.tables[3] desde INSTRUMENTOS APLICADOS hacia abajo, según el rol.
formtablaz- Para informe a la familia: usa la plantilla de familia disponible en los archivos (prioriza plantilla tipo formulario con campos si existe).
u   - Si falta un antecedente que el rol exige, indícalo con la frase o criterio que el rol define.
- No incluyas enlaces sandbox:, rutas /mnt/data/ ni URLs de descarga en el chat.
- NUNCA pegues código Python ni logs del intérprete en el chat.)r   r   r   r   )r   r   r   r   format_wordcommonfamiliatails           r&   _build_platform_rulesr     s     M1#=o#N 	 !		E4 	v 		?	? " !688()>(? @f f 	 
&	 Y*95	'	!,.K 		L 	
 d""r%   c           	        [        U R                  =(       d    S5      R                  5       nU(       d,  [        U R                  =(       d    S5      R                  5       nSnU/nU(       a  UR	                  SU 35        U(       a  UR	                  [        U5      5        [        U=(       d    / 5      n[        U R                  X5      u  ppU
S:X  a|  U	(       au  U Vs/ s HG  n[        XR                  U5      5      (       d  M$  [        XR                  U5      5      (       a  ME  UPMI     nnU(       d  UR	                  [        X5      5        U(       d  U(       aI  U(       a	  U(       a  UOUnU(       a0  SR                  S US S  5       5      nUR	                  SU S	35        U(       a"  UR	                  [        U[        U5      S
95        UR	                  [!        UU	U
US95        SR                  U5      $ s  snf )Nr   u  === INSTRUCCIÓN SUPREMA ===
El ROL DEL AGENTE (bloque siguiente) es la norma obligatoria y tiene prioridad absoluta sobre cualquier otra indicación. Debes seguirlo tal cual: estructura, extensión, formato ministerial, cartilla técnica, flujos de trabajo, redacción, secciones, tablas, estilo institucional y criterios de completitud que allí se exigen.
No resumas el informe Word, no omitas apartados del rol y no sustituyas el formato oficial por un texto corrido. Si el rol exige desarrollo analítico extenso, cumple eso en cada sección aplicable.
Antes de entregar, verifica mentalmente que el .docx cumple cada exigencia del rol.z%=== ROL DEL AGENTE (OBLIGATORIO) ===
r   
c              3  ,   #    U  H
  nS U 3v   M     g7f)z- Nr   ).0rU   s     r&   	<genexpr>&_build_instructions.<locals>.<genexpr>  s     K8J"TF8Js   2   z(=== ARCHIVOS EN EL CODE INTERPRETER ===
u   
OBLIGATORIO: usa estos archivos del contenedor. Si el informe psicopedagógico aparece en la lista, está disponible — no indiques que falta.)narrative_onlyr   

)r   role_instructionsstripr   r   r   r   r   rA   r   getr   r   joinr   boolr   )rg   r   student_contextr   r   	role_textrole_supremacyparts
file_namesr   r   filtered_namesr   nexcludedlisting_nameslistings                    r&   _build_instructionsr   b  s    *%*A*A*GRHNNPIu66<"=CCE		^  ''E=i[IJ=>STUo+,J6M*73In 9  
$Q		!5  )IIaL9  	 
 %LL<YQR&;

P^iiKcr8JKKGLL;) SS (#$9:	
 
LL'"7		
 ;;uE
s   #G<G<'G<c                    U R                   (       a)  [        U R                  5      (       d  SU R                   S.$ SSUSS.S.$ )Ncode_interpreter)type	containerauto4g)r   rh   memory_limit)re   r.   rf   )rg   rh   s     r&   _build_code_interpreter_toolr     sO      )=e>_>_)`)`&22
 	

 #  
 r%   c                h    [        U SS 5      nUb  [        USS 5      nU(       a  U$ [        U SS 5      $ )Nitemrb   r   )eventr   rb   s      r&   _container_id_from_stream_eventr     s<    5&$'Dt^T:5.$//r%   early_savedr   r   c          	        [        X!5      nU(       a4  Xql        [        5       Ul        [        5       Ul        U R                  5         [        USS 5      =(       d    SR                  5       nU(       d  Sn/ n	S n
U(       ae   SSKJ	n  U" U UR                  UUUUS9n	U	(       aB  U(       a;  SSKJn  SSKJn  U(       a  U" UR                  U5      OS nU" UR                  U	UUS	9n	SSKJnJnJn  U" U5      nU" U5      nU(       a  U	(       d  U
(       d  SU S3n
O	U	(       a  S n
U" X5      n[+        U5      (       aQ  U	(       a  SR-                  S U	 5       5      nSU S3nOPU
(       a  U
nOFU" U5      nU" U5      nU(       a  SU S3nO(SnO%U	(       a  SR-                  S U	 5       5      nSU S3nUUR                  [/        U5      [0        R2                  U	U
S.$ ! [         a#  n[         R#                  S
U5        Sn
 S nAGNS nAff = f)Noutput_textr   z>No pude generar una respuesta. Intenta reformular la pregunta.r   ) persist_code_interpreter_outputs)r   postprocess_saved_familia_docxresolve_familia_template_pathform_template_pathz0No se pudieron guardar archivos de respuesta: %szmNo se pudo guardar el archivo generado en el servidor. Vuelve a pedir el informe o contacta al administrador.)best_mentioned_filenameextract_mentioned_filenamessanitize_reply_sandbox_linkszNo se pudo guardar zB en el servidor. Vuelve a pedir al agente que genere el documento.z, c              3  *   #    U  H	  oS    v   M     g7frU   Nr   r   r   s     r&   r   ,_finalize_openai_response.<locals>.<genexpr>  s     F~t6l~   u   Listo. Generé el documento: uA   . Usa el botón «Descargar» que aparece debajo de este mensaje.u   Generé el archivo zC, pero no pude guardarlo en el servidor. Vuelve a pedir el informe.uW   Generé el documento, pero no pude guardarlo en el servidor. Vuelve a pedir el informe.c              3  *   #    U  H	  oS    v   M     g7fr   r   r   s     r&   r   r   $  s     B>4v,>r   u5   . Usa el botón «Descargar» debajo de este mensaje.)replycontainerIdopenaiFilesUsedmodelresponseFilesresponseFilesWarning)r   re   r*   rf   r-   ro   r   r   r   r   rA   'app.backend.utils.agent_familia_prefillr   (app.backend.utils.agent_familia_templater   rN   r\   r]   r   r   r   _is_code_interpreter_dumpr   lenr	   openai_agent_model)rq   rg   r   rh   r   r   r   rb   r   response_filesresponse_files_warningr   r   r   	form_pathrQ   r   r   r   	mentionedbest_mentionedr   	best_names                          r&   _finalize_openai_responser     s2    )9L$0!,3I)"9

X}d39r@@BEP+-N)-	j='N /bb % 2%((MJ 
 "@HH"#'0	"  ,E2I,Y7Nn5K!.!1 2@ @ 	 
!%(?E ''IIF~FFE/w 7R R  $*E3E:I/	:I)) 51 1 1  
		B>BB+E7 3B B 	 00x=,,' 6 k  	NNMsSI #	s    A$G 
H%HHu   Conectando con el modelo…u   Analizando tu solicitud…u
   En cola…u'   Preparando el intérprete de código…u   Ejecutando comando (Python)…u#   Código listo, aplicando cambios…zComando completado.u   Redactando respuesta…u   Bloque de respuesta listo…u   Texto final listo…u   Escribiendo respuesta…u   Respuesta escrita…u    Trabajo del modelo finalizado…)zresponse.createdzresponse.in_progresszresponse.queued*response.code_interpreter_call.in_progressz+response.code_interpreter_call.interpretingz(response.code_interpreter_call.code_done(response.code_interpreter_call.completedzresponse.output_item.addedzresponse.output_item.donezresponse.output_text.donezresponse.content_part.addedzresponse.content_part.donezresponse.completedzdict[str, str]_STREAM_STEP_LABELS>      Elaborando el informe…   Razonamiento completado…   Organizando el análisis…    Redacción interna completada…#   Razonando sobre los antecedentes…1   Elaborando el informe con los datos analizados…u%   Preparando el documento Word final…c                    [        U SS 5      =(       d    SnUS;   a*  [        U SS 5      =(       d    [        U SS 5      =(       d    S$ g)Nr   r   )z%response.reasoning_summary_text.deltazresponse.reasoning_text.deltadeltatextr   r   etypes     r&   _extract_reasoning_deltar   R  sJ    E64(.BE   ugt,Rvt0LRPRRr%   Ffinalc               &   / nU nSU;   aL  UR                  SS5      u  pCUR                  5       n[        U5      S:  a  UR                  U5        SU;   a  ML  U(       a2  UR                  5       n[        U5      S:  a  UR                  U5        SnX#4$ )u3   Divide el razonamiento en párrafos estilo ChatGPT.r         r   )rM   r   r   r   )bufferr  
paragraphs	remainingheadr   s         r&   _flush_thinking_paragraphsr
  \  s     JI
I
#//&!4zz|t9?d#	 I

  t9?d#	  r%   c                V    [        U SS 5      =(       d    SnU[        ;   a	  [        U   $ g )Nr   r   )r   r   r   s     r&   _step_from_stream_eventr  q  s,    E64(.BE##"5))r%   c                    [        U SS5      =(       d    SnUS;   a*  [        U SS5      =(       d    [        U SS5      =(       d    S$ g)uH   Solo texto final del asistente; nunca logs/código del code interpreter.r   Nr   )zresponse.output_text.deltazresponse.text.deltar   r   r   r   s     r&   _extract_text_deltar  x  sD    E64(.BEEEugt,Rvt0LRPRRr%   c                j   ^  T (       a  [        T 5      S:  a  gSn[        U 4S jU 5       5      nUS:  $ )NP   F)zimport zdef zsubprocess.z	doc.save(z	for p in zPt(12)zqn('w:zcapture_output=Truec              3  6   >#    U  H  oT;   d  M
  S v   M     g7f)r  Nr   )r   markerr   s     r&   r   ,_is_code_interpreter_dump.<locals>.<genexpr>  s     9wVD.qqws   		   )r   sum)r   markershitss   `  r&   r   r     s6    3t9r>	G 9w99D19r%   c              #    ^'^(#    [        5       n[        X5      /n	U=(       d    [        XR                  5      n
[	        5       m(/ nUR
                  nSnSm'SU'U(4S jjnS U'4S jjnU" S[        R                   S35      nU(       a  Uv   [        X5        UR                  R                  [        R                  [        UU
UUUS9UU	S9 nU GH  n[        US	S
5      =(       d    Sn[        U5      nU(       a  U" U5      nU(       a  Uv   [        U5      nU(       a-  UU-  nSUS.v   [        U5      u  nnU H  nU" U5      v   M     US;   a   [        USS9u  nnU H  nU" U5      v   M     US:X  a  U" [         5      nU(       a  Uv   [#        U5      =(       d    UnU(       a  UnU(       d  SSKJn  U" U UR                  UU5      nU(       aB  U(       a;  SSKJn  SSKJn  U(       a  U" UR                  U5      OS
n U" UR                  UUU S9nU(       a  UnU" SUS   S    35      n!U!(       a  U!v   US:X  a  [#        U5      nU(       a  Un[1        U5      n"U"(       d  GM  SU"S.v   GM     U" S5      n#U#(       a  U#v   UR3                  5       n$S
S
S
5        U" S5      n%U%(       a  U%v   [5        U UW$UU=(       d    S
UUS9n&SU&S.v   g
! , (       d  f       NA= f7f)!zJGenera eventos {type: step|text_delta} y al final {type: done, data: ...}.r   Fc                b   > U [         ;   a  T(       a  g U T;   a  g TR                  U 5        SU S.$ )Nstepr   message)_GENERIC_REASONING_STEPSadd)labelhas_thinking_steps
seen_stepss    r&   	emit_step4stream_chat_with_openai_responses.<locals>.emit_step  s4    ,,1CJu511r%   c                   > SmSU S.$ )NTthinking_stepr  r   )r   r   s    r&   emit_thinking_step=stream_chat_with_openai_responses.<locals>.emit_thinking_step  s    !'D99r%   zConectando con u   …r   r   r   instructionsinputtoolsr   Nthinking_delta)r   r   )z$response.reasoning_summary_text.donezresponse.reasoning_text.doneTr  r   r   )try_capture_from_containerr   r   r   zArchivo guardado: rU   r   
text_deltau$   Consolidando respuesta del modelo…u+   Guardando archivos generados, si los hay…r   done)r   data)r  rO   returndict[str, Any] | None)r   rO   r2  dict[str, Any])r7   r   r   rA   setre   r	   r   ri   	responsesstreamr   r   r  r   r
  _POST_INTERPRETER_STEPr   r   r.  r   r   r   r   r  get_final_responser   ))rq   rg   r  rh   instruction_file_namesr   r   r   rD   r,  r   r   stream_container_idthinking_bufferr"  r&  
first_stepr7  r   r   
step_label
step_eventreasoning_deltanew_paragraphs	paragraphfinal_paragraphs	post_steprb   r.  capturedr   r   r   
save_eventr   consolidatingr   	save_stepresultr   r!  s)                                          @@r&   !stream_chat_with_openai_responsesrJ    s!      F)%:;E'S+Eb((+SJ5J(*K&+&?&?O2 2:
 _X-H-H,IMNJ$U5				 	 ))('"7
  
! 
 
EE6406BE07J&z2
$$6u=O?2//JJ2L_2]/!/I,Y77 "0    5O#51 / "2I,Y77 "2 BB%&<=	#O>uE\I\*6'&p#=!HH($	$ $ $1 !>ehh V%) &
 (F % ( /3<	(H $*2K)2"4Xa[5H4I J*J  *&0 0DD>uE*6''.Eu+e<<] ` ""HI,,.
B GHI&
'4'#F 6
**[
 
s%   CK&FK+/K;K&
K#K&c                   [        5       n[        X5      /n	U=(       d    [        XR                  5      n
[	        X5        UR
                  R                  [        R                  [        UU
UUUS9UU	S9n[        U UUUUUS9$ )Nr(  r)  )r   r   )r7   r   r   rA   ri   r6  r@   r	   r   r   r   )rq   rg   r  rh   r   r   r:  r   rD   r,  r   r   s               r&   chat_with_openai_responsesrL  (  s      F)%:;E'S+Eb((+SJ$U5&&))('"7
  ' H %
'# r%   )r2  r   )r-   zdatetime | Noner2  r   )rB   bytesrC   rO   r2  rO   r(   )rW   r   rC   
str | Noner2  rO   )r^   rN  r2  None)rb   rO   r^   rO   r2  rO  )rg   r   rh   	list[str]r2  rO  )rg   r   r2  rO  )
rq   r   rg   r   rr   r
   rs   r   r2  rN  )rq   r   rz   rO   ru   zlist[AgentFileModel] | Noner2  rP  )r   r   rg   zAgentModel | Noner2  rN  )rq   r   rz   rO   r2  rP  )r2  rO   )rz   rO   r   list[str] | Noner   list[Any] | Noner2  z2tuple[str | None, str, list[str], dict[str, Path]])
r   rQ  r   rN  r   rN  r   rN  r2  rO   )NNNN)rg   r   r   rQ  r   r3  r   rR  r   rN  r2  rO   )rg   r   rh   rP  r2  r4  )r   r   r2  rN  )rq   r   rg   r   r   r   rh   rP  r   zlist[dict[str, Any]] | Noner   r3  r   rR  r2  r4  )r   r   r2  rO   )r  rO   r  r   r2  ztuple[list[str], str])r   rO   r2  r   )rq   r   rg   r   r  rO   rh   rP  r:  rQ  r   r3  r   rR  r   rN  )rq   r   rg   r   r  rO   rh   rP  r   r3  r   rR  r:  rQ  r   rN  r2  r4  )Ir#   
__future__r   loggingr   r   pathlibr   typingr   sqlalchemy.ormr   app.backend.core.configr	   app.backend.db.modelsr
   r   &app.backend.utils.agent_document_indexr   r   r   r   r   r   r   r   r   r   r   r   &app.backend.utils.agent_student_lookupr   app.backend.utils.agent_filesr   	getLoggerr   r\   r,   r5   r   r*   r.   r7   rG   rR   rY   r_   rc   ri   rk   rt   r   r   r   r   r   r   r   r   r   r   r   __annotations__	frozensetr  r8  r   r
  r  r  r   rJ  rL  r   r%   r&   <module>r`     s   F "  (   " , < X
 
 
 P 3			8	$"%. .23	3RB
$-
""" 
" 	"
 "R .2	 +	
 <.+\55%5 $5 8	5< )-A# ! $(,A#%A# A# 	A#
 &A# 	A#L )--1&*(,EE%E +E $	E
 &E 	EP 0 04-1&*nnn n 	n -n +n $n nd 68#2[3S0U0E";!?!7#="8<' ^   %	  A  !! ! 	!*, 04-1&*(,T+T+T+ T+ 	T+
 -T+ +T+ $T+ &T+x .2&*/3(,$$$ $ 	$
 +$ $$ -$ &$ $r%   