y83 code / инструмент

Задачи

Экран «Задачи» показывает реестр фоновых задач оркестратора: какие сабагент-сессии запущены, какие упали и почему, и позволяет продолжить прерванный прогон прямо из приложения.

раздел реестра
AI и агенты
код
528 строк в 2 файлах
документ
16-tasks.md
Раздел: AI & Agents
Идентификатор: tasks · Экран: ui/tasks/TasksScreen.kt (410) + TasksViewModel.kt (118)
Снимок: 2026-10-11

1. Зачем и что это

Реестр ведёт backend сам (auto-task-registry): связь «key задачи → session_id сабагента» и статусы. Задача появляется в реестре, когда промпт сабагента начинается со строки вида «Задача auto-task-registry: …» — тогда реестр извлекает key и привязывает его к сессии. Это соглашение оркестратора, а не функция приложения.

Главная ценность экрана — кнопка Resume: она пишет сообщение прямо в чужую сессию сабагента, которая потерялась, зависла в busy или была прервана.

2. Как попасть

Хаб инструментов → секция AI & Agents → карточка «Задачи» (hub_tasks_title, подпись «Фоновые задачи и возобновление прерванных прогонов», тайл «Задачи»).

Откуда ещёПуть
Мостapp_navigate с screen: "tasks"

Маршрут: Screen.kt:156 ("tasks" -> Screen.Tasks) → MainRouter.kt:250 (TasksScreen(onBack = …)).

3. Экран: элементы и действия

ЭлементЧто делаетГде в коде
Шапка y83@tasks :~$Терминальная шапка; meta: «N tasks · serve up/down/unknown»TASKS_PROMPT, tasksMetaLabel
Кнопка RefreshПерезагрузка спискаviewModel.refresh()
Кнопка MoreVertМеню с единственным пунктом «Rescan registry»DropdownMenu
Ряд чипов фильтраAll / Running / Completed / Error / AbortedTASK_FILTERS + SelectChip
Pull-to-refreshОбновить список жестомPullToRefreshBox
Карточка задачиТочка статуса, key (моноширинный), время «сколько назад», title, agent · status · attempt N, ошибкаTaskRow
Пустое состояние«No tasks in the registry» + пояснение про «Задача <key>: …» + кнопка RescanTasksEmptyState
Диалог Resumekey, session, status, attempt, ошибка + поле сообщенияResumeTaskDialog

Точка статуса окрашена функцией taskStatusColor: running — успех (зелёный), error/aborted — ошибка (красный), остальное — нейтральный серый. Время показывается через elapsedLabel — «just now», «5m ago», «2h ago», «3d ago»; если метка неизвестна — «unknown».

4. Возможности подробно

Получение списка

TasksViewModel.refresh() вызывает tasksList(status = filter, limit = 50). Экран грузит первые 50 задач текущего фильтра; полный total приходит в ответе, но пагинации на экране нет — если задач больше 50, остальные не видны без REST-запроса вручную.

При первом открытии (tasks.isEmpty()) показывается полный спиннер, при повторном обновлении — только индикатор pull-to-refresh (isRefreshing = busy && !loading).

Фильтры

TASK_FILTERS = null→All, running, completed, error, aborted. Фильтр уходит на сервер, а не режется на клиенте. Смена фильтра немедленно вызывает refresh().

Resume по key

Диалог открывается тапом по карточке. В нём видно session <id> и attempt N, а поле сообщения по умолчанию — «продолжай». По кнопке Resume вызывается tasksResume(key, text).

Важно: resume идёт по key, а не по session_id — сессию подставляет сервер из реестра. Это защита от рассинхрона между экраном и живой сессией.

Сервер со своей стороны отправляет в сессию сабагента сообщение вида «Продолжай задачу <key>. <text>» и инкрементит attempt. Ответ содержит session_id, message_id, attempt, а экран показывает плашку «Resumed <key> · attempt N».

Rescan реестра

rescan() дёргает POST /api/v1/tasks/refresh — внеочередной backfill, который перечитывает сессии у opencode serve. Нужен, когда задача точно существует, но её нет в реестре (например, бэкенд перезапустился). После успеха экран автоматически перечитывает список и показывает «Registry refreshed».

Статусы и ошибки

Статусы: running | completed | error | aborted | unknown, переходы только вперёд. Причины aborted приходят в last_error:

Текст ошибкиЧто означает
session lost (serve)сессия пропала из opencode serve (3 поллинга подряд)
stuck busy (opencode #6573)running-сессия без активности дольше таймаута (по умолчанию 15 мин)

Поле serve в метрике шапки говорит, отвечает ли сейчас opencode serve. Если serve: "down", данные реестра могли устареть — resume в этом случае вернёт 503.

Соглашение по промпту

Ключ задачи извлекается из task-part input.prompt, а не из title сессии (модель может переписать title и потерять ключ). Промпт всегда должен начинаться со строки «Задача <key>: …», где key без пробелов и двоеточий. Без этого задача в реестр не попадёт — и экран покажет пустое состояние с этой же подсказкой.

5. Данные: БД, файлы, настройки

ЧтоГде лежитКак меняетсяКто читает
Реестр задачПамять backend (in-memory), не в SQLiteСобытия opencode serve + backfillGET /api/v1/tasks
Восстановление реестраBackfill GET /session при старте + поллинг 45 с + подписка /eventАвтоматическиBackend

DTO задачи (data/api/TasksApi.kt): key, session_id, parent_session_id, agent, title, status, task_part_status, attempt, last_error, created, updated, last_seen.

6. Backend: REST/роуты

Метод и путьНазначениеОбработчик
GET /api/v1/tasksвесь реестр (фильтры status, key, parent, limit)tr.List
POST /api/v1/tasks/refreshвнеочередной backfilltr.Refresh
POST /api/v1/tasks/{key}/resumeпродолжить задачу (пишет в сессию сабагента)tr.Resume

Роуты: backend/internal/api/v1/routes.go:317–319. Реализация: backend/internal/tasks/* (Store/Service/event/backfill/worker). Серверная версия реестра — 0.6.0.

Ошибки resume: 404 «task not found», 503 «opencode serve недоступен», 400 «bad json». Refresh может вернуть 409 «refresh in progress», если сканирование уже идёт.

7. Мост и MCP

ЧтоКакПримечание
Открыть экранapp_navigate с screen: "tasks"BridgeScreenCatalog
Список задачGET /api/v1/tasks?status=runningСкилл y83-tasks
ПродолжитьPOST /api/v1/tasks/{key}/resumeСкилл y83-tasks
Обновить реестрPOST /api/v1/tasks/refreshСкилл y83-tasks

Отдельных MCP-тулов для задач в инвентаре /mcp нет — агент работает с реестром через REST. Документация — docs/tasks.md, план — /root/plans/auto-task-registry.md.

8. Настройки, конфиг, квоты и лимиты

ПараметрЗначениеГде задаётся
Лимит выборки на экране50tasksList(limit = 50)
Поллинг реестра45 сBackend worker
Таймаут «stuck busy»15 мин (TASK_REGISTRY_BUSY_TIMEOUT)Backend env
Порог «session lost»3 поллингаTASK_REGISTRY_LOST_POLLS
Фильтров статуса5 (All + 4 статуса)TASK_FILTERS

9. Ловушки и ограничения

  • Показ ограничен 50 задачами — пагинации на экране нет. Если задач больше, список обрезан; за полной картиной нужно идти в REST.
  • Ключ задачи зависит от формата промпта. Если промпт не начинается с «Задача <key>: …», задача просто не появится в реестре — экран покажет пустое состояние с этой подсказкой.
  • serve: down означает «данные могли устареть». Реестр живёт в памяти backend, при падении serve он не обновляется; resume вернёт 503.
  • Resume при stuck busy создаёт новое сообщение в той же сессии — статус пересчитается при активности. При session lost так не выйдет: сессии больше нет, задачу нужно перезапустить с новым промптом «Задача <key>: …».
  • Refresh может вернуть 409, если сканирование уже идёт (это защита от параллельных запросов).
  • Все строки захардкожены по-английски — экран не локализован.
  • Кнопка Resume пишет в чужую сессию. Это осознанное действие оркестратора, поэтому оно спрятано за подтверждением в диалоге, а не делается одним тапом.
  • Статусы переходят только вперёд. После completed таск не вернётся в running, даже если вызвать resume.

10. Источники правды

  • app/src/main/java/com/y83/ws/ui/tasks/TasksScreen.kt — экран, форматирование, диалог Resume.
  • app/src/main/java/com/y83/ws/ui/tasks/TasksViewModel.kt — состояние, фильтры, rescan, resume.
  • app/src/main/java/com/y83/ws/data/api/TasksApi.kt — DTO и клиент.
  • backend/internal/api/v1/routes.go:317–319 — роуты.
  • backend/internal/tasks/* — Store/Service/event/backfill/worker реестра.
  • backend/internal/handlers/tasks/tasks.go — обработчики.
  • skills/y83-tasks/SKILL.md — соглашение оркестратора и сценарии.
  • docs/tasks.md — документация реестра.

Источник: docs/project/hub/16-tasks.md · AI и агенты · 528 строк в 2 файлах. Страница собирается из документации проекта при сборке сайта.