# Агент

Агент — SWR-наблюдатель, связывающий UI-компонент с [записью кэша][cache]. Он отслеживает текущую запись, транслирует её состояние в плоский реактивный сигнал и управляет переходами при смене аргументов. Агент используется как [ресурсами][usage-res], так и [командами][usage-cmd] — хуки `useResource` и `useCommand` создают его автоматически.

## SKIP и состояние idle

Специальный символ `SKIP` передаётся вместо аргументов, когда запрос выполнять не нужно — например, пока зависимые данные ещё не готовы. Агент переходит в состояние `idle`: запись кэша не создаётся, сетевой запрос не выполняется.

## SWR-fallback при смене аргументов

Агент хранит два слота: **текущая** и **предыдущая** запись. При смене аргументов:

1. Если предыдущая запись содержит данные (`success` / `refreshing`/`refresh-error`), агент сохраняет их как устаревшие.
2. Пока новая запись в `pending`, агент отдаёт устаревшие данные и выставляет статус `refreshing` с флагом `isSwitching: true`; `dataArgs` при этом указывает на аргументы предыдущей записи, `args` — на новые. При `error` данные из предыдущей записи остаются доступны (`dataArgs` — их аргументы), но статус — `error`.
3. Как только новая запись разрешается `success` — предыдущий слот очищается.

Благодаря этому UI показывает предыдущие данные вместо пустого состояния, пока новый запрос загружается.

React-хуки (`useResource`, `useSuspenseResource`, `useInfiniteResource`) не вызывают `set` на живом агенте: рендер должен оставаться чистым, а общий мутируемый агент между параллельными рендерами React (transition-ветка и закоммиченное дерево) зацикливал бы обновления. Вместо этого хук создаёт агент на каждую пару «ресурс + ключ args», а устаревшие данные передаются новому агенту от последнего закоммиченного через `adoptPrevious` — с теми же правилами, что и у `set`.

## Статусы

Агент предоставляет шесть статусов:

- **idle** — передан `SKIP`, наблюдение не активно.
- **pending** — первичный запрос в процессе.
- **success** — данные получены.
- **error** — запрос завершился ошибкой.
- **refreshing** — фоновое обновление (SWR); устаревшие данные доступны. Как состояние машины — только у ресурсов (через `refresh()`). Как статус агента — также при SWR-маскировании (`pending` + предыдущие данные).
- **refresh-error** — фоновое обновление завершилось ошибкой; устаревшие данные сохранены. Только для ресурсов.

Статус `refresh-error` — это полноценное состояние [машины состояний][machine] (переход `refreshing → refresh-error` при ошибке фонового обновления). Агент транслирует его напрямую, без трансформации.

Булевые флаги и полная таблица соответствий описаны в руководствах по [ресурсам][usage-res] и [командам][usage-cmd].

Подробные sequence-диаграммы потоков (cache miss, cache hit, refresh, SWR-fallback и др.) — в [dataflows.md][dataflows].

## Матрица состояний

| Состояние машины | Статус агента | data | dataArgs | Описание поведения |
|---|---|---|---|---|
| _(нет записи / SKIP)_ | `idle` | `null` | `null` | Запрос не выполняется |
| `pending` | `pending` | `null` | `null` | Ожидание первого ответа |
| `pending` + _previous_ | `refreshing` (`isSwitching`) | stale data из prev | args prev | SWR: pending маскируется в refreshing; stale данные показываются, пока новая запись загружается |
| `pending` (`isRetrying`) | `pending` (`isRetrying`) | `null` | `null` | Повтор после `error` через `retry()`; `error` хранит повторяемую ошибку |
| `success` | `success` | `TData` | = args | Данные получены |
| `error` | `error` | `null` | `null` | Ошибка, данных нет |
| `error` + _previous_ | `error` | stale data из prev | args prev | Ошибка; stale данные из prev доступны, но статус — error |
| `refreshing` | `refreshing` | stale `TData` | = args | Фоновое обновление, показываются устаревшие данные (только ресурс) |
| `refreshing` (`isRetrying`) | `refreshing` (`isRetrying`) | stale `TData` | = args | Повтор после `refresh-error` через `retry()`; `error` хранит повторяемую ошибку |
| `refresh-error` | `refresh-error` | stale `TData` | = args | Обновление завершилось ошибкой, стейл данные сохраняются (только ресурс) |

Подробнее о механизме слотов — в разделе [SWR-fallback при смене аргументов][swr-fallback].

## См. также

- [Потоки данных][dataflows] — диаграммы всех ресурсных и командных потоков.
- [Машина состояний][machine] — состояние, которое агент транслирует из записи кэша.
- [Кэш][cache] — хранилище записей, за которыми наблюдает агент.
- [Использование ресурсов][usage-res] — хук `useResource` и полная таблица состояний.
- [Использование команд][usage-cmd] — хук `useCommand` и жизненный цикл мутаций.
- [API: createResource][api-res] — создание ресурса и его агента.
- [API: createCommand][api-cmd] — создание команды и её агента.

---

[swr-fallback]: #swr-fallback-при-смене-аргументов
[machine]: machine.md
[cache]: cache.md
[dataflows]: dataflows.md
[usage-res]: ../usage/resource.md
[usage-cmd]: ../usage/command.md
[api-res]: ../api/resource.md
[api-cmd]: ../api/command.md
