Результат шага

CommandStepResult — объект, который шаг возвращает после обработки Update.

Он описывает, что должно произойти дальше в рамках многошаговой команды.

Важно понимать:

CommandStepResult управляет только переходами между шагами. Он не может завершить команду напрямую и не выполняет навигацию. Эта ответственность принадлежит уровню команды.

Структура CommandStepResult

public class CommandStepResult
{
    public CommandStepAction Action { get; init; }
    public int GoToStepNumber { get; init; }
    public CommandStepHoldOnReason HoldOnReason { get; init; }
    public string? HoldOnMessage { get; init; }

    public static CommandStepResult Next => ...
    public static CommandStepResult Previous => ...
    public static CommandStepResult HoldOn(...) => ...
    public static CommandStepResult GoTo(int stepNumber) => ...
}

Основная идея — один объект описывает намерение шага.

Возможные действия

CommandStepAction определяет тип перехода:

public enum CommandStepAction
{
    MoveNext,
    HoldOn,
    MovePrevious,
    GoTo
}

### MoveNext

Переход к следующему шагу.

Обычно используется, когда ввод валиден и шаг успешно завершён.

### MovePrevious

Переход к предыдущему шагу.

Используется реже, например при реализации кнопки “Назад”.

Если текущий шаг — первый, будет выброшено исключение, так как номер шага не может быть отрицательным.

### GoTo

Переход к шагу с конкретным номером.

Позволяет реализовать произвольную логику переходов.

Если номер шага превышает количество шагов в команде, команда считается завершённой.

### HoldOn

Оставляет выполнение на текущем шаге.

Используется в ситуациях:

  • инициализация шага;

  • некорректный ввод пользователя;

  • ожидание повторного ввода.

HoldOnMessage позволяет отправить пользователю сообщение с объяснением причины остановки.

Фабричные методы

Для удобства используются статические методы:

CommandStepResult.Next
CommandStepResult.Previous
CommandStepResult.GoTo(stepNumber)
CommandStepResult.HoldOn(reason, message)

Это упрощает читаемость кода шага.

Граничные случаи

Поведение оркестратора шагов:

  • Previous на первом шаге → исключение.

  • Next на последнем шаге → завершение команды.

  • GoTo(N), где N больше количества шагов → завершение команды.

Таким образом, завершить Stateful-команду можно:

  • вернув Next на последнем шаге;

  • вернув GoTo с номером шага вне диапазона.

Связь с CommandResult

CommandStepResult не изменяет ChatSession напрямую.

Он преобразуется оркестратором в соответствующий CommandResult:

  • MoveNextGoToStatefulResult

  • HoldOnHoldOnStatefulResult

  • и т.д.

Подробности логики перехода находятся в реализации Stateful-оркестратора.

Практическая модель

Шаг отвечает за локальную логику. Команда отвечает за жизненный цикл. Интерпретаторы отвечают за изменение состояния.

Такое разделение делает поведение предсказуемым и упрощает построение сложных диалогов.