from __future__ import annotations import pytest from EvoScientist.llm.contracts import EvoRuntimeError from EvoScientist.llm.user_options import ( model_options_schema_hash, project_user_options_for_purpose, validate_user_model_options, ) def _validate(options): return validate_user_model_options( supplied=options, user_options={ "temperature": { "type": "number", "minimum": 0, "maximum": 2, "applies_to": ["main_agent"], }, "top_p": { "type": "number", "minimum_exclusive": 0, "maximum": 1, "applies_to": ["main_agent"], }, }, supports_reasoning=True, reasoning_mode="effort", allowed_reasoning_efforts=("low", "high"), default_reasoning_effort="high", parameter_constraints=({"at_most_one_of": ("temperature", "top_p")},), ) def test_user_options_validate_canonical_values(): assert _validate({"temperature": 0.4, "reasoning": "high"}) == { "temperature": 0.4, "reasoning": "high", } def test_purpose_projection_filters_user_options_but_preserves_runtime_parameters(): projected = project_user_options_for_purpose( values={"temperature": 1, "structured_output": True}, user_options={ "temperature": { "type": "number", "applies_to": ["main_agent"], } }, purpose="tool_selector", ) assert projected == {"structured_output": True} @pytest.mark.parametrize( "options", [ {"temperature": 3}, {"top_p": 0}, {"unknown": True}, {"temperature": 0.4, "top_p": 0.8}, ], ) def test_user_options_reject_invalid_or_conflicting_values(options): with pytest.raises(EvoRuntimeError): _validate(options) def test_options_schema_hash_tracks_semantics_not_defaults(): common = { "model_profile_id": "profile-1", "supports_reasoning": False, "reasoning_mode": "none", "allowed_reasoning_efforts": (), "parameter_constraints": (), "adapter_id": "openai-compatible", "adapter_revision": "3", } first = model_options_schema_hash( **common, user_options={"temperature": {"type": "number", "maximum": 2, "default": 1}}, ) default_changed = model_options_schema_hash( **common, user_options={"temperature": {"type": "number", "maximum": 2, "default": 0}}, ) constraint_changed = model_options_schema_hash( **common, user_options={"temperature": {"type": "number", "maximum": 1, "default": 0}}, ) adapter_changed = model_options_schema_hash( **{**common, "adapter_revision": "4"}, user_options={"temperature": {"type": "number", "maximum": 2, "default": 0}}, ) assert first == default_changed assert first != constraint_changed assert first != adapter_changed