AI replies
When a user chats one-to-one with an AI bot, the bot's reply is a message of type ai whose content is pushed while it is being generated. im.ai receives this live content: it joins it in order, resumes after disconnects and fills in after reconnecting, and once the reply ends the message body is authoritative. You only need to display it. Bots and replies are created by your server, see AI conversations.
Version
AI replies are available from 1.0.0-alpha.3; upgrade to the current version: flutter pub add deeprespond_im_flutter:^1.0.0-alpha.4 (from 1.0.0-alpha.4 this is the only package you need).
Bots
In the client a bot is a normal user: its profile's kind is bot, it can be added as a friend and appears in the conversation list, and users simply send it text messages. Bots cannot be added to groups; inviting one fails with permission_denied (details.reason is bot_account).
AI messages
When MessageView.type is ai, read the body with im.ai.bodyOf(message):
final body = im.ai.bodyOf(message); // 不是 ai 消息时为 null
if (body != null) {
print(body.status); // streaming、completed、stopped、failed
print(body.parts); // 结束后的完整内容;生成中为空
}| Field | Description |
|---|---|
streamId | Stream ID of the reply, used to read live content and to stop generation |
status | streaming generating, completed, stopped, failed interrupted |
parts | Parts (AIPart): text body (Markdown), reasoning, image and file attachments, tool tool-call progress (state is running, done or failed) |
text | Plain text without Markdown, up to 2000 characters, for copying and previews |
finishReason, error | Finish reason; when interrupted, error.message is the explanation to show the user |
Parts are described fully in AI messages. Conversation previews (summarize() supports AI messages, with wording for generating, stopped and interrupted replies), unread counts and search work like normal messages.
Display content while generating
While a message is generating its parts is empty; the live content is in im.ai.state(streamId), and every update emits an AIStreamUpdated event:
List<AIPart> partsOf(MessageView message) {
final body = im.ai.bodyOf(message);
if (body == null) return const [];
return body.status == 'streaming' ? im.ai.state(body.streamId)?.parts ?? const [] : body.parts;
}
final sub = im.on<AIStreamUpdated>().listen((e) {
// e.state.parts 是当前完整内容(不是增量),按它整体重画这条消息
setState(() {});
});
// 页面销毁时:sub.cancel();| Event | When |
|---|---|
AIStreamStarted | A generating AI message arrives |
AIStreamUpdated | The content changes: new content arrived, or it was filled in after a disconnect or reconnect; state.parts is the full current content |
AIStreamEnded | The reply ended (status is completed, stopped or failed); the final content is in the message body and the message list updates afterwards |
- Pushes are merged into one every 50 ms or 2 KB. Let only the widget showing this message subscribe and rebuild; do not rebuild the whole list on every update.
- After disconnects, returning from the background or restarting the app, the SDK fills in content still being generated; you do not need to handle it.
im.ai.state()returnsnullafter the reply ends; read the message body from then on.
Stop generating
final stream = await im.ai.stop(body.streamId);
// stream.status 为 stopped;已结束的回复返回当前状态,不报错Only the user receiving the reply can stop it. Stopping ends the reply immediately, keeps what was generated, and notifies the bot's server. To read a reply's current content from the server, use im.ai.get(streamId); replies that ended more than 10 minutes ago fail with not_found, so read the message instead.
Regenerate
There is no separate "regenerate" API: send the answered question again and the bot's server starts a new reply. An AI message's replyTo points to the message it answers.
Example app
The chat page of the example app already displays AI replies (lib/pages/ai_bubble.dart) and can serve as a reference:
- The body is rendered as Markdown (headings, bold, inline code, lists, quotes, code blocks, tables), with a cursor at the end while generating;
- Reasoning, tool-call progress (running, done, failed, canceled) and file attachments;
- "Stop generating" while generating, "Copy" afterwards; notices for stopped and interrupted replies (with the reason).
Showing Chinese on the Linux desktop needs a Chinese font; the example sets fontFamilyFallback in its theme (Noto Sans CJK SC, WenQuanYi Micro Hei and others), otherwise Chinese shows as boxes.
