Логика состояния строки меню
Что отображается
- Мы отображаем текущее рабочее состояние агента в значке строки меню и в первой строке состояния меню.
- Состояние здоровья скрывается, пока работа активна; оно возвращается, когда все сеансы бездействуют.
- Блок «Nodes» в меню перечисляет только устройства (сопряжённые узлы через
node.list), а не записи клиентов/присутствия. - Раздел «Usage» появляется под «Context», когда доступны снимки использования провайдера.
Модель состояний
- Сеансы: события приходят с
runId(per-run) плюсsessionKeyв полезной нагрузке. «Основной» сеанс — это ключmain; если он отсутствует, используется наиболее недавно обновлённый сеанс. - Приоритет: основной всегда имеет приоритет. Если основной активен, его состояние отображается немедленно. Если основной бездействует, отображается наиболее недавно активный неосновной сеанс. Мы не «переключаемся туда‑сюда» в середине активности; переключение происходит только когда текущий сеанс становится бездействующим или основной становится активным.
- Виды активности:
job: выполнение высокоуровневых команд (state: started|streaming|done|error).tool:phase: start|resultсtoolNameиmeta/args.
Перечисление IconState (Swift)
idleworkingMain(ActivityKind)workingOther(ActivityKind)overridden(ActivityKind)(переопределение для отладки)
ActivityKind → глиф
exec→ 💻read→ 📄write→ ✍️edit→ 📝attach→ 📎- default → 🛠️
Визуальное сопоставление
idle: обычный «криттер».workingMain: бейдж с глифом, полная окраска, анимация «working» для лап.workingOther: бейдж с глифом, приглушённая окраска, без «шуршания».overridden: использует выбранные глиф/окраску независимо от активности.
Текст строки состояния (меню)
- Пока работа активна:
<Session role> · <activity label>- Примеры:
Main · exec: pnpm test,Other · read: apps/macos/Sources/OpenClaw/AppState.swift.
- Примеры:
- В состоянии простоя: возвращается к сводке состояния здоровья.
Приём событий
- Источник: события канала управления
agent(ControlChannel.handleAgentEvent). - Разобранные поля:
stream: "job"сdata.stateдля начала/окончания.stream: "tool"сdata.phase,name, необязательныеmeta/args.
- Метки:
exec: первая строкаargs.command.read/write: сокращённый путь.edit: путь плюс предполагаемый тип изменения изmeta/счётчиков diff.- fallback: имя инструмента.
Переопределение отладки
- Настройки ▸ Debug ▸ селектор «Icon override»:
System (auto)(по умолчанию)Working: main(по типу инструмента)Working: other(по типу инструмента)Idle
- Сохраняется через
@AppStorage("iconOverride"); сопоставляется сIconState.overridden.
Чек‑лист тестирования
- Запустить задание основного сеанса: убедиться, что значок переключается немедленно и строка состояния показывает метку основного.
- Запустить задание неосновного сеанса, пока основной простаивает: значок/статус показывает неосновной; остаётся стабильным до завершения.
- Запустить основной, пока другой активен: значок мгновенно переключается на основной.
- Быстрые серии инструментов: убедиться, что бейдж не мерцает (TTL‑поблажка на результаты инструментов).
- Строка здоровья появляется снова, как только все сеансы бездействуют.