Diagnose interrupted agent SSE streams
This commit is contained in:
@@ -568,10 +568,16 @@ class ApiRepository {
|
||||
.send(request)
|
||||
.timeout(const Duration(minutes: 10));
|
||||
final auditId = streamed.headers['x-agent-audit-id'];
|
||||
final streamStopwatch = Stopwatch()..start();
|
||||
var heartbeatCount = 0;
|
||||
var lastEventName = 'بدء الاتصال';
|
||||
String withAuditId(String message) =>
|
||||
auditId == null || auditId.isEmpty
|
||||
? message
|
||||
: '$message\nمعرّف تتبع الطلب: $auditId';
|
||||
String streamDiagnostics() =>
|
||||
'بعد ${streamStopwatch.elapsed.inSeconds} ثانية؛ آخر حدث: '
|
||||
'$lastEventName؛ عدد النبضات: $heartbeatCount.';
|
||||
if (streamed.statusCode < 200 || streamed.statusCode >= 300) {
|
||||
final response = await http.Response.fromStream(streamed);
|
||||
_checkStatus(response);
|
||||
@@ -579,37 +585,50 @@ class ApiRepository {
|
||||
String? eventName;
|
||||
Map<String, dynamic>? resultData;
|
||||
String? streamError;
|
||||
await for (final line in streamed.stream
|
||||
.transform(utf8.decoder)
|
||||
.transform(const LineSplitter())
|
||||
.timeout(const Duration(minutes: 10))) {
|
||||
if (line.startsWith('event: ')) {
|
||||
eventName = line.substring(7).trim();
|
||||
} else if (line.startsWith('data: ')) {
|
||||
final data = jsonDecode(line.substring(6)) as Map<String, dynamic>;
|
||||
switch (eventName) {
|
||||
case 'progress':
|
||||
final message = data['message']?.toString();
|
||||
if (message != null) onProgress?.call(message);
|
||||
break;
|
||||
case 'heartbeat':
|
||||
onProgress?.call('الوكيل ما زال يعمل، أنتظر النموذج المحلي...');
|
||||
break;
|
||||
case 'done':
|
||||
resultData = data;
|
||||
break;
|
||||
case 'error':
|
||||
streamError =
|
||||
data['message']?.toString() ?? 'تعذر تنفيذ مهمة الوكيل.';
|
||||
break;
|
||||
try {
|
||||
await for (final line in streamed.stream
|
||||
.transform(utf8.decoder)
|
||||
.transform(const LineSplitter())
|
||||
.timeout(const Duration(minutes: 10))) {
|
||||
if (line.startsWith('event: ')) {
|
||||
eventName = line.substring(7).trim();
|
||||
lastEventName = eventName;
|
||||
} else if (line.startsWith('data: ')) {
|
||||
final data = jsonDecode(line.substring(6)) as Map<String, dynamic>;
|
||||
switch (eventName) {
|
||||
case 'progress':
|
||||
final message = data['message']?.toString();
|
||||
if (message != null) onProgress?.call(message);
|
||||
break;
|
||||
case 'heartbeat':
|
||||
heartbeatCount++;
|
||||
onProgress?.call('الوكيل ما زال يعمل، أنتظر النموذج المحلي...');
|
||||
break;
|
||||
case 'done':
|
||||
resultData = data;
|
||||
break;
|
||||
case 'error':
|
||||
streamError =
|
||||
data['message']?.toString() ?? 'تعذر تنفيذ مهمة الوكيل.';
|
||||
break;
|
||||
}
|
||||
eventName = null;
|
||||
}
|
||||
eventName = null;
|
||||
}
|
||||
} on Exception catch (error) {
|
||||
throw Exception(
|
||||
withAuditId(
|
||||
'انقطع اتصال بث الوكيل ${streamDiagnostics()} نوع الخطأ: '
|
||||
'${error.runtimeType}.',
|
||||
),
|
||||
);
|
||||
}
|
||||
if (streamError != null) throw Exception(withAuditId(streamError));
|
||||
final data = resultData;
|
||||
if (data == null) {
|
||||
throw Exception(withAuditId('انقطع اتصال البث قبل اكتمال الوكيل.'));
|
||||
throw Exception(
|
||||
withAuditId('انتهى البث قبل اكتمال الوكيل ${streamDiagnostics()}'),
|
||||
);
|
||||
}
|
||||
return AgentRunResult.fromApiData(data);
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user