Skip to content

datarobot_genai.core.config

config

Config

Bases: DataRobotAppFrameworkBaseSettings

The single GLOBAL application config. There is exactly one.

Finds variables in priority order: env vars (including Runtime Parameters), .env, file secrets, then Pulumi outputs. It holds the two ecosystem-wide globals, app-wide settings, and the default LLM instance's flat, instance-namespaced fields so a standalone genai (no app registered) can still resolve the default LLM from the environment.

This is NOT an :class:LLMConfig. genai never reads LLM routing fields off it directly; those are mapped into an :class:LLMConfig by its resolve_llm_config(name=...) method, and the two globals through the base class's resolve_datarobot_endpoint / resolve_datarobot_api_token methods.

Source code in datarobot_genai/core/config.py
class Config(DataRobotAppFrameworkBaseSettings):
    """The single GLOBAL application config. There is exactly one.

    Finds variables in priority order: env vars (including Runtime Parameters),
    .env, file secrets, then Pulumi outputs. It holds the two ecosystem-wide
    globals, app-wide settings, and the default LLM instance's flat,
    instance-namespaced fields so a standalone genai (no app registered) can still
    resolve the default LLM from the environment.

    This is NOT an :class:`LLMConfig`. genai never reads LLM routing fields off it
    directly; those are mapped into an :class:`LLMConfig` by its
    ``resolve_llm_config(name=...)`` method, and the two globals through the base
    class's ``resolve_datarobot_endpoint`` / ``resolve_datarobot_api_token`` methods.
    """

    # --- CLOSED CLASS. Do not add fields here. ------------------------------
    # datarobot-genai is a dependency, so an application cannot edit this class. A field
    # added here is not a configuration point for that application, only one
    # more environment variable this library reads and nobody downstream can
    # add to, rename, or override. New settings belong on the app's own
    # registered config, or behind a `default_*` helper further down this file.
    # Enforced by `test_config_field_set_is_closed` in tests/core/test_config.py.

    # True ecosystem-wide globals. Fixed names, shared by every LLM instance.
    datarobot_endpoint: str = DEFAULT_DATAROBOT_ENDPOINT
    datarobot_api_token: str | None = None

    # Default LLM instance ("llm") fields, namespaced by instance name, so a
    # standalone genai reads them from the environment. An app registers its own
    # config, which may namespace by a different instance name; see the seam below.
    llm_deployment_id: str | None = None
    llm_nim_deployment_id: str | None = None
    llm_use_datarobot_llm_gateway: bool = True
    llm_default_model: str | None = None

register_config_provider

register_config_provider(provider: Callable[[], object | None] | None, default_llm_name: str = DEFAULT_LLM_NAME) -> None

Register the app's authoritative GLOBAL config source, or clear it with None.

provider is a zero-arg callable returning the app's global config object (typically lambda: Config() over the app's own Config). It is called each time genai resolves config, so values re-resolve through the app's settings sources (env / .env / secrets / Pulumi) on every read.

default_llm_name is the app's default LLM instance name (the prefix on its per-LLM fields), read back by :func:registered_default_llm_name. Call sites with no name of their own pass it to config.resolve_llm_config(name=...), so a non-"llm" component name still works for a bare get_llm().

Source code in datarobot_genai/core/config.py
def register_config_provider(
    provider: Callable[[], object | None] | None,
    default_llm_name: str = DEFAULT_LLM_NAME,
) -> None:
    """Register the app's authoritative GLOBAL config source, or clear it with ``None``.

    ``provider`` is a zero-arg callable returning the app's global config object
    (typically ``lambda: Config()`` over the app's own ``Config``). It is called
    each time genai resolves config, so values re-resolve through the app's
    settings sources (env / .env / secrets / Pulumi) on every read.

    ``default_llm_name`` is the app's default LLM instance name (the prefix on its
    per-LLM fields), read back by :func:`registered_default_llm_name`. Call sites
    with no name of their own pass it to ``config.resolve_llm_config(name=...)``, so
    a non-"llm" component name still works for a bare ``get_llm()``.
    """
    _provider_registry["provider"] = provider
    _provider_registry["default_llm_name"] = default_llm_name

resolve_config

resolve_config() -> Config

Return the single GLOBAL application config.

The registered app config when a provider is registered, otherwise genai's own env-reading :class:Config (a standalone genai with no app around it). Everything is resolved off the returned config through the datarobot.core base class methods (resolve_datarobot_endpoint / resolve_datarobot_api_token); for LLM routing call resolve_llm_config(name=...) on the returned config.

Source code in datarobot_genai/core/config.py
def resolve_config() -> Config:
    """Return the single GLOBAL application config.

    The registered app config when a provider is registered, otherwise genai's own
    env-reading :class:`Config` (a standalone genai with no app around it).
    Everything is resolved off the returned config through the ``datarobot.core``
    base class methods (``resolve_datarobot_endpoint`` / ``resolve_datarobot_api_token``);
    for LLM routing call ``resolve_llm_config(name=...)`` on the returned config.
    """
    provider = _provider_registry["provider"]
    if provider is not None:
        provided = provider()
        if provided is not None:
            _validate_global_config(provided)
            # provided is a DataRobotAppFrameworkBaseSettings subclass (validated
            # above); genai resolves everything off it through its resolve_* methods.
            # Cast to Config for typing since genai cannot import the app's class.
            return cast(Config, provided)

    _warn_no_config_provider()
    return Config()

registered_default_llm_name

registered_default_llm_name() -> str

Return the app's registered default LLM instance name ("llm" if none).

This is a plain lookup of the name registered with :func:register_config_provider, and nothing more. It exists so a call site with no instance name of its own can still target the app's namespace:

config = resolve_config()
llm_config = config.resolve_llm_config(name=registered_default_llm_name())

Deliberately returns a str and not an :class:LLMConfig. See the DO NOT note above: genai must not have a function that resolves an LLM config for you.

Source code in datarobot_genai/core/config.py
def registered_default_llm_name() -> str:
    """Return the app's registered default LLM instance name (``"llm"`` if none).

    This is a plain lookup of the name registered with
    :func:`register_config_provider`, and nothing more. It exists so a call site
    with no instance name of its own can still target the app's namespace:

        config = resolve_config()
        llm_config = config.resolve_llm_config(name=registered_default_llm_name())

    Deliberately returns a ``str`` and not an :class:`LLMConfig`. See the DO NOT
    note above: genai must not have a function that resolves an LLM config for you.
    """
    return cast(str, _provider_registry["default_llm_name"])

get_max_history_messages_default

get_max_history_messages_default() -> int

Return the default maximum number of history messages.

genai does not declare this field itself, so standalone genai always gets DEFAULT_MAX_HISTORY_MESSAGES. A component that declares max_history_messages on its own registered config drives the value instead (like af-component-agent). Negative values are treated as 0 (disable history).

Source code in datarobot_genai/core/config.py
def get_max_history_messages_default() -> int:
    """Return the default maximum number of history messages.

    genai does not declare this field itself, so standalone genai always gets
    ``DEFAULT_MAX_HISTORY_MESSAGES``. A component that declares
    ``max_history_messages`` on its own registered config drives the value
    instead (like af-component-agent). Negative values are treated as 0 (disable history).
    """
    config = resolve_config()
    return max(getattr(config, "max_history_messages", DEFAULT_MAX_HISTORY_MESSAGES), 0)

default_response_model

default_response_model() -> str

Return the configured model to report in OpenAI chat/completions responses.

dragent agents ignore the request's model and run the LLM configured in workflow.yaml / env, so the response should report that actual model, not echo the caller's string (which need not be sent at all) nor NAT's "unknown-model" placeholder. Resolves the same way the LLM client does (the default LLM's model), always datarobot/-prefixed and never None so the response can never regress to "unknown-model".

Source code in datarobot_genai/core/config.py
def default_response_model() -> str:
    """Return the configured model to report in OpenAI ``chat/completions`` responses.

    dragent agents ignore the request's ``model`` and run the LLM configured in
    ``workflow.yaml`` / env, so the response should report that actual model, not
    echo the caller's string (which need not be sent at all) nor NAT's
    ``"unknown-model"`` placeholder. Resolves the same way the LLM client does
    (the default LLM's model), always ``datarobot/``-prefixed and never ``None`` so
    the response can never regress to ``"unknown-model"``.
    """
    return _with_datarobot_prefix(default_model_name() or "datarobot-deployed-llm")

default_assume_native_tool_calling_when_unmapped

default_assume_native_tool_calling_when_unmapped() -> bool

Return the CrewAI native-tool-calling override for unmapped NIM models.

When LiteLLM has no catalog entry for a NIM model, this reports native tool-calling support so CrewAI uses API tool_calls instead of the ReAct text path. Like :func:get_max_history_messages_default, genai does not declare the field, so standalone genai is always False and a component that declares assume_native_tool_calling_when_unmapped drives it (like af-component-agent).

Source code in datarobot_genai/core/config.py
def default_assume_native_tool_calling_when_unmapped() -> bool:
    """Return the CrewAI native-tool-calling override for unmapped NIM models.

    When LiteLLM has no catalog entry for a NIM model, this reports native
    tool-calling support so CrewAI uses API ``tool_calls`` instead of the ReAct
    text path. Like :func:`get_max_history_messages_default`, genai does not
    declare the field, so standalone genai is always ``False`` and a component
    that declares ``assume_native_tool_calling_when_unmapped`` drives it
    (like af-component-agent).
    """
    config = resolve_config()
    return bool(getattr(config, "assume_native_tool_calling_when_unmapped", False))