Адаптеры статусов жизненного цикла каналов
Дата: 2026-07-01
Цель
Предоставить состояние жизненного цикла задачи через первые четыре адаптера каналов:
- Telegram
- Weixin
- DingTalk
- Feishu
Это продолжение задачи P1.1 по работе с идентификацией каналов и метаданными жизненного цикла. Цель — заставить каждый поддерживаемый канал отображать наилучший доступный нативный сигнал прогресса, не изменяя при этом общий контракт канала.
Не цели
- Не реализовывать поведение для Slack.
- Не реализовывать поведение для QQ Bot.
- Не обновлять примеры моков/плагинов.
- Не добавлять эмодзи терминального статуса для DingTalk.
- Не вводить общую абстракцию для рендеринга статусов ради одного раунда специфичных для адаптеров маппингов.
Ссылки и согласованность
При проектировании в первую очередь учитываются текущие возможности адаптеров каналов Qwen. Семантика жизненного цикла остается согласованной с существующей моделью статусов задач/сессий, уже используемой в этом репозитории: задача может начаться, выполняться, завершиться, быть отменена или завершиться с ошибкой. В этом скоупе не вводится дополнительная внешняя модель статусов, так как каждый канал уже имеет четкую нативную поверхность для этих состояний.
Текущее состояние
| Канал | Существующая поверхность статусов | Текущее поведение |
|---|---|---|
| Telegram | Индикатор набора текста | Начинает набор при старте промпта и останавливает при его завершении. |
| Weixin | Индикатор набора текста | Начинает набор при старте промпта и останавливает при его завершении. |
| DingTalk | Реакция на сообщение | Добавляет реакцию «глаз» при старте промпта и отзывает её при завершении. |
| Feishu | Стриминговая карточка | Отображает и обновляет стриминговую карточку, включая пути завершения и обработки ошибок. |
Предлагаемый дизайн
Реализация должна быть локальной для каждого адаптера. Каждый адаптер потребляет хук события жизненного цикла и маппит событие на существующую нативную поверхность статусов платформы.
| Событие жизненного цикла | Telegram | Weixin | DingTalk | Feishu |
|---|---|---|---|---|
started | Начать набор. | Начать набор. | Добавить реакцию «глаз». | Показать/обновить карточку как выполняющуюся. |
text_chunk | Игнорировать. | Игнорировать. | Игнорировать. | Игнорировать в хуке жизненного цикла. Стриминг контента остается на существующем пути стриминга ответов/карточек. |
tool_call | Игнорировать. | Игнорировать. | Игнорировать. | Игнорировать для UI. |
completed | Остановить набор. | Остановить набор. | Отозвать реакцию «глаз». | Отметить карточку как завершенную. |
cancelled | Остановить набор. | Остановить набор. | Отозвать реакцию «глаз». | Отметить карточку как отмененную. |
failed | Остановить набор. | Остановить набор. | Отозвать реакцию «глаз». | Отметить карточку как завершенную с ошибкой. |
Telegram
Telegram сохраняет существующую реализацию набора текста. Хук жизненного цикла должен маппить started на существующий путь начала набора текста, а все терминальные события — на путь остановки набора.
text_chunk и tool_call не требуют изменений в UI Telegram.
Weixin
Weixin следует той же структуре, что и Telegram. Хук жизненного цикла должен маппить started на setTyping(true), а терминальные события — на setTyping(false).
Дополнительные сообщения не отправляются.
DingTalk
DingTalk сохраняет существующее поведение реакции «глаз»:
started: добавить существующую реакцию «глаз».completed,cancelled,failed: отозвать существующую реакцию «глаз».
В этом скоупе нет терминальных эмодзи. Задачи со статусом failed и cancelled не должны отправлять дополнительные сообщения о статусе, если только существующий путь обработки ошибок уже не делает этого.
Feishu
Feishu сохраняет стриминговую карточку в качестве поверхности статусов и делает терминальное состояние явным в содержимом карточки:
| Состояние | Метка карточки |
|---|---|
| Выполняется | 运行中... |
| Завершено | 已完成 |
| Отменено | 已取消 |
| Ошибка | 已失败,请重试 |
Карточка по-прежнему стримит контент ответа, как и сегодня, через существующий хук стриминга ответов/карточек. Событие жизненного цикла text_chunk не потребляется адаптером напрямую в этом скоупе, что отменяет более раннюю идею использования чанков жизненного цикла для добавления контента в карточку на уровне адаптера. tool_call остается скрытым от UI карточки в этом скоупе.
Хелпер для markdown/карточек может принимать минимальную опцию метки статуса при необходимости, но не должен перерастать в универсальный фреймворк для рендеринга.
Поток данных
- Выполнение канала генерирует события жизненного цикла из базового слоя канала.
- Выбранный адаптер получает событие через свой хук жизненного цикла.
- Адаптер маппит событие на поверхность статусов платформы.
- Обновления статусов платформы выполняются в режиме best-effort и не влияют на выполнение задачи.
Полезная нагрузка события жизненного цикла должна предоставлять достаточно существующего контекста для идентификации сообщения/сессии канала. Если специфичный для платформы идентификатор отсутствует, адаптер пропускает обновление статуса.
Обработка ошибок
Обновления статусов платформы не являются критичными. Сбой при наборе текста, реакции или обновлении статуса карточки должен логироваться или игнорироваться в соответствии с существующим стилем адаптера и не должен приводить к сбою задачи.
Терминальные события должны быть идемпотентными для сообщения/сессии. Повторные терминальные события не должны создавать дублирующиеся обновления статуса или оставлять устаревший индикатор выполнения.
Feishu требует особого внимания, так как в нем уже есть потоки завершения карточки, обработки ошибок и кнопки остановки. Маппинг жизненного цикла должен переиспользовать существующее состояние сессии карточки и избегать конкурирующих обновлений, которые перезаписывают более специфичное терминальное состояние.
План тестирования
Добавить целенаправленное юнит-покрытие в затронутые пакеты каналов:
- Telegram: событие
startedзапускает набор текста; терминальные события останавливают набор; не вводится дублирующий интервал набора. - Weixin: событие
startedвызываетsetTyping(true); терминальные события вызываютsetTyping(false). - DingTalk: событие
startedдобавляет реакцию «глаз»; терминальные события отзывают её; терминальные эмодзи не отправляются. - Feishu: состояния карточки running, completed, cancelled и failed рендерят ожидаемые метки; событие
text_chunkостается в ведении существующего пути стриминга, а не хука жизненного цикла;tool_callне добавляет вывод в UI.
Для верификации следует запустить локальные для пакета команды Vitest для затронутых адаптеров, затем выполнить сборку проекта и проверку типов перед отправкой PR.
Открытые вопросы
Отсутствуют. Текущий скоуп намеренно узок и следует существующим возможностям адаптеров.