Skip to content

Commit f521ece

Browse files
committed
Version 1.0.4 is expected to be released.
1 parent bbb980e commit f521ece

1 file changed

Lines changed: 33 additions & 14 deletions

File tree

lib/features/chat/chat_provider.dart

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -626,24 +626,16 @@ class ChatNotifier extends StateNotifier<ChatState> {
626626
return;
627627
}
628628

629+
// ─── 防御性清理:上一轮被中断后 AgentLoop generator 可能在后续微任务
630+
// 中继续往 _agentMessages 追加了 tool/assistant(tool_calls) 消息,
631+
// 导致消息链不合法。在新一轮起步前再做一次 sanitize 确保干净。
632+
_sanitizeAgentMessages();
633+
629634
// 快照附件并立即清空 UI 中的附件列表
630635
final pendingAttachments = List<FileAttachment>.from(state.attachments);
631636

632-
// 如果当前没有会话,创建一个
633-
int? conversationId = state.currentConversationId;
634-
if (conversationId == null) {
635-
final title = input.length > 20 ? '${input.substring(0, 20)}...' : input;
636-
final conversation = await _conversationsDao.create(
637-
title: title,
638-
modelCardId: modelCard.id,
639-
);
640-
conversationId = conversation.id;
641-
state = state.copyWith(currentConversationId: conversationId);
642-
_ref.read(conversationsProvider.notifier).refresh();
643-
}
644-
637+
// ─── 立即更新 UI 状态 → 让按钮点击有即时视觉反馈,消除卡顿感 ───
645638
final userMsg = ChatMessage.user(input, attachments: pendingAttachments);
646-
// 新一轮开始前清理可能残留的流式缓冲/计时器
647639
_flushTimer?.cancel();
648640
_flushTimer = null;
649641
_streamBuffer.clear();
@@ -659,6 +651,24 @@ class ChatNotifier extends StateNotifier<ChatState> {
659651
preview: input.length > 30 ? '${input.substring(0, 30)}...' : input,
660652
);
661653

654+
// ─── 让出一帧给 UI 渲染 loading 状态,然后再执行重活 ───
655+
// 这保证了上面 setState 的新状态能先被 Flutter 引擎处理并绘制,
656+
// 用户看到的是"发送后立即进入 loading 动画",而不是"按钮卡住不动"。
657+
await Future<void>.delayed(Duration.zero);
658+
659+
// 如果当前没有会话,创建一个
660+
int? conversationId = state.currentConversationId;
661+
if (conversationId == null) {
662+
final title = input.length > 20 ? '${input.substring(0, 20)}...' : input;
663+
final conversation = await _conversationsDao.create(
664+
title: title,
665+
modelCardId: modelCard.id,
666+
);
667+
conversationId = conversation.id;
668+
state = state.copyWith(currentConversationId: conversationId);
669+
_ref.read(conversationsProvider.notifier).refresh();
670+
}
671+
662672
await _conversationsDao.saveMessage(conversationId, userMsg);
663673

664674
// 处理附件为 content parts
@@ -1042,6 +1052,15 @@ class ChatNotifier extends StateNotifier<ChatState> {
10421052
activeToolCalls: [],
10431053
);
10441054
}
1055+
1056+
// ─── 延迟防御清理 ───
1057+
// _subscription?.cancel() 只是调度了取消,AgentLoop 的 async* generator
1058+
// 在后续微任务中可能仍会往 _agentMessages 追加消息(比如 tool result 或
1059+
// assistant(tool_calls)),导致消息链再次进入不合法状态。
1060+
// 调度一个延迟微任务,在 generator 最终停止后做最后一遍 sanitize。
1061+
Future<void>.delayed(const Duration(milliseconds: 50)).then((_) {
1062+
if (mounted) _sanitizeAgentMessages();
1063+
});
10451064
}
10461065

10471066
/// 删除指定索引的消息

0 commit comments

Comments
 (0)