fix(chat): fix ChatBloc event callback and test reliability
- Fix onEvent callback initialization in ChatBloc constructor - Add MockAgUiService to isolate test from mock API behavior - Remove unnecessary non-null assertions in tests
This commit is contained in:
@@ -8,6 +8,18 @@ import '../models/ag_ui_event.dart';
|
||||
import '../models/tool_result.dart';
|
||||
import '../tools/tool_registry.dart';
|
||||
|
||||
/// Mock ID 前缀常量
|
||||
const _threadIdPrefix = 'thread_';
|
||||
const _runIdPrefix = 'run_';
|
||||
const _toolCallIdPrefix = 'tc_';
|
||||
const _messageIdPrefix = 'msg_';
|
||||
|
||||
/// 流式输出延迟 (毫秒)
|
||||
const _streamChunkDelayMs = 50;
|
||||
|
||||
/// 文本块大小
|
||||
const _textChunkSize = 10;
|
||||
|
||||
typedef EventCallback = void Function(AgUiEvent event);
|
||||
|
||||
class AgUiService {
|
||||
@@ -27,8 +39,8 @@ class AgUiService {
|
||||
}
|
||||
|
||||
Future<void> _mockEventStream(String content) async {
|
||||
final threadId = 'thread_${DateTime.now().millisecondsSinceEpoch}';
|
||||
final runId = 'run_${DateTime.now().millisecondsSinceEpoch}';
|
||||
final threadId = '$_threadIdPrefix${DateTime.now().millisecondsSinceEpoch}';
|
||||
final runId = '$_runIdPrefix${DateTime.now().millisecondsSinceEpoch}';
|
||||
|
||||
onEvent(RunStartedEvent(threadId: threadId, runId: runId));
|
||||
|
||||
@@ -58,7 +70,8 @@ class AgUiService {
|
||||
String toolName,
|
||||
Map<String, dynamic> args,
|
||||
) async {
|
||||
final toolCallId = 'tc_${DateTime.now().millisecondsSinceEpoch}';
|
||||
final toolCallId =
|
||||
'$_toolCallIdPrefix${DateTime.now().millisecondsSinceEpoch}';
|
||||
|
||||
onEvent(ToolCallStartEvent(toolCallId: toolCallId, toolCallName: toolName));
|
||||
|
||||
@@ -82,7 +95,8 @@ class AgUiService {
|
||||
ToolRegistry.initialize();
|
||||
final result = await ToolRegistry.execute(toolName, args);
|
||||
final ui = _buildUiCard(toolName, result);
|
||||
final messageId = 'msg_${DateTime.now().millisecondsSinceEpoch}';
|
||||
final messageId =
|
||||
'$_messageIdPrefix${DateTime.now().millisecondsSinceEpoch}';
|
||||
|
||||
onEvent(
|
||||
ToolCallResultEvent(
|
||||
@@ -145,20 +159,20 @@ class AgUiService {
|
||||
|
||||
Future<void> _mockTextMessageStream(List<String> replies) async {
|
||||
for (final reply in replies) {
|
||||
final messageId = 'msg_${DateTime.now().millisecondsSinceEpoch}';
|
||||
final messageId =
|
||||
'$_messageIdPrefix${DateTime.now().millisecondsSinceEpoch}';
|
||||
|
||||
onEvent(TextMessageStartEvent(messageId: messageId, role: 'assistant'));
|
||||
|
||||
const chunkSize = 10;
|
||||
for (var i = 0; i < reply.length; i += chunkSize) {
|
||||
final end = (i + chunkSize < reply.length)
|
||||
? i + chunkSize
|
||||
for (var i = 0; i < reply.length; i += _textChunkSize) {
|
||||
final end = (i + _textChunkSize < reply.length)
|
||||
? i + _textChunkSize
|
||||
: reply.length;
|
||||
final chunk = reply.substring(i, end);
|
||||
|
||||
onEvent(TextMessageContentEvent(messageId: messageId, delta: chunk));
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 50));
|
||||
await Future.delayed(const Duration(milliseconds: _streamChunkDelayMs));
|
||||
}
|
||||
|
||||
onEvent(TextMessageEndEvent(messageId: messageId));
|
||||
|
||||
Reference in New Issue
Block a user