§
    U…›jp  ã                   óÂ   — 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	m
Z
mZmZ d dlmZmZmZmZmZmZmZ d dlmZ d dlmZmZ d dlmZ d dlmZ d„ Zd	„ Zd
„ Z d„ Z!d„ Z"dS )é    N)Ú	AsyncMockÚ	MagicMockÚpatch)ÚAiCapabilityÚAiModelSpecÚAiProviderTypeÚ
AiResponseÚAiStructuredRequestÚAiTextRequestÚAiVisionRequest)ÚProviderCircuitBreaker)ÚEnterpriseAiGatewayÚget_ai_gateway)ÚCanonicalModelRegistry)ÚMultimodalOcrServicec                  ó  — t          j        d¦  «        } | j        }d}||k    }|sªt          j        d|fd||f¦  «        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}}| j        }t          j        }||k    }|sòt          j        d|fd	||f¦  «        dt          j        ¦   «         v st          j        | ¦  «        rt          j        | ¦  «        ndt          j        |¦  «        d
t          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        nd
t          j        |¦  «        dœz  }dd|iz  }t          t          j
        |¦  «        ¦  «        ‚dx}x}}t          j        }| j        }||v }|sòt          j        d|fd||f¦  «        dt          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        ndt          j        |¦  «        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}x}}t          j        d¦  «        }	|	j        }d}||k    }|sªt          j        d|fd||f¦  «        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}}t          j        d¦  «        }
|
j        }d}||k    }|sªt          j        d|fd||f¦  «        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}}|
j        }t          j        }||k    }|sòt          j        d|fd||f¦  «        dt          j        ¦   «         v st          j        |
¦  «        rt          j        |
¦  «        ndt          j        |¦  «        d
t          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        nd
t          j        |¦  «        dœz  }dd|iz  }t          t          j
        |¦  «        ¦  «        ‚dx}x}}t          j        d¦  «        }|j        }d}||k    }|sªt          j        d|fd||f¦  «        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}}|j        }t          j        }||k    }|sòt          j        d|fd||f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        d
t          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        nd
t          j        |¦  «        dœz  }dd|iz  }t          t          j
        |¦  «        ¦  «        ‚dx}x}}t          j        d¦  «        }|j        }t          j        }||k    }|sòt          j        d|fd||f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        d
t          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        nd
t          j        |¦  «        dœz  }dd|iz  }t          t          j
        |¦  «        ¦  «        ‚dx}x}}|j        }d}||k    }|sªt          j        d|fd||f¦  «        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S )zIEnsures all legacy, deprecated, and aliased model IDs resolve accurately.úgemini-3.8-flash©ú==)z4%(py2)s
{%(py2)s = %(py0)s.canonical_id
} == %(py5)sÚspec©Úpy0Úpy2Úpy5úassert %(py7)sÚpy7N)zV%(py2)s
{%(py2)s = %(py0)s.provider_type
} == %(py6)s
{%(py6)s = %(py4)s.ANTIGRAVITY
}r   ©r   r   Úpy4Úpy6úassert %(py8)sÚpy8©Úin)z[%(py2)s
{%(py2)s = %(py0)s.MULTIMODAL_VISION
} in %(py6)s
{%(py6)s = %(py4)s.capabilities
}r   zgemini-3.1-proÚalias_31z google/gemini-2.0-flash-exp:freeúopenrouter/gemini-3.8-flashÚexp_free)zU%(py2)s
{%(py2)s = %(py0)s.provider_type
} == %(py6)s
{%(py6)s = %(py4)s.OPENROUTER
}zliquid/lfm-2.5-2.6bzlfm-2.5-2.6bÚlfm)zS%(py2)s
{%(py2)s = %(py0)s.provider_type
} == %(py6)s
{%(py6)s = %(py4)s.LMSTUDIO
}zqwen/qwen-2.5-vl-72b-instructÚdynamic_spec)z9%(py2)s
{%(py2)s = %(py0)s.provider_model_id
} == %(py5)s)r   Úresolve_specÚcanonical_idÚ
@pytest_arÚ_call_reprcompareÚ@py_builtinsÚlocalsÚ_should_repr_global_nameÚ	_safereprÚAssertionErrorÚ_format_explanationÚprovider_typer   ÚANTIGRAVITYr   ÚMULTIMODAL_VISIONÚcapabilitiesÚ
OPENROUTERÚLMSTUDIOÚprovider_model_id)r   Ú@py_assert1Ú@py_assert4Ú@py_assert3Ú@py_format6Ú@py_format8Ú@py_assert5Ú@py_format7Ú@py_format9r$   r&   r'   r(   s                úAC:\Projects\DSCons\tests\test_ai_gateway_architecture_boundary.pyÚ.test_canonical_registry_resolution_and_aliasesrC      s�
  € õ "Ô.Ð/AÑBÔB€DØÔÐ2Ð 2Ð2ÐÐ 2Ò2Ð2Ð2Ð2Õ2Ô2Ð2Ð2Ð2Ð2ÐÐ 2Ð2Ñ2Ô2Ð2Õ2Ô2Ñ2Ô2Ð2Ð2Õ2Ô2ˆ4Ñ2Ô2Ð2Õ2Ô2ˆ4Ñ2Ô2Ð2Ð2Õ2Ô2ÐÑ2Ô2Õ2Ô2Ð 2Ñ2Ô2Ð2Ð2Ñ2Ð2Ð2Ð2Ð2Ð2Ñ2Ð2Õ2Õ2Ô2Ð2Ñ2Ô2Ñ2Ô2Ð2Ð2Ð2Ð2Ð2Ð2Ð2ØÔÐ;¥Ô!;Ð;ÐÐ!;Ò;Ð;Ð;Ð;Õ;Ô;Ð;Ð;Ð;Ð;ÐÐ!;Ð;Ñ;Ô;Ð;Õ;Ô;Ñ;Ô;Ð;Ð;Õ;Ô;ˆ4Ñ;Ô;Ð;Õ;Ô;ˆ4Ñ;Ô;Ð;Ð;Õ;Ô;ÐÑ;Ô;Ð;Õ;Ô;Ñ;Ô;Ð;Ð;Õ;Ô;¥Ñ;Ô;Ð;Õ;Ô;¥Ñ;Ô;Ð;Ð;Õ;Ô;Ð!;Ñ;Ô;Ð;Ð;Ñ;Ð;Ð;Ð;Ð;Ð;Ñ;Ð;Õ;Õ;Ô;Ð;Ñ;Ô;Ñ;Ô;Ð;Ð;Ð;Ð;Ð;Ð;Ð;ÝÔ)Ð>¨TÔ->Ð>Ð)Ð->Ð>Ð>Ð>Ð>Õ>Ô>Ð>Ð>Ð>Ð>Ð)Ð->Ð>Ñ>Ô>Ð>Õ>Ô>Ñ>Ô>Ð>Ð>Õ>Ô>�<Ñ>Ô>Ð>Õ>Ô>�<Ñ>Ô>Ð>Ð>Õ>Ô>Ð)Ñ>Ô>Ð>Õ>Ô>Ñ>Ô>Ð>Ð>Õ>Ô>¨TÑ>Ô>Ð>Õ>Ô>¨TÑ>Ô>Ð>Ð>Õ>Ô>Ð->Ñ>Ô>Ð>Ð>Ñ>Ð>Ð>Ð>Ð>Ð>Ñ>Ð>Õ>Õ>Ô>Ð>Ñ>Ô>Ñ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>Ð>õ &Ô2Ð3CÑDÔD€HØÔ Ð6Ð$6Ð6Ð Ð$6Ò6Ð6Ð6Ð6Õ6Ô6Ð6Ð6Ð6Ð6Ð Ð$6Ð6Ñ6Ô6Ð6Õ6Ô6Ñ6Ô6Ð6Ð6Õ6Ô6ˆ8Ñ6Ô6Ð6Õ6Ô6ˆ8Ñ6Ô6Ð6Ð6Õ6Ô6Ð Ñ6Ô6Õ6Ô6Ð$6Ñ6Ô6Ð6Ð6Ñ6Ð6Ð6Ð6Ð6Ð6Ñ6Ð6Õ6Õ6Ô6Ð6Ñ6Ô6Ñ6Ô6Ð6Ð6Ð6Ð6Ð6Ð6Ð6õ &Ô2Ð3UÑVÔV€HØÔ ÐAÐ$AÐAÐ Ð$AÒAÐAÐAÐAÕAÔAÐAÐAÐAÐAÐ Ð$AÐAÑAÔAÐAÕAÔAÑAÔAÐAÐAÕAÔAˆ8ÑAÔAÐAÕAÔAˆ8ÑAÔAÐAÐAÕAÔAÐ ÑAÔAÕAÔAÐ$AÑAÔAÐAÐAÑAÐAÐAÐAÐAÐAÑAÐAÕAÕAÔAÐAÑAÔAÑAÔAÐAÐAÐAÐAÐAÐAÐAØÔ!Ð>¥^Ô%>Ð>Ð!Ð%>Ò>Ð>Ð>Ð>Õ>Ô>Ð>Ð>Ð>Ð>Ð!Ð%>Ð>Ñ>Ô>Ð>Õ>Ô>Ñ>Ô>Ð>Ð>Õ>Ô>ˆ8Ñ>Ô>Ð>Õ>Ô>ˆ8Ñ>Ô>Ð>Ð>Õ>Ô>Ð!Ñ>Ô>Ð>Õ>Ô>Ñ>Ô>Ð>Ð>Õ>Ô>¥^Ñ>Ô>Ð>Õ>Ô>¥^Ñ>Ô>Ð>Ð>Õ>Ô>Ð%>Ñ>Ô>Ð>Ð>Ñ>Ð>Ð>Ð>Ð>Ð>Ñ>Ð>Õ>Õ>Ô>Ð>Ñ>Ô>Ñ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>Ð>õ !Ô
-Ð.CÑ
DÔ
D€CØÔÐ-˜~Ð-Ð˜~Ò-Ð-Ð-Ð-Õ-Ô-Ð-Ð-Ð-Ð-Ð˜~Ð-Ñ-Ô-Ð-Õ-Ô-Ñ-Ô-Ð-Ð-Õ-Ô-ˆ3Ñ-Ô-Ð-Õ-Ô-ˆ3Ñ-Ô-Ð-Ð-Õ-Ô-ÐÑ-Ô-Õ-Ô-˜~Ñ-Ô-Ð-Ð-Ñ-Ð-Ð-Ð-Ð-Ð-Ñ-Ð-Õ-Õ-Ô-Ð-Ñ-Ô-Ñ-Ô-Ð-Ð-Ð-Ð-Ð-Ð-Ð-ØÔÐ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ˆ3Ñ7Ô7Ð7Õ7Ô7ˆ3Ñ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Ô7Ð7Ð7Ð7Ð7Ð7Ð7Ð7õ *Ô6Ð7VÑWÔW€LØÔ%ÐB­Ô)BÐBÐ%Ð)BÒBÐBÐBÐBÕBÔBÐBÐBÐBÐBÐ%Ð)BÐBÑBÔBÐBÕBÔBÑBÔBÐBÐBÕBÔBˆ<ÑBÔBÐBÕBÔBˆ<ÑBÔBÐBÐBÕBÔBÐ%ÑBÔBÐBÕBÔBÑBÔBÐBÐBÕBÔB­ÑBÔBÐBÕBÔB­ÑBÔBÐBÐBÕBÔBÐ)BÑBÔBÐBÐBÑBÐBÐBÐBÐBÐBÑBÐBÕBÕBÔBÐBÑBÔBÑBÔBÐBÐBÐBÐBÐBÐBÐBØÔ)ÐLÐ-LÐLÐ)Ð-LÒLÐLÐLÐLÕLÔLÐLÐLÐLÐLÐ)Ð-LÐLÑLÔLÐLÕLÔLÑLÔLÐLÐLÕLÔLˆ<ÑLÔLÐLÕLÔLˆ<ÑLÔLÐLÐLÕLÔLÐ)ÑLÔLÕLÔLÐ-LÑLÔLÐLÐLÑLÐLÐLÐLÐLÐLÑLÐLÕLÕLÔLÐLÑLÔLÑLÔLÐLÐLÐLÐLÐLÐLÐLÐLÐLó    c            	      ó  — t          d¬¦  «        } | j        }t          j        } ||¦  «        }d}||u }|�st	          j        d|fd||f¦  «        dt          j        ¦   «         v st	          j        | ¦  «        rt	          j	        | ¦  «        ndt	          j	        |¦  «        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}x}}|                      t          j        t          d¦  «        ¦  «         | j        }t          j        } ||¦  «        }d}||u }|�st	          j        d|fd||f¦  «        dt          j        ¦   «         v st	          j        | ¦  «        rt	          j	        | ¦  «        ndt	          j	        |¦  «        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}x}}| j        }t          j        } ||¦  «        }d}||u }|�st	          j        d|fd||f¦  «        dt          j        ¦   «         v st	          j        | ¦  «        rt	          j	        | ¦  «        ndt	          j	        |¦  «        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}x}}|                      t          j        ¦  «         | j        }t          j        } ||¦  «        }d}||u }|�st	          j        d|fd||f¦  «        dt          j        ¦   «         v st	          j        | ¦  «        rt	          j	        | ¦  «        ndt	          j	        |¦  «        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}x}}dS )zVVerifies that 503 errors instantly trip the circuit to protect against latency spikes.g       @)Úrecovery_time_secondsT©Úis)zs%(py7)s
{%(py7)s = %(py2)s
{%(py2)s = %(py0)s.can_attempt
}(%(py5)s
{%(py5)s = %(py3)s.ANTIGRAVITY
})
} is %(py10)sÚcbr   )r   r   Úpy3r   r   Úpy10zassert %(py12)sÚpy12Nz6503 Service Unavailable: spikes in demand on free tierF)zr%(py7)s
{%(py7)s = %(py2)s
{%(py2)s = %(py0)s.can_attempt
}(%(py5)s
{%(py5)s = %(py3)s.OPENROUTER
})
} is %(py10)s)r   Úcan_attemptr   r4   r+   r,   r-   r.   r/   r0   r1   r2   Úrecord_failureÚ	Exceptionr7   Úrecord_success)rI   r:   r;   Ú@py_assert6Ú@py_assert9Ú@py_assert8Ú@py_format11Ú@py_format13s           rB   Ú.test_circuit_breaker_trips_on_503_and_recoversrV   7   sÍ  € å	°cÐ	:Ñ	:Ô	:€BØŒ>Ð=�.Ô4Ð=ˆ>ˆ>Ð4Ñ5Ô5Ð=¸Ð=Ð5¸Ð=Ð=Ð=Ñ=Õ=Ô=Ð=Ð=Ð=Ð=Ð5¸Ð=Ñ=Ô=Ð=Õ=Ô=Ñ=Ô=Ð=Ð=Õ=Ô=ˆ2Ñ=Ô=Ð=Õ=Ô=ˆ2Ñ=Ô=Ð=Ð=Õ=Ô=ˆ>Ñ=Ô=Ð=Õ=Ô=Ñ=Ô=Ð=Ð=Õ=Ô=�.Ñ=Ô=Ð=Õ=Ô=�.Ñ=Ô=Ð=Ð=Õ=Ô=Ð4Ñ=Ô=Õ=Ô=Ð5Ñ=Ô=Õ=Ô=¸Ñ=Ô=Ð=Ð=Ñ=Ð=Ð=Ð=Ð=Ð=Ñ=Ð=Õ=Õ=Ô=Ð=Ñ=Ô=Ñ=Ô=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=ð ×ÒÝÔ"ÝÐJÑKÔKñô ð ð Œ>Ð>�.Ô4Ð>ˆ>ˆ>Ð4Ñ5Ô5Ð>¸Ð>Ð5¸Ð>Ð>Ð>Ñ>Õ>Ô>Ð>Ð>Ð>Ð>Ð5¸Ð>Ñ>Ô>Ð>Õ>Ô>Ñ>Ô>Ð>Ð>Õ>Ô>ˆ2Ñ>Ô>Ð>Õ>Ô>ˆ2Ñ>Ô>Ð>Ð>Õ>Ô>ˆ>Ñ>Ô>Ð>Õ>Ô>Ñ>Ô>Ð>Ð>Õ>Ô>�.Ñ>Ô>Ð>Õ>Ô>�.Ñ>Ô>Ð>Ð>Õ>Ô>Ð4Ñ>Ô>Õ>Ô>Ð5Ñ>Ô>Õ>Ô>¸Ñ>Ô>Ð>Ð>Ñ>Ð>Ð>Ð>Ð>Ð>Ñ>Ð>Õ>Õ>Ô>Ð>Ñ>Ô>Ñ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>Ð>Ð>Ð>Ð>Ð>ð Œ>Ð<�.Ô3Ð<ˆ>ˆ>Ð3Ñ4Ô4Ð<¸Ð<Ð4¸Ð<Ð<Ð<Ñ<Õ<Ô<Ð<Ð<Ð<Ð<Ð4¸Ð<Ñ<Ô<Ð<Õ<Ô<Ñ<Ô<Ð<Ð<Õ<Ô<ˆ2Ñ<Ô<Ð<Õ<Ô<ˆ2Ñ<Ô<Ð<Ð<Õ<Ô<ˆ>Ñ<Ô<Ð<Õ<Ô<Ñ<Ô<Ð<Ð<Õ<Ô<�.Ñ<Ô<Ð<Õ<Ô<�.Ñ<Ô<Ð<Ð<Õ<Ô<Ð3Ñ<Ô<Õ<Ô<Ð4Ñ<Ô<Õ<Ô<¸Ñ<Ô<Ð<Ð<Ñ<Ð<Ð<Ð<Ð<Ð<Ñ<Ð<Õ<Õ<Ô<Ð<Ñ<Ô<Ñ<Ô<Ð<Ð<Ð<Ð<Ð<Ð<Ð<Ð<Ð<Ð<Ð<ð ×Ò•nÔ0Ñ1Ô1Ð1ØŒ>Ð=�.Ô4Ð=ˆ>ˆ>Ð4Ñ5Ô5Ð=¸Ð=Ð5¸Ð=Ð=Ð=Ñ=Õ=Ô=Ð=Ð=Ð=Ð=Ð5¸Ð=Ñ=Ô=Ð=Õ=Ô=Ñ=Ô=Ð=Ð=Õ=Ô=ˆ2Ñ=Ô=Ð=Õ=Ô=ˆ2Ñ=Ô=Ð=Ð=Õ=Ô=ˆ>Ñ=Ô=Ð=Õ=Ô=Ñ=Ô=Ð=Ð=Õ=Ô=�.Ñ=Ô=Ð=Õ=Ô=�.Ñ=Ô=Ð=Ð=Õ=Ô=Ð4Ñ=Ô=Õ=Ô=Ð5Ñ=Ô=Õ=Ô=¸Ñ=Ô=Ð=Ð=Ñ=Ð=Ð=Ð=Ð=Ð=Ñ=Ð=Õ=Õ=Ô=Ð=Ñ=Ô=Ñ=Ô=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=rD   c                  óN   — ddl } d„ }|                       |¦   «         ¦  «         dS )z`Verifies that when Antigravity fails (e.g. 503), the gateway automatically routes to OpenRouter.r   Nc            	   “   óz  K  — t          ¦   «         } t          ¦   «         }t          d¦  «        |j        _        t          ¦   «         }t          ddt          j        d¬¦  «        |j        _        t          j
        | d|¦  «        5  t          j
        | d|¦  «        5  t          dd	¬
¦  «        }|                      |¦  «        ƒ d {V —†}|j        }d}||k    }|sªt          j        d|fd||f¦  «        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}}|j        }t          j        }
||
k    }|sòt          j        d|fd||
f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        dt          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        ndt          j        |
¦  «        dœz  }dd|iz  }t'          t          j        |¦  «        ¦  «        ‚d x}x}}
|j        }d}||u }|sªt          j        d|fd||f¦  «        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}}|j                             ¦   «          |j                             ¦   «          d d d ¦  «         n# 1 swxY w Y   d d d ¦  «         d S # 1 swxY w Y   d S )Nz503 Service Unavailableu9   Ná»™i dung Ä‘Ã£ Ä‘Æ°á»£c xá»­ lÃ½ qua OpenRouter Fallbackr%   g      ^@)ÚcontentÚ
model_usedÚprovider_usedÚ
latency_msÚ_antigravity_adapterÚ_openrouter_adapteru/   Kiá»ƒm tra tháº©m Ä‘á»‹nh há»“ sÆ¡ cÃ´ng trÃ¬nhr   )ÚpromptÚcanonical_model_idr   )z/%(py2)s
{%(py2)s = %(py0)s.content
} == %(py5)sÚresponser   r   r   )zU%(py2)s
{%(py2)s = %(py0)s.provider_used
} == %(py6)s
{%(py6)s = %(py4)s.OPENROUTER
}r   r   r    r!   TrG   )z3%(py2)s
{%(py2)s = %(py0)s.is_fallback
} is %(py5)s)r   r   ÚRuntimeErrorÚgenerate_textÚside_effectr	   r   r7   Úreturn_valuer   Úobjectr   rY   r+   r,   r-   r.   r/   r0   r1   r2   r[   Úis_fallbackÚassert_awaited_once)ÚgatewayÚmock_agÚmock_orÚreqra   r:   r;   r<   r=   r>   r?   r@   rA   s                rB   Ú	_run_testzGtest_gateway_failover_from_antigravity_to_openrouter.<locals>._run_testR   s£  è è € Ý%Ñ'Ô'ˆõ ‘+”+ˆÝ,8Ð9RÑ,SÔ,SˆÔÔ)õ ‘+”+ˆÝ-7ØOØ4Ý(Ô3Øð	.
ñ .
ô .
ˆÔÔ*õ Œ\˜'Ð#9¸7ÑCÔCð 	8ð 	8ÅUÄ\ØÐ*¨GñF
ô F
ð 	8ð 	8õ  ØHØ#5ðñ ô ˆCð %×2Ò2°3Ñ7Ô7Ð7Ð7Ð7Ð7Ð7Ð7ˆHàÔ#ÐbÐ'bÐbÐ#Ð'bÒbÐbÐbÐbÕbÔbÐbÐbÐbÐbÐ#Ð'bÐbÑbÔbÐbÕbÔbÑbÔbÐbÐbÕbÔb�8ÑbÔbÐbÕbÔb�8ÑbÔbÐbÐbÕbÔbÐ#ÑbÔbÕbÔbÐ'bÑbÔbÐbÐbÑbÐbÐbÐbÐbÐbÑbÐbÕbÕbÔbÐbÑbÔbÑbÔbÐbÐbÐbÐbÐbÐbÐbØÔ)ÐF­^Ô-FÐFÐ)Ð-FÒFÐFÐFÐFÕFÔFÐFÐFÐFÐFÐ)Ð-FÐFÑFÔFÐFÕFÔFÑFÔFÐFÐFÕFÔF�8ÑFÔFÐFÕFÔF�8ÑFÔFÐFÐFÕFÔFÐ)ÑFÔFÐFÕFÔFÑFÔFÐFÐFÕFÔF­^ÑFÔFÐFÕFÔF­^ÑFÔFÐFÐFÕFÔFÐ-FÑFÔFÐFÐFÑFÐFÐFÐFÐFÐFÑFÐFÕFÕFÔFÐFÑFÔFÑFÔFÐFÐFÐFÐFÐFÐFÐFØÔ'Ð/¨4Ð/Ð'¨4Ð/Ð/Ð/Ð/Õ/Ô/Ð/Ð/Ð/Ð/Ð'¨4Ð/Ñ/Ô/Ð/Õ/Ô/Ñ/Ô/Ð/Ð/Õ/Ô/�8Ñ/Ô/Ð/Õ/Ô/�8Ñ/Ô/Ð/Ð/Õ/Ô/Ð'Ñ/Ô/Õ/Ô/¨4Ñ/Ô/Ð/Ð/Ñ/Ð/Ð/Ð/Ð/Ð/Ñ/Ð/Õ/Õ/Ô/Ð/Ñ/Ô/Ñ/Ô/Ð/Ð/Ð/Ð/Ð/Ð/Ð/ØÔ!×5Ò5Ñ7Ô7Ð7ØÔ!×5Ò5Ñ7Ô7Ð7ð	8ð 	8ð 	8ñ 	8ô 	8ð 	8ð 	8ð 	8ð 	8ð 	8ð 	8øøøð 	8ð 	8ð 	8ð 	8ð 	8ð 	8ð 	8ñ 	8ô 	8ð 	8ð 	8ð 	8ð 	8ð 	8ð 	8ð 	8øøøð 	8ð 	8ð 	8ð 	8ð 	8ð 	8s7   ÂN0ÂK2NÎN0ÎN	ÎN0ÎN	Î N0Î0N4Î7N4)ÚasyncioÚrun)rn   rm   s     rB   Ú4test_gateway_failover_from_antigravity_to_openrouterrp   N   s:   € à€N€N€Nð8ð 8ð 8ð> ‡K‚K�	�	‘”ÑÔÐÐÐrD   c                  óZ  — t          ¦   «         } d}d}t          ddt          j        ¬¦  «        }t	          d|¬¦  «        5 }|                      ||¦  «        }d}||v }|s—t          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}}|                     ¦   «          |j        d         d         }
t!          |
t"          ¦  «        }|�sd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dt          j
        ¦   «         v st          j        t"          ¦  «        rt          j        t"          ¦  «        ndt          j        |¦  «        dœz  }t          t          j        |¦  «        ¦  «        ‚d}|
j        }||k    }|sÕt          j        d|fd||f¦  «        dt          j
        ¦   «         v st          j        |
¦  «        rt          j        |
¦  «        nd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}}|
j        }||k    }|sÕt          j        d|fd||f¦  «        dt          j
        ¦   «         v st          j        |
¦  «        rt          j        |
¦  «        nd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dd¦  «         dS # 1 swxY w Y   dS )zeVerifies that MultimodalOcrService calls gateway.analyze_vision_sync and eliminates raw urllib calls.z'data:image/jpeg;base64,/9j/4AAQSkZJRg==u9   Ä�á»�c vÃ  phiÃªn Ã¢m toÃ n bá»™ chá»¯ viáº¿t trong áº£nhuK   Cá»˜NG HÃ’A XÃƒ Há»˜I CHá»¦ NGHÄ¨A VIá»†T NAM
QUYáº¾T Ä�á»ŠNH 1310/QÄ�-UBNDr   )rY   rZ   r[   zJapp.core.ai.infrastructure.gateway.EnterpriseAiGateway.analyze_vision_sync)re   u   QUYáº¾T Ä�á»ŠNH 1310/QÄ�-UBNDr"   )z%(py1)s in %(py3)sÚresult)Úpy1rJ   zassert %(py5)sr   Nr   z5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}Ú
isinstanceÚcall_reqr   )r   rs   r   r   r   )z0%(py2)s
{%(py2)s = %(py0)s.data_uri
} == %(py4)sÚdummy_data_uri)r   r   r   zassert %(py6)sr   )z.%(py2)s
{%(py2)s = %(py0)s.prompt
} == %(py4)sr_   )r   r	   r   r4   r   Ú_call_vision_modelr+   r,   r0   r-   r.   r/   r1   r2   Úassert_called_onceÚ	call_argsrt   r   Údata_urir_   )Úocr_servicerv   r_   Ú	mock_respÚ	mock_syncrr   Ú@py_assert0Ú@py_assert2Ú@py_format4r=   ru   r<   Ú@py_format5r:   r@   s                  rB   Ú+test_multimodal_ocr_delegates_to_ai_gatewayr‚   w   s¹  € å&Ñ(Ô(€KØ>€NØH€FåØ^Ø%Ý$Ô0ðñ ô €Iõ 
ØTØð
ñ 
ô 
ð 
)ð 
Ø×/Ò/°ÀÑGÔGˆØ.Ð8Ð.°&Ð8Ð8Ð8Ð8Õ8Ô8Ð8Ð8Ð8Ð8Ð.°&Ð8Ñ8Ô8Õ8Ô8Ð.Ñ8Ô8Ð8Õ8Ô8Ñ8Ô8Ð8Ð8Õ8Ô8°&Ñ8Ô8Ð8Õ8Ô8°&Ñ8Ô8Ð8Ð8Ð8Ð8Ñ8Ð8Ð8Ð8Ð8Ð8Ñ8Ð8Õ8Õ8Ô8Ð8Ñ8Ô8Ñ8Ô8Ð8Ð8Ð8Ð8Ð8Ø×$Ò$Ñ&Ô&Ð&ØÔ& qÔ)¨!Ô,ˆÝ˜(¥OÑ4Ô4Ð4Ð4Ñ4Ð4Ð4Õ4Ô4Ñ4Ô4Ð4Ð4Õ4Ô4�zÑ4Ô4Ð4Õ4Ô4�zÑ4Ô4Ð4Ð4Ð4Õ4Ô4Ñ4Ô4Ð4Ð4Õ4Ô4˜(Ñ4Ô4Ð4Õ4Ô4˜(Ñ4Ô4Ð4Ð4Ð4Õ4Ô4Ñ4Ô4Ð4Ð4Õ4Ô4¥OÑ4Ô4Ð4Õ4Ô4¥OÑ4Ô4Ð4Ð4Õ4Ô4Ð4Ñ4Ô4Ð4Ð4Ñ4Ð4Õ4Õ4Ô4Ð4Ñ4Ô4Ñ4Ô4Ð4Ð4Ð4ØÔ Ð2Ð  NÒ2Ð2Ð2Ð2Õ2Ô2Ð2Ð2Ð2Ð2Ð  NÐ2Ñ2Ô2Ð2Õ2Ô2Ñ2Ô2Ð2Ð2Õ2Ô2ˆxÑ2Ô2Ð2Õ2Ô2ˆxÑ2Ô2Ð2Ð2Õ2Ô2Ð Ñ2Ô2Ð2Õ2Ô2Ñ2Ô2Ð2Ð2Õ2Ô2 NÑ2Ô2Ð2Õ2Ô2 NÑ2Ô2Ð2Ð2Ð2Ð2Ñ2Ð2Ð2Ð2Ð2Ð2Ñ2Ð2Õ2Õ2Ô2Ð2Ñ2Ô2Ñ2Ô2Ð2Ð2Ð2Ð2Ð2ØŒÐ(ˆ &Ò(Ð(Ð(Ð(Õ(Ô(Ð(Ð(Ð(Ð(ˆ &Ð(Ñ(Ô(Ð(Õ(Ô(Ñ(Ô(Ð(Ð(Õ(Ô(ˆxÑ(Ô(Ð(Õ(Ô(ˆxÑ(Ô(Ð(Ð(Õ(Ô(ˆÑ(Ô(Ð(Õ(Ô(Ñ(Ô(Ð(Ð(Õ(Ô( &Ñ(Ô(Ð(Õ(Ô( &Ñ(Ô(Ð(Ð(Ð(Ð(Ñ(Ð(Ð(Ð(Ð(Ð(Ñ(Ð(Õ(Õ(Ô(Ð(Ñ(Ô(Ñ(Ô(Ð(Ð(Ð(Ð(Ð(ð
)ð 
)ð 
)ñ 
)ô 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)øøøð 
)ð 
)ð 
)ð 
)ð 
)ð 
)s   Á OP Ð P$Ð'P$c            
      óâ  — ddg} | D �]æ}t           j                             t          j        ¦   «         |                     dt           j        ¦  «        ¦  «        }t           j        }|j        } ||¦  «        }|sþt          j        d|› �¦  «        dz   dt          j
        ¦   «         v st          j        t           ¦  «        rt          j        t           ¦  «        ndt          j        |¦  «        t          j        |¦  «        dt          j
        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        dœz  }t          t          j        |¦  «        ¦  «        ‚d	x}x}}t          |d
d¬¦  «        5 }t!          j        |                     ¦   «         |¬¦  «        }d	d	d	¦  «         n# 1 swxY w Y   t!          j        |¦  «        D �]}	t)          |	t           j        ¦  «        rë|	j        D ]á}
d}|
j        }||v}|sÊt          j        d|fd||f¦  «        t          j        |¦  «        dt          j
        ¦   «         v st          j        |
¦  «        rt          j        |
¦  «        ndt          j        |¦  «        dœz  }t          j        d|
j        › d|› �¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚d	x}x}}Œâ�Œt)          |	t           j        ¦  «        ræ|	j        rßd}|	j        }||v}|sÊt          j        d|fd||f¦  «        t          j        |¦  «        dt          j
        ¦   «         v st          j        |	¦  «        rt          j        |	¦  «        ndt          j        |¦  «        dœz  }t          j        d|	j        › d|› �¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚d	x}x}}�Œ
�Œèd	S )z`Architectural Gate: Ensures NO module in application OCR or LLM service uses raw urllib.request.z:app/modules/core/application/ocr/multimodal_ocr_service.pyz-app/modules/agents/application/llm/service.pyú/zFile not found: zd
>assert %(py7)s
{%(py7)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.path
}.exists
}(%(py5)s)
}ÚosÚabs_path)r   r   r   r   r   NÚrzutf-8)Úencoding)ÚfilenameÚurllib)únot in)z0%(py1)s not in %(py5)s
{%(py5)s = %(py3)s.name
}Úalias)rs   rJ   r   z#Architecture violation: Forbidden 'z' imported in z
>assert %(py7)sr   )z2%(py1)s not in %(py5)s
{%(py5)s = %(py3)s.module
}Únodez(Architecture violation: Forbidden from ')r…   ÚpathÚjoinÚgetcwdÚreplaceÚsepÚexistsr+   Ú_format_assertmsgr-   r.   r/   r0   r1   r2   ÚopenÚastÚparseÚreadÚwalkrt   ÚImportÚnamesÚnamer,   Ú
ImportFromÚmodule)Útarget_filesÚrel_pathr†   r:   r<   rQ   r>   ÚfÚtreer�   rŒ   r~   r;   r   r=   s                  rB   Ú9test_ast_architecture_boundary_no_urllib_in_ocr_or_agentsr£   “   s  € ð 	EØ7ð€Lð
 !ð hñ hˆÝ”7—<’<¥¤	¡¤¨X×-=Ò-=¸cÅ2Ä6Ñ-JÔ-JÑKÔKˆÝŒwÐFˆwŒ~ÐFˆ~ˆ~˜hÑ'Ô'ÐFÐ'ÐFÕFÔFÐ)F¸HÐ)FÐ)FÑFÔFÐFÑFÐFÕFÔFÑFÔFÐFÐFÕFÔF�rÑFÔFÐFÕFÔF�rÑFÔFÐFÐFÕFÔFˆwÑFÔFÕFÔFˆ~ÑFÔFÐFÕFÔFÑFÔFÐFÐFÕFÔF˜hÑFÔFÐFÕFÔF˜hÑFÔFÐFÐFÕFÔFÐ'ÑFÔFÐFÐFÑFÐFÕFÕFÔFÐFÑFÔFÑFÔFÐFÐFÐFÐFÐFÐFÐFå�(˜C¨'Ð2Ñ2Ô2ð 	:°aÝ”9˜QŸVšV™XœX°Ð9Ñ9Ô9ˆDð	:ð 	:ð 	:ñ 	:ô 	:ð 	:ð 	:ð 	:ð 	:ð 	:ð 	:øøøð 	:ð 	:ð 	:ð 	:õ ”H˜T‘N”Nð 
	hñ 
	hˆDÝ˜$¥¤
Ñ+Ô+ð 	hØ!œZð bð b�Eà ðbØ(-¬
ðbØ ¨
Ð2ðbð bð bõ bäPaðbð bð bð bØ ¨
ðbñ bô bõ bäXað !ñbô bð bõ bä[añbô bð bð bõ bäIað ).ñbô bð bõ bäXað ).ñbô bð bð bõ bäXað )3ñbô bð bð bñ bð bõ bäPaÐa¸U¼ZÐaÐaÐW_ÐaÐañbô bð bñ bð bð bð bñ bð bõ bõ bäNaðbñ bô bñ bô bð bð bð bð bð bð bð bð bñbõ ˜D¥#¤.Ñ1Ô1ð hØ”;ð hà ðhØ(,¬ðhØ ¨Ð3ðhð hð hõ häVgðhð hð hð hØ ¨ðhñ hô hõ hä^gð !ñhô hð hõ häagñhô hð hð hõ häOgð )-ñhô hð hõ hä^gð )-ñhô hð hð hõ hä^gð )4ñhô hð hð hñ hð hõ häVgÐgÀ$Ä+ÐgÐgÐ]eÐgÐgñhô hð hñ hð hð hð hñ hð hõ hõ häTgðhñ hô hñ hô hð hð hð hð hð hð hð hùñ
	hðhð hs   Æ)GÇG	ÇG	)#Úbuiltinsr-   Ú_pytest.assertion.rewriteÚ	assertionÚrewriter+   r–   r…   ÚpytestÚunittest.mockr   r   r   Úapp.core.ai.domain.modelsr   r   r   r	   r
   r   r   Ú*app.core.ai.infrastructure.circuit_breakerr   Ú"app.core.ai.infrastructure.gatewayr   r   Ú#app.core.ai.infrastructure.registryr   Ú7app.modules.core.application.ocr.multimodal_ocr_servicer   rC   rV   rp   r‚   r£   © rD   rB   ú<module>r°      sa  ðØ  € € € € € € € € € € € € €
€
€
€
Ø 	€	€	€	Ø €€€Ø 5Ð 5Ð 5Ð 5Ð 5Ð 5Ð 5Ð 5Ð 5Ð 5ðð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð NÐ MÐ MÐ MÐ MÐ MØ RÐ RÐ RÐ RÐ RÐ RÐ RÐ RØ FÐ FÐ FÐ FÐ FÐ FØ XÐ XÐ XÐ XÐ XÐ XðMð Mð Mð>>ð >ð >ð.#ð #ð #ðR)ð )ð )ð8hð hð hð hð hrD   