.qwen/design/2026-07-01-channel-lifecycle-status-adapters.md
Date: 2026-07-01
Expose task lifecycle state through the first four channel adapters:
This is a P1.1 follow-up to the channel identity and lifecycle metadata work. The goal is to make each supported channel show the best native progress signal available without changing the shared channel contract again.
The design follows the current Qwen channel adapter capabilities first. Lifecycle semantics stay aligned with the existing task/session status model already used in this repository: a task can start, run, complete, be cancelled, or fail. No additional external status model is introduced in this scope because each channel already has a clear native surface for these states.
| Channel | Existing status surface | Current behavior |
|---|---|---|
| Telegram | Typing indicator | Starts typing on prompt start and stops on prompt end. |
| Weixin | Typing indicator | Starts typing on prompt start and stops on prompt end. |
| DingTalk | Message reaction | Adds the eye reaction on prompt start and recalls it on prompt end. |
| Feishu | Streaming card | Shows and updates a streaming card, with completion and error paths. |
Keep the implementation adapter-local. Each adapter consumes the lifecycle event hook and maps the event into the platform's existing native status surface.
| Lifecycle event | Telegram | Weixin | DingTalk | Feishu |
|---|---|---|---|---|
started | Start typing. | Start typing. | Add eye reaction. | Show/update card as running. |
text_chunk | Ignore. | Ignore. | Ignore. | Ignore in the lifecycle hook. Content streaming stays on the existing response/card stream path. |
tool_call | Ignore. | Ignore. | Ignore. | Ignore for UI. |
completed | Stop typing. | Stop typing. | Recall eye reaction. | Mark card completed. |
cancelled | Stop typing. | Stop typing. | Recall eye reaction. | Mark card cancelled. |
failed | Stop typing. | Stop typing. | Recall eye reaction. | Mark card failed. |
Telegram keeps the existing typing implementation. The lifecycle hook should map
started to the existing typing start path and all terminal events to the
existing typing stop path.
text_chunk and tool_call do not need Telegram UI changes.
Weixin follows the same shape as Telegram. The lifecycle hook should map
started to setTyping(true) and terminal events to setTyping(false).
No additional messages are sent.
DingTalk keeps the existing eye reaction behavior:
started: attach the existing eye reaction.completed, cancelled, failed: recall the existing eye reaction.There is no terminal emoji in this scope. Failed and cancelled tasks should not send extra status messages unless an existing error path already does so.
Feishu keeps the streaming card as the status surface and makes the terminal state explicit in card content:
| State | Card label |
|---|---|
| Running | 运行中... |
| Completed | 已完成 |
| Cancelled | 已取消 |
| Failed | 已失败,请重试 |
The card still streams answer content as it does today through the existing
response/card stream hook. Lifecycle text_chunk is not consumed directly by
the adapter in this scope, which supersedes the earlier adapter-local idea of
using lifecycle chunks to append card content. tool_call remains hidden from
the card UI in this scope.
The markdown/card helper can accept a minimal status label option if needed, but should not grow into a generic rendering framework.
The lifecycle event payload should provide enough existing context to identify the channel message/session. If a platform-specific identifier is missing, the adapter skips the status update.
Platform status updates are non-critical. A failed typing, reaction, or card status update should be logged or swallowed according to the adapter's existing style and must not fail the task.
Terminal events should be idempotent for a message/session. Repeated terminal events should not create duplicate status updates or leave a stale running indicator.
Feishu needs special care because it already has card completion, error, and stop-button flows. The lifecycle mapping should reuse the existing card session state and avoid competing updates that overwrite a more specific terminal state.
Add focused unit coverage in the affected channel packages:
started starts typing; terminal events stop typing; no
duplicate typing interval is introduced.started calls setTyping(true); terminal events call
setTyping(false).started attaches the eye reaction; terminal events
recall it; no terminal emoji is sent.text_chunk remains owned by the existing stream
path rather than the lifecycle hook; tool_call does not add UI output.Verification should run package-local Vitest commands for the touched adapters, then project build and typecheck before the PR is submitted.
None. The current scope is intentionally narrow and follows existing adapter capabilities.