
    si?                          d Z ddlZddlmc mZ ddlZddlZddl	Z
ddlZ
ddlZ
d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 Zd Zd Zd ZdS )zR
Sprint 12 Tests: settings panel, session pinning, session import, SSE reconnect.
    Nzhttp://127.0.0.1:8788c                     t           j                            t          | z   d          5 }t	          j        |                                          |j        fcd d d            S # 1 swxY w Y   d S )N
   timeout)urllibrequesturlopenBASEjsonloadsreadstatus)pathrs     0/home/ubuntu/hermes-webui/tests/test_sprint12.pygetr   	   s    			tR		8	8 .Az!&&((##QX-. . . . . . . . . . . . . . . . . .s   -A$$A(+A(c                    t          j        |pi                                           }t          j                            t          | z   |ddi          }	 t          j                            |d          5 }t          j        |	                                          |j
        fcd d d            S # 1 swxY w Y   d S # t          j        j        $ r7}t          j        |	                                          |j        fcY d }~S d }~ww xY w)NzContent-Typezapplication/json)dataheadersr   r   )r   dumpsencoder   r   Requestr
   r	   r   r   r   error	HTTPErrorcode)r   bodyr   reqr   es         r   postr      s?   :djb!!((**D
.
 
 4)79K(L ! N NC,^##C#44 	2:affhh''1	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2<! , , ,z!&&((##QV+++++++,sB   !B> 7-B1$B> 1B55B> 8B59B> >D	,D>D	D	c                 r    t          di           \  }}|d         d         }|                     |           |S )Nz/api/session/newsession
session_id)r   append)created_listd_sids       r   make_sessionr(      s=    "B''DAq
I,|
$CJ    c                      t          d          \  } }d}||k    }|st          j        d|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          dz  }dd|iz  }t          t          j        |                    d	x}}d
}|| v }|st          j        d|fd|| f          t          j        |          dt          j                    v st          j        |           rt          j        |           nddz  }dd|iz  }t          t          j        |                    d	x}}d}|| v }|st          j        d|fd|| f          t          j        |          dt          j                    v st          j        |           rt          j        |           nddz  }dd|iz  }t          t          j        |                    d	x}}d	S )z+GET /api/settings returns default settings./api/settings   ==z%(py0)s == %(py3)sr   py0py3assert %(py5)spy5Ndefault_modelinz%(py1)s in %(py3)sr%   py1r2   default_workspace)	r   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanation)r%   r   @py_assert2@py_assert1@py_format4@py_format6@py_assert0s          r   "test_settings_get_returns_defaultsrI   "   sa   O$$IAv6S=6S66S?a?a?aa#!##########!################!#####!#############################r)   c                     t          dddd          \  } }d}||k    }|st          j        d|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          d	z  }d
d|iz  }t          t          j        |                    dx}}| d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j        |	                    dx}x}}| d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j        |	                    dx}x}}t          d          \  }
}|
d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j        |	                    dx}x}}|
d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j        |	                    dx}x}}t          dddd           dS )z-POST /api/settings saves general UI settings.r+   z
ctrl+enternord)send_keythemer,   r-   r/   r   r0   r3   r4   NrL   z%(py1)s == %(py4)sr:   py4assert %(py6)spy6rM   enterdark)
r   r<   r=   r>   r?   r@   rA   rB   rC   r   )r%   r   rD   rE   rF   rG   rH   @py_assert3@py_format5@py_format7d2r&   s               r   ,test_settings_post_persists_general_settingsrY   )   s   _<&&Q&QRRIAv6S=6S66SZ=(L(=L((((((((((=L(((((=((((L(((((((((((((((((((((((((((W::::  EBj>)\)>\))))))))))>\)))))>))))\)))))))))))))))))))))))))))g; & ;&          ;&     ;    &                           w@@AAAAAr)   c                  ~   t          d          \  } }| d         }t          dddi          \  }}d}||k    }|st          j        d|fd||f          dt	          j                    v st          j        |          rt          j        |          ndt          j        |          d	z  }d
d|iz  }t          t          j	        |                    dx}}|d         }	|	|k    }|st          j        d|fd|	|f          t          j        |	          dt	          j                    v st          j        |          rt          j        |          nddz  }d
d|iz  }t          t          j	        |                    dx}	}t          d          \  }
}|
d         }	|	|k    }|st          j        d|fd|	|f          t          j        |	          dt	          j                    v st          j        |          rt          j        |          nddz  }d
d|iz  }t          t          j	        |                    dx}	}dS )zLdefault_model in /api/settings mirrors config.yaml and ignores stale writes.z/api/modelsr5   r+   ztest/model-123r,   r-   r/   r   r0   r3   r4   Nz%(py1)s == %(py3)sexpected_modelr9   )
r   r   r<   r=   r>   r?   r@   rA   rB   rC   )modelsr&   r\   r%   r   rD   rE   rF   rG   rH   rX   s              r   (test_settings_default_model_is_read_onlyr^   6   s   M""IFAO,N_8H&IJJIAv6S=6S66S_///////////////////////////////////////////////////////////  EBo0.0000000000.0000000000000000.00000.00000000000000000000000000000r)   c                  f   t          d          \  } }| d         }| d         }t          dddi           t          d          \  }}|d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }d	d
|iz  }	t          t          j        |	                    dx}x}}|d         }||k    }|st          j        d|fd||f          t          j        |          dt          j                    v st          j	        |          rt          j        |          nddz  }
dd|
iz  }t          t          j        |                    dx}}|d         }||k    }|st          j        d|fd||f          t          j        |          dt          j                    v st          j	        |          rt          j        |          nddz  }
dd|
iz  }t          t          j        |                    dx}}t          dddi           dS )zBPOST /api/settings with partial data doesn't clobber other fields.r+   r;   r5   show_cli_sessionsTisz%(py1)s is %(py4)srO   rQ   rR   Nr-   r[   original_wsr9   r3   r4   original_modelF)
r   r   r<   r=   rA   rB   rC   r>   r?   r@   )d1r&   rd   re   rX   rH   rU   rD   rV   rW   rF   rG   s               r   test_settings_partial_updaterg   @   s     EB()K(N.5666  EB!"*d*"d**********"d*****"****d***************************!"1"k1111111111"k11111"11111111111k11111k111111111111111111111111111o0.0000000000.0000000000000000.00000.000000000000000000000000000.677777r)   c                     t          j        d                              d          } d}|| v }|st          j        d|fd|| f          t          j        |          dt          j                    v st          j        |           rt          j        |           nddz  }d	d
|iz  }t          t          j
        |                    dx}}d}|| v }|st          j        d|fd|| f          t          j        |          dt          j                    v st          j        |           rt          j        |           nddz  }d	d
|iz  }t          t          j
        |                    dx}}dS )z@Agent settings explain that sidebar model selection is per-chat.static/index.htmlutf-8encodingzAApplies to this chat. Profile defaults live in Settings -> Agent.r6   r8   htmlr9   r3   r4   Nz_These are profile defaults. The model picker in the left sidebar only changes the current chat.pathlibPath	read_textr<   r=   rA   r>   r?   r@   rB   rC   )rm   rH   rD   rF   rG   s        r   6test_agent_settings_copy_clarifies_sidebar_vs_defaultsrr   M   s   <+,,666HHDNVNRVVVVVVVVVVVNRVVVVVVNVVVVVVVVVVVRVVVVVVRVVVVVVVVVVVVVVVVVVVVVVVVVVVVltlptttttttttttlpttttttltttttttttttpttttttpttttttttttttttttttttttttttttttr)   c                  J   t          j        d                              d          } t          j        d                              d          }d}|| v }|st          j        d|fd|| f          t          j        |          dt          j                    v st          j        |           rt          j        |           ndd	z  }d
d|iz  }t          t          j
        |                    dx}}d}|| v }|st          j        d|fd|| f          t          j        |          dt          j                    v st          j        |           rt          j        |           ndd	z  }d
d|iz  }t          t          j
        |                    dx}}d}|| v }|st          j        d|fd|| f          t          j        |          dt          j                    v st          j        |           rt          j        |           ndd	z  }d
d|iz  }t          t          j
        |                    dx}}d}|| v }|st          j        d|fd|| f          t          j        |          dt          j                    v st          j        |           rt          j        |           ndd	z  }d
d|iz  }t          t          j
        |                    dx}}d}||v }|st          j        d|fd||f          t          j        |          dt          j                    v st          j        |          rt          j        |          ndd	z  }d
d|iz  }t          t          j
        |                    dx}}d}||v }|st          j        d|fd||f          t          j        |          dt          j                    v st          j        |          rt          j        |          ndd	z  }d
d|iz  }t          t          j
        |                    dx}}dS )zNBase URL and toolsets live behind an Advanced toggle with plain-language help.ri   rj   rk   zstatic/panels.jszid="agentConfigAdvancedToggle"r6   r8   rm   r9   r3   r4   Nz3id="agentConfigAdvancedFields" style="display:none"zCustom API Base URLz$Most users should leave these as-is.z&function toggleAgentAdvancedSettings()jsz+function setAgentAdvancedSettingsOpen(open)rn   )rm   rt   rH   rD   rF   rG   s         r   6test_agent_settings_hide_advanced_fields_behind_toggleru   S   s   <+,,666HHD	(	)	)	3	3W	3	E	EB+3+t3333333333+t33333+33333333333t33333t333333333333333333333333333@H@DHHHHHHHHHH@DHHHHH@HHHHHHHHHHHDHHHHHDHHHHHHHHHHHHHHHHHHHHHHHHHHH ( D(((((((((( D((((( (((((((((((D(((((D(((((((((((((((((((((((((((191T99999999991T99999199999999999T99999T999999999999999999999999999393r99999999993r99999399999999999r99999r9999999999999999999999999998>8B>>>>>>>>>>8B>>>>>8>>>>>>>>>>>B>>>>>B>>>>>>>>>>>>>>>>>>>>>>>>>>>>>r)   c                     g } 	 t          |           }t          d|dd          \  }}d}||k    }|st          j        d|fd||f          dt	          j                    v st          j        |          rt          j        |          ndt          j        |          dz  }d	d
|iz  }t          t          j	        |                    dx}}|d         }d}	||	u }|slt          j        d|fd||	f          t          j        |          t          j        |	          dz  }
dd|
iz  }t          t          j	        |                    dx}x}}	|d         d         }d}	||	u }|slt          j        d|fd||	f          t          j        |          t          j        |	          dz  }
dd|
iz  }t          t          j	        |                    dx}x}}	| D ]}t          dd|i           dS # | D ]}t          dd|i           w xY w)z'POST /api/session/pin sets pinned=true./api/session/pinTr"   pinnedr,   r-   r/   r   r0   r3   r4   Nokra   rc   rO   rQ   rR   r!   ry   /api/session/deleter"   
r(   r   r<   r=   r>   r?   r@   rA   rB   rC   createdr'   r%   r   rD   rE   rF   rG   rH   rU   rV   rW   s               r   test_pin_sessionr   a   s   G=7##+C4-P-PQQ	6v}vvvw$w$w$w$|H%--%----------%-----%------------------------------- 	= 	=C&s(;<<<<	= 	=7 	= 	=C&s(;<<<<	=s   GG1 1H
c                  <   g } 	 t          |           }t          d|dd           t          d|dd          \  }}d}||k    }|st          j        d|fd||f          dt	          j                    v st          j        |          rt          j        |          ndt          j        |          d	z  }d
d|iz  }t          t          j	        |                    dx}}|d         d         }d}	||	u }|slt          j        d|fd||	f          t          j        |          t          j        |	          dz  }
dd|
iz  }t          t          j	        |                    dx}x}}	| D ]}t          dd|i           dS # | D ]}t          dd|i           w xY w)z/POST /api/session/pin with pinned=false unpins.rw   Trx   Fr,   r-   r/   r   r0   r3   r4   Nr!   ry   ra   rc   rO   rQ   rR   r{   r"   r|   r}   s               r   test_unpin_sessionr   n   s   G=7##t!D!DEEE+C5-Q-QRR	6v}vvv|H%..%..........%.....%............................... 	= 	=C&s(;<<<<	= 	=7 	= 	=C&s(;<<<<	=s   E%F Fc                  \   g } 	 t          |           t          ddd           t          ddd           t          d          \  }}fd|d	         D             }t          |          }d
}||k    }|st	          j        d|fd||f          dt          j                    v st	          j        t                    rt	          j	        t                    nddt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          dz  }dd|iz  }t          t	          j        |                    dx}x}}|d         d         }	d}
|	|
u }|slt	          j        d|fd|	|
f          t	          j	        |	          t	          j	        |
          dz  }dd|iz  }t          t	          j        |                    dx}	x}}
| D ]t          ddi           dS # | D ]t          ddi           w xY w)z5Pinned sessions include pinned field in session list.z/api/session/renamezPinned Test)r"   titlerw   Trx   z/api/sessionsc                 ,    g | ]}|d          k    |S )r"    ).0sr'   s     r   
<listcomp>z/test_pinned_in_session_list.<locals>.<listcomp>   s'    DDDqQ|_-C-C-C-C-Cr)   sessions   r-   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenmatch)r1   r:   r2   rR   zassert %(py8)spy8Nr   ry   ra   rc   rO   rQ   rR   r{   r"   )r(   r   r   r   r<   r=   r>   r?   r@   rA   rB   rC   )r~   r%   r&   r   rD   @py_assert5@py_assert4rW   @py_format9rH   rU   rV   r'   s               @r   test_pinned_in_session_listr   {   s   G=7##"3$O$OPPPt!D!DEEE?##1DDDDAjMDDD5zzQzQzQss55zQQx!)T)!T))))))))))!T)))))!))))T))))))))))))))))))))))))))) 	= 	=C&s(;<<<<	= 	=7 	= 	=C&s(;<<<<	=s   G4H H+c                     g } 	 t          |           }t          d|dd           t          d|           \  }}|d         d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          d	z  }d
d|iz  }t          t          j        |                    dx}x}}| D ]}t          dd|i           dS # | D ]}t          dd|i           w xY w)z-Pin status survives session reload from disk.rw   Trx   /api/session?session_id=r!   ry   ra   rc   rO   rQ   rR   Nr{   r"   )r(   r   r   r<   r=   rA   rB   rC   )	r~   r'   r%   r&   rH   rU   rD   rV   rW   s	            r   test_pinned_persists_on_reloadr      s[   G=7##t!D!DEEE3c33441|H%--%----------%-----%------------------------------- 	= 	=C&s(;<<<<	= 	=7 	= 	=C&s(;<<<<	=s   B?C C5c                  D   dddddddgdd} t          d	|           \  }}d
}||k    }|st          j        d|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          dz  }dd|iz  }t          t          j        |                    dx}}|d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }	dd|	iz  }
t          t          j        |
                    dx}x}}|d         d         }	 |d         d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }	dd|	iz  }
t          t          j        |
                    dx}x}}|d         d         }t          |          }d}||k    }|st          j        d|fd||f          d t          j                    v st          j        t                    rt          j        t                    nd t          j        |          t          j        |          t          j        |          d!z  }d"d#|iz  }t          t          j        |                    dx}x}x}}t          d$|           \  }}|d         d%         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }	dd|	iz  }
t          t          j        |
                    dx}x}}t          d&d|i           dS # t          d&d|i           w xY w)'z9POST /api/session/import creates a new session from JSON.zImported TestuserzHello from importrolecontent	assistantz	Hi there!ztest/import-model)r   messagesmodel/api/session/importr,   r-   r/   r   r0   r3   r4   Nrz   Tra   rc   rO   rQ   rR   r!   r"   r   rN   r      )z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py7)sr   )r1   py2rP   py7zassert %(py9)spy9r   r   r{   )r   r<   r=   r>   r?   r@   rA   rB   rC   r   r   )payloadr%   r   rD   rE   rF   rG   rH   rU   rV   rW   r'   @py_assert6r   @py_format8@py_format10rX   r&   s                     r   test_import_session_basicr      s|    !(;<< [99
 % G *G44IAv6S=6S66ST7d7d?7d7d
I,|
$C9|G$77$7777777777$77777$7777777777777777777777777777777Y<
+1s+,,11,1111111111,111111111111s11111s111111+1111,1111111111111111111111111111111114s4455A)}W%<)<<%)<<<<<<<<<<<%)<<<<<<%<<<<)<<<<<<<<<<<<<<<<<<<<<<<<<<<<"\3$788888"\3$78888s   HN Nc                  z   t          dddi          \  } }d}||k    }|st          j        d|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          dz  }d	d
|iz  }t          t          j        |                    dx}}dS )z&Import fails without a messages array.r   r   zNo messagesi  r-   r/   r   r0   r3   r4   N	r   r<   r=   r>   r?   r@   rA   rB   rC   )r%   r   rD   rE   rF   rG   s         r   test_import_requires_messagesr      s    *Wm,DEEIAv6S=6S66Sr)   c                     dddddgd} t          d|           \  }}|d         d	         }	 d}||k    }|st          j        d
|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          dz  }dd|iz  }t          t          j        |                    dx}}t          dd	|i           dS # t          dd	|i           w xY w)zIImported session gets a new session_id, not reusing any from the payload.should_be_ignoredzID Testr   testr   )r"   r   r   r   r!   r"   )!=)z%(py0)s != %(py3)sr'   r0   r3   r4   Nr{   r   )r   r%   r&   r'   rD   rE   rF   rG   s           r   test_import_creates_new_idr      sJ    *$889 G
 %w//DAq
I,|
$C9))s)))))))))))s)))))))))))))s)))))s))))))))))))))))))))))))))))))))"\3$788888"\3$78888s   B%C& &C:c                     ddddgdd} t          d|           \  }}|d         d	         }	 t          d
|           \  }}|d         d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j        |	                    dx}x}}t          dd	|i           dS # t          dd	|i           w xY w)zImported session can be pinned.zPinned Importr   r   r   T)r   r   ry   r   r!   r"   r   ry   ra   rc   rO   rQ   rR   Nr{   )r   r   r<   r=   rA   rB   rC   )
r   r%   r&   r'   rX   rH   rU   rD   rV   rW   s
             r   test_import_with_pinnedr      sL    !$889 G
 %w//DAq
I,|
$C94s4455A)}X&.$.&$..........&$.....&....$..........................."\3$788888"\3$78888s   BC C2)N)__doc__builtinsr>   _pytest.assertion.rewrite	assertionrewriter<   r   ro   urllib.errorr   urllib.requesturllib.parser
   r   r   r(   rI   rY   r^   rg   rr   ru   r   r   r   r   r   r   r   r   r   r)   r   <module>r      s                 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @. . .
, , , ,  $ $ $B B B1 1 18 8 8u u u	? 	? 	?= = == = == = = 
= 
= 
=9 9 9.  
9 9 99 9 9 9 9r)   