neoagent 3.0.1-beta.19 → 3.0.1-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/flutter_app/lib/main_chat.dart +136 -120
- package/flutter_app/lib/main_controller.dart +1 -1
- package/flutter_app/lib/main_devices.dart +1 -1
- package/package.json +1 -1
- package/server/admin/admin.js +439 -1
- package/server/admin/index.html +71 -1
- package/server/public/.last_build_id +1 -1
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +23112 -23103
- package/server/routes/admin.js +359 -10
|
@@ -24,6 +24,10 @@ class _ChatPanelState extends State<ChatPanel> with WidgetsBindingObserver {
|
|
|
24
24
|
bool _ignoreScrollUpdates = false;
|
|
25
25
|
bool _loadingOlderHistory = false;
|
|
26
26
|
int _scrollGeneration = 0;
|
|
27
|
+
// Opacity-hide the list while the initial batch of messages settles to the
|
|
28
|
+
// bottom, so the user never sees the layout jitter across settle passes.
|
|
29
|
+
bool _awaitingInitialScrollSettle = false;
|
|
30
|
+
int _visibleMessageCountAtLastSettle = 0;
|
|
27
31
|
bool _isSendingChatMessage = false;
|
|
28
32
|
bool _isDictating = false;
|
|
29
33
|
bool _isTranscribing = false;
|
|
@@ -56,6 +60,8 @@ class _ChatPanelState extends State<ChatPanel> with WidgetsBindingObserver {
|
|
|
56
60
|
_appliedSharedPayloadSignature = null;
|
|
57
61
|
_lastScrollContentSignature = '';
|
|
58
62
|
_stickToBottom = true;
|
|
63
|
+
_awaitingInitialScrollSettle = false;
|
|
64
|
+
_visibleMessageCountAtLastSettle = 0;
|
|
59
65
|
_consumeQueuedDraft();
|
|
60
66
|
_scheduleScrollToBottom(force: true);
|
|
61
67
|
}
|
|
@@ -446,6 +452,12 @@ class _ChatPanelState extends State<ChatPanel> with WidgetsBindingObserver {
|
|
|
446
452
|
settle(remainingPasses - 1);
|
|
447
453
|
}
|
|
448
454
|
});
|
|
455
|
+
} else if (_awaitingInitialScrollSettle) {
|
|
456
|
+
setState(() {
|
|
457
|
+
_awaitingInitialScrollSettle = false;
|
|
458
|
+
_visibleMessageCountAtLastSettle =
|
|
459
|
+
widget.controller.visibleChatMessages.length;
|
|
460
|
+
});
|
|
449
461
|
}
|
|
450
462
|
});
|
|
451
463
|
}
|
|
@@ -462,6 +474,15 @@ class _ChatPanelState extends State<ChatPanel> with WidgetsBindingObserver {
|
|
|
462
474
|
final isInitialContent = _lastScrollContentSignature.isEmpty;
|
|
463
475
|
final shouldFollow = _stickToBottom || isInitialContent;
|
|
464
476
|
_lastScrollContentSignature = signature;
|
|
477
|
+
|
|
478
|
+
if (messages.isEmpty) {
|
|
479
|
+
// Agent switch resets the settle tracker so the next batch triggers hiding.
|
|
480
|
+
_visibleMessageCountAtLastSettle = 0;
|
|
481
|
+
} else if (_visibleMessageCountAtLastSettle == 0 && !_awaitingInitialScrollSettle) {
|
|
482
|
+
// Messages just went from 0 → N: hide until the scroll position settles.
|
|
483
|
+
_awaitingInitialScrollSettle = true;
|
|
484
|
+
}
|
|
485
|
+
|
|
465
486
|
if (shouldFollow) {
|
|
466
487
|
_scheduleScrollToBottom(force: isInitialContent);
|
|
467
488
|
}
|
|
@@ -561,26 +582,29 @@ class _ChatPanelState extends State<ChatPanel> with WidgetsBindingObserver {
|
|
|
561
582
|
Expanded(
|
|
562
583
|
child: Stack(
|
|
563
584
|
children: <Widget>[
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
child:
|
|
578
|
-
|
|
579
|
-
|
|
585
|
+
Opacity(
|
|
586
|
+
opacity: _awaitingInitialScrollSettle ? 0.0 : 1.0,
|
|
587
|
+
child: SelectionArea(
|
|
588
|
+
child: ListView(
|
|
589
|
+
controller: _scrollController,
|
|
590
|
+
padding: EdgeInsets.fromLTRB(
|
|
591
|
+
sidePadding,
|
|
592
|
+
30,
|
|
593
|
+
sidePadding,
|
|
594
|
+
18,
|
|
595
|
+
),
|
|
596
|
+
children: <Widget>[
|
|
597
|
+
Center(
|
|
598
|
+
child: ConstrainedBox(
|
|
599
|
+
constraints: const BoxConstraints(maxWidth: 860),
|
|
600
|
+
child: Column(
|
|
601
|
+
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
602
|
+
children: threadChildren,
|
|
603
|
+
),
|
|
580
604
|
),
|
|
581
605
|
),
|
|
582
|
-
|
|
583
|
-
|
|
606
|
+
],
|
|
607
|
+
),
|
|
584
608
|
),
|
|
585
609
|
),
|
|
586
610
|
if (!_stickToBottom)
|
|
@@ -4027,113 +4051,105 @@ class _RunHeroCard extends StatelessWidget {
|
|
|
4027
4051
|
|
|
4028
4052
|
@override
|
|
4029
4053
|
Widget build(BuildContext context) {
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
children: <Widget>[
|
|
4048
|
-
Row(
|
|
4049
|
-
crossAxisAlignment: CrossAxisAlignment.start,
|
|
4050
|
-
children: <Widget>[
|
|
4051
|
-
Expanded(
|
|
4052
|
-
child: Column(
|
|
4053
|
-
crossAxisAlignment: CrossAxisAlignment.start,
|
|
4054
|
-
children: <Widget>[
|
|
4055
|
-
Wrap(
|
|
4056
|
-
spacing: 10,
|
|
4057
|
-
runSpacing: 10,
|
|
4058
|
-
children: <Widget>[
|
|
4059
|
-
_StatusPill(
|
|
4060
|
-
label: run.statusLabel,
|
|
4061
|
-
color: run.statusColor,
|
|
4062
|
-
),
|
|
4063
|
-
_MetaPill(
|
|
4064
|
-
label: run.triggerLabel,
|
|
4065
|
-
icon: Icons.bolt_outlined,
|
|
4066
|
-
),
|
|
4067
|
-
_MetaPill(
|
|
4068
|
-
label: run.modelLabel,
|
|
4069
|
-
icon: Icons.memory_outlined,
|
|
4070
|
-
),
|
|
4071
|
-
if (run.deliverableType.trim().isNotEmpty)
|
|
4072
|
-
_MetaPill(
|
|
4073
|
-
label: run.deliverableType.replaceAll('_', ' '),
|
|
4074
|
-
icon: Icons.inventory_2_outlined,
|
|
4075
|
-
),
|
|
4076
|
-
],
|
|
4077
|
-
),
|
|
4078
|
-
const SizedBox(height: 16),
|
|
4079
|
-
Text(
|
|
4080
|
-
run.title,
|
|
4081
|
-
style: TextStyle(
|
|
4082
|
-
fontSize: 24,
|
|
4083
|
-
fontWeight: FontWeight.w800,
|
|
4084
|
-
height: 1.15,
|
|
4085
|
-
),
|
|
4086
|
-
),
|
|
4087
|
-
const SizedBox(height: 10),
|
|
4088
|
-
Wrap(
|
|
4089
|
-
spacing: 10,
|
|
4090
|
-
runSpacing: 10,
|
|
4091
|
-
children: <Widget>[
|
|
4092
|
-
_MetaPill(
|
|
4093
|
-
label: 'Started ${run.createdAtLabel}',
|
|
4094
|
-
icon: Icons.schedule_outlined,
|
|
4095
|
-
),
|
|
4096
|
-
_MetaPill(
|
|
4097
|
-
label: run.durationLabel,
|
|
4098
|
-
icon: Icons.timer_outlined,
|
|
4099
|
-
),
|
|
4100
|
-
_MetaPill(
|
|
4101
|
-
label: '${run.totalTokensLabel} tokens',
|
|
4102
|
-
icon: Icons.toll_outlined,
|
|
4103
|
-
),
|
|
4104
|
-
_MetaPill(
|
|
4105
|
-
label: run.id.length <= 12
|
|
4106
|
-
? run.id
|
|
4107
|
-
: '${run.id.substring(0, 12)}…',
|
|
4108
|
-
icon: Icons.tag_outlined,
|
|
4109
|
-
),
|
|
4110
|
-
],
|
|
4111
|
-
),
|
|
4112
|
-
],
|
|
4054
|
+
final statusColor = run.statusColor;
|
|
4055
|
+
return Card(
|
|
4056
|
+
child: Padding(
|
|
4057
|
+
padding: const EdgeInsets.all(14),
|
|
4058
|
+
child: Column(
|
|
4059
|
+
crossAxisAlignment: CrossAxisAlignment.start,
|
|
4060
|
+
children: <Widget>[
|
|
4061
|
+
Row(
|
|
4062
|
+
crossAxisAlignment: CrossAxisAlignment.center,
|
|
4063
|
+
children: <Widget>[
|
|
4064
|
+
Container(
|
|
4065
|
+
width: 8,
|
|
4066
|
+
height: 8,
|
|
4067
|
+
decoration: BoxDecoration(
|
|
4068
|
+
color: statusColor,
|
|
4069
|
+
shape: BoxShape.circle,
|
|
4070
|
+
),
|
|
4113
4071
|
),
|
|
4072
|
+
const SizedBox(width: 7),
|
|
4073
|
+
Text(
|
|
4074
|
+
run.statusLabel,
|
|
4075
|
+
style: TextStyle(
|
|
4076
|
+
color: statusColor,
|
|
4077
|
+
fontWeight: FontWeight.w600,
|
|
4078
|
+
fontSize: 12,
|
|
4079
|
+
),
|
|
4080
|
+
),
|
|
4081
|
+
const Spacer(),
|
|
4082
|
+
IconButton(
|
|
4083
|
+
tooltip: 'Delete run',
|
|
4084
|
+
icon: const Icon(Icons.delete_outline, size: 18),
|
|
4085
|
+
onPressed: onDelete,
|
|
4086
|
+
visualDensity: VisualDensity.compact,
|
|
4087
|
+
color: _textSecondary,
|
|
4088
|
+
),
|
|
4089
|
+
],
|
|
4090
|
+
),
|
|
4091
|
+
const SizedBox(height: 8),
|
|
4092
|
+
Text(
|
|
4093
|
+
run.title,
|
|
4094
|
+
style: const TextStyle(
|
|
4095
|
+
fontSize: 15,
|
|
4096
|
+
fontWeight: FontWeight.w700,
|
|
4097
|
+
height: 1.3,
|
|
4114
4098
|
),
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4099
|
+
maxLines: 3,
|
|
4100
|
+
overflow: TextOverflow.ellipsis,
|
|
4101
|
+
),
|
|
4102
|
+
const SizedBox(height: 10),
|
|
4103
|
+
Wrap(
|
|
4104
|
+
spacing: 6,
|
|
4105
|
+
runSpacing: 6,
|
|
4106
|
+
children: <Widget>[
|
|
4107
|
+
_MetaPill(
|
|
4108
|
+
label: run.triggerLabel,
|
|
4109
|
+
icon: Icons.bolt_outlined,
|
|
4110
|
+
),
|
|
4111
|
+
_MetaPill(
|
|
4112
|
+
label: run.modelLabel,
|
|
4113
|
+
icon: Icons.memory_outlined,
|
|
4114
|
+
),
|
|
4115
|
+
_MetaPill(
|
|
4116
|
+
label: run.createdAtLabel,
|
|
4117
|
+
icon: Icons.schedule_outlined,
|
|
4118
|
+
),
|
|
4119
|
+
_MetaPill(
|
|
4120
|
+
label: run.durationLabel,
|
|
4121
|
+
icon: Icons.timer_outlined,
|
|
4122
|
+
),
|
|
4123
|
+
if (run.totalTokensLabel.isNotEmpty)
|
|
4124
|
+
_MetaPill(
|
|
4125
|
+
label: '${run.totalTokensLabel} tok',
|
|
4126
|
+
icon: Icons.toll_outlined,
|
|
4127
|
+
),
|
|
4128
|
+
if (run.deliverableType.trim().isNotEmpty)
|
|
4129
|
+
_MetaPill(
|
|
4130
|
+
label: run.deliverableType.replaceAll('_', ' '),
|
|
4131
|
+
icon: Icons.inventory_2_outlined,
|
|
4132
|
+
),
|
|
4133
|
+
],
|
|
4134
|
+
),
|
|
4135
|
+
if (run.error.trim().isNotEmpty) ...<Widget>[
|
|
4136
|
+
const SizedBox(height: 10),
|
|
4137
|
+
Container(
|
|
4138
|
+
width: double.infinity,
|
|
4139
|
+
padding: const EdgeInsets.all(10),
|
|
4140
|
+
decoration: BoxDecoration(
|
|
4141
|
+
color: const Color(0x19EF4444),
|
|
4142
|
+
borderRadius: BorderRadius.circular(10),
|
|
4143
|
+
border: Border.all(color: const Color(0x4CEF4444)),
|
|
4144
|
+
),
|
|
4145
|
+
child: Text(
|
|
4146
|
+
run.error,
|
|
4147
|
+
style: TextStyle(fontSize: 12, height: 1.45),
|
|
4148
|
+
),
|
|
4120
4149
|
),
|
|
4121
4150
|
],
|
|
4122
|
-
),
|
|
4123
|
-
if (run.error.trim().isNotEmpty) ...<Widget>[
|
|
4124
|
-
const SizedBox(height: 16),
|
|
4125
|
-
Container(
|
|
4126
|
-
width: double.infinity,
|
|
4127
|
-
padding: const EdgeInsets.all(14),
|
|
4128
|
-
decoration: BoxDecoration(
|
|
4129
|
-
color: const Color(0x19EF4444),
|
|
4130
|
-
borderRadius: BorderRadius.circular(14),
|
|
4131
|
-
border: Border.all(color: const Color(0x4CEF4444)),
|
|
4132
|
-
),
|
|
4133
|
-
child: Text(run.error, style: TextStyle(height: 1.45)),
|
|
4134
|
-
),
|
|
4135
4151
|
],
|
|
4136
|
-
|
|
4152
|
+
),
|
|
4137
4153
|
),
|
|
4138
4154
|
);
|
|
4139
4155
|
}
|
|
@@ -67,7 +67,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
67
67
|
final Map<String, DateTime> _manualRunCooldowns = <String, DateTime>{};
|
|
68
68
|
static const Duration _manualRunCooldownDuration = Duration(seconds: 10);
|
|
69
69
|
static const Duration _homeWidgetSyncCooldown = Duration(seconds: 5);
|
|
70
|
-
static const int _chatHistoryPageSize =
|
|
70
|
+
static const int _chatHistoryPageSize = 20;
|
|
71
71
|
DateTime? _lastHomeWidgetSyncAt;
|
|
72
72
|
int _authCycle = 0;
|
|
73
73
|
bool _isPollingQrLogin = false;
|
package/package.json
CHANGED