From a88c1c992d56b611a02e4f2e9f48b530676b1359 Mon Sep 17 00:00:00 2001 From: Cesar Cardoso Date: Thu, 2 Apr 2026 15:49:01 -0700 Subject: [PATCH 1/2] Add UNSET sentinel class Summary: Add UNSET sentinel class in ax/utils/common/sentinel.py for distinguishing "not provided" from None in runner config updates Reviewed By: andycylmeta Differential Revision: D97988143 --- ax/utils/common/sentinel.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 ax/utils/common/sentinel.py diff --git a/ax/utils/common/sentinel.py b/ax/utils/common/sentinel.py new file mode 100644 index 00000000000..2b8a7ca3f39 --- /dev/null +++ b/ax/utils/common/sentinel.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# pyre-strict + + +class Unset: + """Sentinel type for distinguishing "not provided" from an explicit ``None``. + + Use the module-level ``UNSET`` instance as the default value for + optional fields where ``None`` is a valid, meaningful value and a + separate "not set" state is needed. + """ + + def __repr__(self) -> str: + return "UNSET" + + +UNSET: Unset = Unset() From b298f8e5133430ae07daf210ed166f5d1c0ceb3d Mon Sep 17 00:00:00 2001 From: Cesar Cardoso Date: Thu, 2 Apr 2026 15:49:01 -0700 Subject: [PATCH 2/2] Add RunnerConfig typed configuration infrastructure Summary: Introduce `RunnerConfig` base class in `runner.py` with nested `SearchSpaceUpdateArguments` and `RunnerUpdateArguments` frozen dataclasses, and a `config_type` ClassVar on `Runner` so each runner subclass can declare its config type. Reviewed By: andycylmeta Differential Revision: D99150292 --- ax/core/runner.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/ax/core/runner.py b/ax/core/runner.py index 39d71ed99f8..89f2bdbed86 100644 --- a/ax/core/runner.py +++ b/ax/core/runner.py @@ -10,7 +10,8 @@ from abc import ABC, abstractmethod from collections.abc import Iterable -from typing import Any, Self, TYPE_CHECKING +from dataclasses import dataclass +from typing import Any, ClassVar, Self, TYPE_CHECKING from ax.utils.common.base import Base from ax.utils.common.serialization import SerializationMixin @@ -21,9 +22,27 @@ from ax import core # noqa F401 +class RunnerConfig: + @dataclass(frozen=True) + class SearchSpaceUpdateArguments: + """Base arguments for search space updates. Override in RunnerConfig + subclasses to add runner-specific fields.""" + + pass + + @dataclass(frozen=True) + class RunnerUpdateArguments: + """Base arguments for general runner updates. Override in RunnerConfig + subclasses to add runner-specific fields.""" + + pass + + class Runner(Base, SerializationMixin, ABC): """Abstract base class for custom runner classes""" + config_type: ClassVar[type[RunnerConfig]] = RunnerConfig + @property def staging_required(self) -> bool: """Whether the trial goes to staged or running state once deployed."""