from __future__ import annotations import pytest from EvoScientist.llm.configuration import ( EndpointConfig, ModelConfig, ProviderConfig, ) from EvoScientist.llm.contracts import EvoRuntimeError from EvoScientist.llm.invocation import ( compile_invocation_plan, derive_runtime_invocation, derive_tool_call_transport, ) from EvoScientist.llm.model_config import ( EndpointConfig as LegacyEndpointConfig, ) from EvoScientist.llm.model_config import ModelConfig as LegacyModelConfig from EvoScientist.llm.model_config import ProviderConfig as LegacyProviderConfig @pytest.mark.parametrize( ("capabilities", "expected"), [ ({"text": True, "tools": True}, "native"), ({"text": True, "tools": False}, "disabled"), ({"text": True}, "disabled"), ], ) def test_tool_transport_is_derived_only_from_model_capabilities( capabilities, expected ): assert derive_tool_call_transport(capabilities) == expected def test_runtime_invocation_combines_model_api_mode_and_derived_transport(): assert derive_runtime_invocation( "chat_completions", {"text": True, "tools": False} ) == { "api_mode": "chat_completions", "tool_call_transport": "disabled", } def test_k3_chat_plan_freezes_adapter_compiled_parameters(): plan = compile_invocation_plan( api_mode="chat_completions", declared_tool_call_transport="disabled", supports_tools=False, purpose="main_agent", output_token_limit=65_000, reasoning_effort="high", runtime_provider="openai", sdk_params={ "max_completion_tokens": 65_000, "reasoning_effort": "high", "use_responses_api": False, }, ) assert plan.output_token_parameter == "max_completion_tokens" assert plan.tool_call_transport == "disabled" assert plan.streaming is True assert plan.sdk_params["streaming"] is True with pytest.raises(TypeError): plan.sdk_params["max_completion_tokens"] = 1 def test_responses_plan_accepts_native_tools_when_capability_is_enabled(): plan = compile_invocation_plan( api_mode="responses", declared_tool_call_transport="native", supports_tools=True, purpose="title", output_token_limit=1_024, reasoning_effort="disabled", runtime_provider="openai", sdk_params={"max_output_tokens": 1_024, "use_responses_api": True}, ) assert plan.tool_call_transport == "native" assert plan.streaming is False def test_plan_rejects_runtime_projection_that_disagrees_with_capabilities(): with pytest.raises(EvoRuntimeError, match="MODEL_ADAPTER_COMPILE_FAILED"): compile_invocation_plan( api_mode="chat_completions", declared_tool_call_transport="native", supports_tools=False, purpose="main_agent", output_token_limit=1_024, reasoning_effort="disabled", runtime_provider="openai", sdk_params={"max_tokens": 1_024, "use_responses_api": False}, ) def test_provider_and_model_contracts_have_separate_ownership(): model_fields = ModelConfig.__dataclass_fields__ endpoint_fields = EndpointConfig.__dataclass_fields__ provider_fields = ProviderConfig.__dataclass_fields__ assert "capabilities" in model_fields assert "max_output_tokens" in model_fields assert "base_url" not in model_fields assert "auth" not in model_fields assert "tool_call_transport" not in model_fields assert "base_url" in endpoint_fields assert "auth" in endpoint_fields assert "adapter_id" in provider_fields assert "connection_defaults" in provider_fields def test_legacy_model_config_imports_reexport_canonical_contracts(): assert LegacyEndpointConfig is EndpointConfig assert LegacyModelConfig is ModelConfig assert LegacyProviderConfig is ProviderConfig