Get available models dynamically from installed LangChain provider packages. Imports model profiles from each provider package and extracts model names. Results are cached after the first call; use `clear_caches()` to reset. Returns: Dictionary mapping provider names to lists
()
| 923 | |
| 924 | |
| 925 | def get_available_models() -> dict[str, list[str]]: |
| 926 | """Get available models dynamically from installed LangChain provider packages. |
| 927 | |
| 928 | Imports model profiles from each provider package and extracts model names. |
| 929 | |
| 930 | Results are cached after the first call; use `clear_caches()` to reset. |
| 931 | |
| 932 | Returns: |
| 933 | Dictionary mapping provider names to lists of model identifiers. |
| 934 | Includes providers from the langchain registry, config-file |
| 935 | providers with explicit model lists, and `class_path` providers |
| 936 | whose packages expose a `_profiles` module. |
| 937 | """ |
| 938 | global _available_models_cache # noqa: PLW0603 # Module-level cache requires global statement |
| 939 | if _available_models_cache is not None: |
| 940 | return _available_models_cache |
| 941 | |
| 942 | available: dict[str, list[str]] = {} |
| 943 | config = ModelConfig.load() |
| 944 | |
| 945 | # Try to load from langchain provider profile data. |
| 946 | # Build the list dynamically from langchain's supported-provider registry |
| 947 | # so new providers are picked up automatically when langchain adds them. |
| 948 | provider_modules = _get_provider_profile_modules() |
| 949 | registry_providers: set[str] = set() |
| 950 | |
| 951 | for provider, module_path in provider_modules: |
| 952 | registry_providers.add(provider) |
| 953 | # Skip providers explicitly disabled in config. |
| 954 | if not config.is_provider_enabled(provider): |
| 955 | logger.debug( |
| 956 | "Provider '%s' is disabled in config; skipping registry discovery", |
| 957 | provider, |
| 958 | ) |
| 959 | continue |
| 960 | try: |
| 961 | profiles = _load_provider_profiles(module_path) |
| 962 | except ImportError: |
| 963 | logger.debug( |
| 964 | "Could not import profiles from %s (package may not be installed)", |
| 965 | module_path, |
| 966 | ) |
| 967 | continue |
| 968 | except Exception: |
| 969 | logger.warning( |
| 970 | "Failed to load profiles from %s, skipping provider '%s'", |
| 971 | module_path, |
| 972 | provider, |
| 973 | exc_info=True, |
| 974 | ) |
| 975 | continue |
| 976 | |
| 977 | # Filter to models that support tool calling and text I/O. |
| 978 | models = [ |
| 979 | name |
| 980 | for name, profile in profiles.items() |
| 981 | if profile.get("tool_calling", False) |
| 982 | and profile.get("text_inputs", True) is not False |